diff options
author | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 |
---|---|---|
committer | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 |
commit | 6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch) | |
tree | e3eda937a05d7db42de725b7013bd0344b987f34 /code/renderer | |
parent | 872d4d7f55af706737ffb361bb76ad13e7496770 (diff) | |
download | ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip |
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/renderer')
29 files changed, 30364 insertions, 30364 deletions
diff --git a/code/renderer/qgl.h b/code/renderer/qgl.h index 5087b2e..3aa111a 100755 --- a/code/renderer/qgl.h +++ b/code/renderer/qgl.h @@ -1,572 +1,572 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-/*
-** QGL.H
-*/
-
-#ifndef __QGL_H__
-#define __QGL_H__
-
-#if defined( __LINT__ )
-
-#include <GL/gl.h>
-
-#elif defined( _WIN32 )
-
-#pragma warning (disable: 4201)
-#pragma warning (disable: 4214)
-#pragma warning (disable: 4514)
-#pragma warning (disable: 4032)
-#pragma warning (disable: 4201)
-#pragma warning (disable: 4214)
-#include <windows.h>
-#include <gl/gl.h>
-
-#elif defined(MACOS_X)
-
-#include "macosx_glimp.h"
-
-#elif defined( __linux__ )
-
-#include <GL/gl.h>
-#include <GL/glx.h>
-// bk001129 - from cvs1.17 (mkv)
-#if defined(__FX__)
-#include <GL/fxmesa.h>
-#endif
-
-#elif defined( __FreeBSD__ ) // rb010123
-
-#include <GL/gl.h>
-#include <GL/glx.h>
-#if defined(__FX__)
-#include <GL/fxmesa.h>
-#endif
-
-#else
-
-#include <gl.h>
-
-#endif
-
-#ifndef APIENTRY
-#define APIENTRY
-#endif
-#ifndef WINAPI
-#define WINAPI
-#endif
-
-
-//===========================================================================
-
-/*
-** multitexture extension definitions
-*/
-#define GL_ACTIVE_TEXTURE_ARB 0x84E0
-#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
-#define GL_MAX_ACTIVE_TEXTURES_ARB 0x84E2
-
-#define GL_TEXTURE0_ARB 0x84C0
-#define GL_TEXTURE1_ARB 0x84C1
-#define GL_TEXTURE2_ARB 0x84C2
-#define GL_TEXTURE3_ARB 0x84C3
-
-// NOTE: some Linux platforms would need those prototypes
-#if defined(MACOS_X)
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
-typedef void (APIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
-typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target);
-typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target);
-#endif
-
-// TTimo - VC7 / XP ?
-#ifdef WIN32
-typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
-typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target);
-typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target);
-#endif
-
-/*
-** extension constants
-*/
-
-
-// S3TC compression constants
-#define GL_RGB_S3TC 0x83A0
-#define GL_RGB4_S3TC 0x83A1
-
-
-// extensions will be function pointers on all platforms
-
-extern void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t );
-extern void ( APIENTRY * qglActiveTextureARB )( GLenum texture );
-extern void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );
-
-extern void ( APIENTRY * qglLockArraysEXT) (GLint, GLint);
-extern void ( APIENTRY * qglUnlockArraysEXT) (void);
-
-//===========================================================================
-
-// non-windows systems will just redefine qgl* to gl*
-#if !defined( _WIN32 ) && !defined(MACOS_X) && !defined( __linux__ ) && !defined( __FreeBSD__ ) // rb010123
-
-#include "qgl_linked.h"
-
-#elif defined(MACOS_X)
-// This includes #ifdefs for optional logging and GL error checking after every GL call as well as #defines to prevent incorrect usage of the non-'qgl' versions of the GL API.
-#include "macosx_qgl.h"
-
-#else
-
-// windows systems use a function pointer for each call so we can load minidrivers
-
-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);
-
-#if defined( _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 * qwglGetDeviceGammaRamp3DFX)( HDC, LPVOID );
-extern BOOL ( WINAPI * qwglSetDeviceGammaRamp3DFX)( HDC, LPVOID );
-
-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 );
-
-#endif // _WIN32
-
-#if ( (defined __linux__ ) || (defined __FreeBSD__ ) ) // rb010123
-
-//FX Mesa Functions
-// bk001129 - from cvs1.17 (mkv)
-#if defined (__FX__)
-extern fxMesaContext (*qfxMesaCreateContext)(GLuint win, GrScreenResolution_t, GrScreenRefresh_t, const GLint attribList[]);
-extern fxMesaContext (*qfxMesaCreateBestContext)(GLuint win, GLint width, GLint height, const GLint attribList[]);
-extern void (*qfxMesaDestroyContext)(fxMesaContext ctx);
-extern void (*qfxMesaMakeCurrent)(fxMesaContext ctx);
-extern fxMesaContext (*qfxMesaGetCurrentContext)(void);
-extern void (*qfxMesaSwapBuffers)(void);
-#endif
-
-//GLX Functions
-extern XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList );
-extern GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct );
-extern void (*qglXDestroyContext)( Display *dpy, GLXContext ctx );
-extern Bool (*qglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx);
-extern void (*qglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, GLuint mask );
-extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable );
-
-#endif // __linux__ || __FreeBSD__ // rb010123
-
-#endif // _WIN32 && __linux__
-
-#endif
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +/* +** QGL.H +*/ + +#ifndef __QGL_H__ +#define __QGL_H__ + +#if defined( __LINT__ ) + +#include <GL/gl.h> + +#elif defined( _WIN32 ) + +#pragma warning (disable: 4201) +#pragma warning (disable: 4214) +#pragma warning (disable: 4514) +#pragma warning (disable: 4032) +#pragma warning (disable: 4201) +#pragma warning (disable: 4214) +#include <windows.h> +#include <gl/gl.h> + +#elif defined(MACOS_X) + +#include "macosx_glimp.h" + +#elif defined( __linux__ ) + +#include <GL/gl.h> +#include <GL/glx.h> +// bk001129 - from cvs1.17 (mkv) +#if defined(__FX__) +#include <GL/fxmesa.h> +#endif + +#elif defined( __FreeBSD__ ) // rb010123 + +#include <GL/gl.h> +#include <GL/glx.h> +#if defined(__FX__) +#include <GL/fxmesa.h> +#endif + +#else + +#include <gl.h> + +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef WINAPI +#define WINAPI +#endif + + +//=========================================================================== + +/* +** multitexture extension definitions +*/ +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_ACTIVE_TEXTURES_ARB 0x84E2 + +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3_ARB 0x84C3 + +// NOTE: some Linux platforms would need those prototypes +#if defined(MACOS_X) +typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target); +typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target); +#endif + +// TTimo - VC7 / XP ? +#ifdef WIN32 +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target); +typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target); +#endif + +/* +** extension constants +*/ + + +// S3TC compression constants +#define GL_RGB_S3TC 0x83A0 +#define GL_RGB4_S3TC 0x83A1 + + +// extensions will be function pointers on all platforms + +extern void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); +extern void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); +extern void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); + +extern void ( APIENTRY * qglLockArraysEXT) (GLint, GLint); +extern void ( APIENTRY * qglUnlockArraysEXT) (void); + +//=========================================================================== + +// non-windows systems will just redefine qgl* to gl* +#if !defined( _WIN32 ) && !defined(MACOS_X) && !defined( __linux__ ) && !defined( __FreeBSD__ ) // rb010123 + +#include "qgl_linked.h" + +#elif defined(MACOS_X) +// This includes #ifdefs for optional logging and GL error checking after every GL call as well as #defines to prevent incorrect usage of the non-'qgl' versions of the GL API. +#include "macosx_qgl.h" + +#else + +// windows systems use a function pointer for each call so we can load minidrivers + +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); + +#if defined( _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 * qwglGetDeviceGammaRamp3DFX)( HDC, LPVOID ); +extern BOOL ( WINAPI * qwglSetDeviceGammaRamp3DFX)( HDC, LPVOID ); + +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 ); + +#endif // _WIN32 + +#if ( (defined __linux__ ) || (defined __FreeBSD__ ) ) // rb010123 + +//FX Mesa Functions +// bk001129 - from cvs1.17 (mkv) +#if defined (__FX__) +extern fxMesaContext (*qfxMesaCreateContext)(GLuint win, GrScreenResolution_t, GrScreenRefresh_t, const GLint attribList[]); +extern fxMesaContext (*qfxMesaCreateBestContext)(GLuint win, GLint width, GLint height, const GLint attribList[]); +extern void (*qfxMesaDestroyContext)(fxMesaContext ctx); +extern void (*qfxMesaMakeCurrent)(fxMesaContext ctx); +extern fxMesaContext (*qfxMesaGetCurrentContext)(void); +extern void (*qfxMesaSwapBuffers)(void); +#endif + +//GLX Functions +extern XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList ); +extern GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct ); +extern void (*qglXDestroyContext)( Display *dpy, GLXContext ctx ); +extern Bool (*qglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx); +extern void (*qglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, GLuint mask ); +extern void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); + +#endif // __linux__ || __FreeBSD__ // rb010123 + +#endif // _WIN32 && __linux__ + +#endif diff --git a/code/renderer/qgl_linked.h b/code/renderer/qgl_linked.h index 6028a74..b13163d 100755 --- a/code/renderer/qgl_linked.h +++ b/code/renderer/qgl_linked.h @@ -1,357 +1,357 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#define qglAccum glAccum
-#define qglAlphaFunc glAlphaFunc
-#define qglAreTexturesResident glAreTexturesResident
-#define qglArrayElement glArrayElement
-#define qglBegin glBegin
-#define qglBindTexture glBindTexture
-#define qglBitmap glBitmap
-#define qglBlendFunc glBlendFunc
-#define qglCallList glCallList
-#define qglCallLists glCallLists
-#define qglClear glClear
-#define qglClearAccum glClearAccum
-#define qglClearColor glClearColor
-#define qglClearDepth glClearDepth
-#define qglClearIndex glClearIndex
-#define qglClearStencil glClearStencil
-#define qglClipPlane glClipPlane
-#define qglColor3b glColor3b
-#define qglColor3bv glColor3bv
-#define qglColor3d glColor3d
-#define qglColor3dv glColor3dv
-#define qglColor3f glColor3f
-#define qglColor3fv glColor3fv
-#define qglColor3i glColor3i
-#define qglColor3iv glColor3iv
-#define qglColor3s glColor3s
-#define qglColor3sv glColor3sv
-#define qglColor3ub glColor3ub
-#define qglColor3ubv glColor3ubv
-#define qglColor3ui glColor3ui
-#define qglColor3uiv glColor3uiv
-#define qglColor3us glColor3us
-#define qglColor3usv glColor3usv
-#define qglColor4b glColor4b
-#define qglColor4bv glColor4bv
-#define qglColor4d glColor4d
-#define qglColor4dv glColor4dv
-#define qglColor4f glColor4f
-#define qglColor4fv glColor4fv
-#define qglColor4i glColor4i
-#define qglColor4iv glColor4iv
-#define qglColor4s glColor4s
-#define qglColor4sv glColor4sv
-#define qglColor4ub glColor4ub
-#define qglColor4ubv glColor4ubv
-#define qglColor4ui glColor4ui
-#define qglColor4uiv glColor4uiv
-#define qglColor4us glColor4us
-#define qglColor4usv glColor4usv
-#define qglColorMask glColorMask
-#define qglColorMaterial glColorMaterial
-#define qglColorPointer glColorPointer
-#define qglCopyPixels glCopyPixels
-#define qglCopyTexImage1D glCopyTexImage1D
-#define qglCopyTexImage2D glCopyTexImage2D
-#define qglCopyTexSubImage1D glCopyTexSubImage1D
-#define qglCopyTexSubImage2D glCopyTexSubImage2D
-#define qglCullFace glCullFace
-#define qglDeleteLists glDeleteLists
-#define qglDeleteTextures glDeleteTextures
-#define qglDepthFunc glDepthFunc
-#define qglDepthMask glDepthMask
-#define qglDepthRange glDepthRange
-#define qglDisable glDisable
-#define qglDisableClientState glDisableClientState
-#define qglDrawArrays glDrawArrays
-#define qglDrawBuffer glDrawBuffer
-#define qglDrawElements glDrawElements
-#define qglDrawPixels glDrawPixels
-#define qglEdgeFlag glEdgeFlag
-#define qglEdgeFlagPointer glEdgeFlagPointer
-#define qglEdgeFlagv glEdgeFlagv
-#define qglEnable glEnable
-#define qglEnableClientState glEnableClientState
-#define qglEnd glEnd
-#define qglEndList glEndList
-#define qglEvalCoord1d glEvalCoord1d
-#define qglEvalCoord1dv glEvalCoord1dv
-#define qglEvalCoord1f glEvalCoord1f
-#define qglEvalCoord1fv glEvalCoord1fv
-#define qglEvalCoord2d glEvalCoord2d
-#define qglEvalCoord2dv glEvalCoord2dv
-#define qglEvalCoord2f glEvalCoord2f
-#define qglEvalCoord2fv glEvalCoord2fv
-#define qglEvalMesh1 glEvalMesh1
-#define qglEvalMesh2 glEvalMesh2
-#define qglEvalPoint1 glEvalPoint1
-#define qglEvalPoint2 glEvalPoint2
-#define qglFeedbackBuffer glFeedbackBuffer
-#define qglFinish glFinish
-#define qglFlush glFlush
-#define qglFogf glFogf
-#define qglFogfv glFogfv
-#define qglFogi glFogi
-#define qglFogiv glFogiv
-#define qglFrontFace glFrontFace
-#define qglFrustum glFrustum
-#define qglGenLists glGenLists
-#define qglGenTextures glGenTextures
-#define qglGetBooleanv glGetBooleanv
-#define qglGetClipPlane glGetClipPlane
-#define qglGetDoublev glGetDoublev
-#define qglGetError glGetError
-#define qglGetFloatv glGetFloatv
-#define qglGetIntegerv glGetIntegerv
-#define qglGetLightfv glGetLightfv
-#define qglGetLightiv glGetLightiv
-#define qglGetMapdv glGetMapdv
-#define qglGetMapfv glGetMapfv
-#define qglGetMapiv glGetMapiv
-#define qglGetMaterialfv glGetMaterialfv
-#define qglGetMaterialiv glGetMaterialiv
-#define qglGetPixelMapfv glGetPixelMapfv
-#define qglGetPixelMapuiv glGetPixelMapuiv
-#define qglGetPixelMapusv glGetPixelMapusv
-#define qglGetPointerv glGetPointerv
-#define qglGetPolygonStipple glGetPolygonStipple
-#define qglGetString glGetString
-#define qglGetTexGendv glGetTexGendv
-#define qglGetTexGenfv glGetTexGenfv
-#define qglGetTexGeniv glGetTexGeniv
-#define qglGetTexImage glGetTexImage
-#define qglGetTexLevelParameterfv glGetTexLevelParameterfv
-#define qglGetTexLevelParameteriv glGetTexLevelParameteriv
-#define qglGetTexParameterfv glGetTexParameterfv
-#define qglGetTexParameteriv glGetTexParameteriv
-#define qglHint glHint
-#define qglIndexMask glIndexMask
-#define qglIndexPointer glIndexPointer
-#define qglIndexd glIndexd
-#define qglIndexdv glIndexdv
-#define qglIndexf glIndexf
-#define qglIndexfv glIndexfv
-#define qglIndexi glIndexi
-#define qglIndexiv glIndexiv
-#define qglIndexs glIndexs
-#define qglIndexsv glIndexsv
-#define qglIndexub glIndexub
-#define qglIndexubv glIndexubv
-#define qglInitNames glInitNames
-#define qglInterleavedArrays glInterleavedArrays
-#define qglIsEnabled glIsEnabled
-#define qglIsList glIsList
-#define qglIsTexture glIsTexture
-#define qglLightModelf glLightModelf
-#define qglLightModelfv glLightModelfv
-#define qglLightModeli glLightModeli
-#define qglLightModeliv glLightModeliv
-#define qglLightf glLightf
-#define qglLightfv glLightfv
-#define qglLighti glLighti
-#define qglLightiv glLightiv
-#define qglLineStipple glLineStipple
-#define qglLineWidth glLineWidth
-#define qglListBase glListBase
-#define qglLoadIdentity glLoadIdentity
-#define qglLoadMatrixd glLoadMatrixd
-#define qglLoadMatrixf glLoadMatrixf
-#define qglLoadName glLoadName
-#define qglLogicOp glLogicOp
-#define qglMap1d glMap1d
-#define qglMap1f glMap1f
-#define qglMap2d glMap2d
-#define qglMap2f glMap2f
-#define qglMapGrid1d glMapGrid1d
-#define qglMapGrid1f glMapGrid1f
-#define qglMapGrid2d glMapGrid2d
-#define qglMapGrid2f glMapGrid2f
-#define qglMaterialf glMaterialf
-#define qglMaterialfv glMaterialfv
-#define qglMateriali glMateriali
-#define qglMaterialiv glMaterialiv
-#define qglMatrixMode glMatrixMode
-#define qglMultMatrixd glMultMatrixd
-#define qglMultMatrixf glMultMatrixf
-#define qglNewList glNewList
-#define qglNormal3b glNormal3b
-#define qglNormal3bv glNormal3bv
-#define qglNormal3d glNormal3d
-#define qglNormal3dv glNormal3dv
-#define qglNormal3f glNormal3f
-#define qglNormal3fv glNormal3fv
-#define qglNormal3i glNormal3i
-#define qglNormal3iv glNormal3iv
-#define qglNormal3s glNormal3s
-#define qglNormal3sv glNormal3sv
-#define qglNormalPointer glNormalPointer
-#define qglOrtho glOrtho
-#define qglPassThrough glPassThrough
-#define qglPixelMapfv glPixelMapfv
-#define qglPixelMapuiv glPixelMapuiv
-#define qglPixelMapusv glPixelMapusv
-#define qglPixelStoref glPixelStoref
-#define qglPixelStorei glPixelStorei
-#define qglPixelTransferf glPixelTransferf
-#define qglPixelTransferi glPixelTransferi
-#define qglPixelZoom glPixelZoom
-#define qglPointSize glPointSize
-#define qglPolygonMode glPolygonMode
-#define qglPolygonOffset glPolygonOffset
-#define qglPolygonStipple glPolygonStipple
-#define qglPopAttrib glPopAttrib
-#define qglPopClientAttrib glPopClientAttrib
-#define qglPopMatrix glPopMatrix
-#define qglPopName glPopName
-#define qglPrioritizeTextures glPrioritizeTextures
-#define qglPushAttrib glPushAttrib
-#define qglPushClientAttrib glPushClientAttrib
-#define qglPushMatrix glPushMatrix
-#define qglPushName glPushName
-#define qglRasterPos2d glRasterPos2d
-#define qglRasterPos2dv glRasterPos2dv
-#define qglRasterPos2f glRasterPos2f
-#define qglRasterPos2fv glRasterPos2fv
-#define qglRasterPos2i glRasterPos2i
-#define qglRasterPos2iv glRasterPos2iv
-#define qglRasterPos2s glRasterPos2s
-#define qglRasterPos2sv glRasterPos2sv
-#define qglRasterPos3d glRasterPos3d
-#define qglRasterPos3dv glRasterPos3dv
-#define qglRasterPos3f glRasterPos3f
-#define qglRasterPos3fv glRasterPos3fv
-#define qglRasterPos3i glRasterPos3i
-#define qglRasterPos3iv glRasterPos3iv
-#define qglRasterPos3s glRasterPos3s
-#define qglRasterPos3sv glRasterPos3sv
-#define qglRasterPos4d glRasterPos4d
-#define qglRasterPos4dv glRasterPos4dv
-#define qglRasterPos4f glRasterPos4f
-#define qglRasterPos4fv glRasterPos4fv
-#define qglRasterPos4i glRasterPos4i
-#define qglRasterPos4iv glRasterPos4iv
-#define qglRasterPos4s glRasterPos4s
-#define qglRasterPos4sv glRasterPos4sv
-#define qglReadBuffer glReadBuffer
-#define qglReadPixels glReadPixels
-#define qglRectd glRectd
-#define qglRectdv glRectdv
-#define qglRectf glRectf
-#define qglRectfv glRectfv
-#define qglRecti glRecti
-#define qglRectiv glRectiv
-#define qglRects glRects
-#define qglRectsv glRectsv
-#define qglRenderMode glRenderMode
-#define qglRotated glRotated
-#define qglRotatef glRotatef
-#define qglScaled glScaled
-#define qglScalef glScalef
-#define qglScissor glScissor
-#define qglSelectBuffer glSelectBuffer
-#define qglShadeModel glShadeModel
-#define qglStencilFunc glStencilFunc
-#define qglStencilMask glStencilMask
-#define qglStencilOp glStencilOp
-#define qglTexCoord1d glTexCoord1d
-#define qglTexCoord1dv glTexCoord1dv
-#define qglTexCoord1f glTexCoord1f
-#define qglTexCoord1fv glTexCoord1fv
-#define qglTexCoord1i glTexCoord1i
-#define qglTexCoord1iv glTexCoord1iv
-#define qglTexCoord1s glTexCoord1s
-#define qglTexCoord1sv glTexCoord1sv
-#define qglTexCoord2d glTexCoord2d
-#define qglTexCoord2dv glTexCoord2dv
-#define qglTexCoord2f glTexCoord2f
-#define qglTexCoord2fv glTexCoord2fv
-#define qglTexCoord2i glTexCoord2i
-#define qglTexCoord2iv glTexCoord2iv
-#define qglTexCoord2s glTexCoord2s
-#define qglTexCoord2sv glTexCoord2sv
-#define qglTexCoord3d glTexCoord3d
-#define qglTexCoord3dv glTexCoord3dv
-#define qglTexCoord3f glTexCoord3f
-#define qglTexCoord3fv glTexCoord3fv
-#define qglTexCoord3i glTexCoord3i
-#define qglTexCoord3iv glTexCoord3iv
-#define qglTexCoord3s glTexCoord3s
-#define qglTexCoord3sv glTexCoord3sv
-#define qglTexCoord4d glTexCoord4d
-#define qglTexCoord4dv glTexCoord4dv
-#define qglTexCoord4f glTexCoord4f
-#define qglTexCoord4fv glTexCoord4fv
-#define qglTexCoord4i glTexCoord4i
-#define qglTexCoord4iv glTexCoord4iv
-#define qglTexCoord4s glTexCoord4s
-#define qglTexCoord4sv glTexCoord4sv
-#define qglTexCoordPointer glTexCoordPointer
-#define qglTexEnvf glTexEnvf
-#define qglTexEnvfv glTexEnvfv
-#define qglTexEnvi glTexEnvi
-#define qglTexEnviv glTexEnviv
-#define qglTexGend glTexGend
-#define qglTexGendv glTexGendv
-#define qglTexGenf glTexGenf
-#define qglTexGenfv glTexGenfv
-#define qglTexGeni glTexGeni
-#define qglTexGeniv glTexGeniv
-#define qglTexImage1D glTexImage1D
-#define qglTexImage2D glTexImage2D
-#define qglTexParameterf glTexParameterf
-#define qglTexParameterfv glTexParameterfv
-#define qglTexParameteri glTexParameteri
-#define qglTexParameteriv glTexParameteriv
-#define qglTexSubImage1D glTexSubImage1D
-#define qglTexSubImage2D glTexSubImage2D
-#define qglTranslated glTranslated
-#define qglTranslatef glTranslatef
-#define qglVertex2d glVertex2d
-#define qglVertex2dv glVertex2dv
-#define qglVertex2f glVertex2f
-#define qglVertex2fv glVertex2fv
-#define qglVertex2i glVertex2i
-#define qglVertex2iv glVertex2iv
-#define qglVertex2s glVertex2s
-#define qglVertex2sv glVertex2sv
-#define qglVertex3d glVertex3d
-#define qglVertex3dv glVertex3dv
-#define qglVertex3f glVertex3f
-#define qglVertex3fv glVertex3fv
-#define qglVertex3i glVertex3i
-#define qglVertex3iv glVertex3iv
-#define qglVertex3s glVertex3s
-#define qglVertex3sv glVertex3sv
-#define qglVertex4d glVertex4d
-#define qglVertex4dv glVertex4dv
-#define qglVertex4f glVertex4f
-#define qglVertex4fv glVertex4fv
-#define qglVertex4i glVertex4i
-#define qglVertex4iv glVertex4iv
-#define qglVertex4s glVertex4s
-#define qglVertex4sv glVertex4sv
-#define qglVertexPointer glVertexPointer
-#define qglViewport glViewport
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#define qglAccum glAccum +#define qglAlphaFunc glAlphaFunc +#define qglAreTexturesResident glAreTexturesResident +#define qglArrayElement glArrayElement +#define qglBegin glBegin +#define qglBindTexture glBindTexture +#define qglBitmap glBitmap +#define qglBlendFunc glBlendFunc +#define qglCallList glCallList +#define qglCallLists glCallLists +#define qglClear glClear +#define qglClearAccum glClearAccum +#define qglClearColor glClearColor +#define qglClearDepth glClearDepth +#define qglClearIndex glClearIndex +#define qglClearStencil glClearStencil +#define qglClipPlane glClipPlane +#define qglColor3b glColor3b +#define qglColor3bv glColor3bv +#define qglColor3d glColor3d +#define qglColor3dv glColor3dv +#define qglColor3f glColor3f +#define qglColor3fv glColor3fv +#define qglColor3i glColor3i +#define qglColor3iv glColor3iv +#define qglColor3s glColor3s +#define qglColor3sv glColor3sv +#define qglColor3ub glColor3ub +#define qglColor3ubv glColor3ubv +#define qglColor3ui glColor3ui +#define qglColor3uiv glColor3uiv +#define qglColor3us glColor3us +#define qglColor3usv glColor3usv +#define qglColor4b glColor4b +#define qglColor4bv glColor4bv +#define qglColor4d glColor4d +#define qglColor4dv glColor4dv +#define qglColor4f glColor4f +#define qglColor4fv glColor4fv +#define qglColor4i glColor4i +#define qglColor4iv glColor4iv +#define qglColor4s glColor4s +#define qglColor4sv glColor4sv +#define qglColor4ub glColor4ub +#define qglColor4ubv glColor4ubv +#define qglColor4ui glColor4ui +#define qglColor4uiv glColor4uiv +#define qglColor4us glColor4us +#define qglColor4usv glColor4usv +#define qglColorMask glColorMask +#define qglColorMaterial glColorMaterial +#define qglColorPointer glColorPointer +#define qglCopyPixels glCopyPixels +#define qglCopyTexImage1D glCopyTexImage1D +#define qglCopyTexImage2D glCopyTexImage2D +#define qglCopyTexSubImage1D glCopyTexSubImage1D +#define qglCopyTexSubImage2D glCopyTexSubImage2D +#define qglCullFace glCullFace +#define qglDeleteLists glDeleteLists +#define qglDeleteTextures glDeleteTextures +#define qglDepthFunc glDepthFunc +#define qglDepthMask glDepthMask +#define qglDepthRange glDepthRange +#define qglDisable glDisable +#define qglDisableClientState glDisableClientState +#define qglDrawArrays glDrawArrays +#define qglDrawBuffer glDrawBuffer +#define qglDrawElements glDrawElements +#define qglDrawPixels glDrawPixels +#define qglEdgeFlag glEdgeFlag +#define qglEdgeFlagPointer glEdgeFlagPointer +#define qglEdgeFlagv glEdgeFlagv +#define qglEnable glEnable +#define qglEnableClientState glEnableClientState +#define qglEnd glEnd +#define qglEndList glEndList +#define qglEvalCoord1d glEvalCoord1d +#define qglEvalCoord1dv glEvalCoord1dv +#define qglEvalCoord1f glEvalCoord1f +#define qglEvalCoord1fv glEvalCoord1fv +#define qglEvalCoord2d glEvalCoord2d +#define qglEvalCoord2dv glEvalCoord2dv +#define qglEvalCoord2f glEvalCoord2f +#define qglEvalCoord2fv glEvalCoord2fv +#define qglEvalMesh1 glEvalMesh1 +#define qglEvalMesh2 glEvalMesh2 +#define qglEvalPoint1 glEvalPoint1 +#define qglEvalPoint2 glEvalPoint2 +#define qglFeedbackBuffer glFeedbackBuffer +#define qglFinish glFinish +#define qglFlush glFlush +#define qglFogf glFogf +#define qglFogfv glFogfv +#define qglFogi glFogi +#define qglFogiv glFogiv +#define qglFrontFace glFrontFace +#define qglFrustum glFrustum +#define qglGenLists glGenLists +#define qglGenTextures glGenTextures +#define qglGetBooleanv glGetBooleanv +#define qglGetClipPlane glGetClipPlane +#define qglGetDoublev glGetDoublev +#define qglGetError glGetError +#define qglGetFloatv glGetFloatv +#define qglGetIntegerv glGetIntegerv +#define qglGetLightfv glGetLightfv +#define qglGetLightiv glGetLightiv +#define qglGetMapdv glGetMapdv +#define qglGetMapfv glGetMapfv +#define qglGetMapiv glGetMapiv +#define qglGetMaterialfv glGetMaterialfv +#define qglGetMaterialiv glGetMaterialiv +#define qglGetPixelMapfv glGetPixelMapfv +#define qglGetPixelMapuiv glGetPixelMapuiv +#define qglGetPixelMapusv glGetPixelMapusv +#define qglGetPointerv glGetPointerv +#define qglGetPolygonStipple glGetPolygonStipple +#define qglGetString glGetString +#define qglGetTexGendv glGetTexGendv +#define qglGetTexGenfv glGetTexGenfv +#define qglGetTexGeniv glGetTexGeniv +#define qglGetTexImage glGetTexImage +#define qglGetTexLevelParameterfv glGetTexLevelParameterfv +#define qglGetTexLevelParameteriv glGetTexLevelParameteriv +#define qglGetTexParameterfv glGetTexParameterfv +#define qglGetTexParameteriv glGetTexParameteriv +#define qglHint glHint +#define qglIndexMask glIndexMask +#define qglIndexPointer glIndexPointer +#define qglIndexd glIndexd +#define qglIndexdv glIndexdv +#define qglIndexf glIndexf +#define qglIndexfv glIndexfv +#define qglIndexi glIndexi +#define qglIndexiv glIndexiv +#define qglIndexs glIndexs +#define qglIndexsv glIndexsv +#define qglIndexub glIndexub +#define qglIndexubv glIndexubv +#define qglInitNames glInitNames +#define qglInterleavedArrays glInterleavedArrays +#define qglIsEnabled glIsEnabled +#define qglIsList glIsList +#define qglIsTexture glIsTexture +#define qglLightModelf glLightModelf +#define qglLightModelfv glLightModelfv +#define qglLightModeli glLightModeli +#define qglLightModeliv glLightModeliv +#define qglLightf glLightf +#define qglLightfv glLightfv +#define qglLighti glLighti +#define qglLightiv glLightiv +#define qglLineStipple glLineStipple +#define qglLineWidth glLineWidth +#define qglListBase glListBase +#define qglLoadIdentity glLoadIdentity +#define qglLoadMatrixd glLoadMatrixd +#define qglLoadMatrixf glLoadMatrixf +#define qglLoadName glLoadName +#define qglLogicOp glLogicOp +#define qglMap1d glMap1d +#define qglMap1f glMap1f +#define qglMap2d glMap2d +#define qglMap2f glMap2f +#define qglMapGrid1d glMapGrid1d +#define qglMapGrid1f glMapGrid1f +#define qglMapGrid2d glMapGrid2d +#define qglMapGrid2f glMapGrid2f +#define qglMaterialf glMaterialf +#define qglMaterialfv glMaterialfv +#define qglMateriali glMateriali +#define qglMaterialiv glMaterialiv +#define qglMatrixMode glMatrixMode +#define qglMultMatrixd glMultMatrixd +#define qglMultMatrixf glMultMatrixf +#define qglNewList glNewList +#define qglNormal3b glNormal3b +#define qglNormal3bv glNormal3bv +#define qglNormal3d glNormal3d +#define qglNormal3dv glNormal3dv +#define qglNormal3f glNormal3f +#define qglNormal3fv glNormal3fv +#define qglNormal3i glNormal3i +#define qglNormal3iv glNormal3iv +#define qglNormal3s glNormal3s +#define qglNormal3sv glNormal3sv +#define qglNormalPointer glNormalPointer +#define qglOrtho glOrtho +#define qglPassThrough glPassThrough +#define qglPixelMapfv glPixelMapfv +#define qglPixelMapuiv glPixelMapuiv +#define qglPixelMapusv glPixelMapusv +#define qglPixelStoref glPixelStoref +#define qglPixelStorei glPixelStorei +#define qglPixelTransferf glPixelTransferf +#define qglPixelTransferi glPixelTransferi +#define qglPixelZoom glPixelZoom +#define qglPointSize glPointSize +#define qglPolygonMode glPolygonMode +#define qglPolygonOffset glPolygonOffset +#define qglPolygonStipple glPolygonStipple +#define qglPopAttrib glPopAttrib +#define qglPopClientAttrib glPopClientAttrib +#define qglPopMatrix glPopMatrix +#define qglPopName glPopName +#define qglPrioritizeTextures glPrioritizeTextures +#define qglPushAttrib glPushAttrib +#define qglPushClientAttrib glPushClientAttrib +#define qglPushMatrix glPushMatrix +#define qglPushName glPushName +#define qglRasterPos2d glRasterPos2d +#define qglRasterPos2dv glRasterPos2dv +#define qglRasterPos2f glRasterPos2f +#define qglRasterPos2fv glRasterPos2fv +#define qglRasterPos2i glRasterPos2i +#define qglRasterPos2iv glRasterPos2iv +#define qglRasterPos2s glRasterPos2s +#define qglRasterPos2sv glRasterPos2sv +#define qglRasterPos3d glRasterPos3d +#define qglRasterPos3dv glRasterPos3dv +#define qglRasterPos3f glRasterPos3f +#define qglRasterPos3fv glRasterPos3fv +#define qglRasterPos3i glRasterPos3i +#define qglRasterPos3iv glRasterPos3iv +#define qglRasterPos3s glRasterPos3s +#define qglRasterPos3sv glRasterPos3sv +#define qglRasterPos4d glRasterPos4d +#define qglRasterPos4dv glRasterPos4dv +#define qglRasterPos4f glRasterPos4f +#define qglRasterPos4fv glRasterPos4fv +#define qglRasterPos4i glRasterPos4i +#define qglRasterPos4iv glRasterPos4iv +#define qglRasterPos4s glRasterPos4s +#define qglRasterPos4sv glRasterPos4sv +#define qglReadBuffer glReadBuffer +#define qglReadPixels glReadPixels +#define qglRectd glRectd +#define qglRectdv glRectdv +#define qglRectf glRectf +#define qglRectfv glRectfv +#define qglRecti glRecti +#define qglRectiv glRectiv +#define qglRects glRects +#define qglRectsv glRectsv +#define qglRenderMode glRenderMode +#define qglRotated glRotated +#define qglRotatef glRotatef +#define qglScaled glScaled +#define qglScalef glScalef +#define qglScissor glScissor +#define qglSelectBuffer glSelectBuffer +#define qglShadeModel glShadeModel +#define qglStencilFunc glStencilFunc +#define qglStencilMask glStencilMask +#define qglStencilOp glStencilOp +#define qglTexCoord1d glTexCoord1d +#define qglTexCoord1dv glTexCoord1dv +#define qglTexCoord1f glTexCoord1f +#define qglTexCoord1fv glTexCoord1fv +#define qglTexCoord1i glTexCoord1i +#define qglTexCoord1iv glTexCoord1iv +#define qglTexCoord1s glTexCoord1s +#define qglTexCoord1sv glTexCoord1sv +#define qglTexCoord2d glTexCoord2d +#define qglTexCoord2dv glTexCoord2dv +#define qglTexCoord2f glTexCoord2f +#define qglTexCoord2fv glTexCoord2fv +#define qglTexCoord2i glTexCoord2i +#define qglTexCoord2iv glTexCoord2iv +#define qglTexCoord2s glTexCoord2s +#define qglTexCoord2sv glTexCoord2sv +#define qglTexCoord3d glTexCoord3d +#define qglTexCoord3dv glTexCoord3dv +#define qglTexCoord3f glTexCoord3f +#define qglTexCoord3fv glTexCoord3fv +#define qglTexCoord3i glTexCoord3i +#define qglTexCoord3iv glTexCoord3iv +#define qglTexCoord3s glTexCoord3s +#define qglTexCoord3sv glTexCoord3sv +#define qglTexCoord4d glTexCoord4d +#define qglTexCoord4dv glTexCoord4dv +#define qglTexCoord4f glTexCoord4f +#define qglTexCoord4fv glTexCoord4fv +#define qglTexCoord4i glTexCoord4i +#define qglTexCoord4iv glTexCoord4iv +#define qglTexCoord4s glTexCoord4s +#define qglTexCoord4sv glTexCoord4sv +#define qglTexCoordPointer glTexCoordPointer +#define qglTexEnvf glTexEnvf +#define qglTexEnvfv glTexEnvfv +#define qglTexEnvi glTexEnvi +#define qglTexEnviv glTexEnviv +#define qglTexGend glTexGend +#define qglTexGendv glTexGendv +#define qglTexGenf glTexGenf +#define qglTexGenfv glTexGenfv +#define qglTexGeni glTexGeni +#define qglTexGeniv glTexGeniv +#define qglTexImage1D glTexImage1D +#define qglTexImage2D glTexImage2D +#define qglTexParameterf glTexParameterf +#define qglTexParameterfv glTexParameterfv +#define qglTexParameteri glTexParameteri +#define qglTexParameteriv glTexParameteriv +#define qglTexSubImage1D glTexSubImage1D +#define qglTexSubImage2D glTexSubImage2D +#define qglTranslated glTranslated +#define qglTranslatef glTranslatef +#define qglVertex2d glVertex2d +#define qglVertex2dv glVertex2dv +#define qglVertex2f glVertex2f +#define qglVertex2fv glVertex2fv +#define qglVertex2i glVertex2i +#define qglVertex2iv glVertex2iv +#define qglVertex2s glVertex2s +#define qglVertex2sv glVertex2sv +#define qglVertex3d glVertex3d +#define qglVertex3dv glVertex3dv +#define qglVertex3f glVertex3f +#define qglVertex3fv glVertex3fv +#define qglVertex3i glVertex3i +#define qglVertex3iv glVertex3iv +#define qglVertex3s glVertex3s +#define qglVertex3sv glVertex3sv +#define qglVertex4d glVertex4d +#define qglVertex4dv glVertex4dv +#define qglVertex4f glVertex4f +#define qglVertex4fv glVertex4fv +#define qglVertex4i glVertex4i +#define qglVertex4iv glVertex4iv +#define qglVertex4s glVertex4s +#define qglVertex4sv glVertex4sv +#define qglVertexPointer glVertexPointer +#define qglViewport glViewport + diff --git a/code/renderer/ref_trin.def b/code/renderer/ref_trin.def index 2fefbd3..cfbb471 100755 --- a/code/renderer/ref_trin.def +++ b/code/renderer/ref_trin.def @@ -1,2 +1,2 @@ -EXPORTS
- GetRefAPI
+EXPORTS + GetRefAPI diff --git a/code/renderer/renderer.vcproj b/code/renderer/renderer.vcproj index edbd1ec..848f39b 100755 --- a/code/renderer/renderer.vcproj +++ b/code/renderer/renderer.vcproj @@ -1,6112 +1,6112 @@ -<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="renderer"
- SccProjectName=""$/MissionPack/code/renderer", EJBAAAAA"
- SccLocalPath=".">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug TA|Win32"
- OutputDirectory=".\Debug_TA"
- IntermediateDirectory=".\Debug_TA"
- ConfigurationType="4"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- OptimizeForProcessor="1"
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Debug_TA/renderer.pch"
- AssemblerListingLocation=".\Debug_TA/"
- ObjectFile=".\Debug_TA/"
- ProgramDataBaseFileName=".\Debug_TA/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLibrarianTool"
- OutputFile=".\Debug_TA\renderer.lib"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="4"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- OptimizeForProcessor="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
- StringPooling="TRUE"
- RuntimeLibrary="4"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Release/renderer.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- WarningLevel="4"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLibrarianTool"
- OutputFile=".\Release\renderer.lib"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory=".\Debug"
- IntermediateDirectory=".\Debug"
- ConfigurationType="4"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- OptimizeForProcessor="1"
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Debug/renderer.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLibrarianTool"
- OutputFile=".\Debug\renderer.lib"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release TA|Win32"
- OutputDirectory=".\Release_TA"
- IntermediateDirectory=".\Release_TA"
- ConfigurationType="4"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- OptimizeForProcessor="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
- StringPooling="TRUE"
- RuntimeLibrary="4"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Release_TA/renderer.pch"
- AssemblerListingLocation=".\Release_TA/"
- ObjectFile=".\Release_TA/"
- ProgramDataBaseFileName=".\Release_TA/"
- WarningLevel="4"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLibrarianTool"
- OutputFile=".\Release_TA\renderer.lib"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="vector|Win32"
- OutputDirectory=".\renderer___Win32_vector0"
- IntermediateDirectory=".\renderer___Win32_vector0"
- ConfigurationType="4"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="/vec /vec:stats /vec:pii /vec:o10 /vec:yes "
- Optimization="2"
- InlineFunctionExpansion="2"
- OptimizeForProcessor="2"
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
- StringPooling="TRUE"
- RuntimeLibrary="4"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\renderer___Win32_vector0/renderer.pch"
- AssemblerListingLocation=".\renderer___Win32_vector0/"
- ObjectFile=".\renderer___Win32_vector0/"
- ProgramDataBaseFileName=".\renderer___Win32_vector0/"
- WarningLevel="4"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLibrarianTool"
- OutputFile=".\renderer___Win32_vector0\renderer.lib"
- SuppressStartupBanner="TRUE"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
- <File
- RelativePath="ref_trin.def">
- </File>
- <File
- RelativePath="tr_animation.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_backend.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_bsp.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_cmds.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_curve.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_flares.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_font.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_image.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_init.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_light.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_main.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_marks.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_mesh.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_model.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_noise.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_scene.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_shade.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_shade_calc.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_shader.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_shadows.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_sky.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_surface.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tr_world.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\win32\win_gamma.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\win32\win_glimp.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\win32\win_qgl.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl">
- <File
- RelativePath="..\qcommon\cm_public.h">
- </File>
- <File
- RelativePath="..\win32\glw_win.h">
- </File>
- <File
- RelativePath="..\game\q_shared.h">
- </File>
- <File
- RelativePath="..\qcommon\qcommon.h">
- </File>
- <File
- RelativePath="..\qcommon\qfiles.h">
- </File>
- <File
- RelativePath="qgl.h">
- </File>
- <File
- RelativePath="..\game\surfaceflags.h">
- </File>
- <File
- RelativePath="tr_local.h">
- </File>
- <File
- RelativePath="tr_public.h">
- </File>
- <File
- RelativePath="..\cgame\tr_types.h">
- </File>
- <File
- RelativePath="..\win32\win_local.h">
- </File>
- </Filter>
- <Filter
- Name="jpeg"
- Filter="">
- <Filter
- Name="Source Files No. 1"
- Filter="">
- <File
- RelativePath="..\jpeg-6\jcapimin.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jccoefct.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jccolor.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcdctmgr.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jchuff.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcinit.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcmainct.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcmarker.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcmaster.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcomapi.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcparam.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcphuff.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcprepct.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jcsample.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jctrans.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdapimin.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdapistd.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdatadst.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdatasrc.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdcoefct.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdcolor.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jddctmgr.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdhuff.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdinput.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdmainct.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdmarker.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdmaster.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdpostct.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdsample.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jdtrans.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jerror.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jfdctflt.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jidctflt.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jmemmgr.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jmemnobs.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\jpeg-6\jutils.c">
- <FileConfiguration
- Name="Debug TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- </Filter>
- <Filter
- Name="Header Files No. 1"
- Filter="">
- <File
- RelativePath="..\jpeg-6\jchuff.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jconfig.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jdct.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jdhuff.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jerror.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jinclude.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jmemsys.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jmorecfg.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jpegint.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jpeglib.h">
- </File>
- <File
- RelativePath="..\jpeg-6\jversion.h">
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="FreeType2"
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
- <File
- RelativePath="..\ft2\ahangles.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahglobal.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahglyph.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahhint.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahmodule.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahoptim.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftcalc.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftdebug.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftextend.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftglyph.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftgrays.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftinit.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftlist.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftmm.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftnames.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftobjs.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftoutln.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftraster.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftrend1.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftsmooth.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftstream.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftsystem.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\sfdriver.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\sfobjs.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttcmap.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttdriver.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttgload.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttinterp.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttload.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttobjs.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttpload.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttpost.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttsbit.c">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions=""
- BasicRuntimeChecks="3"
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <Filter
- Name="Include files"
- Filter="*.h">
- <File
- RelativePath="..\ft2\ahangles.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahglobal.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahglyph.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahhint.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahloader.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahmodule.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahoptim.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ahtypes.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\autohint.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\freetype.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftbbox.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftcalc.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftconfig.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftdebug.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftdriver.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\fterrors.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftextend.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftglyph.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftimage.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftlist.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftmemory.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftmm.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftmodule.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftnames.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftobjs.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftoption.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftoutln.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftrender.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftstream.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ftsystem.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\fttypes.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\psnames.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\sfnt.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\t1errors.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\t1tables.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\t1types.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\t2errors.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\t2types.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttdriver.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\tterrors.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttgload.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttinterp.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttnameid.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttobjs.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\ttpload.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\tttables.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\tttags.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\ft2\tttypes.h">
- <FileConfiguration
- Name="Debug TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release TA|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- <FileConfiguration
- Name="vector|Win32"
- ExcludedFromBuild="TRUE">
- <Tool
- Name="VCCustomBuildTool"/>
- </FileConfiguration>
- </File>
- </Filter>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="renderer" + SccProjectName=""$/MissionPack/code/renderer", EJBAAAAA" + SccLocalPath="."> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug TA|Win32" + OutputDirectory=".\Debug_TA" + IntermediateDirectory=".\Debug_TA" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + OptimizeForProcessor="1" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="2" + PrecompiledHeaderFile=".\Debug_TA/renderer.pch" + AssemblerListingLocation=".\Debug_TA/" + ObjectFile=".\Debug_TA/" + ProgramDataBaseFileName=".\Debug_TA/" + BrowseInformation="1" + WarningLevel="3" + SuppressStartupBanner="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Debug_TA\renderer.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="_DEBUG" + Culture="1033"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\Release" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="2" + OptimizeForProcessor="2" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="4" + EnableFunctionLevelLinking="TRUE" + UsePrecompiledHeader="2" + PrecompiledHeaderFile=".\Release/renderer.pch" + AssemblerListingLocation=".\Release/" + ObjectFile=".\Release/" + ProgramDataBaseFileName=".\Release/" + WarningLevel="4" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Release\renderer.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="1033"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory=".\Debug" + IntermediateDirectory=".\Debug" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + OptimizeForProcessor="1" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="2" + PrecompiledHeaderFile=".\Debug/renderer.pch" + AssemblerListingLocation=".\Debug/" + ObjectFile=".\Debug/" + ProgramDataBaseFileName=".\Debug/" + BrowseInformation="1" + WarningLevel="3" + SuppressStartupBanner="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Debug\renderer.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="_DEBUG" + Culture="1033"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release TA|Win32" + OutputDirectory=".\Release_TA" + IntermediateDirectory=".\Release_TA" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="2" + OptimizeForProcessor="2" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="4" + EnableFunctionLevelLinking="TRUE" + UsePrecompiledHeader="2" + PrecompiledHeaderFile=".\Release_TA/renderer.pch" + AssemblerListingLocation=".\Release_TA/" + ObjectFile=".\Release_TA/" + ProgramDataBaseFileName=".\Release_TA/" + WarningLevel="4" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\Release_TA\renderer.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="1033"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="vector|Win32" + OutputDirectory=".\renderer___Win32_vector0" + IntermediateDirectory=".\renderer___Win32_vector0" + ConfigurationType="4" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + AdditionalOptions="/vec /vec:stats /vec:pii /vec:o10 /vec:yes " + Optimization="2" + InlineFunctionExpansion="2" + OptimizeForProcessor="2" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + StringPooling="TRUE" + RuntimeLibrary="4" + EnableFunctionLevelLinking="TRUE" + UsePrecompiledHeader="2" + PrecompiledHeaderFile=".\renderer___Win32_vector0/renderer.pch" + AssemblerListingLocation=".\renderer___Win32_vector0/" + ObjectFile=".\renderer___Win32_vector0/" + ProgramDataBaseFileName=".\renderer___Win32_vector0/" + WarningLevel="4" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile=".\renderer___Win32_vector0\renderer.lib" + SuppressStartupBanner="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="1033"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="ref_trin.def"> + </File> + <File + RelativePath="tr_animation.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_backend.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_bsp.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_cmds.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_curve.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_flares.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_font.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_image.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_init.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_light.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_main.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_marks.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_mesh.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_model.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_noise.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_scene.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_shade.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_shade_calc.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_shader.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_shadows.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_sky.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_surface.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="tr_world.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\win32\win_gamma.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\win32\win_glimp.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\win32\win_qgl.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl"> + <File + RelativePath="..\qcommon\cm_public.h"> + </File> + <File + RelativePath="..\win32\glw_win.h"> + </File> + <File + RelativePath="..\game\q_shared.h"> + </File> + <File + RelativePath="..\qcommon\qcommon.h"> + </File> + <File + RelativePath="..\qcommon\qfiles.h"> + </File> + <File + RelativePath="qgl.h"> + </File> + <File + RelativePath="..\game\surfaceflags.h"> + </File> + <File + RelativePath="tr_local.h"> + </File> + <File + RelativePath="tr_public.h"> + </File> + <File + RelativePath="..\cgame\tr_types.h"> + </File> + <File + RelativePath="..\win32\win_local.h"> + </File> + </Filter> + <Filter + Name="jpeg" + Filter=""> + <Filter + Name="Source Files No. 1" + Filter=""> + <File + RelativePath="..\jpeg-6\jcapimin.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jccoefct.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jccolor.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcdctmgr.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jchuff.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcinit.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcmainct.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcmarker.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcmaster.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcomapi.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcparam.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcphuff.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcprepct.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jcsample.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jctrans.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdapimin.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdapistd.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdatadst.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdatasrc.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdcoefct.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdcolor.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jddctmgr.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdhuff.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdinput.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdmainct.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdmarker.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdmaster.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdpostct.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdsample.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jdtrans.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jerror.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jfdctflt.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jidctflt.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jmemmgr.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jmemnobs.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\jpeg-6\jutils.c"> + <FileConfiguration + Name="Debug TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files No. 1" + Filter=""> + <File + RelativePath="..\jpeg-6\jchuff.h"> + </File> + <File + RelativePath="..\jpeg-6\jconfig.h"> + </File> + <File + RelativePath="..\jpeg-6\jdct.h"> + </File> + <File + RelativePath="..\jpeg-6\jdhuff.h"> + </File> + <File + RelativePath="..\jpeg-6\jerror.h"> + </File> + <File + RelativePath="..\jpeg-6\jinclude.h"> + </File> + <File + RelativePath="..\jpeg-6\jmemsys.h"> + </File> + <File + RelativePath="..\jpeg-6\jmorecfg.h"> + </File> + <File + RelativePath="..\jpeg-6\jpegint.h"> + </File> + <File + RelativePath="..\jpeg-6\jpeglib.h"> + </File> + <File + RelativePath="..\jpeg-6\jversion.h"> + </File> + </Filter> + </Filter> + <Filter + Name="FreeType2" + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> + <File + RelativePath="..\ft2\ahangles.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahglobal.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahglyph.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahhint.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahmodule.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahoptim.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftcalc.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftdebug.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftextend.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftglyph.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftgrays.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftinit.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftlist.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftmm.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftnames.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftobjs.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftoutln.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftraster.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftrend1.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftsmooth.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftstream.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftsystem.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\sfdriver.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\sfobjs.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttcmap.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttdriver.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttgload.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttinterp.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttload.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttobjs.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttpload.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttpost.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttsbit.c"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <Filter + Name="Include files" + Filter="*.h"> + <File + RelativePath="..\ft2\ahangles.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahglobal.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahglyph.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahhint.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahloader.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahmodule.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahoptim.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ahtypes.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\autohint.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\freetype.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftbbox.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftcalc.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftconfig.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftdebug.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftdriver.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\fterrors.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftextend.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftglyph.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftimage.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftlist.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftmemory.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftmm.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftmodule.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftnames.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftobjs.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftoption.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftoutln.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftrender.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftstream.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ftsystem.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\fttypes.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\psnames.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\sfnt.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\t1errors.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\t1tables.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\t1types.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\t2errors.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\t2types.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttdriver.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\tterrors.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttgload.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttinterp.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttnameid.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttobjs.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\ttpload.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\tttables.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\tttags.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + <File + RelativePath="..\ft2\tttypes.h"> + <FileConfiguration + Name="Debug TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="Release TA|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + <FileConfiguration + Name="vector|Win32" + ExcludedFromBuild="TRUE"> + <Tool + Name="VCCustomBuildTool"/> + </FileConfiguration> + </File> + </Filter> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/code/renderer/tr_animation.c b/code/renderer/tr_animation.c index 6a6f800..fe06097 100755 --- a/code/renderer/tr_animation.c +++ b/code/renderer/tr_animation.c @@ -1,171 +1,171 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
-
-All bones should be an identity orientation to display the mesh exactly
-as it is specified.
-
-For all other frames, the bones represent the transformation from the
-orientation of the bone in the base frame to the orientation in this
-frame.
-
-*/
-
-/*
-==============
-R_AddAnimSurfaces
-==============
-*/
-void R_AddAnimSurfaces( trRefEntity_t *ent ) {
- md4Header_t *header;
- md4Surface_t *surface;
- md4LOD_t *lod;
- shader_t *shader;
- int i;
-
- header = tr.currentModel->md4;
- lod = (md4LOD_t *)( (byte *)header + header->ofsLODs );
-
- surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces );
- for ( i = 0 ; i < lod->numSurfaces ; i++ ) {
- shader = R_GetShaderByHandle( surface->shaderIndex );
- R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse );
- surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd );
- }
-}
-
-
-/*
-==============
-RB_SurfaceAnim
-==============
-*/
-void RB_SurfaceAnim( md4Surface_t *surface ) {
- int i, j, k;
- float frontlerp, backlerp;
- int *triangles;
- int indexes;
- int baseIndex, baseVertex;
- int numVerts;
- md4Vertex_t *v;
- md4Bone_t bones[MD4_MAX_BONES];
- md4Bone_t *bonePtr, *bone;
- md4Header_t *header;
- md4Frame_t *frame;
- md4Frame_t *oldFrame;
- int frameSize;
-
-
- if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
- backlerp = 0;
- frontlerp = 1;
- } else {
- backlerp = backEnd.currentEntity->e.backlerp;
- frontlerp = 1.0f - backlerp;
- }
- header = (md4Header_t *)((byte *)surface + surface->ofsHeader);
-
- frameSize = (int)( &((md4Frame_t *)0)->bones[ header->numBones ] );
-
- frame = (md4Frame_t *)((byte *)header + header->ofsFrames +
- backEnd.currentEntity->e.frame * frameSize );
- oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames +
- backEnd.currentEntity->e.oldframe * frameSize );
-
- RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 );
-
- triangles = (int *) ((byte *)surface + surface->ofsTriangles);
- indexes = surface->numTriangles * 3;
- baseIndex = tess.numIndexes;
- baseVertex = tess.numVertexes;
- for (j = 0 ; j < indexes ; j++) {
- tess.indexes[baseIndex + j] = baseIndex + triangles[j];
- }
- tess.numIndexes += indexes;
-
- //
- // lerp all the needed bones
- //
- if ( !backlerp ) {
- // no lerping needed
- bonePtr = frame->bones;
- } else {
- bonePtr = bones;
- for ( i = 0 ; i < header->numBones*12 ; i++ ) {
- ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i]
- + backlerp * ((float *)oldFrame->bones)[i];
- }
- }
-
- //
- // deform the vertexes by the lerped bones
- //
- numVerts = surface->numVerts;
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12);
- v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts);
- for ( j = 0; j < numVerts; j++ ) {
- vec3_t tempVert, tempNormal;
- md4Weight_t *w;
-
- VectorClear( tempVert );
- VectorClear( tempNormal );
- w = v->weights;
- for ( k = 0 ; k < v->numWeights ; k++, w++ ) {
- bone = bonePtr + w->boneIndex;
-
- tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
- tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
- tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
-
- tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
- tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
- tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
- }
-
- tess.xyz[baseVertex + j][0] = tempVert[0];
- tess.xyz[baseVertex + j][1] = tempVert[1];
- tess.xyz[baseVertex + j][2] = tempVert[2];
-
- tess.normal[baseVertex + j][0] = tempNormal[0];
- tess.normal[baseVertex + j][1] = tempNormal[1];
- tess.normal[baseVertex + j][2] = tempNormal[2];
-
- tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
- tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
-
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
- v = (md4Vertex_t *)&v->weights[v->numWeights];
- }
-
- tess.numVertexes += surface->numVerts;
-}
-
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "tr_local.h" + +/* + +All bones should be an identity orientation to display the mesh exactly +as it is specified. + +For all other frames, the bones represent the transformation from the +orientation of the bone in the base frame to the orientation in this +frame. + +*/ + +/* +============== +R_AddAnimSurfaces +============== +*/ +void R_AddAnimSurfaces( trRefEntity_t *ent ) { + md4Header_t *header; + md4Surface_t *surface; + md4LOD_t *lod; + shader_t *shader; + int i; + + header = tr.currentModel->md4; + lod = (md4LOD_t *)( (byte *)header + header->ofsLODs ); + + surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces ); + for ( i = 0 ; i < lod->numSurfaces ; i++ ) { + shader = R_GetShaderByHandle( surface->shaderIndex ); + R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse ); + surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd ); + } +} + + +/* +============== +RB_SurfaceAnim +============== +*/ +void RB_SurfaceAnim( md4Surface_t *surface ) { + int i, j, k; + float frontlerp, backlerp; + int *triangles; + int indexes; + int baseIndex, baseVertex; + int numVerts; + md4Vertex_t *v; + md4Bone_t bones[MD4_MAX_BONES]; + md4Bone_t *bonePtr, *bone; + md4Header_t *header; + md4Frame_t *frame; + md4Frame_t *oldFrame; + int frameSize; + + + if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { + backlerp = 0; + frontlerp = 1; + } else { + backlerp = backEnd.currentEntity->e.backlerp; + frontlerp = 1.0f - backlerp; + } + header = (md4Header_t *)((byte *)surface + surface->ofsHeader); + + frameSize = (int)( &((md4Frame_t *)0)->bones[ header->numBones ] ); + + frame = (md4Frame_t *)((byte *)header + header->ofsFrames + + backEnd.currentEntity->e.frame * frameSize ); + oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + + backEnd.currentEntity->e.oldframe * frameSize ); + + RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 ); + + triangles = (int *) ((byte *)surface + surface->ofsTriangles); + indexes = surface->numTriangles * 3; + baseIndex = tess.numIndexes; + baseVertex = tess.numVertexes; + for (j = 0 ; j < indexes ; j++) { + tess.indexes[baseIndex + j] = baseIndex + triangles[j]; + } + tess.numIndexes += indexes; + + // + // lerp all the needed bones + // + if ( !backlerp ) { + // no lerping needed + bonePtr = frame->bones; + } else { + bonePtr = bones; + for ( i = 0 ; i < header->numBones*12 ; i++ ) { + ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + + backlerp * ((float *)oldFrame->bones)[i]; + } + } + + // + // deform the vertexes by the lerped bones + // + numVerts = surface->numVerts; + // FIXME + // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left + // in for reference. + //v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12); + v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts); + for ( j = 0; j < numVerts; j++ ) { + vec3_t tempVert, tempNormal; + md4Weight_t *w; + + VectorClear( tempVert ); + VectorClear( tempNormal ); + w = v->weights; + for ( k = 0 ; k < v->numWeights ; k++, w++ ) { + bone = bonePtr + w->boneIndex; + + tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); + tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); + tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); + + tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); + tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); + tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); + } + + tess.xyz[baseVertex + j][0] = tempVert[0]; + tess.xyz[baseVertex + j][1] = tempVert[1]; + tess.xyz[baseVertex + j][2] = tempVert[2]; + + tess.normal[baseVertex + j][0] = tempNormal[0]; + tess.normal[baseVertex + j][1] = tempNormal[1]; + tess.normal[baseVertex + j][2] = tempNormal[2]; + + tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; + tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; + + // FIXME + // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left + // in for reference. + //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); + v = (md4Vertex_t *)&v->weights[v->numWeights]; + } + + tess.numVertexes += surface->numVerts; +} + + diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 4fff190..b467afb 100755 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -1,1143 +1,1143 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-backEndData_t *backEndData[SMP_FRAMES];
-backEndState_t backEnd;
-
-
-static float s_flipMatrix[16] = {
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- 0, 0, -1, 0,
- -1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 0, 1
-};
-
-
-/*
-** GL_Bind
-*/
-void GL_Bind( image_t *image ) {
- int texnum;
-
- if ( !image ) {
- ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
- texnum = tr.defaultImage->texnum;
- } else {
- texnum = image->texnum;
- }
-
- if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
- texnum = tr.dlightImage->texnum;
- }
-
- if ( glState.currenttextures[glState.currenttmu] != texnum ) {
- image->frameUsed = tr.frameCount;
- glState.currenttextures[glState.currenttmu] = texnum;
- qglBindTexture (GL_TEXTURE_2D, texnum);
- }
-}
-
-/*
-** GL_SelectTexture
-*/
-void GL_SelectTexture( int unit )
-{
- if ( glState.currenttmu == unit )
- {
- return;
- }
-
- if ( unit == 0 )
- {
- qglActiveTextureARB( GL_TEXTURE0_ARB );
- GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" );
- qglClientActiveTextureARB( GL_TEXTURE0_ARB );
- GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" );
- }
- else if ( unit == 1 )
- {
- qglActiveTextureARB( GL_TEXTURE1_ARB );
- GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" );
- qglClientActiveTextureARB( GL_TEXTURE1_ARB );
- GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" );
- } else {
- ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit );
- }
-
- glState.currenttmu = unit;
-}
-
-
-/*
-** GL_BindMultitexture
-*/
-void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) {
- int texnum0, texnum1;
-
- texnum0 = image0->texnum;
- texnum1 = image1->texnum;
-
- if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
- texnum0 = texnum1 = tr.dlightImage->texnum;
- }
-
- if ( glState.currenttextures[1] != texnum1 ) {
- GL_SelectTexture( 1 );
- image1->frameUsed = tr.frameCount;
- glState.currenttextures[1] = texnum1;
- qglBindTexture( GL_TEXTURE_2D, texnum1 );
- }
- if ( glState.currenttextures[0] != texnum0 ) {
- GL_SelectTexture( 0 );
- image0->frameUsed = tr.frameCount;
- glState.currenttextures[0] = texnum0;
- qglBindTexture( GL_TEXTURE_2D, texnum0 );
- }
-}
-
-
-/*
-** GL_Cull
-*/
-void GL_Cull( int cullType ) {
- if ( glState.faceCulling == cullType ) {
- return;
- }
-
- glState.faceCulling = cullType;
-
- if ( cullType == CT_TWO_SIDED )
- {
- qglDisable( GL_CULL_FACE );
- }
- else
- {
- qglEnable( GL_CULL_FACE );
-
- if ( cullType == CT_BACK_SIDED )
- {
- if ( backEnd.viewParms.isMirror )
- {
- qglCullFace( GL_FRONT );
- }
- else
- {
- qglCullFace( GL_BACK );
- }
- }
- else
- {
- if ( backEnd.viewParms.isMirror )
- {
- qglCullFace( GL_BACK );
- }
- else
- {
- qglCullFace( GL_FRONT );
- }
- }
- }
-}
-
-/*
-** GL_TexEnv
-*/
-void GL_TexEnv( int env )
-{
- if ( env == glState.texEnv[glState.currenttmu] )
- {
- return;
- }
-
- glState.texEnv[glState.currenttmu] = env;
-
-
- switch ( env )
- {
- case GL_MODULATE:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- break;
- case GL_REPLACE:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
- break;
- case GL_DECAL:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
- break;
- case GL_ADD:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
- break;
- default:
- ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env );
- break;
- }
-}
-
-/*
-** GL_State
-**
-** This routine is responsible for setting the most commonly changed state
-** in Q3.
-*/
-void GL_State( unsigned long stateBits )
-{
- unsigned long diff = stateBits ^ glState.glStateBits;
-
- if ( !diff )
- {
- return;
- }
-
- //
- // check depthFunc bits
- //
- if ( diff & GLS_DEPTHFUNC_EQUAL )
- {
- if ( stateBits & GLS_DEPTHFUNC_EQUAL )
- {
- qglDepthFunc( GL_EQUAL );
- }
- else
- {
- qglDepthFunc( GL_LEQUAL );
- }
- }
-
- //
- // check blend bits
- //
- if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
- {
- GLenum srcFactor, dstFactor;
-
- if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
- {
- switch ( stateBits & GLS_SRCBLEND_BITS )
- {
- case GLS_SRCBLEND_ZERO:
- srcFactor = GL_ZERO;
- break;
- case GLS_SRCBLEND_ONE:
- srcFactor = GL_ONE;
- break;
- case GLS_SRCBLEND_DST_COLOR:
- srcFactor = GL_DST_COLOR;
- break;
- case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
- srcFactor = GL_ONE_MINUS_DST_COLOR;
- break;
- case GLS_SRCBLEND_SRC_ALPHA:
- srcFactor = GL_SRC_ALPHA;
- break;
- case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
- srcFactor = GL_ONE_MINUS_SRC_ALPHA;
- break;
- case GLS_SRCBLEND_DST_ALPHA:
- srcFactor = GL_DST_ALPHA;
- break;
- case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
- srcFactor = GL_ONE_MINUS_DST_ALPHA;
- break;
- case GLS_SRCBLEND_ALPHA_SATURATE:
- srcFactor = GL_SRC_ALPHA_SATURATE;
- break;
- default:
- srcFactor = GL_ONE; // to get warning to shut up
- ri.Error( ERR_DROP, "GL_State: invalid src blend state bits\n" );
- break;
- }
-
- switch ( stateBits & GLS_DSTBLEND_BITS )
- {
- case GLS_DSTBLEND_ZERO:
- dstFactor = GL_ZERO;
- break;
- case GLS_DSTBLEND_ONE:
- dstFactor = GL_ONE;
- break;
- case GLS_DSTBLEND_SRC_COLOR:
- dstFactor = GL_SRC_COLOR;
- break;
- case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
- dstFactor = GL_ONE_MINUS_SRC_COLOR;
- break;
- case GLS_DSTBLEND_SRC_ALPHA:
- dstFactor = GL_SRC_ALPHA;
- break;
- case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
- dstFactor = GL_ONE_MINUS_SRC_ALPHA;
- break;
- case GLS_DSTBLEND_DST_ALPHA:
- dstFactor = GL_DST_ALPHA;
- break;
- case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
- dstFactor = GL_ONE_MINUS_DST_ALPHA;
- break;
- default:
- dstFactor = GL_ONE; // to get warning to shut up
- ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits\n" );
- break;
- }
-
- qglEnable( GL_BLEND );
- qglBlendFunc( srcFactor, dstFactor );
- }
- else
- {
- qglDisable( GL_BLEND );
- }
- }
-
- //
- // check depthmask
- //
- if ( diff & GLS_DEPTHMASK_TRUE )
- {
- if ( stateBits & GLS_DEPTHMASK_TRUE )
- {
- qglDepthMask( GL_TRUE );
- }
- else
- {
- qglDepthMask( GL_FALSE );
- }
- }
-
- //
- // fill/line mode
- //
- if ( diff & GLS_POLYMODE_LINE )
- {
- if ( stateBits & GLS_POLYMODE_LINE )
- {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
- }
- else
- {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- }
- }
-
- //
- // depthtest
- //
- if ( diff & GLS_DEPTHTEST_DISABLE )
- {
- if ( stateBits & GLS_DEPTHTEST_DISABLE )
- {
- qglDisable( GL_DEPTH_TEST );
- }
- else
- {
- qglEnable( GL_DEPTH_TEST );
- }
- }
-
- //
- // alpha test
- //
- if ( diff & GLS_ATEST_BITS )
- {
- switch ( stateBits & GLS_ATEST_BITS )
- {
- case 0:
- qglDisable( GL_ALPHA_TEST );
- break;
- case GLS_ATEST_GT_0:
- qglEnable( GL_ALPHA_TEST );
- qglAlphaFunc( GL_GREATER, 0.0f );
- break;
- case GLS_ATEST_LT_80:
- qglEnable( GL_ALPHA_TEST );
- qglAlphaFunc( GL_LESS, 0.5f );
- break;
- case GLS_ATEST_GE_80:
- qglEnable( GL_ALPHA_TEST );
- qglAlphaFunc( GL_GEQUAL, 0.5f );
- break;
- default:
- assert( 0 );
- break;
- }
- }
-
- glState.glStateBits = stateBits;
-}
-
-
-
-/*
-================
-RB_Hyperspace
-
-A player has predicted a teleport, but hasn't arrived yet
-================
-*/
-static void RB_Hyperspace( void ) {
- float c;
-
- if ( !backEnd.isHyperspace ) {
- // do initialization shit
- }
-
- c = ( backEnd.refdef.time & 255 ) / 255.0f;
- qglClearColor( c, c, c, 1 );
- qglClear( GL_COLOR_BUFFER_BIT );
-
- backEnd.isHyperspace = qtrue;
-}
-
-
-static void SetViewportAndScissor( void ) {
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf( backEnd.viewParms.projectionMatrix );
- qglMatrixMode(GL_MODELVIEW);
-
- // set the window clipping
- qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
- backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
- qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
- backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
-}
-
-/*
-=================
-RB_BeginDrawingView
-
-Any mirrored or portaled views have already been drawn, so prepare
-to actually render the visible surfaces for this view
-=================
-*/
-void RB_BeginDrawingView (void) {
- int clearBits = 0;
-
- // sync with gl if needed
- if ( r_finish->integer == 1 && !glState.finishCalled ) {
- qglFinish ();
- glState.finishCalled = qtrue;
- }
- if ( r_finish->integer == 0 ) {
- glState.finishCalled = qtrue;
- }
-
- // we will need to change the projection matrix before drawing
- // 2D images again
- backEnd.projection2D = qfalse;
-
- //
- // set the modelview matrix for the viewer
- //
- SetViewportAndScissor();
-
- // ensures that depth writes are enabled for the depth clear
- GL_State( GLS_DEFAULT );
- // clear relevant buffers
- clearBits = GL_DEPTH_BUFFER_BIT;
-
- if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
- {
- clearBits |= GL_STENCIL_BUFFER_BIT;
- }
- if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
- {
- clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
-#ifdef _DEBUG
- qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky
-#else
- qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
-#endif
- }
- qglClear( clearBits );
-
- if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
- {
- RB_Hyperspace();
- return;
- }
- else
- {
- backEnd.isHyperspace = qfalse;
- }
-
- glState.faceCulling = -1; // force face culling to set next time
-
- // we will only draw a sun if there was sky rendered in this view
- backEnd.skyRenderedThisView = qfalse;
-
- // clip to the plane of the portal
- if ( backEnd.viewParms.isPortal ) {
- float plane[4];
- double plane2[4];
-
- plane[0] = backEnd.viewParms.portalPlane.normal[0];
- plane[1] = backEnd.viewParms.portalPlane.normal[1];
- plane[2] = backEnd.viewParms.portalPlane.normal[2];
- plane[3] = backEnd.viewParms.portalPlane.dist;
-
- plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);
- plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);
- plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
- plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
-
- qglLoadMatrixf( s_flipMatrix );
- qglClipPlane (GL_CLIP_PLANE0, plane2);
- qglEnable (GL_CLIP_PLANE0);
- } else {
- qglDisable (GL_CLIP_PLANE0);
- }
-}
-
-
-#define MAC_EVENT_PUMP_MSEC 5
-
-/*
-==================
-RB_RenderDrawSurfList
-==================
-*/
-void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
- shader_t *shader, *oldShader;
- int fogNum, oldFogNum;
- int entityNum, oldEntityNum;
- int dlighted, oldDlighted;
- qboolean depthRange, oldDepthRange;
- int i;
- drawSurf_t *drawSurf;
- int oldSort;
- float originalTime;
-#ifdef __MACOS__
- int macEventTime;
-
- Sys_PumpEvents(); // crutch up the mac's limited buffer queue size
-
- // we don't want to pump the event loop too often and waste time, so
- // we are going to check every shader change
- macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC;
-#endif
-
- // save original time for entity shader offsets
- originalTime = backEnd.refdef.floatTime;
-
- // clear the z buffer, set the modelview, etc
- RB_BeginDrawingView ();
-
- // draw everything
- oldEntityNum = -1;
- backEnd.currentEntity = &tr.worldEntity;
- oldShader = NULL;
- oldFogNum = -1;
- oldDepthRange = qfalse;
- oldDlighted = qfalse;
- oldSort = -1;
- depthRange = qfalse;
-
- backEnd.pc.c_surfaces += numDrawSurfs;
-
- for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {
- if ( drawSurf->sort == oldSort ) {
- // fast path, same as previous sort
- rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
- continue;
- }
- oldSort = drawSurf->sort;
- R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
-
- //
- // change the tess parameters if needed
- // a "entityMergable" shader is a shader that can have surfaces from seperate
- // entities merged into a single batch, like smoke and blood puff sprites
- if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted
- || ( entityNum != oldEntityNum && !shader->entityMergable ) ) {
- if (oldShader != NULL) {
-#ifdef __MACOS__ // crutch up the mac's limited buffer queue size
- int t;
-
- t = ri.Milliseconds();
- if ( t > macEventTime ) {
- macEventTime = t + MAC_EVENT_PUMP_MSEC;
- Sys_PumpEvents();
- }
-#endif
- RB_EndSurface();
- }
- RB_BeginSurface( shader, fogNum );
- oldShader = shader;
- oldFogNum = fogNum;
- oldDlighted = dlighted;
- }
-
- //
- // change the modelview matrix if needed
- //
- if ( entityNum != oldEntityNum ) {
- depthRange = qfalse;
-
- if ( entityNum != ENTITYNUM_WORLD ) {
- backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
- backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
- // we have to reset the shaderTime as well otherwise image animations start
- // from the wrong frame
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
-
- // set up the transformation matrix
- R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or );
-
- // set up the dynamic lighting if needed
- if ( backEnd.currentEntity->needDlights ) {
- R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
- }
-
- if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) {
- // hack the depth range to prevent view model from poking into walls
- depthRange = qtrue;
- }
- } else {
- backEnd.currentEntity = &tr.worldEntity;
- backEnd.refdef.floatTime = originalTime;
- backEnd.or = backEnd.viewParms.world;
- // we have to reset the shaderTime as well otherwise image animations on
- // the world (like water) continue with the wrong frame
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
- R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
- }
-
- qglLoadMatrixf( backEnd.or.modelMatrix );
-
- //
- // change depthrange if needed
- //
- if ( oldDepthRange != depthRange ) {
- if ( depthRange ) {
- qglDepthRange (0, 0.3);
- } else {
- qglDepthRange (0, 1);
- }
- oldDepthRange = depthRange;
- }
-
- oldEntityNum = entityNum;
- }
-
- // add the triangles for this surface
- rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
- }
-
- backEnd.refdef.floatTime = originalTime;
-
- // draw the contents of the last shader batch
- if (oldShader != NULL) {
- RB_EndSurface();
- }
-
- // go back to the world modelview matrix
- qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
- if ( depthRange ) {
- qglDepthRange (0, 1);
- }
-
-#if 0
- RB_DrawSun();
-#endif
- // darken down any stencil shadows
- RB_ShadowFinish();
-
- // add light flares on lights that aren't obscured
- RB_RenderFlares();
-
-#ifdef __MACOS__
- Sys_PumpEvents(); // crutch up the mac's limited buffer queue size
-#endif
-}
-
-
-/*
-============================================================================
-
-RENDER BACK END THREAD FUNCTIONS
-
-============================================================================
-*/
-
-/*
-================
-RB_SetGL2D
-
-================
-*/
-void RB_SetGL2D (void) {
- backEnd.projection2D = qtrue;
-
- // set 2D virtual screen size
- qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
- qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
- qglMatrixMode(GL_PROJECTION);
- qglLoadIdentity ();
- qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
- qglMatrixMode(GL_MODELVIEW);
- qglLoadIdentity ();
-
- GL_State( GLS_DEPTHTEST_DISABLE |
- GLS_SRCBLEND_SRC_ALPHA |
- GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
-
- qglDisable( GL_CULL_FACE );
- qglDisable( GL_CLIP_PLANE0 );
-
- // set time for 2D shaders
- backEnd.refdef.time = ri.Milliseconds();
- backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
-}
-
-
-/*
-=============
-RE_StretchRaw
-
-FIXME: not exactly backend
-Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
-Used for cinematics.
-=============
-*/
-void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
- int i, j;
- int start, end;
-
- if ( !tr.registered ) {
- return;
- }
- R_SyncRenderThread();
-
- // we definately want to sync every frame for the cinematics
- qglFinish();
-
- start = end = 0;
- if ( r_speeds->integer ) {
- start = ri.Milliseconds();
- }
-
- // make sure rows and cols are powers of 2
- for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
- }
- for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
- }
- if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
- ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
- }
-
- GL_Bind( tr.scratchImage[client] );
-
- // if the scratchImage isn't in the format we want, specify it as a new texture
- if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
- tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
- tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
- qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
- } else {
- if (dirty) {
- // otherwise, just subimage upload it so that drivers can tell we are going to be changing
- // it and don't try and do a texture compression
- qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
- }
- }
-
- if ( r_speeds->integer ) {
- end = ri.Milliseconds();
- ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
- }
-
- RB_SetGL2D();
-
- qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
-
- qglBegin (GL_QUADS);
- qglTexCoord2f ( 0.5f / cols, 0.5f / rows );
- qglVertex2f (x, y);
- qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows );
- qglVertex2f (x+w, y);
- qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
- qglVertex2f (x+w, y+h);
- qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
- qglVertex2f (x, y+h);
- qglEnd ();
-}
-
-void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
-
- GL_Bind( tr.scratchImage[client] );
-
- // if the scratchImage isn't in the format we want, specify it as a new texture
- if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
- tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
- tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
- qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
- } else {
- if (dirty) {
- // otherwise, just subimage upload it so that drivers can tell we are going to be changing
- // it and don't try and do a texture compression
- qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
- }
- }
-}
-
-
-/*
-=============
-RB_SetColor
-
-=============
-*/
-const void *RB_SetColor( const void *data ) {
- const setColorCommand_t *cmd;
-
- cmd = (const setColorCommand_t *)data;
-
- backEnd.color2D[0] = cmd->color[0] * 255;
- backEnd.color2D[1] = cmd->color[1] * 255;
- backEnd.color2D[2] = cmd->color[2] * 255;
- backEnd.color2D[3] = cmd->color[3] * 255;
-
- return (const void *)(cmd + 1);
-}
-
-/*
-=============
-RB_StretchPic
-=============
-*/
-const void *RB_StretchPic ( const void *data ) {
- const stretchPicCommand_t *cmd;
- shader_t *shader;
- int numVerts, numIndexes;
-
- cmd = (const stretchPicCommand_t *)data;
-
- if ( !backEnd.projection2D ) {
- RB_SetGL2D();
- }
-
- shader = cmd->shader;
- if ( shader != tess.shader ) {
- if ( tess.numIndexes ) {
- RB_EndSurface();
- }
- backEnd.currentEntity = &backEnd.entity2D;
- RB_BeginSurface( shader, 0 );
- }
-
- RB_CHECKOVERFLOW( 4, 6 );
- numVerts = tess.numVertexes;
- numIndexes = tess.numIndexes;
-
- tess.numVertexes += 4;
- tess.numIndexes += 6;
-
- tess.indexes[ numIndexes ] = numVerts + 3;
- tess.indexes[ numIndexes + 1 ] = numVerts + 0;
- tess.indexes[ numIndexes + 2 ] = numVerts + 2;
- tess.indexes[ numIndexes + 3 ] = numVerts + 2;
- tess.indexes[ numIndexes + 4 ] = numVerts + 0;
- tess.indexes[ numIndexes + 5 ] = numVerts + 1;
-
- *(int *)tess.vertexColors[ numVerts ] =
- *(int *)tess.vertexColors[ numVerts + 1 ] =
- *(int *)tess.vertexColors[ numVerts + 2 ] =
- *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D;
-
- tess.xyz[ numVerts ][0] = cmd->x;
- tess.xyz[ numVerts ][1] = cmd->y;
- tess.xyz[ numVerts ][2] = 0;
-
- tess.texCoords[ numVerts ][0][0] = cmd->s1;
- tess.texCoords[ numVerts ][0][1] = cmd->t1;
-
- tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;
- tess.xyz[ numVerts + 1 ][1] = cmd->y;
- tess.xyz[ numVerts + 1 ][2] = 0;
-
- tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2;
- tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1;
-
- tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;
- tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;
- tess.xyz[ numVerts + 2 ][2] = 0;
-
- tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2;
- tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2;
-
- tess.xyz[ numVerts + 3 ][0] = cmd->x;
- tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;
- tess.xyz[ numVerts + 3 ][2] = 0;
-
- tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1;
- tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2;
-
- return (const void *)(cmd + 1);
-}
-
-
-/*
-=============
-RB_DrawSurfs
-
-=============
-*/
-const void *RB_DrawSurfs( const void *data ) {
- const drawSurfsCommand_t *cmd;
-
- // finish any 2D drawing if needed
- if ( tess.numIndexes ) {
- RB_EndSurface();
- }
-
- cmd = (const drawSurfsCommand_t *)data;
-
- backEnd.refdef = cmd->refdef;
- backEnd.viewParms = cmd->viewParms;
-
- RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
-
- return (const void *)(cmd + 1);
-}
-
-
-/*
-=============
-RB_DrawBuffer
-
-=============
-*/
-const void *RB_DrawBuffer( const void *data ) {
- const drawBufferCommand_t *cmd;
-
- cmd = (const drawBufferCommand_t *)data;
-
- qglDrawBuffer( cmd->buffer );
-
- // clear screen for debugging
- if ( r_clear->integer ) {
- qglClearColor( 1, 0, 0.5, 1 );
- qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
- }
-
- return (const void *)(cmd + 1);
-}
-
-/*
-===============
-RB_ShowImages
-
-Draw all the images to the screen, on top of whatever
-was there. This is used to test for texture thrashing.
-
-Also called by RE_EndRegistration
-===============
-*/
-void RB_ShowImages( void ) {
- int i;
- image_t *image;
- float x, y, w, h;
- int start, end;
-
- if ( !backEnd.projection2D ) {
- RB_SetGL2D();
- }
-
- qglClear( GL_COLOR_BUFFER_BIT );
-
- qglFinish();
-
- start = ri.Milliseconds();
-
- for ( i=0 ; i<tr.numImages ; i++ ) {
- image = tr.images[i];
-
- w = glConfig.vidWidth / 20;
- h = glConfig.vidHeight / 15;
- x = i % 20 * w;
- y = i / 20 * h;
-
- // show in proportional size in mode 2
- if ( r_showImages->integer == 2 ) {
- w *= image->uploadWidth / 512.0f;
- h *= image->uploadHeight / 512.0f;
- }
-
- GL_Bind( image );
- qglBegin (GL_QUADS);
- qglTexCoord2f( 0, 0 );
- qglVertex2f( x, y );
- qglTexCoord2f( 1, 0 );
- qglVertex2f( x + w, y );
- qglTexCoord2f( 1, 1 );
- qglVertex2f( x + w, y + h );
- qglTexCoord2f( 0, 1 );
- qglVertex2f( x, y + h );
- qglEnd();
- }
-
- qglFinish();
-
- end = ri.Milliseconds();
- ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );
-
-}
-
-
-/*
-=============
-RB_SwapBuffers
-
-=============
-*/
-const void *RB_SwapBuffers( const void *data ) {
- const swapBuffersCommand_t *cmd;
-
- // finish any 2D drawing if needed
- if ( tess.numIndexes ) {
- RB_EndSurface();
- }
-
- // texture swapping test
- if ( r_showImages->integer ) {
- RB_ShowImages();
- }
-
- cmd = (const swapBuffersCommand_t *)data;
-
- // we measure overdraw by reading back the stencil buffer and
- // counting up the number of increments that have happened
- if ( r_measureOverdraw->integer ) {
- int i;
- long sum = 0;
- unsigned char *stencilReadback;
-
- stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight );
- qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
-
- for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) {
- sum += stencilReadback[i];
- }
-
- backEnd.pc.c_overDraw += sum;
- ri.Hunk_FreeTempMemory( stencilReadback );
- }
-
-
- if ( !glState.finishCalled ) {
- qglFinish();
- }
-
- GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
-
- GLimp_EndFrame();
-
- backEnd.projection2D = qfalse;
-
- return (const void *)(cmd + 1);
-}
-
-/*
-====================
-RB_ExecuteRenderCommands
-
-This function will be called synchronously if running without
-smp extensions, or asynchronously by another thread.
-====================
-*/
-void RB_ExecuteRenderCommands( const void *data ) {
- int t1, t2;
-
- t1 = ri.Milliseconds ();
-
- if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) {
- backEnd.smpFrame = 0;
- } else {
- backEnd.smpFrame = 1;
- }
-
- while ( 1 ) {
- switch ( *(const int *)data ) {
- case RC_SET_COLOR:
- data = RB_SetColor( data );
- break;
- case RC_STRETCH_PIC:
- data = RB_StretchPic( data );
- break;
- case RC_DRAW_SURFS:
- data = RB_DrawSurfs( data );
- break;
- case RC_DRAW_BUFFER:
- data = RB_DrawBuffer( data );
- break;
- case RC_SWAP_BUFFERS:
- data = RB_SwapBuffers( data );
- break;
- case RC_SCREENSHOT:
- data = RB_TakeScreenshotCmd( data );
- break;
-
- case RC_END_OF_LIST:
- default:
- // stop rendering on this thread
- t2 = ri.Milliseconds ();
- backEnd.pc.msec = t2 - t1;
- return;
- }
- }
-
-}
-
-
-/*
-================
-RB_RenderThread
-================
-*/
-void RB_RenderThread( void ) {
- const void *data;
-
- // wait for either a rendering command or a quit command
- while ( 1 ) {
- // sleep until we have work to do
- data = GLimp_RendererSleep();
-
- if ( !data ) {
- return; // all done, renderer is shutting down
- }
-
- renderThreadActive = qtrue;
-
- RB_ExecuteRenderCommands( data );
-
- renderThreadActive = qfalse;
- }
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "tr_local.h" + +backEndData_t *backEndData[SMP_FRAMES]; +backEndState_t backEnd; + + +static float s_flipMatrix[16] = { + // convert from our coordinate system (looking down X) + // to OpenGL's coordinate system (looking down -Z) + 0, 0, -1, 0, + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1 +}; + + +/* +** GL_Bind +*/ +void GL_Bind( image_t *image ) { + int texnum; + + if ( !image ) { + ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" ); + texnum = tr.defaultImage->texnum; + } else { + texnum = image->texnum; + } + + if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option + texnum = tr.dlightImage->texnum; + } + + if ( glState.currenttextures[glState.currenttmu] != texnum ) { + image->frameUsed = tr.frameCount; + glState.currenttextures[glState.currenttmu] = texnum; + qglBindTexture (GL_TEXTURE_2D, texnum); + } +} + +/* +** GL_SelectTexture +*/ +void GL_SelectTexture( int unit ) +{ + if ( glState.currenttmu == unit ) + { + return; + } + + if ( unit == 0 ) + { + qglActiveTextureARB( GL_TEXTURE0_ARB ); + GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" ); + qglClientActiveTextureARB( GL_TEXTURE0_ARB ); + GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" ); + } + else if ( unit == 1 ) + { + qglActiveTextureARB( GL_TEXTURE1_ARB ); + GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" ); + qglClientActiveTextureARB( GL_TEXTURE1_ARB ); + GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" ); + } else { + ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit ); + } + + glState.currenttmu = unit; +} + + +/* +** GL_BindMultitexture +*/ +void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) { + int texnum0, texnum1; + + texnum0 = image0->texnum; + texnum1 = image1->texnum; + + if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option + texnum0 = texnum1 = tr.dlightImage->texnum; + } + + if ( glState.currenttextures[1] != texnum1 ) { + GL_SelectTexture( 1 ); + image1->frameUsed = tr.frameCount; + glState.currenttextures[1] = texnum1; + qglBindTexture( GL_TEXTURE_2D, texnum1 ); + } + if ( glState.currenttextures[0] != texnum0 ) { + GL_SelectTexture( 0 ); + image0->frameUsed = tr.frameCount; + glState.currenttextures[0] = texnum0; + qglBindTexture( GL_TEXTURE_2D, texnum0 ); + } +} + + +/* +** GL_Cull +*/ +void GL_Cull( int cullType ) { + if ( glState.faceCulling == cullType ) { + return; + } + + glState.faceCulling = cullType; + + if ( cullType == CT_TWO_SIDED ) + { + qglDisable( GL_CULL_FACE ); + } + else + { + qglEnable( GL_CULL_FACE ); + + if ( cullType == CT_BACK_SIDED ) + { + if ( backEnd.viewParms.isMirror ) + { + qglCullFace( GL_FRONT ); + } + else + { + qglCullFace( GL_BACK ); + } + } + else + { + if ( backEnd.viewParms.isMirror ) + { + qglCullFace( GL_BACK ); + } + else + { + qglCullFace( GL_FRONT ); + } + } + } +} + +/* +** GL_TexEnv +*/ +void GL_TexEnv( int env ) +{ + if ( env == glState.texEnv[glState.currenttmu] ) + { + return; + } + + glState.texEnv[glState.currenttmu] = env; + + + switch ( env ) + { + case GL_MODULATE: + qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + break; + case GL_REPLACE: + qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); + break; + case GL_DECAL: + qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); + break; + case GL_ADD: + qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); + break; + default: + ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env ); + break; + } +} + +/* +** GL_State +** +** This routine is responsible for setting the most commonly changed state +** in Q3. +*/ +void GL_State( unsigned long stateBits ) +{ + unsigned long diff = stateBits ^ glState.glStateBits; + + if ( !diff ) + { + return; + } + + // + // check depthFunc bits + // + if ( diff & GLS_DEPTHFUNC_EQUAL ) + { + if ( stateBits & GLS_DEPTHFUNC_EQUAL ) + { + qglDepthFunc( GL_EQUAL ); + } + else + { + qglDepthFunc( GL_LEQUAL ); + } + } + + // + // check blend bits + // + if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) + { + GLenum srcFactor, dstFactor; + + if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) + { + switch ( stateBits & GLS_SRCBLEND_BITS ) + { + case GLS_SRCBLEND_ZERO: + srcFactor = GL_ZERO; + break; + case GLS_SRCBLEND_ONE: + srcFactor = GL_ONE; + break; + case GLS_SRCBLEND_DST_COLOR: + srcFactor = GL_DST_COLOR; + break; + case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: + srcFactor = GL_ONE_MINUS_DST_COLOR; + break; + case GLS_SRCBLEND_SRC_ALPHA: + srcFactor = GL_SRC_ALPHA; + break; + case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: + srcFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + case GLS_SRCBLEND_DST_ALPHA: + srcFactor = GL_DST_ALPHA; + break; + case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: + srcFactor = GL_ONE_MINUS_DST_ALPHA; + break; + case GLS_SRCBLEND_ALPHA_SATURATE: + srcFactor = GL_SRC_ALPHA_SATURATE; + break; + default: + srcFactor = GL_ONE; // to get warning to shut up + ri.Error( ERR_DROP, "GL_State: invalid src blend state bits\n" ); + break; + } + + switch ( stateBits & GLS_DSTBLEND_BITS ) + { + case GLS_DSTBLEND_ZERO: + dstFactor = GL_ZERO; + break; + case GLS_DSTBLEND_ONE: + dstFactor = GL_ONE; + break; + case GLS_DSTBLEND_SRC_COLOR: + dstFactor = GL_SRC_COLOR; + break; + case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: + dstFactor = GL_ONE_MINUS_SRC_COLOR; + break; + case GLS_DSTBLEND_SRC_ALPHA: + dstFactor = GL_SRC_ALPHA; + break; + case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: + dstFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + case GLS_DSTBLEND_DST_ALPHA: + dstFactor = GL_DST_ALPHA; + break; + case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: + dstFactor = GL_ONE_MINUS_DST_ALPHA; + break; + default: + dstFactor = GL_ONE; // to get warning to shut up + ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits\n" ); + break; + } + + qglEnable( GL_BLEND ); + qglBlendFunc( srcFactor, dstFactor ); + } + else + { + qglDisable( GL_BLEND ); + } + } + + // + // check depthmask + // + if ( diff & GLS_DEPTHMASK_TRUE ) + { + if ( stateBits & GLS_DEPTHMASK_TRUE ) + { + qglDepthMask( GL_TRUE ); + } + else + { + qglDepthMask( GL_FALSE ); + } + } + + // + // fill/line mode + // + if ( diff & GLS_POLYMODE_LINE ) + { + if ( stateBits & GLS_POLYMODE_LINE ) + { + qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else + { + qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + } + + // + // depthtest + // + if ( diff & GLS_DEPTHTEST_DISABLE ) + { + if ( stateBits & GLS_DEPTHTEST_DISABLE ) + { + qglDisable( GL_DEPTH_TEST ); + } + else + { + qglEnable( GL_DEPTH_TEST ); + } + } + + // + // alpha test + // + if ( diff & GLS_ATEST_BITS ) + { + switch ( stateBits & GLS_ATEST_BITS ) + { + case 0: + qglDisable( GL_ALPHA_TEST ); + break; + case GLS_ATEST_GT_0: + qglEnable( GL_ALPHA_TEST ); + qglAlphaFunc( GL_GREATER, 0.0f ); + break; + case GLS_ATEST_LT_80: + qglEnable( GL_ALPHA_TEST ); + qglAlphaFunc( GL_LESS, 0.5f ); + break; + case GLS_ATEST_GE_80: + qglEnable( GL_ALPHA_TEST ); + qglAlphaFunc( GL_GEQUAL, 0.5f ); + break; + default: + assert( 0 ); + break; + } + } + + glState.glStateBits = stateBits; +} + + + +/* +================ +RB_Hyperspace + +A player has predicted a teleport, but hasn't arrived yet +================ +*/ +static void RB_Hyperspace( void ) { + float c; + + if ( !backEnd.isHyperspace ) { + // do initialization shit + } + + c = ( backEnd.refdef.time & 255 ) / 255.0f; + qglClearColor( c, c, c, 1 ); + qglClear( GL_COLOR_BUFFER_BIT ); + + backEnd.isHyperspace = qtrue; +} + + +static void SetViewportAndScissor( void ) { + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); + qglMatrixMode(GL_MODELVIEW); + + // set the window clipping + qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); + qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); +} + +/* +================= +RB_BeginDrawingView + +Any mirrored or portaled views have already been drawn, so prepare +to actually render the visible surfaces for this view +================= +*/ +void RB_BeginDrawingView (void) { + int clearBits = 0; + + // sync with gl if needed + if ( r_finish->integer == 1 && !glState.finishCalled ) { + qglFinish (); + glState.finishCalled = qtrue; + } + if ( r_finish->integer == 0 ) { + glState.finishCalled = qtrue; + } + + // we will need to change the projection matrix before drawing + // 2D images again + backEnd.projection2D = qfalse; + + // + // set the modelview matrix for the viewer + // + SetViewportAndScissor(); + + // ensures that depth writes are enabled for the depth clear + GL_State( GLS_DEFAULT ); + // clear relevant buffers + clearBits = GL_DEPTH_BUFFER_BIT; + + if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) + { + clearBits |= GL_STENCIL_BUFFER_BIT; + } + if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) + { + clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used +#ifdef _DEBUG + qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky +#else + qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky +#endif + } + qglClear( clearBits ); + + if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) + { + RB_Hyperspace(); + return; + } + else + { + backEnd.isHyperspace = qfalse; + } + + glState.faceCulling = -1; // force face culling to set next time + + // we will only draw a sun if there was sky rendered in this view + backEnd.skyRenderedThisView = qfalse; + + // clip to the plane of the portal + if ( backEnd.viewParms.isPortal ) { + float plane[4]; + double plane2[4]; + + plane[0] = backEnd.viewParms.portalPlane.normal[0]; + plane[1] = backEnd.viewParms.portalPlane.normal[1]; + plane[2] = backEnd.viewParms.portalPlane.normal[2]; + plane[3] = backEnd.viewParms.portalPlane.dist; + + plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); + plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); + plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); + plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; + + qglLoadMatrixf( s_flipMatrix ); + qglClipPlane (GL_CLIP_PLANE0, plane2); + qglEnable (GL_CLIP_PLANE0); + } else { + qglDisable (GL_CLIP_PLANE0); + } +} + + +#define MAC_EVENT_PUMP_MSEC 5 + +/* +================== +RB_RenderDrawSurfList +================== +*/ +void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { + shader_t *shader, *oldShader; + int fogNum, oldFogNum; + int entityNum, oldEntityNum; + int dlighted, oldDlighted; + qboolean depthRange, oldDepthRange; + int i; + drawSurf_t *drawSurf; + int oldSort; + float originalTime; +#ifdef __MACOS__ + int macEventTime; + + Sys_PumpEvents(); // crutch up the mac's limited buffer queue size + + // we don't want to pump the event loop too often and waste time, so + // we are going to check every shader change + macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; +#endif + + // save original time for entity shader offsets + originalTime = backEnd.refdef.floatTime; + + // clear the z buffer, set the modelview, etc + RB_BeginDrawingView (); + + // draw everything + oldEntityNum = -1; + backEnd.currentEntity = &tr.worldEntity; + oldShader = NULL; + oldFogNum = -1; + oldDepthRange = qfalse; + oldDlighted = qfalse; + oldSort = -1; + depthRange = qfalse; + + backEnd.pc.c_surfaces += numDrawSurfs; + + for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { + if ( drawSurf->sort == oldSort ) { + // fast path, same as previous sort + rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); + continue; + } + oldSort = drawSurf->sort; + R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); + + // + // change the tess parameters if needed + // a "entityMergable" shader is a shader that can have surfaces from seperate + // entities merged into a single batch, like smoke and blood puff sprites + if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted + || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { + if (oldShader != NULL) { +#ifdef __MACOS__ // crutch up the mac's limited buffer queue size + int t; + + t = ri.Milliseconds(); + if ( t > macEventTime ) { + macEventTime = t + MAC_EVENT_PUMP_MSEC; + Sys_PumpEvents(); + } +#endif + RB_EndSurface(); + } + RB_BeginSurface( shader, fogNum ); + oldShader = shader; + oldFogNum = fogNum; + oldDlighted = dlighted; + } + + // + // change the modelview matrix if needed + // + if ( entityNum != oldEntityNum ) { + depthRange = qfalse; + + if ( entityNum != ENTITYNUM_WORLD ) { + backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; + backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; + // we have to reset the shaderTime as well otherwise image animations start + // from the wrong frame + tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; + + // set up the transformation matrix + R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); + + // set up the dynamic lighting if needed + if ( backEnd.currentEntity->needDlights ) { + R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); + } + + if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { + // hack the depth range to prevent view model from poking into walls + depthRange = qtrue; + } + } else { + backEnd.currentEntity = &tr.worldEntity; + backEnd.refdef.floatTime = originalTime; + backEnd.or = backEnd.viewParms.world; + // we have to reset the shaderTime as well otherwise image animations on + // the world (like water) continue with the wrong frame + tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; + R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); + } + + qglLoadMatrixf( backEnd.or.modelMatrix ); + + // + // change depthrange if needed + // + if ( oldDepthRange != depthRange ) { + if ( depthRange ) { + qglDepthRange (0, 0.3); + } else { + qglDepthRange (0, 1); + } + oldDepthRange = depthRange; + } + + oldEntityNum = entityNum; + } + + // add the triangles for this surface + rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); + } + + backEnd.refdef.floatTime = originalTime; + + // draw the contents of the last shader batch + if (oldShader != NULL) { + RB_EndSurface(); + } + + // go back to the world modelview matrix + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); + if ( depthRange ) { + qglDepthRange (0, 1); + } + +#if 0 + RB_DrawSun(); +#endif + // darken down any stencil shadows + RB_ShadowFinish(); + + // add light flares on lights that aren't obscured + RB_RenderFlares(); + +#ifdef __MACOS__ + Sys_PumpEvents(); // crutch up the mac's limited buffer queue size +#endif +} + + +/* +============================================================================ + +RENDER BACK END THREAD FUNCTIONS + +============================================================================ +*/ + +/* +================ +RB_SetGL2D + +================ +*/ +void RB_SetGL2D (void) { + backEnd.projection2D = qtrue; + + // set 2D virtual screen size + qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); + qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1); + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + + GL_State( GLS_DEPTHTEST_DISABLE | + GLS_SRCBLEND_SRC_ALPHA | + GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + + qglDisable( GL_CULL_FACE ); + qglDisable( GL_CLIP_PLANE0 ); + + // set time for 2D shaders + backEnd.refdef.time = ri.Milliseconds(); + backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; +} + + +/* +============= +RE_StretchRaw + +FIXME: not exactly backend +Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. +Used for cinematics. +============= +*/ +void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { + int i, j; + int start, end; + + if ( !tr.registered ) { + return; + } + R_SyncRenderThread(); + + // we definately want to sync every frame for the cinematics + qglFinish(); + + start = end = 0; + if ( r_speeds->integer ) { + start = ri.Milliseconds(); + } + + // make sure rows and cols are powers of 2 + for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { + } + for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { + } + if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { + ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); + } + + GL_Bind( tr.scratchImage[client] ); + + // if the scratchImage isn't in the format we want, specify it as a new texture + if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { + tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; + tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; + qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + } else { + if (dirty) { + // otherwise, just subimage upload it so that drivers can tell we are going to be changing + // it and don't try and do a texture compression + qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); + } + } + + if ( r_speeds->integer ) { + end = ri.Milliseconds(); + ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); + } + + RB_SetGL2D(); + + qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); + + qglBegin (GL_QUADS); + qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); + qglVertex2f (x, y); + qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); + qglVertex2f (x+w, y); + qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); + qglVertex2f (x+w, y+h); + qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); + qglVertex2f (x, y+h); + qglEnd (); +} + +void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { + + GL_Bind( tr.scratchImage[client] ); + + // if the scratchImage isn't in the format we want, specify it as a new texture + if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { + tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; + tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; + qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + } else { + if (dirty) { + // otherwise, just subimage upload it so that drivers can tell we are going to be changing + // it and don't try and do a texture compression + qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); + } + } +} + + +/* +============= +RB_SetColor + +============= +*/ +const void *RB_SetColor( const void *data ) { + const setColorCommand_t *cmd; + + cmd = (const setColorCommand_t *)data; + + backEnd.color2D[0] = cmd->color[0] * 255; + backEnd.color2D[1] = cmd->color[1] * 255; + backEnd.color2D[2] = cmd->color[2] * 255; + backEnd.color2D[3] = cmd->color[3] * 255; + + return (const void *)(cmd + 1); +} + +/* +============= +RB_StretchPic +============= +*/ +const void *RB_StretchPic ( const void *data ) { + const stretchPicCommand_t *cmd; + shader_t *shader; + int numVerts, numIndexes; + + cmd = (const stretchPicCommand_t *)data; + + if ( !backEnd.projection2D ) { + RB_SetGL2D(); + } + + shader = cmd->shader; + if ( shader != tess.shader ) { + if ( tess.numIndexes ) { + RB_EndSurface(); + } + backEnd.currentEntity = &backEnd.entity2D; + RB_BeginSurface( shader, 0 ); + } + + RB_CHECKOVERFLOW( 4, 6 ); + numVerts = tess.numVertexes; + numIndexes = tess.numIndexes; + + tess.numVertexes += 4; + tess.numIndexes += 6; + + tess.indexes[ numIndexes ] = numVerts + 3; + tess.indexes[ numIndexes + 1 ] = numVerts + 0; + tess.indexes[ numIndexes + 2 ] = numVerts + 2; + tess.indexes[ numIndexes + 3 ] = numVerts + 2; + tess.indexes[ numIndexes + 4 ] = numVerts + 0; + tess.indexes[ numIndexes + 5 ] = numVerts + 1; + + *(int *)tess.vertexColors[ numVerts ] = + *(int *)tess.vertexColors[ numVerts + 1 ] = + *(int *)tess.vertexColors[ numVerts + 2 ] = + *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D; + + tess.xyz[ numVerts ][0] = cmd->x; + tess.xyz[ numVerts ][1] = cmd->y; + tess.xyz[ numVerts ][2] = 0; + + tess.texCoords[ numVerts ][0][0] = cmd->s1; + tess.texCoords[ numVerts ][0][1] = cmd->t1; + + tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; + tess.xyz[ numVerts + 1 ][1] = cmd->y; + tess.xyz[ numVerts + 1 ][2] = 0; + + tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; + tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; + + tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; + tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; + tess.xyz[ numVerts + 2 ][2] = 0; + + tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; + tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; + + tess.xyz[ numVerts + 3 ][0] = cmd->x; + tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; + tess.xyz[ numVerts + 3 ][2] = 0; + + tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; + tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; + + return (const void *)(cmd + 1); +} + + +/* +============= +RB_DrawSurfs + +============= +*/ +const void *RB_DrawSurfs( const void *data ) { + const drawSurfsCommand_t *cmd; + + // finish any 2D drawing if needed + if ( tess.numIndexes ) { + RB_EndSurface(); + } + + cmd = (const drawSurfsCommand_t *)data; + + backEnd.refdef = cmd->refdef; + backEnd.viewParms = cmd->viewParms; + + RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); + + return (const void *)(cmd + 1); +} + + +/* +============= +RB_DrawBuffer + +============= +*/ +const void *RB_DrawBuffer( const void *data ) { + const drawBufferCommand_t *cmd; + + cmd = (const drawBufferCommand_t *)data; + + qglDrawBuffer( cmd->buffer ); + + // clear screen for debugging + if ( r_clear->integer ) { + qglClearColor( 1, 0, 0.5, 1 ); + qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + } + + return (const void *)(cmd + 1); +} + +/* +=============== +RB_ShowImages + +Draw all the images to the screen, on top of whatever +was there. This is used to test for texture thrashing. + +Also called by RE_EndRegistration +=============== +*/ +void RB_ShowImages( void ) { + int i; + image_t *image; + float x, y, w, h; + int start, end; + + if ( !backEnd.projection2D ) { + RB_SetGL2D(); + } + + qglClear( GL_COLOR_BUFFER_BIT ); + + qglFinish(); + + start = ri.Milliseconds(); + + for ( i=0 ; i<tr.numImages ; i++ ) { + image = tr.images[i]; + + w = glConfig.vidWidth / 20; + h = glConfig.vidHeight / 15; + x = i % 20 * w; + y = i / 20 * h; + + // show in proportional size in mode 2 + if ( r_showImages->integer == 2 ) { + w *= image->uploadWidth / 512.0f; + h *= image->uploadHeight / 512.0f; + } + + GL_Bind( image ); + qglBegin (GL_QUADS); + qglTexCoord2f( 0, 0 ); + qglVertex2f( x, y ); + qglTexCoord2f( 1, 0 ); + qglVertex2f( x + w, y ); + qglTexCoord2f( 1, 1 ); + qglVertex2f( x + w, y + h ); + qglTexCoord2f( 0, 1 ); + qglVertex2f( x, y + h ); + qglEnd(); + } + + qglFinish(); + + end = ri.Milliseconds(); + ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); + +} + + +/* +============= +RB_SwapBuffers + +============= +*/ +const void *RB_SwapBuffers( const void *data ) { + const swapBuffersCommand_t *cmd; + + // finish any 2D drawing if needed + if ( tess.numIndexes ) { + RB_EndSurface(); + } + + // texture swapping test + if ( r_showImages->integer ) { + RB_ShowImages(); + } + + cmd = (const swapBuffersCommand_t *)data; + + // we measure overdraw by reading back the stencil buffer and + // counting up the number of increments that have happened + if ( r_measureOverdraw->integer ) { + int i; + long sum = 0; + unsigned char *stencilReadback; + + stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight ); + qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); + + for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { + sum += stencilReadback[i]; + } + + backEnd.pc.c_overDraw += sum; + ri.Hunk_FreeTempMemory( stencilReadback ); + } + + + if ( !glState.finishCalled ) { + qglFinish(); + } + + GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" ); + + GLimp_EndFrame(); + + backEnd.projection2D = qfalse; + + return (const void *)(cmd + 1); +} + +/* +==================== +RB_ExecuteRenderCommands + +This function will be called synchronously if running without +smp extensions, or asynchronously by another thread. +==================== +*/ +void RB_ExecuteRenderCommands( const void *data ) { + int t1, t2; + + t1 = ri.Milliseconds (); + + if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) { + backEnd.smpFrame = 0; + } else { + backEnd.smpFrame = 1; + } + + while ( 1 ) { + switch ( *(const int *)data ) { + case RC_SET_COLOR: + data = RB_SetColor( data ); + break; + case RC_STRETCH_PIC: + data = RB_StretchPic( data ); + break; + case RC_DRAW_SURFS: + data = RB_DrawSurfs( data ); + break; + case RC_DRAW_BUFFER: + data = RB_DrawBuffer( data ); + break; + case RC_SWAP_BUFFERS: + data = RB_SwapBuffers( data ); + break; + case RC_SCREENSHOT: + data = RB_TakeScreenshotCmd( data ); + break; + + case RC_END_OF_LIST: + default: + // stop rendering on this thread + t2 = ri.Milliseconds (); + backEnd.pc.msec = t2 - t1; + return; + } + } + +} + + +/* +================ +RB_RenderThread +================ +*/ +void RB_RenderThread( void ) { + const void *data; + + // wait for either a rendering command or a quit command + while ( 1 ) { + // sleep until we have work to do + data = GLimp_RendererSleep(); + + if ( !data ) { + return; // all done, renderer is shutting down + } + + renderThreadActive = qtrue; + + RB_ExecuteRenderCommands( data ); + + renderThreadActive = qfalse; + } +} + diff --git a/code/renderer/tr_bsp.c b/code/renderer/tr_bsp.c index 5aefb24..1f5db42 100755 --- a/code/renderer/tr_bsp.c +++ b/code/renderer/tr_bsp.c @@ -1,1862 +1,1862 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_map.c
-
-#include "tr_local.h"
-
-/*
-
-Loads and prepares a map file for scene rendering.
-
-A single entry point:
-
-void RE_LoadWorldMap( const char *name );
-
-*/
-
-static world_t s_worldData;
-static byte *fileBase;
-
-int c_subdivisions;
-int c_gridVerts;
-
-//===============================================================================
-
-static void HSVtoRGB( float h, float s, float v, float rgb[3] )
-{
- int i;
- float f;
- float p, q, t;
-
- h *= 5;
-
- i = floor( h );
- f = h - i;
-
- p = v * ( 1 - s );
- q = v * ( 1 - s * f );
- t = v * ( 1 - s * ( 1 - f ) );
-
- switch ( i )
- {
- case 0:
- rgb[0] = v;
- rgb[1] = t;
- rgb[2] = p;
- break;
- case 1:
- rgb[0] = q;
- rgb[1] = v;
- rgb[2] = p;
- break;
- case 2:
- rgb[0] = p;
- rgb[1] = v;
- rgb[2] = t;
- break;
- case 3:
- rgb[0] = p;
- rgb[1] = q;
- rgb[2] = v;
- break;
- case 4:
- rgb[0] = t;
- rgb[1] = p;
- rgb[2] = v;
- break;
- case 5:
- rgb[0] = v;
- rgb[1] = p;
- rgb[2] = q;
- break;
- }
-}
-
-/*
-===============
-R_ColorShiftLightingBytes
-
-===============
-*/
-static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
- int shift, r, g, b;
-
- // shift the color data based on overbright range
- shift = r_mapOverBrightBits->integer - tr.overbrightBits;
-
- // shift the data based on overbright range
- r = in[0] << shift;
- g = in[1] << shift;
- b = in[2] << shift;
-
- // normalize by color instead of saturating to white
- if ( ( r | g | b ) > 255 ) {
- int max;
-
- max = r > g ? r : g;
- max = max > b ? max : b;
- r = r * 255 / max;
- g = g * 255 / max;
- b = b * 255 / max;
- }
-
- out[0] = r;
- out[1] = g;
- out[2] = b;
- out[3] = in[3];
-}
-
-/*
-===============
-R_LoadLightmaps
-
-===============
-*/
-#define LIGHTMAP_SIZE 128
-static void R_LoadLightmaps( lump_t *l ) {
- byte *buf, *buf_p;
- int len;
- MAC_STATIC byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4];
- int i, j;
- float maxIntensity = 0;
- double sumIntensity = 0;
-
- len = l->filelen;
- if ( !len ) {
- return;
- }
- buf = fileBase + l->fileofs;
-
- // we are about to upload textures
- R_SyncRenderThread();
-
- // create all the lightmaps
- tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);
- if ( tr.numLightmaps == 1 ) {
- //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.
- //this avoids this, but isn't the correct solution.
- tr.numLightmaps++;
- }
-
- // if we are in r_vertexLight mode, we don't need the lightmaps at all
- if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- return;
- }
-
- for ( i = 0 ; i < tr.numLightmaps ; i++ ) {
- // expand the 24 bit on-disk to 32 bit
- buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3;
-
- if ( r_lightmap->integer == 2 )
- { // color code by intensity as development tool (FIXME: check range)
- for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ )
- {
- float r = buf_p[j*3+0];
- float g = buf_p[j*3+1];
- float b = buf_p[j*3+2];
- float intensity;
- float out[3];
-
- intensity = 0.33f * r + 0.685f * g + 0.063f * b;
-
- if ( intensity > 255 )
- intensity = 1.0f;
- else
- intensity /= 255.0f;
-
- if ( intensity > maxIntensity )
- maxIntensity = intensity;
-
- HSVtoRGB( intensity, 1.00, 0.50, out );
-
- image[j*4+0] = out[0] * 255;
- image[j*4+1] = out[1] * 255;
- image[j*4+2] = out[2] * 255;
- image[j*4+3] = 255;
-
- sumIntensity += intensity;
- }
- } else {
- for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) {
- R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );
- image[j*4+3] = 255;
- }
- }
- tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image,
- LIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP );
- }
-
- if ( r_lightmap->integer == 2 ) {
- ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) );
- }
-}
-
-
-/*
-=================
-RE_SetWorldVisData
-
-This is called by the clipmodel subsystem so we can share the 1.8 megs of
-space in big maps...
-=================
-*/
-void RE_SetWorldVisData( const byte *vis ) {
- tr.externalVisData = vis;
-}
-
-
-/*
-=================
-R_LoadVisibility
-=================
-*/
-static void R_LoadVisibility( lump_t *l ) {
- int len;
- byte *buf;
-
- len = ( s_worldData.numClusters + 63 ) & ~63;
- s_worldData.novis = ri.Hunk_Alloc( len, h_low );
- Com_Memset( s_worldData.novis, 0xff, len );
-
- len = l->filelen;
- if ( !len ) {
- return;
- }
- buf = fileBase + l->fileofs;
-
- s_worldData.numClusters = LittleLong( ((int *)buf)[0] );
- s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );
-
- // CM_Load should have given us the vis data to share, so
- // we don't need to allocate another copy
- if ( tr.externalVisData ) {
- s_worldData.vis = tr.externalVisData;
- } else {
- byte *dest;
-
- dest = ri.Hunk_Alloc( len - 8, h_low );
- Com_Memcpy( dest, buf + 8, len - 8 );
- s_worldData.vis = dest;
- }
-}
-
-//===============================================================================
-
-
-/*
-===============
-ShaderForShaderNum
-===============
-*/
-static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {
- shader_t *shader;
- dshader_t *dsh;
-
- shaderNum = LittleLong( shaderNum );
- if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) {
- ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum );
- }
- dsh = &s_worldData.shaders[ shaderNum ];
-
- if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- lightmapNum = LIGHTMAP_BY_VERTEX;
- }
-
- if ( r_fullbright->integer ) {
- lightmapNum = LIGHTMAP_WHITEIMAGE;
- }
-
- shader = R_FindShader( dsh->shader, lightmapNum, qtrue );
-
- // if the shader had errors, just use default shader
- if ( shader->defaultShader ) {
- return tr.defaultShader;
- }
-
- return shader;
-}
-
-/*
-===============
-ParseFace
-===============
-*/
-static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
- int i, j;
- srfSurfaceFace_t *cv;
- int numPoints, numIndexes;
- int lightmapNum;
- int sfaceSize, ofsIndexes;
-
- lightmapNum = LittleLong( ds->lightmapNum );
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader value
- surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- numPoints = LittleLong( ds->numVerts );
- if (numPoints > MAX_FACE_POINTS) {
- ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints);
- numPoints = MAX_FACE_POINTS;
- surf->shader = tr.defaultShader;
- }
-
- numIndexes = LittleLong( ds->numIndexes );
-
- // create the srfSurfaceFace_t
- sfaceSize = ( int ) &((srfSurfaceFace_t *)0)->points[numPoints];
- ofsIndexes = sfaceSize;
- sfaceSize += sizeof( int ) * numIndexes;
-
- cv = ri.Hunk_Alloc( sfaceSize, h_low );
- cv->surfaceType = SF_FACE;
- cv->numPoints = numPoints;
- cv->numIndices = numIndexes;
- cv->ofsIndices = ofsIndexes;
-
- verts += LittleLong( ds->firstVert );
- for ( i = 0 ; i < numPoints ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- cv->points[i][j] = LittleFloat( verts[i].xyz[j] );
- }
- for ( j = 0 ; j < 2 ; j++ ) {
- cv->points[i][3+j] = LittleFloat( verts[i].st[j] );
- cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] );
- }
- R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] );
- }
-
- indexes += LittleLong( ds->firstIndex );
- for ( i = 0 ; i < numIndexes ; i++ ) {
- ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] );
- }
-
- // take the plane information from the lightmap vector
- for ( i = 0 ; i < 3 ; i++ ) {
- cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
- }
- cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal );
- SetPlaneSignbits( &cv->plane );
- cv->plane.type = PlaneTypeForNormal( cv->plane.normal );
-
- surf->data = (surfaceType_t *)cv;
-}
-
-
-/*
-===============
-ParseMesh
-===============
-*/
-static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) {
- srfGridMesh_t *grid;
- int i, j;
- int width, height, numPoints;
- MAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
- int lightmapNum;
- vec3_t bounds[2];
- vec3_t tmpVec;
- static surfaceType_t skipData = SF_SKIP;
-
- lightmapNum = LittleLong( ds->lightmapNum );
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader value
- surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- // we may have a nodraw surface, because they might still need to
- // be around for movement clipping
- if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {
- surf->data = &skipData;
- return;
- }
-
- width = LittleLong( ds->patchWidth );
- height = LittleLong( ds->patchHeight );
-
- verts += LittleLong( ds->firstVert );
- numPoints = width * height;
- for ( i = 0 ; i < numPoints ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- points[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
- points[i].normal[j] = LittleFloat( verts[i].normal[j] );
- }
- for ( j = 0 ; j < 2 ; j++ ) {
- points[i].st[j] = LittleFloat( verts[i].st[j] );
- points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
- }
- R_ColorShiftLightingBytes( verts[i].color, points[i].color );
- }
-
- // pre-tesseleate
- grid = R_SubdividePatchToGrid( width, height, points );
- surf->data = (surfaceType_t *)grid;
-
- // copy the level of detail origin, which is the center
- // of the group of all curves that must subdivide the same
- // to avoid cracking
- for ( i = 0 ; i < 3 ; i++ ) {
- bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );
- bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );
- }
- VectorAdd( bounds[0], bounds[1], bounds[1] );
- VectorScale( bounds[1], 0.5f, grid->lodOrigin );
- VectorSubtract( bounds[0], grid->lodOrigin, tmpVec );
- grid->lodRadius = VectorLength( tmpVec );
-}
-
-/*
-===============
-ParseTriSurf
-===============
-*/
-static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
- srfTriangles_t *tri;
- int i, j;
- int numVerts, numIndexes;
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader
- surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- numVerts = LittleLong( ds->numVerts );
- numIndexes = LittleLong( ds->numIndexes );
-
- tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] )
- + numIndexes * sizeof( tri->indexes[0] ), h_low );
- tri->surfaceType = SF_TRIANGLES;
- tri->numVerts = numVerts;
- tri->numIndexes = numIndexes;
- tri->verts = (drawVert_t *)(tri + 1);
- tri->indexes = (int *)(tri->verts + tri->numVerts );
-
- surf->data = (surfaceType_t *)tri;
-
- // copy vertexes
- ClearBounds( tri->bounds[0], tri->bounds[1] );
- verts += LittleLong( ds->firstVert );
- for ( i = 0 ; i < numVerts ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
- tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] );
- }
- AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] );
- for ( j = 0 ; j < 2 ; j++ ) {
- tri->verts[i].st[j] = LittleFloat( verts[i].st[j] );
- tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
- }
-
- R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color );
- }
-
- // copy indexes
- indexes += LittleLong( ds->firstIndex );
- for ( i = 0 ; i < numIndexes ; i++ ) {
- tri->indexes[i] = LittleLong( indexes[i] );
- if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) {
- ri.Error( ERR_DROP, "Bad index in triangle surface" );
- }
- }
-}
-
-/*
-===============
-ParseFlare
-===============
-*/
-static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
- srfFlare_t *flare;
- int i;
-
- // get fog volume
- surf->fogIndex = LittleLong( ds->fogNum ) + 1;
-
- // get shader
- surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
- if ( r_singleShader->integer && !surf->shader->isSky ) {
- surf->shader = tr.defaultShader;
- }
-
- flare = ri.Hunk_Alloc( sizeof( *flare ), h_low );
- flare->surfaceType = SF_FLARE;
-
- surf->data = (surfaceType_t *)flare;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );
- flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );
- flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
- }
-}
-
-
-/*
-=================
-R_MergedWidthPoints
-
-returns true if there are grid points merged on a width edge
-=================
-*/
-int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) {
- int i, j;
-
- for (i = 1; i < grid->width-1; i++) {
- for (j = i + 1; j < grid->width-1; j++) {
- if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;
- if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;
- if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-R_MergedHeightPoints
-
-returns true if there are grid points merged on a height edge
-=================
-*/
-int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) {
- int i, j;
-
- for (i = 1; i < grid->height-1; i++) {
- for (j = i + 1; j < grid->height-1; j++) {
- if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;
- if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;
- if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;
- return qtrue;
- }
- }
- return qfalse;
-}
-
-/*
-=================
-R_FixSharedVertexLodError_r
-
-NOTE: never sync LoD through grid edges with merged points!
-
-FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
-=================
-*/
-void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) {
- int j, k, l, m, n, offset1, offset2, touch;
- srfGridMesh_t *grid2;
-
- for ( j = start; j < s_worldData.numsurfaces; j++ ) {
- //
- grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
- // if this surface is not a grid
- if ( grid2->surfaceType != SF_GRID ) continue;
- // if the LOD errors are already fixed for this patch
- if ( grid2->lodFixed == 2 ) continue;
- // grids in the same LOD group should have the exact same lod radius
- if ( grid1->lodRadius != grid2->lodRadius ) continue;
- // grids in the same LOD group should have the exact same lod origin
- if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
- if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
- if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
- //
- touch = qfalse;
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = (grid1->height-1) * grid1->width;
- else offset1 = 0;
- if (R_MergedWidthPoints(grid1, offset1)) continue;
- for (k = 1; k < grid1->width-1; k++) {
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- if (R_MergedWidthPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->width-1; l++) {
- //
- if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->widthLodError[l] = grid1->widthLodError[k];
- touch = qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- if (R_MergedHeightPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->height-1; l++) {
- //
- if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->heightLodError[l] = grid1->widthLodError[k];
- touch = qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = grid1->width-1;
- else offset1 = 0;
- if (R_MergedHeightPoints(grid1, offset1)) continue;
- for (k = 1; k < grid1->height-1; k++) {
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- if (R_MergedWidthPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->width-1; l++) {
- //
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->widthLodError[l] = grid1->heightLodError[k];
- touch = qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- if (R_MergedHeightPoints(grid2, offset2)) continue;
- for ( l = 1; l < grid2->height-1; l++) {
- //
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
- if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
- // ok the points are equal and should have the same lod error
- grid2->heightLodError[l] = grid1->heightLodError[k];
- touch = qtrue;
- }
- }
- }
- }
- if (touch) {
- grid2->lodFixed = 2;
- R_FixSharedVertexLodError_r ( start, grid2 );
- //NOTE: this would be correct but makes things really slow
- //grid2->lodFixed = 1;
- }
- }
-}
-
-/*
-=================
-R_FixSharedVertexLodError
-
-This function assumes that all patches in one group are nicely stitched together for the highest LoD.
-If this is not the case this function will still do its job but won't fix the highest LoD cracks.
-=================
-*/
-void R_FixSharedVertexLodError( void ) {
- int i;
- srfGridMesh_t *grid1;
-
- for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
- //
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
- // if this surface is not a grid
- if ( grid1->surfaceType != SF_GRID )
- continue;
- //
- if ( grid1->lodFixed )
- continue;
- //
- grid1->lodFixed = 2;
- // recursively fix other patches in the same LOD group
- R_FixSharedVertexLodError_r( i + 1, grid1);
- }
-}
-
-
-/*
-===============
-R_StitchPatches
-===============
-*/
-int R_StitchPatches( int grid1num, int grid2num ) {
- float *v1, *v2;
- srfGridMesh_t *grid1, *grid2;
- int k, l, m, n, offset1, offset2, row, column;
-
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
- grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = (grid1->height-1) * grid1->width;
- else offset1 = 0;
- if (R_MergedWidthPoints(grid1, offset1))
- continue;
- for (k = 0; k < grid1->width-2; k += 2) {
-
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k + 2 + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k + 2 + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = grid1->width-1;
- else offset1 = 0;
- if (R_MergedHeightPoints(grid1, offset1))
- continue;
- for (k = 0; k < grid1->height-2; k += 2) {
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[(l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = (grid1->height-1) * grid1->width;
- else offset1 = 0;
- if (R_MergedWidthPoints(grid1, offset1))
- continue;
- for (k = grid1->width-1; k > 1; k -= 2) {
-
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k - 2 + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[(l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[k - 2 + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
- if (!grid2)
- break;
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- for (n = 0; n < 2; n++) {
- //
- if (n) offset1 = grid1->width-1;
- else offset1 = 0;
- if (R_MergedHeightPoints(grid1, offset1))
- continue;
- for (k = grid1->height-1; k > 1; k -= 2) {
- for (m = 0; m < 2; m++) {
-
- if ( grid2->width >= MAX_GRID_SIZE )
- break;
- if (m) offset2 = (grid2->height-1) * grid2->width;
- else offset2 = 0;
- for ( l = 0; l < grid2->width-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
- v2 = grid2->verts[l + 1 + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[l + offset2].xyz;
- v2 = grid2->verts[(l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert column into grid2 right after after column l
- if (m) row = grid2->height-1;
- else row = 0;
- grid2 = R_GridInsertColumn( grid2, l+1, row,
- grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- for (m = 0; m < 2; m++) {
-
- if (grid2->height >= MAX_GRID_SIZE)
- break;
- if (m) offset2 = grid2->width-1;
- else offset2 = 0;
- for ( l = 0; l < grid2->height-1; l++) {
- //
- v1 = grid1->verts[grid1->width * k + offset1].xyz;
- v2 = grid2->verts[grid2->width * l + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
-
- v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) > .1)
- continue;
- if ( fabs(v1[1] - v2[1]) > .1)
- continue;
- if ( fabs(v1[2] - v2[2]) > .1)
- continue;
- //
- v1 = grid2->verts[grid2->width * l + offset2].xyz;
- v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
- if ( fabs(v1[0] - v2[0]) < .01 &&
- fabs(v1[1] - v2[1]) < .01 &&
- fabs(v1[2] - v2[2]) < .01)
- continue;
- //
- //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
- // insert row into grid2 right after after row l
- if (m) column = grid2->width-1;
- else column = 0;
- grid2 = R_GridInsertRow( grid2, l+1, column,
- grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
- grid2->lodStitched = qfalse;
- s_worldData.surfaces[grid2num].data = (void *) grid2;
- return qtrue;
- }
- }
- }
- }
- return qfalse;
-}
-
-/*
-===============
-R_TryStitchPatch
-
-This function will try to stitch patches in the same LoD group together for the highest LoD.
-
-Only single missing vertice cracks will be fixed.
-
-Vertices will be joined at the patch side a crack is first found, at the other side
-of the patch (on the same row or column) the vertices will not be joined and cracks
-might still appear at that side.
-===============
-*/
-int R_TryStitchingPatch( int grid1num ) {
- int j, numstitches;
- srfGridMesh_t *grid1, *grid2;
-
- numstitches = 0;
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
- for ( j = 0; j < s_worldData.numsurfaces; j++ ) {
- //
- grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
- // if this surface is not a grid
- if ( grid2->surfaceType != SF_GRID ) continue;
- // grids in the same LOD group should have the exact same lod radius
- if ( grid1->lodRadius != grid2->lodRadius ) continue;
- // grids in the same LOD group should have the exact same lod origin
- if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
- if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
- if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
- //
- while (R_StitchPatches(grid1num, j))
- {
- numstitches++;
- }
- }
- return numstitches;
-}
-
-/*
-===============
-R_StitchAllPatches
-===============
-*/
-void R_StitchAllPatches( void ) {
- int i, stitched, numstitches;
- srfGridMesh_t *grid1;
-
- numstitches = 0;
- do
- {
- stitched = qfalse;
- for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
- //
- grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
- // if this surface is not a grid
- if ( grid1->surfaceType != SF_GRID )
- continue;
- //
- if ( grid1->lodStitched )
- continue;
- //
- grid1->lodStitched = qtrue;
- stitched = qtrue;
- //
- numstitches += R_TryStitchingPatch( i );
- }
- }
- while (stitched);
- ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches );
-}
-
-/*
-===============
-R_MovePatchSurfacesToHunk
-===============
-*/
-void R_MovePatchSurfacesToHunk(void) {
- int i, size;
- srfGridMesh_t *grid, *hunkgrid;
-
- for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
- //
- grid = (srfGridMesh_t *) s_worldData.surfaces[i].data;
- // if this surface is not a grid
- if ( grid->surfaceType != SF_GRID )
- continue;
- //
- size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
- hunkgrid = ri.Hunk_Alloc( size, h_low );
- Com_Memcpy(hunkgrid, grid, size);
-
- hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low );
- Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 );
-
- hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low );
- Com_Memcpy( grid->heightLodError, grid->heightLodError, grid->height * 4 );
-
- R_FreeSurfaceGridMesh( grid );
-
- s_worldData.surfaces[i].data = (void *) hunkgrid;
- }
-}
-
-/*
-===============
-R_LoadSurfaces
-===============
-*/
-static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) {
- dsurface_t *in;
- msurface_t *out;
- drawVert_t *dv;
- int *indexes;
- int count;
- int numFaces, numMeshes, numTriSurfs, numFlares;
- int i;
-
- numFaces = 0;
- numMeshes = 0;
- numTriSurfs = 0;
- numFlares = 0;
-
- in = (void *)(fileBase + surfs->fileofs);
- if (surfs->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = surfs->filelen / sizeof(*in);
-
- dv = (void *)(fileBase + verts->fileofs);
- if (verts->filelen % sizeof(*dv))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
-
- indexes = (void *)(fileBase + indexLump->fileofs);
- if ( indexLump->filelen % sizeof(*indexes))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
-
- out = ri.Hunk_Alloc ( count * sizeof(*out), h_low );
-
- s_worldData.surfaces = out;
- s_worldData.numsurfaces = count;
-
- for ( i = 0 ; i < count ; i++, in++, out++ ) {
- switch ( LittleLong( in->surfaceType ) ) {
- case MST_PATCH:
- ParseMesh ( in, dv, out );
- numMeshes++;
- break;
- case MST_TRIANGLE_SOUP:
- ParseTriSurf( in, dv, out, indexes );
- numTriSurfs++;
- break;
- case MST_PLANAR:
- ParseFace( in, dv, out, indexes );
- numFaces++;
- break;
- case MST_FLARE:
- ParseFlare( in, dv, out, indexes );
- numFlares++;
- break;
- default:
- ri.Error( ERR_DROP, "Bad surfaceType" );
- }
- }
-
-#ifdef PATCH_STITCHING
- R_StitchAllPatches();
-#endif
-
- R_FixSharedVertexLodError();
-
-#ifdef PATCH_STITCHING
- R_MovePatchSurfacesToHunk();
-#endif
-
- ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n",
- numFaces, numMeshes, numTriSurfs, numFlares );
-}
-
-
-
-/*
-=================
-R_LoadSubmodels
-=================
-*/
-static void R_LoadSubmodels( lump_t *l ) {
- dmodel_t *in;
- bmodel_t *out;
- int i, j, count;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
-
- s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low );
-
- for ( i=0 ; i<count ; i++, in++, out++ ) {
- model_t *model;
-
- model = R_AllocModel();
-
- assert( model != NULL ); // this should never happen
-
- model->type = MOD_BRUSH;
- model->bmodel = out;
- Com_sprintf( model->name, sizeof( model->name ), "*%d", i );
-
- for (j=0 ; j<3 ; j++) {
- out->bounds[0][j] = LittleFloat (in->mins[j]);
- out->bounds[1][j] = LittleFloat (in->maxs[j]);
- }
-
- out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface );
- out->numSurfaces = LittleLong( in->numSurfaces );
- }
-}
-
-
-
-//==================================================================
-
-/*
-=================
-R_SetParent
-=================
-*/
-static void R_SetParent (mnode_t *node, mnode_t *parent)
-{
- node->parent = parent;
- if (node->contents != -1)
- return;
- R_SetParent (node->children[0], node);
- R_SetParent (node->children[1], node);
-}
-
-/*
-=================
-R_LoadNodesAndLeafs
-=================
-*/
-static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) {
- int i, j, p;
- dnode_t *in;
- dleaf_t *inLeaf;
- mnode_t *out;
- int numNodes, numLeafs;
-
- in = (void *)(fileBase + nodeLump->fileofs);
- if (nodeLump->filelen % sizeof(dnode_t) ||
- leafLump->filelen % sizeof(dleaf_t) ) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- numNodes = nodeLump->filelen / sizeof(dnode_t);
- numLeafs = leafLump->filelen / sizeof(dleaf_t);
-
- out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low);
-
- s_worldData.nodes = out;
- s_worldData.numnodes = numNodes + numLeafs;
- s_worldData.numDecisionNodes = numNodes;
-
- // load nodes
- for ( i=0 ; i<numNodes; i++, in++, out++)
- {
- for (j=0 ; j<3 ; j++)
- {
- out->mins[j] = LittleLong (in->mins[j]);
- out->maxs[j] = LittleLong (in->maxs[j]);
- }
-
- p = LittleLong(in->planeNum);
- out->plane = s_worldData.planes + p;
-
- out->contents = CONTENTS_NODE; // differentiate from leafs
-
- for (j=0 ; j<2 ; j++)
- {
- p = LittleLong (in->children[j]);
- if (p >= 0)
- out->children[j] = s_worldData.nodes + p;
- else
- out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
- }
- }
-
- // load leafs
- inLeaf = (void *)(fileBase + leafLump->fileofs);
- for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)
- {
- for (j=0 ; j<3 ; j++)
- {
- out->mins[j] = LittleLong (inLeaf->mins[j]);
- out->maxs[j] = LittleLong (inLeaf->maxs[j]);
- }
-
- out->cluster = LittleLong(inLeaf->cluster);
- out->area = LittleLong(inLeaf->area);
-
- if ( out->cluster >= s_worldData.numClusters ) {
- s_worldData.numClusters = out->cluster + 1;
- }
-
- out->firstmarksurface = s_worldData.marksurfaces +
- LittleLong(inLeaf->firstLeafSurface);
- out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
- }
-
- // chain decendants
- R_SetParent (s_worldData.nodes, NULL);
-}
-
-//=============================================================================
-
-/*
-=================
-R_LoadShaders
-=================
-*/
-static void R_LoadShaders( lump_t *l ) {
- int i, count;
- dshader_t *in, *out;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
- out = ri.Hunk_Alloc ( count*sizeof(*out), h_low );
-
- s_worldData.shaders = out;
- s_worldData.numShaders = count;
-
- Com_Memcpy( out, in, count*sizeof(*out) );
-
- for ( i=0 ; i<count ; i++ ) {
- out[i].surfaceFlags = LittleLong( out[i].surfaceFlags );
- out[i].contentFlags = LittleLong( out[i].contentFlags );
- }
-}
-
-
-/*
-=================
-R_LoadMarksurfaces
-=================
-*/
-static void R_LoadMarksurfaces (lump_t *l)
-{
- int i, j, count;
- int *in;
- msurface_t **out;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
- out = ri.Hunk_Alloc ( count*sizeof(*out), h_low);
-
- s_worldData.marksurfaces = out;
- s_worldData.nummarksurfaces = count;
-
- for ( i=0 ; i<count ; i++)
- {
- j = LittleLong(in[i]);
- out[i] = s_worldData.surfaces + j;
- }
-}
-
-
-/*
-=================
-R_LoadPlanes
-=================
-*/
-static void R_LoadPlanes( lump_t *l ) {
- int i, j;
- cplane_t *out;
- dplane_t *in;
- int count;
- int bits;
-
- in = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- count = l->filelen / sizeof(*in);
- out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);
-
- s_worldData.planes = out;
- s_worldData.numplanes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++) {
- bits = 0;
- for (j=0 ; j<3 ; j++) {
- out->normal[j] = LittleFloat (in->normal[j]);
- if (out->normal[j] < 0) {
- bits |= 1<<j;
- }
- }
-
- out->dist = LittleFloat (in->dist);
- out->type = PlaneTypeForNormal( out->normal );
- out->signbits = bits;
- }
-}
-
-/*
-=================
-R_LoadFogs
-
-=================
-*/
-static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
- int i;
- fog_t *out;
- dfog_t *fogs;
- dbrush_t *brushes, *brush;
- dbrushside_t *sides;
- int count, brushesCount, sidesCount;
- int sideNum;
- int planeNum;
- shader_t *shader;
- float d;
- int firstSide;
-
- fogs = (void *)(fileBase + l->fileofs);
- if (l->filelen % sizeof(*fogs)) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- count = l->filelen / sizeof(*fogs);
-
- // create fog strucutres for them
- s_worldData.numfogs = count + 1;
- s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);
- out = s_worldData.fogs + 1;
-
- if ( !count ) {
- return;
- }
-
- brushes = (void *)(fileBase + brushesLump->fileofs);
- if (brushesLump->filelen % sizeof(*brushes)) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- brushesCount = brushesLump->filelen / sizeof(*brushes);
-
- sides = (void *)(fileBase + sidesLump->fileofs);
- if (sidesLump->filelen % sizeof(*sides)) {
- ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
- }
- sidesCount = sidesLump->filelen / sizeof(*sides);
-
- for ( i=0 ; i<count ; i++, fogs++) {
- out->originalBrushNumber = LittleLong( fogs->brushNum );
-
- if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
- ri.Error( ERR_DROP, "fog brushNumber out of range" );
- }
- brush = brushes + out->originalBrushNumber;
-
- firstSide = LittleLong( brush->firstSide );
-
- if ( (unsigned)firstSide > sidesCount - 6 ) {
- ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
- }
-
- // brushes are always sorted with the axial sides first
- sideNum = firstSide + 0;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 1;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 2;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 3;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 4;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;
-
- sideNum = firstSide + 5;
- planeNum = LittleLong( sides[ sideNum ].planeNum );
- out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
-
- // get information from the shader for fog parameters
- shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue );
-
- out->parms = shader->fogParms;
-
- out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight,
- shader->fogParms.color[1] * tr.identityLight,
- shader->fogParms.color[2] * tr.identityLight, 1.0 );
-
- d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
- out->tcScale = 1.0f / ( d * 8 );
-
- // set the gradient vector
- sideNum = LittleLong( fogs->visibleSide );
-
- if ( sideNum == -1 ) {
- out->hasSurface = qfalse;
- } else {
- out->hasSurface = qtrue;
- planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
- VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
- out->surface[3] = -s_worldData.planes[ planeNum ].dist;
- }
-
- out++;
- }
-
-}
-
-
-/*
-================
-R_LoadLightGrid
-
-================
-*/
-void R_LoadLightGrid( lump_t *l ) {
- int i;
- vec3_t maxs;
- int numGridPoints;
- world_t *w;
- float *wMins, *wMaxs;
-
- w = &s_worldData;
-
- w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
- w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
- w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
-
- wMins = w->bmodels[0].bounds[0];
- wMaxs = w->bmodels[0].bounds[1];
-
- for ( i = 0 ; i < 3 ; i++ ) {
- w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );
- maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );
- w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;
- }
-
- numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
-
- if ( l->filelen != numGridPoints * 8 ) {
- ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" );
- w->lightGridData = NULL;
- return;
- }
-
- w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low );
- Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );
-
- // deal with overbright bits
- for ( i = 0 ; i < numGridPoints ; i++ ) {
- R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );
- R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );
- }
-}
-
-/*
-================
-R_LoadEntities
-================
-*/
-void R_LoadEntities( lump_t *l ) {
- char *p, *token, *s;
- char keyname[MAX_TOKEN_CHARS];
- char value[MAX_TOKEN_CHARS];
- world_t *w;
-
- w = &s_worldData;
- w->lightGridSize[0] = 64;
- w->lightGridSize[1] = 64;
- w->lightGridSize[2] = 128;
-
- p = (char *)(fileBase + l->fileofs);
-
- // store for reference by the cgame
- w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low );
- strcpy( w->entityString, p );
- w->entityParsePoint = w->entityString;
-
- token = COM_ParseExt( &p, qtrue );
- if (!*token || *token != '{') {
- return;
- }
-
- // only parse the world spawn
- while ( 1 ) {
- // parse key
- token = COM_ParseExt( &p, qtrue );
-
- if ( !*token || *token == '}' ) {
- break;
- }
- Q_strncpyz(keyname, token, sizeof(keyname));
-
- // parse value
- token = COM_ParseExt( &p, qtrue );
-
- if ( !*token || *token == '}' ) {
- break;
- }
- Q_strncpyz(value, token, sizeof(value));
-
- // check for remapping of shaders for vertex lighting
- s = "vertexremapshader";
- if (!Q_strncmp(keyname, s, strlen(s)) ) {
- s = strchr(value, ';');
- if (!s) {
- ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value );
- break;
- }
- *s++ = 0;
- if (r_vertexLight->integer) {
- R_RemapShader(value, s, "0");
- }
- continue;
- }
- // check for remapping of shaders
- s = "remapshader";
- if (!Q_strncmp(keyname, s, strlen(s)) ) {
- s = strchr(value, ';');
- if (!s) {
- ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value );
- break;
- }
- *s++ = 0;
- R_RemapShader(value, s, "0");
- continue;
- }
- // check for a different grid size
- if (!Q_stricmp(keyname, "gridsize")) {
- sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );
- continue;
- }
- }
-}
-
-/*
-=================
-R_GetEntityToken
-=================
-*/
-qboolean R_GetEntityToken( char *buffer, int size ) {
- const char *s;
-
- s = COM_Parse( &s_worldData.entityParsePoint );
- Q_strncpyz( buffer, s, size );
- if ( !s_worldData.entityParsePoint || !s[0] ) {
- s_worldData.entityParsePoint = s_worldData.entityString;
- return qfalse;
- } else {
- return qtrue;
- }
-}
-
-/*
-=================
-RE_LoadWorldMap
-
-Called directly from cgame
-=================
-*/
-void RE_LoadWorldMap( const char *name ) {
- int i;
- dheader_t *header;
- byte *buffer;
- byte *startMarker;
-
- if ( tr.worldMapLoaded ) {
- ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" );
- }
-
- // set default sun direction to be used if it isn't
- // overridden by a shader
- tr.sunDirection[0] = 0.45f;
- tr.sunDirection[1] = 0.3f;
- tr.sunDirection[2] = 0.9f;
-
- VectorNormalize( tr.sunDirection );
-
- tr.worldMapLoaded = qtrue;
-
- // load it
- ri.FS_ReadFile( name, (void **)&buffer );
- if ( !buffer ) {
- ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
- }
-
- // clear tr.world so if the level fails to load, the next
- // try will not look at the partially loaded version
- tr.world = NULL;
-
- Com_Memset( &s_worldData, 0, sizeof( s_worldData ) );
- Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
-
- Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
- COM_StripExtension( s_worldData.baseName, s_worldData.baseName );
-
- startMarker = ri.Hunk_Alloc(0, h_low);
- c_gridVerts = 0;
-
- header = (dheader_t *)buffer;
- fileBase = (byte *)header;
-
- i = LittleLong (header->version);
- if ( i != BSP_VERSION ) {
- ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)",
- name, i, BSP_VERSION);
- }
-
- // swap all the lumps
- for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
- }
-
- // load into heap
- R_LoadShaders( &header->lumps[LUMP_SHADERS] );
- R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] );
- R_LoadPlanes (&header->lumps[LUMP_PLANES]);
- R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );
- R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );
- R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);
- R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
- R_LoadSubmodels (&header->lumps[LUMP_MODELS]);
- R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
- R_LoadEntities( &header->lumps[LUMP_ENTITIES] );
- R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );
-
- s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
-
- // only set tr.world now that we know the entire level has loaded properly
- tr.world = &s_worldData;
-
- ri.FS_FreeFile( buffer );
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_map.c + +#include "tr_local.h" + +/* + +Loads and prepares a map file for scene rendering. + +A single entry point: + +void RE_LoadWorldMap( const char *name ); + +*/ + +static world_t s_worldData; +static byte *fileBase; + +int c_subdivisions; +int c_gridVerts; + +//=============================================================================== + +static void HSVtoRGB( float h, float s, float v, float rgb[3] ) +{ + int i; + float f; + float p, q, t; + + h *= 5; + + i = floor( h ); + f = h - i; + + p = v * ( 1 - s ); + q = v * ( 1 - s * f ); + t = v * ( 1 - s * ( 1 - f ) ); + + switch ( i ) + { + case 0: + rgb[0] = v; + rgb[1] = t; + rgb[2] = p; + break; + case 1: + rgb[0] = q; + rgb[1] = v; + rgb[2] = p; + break; + case 2: + rgb[0] = p; + rgb[1] = v; + rgb[2] = t; + break; + case 3: + rgb[0] = p; + rgb[1] = q; + rgb[2] = v; + break; + case 4: + rgb[0] = t; + rgb[1] = p; + rgb[2] = v; + break; + case 5: + rgb[0] = v; + rgb[1] = p; + rgb[2] = q; + break; + } +} + +/* +=============== +R_ColorShiftLightingBytes + +=============== +*/ +static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { + int shift, r, g, b; + + // shift the color data based on overbright range + shift = r_mapOverBrightBits->integer - tr.overbrightBits; + + // shift the data based on overbright range + r = in[0] << shift; + g = in[1] << shift; + b = in[2] << shift; + + // normalize by color instead of saturating to white + if ( ( r | g | b ) > 255 ) { + int max; + + max = r > g ? r : g; + max = max > b ? max : b; + r = r * 255 / max; + g = g * 255 / max; + b = b * 255 / max; + } + + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = in[3]; +} + +/* +=============== +R_LoadLightmaps + +=============== +*/ +#define LIGHTMAP_SIZE 128 +static void R_LoadLightmaps( lump_t *l ) { + byte *buf, *buf_p; + int len; + MAC_STATIC byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4]; + int i, j; + float maxIntensity = 0; + double sumIntensity = 0; + + len = l->filelen; + if ( !len ) { + return; + } + buf = fileBase + l->fileofs; + + // we are about to upload textures + R_SyncRenderThread(); + + // create all the lightmaps + tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); + if ( tr.numLightmaps == 1 ) { + //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason. + //this avoids this, but isn't the correct solution. + tr.numLightmaps++; + } + + // if we are in r_vertexLight mode, we don't need the lightmaps at all + if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { + return; + } + + for ( i = 0 ; i < tr.numLightmaps ; i++ ) { + // expand the 24 bit on-disk to 32 bit + buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3; + + if ( r_lightmap->integer == 2 ) + { // color code by intensity as development tool (FIXME: check range) + for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) + { + float r = buf_p[j*3+0]; + float g = buf_p[j*3+1]; + float b = buf_p[j*3+2]; + float intensity; + float out[3]; + + intensity = 0.33f * r + 0.685f * g + 0.063f * b; + + if ( intensity > 255 ) + intensity = 1.0f; + else + intensity /= 255.0f; + + if ( intensity > maxIntensity ) + maxIntensity = intensity; + + HSVtoRGB( intensity, 1.00, 0.50, out ); + + image[j*4+0] = out[0] * 255; + image[j*4+1] = out[1] * 255; + image[j*4+2] = out[2] * 255; + image[j*4+3] = 255; + + sumIntensity += intensity; + } + } else { + for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) { + R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); + image[j*4+3] = 255; + } + } + tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image, + LIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP ); + } + + if ( r_lightmap->integer == 2 ) { + ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); + } +} + + +/* +================= +RE_SetWorldVisData + +This is called by the clipmodel subsystem so we can share the 1.8 megs of +space in big maps... +================= +*/ +void RE_SetWorldVisData( const byte *vis ) { + tr.externalVisData = vis; +} + + +/* +================= +R_LoadVisibility +================= +*/ +static void R_LoadVisibility( lump_t *l ) { + int len; + byte *buf; + + len = ( s_worldData.numClusters + 63 ) & ~63; + s_worldData.novis = ri.Hunk_Alloc( len, h_low ); + Com_Memset( s_worldData.novis, 0xff, len ); + + len = l->filelen; + if ( !len ) { + return; + } + buf = fileBase + l->fileofs; + + s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); + s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); + + // CM_Load should have given us the vis data to share, so + // we don't need to allocate another copy + if ( tr.externalVisData ) { + s_worldData.vis = tr.externalVisData; + } else { + byte *dest; + + dest = ri.Hunk_Alloc( len - 8, h_low ); + Com_Memcpy( dest, buf + 8, len - 8 ); + s_worldData.vis = dest; + } +} + +//=============================================================================== + + +/* +=============== +ShaderForShaderNum +=============== +*/ +static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { + shader_t *shader; + dshader_t *dsh; + + shaderNum = LittleLong( shaderNum ); + if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) { + ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum ); + } + dsh = &s_worldData.shaders[ shaderNum ]; + + if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { + lightmapNum = LIGHTMAP_BY_VERTEX; + } + + if ( r_fullbright->integer ) { + lightmapNum = LIGHTMAP_WHITEIMAGE; + } + + shader = R_FindShader( dsh->shader, lightmapNum, qtrue ); + + // if the shader had errors, just use default shader + if ( shader->defaultShader ) { + return tr.defaultShader; + } + + return shader; +} + +/* +=============== +ParseFace +=============== +*/ +static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { + int i, j; + srfSurfaceFace_t *cv; + int numPoints, numIndexes; + int lightmapNum; + int sfaceSize, ofsIndexes; + + lightmapNum = LittleLong( ds->lightmapNum ); + + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; + + // get shader value + surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } + + numPoints = LittleLong( ds->numVerts ); + if (numPoints > MAX_FACE_POINTS) { + ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints); + numPoints = MAX_FACE_POINTS; + surf->shader = tr.defaultShader; + } + + numIndexes = LittleLong( ds->numIndexes ); + + // create the srfSurfaceFace_t + sfaceSize = ( int ) &((srfSurfaceFace_t *)0)->points[numPoints]; + ofsIndexes = sfaceSize; + sfaceSize += sizeof( int ) * numIndexes; + + cv = ri.Hunk_Alloc( sfaceSize, h_low ); + cv->surfaceType = SF_FACE; + cv->numPoints = numPoints; + cv->numIndices = numIndexes; + cv->ofsIndices = ofsIndexes; + + verts += LittleLong( ds->firstVert ); + for ( i = 0 ; i < numPoints ; i++ ) { + for ( j = 0 ; j < 3 ; j++ ) { + cv->points[i][j] = LittleFloat( verts[i].xyz[j] ); + } + for ( j = 0 ; j < 2 ; j++ ) { + cv->points[i][3+j] = LittleFloat( verts[i].st[j] ); + cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] ); + } + R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] ); + } + + indexes += LittleLong( ds->firstIndex ); + for ( i = 0 ; i < numIndexes ; i++ ) { + ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] ); + } + + // take the plane information from the lightmap vector + for ( i = 0 ; i < 3 ; i++ ) { + cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); + } + cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal ); + SetPlaneSignbits( &cv->plane ); + cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); + + surf->data = (surfaceType_t *)cv; +} + + +/* +=============== +ParseMesh +=============== +*/ +static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { + srfGridMesh_t *grid; + int i, j; + int width, height, numPoints; + MAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; + int lightmapNum; + vec3_t bounds[2]; + vec3_t tmpVec; + static surfaceType_t skipData = SF_SKIP; + + lightmapNum = LittleLong( ds->lightmapNum ); + + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; + + // get shader value + surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } + + // we may have a nodraw surface, because they might still need to + // be around for movement clipping + if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { + surf->data = &skipData; + return; + } + + width = LittleLong( ds->patchWidth ); + height = LittleLong( ds->patchHeight ); + + verts += LittleLong( ds->firstVert ); + numPoints = width * height; + for ( i = 0 ; i < numPoints ; i++ ) { + for ( j = 0 ; j < 3 ; j++ ) { + points[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); + points[i].normal[j] = LittleFloat( verts[i].normal[j] ); + } + for ( j = 0 ; j < 2 ; j++ ) { + points[i].st[j] = LittleFloat( verts[i].st[j] ); + points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); + } + R_ColorShiftLightingBytes( verts[i].color, points[i].color ); + } + + // pre-tesseleate + grid = R_SubdividePatchToGrid( width, height, points ); + surf->data = (surfaceType_t *)grid; + + // copy the level of detail origin, which is the center + // of the group of all curves that must subdivide the same + // to avoid cracking + for ( i = 0 ; i < 3 ; i++ ) { + bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); + bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); + } + VectorAdd( bounds[0], bounds[1], bounds[1] ); + VectorScale( bounds[1], 0.5f, grid->lodOrigin ); + VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); + grid->lodRadius = VectorLength( tmpVec ); +} + +/* +=============== +ParseTriSurf +=============== +*/ +static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { + srfTriangles_t *tri; + int i, j; + int numVerts, numIndexes; + + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; + + // get shader + surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } + + numVerts = LittleLong( ds->numVerts ); + numIndexes = LittleLong( ds->numIndexes ); + + tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) + + numIndexes * sizeof( tri->indexes[0] ), h_low ); + tri->surfaceType = SF_TRIANGLES; + tri->numVerts = numVerts; + tri->numIndexes = numIndexes; + tri->verts = (drawVert_t *)(tri + 1); + tri->indexes = (int *)(tri->verts + tri->numVerts ); + + surf->data = (surfaceType_t *)tri; + + // copy vertexes + ClearBounds( tri->bounds[0], tri->bounds[1] ); + verts += LittleLong( ds->firstVert ); + for ( i = 0 ; i < numVerts ; i++ ) { + for ( j = 0 ; j < 3 ; j++ ) { + tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); + tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] ); + } + AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] ); + for ( j = 0 ; j < 2 ; j++ ) { + tri->verts[i].st[j] = LittleFloat( verts[i].st[j] ); + tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); + } + + R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color ); + } + + // copy indexes + indexes += LittleLong( ds->firstIndex ); + for ( i = 0 ; i < numIndexes ; i++ ) { + tri->indexes[i] = LittleLong( indexes[i] ); + if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) { + ri.Error( ERR_DROP, "Bad index in triangle surface" ); + } + } +} + +/* +=============== +ParseFlare +=============== +*/ +static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { + srfFlare_t *flare; + int i; + + // get fog volume + surf->fogIndex = LittleLong( ds->fogNum ) + 1; + + // get shader + surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); + if ( r_singleShader->integer && !surf->shader->isSky ) { + surf->shader = tr.defaultShader; + } + + flare = ri.Hunk_Alloc( sizeof( *flare ), h_low ); + flare->surfaceType = SF_FLARE; + + surf->data = (surfaceType_t *)flare; + + for ( i = 0 ; i < 3 ; i++ ) { + flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); + flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); + flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); + } +} + + +/* +================= +R_MergedWidthPoints + +returns true if there are grid points merged on a width edge +================= +*/ +int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) { + int i, j; + + for (i = 1; i < grid->width-1; i++) { + for (j = i + 1; j < grid->width-1; j++) { + if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; + if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; + if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; + return qtrue; + } + } + return qfalse; +} + +/* +================= +R_MergedHeightPoints + +returns true if there are grid points merged on a height edge +================= +*/ +int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) { + int i, j; + + for (i = 1; i < grid->height-1; i++) { + for (j = i + 1; j < grid->height-1; j++) { + if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; + if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; + if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; + return qtrue; + } + } + return qfalse; +} + +/* +================= +R_FixSharedVertexLodError_r + +NOTE: never sync LoD through grid edges with merged points! + +FIXME: write generalized version that also avoids cracks between a patch and one that meets half way? +================= +*/ +void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) { + int j, k, l, m, n, offset1, offset2, touch; + srfGridMesh_t *grid2; + + for ( j = start; j < s_worldData.numsurfaces; j++ ) { + // + grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; + // if this surface is not a grid + if ( grid2->surfaceType != SF_GRID ) continue; + // if the LOD errors are already fixed for this patch + if ( grid2->lodFixed == 2 ) continue; + // grids in the same LOD group should have the exact same lod radius + if ( grid1->lodRadius != grid2->lodRadius ) continue; + // grids in the same LOD group should have the exact same lod origin + if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; + if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; + if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; + // + touch = qfalse; + for (n = 0; n < 2; n++) { + // + if (n) offset1 = (grid1->height-1) * grid1->width; + else offset1 = 0; + if (R_MergedWidthPoints(grid1, offset1)) continue; + for (k = 1; k < grid1->width-1; k++) { + for (m = 0; m < 2; m++) { + + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + if (R_MergedWidthPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->width-1; l++) { + // + if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->widthLodError[l] = grid1->widthLodError[k]; + touch = qtrue; + } + } + for (m = 0; m < 2; m++) { + + if (m) offset2 = grid2->width-1; + else offset2 = 0; + if (R_MergedHeightPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->height-1; l++) { + // + if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->heightLodError[l] = grid1->widthLodError[k]; + touch = qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = grid1->width-1; + else offset1 = 0; + if (R_MergedHeightPoints(grid1, offset1)) continue; + for (k = 1; k < grid1->height-1; k++) { + for (m = 0; m < 2; m++) { + + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + if (R_MergedWidthPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->width-1; l++) { + // + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->widthLodError[l] = grid1->heightLodError[k]; + touch = qtrue; + } + } + for (m = 0; m < 2; m++) { + + if (m) offset2 = grid2->width-1; + else offset2 = 0; + if (R_MergedHeightPoints(grid2, offset2)) continue; + for ( l = 1; l < grid2->height-1; l++) { + // + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; + if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; + // ok the points are equal and should have the same lod error + grid2->heightLodError[l] = grid1->heightLodError[k]; + touch = qtrue; + } + } + } + } + if (touch) { + grid2->lodFixed = 2; + R_FixSharedVertexLodError_r ( start, grid2 ); + //NOTE: this would be correct but makes things really slow + //grid2->lodFixed = 1; + } + } +} + +/* +================= +R_FixSharedVertexLodError + +This function assumes that all patches in one group are nicely stitched together for the highest LoD. +If this is not the case this function will still do its job but won't fix the highest LoD cracks. +================= +*/ +void R_FixSharedVertexLodError( void ) { + int i; + srfGridMesh_t *grid1; + + for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + // + grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; + // if this surface is not a grid + if ( grid1->surfaceType != SF_GRID ) + continue; + // + if ( grid1->lodFixed ) + continue; + // + grid1->lodFixed = 2; + // recursively fix other patches in the same LOD group + R_FixSharedVertexLodError_r( i + 1, grid1); + } +} + + +/* +=============== +R_StitchPatches +=============== +*/ +int R_StitchPatches( int grid1num, int grid2num ) { + float *v1, *v2; + srfGridMesh_t *grid1, *grid2; + int k, l, m, n, offset1, offset2, row, column; + + grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; + grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data; + for (n = 0; n < 2; n++) { + // + if (n) offset1 = (grid1->height-1) * grid1->width; + else offset1 = 0; + if (R_MergedWidthPoints(grid1, offset1)) + continue; + for (k = 0; k < grid1->width-2; k += 2) { + + for (m = 0; m < 2; m++) { + + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[k + 2 + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { + + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[k + 2 + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = grid1->width-1; + else offset1 = 0; + if (R_MergedHeightPoints(grid1, offset1)) + continue; + for (k = 0; k < grid1->height-2; k += 2) { + for (m = 0; m < 2; m++) { + + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[(l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { + + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = (grid1->height-1) * grid1->width; + else offset1 = 0; + if (R_MergedWidthPoints(grid1, offset1)) + continue; + for (k = grid1->width-1; k > 1; k -= 2) { + + for (m = 0; m < 2; m++) { + + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[k - 2 + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[(l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { + + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[k - 2 + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); + if (!grid2) + break; + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + for (n = 0; n < 2; n++) { + // + if (n) offset1 = grid1->width-1; + else offset1 = 0; + if (R_MergedHeightPoints(grid1, offset1)) + continue; + for (k = grid1->height-1; k > 1; k -= 2) { + for (m = 0; m < 2; m++) { + + if ( grid2->width >= MAX_GRID_SIZE ) + break; + if (m) offset2 = (grid2->height-1) * grid2->width; + else offset2 = 0; + for ( l = 0; l < grid2->width-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; + v2 = grid2->verts[l + 1 + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[l + offset2].xyz; + v2 = grid2->verts[(l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert column into grid2 right after after column l + if (m) row = grid2->height-1; + else row = 0; + grid2 = R_GridInsertColumn( grid2, l+1, row, + grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + for (m = 0; m < 2; m++) { + + if (grid2->height >= MAX_GRID_SIZE) + break; + if (m) offset2 = grid2->width-1; + else offset2 = 0; + for ( l = 0; l < grid2->height-1; l++) { + // + v1 = grid1->verts[grid1->width * k + offset1].xyz; + v2 = grid2->verts[grid2->width * l + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + + v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) > .1) + continue; + if ( fabs(v1[1] - v2[1]) > .1) + continue; + if ( fabs(v1[2] - v2[2]) > .1) + continue; + // + v1 = grid2->verts[grid2->width * l + offset2].xyz; + v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; + if ( fabs(v1[0] - v2[0]) < .01 && + fabs(v1[1] - v2[1]) < .01 && + fabs(v1[2] - v2[2]) < .01) + continue; + // + //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); + // insert row into grid2 right after after row l + if (m) column = grid2->width-1; + else column = 0; + grid2 = R_GridInsertRow( grid2, l+1, column, + grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); + grid2->lodStitched = qfalse; + s_worldData.surfaces[grid2num].data = (void *) grid2; + return qtrue; + } + } + } + } + return qfalse; +} + +/* +=============== +R_TryStitchPatch + +This function will try to stitch patches in the same LoD group together for the highest LoD. + +Only single missing vertice cracks will be fixed. + +Vertices will be joined at the patch side a crack is first found, at the other side +of the patch (on the same row or column) the vertices will not be joined and cracks +might still appear at that side. +=============== +*/ +int R_TryStitchingPatch( int grid1num ) { + int j, numstitches; + srfGridMesh_t *grid1, *grid2; + + numstitches = 0; + grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; + for ( j = 0; j < s_worldData.numsurfaces; j++ ) { + // + grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; + // if this surface is not a grid + if ( grid2->surfaceType != SF_GRID ) continue; + // grids in the same LOD group should have the exact same lod radius + if ( grid1->lodRadius != grid2->lodRadius ) continue; + // grids in the same LOD group should have the exact same lod origin + if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; + if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; + if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; + // + while (R_StitchPatches(grid1num, j)) + { + numstitches++; + } + } + return numstitches; +} + +/* +=============== +R_StitchAllPatches +=============== +*/ +void R_StitchAllPatches( void ) { + int i, stitched, numstitches; + srfGridMesh_t *grid1; + + numstitches = 0; + do + { + stitched = qfalse; + for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + // + grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; + // if this surface is not a grid + if ( grid1->surfaceType != SF_GRID ) + continue; + // + if ( grid1->lodStitched ) + continue; + // + grid1->lodStitched = qtrue; + stitched = qtrue; + // + numstitches += R_TryStitchingPatch( i ); + } + } + while (stitched); + ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); +} + +/* +=============== +R_MovePatchSurfacesToHunk +=============== +*/ +void R_MovePatchSurfacesToHunk(void) { + int i, size; + srfGridMesh_t *grid, *hunkgrid; + + for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + // + grid = (srfGridMesh_t *) s_worldData.surfaces[i].data; + // if this surface is not a grid + if ( grid->surfaceType != SF_GRID ) + continue; + // + size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); + hunkgrid = ri.Hunk_Alloc( size, h_low ); + Com_Memcpy(hunkgrid, grid, size); + + hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); + Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); + + hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); + Com_Memcpy( grid->heightLodError, grid->heightLodError, grid->height * 4 ); + + R_FreeSurfaceGridMesh( grid ); + + s_worldData.surfaces[i].data = (void *) hunkgrid; + } +} + +/* +=============== +R_LoadSurfaces +=============== +*/ +static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { + dsurface_t *in; + msurface_t *out; + drawVert_t *dv; + int *indexes; + int count; + int numFaces, numMeshes, numTriSurfs, numFlares; + int i; + + numFaces = 0; + numMeshes = 0; + numTriSurfs = 0; + numFlares = 0; + + in = (void *)(fileBase + surfs->fileofs); + if (surfs->filelen % sizeof(*in)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + count = surfs->filelen / sizeof(*in); + + dv = (void *)(fileBase + verts->fileofs); + if (verts->filelen % sizeof(*dv)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + + indexes = (void *)(fileBase + indexLump->fileofs); + if ( indexLump->filelen % sizeof(*indexes)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + + out = ri.Hunk_Alloc ( count * sizeof(*out), h_low ); + + s_worldData.surfaces = out; + s_worldData.numsurfaces = count; + + for ( i = 0 ; i < count ; i++, in++, out++ ) { + switch ( LittleLong( in->surfaceType ) ) { + case MST_PATCH: + ParseMesh ( in, dv, out ); + numMeshes++; + break; + case MST_TRIANGLE_SOUP: + ParseTriSurf( in, dv, out, indexes ); + numTriSurfs++; + break; + case MST_PLANAR: + ParseFace( in, dv, out, indexes ); + numFaces++; + break; + case MST_FLARE: + ParseFlare( in, dv, out, indexes ); + numFlares++; + break; + default: + ri.Error( ERR_DROP, "Bad surfaceType" ); + } + } + +#ifdef PATCH_STITCHING + R_StitchAllPatches(); +#endif + + R_FixSharedVertexLodError(); + +#ifdef PATCH_STITCHING + R_MovePatchSurfacesToHunk(); +#endif + + ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", + numFaces, numMeshes, numTriSurfs, numFlares ); +} + + + +/* +================= +R_LoadSubmodels +================= +*/ +static void R_LoadSubmodels( lump_t *l ) { + dmodel_t *in; + bmodel_t *out; + int i, j, count; + + in = (void *)(fileBase + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + count = l->filelen / sizeof(*in); + + s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low ); + + for ( i=0 ; i<count ; i++, in++, out++ ) { + model_t *model; + + model = R_AllocModel(); + + assert( model != NULL ); // this should never happen + + model->type = MOD_BRUSH; + model->bmodel = out; + Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); + + for (j=0 ; j<3 ; j++) { + out->bounds[0][j] = LittleFloat (in->mins[j]); + out->bounds[1][j] = LittleFloat (in->maxs[j]); + } + + out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface ); + out->numSurfaces = LittleLong( in->numSurfaces ); + } +} + + + +//================================================================== + +/* +================= +R_SetParent +================= +*/ +static void R_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents != -1) + return; + R_SetParent (node->children[0], node); + R_SetParent (node->children[1], node); +} + +/* +================= +R_LoadNodesAndLeafs +================= +*/ +static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { + int i, j, p; + dnode_t *in; + dleaf_t *inLeaf; + mnode_t *out; + int numNodes, numLeafs; + + in = (void *)(fileBase + nodeLump->fileofs); + if (nodeLump->filelen % sizeof(dnode_t) || + leafLump->filelen % sizeof(dleaf_t) ) { + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + } + numNodes = nodeLump->filelen / sizeof(dnode_t); + numLeafs = leafLump->filelen / sizeof(dleaf_t); + + out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); + + s_worldData.nodes = out; + s_worldData.numnodes = numNodes + numLeafs; + s_worldData.numDecisionNodes = numNodes; + + // load nodes + for ( i=0 ; i<numNodes; i++, in++, out++) + { + for (j=0 ; j<3 ; j++) + { + out->mins[j] = LittleLong (in->mins[j]); + out->maxs[j] = LittleLong (in->maxs[j]); + } + + p = LittleLong(in->planeNum); + out->plane = s_worldData.planes + p; + + out->contents = CONTENTS_NODE; // differentiate from leafs + + for (j=0 ; j<2 ; j++) + { + p = LittleLong (in->children[j]); + if (p >= 0) + out->children[j] = s_worldData.nodes + p; + else + out->children[j] = s_worldData.nodes + numNodes + (-1 - p); + } + } + + // load leafs + inLeaf = (void *)(fileBase + leafLump->fileofs); + for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++) + { + for (j=0 ; j<3 ; j++) + { + out->mins[j] = LittleLong (inLeaf->mins[j]); + out->maxs[j] = LittleLong (inLeaf->maxs[j]); + } + + out->cluster = LittleLong(inLeaf->cluster); + out->area = LittleLong(inLeaf->area); + + if ( out->cluster >= s_worldData.numClusters ) { + s_worldData.numClusters = out->cluster + 1; + } + + out->firstmarksurface = s_worldData.marksurfaces + + LittleLong(inLeaf->firstLeafSurface); + out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); + } + + // chain decendants + R_SetParent (s_worldData.nodes, NULL); +} + +//============================================================================= + +/* +================= +R_LoadShaders +================= +*/ +static void R_LoadShaders( lump_t *l ) { + int i, count; + dshader_t *in, *out; + + in = (void *)(fileBase + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + count = l->filelen / sizeof(*in); + out = ri.Hunk_Alloc ( count*sizeof(*out), h_low ); + + s_worldData.shaders = out; + s_worldData.numShaders = count; + + Com_Memcpy( out, in, count*sizeof(*out) ); + + for ( i=0 ; i<count ; i++ ) { + out[i].surfaceFlags = LittleLong( out[i].surfaceFlags ); + out[i].contentFlags = LittleLong( out[i].contentFlags ); + } +} + + +/* +================= +R_LoadMarksurfaces +================= +*/ +static void R_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + int *in; + msurface_t **out; + + in = (void *)(fileBase + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + count = l->filelen / sizeof(*in); + out = ri.Hunk_Alloc ( count*sizeof(*out), h_low); + + s_worldData.marksurfaces = out; + s_worldData.nummarksurfaces = count; + + for ( i=0 ; i<count ; i++) + { + j = LittleLong(in[i]); + out[i] = s_worldData.surfaces + j; + } +} + + +/* +================= +R_LoadPlanes +================= +*/ +static void R_LoadPlanes( lump_t *l ) { + int i, j; + cplane_t *out; + dplane_t *in; + int count; + int bits; + + in = (void *)(fileBase + l->fileofs); + if (l->filelen % sizeof(*in)) + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + count = l->filelen / sizeof(*in); + out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); + + s_worldData.planes = out; + s_worldData.numplanes = count; + + for ( i=0 ; i<count ; i++, in++, out++) { + bits = 0; + for (j=0 ; j<3 ; j++) { + out->normal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) { + bits |= 1<<j; + } + } + + out->dist = LittleFloat (in->dist); + out->type = PlaneTypeForNormal( out->normal ); + out->signbits = bits; + } +} + +/* +================= +R_LoadFogs + +================= +*/ +static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) { + int i; + fog_t *out; + dfog_t *fogs; + dbrush_t *brushes, *brush; + dbrushside_t *sides; + int count, brushesCount, sidesCount; + int sideNum; + int planeNum; + shader_t *shader; + float d; + int firstSide; + + fogs = (void *)(fileBase + l->fileofs); + if (l->filelen % sizeof(*fogs)) { + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + } + count = l->filelen / sizeof(*fogs); + + // create fog strucutres for them + s_worldData.numfogs = count + 1; + s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low); + out = s_worldData.fogs + 1; + + if ( !count ) { + return; + } + + brushes = (void *)(fileBase + brushesLump->fileofs); + if (brushesLump->filelen % sizeof(*brushes)) { + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + } + brushesCount = brushesLump->filelen / sizeof(*brushes); + + sides = (void *)(fileBase + sidesLump->fileofs); + if (sidesLump->filelen % sizeof(*sides)) { + ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); + } + sidesCount = sidesLump->filelen / sizeof(*sides); + + for ( i=0 ; i<count ; i++, fogs++) { + out->originalBrushNumber = LittleLong( fogs->brushNum ); + + if ( (unsigned)out->originalBrushNumber >= brushesCount ) { + ri.Error( ERR_DROP, "fog brushNumber out of range" ); + } + brush = brushes + out->originalBrushNumber; + + firstSide = LittleLong( brush->firstSide ); + + if ( (unsigned)firstSide > sidesCount - 6 ) { + ri.Error( ERR_DROP, "fog brush sideNumber out of range" ); + } + + // brushes are always sorted with the axial sides first + sideNum = firstSide + 0; + planeNum = LittleLong( sides[ sideNum ].planeNum ); + out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist; + + sideNum = firstSide + 1; + planeNum = LittleLong( sides[ sideNum ].planeNum ); + out->bounds[1][0] = s_worldData.planes[ planeNum ].dist; + + sideNum = firstSide + 2; + planeNum = LittleLong( sides[ sideNum ].planeNum ); + out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist; + + sideNum = firstSide + 3; + planeNum = LittleLong( sides[ sideNum ].planeNum ); + out->bounds[1][1] = s_worldData.planes[ planeNum ].dist; + + sideNum = firstSide + 4; + planeNum = LittleLong( sides[ sideNum ].planeNum ); + out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist; + + sideNum = firstSide + 5; + planeNum = LittleLong( sides[ sideNum ].planeNum ); + out->bounds[1][2] = s_worldData.planes[ planeNum ].dist; + + // get information from the shader for fog parameters + shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue ); + + out->parms = shader->fogParms; + + out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, + shader->fogParms.color[1] * tr.identityLight, + shader->fogParms.color[2] * tr.identityLight, 1.0 ); + + d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; + out->tcScale = 1.0f / ( d * 8 ); + + // set the gradient vector + sideNum = LittleLong( fogs->visibleSide ); + + if ( sideNum == -1 ) { + out->hasSurface = qfalse; + } else { + out->hasSurface = qtrue; + planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum ); + VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface ); + out->surface[3] = -s_worldData.planes[ planeNum ].dist; + } + + out++; + } + +} + + +/* +================ +R_LoadLightGrid + +================ +*/ +void R_LoadLightGrid( lump_t *l ) { + int i; + vec3_t maxs; + int numGridPoints; + world_t *w; + float *wMins, *wMaxs; + + w = &s_worldData; + + w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0]; + w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1]; + w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2]; + + wMins = w->bmodels[0].bounds[0]; + wMaxs = w->bmodels[0].bounds[1]; + + for ( i = 0 ; i < 3 ; i++ ) { + w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); + maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); + w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1; + } + + numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; + + if ( l->filelen != numGridPoints * 8 ) { + ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" ); + w->lightGridData = NULL; + return; + } + + w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low ); + Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen ); + + // deal with overbright bits + for ( i = 0 ; i < numGridPoints ; i++ ) { + R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] ); + R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] ); + } +} + +/* +================ +R_LoadEntities +================ +*/ +void R_LoadEntities( lump_t *l ) { + char *p, *token, *s; + char keyname[MAX_TOKEN_CHARS]; + char value[MAX_TOKEN_CHARS]; + world_t *w; + + w = &s_worldData; + w->lightGridSize[0] = 64; + w->lightGridSize[1] = 64; + w->lightGridSize[2] = 128; + + p = (char *)(fileBase + l->fileofs); + + // store for reference by the cgame + w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low ); + strcpy( w->entityString, p ); + w->entityParsePoint = w->entityString; + + token = COM_ParseExt( &p, qtrue ); + if (!*token || *token != '{') { + return; + } + + // only parse the world spawn + while ( 1 ) { + // parse key + token = COM_ParseExt( &p, qtrue ); + + if ( !*token || *token == '}' ) { + break; + } + Q_strncpyz(keyname, token, sizeof(keyname)); + + // parse value + token = COM_ParseExt( &p, qtrue ); + + if ( !*token || *token == '}' ) { + break; + } + Q_strncpyz(value, token, sizeof(value)); + + // check for remapping of shaders for vertex lighting + s = "vertexremapshader"; + if (!Q_strncmp(keyname, s, strlen(s)) ) { + s = strchr(value, ';'); + if (!s) { + ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value ); + break; + } + *s++ = 0; + if (r_vertexLight->integer) { + R_RemapShader(value, s, "0"); + } + continue; + } + // check for remapping of shaders + s = "remapshader"; + if (!Q_strncmp(keyname, s, strlen(s)) ) { + s = strchr(value, ';'); + if (!s) { + ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value ); + break; + } + *s++ = 0; + R_RemapShader(value, s, "0"); + continue; + } + // check for a different grid size + if (!Q_stricmp(keyname, "gridsize")) { + sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] ); + continue; + } + } +} + +/* +================= +R_GetEntityToken +================= +*/ +qboolean R_GetEntityToken( char *buffer, int size ) { + const char *s; + + s = COM_Parse( &s_worldData.entityParsePoint ); + Q_strncpyz( buffer, s, size ); + if ( !s_worldData.entityParsePoint || !s[0] ) { + s_worldData.entityParsePoint = s_worldData.entityString; + return qfalse; + } else { + return qtrue; + } +} + +/* +================= +RE_LoadWorldMap + +Called directly from cgame +================= +*/ +void RE_LoadWorldMap( const char *name ) { + int i; + dheader_t *header; + byte *buffer; + byte *startMarker; + + if ( tr.worldMapLoaded ) { + ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" ); + } + + // set default sun direction to be used if it isn't + // overridden by a shader + tr.sunDirection[0] = 0.45f; + tr.sunDirection[1] = 0.3f; + tr.sunDirection[2] = 0.9f; + + VectorNormalize( tr.sunDirection ); + + tr.worldMapLoaded = qtrue; + + // load it + ri.FS_ReadFile( name, (void **)&buffer ); + if ( !buffer ) { + ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name); + } + + // clear tr.world so if the level fails to load, the next + // try will not look at the partially loaded version + tr.world = NULL; + + Com_Memset( &s_worldData, 0, sizeof( s_worldData ) ); + Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); + + Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) ); + COM_StripExtension( s_worldData.baseName, s_worldData.baseName ); + + startMarker = ri.Hunk_Alloc(0, h_low); + c_gridVerts = 0; + + header = (dheader_t *)buffer; + fileBase = (byte *)header; + + i = LittleLong (header->version); + if ( i != BSP_VERSION ) { + ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", + name, i, BSP_VERSION); + } + + // swap all the lumps + for (i=0 ; i<sizeof(dheader_t)/4 ; i++) { + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + } + + // load into heap + R_LoadShaders( &header->lumps[LUMP_SHADERS] ); + R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] ); + R_LoadPlanes (&header->lumps[LUMP_PLANES]); + R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] ); + R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] ); + R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]); + R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]); + R_LoadSubmodels (&header->lumps[LUMP_MODELS]); + R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] ); + R_LoadEntities( &header->lumps[LUMP_ENTITIES] ); + R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); + + s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; + + // only set tr.world now that we know the entire level has loaded properly + tr.world = &s_worldData; + + ri.FS_FreeFile( buffer ); +} + diff --git a/code/renderer/tr_cmds.c b/code/renderer/tr_cmds.c index 3808dc3..33f43cc 100755 --- a/code/renderer/tr_cmds.c +++ b/code/renderer/tr_cmds.c @@ -1,447 +1,447 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-volatile renderCommandList_t *renderCommandList;
-
-volatile qboolean renderThreadActive;
-
-
-/*
-=====================
-R_PerformanceCounters
-=====================
-*/
-void R_PerformanceCounters( void ) {
- if ( !r_speeds->integer ) {
- // clear the counters even if we aren't printing
- Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
- Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
- return;
- }
-
- if (r_speeds->integer == 1) {
- ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
- backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
- backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
- R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
- } else if (r_speeds->integer == 2) {
- ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
- tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
- tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
- ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
- tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
- tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
- } else if (r_speeds->integer == 3) {
- ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
- } else if (r_speeds->integer == 4) {
- if ( backEnd.pc.c_dlightVertexes ) {
- ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
- tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
- backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
- }
- }
- else if (r_speeds->integer == 5 )
- {
- ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
- }
- else if (r_speeds->integer == 6 )
- {
- ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n",
- backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
- }
-
- Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
- Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
-}
-
-
-/*
-====================
-R_InitCommandBuffers
-====================
-*/
-void R_InitCommandBuffers( void ) {
- glConfig.smpActive = qfalse;
- if ( r_smp->integer ) {
- ri.Printf( PRINT_ALL, "Trying SMP acceleration...\n" );
- if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) {
- ri.Printf( PRINT_ALL, "...succeeded.\n" );
- glConfig.smpActive = qtrue;
- } else {
- ri.Printf( PRINT_ALL, "...failed.\n" );
- }
- }
-}
-
-/*
-====================
-R_ShutdownCommandBuffers
-====================
-*/
-void R_ShutdownCommandBuffers( void ) {
- // kill the rendering thread
- if ( glConfig.smpActive ) {
- GLimp_WakeRenderer( NULL );
- glConfig.smpActive = qfalse;
- }
-}
-
-/*
-====================
-R_IssueRenderCommands
-====================
-*/
-int c_blockedOnRender;
-int c_blockedOnMain;
-
-void R_IssueRenderCommands( qboolean runPerformanceCounters ) {
- renderCommandList_t *cmdList;
-
- cmdList = &backEndData[tr.smpFrame]->commands;
- assert(cmdList); // bk001205
- // add an end-of-list command
- *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
-
- // clear it out, in case this is a sync and not a buffer flip
- cmdList->used = 0;
-
- if ( glConfig.smpActive ) {
- // if the render thread is not idle, wait for it
- if ( renderThreadActive ) {
- c_blockedOnRender++;
- if ( r_showSmp->integer ) {
- ri.Printf( PRINT_ALL, "R" );
- }
- } else {
- c_blockedOnMain++;
- if ( r_showSmp->integer ) {
- ri.Printf( PRINT_ALL, "." );
- }
- }
-
- // sleep until the renderer has completed
- GLimp_FrontEndSleep();
- }
-
- // at this point, the back end thread is idle, so it is ok
- // to look at it's performance counters
- if ( runPerformanceCounters ) {
- R_PerformanceCounters();
- }
-
- // actually start the commands going
- if ( !r_skipBackEnd->integer ) {
- // let it start on the new batch
- if ( !glConfig.smpActive ) {
- RB_ExecuteRenderCommands( cmdList->cmds );
- } else {
- GLimp_WakeRenderer( cmdList );
- }
- }
-}
-
-
-/*
-====================
-R_SyncRenderThread
-
-Issue any pending commands and wait for them to complete.
-After exiting, the render thread will have completed its work
-and will remain idle and the main thread is free to issue
-OpenGL calls until R_IssueRenderCommands is called.
-====================
-*/
-void R_SyncRenderThread( void ) {
- if ( !tr.registered ) {
- return;
- }
- R_IssueRenderCommands( qfalse );
-
- if ( !glConfig.smpActive ) {
- return;
- }
- GLimp_FrontEndSleep();
-}
-
-/*
-============
-R_GetCommandBuffer
-
-make sure there is enough command space, waiting on the
-render thread if needed.
-============
-*/
-void *R_GetCommandBuffer( int bytes ) {
- renderCommandList_t *cmdList;
-
- cmdList = &backEndData[tr.smpFrame]->commands;
-
- // always leave room for the end of list command
- if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
- if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
- ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
- }
- // if we run out of room, just start dropping commands
- return NULL;
- }
-
- cmdList->used += bytes;
-
- return cmdList->cmds + cmdList->used - bytes;
-}
-
-
-/*
-=============
-R_AddDrawSurfCmd
-
-=============
-*/
-void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
- drawSurfsCommand_t *cmd;
-
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_DRAW_SURFS;
-
- cmd->drawSurfs = drawSurfs;
- cmd->numDrawSurfs = numDrawSurfs;
-
- cmd->refdef = tr.refdef;
- cmd->viewParms = tr.viewParms;
-}
-
-
-/*
-=============
-RE_SetColor
-
-Passing NULL will set the color to white
-=============
-*/
-void RE_SetColor( const float *rgba ) {
- setColorCommand_t *cmd;
-
- if ( !tr.registered ) {
- return;
- }
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_SET_COLOR;
- if ( !rgba ) {
- static float colorWhite[4] = { 1, 1, 1, 1 };
-
- rgba = colorWhite;
- }
-
- cmd->color[0] = rgba[0];
- cmd->color[1] = rgba[1];
- cmd->color[2] = rgba[2];
- cmd->color[3] = rgba[3];
-}
-
-
-/*
-=============
-RE_StretchPic
-=============
-*/
-void RE_StretchPic ( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ) {
- stretchPicCommand_t *cmd;
-
- if (!tr.registered) {
- return;
- }
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_STRETCH_PIC;
- cmd->shader = R_GetShaderByHandle( hShader );
- cmd->x = x;
- cmd->y = y;
- cmd->w = w;
- cmd->h = h;
- cmd->s1 = s1;
- cmd->t1 = t1;
- cmd->s2 = s2;
- cmd->t2 = t2;
-}
-
-
-/*
-====================
-RE_BeginFrame
-
-If running in stereo, RE_BeginFrame will be called twice
-for each RE_EndFrame
-====================
-*/
-void RE_BeginFrame( stereoFrame_t stereoFrame ) {
- drawBufferCommand_t *cmd;
-
- if ( !tr.registered ) {
- return;
- }
- glState.finishCalled = qfalse;
-
- tr.frameCount++;
- tr.frameSceneNum = 0;
-
- //
- // do overdraw measurement
- //
- if ( r_measureOverdraw->integer )
- {
- if ( glConfig.stencilBits < 4 )
- {
- ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
- ri.Cvar_Set( "r_measureOverdraw", "0" );
- r_measureOverdraw->modified = qfalse;
- }
- else if ( r_shadows->integer == 2 )
- {
- ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
- ri.Cvar_Set( "r_measureOverdraw", "0" );
- r_measureOverdraw->modified = qfalse;
- }
- else
- {
- R_SyncRenderThread();
- qglEnable( GL_STENCIL_TEST );
- qglStencilMask( ~0U );
- qglClearStencil( 0U );
- qglStencilFunc( GL_ALWAYS, 0U, ~0U );
- qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
- }
- r_measureOverdraw->modified = qfalse;
- }
- else
- {
- // this is only reached if it was on and is now off
- if ( r_measureOverdraw->modified ) {
- R_SyncRenderThread();
- qglDisable( GL_STENCIL_TEST );
- }
- r_measureOverdraw->modified = qfalse;
- }
-
- //
- // texturemode stuff
- //
- if ( r_textureMode->modified ) {
- R_SyncRenderThread();
- GL_TextureMode( r_textureMode->string );
- r_textureMode->modified = qfalse;
- }
-
- //
- // gamma stuff
- //
- if ( r_gamma->modified ) {
- r_gamma->modified = qfalse;
-
- R_SyncRenderThread();
- R_SetColorMappings();
- }
-
- // check for errors
- if ( !r_ignoreGLErrors->integer ) {
- int err;
-
- R_SyncRenderThread();
- if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
- ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err );
- }
- }
-
- //
- // draw buffer stuff
- //
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_DRAW_BUFFER;
-
- if ( glConfig.stereoEnabled ) {
- if ( stereoFrame == STEREO_LEFT ) {
- cmd->buffer = (int)GL_BACK_LEFT;
- } else if ( stereoFrame == STEREO_RIGHT ) {
- cmd->buffer = (int)GL_BACK_RIGHT;
- } else {
- ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
- }
- } else {
- if ( stereoFrame != STEREO_CENTER ) {
- ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
- }
- if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
- cmd->buffer = (int)GL_FRONT;
- } else {
- cmd->buffer = (int)GL_BACK;
- }
- }
-}
-
-
-/*
-=============
-RE_EndFrame
-
-Returns the number of msec spent in the back end
-=============
-*/
-void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
- swapBuffersCommand_t *cmd;
-
- if ( !tr.registered ) {
- return;
- }
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_SWAP_BUFFERS;
-
- R_IssueRenderCommands( qtrue );
-
- // use the other buffers next frame, because another CPU
- // may still be rendering into the current ones
- R_ToggleSmpFrame();
-
- if ( frontEndMsec ) {
- *frontEndMsec = tr.frontEndMsec;
- }
- tr.frontEndMsec = 0;
- if ( backEndMsec ) {
- *backEndMsec = backEnd.pc.msec;
- }
- backEnd.pc.msec = 0;
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "tr_local.h" + +volatile renderCommandList_t *renderCommandList; + +volatile qboolean renderThreadActive; + + +/* +===================== +R_PerformanceCounters +===================== +*/ +void R_PerformanceCounters( void ) { + if ( !r_speeds->integer ) { + // clear the counters even if we aren't printing + Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); + Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); + return; + } + + if (r_speeds->integer == 1) { + ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n", + backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, + backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, + R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) ); + } else if (r_speeds->integer == 2) { + ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", + tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, + tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out ); + ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", + tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, + tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out ); + } else if (r_speeds->integer == 3) { + ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster ); + } else if (r_speeds->integer == 4) { + if ( backEnd.pc.c_dlightVertexes ) { + ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n", + tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled, + backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 ); + } + } + else if (r_speeds->integer == 5 ) + { + ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar ); + } + else if (r_speeds->integer == 6 ) + { + ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", + backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders ); + } + + Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); + Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); +} + + +/* +==================== +R_InitCommandBuffers +==================== +*/ +void R_InitCommandBuffers( void ) { + glConfig.smpActive = qfalse; + if ( r_smp->integer ) { + ri.Printf( PRINT_ALL, "Trying SMP acceleration...\n" ); + if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) { + ri.Printf( PRINT_ALL, "...succeeded.\n" ); + glConfig.smpActive = qtrue; + } else { + ri.Printf( PRINT_ALL, "...failed.\n" ); + } + } +} + +/* +==================== +R_ShutdownCommandBuffers +==================== +*/ +void R_ShutdownCommandBuffers( void ) { + // kill the rendering thread + if ( glConfig.smpActive ) { + GLimp_WakeRenderer( NULL ); + glConfig.smpActive = qfalse; + } +} + +/* +==================== +R_IssueRenderCommands +==================== +*/ +int c_blockedOnRender; +int c_blockedOnMain; + +void R_IssueRenderCommands( qboolean runPerformanceCounters ) { + renderCommandList_t *cmdList; + + cmdList = &backEndData[tr.smpFrame]->commands; + assert(cmdList); // bk001205 + // add an end-of-list command + *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; + + // clear it out, in case this is a sync and not a buffer flip + cmdList->used = 0; + + if ( glConfig.smpActive ) { + // if the render thread is not idle, wait for it + if ( renderThreadActive ) { + c_blockedOnRender++; + if ( r_showSmp->integer ) { + ri.Printf( PRINT_ALL, "R" ); + } + } else { + c_blockedOnMain++; + if ( r_showSmp->integer ) { + ri.Printf( PRINT_ALL, "." ); + } + } + + // sleep until the renderer has completed + GLimp_FrontEndSleep(); + } + + // at this point, the back end thread is idle, so it is ok + // to look at it's performance counters + if ( runPerformanceCounters ) { + R_PerformanceCounters(); + } + + // actually start the commands going + if ( !r_skipBackEnd->integer ) { + // let it start on the new batch + if ( !glConfig.smpActive ) { + RB_ExecuteRenderCommands( cmdList->cmds ); + } else { + GLimp_WakeRenderer( cmdList ); + } + } +} + + +/* +==================== +R_SyncRenderThread + +Issue any pending commands and wait for them to complete. +After exiting, the render thread will have completed its work +and will remain idle and the main thread is free to issue +OpenGL calls until R_IssueRenderCommands is called. +==================== +*/ +void R_SyncRenderThread( void ) { + if ( !tr.registered ) { + return; + } + R_IssueRenderCommands( qfalse ); + + if ( !glConfig.smpActive ) { + return; + } + GLimp_FrontEndSleep(); +} + +/* +============ +R_GetCommandBuffer + +make sure there is enough command space, waiting on the +render thread if needed. +============ +*/ +void *R_GetCommandBuffer( int bytes ) { + renderCommandList_t *cmdList; + + cmdList = &backEndData[tr.smpFrame]->commands; + + // always leave room for the end of list command + if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { + if ( bytes > MAX_RENDER_COMMANDS - 4 ) { + ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); + } + // if we run out of room, just start dropping commands + return NULL; + } + + cmdList->used += bytes; + + return cmdList->cmds + cmdList->used - bytes; +} + + +/* +============= +R_AddDrawSurfCmd + +============= +*/ +void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { + drawSurfsCommand_t *cmd; + + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_DRAW_SURFS; + + cmd->drawSurfs = drawSurfs; + cmd->numDrawSurfs = numDrawSurfs; + + cmd->refdef = tr.refdef; + cmd->viewParms = tr.viewParms; +} + + +/* +============= +RE_SetColor + +Passing NULL will set the color to white +============= +*/ +void RE_SetColor( const float *rgba ) { + setColorCommand_t *cmd; + + if ( !tr.registered ) { + return; + } + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_SET_COLOR; + if ( !rgba ) { + static float colorWhite[4] = { 1, 1, 1, 1 }; + + rgba = colorWhite; + } + + cmd->color[0] = rgba[0]; + cmd->color[1] = rgba[1]; + cmd->color[2] = rgba[2]; + cmd->color[3] = rgba[3]; +} + + +/* +============= +RE_StretchPic +============= +*/ +void RE_StretchPic ( float x, float y, float w, float h, + float s1, float t1, float s2, float t2, qhandle_t hShader ) { + stretchPicCommand_t *cmd; + + if (!tr.registered) { + return; + } + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_STRETCH_PIC; + cmd->shader = R_GetShaderByHandle( hShader ); + cmd->x = x; + cmd->y = y; + cmd->w = w; + cmd->h = h; + cmd->s1 = s1; + cmd->t1 = t1; + cmd->s2 = s2; + cmd->t2 = t2; +} + + +/* +==================== +RE_BeginFrame + +If running in stereo, RE_BeginFrame will be called twice +for each RE_EndFrame +==================== +*/ +void RE_BeginFrame( stereoFrame_t stereoFrame ) { + drawBufferCommand_t *cmd; + + if ( !tr.registered ) { + return; + } + glState.finishCalled = qfalse; + + tr.frameCount++; + tr.frameSceneNum = 0; + + // + // do overdraw measurement + // + if ( r_measureOverdraw->integer ) + { + if ( glConfig.stencilBits < 4 ) + { + ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits ); + ri.Cvar_Set( "r_measureOverdraw", "0" ); + r_measureOverdraw->modified = qfalse; + } + else if ( r_shadows->integer == 2 ) + { + ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" ); + ri.Cvar_Set( "r_measureOverdraw", "0" ); + r_measureOverdraw->modified = qfalse; + } + else + { + R_SyncRenderThread(); + qglEnable( GL_STENCIL_TEST ); + qglStencilMask( ~0U ); + qglClearStencil( 0U ); + qglStencilFunc( GL_ALWAYS, 0U, ~0U ); + qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); + } + r_measureOverdraw->modified = qfalse; + } + else + { + // this is only reached if it was on and is now off + if ( r_measureOverdraw->modified ) { + R_SyncRenderThread(); + qglDisable( GL_STENCIL_TEST ); + } + r_measureOverdraw->modified = qfalse; + } + + // + // texturemode stuff + // + if ( r_textureMode->modified ) { + R_SyncRenderThread(); + GL_TextureMode( r_textureMode->string ); + r_textureMode->modified = qfalse; + } + + // + // gamma stuff + // + if ( r_gamma->modified ) { + r_gamma->modified = qfalse; + + R_SyncRenderThread(); + R_SetColorMappings(); + } + + // check for errors + if ( !r_ignoreGLErrors->integer ) { + int err; + + R_SyncRenderThread(); + if ( ( err = qglGetError() ) != GL_NO_ERROR ) { + ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err ); + } + } + + // + // draw buffer stuff + // + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_DRAW_BUFFER; + + if ( glConfig.stereoEnabled ) { + if ( stereoFrame == STEREO_LEFT ) { + cmd->buffer = (int)GL_BACK_LEFT; + } else if ( stereoFrame == STEREO_RIGHT ) { + cmd->buffer = (int)GL_BACK_RIGHT; + } else { + ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); + } + } else { + if ( stereoFrame != STEREO_CENTER ) { + ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame ); + } + if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) { + cmd->buffer = (int)GL_FRONT; + } else { + cmd->buffer = (int)GL_BACK; + } + } +} + + +/* +============= +RE_EndFrame + +Returns the number of msec spent in the back end +============= +*/ +void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { + swapBuffersCommand_t *cmd; + + if ( !tr.registered ) { + return; + } + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_SWAP_BUFFERS; + + R_IssueRenderCommands( qtrue ); + + // use the other buffers next frame, because another CPU + // may still be rendering into the current ones + R_ToggleSmpFrame(); + + if ( frontEndMsec ) { + *frontEndMsec = tr.frontEndMsec; + } + tr.frontEndMsec = 0; + if ( backEndMsec ) { + *backEndMsec = backEnd.pc.msec; + } + backEnd.pc.msec = 0; +} + diff --git a/code/renderer/tr_curve.c b/code/renderer/tr_curve.c index 91a9e62..14db39a 100755 --- a/code/renderer/tr_curve.c +++ b/code/renderer/tr_curve.c @@ -1,624 +1,624 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-/*
-
-This file does all of the processing necessary to turn a raw grid of points
-read from the map file into a srfGridMesh_t ready for rendering.
-
-The level of detail solution is direction independent, based only on subdivided
-distance from the true curve.
-
-Only a single entry point:
-
-srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
-
-*/
-
-
-/*
-============
-LerpDrawVert
-============
-*/
-static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
- out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
- out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
- out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
-
- out->st[0] = 0.5f * (a->st[0] + b->st[0]);
- out->st[1] = 0.5f * (a->st[1] + b->st[1]);
-
- out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
- out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
-
- out->color[0] = (a->color[0] + b->color[0]) >> 1;
- out->color[1] = (a->color[1] + b->color[1]) >> 1;
- out->color[2] = (a->color[2] + b->color[2]) >> 1;
- out->color[3] = (a->color[3] + b->color[3]) >> 1;
-}
-
-/*
-============
-Transpose
-============
-*/
-static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
- int i, j;
- drawVert_t temp;
-
- if ( width > height ) {
- for ( i = 0 ; i < height ; i++ ) {
- for ( j = i + 1 ; j < width ; j++ ) {
- if ( j < height ) {
- // swap the value
- temp = ctrl[j][i];
- ctrl[j][i] = ctrl[i][j];
- ctrl[i][j] = temp;
- } else {
- // just copy
- ctrl[j][i] = ctrl[i][j];
- }
- }
- }
- } else {
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = i + 1 ; j < height ; j++ ) {
- if ( j < width ) {
- // swap the value
- temp = ctrl[i][j];
- ctrl[i][j] = ctrl[j][i];
- ctrl[j][i] = temp;
- } else {
- // just copy
- ctrl[i][j] = ctrl[j][i];
- }
- }
- }
- }
-
-}
-
-
-/*
-=================
-MakeMeshNormals
-
-Handles all the complicated wrapping and degenerate cases
-=================
-*/
-static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
- int i, j, k, dist;
- vec3_t normal;
- vec3_t sum;
- int count;
- vec3_t base;
- vec3_t delta;
- int x, y;
- drawVert_t *dv;
- vec3_t around[8], temp;
- qboolean good[8];
- qboolean wrapWidth, wrapHeight;
- float len;
-static int neighbors[8][2] = {
- {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
- };
-
- wrapWidth = qfalse;
- for ( i = 0 ; i < height ; i++ ) {
- VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
- len = VectorLengthSquared( delta );
- if ( len > 1.0 ) {
- break;
- }
- }
- if ( i == height ) {
- wrapWidth = qtrue;
- }
-
- wrapHeight = qfalse;
- for ( i = 0 ; i < width ; i++ ) {
- VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
- len = VectorLengthSquared( delta );
- if ( len > 1.0 ) {
- break;
- }
- }
- if ( i == width) {
- wrapHeight = qtrue;
- }
-
-
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- count = 0;
- dv = &ctrl[j][i];
- VectorCopy( dv->xyz, base );
- for ( k = 0 ; k < 8 ; k++ ) {
- VectorClear( around[k] );
- good[k] = qfalse;
-
- for ( dist = 1 ; dist <= 3 ; dist++ ) {
- x = i + neighbors[k][0] * dist;
- y = j + neighbors[k][1] * dist;
- if ( wrapWidth ) {
- if ( x < 0 ) {
- x = width - 1 + x;
- } else if ( x >= width ) {
- x = 1 + x - width;
- }
- }
- if ( wrapHeight ) {
- if ( y < 0 ) {
- y = height - 1 + y;
- } else if ( y >= height ) {
- y = 1 + y - height;
- }
- }
-
- if ( x < 0 || x >= width || y < 0 || y >= height ) {
- break; // edge of patch
- }
- VectorSubtract( ctrl[y][x].xyz, base, temp );
- if ( VectorNormalize2( temp, temp ) == 0 ) {
- continue; // degenerate edge, get more dist
- } else {
- good[k] = qtrue;
- VectorCopy( temp, around[k] );
- break; // good edge
- }
- }
- }
-
- VectorClear( sum );
- for ( k = 0 ; k < 8 ; k++ ) {
- if ( !good[k] || !good[(k+1)&7] ) {
- continue; // didn't get two points
- }
- CrossProduct( around[(k+1)&7], around[k], normal );
- if ( VectorNormalize2( normal, normal ) == 0 ) {
- continue;
- }
- VectorAdd( normal, sum, sum );
- count++;
- }
- if ( count == 0 ) {
-//printf("bad normal\n");
- count = 1;
- }
- VectorNormalize2( sum, dv->normal );
- }
- }
-}
-
-
-/*
-============
-InvertCtrl
-============
-*/
-static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
- int i, j;
- drawVert_t temp;
-
- for ( i = 0 ; i < height ; i++ ) {
- for ( j = 0 ; j < width/2 ; j++ ) {
- temp = ctrl[i][j];
- ctrl[i][j] = ctrl[i][width-1-j];
- ctrl[i][width-1-j] = temp;
- }
- }
-}
-
-
-/*
-=================
-InvertErrorTable
-=================
-*/
-static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
- int i;
- float copy[2][MAX_GRID_SIZE];
-
- Com_Memcpy( copy, errorTable, sizeof( copy ) );
-
- for ( i = 0 ; i < width ; i++ ) {
- errorTable[1][i] = copy[0][i]; //[width-1-i];
- }
-
- for ( i = 0 ; i < height ; i++ ) {
- errorTable[0][i] = copy[1][height-1-i];
- }
-
-}
-
-/*
-==================
-PutPointsOnCurve
-==================
-*/
-static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
- int width, int height ) {
- int i, j;
- drawVert_t prev, next;
-
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 1 ; j < height ; j += 2 ) {
- LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
- LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
- LerpDrawVert( &prev, &next, &ctrl[j][i] );
- }
- }
-
-
- for ( j = 0 ; j < height ; j++ ) {
- for ( i = 1 ; i < width ; i += 2 ) {
- LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
- LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
- LerpDrawVert( &prev, &next, &ctrl[j][i] );
- }
- }
-}
-
-/*
-=================
-R_CreateSurfaceGridMesh
-=================
-*/
-srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
- drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
- int i, j, size;
- drawVert_t *vert;
- vec3_t tmpVec;
- srfGridMesh_t *grid;
-
- // copy the results out to a grid
- size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
-
-#ifdef PATCH_STITCHING
- grid = /*ri.Hunk_Alloc*/ ri.Malloc( size );
- Com_Memset(grid, 0, size);
-
- grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 );
- Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
-
- grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 );
- Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
-#else
- grid = ri.Hunk_Alloc( size );
- Com_Memset(grid, 0, size);
-
- grid->widthLodError = ri.Hunk_Alloc( width * 4 );
- Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
-
- grid->heightLodError = ri.Hunk_Alloc( height * 4 );
- Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
-#endif
-
- grid->width = width;
- grid->height = height;
- grid->surfaceType = SF_GRID;
- ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- vert = &grid->verts[j*width+i];
- *vert = ctrl[j][i];
- AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
- }
- }
-
- // compute local origin and bounds
- VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
- VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
- VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
- grid->meshRadius = VectorLength( tmpVec );
-
- VectorCopy( grid->localOrigin, grid->lodOrigin );
- grid->lodRadius = grid->meshRadius;
- //
- return grid;
-}
-
-/*
-=================
-R_FreeSurfaceGridMesh
-=================
-*/
-void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
- ri.Free(grid->widthLodError);
- ri.Free(grid->heightLodError);
- ri.Free(grid);
-}
-
-/*
-=================
-R_SubdividePatchToGrid
-=================
-*/
-srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
- int i, j, k, l;
- drawVert_t prev, next, mid;
- float len, maxLen;
- int dir;
- int t;
- MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
- float errorTable[2][MAX_GRID_SIZE];
-
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height ; j++ ) {
- ctrl[j][i] = points[j*width+i];
- }
- }
-
- for ( dir = 0 ; dir < 2 ; dir++ ) {
-
- for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
- errorTable[dir][j] = 0;
- }
-
- // horizontal subdivisions
- for ( j = 0 ; j + 2 < width ; j += 2 ) {
- // check subdivided midpoints against control points
-
- // FIXME: also check midpoints of adjacent patches against the control points
- // this would basically stitch all patches in the same LOD group together.
-
- maxLen = 0;
- for ( i = 0 ; i < height ; i++ ) {
- vec3_t midxyz;
- vec3_t midxyz2;
- vec3_t dir;
- vec3_t projected;
- float d;
-
- // calculate the point on the curve
- for ( l = 0 ; l < 3 ; l++ ) {
- midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
- + ctrl[i][j+2].xyz[l] ) * 0.25f;
- }
-
- // see how far off the line it is
- // using dist-from-line will not account for internal
- // texture warping, but it gives a lot less polygons than
- // dist-from-midpoint
- VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
- VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
- VectorNormalize( dir );
-
- d = DotProduct( midxyz, dir );
- VectorScale( dir, d, projected );
- VectorSubtract( midxyz, projected, midxyz2);
- len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
- if ( len > maxLen ) {
- maxLen = len;
- }
- }
-
- maxLen = sqrt(maxLen);
-
- // if all the points are on the lines, remove the entire columns
- if ( maxLen < 0.1f ) {
- errorTable[dir][j+1] = 999;
- continue;
- }
-
- // see if we want to insert subdivided columns
- if ( width + 2 > MAX_GRID_SIZE ) {
- errorTable[dir][j+1] = 1.0f/maxLen;
- continue; // can't subdivide any more
- }
-
- if ( maxLen <= r_subdivisions->value ) {
- errorTable[dir][j+1] = 1.0f/maxLen;
- continue; // didn't need subdivision
- }
-
- errorTable[dir][j+2] = 1.0f/maxLen;
-
- // insert two columns and replace the peak
- width += 2;
- for ( i = 0 ; i < height ; i++ ) {
- LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
- LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
- LerpDrawVert( &prev, &next, &mid );
-
- for ( k = width - 1 ; k > j + 3 ; k-- ) {
- ctrl[i][k] = ctrl[i][k-2];
- }
- ctrl[i][j + 1] = prev;
- ctrl[i][j + 2] = mid;
- ctrl[i][j + 3] = next;
- }
-
- // back up and recheck this set again, it may need more subdivision
- j -= 2;
-
- }
-
- Transpose( width, height, ctrl );
- t = width;
- width = height;
- height = t;
- }
-
-
- // put all the aproximating points on the curve
- PutPointsOnCurve( ctrl, width, height );
-
- // cull out any rows or columns that are colinear
- for ( i = 1 ; i < width-1 ; i++ ) {
- if ( errorTable[0][i] != 999 ) {
- continue;
- }
- for ( j = i+1 ; j < width ; j++ ) {
- for ( k = 0 ; k < height ; k++ ) {
- ctrl[k][j-1] = ctrl[k][j];
- }
- errorTable[0][j-1] = errorTable[0][j];
- }
- width--;
- }
-
- for ( i = 1 ; i < height-1 ; i++ ) {
- if ( errorTable[1][i] != 999 ) {
- continue;
- }
- for ( j = i+1 ; j < height ; j++ ) {
- for ( k = 0 ; k < width ; k++ ) {
- ctrl[j-1][k] = ctrl[j][k];
- }
- errorTable[1][j-1] = errorTable[1][j];
- }
- height--;
- }
-
-#if 1
- // flip for longest tristrips as an optimization
- // the results should be visually identical with or
- // without this step
- if ( height > width ) {
- Transpose( width, height, ctrl );
- InvertErrorTable( errorTable, width, height );
- t = width;
- width = height;
- height = t;
- InvertCtrl( width, height, ctrl );
- }
-#endif
-
- // calculate normals
- MakeMeshNormals( width, height, ctrl );
-
- return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
-}
-
-/*
-===============
-R_GridInsertColumn
-===============
-*/
-srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
- int i, j;
- int width, height, oldwidth;
- MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
- float errorTable[2][MAX_GRID_SIZE];
- float lodRadius;
- vec3_t lodOrigin;
-
- oldwidth = 0;
- width = grid->width + 1;
- if (width > MAX_GRID_SIZE)
- return NULL;
- height = grid->height;
- for (i = 0; i < width; i++) {
- if (i == column) {
- //insert new column
- for (j = 0; j < grid->height; j++) {
- LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
- if (j == row)
- VectorCopy(point, ctrl[j][i].xyz);
- }
- errorTable[0][i] = loderror;
- continue;
- }
- errorTable[0][i] = grid->widthLodError[oldwidth];
- for (j = 0; j < grid->height; j++) {
- ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
- }
- oldwidth++;
- }
- for (j = 0; j < grid->height; j++) {
- errorTable[1][j] = grid->heightLodError[j];
- }
- // put all the aproximating points on the curve
- //PutPointsOnCurve( ctrl, width, height );
- // calculate normals
- MakeMeshNormals( width, height, ctrl );
-
- VectorCopy(grid->lodOrigin, lodOrigin);
- lodRadius = grid->lodRadius;
- // free the old grid
- R_FreeSurfaceGridMesh(grid);
- // create a new grid
- grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
- grid->lodRadius = lodRadius;
- VectorCopy(lodOrigin, grid->lodOrigin);
- return grid;
-}
-
-/*
-===============
-R_GridInsertRow
-===============
-*/
-srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
- int i, j;
- int width, height, oldheight;
- MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
- float errorTable[2][MAX_GRID_SIZE];
- float lodRadius;
- vec3_t lodOrigin;
-
- oldheight = 0;
- width = grid->width;
- height = grid->height + 1;
- if (height > MAX_GRID_SIZE)
- return NULL;
- for (i = 0; i < height; i++) {
- if (i == row) {
- //insert new row
- for (j = 0; j < grid->width; j++) {
- LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
- if (j == column)
- VectorCopy(point, ctrl[i][j].xyz);
- }
- errorTable[1][i] = loderror;
- continue;
- }
- errorTable[1][i] = grid->heightLodError[oldheight];
- for (j = 0; j < grid->width; j++) {
- ctrl[i][j] = grid->verts[oldheight * grid->width + j];
- }
- oldheight++;
- }
- for (j = 0; j < grid->width; j++) {
- errorTable[0][j] = grid->widthLodError[j];
- }
- // put all the aproximating points on the curve
- //PutPointsOnCurve( ctrl, width, height );
- // calculate normals
- MakeMeshNormals( width, height, ctrl );
-
- VectorCopy(grid->lodOrigin, lodOrigin);
- lodRadius = grid->lodRadius;
- // free the old grid
- R_FreeSurfaceGridMesh(grid);
- // create a new grid
- grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
- grid->lodRadius = lodRadius;
- VectorCopy(lodOrigin, grid->lodOrigin);
- return grid;
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "tr_local.h" + +/* + +This file does all of the processing necessary to turn a raw grid of points +read from the map file into a srfGridMesh_t ready for rendering. + +The level of detail solution is direction independent, based only on subdivided +distance from the true curve. + +Only a single entry point: + +srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, + drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { + +*/ + + +/* +============ +LerpDrawVert +============ +*/ +static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) { + out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]); + out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]); + out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]); + + out->st[0] = 0.5f * (a->st[0] + b->st[0]); + out->st[1] = 0.5f * (a->st[1] + b->st[1]); + + out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); + out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); + + out->color[0] = (a->color[0] + b->color[0]) >> 1; + out->color[1] = (a->color[1] + b->color[1]) >> 1; + out->color[2] = (a->color[2] + b->color[2]) >> 1; + out->color[3] = (a->color[3] + b->color[3]) >> 1; +} + +/* +============ +Transpose +============ +*/ +static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { + int i, j; + drawVert_t temp; + + if ( width > height ) { + for ( i = 0 ; i < height ; i++ ) { + for ( j = i + 1 ; j < width ; j++ ) { + if ( j < height ) { + // swap the value + temp = ctrl[j][i]; + ctrl[j][i] = ctrl[i][j]; + ctrl[i][j] = temp; + } else { + // just copy + ctrl[j][i] = ctrl[i][j]; + } + } + } + } else { + for ( i = 0 ; i < width ; i++ ) { + for ( j = i + 1 ; j < height ; j++ ) { + if ( j < width ) { + // swap the value + temp = ctrl[i][j]; + ctrl[i][j] = ctrl[j][i]; + ctrl[j][i] = temp; + } else { + // just copy + ctrl[i][j] = ctrl[j][i]; + } + } + } + } + +} + + +/* +================= +MakeMeshNormals + +Handles all the complicated wrapping and degenerate cases +================= +*/ +static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { + int i, j, k, dist; + vec3_t normal; + vec3_t sum; + int count; + vec3_t base; + vec3_t delta; + int x, y; + drawVert_t *dv; + vec3_t around[8], temp; + qboolean good[8]; + qboolean wrapWidth, wrapHeight; + float len; +static int neighbors[8][2] = { + {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} + }; + + wrapWidth = qfalse; + for ( i = 0 ; i < height ; i++ ) { + VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta ); + len = VectorLengthSquared( delta ); + if ( len > 1.0 ) { + break; + } + } + if ( i == height ) { + wrapWidth = qtrue; + } + + wrapHeight = qfalse; + for ( i = 0 ; i < width ; i++ ) { + VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta ); + len = VectorLengthSquared( delta ); + if ( len > 1.0 ) { + break; + } + } + if ( i == width) { + wrapHeight = qtrue; + } + + + for ( i = 0 ; i < width ; i++ ) { + for ( j = 0 ; j < height ; j++ ) { + count = 0; + dv = &ctrl[j][i]; + VectorCopy( dv->xyz, base ); + for ( k = 0 ; k < 8 ; k++ ) { + VectorClear( around[k] ); + good[k] = qfalse; + + for ( dist = 1 ; dist <= 3 ; dist++ ) { + x = i + neighbors[k][0] * dist; + y = j + neighbors[k][1] * dist; + if ( wrapWidth ) { + if ( x < 0 ) { + x = width - 1 + x; + } else if ( x >= width ) { + x = 1 + x - width; + } + } + if ( wrapHeight ) { + if ( y < 0 ) { + y = height - 1 + y; + } else if ( y >= height ) { + y = 1 + y - height; + } + } + + if ( x < 0 || x >= width || y < 0 || y >= height ) { + break; // edge of patch + } + VectorSubtract( ctrl[y][x].xyz, base, temp ); + if ( VectorNormalize2( temp, temp ) == 0 ) { + continue; // degenerate edge, get more dist + } else { + good[k] = qtrue; + VectorCopy( temp, around[k] ); + break; // good edge + } + } + } + + VectorClear( sum ); + for ( k = 0 ; k < 8 ; k++ ) { + if ( !good[k] || !good[(k+1)&7] ) { + continue; // didn't get two points + } + CrossProduct( around[(k+1)&7], around[k], normal ); + if ( VectorNormalize2( normal, normal ) == 0 ) { + continue; + } + VectorAdd( normal, sum, sum ); + count++; + } + if ( count == 0 ) { +//printf("bad normal\n"); + count = 1; + } + VectorNormalize2( sum, dv->normal ); + } + } +} + + +/* +============ +InvertCtrl +============ +*/ +static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { + int i, j; + drawVert_t temp; + + for ( i = 0 ; i < height ; i++ ) { + for ( j = 0 ; j < width/2 ; j++ ) { + temp = ctrl[i][j]; + ctrl[i][j] = ctrl[i][width-1-j]; + ctrl[i][width-1-j] = temp; + } + } +} + + +/* +================= +InvertErrorTable +================= +*/ +static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) { + int i; + float copy[2][MAX_GRID_SIZE]; + + Com_Memcpy( copy, errorTable, sizeof( copy ) ); + + for ( i = 0 ; i < width ; i++ ) { + errorTable[1][i] = copy[0][i]; //[width-1-i]; + } + + for ( i = 0 ; i < height ; i++ ) { + errorTable[0][i] = copy[1][height-1-i]; + } + +} + +/* +================== +PutPointsOnCurve +================== +*/ +static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], + int width, int height ) { + int i, j; + drawVert_t prev, next; + + for ( i = 0 ; i < width ; i++ ) { + for ( j = 1 ; j < height ; j += 2 ) { + LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev ); + LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next ); + LerpDrawVert( &prev, &next, &ctrl[j][i] ); + } + } + + + for ( j = 0 ; j < height ; j++ ) { + for ( i = 1 ; i < width ; i += 2 ) { + LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev ); + LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next ); + LerpDrawVert( &prev, &next, &ctrl[j][i] ); + } + } +} + +/* +================= +R_CreateSurfaceGridMesh +================= +*/ +srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, + drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) { + int i, j, size; + drawVert_t *vert; + vec3_t tmpVec; + srfGridMesh_t *grid; + + // copy the results out to a grid + size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); + +#ifdef PATCH_STITCHING + grid = /*ri.Hunk_Alloc*/ ri.Malloc( size ); + Com_Memset(grid, 0, size); + + grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); + Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); + + grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 ); + Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); +#else + grid = ri.Hunk_Alloc( size ); + Com_Memset(grid, 0, size); + + grid->widthLodError = ri.Hunk_Alloc( width * 4 ); + Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); + + grid->heightLodError = ri.Hunk_Alloc( height * 4 ); + Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); +#endif + + grid->width = width; + grid->height = height; + grid->surfaceType = SF_GRID; + ClearBounds( grid->meshBounds[0], grid->meshBounds[1] ); + for ( i = 0 ; i < width ; i++ ) { + for ( j = 0 ; j < height ; j++ ) { + vert = &grid->verts[j*width+i]; + *vert = ctrl[j][i]; + AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] ); + } + } + + // compute local origin and bounds + VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin ); + VectorScale( grid->localOrigin, 0.5f, grid->localOrigin ); + VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec ); + grid->meshRadius = VectorLength( tmpVec ); + + VectorCopy( grid->localOrigin, grid->lodOrigin ); + grid->lodRadius = grid->meshRadius; + // + return grid; +} + +/* +================= +R_FreeSurfaceGridMesh +================= +*/ +void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) { + ri.Free(grid->widthLodError); + ri.Free(grid->heightLodError); + ri.Free(grid); +} + +/* +================= +R_SubdividePatchToGrid +================= +*/ +srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, + drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { + int i, j, k, l; + drawVert_t prev, next, mid; + float len, maxLen; + int dir; + int t; + MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; + float errorTable[2][MAX_GRID_SIZE]; + + for ( i = 0 ; i < width ; i++ ) { + for ( j = 0 ; j < height ; j++ ) { + ctrl[j][i] = points[j*width+i]; + } + } + + for ( dir = 0 ; dir < 2 ; dir++ ) { + + for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) { + errorTable[dir][j] = 0; + } + + // horizontal subdivisions + for ( j = 0 ; j + 2 < width ; j += 2 ) { + // check subdivided midpoints against control points + + // FIXME: also check midpoints of adjacent patches against the control points + // this would basically stitch all patches in the same LOD group together. + + maxLen = 0; + for ( i = 0 ; i < height ; i++ ) { + vec3_t midxyz; + vec3_t midxyz2; + vec3_t dir; + vec3_t projected; + float d; + + // calculate the point on the curve + for ( l = 0 ; l < 3 ; l++ ) { + midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2 + + ctrl[i][j+2].xyz[l] ) * 0.25f; + } + + // see how far off the line it is + // using dist-from-line will not account for internal + // texture warping, but it gives a lot less polygons than + // dist-from-midpoint + VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz ); + VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir ); + VectorNormalize( dir ); + + d = DotProduct( midxyz, dir ); + VectorScale( dir, d, projected ); + VectorSubtract( midxyz, projected, midxyz2); + len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later + if ( len > maxLen ) { + maxLen = len; + } + } + + maxLen = sqrt(maxLen); + + // if all the points are on the lines, remove the entire columns + if ( maxLen < 0.1f ) { + errorTable[dir][j+1] = 999; + continue; + } + + // see if we want to insert subdivided columns + if ( width + 2 > MAX_GRID_SIZE ) { + errorTable[dir][j+1] = 1.0f/maxLen; + continue; // can't subdivide any more + } + + if ( maxLen <= r_subdivisions->value ) { + errorTable[dir][j+1] = 1.0f/maxLen; + continue; // didn't need subdivision + } + + errorTable[dir][j+2] = 1.0f/maxLen; + + // insert two columns and replace the peak + width += 2; + for ( i = 0 ; i < height ; i++ ) { + LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev ); + LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next ); + LerpDrawVert( &prev, &next, &mid ); + + for ( k = width - 1 ; k > j + 3 ; k-- ) { + ctrl[i][k] = ctrl[i][k-2]; + } + ctrl[i][j + 1] = prev; + ctrl[i][j + 2] = mid; + ctrl[i][j + 3] = next; + } + + // back up and recheck this set again, it may need more subdivision + j -= 2; + + } + + Transpose( width, height, ctrl ); + t = width; + width = height; + height = t; + } + + + // put all the aproximating points on the curve + PutPointsOnCurve( ctrl, width, height ); + + // cull out any rows or columns that are colinear + for ( i = 1 ; i < width-1 ; i++ ) { + if ( errorTable[0][i] != 999 ) { + continue; + } + for ( j = i+1 ; j < width ; j++ ) { + for ( k = 0 ; k < height ; k++ ) { + ctrl[k][j-1] = ctrl[k][j]; + } + errorTable[0][j-1] = errorTable[0][j]; + } + width--; + } + + for ( i = 1 ; i < height-1 ; i++ ) { + if ( errorTable[1][i] != 999 ) { + continue; + } + for ( j = i+1 ; j < height ; j++ ) { + for ( k = 0 ; k < width ; k++ ) { + ctrl[j-1][k] = ctrl[j][k]; + } + errorTable[1][j-1] = errorTable[1][j]; + } + height--; + } + +#if 1 + // flip for longest tristrips as an optimization + // the results should be visually identical with or + // without this step + if ( height > width ) { + Transpose( width, height, ctrl ); + InvertErrorTable( errorTable, width, height ); + t = width; + width = height; + height = t; + InvertCtrl( width, height, ctrl ); + } +#endif + + // calculate normals + MakeMeshNormals( width, height, ctrl ); + + return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); +} + +/* +=============== +R_GridInsertColumn +=============== +*/ +srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) { + int i, j; + int width, height, oldwidth; + MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; + float errorTable[2][MAX_GRID_SIZE]; + float lodRadius; + vec3_t lodOrigin; + + oldwidth = 0; + width = grid->width + 1; + if (width > MAX_GRID_SIZE) + return NULL; + height = grid->height; + for (i = 0; i < width; i++) { + if (i == column) { + //insert new column + for (j = 0; j < grid->height; j++) { + LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] ); + if (j == row) + VectorCopy(point, ctrl[j][i].xyz); + } + errorTable[0][i] = loderror; + continue; + } + errorTable[0][i] = grid->widthLodError[oldwidth]; + for (j = 0; j < grid->height; j++) { + ctrl[j][i] = grid->verts[j * grid->width + oldwidth]; + } + oldwidth++; + } + for (j = 0; j < grid->height; j++) { + errorTable[1][j] = grid->heightLodError[j]; + } + // put all the aproximating points on the curve + //PutPointsOnCurve( ctrl, width, height ); + // calculate normals + MakeMeshNormals( width, height, ctrl ); + + VectorCopy(grid->lodOrigin, lodOrigin); + lodRadius = grid->lodRadius; + // free the old grid + R_FreeSurfaceGridMesh(grid); + // create a new grid + grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); + grid->lodRadius = lodRadius; + VectorCopy(lodOrigin, grid->lodOrigin); + return grid; +} + +/* +=============== +R_GridInsertRow +=============== +*/ +srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) { + int i, j; + int width, height, oldheight; + MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; + float errorTable[2][MAX_GRID_SIZE]; + float lodRadius; + vec3_t lodOrigin; + + oldheight = 0; + width = grid->width; + height = grid->height + 1; + if (height > MAX_GRID_SIZE) + return NULL; + for (i = 0; i < height; i++) { + if (i == row) { + //insert new row + for (j = 0; j < grid->width; j++) { + LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] ); + if (j == column) + VectorCopy(point, ctrl[i][j].xyz); + } + errorTable[1][i] = loderror; + continue; + } + errorTable[1][i] = grid->heightLodError[oldheight]; + for (j = 0; j < grid->width; j++) { + ctrl[i][j] = grid->verts[oldheight * grid->width + j]; + } + oldheight++; + } + for (j = 0; j < grid->width; j++) { + errorTable[0][j] = grid->widthLodError[j]; + } + // put all the aproximating points on the curve + //PutPointsOnCurve( ctrl, width, height ); + // calculate normals + MakeMeshNormals( width, height, ctrl ); + + VectorCopy(grid->lodOrigin, lodOrigin); + lodRadius = grid->lodRadius; + // free the old grid + R_FreeSurfaceGridMesh(grid); + // create a new grid + grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); + grid->lodRadius = lodRadius; + VectorCopy(lodOrigin, grid->lodOrigin); + return grid; +} diff --git a/code/renderer/tr_flares.c b/code/renderer/tr_flares.c index 3ef4c58..aa4e8c3 100755 --- a/code/renderer/tr_flares.c +++ b/code/renderer/tr_flares.c @@ -1,447 +1,447 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_flares.c
-
-#include "tr_local.h"
-
-/*
-=============================================================================
-
-LIGHT FLARES
-
-A light flare is an effect that takes place inside the eye when bright light
-sources are visible. The size of the flare reletive to the screen is nearly
-constant, irrespective of distance, but the intensity should be proportional to the
-projected area of the light source.
-
-A surface that has been flagged as having a light flare will calculate the depth
-buffer value that it's midpoint should have when the surface is added.
-
-After all opaque surfaces have been rendered, the depth buffer is read back for
-each flare in view. If the point has not been obscured by a closer surface, the
-flare should be drawn.
-
-Surfaces that have a repeated texture should never be flagged as flaring, because
-there will only be a single flare added at the midpoint of the polygon.
-
-To prevent abrupt popping, the intensity of the flare is interpolated up and
-down as it changes visibility. This involves scene to scene state, unlike almost
-all other aspects of the renderer, and is complicated by the fact that a single
-frame may have multiple scenes.
-
-RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
-up to five or more times in a frame with 3D status bar icons).
-
-=============================================================================
-*/
-
-
-// flare states maintain visibility over multiple frames for fading
-// layers: view, mirror, menu
-typedef struct flare_s {
- struct flare_s *next; // for active chain
-
- int addedFrame;
-
- qboolean inPortal; // true if in a portal view of the scene
- int frameSceneNum;
- void *surface;
- int fogNum;
-
- int fadeTime;
-
- qboolean visible; // state of last test
- float drawIntensity; // may be non 0 even if !visible due to fading
-
- int windowX, windowY;
- float eyeZ;
-
- vec3_t color;
-} flare_t;
-
-#define MAX_FLARES 128
-
-flare_t r_flareStructs[MAX_FLARES];
-flare_t *r_activeFlares, *r_inactiveFlares;
-
-/*
-==================
-R_ClearFlares
-==================
-*/
-void R_ClearFlares( void ) {
- int i;
-
- Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
- r_activeFlares = NULL;
- r_inactiveFlares = NULL;
-
- for ( i = 0 ; i < MAX_FLARES ; i++ ) {
- r_flareStructs[i].next = r_inactiveFlares;
- r_inactiveFlares = &r_flareStructs[i];
- }
-}
-
-
-/*
-==================
-RB_AddFlare
-
-This is called at surface tesselation time
-==================
-*/
-void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
- int i;
- flare_t *f, *oldest;
- vec3_t local;
- float d;
- vec4_t eye, clip, normalized, window;
-
- backEnd.pc.c_flareAdds++;
-
- // if the point is off the screen, don't bother adding it
- // calculate screen coordinates and depth
- R_TransformModelToClip( point, backEnd.or.modelMatrix,
- backEnd.viewParms.projectionMatrix, eye, clip );
-
- // check to see if the point is completely off screen
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
- return;
- }
- }
-
- R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
-
- if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
- || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
- return; // shouldn't happen, since we check the clip[] above, except for FP rounding
- }
-
- // see if a flare with a matching surface, scene, and view exists
- oldest = r_flareStructs;
- for ( f = r_activeFlares ; f ; f = f->next ) {
- if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
- && f->inPortal == backEnd.viewParms.isPortal ) {
- break;
- }
- }
-
- // allocate a new one
- if (!f ) {
- if ( !r_inactiveFlares ) {
- // the list is completely full
- return;
- }
- f = r_inactiveFlares;
- r_inactiveFlares = r_inactiveFlares->next;
- f->next = r_activeFlares;
- r_activeFlares = f;
-
- f->surface = surface;
- f->frameSceneNum = backEnd.viewParms.frameSceneNum;
- f->inPortal = backEnd.viewParms.isPortal;
- f->addedFrame = -1;
- }
-
- if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
- f->visible = qfalse;
- f->fadeTime = backEnd.refdef.time - 2000;
- }
-
- f->addedFrame = backEnd.viewParms.frameCount;
- f->fogNum = fogNum;
-
- VectorCopy( color, f->color );
-
- // fade the intensity of the flare down as the
- // light surface turns away from the viewer
- if ( normal ) {
- VectorSubtract( backEnd.viewParms.or.origin, point, local );
- VectorNormalizeFast( local );
- d = DotProduct( local, normal );
- VectorScale( f->color, d, f->color );
- }
-
- // save info needed to test
- f->windowX = backEnd.viewParms.viewportX + window[0];
- f->windowY = backEnd.viewParms.viewportY + window[1];
-
- f->eyeZ = eye[2];
-}
-
-/*
-==================
-RB_AddDlightFlares
-==================
-*/
-void RB_AddDlightFlares( void ) {
- dlight_t *l;
- int i, j, k;
- fog_t *fog;
-
- if ( !r_flares->integer ) {
- return;
- }
-
- l = backEnd.refdef.dlights;
- fog = tr.world->fogs;
- for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
-
- // find which fog volume the light is in
- for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
- fog = &tr.world->fogs[j];
- for ( k = 0 ; k < 3 ; k++ ) {
- if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
- break;
- }
- }
- if ( k == 3 ) {
- break;
- }
- }
- if ( j == tr.world->numfogs ) {
- j = 0;
- }
-
- RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
- }
-}
-
-/*
-===============================================================================
-
-FLARE BACK END
-
-===============================================================================
-*/
-
-/*
-==================
-RB_TestFlare
-==================
-*/
-void RB_TestFlare( flare_t *f ) {
- float depth;
- qboolean visible;
- float fade;
- float screenZ;
-
- backEnd.pc.c_flareTests++;
-
- // doing a readpixels is as good as doing a glFinish(), so
- // don't bother with another sync
- glState.finishCalled = qfalse;
-
- // read back the z buffer contents
- qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
-
- screenZ = backEnd.viewParms.projectionMatrix[14] /
- ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
-
- visible = ( -f->eyeZ - -screenZ ) < 24;
-
- if ( visible ) {
- if ( !f->visible ) {
- f->visible = qtrue;
- f->fadeTime = backEnd.refdef.time - 1;
- }
- fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
- } else {
- if ( f->visible ) {
- f->visible = qfalse;
- f->fadeTime = backEnd.refdef.time - 1;
- }
- fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
- }
-
- if ( fade < 0 ) {
- fade = 0;
- }
- if ( fade > 1 ) {
- fade = 1;
- }
-
- f->drawIntensity = fade;
-}
-
-
-/*
-==================
-RB_RenderFlare
-==================
-*/
-void RB_RenderFlare( flare_t *f ) {
- float size;
- vec3_t color;
- int iColor[3];
-
- backEnd.pc.c_flareRenders++;
-
- VectorScale( f->color, f->drawIntensity*tr.identityLight, color );
- iColor[0] = color[0] * 255;
- iColor[1] = color[1] * 255;
- iColor[2] = color[2] * 255;
-
- size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / -f->eyeZ );
-
- RB_BeginSurface( tr.flareShader, f->fogNum );
-
- // FIXME: use quadstamp?
- tess.xyz[tess.numVertexes][0] = f->windowX - size;
- tess.xyz[tess.numVertexes][1] = f->windowY - size;
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.xyz[tess.numVertexes][0] = f->windowX - size;
- tess.xyz[tess.numVertexes][1] = f->windowY + size;
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.xyz[tess.numVertexes][0] = f->windowX + size;
- tess.xyz[tess.numVertexes][1] = f->windowY + size;
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.xyz[tess.numVertexes][0] = f->windowX + size;
- tess.xyz[tess.numVertexes][1] = f->windowY - size;
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = iColor[0];
- tess.vertexColors[tess.numVertexes][1] = iColor[1];
- tess.vertexColors[tess.numVertexes][2] = iColor[2];
- tess.vertexColors[tess.numVertexes][3] = 255;
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 1;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 3;
-
- RB_EndSurface();
-}
-
-/*
-==================
-RB_RenderFlares
-
-Because flares are simulating an occular effect, they should be drawn after
-everything (all views) in the entire frame has been drawn.
-
-Because of the way portals use the depth buffer to mark off areas, the
-needed information would be lost after each view, so we are forced to draw
-flares after each view.
-
-The resulting artifact is that flares in mirrors or portals don't dim properly
-when occluded by something in the main view, and portal flares that should
-extend past the portal edge will be overwritten.
-==================
-*/
-void RB_RenderFlares (void) {
- flare_t *f;
- flare_t **prev;
- qboolean draw;
-
- if ( !r_flares->integer ) {
- return;
- }
-
-// RB_AddDlightFlares();
-
- // perform z buffer readback on each flare in this view
- draw = qfalse;
- prev = &r_activeFlares;
- while ( ( f = *prev ) != NULL ) {
- // throw out any flares that weren't added last frame
- if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
- *prev = f->next;
- f->next = r_inactiveFlares;
- r_inactiveFlares = f;
- continue;
- }
-
- // don't draw any here that aren't from this scene / portal
- f->drawIntensity = 0;
- if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
- && f->inPortal == backEnd.viewParms.isPortal ) {
- RB_TestFlare( f );
- if ( f->drawIntensity ) {
- draw = qtrue;
- } else {
- // this flare has completely faded out, so remove it from the chain
- *prev = f->next;
- f->next = r_inactiveFlares;
- r_inactiveFlares = f;
- continue;
- }
- }
-
- prev = &f->next;
- }
-
- if ( !draw ) {
- return; // none visible
- }
-
- if ( backEnd.viewParms.isPortal ) {
- qglDisable (GL_CLIP_PLANE0);
- }
-
- qglPushMatrix();
- qglLoadIdentity();
- qglMatrixMode( GL_PROJECTION );
- qglPushMatrix();
- qglLoadIdentity();
- qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
- backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
- -99999, 99999 );
-
- for ( f = r_activeFlares ; f ; f = f->next ) {
- if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
- && f->inPortal == backEnd.viewParms.isPortal
- && f->drawIntensity ) {
- RB_RenderFlare( f );
- }
- }
-
- qglPopMatrix();
- qglMatrixMode( GL_MODELVIEW );
- qglPopMatrix();
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_flares.c + +#include "tr_local.h" + +/* +============================================================================= + +LIGHT FLARES + +A light flare is an effect that takes place inside the eye when bright light +sources are visible. The size of the flare reletive to the screen is nearly +constant, irrespective of distance, but the intensity should be proportional to the +projected area of the light source. + +A surface that has been flagged as having a light flare will calculate the depth +buffer value that it's midpoint should have when the surface is added. + +After all opaque surfaces have been rendered, the depth buffer is read back for +each flare in view. If the point has not been obscured by a closer surface, the +flare should be drawn. + +Surfaces that have a repeated texture should never be flagged as flaring, because +there will only be a single flare added at the midpoint of the polygon. + +To prevent abrupt popping, the intensity of the flare is interpolated up and +down as it changes visibility. This involves scene to scene state, unlike almost +all other aspects of the renderer, and is complicated by the fact that a single +frame may have multiple scenes. + +RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially +up to five or more times in a frame with 3D status bar icons). + +============================================================================= +*/ + + +// flare states maintain visibility over multiple frames for fading +// layers: view, mirror, menu +typedef struct flare_s { + struct flare_s *next; // for active chain + + int addedFrame; + + qboolean inPortal; // true if in a portal view of the scene + int frameSceneNum; + void *surface; + int fogNum; + + int fadeTime; + + qboolean visible; // state of last test + float drawIntensity; // may be non 0 even if !visible due to fading + + int windowX, windowY; + float eyeZ; + + vec3_t color; +} flare_t; + +#define MAX_FLARES 128 + +flare_t r_flareStructs[MAX_FLARES]; +flare_t *r_activeFlares, *r_inactiveFlares; + +/* +================== +R_ClearFlares +================== +*/ +void R_ClearFlares( void ) { + int i; + + Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) ); + r_activeFlares = NULL; + r_inactiveFlares = NULL; + + for ( i = 0 ; i < MAX_FLARES ; i++ ) { + r_flareStructs[i].next = r_inactiveFlares; + r_inactiveFlares = &r_flareStructs[i]; + } +} + + +/* +================== +RB_AddFlare + +This is called at surface tesselation time +================== +*/ +void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { + int i; + flare_t *f, *oldest; + vec3_t local; + float d; + vec4_t eye, clip, normalized, window; + + backEnd.pc.c_flareAdds++; + + // if the point is off the screen, don't bother adding it + // calculate screen coordinates and depth + R_TransformModelToClip( point, backEnd.or.modelMatrix, + backEnd.viewParms.projectionMatrix, eye, clip ); + + // check to see if the point is completely off screen + for ( i = 0 ; i < 3 ; i++ ) { + if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { + return; + } + } + + R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); + + if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth + || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { + return; // shouldn't happen, since we check the clip[] above, except for FP rounding + } + + // see if a flare with a matching surface, scene, and view exists + oldest = r_flareStructs; + for ( f = r_activeFlares ; f ; f = f->next ) { + if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum + && f->inPortal == backEnd.viewParms.isPortal ) { + break; + } + } + + // allocate a new one + if (!f ) { + if ( !r_inactiveFlares ) { + // the list is completely full + return; + } + f = r_inactiveFlares; + r_inactiveFlares = r_inactiveFlares->next; + f->next = r_activeFlares; + r_activeFlares = f; + + f->surface = surface; + f->frameSceneNum = backEnd.viewParms.frameSceneNum; + f->inPortal = backEnd.viewParms.isPortal; + f->addedFrame = -1; + } + + if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { + f->visible = qfalse; + f->fadeTime = backEnd.refdef.time - 2000; + } + + f->addedFrame = backEnd.viewParms.frameCount; + f->fogNum = fogNum; + + VectorCopy( color, f->color ); + + // fade the intensity of the flare down as the + // light surface turns away from the viewer + if ( normal ) { + VectorSubtract( backEnd.viewParms.or.origin, point, local ); + VectorNormalizeFast( local ); + d = DotProduct( local, normal ); + VectorScale( f->color, d, f->color ); + } + + // save info needed to test + f->windowX = backEnd.viewParms.viewportX + window[0]; + f->windowY = backEnd.viewParms.viewportY + window[1]; + + f->eyeZ = eye[2]; +} + +/* +================== +RB_AddDlightFlares +================== +*/ +void RB_AddDlightFlares( void ) { + dlight_t *l; + int i, j, k; + fog_t *fog; + + if ( !r_flares->integer ) { + return; + } + + l = backEnd.refdef.dlights; + fog = tr.world->fogs; + for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) { + + // find which fog volume the light is in + for ( j = 1 ; j < tr.world->numfogs ; j++ ) { + fog = &tr.world->fogs[j]; + for ( k = 0 ; k < 3 ; k++ ) { + if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) { + break; + } + } + if ( k == 3 ) { + break; + } + } + if ( j == tr.world->numfogs ) { + j = 0; + } + + RB_AddFlare( (void *)l, j, l->origin, l->color, NULL ); + } +} + +/* +=============================================================================== + +FLARE BACK END + +=============================================================================== +*/ + +/* +================== +RB_TestFlare +================== +*/ +void RB_TestFlare( flare_t *f ) { + float depth; + qboolean visible; + float fade; + float screenZ; + + backEnd.pc.c_flareTests++; + + // doing a readpixels is as good as doing a glFinish(), so + // don't bother with another sync + glState.finishCalled = qfalse; + + // read back the z buffer contents + qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); + + screenZ = backEnd.viewParms.projectionMatrix[14] / + ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); + + visible = ( -f->eyeZ - -screenZ ) < 24; + + if ( visible ) { + if ( !f->visible ) { + f->visible = qtrue; + f->fadeTime = backEnd.refdef.time - 1; + } + fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value; + } else { + if ( f->visible ) { + f->visible = qfalse; + f->fadeTime = backEnd.refdef.time - 1; + } + fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value; + } + + if ( fade < 0 ) { + fade = 0; + } + if ( fade > 1 ) { + fade = 1; + } + + f->drawIntensity = fade; +} + + +/* +================== +RB_RenderFlare +================== +*/ +void RB_RenderFlare( flare_t *f ) { + float size; + vec3_t color; + int iColor[3]; + + backEnd.pc.c_flareRenders++; + + VectorScale( f->color, f->drawIntensity*tr.identityLight, color ); + iColor[0] = color[0] * 255; + iColor[1] = color[1] * 255; + iColor[2] = color[2] * 255; + + size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / -f->eyeZ ); + + RB_BeginSurface( tr.flareShader, f->fogNum ); + + // FIXME: use quadstamp? + tess.xyz[tess.numVertexes][0] = f->windowX - size; + tess.xyz[tess.numVertexes][1] = f->windowY - size; + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.xyz[tess.numVertexes][0] = f->windowX - size; + tess.xyz[tess.numVertexes][1] = f->windowY + size; + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.xyz[tess.numVertexes][0] = f->windowX + size; + tess.xyz[tess.numVertexes][1] = f->windowY + size; + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.xyz[tess.numVertexes][0] = f->windowX + size; + tess.xyz[tess.numVertexes][1] = f->windowY - size; + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + RB_EndSurface(); +} + +/* +================== +RB_RenderFlares + +Because flares are simulating an occular effect, they should be drawn after +everything (all views) in the entire frame has been drawn. + +Because of the way portals use the depth buffer to mark off areas, the +needed information would be lost after each view, so we are forced to draw +flares after each view. + +The resulting artifact is that flares in mirrors or portals don't dim properly +when occluded by something in the main view, and portal flares that should +extend past the portal edge will be overwritten. +================== +*/ +void RB_RenderFlares (void) { + flare_t *f; + flare_t **prev; + qboolean draw; + + if ( !r_flares->integer ) { + return; + } + +// RB_AddDlightFlares(); + + // perform z buffer readback on each flare in this view + draw = qfalse; + prev = &r_activeFlares; + while ( ( f = *prev ) != NULL ) { + // throw out any flares that weren't added last frame + if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) { + *prev = f->next; + f->next = r_inactiveFlares; + r_inactiveFlares = f; + continue; + } + + // don't draw any here that aren't from this scene / portal + f->drawIntensity = 0; + if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum + && f->inPortal == backEnd.viewParms.isPortal ) { + RB_TestFlare( f ); + if ( f->drawIntensity ) { + draw = qtrue; + } else { + // this flare has completely faded out, so remove it from the chain + *prev = f->next; + f->next = r_inactiveFlares; + r_inactiveFlares = f; + continue; + } + } + + prev = &f->next; + } + + if ( !draw ) { + return; // none visible + } + + if ( backEnd.viewParms.isPortal ) { + qglDisable (GL_CLIP_PLANE0); + } + + qglPushMatrix(); + qglLoadIdentity(); + qglMatrixMode( GL_PROJECTION ); + qglPushMatrix(); + qglLoadIdentity(); + qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, + backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, + -99999, 99999 ); + + for ( f = r_activeFlares ; f ; f = f->next ) { + if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum + && f->inPortal == backEnd.viewParms.isPortal + && f->drawIntensity ) { + RB_RenderFlare( f ); + } + } + + qglPopMatrix(); + qglMatrixMode( GL_MODELVIEW ); + qglPopMatrix(); +} + diff --git a/code/renderer/tr_font.c b/code/renderer/tr_font.c index a40c935..3813ce4 100755 --- a/code/renderer/tr_font.c +++ b/code/renderer/tr_font.c @@ -1,542 +1,542 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_font.c
-//
-//
-// The font system uses FreeType 2.x to render TrueType fonts for use within the game.
-// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and
-// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old
-// fonts since the code is shared with standard Q3A.
-//
-// If you include this font rendering code in a commercial product you MUST include the
-// following somewhere with your product, see www.freetype.org for specifics or changes.
-// The Freetype code also uses some hinting techniques that MIGHT infringe on patents
-// held by apple so be aware of that also.
-//
-// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code
-// disabled. This removes any potential patent issues and it keeps us from having to
-// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require
-// an act of god to accomplish.
-//
-// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType
-// credit in the credits ) and then saved off the glyph data and then hand touched up the
-// font bitmaps so they scale a bit better in GL.
-//
-// There are limitations in the way fonts are saved and reloaded in that it is based on
-// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point
-// you will end up with a single 18 point data file and image set. Typically you will want to
-// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system
-//
-// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we
-// use three or four scales, most of them exactly equaling the specific rendered size. We
-// rendered three sizes in Team Arena, 12, 16, and 20.
-//
-// To generate new font data you need to go through the following steps.
-// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path.
-// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and
-// point size. the original TrueType fonts must exist in fonts at this point.
-// 3. run the game, you should see things normally.
-// 4. Exit the game and there will be three dat files and at least three tga files. The
-// tga's are in 256x256 pages so if it takes three images to render a 24 point font you
-// will end up with fontImage_0_24.tga through fontImage_2_24.tga
-// 5. You will need to flip the tga's in Photoshop as the tga output code writes them upside
-// down.
-// 6. In future runs of the game, the system looks for these images and data files when a s
-// specific point sized font is rendered and loads them for use.
-// 7. Because of the original beta nature of the FreeType code you will probably want to hand
-// touch the font bitmaps.
-//
-// Currently a define in the project turns on or off the FreeType code which is currently
-// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and
-// uncheck the exclude from build check box in the FreeType2 area of the Renderer project.
-
-
-#include "tr_local.h"
-#include "../qcommon/qcommon.h"
-
-#ifdef BUILD_FREETYPE
-#include "../ft2/fterrors.h"
-#include "../ft2/ftsystem.h"
-#include "../ft2/ftimage.h"
-#include "../ft2/freetype.h"
-#include "../ft2/ftoutln.h"
-
-#define _FLOOR(x) ((x) & -64)
-#define _CEIL(x) (((x)+63) & -64)
-#define _TRUNC(x) ((x) >> 6)
-
-FT_Library ftLibrary = NULL;
-#endif
-
-#define MAX_FONTS 6
-static int registeredFontCount = 0;
-static fontInfo_t registeredFont[MAX_FONTS];
-
-#ifdef BUILD_FREETYPE
-void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
-
- *left = _FLOOR( glyph->metrics.horiBearingX );
- *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
- *width = _TRUNC(*right - *left);
-
- *top = _CEIL( glyph->metrics.horiBearingY );
- *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );
- *height = _TRUNC( *top - *bottom );
- *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 );
-}
-
-
-FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {
-
- FT_Bitmap *bit2;
- int left, right, width, top, bottom, height, pitch, size;
-
- R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);
-
- if ( glyph->format == ft_glyph_format_outline ) {
- size = pitch*height;
-
- bit2 = Z_Malloc(sizeof(FT_Bitmap));
-
- bit2->width = width;
- bit2->rows = height;
- bit2->pitch = pitch;
- bit2->pixel_mode = ft_pixel_mode_grays;
- //bit2->pixel_mode = ft_pixel_mode_mono;
- bit2->buffer = Z_Malloc(pitch*height);
- bit2->num_grays = 256;
-
- Com_Memset( bit2->buffer, 0, size );
-
- FT_Outline_Translate( &glyph->outline, -left, -bottom );
-
- FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );
-
- glyphOut->height = height;
- glyphOut->pitch = pitch;
- glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;
- glyphOut->bottom = bottom;
-
- return bit2;
- }
- else {
- ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n");
- }
- return NULL;
-}
-
-void WriteTGA (char *filename, byte *data, int width, int height) {
- byte *buffer;
- int i, c;
-
- buffer = Z_Malloc(width*height*4 + 18);
- Com_Memset (buffer, 0, 18);
- buffer[2] = 2; // uncompressed type
- buffer[12] = width&255;
- buffer[13] = width>>8;
- buffer[14] = height&255;
- buffer[15] = height>>8;
- buffer[16] = 32; // pixel size
-
- // swap rgb to bgr
- c = 18 + width * height * 4;
- for (i=18 ; i<c ; i+=4)
- {
- buffer[i] = data[i-18+2]; // blue
- buffer[i+1] = data[i-18+1]; // green
- buffer[i+2] = data[i-18+0]; // red
- buffer[i+3] = data[i-18+3]; // alpha
- }
-
- ri.FS_WriteFile(filename, buffer, c);
-
- //f = fopen (filename, "wb");
- //fwrite (buffer, 1, c, f);
- //fclose (f);
-
- Z_Free (buffer);
-}
-
-static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) {
- int i;
- static glyphInfo_t glyph;
- unsigned char *src, *dst;
- float scaled_width, scaled_height;
- FT_Bitmap *bitmap = NULL;
-
- Com_Memset(&glyph, 0, sizeof(glyphInfo_t));
- // make sure everything is here
- if (face != NULL) {
- FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );
- bitmap = R_RenderGlyph(face->glyph, &glyph);
- if (bitmap) {
- glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;
- } else {
- return &glyph;
- }
-
- if (glyph.height > *maxHeight) {
- *maxHeight = glyph.height;
- }
-
- if (calcHeight) {
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
- return &glyph;
- }
-
-/*
- // need to convert to power of 2 sizes so we do not get
- // any scaling from the gl upload
- for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1)
- ;
- for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)
- ;
-*/
-
- scaled_width = glyph.pitch;
- scaled_height = glyph.height;
-
- // we need to make sure we fit
- if (*xOut + scaled_width + 1 >= 255) {
- if (*yOut + *maxHeight + 1 >= 255) {
- *yOut = -1;
- *xOut = -1;
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
- return &glyph;
- } else {
- *xOut = 0;
- *yOut += *maxHeight + 1;
- }
- } else if (*yOut + *maxHeight + 1 >= 255) {
- *yOut = -1;
- *xOut = -1;
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
- return &glyph;
- }
-
-
- src = bitmap->buffer;
- dst = imageOut + (*yOut * 256) + *xOut;
-
- if (bitmap->pixel_mode == ft_pixel_mode_mono) {
- for (i = 0; i < glyph.height; i++) {
- int j;
- unsigned char *_src = src;
- unsigned char *_dst = dst;
- unsigned char mask = 0x80;
- unsigned char val = *_src;
- for (j = 0; j < glyph.pitch; j++) {
- if (mask == 0x80) {
- val = *_src++;
- }
- if (val & mask) {
- *_dst = 0xff;
- }
- mask >>= 1;
-
- if ( mask == 0 ) {
- mask = 0x80;
- }
- _dst++;
- }
-
- src += glyph.pitch;
- dst += 256;
-
- }
- } else {
- for (i = 0; i < glyph.height; i++) {
- Com_Memcpy(dst, src, glyph.pitch);
- src += glyph.pitch;
- dst += 256;
- }
- }
-
- // we now have an 8 bit per pixel grey scale bitmap
- // that is width wide and pf->ftSize->metrics.y_ppem tall
-
- glyph.imageHeight = scaled_height;
- glyph.imageWidth = scaled_width;
- glyph.s = (float)*xOut / 256;
- glyph.t = (float)*yOut / 256;
- glyph.s2 = glyph.s + (float)scaled_width / 256;
- glyph.t2 = glyph.t + (float)scaled_height / 256;
-
- *xOut += scaled_width + 1;
- }
-
- Z_Free(bitmap->buffer);
- Z_Free(bitmap);
-
- return &glyph;
-}
-#endif
-
-static int fdOffset;
-static byte *fdFile;
-
-int readInt() {
- int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);
- fdOffset += 4;
- return i;
-}
-
-typedef union {
- byte fred[4];
- float ffred;
-} poor;
-
-float readFloat() {
- poor me;
-#if idppc
- me.fred[0] = fdFile[fdOffset+3];
- me.fred[1] = fdFile[fdOffset+2];
- me.fred[2] = fdFile[fdOffset+1];
- me.fred[3] = fdFile[fdOffset+0];
-#else
- me.fred[0] = fdFile[fdOffset+0];
- me.fred[1] = fdFile[fdOffset+1];
- me.fred[2] = fdFile[fdOffset+2];
- me.fred[3] = fdFile[fdOffset+3];
-#endif
- fdOffset += 4;
- return me.ffred;
-}
-
-void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
-#ifdef BUILD_FREETYPE
- FT_Face face;
- int j, k, xOut, yOut, lastStart, imageNumber;
- int scaledSize, newSize, maxHeight, left, satLevels;
- unsigned char *out, *imageBuff;
- glyphInfo_t *glyph;
- image_t *image;
- qhandle_t h;
- float max;
-#endif
- void *faceData;
- int i, len;
- char name[1024];
- float dpi = 72; //
- float glyphScale = 72.0f / dpi; // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 )
-
- if (pointSize <= 0) {
- pointSize = 12;
- }
- // we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font
- glyphScale *= 48.0f / pointSize;
-
- // make sure the render thread is stopped
- R_SyncRenderThread();
-
- if (registeredFontCount >= MAX_FONTS) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: Too many fonts registered already.\n");
- return;
- }
-
- Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
- for (i = 0; i < registeredFontCount; i++) {
- if (Q_stricmp(name, registeredFont[i].name) == 0) {
- Com_Memcpy(font, ®isteredFont[i], sizeof(fontInfo_t));
- return;
- }
- }
-
- len = ri.FS_ReadFile(name, NULL);
- if (len == sizeof(fontInfo_t)) {
- ri.FS_ReadFile(name, &faceData);
- fdOffset = 0;
- fdFile = faceData;
- for(i=0; i<GLYPHS_PER_FONT; i++) {
- font->glyphs[i].height = readInt();
- font->glyphs[i].top = readInt();
- font->glyphs[i].bottom = readInt();
- font->glyphs[i].pitch = readInt();
- font->glyphs[i].xSkip = readInt();
- font->glyphs[i].imageWidth = readInt();
- font->glyphs[i].imageHeight = readInt();
- font->glyphs[i].s = readFloat();
- font->glyphs[i].t = readFloat();
- font->glyphs[i].s2 = readFloat();
- font->glyphs[i].t2 = readFloat();
- font->glyphs[i].glyph = readInt();
- Com_Memcpy(font->glyphs[i].shaderName, &fdFile[fdOffset], 32);
- fdOffset += 32;
- }
- font->glyphScale = readFloat();
- Com_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH);
-
-// Com_Memcpy(font, faceData, sizeof(fontInfo_t));
- Q_strncpyz(font->name, name, sizeof(font->name));
- for (i = GLYPH_START; i < GLYPH_END; i++) {
- font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName);
- }
- Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t));
- return;
- }
-
-#ifndef BUILD_FREETYPE
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType code not available\n");
-#else
- if (ftLibrary == NULL) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType not initialized.\n");
- return;
- }
-
- len = ri.FS_ReadFile(fontName, &faceData);
- if (len <= 0) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: Unable to read font file\n");
- return;
- }
-
- // allocate on the stack first in case we fail
- if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, unable to allocate new face.\n");
- return;
- }
-
-
- if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, Unable to set face char size.\n");
- return;
- }
-
- //*font = ®isteredFonts[registeredFontCount++];
-
- // make a 256x256 image buffer, once it is full, register it, clean it and keep going
- // until all glyphs are rendered
-
- out = Z_Malloc(1024*1024);
- if (out == NULL) {
- ri.Printf(PRINT_ALL, "RE_RegisterFont: Z_Malloc failure during output image creation.\n");
- return;
- }
- Com_Memset(out, 0, 1024*1024);
-
- maxHeight = 0;
-
- for (i = GLYPH_START; i < GLYPH_END; i++) {
- glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);
- }
-
- xOut = 0;
- yOut = 0;
- i = GLYPH_START;
- lastStart = i;
- imageNumber = 0;
-
- while ( i <= GLYPH_END ) {
-
- glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);
-
- if (xOut == -1 || yOut == -1 || i == GLYPH_END) {
- // ran out of room
- // we need to create an image from the bitmap, set all the handles in the glyphs to this point
- //
-
- scaledSize = 256*256;
- newSize = scaledSize * 4;
- imageBuff = Z_Malloc(newSize);
- left = 0;
- max = 0;
- satLevels = 255;
- for ( k = 0; k < (scaledSize) ; k++ ) {
- if (max < out[k]) {
- max = out[k];
- }
- }
-
- if (max > 0) {
- max = 255/max;
- }
-
- for ( k = 0; k < (scaledSize) ; k++ ) {
- imageBuff[left++] = 255;
- imageBuff[left++] = 255;
- imageBuff[left++] = 255;
-
- imageBuff[left++] = ((float)out[k] * max);
- }
-
- Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize);
- if (r_saveFontData->integer) {
- WriteTGA(name, imageBuff, 256, 256);
- }
-
- //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize);
- image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP);
- h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse);
- for (j = lastStart; j < i; j++) {
- font->glyphs[j].glyph = h;
- Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName));
- }
- lastStart = i;
- Com_Memset(out, 0, 1024*1024);
- xOut = 0;
- yOut = 0;
- Z_Free(imageBuff);
- i++;
- } else {
- Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t));
- i++;
- }
- }
-
- registeredFont[registeredFontCount].glyphScale = glyphScale;
- font->glyphScale = glyphScale;
- Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t));
-
- if (r_saveFontData->integer) {
- ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t));
- }
-
- Z_Free(out);
-
- ri.FS_FreeFile(faceData);
-#endif
-}
-
-
-
-void R_InitFreeType() {
-#ifdef BUILD_FREETYPE
- if (FT_Init_FreeType( &ftLibrary )) {
- ri.Printf(PRINT_ALL, "R_InitFreeType: Unable to initialize FreeType.\n");
- }
-#endif
- registeredFontCount = 0;
-}
-
-
-void R_DoneFreeType() {
-#ifdef BUILD_FREETYPE
- if (ftLibrary) {
- FT_Done_FreeType( ftLibrary );
- ftLibrary = NULL;
- }
-#endif
- registeredFontCount = 0;
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_font.c +// +// +// The font system uses FreeType 2.x to render TrueType fonts for use within the game. +// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and +// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old +// fonts since the code is shared with standard Q3A. +// +// If you include this font rendering code in a commercial product you MUST include the +// following somewhere with your product, see www.freetype.org for specifics or changes. +// The Freetype code also uses some hinting techniques that MIGHT infringe on patents +// held by apple so be aware of that also. +// +// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code +// disabled. This removes any potential patent issues and it keeps us from having to +// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require +// an act of god to accomplish. +// +// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType +// credit in the credits ) and then saved off the glyph data and then hand touched up the +// font bitmaps so they scale a bit better in GL. +// +// There are limitations in the way fonts are saved and reloaded in that it is based on +// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point +// you will end up with a single 18 point data file and image set. Typically you will want to +// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system +// +// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we +// use three or four scales, most of them exactly equaling the specific rendered size. We +// rendered three sizes in Team Arena, 12, 16, and 20. +// +// To generate new font data you need to go through the following steps. +// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path. +// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and +// point size. the original TrueType fonts must exist in fonts at this point. +// 3. run the game, you should see things normally. +// 4. Exit the game and there will be three dat files and at least three tga files. The +// tga's are in 256x256 pages so if it takes three images to render a 24 point font you +// will end up with fontImage_0_24.tga through fontImage_2_24.tga +// 5. You will need to flip the tga's in Photoshop as the tga output code writes them upside +// down. +// 6. In future runs of the game, the system looks for these images and data files when a s +// specific point sized font is rendered and loads them for use. +// 7. Because of the original beta nature of the FreeType code you will probably want to hand +// touch the font bitmaps. +// +// Currently a define in the project turns on or off the FreeType code which is currently +// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and +// uncheck the exclude from build check box in the FreeType2 area of the Renderer project. + + +#include "tr_local.h" +#include "../qcommon/qcommon.h" + +#ifdef BUILD_FREETYPE +#include "../ft2/fterrors.h" +#include "../ft2/ftsystem.h" +#include "../ft2/ftimage.h" +#include "../ft2/freetype.h" +#include "../ft2/ftoutln.h" + +#define _FLOOR(x) ((x) & -64) +#define _CEIL(x) (((x)+63) & -64) +#define _TRUNC(x) ((x) >> 6) + +FT_Library ftLibrary = NULL; +#endif + +#define MAX_FONTS 6 +static int registeredFontCount = 0; +static fontInfo_t registeredFont[MAX_FONTS]; + +#ifdef BUILD_FREETYPE +void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) { + + *left = _FLOOR( glyph->metrics.horiBearingX ); + *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width ); + *width = _TRUNC(*right - *left); + + *top = _CEIL( glyph->metrics.horiBearingY ); + *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height ); + *height = _TRUNC( *top - *bottom ); + *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 ); +} + + +FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) { + + FT_Bitmap *bit2; + int left, right, width, top, bottom, height, pitch, size; + + R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch); + + if ( glyph->format == ft_glyph_format_outline ) { + size = pitch*height; + + bit2 = Z_Malloc(sizeof(FT_Bitmap)); + + bit2->width = width; + bit2->rows = height; + bit2->pitch = pitch; + bit2->pixel_mode = ft_pixel_mode_grays; + //bit2->pixel_mode = ft_pixel_mode_mono; + bit2->buffer = Z_Malloc(pitch*height); + bit2->num_grays = 256; + + Com_Memset( bit2->buffer, 0, size ); + + FT_Outline_Translate( &glyph->outline, -left, -bottom ); + + FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 ); + + glyphOut->height = height; + glyphOut->pitch = pitch; + glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1; + glyphOut->bottom = bottom; + + return bit2; + } + else { + ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n"); + } + return NULL; +} + +void WriteTGA (char *filename, byte *data, int width, int height) { + byte *buffer; + int i, c; + + buffer = Z_Malloc(width*height*4 + 18); + Com_Memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = width&255; + buffer[13] = width>>8; + buffer[14] = height&255; + buffer[15] = height>>8; + buffer[16] = 32; // pixel size + + // swap rgb to bgr + c = 18 + width * height * 4; + for (i=18 ; i<c ; i+=4) + { + buffer[i] = data[i-18+2]; // blue + buffer[i+1] = data[i-18+1]; // green + buffer[i+2] = data[i-18+0]; // red + buffer[i+3] = data[i-18+3]; // alpha + } + + ri.FS_WriteFile(filename, buffer, c); + + //f = fopen (filename, "wb"); + //fwrite (buffer, 1, c, f); + //fclose (f); + + Z_Free (buffer); +} + +static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) { + int i; + static glyphInfo_t glyph; + unsigned char *src, *dst; + float scaled_width, scaled_height; + FT_Bitmap *bitmap = NULL; + + Com_Memset(&glyph, 0, sizeof(glyphInfo_t)); + // make sure everything is here + if (face != NULL) { + FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT ); + bitmap = R_RenderGlyph(face->glyph, &glyph); + if (bitmap) { + glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1; + } else { + return &glyph; + } + + if (glyph.height > *maxHeight) { + *maxHeight = glyph.height; + } + + if (calcHeight) { + Z_Free(bitmap->buffer); + Z_Free(bitmap); + return &glyph; + } + +/* + // need to convert to power of 2 sizes so we do not get + // any scaling from the gl upload + for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1) + ; + for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1) + ; +*/ + + scaled_width = glyph.pitch; + scaled_height = glyph.height; + + // we need to make sure we fit + if (*xOut + scaled_width + 1 >= 255) { + if (*yOut + *maxHeight + 1 >= 255) { + *yOut = -1; + *xOut = -1; + Z_Free(bitmap->buffer); + Z_Free(bitmap); + return &glyph; + } else { + *xOut = 0; + *yOut += *maxHeight + 1; + } + } else if (*yOut + *maxHeight + 1 >= 255) { + *yOut = -1; + *xOut = -1; + Z_Free(bitmap->buffer); + Z_Free(bitmap); + return &glyph; + } + + + src = bitmap->buffer; + dst = imageOut + (*yOut * 256) + *xOut; + + if (bitmap->pixel_mode == ft_pixel_mode_mono) { + for (i = 0; i < glyph.height; i++) { + int j; + unsigned char *_src = src; + unsigned char *_dst = dst; + unsigned char mask = 0x80; + unsigned char val = *_src; + for (j = 0; j < glyph.pitch; j++) { + if (mask == 0x80) { + val = *_src++; + } + if (val & mask) { + *_dst = 0xff; + } + mask >>= 1; + + if ( mask == 0 ) { + mask = 0x80; + } + _dst++; + } + + src += glyph.pitch; + dst += 256; + + } + } else { + for (i = 0; i < glyph.height; i++) { + Com_Memcpy(dst, src, glyph.pitch); + src += glyph.pitch; + dst += 256; + } + } + + // we now have an 8 bit per pixel grey scale bitmap + // that is width wide and pf->ftSize->metrics.y_ppem tall + + glyph.imageHeight = scaled_height; + glyph.imageWidth = scaled_width; + glyph.s = (float)*xOut / 256; + glyph.t = (float)*yOut / 256; + glyph.s2 = glyph.s + (float)scaled_width / 256; + glyph.t2 = glyph.t + (float)scaled_height / 256; + + *xOut += scaled_width + 1; + } + + Z_Free(bitmap->buffer); + Z_Free(bitmap); + + return &glyph; +} +#endif + +static int fdOffset; +static byte *fdFile; + +int readInt() { + int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24); + fdOffset += 4; + return i; +} + +typedef union { + byte fred[4]; + float ffred; +} poor; + +float readFloat() { + poor me; +#if idppc + me.fred[0] = fdFile[fdOffset+3]; + me.fred[1] = fdFile[fdOffset+2]; + me.fred[2] = fdFile[fdOffset+1]; + me.fred[3] = fdFile[fdOffset+0]; +#else + me.fred[0] = fdFile[fdOffset+0]; + me.fred[1] = fdFile[fdOffset+1]; + me.fred[2] = fdFile[fdOffset+2]; + me.fred[3] = fdFile[fdOffset+3]; +#endif + fdOffset += 4; + return me.ffred; +} + +void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { +#ifdef BUILD_FREETYPE + FT_Face face; + int j, k, xOut, yOut, lastStart, imageNumber; + int scaledSize, newSize, maxHeight, left, satLevels; + unsigned char *out, *imageBuff; + glyphInfo_t *glyph; + image_t *image; + qhandle_t h; + float max; +#endif + void *faceData; + int i, len; + char name[1024]; + float dpi = 72; // + float glyphScale = 72.0f / dpi; // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 ) + + if (pointSize <= 0) { + pointSize = 12; + } + // we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font + glyphScale *= 48.0f / pointSize; + + // make sure the render thread is stopped + R_SyncRenderThread(); + + if (registeredFontCount >= MAX_FONTS) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: Too many fonts registered already.\n"); + return; + } + + Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize); + for (i = 0; i < registeredFontCount; i++) { + if (Q_stricmp(name, registeredFont[i].name) == 0) { + Com_Memcpy(font, ®isteredFont[i], sizeof(fontInfo_t)); + return; + } + } + + len = ri.FS_ReadFile(name, NULL); + if (len == sizeof(fontInfo_t)) { + ri.FS_ReadFile(name, &faceData); + fdOffset = 0; + fdFile = faceData; + for(i=0; i<GLYPHS_PER_FONT; i++) { + font->glyphs[i].height = readInt(); + font->glyphs[i].top = readInt(); + font->glyphs[i].bottom = readInt(); + font->glyphs[i].pitch = readInt(); + font->glyphs[i].xSkip = readInt(); + font->glyphs[i].imageWidth = readInt(); + font->glyphs[i].imageHeight = readInt(); + font->glyphs[i].s = readFloat(); + font->glyphs[i].t = readFloat(); + font->glyphs[i].s2 = readFloat(); + font->glyphs[i].t2 = readFloat(); + font->glyphs[i].glyph = readInt(); + Com_Memcpy(font->glyphs[i].shaderName, &fdFile[fdOffset], 32); + fdOffset += 32; + } + font->glyphScale = readFloat(); + Com_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH); + +// Com_Memcpy(font, faceData, sizeof(fontInfo_t)); + Q_strncpyz(font->name, name, sizeof(font->name)); + for (i = GLYPH_START; i < GLYPH_END; i++) { + font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName); + } + Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); + return; + } + +#ifndef BUILD_FREETYPE + ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType code not available\n"); +#else + if (ftLibrary == NULL) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType not initialized.\n"); + return; + } + + len = ri.FS_ReadFile(fontName, &faceData); + if (len <= 0) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: Unable to read font file\n"); + return; + } + + // allocate on the stack first in case we fail + if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, unable to allocate new face.\n"); + return; + } + + + if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: FreeType2, Unable to set face char size.\n"); + return; + } + + //*font = ®isteredFonts[registeredFontCount++]; + + // make a 256x256 image buffer, once it is full, register it, clean it and keep going + // until all glyphs are rendered + + out = Z_Malloc(1024*1024); + if (out == NULL) { + ri.Printf(PRINT_ALL, "RE_RegisterFont: Z_Malloc failure during output image creation.\n"); + return; + } + Com_Memset(out, 0, 1024*1024); + + maxHeight = 0; + + for (i = GLYPH_START; i < GLYPH_END; i++) { + glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue); + } + + xOut = 0; + yOut = 0; + i = GLYPH_START; + lastStart = i; + imageNumber = 0; + + while ( i <= GLYPH_END ) { + + glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse); + + if (xOut == -1 || yOut == -1 || i == GLYPH_END) { + // ran out of room + // we need to create an image from the bitmap, set all the handles in the glyphs to this point + // + + scaledSize = 256*256; + newSize = scaledSize * 4; + imageBuff = Z_Malloc(newSize); + left = 0; + max = 0; + satLevels = 255; + for ( k = 0; k < (scaledSize) ; k++ ) { + if (max < out[k]) { + max = out[k]; + } + } + + if (max > 0) { + max = 255/max; + } + + for ( k = 0; k < (scaledSize) ; k++ ) { + imageBuff[left++] = 255; + imageBuff[left++] = 255; + imageBuff[left++] = 255; + + imageBuff[left++] = ((float)out[k] * max); + } + + Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize); + if (r_saveFontData->integer) { + WriteTGA(name, imageBuff, 256, 256); + } + + //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize); + image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP); + h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse); + for (j = lastStart; j < i; j++) { + font->glyphs[j].glyph = h; + Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName)); + } + lastStart = i; + Com_Memset(out, 0, 1024*1024); + xOut = 0; + yOut = 0; + Z_Free(imageBuff); + i++; + } else { + Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t)); + i++; + } + } + + registeredFont[registeredFontCount].glyphScale = glyphScale; + font->glyphScale = glyphScale; + Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); + + if (r_saveFontData->integer) { + ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t)); + } + + Z_Free(out); + + ri.FS_FreeFile(faceData); +#endif +} + + + +void R_InitFreeType() { +#ifdef BUILD_FREETYPE + if (FT_Init_FreeType( &ftLibrary )) { + ri.Printf(PRINT_ALL, "R_InitFreeType: Unable to initialize FreeType.\n"); + } +#endif + registeredFontCount = 0; +} + + +void R_DoneFreeType() { +#ifdef BUILD_FREETYPE + if (ftLibrary) { + FT_Done_FreeType( ftLibrary ); + ftLibrary = NULL; + } +#endif + registeredFontCount = 0; +} + diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 11e7913..edebb4b 100755 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -1,2520 +1,2520 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_image.c
-#include "tr_local.h"
-
-/*
- * Include file for users of JPEG library.
- * You will need to have included system headers that define at least
- * the typedefs FILE and size_t before you can include jpeglib.h.
- * (stdio.h is sufficient on ANSI-conforming systems.)
- * You may also wish to include "jerror.h".
- */
-
-#define JPEG_INTERNALS
-#include "../jpeg-6/jpeglib.h"
-
-
-static void LoadBMP( const char *name, byte **pic, int *width, int *height );
-static void LoadTGA( const char *name, byte **pic, int *width, int *height );
-static void LoadJPG( const char *name, byte **pic, int *width, int *height );
-
-static byte s_intensitytable[256];
-static unsigned char s_gammatable[256];
-
-int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
-int gl_filter_max = GL_LINEAR;
-
-#define FILE_HASH_SIZE 1024
-static image_t* hashTable[FILE_HASH_SIZE];
-
-/*
-** R_GammaCorrect
-*/
-void R_GammaCorrect( byte *buffer, int bufSize ) {
- int i;
-
- for ( i = 0; i < bufSize; i++ ) {
- buffer[i] = s_gammatable[buffer[i]];
- }
-}
-
-typedef struct {
- char *name;
- int minimize, maximize;
-} textureMode_t;
-
-textureMode_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}
-};
-
-/*
-================
-return a hash value for the filename
-================
-*/
-static long generateHashValue( const char *fname ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash &= (FILE_HASH_SIZE-1);
- return hash;
-}
-
-/*
-===============
-GL_TextureMode
-===============
-*/
-void GL_TextureMode( const char *string ) {
- int i;
- image_t *glt;
-
- for ( i=0 ; i< 6 ; i++ ) {
- if ( !Q_stricmp( modes[i].name, string ) ) {
- break;
- }
- }
-
- // hack to prevent trilinear from being set on voodoo,
- // because their driver freaks...
- if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
- ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
- i = 3;
- }
-
-
- if ( i == 6 ) {
- ri.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 ; i < tr.numImages ; i++ ) {
- glt = tr.images[ i ];
- if ( glt->mipmap ) {
- GL_Bind (glt);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
- }
- }
-}
-
-/*
-===============
-R_SumOfUsedImages
-===============
-*/
-int R_SumOfUsedImages( void ) {
- int total;
- int i;
-
- total = 0;
- for ( i = 0; i < tr.numImages; i++ ) {
- if ( tr.images[i]->frameUsed == tr.frameCount ) {
- total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight;
- }
- }
-
- return total;
-}
-
-/*
-===============
-R_ImageList_f
-===============
-*/
-void R_ImageList_f( void ) {
- int i;
- image_t *image;
- int texels;
- const char *yesno[] = {
- "no ", "yes"
- };
-
- ri.Printf (PRINT_ALL, "\n -w-- -h-- -mm- -TMU- -if-- wrap --name-------\n");
- texels = 0;
-
- for ( i = 0 ; i < tr.numImages ; i++ ) {
- image = tr.images[ i ];
-
- texels += image->uploadWidth*image->uploadHeight;
- ri.Printf (PRINT_ALL, "%4i: %4i %4i %s %d ",
- i, image->uploadWidth, image->uploadHeight, yesno[image->mipmap], image->TMU );
- switch ( image->internalFormat ) {
- case 1:
- ri.Printf( PRINT_ALL, "I " );
- break;
- case 2:
- ri.Printf( PRINT_ALL, "IA " );
- break;
- case 3:
- ri.Printf( PRINT_ALL, "RGB " );
- break;
- case 4:
- ri.Printf( PRINT_ALL, "RGBA " );
- break;
- case GL_RGBA8:
- ri.Printf( PRINT_ALL, "RGBA8" );
- break;
- case GL_RGB8:
- ri.Printf( PRINT_ALL, "RGB8" );
- break;
- case GL_RGB4_S3TC:
- ri.Printf( PRINT_ALL, "S3TC " );
- break;
- case GL_RGBA4:
- ri.Printf( PRINT_ALL, "RGBA4" );
- break;
- case GL_RGB5:
- ri.Printf( PRINT_ALL, "RGB5 " );
- break;
- default:
- ri.Printf( PRINT_ALL, "???? " );
- }
-
- switch ( image->wrapClampMode ) {
- case GL_REPEAT:
- ri.Printf( PRINT_ALL, "rept " );
- break;
- case GL_CLAMP:
- ri.Printf( PRINT_ALL, "clmp " );
- break;
- default:
- ri.Printf( PRINT_ALL, "%4i ", image->wrapClampMode );
- break;
- }
-
- ri.Printf( PRINT_ALL, " %s\n", image->imgName );
- }
- ri.Printf (PRINT_ALL, " ---------\n");
- ri.Printf (PRINT_ALL, " %i total texels (not including mipmaps)\n", texels);
- ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages );
-}
-
-//=======================================================================
-
-/*
-================
-ResampleTexture
-
-Used to resample images in a more general than quartering fashion.
-
-This will only be filtered properly if the resampled size
-is greater than half the original size.
-
-If a larger shrinking is needed, use the mipmap function
-before or after.
-================
-*/
-static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out,
- int outwidth, int outheight ) {
- int i, j;
- unsigned *inrow, *inrow2;
- unsigned frac, fracstep;
- unsigned p1[2048], p2[2048];
- byte *pix1, *pix2, *pix3, *pix4;
-
- if (outwidth>2048)
- ri.Error(ERR_DROP, "ResampleTexture: max width");
-
- fracstep = inwidth*0x10000/outwidth;
-
- frac = fracstep>>2;
- for ( i=0 ; i<outwidth ; i++ ) {
- p1[i] = 4*(frac>>16);
- frac += fracstep;
- }
- frac = 3*(fracstep>>2);
- for ( i=0 ; i<outwidth ; i++ ) {
- p2[i] = 4*(frac>>16);
- frac += fracstep;
- }
-
- for (i=0 ; i<outheight ; i++, out += outwidth) {
- inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
- inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
- frac = fracstep >> 1;
- for (j=0 ; j<outwidth ; j++) {
- pix1 = (byte *)inrow + p1[j];
- pix2 = (byte *)inrow + p2[j];
- pix3 = (byte *)inrow2 + p1[j];
- pix4 = (byte *)inrow2 + p2[j];
- ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>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;
- }
- }
-}
-
-/*
-================
-R_LightScaleTexture
-
-Scale up the pixel values in a texture to increase the
-lighting range
-================
-*/
-void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )
-{
- if ( only_gamma )
- {
- if ( !glConfig.deviceSupportsGamma )
- {
- int i, c;
- byte *p;
-
- p = (byte *)in;
-
- c = inwidth*inheight;
- for (i=0 ; i<c ; i++, p+=4)
- {
- p[0] = s_gammatable[p[0]];
- p[1] = s_gammatable[p[1]];
- p[2] = s_gammatable[p[2]];
- }
- }
- }
- else
- {
- int i, c;
- byte *p;
-
- p = (byte *)in;
-
- c = inwidth*inheight;
-
- if ( glConfig.deviceSupportsGamma )
- {
- for (i=0 ; i<c ; i++, p+=4)
- {
- p[0] = s_intensitytable[p[0]];
- p[1] = s_intensitytable[p[1]];
- p[2] = s_intensitytable[p[2]];
- }
- }
- else
- {
- for (i=0 ; i<c ; i++, p+=4)
- {
- p[0] = s_gammatable[s_intensitytable[p[0]]];
- p[1] = s_gammatable[s_intensitytable[p[1]]];
- p[2] = s_gammatable[s_intensitytable[p[2]]];
- }
- }
- }
-}
-
-
-/*
-================
-R_MipMap2
-
-Operates in place, quartering the size of the texture
-Proper linear filter
-================
-*/
-static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {
- int i, j, k;
- byte *outpix;
- int inWidthMask, inHeightMask;
- int total;
- int outWidth, outHeight;
- unsigned *temp;
-
- outWidth = inWidth >> 1;
- outHeight = inHeight >> 1;
- temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 );
-
- inWidthMask = inWidth - 1;
- inHeightMask = inHeight - 1;
-
- for ( i = 0 ; i < outHeight ; i++ ) {
- for ( j = 0 ; j < outWidth ; j++ ) {
- outpix = (byte *) ( temp + i * outWidth + j );
- for ( k = 0 ; k < 4 ; k++ ) {
- total =
- 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
-
- 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
-
- 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
-
- 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
- 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
- 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
- outpix[k] = total / 36;
- }
- }
- }
-
- Com_Memcpy( in, temp, outWidth * outHeight * 4 );
- ri.Hunk_FreeTempMemory( temp );
-}
-
-/*
-================
-R_MipMap
-
-Operates in place, quartering the size of the texture
-================
-*/
-static void R_MipMap (byte *in, int width, int height) {
- int i, j;
- byte *out;
- int row;
-
- if ( !r_simpleMipMaps->integer ) {
- R_MipMap2( (unsigned *)in, width, height );
- return;
- }
-
- if ( width == 1 && height == 1 ) {
- return;
- }
-
- row = width * 4;
- out = in;
- width >>= 1;
- height >>= 1;
-
- if ( width == 0 || height == 0 ) {
- width += height; // get largest
- for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
- out[0] = ( in[0] + in[4] )>>1;
- out[1] = ( in[1] + in[5] )>>1;
- out[2] = ( in[2] + in[6] )>>1;
- out[3] = ( in[3] + in[7] )>>1;
- }
- return;
- }
-
- for (i=0 ; i<height ; i++, in+=row) {
- for (j=0 ; j<width ; j++, out+=4, in+=8) {
- out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
- out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
- out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
- out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
- }
- }
-}
-
-
-/*
-==================
-R_BlendOverTexture
-
-Apply a color blend over a set of pixels
-==================
-*/
-static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {
- int i;
- int inverseAlpha;
- int premult[3];
-
- inverseAlpha = 255 - blend[3];
- premult[0] = blend[0] * blend[3];
- premult[1] = blend[1] * blend[3];
- premult[2] = blend[2] * blend[3];
-
- for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
- data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
- data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
- data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
- }
-}
-
-byte mipBlendColors[16][4] = {
- {0,0,0,0},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
- {255,0,0,128},
- {0,255,0,128},
- {0,0,255,128},
-};
-
-
-/*
-===============
-Upload32
-
-===============
-*/
-extern qboolean charSet;
-static void Upload32( unsigned *data,
- int width, int height,
- qboolean mipmap,
- qboolean picmip,
- qboolean lightMap,
- int *format,
- int *pUploadWidth, int *pUploadHeight )
-{
- int samples;
- unsigned *scaledBuffer = NULL;
- unsigned *resampledBuffer = NULL;
- int scaled_width, scaled_height;
- int i, c;
- byte *scan;
- GLenum internalFormat = GL_RGB;
- float rMax = 0, gMax = 0, bMax = 0;
-
- //
- // convert to exact power of 2 sizes
- //
- for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
- ;
- for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
- ;
- if ( r_roundImagesDown->integer && scaled_width > width )
- scaled_width >>= 1;
- if ( r_roundImagesDown->integer && scaled_height > height )
- scaled_height >>= 1;
-
- if ( scaled_width != width || scaled_height != height ) {
- resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );
- ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height);
- data = resampledBuffer;
- width = scaled_width;
- height = scaled_height;
- }
-
- //
- // perform optional picmip operation
- //
- if ( picmip ) {
- scaled_width >>= r_picmip->integer;
- scaled_height >>= r_picmip->integer;
- }
-
- //
- // clamp to minimum size
- //
- if (scaled_width < 1) {
- scaled_width = 1;
- }
- if (scaled_height < 1) {
- scaled_height = 1;
- }
-
- //
- // clamp to the current upper OpenGL limit
- // scale both axis down equally so we don't have to
- // deal with a half mip resampling
- //
- while ( scaled_width > glConfig.maxTextureSize
- || scaled_height > glConfig.maxTextureSize ) {
- scaled_width >>= 1;
- scaled_height >>= 1;
- }
-
- scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
-
- //
- // scan the texture for each channel's max values
- // and verify if the alpha channel is being used or not
- //
- c = width*height;
- scan = ((byte *)data);
- samples = 3;
- if (!lightMap) {
- for ( i = 0; i < c; i++ )
- {
- if ( scan[i*4+0] > rMax )
- {
- rMax = scan[i*4+0];
- }
- if ( scan[i*4+1] > gMax )
- {
- gMax = scan[i*4+1];
- }
- if ( scan[i*4+2] > bMax )
- {
- bMax = scan[i*4+2];
- }
- if ( scan[i*4 + 3] != 255 )
- {
- samples = 4;
- break;
- }
- }
- // select proper internal format
- if ( samples == 3 )
- {
- if ( glConfig.textureCompression == TC_S3TC )
- {
- internalFormat = GL_RGB4_S3TC;
- }
- else if ( r_texturebits->integer == 16 )
- {
- internalFormat = GL_RGB5;
- }
- else if ( r_texturebits->integer == 32 )
- {
- internalFormat = GL_RGB8;
- }
- else
- {
- internalFormat = 3;
- }
- }
- else if ( samples == 4 )
- {
- if ( r_texturebits->integer == 16 )
- {
- internalFormat = GL_RGBA4;
- }
- else if ( r_texturebits->integer == 32 )
- {
- internalFormat = GL_RGBA8;
- }
- else
- {
- internalFormat = 4;
- }
- }
- } else {
- internalFormat = 3;
- }
- // copy or resample data as appropriate for first MIP level
- if ( ( scaled_width == width ) &&
- ( scaled_height == height ) ) {
- if (!mipmap)
- {
- qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
- *format = internalFormat;
-
- goto done;
- }
- Com_Memcpy (scaledBuffer, data, width*height*4);
- }
- else
- {
- // use the normal mip-mapping function to go down from here
- while ( width > scaled_width || height > scaled_height ) {
- R_MipMap( (byte *)data, width, height );
- width >>= 1;
- height >>= 1;
- if ( width < 1 ) {
- width = 1;
- }
- if ( height < 1 ) {
- height = 1;
- }
- }
- Com_Memcpy( scaledBuffer, data, width * height * 4 );
- }
-
- R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap );
-
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
- *format = internalFormat;
-
- qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
-
- if (mipmap)
- {
- int miplevel;
-
- miplevel = 0;
- while (scaled_width > 1 || scaled_height > 1)
- {
- R_MipMap( (byte *)scaledBuffer, 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 ( r_colorMipLevels->integer ) {
- R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] );
- }
-
- qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
- }
- }
-done:
-
- 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_LINEAR );
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- }
-
- GL_CheckErrors();
-
- if ( scaledBuffer != 0 )
- ri.Hunk_FreeTempMemory( scaledBuffer );
- if ( resampledBuffer != 0 )
- ri.Hunk_FreeTempMemory( resampledBuffer );
-}
-
-
-/*
-================
-R_CreateImage
-
-This is the only way any image_t are created
-================
-*/
-image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
- qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
- image_t *image;
- qboolean isLightmap = qfalse;
- long hash;
-
- if (strlen(name) >= MAX_QPATH ) {
- ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
- }
- if ( !strncmp( name, "*lightmap", 9 ) ) {
- isLightmap = qtrue;
- }
-
- if ( tr.numImages == MAX_DRAWIMAGES ) {
- ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n");
- }
-
- image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
- image->texnum = 1024 + tr.numImages;
- tr.numImages++;
-
- image->mipmap = mipmap;
- image->allowPicmip = allowPicmip;
-
- strcpy (image->imgName, name);
-
- image->width = width;
- image->height = height;
- image->wrapClampMode = glWrapClampMode;
-
- // lightmaps are always allocated on TMU 1
- if ( qglActiveTextureARB && isLightmap ) {
- image->TMU = 1;
- } else {
- image->TMU = 0;
- }
-
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( image->TMU );
- }
-
- GL_Bind(image);
-
- Upload32( (unsigned *)pic, image->width, image->height,
- image->mipmap,
- allowPicmip,
- isLightmap,
- &image->internalFormat,
- &image->uploadWidth,
- &image->uploadHeight );
-
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
-
- qglBindTexture( GL_TEXTURE_2D, 0 );
-
- if ( image->TMU == 1 ) {
- GL_SelectTexture( 0 );
- }
-
- hash = generateHashValue(name);
- image->next = hashTable[hash];
- hashTable[hash] = image;
-
- return image;
-}
-
-
-/*
-=========================================================
-
-BMP LOADING
-
-=========================================================
-*/
-typedef struct
-{
- char id[2];
- unsigned long fileSize;
- unsigned long reserved0;
- unsigned long bitmapDataOffset;
- unsigned long bitmapHeaderSize;
- unsigned long width;
- unsigned long height;
- unsigned short planes;
- unsigned short bitsPerPixel;
- unsigned long compression;
- unsigned long bitmapDataSize;
- unsigned long hRes;
- unsigned long vRes;
- unsigned long colors;
- unsigned long importantColors;
- unsigned char palette[256][4];
-} BMPHeader_t;
-
-static void LoadBMP( const char *name, byte **pic, int *width, int *height )
-{
- int columns, rows, numPixels;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *buffer;
- int length;
- BMPHeader_t bmpHeader;
- byte *bmpRGBA;
-
- *pic = NULL;
-
- //
- // load the file
- //
- length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
- if (!buffer) {
- return;
- }
-
- buf_p = buffer;
-
- bmpHeader.id[0] = *buf_p++;
- bmpHeader.id[1] = *buf_p++;
- bmpHeader.fileSize = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.width = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.height = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.planes = LittleShort( * ( short * ) buf_p );
- buf_p += 2;
- bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
- buf_p += 2;
- bmpHeader.compression = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.hRes = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.vRes = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.colors = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
- bmpHeader.importantColors = LittleLong( * ( long * ) buf_p );
- buf_p += 4;
-
- Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
-
- if ( bmpHeader.bitsPerPixel == 8 )
- buf_p += 1024;
-
- if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
- {
- ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
- }
- if ( bmpHeader.fileSize != length )
- {
- ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name );
- }
- if ( bmpHeader.compression != 0 )
- {
- ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
- }
- if ( bmpHeader.bitsPerPixel < 8 )
- {
- ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
- }
-
- columns = bmpHeader.width;
- rows = bmpHeader.height;
- if ( rows < 0 )
- rows = -rows;
- numPixels = columns * rows;
-
- if ( width )
- *width = columns;
- if ( height )
- *height = rows;
-
- bmpRGBA = ri.Malloc( numPixels * 4 );
- *pic = bmpRGBA;
-
-
- for ( row = rows-1; row >= 0; row-- )
- {
- pixbuf = bmpRGBA + row*columns*4;
-
- for ( column = 0; column < columns; column++ )
- {
- unsigned char red, green, blue, alpha;
- int palIndex;
- unsigned short shortPixel;
-
- switch ( bmpHeader.bitsPerPixel )
- {
- case 8:
- palIndex = *buf_p++;
- *pixbuf++ = bmpHeader.palette[palIndex][2];
- *pixbuf++ = bmpHeader.palette[palIndex][1];
- *pixbuf++ = bmpHeader.palette[palIndex][0];
- *pixbuf++ = 0xff;
- break;
- case 16:
- shortPixel = * ( unsigned short * ) pixbuf;
- pixbuf += 2;
- *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
- *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
- *pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
- *pixbuf++ = 0xff;
- break;
-
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alpha = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alpha;
- break;
- default:
- ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
- break;
- }
- }
- }
-
- ri.FS_FreeFile( buffer );
-
-}
-
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-
-/*
-==============
-LoadPCX
-==============
-*/
-static void LoadPCX ( const 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;
- int xmax, ymax;
-
- *pic = NULL;
- *palette = NULL;
-
- //
- // load the file
- //
- len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);
- if (!raw) {
- return;
- }
-
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw;
- raw = &pcx->data;
-
- xmax = LittleShort(pcx->xmax);
- ymax = LittleShort(pcx->ymax);
-
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->bits_per_pixel != 8
- || xmax >= 1024
- || ymax >= 1024)
- {
- ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);
- return;
- }
-
- out = ri.Malloc ( (ymax+1) * (xmax+1) );
-
- *pic = out;
-
- pix = out;
-
- if (palette)
- {
- *palette = ri.Malloc(768);
- Com_Memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
-
- if (width)
- *width = xmax+1;
- if (height)
- *height = ymax+1;
-// FIXME: use bytes_per_line here?
-
- for (y=0 ; y<=ymax ; y++, pix += xmax+1)
- {
- for (x=0 ; x<=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.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
- ri.Free (*pic);
- *pic = NULL;
- }
-
- ri.FS_FreeFile (pcx);
-}
-
-
-/*
-==============
-LoadPCX32
-==============
-*/
-static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height) {
- byte *palette;
- byte *pic8;
- int i, c, p;
- byte *pic32;
-
- LoadPCX (filename, &pic8, &palette, width, height);
- if (!pic8) {
- *pic = NULL;
- return;
- }
-
- c = (*width) * (*height);
- pic32 = *pic = ri.Malloc(4 * c );
- for (i = 0 ; i < c ; i++) {
- p = pic8[i];
- pic32[0] = palette[p*3];
- pic32[1] = palette[p*3 + 1];
- pic32[2] = palette[p*3 + 2];
- pic32[3] = 255;
- pic32 += 4;
- }
-
- ri.Free (pic8);
- ri.Free (palette);
-}
-
-/*
-=========================================================
-
-TARGA LOADING
-
-=========================================================
-*/
-
-/*
-=============
-LoadTGA
-=============
-*/
-static void LoadTGA ( const char *name, byte **pic, int *width, int *height)
-{
- int columns, rows, numPixels;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *buffer;
- TargaHeader targa_header;
- byte *targa_rgba;
-
- *pic = NULL;
-
- //
- // load the file
- //
- ri.FS_ReadFile ( ( char * ) name, (void **)&buffer);
- if (!buffer) {
- 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
- && targa_header.image_type != 3 )
- {
- ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
- }
-
- if ( targa_header.colormap_type != 0 )
- {
- ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" );
- }
-
- if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
- {
- ri.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 = ri.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 || targa_header.image_type == 3 )
- {
- // Uncompressed RGB or gray scale image
- for(row=rows-1; row>=0; row--)
- {
- pixbuf = targa_rgba + row*columns*4;
- for(column=0; column<columns; column++)
- {
- unsigned char red,green,blue,alphabyte;
- switch (targa_header.pixel_size)
- {
-
- case 8:
- blue = *buf_p++;
- green = blue;
- red = blue;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
-
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- default:
- ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
- break;
- }
- }
- }
- }
- else if (targa_header.image_type==10) { // Runlength encoded RGB images
- unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
-
- red = 0;
- green = 0;
- blue = 0;
- alphabyte = 0xff;
-
- for(row=rows-1; row>=0; row--) {
- pixbuf = targa_rgba + row*columns*4;
- for(column=0; column<columns; ) {
- packetHeader= *buf_p++;
- packetSize = 1 + (packetHeader & 0x7f);
- if (packetHeader & 0x80) { // run-length packet
- switch (targa_header.pixel_size) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- break;
- default:
- ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
- break;
- }
-
- for(j=0;j<packetSize;j++) {
- *pixbuf++=red;
- *pixbuf++=green;
- *pixbuf++=blue;
- *pixbuf++=alphabyte;
- column++;
- if (column==columns) { // run spans across rows
- column=0;
- if (row>0)
- row--;
- else
- goto breakOut;
- pixbuf = targa_rgba + row*columns*4;
- }
- }
- }
- else { // non run-length packet
- for(j=0;j<packetSize;j++) {
- switch (targa_header.pixel_size) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- default:
- ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
- break;
- }
- column++;
- if (column==columns) { // pixel packet run spans across rows
- column=0;
- if (row>0)
- row--;
- else
- goto breakOut;
- pixbuf = targa_rgba + row*columns*4;
- }
- }
- }
- }
- breakOut:;
- }
- }
-
-#if 0
- // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs
- // bk0101024 - fix from Leonardo
- // bit 5 set => top-down
- if (targa_header.attributes & 0x20) {
- unsigned char *flip = (unsigned char*)malloc (columns*4);
- unsigned char *src, *dst;
-
- for (row = 0; row < rows/2; row++) {
- src = targa_rgba + row * 4 * columns;
- dst = targa_rgba + (rows - row - 1) * 4 * columns;
-
- memcpy (flip, src, columns*4);
- memcpy (src, dst, columns*4);
- memcpy (dst, flip, columns*4);
- }
- free (flip);
- }
-#endif
- // instead we just print a warning
- if (targa_header.attributes & 0x20) {
- ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
- }
-
- ri.FS_FreeFile (buffer);
-}
-
-static void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) {
- /* This struct contains the JPEG decompression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- */
- struct jpeg_decompress_struct cinfo;
- /* We use our private extension JPEG error handler.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- JSAMPARRAY buffer; /* Output row buffer */
- int row_stride; /* physical row width in output buffer */
- unsigned char *out;
- byte *fbuffer;
- byte *bbuf;
-
- /* In this example we want to open the input file before doing anything else,
- * so that the setjmp() error recovery below can assume the file is open.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to read binary files.
- */
-
- ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);
- if (!fbuffer) {
- return;
- }
-
- /* Step 1: allocate and initialize JPEG decompression object */
-
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
-
- /* Now we can initialize the JPEG decompression object. */
- jpeg_create_decompress(&cinfo);
-
- /* Step 2: specify data source (eg, a file) */
-
- jpeg_stdio_src(&cinfo, fbuffer);
-
- /* Step 3: read file parameters with jpeg_read_header() */
-
- (void) jpeg_read_header(&cinfo, TRUE);
- /* We can ignore the return value from jpeg_read_header since
- * (a) suspension is not possible with the stdio data source, and
- * (b) we passed TRUE to reject a tables-only JPEG file as an error.
- * See libjpeg.doc for more info.
- */
-
- /* Step 4: set parameters for decompression */
-
- /* In this example, we don't need to change any of the defaults set by
- * jpeg_read_header(), so we do nothing here.
- */
-
- /* Step 5: Start decompressor */
-
- (void) jpeg_start_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
-
- /* We may need to do some setup of our own at this point before reading
- * the data. After jpeg_start_decompress() we have the correct scaled
- * output image dimensions available, as well as the output colormap
- * if we asked for color quantization.
- * In this example, we need to make an output work buffer of the right size.
- */
- /* JSAMPLEs per row in output buffer */
- row_stride = cinfo.output_width * cinfo.output_components;
-
- out = ri.Malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components);
-
- *pic = out;
- *width = cinfo.output_width;
- *height = cinfo.output_height;
-
- /* Step 6: while (scan lines remain to be read) */
- /* jpeg_read_scanlines(...); */
-
- /* Here we use the library's state variable cinfo.output_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- */
- while (cinfo.output_scanline < cinfo.output_height) {
- /* jpeg_read_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could ask for
- * more than one scanline at a time if that's more convenient.
- */
- bbuf = ((out+(row_stride*cinfo.output_scanline)));
- buffer = &bbuf;
- (void) jpeg_read_scanlines(&cinfo, buffer, 1);
- }
-
- // clear all the alphas to 255
- {
- int i, j;
- byte *buf;
-
- buf = *pic;
-
- j = cinfo.output_width * cinfo.output_height * 4;
- for ( i = 3 ; i < j ; i+=4 ) {
- buf[i] = 255;
- }
- }
-
- /* Step 7: Finish decompression */
-
- (void) jpeg_finish_decompress(&cinfo);
- /* We can ignore the return value since suspension is not possible
- * with the stdio data source.
- */
-
- /* Step 8: Release JPEG decompression object */
-
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_decompress(&cinfo);
-
- /* After finish_decompress, we can close the input file.
- * Here we postpone it until after no more JPEG errors are possible,
- * so as to simplify the setjmp error logic above. (Actually, I don't
- * think that jpeg_destroy can do an error exit, but why assume anything...)
- */
- ri.FS_FreeFile (fbuffer);
-
- /* At this point you may want to check to see whether any corrupt-data
- * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
- */
-
- /* And we're done! */
-}
-
-
-/* Expanded data destination object for stdio output */
-
-typedef struct {
- struct jpeg_destination_mgr pub; /* public fields */
-
- byte* outfile; /* target stream */
- int size;
-} my_destination_mgr;
-
-typedef my_destination_mgr * my_dest_ptr;
-
-
-/*
- * Initialize destination --- called by jpeg_start_compress
- * before any data is actually written.
- */
-
-void init_destination (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
-
- dest->pub.next_output_byte = dest->outfile;
- dest->pub.free_in_buffer = dest->size;
-}
-
-
-/*
- * Empty the output buffer --- called whenever buffer fills up.
- *
- * In typical applications, this should write the entire output buffer
- * (ignoring the current state of next_output_byte & free_in_buffer),
- * reset the pointer & count to the start of the buffer, and return TRUE
- * indicating that the buffer has been dumped.
- *
- * In applications that need to be able to suspend compression due to output
- * overrun, a FALSE return indicates that the buffer cannot be emptied now.
- * In this situation, the compressor will return to its caller (possibly with
- * an indication that it has not accepted all the supplied scanlines). The
- * application should resume compression after it has made more room in the
- * output buffer. Note that there are substantial restrictions on the use of
- * suspension --- see the documentation.
- *
- * When suspending, the compressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_output_byte & free_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point will be regenerated after resumption, so do not
- * write it out when emptying the buffer externally.
- */
-
-boolean empty_output_buffer (j_compress_ptr cinfo)
-{
- return TRUE;
-}
-
-
-/*
- * Compression initialization.
- * Before calling this, all parameters and a data destination must be set up.
- *
- * We require a write_all_tables parameter as a failsafe check when writing
- * multiple datastreams from the same compression object. Since prior runs
- * will have left all the tables marked sent_table=TRUE, a subsequent run
- * would emit an abbreviated stream (no tables) by default. This may be what
- * is wanted, but for safety's sake it should not be the default behavior:
- * programmers should have to make a deliberate choice to emit abbreviated
- * images. Therefore the documentation and examples should encourage people
- * to pass write_all_tables=TRUE; then it will take active thought to do the
- * wrong thing.
- */
-
-GLOBAL void
-jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
-{
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- if (write_all_tables)
- jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
-
- /* (Re)initialize error mgr and destination modules */
- (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
- (*cinfo->dest->init_destination) (cinfo);
- /* Perform master selection of active modules */
- jinit_compress_master(cinfo);
- /* Set up for the first pass */
- (*cinfo->master->prepare_for_pass) (cinfo);
- /* Ready for application to drive first pass through jpeg_write_scanlines
- * or jpeg_write_raw_data.
- */
- cinfo->next_scanline = 0;
- cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
-}
-
-
-/*
- * Write some scanlines of data to the JPEG compressor.
- *
- * The return value will be the number of lines actually written.
- * This should be less than the supplied num_lines only in case that
- * the data destination module has requested suspension of the compressor,
- * or if more than image_height scanlines are passed in.
- *
- * Note: we warn about excess calls to jpeg_write_scanlines() since
- * this likely signals an application programmer error. However,
- * excess scanlines passed in the last valid call are *silently* ignored,
- * so that the application need not adjust num_lines for end-of-image
- * when using a multiple-scanline buffer.
- */
-
-GLOBAL JDIMENSION
-jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION num_lines)
-{
- JDIMENSION row_ctr, rows_left;
-
- if (cinfo->global_state != CSTATE_SCANNING)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (cinfo->next_scanline >= cinfo->image_height)
- WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
-
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->next_scanline;
- cinfo->progress->pass_limit = (long) cinfo->image_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
-
- /* Give master control module another chance if this is first call to
- * jpeg_write_scanlines. This lets output of the frame/scan headers be
- * delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_scanlines.
- */
- if (cinfo->master->call_pass_startup)
- (*cinfo->master->pass_startup) (cinfo);
-
- /* Ignore any extra scanlines at bottom of image. */
- rows_left = cinfo->image_height - cinfo->next_scanline;
- if (num_lines > rows_left)
- num_lines = rows_left;
-
- row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
- cinfo->next_scanline += row_ctr;
- return row_ctr;
-}
-
-/*
- * Terminate destination --- called by jpeg_finish_compress
- * after all data has been written. Usually needs to flush buffer.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
-
-static int hackSize;
-
-void term_destination (j_compress_ptr cinfo)
-{
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
- size_t datacount = dest->size - dest->pub.free_in_buffer;
- hackSize = datacount;
-}
-
-
-/*
- * Prepare for output to a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing compression.
- */
-
-void jpegDest (j_compress_ptr cinfo, byte* outfile, int size)
-{
- my_dest_ptr dest;
-
- /* The destination object is made permanent so that multiple JPEG images
- * can be written to the same file without re-executing jpeg_stdio_dest.
- * This makes it dangerous to use this manager and a different destination
- * manager serially with the same JPEG object, because their private object
- * sizes may be different. Caveat programmer.
- */
- if (cinfo->dest == NULL) { /* first time for this JPEG object? */
- cinfo->dest = (struct jpeg_destination_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof(my_destination_mgr));
- }
-
- dest = (my_dest_ptr) cinfo->dest;
- dest->pub.init_destination = init_destination;
- dest->pub.empty_output_buffer = empty_output_buffer;
- dest->pub.term_destination = term_destination;
- dest->outfile = outfile;
- dest->size = size;
-}
-
-void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer) {
- /* This struct contains the JPEG compression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- * It is possible to have several such structures, representing multiple
- * compression/decompression processes, in existence at once. We refer
- * to any one struct (and its associated working data) as a "JPEG object".
- */
- struct jpeg_compress_struct cinfo;
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
- int row_stride; /* physical row width in image buffer */
- unsigned char *out;
-
- /* Step 1: allocate and initialize JPEG compression object */
-
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
- /* Now we can initialize the JPEG compression object. */
- jpeg_create_compress(&cinfo);
-
- /* Step 2: specify data destination (eg, a file) */
- /* Note: steps 2 and 3 can be done in either order. */
-
- /* Here we use the library-supplied code to send compressed data to a
- * stdio stream. You can also write your own code to do something else.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to write binary files.
- */
- out = ri.Hunk_AllocateTempMemory(image_width*image_height*4);
- jpegDest(&cinfo, out, image_width*image_height*4);
-
- /* Step 3: set parameters for compression */
-
- /* First we supply a description of the input image.
- * Four fields of the cinfo struct must be filled in:
- */
- cinfo.image_width = image_width; /* image width and height, in pixels */
- cinfo.image_height = image_height;
- cinfo.input_components = 4; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
- /* Now use the library's routine to set default compression parameters.
- * (You must set at least cinfo.in_color_space before calling this,
- * since the defaults depend on the source color space.)
- */
- jpeg_set_defaults(&cinfo);
- /* Now you can set any non-default parameters you wish to.
- * Here we just illustrate the use of quality (quantization table) scaling:
- */
- jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
-
- /* Step 4: Start compressor */
-
- /* TRUE ensures that we will write a complete interchange-JPEG file.
- * Pass TRUE unless you are very sure of what you're doing.
- */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Step 5: while (scan lines remain to be written) */
- /* jpeg_write_scanlines(...); */
-
- /* Here we use the library's state variable cinfo.next_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- * To keep things simple, we pass one scanline per call; you can pass
- * more if you wish, though.
- */
- row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */
-
- while (cinfo.next_scanline < cinfo.image_height) {
- /* jpeg_write_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could pass
- * more than one scanline at a time if that's more convenient.
- */
- row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
- (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
-
- /* Step 6: Finish compression */
-
- jpeg_finish_compress(&cinfo);
- /* After finish_compress, we can close the output file. */
- ri.FS_WriteFile( filename, out, hackSize );
-
- ri.Hunk_FreeTempMemory(out);
-
- /* Step 7: release JPEG compression object */
-
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_compress(&cinfo);
-
- /* And we're done! */
-}
-
-//===================================================================
-
-/*
-=================
-R_LoadImage
-
-Loads any of the supported image types into a cannonical
-32 bit format.
-=================
-*/
-void R_LoadImage( const char *name, byte **pic, int *width, int *height ) {
- int len;
-
- *pic = NULL;
- *width = 0;
- *height = 0;
-
- len = strlen(name);
- if (len<5) {
- return;
- }
-
- if ( !Q_stricmp( name+len-4, ".tga" ) ) {
- LoadTGA( name, pic, width, height ); // try tga first
- if (!*pic) { //
- char altname[MAX_QPATH]; // try jpg in place of tga
- strcpy( altname, name );
- len = strlen( altname );
- altname[len-3] = 'j';
- altname[len-2] = 'p';
- altname[len-1] = 'g';
- LoadJPG( altname, pic, width, height );
- }
- } else if ( !Q_stricmp(name+len-4, ".pcx") ) {
- LoadPCX32( name, pic, width, height );
- } else if ( !Q_stricmp( name+len-4, ".bmp" ) ) {
- LoadBMP( name, pic, width, height );
- } else if ( !Q_stricmp( name+len-4, ".jpg" ) ) {
- LoadJPG( name, pic, width, height );
- }
-}
-
-
-/*
-===============
-R_FindImageFile
-
-Finds or loads the given image.
-Returns NULL if it fails, not a default image.
-==============
-*/
-image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
- image_t *image;
- int width, height;
- byte *pic;
- long hash;
-
- if (!name) {
- return NULL;
- }
-
- hash = generateHashValue(name);
-
- //
- // see if the image is already loaded
- //
- for (image=hashTable[hash]; image; image=image->next) {
- if ( !strcmp( name, image->imgName ) ) {
- // the white image can be used with any set of parms, but other mismatches are errors
- if ( strcmp( name, "*white" ) ) {
- if ( image->mipmap != mipmap ) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed mipmap parm\n", name );
- }
- if ( image->allowPicmip != allowPicmip ) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed allowPicmip parm\n", name );
- }
- if ( image->wrapClampMode != glWrapClampMode ) {
- ri.Printf( PRINT_ALL, "WARNING: reused image %s with mixed glWrapClampMode parm\n", name );
- }
- }
- return image;
- }
- }
-
- //
- // load the pic from disk
- //
- R_LoadImage( name, &pic, &width, &height );
- if ( pic == NULL ) { // if we dont get a successful load
- char altname[MAX_QPATH]; // copy the name
- int len; //
- strcpy( altname, name ); //
- len = strlen( altname ); //
- altname[len-3] = toupper(altname[len-3]); // and try upper case extension for unix systems
- altname[len-2] = toupper(altname[len-2]); //
- altname[len-1] = toupper(altname[len-1]); //
- ri.Printf( PRINT_ALL, "trying %s...\n", altname ); //
- R_LoadImage( altname, &pic, &width, &height ); //
- if (pic == NULL) { // if that fails
- return NULL; // bail
- }
- }
-
- image = R_CreateImage( ( char * ) name, pic, width, height, mipmap, allowPicmip, glWrapClampMode );
- ri.Free( pic );
- return image;
-}
-
-
-/*
-================
-R_CreateDlightImage
-================
-*/
-#define DLIGHT_SIZE 16
-static void R_CreateDlightImage( void ) {
- int x,y;
- byte data[DLIGHT_SIZE][DLIGHT_SIZE][4];
- int b;
-
- // make a centered inverse-square falloff blob for dynamic lighting
- for (x=0 ; x<DLIGHT_SIZE ; x++) {
- for (y=0 ; y<DLIGHT_SIZE ; y++) {
- float d;
-
- d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +
- ( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );
- b = 4000 / d;
- if (b > 255) {
- b = 255;
- } else if ( b < 75 ) {
- b = 0;
- }
- data[y][x][0] =
- data[y][x][1] =
- data[y][x][2] = b;
- data[y][x][3] = 255;
- }
- }
- tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, qfalse, qfalse, GL_CLAMP );
-}
-
-
-/*
-=================
-R_InitFogTable
-=================
-*/
-void R_InitFogTable( void ) {
- int i;
- float d;
- float exp;
-
- exp = 0.5;
-
- for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
- d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
-
- tr.fogTable[i] = d;
- }
-}
-
-/*
-================
-R_FogFactor
-
-Returns a 0.0 to 1.0 fog density value
-This is called for each texel of the fog texture on startup
-and for each vertex of transparent shaders in fog dynamically
-================
-*/
-float R_FogFactor( float s, float t ) {
- float d;
-
- s -= 1.0/512;
- if ( s < 0 ) {
- return 0;
- }
- if ( t < 1.0/32 ) {
- return 0;
- }
- if ( t < 31.0/32 ) {
- s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
- }
-
- // we need to leave a lot of clamp range
- s *= 8;
-
- if ( s > 1.0 ) {
- s = 1.0;
- }
-
- d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
-
- return d;
-}
-
-/*
-================
-R_CreateFogImage
-================
-*/
-#define FOG_S 256
-#define FOG_T 32
-static void R_CreateFogImage( void ) {
- int x,y;
- byte *data;
- float g;
- float d;
- float borderColor[4];
-
- data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );
-
- g = 2.0;
-
- // S is distance, T is depth
- for (x=0 ; x<FOG_S ; x++) {
- for (y=0 ; y<FOG_T ; y++) {
- d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );
-
- data[(y*FOG_S+x)*4+0] =
- data[(y*FOG_S+x)*4+1] =
- data[(y*FOG_S+x)*4+2] = 255;
- data[(y*FOG_S+x)*4+3] = 255*d;
- }
- }
- // standard openGL clamping doesn't really do what we want -- it includes
- // the border color at the edges. OpenGL 1.2 has clamp-to-edge, which does
- // what we want.
- tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, qfalse, qfalse, GL_CLAMP );
- ri.Hunk_FreeTempMemory( data );
-
- borderColor[0] = 1.0;
- borderColor[1] = 1.0;
- borderColor[2] = 1.0;
- borderColor[3] = 1;
-
- qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
-}
-
-/*
-==================
-R_CreateDefaultImage
-==================
-*/
-#define DEFAULT_SIZE 16
-static void R_CreateDefaultImage( void ) {
- int x;
- byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
-
- // the default image will be a box, to allow you to see the mapping coordinates
- Com_Memset( data, 32, sizeof( data ) );
- for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
- data[0][x][0] =
- data[0][x][1] =
- data[0][x][2] =
- data[0][x][3] = 255;
-
- data[x][0][0] =
- data[x][0][1] =
- data[x][0][2] =
- data[x][0][3] = 255;
-
- data[DEFAULT_SIZE-1][x][0] =
- data[DEFAULT_SIZE-1][x][1] =
- data[DEFAULT_SIZE-1][x][2] =
- data[DEFAULT_SIZE-1][x][3] = 255;
-
- data[x][DEFAULT_SIZE-1][0] =
- data[x][DEFAULT_SIZE-1][1] =
- data[x][DEFAULT_SIZE-1][2] =
- data[x][DEFAULT_SIZE-1][3] = 255;
- }
- tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qtrue, qfalse, GL_REPEAT );
-}
-
-/*
-==================
-R_CreateBuiltinImages
-==================
-*/
-void R_CreateBuiltinImages( void ) {
- int x,y;
- byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
-
- R_CreateDefaultImage();
-
- // we use a solid white image instead of disabling texturing
- Com_Memset( data, 255, sizeof( data ) );
- tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );
-
- // with overbright bits active, we need an image which is some fraction of full color,
- // for default lightmaps, etc
- for (x=0 ; x<DEFAULT_SIZE ; x++) {
- for (y=0 ; y<DEFAULT_SIZE ; y++) {
- data[y][x][0] =
- data[y][x][1] =
- data[y][x][2] = tr.identityLightByte;
- data[y][x][3] = 255;
- }
- }
-
- tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );
-
-
- for(x=0;x<32;x++) {
- // scratchimage is usually used for cinematic drawing
- tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, GL_CLAMP );
- }
-
- R_CreateDlightImage();
- R_CreateFogImage();
-}
-
-
-/*
-===============
-R_SetColorMappings
-===============
-*/
-void R_SetColorMappings( void ) {
- int i, j;
- float g;
- int inf;
- int shift;
-
- // setup the overbright lighting
- tr.overbrightBits = r_overBrightBits->integer;
- if ( !glConfig.deviceSupportsGamma ) {
- tr.overbrightBits = 0; // need hardware gamma for overbright
- }
-
- // never overbright in windowed mode
- if ( !glConfig.isFullscreen )
- {
- tr.overbrightBits = 0;
- }
-
- // allow 2 overbright bits in 24 bit, but only 1 in 16 bit
- if ( glConfig.colorBits > 16 ) {
- if ( tr.overbrightBits > 2 ) {
- tr.overbrightBits = 2;
- }
- } else {
- if ( tr.overbrightBits > 1 ) {
- tr.overbrightBits = 1;
- }
- }
- if ( tr.overbrightBits < 0 ) {
- tr.overbrightBits = 0;
- }
-
- tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
- tr.identityLightByte = 255 * tr.identityLight;
-
-
- if ( r_intensity->value <= 1 ) {
- ri.Cvar_Set( "r_intensity", "1" );
- }
-
- if ( r_gamma->value < 0.5f ) {
- ri.Cvar_Set( "r_gamma", "0.5" );
- } else if ( r_gamma->value > 3.0f ) {
- ri.Cvar_Set( "r_gamma", "3.0" );
- }
-
- g = r_gamma->value;
-
- shift = tr.overbrightBits;
-
- for ( i = 0; i < 256; i++ ) {
- if ( g == 1 ) {
- inf = i;
- } else {
- inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
- }
- inf <<= shift;
- if (inf < 0) {
- inf = 0;
- }
- if (inf > 255) {
- inf = 255;
- }
- s_gammatable[i] = inf;
- }
-
- for (i=0 ; i<256 ; i++) {
- j = i * r_intensity->value;
- if (j > 255) {
- j = 255;
- }
- s_intensitytable[i] = j;
- }
-
- if ( glConfig.deviceSupportsGamma )
- {
- GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable );
- }
-}
-
-/*
-===============
-R_InitImages
-===============
-*/
-void R_InitImages( void ) {
- Com_Memset(hashTable, 0, sizeof(hashTable));
- // build brightness translation tables
- R_SetColorMappings();
-
- // create default texture and white texture
- R_CreateBuiltinImages();
-}
-
-/*
-===============
-R_DeleteTextures
-===============
-*/
-void R_DeleteTextures( void ) {
- int i;
-
- for ( i=0; i<tr.numImages ; i++ ) {
- qglDeleteTextures( 1, &tr.images[i]->texnum );
- }
- Com_Memset( tr.images, 0, sizeof( tr.images ) );
-
- tr.numImages = 0;
-
- Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
- if ( qglBindTexture ) {
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( 1 );
- qglBindTexture( GL_TEXTURE_2D, 0 );
- GL_SelectTexture( 0 );
- qglBindTexture( GL_TEXTURE_2D, 0 );
- } else {
- qglBindTexture( GL_TEXTURE_2D, 0 );
- }
- }
-}
-
-/*
-============================================================================
-
-SKINS
-
-============================================================================
-*/
-
-/*
-==================
-CommaParse
-
-This is unfortunate, but the skin files aren't
-compatable with our normal parsing rules.
-==================
-*/
-static char *CommaParse( char **data_p ) {
- int c = 0, len;
- char *data;
- static char com_token[MAX_TOKEN_CHARS];
-
- data = *data_p;
- len = 0;
- com_token[0] = 0;
-
- // make sure incoming data is valid
- if ( !data ) {
- *data_p = NULL;
- return com_token;
- }
-
- while ( 1 ) {
- // skip whitespace
- while( (c = *data) <= ' ') {
- if( !c ) {
- break;
- }
- data++;
- }
-
-
- c = *data;
-
- // skip double slash comments
- if ( c == '/' && data[1] == '/' )
- {
- while (*data && *data != '\n')
- data++;
- }
- // skip /* */ comments
- else if ( c=='/' && data[1] == '*' )
- {
- while ( *data && ( *data != '*' || data[1] != '/' ) )
- {
- data++;
- }
- if ( *data )
- {
- data += 2;
- }
- }
- else
- {
- break;
- }
- }
-
- if ( c == 0 ) {
- return "";
- }
-
- // handle quoted strings
- if (c == '\"')
- {
- data++;
- while (1)
- {
- c = *data++;
- if (c=='\"' || !c)
- {
- com_token[len] = 0;
- *data_p = ( char * ) data;
- return com_token;
- }
- if (len < MAX_TOKEN_CHARS)
- {
- com_token[len] = c;
- len++;
- }
- }
- }
-
- // parse a regular word
- do
- {
- if (len < MAX_TOKEN_CHARS)
- {
- com_token[len] = c;
- len++;
- }
- data++;
- c = *data;
- } while (c>32 && c != ',' );
-
- if (len == MAX_TOKEN_CHARS)
- {
-// Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
- len = 0;
- }
- com_token[len] = 0;
-
- *data_p = ( char * ) data;
- return com_token;
-}
-
-
-/*
-===============
-RE_RegisterSkin
-
-===============
-*/
-qhandle_t RE_RegisterSkin( const char *name ) {
- qhandle_t hSkin;
- skin_t *skin;
- skinSurface_t *surf;
- char *text, *text_p;
- char *token;
- char surfName[MAX_QPATH];
-
- if ( !name || !name[0] ) {
- Com_Printf( "Empty name passed to RE_RegisterSkin\n" );
- return 0;
- }
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Skin name exceeds MAX_QPATH\n" );
- return 0;
- }
-
-
- // see if the skin is already loaded
- for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
- skin = tr.skins[hSkin];
- if ( !Q_stricmp( skin->name, name ) ) {
- if( skin->numSurfaces == 0 ) {
- return 0; // default skin
- }
- return hSkin;
- }
- }
-
- // allocate a new skin
- if ( tr.numSkins == MAX_SKINS ) {
- ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
- return 0;
- }
- tr.numSkins++;
- skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
- tr.skins[hSkin] = skin;
- Q_strncpyz( skin->name, name, sizeof( skin->name ) );
- skin->numSurfaces = 0;
-
- // make sure the render thread is stopped
- R_SyncRenderThread();
-
- // If not a .skin file, load as a single shader
- if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
- skin->numSurfaces = 1;
- skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low );
- skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
- return hSkin;
- }
-
- // load and parse the skin file
- ri.FS_ReadFile( name, (void **)&text );
- if ( !text ) {
- return 0;
- }
-
- text_p = text;
- while ( text_p && *text_p ) {
- // get surface name
- token = CommaParse( &text_p );
- Q_strncpyz( surfName, token, sizeof( surfName ) );
-
- if ( !token[0] ) {
- break;
- }
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surfName );
-
- if ( *text_p == ',' ) {
- text_p++;
- }
-
- if ( strstr( token, "tag_" ) ) {
- continue;
- }
-
- // parse the shader name
- token = CommaParse( &text_p );
-
- surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
- Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
- surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
- skin->numSurfaces++;
- }
-
- ri.FS_FreeFile( text );
-
-
- // never let a skin have 0 shaders
- if ( skin->numSurfaces == 0 ) {
- return 0; // use default skin
- }
-
- return hSkin;
-}
-
-
-/*
-===============
-R_InitSkins
-===============
-*/
-void R_InitSkins( void ) {
- skin_t *skin;
-
- tr.numSkins = 1;
-
- // make the default skin have all default shaders
- skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
- Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
- skin->numSurfaces = 1;
- skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );
- skin->surfaces[0]->shader = tr.defaultShader;
-}
-
-/*
-===============
-R_GetSkinByHandle
-===============
-*/
-skin_t *R_GetSkinByHandle( qhandle_t hSkin ) {
- if ( hSkin < 1 || hSkin >= tr.numSkins ) {
- return tr.skins[0];
- }
- return tr.skins[ hSkin ];
-}
-
-/*
-===============
-R_SkinList_f
-===============
-*/
-void R_SkinList_f( void ) {
- int i, j;
- skin_t *skin;
-
- ri.Printf (PRINT_ALL, "------------------\n");
-
- for ( i = 0 ; i < tr.numSkins ; i++ ) {
- skin = tr.skins[i];
-
- ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
- for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
- ri.Printf( PRINT_ALL, " %s = %s\n",
- skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
- }
- }
- ri.Printf (PRINT_ALL, "------------------\n");
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_image.c +#include "tr_local.h" + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#define JPEG_INTERNALS +#include "../jpeg-6/jpeglib.h" + + +static void LoadBMP( const char *name, byte **pic, int *width, int *height ); +static void LoadTGA( const char *name, byte **pic, int *width, int *height ); +static void LoadJPG( const char *name, byte **pic, int *width, int *height ); + +static byte s_intensitytable[256]; +static unsigned char s_gammatable[256]; + +int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; +int gl_filter_max = GL_LINEAR; + +#define FILE_HASH_SIZE 1024 +static image_t* hashTable[FILE_HASH_SIZE]; + +/* +** R_GammaCorrect +*/ +void R_GammaCorrect( byte *buffer, int bufSize ) { + int i; + + for ( i = 0; i < bufSize; i++ ) { + buffer[i] = s_gammatable[buffer[i]]; + } +} + +typedef struct { + char *name; + int minimize, maximize; +} textureMode_t; + +textureMode_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} +}; + +/* +================ +return a hash value for the filename +================ +*/ +static long generateHashValue( const char *fname ) { + int i; + long hash; + char letter; + + hash = 0; + i = 0; + while (fname[i] != '\0') { + letter = tolower(fname[i]); + if (letter =='.') break; // don't include extension + if (letter =='\\') letter = '/'; // damn path names + hash+=(long)(letter)*(i+119); + i++; + } + hash &= (FILE_HASH_SIZE-1); + return hash; +} + +/* +=============== +GL_TextureMode +=============== +*/ +void GL_TextureMode( const char *string ) { + int i; + image_t *glt; + + for ( i=0 ; i< 6 ; i++ ) { + if ( !Q_stricmp( modes[i].name, string ) ) { + break; + } + } + + // hack to prevent trilinear from being set on voodoo, + // because their driver freaks... + if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) { + ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" ); + i = 3; + } + + + if ( i == 6 ) { + ri.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 ; i < tr.numImages ; i++ ) { + glt = tr.images[ i ]; + if ( glt->mipmap ) { + GL_Bind (glt); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + } +} + +/* +=============== +R_SumOfUsedImages +=============== +*/ +int R_SumOfUsedImages( void ) { + int total; + int i; + + total = 0; + for ( i = 0; i < tr.numImages; i++ ) { + if ( tr.images[i]->frameUsed == tr.frameCount ) { + total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight; + } + } + + return total; +} + +/* +=============== +R_ImageList_f +=============== +*/ +void R_ImageList_f( void ) { + int i; + image_t *image; + int texels; + const char *yesno[] = { + "no ", "yes" + }; + + ri.Printf (PRINT_ALL, "\n -w-- -h-- -mm- -TMU- -if-- wrap --name-------\n"); + texels = 0; + + for ( i = 0 ; i < tr.numImages ; i++ ) { + image = tr.images[ i ]; + + texels += image->uploadWidth*image->uploadHeight; + ri.Printf (PRINT_ALL, "%4i: %4i %4i %s %d ", + i, image->uploadWidth, image->uploadHeight, yesno[image->mipmap], image->TMU ); + switch ( image->internalFormat ) { + case 1: + ri.Printf( PRINT_ALL, "I " ); + break; + case 2: + ri.Printf( PRINT_ALL, "IA " ); + break; + case 3: + ri.Printf( PRINT_ALL, "RGB " ); + break; + case 4: + ri.Printf( PRINT_ALL, "RGBA " ); + break; + case GL_RGBA8: + ri.Printf( PRINT_ALL, "RGBA8" ); + break; + case GL_RGB8: + ri.Printf( PRINT_ALL, "RGB8" ); + break; + case GL_RGB4_S3TC: + ri.Printf( PRINT_ALL, "S3TC " ); + break; + case GL_RGBA4: + ri.Printf( PRINT_ALL, "RGBA4" ); + break; + case GL_RGB5: + ri.Printf( PRINT_ALL, "RGB5 " ); + break; + default: + ri.Printf( PRINT_ALL, "???? " ); + } + + switch ( image->wrapClampMode ) { + case GL_REPEAT: + ri.Printf( PRINT_ALL, "rept " ); + break; + case GL_CLAMP: + ri.Printf( PRINT_ALL, "clmp " ); + break; + default: + ri.Printf( PRINT_ALL, "%4i ", image->wrapClampMode ); + break; + } + + ri.Printf( PRINT_ALL, " %s\n", image->imgName ); + } + ri.Printf (PRINT_ALL, " ---------\n"); + ri.Printf (PRINT_ALL, " %i total texels (not including mipmaps)\n", texels); + ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); +} + +//======================================================================= + +/* +================ +ResampleTexture + +Used to resample images in a more general than quartering fashion. + +This will only be filtered properly if the resampled size +is greater than half the original size. + +If a larger shrinking is needed, use the mipmap function +before or after. +================ +*/ +static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out, + int outwidth, int outheight ) { + int i, j; + unsigned *inrow, *inrow2; + unsigned frac, fracstep; + unsigned p1[2048], p2[2048]; + byte *pix1, *pix2, *pix3, *pix4; + + if (outwidth>2048) + ri.Error(ERR_DROP, "ResampleTexture: max width"); + + fracstep = inwidth*0x10000/outwidth; + + frac = fracstep>>2; + for ( i=0 ; i<outwidth ; i++ ) { + p1[i] = 4*(frac>>16); + frac += fracstep; + } + frac = 3*(fracstep>>2); + for ( i=0 ; i<outwidth ; i++ ) { + p2[i] = 4*(frac>>16); + frac += fracstep; + } + + for (i=0 ; i<outheight ; i++, out += outwidth) { + inrow = in + inwidth*(int)((i+0.25)*inheight/outheight); + inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight); + frac = fracstep >> 1; + for (j=0 ; j<outwidth ; j++) { + pix1 = (byte *)inrow + p1[j]; + pix2 = (byte *)inrow + p2[j]; + pix3 = (byte *)inrow2 + p1[j]; + pix4 = (byte *)inrow2 + p2[j]; + ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>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; + } + } +} + +/* +================ +R_LightScaleTexture + +Scale up the pixel values in a texture to increase the +lighting range +================ +*/ +void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma ) +{ + if ( only_gamma ) + { + if ( !glConfig.deviceSupportsGamma ) + { + int i, c; + byte *p; + + p = (byte *)in; + + c = inwidth*inheight; + for (i=0 ; i<c ; i++, p+=4) + { + p[0] = s_gammatable[p[0]]; + p[1] = s_gammatable[p[1]]; + p[2] = s_gammatable[p[2]]; + } + } + } + else + { + int i, c; + byte *p; + + p = (byte *)in; + + c = inwidth*inheight; + + if ( glConfig.deviceSupportsGamma ) + { + for (i=0 ; i<c ; i++, p+=4) + { + p[0] = s_intensitytable[p[0]]; + p[1] = s_intensitytable[p[1]]; + p[2] = s_intensitytable[p[2]]; + } + } + else + { + for (i=0 ; i<c ; i++, p+=4) + { + p[0] = s_gammatable[s_intensitytable[p[0]]]; + p[1] = s_gammatable[s_intensitytable[p[1]]]; + p[2] = s_gammatable[s_intensitytable[p[2]]]; + } + } + } +} + + +/* +================ +R_MipMap2 + +Operates in place, quartering the size of the texture +Proper linear filter +================ +*/ +static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) { + int i, j, k; + byte *outpix; + int inWidthMask, inHeightMask; + int total; + int outWidth, outHeight; + unsigned *temp; + + outWidth = inWidth >> 1; + outHeight = inHeight >> 1; + temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); + + inWidthMask = inWidth - 1; + inHeightMask = inHeight - 1; + + for ( i = 0 ; i < outHeight ; i++ ) { + for ( j = 0 ; j < outWidth ; j++ ) { + outpix = (byte *) ( temp + i * outWidth + j ); + for ( k = 0 ; k < 4 ; k++ ) { + total = + 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + + 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + + 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + + 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + + + 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + + 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + + 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + + 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + + + 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + + 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + + 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + + 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + + + 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + + 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + + 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + + 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k]; + outpix[k] = total / 36; + } + } + } + + Com_Memcpy( in, temp, outWidth * outHeight * 4 ); + ri.Hunk_FreeTempMemory( temp ); +} + +/* +================ +R_MipMap + +Operates in place, quartering the size of the texture +================ +*/ +static void R_MipMap (byte *in, int width, int height) { + int i, j; + byte *out; + int row; + + if ( !r_simpleMipMaps->integer ) { + R_MipMap2( (unsigned *)in, width, height ); + return; + } + + if ( width == 1 && height == 1 ) { + return; + } + + row = width * 4; + out = in; + width >>= 1; + height >>= 1; + + if ( width == 0 || height == 0 ) { + width += height; // get largest + for (i=0 ; i<width ; i++, out+=4, in+=8 ) { + out[0] = ( in[0] + in[4] )>>1; + out[1] = ( in[1] + in[5] )>>1; + out[2] = ( in[2] + in[6] )>>1; + out[3] = ( in[3] + in[7] )>>1; + } + return; + } + + for (i=0 ; i<height ; i++, in+=row) { + for (j=0 ; j<width ; j++, out+=4, in+=8) { + out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2; + out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2; + out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2; + out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2; + } + } +} + + +/* +================== +R_BlendOverTexture + +Apply a color blend over a set of pixels +================== +*/ +static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) { + int i; + int inverseAlpha; + int premult[3]; + + inverseAlpha = 255 - blend[3]; + premult[0] = blend[0] * blend[3]; + premult[1] = blend[1] * blend[3]; + premult[2] = blend[2] * blend[3]; + + for ( i = 0 ; i < pixelCount ; i++, data+=4 ) { + data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9; + data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9; + data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9; + } +} + +byte mipBlendColors[16][4] = { + {0,0,0,0}, + {255,0,0,128}, + {0,255,0,128}, + {0,0,255,128}, + {255,0,0,128}, + {0,255,0,128}, + {0,0,255,128}, + {255,0,0,128}, + {0,255,0,128}, + {0,0,255,128}, + {255,0,0,128}, + {0,255,0,128}, + {0,0,255,128}, + {255,0,0,128}, + {0,255,0,128}, + {0,0,255,128}, +}; + + +/* +=============== +Upload32 + +=============== +*/ +extern qboolean charSet; +static void Upload32( unsigned *data, + int width, int height, + qboolean mipmap, + qboolean picmip, + qboolean lightMap, + int *format, + int *pUploadWidth, int *pUploadHeight ) +{ + int samples; + unsigned *scaledBuffer = NULL; + unsigned *resampledBuffer = NULL; + int scaled_width, scaled_height; + int i, c; + byte *scan; + GLenum internalFormat = GL_RGB; + float rMax = 0, gMax = 0, bMax = 0; + + // + // convert to exact power of 2 sizes + // + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if ( r_roundImagesDown->integer && scaled_width > width ) + scaled_width >>= 1; + if ( r_roundImagesDown->integer && scaled_height > height ) + scaled_height >>= 1; + + if ( scaled_width != width || scaled_height != height ) { + resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); + ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); + data = resampledBuffer; + width = scaled_width; + height = scaled_height; + } + + // + // perform optional picmip operation + // + if ( picmip ) { + scaled_width >>= r_picmip->integer; + scaled_height >>= r_picmip->integer; + } + + // + // clamp to minimum size + // + if (scaled_width < 1) { + scaled_width = 1; + } + if (scaled_height < 1) { + scaled_height = 1; + } + + // + // clamp to the current upper OpenGL limit + // scale both axis down equally so we don't have to + // deal with a half mip resampling + // + while ( scaled_width > glConfig.maxTextureSize + || scaled_height > glConfig.maxTextureSize ) { + scaled_width >>= 1; + scaled_height >>= 1; + } + + scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); + + // + // scan the texture for each channel's max values + // and verify if the alpha channel is being used or not + // + c = width*height; + scan = ((byte *)data); + samples = 3; + if (!lightMap) { + for ( i = 0; i < c; i++ ) + { + if ( scan[i*4+0] > rMax ) + { + rMax = scan[i*4+0]; + } + if ( scan[i*4+1] > gMax ) + { + gMax = scan[i*4+1]; + } + if ( scan[i*4+2] > bMax ) + { + bMax = scan[i*4+2]; + } + if ( scan[i*4 + 3] != 255 ) + { + samples = 4; + break; + } + } + // select proper internal format + if ( samples == 3 ) + { + if ( glConfig.textureCompression == TC_S3TC ) + { + internalFormat = GL_RGB4_S3TC; + } + else if ( r_texturebits->integer == 16 ) + { + internalFormat = GL_RGB5; + } + else if ( r_texturebits->integer == 32 ) + { + internalFormat = GL_RGB8; + } + else + { + internalFormat = 3; + } + } + else if ( samples == 4 ) + { + if ( r_texturebits->integer == 16 ) + { + internalFormat = GL_RGBA4; + } + else if ( r_texturebits->integer == 32 ) + { + internalFormat = GL_RGBA8; + } + else + { + internalFormat = 4; + } + } + } else { + internalFormat = 3; + } + // copy or resample data as appropriate for first MIP level + if ( ( scaled_width == width ) && + ( scaled_height == height ) ) { + if (!mipmap) + { + qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + *pUploadWidth = scaled_width; + *pUploadHeight = scaled_height; + *format = internalFormat; + + goto done; + } + Com_Memcpy (scaledBuffer, data, width*height*4); + } + else + { + // use the normal mip-mapping function to go down from here + while ( width > scaled_width || height > scaled_height ) { + R_MipMap( (byte *)data, width, height ); + width >>= 1; + height >>= 1; + if ( width < 1 ) { + width = 1; + } + if ( height < 1 ) { + height = 1; + } + } + Com_Memcpy( scaledBuffer, data, width * height * 4 ); + } + + R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap ); + + *pUploadWidth = scaled_width; + *pUploadHeight = scaled_height; + *format = internalFormat; + + qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + + if (mipmap) + { + int miplevel; + + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) + { + R_MipMap( (byte *)scaledBuffer, 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 ( r_colorMipLevels->integer ) { + R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] ); + } + + qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + } + } +done: + + 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_LINEAR ); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + + GL_CheckErrors(); + + if ( scaledBuffer != 0 ) + ri.Hunk_FreeTempMemory( scaledBuffer ); + if ( resampledBuffer != 0 ) + ri.Hunk_FreeTempMemory( resampledBuffer ); +} + + +/* +================ +R_CreateImage + +This is the only way any image_t are created +================ +*/ +image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, + qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) { + image_t *image; + qboolean isLightmap = qfalse; + long hash; + + if (strlen(name) >= MAX_QPATH ) { + ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name); + } + if ( !strncmp( name, "*lightmap", 9 ) ) { + isLightmap = qtrue; + } + + if ( tr.numImages == MAX_DRAWIMAGES ) { + ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n"); + } + + image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); + image->texnum = 1024 + tr.numImages; + tr.numImages++; + + image->mipmap = mipmap; + image->allowPicmip = allowPicmip; + + strcpy (image->imgName, name); + + image->width = width; + image->height = height; + image->wrapClampMode = glWrapClampMode; + + // lightmaps are always allocated on TMU 1 + if ( qglActiveTextureARB && isLightmap ) { + image->TMU = 1; + } else { + image->TMU = 0; + } + + if ( qglActiveTextureARB ) { + GL_SelectTexture( image->TMU ); + } + + GL_Bind(image); + + Upload32( (unsigned *)pic, image->width, image->height, + image->mipmap, + allowPicmip, + isLightmap, + &image->internalFormat, + &image->uploadWidth, + &image->uploadHeight ); + + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); + + qglBindTexture( GL_TEXTURE_2D, 0 ); + + if ( image->TMU == 1 ) { + GL_SelectTexture( 0 ); + } + + hash = generateHashValue(name); + image->next = hashTable[hash]; + hashTable[hash] = image; + + return image; +} + + +/* +========================================================= + +BMP LOADING + +========================================================= +*/ +typedef struct +{ + char id[2]; + unsigned long fileSize; + unsigned long reserved0; + unsigned long bitmapDataOffset; + unsigned long bitmapHeaderSize; + unsigned long width; + unsigned long height; + unsigned short planes; + unsigned short bitsPerPixel; + unsigned long compression; + unsigned long bitmapDataSize; + unsigned long hRes; + unsigned long vRes; + unsigned long colors; + unsigned long importantColors; + unsigned char palette[256][4]; +} BMPHeader_t; + +static void LoadBMP( const char *name, byte **pic, int *width, int *height ) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; + BMPHeader_t bmpHeader; + byte *bmpRGBA; + + *pic = NULL; + + // + // load the file + // + length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer); + if (!buffer) { + return; + } + + buf_p = buffer; + + bmpHeader.id[0] = *buf_p++; + bmpHeader.id[1] = *buf_p++; + bmpHeader.fileSize = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.width = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.height = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.planes = LittleShort( * ( short * ) buf_p ); + buf_p += 2; + bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p ); + buf_p += 2; + bmpHeader.compression = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.hRes = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.vRes = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.colors = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + bmpHeader.importantColors = LittleLong( * ( long * ) buf_p ); + buf_p += 4; + + Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); + + if ( bmpHeader.bitsPerPixel == 8 ) + buf_p += 1024; + + if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) + { + ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); + } + if ( bmpHeader.fileSize != length ) + { + ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); + } + if ( bmpHeader.compression != 0 ) + { + ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); + } + if ( bmpHeader.bitsPerPixel < 8 ) + { + ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); + } + + columns = bmpHeader.width; + rows = bmpHeader.height; + if ( rows < 0 ) + rows = -rows; + numPixels = columns * rows; + + if ( width ) + *width = columns; + if ( height ) + *height = rows; + + bmpRGBA = ri.Malloc( numPixels * 4 ); + *pic = bmpRGBA; + + + for ( row = rows-1; row >= 0; row-- ) + { + pixbuf = bmpRGBA + row*columns*4; + + for ( column = 0; column < columns; column++ ) + { + unsigned char red, green, blue, alpha; + int palIndex; + unsigned short shortPixel; + + switch ( bmpHeader.bitsPerPixel ) + { + case 8: + palIndex = *buf_p++; + *pixbuf++ = bmpHeader.palette[palIndex][2]; + *pixbuf++ = bmpHeader.palette[palIndex][1]; + *pixbuf++ = bmpHeader.palette[palIndex][0]; + *pixbuf++ = 0xff; + break; + case 16: + shortPixel = * ( unsigned short * ) pixbuf; + pixbuf += 2; + *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7; + *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2; + *pixbuf++ = ( shortPixel & ( 31 ) ) << 3; + *pixbuf++ = 0xff; + break; + + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + break; + default: + ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name ); + break; + } + } + } + + ri.FS_FreeFile( buffer ); + +} + + +/* +================================================================= + +PCX LOADING + +================================================================= +*/ + + +/* +============== +LoadPCX +============== +*/ +static void LoadPCX ( const 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; + int xmax, ymax; + + *pic = NULL; + *palette = NULL; + + // + // load the file + // + len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw); + if (!raw) { + return; + } + + // + // parse the PCX file + // + pcx = (pcx_t *)raw; + raw = &pcx->data; + + xmax = LittleShort(pcx->xmax); + ymax = LittleShort(pcx->ymax); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || xmax >= 1024 + || ymax >= 1024) + { + ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax); + return; + } + + out = ri.Malloc ( (ymax+1) * (xmax+1) ); + + *pic = out; + + pix = out; + + if (palette) + { + *palette = ri.Malloc(768); + Com_Memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = xmax+1; + if (height) + *height = ymax+1; +// FIXME: use bytes_per_line here? + + for (y=0 ; y<=ymax ; y++, pix += xmax+1) + { + for (x=0 ; x<=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.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); + ri.Free (*pic); + *pic = NULL; + } + + ri.FS_FreeFile (pcx); +} + + +/* +============== +LoadPCX32 +============== +*/ +static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height) { + byte *palette; + byte *pic8; + int i, c, p; + byte *pic32; + + LoadPCX (filename, &pic8, &palette, width, height); + if (!pic8) { + *pic = NULL; + return; + } + + c = (*width) * (*height); + pic32 = *pic = ri.Malloc(4 * c ); + for (i = 0 ; i < c ; i++) { + p = pic8[i]; + pic32[0] = palette[p*3]; + pic32[1] = palette[p*3 + 1]; + pic32[2] = palette[p*3 + 2]; + pic32[3] = 255; + pic32 += 4; + } + + ri.Free (pic8); + ri.Free (palette); +} + +/* +========================================================= + +TARGA LOADING + +========================================================= +*/ + +/* +============= +LoadTGA +============= +*/ +static void LoadTGA ( const char *name, byte **pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + TargaHeader targa_header; + byte *targa_rgba; + + *pic = NULL; + + // + // load the file + // + ri.FS_ReadFile ( ( char * ) name, (void **)&buffer); + if (!buffer) { + 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 + && targa_header.image_type != 3 ) + { + ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + } + + if ( targa_header.colormap_type != 0 ) + { + ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" ); + } + + if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) + { + ri.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 = ri.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 || targa_header.image_type == 3 ) + { + // Uncompressed RGB or gray scale image + for(row=rows-1; row>=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; column++) + { + unsigned char red,green,blue,alphabyte; + switch (targa_header.pixel_size) + { + + case 8: + blue = *buf_p++; + green = blue; + red = blue; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + break; + } + } + } + } + else if (targa_header.image_type==10) { // Runlength encoded RGB images + unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; + + red = 0; + green = 0; + blue = 0; + alphabyte = 0xff; + + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; ) { + packetHeader= *buf_p++; + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + break; + default: + ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + break; + } + + for(j=0;j<packetSize;j++) { + *pixbuf++=red; + *pixbuf++=green; + *pixbuf++=blue; + *pixbuf++=alphabyte; + column++; + if (column==columns) { // run spans across rows + column=0; + if (row>0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j<packetSize;j++) { + switch (targa_header.pixel_size) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + break; + } + column++; + if (column==columns) { // pixel packet run spans across rows + column=0; + if (row>0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + +#if 0 + // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs + // bk0101024 - fix from Leonardo + // bit 5 set => top-down + if (targa_header.attributes & 0x20) { + unsigned char *flip = (unsigned char*)malloc (columns*4); + unsigned char *src, *dst; + + for (row = 0; row < rows/2; row++) { + src = targa_rgba + row * 4 * columns; + dst = targa_rgba + (rows - row - 1) * 4 * columns; + + memcpy (flip, src, columns*4); + memcpy (src, dst, columns*4); + memcpy (dst, flip, columns*4); + } + free (flip); + } +#endif + // instead we just print a warning + if (targa_header.attributes & 0x20) { + ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name); + } + + ri.FS_FreeFile (buffer); +} + +static void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) { + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + unsigned char *out; + byte *fbuffer; + byte *bbuf; + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer); + if (!fbuffer) { + return; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, fbuffer); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + + out = ri.Malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components); + + *pic = out; + *width = cinfo.output_width; + *height = cinfo.output_height; + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + bbuf = ((out+(row_stride*cinfo.output_scanline))); + buffer = &bbuf; + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + } + + // clear all the alphas to 255 + { + int i, j; + byte *buf; + + buf = *pic; + + j = cinfo.output_width * cinfo.output_height * 4; + for ( i = 3 ; i < j ; i+=4 ) { + buf[i] = 255; + } + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + ri.FS_FreeFile (fbuffer); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ +} + + +/* Expanded data destination object for stdio output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + byte* outfile; /* target stream */ + int size; +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +void init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + dest->pub.next_output_byte = dest->outfile; + dest->pub.free_in_buffer = dest->size; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +boolean empty_output_buffer (j_compress_ptr cinfo) +{ + return TRUE; +} + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL void +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL JDIMENSION +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +static int hackSize; + +void term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = dest->size - dest->pub.free_in_buffer; + hackSize = datacount; +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +void jpegDest (j_compress_ptr cinfo, byte* outfile, int size) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; + dest->size = size; +} + +void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer) { + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + unsigned char *out; + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + out = ri.Hunk_AllocateTempMemory(image_width*image_height*4); + jpegDest(&cinfo, out, image_width*image_height*4); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 4; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + ri.FS_WriteFile( filename, out, hackSize ); + + ri.Hunk_FreeTempMemory(out); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ +} + +//=================================================================== + +/* +================= +R_LoadImage + +Loads any of the supported image types into a cannonical +32 bit format. +================= +*/ +void R_LoadImage( const char *name, byte **pic, int *width, int *height ) { + int len; + + *pic = NULL; + *width = 0; + *height = 0; + + len = strlen(name); + if (len<5) { + return; + } + + if ( !Q_stricmp( name+len-4, ".tga" ) ) { + LoadTGA( name, pic, width, height ); // try tga first + if (!*pic) { // + char altname[MAX_QPATH]; // try jpg in place of tga + strcpy( altname, name ); + len = strlen( altname ); + altname[len-3] = 'j'; + altname[len-2] = 'p'; + altname[len-1] = 'g'; + LoadJPG( altname, pic, width, height ); + } + } else if ( !Q_stricmp(name+len-4, ".pcx") ) { + LoadPCX32( name, pic, width, height ); + } else if ( !Q_stricmp( name+len-4, ".bmp" ) ) { + LoadBMP( name, pic, width, height ); + } else if ( !Q_stricmp( name+len-4, ".jpg" ) ) { + LoadJPG( name, pic, width, height ); + } +} + + +/* +=============== +R_FindImageFile + +Finds or loads the given image. +Returns NULL if it fails, not a default image. +============== +*/ +image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) { + image_t *image; + int width, height; + byte *pic; + long hash; + + if (!name) { + return NULL; + } + + hash = generateHashValue(name); + + // + // see if the image is already loaded + // + for (image=hashTable[hash]; image; image=image->next) { + if ( !strcmp( name, image->imgName ) ) { + // the white image can be used with any set of parms, but other mismatches are errors + if ( strcmp( name, "*white" ) ) { + if ( image->mipmap != mipmap ) { + ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed mipmap parm\n", name ); + } + if ( image->allowPicmip != allowPicmip ) { + ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed allowPicmip parm\n", name ); + } + if ( image->wrapClampMode != glWrapClampMode ) { + ri.Printf( PRINT_ALL, "WARNING: reused image %s with mixed glWrapClampMode parm\n", name ); + } + } + return image; + } + } + + // + // load the pic from disk + // + R_LoadImage( name, &pic, &width, &height ); + if ( pic == NULL ) { // if we dont get a successful load + char altname[MAX_QPATH]; // copy the name + int len; // + strcpy( altname, name ); // + len = strlen( altname ); // + altname[len-3] = toupper(altname[len-3]); // and try upper case extension for unix systems + altname[len-2] = toupper(altname[len-2]); // + altname[len-1] = toupper(altname[len-1]); // + ri.Printf( PRINT_ALL, "trying %s...\n", altname ); // + R_LoadImage( altname, &pic, &width, &height ); // + if (pic == NULL) { // if that fails + return NULL; // bail + } + } + + image = R_CreateImage( ( char * ) name, pic, width, height, mipmap, allowPicmip, glWrapClampMode ); + ri.Free( pic ); + return image; +} + + +/* +================ +R_CreateDlightImage +================ +*/ +#define DLIGHT_SIZE 16 +static void R_CreateDlightImage( void ) { + int x,y; + byte data[DLIGHT_SIZE][DLIGHT_SIZE][4]; + int b; + + // make a centered inverse-square falloff blob for dynamic lighting + for (x=0 ; x<DLIGHT_SIZE ; x++) { + for (y=0 ; y<DLIGHT_SIZE ; y++) { + float d; + + d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) + + ( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y ); + b = 4000 / d; + if (b > 255) { + b = 255; + } else if ( b < 75 ) { + b = 0; + } + data[y][x][0] = + data[y][x][1] = + data[y][x][2] = b; + data[y][x][3] = 255; + } + } + tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, qfalse, qfalse, GL_CLAMP ); +} + + +/* +================= +R_InitFogTable +================= +*/ +void R_InitFogTable( void ) { + int i; + float d; + float exp; + + exp = 0.5; + + for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) { + d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp ); + + tr.fogTable[i] = d; + } +} + +/* +================ +R_FogFactor + +Returns a 0.0 to 1.0 fog density value +This is called for each texel of the fog texture on startup +and for each vertex of transparent shaders in fog dynamically +================ +*/ +float R_FogFactor( float s, float t ) { + float d; + + s -= 1.0/512; + if ( s < 0 ) { + return 0; + } + if ( t < 1.0/32 ) { + return 0; + } + if ( t < 31.0/32 ) { + s *= (t - 1.0f/32.0f) / (30.0f/32.0f); + } + + // we need to leave a lot of clamp range + s *= 8; + + if ( s > 1.0 ) { + s = 1.0; + } + + d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ]; + + return d; +} + +/* +================ +R_CreateFogImage +================ +*/ +#define FOG_S 256 +#define FOG_T 32 +static void R_CreateFogImage( void ) { + int x,y; + byte *data; + float g; + float d; + float borderColor[4]; + + data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 ); + + g = 2.0; + + // S is distance, T is depth + for (x=0 ; x<FOG_S ; x++) { + for (y=0 ; y<FOG_T ; y++) { + d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T ); + + data[(y*FOG_S+x)*4+0] = + data[(y*FOG_S+x)*4+1] = + data[(y*FOG_S+x)*4+2] = 255; + data[(y*FOG_S+x)*4+3] = 255*d; + } + } + // standard openGL clamping doesn't really do what we want -- it includes + // the border color at the edges. OpenGL 1.2 has clamp-to-edge, which does + // what we want. + tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, qfalse, qfalse, GL_CLAMP ); + ri.Hunk_FreeTempMemory( data ); + + borderColor[0] = 1.0; + borderColor[1] = 1.0; + borderColor[2] = 1.0; + borderColor[3] = 1; + + qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor ); +} + +/* +================== +R_CreateDefaultImage +================== +*/ +#define DEFAULT_SIZE 16 +static void R_CreateDefaultImage( void ) { + int x; + byte data[DEFAULT_SIZE][DEFAULT_SIZE][4]; + + // the default image will be a box, to allow you to see the mapping coordinates + Com_Memset( data, 32, sizeof( data ) ); + for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) { + data[0][x][0] = + data[0][x][1] = + data[0][x][2] = + data[0][x][3] = 255; + + data[x][0][0] = + data[x][0][1] = + data[x][0][2] = + data[x][0][3] = 255; + + data[DEFAULT_SIZE-1][x][0] = + data[DEFAULT_SIZE-1][x][1] = + data[DEFAULT_SIZE-1][x][2] = + data[DEFAULT_SIZE-1][x][3] = 255; + + data[x][DEFAULT_SIZE-1][0] = + data[x][DEFAULT_SIZE-1][1] = + data[x][DEFAULT_SIZE-1][2] = + data[x][DEFAULT_SIZE-1][3] = 255; + } + tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qtrue, qfalse, GL_REPEAT ); +} + +/* +================== +R_CreateBuiltinImages +================== +*/ +void R_CreateBuiltinImages( void ) { + int x,y; + byte data[DEFAULT_SIZE][DEFAULT_SIZE][4]; + + R_CreateDefaultImage(); + + // we use a solid white image instead of disabling texturing + Com_Memset( data, 255, sizeof( data ) ); + tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT ); + + // with overbright bits active, we need an image which is some fraction of full color, + // for default lightmaps, etc + for (x=0 ; x<DEFAULT_SIZE ; x++) { + for (y=0 ; y<DEFAULT_SIZE ; y++) { + data[y][x][0] = + data[y][x][1] = + data[y][x][2] = tr.identityLightByte; + data[y][x][3] = 255; + } + } + + tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT ); + + + for(x=0;x<32;x++) { + // scratchimage is usually used for cinematic drawing + tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, GL_CLAMP ); + } + + R_CreateDlightImage(); + R_CreateFogImage(); +} + + +/* +=============== +R_SetColorMappings +=============== +*/ +void R_SetColorMappings( void ) { + int i, j; + float g; + int inf; + int shift; + + // setup the overbright lighting + tr.overbrightBits = r_overBrightBits->integer; + if ( !glConfig.deviceSupportsGamma ) { + tr.overbrightBits = 0; // need hardware gamma for overbright + } + + // never overbright in windowed mode + if ( !glConfig.isFullscreen ) + { + tr.overbrightBits = 0; + } + + // allow 2 overbright bits in 24 bit, but only 1 in 16 bit + if ( glConfig.colorBits > 16 ) { + if ( tr.overbrightBits > 2 ) { + tr.overbrightBits = 2; + } + } else { + if ( tr.overbrightBits > 1 ) { + tr.overbrightBits = 1; + } + } + if ( tr.overbrightBits < 0 ) { + tr.overbrightBits = 0; + } + + tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); + tr.identityLightByte = 255 * tr.identityLight; + + + if ( r_intensity->value <= 1 ) { + ri.Cvar_Set( "r_intensity", "1" ); + } + + if ( r_gamma->value < 0.5f ) { + ri.Cvar_Set( "r_gamma", "0.5" ); + } else if ( r_gamma->value > 3.0f ) { + ri.Cvar_Set( "r_gamma", "3.0" ); + } + + g = r_gamma->value; + + shift = tr.overbrightBits; + + for ( i = 0; i < 256; i++ ) { + if ( g == 1 ) { + inf = i; + } else { + inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f; + } + inf <<= shift; + if (inf < 0) { + inf = 0; + } + if (inf > 255) { + inf = 255; + } + s_gammatable[i] = inf; + } + + for (i=0 ; i<256 ; i++) { + j = i * r_intensity->value; + if (j > 255) { + j = 255; + } + s_intensitytable[i] = j; + } + + if ( glConfig.deviceSupportsGamma ) + { + GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable ); + } +} + +/* +=============== +R_InitImages +=============== +*/ +void R_InitImages( void ) { + Com_Memset(hashTable, 0, sizeof(hashTable)); + // build brightness translation tables + R_SetColorMappings(); + + // create default texture and white texture + R_CreateBuiltinImages(); +} + +/* +=============== +R_DeleteTextures +=============== +*/ +void R_DeleteTextures( void ) { + int i; + + for ( i=0; i<tr.numImages ; i++ ) { + qglDeleteTextures( 1, &tr.images[i]->texnum ); + } + Com_Memset( tr.images, 0, sizeof( tr.images ) ); + + tr.numImages = 0; + + Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) ); + if ( qglBindTexture ) { + if ( qglActiveTextureARB ) { + GL_SelectTexture( 1 ); + qglBindTexture( GL_TEXTURE_2D, 0 ); + GL_SelectTexture( 0 ); + qglBindTexture( GL_TEXTURE_2D, 0 ); + } else { + qglBindTexture( GL_TEXTURE_2D, 0 ); + } + } +} + +/* +============================================================================ + +SKINS + +============================================================================ +*/ + +/* +================== +CommaParse + +This is unfortunate, but the skin files aren't +compatable with our normal parsing rules. +================== +*/ +static char *CommaParse( char **data_p ) { + int c = 0, len; + char *data; + static char com_token[MAX_TOKEN_CHARS]; + + data = *data_p; + len = 0; + com_token[0] = 0; + + // make sure incoming data is valid + if ( !data ) { + *data_p = NULL; + return com_token; + } + + while ( 1 ) { + // skip whitespace + while( (c = *data) <= ' ') { + if( !c ) { + break; + } + data++; + } + + + c = *data; + + // skip double slash comments + if ( c == '/' && data[1] == '/' ) + { + while (*data && *data != '\n') + data++; + } + // skip /* */ comments + else if ( c=='/' && data[1] == '*' ) + { + while ( *data && ( *data != '*' || data[1] != '/' ) ) + { + data++; + } + if ( *data ) + { + data += 2; + } + } + else + { + break; + } + } + + if ( c == 0 ) { + return ""; + } + + // handle quoted strings + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c=='\"' || !c) + { + com_token[len] = 0; + *data_p = ( char * ) data; + return com_token; + } + if (len < MAX_TOKEN_CHARS) + { + com_token[len] = c; + len++; + } + } + } + + // parse a regular word + do + { + if (len < MAX_TOKEN_CHARS) + { + com_token[len] = c; + len++; + } + data++; + c = *data; + } while (c>32 && c != ',' ); + + if (len == MAX_TOKEN_CHARS) + { +// Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); + len = 0; + } + com_token[len] = 0; + + *data_p = ( char * ) data; + return com_token; +} + + +/* +=============== +RE_RegisterSkin + +=============== +*/ +qhandle_t RE_RegisterSkin( const char *name ) { + qhandle_t hSkin; + skin_t *skin; + skinSurface_t *surf; + char *text, *text_p; + char *token; + char surfName[MAX_QPATH]; + + if ( !name || !name[0] ) { + Com_Printf( "Empty name passed to RE_RegisterSkin\n" ); + return 0; + } + + if ( strlen( name ) >= MAX_QPATH ) { + Com_Printf( "Skin name exceeds MAX_QPATH\n" ); + return 0; + } + + + // see if the skin is already loaded + for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) { + skin = tr.skins[hSkin]; + if ( !Q_stricmp( skin->name, name ) ) { + if( skin->numSurfaces == 0 ) { + return 0; // default skin + } + return hSkin; + } + } + + // allocate a new skin + if ( tr.numSkins == MAX_SKINS ) { + ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name ); + return 0; + } + tr.numSkins++; + skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); + tr.skins[hSkin] = skin; + Q_strncpyz( skin->name, name, sizeof( skin->name ) ); + skin->numSurfaces = 0; + + // make sure the render thread is stopped + R_SyncRenderThread(); + + // If not a .skin file, load as a single shader + if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { + skin->numSurfaces = 1; + skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low ); + skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); + return hSkin; + } + + // load and parse the skin file + ri.FS_ReadFile( name, (void **)&text ); + if ( !text ) { + return 0; + } + + text_p = text; + while ( text_p && *text_p ) { + // get surface name + token = CommaParse( &text_p ); + Q_strncpyz( surfName, token, sizeof( surfName ) ); + + if ( !token[0] ) { + break; + } + // lowercase the surface name so skin compares are faster + Q_strlwr( surfName ); + + if ( *text_p == ',' ) { + text_p++; + } + + if ( strstr( token, "tag_" ) ) { + continue; + } + + // parse the shader name + token = CommaParse( &text_p ); + + surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); + Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); + surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); + skin->numSurfaces++; + } + + ri.FS_FreeFile( text ); + + + // never let a skin have 0 shaders + if ( skin->numSurfaces == 0 ) { + return 0; // use default skin + } + + return hSkin; +} + + +/* +=============== +R_InitSkins +=============== +*/ +void R_InitSkins( void ) { + skin_t *skin; + + tr.numSkins = 1; + + // make the default skin have all default shaders + skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); + Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) ); + skin->numSurfaces = 1; + skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low ); + skin->surfaces[0]->shader = tr.defaultShader; +} + +/* +=============== +R_GetSkinByHandle +=============== +*/ +skin_t *R_GetSkinByHandle( qhandle_t hSkin ) { + if ( hSkin < 1 || hSkin >= tr.numSkins ) { + return tr.skins[0]; + } + return tr.skins[ hSkin ]; +} + +/* +=============== +R_SkinList_f +=============== +*/ +void R_SkinList_f( void ) { + int i, j; + skin_t *skin; + + ri.Printf (PRINT_ALL, "------------------\n"); + + for ( i = 0 ; i < tr.numSkins ; i++ ) { + skin = tr.skins[i]; + + ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); + for ( j = 0 ; j < skin->numSurfaces ; j++ ) { + ri.Printf( PRINT_ALL, " %s = %s\n", + skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); + } + } + ri.Printf (PRINT_ALL, "------------------\n"); +} + diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c index 536ee48..d7e8db5 100755 --- a/code/renderer/tr_init.c +++ b/code/renderer/tr_init.c @@ -1,1217 +1,1217 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_init.c -- functions that are not called every frame
-
-#include "tr_local.h"
-
-glconfig_t glConfig;
-glstate_t glState;
-
-static void GfxInfo_f( void );
-
-cvar_t *r_flareSize;
-cvar_t *r_flareFade;
-
-cvar_t *r_railWidth;
-cvar_t *r_railCoreWidth;
-cvar_t *r_railSegmentLength;
-
-cvar_t *r_ignoreFastPath;
-
-cvar_t *r_verbose;
-cvar_t *r_ignore;
-
-cvar_t *r_displayRefresh;
-
-cvar_t *r_detailTextures;
-
-cvar_t *r_znear;
-
-cvar_t *r_smp;
-cvar_t *r_showSmp;
-cvar_t *r_skipBackEnd;
-
-cvar_t *r_ignorehwgamma;
-cvar_t *r_measureOverdraw;
-
-cvar_t *r_inGameVideo;
-cvar_t *r_fastsky;
-cvar_t *r_drawSun;
-cvar_t *r_dynamiclight;
-cvar_t *r_dlightBacks;
-
-cvar_t *r_lodbias;
-cvar_t *r_lodscale;
-
-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_facePlaneCull;
-cvar_t *r_showcluster;
-cvar_t *r_nocurves;
-
-cvar_t *r_allowExtensions;
-
-cvar_t *r_ext_compressed_textures;
-cvar_t *r_ext_gamma_control;
-cvar_t *r_ext_multitexture;
-cvar_t *r_ext_compiled_vertex_array;
-cvar_t *r_ext_texture_env_add;
-
-cvar_t *r_ignoreGLErrors;
-cvar_t *r_logFile;
-
-cvar_t *r_stencilbits;
-cvar_t *r_depthbits;
-cvar_t *r_colorbits;
-cvar_t *r_stereo;
-cvar_t *r_primitives;
-cvar_t *r_texturebits;
-
-cvar_t *r_drawBuffer;
-cvar_t *r_glDriver;
-cvar_t *r_lightmap;
-cvar_t *r_vertexLight;
-cvar_t *r_uiFullScreen;
-cvar_t *r_shadows;
-cvar_t *r_flares;
-cvar_t *r_mode;
-cvar_t *r_nobind;
-cvar_t *r_singleShader;
-cvar_t *r_roundImagesDown;
-cvar_t *r_colorMipLevels;
-cvar_t *r_picmip;
-cvar_t *r_showtris;
-cvar_t *r_showsky;
-cvar_t *r_shownormals;
-cvar_t *r_finish;
-cvar_t *r_clear;
-cvar_t *r_swapInterval;
-cvar_t *r_textureMode;
-cvar_t *r_offsetFactor;
-cvar_t *r_offsetUnits;
-cvar_t *r_gamma;
-cvar_t *r_intensity;
-cvar_t *r_lockpvs;
-cvar_t *r_noportals;
-cvar_t *r_portalOnly;
-
-cvar_t *r_subdivisions;
-cvar_t *r_lodCurveError;
-
-cvar_t *r_fullscreen;
-
-cvar_t *r_customwidth;
-cvar_t *r_customheight;
-cvar_t *r_customaspect;
-
-cvar_t *r_overBrightBits;
-cvar_t *r_mapOverBrightBits;
-
-cvar_t *r_debugSurface;
-cvar_t *r_simpleMipMaps;
-
-cvar_t *r_showImages;
-
-cvar_t *r_ambientScale;
-cvar_t *r_directedScale;
-cvar_t *r_debugLight;
-cvar_t *r_debugSort;
-cvar_t *r_printShaders;
-cvar_t *r_saveFontData;
-
-cvar_t *r_maxpolys;
-int max_polys;
-cvar_t *r_maxpolyverts;
-int max_polyverts;
-
-void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t );
-void ( APIENTRY * qglActiveTextureARB )( GLenum texture );
-void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture );
-
-void ( APIENTRY * qglLockArraysEXT)( GLint, GLint);
-void ( APIENTRY * qglUnlockArraysEXT) ( void );
-
-static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral )
-{
- if ( shouldBeIntegral )
- {
- if ( ( int ) cv->value != cv->integer )
- {
- ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' must be integral (%f)\n", cv->name, cv->value );
- ri.Cvar_Set( cv->name, va( "%d", cv->integer ) );
- }
- }
-
- if ( cv->value < minVal )
- {
- ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' out of range (%f < %f)\n", cv->name, cv->value, minVal );
- ri.Cvar_Set( cv->name, va( "%f", minVal ) );
- }
- else if ( cv->value > maxVal )
- {
- ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' out of range (%f > %f)\n", cv->name, cv->value, maxVal );
- ri.Cvar_Set( cv->name, va( "%f", maxVal ) );
- }
-}
-
-
-/*
-** InitOpenGL
-**
-** This function is responsible for initializing a valid OpenGL subsystem. This
-** is done by calling GLimp_Init (which gives us a working OGL subsystem) then
-** setting variables, checking GL constants, and reporting the gfx system config
-** to the user.
-*/
-static void InitOpenGL( void )
-{
- char renderer_buffer[1024];
-
- //
- // initialize OS specific portions of the renderer
- //
- // GLimp_Init directly or indirectly references the following cvars:
- // - r_fullscreen
- // - r_glDriver
- // - r_mode
- // - r_(color|depth|stencil)bits
- // - r_ignorehwgamma
- // - r_gamma
- //
-
- if ( glConfig.vidWidth == 0 )
- {
- GLint temp;
-
- GLimp_Init();
-
- strcpy( renderer_buffer, glConfig.renderer_string );
- Q_strlwr( renderer_buffer );
-
- // OpenGL driver constants
- qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
- glConfig.maxTextureSize = temp;
-
- // stubbed or broken drivers may have reported 0...
- if ( glConfig.maxTextureSize <= 0 )
- {
- glConfig.maxTextureSize = 0;
- }
- }
-
- // init command buffers and SMP
- R_InitCommandBuffers();
-
- // print info
- GfxInfo_f();
-
- // set default state
- GL_SetDefaultState();
-}
-
-/*
-==================
-GL_CheckErrors
-==================
-*/
-void GL_CheckErrors( void ) {
- int err;
- char s[64];
-
- err = qglGetError();
- if ( err == GL_NO_ERROR ) {
- return;
- }
- if ( r_ignoreGLErrors->integer ) {
- return;
- }
- switch( err ) {
- case GL_INVALID_ENUM:
- strcpy( s, "GL_INVALID_ENUM" );
- break;
- case GL_INVALID_VALUE:
- strcpy( s, "GL_INVALID_VALUE" );
- break;
- case GL_INVALID_OPERATION:
- strcpy( s, "GL_INVALID_OPERATION" );
- break;
- case GL_STACK_OVERFLOW:
- strcpy( s, "GL_STACK_OVERFLOW" );
- break;
- case GL_STACK_UNDERFLOW:
- strcpy( s, "GL_STACK_UNDERFLOW" );
- break;
- case GL_OUT_OF_MEMORY:
- strcpy( s, "GL_OUT_OF_MEMORY" );
- break;
- default:
- Com_sprintf( s, sizeof(s), "%i", err);
- break;
- }
-
- ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s );
-}
-
-
-/*
-** R_GetModeInfo
-*/
-typedef struct vidmode_s
-{
- const char *description;
- int width, height;
- float pixelAspect; // pixel width / height
-} vidmode_t;
-
-vidmode_t r_vidModes[] =
-{
- { "Mode 0: 320x240", 320, 240, 1 },
- { "Mode 1: 400x300", 400, 300, 1 },
- { "Mode 2: 512x384", 512, 384, 1 },
- { "Mode 3: 640x480", 640, 480, 1 },
- { "Mode 4: 800x600", 800, 600, 1 },
- { "Mode 5: 960x720", 960, 720, 1 },
- { "Mode 6: 1024x768", 1024, 768, 1 },
- { "Mode 7: 1152x864", 1152, 864, 1 },
- { "Mode 8: 1280x1024", 1280, 1024, 1 },
- { "Mode 9: 1600x1200", 1600, 1200, 1 },
- { "Mode 10: 2048x1536", 2048, 1536, 1 },
- { "Mode 11: 856x480 (wide)",856, 480, 1 }
-};
-static int s_numVidModes = ( sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) );
-
-qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) {
- vidmode_t *vm;
-
- if ( mode < -1 ) {
- return qfalse;
- }
- if ( mode >= s_numVidModes ) {
- return qfalse;
- }
-
- if ( mode == -1 ) {
- *width = r_customwidth->integer;
- *height = r_customheight->integer;
- *windowAspect = r_customaspect->value;
- return qtrue;
- }
-
- vm = &r_vidModes[mode];
-
- *width = vm->width;
- *height = vm->height;
- *windowAspect = (float)vm->width / ( vm->height * vm->pixelAspect );
-
- return qtrue;
-}
-
-/*
-** R_ModeList_f
-*/
-static void R_ModeList_f( void )
-{
- int i;
-
- ri.Printf( PRINT_ALL, "\n" );
- for ( i = 0; i < s_numVidModes; i++ )
- {
- ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description );
- }
- ri.Printf( PRINT_ALL, "\n" );
-}
-
-
-/*
-==============================================================================
-
- SCREEN SHOTS
-
-NOTE TTimo
-some thoughts about the screenshots system:
-screenshots get written in fs_homepath + fs_gamedir
-vanilla q3 .. baseq3/screenshots/ *.tga
-team arena .. missionpack/screenshots/ *.tga
-
-two commands: "screenshot" and "screenshotJPEG"
-we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available
-(with FS_FileExists / FS_FOpenFileWrite calls)
-FIXME: the statics don't get a reinit between fs_game changes
-
-==============================================================================
-*/
-
-/*
-==================
-RB_TakeScreenshot
-==================
-*/
-void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) {
- byte *buffer;
- int i, c, temp;
-
- buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18);
-
- Com_Memset (buffer, 0, 18);
- buffer[2] = 2; // uncompressed type
- buffer[12] = width & 255;
- buffer[13] = width >> 8;
- buffer[14] = height & 255;
- buffer[15] = height >> 8;
- buffer[16] = 24; // pixel size
-
- qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
-
- // swap rgb to bgr
- c = 18 + width * height * 3;
- for (i=18 ; i<c ; i+=3) {
- temp = buffer[i];
- buffer[i] = buffer[i+2];
- buffer[i+2] = temp;
- }
-
- // gamma correct
- if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {
- R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 );
- }
-
- ri.FS_WriteFile( fileName, buffer, c );
-
- ri.Hunk_FreeTempMemory( buffer );
-}
-
-/*
-==================
-RB_TakeScreenshotJPEG
-==================
-*/
-void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) {
- byte *buffer;
-
- buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);
-
- qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
-
- // gamma correct
- if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {
- R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 );
- }
-
- ri.FS_WriteFile( fileName, buffer, 1 ); // create path
- SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer);
-
- ri.Hunk_FreeTempMemory( buffer );
-}
-
-/*
-==================
-RB_TakeScreenshotCmd
-==================
-*/
-const void *RB_TakeScreenshotCmd( const void *data ) {
- const screenshotCommand_t *cmd;
-
- cmd = (const screenshotCommand_t *)data;
-
- if (cmd->jpeg)
- RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
- else
- RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
-
- return (const void *)(cmd + 1);
-}
-
-/*
-==================
-R_TakeScreenshot
-==================
-*/
-void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) {
- static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame?
- screenshotCommand_t *cmd;
-
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
- if ( !cmd ) {
- return;
- }
- cmd->commandId = RC_SCREENSHOT;
-
- cmd->x = x;
- cmd->y = y;
- cmd->width = width;
- cmd->height = height;
- Q_strncpyz( fileName, name, sizeof(fileName) );
- cmd->fileName = fileName;
- cmd->jpeg = jpeg;
-}
-
-/*
-==================
-R_ScreenshotFilename
-==================
-*/
-void R_ScreenshotFilename( int lastNumber, char *fileName ) {
- int a,b,c,d;
-
- if ( lastNumber < 0 || lastNumber > 9999 ) {
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" );
- return;
- }
-
- a = lastNumber / 1000;
- lastNumber -= a*1000;
- b = lastNumber / 100;
- lastNumber -= b*100;
- c = lastNumber / 10;
- lastNumber -= c*10;
- d = lastNumber;
-
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga"
- , a, b, c, d );
-}
-
-/*
-==================
-R_ScreenshotFilename
-==================
-*/
-void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) {
- int a,b,c,d;
-
- if ( lastNumber < 0 || lastNumber > 9999 ) {
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" );
- return;
- }
-
- a = lastNumber / 1000;
- lastNumber -= a*1000;
- b = lastNumber / 100;
- lastNumber -= b*100;
- c = lastNumber / 10;
- lastNumber -= c*10;
- d = lastNumber;
-
- Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg"
- , a, b, c, d );
-}
-
-/*
-====================
-R_LevelShot
-
-levelshots are specialized 128*128 thumbnails for
-the menu system, sampled down from full screen distorted images
-====================
-*/
-void R_LevelShot( void ) {
- char checkname[MAX_OSPATH];
- byte *buffer;
- byte *source;
- byte *src, *dst;
- int x, y;
- int r, g, b;
- float xScale, yScale;
- int xx, yy;
-
- sprintf( checkname, "levelshots/%s.tga", tr.world->baseName );
-
- source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 );
-
- buffer = ri.Hunk_AllocateTempMemory( 128 * 128*3 + 18);
- Com_Memset (buffer, 0, 18);
- buffer[2] = 2; // uncompressed type
- buffer[12] = 128;
- buffer[14] = 128;
- buffer[16] = 24; // pixel size
-
- qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source );
-
- // resample from source
- xScale = glConfig.vidWidth / 512.0f;
- yScale = glConfig.vidHeight / 384.0f;
- for ( y = 0 ; y < 128 ; y++ ) {
- for ( x = 0 ; x < 128 ; x++ ) {
- r = g = b = 0;
- for ( yy = 0 ; yy < 3 ; yy++ ) {
- for ( xx = 0 ; xx < 4 ; xx++ ) {
- src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) );
- r += src[0];
- g += src[1];
- b += src[2];
- }
- }
- dst = buffer + 18 + 3 * ( y * 128 + x );
- dst[0] = b / 12;
- dst[1] = g / 12;
- dst[2] = r / 12;
- }
- }
-
- // gamma correct
- if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {
- R_GammaCorrect( buffer + 18, 128 * 128 * 3 );
- }
-
- ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 );
-
- ri.Hunk_FreeTempMemory( buffer );
- ri.Hunk_FreeTempMemory( source );
-
- ri.Printf( PRINT_ALL, "Wrote %s\n", checkname );
-}
-
-/*
-==================
-R_ScreenShot_f
-
-screenshot
-screenshot [silent]
-screenshot [levelshot]
-screenshot [filename]
-
-Doesn't print the pacifier message if there is a second arg
-==================
-*/
-void R_ScreenShot_f (void) {
- char checkname[MAX_OSPATH];
- static int lastNumber = -1;
- qboolean silent;
-
- if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
- R_LevelShot();
- return;
- }
-
- if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
- silent = qtrue;
- } else {
- silent = qfalse;
- }
-
- if ( ri.Cmd_Argc() == 2 && !silent ) {
- // explicit filename
- Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) );
- } else {
- // scan for a free filename
-
- // if we have saved a previous screenshot, don't scan
- // again, because recording demo avis can involve
- // thousands of shots
- if ( lastNumber == -1 ) {
- lastNumber = 0;
- }
- // scan for a free number
- for ( ; lastNumber <= 9999 ; lastNumber++ ) {
- R_ScreenshotFilename( lastNumber, checkname );
-
- if (!ri.FS_FileExists( checkname ))
- {
- break; // file doesn't exist
- }
- }
-
- if ( lastNumber >= 9999 ) {
- ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
- return;
- }
-
- lastNumber++;
- }
-
- R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse );
-
- if ( !silent ) {
- ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
- }
-}
-
-void R_ScreenShotJPEG_f (void) {
- char checkname[MAX_OSPATH];
- static int lastNumber = -1;
- qboolean silent;
-
- if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) {
- R_LevelShot();
- return;
- }
-
- if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) {
- silent = qtrue;
- } else {
- silent = qfalse;
- }
-
- if ( ri.Cmd_Argc() == 2 && !silent ) {
- // explicit filename
- Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) );
- } else {
- // scan for a free filename
-
- // if we have saved a previous screenshot, don't scan
- // again, because recording demo avis can involve
- // thousands of shots
- if ( lastNumber == -1 ) {
- lastNumber = 0;
- }
- // scan for a free number
- for ( ; lastNumber <= 9999 ; lastNumber++ ) {
- R_ScreenshotFilenameJPEG( lastNumber, checkname );
-
- if (!ri.FS_FileExists( checkname ))
- {
- break; // file doesn't exist
- }
- }
-
- if ( lastNumber == 10000 ) {
- ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n");
- return;
- }
-
- lastNumber++;
- }
-
- R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue );
-
- if ( !silent ) {
- ri.Printf (PRINT_ALL, "Wrote %s\n", checkname);
- }
-}
-
-//============================================================================
-
-/*
-** GL_SetDefaultState
-*/
-void GL_SetDefaultState( void )
-{
- qglClearDepth( 1.0f );
-
- qglCullFace(GL_FRONT);
-
- qglColor4f (1,1,1,1);
-
- // initialize downstream texture unit if we're running
- // in a multitexture environment
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( 1 );
- GL_TextureMode( r_textureMode->string );
- GL_TexEnv( GL_MODULATE );
- qglDisable( GL_TEXTURE_2D );
- GL_SelectTexture( 0 );
- }
-
- qglEnable(GL_TEXTURE_2D);
- GL_TextureMode( r_textureMode->string );
- GL_TexEnv( GL_MODULATE );
-
- qglShadeModel( GL_SMOOTH );
- qglDepthFunc( GL_LEQUAL );
-
- // the vertex array is always enabled, but the color and texture
- // arrays are enabled and disabled around the compiled vertex array call
- qglEnableClientState (GL_VERTEX_ARRAY);
-
- //
- // make sure our GL state vector is set correctly
- //
- glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;
-
- qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
- qglDepthMask( GL_TRUE );
- qglDisable( GL_DEPTH_TEST );
- qglEnable( GL_SCISSOR_TEST );
- qglDisable( GL_CULL_FACE );
- qglDisable( GL_BLEND );
-}
-
-
-/*
-================
-GfxInfo_f
-================
-*/
-void GfxInfo_f( void )
-{
- cvar_t *sys_cpustring = ri.Cvar_Get( "sys_cpustring", "", 0 );
- const char *enablestrings[] =
- {
- "disabled",
- "enabled"
- };
- const char *fsstrings[] =
- {
- "windowed",
- "fullscreen"
- };
-
- ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string );
- ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string );
- ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string );
- ri.Printf( PRINT_ALL, "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
- ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
- ri.Printf( PRINT_ALL, "GL_MAX_ACTIVE_TEXTURES_ARB: %d\n", glConfig.maxActiveTextures );
- ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
- ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] );
- if ( glConfig.displayFrequency )
- {
- ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency );
- }
- else
- {
- ri.Printf( PRINT_ALL, "N/A\n" );
- }
- if ( glConfig.deviceSupportsGamma )
- {
- ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits );
- }
- else
- {
- ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits );
- }
- ri.Printf( PRINT_ALL, "CPU: %s\n", sys_cpustring->string );
-
- // rendering primitives
- {
- int primitives;
-
- // default is to use triangles if compiled vertex arrays are present
- ri.Printf( PRINT_ALL, "rendering primitives: " );
- primitives = r_primitives->integer;
- if ( primitives == 0 ) {
- if ( qglLockArraysEXT ) {
- primitives = 2;
- } else {
- primitives = 1;
- }
- }
- if ( primitives == -1 ) {
- ri.Printf( PRINT_ALL, "none\n" );
- } else if ( primitives == 2 ) {
- ri.Printf( PRINT_ALL, "single glDrawElements\n" );
- } else if ( primitives == 1 ) {
- ri.Printf( PRINT_ALL, "multiple glArrayElement\n" );
- } else if ( primitives == 3 ) {
- ri.Printf( PRINT_ALL, "multiple glColor4ubv + glTexCoord2fv + glVertex3fv\n" );
- }
- }
-
- ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string );
- ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer );
- ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer );
- ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] );
- ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] );
- ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] );
- ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] );
- if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 )
- {
- ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" );
- }
- if ( glConfig.hardwareType == GLHW_RAGEPRO )
- {
- ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" );
- }
- if ( glConfig.hardwareType == GLHW_RIVA128 )
- {
- ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" );
- }
- if ( glConfig.smpActive ) {
- ri.Printf( PRINT_ALL, "Using dual processor acceleration\n" );
- }
- if ( r_finish->integer ) {
- ri.Printf( PRINT_ALL, "Forcing glFinish\n" );
- }
-}
-
-/*
-===============
-R_Register
-===============
-*/
-void R_Register( void )
-{
- //
- // latched and archived variables
- //
- r_glDriver = ri.Cvar_Get( "r_glDriver", OPENGL_DRIVER_NAME, CVAR_ARCHIVE | CVAR_LATCH );
- r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_gamma_control = ri.Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
-#ifdef __linux__ // broken on linux
- r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "0", CVAR_ARCHIVE | CVAR_LATCH);
-#else
- r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
-#endif
-
- r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
- AssertCvarRange( r_picmip, 0, 16, qtrue );
- r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_stereo = ri.Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH );
-#ifdef __linux__
- r_stencilbits = ri.Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
-#else
- r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
-#endif
- r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH);
- r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH );
- r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH );
- r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH );
- r_customaspect = ri.Cvar_Get( "r_customaspect", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0);
- r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH);
-#if (defined(MACOS_X) || defined(__linux__)) && defined(SMP)
- // Default to using SMP on Mac OS X or Linux if we have multiple processors
- r_smp = ri.Cvar_Get( "r_smp", Sys_ProcessorCount() > 1 ? "1" : "0", CVAR_ARCHIVE | CVAR_LATCH);
-#else
- r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_ARCHIVE | CVAR_LATCH);
-#endif
- r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH );
-
- //
- // temporary latched variables that can only change over a restart
- //
- r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH );
- AssertCvarRange( r_displayRefresh, 0, 200, qtrue );
- r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
- r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
- r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
- r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH );
-
- //
- // archived variables that can change at any time
- //
- r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT );
- r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE );
- r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
- r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT );
- AssertCvarRange( r_znear, 0.001f, 200, qtrue );
- r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
- r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
- r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
- r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
- r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
- r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
- r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
- r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
- r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", CVAR_ARCHIVE );
-#ifdef __MACOS__
- r_gamma = ri.Cvar_Get( "r_gamma", "1.2", CVAR_ARCHIVE );
-#else
- r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );
-#endif
- r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE );
-
- r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE );
- r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE );
- r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE );
-
- r_primitives = ri.Cvar_Get( "r_primitives", "0", CVAR_ARCHIVE );
-
- r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT );
- r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
-
- //
- // temporary variables that can change at any time
- //
- r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP );
-
- r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP );
- r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT );
- r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 );
- r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 );
-
- r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT );
- r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT );
- r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 );
- r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT );
-
- r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT);
- r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT);
-
- r_showSmp = ri.Cvar_Get ("r_showSmp", "0", CVAR_CHEAT);
- r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT);
-
- r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT );
- r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT );
- r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
- r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
- r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT );
- r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT);
- r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
- r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
- r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT);
- r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT );
- r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT );
- r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT);
- r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT);
- r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT);
- r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT);
- r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT);
- r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT);
- r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT );
- r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT );
- r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT );
- r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT);
- r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT);
- r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 );
-
- r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0);
- r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0);
-
- // make sure all the commands added here are also
- // removed in R_Shutdown
- ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
- ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f );
- ri.Cmd_AddCommand( "skinlist", R_SkinList_f );
- ri.Cmd_AddCommand( "modellist", R_Modellist_f );
- ri.Cmd_AddCommand( "modelist", R_ModeList_f );
- ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
- ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f );
- ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
-}
-
-/*
-===============
-R_Init
-===============
-*/
-void R_Init( void ) {
- int err;
- int i;
- byte *ptr;
-
- ri.Printf( PRINT_ALL, "----- R_Init -----\n" );
-
- // clear all our internal state
- Com_Memset( &tr, 0, sizeof( tr ) );
- Com_Memset( &backEnd, 0, sizeof( backEnd ) );
- Com_Memset( &tess, 0, sizeof( tess ) );
-
-// Swap_Init();
-
- if ( (int)tess.xyz & 15 ) {
- Com_Printf( "WARNING: tess.xyz not 16 byte aligned\n" );
- }
- Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );
-
- //
- // init function tables
- //
- for ( i = 0; i < FUNCTABLE_SIZE; i++ )
- {
- tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
- tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
- tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
- tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
-
- if ( i < FUNCTABLE_SIZE / 2 )
- {
- if ( i < FUNCTABLE_SIZE / 4 )
- {
- tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
- }
- else
- {
- tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
- }
- }
- else
- {
- tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
- }
- }
-
- R_InitFogTable();
-
- R_NoiseInit();
-
- R_Register();
-
- max_polys = r_maxpolys->integer;
- if (max_polys < MAX_POLYS)
- max_polys = MAX_POLYS;
-
- max_polyverts = r_maxpolyverts->integer;
- if (max_polyverts < MAX_POLYVERTS)
- max_polyverts = MAX_POLYVERTS;
-
- ptr = ri.Hunk_Alloc( sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
- backEndData[0] = (backEndData_t *) ptr;
- backEndData[0]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[0] ));
- backEndData[0]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys);
- if ( r_smp->integer ) {
- ptr = ri.Hunk_Alloc( sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low);
- backEndData[1] = (backEndData_t *) ptr;
- backEndData[1]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[1] ));
- backEndData[1]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys);
- } else {
- backEndData[1] = NULL;
- }
- R_ToggleSmpFrame();
-
- InitOpenGL();
-
- R_InitImages();
-
- R_InitShaders();
-
- R_InitSkins();
-
- R_ModelInit();
-
- R_InitFreeType();
-
-
- err = qglGetError();
- if ( err != GL_NO_ERROR )
- ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err);
-
- ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" );
-}
-
-/*
-===============
-RE_Shutdown
-===============
-*/
-void RE_Shutdown( qboolean destroyWindow ) {
-
- ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow );
-
- ri.Cmd_RemoveCommand ("modellist");
- ri.Cmd_RemoveCommand ("screenshotJPEG");
- ri.Cmd_RemoveCommand ("screenshot");
- ri.Cmd_RemoveCommand ("imagelist");
- ri.Cmd_RemoveCommand ("shaderlist");
- ri.Cmd_RemoveCommand ("skinlist");
- ri.Cmd_RemoveCommand ("gfxinfo");
- ri.Cmd_RemoveCommand( "modelist" );
- ri.Cmd_RemoveCommand( "shaderstate" );
-
-
- if ( tr.registered ) {
- R_SyncRenderThread();
- R_ShutdownCommandBuffers();
- R_DeleteTextures();
- }
-
- R_DoneFreeType();
-
- // shut down platform specific OpenGL stuff
- if ( destroyWindow ) {
- GLimp_Shutdown();
- }
-
- tr.registered = qfalse;
-}
-
-
-/*
-=============
-RE_EndRegistration
-
-Touch all images to make sure they are resident
-=============
-*/
-void RE_EndRegistration( void ) {
- R_SyncRenderThread();
- if (!Sys_LowPhysicalMemory()) {
- RB_ShowImages();
- }
-}
-
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-GetRefAPI
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
- static refexport_t re;
-
- ri = *rimp;
-
- Com_Memset( &re, 0, sizeof( re ) );
-
- if ( apiVersion != REF_API_VERSION ) {
- ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n",
- REF_API_VERSION, apiVersion );
- return NULL;
- }
-
- // the RE_ functions are Renderer Entry points
-
- re.Shutdown = RE_Shutdown;
-
- re.BeginRegistration = RE_BeginRegistration;
- re.RegisterModel = RE_RegisterModel;
- re.RegisterSkin = RE_RegisterSkin;
- re.RegisterShader = RE_RegisterShader;
- re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
- re.LoadWorld = RE_LoadWorldMap;
- re.SetWorldVisData = RE_SetWorldVisData;
- re.EndRegistration = RE_EndRegistration;
-
- re.BeginFrame = RE_BeginFrame;
- re.EndFrame = RE_EndFrame;
-
- re.MarkFragments = R_MarkFragments;
- re.LerpTag = R_LerpTag;
- re.ModelBounds = R_ModelBounds;
-
- re.ClearScene = RE_ClearScene;
- re.AddRefEntityToScene = RE_AddRefEntityToScene;
- re.AddPolyToScene = RE_AddPolyToScene;
- re.LightForPoint = R_LightForPoint;
- re.AddLightToScene = RE_AddLightToScene;
- re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene;
- re.RenderScene = RE_RenderScene;
-
- re.SetColor = RE_SetColor;
- re.DrawStretchPic = RE_StretchPic;
- re.DrawStretchRaw = RE_StretchRaw;
- re.UploadCinematic = RE_UploadCinematic;
-
- re.RegisterFont = RE_RegisterFont;
- re.RemapShader = R_RemapShader;
- re.GetEntityToken = R_GetEntityToken;
- re.inPVS = R_inPVS;
-
- return &re;
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_init.c -- functions that are not called every frame + +#include "tr_local.h" + +glconfig_t glConfig; +glstate_t glState; + +static void GfxInfo_f( void ); + +cvar_t *r_flareSize; +cvar_t *r_flareFade; + +cvar_t *r_railWidth; +cvar_t *r_railCoreWidth; +cvar_t *r_railSegmentLength; + +cvar_t *r_ignoreFastPath; + +cvar_t *r_verbose; +cvar_t *r_ignore; + +cvar_t *r_displayRefresh; + +cvar_t *r_detailTextures; + +cvar_t *r_znear; + +cvar_t *r_smp; +cvar_t *r_showSmp; +cvar_t *r_skipBackEnd; + +cvar_t *r_ignorehwgamma; +cvar_t *r_measureOverdraw; + +cvar_t *r_inGameVideo; +cvar_t *r_fastsky; +cvar_t *r_drawSun; +cvar_t *r_dynamiclight; +cvar_t *r_dlightBacks; + +cvar_t *r_lodbias; +cvar_t *r_lodscale; + +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_facePlaneCull; +cvar_t *r_showcluster; +cvar_t *r_nocurves; + +cvar_t *r_allowExtensions; + +cvar_t *r_ext_compressed_textures; +cvar_t *r_ext_gamma_control; +cvar_t *r_ext_multitexture; +cvar_t *r_ext_compiled_vertex_array; +cvar_t *r_ext_texture_env_add; + +cvar_t *r_ignoreGLErrors; +cvar_t *r_logFile; + +cvar_t *r_stencilbits; +cvar_t *r_depthbits; +cvar_t *r_colorbits; +cvar_t *r_stereo; +cvar_t *r_primitives; +cvar_t *r_texturebits; + +cvar_t *r_drawBuffer; +cvar_t *r_glDriver; +cvar_t *r_lightmap; +cvar_t *r_vertexLight; +cvar_t *r_uiFullScreen; +cvar_t *r_shadows; +cvar_t *r_flares; +cvar_t *r_mode; +cvar_t *r_nobind; +cvar_t *r_singleShader; +cvar_t *r_roundImagesDown; +cvar_t *r_colorMipLevels; +cvar_t *r_picmip; +cvar_t *r_showtris; +cvar_t *r_showsky; +cvar_t *r_shownormals; +cvar_t *r_finish; +cvar_t *r_clear; +cvar_t *r_swapInterval; +cvar_t *r_textureMode; +cvar_t *r_offsetFactor; +cvar_t *r_offsetUnits; +cvar_t *r_gamma; +cvar_t *r_intensity; +cvar_t *r_lockpvs; +cvar_t *r_noportals; +cvar_t *r_portalOnly; + +cvar_t *r_subdivisions; +cvar_t *r_lodCurveError; + +cvar_t *r_fullscreen; + +cvar_t *r_customwidth; +cvar_t *r_customheight; +cvar_t *r_customaspect; + +cvar_t *r_overBrightBits; +cvar_t *r_mapOverBrightBits; + +cvar_t *r_debugSurface; +cvar_t *r_simpleMipMaps; + +cvar_t *r_showImages; + +cvar_t *r_ambientScale; +cvar_t *r_directedScale; +cvar_t *r_debugLight; +cvar_t *r_debugSort; +cvar_t *r_printShaders; +cvar_t *r_saveFontData; + +cvar_t *r_maxpolys; +int max_polys; +cvar_t *r_maxpolyverts; +int max_polyverts; + +void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); +void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); +void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); + +void ( APIENTRY * qglLockArraysEXT)( GLint, GLint); +void ( APIENTRY * qglUnlockArraysEXT) ( void ); + +static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral ) +{ + if ( shouldBeIntegral ) + { + if ( ( int ) cv->value != cv->integer ) + { + ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' must be integral (%f)\n", cv->name, cv->value ); + ri.Cvar_Set( cv->name, va( "%d", cv->integer ) ); + } + } + + if ( cv->value < minVal ) + { + ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' out of range (%f < %f)\n", cv->name, cv->value, minVal ); + ri.Cvar_Set( cv->name, va( "%f", minVal ) ); + } + else if ( cv->value > maxVal ) + { + ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' out of range (%f > %f)\n", cv->name, cv->value, maxVal ); + ri.Cvar_Set( cv->name, va( "%f", maxVal ) ); + } +} + + +/* +** InitOpenGL +** +** This function is responsible for initializing a valid OpenGL subsystem. This +** is done by calling GLimp_Init (which gives us a working OGL subsystem) then +** setting variables, checking GL constants, and reporting the gfx system config +** to the user. +*/ +static void InitOpenGL( void ) +{ + char renderer_buffer[1024]; + + // + // initialize OS specific portions of the renderer + // + // GLimp_Init directly or indirectly references the following cvars: + // - r_fullscreen + // - r_glDriver + // - r_mode + // - r_(color|depth|stencil)bits + // - r_ignorehwgamma + // - r_gamma + // + + if ( glConfig.vidWidth == 0 ) + { + GLint temp; + + GLimp_Init(); + + strcpy( renderer_buffer, glConfig.renderer_string ); + Q_strlwr( renderer_buffer ); + + // OpenGL driver constants + qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); + glConfig.maxTextureSize = temp; + + // stubbed or broken drivers may have reported 0... + if ( glConfig.maxTextureSize <= 0 ) + { + glConfig.maxTextureSize = 0; + } + } + + // init command buffers and SMP + R_InitCommandBuffers(); + + // print info + GfxInfo_f(); + + // set default state + GL_SetDefaultState(); +} + +/* +================== +GL_CheckErrors +================== +*/ +void GL_CheckErrors( void ) { + int err; + char s[64]; + + err = qglGetError(); + if ( err == GL_NO_ERROR ) { + return; + } + if ( r_ignoreGLErrors->integer ) { + return; + } + switch( err ) { + case GL_INVALID_ENUM: + strcpy( s, "GL_INVALID_ENUM" ); + break; + case GL_INVALID_VALUE: + strcpy( s, "GL_INVALID_VALUE" ); + break; + case GL_INVALID_OPERATION: + strcpy( s, "GL_INVALID_OPERATION" ); + break; + case GL_STACK_OVERFLOW: + strcpy( s, "GL_STACK_OVERFLOW" ); + break; + case GL_STACK_UNDERFLOW: + strcpy( s, "GL_STACK_UNDERFLOW" ); + break; + case GL_OUT_OF_MEMORY: + strcpy( s, "GL_OUT_OF_MEMORY" ); + break; + default: + Com_sprintf( s, sizeof(s), "%i", err); + break; + } + + ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s ); +} + + +/* +** R_GetModeInfo +*/ +typedef struct vidmode_s +{ + const char *description; + int width, height; + float pixelAspect; // pixel width / height +} vidmode_t; + +vidmode_t r_vidModes[] = +{ + { "Mode 0: 320x240", 320, 240, 1 }, + { "Mode 1: 400x300", 400, 300, 1 }, + { "Mode 2: 512x384", 512, 384, 1 }, + { "Mode 3: 640x480", 640, 480, 1 }, + { "Mode 4: 800x600", 800, 600, 1 }, + { "Mode 5: 960x720", 960, 720, 1 }, + { "Mode 6: 1024x768", 1024, 768, 1 }, + { "Mode 7: 1152x864", 1152, 864, 1 }, + { "Mode 8: 1280x1024", 1280, 1024, 1 }, + { "Mode 9: 1600x1200", 1600, 1200, 1 }, + { "Mode 10: 2048x1536", 2048, 1536, 1 }, + { "Mode 11: 856x480 (wide)",856, 480, 1 } +}; +static int s_numVidModes = ( sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) ); + +qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) { + vidmode_t *vm; + + if ( mode < -1 ) { + return qfalse; + } + if ( mode >= s_numVidModes ) { + return qfalse; + } + + if ( mode == -1 ) { + *width = r_customwidth->integer; + *height = r_customheight->integer; + *windowAspect = r_customaspect->value; + return qtrue; + } + + vm = &r_vidModes[mode]; + + *width = vm->width; + *height = vm->height; + *windowAspect = (float)vm->width / ( vm->height * vm->pixelAspect ); + + return qtrue; +} + +/* +** R_ModeList_f +*/ +static void R_ModeList_f( void ) +{ + int i; + + ri.Printf( PRINT_ALL, "\n" ); + for ( i = 0; i < s_numVidModes; i++ ) + { + ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description ); + } + ri.Printf( PRINT_ALL, "\n" ); +} + + +/* +============================================================================== + + SCREEN SHOTS + +NOTE TTimo +some thoughts about the screenshots system: +screenshots get written in fs_homepath + fs_gamedir +vanilla q3 .. baseq3/screenshots/ *.tga +team arena .. missionpack/screenshots/ *.tga + +two commands: "screenshot" and "screenshotJPEG" +we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available +(with FS_FileExists / FS_FOpenFileWrite calls) +FIXME: the statics don't get a reinit between fs_game changes + +============================================================================== +*/ + +/* +================== +RB_TakeScreenshot +================== +*/ +void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { + byte *buffer; + int i, c, temp; + + buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18); + + Com_Memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = width & 255; + buffer[13] = width >> 8; + buffer[14] = height & 255; + buffer[15] = height >> 8; + buffer[16] = 24; // pixel size + + qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + + // swap rgb to bgr + c = 18 + width * height * 3; + for (i=18 ; i<c ; i+=3) { + temp = buffer[i]; + buffer[i] = buffer[i+2]; + buffer[i+2] = temp; + } + + // gamma correct + if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); + } + + ri.FS_WriteFile( fileName, buffer, c ); + + ri.Hunk_FreeTempMemory( buffer ); +} + +/* +================== +RB_TakeScreenshotJPEG +================== +*/ +void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { + byte *buffer; + + buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); + + qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); + + // gamma correct + if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); + } + + ri.FS_WriteFile( fileName, buffer, 1 ); // create path + SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer); + + ri.Hunk_FreeTempMemory( buffer ); +} + +/* +================== +RB_TakeScreenshotCmd +================== +*/ +const void *RB_TakeScreenshotCmd( const void *data ) { + const screenshotCommand_t *cmd; + + cmd = (const screenshotCommand_t *)data; + + if (cmd->jpeg) + RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); + else + RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); + + return (const void *)(cmd + 1); +} + +/* +================== +R_TakeScreenshot +================== +*/ +void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) { + static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame? + screenshotCommand_t *cmd; + + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_SCREENSHOT; + + cmd->x = x; + cmd->y = y; + cmd->width = width; + cmd->height = height; + Q_strncpyz( fileName, name, sizeof(fileName) ); + cmd->fileName = fileName; + cmd->jpeg = jpeg; +} + +/* +================== +R_ScreenshotFilename +================== +*/ +void R_ScreenshotFilename( int lastNumber, char *fileName ) { + int a,b,c,d; + + if ( lastNumber < 0 || lastNumber > 9999 ) { + Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" ); + return; + } + + a = lastNumber / 1000; + lastNumber -= a*1000; + b = lastNumber / 100; + lastNumber -= b*100; + c = lastNumber / 10; + lastNumber -= c*10; + d = lastNumber; + + Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga" + , a, b, c, d ); +} + +/* +================== +R_ScreenshotFilename +================== +*/ +void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) { + int a,b,c,d; + + if ( lastNumber < 0 || lastNumber > 9999 ) { + Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" ); + return; + } + + a = lastNumber / 1000; + lastNumber -= a*1000; + b = lastNumber / 100; + lastNumber -= b*100; + c = lastNumber / 10; + lastNumber -= c*10; + d = lastNumber; + + Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg" + , a, b, c, d ); +} + +/* +==================== +R_LevelShot + +levelshots are specialized 128*128 thumbnails for +the menu system, sampled down from full screen distorted images +==================== +*/ +void R_LevelShot( void ) { + char checkname[MAX_OSPATH]; + byte *buffer; + byte *source; + byte *src, *dst; + int x, y; + int r, g, b; + float xScale, yScale; + int xx, yy; + + sprintf( checkname, "levelshots/%s.tga", tr.world->baseName ); + + source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); + + buffer = ri.Hunk_AllocateTempMemory( 128 * 128*3 + 18); + Com_Memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = 128; + buffer[14] = 128; + buffer[16] = 24; // pixel size + + qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); + + // resample from source + xScale = glConfig.vidWidth / 512.0f; + yScale = glConfig.vidHeight / 384.0f; + for ( y = 0 ; y < 128 ; y++ ) { + for ( x = 0 ; x < 128 ; x++ ) { + r = g = b = 0; + for ( yy = 0 ; yy < 3 ; yy++ ) { + for ( xx = 0 ; xx < 4 ; xx++ ) { + src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) ); + r += src[0]; + g += src[1]; + b += src[2]; + } + } + dst = buffer + 18 + 3 * ( y * 128 + x ); + dst[0] = b / 12; + dst[1] = g / 12; + dst[2] = r / 12; + } + } + + // gamma correct + if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); + } + + ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); + + ri.Hunk_FreeTempMemory( buffer ); + ri.Hunk_FreeTempMemory( source ); + + ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); +} + +/* +================== +R_ScreenShot_f + +screenshot +screenshot [silent] +screenshot [levelshot] +screenshot [filename] + +Doesn't print the pacifier message if there is a second arg +================== +*/ +void R_ScreenShot_f (void) { + char checkname[MAX_OSPATH]; + static int lastNumber = -1; + qboolean silent; + + if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { + R_LevelShot(); + return; + } + + if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { + silent = qtrue; + } else { + silent = qfalse; + } + + if ( ri.Cmd_Argc() == 2 && !silent ) { + // explicit filename + Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) ); + } else { + // scan for a free filename + + // if we have saved a previous screenshot, don't scan + // again, because recording demo avis can involve + // thousands of shots + if ( lastNumber == -1 ) { + lastNumber = 0; + } + // scan for a free number + for ( ; lastNumber <= 9999 ; lastNumber++ ) { + R_ScreenshotFilename( lastNumber, checkname ); + + if (!ri.FS_FileExists( checkname )) + { + break; // file doesn't exist + } + } + + if ( lastNumber >= 9999 ) { + ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); + return; + } + + lastNumber++; + } + + R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse ); + + if ( !silent ) { + ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); + } +} + +void R_ScreenShotJPEG_f (void) { + char checkname[MAX_OSPATH]; + static int lastNumber = -1; + qboolean silent; + + if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { + R_LevelShot(); + return; + } + + if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { + silent = qtrue; + } else { + silent = qfalse; + } + + if ( ri.Cmd_Argc() == 2 && !silent ) { + // explicit filename + Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) ); + } else { + // scan for a free filename + + // if we have saved a previous screenshot, don't scan + // again, because recording demo avis can involve + // thousands of shots + if ( lastNumber == -1 ) { + lastNumber = 0; + } + // scan for a free number + for ( ; lastNumber <= 9999 ; lastNumber++ ) { + R_ScreenshotFilenameJPEG( lastNumber, checkname ); + + if (!ri.FS_FileExists( checkname )) + { + break; // file doesn't exist + } + } + + if ( lastNumber == 10000 ) { + ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); + return; + } + + lastNumber++; + } + + R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue ); + + if ( !silent ) { + ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); + } +} + +//============================================================================ + +/* +** GL_SetDefaultState +*/ +void GL_SetDefaultState( void ) +{ + qglClearDepth( 1.0f ); + + qglCullFace(GL_FRONT); + + qglColor4f (1,1,1,1); + + // initialize downstream texture unit if we're running + // in a multitexture environment + if ( qglActiveTextureARB ) { + GL_SelectTexture( 1 ); + GL_TextureMode( r_textureMode->string ); + GL_TexEnv( GL_MODULATE ); + qglDisable( GL_TEXTURE_2D ); + GL_SelectTexture( 0 ); + } + + qglEnable(GL_TEXTURE_2D); + GL_TextureMode( r_textureMode->string ); + GL_TexEnv( GL_MODULATE ); + + qglShadeModel( GL_SMOOTH ); + qglDepthFunc( GL_LEQUAL ); + + // the vertex array is always enabled, but the color and texture + // arrays are enabled and disabled around the compiled vertex array call + qglEnableClientState (GL_VERTEX_ARRAY); + + // + // make sure our GL state vector is set correctly + // + glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; + + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + qglDepthMask( GL_TRUE ); + qglDisable( GL_DEPTH_TEST ); + qglEnable( GL_SCISSOR_TEST ); + qglDisable( GL_CULL_FACE ); + qglDisable( GL_BLEND ); +} + + +/* +================ +GfxInfo_f +================ +*/ +void GfxInfo_f( void ) +{ + cvar_t *sys_cpustring = ri.Cvar_Get( "sys_cpustring", "", 0 ); + const char *enablestrings[] = + { + "disabled", + "enabled" + }; + const char *fsstrings[] = + { + "windowed", + "fullscreen" + }; + + ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string ); + ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); + ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); + ri.Printf( PRINT_ALL, "GL_EXTENSIONS: %s\n", glConfig.extensions_string ); + ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); + ri.Printf( PRINT_ALL, "GL_MAX_ACTIVE_TEXTURES_ARB: %d\n", glConfig.maxActiveTextures ); + ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); + ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); + if ( glConfig.displayFrequency ) + { + ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency ); + } + else + { + ri.Printf( PRINT_ALL, "N/A\n" ); + } + if ( glConfig.deviceSupportsGamma ) + { + ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits ); + } + else + { + ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits ); + } + ri.Printf( PRINT_ALL, "CPU: %s\n", sys_cpustring->string ); + + // rendering primitives + { + int primitives; + + // default is to use triangles if compiled vertex arrays are present + ri.Printf( PRINT_ALL, "rendering primitives: " ); + primitives = r_primitives->integer; + if ( primitives == 0 ) { + if ( qglLockArraysEXT ) { + primitives = 2; + } else { + primitives = 1; + } + } + if ( primitives == -1 ) { + ri.Printf( PRINT_ALL, "none\n" ); + } else if ( primitives == 2 ) { + ri.Printf( PRINT_ALL, "single glDrawElements\n" ); + } else if ( primitives == 1 ) { + ri.Printf( PRINT_ALL, "multiple glArrayElement\n" ); + } else if ( primitives == 3 ) { + ri.Printf( PRINT_ALL, "multiple glColor4ubv + glTexCoord2fv + glVertex3fv\n" ); + } + } + + ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); + ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); + ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); + ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); + ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); + ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); + ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); + if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) + { + ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" ); + } + if ( glConfig.hardwareType == GLHW_RAGEPRO ) + { + ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" ); + } + if ( glConfig.hardwareType == GLHW_RIVA128 ) + { + ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); + } + if ( glConfig.smpActive ) { + ri.Printf( PRINT_ALL, "Using dual processor acceleration\n" ); + } + if ( r_finish->integer ) { + ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); + } +} + +/* +=============== +R_Register +=============== +*/ +void R_Register( void ) +{ + // + // latched and archived variables + // + r_glDriver = ri.Cvar_Get( "r_glDriver", OPENGL_DRIVER_NAME, CVAR_ARCHIVE | CVAR_LATCH ); + r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_gamma_control = ri.Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); +#ifdef __linux__ // broken on linux + r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "0", CVAR_ARCHIVE | CVAR_LATCH); +#else + r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); +#endif + + r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); + AssertCvarRange( r_picmip, 0, 16, qtrue ); + r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_stereo = ri.Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH ); +#ifdef __linux__ + r_stencilbits = ri.Cvar_Get( "r_stencilbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); +#else + r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); +#endif + r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); + r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH ); + r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); + r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); + r_customaspect = ri.Cvar_Get( "r_customaspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); + r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); +#if (defined(MACOS_X) || defined(__linux__)) && defined(SMP) + // Default to using SMP on Mac OS X or Linux if we have multiple processors + r_smp = ri.Cvar_Get( "r_smp", Sys_ProcessorCount() > 1 ? "1" : "0", CVAR_ARCHIVE | CVAR_LATCH); +#else + r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_ARCHIVE | CVAR_LATCH); +#endif + r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH ); + + // + // temporary latched variables that can only change over a restart + // + r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH ); + AssertCvarRange( r_displayRefresh, 0, 200, qtrue ); + r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT ); + r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH ); + r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); + r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); + + // + // archived variables that can change at any time + // + r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT ); + r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); + r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); + r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); + AssertCvarRange( r_znear, 0.001f, 200, qtrue ); + r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); + r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); + r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); + r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); + r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); + r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); + r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); + r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); + r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", CVAR_ARCHIVE ); +#ifdef __MACOS__ + r_gamma = ri.Cvar_Get( "r_gamma", "1.2", CVAR_ARCHIVE ); +#else + r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE ); +#endif + r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE ); + + r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE ); + r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE ); + r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE ); + + r_primitives = ri.Cvar_Get( "r_primitives", "0", CVAR_ARCHIVE ); + + r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT ); + r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); + + // + // temporary variables that can change at any time + // + r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); + + r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP ); + r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); + r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); + r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 ); + + r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); + r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); + r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); + r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); + + r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT); + r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); + + r_showSmp = ri.Cvar_Get ("r_showSmp", "0", CVAR_CHEAT); + r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); + + r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); + r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT ); + r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); + r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT ); + r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); + r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT); + r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT); + r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT); + r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT); + r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); + r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); + r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT); + r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT); + r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT); + r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT); + r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT); + r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT); + r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT ); + r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT ); + r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); + r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT); + r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT); + r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 ); + + r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); + r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); + + // make sure all the commands added here are also + // removed in R_Shutdown + ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); + ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); + ri.Cmd_AddCommand( "skinlist", R_SkinList_f ); + ri.Cmd_AddCommand( "modellist", R_Modellist_f ); + ri.Cmd_AddCommand( "modelist", R_ModeList_f ); + ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); + ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f ); + ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); +} + +/* +=============== +R_Init +=============== +*/ +void R_Init( void ) { + int err; + int i; + byte *ptr; + + ri.Printf( PRINT_ALL, "----- R_Init -----\n" ); + + // clear all our internal state + Com_Memset( &tr, 0, sizeof( tr ) ); + Com_Memset( &backEnd, 0, sizeof( backEnd ) ); + Com_Memset( &tess, 0, sizeof( tess ) ); + +// Swap_Init(); + + if ( (int)tess.xyz & 15 ) { + Com_Printf( "WARNING: tess.xyz not 16 byte aligned\n" ); + } + Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); + + // + // init function tables + // + for ( i = 0; i < FUNCTABLE_SIZE; i++ ) + { + tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) ); + tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f; + tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE; + tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i]; + + if ( i < FUNCTABLE_SIZE / 2 ) + { + if ( i < FUNCTABLE_SIZE / 4 ) + { + tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 ); + } + else + { + tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4]; + } + } + else + { + tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2]; + } + } + + R_InitFogTable(); + + R_NoiseInit(); + + R_Register(); + + max_polys = r_maxpolys->integer; + if (max_polys < MAX_POLYS) + max_polys = MAX_POLYS; + + max_polyverts = r_maxpolyverts->integer; + if (max_polyverts < MAX_POLYVERTS) + max_polyverts = MAX_POLYVERTS; + + ptr = ri.Hunk_Alloc( sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); + backEndData[0] = (backEndData_t *) ptr; + backEndData[0]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[0] )); + backEndData[0]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys); + if ( r_smp->integer ) { + ptr = ri.Hunk_Alloc( sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); + backEndData[1] = (backEndData_t *) ptr; + backEndData[1]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[1] )); + backEndData[1]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys); + } else { + backEndData[1] = NULL; + } + R_ToggleSmpFrame(); + + InitOpenGL(); + + R_InitImages(); + + R_InitShaders(); + + R_InitSkins(); + + R_ModelInit(); + + R_InitFreeType(); + + + err = qglGetError(); + if ( err != GL_NO_ERROR ) + ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); + + ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" ); +} + +/* +=============== +RE_Shutdown +=============== +*/ +void RE_Shutdown( qboolean destroyWindow ) { + + ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); + + ri.Cmd_RemoveCommand ("modellist"); + ri.Cmd_RemoveCommand ("screenshotJPEG"); + ri.Cmd_RemoveCommand ("screenshot"); + ri.Cmd_RemoveCommand ("imagelist"); + ri.Cmd_RemoveCommand ("shaderlist"); + ri.Cmd_RemoveCommand ("skinlist"); + ri.Cmd_RemoveCommand ("gfxinfo"); + ri.Cmd_RemoveCommand( "modelist" ); + ri.Cmd_RemoveCommand( "shaderstate" ); + + + if ( tr.registered ) { + R_SyncRenderThread(); + R_ShutdownCommandBuffers(); + R_DeleteTextures(); + } + + R_DoneFreeType(); + + // shut down platform specific OpenGL stuff + if ( destroyWindow ) { + GLimp_Shutdown(); + } + + tr.registered = qfalse; +} + + +/* +============= +RE_EndRegistration + +Touch all images to make sure they are resident +============= +*/ +void RE_EndRegistration( void ) { + R_SyncRenderThread(); + if (!Sys_LowPhysicalMemory()) { + RB_ShowImages(); + } +} + + +/* +@@@@@@@@@@@@@@@@@@@@@ +GetRefAPI + +@@@@@@@@@@@@@@@@@@@@@ +*/ +refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { + static refexport_t re; + + ri = *rimp; + + Com_Memset( &re, 0, sizeof( re ) ); + + if ( apiVersion != REF_API_VERSION ) { + ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", + REF_API_VERSION, apiVersion ); + return NULL; + } + + // the RE_ functions are Renderer Entry points + + re.Shutdown = RE_Shutdown; + + re.BeginRegistration = RE_BeginRegistration; + re.RegisterModel = RE_RegisterModel; + re.RegisterSkin = RE_RegisterSkin; + re.RegisterShader = RE_RegisterShader; + re.RegisterShaderNoMip = RE_RegisterShaderNoMip; + re.LoadWorld = RE_LoadWorldMap; + re.SetWorldVisData = RE_SetWorldVisData; + re.EndRegistration = RE_EndRegistration; + + re.BeginFrame = RE_BeginFrame; + re.EndFrame = RE_EndFrame; + + re.MarkFragments = R_MarkFragments; + re.LerpTag = R_LerpTag; + re.ModelBounds = R_ModelBounds; + + re.ClearScene = RE_ClearScene; + re.AddRefEntityToScene = RE_AddRefEntityToScene; + re.AddPolyToScene = RE_AddPolyToScene; + re.LightForPoint = R_LightForPoint; + re.AddLightToScene = RE_AddLightToScene; + re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; + re.RenderScene = RE_RenderScene; + + re.SetColor = RE_SetColor; + re.DrawStretchPic = RE_StretchPic; + re.DrawStretchRaw = RE_StretchRaw; + re.UploadCinematic = RE_UploadCinematic; + + re.RegisterFont = RE_RegisterFont; + re.RemapShader = R_RemapShader; + re.GetEntityToken = R_GetEntityToken; + re.inPVS = R_inPVS; + + return &re; +} diff --git a/code/renderer/tr_light.c b/code/renderer/tr_light.c index 01d046c..b20e253 100755 --- a/code/renderer/tr_light.c +++ b/code/renderer/tr_light.c @@ -1,395 +1,395 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_light.c
-
-#include "tr_local.h"
-
-#define DLIGHT_AT_RADIUS 16
-// at the edge of a dlight's influence, this amount of light will be added
-
-#define DLIGHT_MINIMUM_RADIUS 16
-// never calculate a range less than this to prevent huge light numbers
-
-
-/*
-===============
-R_TransformDlights
-
-Transforms the origins of an array of dlights.
-Used by both the front end (for DlightBmodel) and
-the back end (before doing the lighting calculation)
-===============
-*/
-void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) {
- int i;
- vec3_t temp;
-
- for ( i = 0 ; i < count ; i++, dl++ ) {
- VectorSubtract( dl->origin, or->origin, temp );
- dl->transformed[0] = DotProduct( temp, or->axis[0] );
- dl->transformed[1] = DotProduct( temp, or->axis[1] );
- dl->transformed[2] = DotProduct( temp, or->axis[2] );
- }
-}
-
-/*
-=============
-R_DlightBmodel
-
-Determine which dynamic lights may effect this bmodel
-=============
-*/
-void R_DlightBmodel( bmodel_t *bmodel ) {
- int i, j;
- dlight_t *dl;
- int mask;
- msurface_t *surf;
-
- // transform all the lights
- R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );
-
- mask = 0;
- for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
- dl = &tr.refdef.dlights[i];
-
- // see if the point is close enough to the bounds to matter
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
- break;
- }
- if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
- break;
- }
- }
- if ( j < 3 ) {
- continue;
- }
-
- // we need to check this light
- mask |= 1 << i;
- }
-
- tr.currentEntity->needDlights = (mask != 0);
-
- // set the dlight bits in all the surfaces
- for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
- surf = bmodel->firstSurface + i;
-
- if ( *surf->data == SF_FACE ) {
- ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
- } else if ( *surf->data == SF_GRID ) {
- ((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
- } else if ( *surf->data == SF_TRIANGLES ) {
- ((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask;
- }
- }
-}
-
-
-/*
-=============================================================================
-
-LIGHT SAMPLING
-
-=============================================================================
-*/
-
-extern cvar_t *r_ambientScale;
-extern cvar_t *r_directedScale;
-extern cvar_t *r_debugLight;
-
-/*
-=================
-R_SetupEntityLightingGrid
-
-=================
-*/
-static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
- vec3_t lightOrigin;
- int pos[3];
- int i, j;
- byte *gridData;
- float frac[3];
- int gridStep[3];
- vec3_t direction;
- float totalFactor;
-
- if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
- // seperate lightOrigins are needed so an object that is
- // sinking into the ground can still be lit, and so
- // multi-part models can be lit identically
- VectorCopy( ent->e.lightingOrigin, lightOrigin );
- } else {
- VectorCopy( ent->e.origin, lightOrigin );
- }
-
- VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
- for ( i = 0 ; i < 3 ; i++ ) {
- float v;
-
- v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
- pos[i] = floor( v );
- frac[i] = v - pos[i];
- if ( pos[i] < 0 ) {
- pos[i] = 0;
- } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
- pos[i] = tr.world->lightGridBounds[i] - 1;
- }
- }
-
- VectorClear( ent->ambientLight );
- VectorClear( ent->directedLight );
- VectorClear( direction );
-
- assert( tr.world->lightGridData ); // bk010103 - NULL with -nolight maps
-
- // trilerp the light value
- gridStep[0] = 8;
- gridStep[1] = 8 * tr.world->lightGridBounds[0];
- gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
- gridData = tr.world->lightGridData + pos[0] * gridStep[0]
- + pos[1] * gridStep[1] + pos[2] * gridStep[2];
-
- totalFactor = 0;
- for ( i = 0 ; i < 8 ; i++ ) {
- float factor;
- byte *data;
- int lat, lng;
- vec3_t normal;
- #if idppc
- float d0, d1, d2, d3, d4, d5;
- #endif
- factor = 1.0;
- data = gridData;
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( i & (1<<j) ) {
- factor *= frac[j];
- data += gridStep[j];
- } else {
- factor *= (1.0f - frac[j]);
- }
- }
-
- if ( !(data[0]+data[1]+data[2]) ) {
- continue; // ignore samples in walls
- }
- totalFactor += factor;
- #if idppc
- d0 = data[0]; d1 = data[1]; d2 = data[2];
- d3 = data[3]; d4 = data[4]; d5 = data[5];
-
- ent->ambientLight[0] += factor * d0;
- ent->ambientLight[1] += factor * d1;
- ent->ambientLight[2] += factor * d2;
-
- ent->directedLight[0] += factor * d3;
- ent->directedLight[1] += factor * d4;
- ent->directedLight[2] += factor * d5;
- #else
- ent->ambientLight[0] += factor * data[0];
- ent->ambientLight[1] += factor * data[1];
- ent->ambientLight[2] += factor * data[2];
-
- ent->directedLight[0] += factor * data[3];
- ent->directedLight[1] += factor * data[4];
- ent->directedLight[2] += factor * data[5];
- #endif
- lat = data[7];
- lng = data[6];
- lat *= (FUNCTABLE_SIZE/256);
- lng *= (FUNCTABLE_SIZE/256);
-
- // decode X as cos( lat ) * sin( long )
- // decode Y as sin( lat ) * sin( long )
- // decode Z as cos( long )
-
- normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- VectorMA( direction, factor, normal, direction );
- }
-
- if ( totalFactor > 0 && totalFactor < 0.99 ) {
- totalFactor = 1.0f / totalFactor;
- VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
- VectorScale( ent->directedLight, totalFactor, ent->directedLight );
- }
-
- VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
- VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
-
- VectorNormalize2( direction, ent->lightDir );
-}
-
-
-/*
-===============
-LogLight
-===============
-*/
-static void LogLight( trRefEntity_t *ent ) {
- int max1, max2;
-
- if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
- return;
- }
-
- max1 = ent->ambientLight[0];
- if ( ent->ambientLight[1] > max1 ) {
- max1 = ent->ambientLight[1];
- } else if ( ent->ambientLight[2] > max1 ) {
- max1 = ent->ambientLight[2];
- }
-
- max2 = ent->directedLight[0];
- if ( ent->directedLight[1] > max2 ) {
- max2 = ent->directedLight[1];
- } else if ( ent->directedLight[2] > max2 ) {
- max2 = ent->directedLight[2];
- }
-
- ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
-}
-
-/*
-=================
-R_SetupEntityLighting
-
-Calculates all the lighting values that will be used
-by the Calc_* functions
-=================
-*/
-void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
- int i;
- dlight_t *dl;
- float power;
- vec3_t dir;
- float d;
- vec3_t lightDir;
- vec3_t lightOrigin;
-
- // lighting calculations
- if ( ent->lightingCalculated ) {
- return;
- }
- ent->lightingCalculated = qtrue;
-
- //
- // trace a sample point down to find ambient light
- //
- if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
- // seperate lightOrigins are needed so an object that is
- // sinking into the ground can still be lit, and so
- // multi-part models can be lit identically
- VectorCopy( ent->e.lightingOrigin, lightOrigin );
- } else {
- VectorCopy( ent->e.origin, lightOrigin );
- }
-
- // if NOWORLDMODEL, only use dynamic lights (menu system, etc)
- if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
- && tr.world->lightGridData ) {
- R_SetupEntityLightingGrid( ent );
- } else {
- ent->ambientLight[0] = ent->ambientLight[1] =
- ent->ambientLight[2] = tr.identityLight * 150;
- ent->directedLight[0] = ent->directedLight[1] =
- ent->directedLight[2] = tr.identityLight * 150;
- VectorCopy( tr.sunDirection, ent->lightDir );
- }
-
- // bonus items and view weapons have a fixed minimum add
- if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
- // give everything a minimum light add
- ent->ambientLight[0] += tr.identityLight * 32;
- ent->ambientLight[1] += tr.identityLight * 32;
- ent->ambientLight[2] += tr.identityLight * 32;
- }
-
- //
- // modify the light by dynamic lights
- //
- d = VectorLength( ent->directedLight );
- VectorScale( ent->lightDir, d, lightDir );
-
- for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
- dl = &refdef->dlights[i];
- VectorSubtract( dl->origin, lightOrigin, dir );
- d = VectorNormalize( dir );
-
- power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
- if ( d < DLIGHT_MINIMUM_RADIUS ) {
- d = DLIGHT_MINIMUM_RADIUS;
- }
- d = power / ( d * d );
-
- VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
- VectorMA( lightDir, d, dir, lightDir );
- }
-
- // clamp ambient
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( ent->ambientLight[i] > tr.identityLightByte ) {
- ent->ambientLight[i] = tr.identityLightByte;
- }
- }
-
- if ( r_debugLight->integer ) {
- LogLight( ent );
- }
-
- // save out the byte packet version
- ((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] );
- ((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] );
- ((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] );
- ((byte *)&ent->ambientLightInt)[3] = 0xff;
-
- // transform the direction to local space
- VectorNormalize( lightDir );
- ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
- ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
- ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
-}
-
-/*
-=================
-R_LightForPoint
-=================
-*/
-int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
-{
- trRefEntity_t ent;
-
- // bk010103 - this segfaults with -nolight maps
- if ( tr.world->lightGridData == NULL )
- return qfalse;
-
- Com_Memset(&ent, 0, sizeof(ent));
- VectorCopy( point, ent.e.origin );
- R_SetupEntityLightingGrid( &ent );
- VectorCopy(ent.ambientLight, ambientLight);
- VectorCopy(ent.directedLight, directedLight);
- VectorCopy(ent.lightDir, lightDir);
-
- return qtrue;
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_light.c + +#include "tr_local.h" + +#define DLIGHT_AT_RADIUS 16 +// at the edge of a dlight's influence, this amount of light will be added + +#define DLIGHT_MINIMUM_RADIUS 16 +// never calculate a range less than this to prevent huge light numbers + + +/* +=============== +R_TransformDlights + +Transforms the origins of an array of dlights. +Used by both the front end (for DlightBmodel) and +the back end (before doing the lighting calculation) +=============== +*/ +void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { + int i; + vec3_t temp; + + for ( i = 0 ; i < count ; i++, dl++ ) { + VectorSubtract( dl->origin, or->origin, temp ); + dl->transformed[0] = DotProduct( temp, or->axis[0] ); + dl->transformed[1] = DotProduct( temp, or->axis[1] ); + dl->transformed[2] = DotProduct( temp, or->axis[2] ); + } +} + +/* +============= +R_DlightBmodel + +Determine which dynamic lights may effect this bmodel +============= +*/ +void R_DlightBmodel( bmodel_t *bmodel ) { + int i, j; + dlight_t *dl; + int mask; + msurface_t *surf; + + // transform all the lights + R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or ); + + mask = 0; + for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) { + dl = &tr.refdef.dlights[i]; + + // see if the point is close enough to the bounds to matter + for ( j = 0 ; j < 3 ; j++ ) { + if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) { + break; + } + if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) { + break; + } + } + if ( j < 3 ) { + continue; + } + + // we need to check this light + mask |= 1 << i; + } + + tr.currentEntity->needDlights = (mask != 0); + + // set the dlight bits in all the surfaces + for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { + surf = bmodel->firstSurface + i; + + if ( *surf->data == SF_FACE ) { + ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + } else if ( *surf->data == SF_GRID ) { + ((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + } else if ( *surf->data == SF_TRIANGLES ) { + ((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + } + } +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +extern cvar_t *r_ambientScale; +extern cvar_t *r_directedScale; +extern cvar_t *r_debugLight; + +/* +================= +R_SetupEntityLightingGrid + +================= +*/ +static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) { + vec3_t lightOrigin; + int pos[3]; + int i, j; + byte *gridData; + float frac[3]; + int gridStep[3]; + vec3_t direction; + float totalFactor; + + if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { + // seperate lightOrigins are needed so an object that is + // sinking into the ground can still be lit, and so + // multi-part models can be lit identically + VectorCopy( ent->e.lightingOrigin, lightOrigin ); + } else { + VectorCopy( ent->e.origin, lightOrigin ); + } + + VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); + for ( i = 0 ; i < 3 ; i++ ) { + float v; + + v = lightOrigin[i]*tr.world->lightGridInverseSize[i]; + pos[i] = floor( v ); + frac[i] = v - pos[i]; + if ( pos[i] < 0 ) { + pos[i] = 0; + } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) { + pos[i] = tr.world->lightGridBounds[i] - 1; + } + } + + VectorClear( ent->ambientLight ); + VectorClear( ent->directedLight ); + VectorClear( direction ); + + assert( tr.world->lightGridData ); // bk010103 - NULL with -nolight maps + + // trilerp the light value + gridStep[0] = 8; + gridStep[1] = 8 * tr.world->lightGridBounds[0]; + gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1]; + gridData = tr.world->lightGridData + pos[0] * gridStep[0] + + pos[1] * gridStep[1] + pos[2] * gridStep[2]; + + totalFactor = 0; + for ( i = 0 ; i < 8 ; i++ ) { + float factor; + byte *data; + int lat, lng; + vec3_t normal; + #if idppc + float d0, d1, d2, d3, d4, d5; + #endif + factor = 1.0; + data = gridData; + for ( j = 0 ; j < 3 ; j++ ) { + if ( i & (1<<j) ) { + factor *= frac[j]; + data += gridStep[j]; + } else { + factor *= (1.0f - frac[j]); + } + } + + if ( !(data[0]+data[1]+data[2]) ) { + continue; // ignore samples in walls + } + totalFactor += factor; + #if idppc + d0 = data[0]; d1 = data[1]; d2 = data[2]; + d3 = data[3]; d4 = data[4]; d5 = data[5]; + + ent->ambientLight[0] += factor * d0; + ent->ambientLight[1] += factor * d1; + ent->ambientLight[2] += factor * d2; + + ent->directedLight[0] += factor * d3; + ent->directedLight[1] += factor * d4; + ent->directedLight[2] += factor * d5; + #else + ent->ambientLight[0] += factor * data[0]; + ent->ambientLight[1] += factor * data[1]; + ent->ambientLight[2] += factor * data[2]; + + ent->directedLight[0] += factor * data[3]; + ent->directedLight[1] += factor * data[4]; + ent->directedLight[2] += factor * data[5]; + #endif + lat = data[7]; + lng = data[6]; + lat *= (FUNCTABLE_SIZE/256); + lng *= (FUNCTABLE_SIZE/256); + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + VectorMA( direction, factor, normal, direction ); + } + + if ( totalFactor > 0 && totalFactor < 0.99 ) { + totalFactor = 1.0f / totalFactor; + VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); + VectorScale( ent->directedLight, totalFactor, ent->directedLight ); + } + + VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); + VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); + + VectorNormalize2( direction, ent->lightDir ); +} + + +/* +=============== +LogLight +=============== +*/ +static void LogLight( trRefEntity_t *ent ) { + int max1, max2; + + if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) { + return; + } + + max1 = ent->ambientLight[0]; + if ( ent->ambientLight[1] > max1 ) { + max1 = ent->ambientLight[1]; + } else if ( ent->ambientLight[2] > max1 ) { + max1 = ent->ambientLight[2]; + } + + max2 = ent->directedLight[0]; + if ( ent->directedLight[1] > max2 ) { + max2 = ent->directedLight[1]; + } else if ( ent->directedLight[2] > max2 ) { + max2 = ent->directedLight[2]; + } + + ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 ); +} + +/* +================= +R_SetupEntityLighting + +Calculates all the lighting values that will be used +by the Calc_* functions +================= +*/ +void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { + int i; + dlight_t *dl; + float power; + vec3_t dir; + float d; + vec3_t lightDir; + vec3_t lightOrigin; + + // lighting calculations + if ( ent->lightingCalculated ) { + return; + } + ent->lightingCalculated = qtrue; + + // + // trace a sample point down to find ambient light + // + if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { + // seperate lightOrigins are needed so an object that is + // sinking into the ground can still be lit, and so + // multi-part models can be lit identically + VectorCopy( ent->e.lightingOrigin, lightOrigin ); + } else { + VectorCopy( ent->e.origin, lightOrigin ); + } + + // if NOWORLDMODEL, only use dynamic lights (menu system, etc) + if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) + && tr.world->lightGridData ) { + R_SetupEntityLightingGrid( ent ); + } else { + ent->ambientLight[0] = ent->ambientLight[1] = + ent->ambientLight[2] = tr.identityLight * 150; + ent->directedLight[0] = ent->directedLight[1] = + ent->directedLight[2] = tr.identityLight * 150; + VectorCopy( tr.sunDirection, ent->lightDir ); + } + + // bonus items and view weapons have a fixed minimum add + if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) { + // give everything a minimum light add + ent->ambientLight[0] += tr.identityLight * 32; + ent->ambientLight[1] += tr.identityLight * 32; + ent->ambientLight[2] += tr.identityLight * 32; + } + + // + // modify the light by dynamic lights + // + d = VectorLength( ent->directedLight ); + VectorScale( ent->lightDir, d, lightDir ); + + for ( i = 0 ; i < refdef->num_dlights ; i++ ) { + dl = &refdef->dlights[i]; + VectorSubtract( dl->origin, lightOrigin, dir ); + d = VectorNormalize( dir ); + + power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); + if ( d < DLIGHT_MINIMUM_RADIUS ) { + d = DLIGHT_MINIMUM_RADIUS; + } + d = power / ( d * d ); + + VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); + VectorMA( lightDir, d, dir, lightDir ); + } + + // clamp ambient + for ( i = 0 ; i < 3 ; i++ ) { + if ( ent->ambientLight[i] > tr.identityLightByte ) { + ent->ambientLight[i] = tr.identityLightByte; + } + } + + if ( r_debugLight->integer ) { + LogLight( ent ); + } + + // save out the byte packet version + ((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] ); + ((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] ); + ((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] ); + ((byte *)&ent->ambientLightInt)[3] = 0xff; + + // transform the direction to local space + VectorNormalize( lightDir ); + ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); + ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); + ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); +} + +/* +================= +R_LightForPoint +================= +*/ +int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) +{ + trRefEntity_t ent; + + // bk010103 - this segfaults with -nolight maps + if ( tr.world->lightGridData == NULL ) + return qfalse; + + Com_Memset(&ent, 0, sizeof(ent)); + VectorCopy( point, ent.e.origin ); + R_SetupEntityLightingGrid( &ent ); + VectorCopy(ent.ambientLight, ambientLight); + VectorCopy(ent.directedLight, directedLight); + VectorCopy(ent.lightDir, lightDir); + + return qtrue; +} diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 1228661..8ad6701 100755 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1,1609 +1,1609 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-
-#ifndef TR_LOCAL_H
-#define TR_LOCAL_H
-
-#include "../game/q_shared.h"
-#include "../qcommon/qfiles.h"
-#include "../qcommon/qcommon.h"
-#include "tr_public.h"
-#include "qgl.h"
-
-#define GL_INDEX_TYPE GL_UNSIGNED_INT
-typedef unsigned int glIndex_t;
-
-// fast float to int conversion
-#if id386 && !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__ ) ) // rb010123
-long myftol( float f );
-#else
-#define myftol(x) ((int)(x))
-#endif
-
-
-// everything that is needed by the backend needs
-// to be double buffered to allow it to run in
-// parallel on a dual cpu machine
-#define SMP_FRAMES 2
-
-// 12 bits
-// see QSORT_SHADERNUM_SHIFT
-#define MAX_SHADERS 16384
-
-//#define MAX_SHADER_STATES 2048
-#define MAX_STATES_PER_SHADER 32
-#define MAX_STATE_NAME 32
-
-// can't be increased without changing bit packing for drawsurfs
-
-
-typedef struct dlight_s {
- vec3_t origin;
- vec3_t color; // range from 0.0 to 1.0, should be color normalized
- float radius;
-
- vec3_t transformed; // origin in local coordinate system
- int additive; // texture detail is lost tho when the lightmap is dark
-} dlight_t;
-
-
-// a trRefEntity_t has all the information passed in by
-// the client game, as well as some locally derived info
-typedef struct {
- refEntity_t e;
-
- float axisLength; // compensate for non-normalized axis
-
- qboolean needDlights; // true for bmodels that touch a dlight
- qboolean lightingCalculated;
- vec3_t lightDir; // normalized direction towards light
- vec3_t ambientLight; // color normalized to 0-255
- int ambientLightInt; // 32 bit rgba packed
- vec3_t directedLight;
-} trRefEntity_t;
-
-
-typedef struct {
- vec3_t origin; // in world coordinates
- vec3_t axis[3]; // orientation in world
- vec3_t viewOrigin; // viewParms->or.origin in local coordinates
- float modelMatrix[16];
-} orientationr_t;
-
-typedef struct image_s {
- char imgName[MAX_QPATH]; // game path, including extension
- int width, height; // source image
- int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE
- GLuint texnum; // gl texture binding
-
- int frameUsed; // for texture usage in frame statistics
-
- int internalFormat;
- int TMU; // only needed for voodoo2
-
- qboolean mipmap;
- qboolean allowPicmip;
- int wrapClampMode; // GL_CLAMP or GL_REPEAT
-
- struct image_s* next;
-} image_t;
-
-//===============================================================================
-
-typedef enum {
- SS_BAD,
- SS_PORTAL, // mirrors, portals, viewscreens
- SS_ENVIRONMENT, // sky box
- SS_OPAQUE, // opaque
-
- SS_DECAL, // scorch marks, etc.
- SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges
- // in addition to alpha test
- SS_BANNER,
-
- SS_FOG,
-
- SS_UNDERWATER, // for items that should be drawn in front of the water plane
-
- SS_BLEND0, // regular transparency and filters
- SS_BLEND1, // generally only used for additive type effects
- SS_BLEND2,
- SS_BLEND3,
-
- SS_BLEND6,
- SS_STENCIL_SHADOW,
- SS_ALMOST_NEAREST, // gun smoke puffs
-
- SS_NEAREST // blood blobs
-} shaderSort_t;
-
-
-#define MAX_SHADER_STAGES 8
-
-typedef enum {
- GF_NONE,
-
- GF_SIN,
- GF_SQUARE,
- GF_TRIANGLE,
- GF_SAWTOOTH,
- GF_INVERSE_SAWTOOTH,
-
- GF_NOISE
-
-} genFunc_t;
-
-
-typedef enum {
- DEFORM_NONE,
- DEFORM_WAVE,
- DEFORM_NORMALS,
- DEFORM_BULGE,
- DEFORM_MOVE,
- DEFORM_PROJECTION_SHADOW,
- DEFORM_AUTOSPRITE,
- DEFORM_AUTOSPRITE2,
- DEFORM_TEXT0,
- DEFORM_TEXT1,
- DEFORM_TEXT2,
- DEFORM_TEXT3,
- DEFORM_TEXT4,
- DEFORM_TEXT5,
- DEFORM_TEXT6,
- DEFORM_TEXT7
-} deform_t;
-
-typedef enum {
- AGEN_IDENTITY,
- AGEN_SKIP,
- AGEN_ENTITY,
- AGEN_ONE_MINUS_ENTITY,
- AGEN_VERTEX,
- AGEN_ONE_MINUS_VERTEX,
- AGEN_LIGHTING_SPECULAR,
- AGEN_WAVEFORM,
- AGEN_PORTAL,
- AGEN_CONST
-} alphaGen_t;
-
-typedef enum {
- CGEN_BAD,
- CGEN_IDENTITY_LIGHTING, // tr.identityLight
- CGEN_IDENTITY, // always (1,1,1,1)
- CGEN_ENTITY, // grabbed from entity's modulate field
- CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate
- CGEN_EXACT_VERTEX, // tess.vertexColors
- CGEN_VERTEX, // tess.vertexColors * tr.identityLight
- CGEN_ONE_MINUS_VERTEX,
- CGEN_WAVEFORM, // programmatically generated
- CGEN_LIGHTING_DIFFUSE,
- CGEN_FOG, // standard fog
- CGEN_CONST // fixed color
-} colorGen_t;
-
-typedef enum {
- TCGEN_BAD,
- TCGEN_IDENTITY, // clear to 0,0
- TCGEN_LIGHTMAP,
- TCGEN_TEXTURE,
- TCGEN_ENVIRONMENT_MAPPED,
- TCGEN_FOG,
- TCGEN_VECTOR // S and T from world coordinates
-} texCoordGen_t;
-
-typedef enum {
- ACFF_NONE,
- ACFF_MODULATE_RGB,
- ACFF_MODULATE_RGBA,
- ACFF_MODULATE_ALPHA
-} acff_t;
-
-typedef struct {
- genFunc_t func;
-
- float base;
- float amplitude;
- float phase;
- float frequency;
-} waveForm_t;
-
-#define TR_MAX_TEXMODS 4
-
-typedef enum {
- TMOD_NONE,
- TMOD_TRANSFORM,
- TMOD_TURBULENT,
- TMOD_SCROLL,
- TMOD_SCALE,
- TMOD_STRETCH,
- TMOD_ROTATE,
- TMOD_ENTITY_TRANSLATE
-} texMod_t;
-
-#define MAX_SHADER_DEFORMS 3
-typedef struct {
- deform_t deformation; // vertex coordinate modification type
-
- vec3_t moveVector;
- waveForm_t deformationWave;
- float deformationSpread;
-
- float bulgeWidth;
- float bulgeHeight;
- float bulgeSpeed;
-} deformStage_t;
-
-
-typedef struct {
- texMod_t type;
-
- // used for TMOD_TURBULENT and TMOD_STRETCH
- waveForm_t wave;
-
- // used for TMOD_TRANSFORM
- float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0]
- float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1]
-
- // used for TMOD_SCALE
- float scale[2]; // s *= scale[0]
- // t *= scale[1]
-
- // used for TMOD_SCROLL
- float scroll[2]; // s' = s + scroll[0] * time
- // t' = t + scroll[1] * time
-
- // + = clockwise
- // - = counterclockwise
- float rotateSpeed;
-
-} texModInfo_t;
-
-
-#define MAX_IMAGE_ANIMATIONS 8
-
-typedef struct {
- image_t *image[MAX_IMAGE_ANIMATIONS];
- int numImageAnimations;
- float imageAnimationSpeed;
-
- texCoordGen_t tcGen;
- vec3_t tcGenVectors[2];
-
- int numTexMods;
- texModInfo_t *texMods;
-
- int videoMapHandle;
- qboolean isLightmap;
- qboolean vertexLightmap;
- qboolean isVideoMap;
-} textureBundle_t;
-
-#define NUM_TEXTURE_BUNDLES 2
-
-typedef struct {
- qboolean active;
-
- textureBundle_t bundle[NUM_TEXTURE_BUNDLES];
-
- waveForm_t rgbWave;
- colorGen_t rgbGen;
-
- waveForm_t alphaWave;
- alphaGen_t alphaGen;
-
- byte constantColor[4]; // for CGEN_CONST and AGEN_CONST
-
- unsigned stateBits; // GLS_xxxx mask
-
- acff_t adjustColorsForFog;
-
- qboolean isDetail;
-} shaderStage_t;
-
-struct shaderCommands_s;
-
-#define LIGHTMAP_2D -4 // shader is for 2D rendering
-#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models
-#define LIGHTMAP_WHITEIMAGE -2
-#define LIGHTMAP_NONE -1
-
-typedef enum {
- CT_FRONT_SIDED,
- CT_BACK_SIDED,
- CT_TWO_SIDED
-} cullType_t;
-
-typedef enum {
- FP_NONE, // surface is translucent and will just be adjusted properly
- FP_EQUAL, // surface is opaque but possibly alpha tested
- FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface)
-} fogPass_t;
-
-typedef struct {
- float cloudHeight;
- image_t *outerbox[6], *innerbox[6];
-} skyParms_t;
-
-typedef struct {
- vec3_t color;
- float depthForOpaque;
-} fogParms_t;
-
-
-typedef struct shader_s {
- char name[MAX_QPATH]; // game path, including extension
- int lightmapIndex; // for a shader to match, both name and lightmapIndex must match
-
- int index; // this shader == tr.shaders[index]
- int sortedIndex; // this shader == tr.sortedShaders[sortedIndex]
-
- float sort; // lower numbered shaders draw before higher numbered
-
- qboolean defaultShader; // we want to return index 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
-
- qboolean explicitlyDefined; // found in a .shader file
-
- int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags
- int contentFlags;
-
- qboolean entityMergable; // merge across entites optimizable (smoke, blood)
-
- qboolean isSky;
- skyParms_t sky;
- fogParms_t fogParms;
-
- float portalRange; // distance to fog out at
-
- int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage)
-
- cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
- qboolean polygonOffset; // set for decals and other items that must be offset
- qboolean noMipMaps; // for console fonts, 2D elements, etc.
- qboolean noPicMip; // for images that must always be full resolution
-
- fogPass_t fogPass; // draw a blended pass, possibly with depth test equals
-
- qboolean needsNormal; // not all shaders will need all data to be gathered
- qboolean needsST1;
- qboolean needsST2;
- qboolean needsColor;
-
- int numDeforms;
- deformStage_t deforms[MAX_SHADER_DEFORMS];
-
- int numUnfoggedPasses;
- shaderStage_t *stages[MAX_SHADER_STAGES];
-
- void (*optimalStageIteratorFunc)( void );
-
- float clampTime; // time this shader is clamped to
- float timeOffset; // current time offset for this shader
-
- int numStates; // if non-zero this is a state shader
- struct shader_s *currentShader; // current state if this is a state shader
- struct shader_s *parentShader; // current state if this is a state shader
- int currentState; // current state index for cycle purposes
- long expireTime; // time in milliseconds this expires
-
- struct shader_s *remappedShader; // current shader this one is remapped too
-
- int shaderStates[MAX_STATES_PER_SHADER]; // index to valid shader states
-
- struct shader_s *next;
-} shader_t;
-
-typedef struct shaderState_s {
- char shaderName[MAX_QPATH]; // name of shader this state belongs to
- char name[MAX_STATE_NAME]; // name of this state
- char stateShader[MAX_QPATH]; // shader this name invokes
- int cycleTime; // time this cycle lasts, <= 0 is forever
- shader_t *shader;
-} shaderState_t;
-
-
-// trRefdef_t holds everything that comes in refdef_t,
-// as well as the locally generated scene information
-typedef struct {
- int x, y, width, height;
- float fov_x, fov_y;
- vec3_t vieworg;
- vec3_t viewaxis[3]; // transformation matrix
-
- int time; // time in milliseconds for shader effects and other time dependent rendering issues
- int rdflags; // RDF_NOWORLDMODEL, etc
-
- // 1 bits will prevent the associated area from rendering at all
- byte areamask[MAX_MAP_AREA_BYTES];
- qboolean areamaskModified; // qtrue if areamask changed since last scene
-
- float floatTime; // tr.refdef.time / 1000.0
-
- // text messages for deform text shaders
- char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
-
- int num_entities;
- trRefEntity_t *entities;
-
- int num_dlights;
- struct dlight_s *dlights;
-
- int numPolys;
- struct srfPoly_s *polys;
-
- int numDrawSurfs;
- struct drawSurf_s *drawSurfs;
-
-
-} trRefdef_t;
-
-
-//=================================================================================
-
-// skins allow models to be retextured without modifying the model file
-typedef struct {
- char name[MAX_QPATH];
- shader_t *shader;
-} skinSurface_t;
-
-typedef struct skin_s {
- char name[MAX_QPATH]; // game path, including extension
- int numSurfaces;
- skinSurface_t *surfaces[MD3_MAX_SURFACES];
-} skin_t;
-
-
-typedef struct {
- int originalBrushNumber;
- vec3_t bounds[2];
-
- unsigned colorInt; // in packed byte format
- float tcScale; // texture coordinate vector scales
- fogParms_t parms;
-
- // for clipping distance in fog when outside
- qboolean hasSurface;
- float surface[4];
-} fog_t;
-
-typedef struct {
- orientationr_t or;
- orientationr_t world;
- vec3_t pvsOrigin; // may be different than or.origin for portals
- qboolean isPortal; // true if this view is through a portal
- qboolean isMirror; // the portal is a mirror, invert the face culling
- int frameSceneNum; // copied from tr.frameSceneNum
- int frameCount; // copied from tr.frameCount
- cplane_t portalPlane; // clip anything behind this if mirroring
- int viewportX, viewportY, viewportWidth, viewportHeight;
- float fovX, fovY;
- float projectionMatrix[16];
- cplane_t frustum[4];
- vec3_t visBounds[2];
- float zFar;
-} viewParms_t;
-
-
-/*
-==============================================================================
-
-SURFACES
-
-==============================================================================
-*/
-
-// any changes in surfaceType must be mirrored in rb_surfaceTable[]
-typedef enum {
- SF_BAD,
- SF_SKIP, // ignore
- SF_FACE,
- SF_GRID,
- SF_TRIANGLES,
- SF_POLY,
- SF_MD3,
- SF_MD4,
- SF_FLARE,
- SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
- SF_DISPLAY_LIST,
-
- SF_NUM_SURFACE_TYPES,
- SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
-} surfaceType_t;
-
-typedef struct drawSurf_s {
- unsigned sort; // bit combination for fast compares
- surfaceType_t *surface; // any of surface*_t
-} drawSurf_t;
-
-#define MAX_FACE_POINTS 64
-
-#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file
-#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory
-
-// when cgame directly specifies a polygon, it becomes a srfPoly_t
-// as soon as it is called
-typedef struct srfPoly_s {
- surfaceType_t surfaceType;
- qhandle_t hShader;
- int fogIndex;
- int numVerts;
- polyVert_t *verts;
-} srfPoly_t;
-
-typedef struct srfDisplayList_s {
- surfaceType_t surfaceType;
- int listNum;
-} srfDisplayList_t;
-
-
-typedef struct srfFlare_s {
- surfaceType_t surfaceType;
- vec3_t origin;
- vec3_t normal;
- vec3_t color;
-} srfFlare_t;
-
-typedef struct srfGridMesh_s {
- surfaceType_t surfaceType;
-
- // dynamic lighting information
- int dlightBits[SMP_FRAMES];
-
- // culling information
- vec3_t meshBounds[2];
- vec3_t localOrigin;
- float meshRadius;
-
- // lod information, which may be different
- // than the culling information to allow for
- // groups of curves that LOD as a unit
- vec3_t lodOrigin;
- float lodRadius;
- int lodFixed;
- int lodStitched;
-
- // vertexes
- int width, height;
- float *widthLodError;
- float *heightLodError;
- drawVert_t verts[1]; // variable sized
-} srfGridMesh_t;
-
-
-
-#define VERTEXSIZE 8
-typedef struct {
- surfaceType_t surfaceType;
- cplane_t plane;
-
- // dynamic lighting information
- int dlightBits[SMP_FRAMES];
-
- // triangle definitions (no normals at points)
- int numPoints;
- int numIndices;
- int ofsIndices;
- float points[1][VERTEXSIZE]; // variable sized
- // there is a variable length list of indices here also
-} srfSurfaceFace_t;
-
-
-// misc_models in maps are turned into direct geometry by q3map
-typedef struct {
- surfaceType_t surfaceType;
-
- // dynamic lighting information
- int dlightBits[SMP_FRAMES];
-
- // culling information (FIXME: use this!)
- vec3_t bounds[2];
- vec3_t localOrigin;
- float radius;
-
- // triangle definitions
- int numIndexes;
- int *indexes;
-
- int numVerts;
- drawVert_t *verts;
-} srfTriangles_t;
-
-
-extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *);
-
-/*
-==============================================================================
-
-BRUSH MODELS
-
-==============================================================================
-*/
-
-
-//
-// in memory representation
-//
-
-#define SIDE_FRONT 0
-#define SIDE_BACK 1
-#define SIDE_ON 2
-
-typedef struct msurface_s {
- int viewCount; // if == tr.viewCount, already added
- struct shader_s *shader;
- int fogIndex;
-
- surfaceType_t *data; // any of srf*_t
-} msurface_t;
-
-
-
-#define CONTENTS_NODE -1
-typedef struct mnode_s {
- // common with leaf and node
- int contents; // -1 for nodes, to differentiate from leafs
- int visframe; // node needs to be traversed if current
- vec3_t mins, maxs; // for bounding box culling
- struct mnode_s *parent;
-
- // node specific
- cplane_t *plane;
- struct mnode_s *children[2];
-
- // leaf specific
- int cluster;
- int area;
-
- msurface_t **firstmarksurface;
- int nummarksurfaces;
-} mnode_t;
-
-typedef struct {
- vec3_t bounds[2]; // for culling
- msurface_t *firstSurface;
- int numSurfaces;
-} bmodel_t;
-
-typedef struct {
- char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp
- char baseName[MAX_QPATH]; // ie: tim_dm2
-
- int dataSize;
-
- int numShaders;
- dshader_t *shaders;
-
- bmodel_t *bmodels;
-
- int numplanes;
- cplane_t *planes;
-
- int numnodes; // includes leafs
- int numDecisionNodes;
- mnode_t *nodes;
-
- int numsurfaces;
- msurface_t *surfaces;
-
- int nummarksurfaces;
- msurface_t **marksurfaces;
-
- int numfogs;
- fog_t *fogs;
-
- vec3_t lightGridOrigin;
- vec3_t lightGridSize;
- vec3_t lightGridInverseSize;
- int lightGridBounds[3];
- byte *lightGridData;
-
-
- int numClusters;
- int clusterBytes;
- const byte *vis; // may be passed in by CM_LoadMap to save space
-
- byte *novis; // clusterBytes of 0xff
-
- char *entityString;
- char *entityParsePoint;
-} world_t;
-
-//======================================================================
-
-typedef enum {
- MOD_BAD,
- MOD_BRUSH,
- MOD_MESH,
- MOD_MD4
-} modtype_t;
-
-typedef struct model_s {
- char name[MAX_QPATH];
- modtype_t type;
- int index; // model = tr.models[model->index]
-
- int dataSize; // just for listing purposes
- bmodel_t *bmodel; // only if type == MOD_BRUSH
- md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH
- md4Header_t *md4; // only if type == MOD_MD4
-
- int numLods;
-} model_t;
-
-
-#define MAX_MOD_KNOWN 1024
-
-void R_ModelInit (void);
-model_t *R_GetModelByHandle( qhandle_t hModel );
-int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
- float frac, const char *tagName );
-void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs );
-
-void R_Modellist_f (void);
-
-//====================================================
-extern refimport_t ri;
-
-#define MAX_DRAWIMAGES 2048
-#define MAX_LIGHTMAPS 256
-#define MAX_SKINS 1024
-
-
-#define MAX_DRAWSURFS 0x10000
-#define DRAWSURF_MASK (MAX_DRAWSURFS-1)
-
-/*
-
-the drawsurf sort data is packed into a single 32 bit value so it can be
-compared quickly during the qsorting process
-
-the bits are allocated as follows:
-
-21 - 31 : sorted shader index
-11 - 20 : entity index
-2 - 6 : fog index
-//2 : used to be clipped flag REMOVED - 03.21.00 rad
-0 - 1 : dlightmap index
-
- TTimo - 1.32
-17-31 : sorted shader index
-7-16 : entity index
-2-6 : fog index
-0-1 : dlightmap index
-*/
-#define QSORT_SHADERNUM_SHIFT 17
-#define QSORT_ENTITYNUM_SHIFT 7
-#define QSORT_FOGNUM_SHIFT 2
-
-extern int gl_filter_min, gl_filter_max;
-
-/*
-** performanceCounters_t
-*/
-typedef struct {
- int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out;
- int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out;
- int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out;
- int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out;
-
- int c_leafs;
- int c_dlightSurfaces;
- int c_dlightSurfacesCulled;
-} frontEndCounters_t;
-
-#define FOG_TABLE_SIZE 256
-#define FUNCTABLE_SIZE 1024
-#define FUNCTABLE_SIZE2 10
-#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1)
-
-
-// the renderer front end should never modify glstate_t
-typedef struct {
- int currenttextures[2];
- int currenttmu;
- qboolean finishCalled;
- int texEnv[2];
- int faceCulling;
- unsigned long glStateBits;
-} glstate_t;
-
-
-typedef struct {
- int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes;
- float c_overDraw;
-
- int c_dlightVertexes;
- int c_dlightIndexes;
-
- int c_flareAdds;
- int c_flareTests;
- int c_flareRenders;
-
- int msec; // total msec for backend run
-} backEndCounters_t;
-
-// all state modified by the back end is seperated
-// from the front end state
-typedef struct {
- int smpFrame;
- trRefdef_t refdef;
- viewParms_t viewParms;
- orientationr_t or;
- backEndCounters_t pc;
- qboolean isHyperspace;
- trRefEntity_t *currentEntity;
- qboolean skyRenderedThisView; // flag for drawing sun
-
- qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes
- byte color2D[4];
- qboolean vertexes2D; // shader needs to be finished
- trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
-} backEndState_t;
-
-/*
-** trGlobals_t
-**
-** Most renderer globals are defined here.
-** backend functions should never modify any of these fields,
-** but may read fields that aren't dynamically modified
-** by the frontend.
-*/
-typedef struct {
- qboolean registered; // cleared at shutdown, set at beginRegistration
-
- int visCount; // incremented every time a new vis cluster is entered
- int frameCount; // incremented every frame
- int sceneCount; // incremented every scene
- int viewCount; // incremented every view (twice a scene if portaled)
- // and every R_MarkFragments call
-
- int smpFrame; // toggles from 0 to 1 every endFrame
-
- int frameSceneNum; // zeroed at RE_BeginFrame
-
- qboolean worldMapLoaded;
- world_t *world;
-
- const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load
-
- image_t *defaultImage;
- image_t *scratchImage[32];
- image_t *fogImage;
- image_t *dlightImage; // inverse-quare highlight for projective adding
- image_t *flareImage;
- image_t *whiteImage; // full of 0xff
- image_t *identityLightImage; // full of tr.identityLightByte
-
- shader_t *defaultShader;
- shader_t *shadowShader;
- shader_t *projectionShadowShader;
-
- shader_t *flareShader;
- shader_t *sunShader;
-
- int numLightmaps;
- image_t *lightmaps[MAX_LIGHTMAPS];
-
- trRefEntity_t *currentEntity;
- trRefEntity_t worldEntity; // point currentEntity at this when rendering world
- int currentEntityNum;
- int shiftedEntityNum; // currentEntityNum << QSORT_ENTITYNUM_SHIFT
- model_t *currentModel;
-
- viewParms_t viewParms;
-
- float identityLight; // 1.0 / ( 1 << overbrightBits )
- int identityLightByte; // identityLight * 255
- int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma
-
- orientationr_t or; // for current entity
-
- trRefdef_t refdef;
-
- int viewCluster;
-
- vec3_t sunLight; // from the sky shader for this level
- vec3_t sunDirection;
-
- frontEndCounters_t pc;
- int frontEndMsec; // not in pc due to clearing issue
-
- //
- // put large tables at the end, so most elements will be
- // within the +/32K indexed range on risc processors
- //
- model_t *models[MAX_MOD_KNOWN];
- int numModels;
-
- int numImages;
- image_t *images[MAX_DRAWIMAGES];
-
- // shader indexes from other modules will be looked up in tr.shaders[]
- // shader indexes from drawsurfs will be looked up in sortedShaders[]
- // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)
- int numShaders;
- shader_t *shaders[MAX_SHADERS];
- shader_t *sortedShaders[MAX_SHADERS];
-
- int numSkins;
- skin_t *skins[MAX_SKINS];
-
- float sinTable[FUNCTABLE_SIZE];
- float squareTable[FUNCTABLE_SIZE];
- float triangleTable[FUNCTABLE_SIZE];
- float sawToothTable[FUNCTABLE_SIZE];
- float inverseSawToothTable[FUNCTABLE_SIZE];
- float fogTable[FOG_TABLE_SIZE];
-} trGlobals_t;
-
-extern backEndState_t backEnd;
-extern trGlobals_t tr;
-extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init
-extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init
-
-
-//
-// cvars
-//
-extern cvar_t *r_flareSize;
-extern cvar_t *r_flareFade;
-
-extern cvar_t *r_railWidth;
-extern cvar_t *r_railCoreWidth;
-extern cvar_t *r_railSegmentLength;
-
-extern cvar_t *r_ignore; // used for debugging anything
-extern cvar_t *r_verbose; // used for verbose debug spew
-extern cvar_t *r_ignoreFastPath; // allows us to ignore our Tess fast paths
-
-extern cvar_t *r_znear; // near Z clip plane
-
-extern cvar_t *r_stencilbits; // number of desired stencil bits
-extern cvar_t *r_depthbits; // number of desired depth bits
-extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen
-extern cvar_t *r_stereo; // desired pixelformat stereo flag
-extern cvar_t *r_texturebits; // number of desired texture bits
- // 0 = use framebuffer depth
- // 16 = use 16-bit textures
- // 32 = use 32-bit textures
- // all else = error
-
-extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement
-
-extern cvar_t *r_lodbias; // push/pull LOD transitions
-extern cvar_t *r_lodscale;
-
-extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance
- // "1" = glDrawElemet tristrips
- // "2" = glDrawElements triangles
- // "-1" = no drawing
-
-extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
-extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn
-extern cvar_t *r_drawSun; // controls drawing of sun quad
-extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
-extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity
-
-extern cvar_t *r_norefresh; // bypasses the ref rendering
-extern cvar_t *r_drawentities; // disable/enable entity rendering
-extern cvar_t *r_drawworld; // disable/enable world rendering
-extern cvar_t *r_speeds; // various levels of information display
-extern cvar_t *r_detailTextures; // enables/disables detail texturing stages
-extern cvar_t *r_novis; // disable/enable usage of PVS
-extern cvar_t *r_nocull;
-extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test
-extern cvar_t *r_nocurves;
-extern cvar_t *r_showcluster;
-
-extern cvar_t *r_mode; // video mode
-extern cvar_t *r_fullscreen;
-extern cvar_t *r_gamma;
-extern cvar_t *r_displayRefresh; // optional display refresh option
-extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities
-
-extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions
-extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions
-extern cvar_t *r_ext_gamma_control;
-extern cvar_t *r_ext_texenv_op;
-extern cvar_t *r_ext_multitexture;
-extern cvar_t *r_ext_compiled_vertex_array;
-extern cvar_t *r_ext_texture_env_add;
-
-extern cvar_t *r_nobind; // turns off binding to appropriate textures
-extern cvar_t *r_singleShader; // make most world faces use default shader
-extern cvar_t *r_roundImagesDown;
-extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage
-extern cvar_t *r_picmip; // controls picmip values
-extern cvar_t *r_finish;
-extern cvar_t *r_drawBuffer;
-extern cvar_t *r_glDriver;
-extern cvar_t *r_swapInterval;
-extern cvar_t *r_textureMode;
-extern cvar_t *r_offsetFactor;
-extern cvar_t *r_offsetUnits;
-
-extern cvar_t *r_fullbright; // avoid lightmap pass
-extern cvar_t *r_lightmap; // render lightmaps only
-extern cvar_t *r_vertexLight; // vertex lighting mode for better performance
-extern cvar_t *r_uiFullScreen; // ui is running fullscreen
-
-extern cvar_t *r_logFile; // number of frames to emit GL logs
-extern cvar_t *r_showtris; // enables wireframe rendering of the world
-extern cvar_t *r_showsky; // forces sky in front of all surfaces
-extern cvar_t *r_shownormals; // draws wireframe normals
-extern cvar_t *r_clear; // force screen clear every frame
-
-extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection
-extern cvar_t *r_flares; // light flares
-
-extern cvar_t *r_intensity;
-
-extern cvar_t *r_lockpvs;
-extern cvar_t *r_noportals;
-extern cvar_t *r_portalOnly;
-
-extern cvar_t *r_subdivisions;
-extern cvar_t *r_lodCurveError;
-extern cvar_t *r_smp;
-extern cvar_t *r_showSmp;
-extern cvar_t *r_skipBackEnd;
-
-extern cvar_t *r_ignoreGLErrors;
-
-extern cvar_t *r_overBrightBits;
-extern cvar_t *r_mapOverBrightBits;
-
-extern cvar_t *r_debugSurface;
-extern cvar_t *r_simpleMipMaps;
-
-extern cvar_t *r_showImages;
-extern cvar_t *r_debugSort;
-
-extern cvar_t *r_printShaders;
-extern cvar_t *r_saveFontData;
-
-//====================================================================
-
-float R_NoiseGet4f( float x, float y, float z, float t );
-void R_NoiseInit( void );
-
-void R_SwapBuffers( int );
-
-void R_RenderView( viewParms_t *parms );
-
-void R_AddMD3Surfaces( trRefEntity_t *e );
-void R_AddNullModelSurfaces( trRefEntity_t *e );
-void R_AddBeamSurfaces( trRefEntity_t *e );
-void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater );
-void R_AddLightningBoltSurfaces( trRefEntity_t *e );
-
-void R_AddPolygonSurfaces( void );
-
-void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
- int *fogNum, int *dlightMap );
-
-void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );
-
-
-#define CULL_IN 0 // completely unclipped
-#define CULL_CLIP 1 // clipped by one or more planes
-#define CULL_OUT 2 // completely outside the clipping planes
-void R_LocalNormalToWorld (vec3_t local, vec3_t world);
-void R_LocalPointToWorld (vec3_t local, vec3_t world);
-int R_CullLocalBox (vec3_t bounds[2]);
-int R_CullPointAndRadius( vec3_t origin, float radius );
-int R_CullLocalPointAndRadius( vec3_t origin, float radius );
-
-void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or );
-
-/*
-** GL wrapper/helper functions
-*/
-void GL_Bind( image_t *image );
-void GL_SetDefaultState (void);
-void GL_SelectTexture( int unit );
-void GL_TextureMode( const char *string );
-void GL_CheckErrors( void );
-void GL_State( unsigned long stateVector );
-void GL_TexEnv( int env );
-void GL_Cull( int cullType );
-
-#define GLS_SRCBLEND_ZERO 0x00000001
-#define GLS_SRCBLEND_ONE 0x00000002
-#define GLS_SRCBLEND_DST_COLOR 0x00000003
-#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004
-#define GLS_SRCBLEND_SRC_ALPHA 0x00000005
-#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006
-#define GLS_SRCBLEND_DST_ALPHA 0x00000007
-#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008
-#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009
-#define GLS_SRCBLEND_BITS 0x0000000f
-
-#define GLS_DSTBLEND_ZERO 0x00000010
-#define GLS_DSTBLEND_ONE 0x00000020
-#define GLS_DSTBLEND_SRC_COLOR 0x00000030
-#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040
-#define GLS_DSTBLEND_SRC_ALPHA 0x00000050
-#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060
-#define GLS_DSTBLEND_DST_ALPHA 0x00000070
-#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080
-#define GLS_DSTBLEND_BITS 0x000000f0
-
-#define GLS_DEPTHMASK_TRUE 0x00000100
-
-#define GLS_POLYMODE_LINE 0x00001000
-
-#define GLS_DEPTHTEST_DISABLE 0x00010000
-#define GLS_DEPTHFUNC_EQUAL 0x00020000
-
-#define GLS_ATEST_GT_0 0x10000000
-#define GLS_ATEST_LT_80 0x20000000
-#define GLS_ATEST_GE_80 0x40000000
-#define GLS_ATEST_BITS 0x70000000
-
-#define GLS_DEFAULT GLS_DEPTHMASK_TRUE
-
-void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
-void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
-
-void RE_BeginFrame( stereoFrame_t stereoFrame );
-void RE_BeginRegistration( glconfig_t *glconfig );
-void RE_LoadWorldMap( const char *mapname );
-void RE_SetWorldVisData( const byte *vis );
-qhandle_t RE_RegisterModel( const char *name );
-qhandle_t RE_RegisterSkin( const char *name );
-void RE_Shutdown( qboolean destroyWindow );
-
-qboolean R_GetEntityToken( char *buffer, int size );
-
-model_t *R_AllocModel( void );
-
-void R_Init( void );
-image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode );
-
-image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, qboolean mipmap
- , qboolean allowPicmip, int wrapClampMode );
-qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode );
-
-void R_SetColorMappings( void );
-void R_GammaCorrect( byte *buffer, int bufSize );
-
-void R_ImageList_f( void );
-void R_SkinList_f( void );
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516
-const void *RB_TakeScreenshotCmd( const void *data );
-void R_ScreenShot_f( void );
-
-void R_InitFogTable( void );
-float R_FogFactor( float s, float t );
-void R_InitImages( void );
-void R_DeleteTextures( void );
-int R_SumOfUsedImages( void );
-void R_InitSkins( void );
-skin_t *R_GetSkinByHandle( qhandle_t hSkin );
-
-
-//
-// tr_shader.c
-//
-qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex );
-qhandle_t RE_RegisterShader( const char *name );
-qhandle_t RE_RegisterShaderNoMip( const char *name );
-qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage);
-
-shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage );
-shader_t *R_GetShaderByHandle( qhandle_t hShader );
-shader_t *R_GetShaderByState( int index, long *cycleTime );
-shader_t *R_FindShaderByName( const char *name );
-void R_InitShaders( void );
-void R_ShaderList_f( void );
-void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);
-
-/*
-====================================================================
-
-IMPLEMENTATION SPECIFIC FUNCTIONS
-
-====================================================================
-*/
-
-void GLimp_Init( void );
-void GLimp_Shutdown( void );
-void GLimp_EndFrame( void );
-
-qboolean GLimp_SpawnRenderThread( void (*function)( void ) );
-void *GLimp_RendererSleep( void );
-void GLimp_FrontEndSleep( void );
-void GLimp_WakeRenderer( void *data );
-
-void GLimp_LogComment( char *comment );
-
-// NOTE TTimo linux works with float gamma value, not the gamma table
-// the params won't be used, getting the r_gamma cvar directly
-void GLimp_SetGamma( unsigned char red[256],
- unsigned char green[256],
- unsigned char blue[256] );
-
-
-/*
-====================================================================
-
-TESSELATOR/SHADER DECLARATIONS
-
-====================================================================
-*/
-typedef byte color4ub_t[4];
-
-typedef struct stageVars
-{
- color4ub_t colors[SHADER_MAX_VERTEXES];
- vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES];
-} stageVars_t;
-
-typedef struct shaderCommands_s
-{
- glIndex_t indexes[SHADER_MAX_INDEXES];
- vec4_t xyz[SHADER_MAX_VERTEXES];
- vec4_t normal[SHADER_MAX_VERTEXES];
- vec2_t texCoords[SHADER_MAX_VERTEXES][2];
- color4ub_t vertexColors[SHADER_MAX_VERTEXES];
- int vertexDlightBits[SHADER_MAX_VERTEXES];
-
- stageVars_t svars;
-
- color4ub_t constantColor255[SHADER_MAX_VERTEXES];
-
- shader_t *shader;
- float shaderTime;
- int fogNum;
-
- int dlightBits; // or together of all vertexDlightBits
-
- int numIndexes;
- int numVertexes;
-
- // info extracted from current shader
- int numPasses;
- void (*currentStageIteratorFunc)( void );
- shaderStage_t **xstages;
-} shaderCommands_t;
-
-extern shaderCommands_t tess;
-
-void RB_BeginSurface(shader_t *shader, int fogNum );
-void RB_EndSurface(void);
-void RB_CheckOverflow( int verts, int indexes );
-#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);}
-
-void RB_StageIteratorGeneric( void );
-void RB_StageIteratorSky( void );
-void RB_StageIteratorVertexLitTexture( void );
-void RB_StageIteratorLightmappedMultitexture( void );
-
-void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color );
-void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 );
-
-void RB_ShowImages( void );
-
-
-/*
-============================================================
-
-WORLD MAP
-
-============================================================
-*/
-
-void R_AddBrushModelSurfaces( trRefEntity_t *e );
-void R_AddWorldSurfaces( void );
-qboolean R_inPVS( const vec3_t p1, const vec3_t p2 );
-
-
-/*
-============================================================
-
-FLARES
-
-============================================================
-*/
-
-void R_ClearFlares( void );
-
-void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal );
-void RB_AddDlightFlares( void );
-void RB_RenderFlares (void);
-
-/*
-============================================================
-
-LIGHTS
-
-============================================================
-*/
-
-void R_DlightBmodel( bmodel_t *bmodel );
-void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
-void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or );
-int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
-
-
-/*
-============================================================
-
-SHADOWS
-
-============================================================
-*/
-
-void RB_ShadowTessEnd( void );
-void RB_ShadowFinish( void );
-void RB_ProjectionShadowDeform( void );
-
-/*
-============================================================
-
-SKIES
-
-============================================================
-*/
-
-void R_BuildCloudData( shaderCommands_t *shader );
-void R_InitSkyTexCoords( float cloudLayerHeight );
-void R_DrawSkyBox( shaderCommands_t *shader );
-void RB_DrawSun( void );
-void RB_ClipSkyPolygons( shaderCommands_t *shader );
-
-/*
-============================================================
-
-CURVE TESSELATION
-
-============================================================
-*/
-
-#define PATCH_STITCHING
-
-srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
- drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] );
-srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror );
-srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror );
-void R_FreeSurfaceGridMesh( srfGridMesh_t *grid );
-
-/*
-============================================================
-
-MARKERS, POLYGON PROJECTION ON WORLD POLYGONS
-
-============================================================
-*/
-
-int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
-
-
-/*
-============================================================
-
-SCENE GENERATION
-
-============================================================
-*/
-
-void R_ToggleSmpFrame( void );
-
-void RE_ClearScene( void );
-void RE_AddRefEntityToScene( const refEntity_t *ent );
-void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
-void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
-void RE_RenderScene( const refdef_t *fd );
-
-/*
-=============================================================
-
-ANIMATED MODELS
-
-=============================================================
-*/
-
-void R_MakeAnimModel( model_t *model );
-void R_AddAnimSurfaces( trRefEntity_t *ent );
-void RB_SurfaceAnim( md4Surface_t *surfType );
-
-/*
-=============================================================
-=============================================================
-*/
-void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
- vec4_t eye, vec4_t dst );
-void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window );
-
-void RB_DeformTessGeometry( void );
-
-void RB_CalcEnvironmentTexCoords( float *dstTexCoords );
-void RB_CalcFogTexCoords( float *dstTexCoords );
-void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords );
-void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords );
-void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords );
-void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords );
-void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords );
-void RB_CalcModulateColorsByFog( unsigned char *dstColors );
-void RB_CalcModulateAlphasByFog( unsigned char *dstColors );
-void RB_CalcModulateRGBAsByFog( unsigned char *dstColors );
-void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors );
-void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors );
-void RB_CalcAlphaFromEntity( unsigned char *dstColors );
-void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors );
-void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords );
-void RB_CalcColorFromEntity( unsigned char *dstColors );
-void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors );
-void RB_CalcSpecularAlpha( unsigned char *alphas );
-void RB_CalcDiffuseColor( unsigned char *colors );
-
-/*
-=============================================================
-
-RENDERER BACK END FUNCTIONS
-
-=============================================================
-*/
-
-void RB_RenderThread( void );
-void RB_ExecuteRenderCommands( const void *data );
-
-/*
-=============================================================
-
-RENDERER BACK END COMMAND QUEUE
-
-=============================================================
-*/
-
-#define MAX_RENDER_COMMANDS 0x40000
-
-typedef struct {
- byte cmds[MAX_RENDER_COMMANDS];
- int used;
-} renderCommandList_t;
-
-typedef struct {
- int commandId;
- float color[4];
-} setColorCommand_t;
-
-typedef struct {
- int commandId;
- int buffer;
-} drawBufferCommand_t;
-
-typedef struct {
- int commandId;
- image_t *image;
- int width;
- int height;
- void *data;
-} subImageCommand_t;
-
-typedef struct {
- int commandId;
-} swapBuffersCommand_t;
-
-typedef struct {
- int commandId;
- int buffer;
-} endFrameCommand_t;
-
-typedef struct {
- int commandId;
- shader_t *shader;
- float x, y;
- float w, h;
- float s1, t1;
- float s2, t2;
-} stretchPicCommand_t;
-
-typedef struct {
- int commandId;
- trRefdef_t refdef;
- viewParms_t viewParms;
- drawSurf_t *drawSurfs;
- int numDrawSurfs;
-} drawSurfsCommand_t;
-
-typedef struct {
- int commandId;
- int x;
- int y;
- int width;
- int height;
- char *fileName;
- qboolean jpeg;
-} screenshotCommand_t;
-
-typedef enum {
- RC_END_OF_LIST,
- RC_SET_COLOR,
- RC_STRETCH_PIC,
- RC_DRAW_SURFS,
- RC_DRAW_BUFFER,
- RC_SWAP_BUFFERS,
- RC_SCREENSHOT
-} renderCommand_t;
-
-
-// these are sort of arbitrary limits.
-// the limits apply to the sum of all scenes in a frame --
-// the main view, all the 3D icons, etc
-#define MAX_POLYS 600
-#define MAX_POLYVERTS 3000
-
-// all of the information needed by the back end must be
-// contained in a backEndData_t. This entire structure is
-// duplicated so the front and back end can run in parallel
-// on an SMP machine
-typedef struct {
- drawSurf_t drawSurfs[MAX_DRAWSURFS];
- dlight_t dlights[MAX_DLIGHTS];
- trRefEntity_t entities[MAX_ENTITIES];
- srfPoly_t *polys;//[MAX_POLYS];
- polyVert_t *polyVerts;//[MAX_POLYVERTS];
- renderCommandList_t commands;
-} backEndData_t;
-
-extern int max_polys;
-extern int max_polyverts;
-
-extern backEndData_t *backEndData[SMP_FRAMES]; // the second one may not be allocated
-
-extern volatile renderCommandList_t *renderCommandList;
-
-extern volatile qboolean renderThreadActive;
-
-
-void *R_GetCommandBuffer( int bytes );
-void RB_ExecuteRenderCommands( const void *data );
-
-void R_InitCommandBuffers( void );
-void R_ShutdownCommandBuffers( void );
-
-void R_SyncRenderThread( void );
-
-void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs );
-
-void RE_SetColor( const float *rgba );
-void RE_StretchPic ( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader );
-void RE_BeginFrame( stereoFrame_t stereoFrame );
-void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
-void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer);
-
-// font stuff
-void R_InitFreeType();
-void R_DoneFreeType();
-void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
-
-
-#endif //TR_LOCAL_H
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + + +#ifndef TR_LOCAL_H +#define TR_LOCAL_H + +#include "../game/q_shared.h" +#include "../qcommon/qfiles.h" +#include "../qcommon/qcommon.h" +#include "tr_public.h" +#include "qgl.h" + +#define GL_INDEX_TYPE GL_UNSIGNED_INT +typedef unsigned int glIndex_t; + +// fast float to int conversion +#if id386 && !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__ ) ) // rb010123 +long myftol( float f ); +#else +#define myftol(x) ((int)(x)) +#endif + + +// everything that is needed by the backend needs +// to be double buffered to allow it to run in +// parallel on a dual cpu machine +#define SMP_FRAMES 2 + +// 12 bits +// see QSORT_SHADERNUM_SHIFT +#define MAX_SHADERS 16384 + +//#define MAX_SHADER_STATES 2048 +#define MAX_STATES_PER_SHADER 32 +#define MAX_STATE_NAME 32 + +// can't be increased without changing bit packing for drawsurfs + + +typedef struct dlight_s { + vec3_t origin; + vec3_t color; // range from 0.0 to 1.0, should be color normalized + float radius; + + vec3_t transformed; // origin in local coordinate system + int additive; // texture detail is lost tho when the lightmap is dark +} dlight_t; + + +// a trRefEntity_t has all the information passed in by +// the client game, as well as some locally derived info +typedef struct { + refEntity_t e; + + float axisLength; // compensate for non-normalized axis + + qboolean needDlights; // true for bmodels that touch a dlight + qboolean lightingCalculated; + vec3_t lightDir; // normalized direction towards light + vec3_t ambientLight; // color normalized to 0-255 + int ambientLightInt; // 32 bit rgba packed + vec3_t directedLight; +} trRefEntity_t; + + +typedef struct { + vec3_t origin; // in world coordinates + vec3_t axis[3]; // orientation in world + vec3_t viewOrigin; // viewParms->or.origin in local coordinates + float modelMatrix[16]; +} orientationr_t; + +typedef struct image_s { + char imgName[MAX_QPATH]; // game path, including extension + int width, height; // source image + int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE + GLuint texnum; // gl texture binding + + int frameUsed; // for texture usage in frame statistics + + int internalFormat; + int TMU; // only needed for voodoo2 + + qboolean mipmap; + qboolean allowPicmip; + int wrapClampMode; // GL_CLAMP or GL_REPEAT + + struct image_s* next; +} image_t; + +//=============================================================================== + +typedef enum { + SS_BAD, + SS_PORTAL, // mirrors, portals, viewscreens + SS_ENVIRONMENT, // sky box + SS_OPAQUE, // opaque + + SS_DECAL, // scorch marks, etc. + SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges + // in addition to alpha test + SS_BANNER, + + SS_FOG, + + SS_UNDERWATER, // for items that should be drawn in front of the water plane + + SS_BLEND0, // regular transparency and filters + SS_BLEND1, // generally only used for additive type effects + SS_BLEND2, + SS_BLEND3, + + SS_BLEND6, + SS_STENCIL_SHADOW, + SS_ALMOST_NEAREST, // gun smoke puffs + + SS_NEAREST // blood blobs +} shaderSort_t; + + +#define MAX_SHADER_STAGES 8 + +typedef enum { + GF_NONE, + + GF_SIN, + GF_SQUARE, + GF_TRIANGLE, + GF_SAWTOOTH, + GF_INVERSE_SAWTOOTH, + + GF_NOISE + +} genFunc_t; + + +typedef enum { + DEFORM_NONE, + DEFORM_WAVE, + DEFORM_NORMALS, + DEFORM_BULGE, + DEFORM_MOVE, + DEFORM_PROJECTION_SHADOW, + DEFORM_AUTOSPRITE, + DEFORM_AUTOSPRITE2, + DEFORM_TEXT0, + DEFORM_TEXT1, + DEFORM_TEXT2, + DEFORM_TEXT3, + DEFORM_TEXT4, + DEFORM_TEXT5, + DEFORM_TEXT6, + DEFORM_TEXT7 +} deform_t; + +typedef enum { + AGEN_IDENTITY, + AGEN_SKIP, + AGEN_ENTITY, + AGEN_ONE_MINUS_ENTITY, + AGEN_VERTEX, + AGEN_ONE_MINUS_VERTEX, + AGEN_LIGHTING_SPECULAR, + AGEN_WAVEFORM, + AGEN_PORTAL, + AGEN_CONST +} alphaGen_t; + +typedef enum { + CGEN_BAD, + CGEN_IDENTITY_LIGHTING, // tr.identityLight + CGEN_IDENTITY, // always (1,1,1,1) + CGEN_ENTITY, // grabbed from entity's modulate field + CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate + CGEN_EXACT_VERTEX, // tess.vertexColors + CGEN_VERTEX, // tess.vertexColors * tr.identityLight + CGEN_ONE_MINUS_VERTEX, + CGEN_WAVEFORM, // programmatically generated + CGEN_LIGHTING_DIFFUSE, + CGEN_FOG, // standard fog + CGEN_CONST // fixed color +} colorGen_t; + +typedef enum { + TCGEN_BAD, + TCGEN_IDENTITY, // clear to 0,0 + TCGEN_LIGHTMAP, + TCGEN_TEXTURE, + TCGEN_ENVIRONMENT_MAPPED, + TCGEN_FOG, + TCGEN_VECTOR // S and T from world coordinates +} texCoordGen_t; + +typedef enum { + ACFF_NONE, + ACFF_MODULATE_RGB, + ACFF_MODULATE_RGBA, + ACFF_MODULATE_ALPHA +} acff_t; + +typedef struct { + genFunc_t func; + + float base; + float amplitude; + float phase; + float frequency; +} waveForm_t; + +#define TR_MAX_TEXMODS 4 + +typedef enum { + TMOD_NONE, + TMOD_TRANSFORM, + TMOD_TURBULENT, + TMOD_SCROLL, + TMOD_SCALE, + TMOD_STRETCH, + TMOD_ROTATE, + TMOD_ENTITY_TRANSLATE +} texMod_t; + +#define MAX_SHADER_DEFORMS 3 +typedef struct { + deform_t deformation; // vertex coordinate modification type + + vec3_t moveVector; + waveForm_t deformationWave; + float deformationSpread; + + float bulgeWidth; + float bulgeHeight; + float bulgeSpeed; +} deformStage_t; + + +typedef struct { + texMod_t type; + + // used for TMOD_TURBULENT and TMOD_STRETCH + waveForm_t wave; + + // used for TMOD_TRANSFORM + float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0] + float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1] + + // used for TMOD_SCALE + float scale[2]; // s *= scale[0] + // t *= scale[1] + + // used for TMOD_SCROLL + float scroll[2]; // s' = s + scroll[0] * time + // t' = t + scroll[1] * time + + // + = clockwise + // - = counterclockwise + float rotateSpeed; + +} texModInfo_t; + + +#define MAX_IMAGE_ANIMATIONS 8 + +typedef struct { + image_t *image[MAX_IMAGE_ANIMATIONS]; + int numImageAnimations; + float imageAnimationSpeed; + + texCoordGen_t tcGen; + vec3_t tcGenVectors[2]; + + int numTexMods; + texModInfo_t *texMods; + + int videoMapHandle; + qboolean isLightmap; + qboolean vertexLightmap; + qboolean isVideoMap; +} textureBundle_t; + +#define NUM_TEXTURE_BUNDLES 2 + +typedef struct { + qboolean active; + + textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; + + waveForm_t rgbWave; + colorGen_t rgbGen; + + waveForm_t alphaWave; + alphaGen_t alphaGen; + + byte constantColor[4]; // for CGEN_CONST and AGEN_CONST + + unsigned stateBits; // GLS_xxxx mask + + acff_t adjustColorsForFog; + + qboolean isDetail; +} shaderStage_t; + +struct shaderCommands_s; + +#define LIGHTMAP_2D -4 // shader is for 2D rendering +#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models +#define LIGHTMAP_WHITEIMAGE -2 +#define LIGHTMAP_NONE -1 + +typedef enum { + CT_FRONT_SIDED, + CT_BACK_SIDED, + CT_TWO_SIDED +} cullType_t; + +typedef enum { + FP_NONE, // surface is translucent and will just be adjusted properly + FP_EQUAL, // surface is opaque but possibly alpha tested + FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface) +} fogPass_t; + +typedef struct { + float cloudHeight; + image_t *outerbox[6], *innerbox[6]; +} skyParms_t; + +typedef struct { + vec3_t color; + float depthForOpaque; +} fogParms_t; + + +typedef struct shader_s { + char name[MAX_QPATH]; // game path, including extension + int lightmapIndex; // for a shader to match, both name and lightmapIndex must match + + int index; // this shader == tr.shaders[index] + int sortedIndex; // this shader == tr.sortedShaders[sortedIndex] + + float sort; // lower numbered shaders draw before higher numbered + + qboolean defaultShader; // we want to return index 0 if the shader failed to + // load for some reason, but R_FindShader should + // still keep a name allocated for it, so if + // something calls RE_RegisterShader again with + // the same name, we don't try looking for it again + + qboolean explicitlyDefined; // found in a .shader file + + int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags + int contentFlags; + + qboolean entityMergable; // merge across entites optimizable (smoke, blood) + + qboolean isSky; + skyParms_t sky; + fogParms_t fogParms; + + float portalRange; // distance to fog out at + + int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage) + + cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED + qboolean polygonOffset; // set for decals and other items that must be offset + qboolean noMipMaps; // for console fonts, 2D elements, etc. + qboolean noPicMip; // for images that must always be full resolution + + fogPass_t fogPass; // draw a blended pass, possibly with depth test equals + + qboolean needsNormal; // not all shaders will need all data to be gathered + qboolean needsST1; + qboolean needsST2; + qboolean needsColor; + + int numDeforms; + deformStage_t deforms[MAX_SHADER_DEFORMS]; + + int numUnfoggedPasses; + shaderStage_t *stages[MAX_SHADER_STAGES]; + + void (*optimalStageIteratorFunc)( void ); + + float clampTime; // time this shader is clamped to + float timeOffset; // current time offset for this shader + + int numStates; // if non-zero this is a state shader + struct shader_s *currentShader; // current state if this is a state shader + struct shader_s *parentShader; // current state if this is a state shader + int currentState; // current state index for cycle purposes + long expireTime; // time in milliseconds this expires + + struct shader_s *remappedShader; // current shader this one is remapped too + + int shaderStates[MAX_STATES_PER_SHADER]; // index to valid shader states + + struct shader_s *next; +} shader_t; + +typedef struct shaderState_s { + char shaderName[MAX_QPATH]; // name of shader this state belongs to + char name[MAX_STATE_NAME]; // name of this state + char stateShader[MAX_QPATH]; // shader this name invokes + int cycleTime; // time this cycle lasts, <= 0 is forever + shader_t *shader; +} shaderState_t; + + +// trRefdef_t holds everything that comes in refdef_t, +// as well as the locally generated scene information +typedef struct { + int x, y, width, height; + float fov_x, fov_y; + vec3_t vieworg; + vec3_t viewaxis[3]; // transformation matrix + + int time; // time in milliseconds for shader effects and other time dependent rendering issues + int rdflags; // RDF_NOWORLDMODEL, etc + + // 1 bits will prevent the associated area from rendering at all + byte areamask[MAX_MAP_AREA_BYTES]; + qboolean areamaskModified; // qtrue if areamask changed since last scene + + float floatTime; // tr.refdef.time / 1000.0 + + // text messages for deform text shaders + char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; + + int num_entities; + trRefEntity_t *entities; + + int num_dlights; + struct dlight_s *dlights; + + int numPolys; + struct srfPoly_s *polys; + + int numDrawSurfs; + struct drawSurf_s *drawSurfs; + + +} trRefdef_t; + + +//================================================================================= + +// skins allow models to be retextured without modifying the model file +typedef struct { + char name[MAX_QPATH]; + shader_t *shader; +} skinSurface_t; + +typedef struct skin_s { + char name[MAX_QPATH]; // game path, including extension + int numSurfaces; + skinSurface_t *surfaces[MD3_MAX_SURFACES]; +} skin_t; + + +typedef struct { + int originalBrushNumber; + vec3_t bounds[2]; + + unsigned colorInt; // in packed byte format + float tcScale; // texture coordinate vector scales + fogParms_t parms; + + // for clipping distance in fog when outside + qboolean hasSurface; + float surface[4]; +} fog_t; + +typedef struct { + orientationr_t or; + orientationr_t world; + vec3_t pvsOrigin; // may be different than or.origin for portals + qboolean isPortal; // true if this view is through a portal + qboolean isMirror; // the portal is a mirror, invert the face culling + int frameSceneNum; // copied from tr.frameSceneNum + int frameCount; // copied from tr.frameCount + cplane_t portalPlane; // clip anything behind this if mirroring + int viewportX, viewportY, viewportWidth, viewportHeight; + float fovX, fovY; + float projectionMatrix[16]; + cplane_t frustum[4]; + vec3_t visBounds[2]; + float zFar; +} viewParms_t; + + +/* +============================================================================== + +SURFACES + +============================================================================== +*/ + +// any changes in surfaceType must be mirrored in rb_surfaceTable[] +typedef enum { + SF_BAD, + SF_SKIP, // ignore + SF_FACE, + SF_GRID, + SF_TRIANGLES, + SF_POLY, + SF_MD3, + SF_MD4, + SF_FLARE, + SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity + SF_DISPLAY_LIST, + + SF_NUM_SURFACE_TYPES, + SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) +} surfaceType_t; + +typedef struct drawSurf_s { + unsigned sort; // bit combination for fast compares + surfaceType_t *surface; // any of surface*_t +} drawSurf_t; + +#define MAX_FACE_POINTS 64 + +#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file +#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory + +// when cgame directly specifies a polygon, it becomes a srfPoly_t +// as soon as it is called +typedef struct srfPoly_s { + surfaceType_t surfaceType; + qhandle_t hShader; + int fogIndex; + int numVerts; + polyVert_t *verts; +} srfPoly_t; + +typedef struct srfDisplayList_s { + surfaceType_t surfaceType; + int listNum; +} srfDisplayList_t; + + +typedef struct srfFlare_s { + surfaceType_t surfaceType; + vec3_t origin; + vec3_t normal; + vec3_t color; +} srfFlare_t; + +typedef struct srfGridMesh_s { + surfaceType_t surfaceType; + + // dynamic lighting information + int dlightBits[SMP_FRAMES]; + + // culling information + vec3_t meshBounds[2]; + vec3_t localOrigin; + float meshRadius; + + // lod information, which may be different + // than the culling information to allow for + // groups of curves that LOD as a unit + vec3_t lodOrigin; + float lodRadius; + int lodFixed; + int lodStitched; + + // vertexes + int width, height; + float *widthLodError; + float *heightLodError; + drawVert_t verts[1]; // variable sized +} srfGridMesh_t; + + + +#define VERTEXSIZE 8 +typedef struct { + surfaceType_t surfaceType; + cplane_t plane; + + // dynamic lighting information + int dlightBits[SMP_FRAMES]; + + // triangle definitions (no normals at points) + int numPoints; + int numIndices; + int ofsIndices; + float points[1][VERTEXSIZE]; // variable sized + // there is a variable length list of indices here also +} srfSurfaceFace_t; + + +// misc_models in maps are turned into direct geometry by q3map +typedef struct { + surfaceType_t surfaceType; + + // dynamic lighting information + int dlightBits[SMP_FRAMES]; + + // culling information (FIXME: use this!) + vec3_t bounds[2]; + vec3_t localOrigin; + float radius; + + // triangle definitions + int numIndexes; + int *indexes; + + int numVerts; + drawVert_t *verts; +} srfTriangles_t; + + +extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); + +/* +============================================================================== + +BRUSH MODELS + +============================================================================== +*/ + + +// +// in memory representation +// + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + +typedef struct msurface_s { + int viewCount; // if == tr.viewCount, already added + struct shader_s *shader; + int fogIndex; + + surfaceType_t *data; // any of srf*_t +} msurface_t; + + + +#define CONTENTS_NODE -1 +typedef struct mnode_s { + // common with leaf and node + int contents; // -1 for nodes, to differentiate from leafs + int visframe; // node needs to be traversed if current + vec3_t mins, maxs; // for bounding box culling + struct mnode_s *parent; + + // node specific + cplane_t *plane; + struct mnode_s *children[2]; + + // leaf specific + int cluster; + int area; + + msurface_t **firstmarksurface; + int nummarksurfaces; +} mnode_t; + +typedef struct { + vec3_t bounds[2]; // for culling + msurface_t *firstSurface; + int numSurfaces; +} bmodel_t; + +typedef struct { + char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp + char baseName[MAX_QPATH]; // ie: tim_dm2 + + int dataSize; + + int numShaders; + dshader_t *shaders; + + bmodel_t *bmodels; + + int numplanes; + cplane_t *planes; + + int numnodes; // includes leafs + int numDecisionNodes; + mnode_t *nodes; + + int numsurfaces; + msurface_t *surfaces; + + int nummarksurfaces; + msurface_t **marksurfaces; + + int numfogs; + fog_t *fogs; + + vec3_t lightGridOrigin; + vec3_t lightGridSize; + vec3_t lightGridInverseSize; + int lightGridBounds[3]; + byte *lightGridData; + + + int numClusters; + int clusterBytes; + const byte *vis; // may be passed in by CM_LoadMap to save space + + byte *novis; // clusterBytes of 0xff + + char *entityString; + char *entityParsePoint; +} world_t; + +//====================================================================== + +typedef enum { + MOD_BAD, + MOD_BRUSH, + MOD_MESH, + MOD_MD4 +} modtype_t; + +typedef struct model_s { + char name[MAX_QPATH]; + modtype_t type; + int index; // model = tr.models[model->index] + + int dataSize; // just for listing purposes + bmodel_t *bmodel; // only if type == MOD_BRUSH + md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH + md4Header_t *md4; // only if type == MOD_MD4 + + int numLods; +} model_t; + + +#define MAX_MOD_KNOWN 1024 + +void R_ModelInit (void); +model_t *R_GetModelByHandle( qhandle_t hModel ); +int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, + float frac, const char *tagName ); +void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); + +void R_Modellist_f (void); + +//==================================================== +extern refimport_t ri; + +#define MAX_DRAWIMAGES 2048 +#define MAX_LIGHTMAPS 256 +#define MAX_SKINS 1024 + + +#define MAX_DRAWSURFS 0x10000 +#define DRAWSURF_MASK (MAX_DRAWSURFS-1) + +/* + +the drawsurf sort data is packed into a single 32 bit value so it can be +compared quickly during the qsorting process + +the bits are allocated as follows: + +21 - 31 : sorted shader index +11 - 20 : entity index +2 - 6 : fog index +//2 : used to be clipped flag REMOVED - 03.21.00 rad +0 - 1 : dlightmap index + + TTimo - 1.32 +17-31 : sorted shader index +7-16 : entity index +2-6 : fog index +0-1 : dlightmap index +*/ +#define QSORT_SHADERNUM_SHIFT 17 +#define QSORT_ENTITYNUM_SHIFT 7 +#define QSORT_FOGNUM_SHIFT 2 + +extern int gl_filter_min, gl_filter_max; + +/* +** performanceCounters_t +*/ +typedef struct { + int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out; + int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out; + int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out; + int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out; + + int c_leafs; + int c_dlightSurfaces; + int c_dlightSurfacesCulled; +} frontEndCounters_t; + +#define FOG_TABLE_SIZE 256 +#define FUNCTABLE_SIZE 1024 +#define FUNCTABLE_SIZE2 10 +#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1) + + +// the renderer front end should never modify glstate_t +typedef struct { + int currenttextures[2]; + int currenttmu; + qboolean finishCalled; + int texEnv[2]; + int faceCulling; + unsigned long glStateBits; +} glstate_t; + + +typedef struct { + int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; + float c_overDraw; + + int c_dlightVertexes; + int c_dlightIndexes; + + int c_flareAdds; + int c_flareTests; + int c_flareRenders; + + int msec; // total msec for backend run +} backEndCounters_t; + +// all state modified by the back end is seperated +// from the front end state +typedef struct { + int smpFrame; + trRefdef_t refdef; + viewParms_t viewParms; + orientationr_t or; + backEndCounters_t pc; + qboolean isHyperspace; + trRefEntity_t *currentEntity; + qboolean skyRenderedThisView; // flag for drawing sun + + qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes + byte color2D[4]; + qboolean vertexes2D; // shader needs to be finished + trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering +} backEndState_t; + +/* +** trGlobals_t +** +** Most renderer globals are defined here. +** backend functions should never modify any of these fields, +** but may read fields that aren't dynamically modified +** by the frontend. +*/ +typedef struct { + qboolean registered; // cleared at shutdown, set at beginRegistration + + int visCount; // incremented every time a new vis cluster is entered + int frameCount; // incremented every frame + int sceneCount; // incremented every scene + int viewCount; // incremented every view (twice a scene if portaled) + // and every R_MarkFragments call + + int smpFrame; // toggles from 0 to 1 every endFrame + + int frameSceneNum; // zeroed at RE_BeginFrame + + qboolean worldMapLoaded; + world_t *world; + + const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load + + image_t *defaultImage; + image_t *scratchImage[32]; + image_t *fogImage; + image_t *dlightImage; // inverse-quare highlight for projective adding + image_t *flareImage; + image_t *whiteImage; // full of 0xff + image_t *identityLightImage; // full of tr.identityLightByte + + shader_t *defaultShader; + shader_t *shadowShader; + shader_t *projectionShadowShader; + + shader_t *flareShader; + shader_t *sunShader; + + int numLightmaps; + image_t *lightmaps[MAX_LIGHTMAPS]; + + trRefEntity_t *currentEntity; + trRefEntity_t worldEntity; // point currentEntity at this when rendering world + int currentEntityNum; + int shiftedEntityNum; // currentEntityNum << QSORT_ENTITYNUM_SHIFT + model_t *currentModel; + + viewParms_t viewParms; + + float identityLight; // 1.0 / ( 1 << overbrightBits ) + int identityLightByte; // identityLight * 255 + int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma + + orientationr_t or; // for current entity + + trRefdef_t refdef; + + int viewCluster; + + vec3_t sunLight; // from the sky shader for this level + vec3_t sunDirection; + + frontEndCounters_t pc; + int frontEndMsec; // not in pc due to clearing issue + + // + // put large tables at the end, so most elements will be + // within the +/32K indexed range on risc processors + // + model_t *models[MAX_MOD_KNOWN]; + int numModels; + + int numImages; + image_t *images[MAX_DRAWIMAGES]; + + // shader indexes from other modules will be looked up in tr.shaders[] + // shader indexes from drawsurfs will be looked up in sortedShaders[] + // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent) + int numShaders; + shader_t *shaders[MAX_SHADERS]; + shader_t *sortedShaders[MAX_SHADERS]; + + int numSkins; + skin_t *skins[MAX_SKINS]; + + float sinTable[FUNCTABLE_SIZE]; + float squareTable[FUNCTABLE_SIZE]; + float triangleTable[FUNCTABLE_SIZE]; + float sawToothTable[FUNCTABLE_SIZE]; + float inverseSawToothTable[FUNCTABLE_SIZE]; + float fogTable[FOG_TABLE_SIZE]; +} trGlobals_t; + +extern backEndState_t backEnd; +extern trGlobals_t tr; +extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init +extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init + + +// +// cvars +// +extern cvar_t *r_flareSize; +extern cvar_t *r_flareFade; + +extern cvar_t *r_railWidth; +extern cvar_t *r_railCoreWidth; +extern cvar_t *r_railSegmentLength; + +extern cvar_t *r_ignore; // used for debugging anything +extern cvar_t *r_verbose; // used for verbose debug spew +extern cvar_t *r_ignoreFastPath; // allows us to ignore our Tess fast paths + +extern cvar_t *r_znear; // near Z clip plane + +extern cvar_t *r_stencilbits; // number of desired stencil bits +extern cvar_t *r_depthbits; // number of desired depth bits +extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen +extern cvar_t *r_stereo; // desired pixelformat stereo flag +extern cvar_t *r_texturebits; // number of desired texture bits + // 0 = use framebuffer depth + // 16 = use 16-bit textures + // 32 = use 32-bit textures + // all else = error + +extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement + +extern cvar_t *r_lodbias; // push/pull LOD transitions +extern cvar_t *r_lodscale; + +extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance + // "1" = glDrawElemet tristrips + // "2" = glDrawElements triangles + // "-1" = no drawing + +extern cvar_t *r_inGameVideo; // controls whether in game video should be draw +extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn +extern cvar_t *r_drawSun; // controls drawing of sun quad +extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled +extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity + +extern cvar_t *r_norefresh; // bypasses the ref rendering +extern cvar_t *r_drawentities; // disable/enable entity rendering +extern cvar_t *r_drawworld; // disable/enable world rendering +extern cvar_t *r_speeds; // various levels of information display +extern cvar_t *r_detailTextures; // enables/disables detail texturing stages +extern cvar_t *r_novis; // disable/enable usage of PVS +extern cvar_t *r_nocull; +extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test +extern cvar_t *r_nocurves; +extern cvar_t *r_showcluster; + +extern cvar_t *r_mode; // video mode +extern cvar_t *r_fullscreen; +extern cvar_t *r_gamma; +extern cvar_t *r_displayRefresh; // optional display refresh option +extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities + +extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions +extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions +extern cvar_t *r_ext_gamma_control; +extern cvar_t *r_ext_texenv_op; +extern cvar_t *r_ext_multitexture; +extern cvar_t *r_ext_compiled_vertex_array; +extern cvar_t *r_ext_texture_env_add; + +extern cvar_t *r_nobind; // turns off binding to appropriate textures +extern cvar_t *r_singleShader; // make most world faces use default shader +extern cvar_t *r_roundImagesDown; +extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage +extern cvar_t *r_picmip; // controls picmip values +extern cvar_t *r_finish; +extern cvar_t *r_drawBuffer; +extern cvar_t *r_glDriver; +extern cvar_t *r_swapInterval; +extern cvar_t *r_textureMode; +extern cvar_t *r_offsetFactor; +extern cvar_t *r_offsetUnits; + +extern cvar_t *r_fullbright; // avoid lightmap pass +extern cvar_t *r_lightmap; // render lightmaps only +extern cvar_t *r_vertexLight; // vertex lighting mode for better performance +extern cvar_t *r_uiFullScreen; // ui is running fullscreen + +extern cvar_t *r_logFile; // number of frames to emit GL logs +extern cvar_t *r_showtris; // enables wireframe rendering of the world +extern cvar_t *r_showsky; // forces sky in front of all surfaces +extern cvar_t *r_shownormals; // draws wireframe normals +extern cvar_t *r_clear; // force screen clear every frame + +extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection +extern cvar_t *r_flares; // light flares + +extern cvar_t *r_intensity; + +extern cvar_t *r_lockpvs; +extern cvar_t *r_noportals; +extern cvar_t *r_portalOnly; + +extern cvar_t *r_subdivisions; +extern cvar_t *r_lodCurveError; +extern cvar_t *r_smp; +extern cvar_t *r_showSmp; +extern cvar_t *r_skipBackEnd; + +extern cvar_t *r_ignoreGLErrors; + +extern cvar_t *r_overBrightBits; +extern cvar_t *r_mapOverBrightBits; + +extern cvar_t *r_debugSurface; +extern cvar_t *r_simpleMipMaps; + +extern cvar_t *r_showImages; +extern cvar_t *r_debugSort; + +extern cvar_t *r_printShaders; +extern cvar_t *r_saveFontData; + +//==================================================================== + +float R_NoiseGet4f( float x, float y, float z, float t ); +void R_NoiseInit( void ); + +void R_SwapBuffers( int ); + +void R_RenderView( viewParms_t *parms ); + +void R_AddMD3Surfaces( trRefEntity_t *e ); +void R_AddNullModelSurfaces( trRefEntity_t *e ); +void R_AddBeamSurfaces( trRefEntity_t *e ); +void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater ); +void R_AddLightningBoltSurfaces( trRefEntity_t *e ); + +void R_AddPolygonSurfaces( void ); + +void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, + int *fogNum, int *dlightMap ); + +void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap ); + + +#define CULL_IN 0 // completely unclipped +#define CULL_CLIP 1 // clipped by one or more planes +#define CULL_OUT 2 // completely outside the clipping planes +void R_LocalNormalToWorld (vec3_t local, vec3_t world); +void R_LocalPointToWorld (vec3_t local, vec3_t world); +int R_CullLocalBox (vec3_t bounds[2]); +int R_CullPointAndRadius( vec3_t origin, float radius ); +int R_CullLocalPointAndRadius( vec3_t origin, float radius ); + +void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); + +/* +** GL wrapper/helper functions +*/ +void GL_Bind( image_t *image ); +void GL_SetDefaultState (void); +void GL_SelectTexture( int unit ); +void GL_TextureMode( const char *string ); +void GL_CheckErrors( void ); +void GL_State( unsigned long stateVector ); +void GL_TexEnv( int env ); +void GL_Cull( int cullType ); + +#define GLS_SRCBLEND_ZERO 0x00000001 +#define GLS_SRCBLEND_ONE 0x00000002 +#define GLS_SRCBLEND_DST_COLOR 0x00000003 +#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004 +#define GLS_SRCBLEND_SRC_ALPHA 0x00000005 +#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006 +#define GLS_SRCBLEND_DST_ALPHA 0x00000007 +#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008 +#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009 +#define GLS_SRCBLEND_BITS 0x0000000f + +#define GLS_DSTBLEND_ZERO 0x00000010 +#define GLS_DSTBLEND_ONE 0x00000020 +#define GLS_DSTBLEND_SRC_COLOR 0x00000030 +#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040 +#define GLS_DSTBLEND_SRC_ALPHA 0x00000050 +#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060 +#define GLS_DSTBLEND_DST_ALPHA 0x00000070 +#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080 +#define GLS_DSTBLEND_BITS 0x000000f0 + +#define GLS_DEPTHMASK_TRUE 0x00000100 + +#define GLS_POLYMODE_LINE 0x00001000 + +#define GLS_DEPTHTEST_DISABLE 0x00010000 +#define GLS_DEPTHFUNC_EQUAL 0x00020000 + +#define GLS_ATEST_GT_0 0x10000000 +#define GLS_ATEST_LT_80 0x20000000 +#define GLS_ATEST_GE_80 0x40000000 +#define GLS_ATEST_BITS 0x70000000 + +#define GLS_DEFAULT GLS_DEPTHMASK_TRUE + +void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); +void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); + +void RE_BeginFrame( stereoFrame_t stereoFrame ); +void RE_BeginRegistration( glconfig_t *glconfig ); +void RE_LoadWorldMap( const char *mapname ); +void RE_SetWorldVisData( const byte *vis ); +qhandle_t RE_RegisterModel( const char *name ); +qhandle_t RE_RegisterSkin( const char *name ); +void RE_Shutdown( qboolean destroyWindow ); + +qboolean R_GetEntityToken( char *buffer, int size ); + +model_t *R_AllocModel( void ); + +void R_Init( void ); +image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ); + +image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, qboolean mipmap + , qboolean allowPicmip, int wrapClampMode ); +qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ); + +void R_SetColorMappings( void ); +void R_GammaCorrect( byte *buffer, int bufSize ); + +void R_ImageList_f( void ); +void R_SkinList_f( void ); +// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 +const void *RB_TakeScreenshotCmd( const void *data ); +void R_ScreenShot_f( void ); + +void R_InitFogTable( void ); +float R_FogFactor( float s, float t ); +void R_InitImages( void ); +void R_DeleteTextures( void ); +int R_SumOfUsedImages( void ); +void R_InitSkins( void ); +skin_t *R_GetSkinByHandle( qhandle_t hSkin ); + + +// +// tr_shader.c +// +qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ); +qhandle_t RE_RegisterShader( const char *name ); +qhandle_t RE_RegisterShaderNoMip( const char *name ); +qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage); + +shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); +shader_t *R_GetShaderByHandle( qhandle_t hShader ); +shader_t *R_GetShaderByState( int index, long *cycleTime ); +shader_t *R_FindShaderByName( const char *name ); +void R_InitShaders( void ); +void R_ShaderList_f( void ); +void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +void GLimp_Init( void ); +void GLimp_Shutdown( void ); +void GLimp_EndFrame( void ); + +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ); +void *GLimp_RendererSleep( void ); +void GLimp_FrontEndSleep( void ); +void GLimp_WakeRenderer( void *data ); + +void GLimp_LogComment( char *comment ); + +// NOTE TTimo linux works with float gamma value, not the gamma table +// the params won't be used, getting the r_gamma cvar directly +void GLimp_SetGamma( unsigned char red[256], + unsigned char green[256], + unsigned char blue[256] ); + + +/* +==================================================================== + +TESSELATOR/SHADER DECLARATIONS + +==================================================================== +*/ +typedef byte color4ub_t[4]; + +typedef struct stageVars +{ + color4ub_t colors[SHADER_MAX_VERTEXES]; + vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; +} stageVars_t; + +typedef struct shaderCommands_s +{ + glIndex_t indexes[SHADER_MAX_INDEXES]; + vec4_t xyz[SHADER_MAX_VERTEXES]; + vec4_t normal[SHADER_MAX_VERTEXES]; + vec2_t texCoords[SHADER_MAX_VERTEXES][2]; + color4ub_t vertexColors[SHADER_MAX_VERTEXES]; + int vertexDlightBits[SHADER_MAX_VERTEXES]; + + stageVars_t svars; + + color4ub_t constantColor255[SHADER_MAX_VERTEXES]; + + shader_t *shader; + float shaderTime; + int fogNum; + + int dlightBits; // or together of all vertexDlightBits + + int numIndexes; + int numVertexes; + + // info extracted from current shader + int numPasses; + void (*currentStageIteratorFunc)( void ); + shaderStage_t **xstages; +} shaderCommands_t; + +extern shaderCommands_t tess; + +void RB_BeginSurface(shader_t *shader, int fogNum ); +void RB_EndSurface(void); +void RB_CheckOverflow( int verts, int indexes ); +#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} + +void RB_StageIteratorGeneric( void ); +void RB_StageIteratorSky( void ); +void RB_StageIteratorVertexLitTexture( void ); +void RB_StageIteratorLightmappedMultitexture( void ); + +void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ); +void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ); + +void RB_ShowImages( void ); + + +/* +============================================================ + +WORLD MAP + +============================================================ +*/ + +void R_AddBrushModelSurfaces( trRefEntity_t *e ); +void R_AddWorldSurfaces( void ); +qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ); + + +/* +============================================================ + +FLARES + +============================================================ +*/ + +void R_ClearFlares( void ); + +void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ); +void RB_AddDlightFlares( void ); +void RB_RenderFlares (void); + +/* +============================================================ + +LIGHTS + +============================================================ +*/ + +void R_DlightBmodel( bmodel_t *bmodel ); +void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); +void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); +int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); + + +/* +============================================================ + +SHADOWS + +============================================================ +*/ + +void RB_ShadowTessEnd( void ); +void RB_ShadowFinish( void ); +void RB_ProjectionShadowDeform( void ); + +/* +============================================================ + +SKIES + +============================================================ +*/ + +void R_BuildCloudData( shaderCommands_t *shader ); +void R_InitSkyTexCoords( float cloudLayerHeight ); +void R_DrawSkyBox( shaderCommands_t *shader ); +void RB_DrawSun( void ); +void RB_ClipSkyPolygons( shaderCommands_t *shader ); + +/* +============================================================ + +CURVE TESSELATION + +============================================================ +*/ + +#define PATCH_STITCHING + +srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, + drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); +srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ); +srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ); +void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ); + +/* +============================================================ + +MARKERS, POLYGON PROJECTION ON WORLD POLYGONS + +============================================================ +*/ + +int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, + int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); + + +/* +============================================================ + +SCENE GENERATION + +============================================================ +*/ + +void R_ToggleSmpFrame( void ); + +void RE_ClearScene( void ); +void RE_AddRefEntityToScene( const refEntity_t *ent ); +void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); +void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); +void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); +void RE_RenderScene( const refdef_t *fd ); + +/* +============================================================= + +ANIMATED MODELS + +============================================================= +*/ + +void R_MakeAnimModel( model_t *model ); +void R_AddAnimSurfaces( trRefEntity_t *ent ); +void RB_SurfaceAnim( md4Surface_t *surfType ); + +/* +============================================================= +============================================================= +*/ +void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, + vec4_t eye, vec4_t dst ); +void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ); + +void RB_DeformTessGeometry( void ); + +void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); +void RB_CalcFogTexCoords( float *dstTexCoords ); +void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords ); +void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords ); +void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords ); +void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords ); +void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords ); +void RB_CalcModulateColorsByFog( unsigned char *dstColors ); +void RB_CalcModulateAlphasByFog( unsigned char *dstColors ); +void RB_CalcModulateRGBAsByFog( unsigned char *dstColors ); +void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ); +void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ); +void RB_CalcAlphaFromEntity( unsigned char *dstColors ); +void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ); +void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords ); +void RB_CalcColorFromEntity( unsigned char *dstColors ); +void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ); +void RB_CalcSpecularAlpha( unsigned char *alphas ); +void RB_CalcDiffuseColor( unsigned char *colors ); + +/* +============================================================= + +RENDERER BACK END FUNCTIONS + +============================================================= +*/ + +void RB_RenderThread( void ); +void RB_ExecuteRenderCommands( const void *data ); + +/* +============================================================= + +RENDERER BACK END COMMAND QUEUE + +============================================================= +*/ + +#define MAX_RENDER_COMMANDS 0x40000 + +typedef struct { + byte cmds[MAX_RENDER_COMMANDS]; + int used; +} renderCommandList_t; + +typedef struct { + int commandId; + float color[4]; +} setColorCommand_t; + +typedef struct { + int commandId; + int buffer; +} drawBufferCommand_t; + +typedef struct { + int commandId; + image_t *image; + int width; + int height; + void *data; +} subImageCommand_t; + +typedef struct { + int commandId; +} swapBuffersCommand_t; + +typedef struct { + int commandId; + int buffer; +} endFrameCommand_t; + +typedef struct { + int commandId; + shader_t *shader; + float x, y; + float w, h; + float s1, t1; + float s2, t2; +} stretchPicCommand_t; + +typedef struct { + int commandId; + trRefdef_t refdef; + viewParms_t viewParms; + drawSurf_t *drawSurfs; + int numDrawSurfs; +} drawSurfsCommand_t; + +typedef struct { + int commandId; + int x; + int y; + int width; + int height; + char *fileName; + qboolean jpeg; +} screenshotCommand_t; + +typedef enum { + RC_END_OF_LIST, + RC_SET_COLOR, + RC_STRETCH_PIC, + RC_DRAW_SURFS, + RC_DRAW_BUFFER, + RC_SWAP_BUFFERS, + RC_SCREENSHOT +} renderCommand_t; + + +// these are sort of arbitrary limits. +// the limits apply to the sum of all scenes in a frame -- +// the main view, all the 3D icons, etc +#define MAX_POLYS 600 +#define MAX_POLYVERTS 3000 + +// all of the information needed by the back end must be +// contained in a backEndData_t. This entire structure is +// duplicated so the front and back end can run in parallel +// on an SMP machine +typedef struct { + drawSurf_t drawSurfs[MAX_DRAWSURFS]; + dlight_t dlights[MAX_DLIGHTS]; + trRefEntity_t entities[MAX_ENTITIES]; + srfPoly_t *polys;//[MAX_POLYS]; + polyVert_t *polyVerts;//[MAX_POLYVERTS]; + renderCommandList_t commands; +} backEndData_t; + +extern int max_polys; +extern int max_polyverts; + +extern backEndData_t *backEndData[SMP_FRAMES]; // the second one may not be allocated + +extern volatile renderCommandList_t *renderCommandList; + +extern volatile qboolean renderThreadActive; + + +void *R_GetCommandBuffer( int bytes ); +void RB_ExecuteRenderCommands( const void *data ); + +void R_InitCommandBuffers( void ); +void R_ShutdownCommandBuffers( void ); + +void R_SyncRenderThread( void ); + +void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); + +void RE_SetColor( const float *rgba ); +void RE_StretchPic ( float x, float y, float w, float h, + float s1, float t1, float s2, float t2, qhandle_t hShader ); +void RE_BeginFrame( stereoFrame_t stereoFrame ); +void RE_EndFrame( int *frontEndMsec, int *backEndMsec ); +void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer); + +// font stuff +void R_InitFreeType(); +void R_DoneFreeType(); +void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); + + +#endif //TR_LOCAL_H diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 7b054ca..1c92579 100755 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -1,1485 +1,1485 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_main.c -- main control flow for each frame
-
-#include "tr_local.h"
-
-trGlobals_t tr;
-
-static float s_flipMatrix[16] = {
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- 0, 0, -1, 0,
- -1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 0, 1
-};
-
-
-refimport_t ri;
-
-// entities that will have procedurally generated surfaces will just
-// point at this for their sorting surface
-surfaceType_t entitySurface = SF_ENTITY;
-
-/*
-=================
-R_CullLocalBox
-
-Returns CULL_IN, CULL_CLIP, or CULL_OUT
-=================
-*/
-int R_CullLocalBox (vec3_t bounds[2]) {
- int i, j;
- vec3_t transformed[8];
- float dists[8];
- vec3_t v;
- cplane_t *frust;
- int anyBack;
- int front, back;
-
- if ( r_nocull->integer ) {
- return CULL_CLIP;
- }
-
- // transform into world space
- for (i = 0 ; i < 8 ; i++) {
- v[0] = bounds[i&1][0];
- v[1] = bounds[(i>>1)&1][1];
- v[2] = bounds[(i>>2)&1][2];
-
- VectorCopy( tr.or.origin, transformed[i] );
- VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );
- VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );
- VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );
- }
-
- // check against frustum planes
- anyBack = 0;
- for (i = 0 ; i < 4 ; i++) {
- frust = &tr.viewParms.frustum[i];
-
- front = back = 0;
- for (j = 0 ; j < 8 ; j++) {
- dists[j] = DotProduct(transformed[j], frust->normal);
- if ( dists[j] > frust->dist ) {
- front = 1;
- if ( back ) {
- break; // a point is in front
- }
- } else {
- back = 1;
- }
- }
- if ( !front ) {
- // all points were behind one of the planes
- return CULL_OUT;
- }
- anyBack |= back;
- }
-
- if ( !anyBack ) {
- return CULL_IN; // completely inside frustum
- }
-
- return CULL_CLIP; // partially clipped
-}
-
-/*
-** R_CullLocalPointAndRadius
-*/
-int R_CullLocalPointAndRadius( vec3_t pt, float radius )
-{
- vec3_t transformed;
-
- R_LocalPointToWorld( pt, transformed );
-
- return R_CullPointAndRadius( transformed, radius );
-}
-
-/*
-** R_CullPointAndRadius
-*/
-int R_CullPointAndRadius( vec3_t pt, float radius )
-{
- int i;
- float dist;
- cplane_t *frust;
- qboolean mightBeClipped = qfalse;
-
- if ( r_nocull->integer ) {
- return CULL_CLIP;
- }
-
- // check against frustum planes
- for (i = 0 ; i < 4 ; i++)
- {
- frust = &tr.viewParms.frustum[i];
-
- dist = DotProduct( pt, frust->normal) - frust->dist;
- if ( dist < -radius )
- {
- return CULL_OUT;
- }
- else if ( dist <= radius )
- {
- mightBeClipped = qtrue;
- }
- }
-
- if ( mightBeClipped )
- {
- return CULL_CLIP;
- }
-
- return CULL_IN; // completely inside frustum
-}
-
-
-/*
-=================
-R_LocalNormalToWorld
-
-=================
-*/
-void R_LocalNormalToWorld (vec3_t local, vec3_t world) {
- world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0];
- world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1];
- world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2];
-}
-
-/*
-=================
-R_LocalPointToWorld
-
-=================
-*/
-void R_LocalPointToWorld (vec3_t local, vec3_t world) {
- world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0];
- world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1];
- world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2];
-}
-
-/*
-=================
-R_WorldToLocal
-
-=================
-*/
-void R_WorldToLocal (vec3_t world, vec3_t local) {
- local[0] = DotProduct(world, tr.or.axis[0]);
- local[1] = DotProduct(world, tr.or.axis[1]);
- local[2] = DotProduct(world, tr.or.axis[2]);
-}
-
-/*
-==========================
-R_TransformModelToClip
-
-==========================
-*/
-void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
- vec4_t eye, vec4_t dst ) {
- int i;
-
- for ( i = 0 ; i < 4 ; i++ ) {
- eye[i] =
- src[0] * modelMatrix[ i + 0 * 4 ] +
- src[1] * modelMatrix[ i + 1 * 4 ] +
- src[2] * modelMatrix[ i + 2 * 4 ] +
- 1 * modelMatrix[ i + 3 * 4 ];
- }
-
- for ( i = 0 ; i < 4 ; i++ ) {
- dst[i] =
- eye[0] * projectionMatrix[ i + 0 * 4 ] +
- eye[1] * projectionMatrix[ i + 1 * 4 ] +
- eye[2] * projectionMatrix[ i + 2 * 4 ] +
- eye[3] * projectionMatrix[ i + 3 * 4 ];
- }
-}
-
-/*
-==========================
-R_TransformClipToWindow
-
-==========================
-*/
-void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
- normalized[0] = clip[0] / clip[3];
- normalized[1] = clip[1] / clip[3];
- normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
-
- window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
- window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
- window[2] = normalized[2];
-
- window[0] = (int) ( window[0] + 0.5 );
- window[1] = (int) ( window[1] + 0.5 );
-}
-
-
-/*
-==========================
-myGlMultMatrix
-
-==========================
-*/
-void myGlMultMatrix( const float *a, const float *b, float *out ) {
- int i, j;
-
- for ( i = 0 ; i < 4 ; i++ ) {
- for ( j = 0 ; j < 4 ; j++ ) {
- out[ i * 4 + j ] =
- a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
- + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
- + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
- + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
- }
- }
-}
-
-/*
-=================
-R_RotateForEntity
-
-Generates an orientation for an entity and viewParms
-Does NOT produce any GL calls
-Called by both the front end and the back end
-=================
-*/
-void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
- orientationr_t *or ) {
- float glMatrix[16];
- vec3_t delta;
- float axisLength;
-
- if ( ent->e.reType != RT_MODEL ) {
- *or = viewParms->world;
- return;
- }
-
- VectorCopy( ent->e.origin, or->origin );
-
- VectorCopy( ent->e.axis[0], or->axis[0] );
- VectorCopy( ent->e.axis[1], or->axis[1] );
- VectorCopy( ent->e.axis[2], or->axis[2] );
-
- glMatrix[0] = or->axis[0][0];
- glMatrix[4] = or->axis[1][0];
- glMatrix[8] = or->axis[2][0];
- glMatrix[12] = or->origin[0];
-
- glMatrix[1] = or->axis[0][1];
- glMatrix[5] = or->axis[1][1];
- glMatrix[9] = or->axis[2][1];
- glMatrix[13] = or->origin[1];
-
- glMatrix[2] = or->axis[0][2];
- glMatrix[6] = or->axis[1][2];
- glMatrix[10] = or->axis[2][2];
- glMatrix[14] = or->origin[2];
-
- glMatrix[3] = 0;
- glMatrix[7] = 0;
- glMatrix[11] = 0;
- glMatrix[15] = 1;
-
- myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );
-
- // calculate the viewer origin in the model's space
- // needed for fog, specular, and environment mapping
- VectorSubtract( viewParms->or.origin, or->origin, delta );
-
- // compensate for scale in the axes if necessary
- if ( ent->e.nonNormalizedAxes ) {
- axisLength = VectorLength( ent->e.axis[0] );
- if ( !axisLength ) {
- axisLength = 0;
- } else {
- axisLength = 1.0f / axisLength;
- }
- } else {
- axisLength = 1.0f;
- }
-
- or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength;
- or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength;
- or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;
-}
-
-/*
-=================
-R_RotateForViewer
-
-Sets up the modelview matrix for a given viewParm
-=================
-*/
-void R_RotateForViewer (void)
-{
- float viewerMatrix[16];
- vec3_t origin;
-
- Com_Memset (&tr.or, 0, sizeof(tr.or));
- tr.or.axis[0][0] = 1;
- tr.or.axis[1][1] = 1;
- tr.or.axis[2][2] = 1;
- VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin);
-
- // transform by the camera placement
- VectorCopy( tr.viewParms.or.origin, origin );
-
- viewerMatrix[0] = tr.viewParms.or.axis[0][0];
- viewerMatrix[4] = tr.viewParms.or.axis[0][1];
- viewerMatrix[8] = tr.viewParms.or.axis[0][2];
- viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
-
- viewerMatrix[1] = tr.viewParms.or.axis[1][0];
- viewerMatrix[5] = tr.viewParms.or.axis[1][1];
- viewerMatrix[9] = tr.viewParms.or.axis[1][2];
- viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
-
- viewerMatrix[2] = tr.viewParms.or.axis[2][0];
- viewerMatrix[6] = tr.viewParms.or.axis[2][1];
- viewerMatrix[10] = tr.viewParms.or.axis[2][2];
- viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
-
- viewerMatrix[3] = 0;
- viewerMatrix[7] = 0;
- viewerMatrix[11] = 0;
- viewerMatrix[15] = 1;
-
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix );
-
- tr.viewParms.world = tr.or;
-
-}
-
-/*
-** SetFarClip
-*/
-static void SetFarClip( void )
-{
- float farthestCornerDistance = 0;
- int i;
-
- // if not rendering the world (icons, menus, etc)
- // set a 2k far clip plane
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- tr.viewParms.zFar = 2048;
- return;
- }
-
- //
- // set far clipping planes dynamically
- //
- farthestCornerDistance = 0;
- for ( i = 0; i < 8; i++ )
- {
- vec3_t v;
- vec3_t vecTo;
- float distance;
-
- if ( i & 1 )
- {
- v[0] = tr.viewParms.visBounds[0][0];
- }
- else
- {
- v[0] = tr.viewParms.visBounds[1][0];
- }
-
- if ( i & 2 )
- {
- v[1] = tr.viewParms.visBounds[0][1];
- }
- else
- {
- v[1] = tr.viewParms.visBounds[1][1];
- }
-
- if ( i & 4 )
- {
- v[2] = tr.viewParms.visBounds[0][2];
- }
- else
- {
- v[2] = tr.viewParms.visBounds[1][2];
- }
-
- VectorSubtract( v, tr.viewParms.or.origin, vecTo );
-
- distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
-
- if ( distance > farthestCornerDistance )
- {
- farthestCornerDistance = distance;
- }
- }
- tr.viewParms.zFar = sqrt( farthestCornerDistance );
-}
-
-
-/*
-===============
-R_SetupProjection
-===============
-*/
-void R_SetupProjection( void ) {
- float xmin, xmax, ymin, ymax;
- float width, height, depth;
- float zNear, zFar;
-
- // dynamically compute far clip plane distance
- SetFarClip();
-
- //
- // set up projection matrix
- //
- zNear = r_znear->value;
- zFar = tr.viewParms.zFar;
-
- ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
- ymin = -ymax;
-
- xmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );
- xmin = -xmax;
-
- width = xmax - xmin;
- height = ymax - ymin;
- depth = zFar - zNear;
-
- tr.viewParms.projectionMatrix[0] = 2 * zNear / width;
- tr.viewParms.projectionMatrix[4] = 0;
- tr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
- tr.viewParms.projectionMatrix[12] = 0;
-
- tr.viewParms.projectionMatrix[1] = 0;
- tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
- tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
- tr.viewParms.projectionMatrix[13] = 0;
-
- tr.viewParms.projectionMatrix[2] = 0;
- tr.viewParms.projectionMatrix[6] = 0;
- tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;
- tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;
-
- tr.viewParms.projectionMatrix[3] = 0;
- tr.viewParms.projectionMatrix[7] = 0;
- tr.viewParms.projectionMatrix[11] = -1;
- tr.viewParms.projectionMatrix[15] = 0;
-}
-
-/*
-=================
-R_SetupFrustum
-
-Setup that culling frustum planes for the current view
-=================
-*/
-void R_SetupFrustum (void) {
- int i;
- float xs, xc;
- float ang;
-
- ang = tr.viewParms.fovX / 180 * M_PI * 0.5f;
- xs = sin( ang );
- xc = cos( ang );
-
- VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[0].normal );
- VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[0].normal );
-
- VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[1].normal );
- VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[1].normal );
-
- ang = tr.viewParms.fovY / 180 * M_PI * 0.5f;
- xs = sin( ang );
- xc = cos( ang );
-
- VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[2].normal );
- VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[2].normal );
-
- VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[3].normal );
- VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[3].normal );
-
- for (i=0 ; i<4 ; i++) {
- tr.viewParms.frustum[i].type = PLANE_NON_AXIAL;
- tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.or.origin, tr.viewParms.frustum[i].normal);
- SetPlaneSignbits( &tr.viewParms.frustum[i] );
- }
-}
-
-
-/*
-=================
-R_MirrorPoint
-=================
-*/
-void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
- int i;
- vec3_t local;
- vec3_t transformed;
- float d;
-
- VectorSubtract( in, surface->origin, local );
-
- VectorClear( transformed );
- for ( i = 0 ; i < 3 ; i++ ) {
- d = DotProduct(local, surface->axis[i]);
- VectorMA( transformed, d, camera->axis[i], transformed );
- }
-
- VectorAdd( transformed, camera->origin, out );
-}
-
-void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
- int i;
- float d;
-
- VectorClear( out );
- for ( i = 0 ; i < 3 ; i++ ) {
- d = DotProduct(in, surface->axis[i]);
- VectorMA( out, d, camera->axis[i], out );
- }
-}
-
-
-/*
-=============
-R_PlaneForSurface
-=============
-*/
-void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
- srfTriangles_t *tri;
- srfPoly_t *poly;
- drawVert_t *v1, *v2, *v3;
- vec4_t plane4;
-
- if (!surfType) {
- Com_Memset (plane, 0, sizeof(*plane));
- plane->normal[0] = 1;
- return;
- }
- switch (*surfType) {
- case SF_FACE:
- *plane = ((srfSurfaceFace_t *)surfType)->plane;
- return;
- case SF_TRIANGLES:
- tri = (srfTriangles_t *)surfType;
- v1 = tri->verts + tri->indexes[0];
- v2 = tri->verts + tri->indexes[1];
- v3 = tri->verts + tri->indexes[2];
- PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
- VectorCopy( plane4, plane->normal );
- plane->dist = plane4[3];
- return;
- case SF_POLY:
- poly = (srfPoly_t *)surfType;
- PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
- VectorCopy( plane4, plane->normal );
- plane->dist = plane4[3];
- return;
- default:
- Com_Memset (plane, 0, sizeof(*plane));
- plane->normal[0] = 1;
- return;
- }
-}
-
-/*
-=================
-R_GetPortalOrientation
-
-entityNum is the entity that the portal surface is a part of, which may
-be moving and rotating.
-
-Returns qtrue if it should be mirrored
-=================
-*/
-qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
- orientation_t *surface, orientation_t *camera,
- vec3_t pvsOrigin, qboolean *mirror ) {
- int i;
- cplane_t originalPlane, plane;
- trRefEntity_t *e;
- float d;
- vec3_t transformed;
-
- // create plane axis for the portal we are seeing
- R_PlaneForSurface( drawSurf->surface, &originalPlane );
-
- // rotate the plane if necessary
- if ( entityNum != ENTITYNUM_WORLD ) {
- tr.currentEntityNum = entityNum;
- tr.currentEntity = &tr.refdef.entities[entityNum];
-
- // get the orientation of the entity
- R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
-
- // rotate the plane, but keep the non-rotated version for matching
- // against the portalSurface entities
- R_LocalNormalToWorld( originalPlane.normal, plane.normal );
- plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
-
- // translate the original plane
- originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
- } else {
- plane = originalPlane;
- }
-
- VectorCopy( plane.normal, surface->axis[0] );
- PerpendicularVector( surface->axis[1], surface->axis[0] );
- CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
-
- // locate the portal entity closest to this plane.
- // origin will be the origin of the portal, origin2 will be
- // the origin of the camera
- for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
- e = &tr.refdef.entities[i];
- if ( e->e.reType != RT_PORTALSURFACE ) {
- continue;
- }
-
- d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
- if ( d > 64 || d < -64) {
- continue;
- }
-
- // get the pvsOrigin from the entity
- VectorCopy( e->e.oldorigin, pvsOrigin );
-
- // if the entity is just a mirror, don't use as a camera point
- if ( e->e.oldorigin[0] == e->e.origin[0] &&
- e->e.oldorigin[1] == e->e.origin[1] &&
- e->e.oldorigin[2] == e->e.origin[2] ) {
- VectorScale( plane.normal, plane.dist, surface->origin );
- VectorCopy( surface->origin, camera->origin );
- VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
- VectorCopy( surface->axis[1], camera->axis[1] );
- VectorCopy( surface->axis[2], camera->axis[2] );
-
- *mirror = qtrue;
- return qtrue;
- }
-
- // project the origin onto the surface plane to get
- // an origin point we can rotate around
- d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
- VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
-
- // now get the camera origin and orientation
- VectorCopy( e->e.oldorigin, camera->origin );
- AxisCopy( e->e.axis, camera->axis );
- VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
- VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
-
- // optionally rotate
- if ( e->e.oldframe ) {
- // if a speed is specified
- if ( e->e.frame ) {
- // continuous rotate
- d = (tr.refdef.time/1000.0f) * e->e.frame;
- VectorCopy( camera->axis[1], transformed );
- RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
- CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
- } else {
- // bobbing rotate, with skinNum being the rotation offset
- d = sin( tr.refdef.time * 0.003f );
- d = e->e.skinNum + d * 4;
- VectorCopy( camera->axis[1], transformed );
- RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
- CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
- }
- }
- else if ( e->e.skinNum ) {
- d = e->e.skinNum;
- VectorCopy( camera->axis[1], transformed );
- RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
- CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
- }
- *mirror = qfalse;
- return qtrue;
- }
-
- // if we didn't locate a portal entity, don't render anything.
- // We don't want to just treat it as a mirror, because without a
- // portal entity the server won't have communicated a proper entity set
- // in the snapshot
-
- // unfortunately, with local movement prediction it is easily possible
- // to see a surface before the server has communicated the matching
- // portal surface entity, so we don't want to print anything here...
-
- //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
-
- return qfalse;
-}
-
-static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum )
-{
- int i;
- cplane_t originalPlane, plane;
- trRefEntity_t *e;
- float d;
-
- // create plane axis for the portal we are seeing
- R_PlaneForSurface( drawSurf->surface, &originalPlane );
-
- // rotate the plane if necessary
- if ( entityNum != ENTITYNUM_WORLD )
- {
- tr.currentEntityNum = entityNum;
- tr.currentEntity = &tr.refdef.entities[entityNum];
-
- // get the orientation of the entity
- R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
-
- // rotate the plane, but keep the non-rotated version for matching
- // against the portalSurface entities
- R_LocalNormalToWorld( originalPlane.normal, plane.normal );
- plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
-
- // translate the original plane
- originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
- }
- else
- {
- plane = originalPlane;
- }
-
- // locate the portal entity closest to this plane.
- // origin will be the origin of the portal, origin2 will be
- // the origin of the camera
- for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
- {
- e = &tr.refdef.entities[i];
- if ( e->e.reType != RT_PORTALSURFACE ) {
- continue;
- }
-
- d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
- if ( d > 64 || d < -64) {
- continue;
- }
-
- // if the entity is just a mirror, don't use as a camera point
- if ( e->e.oldorigin[0] == e->e.origin[0] &&
- e->e.oldorigin[1] == e->e.origin[1] &&
- e->e.oldorigin[2] == e->e.origin[2] )
- {
- return qtrue;
- }
-
- return qfalse;
- }
- return qfalse;
-}
-
-/*
-** SurfIsOffscreen
-**
-** Determines if a surface is completely offscreen.
-*/
-static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
- float shortest = 100000000;
- int entityNum;
- int numTriangles;
- shader_t *shader;
- int fogNum;
- int dlighted;
- vec4_t clip, eye;
- int i;
- unsigned int pointOr = 0;
- unsigned int pointAnd = (unsigned int)~0;
-
- if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp!
- return qfalse;
- }
-
- R_RotateForViewer();
-
- R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
- RB_BeginSurface( shader, fogNum );
- rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
-
- assert( tess.numVertexes < 128 );
-
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- int j;
- unsigned int pointFlags = 0;
-
- R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
-
- for ( j = 0; j < 3; j++ )
- {
- if ( clip[j] >= clip[3] )
- {
- pointFlags |= (1 << (j*2));
- }
- else if ( clip[j] <= -clip[3] )
- {
- pointFlags |= ( 1 << (j*2+1));
- }
- }
- pointAnd &= pointFlags;
- pointOr |= pointFlags;
- }
-
- // trivially reject
- if ( pointAnd )
- {
- return qtrue;
- }
-
- // determine if this surface is backfaced and also determine the distance
- // to the nearest vertex so we can cull based on portal range. Culling
- // based on vertex distance isn't 100% correct (we should be checking for
- // range to the surface), but it's good enough for the types of portals
- // we have in the game right now.
- numTriangles = tess.numIndexes / 3;
-
- for ( i = 0; i < tess.numIndexes; i += 3 )
- {
- vec3_t normal;
- float dot;
- float len;
-
- VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );
-
- len = VectorLengthSquared( normal ); // lose the sqrt
- if ( len < shortest )
- {
- shortest = len;
- }
-
- if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 )
- {
- numTriangles--;
- }
- }
- if ( !numTriangles )
- {
- return qtrue;
- }
-
- // mirrors can early out at this point, since we don't do a fade over distance
- // with them (although we could)
- if ( IsMirror( drawSurf, entityNum ) )
- {
- return qfalse;
- }
-
- if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
- {
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-========================
-R_MirrorViewBySurface
-
-Returns qtrue if another view has been rendered
-========================
-*/
-qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
- vec4_t clipDest[128];
- viewParms_t newParms;
- viewParms_t oldParms;
- orientation_t surface, camera;
-
- // don't recursively mirror
- if (tr.viewParms.isPortal) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" );
- return qfalse;
- }
-
- if ( r_noportals->integer || (r_fastsky->integer == 1) ) {
- return qfalse;
- }
-
- // trivially reject portal/mirror
- if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
- return qfalse;
- }
-
- // save old viewParms so we can return to it after the mirror view
- oldParms = tr.viewParms;
-
- newParms = tr.viewParms;
- newParms.isPortal = qtrue;
- if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
- newParms.pvsOrigin, &newParms.isMirror ) ) {
- return qfalse; // bad portal, no portalentity
- }
-
- R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin );
-
- VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
- newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
-
- R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]);
- R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]);
- R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]);
-
- // OPTIMIZE: restrict the viewport on the mirrored view
-
- // render the mirror view
- R_RenderView (&newParms);
-
- tr.viewParms = oldParms;
-
- return qtrue;
-}
-
-/*
-=================
-R_SpriteFogNum
-
-See if a sprite is inside a fog volume
-=================
-*/
-int R_SpriteFogNum( trRefEntity_t *ent ) {
- int i, j;
- fog_t *fog;
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return 0;
- }
-
- for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
- fog = &tr.world->fogs[i];
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
- break;
- }
- if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
- break;
- }
- }
- if ( j == 3 ) {
- return i;
- }
- }
-
- return 0;
-}
-
-/*
-==========================================================================================
-
-DRAWSURF SORTING
-
-==========================================================================================
-*/
-
-/*
-=================
-qsort replacement
-
-=================
-*/
-#define SWAP_DRAW_SURF(a,b) temp=((int *)a)[0];((int *)a)[0]=((int *)b)[0];((int *)b)[0]=temp; temp=((int *)a)[1];((int *)a)[1]=((int *)b)[1];((int *)b)[1]=temp;
-
-/* this parameter defines the cutoff between using quick sort and
- insertion sort for arrays; arrays with lengths shorter or equal to the
- below value use insertion sort */
-
-#define CUTOFF 8 /* testing shows that this is good value */
-
-static void shortsort( drawSurf_t *lo, drawSurf_t *hi ) {
- drawSurf_t *p, *max;
- int temp;
-
- while (hi > lo) {
- max = lo;
- for (p = lo + 1; p <= hi; p++ ) {
- if ( p->sort > max->sort ) {
- max = p;
- }
- }
- SWAP_DRAW_SURF(max, hi);
- hi--;
- }
-}
-
-
-/* sort the array between lo and hi (inclusive)
-FIXME: this was lifted and modified from the microsoft lib source...
- */
-
-void qsortFast (
- void *base,
- unsigned num,
- unsigned width
- )
-{
- char *lo, *hi; /* ends of sub-array currently sorting */
- char *mid; /* points to middle of subarray */
- char *loguy, *higuy; /* traveling pointers for partition step */
- unsigned size; /* size of the sub-array */
- char *lostk[30], *histk[30];
- int stkptr; /* stack for saving sub-array to be processed */
- int temp;
-
- if ( sizeof(drawSurf_t) != 8 ) {
- ri.Error( ERR_DROP, "change SWAP_DRAW_SURF macro" );
- }
-
- /* Note: the number of stack entries required is no more than
- 1 + log2(size), so 30 is sufficient for any array */
-
- if (num < 2 || width == 0)
- return; /* nothing to do */
-
- stkptr = 0; /* initialize stack */
-
- lo = base;
- hi = (char *)base + width * (num-1); /* initialize limits */
-
- /* this entry point is for pseudo-recursion calling: setting
- lo and hi and jumping to here is like recursion, but stkptr is
- prserved, locals aren't, so we preserve stuff on the stack */
-recurse:
-
- size = (hi - lo) / width + 1; /* number of el's to sort */
-
- /* below a certain size, it is faster to use a O(n^2) sorting method */
- if (size <= CUTOFF) {
- shortsort((drawSurf_t *)lo, (drawSurf_t *)hi);
- }
- else {
- /* First we pick a partititioning element. The efficiency of the
- algorithm demands that we find one that is approximately the
- median of the values, but also that we select one fast. Using
- the first one produces bad performace if the array is already
- sorted, so we use the middle one, which would require a very
- wierdly arranged array for worst case performance. Testing shows
- that a median-of-three algorithm does not, in general, increase
- performance. */
-
- mid = lo + (size / 2) * width; /* find middle element */
- SWAP_DRAW_SURF(mid, lo); /* swap it to beginning of array */
-
- /* We now wish to partition the array into three pieces, one
- consisiting of elements <= partition element, one of elements
- equal to the parition element, and one of element >= to it. This
- is done below; comments indicate conditions established at every
- step. */
-
- loguy = lo;
- higuy = hi + width;
-
- /* Note that higuy decreases and loguy increases on every iteration,
- so loop must terminate. */
- for (;;) {
- /* lo <= loguy < hi, lo < higuy <= hi + 1,
- A[i] <= A[lo] for lo <= i <= loguy,
- A[i] >= A[lo] for higuy <= i <= hi */
-
- do {
- loguy += width;
- } while (loguy <= hi &&
- ( ((drawSurf_t *)loguy)->sort <= ((drawSurf_t *)lo)->sort ) );
-
- /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
- either loguy > hi or A[loguy] > A[lo] */
-
- do {
- higuy -= width;
- } while (higuy > lo &&
- ( ((drawSurf_t *)higuy)->sort >= ((drawSurf_t *)lo)->sort ) );
-
- /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
- either higuy <= lo or A[higuy] < A[lo] */
-
- if (higuy < loguy)
- break;
-
- /* if loguy > hi or higuy <= lo, then we would have exited, so
- A[loguy] > A[lo], A[higuy] < A[lo],
- loguy < hi, highy > lo */
-
- SWAP_DRAW_SURF(loguy, higuy);
-
- /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
- of loop is re-established */
- }
-
- /* A[i] >= A[lo] for higuy < i <= hi,
- A[i] <= A[lo] for lo <= i < loguy,
- higuy < loguy, lo <= higuy <= hi
- implying:
- A[i] >= A[lo] for loguy <= i <= hi,
- A[i] <= A[lo] for lo <= i <= higuy,
- A[i] = A[lo] for higuy < i < loguy */
-
- SWAP_DRAW_SURF(lo, higuy); /* put partition element in place */
-
- /* OK, now we have the following:
- A[i] >= A[higuy] for loguy <= i <= hi,
- A[i] <= A[higuy] for lo <= i < higuy
- A[i] = A[lo] for higuy <= i < loguy */
-
- /* We've finished the partition, now we want to sort the subarrays
- [lo, higuy-1] and [loguy, hi].
- We do the smaller one first to minimize stack usage.
- We only sort arrays of length 2 or more.*/
-
- if ( higuy - 1 - lo >= hi - loguy ) {
- if (lo + width < higuy) {
- lostk[stkptr] = lo;
- histk[stkptr] = higuy - width;
- ++stkptr;
- } /* save big recursion for later */
-
- if (loguy < hi) {
- lo = loguy;
- goto recurse; /* do small recursion */
- }
- }
- else {
- if (loguy < hi) {
- lostk[stkptr] = loguy;
- histk[stkptr] = hi;
- ++stkptr; /* save big recursion for later */
- }
-
- if (lo + width < higuy) {
- hi = higuy - width;
- goto recurse; /* do small recursion */
- }
- }
- }
-
- /* We have sorted the array, except for any pending sorts on the stack.
- Check if there are any, and do them. */
-
- --stkptr;
- if (stkptr >= 0) {
- lo = lostk[stkptr];
- hi = histk[stkptr];
- goto recurse; /* pop subarray from stack */
- }
- else
- return; /* all subarrays done */
-}
-
-
-//==========================================================================================
-
-/*
-=================
-R_AddDrawSurf
-=================
-*/
-void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
- int fogIndex, int dlightMap ) {
- int index;
-
- // instead of checking for overflow, we just mask the index
- // so it wraps around
- index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
- // the sort data is packed into a single 32 bit value so it can be
- // compared quickly during the qsorting process
- tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
- | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
- tr.refdef.drawSurfs[index].surface = surface;
- tr.refdef.numDrawSurfs++;
-}
-
-/*
-=================
-R_DecomposeSort
-=================
-*/
-void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
- int *fogNum, int *dlightMap ) {
- *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
- *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
- *entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & 1023;
- *dlightMap = sort & 3;
-}
-
-/*
-=================
-R_SortDrawSurfs
-=================
-*/
-void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
- shader_t *shader;
- int fogNum;
- int entityNum;
- int dlighted;
- int i;
-
- // it is possible for some views to not have any surfaces
- if ( numDrawSurfs < 1 ) {
- // we still need to add it for hyperspace cases
- R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
- return;
- }
-
- // if we overflowed MAX_DRAWSURFS, the drawsurfs
- // wrapped around in the buffer and we will be missing
- // the first surfaces, not the last ones
- if ( numDrawSurfs > MAX_DRAWSURFS ) {
- numDrawSurfs = MAX_DRAWSURFS;
- }
-
- // sort the drawsurfs by sort type, then orientation, then shader
- qsortFast (drawSurfs, numDrawSurfs, sizeof(drawSurf_t) );
-
- // check for any pass through drawing, which
- // may cause another view to be rendered first
- for ( i = 0 ; i < numDrawSurfs ; i++ ) {
- R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted );
-
- if ( shader->sort > SS_PORTAL ) {
- break;
- }
-
- // no shader should ever have this sort type
- if ( shader->sort == SS_BAD ) {
- ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
- }
-
- // if the mirror was completely clipped away, we may need to check another surface
- if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {
- // this is a debug option to see exactly what is being mirrored
- if ( r_portalOnly->integer ) {
- return;
- }
- break; // only one mirror view at a time
- }
- }
-
- R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
-}
-
-/*
-=============
-R_AddEntitySurfaces
-=============
-*/
-void R_AddEntitySurfaces (void) {
- trRefEntity_t *ent;
- shader_t *shader;
-
- if ( !r_drawentities->integer ) {
- return;
- }
-
- for ( tr.currentEntityNum = 0;
- tr.currentEntityNum < tr.refdef.num_entities;
- tr.currentEntityNum++ ) {
- ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
-
- ent->needDlights = qfalse;
-
- // preshift the value we are going to OR into the drawsurf sort
- tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
-
- //
- // the weapon model must be handled special --
- // we don't want the hacked weapon position showing in
- // mirrors, because the true body position will already be drawn
- //
- if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) {
- continue;
- }
-
- // simple generated models, like sprites and beams, are not culled
- switch ( ent->e.reType ) {
- case RT_PORTALSURFACE:
- break; // don't draw anything
- case RT_SPRITE:
- case RT_BEAM:
- case RT_LIGHTNING:
- case RT_RAIL_CORE:
- case RT_RAIL_RINGS:
- // self blood sprites, talk balloons, etc should not be drawn in the primary
- // view. We can't just do this check for all entities, because md3
- // entities may still want to cast shadows from them
- if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
- continue;
- }
- shader = R_GetShaderByHandle( ent->e.customShader );
- R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 );
- break;
-
- case RT_MODEL:
- // we must set up parts of tr.or for model culling
- R_RotateForEntity( ent, &tr.viewParms, &tr.or );
-
- tr.currentModel = R_GetModelByHandle( ent->e.hModel );
- if (!tr.currentModel) {
- R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
- } else {
- switch ( tr.currentModel->type ) {
- case MOD_MESH:
- R_AddMD3Surfaces( ent );
- break;
- case MOD_MD4:
- R_AddAnimSurfaces( ent );
- break;
- case MOD_BRUSH:
- R_AddBrushModelSurfaces( ent );
- break;
- case MOD_BAD: // null model axis
- if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
- break;
- }
- shader = R_GetShaderByHandle( ent->e.customShader );
- R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
- break;
- default:
- ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
- break;
- }
- }
- break;
- default:
- ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
- }
- }
-
-}
-
-
-/*
-====================
-R_GenerateDrawSurfs
-====================
-*/
-void R_GenerateDrawSurfs( void ) {
- R_AddWorldSurfaces ();
-
- R_AddPolygonSurfaces();
-
- // set the projection matrix with the minimum zfar
- // now that we have the world bounded
- // this needs to be done before entities are
- // added, because they use the projection
- // matrix for lod calculation
- R_SetupProjection ();
-
- R_AddEntitySurfaces ();
-}
-
-/*
-================
-R_DebugPolygon
-================
-*/
-void R_DebugPolygon( int color, int numPoints, float *points ) {
- int i;
-
- GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
-
- // draw solid shade
-
- qglColor3f( color&1, (color>>1)&1, (color>>2)&1 );
- qglBegin( GL_POLYGON );
- for ( i = 0 ; i < numPoints ; i++ ) {
- qglVertex3fv( points + i * 3 );
- }
- qglEnd();
-
- // draw wireframe outline
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
- qglDepthRange( 0, 0 );
- qglColor3f( 1, 1, 1 );
- qglBegin( GL_POLYGON );
- for ( i = 0 ; i < numPoints ; i++ ) {
- qglVertex3fv( points + i * 3 );
- }
- qglEnd();
- qglDepthRange( 0, 1 );
-}
-
-/*
-====================
-R_DebugGraphics
-
-Visualization aid for movement clipping debugging
-====================
-*/
-void R_DebugGraphics( void ) {
- if ( !r_debugSurface->integer ) {
- return;
- }
-
- // the render thread can't make callbacks to the main thread
- R_SyncRenderThread();
-
- GL_Bind( tr.whiteImage);
- GL_Cull( CT_FRONT_SIDED );
- ri.CM_DrawDebugSurface( R_DebugPolygon );
-}
-
-
-/*
-================
-R_RenderView
-
-A view may be either the actual camera view,
-or a mirror / remote location
-================
-*/
-void R_RenderView (viewParms_t *parms) {
- int firstDrawSurf;
-
- if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
- return;
- }
-
- tr.viewCount++;
-
- tr.viewParms = *parms;
- tr.viewParms.frameSceneNum = tr.frameSceneNum;
- tr.viewParms.frameCount = tr.frameCount;
-
- firstDrawSurf = tr.refdef.numDrawSurfs;
-
- tr.viewCount++;
-
- // set viewParms.world
- R_RotateForViewer ();
-
- R_SetupFrustum ();
-
- R_GenerateDrawSurfs();
-
- R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
-
- // draw main system development information (surface outlines, etc)
- R_DebugGraphics();
-}
-
-
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_main.c -- main control flow for each frame + +#include "tr_local.h" + +trGlobals_t tr; + +static float s_flipMatrix[16] = { + // convert from our coordinate system (looking down X) + // to OpenGL's coordinate system (looking down -Z) + 0, 0, -1, 0, + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1 +}; + + +refimport_t ri; + +// entities that will have procedurally generated surfaces will just +// point at this for their sorting surface +surfaceType_t entitySurface = SF_ENTITY; + +/* +================= +R_CullLocalBox + +Returns CULL_IN, CULL_CLIP, or CULL_OUT +================= +*/ +int R_CullLocalBox (vec3_t bounds[2]) { + int i, j; + vec3_t transformed[8]; + float dists[8]; + vec3_t v; + cplane_t *frust; + int anyBack; + int front, back; + + if ( r_nocull->integer ) { + return CULL_CLIP; + } + + // transform into world space + for (i = 0 ; i < 8 ; i++) { + v[0] = bounds[i&1][0]; + v[1] = bounds[(i>>1)&1][1]; + v[2] = bounds[(i>>2)&1][2]; + + VectorCopy( tr.or.origin, transformed[i] ); + VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] ); + VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] ); + VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] ); + } + + // check against frustum planes + anyBack = 0; + for (i = 0 ; i < 4 ; i++) { + frust = &tr.viewParms.frustum[i]; + + front = back = 0; + for (j = 0 ; j < 8 ; j++) { + dists[j] = DotProduct(transformed[j], frust->normal); + if ( dists[j] > frust->dist ) { + front = 1; + if ( back ) { + break; // a point is in front + } + } else { + back = 1; + } + } + if ( !front ) { + // all points were behind one of the planes + return CULL_OUT; + } + anyBack |= back; + } + + if ( !anyBack ) { + return CULL_IN; // completely inside frustum + } + + return CULL_CLIP; // partially clipped +} + +/* +** R_CullLocalPointAndRadius +*/ +int R_CullLocalPointAndRadius( vec3_t pt, float radius ) +{ + vec3_t transformed; + + R_LocalPointToWorld( pt, transformed ); + + return R_CullPointAndRadius( transformed, radius ); +} + +/* +** R_CullPointAndRadius +*/ +int R_CullPointAndRadius( vec3_t pt, float radius ) +{ + int i; + float dist; + cplane_t *frust; + qboolean mightBeClipped = qfalse; + + if ( r_nocull->integer ) { + return CULL_CLIP; + } + + // check against frustum planes + for (i = 0 ; i < 4 ; i++) + { + frust = &tr.viewParms.frustum[i]; + + dist = DotProduct( pt, frust->normal) - frust->dist; + if ( dist < -radius ) + { + return CULL_OUT; + } + else if ( dist <= radius ) + { + mightBeClipped = qtrue; + } + } + + if ( mightBeClipped ) + { + return CULL_CLIP; + } + + return CULL_IN; // completely inside frustum +} + + +/* +================= +R_LocalNormalToWorld + +================= +*/ +void R_LocalNormalToWorld (vec3_t local, vec3_t world) { + world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0]; + world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1]; + world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2]; +} + +/* +================= +R_LocalPointToWorld + +================= +*/ +void R_LocalPointToWorld (vec3_t local, vec3_t world) { + world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0]; + world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1]; + world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2]; +} + +/* +================= +R_WorldToLocal + +================= +*/ +void R_WorldToLocal (vec3_t world, vec3_t local) { + local[0] = DotProduct(world, tr.or.axis[0]); + local[1] = DotProduct(world, tr.or.axis[1]); + local[2] = DotProduct(world, tr.or.axis[2]); +} + +/* +========================== +R_TransformModelToClip + +========================== +*/ +void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, + vec4_t eye, vec4_t dst ) { + int i; + + for ( i = 0 ; i < 4 ; i++ ) { + eye[i] = + src[0] * modelMatrix[ i + 0 * 4 ] + + src[1] * modelMatrix[ i + 1 * 4 ] + + src[2] * modelMatrix[ i + 2 * 4 ] + + 1 * modelMatrix[ i + 3 * 4 ]; + } + + for ( i = 0 ; i < 4 ; i++ ) { + dst[i] = + eye[0] * projectionMatrix[ i + 0 * 4 ] + + eye[1] * projectionMatrix[ i + 1 * 4 ] + + eye[2] * projectionMatrix[ i + 2 * 4 ] + + eye[3] * projectionMatrix[ i + 3 * 4 ]; + } +} + +/* +========================== +R_TransformClipToWindow + +========================== +*/ +void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) { + normalized[0] = clip[0] / clip[3]; + normalized[1] = clip[1] / clip[3]; + normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); + + window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth; + window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight; + window[2] = normalized[2]; + + window[0] = (int) ( window[0] + 0.5 ); + window[1] = (int) ( window[1] + 0.5 ); +} + + +/* +========================== +myGlMultMatrix + +========================== +*/ +void myGlMultMatrix( const float *a, const float *b, float *out ) { + int i, j; + + for ( i = 0 ; i < 4 ; i++ ) { + for ( j = 0 ; j < 4 ; j++ ) { + out[ i * 4 + j ] = + a [ i * 4 + 0 ] * b [ 0 * 4 + j ] + + a [ i * 4 + 1 ] * b [ 1 * 4 + j ] + + a [ i * 4 + 2 ] * b [ 2 * 4 + j ] + + a [ i * 4 + 3 ] * b [ 3 * 4 + j ]; + } + } +} + +/* +================= +R_RotateForEntity + +Generates an orientation for an entity and viewParms +Does NOT produce any GL calls +Called by both the front end and the back end +================= +*/ +void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, + orientationr_t *or ) { + float glMatrix[16]; + vec3_t delta; + float axisLength; + + if ( ent->e.reType != RT_MODEL ) { + *or = viewParms->world; + return; + } + + VectorCopy( ent->e.origin, or->origin ); + + VectorCopy( ent->e.axis[0], or->axis[0] ); + VectorCopy( ent->e.axis[1], or->axis[1] ); + VectorCopy( ent->e.axis[2], or->axis[2] ); + + glMatrix[0] = or->axis[0][0]; + glMatrix[4] = or->axis[1][0]; + glMatrix[8] = or->axis[2][0]; + glMatrix[12] = or->origin[0]; + + glMatrix[1] = or->axis[0][1]; + glMatrix[5] = or->axis[1][1]; + glMatrix[9] = or->axis[2][1]; + glMatrix[13] = or->origin[1]; + + glMatrix[2] = or->axis[0][2]; + glMatrix[6] = or->axis[1][2]; + glMatrix[10] = or->axis[2][2]; + glMatrix[14] = or->origin[2]; + + glMatrix[3] = 0; + glMatrix[7] = 0; + glMatrix[11] = 0; + glMatrix[15] = 1; + + myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix ); + + // calculate the viewer origin in the model's space + // needed for fog, specular, and environment mapping + VectorSubtract( viewParms->or.origin, or->origin, delta ); + + // compensate for scale in the axes if necessary + if ( ent->e.nonNormalizedAxes ) { + axisLength = VectorLength( ent->e.axis[0] ); + if ( !axisLength ) { + axisLength = 0; + } else { + axisLength = 1.0f / axisLength; + } + } else { + axisLength = 1.0f; + } + + or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength; + or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength; + or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; +} + +/* +================= +R_RotateForViewer + +Sets up the modelview matrix for a given viewParm +================= +*/ +void R_RotateForViewer (void) +{ + float viewerMatrix[16]; + vec3_t origin; + + Com_Memset (&tr.or, 0, sizeof(tr.or)); + tr.or.axis[0][0] = 1; + tr.or.axis[1][1] = 1; + tr.or.axis[2][2] = 1; + VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin); + + // transform by the camera placement + VectorCopy( tr.viewParms.or.origin, origin ); + + viewerMatrix[0] = tr.viewParms.or.axis[0][0]; + viewerMatrix[4] = tr.viewParms.or.axis[0][1]; + viewerMatrix[8] = tr.viewParms.or.axis[0][2]; + viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; + + viewerMatrix[1] = tr.viewParms.or.axis[1][0]; + viewerMatrix[5] = tr.viewParms.or.axis[1][1]; + viewerMatrix[9] = tr.viewParms.or.axis[1][2]; + viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; + + viewerMatrix[2] = tr.viewParms.or.axis[2][0]; + viewerMatrix[6] = tr.viewParms.or.axis[2][1]; + viewerMatrix[10] = tr.viewParms.or.axis[2][2]; + viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; + + viewerMatrix[3] = 0; + viewerMatrix[7] = 0; + viewerMatrix[11] = 0; + viewerMatrix[15] = 1; + + // convert from our coordinate system (looking down X) + // to OpenGL's coordinate system (looking down -Z) + myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix ); + + tr.viewParms.world = tr.or; + +} + +/* +** SetFarClip +*/ +static void SetFarClip( void ) +{ + float farthestCornerDistance = 0; + int i; + + // if not rendering the world (icons, menus, etc) + // set a 2k far clip plane + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + tr.viewParms.zFar = 2048; + return; + } + + // + // set far clipping planes dynamically + // + farthestCornerDistance = 0; + for ( i = 0; i < 8; i++ ) + { + vec3_t v; + vec3_t vecTo; + float distance; + + if ( i & 1 ) + { + v[0] = tr.viewParms.visBounds[0][0]; + } + else + { + v[0] = tr.viewParms.visBounds[1][0]; + } + + if ( i & 2 ) + { + v[1] = tr.viewParms.visBounds[0][1]; + } + else + { + v[1] = tr.viewParms.visBounds[1][1]; + } + + if ( i & 4 ) + { + v[2] = tr.viewParms.visBounds[0][2]; + } + else + { + v[2] = tr.viewParms.visBounds[1][2]; + } + + VectorSubtract( v, tr.viewParms.or.origin, vecTo ); + + distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2]; + + if ( distance > farthestCornerDistance ) + { + farthestCornerDistance = distance; + } + } + tr.viewParms.zFar = sqrt( farthestCornerDistance ); +} + + +/* +=============== +R_SetupProjection +=============== +*/ +void R_SetupProjection( void ) { + float xmin, xmax, ymin, ymax; + float width, height, depth; + float zNear, zFar; + + // dynamically compute far clip plane distance + SetFarClip(); + + // + // set up projection matrix + // + zNear = r_znear->value; + zFar = tr.viewParms.zFar; + + ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f ); + ymin = -ymax; + + xmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f ); + xmin = -xmax; + + width = xmax - xmin; + height = ymax - ymin; + depth = zFar - zNear; + + tr.viewParms.projectionMatrix[0] = 2 * zNear / width; + tr.viewParms.projectionMatrix[4] = 0; + tr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0 + tr.viewParms.projectionMatrix[12] = 0; + + tr.viewParms.projectionMatrix[1] = 0; + tr.viewParms.projectionMatrix[5] = 2 * zNear / height; + tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 + tr.viewParms.projectionMatrix[13] = 0; + + tr.viewParms.projectionMatrix[2] = 0; + tr.viewParms.projectionMatrix[6] = 0; + tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth; + tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth; + + tr.viewParms.projectionMatrix[3] = 0; + tr.viewParms.projectionMatrix[7] = 0; + tr.viewParms.projectionMatrix[11] = -1; + tr.viewParms.projectionMatrix[15] = 0; +} + +/* +================= +R_SetupFrustum + +Setup that culling frustum planes for the current view +================= +*/ +void R_SetupFrustum (void) { + int i; + float xs, xc; + float ang; + + ang = tr.viewParms.fovX / 180 * M_PI * 0.5f; + xs = sin( ang ); + xc = cos( ang ); + + VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[0].normal ); + VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[0].normal ); + + VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[1].normal ); + VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[1].normal ); + + ang = tr.viewParms.fovY / 180 * M_PI * 0.5f; + xs = sin( ang ); + xc = cos( ang ); + + VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[2].normal ); + VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[2].normal ); + + VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[3].normal ); + VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[3].normal ); + + for (i=0 ; i<4 ; i++) { + tr.viewParms.frustum[i].type = PLANE_NON_AXIAL; + tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.or.origin, tr.viewParms.frustum[i].normal); + SetPlaneSignbits( &tr.viewParms.frustum[i] ); + } +} + + +/* +================= +R_MirrorPoint +================= +*/ +void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { + int i; + vec3_t local; + vec3_t transformed; + float d; + + VectorSubtract( in, surface->origin, local ); + + VectorClear( transformed ); + for ( i = 0 ; i < 3 ; i++ ) { + d = DotProduct(local, surface->axis[i]); + VectorMA( transformed, d, camera->axis[i], transformed ); + } + + VectorAdd( transformed, camera->origin, out ); +} + +void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { + int i; + float d; + + VectorClear( out ); + for ( i = 0 ; i < 3 ; i++ ) { + d = DotProduct(in, surface->axis[i]); + VectorMA( out, d, camera->axis[i], out ); + } +} + + +/* +============= +R_PlaneForSurface +============= +*/ +void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { + srfTriangles_t *tri; + srfPoly_t *poly; + drawVert_t *v1, *v2, *v3; + vec4_t plane4; + + if (!surfType) { + Com_Memset (plane, 0, sizeof(*plane)); + plane->normal[0] = 1; + return; + } + switch (*surfType) { + case SF_FACE: + *plane = ((srfSurfaceFace_t *)surfType)->plane; + return; + case SF_TRIANGLES: + tri = (srfTriangles_t *)surfType; + v1 = tri->verts + tri->indexes[0]; + v2 = tri->verts + tri->indexes[1]; + v3 = tri->verts + tri->indexes[2]; + PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); + VectorCopy( plane4, plane->normal ); + plane->dist = plane4[3]; + return; + case SF_POLY: + poly = (srfPoly_t *)surfType; + PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz ); + VectorCopy( plane4, plane->normal ); + plane->dist = plane4[3]; + return; + default: + Com_Memset (plane, 0, sizeof(*plane)); + plane->normal[0] = 1; + return; + } +} + +/* +================= +R_GetPortalOrientation + +entityNum is the entity that the portal surface is a part of, which may +be moving and rotating. + +Returns qtrue if it should be mirrored +================= +*/ +qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, + orientation_t *surface, orientation_t *camera, + vec3_t pvsOrigin, qboolean *mirror ) { + int i; + cplane_t originalPlane, plane; + trRefEntity_t *e; + float d; + vec3_t transformed; + + // create plane axis for the portal we are seeing + R_PlaneForSurface( drawSurf->surface, &originalPlane ); + + // rotate the plane if necessary + if ( entityNum != ENTITYNUM_WORLD ) { + tr.currentEntityNum = entityNum; + tr.currentEntity = &tr.refdef.entities[entityNum]; + + // get the orientation of the entity + R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); + + // rotate the plane, but keep the non-rotated version for matching + // against the portalSurface entities + R_LocalNormalToWorld( originalPlane.normal, plane.normal ); + plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); + + // translate the original plane + originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); + } else { + plane = originalPlane; + } + + VectorCopy( plane.normal, surface->axis[0] ); + PerpendicularVector( surface->axis[1], surface->axis[0] ); + CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); + + // locate the portal entity closest to this plane. + // origin will be the origin of the portal, origin2 will be + // the origin of the camera + for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { + e = &tr.refdef.entities[i]; + if ( e->e.reType != RT_PORTALSURFACE ) { + continue; + } + + d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; + if ( d > 64 || d < -64) { + continue; + } + + // get the pvsOrigin from the entity + VectorCopy( e->e.oldorigin, pvsOrigin ); + + // if the entity is just a mirror, don't use as a camera point + if ( e->e.oldorigin[0] == e->e.origin[0] && + e->e.oldorigin[1] == e->e.origin[1] && + e->e.oldorigin[2] == e->e.origin[2] ) { + VectorScale( plane.normal, plane.dist, surface->origin ); + VectorCopy( surface->origin, camera->origin ); + VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); + VectorCopy( surface->axis[1], camera->axis[1] ); + VectorCopy( surface->axis[2], camera->axis[2] ); + + *mirror = qtrue; + return qtrue; + } + + // project the origin onto the surface plane to get + // an origin point we can rotate around + d = DotProduct( e->e.origin, plane.normal ) - plane.dist; + VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); + + // now get the camera origin and orientation + VectorCopy( e->e.oldorigin, camera->origin ); + AxisCopy( e->e.axis, camera->axis ); + VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); + VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); + + // optionally rotate + if ( e->e.oldframe ) { + // if a speed is specified + if ( e->e.frame ) { + // continuous rotate + d = (tr.refdef.time/1000.0f) * e->e.frame; + VectorCopy( camera->axis[1], transformed ); + RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); + CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); + } else { + // bobbing rotate, with skinNum being the rotation offset + d = sin( tr.refdef.time * 0.003f ); + d = e->e.skinNum + d * 4; + VectorCopy( camera->axis[1], transformed ); + RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); + CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); + } + } + else if ( e->e.skinNum ) { + d = e->e.skinNum; + VectorCopy( camera->axis[1], transformed ); + RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); + CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); + } + *mirror = qfalse; + return qtrue; + } + + // if we didn't locate a portal entity, don't render anything. + // We don't want to just treat it as a mirror, because without a + // portal entity the server won't have communicated a proper entity set + // in the snapshot + + // unfortunately, with local movement prediction it is easily possible + // to see a surface before the server has communicated the matching + // portal surface entity, so we don't want to print anything here... + + //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); + + return qfalse; +} + +static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) +{ + int i; + cplane_t originalPlane, plane; + trRefEntity_t *e; + float d; + + // create plane axis for the portal we are seeing + R_PlaneForSurface( drawSurf->surface, &originalPlane ); + + // rotate the plane if necessary + if ( entityNum != ENTITYNUM_WORLD ) + { + tr.currentEntityNum = entityNum; + tr.currentEntity = &tr.refdef.entities[entityNum]; + + // get the orientation of the entity + R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); + + // rotate the plane, but keep the non-rotated version for matching + // against the portalSurface entities + R_LocalNormalToWorld( originalPlane.normal, plane.normal ); + plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); + + // translate the original plane + originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); + } + else + { + plane = originalPlane; + } + + // locate the portal entity closest to this plane. + // origin will be the origin of the portal, origin2 will be + // the origin of the camera + for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) + { + e = &tr.refdef.entities[i]; + if ( e->e.reType != RT_PORTALSURFACE ) { + continue; + } + + d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; + if ( d > 64 || d < -64) { + continue; + } + + // if the entity is just a mirror, don't use as a camera point + if ( e->e.oldorigin[0] == e->e.origin[0] && + e->e.oldorigin[1] == e->e.origin[1] && + e->e.oldorigin[2] == e->e.origin[2] ) + { + return qtrue; + } + + return qfalse; + } + return qfalse; +} + +/* +** SurfIsOffscreen +** +** Determines if a surface is completely offscreen. +*/ +static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { + float shortest = 100000000; + int entityNum; + int numTriangles; + shader_t *shader; + int fogNum; + int dlighted; + vec4_t clip, eye; + int i; + unsigned int pointOr = 0; + unsigned int pointAnd = (unsigned int)~0; + + if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp! + return qfalse; + } + + R_RotateForViewer(); + + R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); + RB_BeginSurface( shader, fogNum ); + rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); + + assert( tess.numVertexes < 128 ); + + for ( i = 0; i < tess.numVertexes; i++ ) + { + int j; + unsigned int pointFlags = 0; + + R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); + + for ( j = 0; j < 3; j++ ) + { + if ( clip[j] >= clip[3] ) + { + pointFlags |= (1 << (j*2)); + } + else if ( clip[j] <= -clip[3] ) + { + pointFlags |= ( 1 << (j*2+1)); + } + } + pointAnd &= pointFlags; + pointOr |= pointFlags; + } + + // trivially reject + if ( pointAnd ) + { + return qtrue; + } + + // determine if this surface is backfaced and also determine the distance + // to the nearest vertex so we can cull based on portal range. Culling + // based on vertex distance isn't 100% correct (we should be checking for + // range to the surface), but it's good enough for the types of portals + // we have in the game right now. + numTriangles = tess.numIndexes / 3; + + for ( i = 0; i < tess.numIndexes; i += 3 ) + { + vec3_t normal; + float dot; + float len; + + VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); + + len = VectorLengthSquared( normal ); // lose the sqrt + if ( len < shortest ) + { + shortest = len; + } + + if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 ) + { + numTriangles--; + } + } + if ( !numTriangles ) + { + return qtrue; + } + + // mirrors can early out at this point, since we don't do a fade over distance + // with them (although we could) + if ( IsMirror( drawSurf, entityNum ) ) + { + return qfalse; + } + + if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) + { + return qtrue; + } + + return qfalse; +} + +/* +======================== +R_MirrorViewBySurface + +Returns qtrue if another view has been rendered +======================== +*/ +qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { + vec4_t clipDest[128]; + viewParms_t newParms; + viewParms_t oldParms; + orientation_t surface, camera; + + // don't recursively mirror + if (tr.viewParms.isPortal) { + ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); + return qfalse; + } + + if ( r_noportals->integer || (r_fastsky->integer == 1) ) { + return qfalse; + } + + // trivially reject portal/mirror + if ( SurfIsOffscreen( drawSurf, clipDest ) ) { + return qfalse; + } + + // save old viewParms so we can return to it after the mirror view + oldParms = tr.viewParms; + + newParms = tr.viewParms; + newParms.isPortal = qtrue; + if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, + newParms.pvsOrigin, &newParms.isMirror ) ) { + return qfalse; // bad portal, no portalentity + } + + R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); + + VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); + newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); + + R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); + R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); + R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); + + // OPTIMIZE: restrict the viewport on the mirrored view + + // render the mirror view + R_RenderView (&newParms); + + tr.viewParms = oldParms; + + return qtrue; +} + +/* +================= +R_SpriteFogNum + +See if a sprite is inside a fog volume +================= +*/ +int R_SpriteFogNum( trRefEntity_t *ent ) { + int i, j; + fog_t *fog; + + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + return 0; + } + + for ( i = 1 ; i < tr.world->numfogs ; i++ ) { + fog = &tr.world->fogs[i]; + for ( j = 0 ; j < 3 ; j++ ) { + if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) { + break; + } + if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) { + break; + } + } + if ( j == 3 ) { + return i; + } + } + + return 0; +} + +/* +========================================================================================== + +DRAWSURF SORTING + +========================================================================================== +*/ + +/* +================= +qsort replacement + +================= +*/ +#define SWAP_DRAW_SURF(a,b) temp=((int *)a)[0];((int *)a)[0]=((int *)b)[0];((int *)b)[0]=temp; temp=((int *)a)[1];((int *)a)[1]=((int *)b)[1];((int *)b)[1]=temp; + +/* this parameter defines the cutoff between using quick sort and + insertion sort for arrays; arrays with lengths shorter or equal to the + below value use insertion sort */ + +#define CUTOFF 8 /* testing shows that this is good value */ + +static void shortsort( drawSurf_t *lo, drawSurf_t *hi ) { + drawSurf_t *p, *max; + int temp; + + while (hi > lo) { + max = lo; + for (p = lo + 1; p <= hi; p++ ) { + if ( p->sort > max->sort ) { + max = p; + } + } + SWAP_DRAW_SURF(max, hi); + hi--; + } +} + + +/* sort the array between lo and hi (inclusive) +FIXME: this was lifted and modified from the microsoft lib source... + */ + +void qsortFast ( + void *base, + unsigned num, + unsigned width + ) +{ + char *lo, *hi; /* ends of sub-array currently sorting */ + char *mid; /* points to middle of subarray */ + char *loguy, *higuy; /* traveling pointers for partition step */ + unsigned size; /* size of the sub-array */ + char *lostk[30], *histk[30]; + int stkptr; /* stack for saving sub-array to be processed */ + int temp; + + if ( sizeof(drawSurf_t) != 8 ) { + ri.Error( ERR_DROP, "change SWAP_DRAW_SURF macro" ); + } + + /* Note: the number of stack entries required is no more than + 1 + log2(size), so 30 is sufficient for any array */ + + if (num < 2 || width == 0) + return; /* nothing to do */ + + stkptr = 0; /* initialize stack */ + + lo = base; + hi = (char *)base + width * (num-1); /* initialize limits */ + + /* this entry point is for pseudo-recursion calling: setting + lo and hi and jumping to here is like recursion, but stkptr is + prserved, locals aren't, so we preserve stuff on the stack */ +recurse: + + size = (hi - lo) / width + 1; /* number of el's to sort */ + + /* below a certain size, it is faster to use a O(n^2) sorting method */ + if (size <= CUTOFF) { + shortsort((drawSurf_t *)lo, (drawSurf_t *)hi); + } + else { + /* First we pick a partititioning element. The efficiency of the + algorithm demands that we find one that is approximately the + median of the values, but also that we select one fast. Using + the first one produces bad performace if the array is already + sorted, so we use the middle one, which would require a very + wierdly arranged array for worst case performance. Testing shows + that a median-of-three algorithm does not, in general, increase + performance. */ + + mid = lo + (size / 2) * width; /* find middle element */ + SWAP_DRAW_SURF(mid, lo); /* swap it to beginning of array */ + + /* We now wish to partition the array into three pieces, one + consisiting of elements <= partition element, one of elements + equal to the parition element, and one of element >= to it. This + is done below; comments indicate conditions established at every + step. */ + + loguy = lo; + higuy = hi + width; + + /* Note that higuy decreases and loguy increases on every iteration, + so loop must terminate. */ + for (;;) { + /* lo <= loguy < hi, lo < higuy <= hi + 1, + A[i] <= A[lo] for lo <= i <= loguy, + A[i] >= A[lo] for higuy <= i <= hi */ + + do { + loguy += width; + } while (loguy <= hi && + ( ((drawSurf_t *)loguy)->sort <= ((drawSurf_t *)lo)->sort ) ); + + /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy, + either loguy > hi or A[loguy] > A[lo] */ + + do { + higuy -= width; + } while (higuy > lo && + ( ((drawSurf_t *)higuy)->sort >= ((drawSurf_t *)lo)->sort ) ); + + /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi, + either higuy <= lo or A[higuy] < A[lo] */ + + if (higuy < loguy) + break; + + /* if loguy > hi or higuy <= lo, then we would have exited, so + A[loguy] > A[lo], A[higuy] < A[lo], + loguy < hi, highy > lo */ + + SWAP_DRAW_SURF(loguy, higuy); + + /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top + of loop is re-established */ + } + + /* A[i] >= A[lo] for higuy < i <= hi, + A[i] <= A[lo] for lo <= i < loguy, + higuy < loguy, lo <= higuy <= hi + implying: + A[i] >= A[lo] for loguy <= i <= hi, + A[i] <= A[lo] for lo <= i <= higuy, + A[i] = A[lo] for higuy < i < loguy */ + + SWAP_DRAW_SURF(lo, higuy); /* put partition element in place */ + + /* OK, now we have the following: + A[i] >= A[higuy] for loguy <= i <= hi, + A[i] <= A[higuy] for lo <= i < higuy + A[i] = A[lo] for higuy <= i < loguy */ + + /* We've finished the partition, now we want to sort the subarrays + [lo, higuy-1] and [loguy, hi]. + We do the smaller one first to minimize stack usage. + We only sort arrays of length 2 or more.*/ + + if ( higuy - 1 - lo >= hi - loguy ) { + if (lo + width < higuy) { + lostk[stkptr] = lo; + histk[stkptr] = higuy - width; + ++stkptr; + } /* save big recursion for later */ + + if (loguy < hi) { + lo = loguy; + goto recurse; /* do small recursion */ + } + } + else { + if (loguy < hi) { + lostk[stkptr] = loguy; + histk[stkptr] = hi; + ++stkptr; /* save big recursion for later */ + } + + if (lo + width < higuy) { + hi = higuy - width; + goto recurse; /* do small recursion */ + } + } + } + + /* We have sorted the array, except for any pending sorts on the stack. + Check if there are any, and do them. */ + + --stkptr; + if (stkptr >= 0) { + lo = lostk[stkptr]; + hi = histk[stkptr]; + goto recurse; /* pop subarray from stack */ + } + else + return; /* all subarrays done */ +} + + +//========================================================================================== + +/* +================= +R_AddDrawSurf +================= +*/ +void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, + int fogIndex, int dlightMap ) { + int index; + + // instead of checking for overflow, we just mask the index + // so it wraps around + index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; + // the sort data is packed into a single 32 bit value so it can be + // compared quickly during the qsorting process + tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) + | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; + tr.refdef.drawSurfs[index].surface = surface; + tr.refdef.numDrawSurfs++; +} + +/* +================= +R_DecomposeSort +================= +*/ +void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, + int *fogNum, int *dlightMap ) { + *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; + *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; + *entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & 1023; + *dlightMap = sort & 3; +} + +/* +================= +R_SortDrawSurfs +================= +*/ +void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { + shader_t *shader; + int fogNum; + int entityNum; + int dlighted; + int i; + + // it is possible for some views to not have any surfaces + if ( numDrawSurfs < 1 ) { + // we still need to add it for hyperspace cases + R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); + return; + } + + // if we overflowed MAX_DRAWSURFS, the drawsurfs + // wrapped around in the buffer and we will be missing + // the first surfaces, not the last ones + if ( numDrawSurfs > MAX_DRAWSURFS ) { + numDrawSurfs = MAX_DRAWSURFS; + } + + // sort the drawsurfs by sort type, then orientation, then shader + qsortFast (drawSurfs, numDrawSurfs, sizeof(drawSurf_t) ); + + // check for any pass through drawing, which + // may cause another view to be rendered first + for ( i = 0 ; i < numDrawSurfs ; i++ ) { + R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted ); + + if ( shader->sort > SS_PORTAL ) { + break; + } + + // no shader should ever have this sort type + if ( shader->sort == SS_BAD ) { + ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); + } + + // if the mirror was completely clipped away, we may need to check another surface + if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { + // this is a debug option to see exactly what is being mirrored + if ( r_portalOnly->integer ) { + return; + } + break; // only one mirror view at a time + } + } + + R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); +} + +/* +============= +R_AddEntitySurfaces +============= +*/ +void R_AddEntitySurfaces (void) { + trRefEntity_t *ent; + shader_t *shader; + + if ( !r_drawentities->integer ) { + return; + } + + for ( tr.currentEntityNum = 0; + tr.currentEntityNum < tr.refdef.num_entities; + tr.currentEntityNum++ ) { + ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; + + ent->needDlights = qfalse; + + // preshift the value we are going to OR into the drawsurf sort + tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; + + // + // the weapon model must be handled special -- + // we don't want the hacked weapon position showing in + // mirrors, because the true body position will already be drawn + // + if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) { + continue; + } + + // simple generated models, like sprites and beams, are not culled + switch ( ent->e.reType ) { + case RT_PORTALSURFACE: + break; // don't draw anything + case RT_SPRITE: + case RT_BEAM: + case RT_LIGHTNING: + case RT_RAIL_CORE: + case RT_RAIL_RINGS: + // self blood sprites, talk balloons, etc should not be drawn in the primary + // view. We can't just do this check for all entities, because md3 + // entities may still want to cast shadows from them + if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { + continue; + } + shader = R_GetShaderByHandle( ent->e.customShader ); + R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 ); + break; + + case RT_MODEL: + // we must set up parts of tr.or for model culling + R_RotateForEntity( ent, &tr.viewParms, &tr.or ); + + tr.currentModel = R_GetModelByHandle( ent->e.hModel ); + if (!tr.currentModel) { + R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); + } else { + switch ( tr.currentModel->type ) { + case MOD_MESH: + R_AddMD3Surfaces( ent ); + break; + case MOD_MD4: + R_AddAnimSurfaces( ent ); + break; + case MOD_BRUSH: + R_AddBrushModelSurfaces( ent ); + break; + case MOD_BAD: // null model axis + if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { + break; + } + shader = R_GetShaderByHandle( ent->e.customShader ); + R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); + break; + default: + ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); + break; + } + } + break; + default: + ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); + } + } + +} + + +/* +==================== +R_GenerateDrawSurfs +==================== +*/ +void R_GenerateDrawSurfs( void ) { + R_AddWorldSurfaces (); + + R_AddPolygonSurfaces(); + + // set the projection matrix with the minimum zfar + // now that we have the world bounded + // this needs to be done before entities are + // added, because they use the projection + // matrix for lod calculation + R_SetupProjection (); + + R_AddEntitySurfaces (); +} + +/* +================ +R_DebugPolygon +================ +*/ +void R_DebugPolygon( int color, int numPoints, float *points ) { + int i; + + GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); + + // draw solid shade + + qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); + qglBegin( GL_POLYGON ); + for ( i = 0 ; i < numPoints ; i++ ) { + qglVertex3fv( points + i * 3 ); + } + qglEnd(); + + // draw wireframe outline + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); + qglDepthRange( 0, 0 ); + qglColor3f( 1, 1, 1 ); + qglBegin( GL_POLYGON ); + for ( i = 0 ; i < numPoints ; i++ ) { + qglVertex3fv( points + i * 3 ); + } + qglEnd(); + qglDepthRange( 0, 1 ); +} + +/* +==================== +R_DebugGraphics + +Visualization aid for movement clipping debugging +==================== +*/ +void R_DebugGraphics( void ) { + if ( !r_debugSurface->integer ) { + return; + } + + // the render thread can't make callbacks to the main thread + R_SyncRenderThread(); + + GL_Bind( tr.whiteImage); + GL_Cull( CT_FRONT_SIDED ); + ri.CM_DrawDebugSurface( R_DebugPolygon ); +} + + +/* +================ +R_RenderView + +A view may be either the actual camera view, +or a mirror / remote location +================ +*/ +void R_RenderView (viewParms_t *parms) { + int firstDrawSurf; + + if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { + return; + } + + tr.viewCount++; + + tr.viewParms = *parms; + tr.viewParms.frameSceneNum = tr.frameSceneNum; + tr.viewParms.frameCount = tr.frameCount; + + firstDrawSurf = tr.refdef.numDrawSurfs; + + tr.viewCount++; + + // set viewParms.world + R_RotateForViewer (); + + R_SetupFrustum (); + + R_GenerateDrawSurfs(); + + R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); + + // draw main system development information (surface outlines, etc) + R_DebugGraphics(); +} + + + diff --git a/code/renderer/tr_marks.c b/code/renderer/tr_marks.c index f5f6e97..9d1c254 100755 --- a/code/renderer/tr_marks.c +++ b/code/renderer/tr_marks.c @@ -1,443 +1,443 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_marks.c -- polygon projection on the world polygons
-
-#include "tr_local.h"
-//#include "assert.h"
-
-#define MAX_VERTS_ON_POLY 64
-
-#define MARKER_OFFSET 0 // 1
-
-/*
-=============
-R_ChopPolyBehindPlane
-
-Out must have space for two more vertexes than in
-=============
-*/
-#define SIDE_FRONT 0
-#define SIDE_BACK 1
-#define SIDE_ON 2
-static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
- int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
- vec3_t normal, vec_t dist, vec_t epsilon) {
- float dists[MAX_VERTS_ON_POLY+4];
- int sides[MAX_VERTS_ON_POLY+4];
- int counts[3];
- float dot;
- int i, j;
- float *p1, *p2, *clip;
- float d;
-
- // don't clip if it might overflow
- if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
- *numOutPoints = 0;
- return;
- }
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for ( i = 0 ; i < numInPoints ; i++ ) {
- dot = DotProduct( inPoints[i], normal );
- dot -= dist;
- dists[i] = dot;
- if ( dot > epsilon ) {
- sides[i] = SIDE_FRONT;
- } else if ( dot < -epsilon ) {
- sides[i] = SIDE_BACK;
- } else {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *numOutPoints = 0;
-
- if ( !counts[0] ) {
- return;
- }
- if ( !counts[1] ) {
- *numOutPoints = numInPoints;
- Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
- return;
- }
-
- for ( i = 0 ; i < numInPoints ; i++ ) {
- p1 = inPoints[i];
- clip = outPoints[ *numOutPoints ];
-
- if ( sides[i] == SIDE_ON ) {
- VectorCopy( p1, clip );
- (*numOutPoints)++;
- continue;
- }
-
- if ( sides[i] == SIDE_FRONT ) {
- VectorCopy( p1, clip );
- (*numOutPoints)++;
- clip = outPoints[ *numOutPoints ];
- }
-
- if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
- continue;
- }
-
- // generate a split point
- p2 = inPoints[ (i+1) % numInPoints ];
-
- d = dists[i] - dists[i+1];
- if ( d == 0 ) {
- dot = 0;
- } else {
- dot = dists[i] / d;
- }
-
- // clip xyz
-
- for (j=0 ; j<3 ; j++) {
- clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
- }
-
- (*numOutPoints)++;
- }
-}
-
-/*
-=================
-R_BoxSurfaces_r
-
-=================
-*/
-void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
-
- int s, c;
- msurface_t *surf, **mark;
-
- // do the tail recursion in a loop
- while ( node->contents == -1 ) {
- s = BoxOnPlaneSide( mins, maxs, node->plane );
- if (s == 1) {
- node = node->children[0];
- } else if (s == 2) {
- node = node->children[1];
- } else {
- R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
- node = node->children[1];
- }
- }
-
- // add the individual surfaces
- mark = node->firstmarksurface;
- c = node->nummarksurfaces;
- while (c--) {
- //
- if (*listlength >= listsize) break;
- //
- surf = *mark;
- // check if the surface has NOIMPACT or NOMARKS set
- if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
- || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
- surf->viewCount = tr.viewCount;
- }
- // extra check for surfaces to avoid list overflows
- else if (*(surf->data) == SF_FACE) {
- // the face plane should go through the box
- s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
- if (s == 1 || s == 2) {
- surf->viewCount = tr.viewCount;
- } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
- // don't add faces that make sharp angles with the projection direction
- surf->viewCount = tr.viewCount;
- }
- }
- else if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount;
- // check the viewCount because the surface may have
- // already been added if it spans multiple leafs
- if (surf->viewCount != tr.viewCount) {
- surf->viewCount = tr.viewCount;
- list[*listlength] = (surfaceType_t *) surf->data;
- (*listlength)++;
- }
- mark++;
- }
-}
-
-/*
-=================
-R_AddMarkFragments
-
-=================
-*/
-void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
- int numPlanes, vec3_t *normals, float *dists,
- int maxPoints, vec3_t pointBuffer,
- int maxFragments, markFragment_t *fragmentBuffer,
- int *returnedPoints, int *returnedFragments,
- vec3_t mins, vec3_t maxs) {
- int pingPong, i;
- markFragment_t *mf;
-
- // chop the surface by all the bounding planes of the to be projected polygon
- pingPong = 0;
-
- for ( i = 0 ; i < numPlanes ; i++ ) {
-
- R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
- &numClipPoints, clipPoints[!pingPong],
- normals[i], dists[i], 0.5 );
- pingPong ^= 1;
- if ( numClipPoints == 0 ) {
- break;
- }
- }
- // completely clipped away?
- if ( numClipPoints == 0 ) {
- return;
- }
-
- // add this fragment to the returned list
- if ( numClipPoints + (*returnedPoints) > maxPoints ) {
- return; // not enough space for this polygon
- }
- /*
- // all the clip points should be within the bounding box
- for ( i = 0 ; i < numClipPoints ; i++ ) {
- int j;
- for ( j = 0 ; j < 3 ; j++ ) {
- if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
- if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
- }
- if (j < 3) break;
- }
- if (i < numClipPoints) return;
- */
-
- mf = fragmentBuffer + (*returnedFragments);
- mf->firstPoint = (*returnedPoints);
- mf->numPoints = numClipPoints;
- Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
-
- (*returnedPoints) += numClipPoints;
- (*returnedFragments)++;
-}
-
-/*
-=================
-R_MarkFragments
-
-=================
-*/
-int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
- int numsurfaces, numPlanes;
- int i, j, k, m, n;
- surfaceType_t *surfaces[64];
- vec3_t mins, maxs;
- int returnedFragments;
- int returnedPoints;
- vec3_t normals[MAX_VERTS_ON_POLY+2];
- float dists[MAX_VERTS_ON_POLY+2];
- vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
- int numClipPoints;
- float *v;
- srfSurfaceFace_t *surf;
- srfGridMesh_t *cv;
- drawVert_t *dv;
- vec3_t normal;
- vec3_t projectionDir;
- vec3_t v1, v2;
- int *indexes;
-
- //increment view count for double check prevention
- tr.viewCount++;
-
- //
- VectorNormalize2( projection, projectionDir );
- // find all the brushes that are to be considered
- ClearBounds( mins, maxs );
- for ( i = 0 ; i < numPoints ; i++ ) {
- vec3_t temp;
-
- AddPointToBounds( points[i], mins, maxs );
- VectorAdd( points[i], projection, temp );
- AddPointToBounds( temp, mins, maxs );
- // make sure we get all the leafs (also the one(s) in front of the hit surface)
- VectorMA( points[i], -20, projectionDir, temp );
- AddPointToBounds( temp, mins, maxs );
- }
-
- if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
- // create the bounding planes for the to be projected polygon
- for ( i = 0 ; i < numPoints ; i++ ) {
- VectorSubtract(points[(i+1)%numPoints], points[i], v1);
- VectorAdd(points[i], projection, v2);
- VectorSubtract(points[i], v2, v2);
- CrossProduct(v1, v2, normals[i]);
- VectorNormalizeFast(normals[i]);
- dists[i] = DotProduct(normals[i], points[i]);
- }
- // add near and far clipping planes for projection
- VectorCopy(projectionDir, normals[numPoints]);
- dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
- VectorCopy(projectionDir, normals[numPoints+1]);
- VectorInverse(normals[numPoints+1]);
- dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
- numPlanes = numPoints + 2;
-
- numsurfaces = 0;
- R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
- //assert(numsurfaces <= 64);
- //assert(numsurfaces != 64);
-
- returnedPoints = 0;
- returnedFragments = 0;
-
- for ( i = 0 ; i < numsurfaces ; i++ ) {
-
- if (*surfaces[i] == SF_GRID) {
-
- cv = (srfGridMesh_t *) surfaces[i];
- for ( m = 0 ; m < cv->height - 1 ; m++ ) {
- for ( n = 0 ; n < cv->width - 1 ; n++ ) {
- // We triangulate the grid and chop all triangles within
- // the bounding planes of the to be projected polygon.
- // LOD is not taken into account, not such a big deal though.
- //
- // It's probably much nicer to chop the grid itself and deal
- // with this grid as a normal SF_GRID surface so LOD will
- // be applied. However the LOD of that chopped grid must
- // be synced with the LOD of the original curve.
- // One way to do this; the chopped grid shares vertices with
- // the original curve. When LOD is applied to the original
- // curve the unused vertices are flagged. Now the chopped curve
- // should skip the flagged vertices. This still leaves the
- // problems with the vertices at the chopped grid edges.
- //
- // To avoid issues when LOD applied to "hollow curves" (like
- // the ones around many jump pads) we now just add a 2 unit
- // offset to the triangle vertices.
- // The offset is added in the vertex normal vector direction
- // so all triangles will still fit together.
- // The 2 unit offset should avoid pretty much all LOD problems.
-
- numClipPoints = 3;
-
- dv = cv->verts + m * cv->width + n;
-
- VectorCopy(dv[0].xyz, clipPoints[0][0]);
- VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
- VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
- VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
- VectorCopy(dv[1].xyz, clipPoints[0][2]);
- VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
- // check the normal of this triangle
- VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
- VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
- CrossProduct(v1, v2, normal);
- VectorNormalizeFast(normal);
- if (DotProduct(normal, projectionDir) < -0.1) {
- // add the fragments of this triangle
- R_AddMarkFragments(numClipPoints, clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer,
- &returnedPoints, &returnedFragments, mins, maxs);
-
- if ( returnedFragments == maxFragments ) {
- return returnedFragments; // not enough space for more fragments
- }
- }
-
- VectorCopy(dv[1].xyz, clipPoints[0][0]);
- VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
- VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
- VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
- VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
- VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
- // check the normal of this triangle
- VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
- VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
- CrossProduct(v1, v2, normal);
- VectorNormalizeFast(normal);
- if (DotProduct(normal, projectionDir) < -0.05) {
- // add the fragments of this triangle
- R_AddMarkFragments(numClipPoints, clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer,
- &returnedPoints, &returnedFragments, mins, maxs);
-
- if ( returnedFragments == maxFragments ) {
- return returnedFragments; // not enough space for more fragments
- }
- }
- }
- }
- }
- else if (*surfaces[i] == SF_FACE) {
-
- surf = ( srfSurfaceFace_t * ) surfaces[i];
- // check the normal of this face
- if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
- continue;
- }
-
- /*
- VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
- VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
- CrossProduct(v1, v2, normal);
- VectorNormalize(normal);
- if (DotProduct(normal, projectionDir) > -0.5) continue;
- */
- indexes = (int *)( (byte *)surf + surf->ofsIndices );
- for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
- VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
- }
- // add the fragments of this face
- R_AddMarkFragments( 3 , clipPoints,
- numPlanes, normals, dists,
- maxPoints, pointBuffer,
- maxFragments, fragmentBuffer,
- &returnedPoints, &returnedFragments, mins, maxs);
- if ( returnedFragments == maxFragments ) {
- return returnedFragments; // not enough space for more fragments
- }
- }
- continue;
- }
- else {
- // ignore all other world surfaces
- // might be cool to also project polygons on a triangle soup
- // however this will probably create huge amounts of extra polys
- // even more than the projection onto curves
- continue;
- }
- }
- return returnedFragments;
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_marks.c -- polygon projection on the world polygons + +#include "tr_local.h" +//#include "assert.h" + +#define MAX_VERTS_ON_POLY 64 + +#define MARKER_OFFSET 0 // 1 + +/* +============= +R_ChopPolyBehindPlane + +Out must have space for two more vertexes than in +============= +*/ +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 +static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], + int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], + vec3_t normal, vec_t dist, vec_t epsilon) { + float dists[MAX_VERTS_ON_POLY+4]; + int sides[MAX_VERTS_ON_POLY+4]; + int counts[3]; + float dot; + int i, j; + float *p1, *p2, *clip; + float d; + + // don't clip if it might overflow + if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { + *numOutPoints = 0; + return; + } + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for ( i = 0 ; i < numInPoints ; i++ ) { + dot = DotProduct( inPoints[i], normal ); + dot -= dist; + dists[i] = dot; + if ( dot > epsilon ) { + sides[i] = SIDE_FRONT; + } else if ( dot < -epsilon ) { + sides[i] = SIDE_BACK; + } else { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *numOutPoints = 0; + + if ( !counts[0] ) { + return; + } + if ( !counts[1] ) { + *numOutPoints = numInPoints; + Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) ); + return; + } + + for ( i = 0 ; i < numInPoints ; i++ ) { + p1 = inPoints[i]; + clip = outPoints[ *numOutPoints ]; + + if ( sides[i] == SIDE_ON ) { + VectorCopy( p1, clip ); + (*numOutPoints)++; + continue; + } + + if ( sides[i] == SIDE_FRONT ) { + VectorCopy( p1, clip ); + (*numOutPoints)++; + clip = outPoints[ *numOutPoints ]; + } + + if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { + continue; + } + + // generate a split point + p2 = inPoints[ (i+1) % numInPoints ]; + + d = dists[i] - dists[i+1]; + if ( d == 0 ) { + dot = 0; + } else { + dot = dists[i] / d; + } + + // clip xyz + + for (j=0 ; j<3 ; j++) { + clip[j] = p1[j] + dot * ( p2[j] - p1[j] ); + } + + (*numOutPoints)++; + } +} + +/* +================= +R_BoxSurfaces_r + +================= +*/ +void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { + + int s, c; + msurface_t *surf, **mark; + + // do the tail recursion in a loop + while ( node->contents == -1 ) { + s = BoxOnPlaneSide( mins, maxs, node->plane ); + if (s == 1) { + node = node->children[0]; + } else if (s == 2) { + node = node->children[1]; + } else { + R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); + node = node->children[1]; + } + } + + // add the individual surfaces + mark = node->firstmarksurface; + c = node->nummarksurfaces; + while (c--) { + // + if (*listlength >= listsize) break; + // + surf = *mark; + // check if the surface has NOIMPACT or NOMARKS set + if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) + || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { + surf->viewCount = tr.viewCount; + } + // extra check for surfaces to avoid list overflows + else if (*(surf->data) == SF_FACE) { + // the face plane should go through the box + s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane ); + if (s == 1 || s == 2) { + surf->viewCount = tr.viewCount; + } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) { + // don't add faces that make sharp angles with the projection direction + surf->viewCount = tr.viewCount; + } + } + else if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount; + // check the viewCount because the surface may have + // already been added if it spans multiple leafs + if (surf->viewCount != tr.viewCount) { + surf->viewCount = tr.viewCount; + list[*listlength] = (surfaceType_t *) surf->data; + (*listlength)++; + } + mark++; + } +} + +/* +================= +R_AddMarkFragments + +================= +*/ +void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY], + int numPlanes, vec3_t *normals, float *dists, + int maxPoints, vec3_t pointBuffer, + int maxFragments, markFragment_t *fragmentBuffer, + int *returnedPoints, int *returnedFragments, + vec3_t mins, vec3_t maxs) { + int pingPong, i; + markFragment_t *mf; + + // chop the surface by all the bounding planes of the to be projected polygon + pingPong = 0; + + for ( i = 0 ; i < numPlanes ; i++ ) { + + R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong], + &numClipPoints, clipPoints[!pingPong], + normals[i], dists[i], 0.5 ); + pingPong ^= 1; + if ( numClipPoints == 0 ) { + break; + } + } + // completely clipped away? + if ( numClipPoints == 0 ) { + return; + } + + // add this fragment to the returned list + if ( numClipPoints + (*returnedPoints) > maxPoints ) { + return; // not enough space for this polygon + } + /* + // all the clip points should be within the bounding box + for ( i = 0 ; i < numClipPoints ; i++ ) { + int j; + for ( j = 0 ; j < 3 ; j++ ) { + if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break; + if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break; + } + if (j < 3) break; + } + if (i < numClipPoints) return; + */ + + mf = fragmentBuffer + (*returnedFragments); + mf->firstPoint = (*returnedPoints); + mf->numPoints = numClipPoints; + Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) ); + + (*returnedPoints) += numClipPoints; + (*returnedFragments)++; +} + +/* +================= +R_MarkFragments + +================= +*/ +int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, + int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { + int numsurfaces, numPlanes; + int i, j, k, m, n; + surfaceType_t *surfaces[64]; + vec3_t mins, maxs; + int returnedFragments; + int returnedPoints; + vec3_t normals[MAX_VERTS_ON_POLY+2]; + float dists[MAX_VERTS_ON_POLY+2]; + vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; + int numClipPoints; + float *v; + srfSurfaceFace_t *surf; + srfGridMesh_t *cv; + drawVert_t *dv; + vec3_t normal; + vec3_t projectionDir; + vec3_t v1, v2; + int *indexes; + + //increment view count for double check prevention + tr.viewCount++; + + // + VectorNormalize2( projection, projectionDir ); + // find all the brushes that are to be considered + ClearBounds( mins, maxs ); + for ( i = 0 ; i < numPoints ; i++ ) { + vec3_t temp; + + AddPointToBounds( points[i], mins, maxs ); + VectorAdd( points[i], projection, temp ); + AddPointToBounds( temp, mins, maxs ); + // make sure we get all the leafs (also the one(s) in front of the hit surface) + VectorMA( points[i], -20, projectionDir, temp ); + AddPointToBounds( temp, mins, maxs ); + } + + if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; + // create the bounding planes for the to be projected polygon + for ( i = 0 ; i < numPoints ; i++ ) { + VectorSubtract(points[(i+1)%numPoints], points[i], v1); + VectorAdd(points[i], projection, v2); + VectorSubtract(points[i], v2, v2); + CrossProduct(v1, v2, normals[i]); + VectorNormalizeFast(normals[i]); + dists[i] = DotProduct(normals[i], points[i]); + } + // add near and far clipping planes for projection + VectorCopy(projectionDir, normals[numPoints]); + dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; + VectorCopy(projectionDir, normals[numPoints+1]); + VectorInverse(normals[numPoints+1]); + dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; + numPlanes = numPoints + 2; + + numsurfaces = 0; + R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); + //assert(numsurfaces <= 64); + //assert(numsurfaces != 64); + + returnedPoints = 0; + returnedFragments = 0; + + for ( i = 0 ; i < numsurfaces ; i++ ) { + + if (*surfaces[i] == SF_GRID) { + + cv = (srfGridMesh_t *) surfaces[i]; + for ( m = 0 ; m < cv->height - 1 ; m++ ) { + for ( n = 0 ; n < cv->width - 1 ; n++ ) { + // We triangulate the grid and chop all triangles within + // the bounding planes of the to be projected polygon. + // LOD is not taken into account, not such a big deal though. + // + // It's probably much nicer to chop the grid itself and deal + // with this grid as a normal SF_GRID surface so LOD will + // be applied. However the LOD of that chopped grid must + // be synced with the LOD of the original curve. + // One way to do this; the chopped grid shares vertices with + // the original curve. When LOD is applied to the original + // curve the unused vertices are flagged. Now the chopped curve + // should skip the flagged vertices. This still leaves the + // problems with the vertices at the chopped grid edges. + // + // To avoid issues when LOD applied to "hollow curves" (like + // the ones around many jump pads) we now just add a 2 unit + // offset to the triangle vertices. + // The offset is added in the vertex normal vector direction + // so all triangles will still fit together. + // The 2 unit offset should avoid pretty much all LOD problems. + + numClipPoints = 3; + + dv = cv->verts + m * cv->width + n; + + VectorCopy(dv[0].xyz, clipPoints[0][0]); + VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); + VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); + VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); + VectorCopy(dv[1].xyz, clipPoints[0][2]); + VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); + // check the normal of this triangle + VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); + VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); + CrossProduct(v1, v2, normal); + VectorNormalizeFast(normal); + if (DotProduct(normal, projectionDir) < -0.1) { + // add the fragments of this triangle + R_AddMarkFragments(numClipPoints, clipPoints, + numPlanes, normals, dists, + maxPoints, pointBuffer, + maxFragments, fragmentBuffer, + &returnedPoints, &returnedFragments, mins, maxs); + + if ( returnedFragments == maxFragments ) { + return returnedFragments; // not enough space for more fragments + } + } + + VectorCopy(dv[1].xyz, clipPoints[0][0]); + VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); + VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); + VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); + VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); + VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); + // check the normal of this triangle + VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); + VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); + CrossProduct(v1, v2, normal); + VectorNormalizeFast(normal); + if (DotProduct(normal, projectionDir) < -0.05) { + // add the fragments of this triangle + R_AddMarkFragments(numClipPoints, clipPoints, + numPlanes, normals, dists, + maxPoints, pointBuffer, + maxFragments, fragmentBuffer, + &returnedPoints, &returnedFragments, mins, maxs); + + if ( returnedFragments == maxFragments ) { + return returnedFragments; // not enough space for more fragments + } + } + } + } + } + else if (*surfaces[i] == SF_FACE) { + + surf = ( srfSurfaceFace_t * ) surfaces[i]; + // check the normal of this face + if (DotProduct(surf->plane.normal, projectionDir) > -0.5) { + continue; + } + + /* + VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); + VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); + CrossProduct(v1, v2, normal); + VectorNormalize(normal); + if (DotProduct(normal, projectionDir) > -0.5) continue; + */ + indexes = (int *)( (byte *)surf + surf->ofsIndices ); + for ( k = 0 ; k < surf->numIndices ; k += 3 ) { + for ( j = 0 ; j < 3 ; j++ ) { + v = surf->points[0] + VERTEXSIZE * indexes[k+j];; + VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); + } + // add the fragments of this face + R_AddMarkFragments( 3 , clipPoints, + numPlanes, normals, dists, + maxPoints, pointBuffer, + maxFragments, fragmentBuffer, + &returnedPoints, &returnedFragments, mins, maxs); + if ( returnedFragments == maxFragments ) { + return returnedFragments; // not enough space for more fragments + } + } + continue; + } + else { + // ignore all other world surfaces + // might be cool to also project polygons on a triangle soup + // however this will probably create huge amounts of extra polys + // even more than the projection onto curves + continue; + } + } + return returnedFragments; +} + diff --git a/code/renderer/tr_mesh.c b/code/renderer/tr_mesh.c index 82f9f0c..155b4e6 100755 --- a/code/renderer/tr_mesh.c +++ b/code/renderer/tr_mesh.c @@ -1,397 +1,397 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_mesh.c: triangle model functions
-
-#include "tr_local.h"
-
-static float ProjectRadius( float r, vec3_t location )
-{
- float pr;
- float dist;
- float c;
- vec3_t p;
- float projected[4];
-
- c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin );
- dist = DotProduct( tr.viewParms.or.axis[0], location ) - c;
-
- if ( dist <= 0 )
- return 0;
-
- p[0] = 0;
- p[1] = fabs( r );
- p[2] = -dist;
-
- projected[0] = p[0] * tr.viewParms.projectionMatrix[0] +
- p[1] * tr.viewParms.projectionMatrix[4] +
- p[2] * tr.viewParms.projectionMatrix[8] +
- tr.viewParms.projectionMatrix[12];
-
- projected[1] = p[0] * tr.viewParms.projectionMatrix[1] +
- p[1] * tr.viewParms.projectionMatrix[5] +
- p[2] * tr.viewParms.projectionMatrix[9] +
- tr.viewParms.projectionMatrix[13];
-
- projected[2] = p[0] * tr.viewParms.projectionMatrix[2] +
- p[1] * tr.viewParms.projectionMatrix[6] +
- p[2] * tr.viewParms.projectionMatrix[10] +
- tr.viewParms.projectionMatrix[14];
-
- projected[3] = p[0] * tr.viewParms.projectionMatrix[3] +
- p[1] * tr.viewParms.projectionMatrix[7] +
- p[2] * tr.viewParms.projectionMatrix[11] +
- tr.viewParms.projectionMatrix[15];
-
-
- pr = projected[1] / projected[3];
-
- if ( pr > 1.0f )
- pr = 1.0f;
-
- return pr;
-}
-
-/*
-=============
-R_CullModel
-=============
-*/
-static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {
- vec3_t bounds[2];
- md3Frame_t *oldFrame, *newFrame;
- int i;
-
- // compute frame pointers
- newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
- oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
-
- // cull bounding sphere ONLY if this is not an upscaled entity
- if ( !ent->e.nonNormalizedAxes )
- {
- if ( ent->e.frame == ent->e.oldframe )
- {
- switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
- {
- case CULL_OUT:
- tr.pc.c_sphere_cull_md3_out++;
- return CULL_OUT;
-
- case CULL_IN:
- tr.pc.c_sphere_cull_md3_in++;
- return CULL_IN;
-
- case CULL_CLIP:
- tr.pc.c_sphere_cull_md3_clip++;
- break;
- }
- }
- else
- {
- int sphereCull, sphereCullB;
-
- sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
- if ( newFrame == oldFrame ) {
- sphereCullB = sphereCull;
- } else {
- sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
- }
-
- if ( sphereCull == sphereCullB )
- {
- if ( sphereCull == CULL_OUT )
- {
- tr.pc.c_sphere_cull_md3_out++;
- return CULL_OUT;
- }
- else if ( sphereCull == CULL_IN )
- {
- tr.pc.c_sphere_cull_md3_in++;
- return CULL_IN;
- }
- else
- {
- tr.pc.c_sphere_cull_md3_clip++;
- }
- }
- }
- }
-
- // calculate a bounding box in the current coordinate system
- for (i = 0 ; i < 3 ; i++) {
- bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
- bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
- }
-
- switch ( R_CullLocalBox( bounds ) )
- {
- case CULL_IN:
- tr.pc.c_box_cull_md3_in++;
- return CULL_IN;
- case CULL_CLIP:
- tr.pc.c_box_cull_md3_clip++;
- return CULL_CLIP;
- case CULL_OUT:
- default:
- tr.pc.c_box_cull_md3_out++;
- return CULL_OUT;
- }
-}
-
-
-/*
-=================
-R_ComputeLOD
-
-=================
-*/
-int R_ComputeLOD( trRefEntity_t *ent ) {
- float radius;
- float flod, lodscale;
- float projectedRadius;
- md3Frame_t *frame;
- int lod;
-
- if ( tr.currentModel->numLods < 2 )
- {
- // model has only 1 LOD level, skip computations and bias
- lod = 0;
- }
- else
- {
- // multiple LODs exist, so compute projected bounding sphere
- // and use that as a criteria for selecting LOD
-
- frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
-
- frame += ent->e.frame;
-
- radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
-
- if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
- {
- lodscale = r_lodscale->value;
- if (lodscale > 20) lodscale = 20;
- flod = 1.0f - projectedRadius * lodscale;
- }
- else
- {
- // object intersects near view plane, e.g. view weapon
- flod = 0;
- }
-
- flod *= tr.currentModel->numLods;
- lod = myftol( flod );
-
- if ( lod < 0 )
- {
- lod = 0;
- }
- else if ( lod >= tr.currentModel->numLods )
- {
- lod = tr.currentModel->numLods - 1;
- }
- }
-
- lod += r_lodbias->integer;
-
- if ( lod >= tr.currentModel->numLods )
- lod = tr.currentModel->numLods - 1;
- if ( lod < 0 )
- lod = 0;
-
- return lod;
-}
-
-/*
-=================
-R_ComputeFogNum
-
-=================
-*/
-int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
- int i, j;
- fog_t *fog;
- md3Frame_t *md3Frame;
- vec3_t localOrigin;
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return 0;
- }
-
- // FIXME: non-normalized axis issues
- md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
- VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
- for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
- fog = &tr.world->fogs[i];
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
- break;
- }
- if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
- break;
- }
- }
- if ( j == 3 ) {
- return i;
- }
- }
-
- return 0;
-}
-
-/*
-=================
-R_AddMD3Surfaces
-
-=================
-*/
-void R_AddMD3Surfaces( trRefEntity_t *ent ) {
- int i;
- md3Header_t *header = 0;
- md3Surface_t *surface = 0;
- md3Shader_t *md3Shader = 0;
- shader_t *shader = 0;
- int cull;
- int lod;
- int fogNum;
- qboolean personalModel;
-
- // don't add third_person objects if not in a portal
- personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
-
- if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
- ent->e.frame %= tr.currentModel->md3[0]->numFrames;
- ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
- }
-
- //
- // Validate the frames so there is no chance of a crash.
- // This will write directly into the entity structure, so
- // when the surfaces are rendered, they don't need to be
- // range checked again.
- //
- if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames)
- || (ent->e.frame < 0)
- || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
- || (ent->e.oldframe < 0) ) {
- ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
- ent->e.oldframe, ent->e.frame,
- tr.currentModel->name );
- ent->e.frame = 0;
- ent->e.oldframe = 0;
- }
-
- //
- // compute LOD
- //
- lod = R_ComputeLOD( ent );
-
- header = tr.currentModel->md3[lod];
-
- //
- // cull the entire model if merged bounding box of both frames
- // is outside the view frustum.
- //
- cull = R_CullModel ( header, ent );
- if ( cull == CULL_OUT ) {
- return;
- }
-
- //
- // set up lighting now that we know we aren't culled
- //
- if ( !personalModel || r_shadows->integer > 1 ) {
- R_SetupEntityLighting( &tr.refdef, ent );
- }
-
- //
- // see if we are in a fog volume
- //
- fogNum = R_ComputeFogNum( header, ent );
-
- //
- // draw all surfaces
- //
- surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
- for ( i = 0 ; i < header->numSurfaces ; i++ ) {
-
- if ( ent->e.customShader ) {
- shader = R_GetShaderByHandle( ent->e.customShader );
- } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
- skin_t *skin;
- int j;
-
- skin = R_GetSkinByHandle( ent->e.customSkin );
-
- // match the surface name to something in the skin file
- shader = tr.defaultShader;
- for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
- // the names have both been lowercased
- if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
- shader = skin->surfaces[j]->shader;
- break;
- }
- }
- if (shader == tr.defaultShader) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
- }
- else if (shader->defaultShader) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
- }
- } else if ( surface->numShaders <= 0 ) {
- shader = tr.defaultShader;
- } else {
- md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
- md3Shader += ent->e.skinNum % surface->numShaders;
- shader = tr.shaders[ md3Shader->shaderIndex ];
- }
-
-
- // we will add shadows even if the main object isn't visible in the view
-
- // stencil shadows can't do personal models unless I polyhedron clip
- if ( !personalModel
- && r_shadows->integer == 2
- && fogNum == 0
- && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
- && shader->sort == SS_OPAQUE ) {
- R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
- }
-
- // projection shadows work fine with personal models
- if ( r_shadows->integer == 3
- && fogNum == 0
- && (ent->e.renderfx & RF_SHADOW_PLANE )
- && shader->sort == SS_OPAQUE ) {
- R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
- }
-
- // don't add third_person objects if not viewing through a portal
- if ( !personalModel ) {
- R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
- }
-
- surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
- }
-
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_mesh.c: triangle model functions + +#include "tr_local.h" + +static float ProjectRadius( float r, vec3_t location ) +{ + float pr; + float dist; + float c; + vec3_t p; + float projected[4]; + + c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin ); + dist = DotProduct( tr.viewParms.or.axis[0], location ) - c; + + if ( dist <= 0 ) + return 0; + + p[0] = 0; + p[1] = fabs( r ); + p[2] = -dist; + + projected[0] = p[0] * tr.viewParms.projectionMatrix[0] + + p[1] * tr.viewParms.projectionMatrix[4] + + p[2] * tr.viewParms.projectionMatrix[8] + + tr.viewParms.projectionMatrix[12]; + + projected[1] = p[0] * tr.viewParms.projectionMatrix[1] + + p[1] * tr.viewParms.projectionMatrix[5] + + p[2] * tr.viewParms.projectionMatrix[9] + + tr.viewParms.projectionMatrix[13]; + + projected[2] = p[0] * tr.viewParms.projectionMatrix[2] + + p[1] * tr.viewParms.projectionMatrix[6] + + p[2] * tr.viewParms.projectionMatrix[10] + + tr.viewParms.projectionMatrix[14]; + + projected[3] = p[0] * tr.viewParms.projectionMatrix[3] + + p[1] * tr.viewParms.projectionMatrix[7] + + p[2] * tr.viewParms.projectionMatrix[11] + + tr.viewParms.projectionMatrix[15]; + + + pr = projected[1] / projected[3]; + + if ( pr > 1.0f ) + pr = 1.0f; + + return pr; +} + +/* +============= +R_CullModel +============= +*/ +static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) { + vec3_t bounds[2]; + md3Frame_t *oldFrame, *newFrame; + int i; + + // compute frame pointers + newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame; + oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe; + + // cull bounding sphere ONLY if this is not an upscaled entity + if ( !ent->e.nonNormalizedAxes ) + { + if ( ent->e.frame == ent->e.oldframe ) + { + switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) + { + case CULL_OUT: + tr.pc.c_sphere_cull_md3_out++; + return CULL_OUT; + + case CULL_IN: + tr.pc.c_sphere_cull_md3_in++; + return CULL_IN; + + case CULL_CLIP: + tr.pc.c_sphere_cull_md3_clip++; + break; + } + } + else + { + int sphereCull, sphereCullB; + + sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); + if ( newFrame == oldFrame ) { + sphereCullB = sphereCull; + } else { + sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); + } + + if ( sphereCull == sphereCullB ) + { + if ( sphereCull == CULL_OUT ) + { + tr.pc.c_sphere_cull_md3_out++; + return CULL_OUT; + } + else if ( sphereCull == CULL_IN ) + { + tr.pc.c_sphere_cull_md3_in++; + return CULL_IN; + } + else + { + tr.pc.c_sphere_cull_md3_clip++; + } + } + } + } + + // calculate a bounding box in the current coordinate system + for (i = 0 ; i < 3 ; i++) { + bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; + bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; + } + + switch ( R_CullLocalBox( bounds ) ) + { + case CULL_IN: + tr.pc.c_box_cull_md3_in++; + return CULL_IN; + case CULL_CLIP: + tr.pc.c_box_cull_md3_clip++; + return CULL_CLIP; + case CULL_OUT: + default: + tr.pc.c_box_cull_md3_out++; + return CULL_OUT; + } +} + + +/* +================= +R_ComputeLOD + +================= +*/ +int R_ComputeLOD( trRefEntity_t *ent ) { + float radius; + float flod, lodscale; + float projectedRadius; + md3Frame_t *frame; + int lod; + + if ( tr.currentModel->numLods < 2 ) + { + // model has only 1 LOD level, skip computations and bias + lod = 0; + } + else + { + // multiple LODs exist, so compute projected bounding sphere + // and use that as a criteria for selecting LOD + + frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); + + frame += ent->e.frame; + + radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); + + if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) + { + lodscale = r_lodscale->value; + if (lodscale > 20) lodscale = 20; + flod = 1.0f - projectedRadius * lodscale; + } + else + { + // object intersects near view plane, e.g. view weapon + flod = 0; + } + + flod *= tr.currentModel->numLods; + lod = myftol( flod ); + + if ( lod < 0 ) + { + lod = 0; + } + else if ( lod >= tr.currentModel->numLods ) + { + lod = tr.currentModel->numLods - 1; + } + } + + lod += r_lodbias->integer; + + if ( lod >= tr.currentModel->numLods ) + lod = tr.currentModel->numLods - 1; + if ( lod < 0 ) + lod = 0; + + return lod; +} + +/* +================= +R_ComputeFogNum + +================= +*/ +int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) { + int i, j; + fog_t *fog; + md3Frame_t *md3Frame; + vec3_t localOrigin; + + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + return 0; + } + + // FIXME: non-normalized axis issues + md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame; + VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin ); + for ( i = 1 ; i < tr.world->numfogs ; i++ ) { + fog = &tr.world->fogs[i]; + for ( j = 0 ; j < 3 ; j++ ) { + if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) { + break; + } + if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) { + break; + } + } + if ( j == 3 ) { + return i; + } + } + + return 0; +} + +/* +================= +R_AddMD3Surfaces + +================= +*/ +void R_AddMD3Surfaces( trRefEntity_t *ent ) { + int i; + md3Header_t *header = 0; + md3Surface_t *surface = 0; + md3Shader_t *md3Shader = 0; + shader_t *shader = 0; + int cull; + int lod; + int fogNum; + qboolean personalModel; + + // don't add third_person objects if not in a portal + personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; + + if ( ent->e.renderfx & RF_WRAP_FRAMES ) { + ent->e.frame %= tr.currentModel->md3[0]->numFrames; + ent->e.oldframe %= tr.currentModel->md3[0]->numFrames; + } + + // + // Validate the frames so there is no chance of a crash. + // This will write directly into the entity structure, so + // when the surfaces are rendered, they don't need to be + // range checked again. + // + if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames) + || (ent->e.frame < 0) + || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames) + || (ent->e.oldframe < 0) ) { + ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n", + ent->e.oldframe, ent->e.frame, + tr.currentModel->name ); + ent->e.frame = 0; + ent->e.oldframe = 0; + } + + // + // compute LOD + // + lod = R_ComputeLOD( ent ); + + header = tr.currentModel->md3[lod]; + + // + // cull the entire model if merged bounding box of both frames + // is outside the view frustum. + // + cull = R_CullModel ( header, ent ); + if ( cull == CULL_OUT ) { + return; + } + + // + // set up lighting now that we know we aren't culled + // + if ( !personalModel || r_shadows->integer > 1 ) { + R_SetupEntityLighting( &tr.refdef, ent ); + } + + // + // see if we are in a fog volume + // + fogNum = R_ComputeFogNum( header, ent ); + + // + // draw all surfaces + // + surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces ); + for ( i = 0 ; i < header->numSurfaces ; i++ ) { + + if ( ent->e.customShader ) { + shader = R_GetShaderByHandle( ent->e.customShader ); + } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) { + skin_t *skin; + int j; + + skin = R_GetSkinByHandle( ent->e.customSkin ); + + // match the surface name to something in the skin file + shader = tr.defaultShader; + for ( j = 0 ; j < skin->numSurfaces ; j++ ) { + // the names have both been lowercased + if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { + shader = skin->surfaces[j]->shader; + break; + } + } + if (shader == tr.defaultShader) { + ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name); + } + else if (shader->defaultShader) { + ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); + } + } else if ( surface->numShaders <= 0 ) { + shader = tr.defaultShader; + } else { + md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); + md3Shader += ent->e.skinNum % surface->numShaders; + shader = tr.shaders[ md3Shader->shaderIndex ]; + } + + + // we will add shadows even if the main object isn't visible in the view + + // stencil shadows can't do personal models unless I polyhedron clip + if ( !personalModel + && r_shadows->integer == 2 + && fogNum == 0 + && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) + && shader->sort == SS_OPAQUE ) { + R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); + } + + // projection shadows work fine with personal models + if ( r_shadows->integer == 3 + && fogNum == 0 + && (ent->e.renderfx & RF_SHADOW_PLANE ) + && shader->sort == SS_OPAQUE ) { + R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); + } + + // don't add third_person objects if not viewing through a portal + if ( !personalModel ) { + R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); + } + + surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd ); + } + +} + diff --git a/code/renderer/tr_model.c b/code/renderer/tr_model.c index 990866f..f6fcac4 100755 --- a/code/renderer/tr_model.c +++ b/code/renderer/tr_model.c @@ -1,700 +1,700 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_models.c -- model loading and caching
-
-#include "tr_local.h"
-
-#define LL(x) x=LittleLong(x)
-
-static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name );
-static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name );
-
-model_t *loadmodel;
-
-/*
-** R_GetModelByHandle
-*/
-model_t *R_GetModelByHandle( qhandle_t index ) {
- model_t *mod;
-
- // out of range gets the defualt model
- if ( index < 1 || index >= tr.numModels ) {
- return tr.models[0];
- }
-
- mod = tr.models[index];
-
- return mod;
-}
-
-//===============================================================================
-
-/*
-** R_AllocModel
-*/
-model_t *R_AllocModel( void ) {
- model_t *mod;
-
- if ( tr.numModels == MAX_MOD_KNOWN ) {
- return NULL;
- }
-
- mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
- mod->index = tr.numModels;
- tr.models[tr.numModels] = mod;
- tr.numModels++;
-
- return mod;
-}
-
-/*
-====================
-RE_RegisterModel
-
-Loads in a model for the given name
-
-Zero will be returned if the model fails to load.
-An entry will be retained for failed models as an
-optimization to prevent disk rescanning if they are
-asked for again.
-====================
-*/
-qhandle_t RE_RegisterModel( const char *name ) {
- model_t *mod;
- unsigned *buf;
- int lod;
- int ident;
- qboolean loaded;
- qhandle_t hModel;
- int numLoaded;
-
- if ( !name || !name[0] ) {
- ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
- return 0;
- }
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Model name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- //
- // search the currently loaded models
- //
- for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
- mod = tr.models[hModel];
- if ( !strcmp( mod->name, name ) ) {
- if( mod->type == MOD_BAD ) {
- return 0;
- }
- return hModel;
- }
- }
-
- // allocate a new model_t
-
- if ( ( mod = R_AllocModel() ) == NULL ) {
- ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
- return 0;
- }
-
- // only set the name after the model has been successfully loaded
- Q_strncpyz( mod->name, name, sizeof( mod->name ) );
-
-
- // make sure the render thread is stopped
- R_SyncRenderThread();
-
- mod->numLods = 0;
-
- //
- // load the files
- //
- numLoaded = 0;
-
- for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {
- char filename[1024];
-
- strcpy( filename, name );
-
- if ( lod != 0 ) {
- char namebuf[80];
-
- if ( strrchr( filename, '.' ) ) {
- *strrchr( filename, '.' ) = 0;
- }
- sprintf( namebuf, "_%d.md3", lod );
- strcat( filename, namebuf );
- }
-
- ri.FS_ReadFile( filename, (void **)&buf );
- if ( !buf ) {
- continue;
- }
-
- loadmodel = mod;
-
- ident = LittleLong(*(unsigned *)buf);
- if ( ident == MD4_IDENT ) {
- loaded = R_LoadMD4( mod, buf, name );
- } else {
- if ( ident != MD3_IDENT ) {
- ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name);
- goto fail;
- }
-
- loaded = R_LoadMD3( mod, lod, buf, name );
- }
-
- ri.FS_FreeFile (buf);
-
- if ( !loaded ) {
- if ( lod == 0 ) {
- goto fail;
- } else {
- break;
- }
- } else {
- mod->numLods++;
- numLoaded++;
- // if we have a valid model and are biased
- // so that we won't see any higher detail ones,
- // stop loading them
-// if ( lod <= r_lodbias->integer ) {
-// break;
-// }
- }
- }
-
- if ( numLoaded ) {
- // duplicate into higher lod spots that weren't
- // loaded, in case the user changes r_lodbias on the fly
- for ( lod-- ; lod >= 0 ; lod-- ) {
- mod->numLods++;
- mod->md3[lod] = mod->md3[lod+1];
- }
-
- return mod->index;
- }
-#ifdef _DEBUG
- else {
- ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
- }
-#endif
-
-fail:
- // we still keep the model_t around, so if the model name is asked for
- // again, we won't bother scanning the filesystem
- mod->type = MOD_BAD;
- return 0;
-}
-
-
-/*
-=================
-R_LoadMD3
-=================
-*/
-static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
- int i, j;
- md3Header_t *pinmodel;
- md3Frame_t *frame;
- md3Surface_t *surf;
- md3Shader_t *shader;
- md3Triangle_t *tri;
- md3St_t *st;
- md3XyzNormal_t *xyz;
- md3Tag_t *tag;
- int version;
- int size;
-
- pinmodel = (md3Header_t *)buffer;
-
- version = LittleLong (pinmodel->version);
- if (version != MD3_VERSION) {
- ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
- mod_name, version, MD3_VERSION);
- return qfalse;
- }
-
- mod->type = MOD_MESH;
- size = LittleLong(pinmodel->ofsEnd);
- mod->dataSize += size;
- mod->md3[lod] = ri.Hunk_Alloc( size, h_low );
-
- Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
-
- LL(mod->md3[lod]->ident);
- LL(mod->md3[lod]->version);
- LL(mod->md3[lod]->numFrames);
- LL(mod->md3[lod]->numTags);
- LL(mod->md3[lod]->numSurfaces);
- LL(mod->md3[lod]->ofsFrames);
- LL(mod->md3[lod]->ofsTags);
- LL(mod->md3[lod]->ofsSurfaces);
- LL(mod->md3[lod]->ofsEnd);
-
- if ( mod->md3[lod]->numFrames < 1 ) {
- ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
- return qfalse;
- }
-
- // swap all the frames
- frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
- for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
- frame->radius = LittleFloat( frame->radius );
- for ( j = 0 ; j < 3 ; j++ ) {
- frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
- frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
- frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
- }
- }
-
- // swap all the tags
- tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
- for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
- for ( j = 0 ; j < 3 ; j++ ) {
- tag->origin[j] = LittleFloat( tag->origin[j] );
- tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
- tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
- tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
- }
- }
-
- // swap all the surfaces
- surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
- for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
-
- LL(surf->ident);
- LL(surf->flags);
- LL(surf->numFrames);
- LL(surf->numShaders);
- LL(surf->numTriangles);
- LL(surf->ofsTriangles);
- LL(surf->numVerts);
- LL(surf->ofsShaders);
- LL(surf->ofsSt);
- LL(surf->ofsXyzNormals);
- LL(surf->ofsEnd);
-
- if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
- mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
- }
- if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
- mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
- }
-
- // change to surface identifier
- surf->ident = SF_MD3;
-
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surf->name );
-
- // strip off a trailing _1 or _2
- // this is a crutch for q3data being a mess
- j = strlen( surf->name );
- if ( j > 2 && surf->name[j-2] == '_' ) {
- surf->name[j-2] = 0;
- }
-
- // register the shaders
- shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
- for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
- shader_t *sh;
-
- sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
- if ( sh->defaultShader ) {
- shader->shaderIndex = 0;
- } else {
- shader->shaderIndex = sh->index;
- }
- }
-
- // swap all the triangles
- tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
- for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
- LL(tri->indexes[0]);
- LL(tri->indexes[1]);
- LL(tri->indexes[2]);
- }
-
- // swap all the ST
- st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
- for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
- st->st[0] = LittleFloat( st->st[0] );
- st->st[1] = LittleFloat( st->st[1] );
- }
-
- // swap all the XyzNormals
- xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
- for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
- {
- xyz->xyz[0] = LittleShort( xyz->xyz[0] );
- xyz->xyz[1] = LittleShort( xyz->xyz[1] );
- xyz->xyz[2] = LittleShort( xyz->xyz[2] );
-
- xyz->normal = LittleShort( xyz->normal );
- }
-
-
- // find the next surface
- surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
- }
-
- return qtrue;
-}
-
-
-
-/*
-=================
-R_LoadMD4
-=================
-*/
-static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
- int i, j, k, lodindex;
- md4Header_t *pinmodel, *md4;
- md4Frame_t *frame;
- md4LOD_t *lod;
- md4Surface_t *surf;
- md4Triangle_t *tri;
- md4Vertex_t *v;
- int version;
- int size;
- shader_t *sh;
- int frameSize;
-
- pinmodel = (md4Header_t *)buffer;
-
- version = LittleLong (pinmodel->version);
- if (version != MD4_VERSION) {
- ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n",
- mod_name, version, MD4_VERSION);
- return qfalse;
- }
-
- mod->type = MOD_MD4;
- size = LittleLong(pinmodel->ofsEnd);
- mod->dataSize += size;
- md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );
-
- Com_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) );
-
- LL(md4->ident);
- LL(md4->version);
- LL(md4->numFrames);
- LL(md4->numBones);
- LL(md4->numLODs);
- LL(md4->ofsFrames);
- LL(md4->ofsLODs);
- LL(md4->ofsEnd);
-
- if ( md4->numFrames < 1 ) {
- ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
- return qfalse;
- }
-
- // we don't need to swap tags in the renderer, they aren't used
-
- // swap all the frames
- frameSize = (int)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
- for ( i = 0 ; i < md4->numFrames ; i++, frame++) {
- frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize );
- frame->radius = LittleFloat( frame->radius );
- for ( j = 0 ; j < 3 ; j++ ) {
- frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
- frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
- frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
- }
- for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
- ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
- }
- }
-
- // swap all the LOD's
- lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
- for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {
-
- // swap all the surfaces
- surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
- for ( i = 0 ; i < lod->numSurfaces ; i++) {
- LL(surf->ident);
- LL(surf->numTriangles);
- LL(surf->ofsTriangles);
- LL(surf->numVerts);
- LL(surf->ofsVerts);
- LL(surf->ofsEnd);
-
- if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
- mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
- }
- if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
- ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
- mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
- }
-
- // change to surface identifier
- surf->ident = SF_MD4;
-
- // lowercase the surface name so skin compares are faster
- Q_strlwr( surf->name );
-
- // register the shaders
- sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
- if ( sh->defaultShader ) {
- surf->shaderIndex = 0;
- } else {
- surf->shaderIndex = sh->index;
- }
-
- // swap all the triangles
- tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
- for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
- LL(tri->indexes[0]);
- LL(tri->indexes[1]);
- LL(tri->indexes[2]);
- }
-
- // swap all the vertexes
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
- v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);
- for ( j = 0 ; j < surf->numVerts ; j++ ) {
- v->normal[0] = LittleFloat( v->normal[0] );
- v->normal[1] = LittleFloat( v->normal[1] );
- v->normal[2] = LittleFloat( v->normal[2] );
-
- v->texCoords[0] = LittleFloat( v->texCoords[0] );
- v->texCoords[1] = LittleFloat( v->texCoords[1] );
-
- v->numWeights = LittleLong( v->numWeights );
-
- for ( k = 0 ; k < v->numWeights ; k++ ) {
- v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
- v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
- v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
- v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
- v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
- }
- // FIXME
- // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
- // in for reference.
- //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
- v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);
- }
-
- // find the next surface
- surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd );
- }
-
- // find the next LOD
- lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
- }
-
- return qtrue;
-}
-
-
-
-
-//=============================================================================
-
-/*
-** RE_BeginRegistration
-*/
-void RE_BeginRegistration( glconfig_t *glconfigOut ) {
-
- R_Init();
-
- *glconfigOut = glConfig;
-
- R_SyncRenderThread();
-
- tr.viewCluster = -1; // force markleafs to regenerate
- R_ClearFlares();
- RE_ClearScene();
-
- tr.registered = qtrue;
-
- // NOTE: this sucks, for some reason the first stretch pic is never drawn
- // without this we'd see a white flash on a level load because the very
- // first time the level shot would not be drawn
- RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0);
-}
-
-//=============================================================================
-
-/*
-===============
-R_ModelInit
-===============
-*/
-void R_ModelInit( void ) {
- model_t *mod;
-
- // leave a space for NULL model
- tr.numModels = 0;
-
- mod = R_AllocModel();
- mod->type = MOD_BAD;
-}
-
-
-/*
-================
-R_Modellist_f
-================
-*/
-void R_Modellist_f( void ) {
- int i, j;
- model_t *mod;
- int total;
- int lods;
-
- total = 0;
- for ( i = 1 ; i < tr.numModels; i++ ) {
- mod = tr.models[i];
- lods = 1;
- for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
- if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {
- lods++;
- }
- }
- ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
- total += mod->dataSize;
- }
- ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
-
-#if 0 // not working right with new hunk
- if ( tr.world ) {
- ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name );
- }
-#endif
-}
-
-
-//=============================================================================
-
-
-/*
-================
-R_GetTag
-================
-*/
-static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
- md3Tag_t *tag;
- int i;
-
- if ( frame >= mod->numFrames ) {
- // it is possible to have a bad frame while changing models, so don't error
- frame = mod->numFrames - 1;
- }
-
- tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
- for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
- if ( !strcmp( tag->name, tagName ) ) {
- return tag; // found it
- }
- }
-
- return NULL;
-}
-
-/*
-================
-R_LerpTag
-================
-*/
-int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
- float frac, const char *tagName ) {
- md3Tag_t *start, *end;
- int i;
- float frontLerp, backLerp;
- model_t *model;
-
- model = R_GetModelByHandle( handle );
- if ( !model->md3[0] ) {
- AxisClear( tag->axis );
- VectorClear( tag->origin );
- return qfalse;
- }
-
- start = R_GetTag( model->md3[0], startFrame, tagName );
- end = R_GetTag( model->md3[0], endFrame, tagName );
- if ( !start || !end ) {
- AxisClear( tag->axis );
- VectorClear( tag->origin );
- return qfalse;
- }
-
- frontLerp = frac;
- backLerp = 1.0f - frac;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp;
- tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp;
- tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp;
- tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp;
- }
- VectorNormalize( tag->axis[0] );
- VectorNormalize( tag->axis[1] );
- VectorNormalize( tag->axis[2] );
- return qtrue;
-}
-
-
-/*
-====================
-R_ModelBounds
-====================
-*/
-void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
- model_t *model;
- md3Header_t *header;
- md3Frame_t *frame;
-
- model = R_GetModelByHandle( handle );
-
- if ( model->bmodel ) {
- VectorCopy( model->bmodel->bounds[0], mins );
- VectorCopy( model->bmodel->bounds[1], maxs );
- return;
- }
-
- if ( !model->md3[0] ) {
- VectorClear( mins );
- VectorClear( maxs );
- return;
- }
-
- header = model->md3[0];
-
- frame = (md3Frame_t *)( (byte *)header + header->ofsFrames );
-
- VectorCopy( frame->bounds[0], mins );
- VectorCopy( frame->bounds[1], maxs );
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_models.c -- model loading and caching + +#include "tr_local.h" + +#define LL(x) x=LittleLong(x) + +static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name ); +static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name ); + +model_t *loadmodel; + +/* +** R_GetModelByHandle +*/ +model_t *R_GetModelByHandle( qhandle_t index ) { + model_t *mod; + + // out of range gets the defualt model + if ( index < 1 || index >= tr.numModels ) { + return tr.models[0]; + } + + mod = tr.models[index]; + + return mod; +} + +//=============================================================================== + +/* +** R_AllocModel +*/ +model_t *R_AllocModel( void ) { + model_t *mod; + + if ( tr.numModels == MAX_MOD_KNOWN ) { + return NULL; + } + + mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low ); + mod->index = tr.numModels; + tr.models[tr.numModels] = mod; + tr.numModels++; + + return mod; +} + +/* +==================== +RE_RegisterModel + +Loads in a model for the given name + +Zero will be returned if the model fails to load. +An entry will be retained for failed models as an +optimization to prevent disk rescanning if they are +asked for again. +==================== +*/ +qhandle_t RE_RegisterModel( const char *name ) { + model_t *mod; + unsigned *buf; + int lod; + int ident; + qboolean loaded; + qhandle_t hModel; + int numLoaded; + + if ( !name || !name[0] ) { + ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); + return 0; + } + + if ( strlen( name ) >= MAX_QPATH ) { + Com_Printf( "Model name exceeds MAX_QPATH\n" ); + return 0; + } + + // + // search the currently loaded models + // + for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { + mod = tr.models[hModel]; + if ( !strcmp( mod->name, name ) ) { + if( mod->type == MOD_BAD ) { + return 0; + } + return hModel; + } + } + + // allocate a new model_t + + if ( ( mod = R_AllocModel() ) == NULL ) { + ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); + return 0; + } + + // only set the name after the model has been successfully loaded + Q_strncpyz( mod->name, name, sizeof( mod->name ) ); + + + // make sure the render thread is stopped + R_SyncRenderThread(); + + mod->numLods = 0; + + // + // load the files + // + numLoaded = 0; + + for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) { + char filename[1024]; + + strcpy( filename, name ); + + if ( lod != 0 ) { + char namebuf[80]; + + if ( strrchr( filename, '.' ) ) { + *strrchr( filename, '.' ) = 0; + } + sprintf( namebuf, "_%d.md3", lod ); + strcat( filename, namebuf ); + } + + ri.FS_ReadFile( filename, (void **)&buf ); + if ( !buf ) { + continue; + } + + loadmodel = mod; + + ident = LittleLong(*(unsigned *)buf); + if ( ident == MD4_IDENT ) { + loaded = R_LoadMD4( mod, buf, name ); + } else { + if ( ident != MD3_IDENT ) { + ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name); + goto fail; + } + + loaded = R_LoadMD3( mod, lod, buf, name ); + } + + ri.FS_FreeFile (buf); + + if ( !loaded ) { + if ( lod == 0 ) { + goto fail; + } else { + break; + } + } else { + mod->numLods++; + numLoaded++; + // if we have a valid model and are biased + // so that we won't see any higher detail ones, + // stop loading them +// if ( lod <= r_lodbias->integer ) { +// break; +// } + } + } + + if ( numLoaded ) { + // duplicate into higher lod spots that weren't + // loaded, in case the user changes r_lodbias on the fly + for ( lod-- ; lod >= 0 ; lod-- ) { + mod->numLods++; + mod->md3[lod] = mod->md3[lod+1]; + } + + return mod->index; + } +#ifdef _DEBUG + else { + ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name); + } +#endif + +fail: + // we still keep the model_t around, so if the model name is asked for + // again, we won't bother scanning the filesystem + mod->type = MOD_BAD; + return 0; +} + + +/* +================= +R_LoadMD3 +================= +*/ +static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) { + int i, j; + md3Header_t *pinmodel; + md3Frame_t *frame; + md3Surface_t *surf; + md3Shader_t *shader; + md3Triangle_t *tri; + md3St_t *st; + md3XyzNormal_t *xyz; + md3Tag_t *tag; + int version; + int size; + + pinmodel = (md3Header_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != MD3_VERSION) { + ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", + mod_name, version, MD3_VERSION); + return qfalse; + } + + mod->type = MOD_MESH; + size = LittleLong(pinmodel->ofsEnd); + mod->dataSize += size; + mod->md3[lod] = ri.Hunk_Alloc( size, h_low ); + + Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) ); + + LL(mod->md3[lod]->ident); + LL(mod->md3[lod]->version); + LL(mod->md3[lod]->numFrames); + LL(mod->md3[lod]->numTags); + LL(mod->md3[lod]->numSurfaces); + LL(mod->md3[lod]->ofsFrames); + LL(mod->md3[lod]->ofsTags); + LL(mod->md3[lod]->ofsSurfaces); + LL(mod->md3[lod]->ofsEnd); + + if ( mod->md3[lod]->numFrames < 1 ) { + ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name ); + return qfalse; + } + + // swap all the frames + frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames ); + for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) { + frame->radius = LittleFloat( frame->radius ); + for ( j = 0 ; j < 3 ; j++ ) { + frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); + frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); + frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); + } + } + + // swap all the tags + tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags ); + for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) { + for ( j = 0 ; j < 3 ; j++ ) { + tag->origin[j] = LittleFloat( tag->origin[j] ); + tag->axis[0][j] = LittleFloat( tag->axis[0][j] ); + tag->axis[1][j] = LittleFloat( tag->axis[1][j] ); + tag->axis[2][j] = LittleFloat( tag->axis[2][j] ); + } + } + + // swap all the surfaces + surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces ); + for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) { + + LL(surf->ident); + LL(surf->flags); + LL(surf->numFrames); + LL(surf->numShaders); + LL(surf->numTriangles); + LL(surf->ofsTriangles); + LL(surf->numVerts); + LL(surf->ofsShaders); + LL(surf->ofsSt); + LL(surf->ofsXyzNormals); + LL(surf->ofsEnd); + + if ( surf->numVerts > SHADER_MAX_VERTEXES ) { + ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", + mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + } + if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { + ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", + mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + } + + // change to surface identifier + surf->ident = SF_MD3; + + // lowercase the surface name so skin compares are faster + Q_strlwr( surf->name ); + + // strip off a trailing _1 or _2 + // this is a crutch for q3data being a mess + j = strlen( surf->name ); + if ( j > 2 && surf->name[j-2] == '_' ) { + surf->name[j-2] = 0; + } + + // register the shaders + shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); + for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { + shader_t *sh; + + sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue ); + if ( sh->defaultShader ) { + shader->shaderIndex = 0; + } else { + shader->shaderIndex = sh->index; + } + } + + // swap all the triangles + tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); + for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { + LL(tri->indexes[0]); + LL(tri->indexes[1]); + LL(tri->indexes[2]); + } + + // swap all the ST + st = (md3St_t *) ( (byte *)surf + surf->ofsSt ); + for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { + st->st[0] = LittleFloat( st->st[0] ); + st->st[1] = LittleFloat( st->st[1] ); + } + + // swap all the XyzNormals + xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals ); + for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) + { + xyz->xyz[0] = LittleShort( xyz->xyz[0] ); + xyz->xyz[1] = LittleShort( xyz->xyz[1] ); + xyz->xyz[2] = LittleShort( xyz->xyz[2] ); + + xyz->normal = LittleShort( xyz->normal ); + } + + + // find the next surface + surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd ); + } + + return qtrue; +} + + + +/* +================= +R_LoadMD4 +================= +*/ +static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { + int i, j, k, lodindex; + md4Header_t *pinmodel, *md4; + md4Frame_t *frame; + md4LOD_t *lod; + md4Surface_t *surf; + md4Triangle_t *tri; + md4Vertex_t *v; + int version; + int size; + shader_t *sh; + int frameSize; + + pinmodel = (md4Header_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != MD4_VERSION) { + ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n", + mod_name, version, MD4_VERSION); + return qfalse; + } + + mod->type = MOD_MD4; + size = LittleLong(pinmodel->ofsEnd); + mod->dataSize += size; + md4 = mod->md4 = ri.Hunk_Alloc( size, h_low ); + + Com_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) ); + + LL(md4->ident); + LL(md4->version); + LL(md4->numFrames); + LL(md4->numBones); + LL(md4->numLODs); + LL(md4->ofsFrames); + LL(md4->ofsLODs); + LL(md4->ofsEnd); + + if ( md4->numFrames < 1 ) { + ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name ); + return qfalse; + } + + // we don't need to swap tags in the renderer, they aren't used + + // swap all the frames + frameSize = (int)( &((md4Frame_t *)0)->bones[ md4->numBones ] ); + for ( i = 0 ; i < md4->numFrames ; i++, frame++) { + frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize ); + frame->radius = LittleFloat( frame->radius ); + for ( j = 0 ; j < 3 ; j++ ) { + frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); + frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); + frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); + } + for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) { + ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] ); + } + } + + // swap all the LOD's + lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs ); + for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) { + + // swap all the surfaces + surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces ); + for ( i = 0 ; i < lod->numSurfaces ; i++) { + LL(surf->ident); + LL(surf->numTriangles); + LL(surf->ofsTriangles); + LL(surf->numVerts); + LL(surf->ofsVerts); + LL(surf->ofsEnd); + + if ( surf->numVerts > SHADER_MAX_VERTEXES ) { + ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", + mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + } + if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { + ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", + mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + } + + // change to surface identifier + surf->ident = SF_MD4; + + // lowercase the surface name so skin compares are faster + Q_strlwr( surf->name ); + + // register the shaders + sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue ); + if ( sh->defaultShader ) { + surf->shaderIndex = 0; + } else { + surf->shaderIndex = sh->index; + } + + // swap all the triangles + tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); + for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { + LL(tri->indexes[0]); + LL(tri->indexes[1]); + LL(tri->indexes[2]); + } + + // swap all the vertexes + // FIXME + // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left + // in for reference. + //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12); + v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts); + for ( j = 0 ; j < surf->numVerts ; j++ ) { + v->normal[0] = LittleFloat( v->normal[0] ); + v->normal[1] = LittleFloat( v->normal[1] ); + v->normal[2] = LittleFloat( v->normal[2] ); + + v->texCoords[0] = LittleFloat( v->texCoords[0] ); + v->texCoords[1] = LittleFloat( v->texCoords[1] ); + + v->numWeights = LittleLong( v->numWeights ); + + for ( k = 0 ; k < v->numWeights ; k++ ) { + v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex ); + v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight ); + v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] ); + v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] ); + v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] ); + } + // FIXME + // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left + // in for reference. + //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 ); + v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]); + } + + // find the next surface + surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd ); + } + + // find the next LOD + lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd ); + } + + return qtrue; +} + + + + +//============================================================================= + +/* +** RE_BeginRegistration +*/ +void RE_BeginRegistration( glconfig_t *glconfigOut ) { + + R_Init(); + + *glconfigOut = glConfig; + + R_SyncRenderThread(); + + tr.viewCluster = -1; // force markleafs to regenerate + R_ClearFlares(); + RE_ClearScene(); + + tr.registered = qtrue; + + // NOTE: this sucks, for some reason the first stretch pic is never drawn + // without this we'd see a white flash on a level load because the very + // first time the level shot would not be drawn + RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0); +} + +//============================================================================= + +/* +=============== +R_ModelInit +=============== +*/ +void R_ModelInit( void ) { + model_t *mod; + + // leave a space for NULL model + tr.numModels = 0; + + mod = R_AllocModel(); + mod->type = MOD_BAD; +} + + +/* +================ +R_Modellist_f +================ +*/ +void R_Modellist_f( void ) { + int i, j; + model_t *mod; + int total; + int lods; + + total = 0; + for ( i = 1 ; i < tr.numModels; i++ ) { + mod = tr.models[i]; + lods = 1; + for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) { + if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) { + lods++; + } + } + ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name ); + total += mod->dataSize; + } + ri.Printf( PRINT_ALL, "%8i : Total models\n", total ); + +#if 0 // not working right with new hunk + if ( tr.world ) { + ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name ); + } +#endif +} + + +//============================================================================= + + +/* +================ +R_GetTag +================ +*/ +static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) { + md3Tag_t *tag; + int i; + + if ( frame >= mod->numFrames ) { + // it is possible to have a bad frame while changing models, so don't error + frame = mod->numFrames - 1; + } + + tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags; + for ( i = 0 ; i < mod->numTags ; i++, tag++ ) { + if ( !strcmp( tag->name, tagName ) ) { + return tag; // found it + } + } + + return NULL; +} + +/* +================ +R_LerpTag +================ +*/ +int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, + float frac, const char *tagName ) { + md3Tag_t *start, *end; + int i; + float frontLerp, backLerp; + model_t *model; + + model = R_GetModelByHandle( handle ); + if ( !model->md3[0] ) { + AxisClear( tag->axis ); + VectorClear( tag->origin ); + return qfalse; + } + + start = R_GetTag( model->md3[0], startFrame, tagName ); + end = R_GetTag( model->md3[0], endFrame, tagName ); + if ( !start || !end ) { + AxisClear( tag->axis ); + VectorClear( tag->origin ); + return qfalse; + } + + frontLerp = frac; + backLerp = 1.0f - frac; + + for ( i = 0 ; i < 3 ; i++ ) { + tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp; + tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp; + tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp; + tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp; + } + VectorNormalize( tag->axis[0] ); + VectorNormalize( tag->axis[1] ); + VectorNormalize( tag->axis[2] ); + return qtrue; +} + + +/* +==================== +R_ModelBounds +==================== +*/ +void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { + model_t *model; + md3Header_t *header; + md3Frame_t *frame; + + model = R_GetModelByHandle( handle ); + + if ( model->bmodel ) { + VectorCopy( model->bmodel->bounds[0], mins ); + VectorCopy( model->bmodel->bounds[1], maxs ); + return; + } + + if ( !model->md3[0] ) { + VectorClear( mins ); + VectorClear( maxs ); + return; + } + + header = model->md3[0]; + + frame = (md3Frame_t *)( (byte *)header + header->ofsFrames ); + + VectorCopy( frame->bounds[0], mins ); + VectorCopy( frame->bounds[1], maxs ); +} diff --git a/code/renderer/tr_noise.c b/code/renderer/tr_noise.c index 4aae947..7e172fb 100755 --- a/code/renderer/tr_noise.c +++ b/code/renderer/tr_noise.c @@ -1,95 +1,95 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_noise.c
-#include "tr_local.h"
-
-#define NOISE_SIZE 256
-#define NOISE_MASK ( NOISE_SIZE - 1 )
-
-#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )]
-#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) )
-
-static float s_noise_table[NOISE_SIZE];
-static int s_noise_perm[NOISE_SIZE];
-
-#define LERP( a, b, w ) ( a * ( 1.0f - w ) + b * w )
-
-static float GetNoiseValue( int x, int y, int z, int t )
-{
- int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t );
-
- return s_noise_table[index];
-}
-
-void R_NoiseInit( void )
-{
- int i;
-
- srand( 1001 );
-
- for ( i = 0; i < NOISE_SIZE; i++ )
- {
- s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );
- s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 );
- }
-}
-
-float R_NoiseGet4f( float x, float y, float z, float t )
-{
- int i;
- int ix, iy, iz, it;
- float fx, fy, fz, ft;
- float front[4];
- float back[4];
- float fvalue, bvalue, value[2], finalvalue;
-
- ix = ( int ) floor( x );
- fx = x - ix;
- iy = ( int ) floor( y );
- fy = y - iy;
- iz = ( int ) floor( z );
- fz = z - iz;
- it = ( int ) floor( t );
- ft = t - it;
-
- for ( i = 0; i < 2; i++ )
- {
- front[0] = GetNoiseValue( ix, iy, iz, it + i );
- front[1] = GetNoiseValue( ix+1, iy, iz, it + i );
- front[2] = GetNoiseValue( ix, iy+1, iz, it + i );
- front[3] = GetNoiseValue( ix+1, iy+1, iz, it + i );
-
- back[0] = GetNoiseValue( ix, iy, iz + 1, it + i );
- back[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i );
- back[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i );
- back[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i );
-
- fvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy );
- bvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy );
-
- value[i] = LERP( fvalue, bvalue, fz );
- }
-
- finalvalue = LERP( value[0], value[1], ft );
-
- return finalvalue;
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_noise.c +#include "tr_local.h" + +#define NOISE_SIZE 256 +#define NOISE_MASK ( NOISE_SIZE - 1 ) + +#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )] +#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) ) + +static float s_noise_table[NOISE_SIZE]; +static int s_noise_perm[NOISE_SIZE]; + +#define LERP( a, b, w ) ( a * ( 1.0f - w ) + b * w ) + +static float GetNoiseValue( int x, int y, int z, int t ) +{ + int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t ); + + return s_noise_table[index]; +} + +void R_NoiseInit( void ) +{ + int i; + + srand( 1001 ); + + for ( i = 0; i < NOISE_SIZE; i++ ) + { + s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) ); + s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 ); + } +} + +float R_NoiseGet4f( float x, float y, float z, float t ) +{ + int i; + int ix, iy, iz, it; + float fx, fy, fz, ft; + float front[4]; + float back[4]; + float fvalue, bvalue, value[2], finalvalue; + + ix = ( int ) floor( x ); + fx = x - ix; + iy = ( int ) floor( y ); + fy = y - iy; + iz = ( int ) floor( z ); + fz = z - iz; + it = ( int ) floor( t ); + ft = t - it; + + for ( i = 0; i < 2; i++ ) + { + front[0] = GetNoiseValue( ix, iy, iz, it + i ); + front[1] = GetNoiseValue( ix+1, iy, iz, it + i ); + front[2] = GetNoiseValue( ix, iy+1, iz, it + i ); + front[3] = GetNoiseValue( ix+1, iy+1, iz, it + i ); + + back[0] = GetNoiseValue( ix, iy, iz + 1, it + i ); + back[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i ); + back[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i ); + back[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i ); + + fvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy ); + bvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy ); + + value[i] = LERP( fvalue, bvalue, fz ); + } + + finalvalue = LERP( value[0], value[1], ft ); + + return finalvalue; +} diff --git a/code/renderer/tr_public.h b/code/renderer/tr_public.h index 197fa26..fa20531 100755 --- a/code/renderer/tr_public.h +++ b/code/renderer/tr_public.h @@ -1,167 +1,167 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#ifndef __TR_PUBLIC_H
-#define __TR_PUBLIC_H
-
-#include "../cgame/tr_types.h"
-
-#define REF_API_VERSION 8
-
-//
-// these are the functions exported by the refresh module
-//
-typedef struct {
- // called before the library is unloaded
- // if the system is just reconfiguring, pass destroyWindow = qfalse,
- // which will keep the screen from flashing to the desktop.
- void (*Shutdown)( qboolean destroyWindow );
-
- // All data that will be used in a level should be
- // registered before rendering any frames to prevent disk hits,
- // but they can still be registered at a later time
- // if necessary.
- //
- // BeginRegistration makes any existing media pointers invalid
- // and returns the current gl configuration, including screen width
- // and height, which can be used by the client to intelligently
- // size display elements
- void (*BeginRegistration)( glconfig_t *config );
- qhandle_t (*RegisterModel)( const char *name );
- qhandle_t (*RegisterSkin)( const char *name );
- qhandle_t (*RegisterShader)( const char *name );
- qhandle_t (*RegisterShaderNoMip)( const char *name );
- void (*LoadWorld)( const char *name );
-
- // the vis data is a large enough block of data that we go to the trouble
- // of sharing it with the clipmodel subsystem
- void (*SetWorldVisData)( const byte *vis );
-
- // EndRegistration will draw a tiny polygon with each texture, forcing
- // them to be loaded into card memory
- void (*EndRegistration)( void );
-
- // a scene is built up by calls to R_ClearScene and the various R_Add functions.
- // Nothing is drawn until R_RenderScene is called.
- void (*ClearScene)( void );
- void (*AddRefEntityToScene)( const refEntity_t *re );
- void (*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
- int (*LightForPoint)( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
- void (*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
- void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b );
- void (*RenderScene)( const refdef_t *fd );
-
- void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1
- void (*DrawStretchPic) ( float x, float y, float w, float h,
- float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white
-
- // Draw images for cinematic rendering, pass as 32 bit rgba
- void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
- void (*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
-
- void (*BeginFrame)( stereoFrame_t stereoFrame );
-
- // if the pointers are not NULL, timing info will be returned
- void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
-
-
- int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
- int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
-
- int (*LerpTag)( orientation_t *tag, qhandle_t model, int startFrame, int endFrame,
- float frac, const char *tagName );
- void (*ModelBounds)( qhandle_t model, vec3_t mins, vec3_t maxs );
-
-#ifdef __USEA3D
- void (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus);
-#endif
- void (*RegisterFont)(const char *fontName, int pointSize, fontInfo_t *font);
- void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
- qboolean (*GetEntityToken)( char *buffer, int size );
- qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );
-} refexport_t;
-
-//
-// these are the functions imported by the refresh module
-//
-typedef struct {
- // print message on the local console
- void (QDECL *Printf)( int printLevel, const char *fmt, ...);
-
- // abort the game
- void (QDECL *Error)( int errorLevel, const char *fmt, ...);
-
- // milliseconds should only be used for profiling, never
- // for anything game related. Get time from the refdef
- int (*Milliseconds)( void );
-
- // stack based memory allocation for per-level things that
- // won't be freed
-#ifdef HUNK_DEBUG
- void *(*Hunk_AllocDebug)( int size, ha_pref pref, char *label, char *file, int line );
-#else
- void *(*Hunk_Alloc)( int size, ha_pref pref );
-#endif
- void *(*Hunk_AllocateTempMemory)( int size );
- void (*Hunk_FreeTempMemory)( void *block );
-
- // dynamic memory allocator for things that need to be freed
- void *(*Malloc)( int bytes );
- void (*Free)( void *buf );
-
- cvar_t *(*Cvar_Get)( const char *name, const char *value, int flags );
- void (*Cvar_Set)( const char *name, const char *value );
-
- void (*Cmd_AddCommand)( const char *name, void(*cmd)(void) );
- void (*Cmd_RemoveCommand)( const char *name );
-
- int (*Cmd_Argc) (void);
- char *(*Cmd_Argv) (int i);
-
- void (*Cmd_ExecuteText) (int exec_when, const char *text);
-
- // visualization for debugging collision detection
- void (*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) );
-
- // a -1 return means the file does not exist
- // NULL can be passed for buf to just determine existance
- int (*FS_FileIsInPAK)( const char *name, int *pCheckSum );
- int (*FS_ReadFile)( const char *name, void **buf );
- void (*FS_FreeFile)( void *buf );
- char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
- void (*FS_FreeFileList)( char **filelist );
- void (*FS_WriteFile)( const char *qpath, const void *buffer, int size );
- qboolean (*FS_FileExists)( const char *file );
-
- // cinematic stuff
- void (*CIN_UploadCinematic)(int handle);
- int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);
- e_status (*CIN_RunCinematic) (int handle);
-
-} refimport_t;
-
-
-// this is the only function actually exported at the linker level
-// If the module can't init to a valid rendering state, NULL will be
-// returned.
-refexport_t*GetRefAPI( int apiVersion, refimport_t *rimp );
-
-#endif // __TR_PUBLIC_H
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#ifndef __TR_PUBLIC_H +#define __TR_PUBLIC_H + +#include "../cgame/tr_types.h" + +#define REF_API_VERSION 8 + +// +// these are the functions exported by the refresh module +// +typedef struct { + // called before the library is unloaded + // if the system is just reconfiguring, pass destroyWindow = qfalse, + // which will keep the screen from flashing to the desktop. + void (*Shutdown)( qboolean destroyWindow ); + + // All data that will be used in a level should be + // registered before rendering any frames to prevent disk hits, + // but they can still be registered at a later time + // if necessary. + // + // BeginRegistration makes any existing media pointers invalid + // and returns the current gl configuration, including screen width + // and height, which can be used by the client to intelligently + // size display elements + void (*BeginRegistration)( glconfig_t *config ); + qhandle_t (*RegisterModel)( const char *name ); + qhandle_t (*RegisterSkin)( const char *name ); + qhandle_t (*RegisterShader)( const char *name ); + qhandle_t (*RegisterShaderNoMip)( const char *name ); + void (*LoadWorld)( const char *name ); + + // the vis data is a large enough block of data that we go to the trouble + // of sharing it with the clipmodel subsystem + void (*SetWorldVisData)( const byte *vis ); + + // EndRegistration will draw a tiny polygon with each texture, forcing + // them to be loaded into card memory + void (*EndRegistration)( void ); + + // a scene is built up by calls to R_ClearScene and the various R_Add functions. + // Nothing is drawn until R_RenderScene is called. + void (*ClearScene)( void ); + void (*AddRefEntityToScene)( const refEntity_t *re ); + void (*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); + int (*LightForPoint)( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); + void (*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b ); + void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b ); + void (*RenderScene)( const refdef_t *fd ); + + void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1 + void (*DrawStretchPic) ( float x, float y, float w, float h, + float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white + + // Draw images for cinematic rendering, pass as 32 bit rgba + void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); + void (*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); + + void (*BeginFrame)( stereoFrame_t stereoFrame ); + + // if the pointers are not NULL, timing info will be returned + void (*EndFrame)( int *frontEndMsec, int *backEndMsec ); + + + int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection, + int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); + + int (*LerpTag)( orientation_t *tag, qhandle_t model, int startFrame, int endFrame, + float frac, const char *tagName ); + void (*ModelBounds)( qhandle_t model, vec3_t mins, vec3_t maxs ); + +#ifdef __USEA3D + void (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus); +#endif + void (*RegisterFont)(const char *fontName, int pointSize, fontInfo_t *font); + void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime); + qboolean (*GetEntityToken)( char *buffer, int size ); + qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 ); +} refexport_t; + +// +// these are the functions imported by the refresh module +// +typedef struct { + // print message on the local console + void (QDECL *Printf)( int printLevel, const char *fmt, ...); + + // abort the game + void (QDECL *Error)( int errorLevel, const char *fmt, ...); + + // milliseconds should only be used for profiling, never + // for anything game related. Get time from the refdef + int (*Milliseconds)( void ); + + // stack based memory allocation for per-level things that + // won't be freed +#ifdef HUNK_DEBUG + void *(*Hunk_AllocDebug)( int size, ha_pref pref, char *label, char *file, int line ); +#else + void *(*Hunk_Alloc)( int size, ha_pref pref ); +#endif + void *(*Hunk_AllocateTempMemory)( int size ); + void (*Hunk_FreeTempMemory)( void *block ); + + // dynamic memory allocator for things that need to be freed + void *(*Malloc)( int bytes ); + void (*Free)( void *buf ); + + cvar_t *(*Cvar_Get)( const char *name, const char *value, int flags ); + void (*Cvar_Set)( const char *name, const char *value ); + + void (*Cmd_AddCommand)( const char *name, void(*cmd)(void) ); + void (*Cmd_RemoveCommand)( const char *name ); + + int (*Cmd_Argc) (void); + char *(*Cmd_Argv) (int i); + + void (*Cmd_ExecuteText) (int exec_when, const char *text); + + // visualization for debugging collision detection + void (*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) ); + + // a -1 return means the file does not exist + // NULL can be passed for buf to just determine existance + int (*FS_FileIsInPAK)( const char *name, int *pCheckSum ); + int (*FS_ReadFile)( const char *name, void **buf ); + void (*FS_FreeFile)( void *buf ); + char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound ); + void (*FS_FreeFileList)( char **filelist ); + void (*FS_WriteFile)( const char *qpath, const void *buffer, int size ); + qboolean (*FS_FileExists)( const char *file ); + + // cinematic stuff + void (*CIN_UploadCinematic)(int handle); + int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits); + e_status (*CIN_RunCinematic) (int handle); + +} refimport_t; + + +// this is the only function actually exported at the linker level +// If the module can't init to a valid rendering state, NULL will be +// returned. +refexport_t*GetRefAPI( int apiVersion, refimport_t *rimp ); + +#endif // __TR_PUBLIC_H diff --git a/code/renderer/tr_scene.c b/code/renderer/tr_scene.c index 24f569e..8cde15b 100755 --- a/code/renderer/tr_scene.c +++ b/code/renderer/tr_scene.c @@ -1,409 +1,409 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "tr_local.h"
-
-int r_firstSceneDrawSurf;
-
-int r_numdlights;
-int r_firstSceneDlight;
-
-int r_numentities;
-int r_firstSceneEntity;
-
-int r_numpolys;
-int r_firstScenePoly;
-
-int r_numpolyverts;
-
-
-/*
-====================
-R_ToggleSmpFrame
-
-====================
-*/
-void R_ToggleSmpFrame( void ) {
- if ( r_smp->integer ) {
- // use the other buffers next frame, because another CPU
- // may still be rendering into the current ones
- tr.smpFrame ^= 1;
- } else {
- tr.smpFrame = 0;
- }
-
- backEndData[tr.smpFrame]->commands.used = 0;
-
- r_firstSceneDrawSurf = 0;
-
- r_numdlights = 0;
- r_firstSceneDlight = 0;
-
- r_numentities = 0;
- r_firstSceneEntity = 0;
-
- r_numpolys = 0;
- r_firstScenePoly = 0;
-
- r_numpolyverts = 0;
-}
-
-
-/*
-====================
-RE_ClearScene
-
-====================
-*/
-void RE_ClearScene( void ) {
- r_firstSceneDlight = r_numdlights;
- r_firstSceneEntity = r_numentities;
- r_firstScenePoly = r_numpolys;
-}
-
-/*
-===========================================================================
-
-DISCRETE POLYS
-
-===========================================================================
-*/
-
-/*
-=====================
-R_AddPolygonSurfaces
-
-Adds all the scene's polys into this view's drawsurf list
-=====================
-*/
-void R_AddPolygonSurfaces( void ) {
- int i;
- shader_t *sh;
- srfPoly_t *poly;
-
- tr.currentEntityNum = ENTITYNUM_WORLD;
- tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
-
- for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
- sh = R_GetShaderByHandle( poly->hShader );
- R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
- }
-}
-
-/*
-=====================
-RE_AddPolyToScene
-
-=====================
-*/
-void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
- srfPoly_t *poly;
- int i, j;
- int fogIndex;
- fog_t *fog;
- vec3_t bounds[2];
-
- if ( !tr.registered ) {
- return;
- }
-
- if ( !hShader ) {
- ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
- return;
- }
-
- for ( j = 0; j < numPolys; j++ ) {
- if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
- /*
- NOTE TTimo this was initially a PRINT_WARNING
- but it happens a lot with high fighting scenes and particles
- since we don't plan on changing the const and making for room for those effects
- simply cut this message to developer only
- */
- ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
- return;
- }
-
- poly = &backEndData[tr.smpFrame]->polys[r_numpolys];
- poly->surfaceType = SF_POLY;
- poly->hShader = hShader;
- poly->numVerts = numVerts;
- poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts];
-
- Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
-
- if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
- poly->verts->modulate[0] = 255;
- poly->verts->modulate[1] = 255;
- poly->verts->modulate[2] = 255;
- poly->verts->modulate[3] = 255;
- }
- // done.
- r_numpolys++;
- r_numpolyverts += numVerts;
-
- // if no world is loaded
- if ( tr.world == NULL ) {
- fogIndex = 0;
- }
- // see if it is in a fog volume
- else if ( tr.world->numfogs == 1 ) {
- fogIndex = 0;
- } else {
- // find which fog volume the poly is in
- VectorCopy( poly->verts[0].xyz, bounds[0] );
- VectorCopy( poly->verts[0].xyz, bounds[1] );
- for ( i = 1 ; i < poly->numVerts ; i++ ) {
- AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
- }
- for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
- fog = &tr.world->fogs[fogIndex];
- if ( bounds[1][0] >= fog->bounds[0][0]
- && bounds[1][1] >= fog->bounds[0][1]
- && bounds[1][2] >= fog->bounds[0][2]
- && bounds[0][0] <= fog->bounds[1][0]
- && bounds[0][1] <= fog->bounds[1][1]
- && bounds[0][2] <= fog->bounds[1][2] ) {
- break;
- }
- }
- if ( fogIndex == tr.world->numfogs ) {
- fogIndex = 0;
- }
- }
- poly->fogIndex = fogIndex;
- }
-}
-
-
-//=================================================================================
-
-
-/*
-=====================
-RE_AddRefEntityToScene
-
-=====================
-*/
-void RE_AddRefEntityToScene( const refEntity_t *ent ) {
- if ( !tr.registered ) {
- return;
- }
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=402
- if ( r_numentities >= ENTITYNUM_WORLD ) {
- return;
- }
- if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
- ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
- }
-
- backEndData[tr.smpFrame]->entities[r_numentities].e = *ent;
- backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse;
-
- r_numentities++;
-}
-
-
-/*
-=====================
-RE_AddDynamicLightToScene
-
-=====================
-*/
-void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
- dlight_t *dl;
-
- if ( !tr.registered ) {
- return;
- }
- if ( r_numdlights >= MAX_DLIGHTS ) {
- return;
- }
- if ( intensity <= 0 ) {
- return;
- }
- // these cards don't have the correct blend mode
- if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- return;
- }
- dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++];
- VectorCopy (org, dl->origin);
- dl->radius = intensity;
- dl->color[0] = r;
- dl->color[1] = g;
- dl->color[2] = b;
- dl->additive = additive;
-}
-
-/*
-=====================
-RE_AddLightToScene
-
-=====================
-*/
-void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
-}
-
-/*
-=====================
-RE_AddAdditiveLightToScene
-
-=====================
-*/
-void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
- RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
-}
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-RE_RenderScene
-
-Draw a 3D view into a part of the window, then return
-to 2D drawing.
-
-Rendering a scene may require multiple views to be rendered
-to handle mirrors,
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void RE_RenderScene( const refdef_t *fd ) {
- viewParms_t parms;
- int startTime;
-
- if ( !tr.registered ) {
- return;
- }
- GLimp_LogComment( "====== RE_RenderScene =====\n" );
-
- if ( r_norefresh->integer ) {
- return;
- }
-
- startTime = ri.Milliseconds();
-
- if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
- ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
- }
-
- Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
-
- tr.refdef.x = fd->x;
- tr.refdef.y = fd->y;
- tr.refdef.width = fd->width;
- tr.refdef.height = fd->height;
- tr.refdef.fov_x = fd->fov_x;
- tr.refdef.fov_y = fd->fov_y;
-
- VectorCopy( fd->vieworg, tr.refdef.vieworg );
- VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
- VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
- VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
-
- tr.refdef.time = fd->time;
- tr.refdef.rdflags = fd->rdflags;
-
- // copy the areamask data over and note if it has changed, which
- // will force a reset of the visible leafs even if the view hasn't moved
- tr.refdef.areamaskModified = qfalse;
- if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
- int areaDiff;
- int i;
-
- // compare the area bits
- areaDiff = 0;
- for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
- areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
- ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
- }
-
- if ( areaDiff ) {
- // a door just opened or something
- tr.refdef.areamaskModified = qtrue;
- }
- }
-
-
- // derived info
-
- tr.refdef.floatTime = tr.refdef.time * 0.001f;
-
- tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
- tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs;
-
- tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
- tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity];
-
- tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
- tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight];
-
- tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
- tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly];
-
- // turn off dynamic lighting globally by clearing all the
- // dlights if it needs to be disabled or if vertex lighting is enabled
- if ( r_dynamiclight->integer == 0 ||
- r_vertexLight->integer == 1 ||
- glConfig.hardwareType == GLHW_PERMEDIA2 ) {
- tr.refdef.num_dlights = 0;
- }
-
- // a single frame may have multiple scenes draw inside it --
- // a 3D game view, 3D status bar renderings, 3D menus, etc.
- // They need to be distinguished by the light flare code, because
- // the visibility state for a given surface may be different in
- // each scene / view.
- tr.frameSceneNum++;
- tr.sceneCount++;
-
- // setup view parms for the initial view
- //
- // set up viewport
- // The refdef takes 0-at-the-top y coordinates, so
- // convert to GL's 0-at-the-bottom space
- //
- Com_Memset( &parms, 0, sizeof( parms ) );
- parms.viewportX = tr.refdef.x;
- parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
- parms.viewportWidth = tr.refdef.width;
- parms.viewportHeight = tr.refdef.height;
- parms.isPortal = qfalse;
-
- parms.fovX = tr.refdef.fov_x;
- parms.fovY = tr.refdef.fov_y;
-
- VectorCopy( fd->vieworg, parms.or.origin );
- VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
- VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
- VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
-
- VectorCopy( fd->vieworg, parms.pvsOrigin );
-
- R_RenderView( &parms );
-
- // the next scene rendered in this frame will tack on after this one
- r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
- r_firstSceneEntity = r_numentities;
- r_firstSceneDlight = r_numdlights;
- r_firstScenePoly = r_numpolys;
-
- tr.frontEndMsec += ri.Milliseconds() - startTime;
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "tr_local.h" + +int r_firstSceneDrawSurf; + +int r_numdlights; +int r_firstSceneDlight; + +int r_numentities; +int r_firstSceneEntity; + +int r_numpolys; +int r_firstScenePoly; + +int r_numpolyverts; + + +/* +==================== +R_ToggleSmpFrame + +==================== +*/ +void R_ToggleSmpFrame( void ) { + if ( r_smp->integer ) { + // use the other buffers next frame, because another CPU + // may still be rendering into the current ones + tr.smpFrame ^= 1; + } else { + tr.smpFrame = 0; + } + + backEndData[tr.smpFrame]->commands.used = 0; + + r_firstSceneDrawSurf = 0; + + r_numdlights = 0; + r_firstSceneDlight = 0; + + r_numentities = 0; + r_firstSceneEntity = 0; + + r_numpolys = 0; + r_firstScenePoly = 0; + + r_numpolyverts = 0; +} + + +/* +==================== +RE_ClearScene + +==================== +*/ +void RE_ClearScene( void ) { + r_firstSceneDlight = r_numdlights; + r_firstSceneEntity = r_numentities; + r_firstScenePoly = r_numpolys; +} + +/* +=========================================================================== + +DISCRETE POLYS + +=========================================================================== +*/ + +/* +===================== +R_AddPolygonSurfaces + +Adds all the scene's polys into this view's drawsurf list +===================== +*/ +void R_AddPolygonSurfaces( void ) { + int i; + shader_t *sh; + srfPoly_t *poly; + + tr.currentEntityNum = ENTITYNUM_WORLD; + tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; + + for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { + sh = R_GetShaderByHandle( poly->hShader ); + R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse ); + } +} + +/* +===================== +RE_AddPolyToScene + +===================== +*/ +void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) { + srfPoly_t *poly; + int i, j; + int fogIndex; + fog_t *fog; + vec3_t bounds[2]; + + if ( !tr.registered ) { + return; + } + + if ( !hShader ) { + ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n"); + return; + } + + for ( j = 0; j < numPolys; j++ ) { + if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) { + /* + NOTE TTimo this was initially a PRINT_WARNING + but it happens a lot with high fighting scenes and particles + since we don't plan on changing the const and making for room for those effects + simply cut this message to developer only + */ + ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); + return; + } + + poly = &backEndData[tr.smpFrame]->polys[r_numpolys]; + poly->surfaceType = SF_POLY; + poly->hShader = hShader; + poly->numVerts = numVerts; + poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts]; + + Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); + + if ( glConfig.hardwareType == GLHW_RAGEPRO ) { + poly->verts->modulate[0] = 255; + poly->verts->modulate[1] = 255; + poly->verts->modulate[2] = 255; + poly->verts->modulate[3] = 255; + } + // done. + r_numpolys++; + r_numpolyverts += numVerts; + + // if no world is loaded + if ( tr.world == NULL ) { + fogIndex = 0; + } + // see if it is in a fog volume + else if ( tr.world->numfogs == 1 ) { + fogIndex = 0; + } else { + // find which fog volume the poly is in + VectorCopy( poly->verts[0].xyz, bounds[0] ); + VectorCopy( poly->verts[0].xyz, bounds[1] ); + for ( i = 1 ; i < poly->numVerts ; i++ ) { + AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] ); + } + for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) { + fog = &tr.world->fogs[fogIndex]; + if ( bounds[1][0] >= fog->bounds[0][0] + && bounds[1][1] >= fog->bounds[0][1] + && bounds[1][2] >= fog->bounds[0][2] + && bounds[0][0] <= fog->bounds[1][0] + && bounds[0][1] <= fog->bounds[1][1] + && bounds[0][2] <= fog->bounds[1][2] ) { + break; + } + } + if ( fogIndex == tr.world->numfogs ) { + fogIndex = 0; + } + } + poly->fogIndex = fogIndex; + } +} + + +//================================================================================= + + +/* +===================== +RE_AddRefEntityToScene + +===================== +*/ +void RE_AddRefEntityToScene( const refEntity_t *ent ) { + if ( !tr.registered ) { + return; + } + // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=402 + if ( r_numentities >= ENTITYNUM_WORLD ) { + return; + } + if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) { + ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); + } + + backEndData[tr.smpFrame]->entities[r_numentities].e = *ent; + backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse; + + r_numentities++; +} + + +/* +===================== +RE_AddDynamicLightToScene + +===================== +*/ +void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) { + dlight_t *dl; + + if ( !tr.registered ) { + return; + } + if ( r_numdlights >= MAX_DLIGHTS ) { + return; + } + if ( intensity <= 0 ) { + return; + } + // these cards don't have the correct blend mode + if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { + return; + } + dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++]; + VectorCopy (org, dl->origin); + dl->radius = intensity; + dl->color[0] = r; + dl->color[1] = g; + dl->color[2] = b; + dl->additive = additive; +} + +/* +===================== +RE_AddLightToScene + +===================== +*/ +void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { + RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); +} + +/* +===================== +RE_AddAdditiveLightToScene + +===================== +*/ +void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { + RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue ); +} + +/* +@@@@@@@@@@@@@@@@@@@@@ +RE_RenderScene + +Draw a 3D view into a part of the window, then return +to 2D drawing. + +Rendering a scene may require multiple views to be rendered +to handle mirrors, +@@@@@@@@@@@@@@@@@@@@@ +*/ +void RE_RenderScene( const refdef_t *fd ) { + viewParms_t parms; + int startTime; + + if ( !tr.registered ) { + return; + } + GLimp_LogComment( "====== RE_RenderScene =====\n" ); + + if ( r_norefresh->integer ) { + return; + } + + startTime = ri.Milliseconds(); + + if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { + ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); + } + + Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); + + tr.refdef.x = fd->x; + tr.refdef.y = fd->y; + tr.refdef.width = fd->width; + tr.refdef.height = fd->height; + tr.refdef.fov_x = fd->fov_x; + tr.refdef.fov_y = fd->fov_y; + + VectorCopy( fd->vieworg, tr.refdef.vieworg ); + VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); + VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); + VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); + + tr.refdef.time = fd->time; + tr.refdef.rdflags = fd->rdflags; + + // copy the areamask data over and note if it has changed, which + // will force a reset of the visible leafs even if the view hasn't moved + tr.refdef.areamaskModified = qfalse; + if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { + int areaDiff; + int i; + + // compare the area bits + areaDiff = 0; + for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { + areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; + ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; + } + + if ( areaDiff ) { + // a door just opened or something + tr.refdef.areamaskModified = qtrue; + } + } + + + // derived info + + tr.refdef.floatTime = tr.refdef.time * 0.001f; + + tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; + tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs; + + tr.refdef.num_entities = r_numentities - r_firstSceneEntity; + tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity]; + + tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; + tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight]; + + tr.refdef.numPolys = r_numpolys - r_firstScenePoly; + tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly]; + + // turn off dynamic lighting globally by clearing all the + // dlights if it needs to be disabled or if vertex lighting is enabled + if ( r_dynamiclight->integer == 0 || + r_vertexLight->integer == 1 || + glConfig.hardwareType == GLHW_PERMEDIA2 ) { + tr.refdef.num_dlights = 0; + } + + // a single frame may have multiple scenes draw inside it -- + // a 3D game view, 3D status bar renderings, 3D menus, etc. + // They need to be distinguished by the light flare code, because + // the visibility state for a given surface may be different in + // each scene / view. + tr.frameSceneNum++; + tr.sceneCount++; + + // setup view parms for the initial view + // + // set up viewport + // The refdef takes 0-at-the-top y coordinates, so + // convert to GL's 0-at-the-bottom space + // + Com_Memset( &parms, 0, sizeof( parms ) ); + parms.viewportX = tr.refdef.x; + parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); + parms.viewportWidth = tr.refdef.width; + parms.viewportHeight = tr.refdef.height; + parms.isPortal = qfalse; + + parms.fovX = tr.refdef.fov_x; + parms.fovY = tr.refdef.fov_y; + + VectorCopy( fd->vieworg, parms.or.origin ); + VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); + VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); + VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); + + VectorCopy( fd->vieworg, parms.pvsOrigin ); + + R_RenderView( &parms ); + + // the next scene rendered in this frame will tack on after this one + r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; + r_firstSceneEntity = r_numentities; + r_firstSceneDlight = r_numdlights; + r_firstScenePoly = r_numpolys; + + tr.frontEndMsec += ri.Milliseconds() - startTime; +} diff --git a/code/renderer/tr_shade.c b/code/renderer/tr_shade.c index eae4c1f..e6f8688 100755 --- a/code/renderer/tr_shade.c +++ b/code/renderer/tr_shade.c @@ -1,1361 +1,1361 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_shade.c
-
-#include "tr_local.h"
-
-/*
-
- THIS ENTIRE FILE IS BACK END
-
- This file deals with applying shaders to surface data in the tess struct.
-*/
-
-/*
-================
-R_ArrayElementDiscrete
-
-This is just for OpenGL conformance testing, it should never be the fastest
-================
-*/
-static void APIENTRY R_ArrayElementDiscrete( GLint index ) {
- qglColor4ubv( tess.svars.colors[ index ] );
- if ( glState.currenttmu ) {
- qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] );
- qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] );
- } else {
- qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] );
- }
- qglVertex3fv( tess.xyz[ index ] );
-}
-
-/*
-===================
-R_DrawStripElements
-
-===================
-*/
-static int c_vertexes; // for seeing how long our average strips are
-static int c_begins;
-static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) {
- int i;
- int last[3] = { -1, -1, -1 };
- qboolean even;
-
- c_begins++;
-
- if ( numIndexes <= 0 ) {
- return;
- }
-
- qglBegin( GL_TRIANGLE_STRIP );
-
- // prime the strip
- element( indexes[0] );
- element( indexes[1] );
- element( indexes[2] );
- c_vertexes += 3;
-
- last[0] = indexes[0];
- last[1] = indexes[1];
- last[2] = indexes[2];
-
- even = qfalse;
-
- for ( i = 3; i < numIndexes; i += 3 )
- {
- // odd numbered triangle in potential strip
- if ( !even )
- {
- // check previous triangle to see if we're continuing a strip
- if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) )
- {
- element( indexes[i+2] );
- c_vertexes++;
- assert( indexes[i+2] < tess.numVertexes );
- even = qtrue;
- }
- // otherwise we're done with this strip so finish it and start
- // a new one
- else
- {
- qglEnd();
-
- qglBegin( GL_TRIANGLE_STRIP );
- c_begins++;
-
- element( indexes[i+0] );
- element( indexes[i+1] );
- element( indexes[i+2] );
-
- c_vertexes += 3;
-
- even = qfalse;
- }
- }
- else
- {
- // check previous triangle to see if we're continuing a strip
- if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) )
- {
- element( indexes[i+2] );
- c_vertexes++;
-
- even = qfalse;
- }
- // otherwise we're done with this strip so finish it and start
- // a new one
- else
- {
- qglEnd();
-
- qglBegin( GL_TRIANGLE_STRIP );
- c_begins++;
-
- element( indexes[i+0] );
- element( indexes[i+1] );
- element( indexes[i+2] );
- c_vertexes += 3;
-
- even = qfalse;
- }
- }
-
- // cache the last three vertices
- last[0] = indexes[i+0];
- last[1] = indexes[i+1];
- last[2] = indexes[i+2];
- }
-
- qglEnd();
-}
-
-
-
-/*
-==================
-R_DrawElements
-
-Optionally performs our own glDrawElements that looks for strip conditions
-instead of using the single glDrawElements call that may be inefficient
-without compiled vertex arrays.
-==================
-*/
-static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) {
- int primitives;
-
- primitives = r_primitives->integer;
-
- // default is to use triangles if compiled vertex arrays are present
- if ( primitives == 0 ) {
- if ( qglLockArraysEXT ) {
- primitives = 2;
- } else {
- primitives = 1;
- }
- }
-
-
- if ( primitives == 2 ) {
- qglDrawElements( GL_TRIANGLES,
- numIndexes,
- GL_INDEX_TYPE,
- indexes );
- return;
- }
-
- if ( primitives == 1 ) {
- R_DrawStripElements( numIndexes, indexes, qglArrayElement );
- return;
- }
-
- if ( primitives == 3 ) {
- R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete );
- return;
- }
-
- // anything else will cause no drawing
-}
-
-
-/*
-=============================================================
-
-SURFACE SHADERS
-
-=============================================================
-*/
-
-shaderCommands_t tess;
-static qboolean setArraysOnce;
-
-/*
-=================
-R_BindAnimatedImage
-
-=================
-*/
-static void R_BindAnimatedImage( textureBundle_t *bundle ) {
- int index;
-
- if ( bundle->isVideoMap ) {
- ri.CIN_RunCinematic(bundle->videoMapHandle);
- ri.CIN_UploadCinematic(bundle->videoMapHandle);
- return;
- }
-
- if ( bundle->numImageAnimations <= 1 ) {
- GL_Bind( bundle->image[0] );
- return;
- }
-
- // it is necessary to do this messy calc to make sure animations line up
- // exactly with waveforms of the same frequency
- index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE );
- index >>= FUNCTABLE_SIZE2;
-
- if ( index < 0 ) {
- index = 0; // may happen with shader time offsets
- }
- index %= bundle->numImageAnimations;
-
- GL_Bind( bundle->image[ index ] );
-}
-
-/*
-================
-DrawTris
-
-Draws triangle outlines for debugging
-================
-*/
-static void DrawTris (shaderCommands_t *input) {
- GL_Bind( tr.whiteImage );
- qglColor3f (1,1,1);
-
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
- qglDepthRange( 0, 0 );
-
- qglDisableClientState (GL_COLOR_ARRAY);
- qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
-
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
-
- if (qglLockArraysEXT) {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- R_DrawElements( input->numIndexes, input->indexes );
-
- if (qglUnlockArraysEXT) {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
- qglDepthRange( 0, 1 );
-}
-
-
-/*
-================
-DrawNormals
-
-Draws vertex normals for debugging
-================
-*/
-static void DrawNormals (shaderCommands_t *input) {
- int i;
- vec3_t temp;
-
- GL_Bind( tr.whiteImage );
- qglColor3f (1,1,1);
- qglDepthRange( 0, 0 ); // never occluded
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
-
- qglBegin (GL_LINES);
- for (i = 0 ; i < input->numVertexes ; i++) {
- qglVertex3fv (input->xyz[i]);
- VectorMA (input->xyz[i], 2, input->normal[i], temp);
- qglVertex3fv (temp);
- }
- qglEnd ();
-
- qglDepthRange( 0, 1 );
-}
-
-/*
-==============
-RB_BeginSurface
-
-We must set some things up before beginning any tesselation,
-because a surface may be forced to perform a RB_End due
-to overflow.
-==============
-*/
-void RB_BeginSurface( shader_t *shader, int fogNum ) {
-
- shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
-
- tess.numIndexes = 0;
- tess.numVertexes = 0;
- tess.shader = state;
- tess.fogNum = fogNum;
- tess.dlightBits = 0; // will be OR'd in by surface functions
- tess.xstages = state->stages;
- tess.numPasses = state->numUnfoggedPasses;
- tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
-
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
- if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
- tess.shaderTime = tess.shader->clampTime;
- }
-
-
-}
-
-/*
-===================
-DrawMultitextured
-
-output = t0 * t1 or t0 + t1
-
-t0 = most upstream according to spec
-t1 = most downstream according to spec
-===================
-*/
-static void DrawMultitextured( shaderCommands_t *input, int stage ) {
- shaderStage_t *pStage;
-
- pStage = tess.xstages[stage];
-
- GL_State( pStage->stateBits );
-
- // this is an ugly hack to work around a GeForce driver
- // bug with multitexture and clip planes
- if ( backEnd.viewParms.isPortal ) {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- }
-
- //
- // base
- //
- GL_SelectTexture( 0 );
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
- R_BindAnimatedImage( &pStage->bundle[0] );
-
- //
- // lightmap/secondary pass
- //
- GL_SelectTexture( 1 );
- qglEnable( GL_TEXTURE_2D );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
-
- if ( r_lightmap->integer ) {
- GL_TexEnv( GL_REPLACE );
- } else {
- GL_TexEnv( tess.shader->multitextureEnv );
- }
-
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );
-
- R_BindAnimatedImage( &pStage->bundle[1] );
-
- R_DrawElements( input->numIndexes, input->indexes );
-
- //
- // disable texturing on TEXTURE1, then select TEXTURE0
- //
- //qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
- qglDisable( GL_TEXTURE_2D );
-
- GL_SelectTexture( 0 );
-}
-
-
-
-/*
-===================
-ProjectDlightTexture
-
-Perform dynamic lighting with another rendering pass
-===================
-*/
-static void ProjectDlightTexture( void ) {
- int i, l;
-#if idppc_altivec
- vec_t origin0, origin1, origin2;
- float texCoords0, texCoords1;
- vector float floatColorVec0, floatColorVec1;
- vector float modulateVec, colorVec, zero;
- vector short colorShort;
- vector signed int colorInt;
- vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
- vector unsigned char vSel = (vector unsigned char)(0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff);
-#else
- vec3_t origin;
-#endif
- float *texCoords;
- byte *colors;
- byte clipBits[SHADER_MAX_VERTEXES];
- MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2];
- byte colorArray[SHADER_MAX_VERTEXES][4];
- unsigned hitIndexes[SHADER_MAX_INDEXES];
- int numIndexes;
- float scale;
- float radius;
- vec3_t floatColor;
- float modulate;
-
- if ( !backEnd.refdef.num_dlights ) {
- return;
- }
-
-#if idppc_altivec
- // There has to be a better way to do this so that floatColor
- // and/or modulate are already 16-byte aligned.
- floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
- modulatePerm = vec_lvsl(0,(float *)&modulate);
- modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
- zero = (vector float)vec_splat_s8(0);
-#endif
-
- for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
- dlight_t *dl;
-
- if ( !( tess.dlightBits & ( 1 << l ) ) ) {
- continue; // this surface definately doesn't have any of this light
- }
- texCoords = texCoordsArray[0];
- colors = colorArray[0];
-
- dl = &backEnd.refdef.dlights[l];
-#if idppc_altivec
- origin0 = dl->transformed[0];
- origin1 = dl->transformed[1];
- origin2 = dl->transformed[2];
-#else
- VectorCopy( dl->transformed, origin );
-#endif
- radius = dl->radius;
- scale = 1.0f / radius;
-
- floatColor[0] = dl->color[0] * 255.0f;
- floatColor[1] = dl->color[1] * 255.0f;
- floatColor[2] = dl->color[2] * 255.0f;
-#if idppc_altivec
- floatColorVec0 = vec_ld(0, floatColor);
- floatColorVec1 = vec_ld(11, floatColor);
- floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
-#endif
- for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
-#if idppc_altivec
- vec_t dist0, dist1, dist2;
-#else
- vec3_t dist;
-#endif
- int clip;
-
- backEnd.pc.c_dlightVertexes++;
-
-#if idppc_altivec
- //VectorSubtract( origin, tess.xyz[i], dist );
- dist0 = origin0 - tess.xyz[i][0];
- dist1 = origin1 - tess.xyz[i][1];
- dist2 = origin2 - tess.xyz[i][2];
- texCoords0 = 0.5f + dist0 * scale;
- texCoords1 = 0.5f + dist1 * scale;
-
- clip = 0;
- if ( texCoords0 < 0.0f ) {
- clip |= 1;
- } else if ( texCoords0 > 1.0f ) {
- clip |= 2;
- }
- if ( texCoords1 < 0.0f ) {
- clip |= 4;
- } else if ( texCoords1 > 1.0f ) {
- clip |= 8;
- }
- texCoords[0] = texCoords0;
- texCoords[1] = texCoords1;
-
- // modulate the strength based on the height and color
- if ( dist2 > radius ) {
- clip |= 16;
- modulate = 0.0f;
- } else if ( dist2 < -radius ) {
- clip |= 32;
- modulate = 0.0f;
- } else {
- dist2 = Q_fabs(dist2);
- if ( dist2 < radius * 0.5f ) {
- modulate = 1.0f;
- } else {
- modulate = 2.0f * (radius - dist2) * scale;
- }
- }
- clipBits[i] = clip;
-
- modulateVec = vec_ld(0,(float *)&modulate);
- modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
- colorVec = vec_madd(floatColorVec0,modulateVec,zero);
- colorInt = vec_cts(colorVec,0); // RGBx
- colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx
- colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx
- colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
- vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color
-#else
- VectorSubtract( origin, tess.xyz[i], dist );
- texCoords[0] = 0.5f + dist[0] * scale;
- texCoords[1] = 0.5f + dist[1] * scale;
-
- clip = 0;
- if ( texCoords[0] < 0.0f ) {
- clip |= 1;
- } else if ( texCoords[0] > 1.0f ) {
- clip |= 2;
- }
- if ( texCoords[1] < 0.0f ) {
- clip |= 4;
- } else if ( texCoords[1] > 1.0f ) {
- clip |= 8;
- }
- // modulate the strength based on the height and color
- if ( dist[2] > radius ) {
- clip |= 16;
- modulate = 0.0f;
- } else if ( dist[2] < -radius ) {
- clip |= 32;
- modulate = 0.0f;
- } else {
- dist[2] = Q_fabs(dist[2]);
- if ( dist[2] < radius * 0.5f ) {
- modulate = 1.0f;
- } else {
- modulate = 2.0f * (radius - dist[2]) * scale;
- }
- }
- clipBits[i] = clip;
-
- colors[0] = myftol(floatColor[0] * modulate);
- colors[1] = myftol(floatColor[1] * modulate);
- colors[2] = myftol(floatColor[2] * modulate);
- colors[3] = 255;
-#endif
- }
-
- // build a list of triangles that need light
- numIndexes = 0;
- for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
- int a, b, c;
-
- a = tess.indexes[i];
- b = tess.indexes[i+1];
- c = tess.indexes[i+2];
- if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
- continue; // not lighted
- }
- hitIndexes[numIndexes] = a;
- hitIndexes[numIndexes+1] = b;
- hitIndexes[numIndexes+2] = c;
- numIndexes += 3;
- }
-
- if ( !numIndexes ) {
- continue;
- }
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
-
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
-
- GL_Bind( tr.dlightImage );
- // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
- // where they aren't rendered
- if ( dl->additive ) {
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- else {
- GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- R_DrawElements( numIndexes, hitIndexes );
- backEnd.pc.c_totalIndexes += numIndexes;
- backEnd.pc.c_dlightIndexes += numIndexes;
- }
-}
-
-
-/*
-===================
-RB_FogPass
-
-Blends a fog texture on top of everything else
-===================
-*/
-static void RB_FogPass( void ) {
- fog_t *fog;
- int i;
-
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
-
- fog = tr.world->fogs + tess.fogNum;
-
- for ( i = 0; i < tess.numVertexes; i++ ) {
- * ( int * )&tess.svars.colors[i] = fog->colorInt;
- }
-
- RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );
-
- GL_Bind( tr.fogImage );
-
- if ( tess.shader->fogPass == FP_EQUAL ) {
- GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
- } else {
- GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
- }
-
- R_DrawElements( tess.numIndexes, tess.indexes );
-}
-
-/*
-===============
-ComputeColors
-===============
-*/
-static void ComputeColors( shaderStage_t *pStage )
-{
- int i;
-
- //
- // rgbGen
- //
- switch ( pStage->rgbGen )
- {
- case CGEN_IDENTITY:
- Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 );
- break;
- default:
- case CGEN_IDENTITY_LIGHTING:
- Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );
- break;
- case CGEN_LIGHTING_DIFFUSE:
- RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_EXACT_VERTEX:
- Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
- break;
- case CGEN_CONST:
- for ( i = 0; i < tess.numVertexes; i++ ) {
- *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor;
- }
- break;
- case CGEN_VERTEX:
- if ( tr.identityLight == 1 )
- {
- Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
- }
- else
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight;
- tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight;
- tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight;
- tess.svars.colors[i][3] = tess.vertexColors[i][3];
- }
- }
- break;
- case CGEN_ONE_MINUS_VERTEX:
- if ( tr.identityLight == 1 )
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0];
- tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1];
- tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2];
- }
- }
- else
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight;
- tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight;
- tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight;
- }
- }
- break;
- case CGEN_FOG:
- {
- fog_t *fog;
-
- fog = tr.world->fogs + tess.fogNum;
-
- for ( i = 0; i < tess.numVertexes; i++ ) {
- * ( int * )&tess.svars.colors[i] = fog->colorInt;
- }
- }
- break;
- case CGEN_WAVEFORM:
- RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_ENTITY:
- RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_ONE_MINUS_ENTITY:
- RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
- break;
- }
-
- //
- // alphaGen
- //
- switch ( pStage->alphaGen )
- {
- case AGEN_SKIP:
- break;
- case AGEN_IDENTITY:
- if ( pStage->rgbGen != CGEN_IDENTITY ) {
- if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) ||
- pStage->rgbGen != CGEN_VERTEX ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = 0xff;
- }
- }
- }
- break;
- case AGEN_CONST:
- if ( pStage->rgbGen != CGEN_CONST ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = pStage->constantColor[3];
- }
- }
- break;
- case AGEN_WAVEFORM:
- RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_LIGHTING_SPECULAR:
- RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_ENTITY:
- RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_ONE_MINUS_ENTITY:
- RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_VERTEX:
- if ( pStage->rgbGen != CGEN_VERTEX ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = tess.vertexColors[i][3];
- }
- }
- break;
- case AGEN_ONE_MINUS_VERTEX:
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3];
- }
- break;
- case AGEN_PORTAL:
- {
- unsigned char alpha;
-
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- float len;
- vec3_t v;
-
- VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v );
- len = VectorLength( v );
-
- len /= tess.shader->portalRange;
-
- if ( len < 0 )
- {
- alpha = 0;
- }
- else if ( len > 1 )
- {
- alpha = 0xff;
- }
- else
- {
- alpha = len * 0xff;
- }
-
- tess.svars.colors[i][3] = alpha;
- }
- }
- break;
- }
-
- //
- // fog adjustment for colors to fade out as fog increases
- //
- if ( tess.fogNum )
- {
- switch ( pStage->adjustColorsForFog )
- {
- case ACFF_MODULATE_RGB:
- RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_MODULATE_ALPHA:
- RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_MODULATE_RGBA:
- RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_NONE:
- break;
- }
- }
-}
-
-/*
-===============
-ComputeTexCoords
-===============
-*/
-static void ComputeTexCoords( shaderStage_t *pStage ) {
- int i;
- int b;
-
- for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) {
- int tm;
-
- //
- // generate the texture coordinates
- //
- switch ( pStage->bundle[b].tcGen )
- {
- case TCGEN_IDENTITY:
- Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes );
- break;
- case TCGEN_TEXTURE:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0];
- tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1];
- }
- break;
- case TCGEN_LIGHTMAP:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0];
- tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1];
- }
- break;
- case TCGEN_VECTOR:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] );
- tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] );
- }
- break;
- case TCGEN_FOG:
- RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] );
- break;
- case TCGEN_ENVIRONMENT_MAPPED:
- RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] );
- break;
- case TCGEN_BAD:
- return;
- }
-
- //
- // alter texture coordinates
- //
- for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) {
- switch ( pStage->bundle[b].texMods[tm].type )
- {
- case TMOD_NONE:
- tm = TR_MAX_TEXMODS; // break out of for loop
- break;
-
- case TMOD_TURBULENT:
- RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_ENTITY_TRANSLATE:
- RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_SCROLL:
- RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_SCALE:
- RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_STRETCH:
- RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_TRANSFORM:
- RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm],
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_ROTATE:
- RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- default:
- ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name );
- break;
- }
- }
- }
-}
-
-/*
-** RB_IterateStagesGeneric
-*/
-static void RB_IterateStagesGeneric( shaderCommands_t *input )
-{
- int stage;
-
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
- {
- shaderStage_t *pStage = tess.xstages[stage];
-
- if ( !pStage )
- {
- break;
- }
-
- ComputeColors( pStage );
- ComputeTexCoords( pStage );
-
- if ( !setArraysOnce )
- {
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );
- }
-
- //
- // do multitexture
- //
- if ( pStage->bundle[1].image[0] != 0 )
- {
- DrawMultitextured( input, stage );
- }
- else
- {
- if ( !setArraysOnce )
- {
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
- }
-
- //
- // set state
- //
- if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer )
- {
- GL_Bind( tr.whiteImage );
- }
- else
- R_BindAnimatedImage( &pStage->bundle[0] );
-
- GL_State( pStage->stateBits );
-
- //
- // draw
- //
- R_DrawElements( input->numIndexes, input->indexes );
- }
- // allow skipping out to show just lightmaps during development
- if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) )
- {
- break;
- }
- }
-}
-
-
-/*
-** RB_StageIteratorGeneric
-*/
-void RB_StageIteratorGeneric( void )
-{
- shaderCommands_t *input;
-
- input = &tess;
-
- RB_DeformTessGeometry();
-
- //
- // log this call
- //
- if ( r_logFile->integer )
- {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) );
- }
-
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
-
- // set polygon offset if necessary
- if ( input->shader->polygonOffset )
- {
- qglEnable( GL_POLYGON_OFFSET_FILL );
- qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
- }
-
- //
- // if there is only a single pass then we can enable color
- // and texture arrays before we compile, otherwise we need
- // to avoid compiling those arrays since they will change
- // during multipass rendering
- //
- if ( tess.numPasses > 1 || input->shader->multitextureEnv )
- {
- setArraysOnce = qfalse;
- qglDisableClientState (GL_COLOR_ARRAY);
- qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
- }
- else
- {
- setArraysOnce = qtrue;
-
- qglEnableClientState( GL_COLOR_ARRAY);
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
- }
-
- //
- // lock XYZ
- //
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
- if (qglLockArraysEXT)
- {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- //
- // enable color and texcoord arrays after the lock if necessary
- //
- if ( !setArraysOnce )
- {
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglEnableClientState( GL_COLOR_ARRAY );
- }
-
- //
- // call shader function
- //
- RB_IterateStagesGeneric( input );
-
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE
- && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
- ProjectDlightTexture();
- }
-
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
-
- //
- // unlock arrays
- //
- if (qglUnlockArraysEXT)
- {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
-
- //
- // reset polygon offset
- //
- if ( input->shader->polygonOffset )
- {
- qglDisable( GL_POLYGON_OFFSET_FILL );
- }
-}
-
-
-/*
-** RB_StageIteratorVertexLitTexture
-*/
-void RB_StageIteratorVertexLitTexture( void )
-{
- shaderCommands_t *input;
- shader_t *shader;
-
- input = &tess;
-
- shader = input->shader;
-
- //
- // compute colors
- //
- RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
-
- //
- // log this call
- //
- if ( r_logFile->integer )
- {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) );
- }
-
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
-
- //
- // set arrays and lock
- //
- qglEnableClientState( GL_COLOR_ARRAY);
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
-
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz);
-
- if ( qglLockArraysEXT )
- {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- //
- // call special shade routine
- //
- R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
- GL_State( tess.xstages[0]->stateBits );
- R_DrawElements( input->numIndexes, input->indexes );
-
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
- ProjectDlightTexture();
- }
-
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
-
- //
- // unlock arrays
- //
- if (qglUnlockArraysEXT)
- {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
-}
-
-//define REPLACE_MODE
-
-void RB_StageIteratorLightmappedMultitexture( void ) {
- shaderCommands_t *input;
-
- input = &tess;
-
- //
- // log this call
- //
- if ( r_logFile->integer ) {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) );
- }
-
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
-
- //
- // set color, pointers, and lock
- //
- GL_State( GLS_DEFAULT );
- qglVertexPointer( 3, GL_FLOAT, 16, input->xyz );
-
-#ifdef REPLACE_MODE
- qglDisableClientState( GL_COLOR_ARRAY );
- qglColor3f( 1, 1, 1 );
- qglShadeModel( GL_FLAT );
-#else
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 );
-#endif
-
- //
- // select base stage
- //
- GL_SelectTexture( 0 );
-
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
-
- //
- // configure second stage
- //
- GL_SelectTexture( 1 );
- qglEnable( GL_TEXTURE_2D );
- if ( r_lightmap->integer ) {
- GL_TexEnv( GL_REPLACE );
- } else {
- GL_TexEnv( GL_MODULATE );
- }
- R_BindAnimatedImage( &tess.xstages[0]->bundle[1] );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] );
-
- //
- // lock arrays
- //
- if ( qglLockArraysEXT ) {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
-
- R_DrawElements( input->numIndexes, input->indexes );
-
- //
- // disable texturing on TEXTURE1, then select TEXTURE0
- //
- qglDisable( GL_TEXTURE_2D );
- qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
-
- GL_SelectTexture( 0 );
-#ifdef REPLACE_MODE
- GL_TexEnv( GL_MODULATE );
- qglShadeModel( GL_SMOOTH );
-#endif
-
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
- ProjectDlightTexture();
- }
-
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
-
- //
- // unlock arrays
- //
- if ( qglUnlockArraysEXT ) {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
-}
-
-/*
-** RB_EndSurface
-*/
-void RB_EndSurface( void ) {
- shaderCommands_t *input;
-
- input = &tess;
-
- if (input->numIndexes == 0) {
- return;
- }
-
- if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
- ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
- }
- if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {
- ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
- }
-
- if ( tess.shader == tr.shadowShader ) {
- RB_ShadowTessEnd();
- return;
- }
-
- // for debugging of sort order issues, stop rendering after a given sort value
- if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {
- return;
- }
-
- //
- // update performance counters
- //
- backEnd.pc.c_shaders++;
- backEnd.pc.c_vertexes += tess.numVertexes;
- backEnd.pc.c_indexes += tess.numIndexes;
- backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;
-
- //
- // call off to shader specific tess end function
- //
- tess.currentStageIteratorFunc();
-
- //
- // draw debugging stuff
- //
- if ( r_showtris->integer ) {
- DrawTris (input);
- }
- if ( r_shownormals->integer ) {
- DrawNormals (input);
- }
- // clear shader so we can tell we don't have any unclosed surfaces
- tess.numIndexes = 0;
-
- GLimp_LogComment( "----------\n" );
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_shade.c + +#include "tr_local.h" + +/* + + THIS ENTIRE FILE IS BACK END + + This file deals with applying shaders to surface data in the tess struct. +*/ + +/* +================ +R_ArrayElementDiscrete + +This is just for OpenGL conformance testing, it should never be the fastest +================ +*/ +static void APIENTRY R_ArrayElementDiscrete( GLint index ) { + qglColor4ubv( tess.svars.colors[ index ] ); + if ( glState.currenttmu ) { + qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] ); + qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] ); + } else { + qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] ); + } + qglVertex3fv( tess.xyz[ index ] ); +} + +/* +=================== +R_DrawStripElements + +=================== +*/ +static int c_vertexes; // for seeing how long our average strips are +static int c_begins; +static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) { + int i; + int last[3] = { -1, -1, -1 }; + qboolean even; + + c_begins++; + + if ( numIndexes <= 0 ) { + return; + } + + qglBegin( GL_TRIANGLE_STRIP ); + + // prime the strip + element( indexes[0] ); + element( indexes[1] ); + element( indexes[2] ); + c_vertexes += 3; + + last[0] = indexes[0]; + last[1] = indexes[1]; + last[2] = indexes[2]; + + even = qfalse; + + for ( i = 3; i < numIndexes; i += 3 ) + { + // odd numbered triangle in potential strip + if ( !even ) + { + // check previous triangle to see if we're continuing a strip + if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) ) + { + element( indexes[i+2] ); + c_vertexes++; + assert( indexes[i+2] < tess.numVertexes ); + even = qtrue; + } + // otherwise we're done with this strip so finish it and start + // a new one + else + { + qglEnd(); + + qglBegin( GL_TRIANGLE_STRIP ); + c_begins++; + + element( indexes[i+0] ); + element( indexes[i+1] ); + element( indexes[i+2] ); + + c_vertexes += 3; + + even = qfalse; + } + } + else + { + // check previous triangle to see if we're continuing a strip + if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) ) + { + element( indexes[i+2] ); + c_vertexes++; + + even = qfalse; + } + // otherwise we're done with this strip so finish it and start + // a new one + else + { + qglEnd(); + + qglBegin( GL_TRIANGLE_STRIP ); + c_begins++; + + element( indexes[i+0] ); + element( indexes[i+1] ); + element( indexes[i+2] ); + c_vertexes += 3; + + even = qfalse; + } + } + + // cache the last three vertices + last[0] = indexes[i+0]; + last[1] = indexes[i+1]; + last[2] = indexes[i+2]; + } + + qglEnd(); +} + + + +/* +================== +R_DrawElements + +Optionally performs our own glDrawElements that looks for strip conditions +instead of using the single glDrawElements call that may be inefficient +without compiled vertex arrays. +================== +*/ +static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { + int primitives; + + primitives = r_primitives->integer; + + // default is to use triangles if compiled vertex arrays are present + if ( primitives == 0 ) { + if ( qglLockArraysEXT ) { + primitives = 2; + } else { + primitives = 1; + } + } + + + if ( primitives == 2 ) { + qglDrawElements( GL_TRIANGLES, + numIndexes, + GL_INDEX_TYPE, + indexes ); + return; + } + + if ( primitives == 1 ) { + R_DrawStripElements( numIndexes, indexes, qglArrayElement ); + return; + } + + if ( primitives == 3 ) { + R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); + return; + } + + // anything else will cause no drawing +} + + +/* +============================================================= + +SURFACE SHADERS + +============================================================= +*/ + +shaderCommands_t tess; +static qboolean setArraysOnce; + +/* +================= +R_BindAnimatedImage + +================= +*/ +static void R_BindAnimatedImage( textureBundle_t *bundle ) { + int index; + + if ( bundle->isVideoMap ) { + ri.CIN_RunCinematic(bundle->videoMapHandle); + ri.CIN_UploadCinematic(bundle->videoMapHandle); + return; + } + + if ( bundle->numImageAnimations <= 1 ) { + GL_Bind( bundle->image[0] ); + return; + } + + // it is necessary to do this messy calc to make sure animations line up + // exactly with waveforms of the same frequency + index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); + index >>= FUNCTABLE_SIZE2; + + if ( index < 0 ) { + index = 0; // may happen with shader time offsets + } + index %= bundle->numImageAnimations; + + GL_Bind( bundle->image[ index ] ); +} + +/* +================ +DrawTris + +Draws triangle outlines for debugging +================ +*/ +static void DrawTris (shaderCommands_t *input) { + GL_Bind( tr.whiteImage ); + qglColor3f (1,1,1); + + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); + qglDepthRange( 0, 0 ); + + qglDisableClientState (GL_COLOR_ARRAY); + qglDisableClientState (GL_TEXTURE_COORD_ARRAY); + + qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD + + if (qglLockArraysEXT) { + qglLockArraysEXT(0, input->numVertexes); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + + R_DrawElements( input->numIndexes, input->indexes ); + + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } + qglDepthRange( 0, 1 ); +} + + +/* +================ +DrawNormals + +Draws vertex normals for debugging +================ +*/ +static void DrawNormals (shaderCommands_t *input) { + int i; + vec3_t temp; + + GL_Bind( tr.whiteImage ); + qglColor3f (1,1,1); + qglDepthRange( 0, 0 ); // never occluded + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); + + qglBegin (GL_LINES); + for (i = 0 ; i < input->numVertexes ; i++) { + qglVertex3fv (input->xyz[i]); + VectorMA (input->xyz[i], 2, input->normal[i], temp); + qglVertex3fv (temp); + } + qglEnd (); + + qglDepthRange( 0, 1 ); +} + +/* +============== +RB_BeginSurface + +We must set some things up before beginning any tesselation, +because a surface may be forced to perform a RB_End due +to overflow. +============== +*/ +void RB_BeginSurface( shader_t *shader, int fogNum ) { + + shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader; + + tess.numIndexes = 0; + tess.numVertexes = 0; + tess.shader = state; + tess.fogNum = fogNum; + tess.dlightBits = 0; // will be OR'd in by surface functions + tess.xstages = state->stages; + tess.numPasses = state->numUnfoggedPasses; + tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; + + tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; + if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { + tess.shaderTime = tess.shader->clampTime; + } + + +} + +/* +=================== +DrawMultitextured + +output = t0 * t1 or t0 + t1 + +t0 = most upstream according to spec +t1 = most downstream according to spec +=================== +*/ +static void DrawMultitextured( shaderCommands_t *input, int stage ) { + shaderStage_t *pStage; + + pStage = tess.xstages[stage]; + + GL_State( pStage->stateBits ); + + // this is an ugly hack to work around a GeForce driver + // bug with multitexture and clip planes + if ( backEnd.viewParms.isPortal ) { + qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + + // + // base + // + GL_SelectTexture( 0 ); + qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); + R_BindAnimatedImage( &pStage->bundle[0] ); + + // + // lightmap/secondary pass + // + GL_SelectTexture( 1 ); + qglEnable( GL_TEXTURE_2D ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + if ( r_lightmap->integer ) { + GL_TexEnv( GL_REPLACE ); + } else { + GL_TexEnv( tess.shader->multitextureEnv ); + } + + qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] ); + + R_BindAnimatedImage( &pStage->bundle[1] ); + + R_DrawElements( input->numIndexes, input->indexes ); + + // + // disable texturing on TEXTURE1, then select TEXTURE0 + // + //qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisable( GL_TEXTURE_2D ); + + GL_SelectTexture( 0 ); +} + + + +/* +=================== +ProjectDlightTexture + +Perform dynamic lighting with another rendering pass +=================== +*/ +static void ProjectDlightTexture( void ) { + int i, l; +#if idppc_altivec + vec_t origin0, origin1, origin2; + float texCoords0, texCoords1; + vector float floatColorVec0, floatColorVec1; + vector float modulateVec, colorVec, zero; + vector short colorShort; + vector signed int colorInt; + vector unsigned char floatColorVecPerm, modulatePerm, colorChar; + vector unsigned char vSel = (vector unsigned char)(0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff); +#else + vec3_t origin; +#endif + float *texCoords; + byte *colors; + byte clipBits[SHADER_MAX_VERTEXES]; + MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2]; + byte colorArray[SHADER_MAX_VERTEXES][4]; + unsigned hitIndexes[SHADER_MAX_INDEXES]; + int numIndexes; + float scale; + float radius; + vec3_t floatColor; + float modulate; + + if ( !backEnd.refdef.num_dlights ) { + return; + } + +#if idppc_altivec + // There has to be a better way to do this so that floatColor + // and/or modulate are already 16-byte aligned. + floatColorVecPerm = vec_lvsl(0,(float *)floatColor); + modulatePerm = vec_lvsl(0,(float *)&modulate); + modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); + zero = (vector float)vec_splat_s8(0); +#endif + + for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { + dlight_t *dl; + + if ( !( tess.dlightBits & ( 1 << l ) ) ) { + continue; // this surface definately doesn't have any of this light + } + texCoords = texCoordsArray[0]; + colors = colorArray[0]; + + dl = &backEnd.refdef.dlights[l]; +#if idppc_altivec + origin0 = dl->transformed[0]; + origin1 = dl->transformed[1]; + origin2 = dl->transformed[2]; +#else + VectorCopy( dl->transformed, origin ); +#endif + radius = dl->radius; + scale = 1.0f / radius; + + floatColor[0] = dl->color[0] * 255.0f; + floatColor[1] = dl->color[1] * 255.0f; + floatColor[2] = dl->color[2] * 255.0f; +#if idppc_altivec + floatColorVec0 = vec_ld(0, floatColor); + floatColorVec1 = vec_ld(11, floatColor); + floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); +#endif + for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { +#if idppc_altivec + vec_t dist0, dist1, dist2; +#else + vec3_t dist; +#endif + int clip; + + backEnd.pc.c_dlightVertexes++; + +#if idppc_altivec + //VectorSubtract( origin, tess.xyz[i], dist ); + dist0 = origin0 - tess.xyz[i][0]; + dist1 = origin1 - tess.xyz[i][1]; + dist2 = origin2 - tess.xyz[i][2]; + texCoords0 = 0.5f + dist0 * scale; + texCoords1 = 0.5f + dist1 * scale; + + clip = 0; + if ( texCoords0 < 0.0f ) { + clip |= 1; + } else if ( texCoords0 > 1.0f ) { + clip |= 2; + } + if ( texCoords1 < 0.0f ) { + clip |= 4; + } else if ( texCoords1 > 1.0f ) { + clip |= 8; + } + texCoords[0] = texCoords0; + texCoords[1] = texCoords1; + + // modulate the strength based on the height and color + if ( dist2 > radius ) { + clip |= 16; + modulate = 0.0f; + } else if ( dist2 < -radius ) { + clip |= 32; + modulate = 0.0f; + } else { + dist2 = Q_fabs(dist2); + if ( dist2 < radius * 0.5f ) { + modulate = 1.0f; + } else { + modulate = 2.0f * (radius - dist2) * scale; + } + } + clipBits[i] = clip; + + modulateVec = vec_ld(0,(float *)&modulate); + modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); + colorVec = vec_madd(floatColorVec0,modulateVec,zero); + colorInt = vec_cts(colorVec,0); // RGBx + colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx + colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx + colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 + vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color +#else + VectorSubtract( origin, tess.xyz[i], dist ); + texCoords[0] = 0.5f + dist[0] * scale; + texCoords[1] = 0.5f + dist[1] * scale; + + clip = 0; + if ( texCoords[0] < 0.0f ) { + clip |= 1; + } else if ( texCoords[0] > 1.0f ) { + clip |= 2; + } + if ( texCoords[1] < 0.0f ) { + clip |= 4; + } else if ( texCoords[1] > 1.0f ) { + clip |= 8; + } + // modulate the strength based on the height and color + if ( dist[2] > radius ) { + clip |= 16; + modulate = 0.0f; + } else if ( dist[2] < -radius ) { + clip |= 32; + modulate = 0.0f; + } else { + dist[2] = Q_fabs(dist[2]); + if ( dist[2] < radius * 0.5f ) { + modulate = 1.0f; + } else { + modulate = 2.0f * (radius - dist[2]) * scale; + } + } + clipBits[i] = clip; + + colors[0] = myftol(floatColor[0] * modulate); + colors[1] = myftol(floatColor[1] * modulate); + colors[2] = myftol(floatColor[2] * modulate); + colors[3] = 255; +#endif + } + + // build a list of triangles that need light + numIndexes = 0; + for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { + int a, b, c; + + a = tess.indexes[i]; + b = tess.indexes[i+1]; + c = tess.indexes[i+2]; + if ( clipBits[a] & clipBits[b] & clipBits[c] ) { + continue; // not lighted + } + hitIndexes[numIndexes] = a; + hitIndexes[numIndexes+1] = b; + hitIndexes[numIndexes+2] = c; + numIndexes += 3; + } + + if ( !numIndexes ) { + continue; + } + + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); + + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); + + GL_Bind( tr.dlightImage ); + // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light + // where they aren't rendered + if ( dl->additive ) { + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + } + else { + GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + } + R_DrawElements( numIndexes, hitIndexes ); + backEnd.pc.c_totalIndexes += numIndexes; + backEnd.pc.c_dlightIndexes += numIndexes; + } +} + + +/* +=================== +RB_FogPass + +Blends a fog texture on top of everything else +=================== +*/ +static void RB_FogPass( void ) { + fog_t *fog; + int i; + + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); + + qglEnableClientState( GL_TEXTURE_COORD_ARRAY); + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); + + fog = tr.world->fogs + tess.fogNum; + + for ( i = 0; i < tess.numVertexes; i++ ) { + * ( int * )&tess.svars.colors[i] = fog->colorInt; + } + + RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] ); + + GL_Bind( tr.fogImage ); + + if ( tess.shader->fogPass == FP_EQUAL ) { + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); + } else { + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + } + + R_DrawElements( tess.numIndexes, tess.indexes ); +} + +/* +=============== +ComputeColors +=============== +*/ +static void ComputeColors( shaderStage_t *pStage ) +{ + int i; + + // + // rgbGen + // + switch ( pStage->rgbGen ) + { + case CGEN_IDENTITY: + Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); + break; + default: + case CGEN_IDENTITY_LIGHTING: + Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); + break; + case CGEN_LIGHTING_DIFFUSE: + RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); + break; + case CGEN_EXACT_VERTEX: + Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); + break; + case CGEN_CONST: + for ( i = 0; i < tess.numVertexes; i++ ) { + *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; + } + break; + case CGEN_VERTEX: + if ( tr.identityLight == 1 ) + { + Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); + } + else + { + for ( i = 0; i < tess.numVertexes; i++ ) + { + tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight; + tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight; + tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight; + tess.svars.colors[i][3] = tess.vertexColors[i][3]; + } + } + break; + case CGEN_ONE_MINUS_VERTEX: + if ( tr.identityLight == 1 ) + { + for ( i = 0; i < tess.numVertexes; i++ ) + { + tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0]; + tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1]; + tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2]; + } + } + else + { + for ( i = 0; i < tess.numVertexes; i++ ) + { + tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight; + tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight; + tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight; + } + } + break; + case CGEN_FOG: + { + fog_t *fog; + + fog = tr.world->fogs + tess.fogNum; + + for ( i = 0; i < tess.numVertexes; i++ ) { + * ( int * )&tess.svars.colors[i] = fog->colorInt; + } + } + break; + case CGEN_WAVEFORM: + RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); + break; + case CGEN_ENTITY: + RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); + break; + case CGEN_ONE_MINUS_ENTITY: + RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); + break; + } + + // + // alphaGen + // + switch ( pStage->alphaGen ) + { + case AGEN_SKIP: + break; + case AGEN_IDENTITY: + if ( pStage->rgbGen != CGEN_IDENTITY ) { + if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || + pStage->rgbGen != CGEN_VERTEX ) { + for ( i = 0; i < tess.numVertexes; i++ ) { + tess.svars.colors[i][3] = 0xff; + } + } + } + break; + case AGEN_CONST: + if ( pStage->rgbGen != CGEN_CONST ) { + for ( i = 0; i < tess.numVertexes; i++ ) { + tess.svars.colors[i][3] = pStage->constantColor[3]; + } + } + break; + case AGEN_WAVEFORM: + RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); + break; + case AGEN_LIGHTING_SPECULAR: + RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); + break; + case AGEN_ENTITY: + RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); + break; + case AGEN_ONE_MINUS_ENTITY: + RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); + break; + case AGEN_VERTEX: + if ( pStage->rgbGen != CGEN_VERTEX ) { + for ( i = 0; i < tess.numVertexes; i++ ) { + tess.svars.colors[i][3] = tess.vertexColors[i][3]; + } + } + break; + case AGEN_ONE_MINUS_VERTEX: + for ( i = 0; i < tess.numVertexes; i++ ) + { + tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3]; + } + break; + case AGEN_PORTAL: + { + unsigned char alpha; + + for ( i = 0; i < tess.numVertexes; i++ ) + { + float len; + vec3_t v; + + VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v ); + len = VectorLength( v ); + + len /= tess.shader->portalRange; + + if ( len < 0 ) + { + alpha = 0; + } + else if ( len > 1 ) + { + alpha = 0xff; + } + else + { + alpha = len * 0xff; + } + + tess.svars.colors[i][3] = alpha; + } + } + break; + } + + // + // fog adjustment for colors to fade out as fog increases + // + if ( tess.fogNum ) + { + switch ( pStage->adjustColorsForFog ) + { + case ACFF_MODULATE_RGB: + RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); + break; + case ACFF_MODULATE_ALPHA: + RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); + break; + case ACFF_MODULATE_RGBA: + RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); + break; + case ACFF_NONE: + break; + } + } +} + +/* +=============== +ComputeTexCoords +=============== +*/ +static void ComputeTexCoords( shaderStage_t *pStage ) { + int i; + int b; + + for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) { + int tm; + + // + // generate the texture coordinates + // + switch ( pStage->bundle[b].tcGen ) + { + case TCGEN_IDENTITY: + Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes ); + break; + case TCGEN_TEXTURE: + for ( i = 0 ; i < tess.numVertexes ; i++ ) { + tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0]; + tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1]; + } + break; + case TCGEN_LIGHTMAP: + for ( i = 0 ; i < tess.numVertexes ; i++ ) { + tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0]; + tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1]; + } + break; + case TCGEN_VECTOR: + for ( i = 0 ; i < tess.numVertexes ; i++ ) { + tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] ); + tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] ); + } + break; + case TCGEN_FOG: + RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] ); + break; + case TCGEN_ENVIRONMENT_MAPPED: + RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] ); + break; + case TCGEN_BAD: + return; + } + + // + // alter texture coordinates + // + for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) { + switch ( pStage->bundle[b].texMods[tm].type ) + { + case TMOD_NONE: + tm = TR_MAX_TEXMODS; // break out of for loop + break; + + case TMOD_TURBULENT: + RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave, + ( float * ) tess.svars.texcoords[b] ); + break; + + case TMOD_ENTITY_TRANSLATE: + RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord, + ( float * ) tess.svars.texcoords[b] ); + break; + + case TMOD_SCROLL: + RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll, + ( float * ) tess.svars.texcoords[b] ); + break; + + case TMOD_SCALE: + RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale, + ( float * ) tess.svars.texcoords[b] ); + break; + + case TMOD_STRETCH: + RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave, + ( float * ) tess.svars.texcoords[b] ); + break; + + case TMOD_TRANSFORM: + RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm], + ( float * ) tess.svars.texcoords[b] ); + break; + + case TMOD_ROTATE: + RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed, + ( float * ) tess.svars.texcoords[b] ); + break; + + default: + ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name ); + break; + } + } + } +} + +/* +** RB_IterateStagesGeneric +*/ +static void RB_IterateStagesGeneric( shaderCommands_t *input ) +{ + int stage; + + for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) + { + shaderStage_t *pStage = tess.xstages[stage]; + + if ( !pStage ) + { + break; + } + + ComputeColors( pStage ); + ComputeTexCoords( pStage ); + + if ( !setArraysOnce ) + { + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); + } + + // + // do multitexture + // + if ( pStage->bundle[1].image[0] != 0 ) + { + DrawMultitextured( input, stage ); + } + else + { + if ( !setArraysOnce ) + { + qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); + } + + // + // set state + // + if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer ) + { + GL_Bind( tr.whiteImage ); + } + else + R_BindAnimatedImage( &pStage->bundle[0] ); + + GL_State( pStage->stateBits ); + + // + // draw + // + R_DrawElements( input->numIndexes, input->indexes ); + } + // allow skipping out to show just lightmaps during development + if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) ) + { + break; + } + } +} + + +/* +** RB_StageIteratorGeneric +*/ +void RB_StageIteratorGeneric( void ) +{ + shaderCommands_t *input; + + input = &tess; + + RB_DeformTessGeometry(); + + // + // log this call + // + if ( r_logFile->integer ) + { + // don't just call LogComment, or we will get + // a call to va() every frame! + GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); + } + + // + // set face culling appropriately + // + GL_Cull( input->shader->cullType ); + + // set polygon offset if necessary + if ( input->shader->polygonOffset ) + { + qglEnable( GL_POLYGON_OFFSET_FILL ); + qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + } + + // + // if there is only a single pass then we can enable color + // and texture arrays before we compile, otherwise we need + // to avoid compiling those arrays since they will change + // during multipass rendering + // + if ( tess.numPasses > 1 || input->shader->multitextureEnv ) + { + setArraysOnce = qfalse; + qglDisableClientState (GL_COLOR_ARRAY); + qglDisableClientState (GL_TEXTURE_COORD_ARRAY); + } + else + { + setArraysOnce = qtrue; + + qglEnableClientState( GL_COLOR_ARRAY); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); + + qglEnableClientState( GL_TEXTURE_COORD_ARRAY); + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); + } + + // + // lock XYZ + // + qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD + if (qglLockArraysEXT) + { + qglLockArraysEXT(0, input->numVertexes); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + + // + // enable color and texcoord arrays after the lock if necessary + // + if ( !setArraysOnce ) + { + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnableClientState( GL_COLOR_ARRAY ); + } + + // + // call shader function + // + RB_IterateStagesGeneric( input ); + + // + // now do any dynamic lighting needed + // + if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE + && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { + ProjectDlightTexture(); + } + + // + // now do fog + // + if ( tess.fogNum && tess.shader->fogPass ) { + RB_FogPass(); + } + + // + // unlock arrays + // + if (qglUnlockArraysEXT) + { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } + + // + // reset polygon offset + // + if ( input->shader->polygonOffset ) + { + qglDisable( GL_POLYGON_OFFSET_FILL ); + } +} + + +/* +** RB_StageIteratorVertexLitTexture +*/ +void RB_StageIteratorVertexLitTexture( void ) +{ + shaderCommands_t *input; + shader_t *shader; + + input = &tess; + + shader = input->shader; + + // + // compute colors + // + RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); + + // + // log this call + // + if ( r_logFile->integer ) + { + // don't just call LogComment, or we will get + // a call to va() every frame! + GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) ); + } + + // + // set face culling appropriately + // + GL_Cull( input->shader->cullType ); + + // + // set arrays and lock + // + qglEnableClientState( GL_COLOR_ARRAY); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY); + + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); + qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); + qglVertexPointer (3, GL_FLOAT, 16, input->xyz); + + if ( qglLockArraysEXT ) + { + qglLockArraysEXT(0, input->numVertexes); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + + // + // call special shade routine + // + R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); + GL_State( tess.xstages[0]->stateBits ); + R_DrawElements( input->numIndexes, input->indexes ); + + // + // now do any dynamic lighting needed + // + if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { + ProjectDlightTexture(); + } + + // + // now do fog + // + if ( tess.fogNum && tess.shader->fogPass ) { + RB_FogPass(); + } + + // + // unlock arrays + // + if (qglUnlockArraysEXT) + { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } +} + +//define REPLACE_MODE + +void RB_StageIteratorLightmappedMultitexture( void ) { + shaderCommands_t *input; + + input = &tess; + + // + // log this call + // + if ( r_logFile->integer ) { + // don't just call LogComment, or we will get + // a call to va() every frame! + GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) ); + } + + // + // set face culling appropriately + // + GL_Cull( input->shader->cullType ); + + // + // set color, pointers, and lock + // + GL_State( GLS_DEFAULT ); + qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); + +#ifdef REPLACE_MODE + qglDisableClientState( GL_COLOR_ARRAY ); + qglColor3f( 1, 1, 1 ); + qglShadeModel( GL_FLAT ); +#else + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 ); +#endif + + // + // select base stage + // + GL_SelectTexture( 0 ); + + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); + qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); + + // + // configure second stage + // + GL_SelectTexture( 1 ); + qglEnable( GL_TEXTURE_2D ); + if ( r_lightmap->integer ) { + GL_TexEnv( GL_REPLACE ); + } else { + GL_TexEnv( GL_MODULATE ); + } + R_BindAnimatedImage( &tess.xstages[0]->bundle[1] ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] ); + + // + // lock arrays + // + if ( qglLockArraysEXT ) { + qglLockArraysEXT(0, input->numVertexes); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + + R_DrawElements( input->numIndexes, input->indexes ); + + // + // disable texturing on TEXTURE1, then select TEXTURE0 + // + qglDisable( GL_TEXTURE_2D ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + + GL_SelectTexture( 0 ); +#ifdef REPLACE_MODE + GL_TexEnv( GL_MODULATE ); + qglShadeModel( GL_SMOOTH ); +#endif + + // + // now do any dynamic lighting needed + // + if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { + ProjectDlightTexture(); + } + + // + // now do fog + // + if ( tess.fogNum && tess.shader->fogPass ) { + RB_FogPass(); + } + + // + // unlock arrays + // + if ( qglUnlockArraysEXT ) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } +} + +/* +** RB_EndSurface +*/ +void RB_EndSurface( void ) { + shaderCommands_t *input; + + input = &tess; + + if (input->numIndexes == 0) { + return; + } + + if (input->indexes[SHADER_MAX_INDEXES-1] != 0) { + ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit"); + } + if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) { + ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit"); + } + + if ( tess.shader == tr.shadowShader ) { + RB_ShadowTessEnd(); + return; + } + + // for debugging of sort order issues, stop rendering after a given sort value + if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) { + return; + } + + // + // update performance counters + // + backEnd.pc.c_shaders++; + backEnd.pc.c_vertexes += tess.numVertexes; + backEnd.pc.c_indexes += tess.numIndexes; + backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses; + + // + // call off to shader specific tess end function + // + tess.currentStageIteratorFunc(); + + // + // draw debugging stuff + // + if ( r_showtris->integer ) { + DrawTris (input); + } + if ( r_shownormals->integer ) { + DrawNormals (input); + } + // clear shader so we can tell we don't have any unclosed surfaces + tess.numIndexes = 0; + + GLimp_LogComment( "----------\n" ); +} + diff --git a/code/renderer/tr_shade_calc.c b/code/renderer/tr_shade_calc.c index f1f0e6d..79d25f2 100755 --- a/code/renderer/tr_shade_calc.c +++ b/code/renderer/tr_shade_calc.c @@ -1,1205 +1,1205 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_shade_calc.c
-
-#include "tr_local.h"
-
-
-#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
-
-static float *TableForFunc( genFunc_t func )
-{
- switch ( func )
- {
- case GF_SIN:
- return tr.sinTable;
- case GF_TRIANGLE:
- return tr.triangleTable;
- case GF_SQUARE:
- return tr.squareTable;
- case GF_SAWTOOTH:
- return tr.sawToothTable;
- case GF_INVERSE_SAWTOOTH:
- return tr.inverseSawToothTable;
- case GF_NONE:
- default:
- break;
- }
-
- ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.shader->name );
- return NULL;
-}
-
-/*
-** EvalWaveForm
-**
-** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
-*/
-static float EvalWaveForm( const waveForm_t *wf )
-{
- float *table;
-
- table = TableForFunc( wf->func );
-
- return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
-}
-
-static float EvalWaveFormClamped( const waveForm_t *wf )
-{
- float glow = EvalWaveForm( wf );
-
- if ( glow < 0 )
- {
- return 0;
- }
-
- if ( glow > 1 )
- {
- return 1;
- }
-
- return glow;
-}
-
-/*
-** RB_CalcStretchTexCoords
-*/
-void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st )
-{
- float p;
- texModInfo_t tmi;
-
- p = 1.0f / EvalWaveForm( wf );
-
- tmi.matrix[0][0] = p;
- tmi.matrix[1][0] = 0;
- tmi.translate[0] = 0.5f - 0.5f * p;
-
- tmi.matrix[0][1] = 0;
- tmi.matrix[1][1] = p;
- tmi.translate[1] = 0.5f - 0.5f * p;
-
- RB_CalcTransformTexCoords( &tmi, st );
-}
-
-/*
-====================================================================
-
-DEFORMATIONS
-
-====================================================================
-*/
-
-/*
-========================
-RB_CalcDeformVertexes
-
-========================
-*/
-void RB_CalcDeformVertexes( deformStage_t *ds )
-{
- int i;
- vec3_t offset;
- float scale;
- float *xyz = ( float * ) tess.xyz;
- float *normal = ( float * ) tess.normal;
- float *table;
-
- if ( ds->deformationWave.frequency == 0 )
- {
- scale = EvalWaveForm( &ds->deformationWave );
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
- {
- VectorScale( normal, scale, offset );
-
- xyz[0] += offset[0];
- xyz[1] += offset[1];
- xyz[2] += offset[2];
- }
- }
- else
- {
- table = TableForFunc( ds->deformationWave.func );
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
- {
- float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
-
- scale = WAVEVALUE( table, ds->deformationWave.base,
- ds->deformationWave.amplitude,
- ds->deformationWave.phase + off,
- ds->deformationWave.frequency );
-
- VectorScale( normal, scale, offset );
-
- xyz[0] += offset[0];
- xyz[1] += offset[1];
- xyz[2] += offset[2];
- }
- }
-}
-
-/*
-=========================
-RB_CalcDeformNormals
-
-Wiggle the normals for wavy environment mapping
-=========================
-*/
-void RB_CalcDeformNormals( deformStage_t *ds ) {
- int i;
- float scale;
- float *xyz = ( float * ) tess.xyz;
- float *normal = ( float * ) tess.normal;
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
- scale = 0.98f;
- scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
- tess.shaderTime * ds->deformationWave.frequency );
- normal[ 0 ] += ds->deformationWave.amplitude * scale;
-
- scale = 0.98f;
- scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
- tess.shaderTime * ds->deformationWave.frequency );
- normal[ 1 ] += ds->deformationWave.amplitude * scale;
-
- scale = 0.98f;
- scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
- tess.shaderTime * ds->deformationWave.frequency );
- normal[ 2 ] += ds->deformationWave.amplitude * scale;
-
- VectorNormalizeFast( normal );
- }
-}
-
-/*
-========================
-RB_CalcBulgeVertexes
-
-========================
-*/
-void RB_CalcBulgeVertexes( deformStage_t *ds ) {
- int i;
- const float *st = ( const float * ) tess.texCoords[0];
- float *xyz = ( float * ) tess.xyz;
- float *normal = ( float * ) tess.normal;
- float now;
-
- now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {
- int off;
- float scale;
-
- off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
-
- scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
-
- xyz[0] += normal[0] * scale;
- xyz[1] += normal[1] * scale;
- xyz[2] += normal[2] * scale;
- }
-}
-
-
-/*
-======================
-RB_CalcMoveVertexes
-
-A deformation that can move an entire surface along a wave path
-======================
-*/
-void RB_CalcMoveVertexes( deformStage_t *ds ) {
- int i;
- float *xyz;
- float *table;
- float scale;
- vec3_t offset;
-
- table = TableForFunc( ds->deformationWave.func );
-
- scale = WAVEVALUE( table, ds->deformationWave.base,
- ds->deformationWave.amplitude,
- ds->deformationWave.phase,
- ds->deformationWave.frequency );
-
- VectorScale( ds->moveVector, scale, offset );
-
- xyz = ( float * ) tess.xyz;
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
- VectorAdd( xyz, offset, xyz );
- }
-}
-
-
-/*
-=============
-DeformText
-
-Change a polygon into a bunch of text polygons
-=============
-*/
-void DeformText( const char *text ) {
- int i;
- vec3_t origin, width, height;
- int len;
- int ch;
- byte color[4];
- float bottom, top;
- vec3_t mid;
-
- height[0] = 0;
- height[1] = 0;
- height[2] = -1;
- CrossProduct( tess.normal[0], height, width );
-
- // find the midpoint of the box
- VectorClear( mid );
- bottom = 999999;
- top = -999999;
- for ( i = 0 ; i < 4 ; i++ ) {
- VectorAdd( tess.xyz[i], mid, mid );
- if ( tess.xyz[i][2] < bottom ) {
- bottom = tess.xyz[i][2];
- }
- if ( tess.xyz[i][2] > top ) {
- top = tess.xyz[i][2];
- }
- }
- VectorScale( mid, 0.25f, origin );
-
- // determine the individual character size
- height[0] = 0;
- height[1] = 0;
- height[2] = ( top - bottom ) * 0.5f;
-
- VectorScale( width, height[2] * -0.75f, width );
-
- // determine the starting position
- len = strlen( text );
- VectorMA( origin, (len-1), width, origin );
-
- // clear the shader indexes
- tess.numIndexes = 0;
- tess.numVertexes = 0;
-
- color[0] = color[1] = color[2] = color[3] = 255;
-
- // draw each character
- for ( i = 0 ; i < len ; i++ ) {
- ch = text[i];
- ch &= 255;
-
- if ( ch != ' ' ) {
- int row, col;
- float frow, fcol, size;
-
- row = ch>>4;
- col = ch&15;
-
- frow = row*0.0625f;
- fcol = col*0.0625f;
- size = 0.0625f;
-
- RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
- }
- VectorMA( origin, -2, width, origin );
- }
-}
-
-/*
-==================
-GlobalVectorToLocal
-==================
-*/
-static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
- out[0] = DotProduct( in, backEnd.or.axis[0] );
- out[1] = DotProduct( in, backEnd.or.axis[1] );
- out[2] = DotProduct( in, backEnd.or.axis[2] );
-}
-
-/*
-=====================
-AutospriteDeform
-
-Assuming all the triangles for this shader are independant
-quads, rebuild them as forward facing sprites
-=====================
-*/
-static void AutospriteDeform( void ) {
- int i;
- int oldVerts;
- float *xyz;
- vec3_t mid, delta;
- float radius;
- vec3_t left, up;
- vec3_t leftDir, upDir;
-
- if ( tess.numVertexes & 3 ) {
- ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count", tess.shader->name );
- }
- if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
- ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count", tess.shader->name );
- }
-
- oldVerts = tess.numVertexes;
- tess.numVertexes = 0;
- tess.numIndexes = 0;
-
- if ( backEnd.currentEntity != &tr.worldEntity ) {
- GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir );
- GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir );
- } else {
- VectorCopy( backEnd.viewParms.or.axis[1], leftDir );
- VectorCopy( backEnd.viewParms.or.axis[2], upDir );
- }
-
- for ( i = 0 ; i < oldVerts ; i+=4 ) {
- // find the midpoint
- xyz = tess.xyz[i];
-
- mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
- mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
- mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
-
- VectorSubtract( xyz, mid, delta );
- radius = VectorLength( delta ) * 0.707f; // / sqrt(2)
-
- VectorScale( leftDir, radius, left );
- VectorScale( upDir, radius, up );
-
- if ( backEnd.viewParms.isMirror ) {
- VectorSubtract( vec3_origin, left, left );
- }
-
- // compensate for scale in the axes if necessary
- if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
- float axisLength;
- axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
- if ( !axisLength ) {
- axisLength = 0;
- } else {
- axisLength = 1.0f / axisLength;
- }
- VectorScale(left, axisLength, left);
- VectorScale(up, axisLength, up);
- }
-
- RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] );
- }
-}
-
-
-/*
-=====================
-Autosprite2Deform
-
-Autosprite2 will pivot a rectangular quad along the center of its long axis
-=====================
-*/
-int edgeVerts[6][2] = {
- { 0, 1 },
- { 0, 2 },
- { 0, 3 },
- { 1, 2 },
- { 1, 3 },
- { 2, 3 }
-};
-
-static void Autosprite2Deform( void ) {
- int i, j, k;
- int indexes;
- float *xyz;
- vec3_t forward;
-
- if ( tess.numVertexes & 3 ) {
- ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name );
- }
- if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
- ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name );
- }
-
- if ( backEnd.currentEntity != &tr.worldEntity ) {
- GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward );
- } else {
- VectorCopy( backEnd.viewParms.or.axis[0], forward );
- }
-
- // this is a lot of work for two triangles...
- // we could precalculate a lot of it is an issue, but it would mess up
- // the shader abstraction
- for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {
- float lengths[2];
- int nums[2];
- vec3_t mid[2];
- vec3_t major, minor;
- float *v1, *v2;
-
- // find the midpoint
- xyz = tess.xyz[i];
-
- // identify the two shortest edges
- nums[0] = nums[1] = 0;
- lengths[0] = lengths[1] = 999999;
-
- for ( j = 0 ; j < 6 ; j++ ) {
- float l;
- vec3_t temp;
-
- v1 = xyz + 4 * edgeVerts[j][0];
- v2 = xyz + 4 * edgeVerts[j][1];
-
- VectorSubtract( v1, v2, temp );
-
- l = DotProduct( temp, temp );
- if ( l < lengths[0] ) {
- nums[1] = nums[0];
- lengths[1] = lengths[0];
- nums[0] = j;
- lengths[0] = l;
- } else if ( l < lengths[1] ) {
- nums[1] = j;
- lengths[1] = l;
- }
- }
-
- for ( j = 0 ; j < 2 ; j++ ) {
- v1 = xyz + 4 * edgeVerts[nums[j]][0];
- v2 = xyz + 4 * edgeVerts[nums[j]][1];
-
- mid[j][0] = 0.5f * (v1[0] + v2[0]);
- mid[j][1] = 0.5f * (v1[1] + v2[1]);
- mid[j][2] = 0.5f * (v1[2] + v2[2]);
- }
-
- // find the vector of the major axis
- VectorSubtract( mid[1], mid[0], major );
-
- // cross this with the view direction to get minor axis
- CrossProduct( major, forward, minor );
- VectorNormalize( minor );
-
- // re-project the points
- for ( j = 0 ; j < 2 ; j++ ) {
- float l;
-
- v1 = xyz + 4 * edgeVerts[nums[j]][0];
- v2 = xyz + 4 * edgeVerts[nums[j]][1];
-
- l = 0.5 * sqrt( lengths[j] );
-
- // we need to see which direction this edge
- // is used to determine direction of projection
- for ( k = 0 ; k < 5 ; k++ ) {
- if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
- && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
- break;
- }
- }
-
- if ( k == 5 ) {
- VectorMA( mid[j], l, minor, v1 );
- VectorMA( mid[j], -l, minor, v2 );
- } else {
- VectorMA( mid[j], -l, minor, v1 );
- VectorMA( mid[j], l, minor, v2 );
- }
- }
- }
-}
-
-
-/*
-=====================
-RB_DeformTessGeometry
-
-=====================
-*/
-void RB_DeformTessGeometry( void ) {
- int i;
- deformStage_t *ds;
-
- for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
- ds = &tess.shader->deforms[ i ];
-
- switch ( ds->deformation ) {
- case DEFORM_NONE:
- break;
- case DEFORM_NORMALS:
- RB_CalcDeformNormals( ds );
- break;
- case DEFORM_WAVE:
- RB_CalcDeformVertexes( ds );
- break;
- case DEFORM_BULGE:
- RB_CalcBulgeVertexes( ds );
- break;
- case DEFORM_MOVE:
- RB_CalcMoveVertexes( ds );
- break;
- case DEFORM_PROJECTION_SHADOW:
- RB_ProjectionShadowDeform();
- break;
- case DEFORM_AUTOSPRITE:
- AutospriteDeform();
- break;
- case DEFORM_AUTOSPRITE2:
- Autosprite2Deform();
- break;
- case DEFORM_TEXT0:
- case DEFORM_TEXT1:
- case DEFORM_TEXT2:
- case DEFORM_TEXT3:
- case DEFORM_TEXT4:
- case DEFORM_TEXT5:
- case DEFORM_TEXT6:
- case DEFORM_TEXT7:
- DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
- break;
- }
- }
-}
-
-/*
-====================================================================
-
-COLORS
-
-====================================================================
-*/
-
-
-/*
-** RB_CalcColorFromEntity
-*/
-void RB_CalcColorFromEntity( unsigned char *dstColors )
-{
- int i;
- int *pColors = ( int * ) dstColors;
- int c;
-
- if ( !backEnd.currentEntity )
- return;
-
- c = * ( int * ) backEnd.currentEntity->e.shaderRGBA;
-
- for ( i = 0; i < tess.numVertexes; i++, pColors++ )
- {
- *pColors = c;
- }
-}
-
-/*
-** RB_CalcColorFromOneMinusEntity
-*/
-void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors )
-{
- int i;
- int *pColors = ( int * ) dstColors;
- unsigned char invModulate[3];
- int c;
-
- if ( !backEnd.currentEntity )
- return;
-
- invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];
- invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];
- invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];
- invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it
-
- c = * ( int * ) invModulate;
-
- for ( i = 0; i < tess.numVertexes; i++, pColors++ )
- {
- *pColors = * ( int * ) invModulate;
- }
-}
-
-/*
-** RB_CalcAlphaFromEntity
-*/
-void RB_CalcAlphaFromEntity( unsigned char *dstColors )
-{
- int i;
-
- if ( !backEnd.currentEntity )
- return;
-
- dstColors += 3;
-
- for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
- {
- *dstColors = backEnd.currentEntity->e.shaderRGBA[3];
- }
-}
-
-/*
-** RB_CalcAlphaFromOneMinusEntity
-*/
-void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors )
-{
- int i;
-
- if ( !backEnd.currentEntity )
- return;
-
- dstColors += 3;
-
- for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
- {
- *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3];
- }
-}
-
-/*
-** RB_CalcWaveColor
-*/
-void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors )
-{
- int i;
- int v;
- float glow;
- int *colors = ( int * ) dstColors;
- byte color[4];
-
-
- if ( wf->func == GF_NOISE ) {
- glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
- } else {
- glow = EvalWaveForm( wf ) * tr.identityLight;
- }
-
- if ( glow < 0 ) {
- glow = 0;
- }
- else if ( glow > 1 ) {
- glow = 1;
- }
-
- v = myftol( 255 * glow );
- color[0] = color[1] = color[2] = v;
- color[3] = 255;
- v = *(int *)color;
-
- for ( i = 0; i < tess.numVertexes; i++, colors++ ) {
- *colors = v;
- }
-}
-
-/*
-** RB_CalcWaveAlpha
-*/
-void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors )
-{
- int i;
- int v;
- float glow;
-
- glow = EvalWaveFormClamped( wf );
-
- v = 255 * glow;
-
- for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
- {
- dstColors[3] = v;
- }
-}
-
-/*
-** RB_CalcModulateColorsByFog
-*/
-void RB_CalcModulateColorsByFog( unsigned char *colors ) {
- int i;
- float texCoords[SHADER_MAX_VERTEXES][2];
-
- // calculate texcoords so we can derive density
- // this is not wasted, because it would only have
- // been previously called if the surface was opaque
- RB_CalcFogTexCoords( texCoords[0] );
-
- for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
- float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
- colors[0] *= f;
- colors[1] *= f;
- colors[2] *= f;
- }
-}
-
-/*
-** RB_CalcModulateAlphasByFog
-*/
-void RB_CalcModulateAlphasByFog( unsigned char *colors ) {
- int i;
- float texCoords[SHADER_MAX_VERTEXES][2];
-
- // calculate texcoords so we can derive density
- // this is not wasted, because it would only have
- // been previously called if the surface was opaque
- RB_CalcFogTexCoords( texCoords[0] );
-
- for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
- float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
- colors[3] *= f;
- }
-}
-
-/*
-** RB_CalcModulateRGBAsByFog
-*/
-void RB_CalcModulateRGBAsByFog( unsigned char *colors ) {
- int i;
- float texCoords[SHADER_MAX_VERTEXES][2];
-
- // calculate texcoords so we can derive density
- // this is not wasted, because it would only have
- // been previously called if the surface was opaque
- RB_CalcFogTexCoords( texCoords[0] );
-
- for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
- float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
- colors[0] *= f;
- colors[1] *= f;
- colors[2] *= f;
- colors[3] *= f;
- }
-}
-
-
-/*
-====================================================================
-
-TEX COORDS
-
-====================================================================
-*/
-
-/*
-========================
-RB_CalcFogTexCoords
-
-To do the clipped fog plane really correctly, we should use
-projected textures, but I don't trust the drivers and it
-doesn't fit our shader data.
-========================
-*/
-void RB_CalcFogTexCoords( float *st ) {
- int i;
- float *v;
- float s, t;
- float eyeT;
- qboolean eyeOutside;
- fog_t *fog;
- vec3_t local;
- vec4_t fogDistanceVector, fogDepthVector;
-
- fog = tr.world->fogs + tess.fogNum;
-
- // all fogging distance is based on world Z units
- VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local );
- fogDistanceVector[0] = -backEnd.or.modelMatrix[2];
- fogDistanceVector[1] = -backEnd.or.modelMatrix[6];
- fogDistanceVector[2] = -backEnd.or.modelMatrix[10];
- fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] );
-
- // scale the fog vectors based on the fog's thickness
- fogDistanceVector[0] *= fog->tcScale;
- fogDistanceVector[1] *= fog->tcScale;
- fogDistanceVector[2] *= fog->tcScale;
- fogDistanceVector[3] *= fog->tcScale;
-
- // rotate the gradient vector for this orientation
- if ( fog->hasSurface ) {
- fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] +
- fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2];
- fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] +
- fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2];
- fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] +
- fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2];
- fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface );
-
- eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3];
- } else {
- eyeT = 1; // non-surface fog always has eye inside
- }
-
- // see if the viewpoint is outside
- // this is needed for clipping distance even for constant fog
-
- if ( eyeT < 0 ) {
- eyeOutside = qtrue;
- } else {
- eyeOutside = qfalse;
- }
-
- fogDistanceVector[3] += 1.0/512;
-
- // calculate density for each point
- for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) {
- // calculate the length in fog
- s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];
- t = DotProduct( v, fogDepthVector ) + fogDepthVector[3];
-
- // partially clipped fogs use the T axis
- if ( eyeOutside ) {
- if ( t < 1.0 ) {
- t = 1.0/32; // point is outside, so no fogging
- } else {
- t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane
- }
- } else {
- if ( t < 0 ) {
- t = 1.0/32; // point is outside, so no fogging
- } else {
- t = 31.0/32;
- }
- }
-
- st[0] = s;
- st[1] = t;
- st += 2;
- }
-}
-
-
-
-/*
-** RB_CalcEnvironmentTexCoords
-*/
-void RB_CalcEnvironmentTexCoords( float *st )
-{
- int i;
- float *v, *normal;
- vec3_t viewer, reflected;
- float d;
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
- for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 )
- {
- VectorSubtract (backEnd.or.viewOrigin, v, viewer);
- VectorNormalizeFast (viewer);
-
- d = DotProduct (normal, viewer);
-
- reflected[0] = normal[0]*2*d - viewer[0];
- reflected[1] = normal[1]*2*d - viewer[1];
- reflected[2] = normal[2]*2*d - viewer[2];
-
- st[0] = 0.5 + reflected[1] * 0.5;
- st[1] = 0.5 - reflected[2] * 0.5;
- }
-}
-
-/*
-** RB_CalcTurbulentTexCoords
-*/
-void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )
-{
- int i;
- float now;
-
- now = ( wf->phase + tess.shaderTime * wf->frequency );
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- float s = st[0];
- float t = st[1];
-
- st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
- st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
- }
-}
-
-/*
-** RB_CalcScaleTexCoords
-*/
-void RB_CalcScaleTexCoords( const float scale[2], float *st )
-{
- int i;
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- st[0] *= scale[0];
- st[1] *= scale[1];
- }
-}
-
-/*
-** RB_CalcScrollTexCoords
-*/
-void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )
-{
- int i;
- float timeScale = tess.shaderTime;
- float adjustedScrollS, adjustedScrollT;
-
- adjustedScrollS = scrollSpeed[0] * timeScale;
- adjustedScrollT = scrollSpeed[1] * timeScale;
-
- // clamp so coordinates don't continuously get larger, causing problems
- // with hardware limits
- adjustedScrollS = adjustedScrollS - floor( adjustedScrollS );
- adjustedScrollT = adjustedScrollT - floor( adjustedScrollT );
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- st[0] += adjustedScrollS;
- st[1] += adjustedScrollT;
- }
-}
-
-/*
-** RB_CalcTransformTexCoords
-*/
-void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st )
-{
- int i;
-
- for ( i = 0; i < tess.numVertexes; i++, st += 2 )
- {
- float s = st[0];
- float t = st[1];
-
- st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0];
- st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1];
- }
-}
-
-/*
-** RB_CalcRotateTexCoords
-*/
-void RB_CalcRotateTexCoords( float degsPerSecond, float *st )
-{
- float timeScale = tess.shaderTime;
- float degs;
- int index;
- float sinValue, cosValue;
- texModInfo_t tmi;
-
- degs = -degsPerSecond * timeScale;
- index = degs * ( FUNCTABLE_SIZE / 360.0f );
-
- sinValue = tr.sinTable[ index & FUNCTABLE_MASK ];
- cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];
-
- tmi.matrix[0][0] = cosValue;
- tmi.matrix[1][0] = -sinValue;
- tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
-
- tmi.matrix[0][1] = sinValue;
- tmi.matrix[1][1] = cosValue;
- tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
-
- RB_CalcTransformTexCoords( &tmi, st );
-}
-
-
-
-
-
-
-#if id386 && !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__ ) ) // rb010123
-
-long myftol( float f ) {
- static int tmp;
- __asm fld f
- __asm fistp tmp
- __asm mov eax, tmp
-}
-
-#endif
-
-/*
-** RB_CalcSpecularAlpha
-**
-** Calculates specular coefficient and places it in the alpha channel
-*/
-vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically
-
-void RB_CalcSpecularAlpha( unsigned char *alphas ) {
- int i;
- float *v, *normal;
- vec3_t viewer, reflected;
- float l, d;
- int b;
- vec3_t lightDir;
- int numVertexes;
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
- alphas += 3;
-
- numVertexes = tess.numVertexes;
- for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) {
- float ilength;
-
- VectorSubtract( lightOrigin, v, lightDir );
-// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) );
- VectorNormalizeFast( lightDir );
-
- // calculate the specular color
- d = DotProduct (normal, lightDir);
-// d *= ilength;
-
- // we don't optimize for the d < 0 case since this tends to
- // cause visual artifacts such as faceted "snapping"
- reflected[0] = normal[0]*2*d - lightDir[0];
- reflected[1] = normal[1]*2*d - lightDir[1];
- reflected[2] = normal[2]*2*d - lightDir[2];
-
- VectorSubtract (backEnd.or.viewOrigin, v, viewer);
- ilength = Q_rsqrt( DotProduct( viewer, viewer ) );
- l = DotProduct (reflected, viewer);
- l *= ilength;
-
- if (l < 0) {
- b = 0;
- } else {
- l = l*l;
- l = l*l;
- b = l * 255;
- if (b > 255) {
- b = 255;
- }
- }
-
- *alphas = b;
- }
-}
-
-/*
-** RB_CalcDiffuseColor
-**
-** The basic vertex lighting calc
-*/
-void RB_CalcDiffuseColor( unsigned char *colors )
-{
- int i, j;
- float *v, *normal;
- float incoming;
- trRefEntity_t *ent;
- int ambientLightInt;
- vec3_t ambientLight;
- vec3_t lightDir;
- vec3_t directedLight;
- int numVertexes;
-#if idppc_altivec
- vector unsigned char vSel = (vector unsigned char)(0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff);
- vector float ambientLightVec;
- vector float directedLightVec;
- vector float lightDirVec;
- vector float normalVec0, normalVec1;
- vector float incomingVec0, incomingVec1, incomingVec2;
- vector float zero, jVec;
- vector signed int jVecInt;
- vector signed short jVecShort;
- vector unsigned char jVecChar, normalPerm;
-#endif
- ent = backEnd.currentEntity;
- ambientLightInt = ent->ambientLightInt;
-#if idppc_altivec
- // A lot of this could be simplified if we made sure
- // entities light info was 16-byte aligned.
- jVecChar = vec_lvsl(0, ent->ambientLight);
- ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight);
- jVec = vec_ld(11, (vector float *)ent->ambientLight);
- ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar);
-
- jVecChar = vec_lvsl(0, ent->directedLight);
- directedLightVec = vec_ld(0,(vector float *)ent->directedLight);
- jVec = vec_ld(11,(vector float *)ent->directedLight);
- directedLightVec = vec_perm(directedLightVec,jVec,jVecChar);
-
- jVecChar = vec_lvsl(0, ent->lightDir);
- lightDirVec = vec_ld(0,(vector float *)ent->lightDir);
- jVec = vec_ld(11,(vector float *)ent->lightDir);
- lightDirVec = vec_perm(lightDirVec,jVec,jVecChar);
-
- zero = (vector float)vec_splat_s8(0);
- VectorCopy( ent->lightDir, lightDir );
-#else
- VectorCopy( ent->ambientLight, ambientLight );
- VectorCopy( ent->directedLight, directedLight );
- VectorCopy( ent->lightDir, lightDir );
-#endif
-
- v = tess.xyz[0];
- normal = tess.normal[0];
-
-#if idppc_altivec
- normalPerm = vec_lvsl(0,normal);
-#endif
- numVertexes = tess.numVertexes;
- for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
-#if idppc_altivec
- normalVec0 = vec_ld(0,(vector float *)normal);
- normalVec1 = vec_ld(11,(vector float *)normal);
- normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm);
- incomingVec0 = vec_madd(normalVec0, lightDirVec, zero);
- incomingVec1 = vec_sld(incomingVec0,incomingVec0,4);
- incomingVec2 = vec_add(incomingVec0,incomingVec1);
- incomingVec1 = vec_sld(incomingVec1,incomingVec1,4);
- incomingVec2 = vec_add(incomingVec2,incomingVec1);
- incomingVec0 = vec_splat(incomingVec2,0);
- incomingVec0 = vec_max(incomingVec0,zero);
- normalPerm = vec_lvsl(12,normal);
- jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec);
- jVecInt = vec_cts(jVec,0); // RGBx
- jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx
- jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx
- jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
- vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color
-#else
- incoming = DotProduct (normal, lightDir);
- if ( incoming <= 0 ) {
- *(int *)&colors[i*4] = ambientLightInt;
- continue;
- }
- j = myftol( ambientLight[0] + incoming * directedLight[0] );
- if ( j > 255 ) {
- j = 255;
- }
- colors[i*4+0] = j;
-
- j = myftol( ambientLight[1] + incoming * directedLight[1] );
- if ( j > 255 ) {
- j = 255;
- }
- colors[i*4+1] = j;
-
- j = myftol( ambientLight[2] + incoming * directedLight[2] );
- if ( j > 255 ) {
- j = 255;
- }
- colors[i*4+2] = j;
-
- colors[i*4+3] = 255;
-#endif
- }
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_shade_calc.c + +#include "tr_local.h" + + +#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) + +static float *TableForFunc( genFunc_t func ) +{ + switch ( func ) + { + case GF_SIN: + return tr.sinTable; + case GF_TRIANGLE: + return tr.triangleTable; + case GF_SQUARE: + return tr.squareTable; + case GF_SAWTOOTH: + return tr.sawToothTable; + case GF_INVERSE_SAWTOOTH: + return tr.inverseSawToothTable; + case GF_NONE: + default: + break; + } + + ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.shader->name ); + return NULL; +} + +/* +** EvalWaveForm +** +** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly +*/ +static float EvalWaveForm( const waveForm_t *wf ) +{ + float *table; + + table = TableForFunc( wf->func ); + + return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency ); +} + +static float EvalWaveFormClamped( const waveForm_t *wf ) +{ + float glow = EvalWaveForm( wf ); + + if ( glow < 0 ) + { + return 0; + } + + if ( glow > 1 ) + { + return 1; + } + + return glow; +} + +/* +** RB_CalcStretchTexCoords +*/ +void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st ) +{ + float p; + texModInfo_t tmi; + + p = 1.0f / EvalWaveForm( wf ); + + tmi.matrix[0][0] = p; + tmi.matrix[1][0] = 0; + tmi.translate[0] = 0.5f - 0.5f * p; + + tmi.matrix[0][1] = 0; + tmi.matrix[1][1] = p; + tmi.translate[1] = 0.5f - 0.5f * p; + + RB_CalcTransformTexCoords( &tmi, st ); +} + +/* +==================================================================== + +DEFORMATIONS + +==================================================================== +*/ + +/* +======================== +RB_CalcDeformVertexes + +======================== +*/ +void RB_CalcDeformVertexes( deformStage_t *ds ) +{ + int i; + vec3_t offset; + float scale; + float *xyz = ( float * ) tess.xyz; + float *normal = ( float * ) tess.normal; + float *table; + + if ( ds->deformationWave.frequency == 0 ) + { + scale = EvalWaveForm( &ds->deformationWave ); + + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) + { + VectorScale( normal, scale, offset ); + + xyz[0] += offset[0]; + xyz[1] += offset[1]; + xyz[2] += offset[2]; + } + } + else + { + table = TableForFunc( ds->deformationWave.func ); + + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) + { + float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; + + scale = WAVEVALUE( table, ds->deformationWave.base, + ds->deformationWave.amplitude, + ds->deformationWave.phase + off, + ds->deformationWave.frequency ); + + VectorScale( normal, scale, offset ); + + xyz[0] += offset[0]; + xyz[1] += offset[1]; + xyz[2] += offset[2]; + } + } +} + +/* +========================= +RB_CalcDeformNormals + +Wiggle the normals for wavy environment mapping +========================= +*/ +void RB_CalcDeformNormals( deformStage_t *ds ) { + int i; + float scale; + float *xyz = ( float * ) tess.xyz; + float *normal = ( float * ) tess.normal; + + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { + scale = 0.98f; + scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, + tess.shaderTime * ds->deformationWave.frequency ); + normal[ 0 ] += ds->deformationWave.amplitude * scale; + + scale = 0.98f; + scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, + tess.shaderTime * ds->deformationWave.frequency ); + normal[ 1 ] += ds->deformationWave.amplitude * scale; + + scale = 0.98f; + scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, + tess.shaderTime * ds->deformationWave.frequency ); + normal[ 2 ] += ds->deformationWave.amplitude * scale; + + VectorNormalizeFast( normal ); + } +} + +/* +======================== +RB_CalcBulgeVertexes + +======================== +*/ +void RB_CalcBulgeVertexes( deformStage_t *ds ) { + int i; + const float *st = ( const float * ) tess.texCoords[0]; + float *xyz = ( float * ) tess.xyz; + float *normal = ( float * ) tess.normal; + float now; + + now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; + + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) { + int off; + float scale; + + off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); + + scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight; + + xyz[0] += normal[0] * scale; + xyz[1] += normal[1] * scale; + xyz[2] += normal[2] * scale; + } +} + + +/* +====================== +RB_CalcMoveVertexes + +A deformation that can move an entire surface along a wave path +====================== +*/ +void RB_CalcMoveVertexes( deformStage_t *ds ) { + int i; + float *xyz; + float *table; + float scale; + vec3_t offset; + + table = TableForFunc( ds->deformationWave.func ); + + scale = WAVEVALUE( table, ds->deformationWave.base, + ds->deformationWave.amplitude, + ds->deformationWave.phase, + ds->deformationWave.frequency ); + + VectorScale( ds->moveVector, scale, offset ); + + xyz = ( float * ) tess.xyz; + for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { + VectorAdd( xyz, offset, xyz ); + } +} + + +/* +============= +DeformText + +Change a polygon into a bunch of text polygons +============= +*/ +void DeformText( const char *text ) { + int i; + vec3_t origin, width, height; + int len; + int ch; + byte color[4]; + float bottom, top; + vec3_t mid; + + height[0] = 0; + height[1] = 0; + height[2] = -1; + CrossProduct( tess.normal[0], height, width ); + + // find the midpoint of the box + VectorClear( mid ); + bottom = 999999; + top = -999999; + for ( i = 0 ; i < 4 ; i++ ) { + VectorAdd( tess.xyz[i], mid, mid ); + if ( tess.xyz[i][2] < bottom ) { + bottom = tess.xyz[i][2]; + } + if ( tess.xyz[i][2] > top ) { + top = tess.xyz[i][2]; + } + } + VectorScale( mid, 0.25f, origin ); + + // determine the individual character size + height[0] = 0; + height[1] = 0; + height[2] = ( top - bottom ) * 0.5f; + + VectorScale( width, height[2] * -0.75f, width ); + + // determine the starting position + len = strlen( text ); + VectorMA( origin, (len-1), width, origin ); + + // clear the shader indexes + tess.numIndexes = 0; + tess.numVertexes = 0; + + color[0] = color[1] = color[2] = color[3] = 255; + + // draw each character + for ( i = 0 ; i < len ; i++ ) { + ch = text[i]; + ch &= 255; + + if ( ch != ' ' ) { + int row, col; + float frow, fcol, size; + + row = ch>>4; + col = ch&15; + + frow = row*0.0625f; + fcol = col*0.0625f; + size = 0.0625f; + + RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size ); + } + VectorMA( origin, -2, width, origin ); + } +} + +/* +================== +GlobalVectorToLocal +================== +*/ +static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { + out[0] = DotProduct( in, backEnd.or.axis[0] ); + out[1] = DotProduct( in, backEnd.or.axis[1] ); + out[2] = DotProduct( in, backEnd.or.axis[2] ); +} + +/* +===================== +AutospriteDeform + +Assuming all the triangles for this shader are independant +quads, rebuild them as forward facing sprites +===================== +*/ +static void AutospriteDeform( void ) { + int i; + int oldVerts; + float *xyz; + vec3_t mid, delta; + float radius; + vec3_t left, up; + vec3_t leftDir, upDir; + + if ( tess.numVertexes & 3 ) { + ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count", tess.shader->name ); + } + if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { + ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count", tess.shader->name ); + } + + oldVerts = tess.numVertexes; + tess.numVertexes = 0; + tess.numIndexes = 0; + + if ( backEnd.currentEntity != &tr.worldEntity ) { + GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir ); + GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir ); + } else { + VectorCopy( backEnd.viewParms.or.axis[1], leftDir ); + VectorCopy( backEnd.viewParms.or.axis[2], upDir ); + } + + for ( i = 0 ; i < oldVerts ; i+=4 ) { + // find the midpoint + xyz = tess.xyz[i]; + + mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]); + mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]); + mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]); + + VectorSubtract( xyz, mid, delta ); + radius = VectorLength( delta ) * 0.707f; // / sqrt(2) + + VectorScale( leftDir, radius, left ); + VectorScale( upDir, radius, up ); + + if ( backEnd.viewParms.isMirror ) { + VectorSubtract( vec3_origin, left, left ); + } + + // compensate for scale in the axes if necessary + if ( backEnd.currentEntity->e.nonNormalizedAxes ) { + float axisLength; + axisLength = VectorLength( backEnd.currentEntity->e.axis[0] ); + if ( !axisLength ) { + axisLength = 0; + } else { + axisLength = 1.0f / axisLength; + } + VectorScale(left, axisLength, left); + VectorScale(up, axisLength, up); + } + + RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); + } +} + + +/* +===================== +Autosprite2Deform + +Autosprite2 will pivot a rectangular quad along the center of its long axis +===================== +*/ +int edgeVerts[6][2] = { + { 0, 1 }, + { 0, 2 }, + { 0, 3 }, + { 1, 2 }, + { 1, 3 }, + { 2, 3 } +}; + +static void Autosprite2Deform( void ) { + int i, j, k; + int indexes; + float *xyz; + vec3_t forward; + + if ( tess.numVertexes & 3 ) { + ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name ); + } + if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { + ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name ); + } + + if ( backEnd.currentEntity != &tr.worldEntity ) { + GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward ); + } else { + VectorCopy( backEnd.viewParms.or.axis[0], forward ); + } + + // this is a lot of work for two triangles... + // we could precalculate a lot of it is an issue, but it would mess up + // the shader abstraction + for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) { + float lengths[2]; + int nums[2]; + vec3_t mid[2]; + vec3_t major, minor; + float *v1, *v2; + + // find the midpoint + xyz = tess.xyz[i]; + + // identify the two shortest edges + nums[0] = nums[1] = 0; + lengths[0] = lengths[1] = 999999; + + for ( j = 0 ; j < 6 ; j++ ) { + float l; + vec3_t temp; + + v1 = xyz + 4 * edgeVerts[j][0]; + v2 = xyz + 4 * edgeVerts[j][1]; + + VectorSubtract( v1, v2, temp ); + + l = DotProduct( temp, temp ); + if ( l < lengths[0] ) { + nums[1] = nums[0]; + lengths[1] = lengths[0]; + nums[0] = j; + lengths[0] = l; + } else if ( l < lengths[1] ) { + nums[1] = j; + lengths[1] = l; + } + } + + for ( j = 0 ; j < 2 ; j++ ) { + v1 = xyz + 4 * edgeVerts[nums[j]][0]; + v2 = xyz + 4 * edgeVerts[nums[j]][1]; + + mid[j][0] = 0.5f * (v1[0] + v2[0]); + mid[j][1] = 0.5f * (v1[1] + v2[1]); + mid[j][2] = 0.5f * (v1[2] + v2[2]); + } + + // find the vector of the major axis + VectorSubtract( mid[1], mid[0], major ); + + // cross this with the view direction to get minor axis + CrossProduct( major, forward, minor ); + VectorNormalize( minor ); + + // re-project the points + for ( j = 0 ; j < 2 ; j++ ) { + float l; + + v1 = xyz + 4 * edgeVerts[nums[j]][0]; + v2 = xyz + 4 * edgeVerts[nums[j]][1]; + + l = 0.5 * sqrt( lengths[j] ); + + // we need to see which direction this edge + // is used to determine direction of projection + for ( k = 0 ; k < 5 ; k++ ) { + if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0] + && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) { + break; + } + } + + if ( k == 5 ) { + VectorMA( mid[j], l, minor, v1 ); + VectorMA( mid[j], -l, minor, v2 ); + } else { + VectorMA( mid[j], -l, minor, v1 ); + VectorMA( mid[j], l, minor, v2 ); + } + } + } +} + + +/* +===================== +RB_DeformTessGeometry + +===================== +*/ +void RB_DeformTessGeometry( void ) { + int i; + deformStage_t *ds; + + for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) { + ds = &tess.shader->deforms[ i ]; + + switch ( ds->deformation ) { + case DEFORM_NONE: + break; + case DEFORM_NORMALS: + RB_CalcDeformNormals( ds ); + break; + case DEFORM_WAVE: + RB_CalcDeformVertexes( ds ); + break; + case DEFORM_BULGE: + RB_CalcBulgeVertexes( ds ); + break; + case DEFORM_MOVE: + RB_CalcMoveVertexes( ds ); + break; + case DEFORM_PROJECTION_SHADOW: + RB_ProjectionShadowDeform(); + break; + case DEFORM_AUTOSPRITE: + AutospriteDeform(); + break; + case DEFORM_AUTOSPRITE2: + Autosprite2Deform(); + break; + case DEFORM_TEXT0: + case DEFORM_TEXT1: + case DEFORM_TEXT2: + case DEFORM_TEXT3: + case DEFORM_TEXT4: + case DEFORM_TEXT5: + case DEFORM_TEXT6: + case DEFORM_TEXT7: + DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] ); + break; + } + } +} + +/* +==================================================================== + +COLORS + +==================================================================== +*/ + + +/* +** RB_CalcColorFromEntity +*/ +void RB_CalcColorFromEntity( unsigned char *dstColors ) +{ + int i; + int *pColors = ( int * ) dstColors; + int c; + + if ( !backEnd.currentEntity ) + return; + + c = * ( int * ) backEnd.currentEntity->e.shaderRGBA; + + for ( i = 0; i < tess.numVertexes; i++, pColors++ ) + { + *pColors = c; + } +} + +/* +** RB_CalcColorFromOneMinusEntity +*/ +void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ) +{ + int i; + int *pColors = ( int * ) dstColors; + unsigned char invModulate[3]; + int c; + + if ( !backEnd.currentEntity ) + return; + + invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0]; + invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1]; + invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2]; + invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it + + c = * ( int * ) invModulate; + + for ( i = 0; i < tess.numVertexes; i++, pColors++ ) + { + *pColors = * ( int * ) invModulate; + } +} + +/* +** RB_CalcAlphaFromEntity +*/ +void RB_CalcAlphaFromEntity( unsigned char *dstColors ) +{ + int i; + + if ( !backEnd.currentEntity ) + return; + + dstColors += 3; + + for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) + { + *dstColors = backEnd.currentEntity->e.shaderRGBA[3]; + } +} + +/* +** RB_CalcAlphaFromOneMinusEntity +*/ +void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ) +{ + int i; + + if ( !backEnd.currentEntity ) + return; + + dstColors += 3; + + for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) + { + *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3]; + } +} + +/* +** RB_CalcWaveColor +*/ +void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ) +{ + int i; + int v; + float glow; + int *colors = ( int * ) dstColors; + byte color[4]; + + + if ( wf->func == GF_NOISE ) { + glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude; + } else { + glow = EvalWaveForm( wf ) * tr.identityLight; + } + + if ( glow < 0 ) { + glow = 0; + } + else if ( glow > 1 ) { + glow = 1; + } + + v = myftol( 255 * glow ); + color[0] = color[1] = color[2] = v; + color[3] = 255; + v = *(int *)color; + + for ( i = 0; i < tess.numVertexes; i++, colors++ ) { + *colors = v; + } +} + +/* +** RB_CalcWaveAlpha +*/ +void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ) +{ + int i; + int v; + float glow; + + glow = EvalWaveFormClamped( wf ); + + v = 255 * glow; + + for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) + { + dstColors[3] = v; + } +} + +/* +** RB_CalcModulateColorsByFog +*/ +void RB_CalcModulateColorsByFog( unsigned char *colors ) { + int i; + float texCoords[SHADER_MAX_VERTEXES][2]; + + // calculate texcoords so we can derive density + // this is not wasted, because it would only have + // been previously called if the surface was opaque + RB_CalcFogTexCoords( texCoords[0] ); + + for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { + float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); + colors[0] *= f; + colors[1] *= f; + colors[2] *= f; + } +} + +/* +** RB_CalcModulateAlphasByFog +*/ +void RB_CalcModulateAlphasByFog( unsigned char *colors ) { + int i; + float texCoords[SHADER_MAX_VERTEXES][2]; + + // calculate texcoords so we can derive density + // this is not wasted, because it would only have + // been previously called if the surface was opaque + RB_CalcFogTexCoords( texCoords[0] ); + + for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { + float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); + colors[3] *= f; + } +} + +/* +** RB_CalcModulateRGBAsByFog +*/ +void RB_CalcModulateRGBAsByFog( unsigned char *colors ) { + int i; + float texCoords[SHADER_MAX_VERTEXES][2]; + + // calculate texcoords so we can derive density + // this is not wasted, because it would only have + // been previously called if the surface was opaque + RB_CalcFogTexCoords( texCoords[0] ); + + for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { + float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); + colors[0] *= f; + colors[1] *= f; + colors[2] *= f; + colors[3] *= f; + } +} + + +/* +==================================================================== + +TEX COORDS + +==================================================================== +*/ + +/* +======================== +RB_CalcFogTexCoords + +To do the clipped fog plane really correctly, we should use +projected textures, but I don't trust the drivers and it +doesn't fit our shader data. +======================== +*/ +void RB_CalcFogTexCoords( float *st ) { + int i; + float *v; + float s, t; + float eyeT; + qboolean eyeOutside; + fog_t *fog; + vec3_t local; + vec4_t fogDistanceVector, fogDepthVector; + + fog = tr.world->fogs + tess.fogNum; + + // all fogging distance is based on world Z units + VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); + fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; + fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; + fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; + fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); + + // scale the fog vectors based on the fog's thickness + fogDistanceVector[0] *= fog->tcScale; + fogDistanceVector[1] *= fog->tcScale; + fogDistanceVector[2] *= fog->tcScale; + fogDistanceVector[3] *= fog->tcScale; + + // rotate the gradient vector for this orientation + if ( fog->hasSurface ) { + fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + + fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; + fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + + fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; + fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + + fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; + fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); + + eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; + } else { + eyeT = 1; // non-surface fog always has eye inside + } + + // see if the viewpoint is outside + // this is needed for clipping distance even for constant fog + + if ( eyeT < 0 ) { + eyeOutside = qtrue; + } else { + eyeOutside = qfalse; + } + + fogDistanceVector[3] += 1.0/512; + + // calculate density for each point + for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) { + // calculate the length in fog + s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3]; + t = DotProduct( v, fogDepthVector ) + fogDepthVector[3]; + + // partially clipped fogs use the T axis + if ( eyeOutside ) { + if ( t < 1.0 ) { + t = 1.0/32; // point is outside, so no fogging + } else { + t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane + } + } else { + if ( t < 0 ) { + t = 1.0/32; // point is outside, so no fogging + } else { + t = 31.0/32; + } + } + + st[0] = s; + st[1] = t; + st += 2; + } +} + + + +/* +** RB_CalcEnvironmentTexCoords +*/ +void RB_CalcEnvironmentTexCoords( float *st ) +{ + int i; + float *v, *normal; + vec3_t viewer, reflected; + float d; + + v = tess.xyz[0]; + normal = tess.normal[0]; + + for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + { + VectorSubtract (backEnd.or.viewOrigin, v, viewer); + VectorNormalizeFast (viewer); + + d = DotProduct (normal, viewer); + + reflected[0] = normal[0]*2*d - viewer[0]; + reflected[1] = normal[1]*2*d - viewer[1]; + reflected[2] = normal[2]*2*d - viewer[2]; + + st[0] = 0.5 + reflected[1] * 0.5; + st[1] = 0.5 - reflected[2] * 0.5; + } +} + +/* +** RB_CalcTurbulentTexCoords +*/ +void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) +{ + int i; + float now; + + now = ( wf->phase + tess.shaderTime * wf->frequency ); + + for ( i = 0; i < tess.numVertexes; i++, st += 2 ) + { + float s = st[0]; + float t = st[1]; + + st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; + st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; + } +} + +/* +** RB_CalcScaleTexCoords +*/ +void RB_CalcScaleTexCoords( const float scale[2], float *st ) +{ + int i; + + for ( i = 0; i < tess.numVertexes; i++, st += 2 ) + { + st[0] *= scale[0]; + st[1] *= scale[1]; + } +} + +/* +** RB_CalcScrollTexCoords +*/ +void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st ) +{ + int i; + float timeScale = tess.shaderTime; + float adjustedScrollS, adjustedScrollT; + + adjustedScrollS = scrollSpeed[0] * timeScale; + adjustedScrollT = scrollSpeed[1] * timeScale; + + // clamp so coordinates don't continuously get larger, causing problems + // with hardware limits + adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); + adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); + + for ( i = 0; i < tess.numVertexes; i++, st += 2 ) + { + st[0] += adjustedScrollS; + st[1] += adjustedScrollT; + } +} + +/* +** RB_CalcTransformTexCoords +*/ +void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st ) +{ + int i; + + for ( i = 0; i < tess.numVertexes; i++, st += 2 ) + { + float s = st[0]; + float t = st[1]; + + st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0]; + st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1]; + } +} + +/* +** RB_CalcRotateTexCoords +*/ +void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) +{ + float timeScale = tess.shaderTime; + float degs; + int index; + float sinValue, cosValue; + texModInfo_t tmi; + + degs = -degsPerSecond * timeScale; + index = degs * ( FUNCTABLE_SIZE / 360.0f ); + + sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; + cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; + + tmi.matrix[0][0] = cosValue; + tmi.matrix[1][0] = -sinValue; + tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; + + tmi.matrix[0][1] = sinValue; + tmi.matrix[1][1] = cosValue; + tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; + + RB_CalcTransformTexCoords( &tmi, st ); +} + + + + + + +#if id386 && !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__ ) ) // rb010123 + +long myftol( float f ) { + static int tmp; + __asm fld f + __asm fistp tmp + __asm mov eax, tmp +} + +#endif + +/* +** RB_CalcSpecularAlpha +** +** Calculates specular coefficient and places it in the alpha channel +*/ +vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically + +void RB_CalcSpecularAlpha( unsigned char *alphas ) { + int i; + float *v, *normal; + vec3_t viewer, reflected; + float l, d; + int b; + vec3_t lightDir; + int numVertexes; + + v = tess.xyz[0]; + normal = tess.normal[0]; + + alphas += 3; + + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) { + float ilength; + + VectorSubtract( lightOrigin, v, lightDir ); +// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) ); + VectorNormalizeFast( lightDir ); + + // calculate the specular color + d = DotProduct (normal, lightDir); +// d *= ilength; + + // we don't optimize for the d < 0 case since this tends to + // cause visual artifacts such as faceted "snapping" + reflected[0] = normal[0]*2*d - lightDir[0]; + reflected[1] = normal[1]*2*d - lightDir[1]; + reflected[2] = normal[2]*2*d - lightDir[2]; + + VectorSubtract (backEnd.or.viewOrigin, v, viewer); + ilength = Q_rsqrt( DotProduct( viewer, viewer ) ); + l = DotProduct (reflected, viewer); + l *= ilength; + + if (l < 0) { + b = 0; + } else { + l = l*l; + l = l*l; + b = l * 255; + if (b > 255) { + b = 255; + } + } + + *alphas = b; + } +} + +/* +** RB_CalcDiffuseColor +** +** The basic vertex lighting calc +*/ +void RB_CalcDiffuseColor( unsigned char *colors ) +{ + int i, j; + float *v, *normal; + float incoming; + trRefEntity_t *ent; + int ambientLightInt; + vec3_t ambientLight; + vec3_t lightDir; + vec3_t directedLight; + int numVertexes; +#if idppc_altivec + vector unsigned char vSel = (vector unsigned char)(0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff); + vector float ambientLightVec; + vector float directedLightVec; + vector float lightDirVec; + vector float normalVec0, normalVec1; + vector float incomingVec0, incomingVec1, incomingVec2; + vector float zero, jVec; + vector signed int jVecInt; + vector signed short jVecShort; + vector unsigned char jVecChar, normalPerm; +#endif + ent = backEnd.currentEntity; + ambientLightInt = ent->ambientLightInt; +#if idppc_altivec + // A lot of this could be simplified if we made sure + // entities light info was 16-byte aligned. + jVecChar = vec_lvsl(0, ent->ambientLight); + ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight); + jVec = vec_ld(11, (vector float *)ent->ambientLight); + ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar); + + jVecChar = vec_lvsl(0, ent->directedLight); + directedLightVec = vec_ld(0,(vector float *)ent->directedLight); + jVec = vec_ld(11,(vector float *)ent->directedLight); + directedLightVec = vec_perm(directedLightVec,jVec,jVecChar); + + jVecChar = vec_lvsl(0, ent->lightDir); + lightDirVec = vec_ld(0,(vector float *)ent->lightDir); + jVec = vec_ld(11,(vector float *)ent->lightDir); + lightDirVec = vec_perm(lightDirVec,jVec,jVecChar); + + zero = (vector float)vec_splat_s8(0); + VectorCopy( ent->lightDir, lightDir ); +#else + VectorCopy( ent->ambientLight, ambientLight ); + VectorCopy( ent->directedLight, directedLight ); + VectorCopy( ent->lightDir, lightDir ); +#endif + + v = tess.xyz[0]; + normal = tess.normal[0]; + +#if idppc_altivec + normalPerm = vec_lvsl(0,normal); +#endif + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { +#if idppc_altivec + normalVec0 = vec_ld(0,(vector float *)normal); + normalVec1 = vec_ld(11,(vector float *)normal); + normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm); + incomingVec0 = vec_madd(normalVec0, lightDirVec, zero); + incomingVec1 = vec_sld(incomingVec0,incomingVec0,4); + incomingVec2 = vec_add(incomingVec0,incomingVec1); + incomingVec1 = vec_sld(incomingVec1,incomingVec1,4); + incomingVec2 = vec_add(incomingVec2,incomingVec1); + incomingVec0 = vec_splat(incomingVec2,0); + incomingVec0 = vec_max(incomingVec0,zero); + normalPerm = vec_lvsl(12,normal); + jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec); + jVecInt = vec_cts(jVec,0); // RGBx + jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx + jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx + jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 + vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color +#else + incoming = DotProduct (normal, lightDir); + if ( incoming <= 0 ) { + *(int *)&colors[i*4] = ambientLightInt; + continue; + } + j = myftol( ambientLight[0] + incoming * directedLight[0] ); + if ( j > 255 ) { + j = 255; + } + colors[i*4+0] = j; + + j = myftol( ambientLight[1] + incoming * directedLight[1] ); + if ( j > 255 ) { + j = 255; + } + colors[i*4+1] = j; + + j = myftol( ambientLight[2] + incoming * directedLight[2] ); + if ( j > 255 ) { + j = 255; + } + colors[i*4+2] = j; + + colors[i*4+3] = 255; +#endif + } +} + diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index ecf3798..b554f34 100755 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -1,3013 +1,3013 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-// tr_shader.c -- this file deals with the parsing and definition of shaders
-
-static char *s_shaderText;
-
-// the shader is parsed into these global variables, then copied into
-// dynamically allocated memory if it is valid.
-static shaderStage_t stages[MAX_SHADER_STAGES];
-static shader_t shader;
-static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
-static qboolean deferLoad;
-
-#define FILE_HASH_SIZE 1024
-static shader_t* hashTable[FILE_HASH_SIZE];
-
-#define MAX_SHADERTEXT_HASH 2048
-static char **shaderTextHashTable[MAX_SHADERTEXT_HASH];
-
-/*
-================
-return a hash value for the filename
-================
-*/
-static long generateHashValue( const char *fname, const int size ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- if (letter == PATH_SEP) letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash = (hash ^ (hash >> 10) ^ (hash >> 20));
- hash &= (size-1);
- return hash;
-}
-
-void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {
- char strippedName[MAX_QPATH];
- int hash;
- shader_t *sh, *sh2;
- qhandle_t h;
-
- sh = R_FindShaderByName( shaderName );
- if (sh == NULL || sh == tr.defaultShader) {
- h = RE_RegisterShaderLightMap(shaderName, 0);
- sh = R_GetShaderByHandle(h);
- }
- if (sh == NULL || sh == tr.defaultShader) {
- ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName );
- return;
- }
-
- sh2 = R_FindShaderByName( newShaderName );
- if (sh2 == NULL || sh2 == tr.defaultShader) {
- h = RE_RegisterShaderLightMap(newShaderName, 0);
- sh2 = R_GetShaderByHandle(h);
- }
-
- if (sh2 == NULL || sh2 == tr.defaultShader) {
- ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
- return;
- }
-
- // remap all the shaders with the given name
- // even tho they might have different lightmaps
- COM_StripExtension( shaderName, strippedName );
- hash = generateHashValue(strippedName, FILE_HASH_SIZE);
- for (sh = hashTable[hash]; sh; sh = sh->next) {
- if (Q_stricmp(sh->name, strippedName) == 0) {
- if (sh != sh2) {
- sh->remappedShader = sh2;
- } else {
- sh->remappedShader = NULL;
- }
- }
- }
- if (timeOffset) {
- sh2->timeOffset = atof(timeOffset);
- }
-}
-
-/*
-===============
-ParseVector
-===============
-*/
-static qboolean ParseVector( char **text, int count, float *v ) {
- char *token;
- int i;
-
- // FIXME: spaces are currently required after parens, should change parseext...
- token = COM_ParseExt( text, qfalse );
- if ( strcmp( token, "(" ) ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- for ( i = 0 ; i < count ; i++ ) {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
- return qfalse;
- }
- v[i] = atof( token );
- }
-
- token = COM_ParseExt( text, qfalse );
- if ( strcmp( token, ")" ) ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- return qtrue;
-}
-
-
-/*
-===============
-NameToAFunc
-===============
-*/
-static unsigned NameToAFunc( const char *funcname )
-{
- if ( !Q_stricmp( funcname, "GT0" ) )
- {
- return GLS_ATEST_GT_0;
- }
- else if ( !Q_stricmp( funcname, "LT128" ) )
- {
- return GLS_ATEST_LT_80;
- }
- else if ( !Q_stricmp( funcname, "GE128" ) )
- {
- return GLS_ATEST_GE_80;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
- return 0;
-}
-
-
-/*
-===============
-NameToSrcBlendMode
-===============
-*/
-static int NameToSrcBlendMode( const char *name )
-{
- if ( !Q_stricmp( name, "GL_ONE" ) )
- {
- return GLS_SRCBLEND_ONE;
- }
- else if ( !Q_stricmp( name, "GL_ZERO" ) )
- {
- return GLS_SRCBLEND_ZERO;
- }
- else if ( !Q_stricmp( name, "GL_DST_COLOR" ) )
- {
- return GLS_SRCBLEND_DST_COLOR;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) )
- {
- return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
- }
- else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
- {
- return GLS_SRCBLEND_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
- {
- return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
- {
- return GLS_SRCBLEND_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
- {
- return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) )
- {
- return GLS_SRCBLEND_ALPHA_SATURATE;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
- return GLS_SRCBLEND_ONE;
-}
-
-/*
-===============
-NameToDstBlendMode
-===============
-*/
-static int NameToDstBlendMode( const char *name )
-{
- if ( !Q_stricmp( name, "GL_ONE" ) )
- {
- return GLS_DSTBLEND_ONE;
- }
- else if ( !Q_stricmp( name, "GL_ZERO" ) )
- {
- return GLS_DSTBLEND_ZERO;
- }
- else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
- {
- return GLS_DSTBLEND_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
- {
- return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
- {
- return GLS_DSTBLEND_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
- {
- return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
- }
- else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) )
- {
- return GLS_DSTBLEND_SRC_COLOR;
- }
- else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) )
- {
- return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
- return GLS_DSTBLEND_ONE;
-}
-
-/*
-===============
-NameToGenFunc
-===============
-*/
-static genFunc_t NameToGenFunc( const char *funcname )
-{
- if ( !Q_stricmp( funcname, "sin" ) )
- {
- return GF_SIN;
- }
- else if ( !Q_stricmp( funcname, "square" ) )
- {
- return GF_SQUARE;
- }
- else if ( !Q_stricmp( funcname, "triangle" ) )
- {
- return GF_TRIANGLE;
- }
- else if ( !Q_stricmp( funcname, "sawtooth" ) )
- {
- return GF_SAWTOOTH;
- }
- else if ( !Q_stricmp( funcname, "inversesawtooth" ) )
- {
- return GF_INVERSE_SAWTOOTH;
- }
- else if ( !Q_stricmp( funcname, "noise" ) )
- {
- return GF_NOISE;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
- return GF_SIN;
-}
-
-
-/*
-===================
-ParseWaveForm
-===================
-*/
-static void ParseWaveForm( char **text, waveForm_t *wave )
-{
- char *token;
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->func = NameToGenFunc( token );
-
- // BASE, AMP, PHASE, FREQ
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->base = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->amplitude = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->phase = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
- return;
- }
- wave->frequency = atof( token );
-}
-
-
-/*
-===================
-ParseTexMod
-===================
-*/
-static void ParseTexMod( char *_text, shaderStage_t *stage )
-{
- const char *token;
- char **text = &_text;
- texModInfo_t *tmi;
-
- if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
- ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name );
- return;
- }
-
- tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
- stage->bundle[0].numTexMods++;
-
- token = COM_ParseExt( text, qfalse );
-
- //
- // turb
- //
- if ( !Q_stricmp( token, "turb" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.base = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.amplitude = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.phase = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.frequency = atof( token );
-
- tmi->type = TMOD_TURBULENT;
- }
- //
- // scale
- //
- else if ( !Q_stricmp( token, "scale" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scale[0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scale[1] = atof( token );
- tmi->type = TMOD_SCALE;
- }
- //
- // scroll
- //
- else if ( !Q_stricmp( token, "scroll" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scroll[0] = atof( token );
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->scroll[1] = atof( token );
- tmi->type = TMOD_SCROLL;
- }
- //
- // stretch
- //
- else if ( !Q_stricmp( token, "stretch" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.func = NameToGenFunc( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.base = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.amplitude = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.phase = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->wave.frequency = atof( token );
-
- tmi->type = TMOD_STRETCH;
- }
- //
- // transform
- //
- else if ( !Q_stricmp( token, "transform" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[0][0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[0][1] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[1][0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->matrix[1][1] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->translate[0] = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->translate[1] = atof( token );
-
- tmi->type = TMOD_TRANSFORM;
- }
- //
- // rotate
- //
- else if ( !Q_stricmp( token, "rotate" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
- return;
- }
- tmi->rotateSpeed = atof( token );
- tmi->type = TMOD_ROTATE;
- }
- //
- // entityTranslate
- //
- else if ( !Q_stricmp( token, "entityTranslate" ) )
- {
- tmi->type = TMOD_ENTITY_TRANSLATE;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
- }
-}
-
-
-/*
-===================
-ParseStage
-===================
-*/
-static qboolean ParseStage( shaderStage_t *stage, char **text )
-{
- char *token;
- int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
- qboolean depthMaskExplicit = qfalse;
-
- stage->active = qtrue;
-
- while ( 1 )
- {
- token = COM_ParseExt( text, qtrue );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
- return qfalse;
- }
-
- if ( token[0] == '}' )
- {
- break;
- }
- //
- // map <name>
- //
- else if ( !Q_stricmp( token, "map" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- if ( !Q_stricmp( token, "$whiteimage" ) )
- {
- stage->bundle[0].image[0] = tr.whiteImage;
- continue;
- }
- else if ( !Q_stricmp( token, "$lightmap" ) )
- {
- stage->bundle[0].isLightmap = qtrue;
- if ( shader.lightmapIndex < 0 ) {
- stage->bundle[0].image[0] = tr.whiteImage;
- } else {
- stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
- }
- continue;
- }
- else
- {
- stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT );
- if ( !stage->bundle[0].image[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- }
- }
- //
- // clampmap <name>
- //
- else if ( !Q_stricmp( token, "clampmap" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_CLAMP );
- if ( !stage->bundle[0].image[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- }
- //
- // animMap <frequency> <image1> .... <imageN>
- //
- else if ( !Q_stricmp( token, "animMap" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
- stage->bundle[0].imageAnimationSpeed = atof( token );
-
- // parse up to MAX_IMAGE_ANIMATIONS animations
- while ( 1 ) {
- int num;
-
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] ) {
- break;
- }
- num = stage->bundle[0].numImageAnimations;
- if ( num < MAX_IMAGE_ANIMATIONS ) {
- stage->bundle[0].image[num] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT );
- if ( !stage->bundle[0].image[num] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- stage->bundle[0].numImageAnimations++;
- }
- }
- }
- else if ( !Q_stricmp( token, "videoMap" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
- stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
- if (stage->bundle[0].videoMapHandle != -1) {
- stage->bundle[0].isVideoMap = qtrue;
- stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];
- }
- }
- //
- // alphafunc <func>
- //
- else if ( !Q_stricmp( token, "alphaFunc" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- atestBits = NameToAFunc( token );
- }
- //
- // depthFunc <func>
- //
- else if ( !Q_stricmp( token, "depthfunc" ) )
- {
- token = COM_ParseExt( text, qfalse );
-
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
- return qfalse;
- }
-
- if ( !Q_stricmp( token, "lequal" ) )
- {
- depthFuncBits = 0;
- }
- else if ( !Q_stricmp( token, "equal" ) )
- {
- depthFuncBits = GLS_DEPTHFUNC_EQUAL;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
- continue;
- }
- }
- //
- // detail
- //
- else if ( !Q_stricmp( token, "detail" ) )
- {
- stage->isDetail = qtrue;
- }
- //
- // blendfunc <srcFactor> <dstFactor>
- // or blendfunc <add|filter|blend>
- //
- else if ( !Q_stricmp( token, "blendfunc" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
- continue;
- }
- // check for "simple" blends first
- if ( !Q_stricmp( token, "add" ) ) {
- blendSrcBits = GLS_SRCBLEND_ONE;
- blendDstBits = GLS_DSTBLEND_ONE;
- } else if ( !Q_stricmp( token, "filter" ) ) {
- blendSrcBits = GLS_SRCBLEND_DST_COLOR;
- blendDstBits = GLS_DSTBLEND_ZERO;
- } else if ( !Q_stricmp( token, "blend" ) ) {
- blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
- blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else {
- // complex double blends
- blendSrcBits = NameToSrcBlendMode( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
- continue;
- }
- blendDstBits = NameToDstBlendMode( token );
- }
-
- // clear depth mask for blended surfaces
- if ( !depthMaskExplicit )
- {
- depthMaskBits = 0;
- }
- }
- //
- // rgbGen
- //
- else if ( !Q_stricmp( token, "rgbGen" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "wave" ) )
- {
- ParseWaveForm( text, &stage->rgbWave );
- stage->rgbGen = CGEN_WAVEFORM;
- }
- else if ( !Q_stricmp( token, "const" ) )
- {
- vec3_t color;
-
- ParseVector( text, 3, color );
- stage->constantColor[0] = 255 * color[0];
- stage->constantColor[1] = 255 * color[1];
- stage->constantColor[2] = 255 * color[2];
-
- stage->rgbGen = CGEN_CONST;
- }
- else if ( !Q_stricmp( token, "identity" ) )
- {
- stage->rgbGen = CGEN_IDENTITY;
- }
- else if ( !Q_stricmp( token, "identityLighting" ) )
- {
- stage->rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- else if ( !Q_stricmp( token, "entity" ) )
- {
- stage->rgbGen = CGEN_ENTITY;
- }
- else if ( !Q_stricmp( token, "oneMinusEntity" ) )
- {
- stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
- }
- else if ( !Q_stricmp( token, "vertex" ) )
- {
- stage->rgbGen = CGEN_VERTEX;
- if ( stage->alphaGen == 0 ) {
- stage->alphaGen = AGEN_VERTEX;
- }
- }
- else if ( !Q_stricmp( token, "exactVertex" ) )
- {
- stage->rgbGen = CGEN_EXACT_VERTEX;
- }
- else if ( !Q_stricmp( token, "lightingDiffuse" ) )
- {
- stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
- }
- else if ( !Q_stricmp( token, "oneMinusVertex" ) )
- {
- stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
- continue;
- }
- }
- //
- // alphaGen
- //
- else if ( !Q_stricmp( token, "alphaGen" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "wave" ) )
- {
- ParseWaveForm( text, &stage->alphaWave );
- stage->alphaGen = AGEN_WAVEFORM;
- }
- else if ( !Q_stricmp( token, "const" ) )
- {
- token = COM_ParseExt( text, qfalse );
- stage->constantColor[3] = 255 * atof( token );
- stage->alphaGen = AGEN_CONST;
- }
- else if ( !Q_stricmp( token, "identity" ) )
- {
- stage->alphaGen = AGEN_IDENTITY;
- }
- else if ( !Q_stricmp( token, "entity" ) )
- {
- stage->alphaGen = AGEN_ENTITY;
- }
- else if ( !Q_stricmp( token, "oneMinusEntity" ) )
- {
- stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
- }
- else if ( !Q_stricmp( token, "vertex" ) )
- {
- stage->alphaGen = AGEN_VERTEX;
- }
- else if ( !Q_stricmp( token, "lightingSpecular" ) )
- {
- stage->alphaGen = AGEN_LIGHTING_SPECULAR;
- }
- else if ( !Q_stricmp( token, "oneMinusVertex" ) )
- {
- stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
- }
- else if ( !Q_stricmp( token, "portal" ) )
- {
- stage->alphaGen = AGEN_PORTAL;
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- shader.portalRange = 256;
- ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
- }
- else
- {
- shader.portalRange = atof( token );
- }
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
- continue;
- }
- }
- //
- // tcGen <function>
- //
- else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "environment" ) )
- {
- stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
- }
- else if ( !Q_stricmp( token, "lightmap" ) )
- {
- stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
- }
- else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
- {
- stage->bundle[0].tcGen = TCGEN_TEXTURE;
- }
- else if ( !Q_stricmp( token, "vector" ) )
- {
- ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
- ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
-
- stage->bundle[0].tcGen = TCGEN_VECTOR;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
- }
- }
- //
- // tcMod <type> <...>
- //
- else if ( !Q_stricmp( token, "tcMod" ) )
- {
- char buffer[1024] = "";
-
- while ( 1 )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- break;
- strcat( buffer, token );
- strcat( buffer, " " );
- }
-
- ParseTexMod( buffer, stage );
-
- continue;
- }
- //
- // depthmask
- //
- else if ( !Q_stricmp( token, "depthwrite" ) )
- {
- depthMaskBits = GLS_DEPTHMASK_TRUE;
- depthMaskExplicit = qtrue;
-
- continue;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
- return qfalse;
- }
- }
-
- //
- // if cgen isn't explicitly specified, use either identity or identitylighting
- //
- if ( stage->rgbGen == CGEN_BAD ) {
- if ( blendSrcBits == 0 ||
- blendSrcBits == GLS_SRCBLEND_ONE ||
- blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
- stage->rgbGen = CGEN_IDENTITY_LIGHTING;
- } else {
- stage->rgbGen = CGEN_IDENTITY;
- }
- }
-
-
- //
- // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
- //
- if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
- ( blendDstBits == GLS_DSTBLEND_ZERO ) )
- {
- blendDstBits = blendSrcBits = 0;
- depthMaskBits = GLS_DEPTHMASK_TRUE;
- }
-
- // decide which agens we can skip
- if ( stage->alphaGen == CGEN_IDENTITY ) {
- if ( stage->rgbGen == CGEN_IDENTITY
- || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
- stage->alphaGen = AGEN_SKIP;
- }
- }
-
- //
- // compute state bits
- //
- stage->stateBits = depthMaskBits |
- blendSrcBits | blendDstBits |
- atestBits |
- depthFuncBits;
-
- return qtrue;
-}
-
-/*
-===============
-ParseDeform
-
-deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
-deformVertexes normal <frequency> <amplitude>
-deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
-deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
-deformVertexes projectionShadow
-deformVertexes autoSprite
-deformVertexes autoSprite2
-deformVertexes text[0-7]
-===============
-*/
-static void ParseDeform( char **text ) {
- char *token;
- deformStage_t *ds;
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
- return;
- }
-
- if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
- ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
- return;
- }
-
- ds = &shader.deforms[ shader.numDeforms ];
- shader.numDeforms++;
-
- if ( !Q_stricmp( token, "projectionShadow" ) ) {
- ds->deformation = DEFORM_PROJECTION_SHADOW;
- return;
- }
-
- if ( !Q_stricmp( token, "autosprite" ) ) {
- ds->deformation = DEFORM_AUTOSPRITE;
- return;
- }
-
- if ( !Q_stricmp( token, "autosprite2" ) ) {
- ds->deformation = DEFORM_AUTOSPRITE2;
- return;
- }
-
- if ( !Q_stricmpn( token, "text", 4 ) ) {
- int n;
-
- n = token[4] - '0';
- if ( n < 0 || n > 7 ) {
- n = 0;
- }
- ds->deformation = DEFORM_TEXT0 + n;
- return;
- }
-
- if ( !Q_stricmp( token, "bulge" ) ) {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
- return;
- }
- ds->bulgeWidth = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
- return;
- }
- ds->bulgeHeight = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
- return;
- }
- ds->bulgeSpeed = atof( token );
-
- ds->deformation = DEFORM_BULGE;
- return;
- }
-
- if ( !Q_stricmp( token, "wave" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
-
- if ( atof( token ) != 0 )
- {
- ds->deformationSpread = 1.0f / atof( token );
- }
- else
- {
- ds->deformationSpread = 100.0f;
- ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
- }
-
- ParseWaveForm( text, &ds->deformationWave );
- ds->deformation = DEFORM_WAVE;
- return;
- }
-
- if ( !Q_stricmp( token, "normal" ) )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
- ds->deformationWave.amplitude = atof( token );
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
- ds->deformationWave.frequency = atof( token );
-
- ds->deformation = DEFORM_NORMALS;
- return;
- }
-
- if ( !Q_stricmp( token, "move" ) ) {
- int i;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
- return;
- }
- ds->moveVector[i] = atof( token );
- }
-
- ParseWaveForm( text, &ds->deformationWave );
- ds->deformation = DEFORM_MOVE;
- return;
- }
-
- ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
-}
-
-
-/*
-===============
-ParseSkyParms
-
-skyParms <outerbox> <cloudheight> <innerbox>
-===============
-*/
-static void ParseSkyParms( char **text ) {
- char *token;
- static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
- char pathname[MAX_QPATH];
- int i;
-
- // outerbox
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
- return;
- }
- if ( strcmp( token, "-" ) ) {
- for (i=0 ; i<6 ; i++) {
- Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
- , token, suf[i] );
- shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP );
- if ( !shader.sky.outerbox[i] ) {
- shader.sky.outerbox[i] = tr.defaultImage;
- }
- }
- }
-
- // cloudheight
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
- return;
- }
- shader.sky.cloudHeight = atof( token );
- if ( !shader.sky.cloudHeight ) {
- shader.sky.cloudHeight = 512;
- }
- R_InitSkyTexCoords( shader.sky.cloudHeight );
-
-
- // innerbox
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
- return;
- }
- if ( strcmp( token, "-" ) ) {
- for (i=0 ; i<6 ; i++) {
- Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
- , token, suf[i] );
- shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT );
- if ( !shader.sky.innerbox[i] ) {
- shader.sky.innerbox[i] = tr.defaultImage;
- }
- }
- }
-
- shader.isSky = qtrue;
-}
-
-
-/*
-=================
-ParseSort
-=================
-*/
-void ParseSort( char **text ) {
- char *token;
-
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
- return;
- }
-
- if ( !Q_stricmp( token, "portal" ) ) {
- shader.sort = SS_PORTAL;
- } else if ( !Q_stricmp( token, "sky" ) ) {
- shader.sort = SS_ENVIRONMENT;
- } else if ( !Q_stricmp( token, "opaque" ) ) {
- shader.sort = SS_OPAQUE;
- }else if ( !Q_stricmp( token, "decal" ) ) {
- shader.sort = SS_DECAL;
- } else if ( !Q_stricmp( token, "seeThrough" ) ) {
- shader.sort = SS_SEE_THROUGH;
- } else if ( !Q_stricmp( token, "banner" ) ) {
- shader.sort = SS_BANNER;
- } else if ( !Q_stricmp( token, "additive" ) ) {
- shader.sort = SS_BLEND1;
- } else if ( !Q_stricmp( token, "nearest" ) ) {
- shader.sort = SS_NEAREST;
- } else if ( !Q_stricmp( token, "underwater" ) ) {
- shader.sort = SS_UNDERWATER;
- } else {
- shader.sort = atof( token );
- }
-}
-
-
-
-// this table is also present in q3map
-
-typedef struct {
- char *name;
- int clearSolid, surfaceFlags, contents;
-} infoParm_t;
-
-infoParm_t infoParms[] = {
- // server relevant contents
- {"water", 1, 0, CONTENTS_WATER },
- {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
- {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
- {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
- {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
- {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
- {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
-
- // utility relevant attributes
- {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
- {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
- {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
- {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
- {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
- {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
- {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
-
- {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
- {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
- {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
- {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
- {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
-
- // server attributes
- {"slick", 0, SURF_SLICK, 0 },
- {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
- {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
- {"ladder", 0, SURF_LADDER, 0 },
- {"nodamage", 0, SURF_NODAMAGE, 0 },
- {"metalsteps", 0, SURF_METALSTEPS,0 },
- {"flesh", 0, SURF_FLESH, 0 },
- {"nosteps", 0, SURF_NOSTEPS, 0 },
-
- // drawsurf attributes
- {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
- {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
- {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
- {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
- {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface
-};
-
-
-/*
-===============
-ParseSurfaceParm
-
-surfaceparm <name>
-===============
-*/
-static void ParseSurfaceParm( char **text ) {
- char *token;
- int numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
- int i;
-
- token = COM_ParseExt( text, qfalse );
- for ( i = 0 ; i < numInfoParms ; i++ ) {
- if ( !Q_stricmp( token, infoParms[i].name ) ) {
- shader.surfaceFlags |= infoParms[i].surfaceFlags;
- shader.contentFlags |= infoParms[i].contents;
-#if 0
- if ( infoParms[i].clearSolid ) {
- si->contents &= ~CONTENTS_SOLID;
- }
-#endif
- break;
- }
- }
-}
-
-/*
-=================
-ParseShader
-
-The current text pointer is at the explicit text definition of the
-shader. Parse it into the global shader variable. Later functions
-will optimize it.
-=================
-*/
-static qboolean ParseShader( char **text )
-{
- char *token;
- int s;
-
- s = 0;
-
- token = COM_ParseExt( text, qtrue );
- if ( token[0] != '{' )
- {
- ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
- return qfalse;
- }
-
- while ( 1 )
- {
- token = COM_ParseExt( text, qtrue );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
- return qfalse;
- }
-
- // end of shader definition
- if ( token[0] == '}' )
- {
- break;
- }
- // stage definition
- else if ( token[0] == '{' )
- {
- if ( !ParseStage( &stages[s], text ) )
- {
- return qfalse;
- }
- stages[s].active = qtrue;
- s++;
- continue;
- }
- // skip stuff that only the QuakeEdRadient needs
- else if ( !Q_stricmpn( token, "qer", 3 ) ) {
- SkipRestOfLine( text );
- continue;
- }
- // sun parms
- else if ( !Q_stricmp( token, "q3map_sun" ) ) {
- float a, b;
-
- token = COM_ParseExt( text, qfalse );
- tr.sunLight[0] = atof( token );
- token = COM_ParseExt( text, qfalse );
- tr.sunLight[1] = atof( token );
- token = COM_ParseExt( text, qfalse );
- tr.sunLight[2] = atof( token );
-
- VectorNormalize( tr.sunLight );
-
- token = COM_ParseExt( text, qfalse );
- a = atof( token );
- VectorScale( tr.sunLight, a, tr.sunLight);
-
- token = COM_ParseExt( text, qfalse );
- a = atof( token );
- a = a / 180 * M_PI;
-
- token = COM_ParseExt( text, qfalse );
- b = atof( token );
- b = b / 180 * M_PI;
-
- tr.sunDirection[0] = cos( a ) * cos( b );
- tr.sunDirection[1] = sin( a ) * cos( b );
- tr.sunDirection[2] = sin( b );
- }
- else if ( !Q_stricmp( token, "deformVertexes" ) ) {
- ParseDeform( text );
- continue;
- }
- else if ( !Q_stricmp( token, "tesssize" ) ) {
- SkipRestOfLine( text );
- continue;
- }
- else if ( !Q_stricmp( token, "clampTime" ) ) {
- token = COM_ParseExt( text, qfalse );
- if (token[0]) {
- shader.clampTime = atof(token);
- }
- }
- // skip stuff that only the q3map needs
- else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
- SkipRestOfLine( text );
- continue;
- }
- // skip stuff that only q3map or the server needs
- else if ( !Q_stricmp( token, "surfaceParm" ) ) {
- ParseSurfaceParm( text );
- continue;
- }
- // no mip maps
- else if ( !Q_stricmp( token, "nomipmaps" ) )
- {
- shader.noMipMaps = qtrue;
- shader.noPicMip = qtrue;
- continue;
- }
- // no picmip adjustment
- else if ( !Q_stricmp( token, "nopicmip" ) )
- {
- shader.noPicMip = qtrue;
- continue;
- }
- // polygonOffset
- else if ( !Q_stricmp( token, "polygonOffset" ) )
- {
- shader.polygonOffset = qtrue;
- continue;
- }
- // entityMergable, allowing sprite surfaces from multiple entities
- // to be merged into one batch. This is a savings for smoke
- // puffs and blood, but can't be used for anything where the
- // shader calcs (not the surface function) reference the entity color or scroll
- else if ( !Q_stricmp( token, "entityMergable" ) )
- {
- shader.entityMergable = qtrue;
- continue;
- }
- // fogParms
- else if ( !Q_stricmp( token, "fogParms" ) )
- {
- if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
- return qfalse;
- }
-
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
- continue;
- }
- shader.fogParms.depthForOpaque = atof( token );
-
- // skip any old gradient directions
- SkipRestOfLine( text );
- continue;
- }
- // portal
- else if ( !Q_stricmp(token, "portal") )
- {
- shader.sort = SS_PORTAL;
- continue;
- }
- // skyparms <cloudheight> <outerbox> <innerbox>
- else if ( !Q_stricmp( token, "skyparms" ) )
- {
- ParseSkyParms( text );
- continue;
- }
- // light <value> determines flaring in q3map, not needed here
- else if ( !Q_stricmp(token, "light") )
- {
- token = COM_ParseExt( text, qfalse );
- continue;
- }
- // cull <face>
- else if ( !Q_stricmp( token, "cull") )
- {
- token = COM_ParseExt( text, qfalse );
- if ( token[0] == 0 )
- {
- ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
- continue;
- }
-
- if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) )
- {
- shader.cullType = CT_TWO_SIDED;
- }
- else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) )
- {
- shader.cullType = CT_BACK_SIDED;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
- }
- continue;
- }
- // sort
- else if ( !Q_stricmp( token, "sort" ) )
- {
- ParseSort( text );
- continue;
- }
- else
- {
- ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
- return qfalse;
- }
- }
-
- //
- // ignore shaders that don't have any stages, unless it is a sky or fog
- //
- if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {
- return qfalse;
- }
-
- shader.explicitlyDefined = qtrue;
-
- return qtrue;
-}
-
-/*
-========================================================================================
-
-SHADER OPTIMIZATION AND FOGGING
-
-========================================================================================
-*/
-
-/*
-===================
-ComputeStageIteratorFunc
-
-See if we can use on of the simple fastpath stage functions,
-otherwise set to the generic stage function
-===================
-*/
-static void ComputeStageIteratorFunc( void )
-{
- shader.optimalStageIteratorFunc = RB_StageIteratorGeneric;
-
- //
- // see if this should go into the sky path
- //
- if ( shader.isSky )
- {
- shader.optimalStageIteratorFunc = RB_StageIteratorSky;
- goto done;
- }
-
- if ( r_ignoreFastPath->integer )
- {
- return;
- }
-
- //
- // see if this can go into the vertex lit fast path
- //
- if ( shader.numUnfoggedPasses == 1 )
- {
- if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE )
- {
- if ( stages[0].alphaGen == AGEN_IDENTITY )
- {
- if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE )
- {
- if ( !shader.polygonOffset )
- {
- if ( !shader.multitextureEnv )
- {
- if ( !shader.numDeforms )
- {
- shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture;
- goto done;
- }
- }
- }
- }
- }
- }
- }
-
- //
- // see if this can go into an optimized LM, multitextured path
- //
- if ( shader.numUnfoggedPasses == 1 )
- {
- if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) )
- {
- if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE &&
- stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP )
- {
- if ( !shader.polygonOffset )
- {
- if ( !shader.numDeforms )
- {
- if ( shader.multitextureEnv )
- {
- shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture;
- goto done;
- }
- }
- }
- }
- }
- }
-
-done:
- return;
-}
-
-typedef struct {
- int blendA;
- int blendB;
-
- int multitextureEnv;
- int multitextureBlend;
-} collapse_t;
-
-static collapse_t collapse[] = {
- { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
- GL_MODULATE, 0 },
-
- { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
- GL_MODULATE, 0 },
-
- { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
- GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
-
- { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
- GL_ADD, 0 },
-
- { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
- GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },
-#if 0
- { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA,
- GL_DECAL, 0 },
-#endif
- { -1 }
-};
-
-/*
-================
-CollapseMultitexture
-
-Attempt to combine two stages into a single multitexture stage
-FIXME: I think modulated add + modulated add collapses incorrectly
-=================
-*/
-static qboolean CollapseMultitexture( void ) {
- int abits, bbits;
- int i;
- textureBundle_t tmpBundle;
-
- if ( !qglActiveTextureARB ) {
- return qfalse;
- }
-
- // make sure both stages are active
- if ( !stages[0].active || !stages[1].active ) {
- return qfalse;
- }
-
- // on voodoo2, don't combine different tmus
- if ( glConfig.driverType == GLDRV_VOODOO ) {
- if ( stages[0].bundle[0].image[0]->TMU ==
- stages[1].bundle[0].image[0]->TMU ) {
- return qfalse;
- }
- }
-
- abits = stages[0].stateBits;
- bbits = stages[1].stateBits;
-
- // make sure that both stages have identical state other than blend modes
- if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
- ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
- return qfalse;
- }
-
- abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
- bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
-
- // search for a valid multitexture blend function
- for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
- if ( abits == collapse[i].blendA
- && bbits == collapse[i].blendB ) {
- break;
- }
- }
-
- // nothing found
- if ( collapse[i].blendA == -1 ) {
- return qfalse;
- }
-
- // GL_ADD is a separate extension
- if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
- return qfalse;
- }
-
- // make sure waveforms have identical parameters
- if ( ( stages[0].rgbGen != stages[1].rgbGen ) ||
- ( stages[0].alphaGen != stages[1].alphaGen ) ) {
- return qfalse;
- }
-
- // an add collapse can only have identity colors
- if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {
- return qfalse;
- }
-
- if ( stages[0].rgbGen == CGEN_WAVEFORM )
- {
- if ( memcmp( &stages[0].rgbWave,
- &stages[1].rgbWave,
- sizeof( stages[0].rgbWave ) ) )
- {
- return qfalse;
- }
- }
- if ( stages[0].alphaGen == CGEN_WAVEFORM )
- {
- if ( memcmp( &stages[0].alphaWave,
- &stages[1].alphaWave,
- sizeof( stages[0].alphaWave ) ) )
- {
- return qfalse;
- }
- }
-
-
- // make sure that lightmaps are in bundle 1 for 3dfx
- if ( stages[0].bundle[0].isLightmap )
- {
- tmpBundle = stages[0].bundle[0];
- stages[0].bundle[0] = stages[1].bundle[0];
- stages[0].bundle[1] = tmpBundle;
- }
- else
- {
- stages[0].bundle[1] = stages[1].bundle[0];
- }
-
- // set the new blend state bits
- shader.multitextureEnv = collapse[i].multitextureEnv;
- stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
- stages[0].stateBits |= collapse[i].multitextureBlend;
-
- //
- // move down subsequent shaders
- //
- memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
- Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) );
-
- return qtrue;
-}
-
-/*
-=============
-
-FixRenderCommandList
-https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
-Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
-but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
-to be rendered with bad shaders. To fix this, need to go through all render commands and fix
-sortedIndex.
-==============
-*/
-static void FixRenderCommandList( int newShader ) {
- renderCommandList_t *cmdList = &backEndData[tr.smpFrame]->commands;
-
- if( cmdList ) {
- const void *curCmd = cmdList->cmds;
-
- while ( 1 ) {
- switch ( *(const int *)curCmd ) {
- case RC_SET_COLOR:
- {
- const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
- curCmd = (const void *)(sc_cmd + 1);
- break;
- }
- case RC_STRETCH_PIC:
- {
- const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
- curCmd = (const void *)(sp_cmd + 1);
- break;
- }
- case RC_DRAW_SURFS:
- {
- int i;
- drawSurf_t *drawSurf;
- shader_t *shader;
- int fogNum;
- int entityNum;
- int dlightMap;
- int sortedIndex;
- const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
-
- for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
- R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
- sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
- if( sortedIndex >= newShader ) {
- sortedIndex++;
- drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
- }
- }
- curCmd = (const void *)(ds_cmd + 1);
- break;
- }
- case RC_DRAW_BUFFER:
- {
- const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
- curCmd = (const void *)(db_cmd + 1);
- break;
- }
- case RC_SWAP_BUFFERS:
- {
- const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
- curCmd = (const void *)(sb_cmd + 1);
- break;
- }
- case RC_END_OF_LIST:
- default:
- return;
- }
- }
- }
-}
-
-/*
-==============
-SortNewShader
-
-Positions the most recently created shader in the tr.sortedShaders[]
-array so that the shader->sort key is sorted reletive to the other
-shaders.
-
-Sets shader->sortedIndex
-==============
-*/
-static void SortNewShader( void ) {
- int i;
- float sort;
- shader_t *newShader;
-
- newShader = tr.shaders[ tr.numShaders - 1 ];
- sort = newShader->sort;
-
- for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
- if ( tr.sortedShaders[ i ]->sort <= sort ) {
- break;
- }
- tr.sortedShaders[i+1] = tr.sortedShaders[i];
- tr.sortedShaders[i+1]->sortedIndex++;
- }
-
- // Arnout: fix rendercommandlist
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
- FixRenderCommandList( i+1 );
-
- newShader->sortedIndex = i+1;
- tr.sortedShaders[i+1] = newShader;
-}
-
-
-/*
-====================
-GeneratePermanentShader
-====================
-*/
-static shader_t *GeneratePermanentShader( void ) {
- shader_t *newShader;
- int i, b;
- int size, hash;
-
- if ( tr.numShaders == MAX_SHADERS ) {
- ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
- return tr.defaultShader;
- }
-
- newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low );
-
- *newShader = shader;
-
- if ( shader.sort <= SS_OPAQUE ) {
- newShader->fogPass = FP_EQUAL;
- } else if ( shader.contentFlags & CONTENTS_FOG ) {
- newShader->fogPass = FP_LE;
- }
-
- tr.shaders[ tr.numShaders ] = newShader;
- newShader->index = tr.numShaders;
-
- tr.sortedShaders[ tr.numShaders ] = newShader;
- newShader->sortedIndex = tr.numShaders;
-
- tr.numShaders++;
-
- for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
- if ( !stages[i].active ) {
- break;
- }
- newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low );
- *newShader->stages[i] = stages[i];
-
- for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
- size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
- newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low );
- Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
- }
- }
-
- SortNewShader();
-
- hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
- newShader->next = hashTable[hash];
- hashTable[hash] = newShader;
-
- return newShader;
-}
-
-/*
-=================
-VertexLightingCollapse
-
-If vertex lighting is enabled, only render a single
-pass, trying to guess which is the correct one to best aproximate
-what it is supposed to look like.
-=================
-*/
-static void VertexLightingCollapse( void ) {
- int stage;
- shaderStage_t *bestStage;
- int bestImageRank;
- int rank;
-
- // if we aren't opaque, just use the first pass
- if ( shader.sort == SS_OPAQUE ) {
-
- // pick the best texture for the single pass
- bestStage = &stages[0];
- bestImageRank = -999999;
-
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
- shaderStage_t *pStage = &stages[stage];
-
- if ( !pStage->active ) {
- break;
- }
- rank = 0;
-
- if ( pStage->bundle[0].isLightmap ) {
- rank -= 100;
- }
- if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
- rank -= 5;
- }
- if ( pStage->bundle[0].numTexMods ) {
- rank -= 5;
- }
- if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
- rank -= 3;
- }
-
- if ( rank > bestImageRank ) {
- bestImageRank = rank;
- bestStage = pStage;
- }
- }
-
- stages[0].bundle[0] = bestStage->bundle[0];
- stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
- stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
- if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
- stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
- } else {
- stages[0].rgbGen = CGEN_EXACT_VERTEX;
- }
- stages[0].alphaGen = AGEN_SKIP;
- } else {
- // don't use a lightmap (tesla coils)
- if ( stages[0].bundle[0].isLightmap ) {
- stages[0] = stages[1];
- }
-
- // if we were in a cross-fade cgen, hack it to normal
- if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
- && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
- && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- }
- }
-
- for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {
- shaderStage_t *pStage = &stages[stage];
-
- if ( !pStage->active ) {
- break;
- }
-
- Com_Memset( pStage, 0, sizeof( *pStage ) );
- }
-}
-
-/*
-=========================
-FinishShader
-
-Returns a freshly allocated shader with all the needed info
-from the current global working shader
-=========================
-*/
-static shader_t *FinishShader( void ) {
- int stage;
- qboolean hasLightmapStage;
- qboolean vertexLightmap;
-
- hasLightmapStage = qfalse;
- vertexLightmap = qfalse;
-
- //
- // set sky stuff appropriate
- //
- if ( shader.isSky ) {
- shader.sort = SS_ENVIRONMENT;
- }
-
- //
- // set polygon offset
- //
- if ( shader.polygonOffset && !shader.sort ) {
- shader.sort = SS_DECAL;
- }
-
- //
- // set appropriate stage information
- //
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
- shaderStage_t *pStage = &stages[stage];
-
- if ( !pStage->active ) {
- break;
- }
-
- // check for a missing texture
- if ( !pStage->bundle[0].image[0] ) {
- ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
- pStage->active = qfalse;
- continue;
- }
-
- //
- // ditch this stage if it's detail and detail textures are disabled
- //
- if ( pStage->isDetail && !r_detailTextures->integer ) {
- if ( stage < ( MAX_SHADER_STAGES - 1 ) ) {
- memmove( pStage, pStage + 1, sizeof( *pStage ) * ( MAX_SHADER_STAGES - stage - 1 ) );
- Com_Memset( pStage + 1, 0, sizeof( *pStage ) );
- }
- continue;
- }
-
- //
- // default texture coordinate generation
- //
- if ( pStage->bundle[0].isLightmap ) {
- if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
- pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
- }
- hasLightmapStage = qtrue;
- } else {
- if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
- pStage->bundle[0].tcGen = TCGEN_TEXTURE;
- }
- }
-
-
- // not a true lightmap but we want to leave existing
- // behaviour in place and not print out a warning
- //if (pStage->rgbGen == CGEN_VERTEX) {
- // vertexLightmap = qtrue;
- //}
-
-
-
- //
- // determine sort order and fog color adjustment
- //
- if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
- ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
- int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
- int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
-
- // fog color adjustment only works for blend modes that have a contribution
- // that aproaches 0 as the modulate values aproach 0 --
- // GL_ONE, GL_ONE
- // GL_ZERO, GL_ONE_MINUS_SRC_COLOR
- // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
-
- // modulate, additive
- if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
- ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
- pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
- }
- // strict blend
- else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
- {
- pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
- }
- // premultiplied alpha
- else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
- {
- pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
- } else {
- // we can't adjust this one correctly, so it won't be exactly correct in fog
- }
-
- // don't screw with sort order if this is a portal or environment
- if ( !shader.sort ) {
- // see through item, like a grill or grate
- if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {
- shader.sort = SS_SEE_THROUGH;
- } else {
- shader.sort = SS_BLEND0;
- }
- }
- }
- }
-
- // there are times when you will need to manually apply a sort to
- // opaque alpha tested shaders that have later blend passes
- if ( !shader.sort ) {
- shader.sort = SS_OPAQUE;
- }
-
- //
- // if we are in r_vertexLight mode, never use a lightmap texture
- //
- if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) {
- VertexLightingCollapse();
- stage = 1;
- hasLightmapStage = qfalse;
- }
-
- //
- // look for multitexture potential
- //
- if ( stage > 1 && CollapseMultitexture() ) {
- stage--;
- }
-
- if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
- if (vertexLightmap) {
- ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
- } else {
- ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
- shader.lightmapIndex = LIGHTMAP_NONE;
- }
- }
-
-
- //
- // compute number of passes
- //
- shader.numUnfoggedPasses = stage;
-
- // fogonly shaders don't have any normal passes
- if ( stage == 0 ) {
- shader.sort = SS_FOG;
- }
-
- // determine which stage iterator function is appropriate
- ComputeStageIteratorFunc();
-
- return GeneratePermanentShader();
-}
-
-//========================================================================================
-
-/*
-====================
-FindShaderInShaderText
-
-Scans the combined text description of all the shader files for
-the given shader name.
-
-return NULL if not found
-
-If found, it will return a valid shader
-=====================
-*/
-static char *FindShaderInShaderText( const char *shadername ) {
-
- char *token, *p;
-
- int i, hash;
-
- hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
-
- for (i = 0; shaderTextHashTable[hash][i]; i++) {
- p = shaderTextHashTable[hash][i];
- token = COM_ParseExt(&p, qtrue);
- if ( !Q_stricmp( token, shadername ) ) {
- return p;
- }
- }
-
- p = s_shaderText;
-
- if ( !p ) {
- return NULL;
- }
-
- // look for label
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 ) {
- break;
- }
-
- if ( !Q_stricmp( token, shadername ) ) {
- return p;
- }
- else {
- // skip the definition
- SkipBracedSection( &p );
- }
- }
-
- return NULL;
-}
-
-
-/*
-==================
-R_FindShaderByName
-
-Will always return a valid shader, but it might be the
-default shader if the real one can't be found.
-==================
-*/
-shader_t *R_FindShaderByName( const char *name ) {
- char strippedName[MAX_QPATH];
- int hash;
- shader_t *sh;
-
- if ( (name==NULL) || (name[0] == 0) ) { // bk001205
- return tr.defaultShader;
- }
-
- COM_StripExtension( name, strippedName );
-
- hash = generateHashValue(strippedName, FILE_HASH_SIZE);
-
- //
- // see if the shader is already loaded
- //
- for (sh=hashTable[hash]; sh; sh=sh->next) {
- // NOTE: if there was no shader or image available with the name strippedName
- // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
- // have to check all default shaders otherwise for every call to R_FindShader
- // with that same strippedName a new default shader is created.
- if (Q_stricmp(sh->name, strippedName) == 0) {
- // match found
- return sh;
- }
- }
-
- return tr.defaultShader;
-}
-
-
-/*
-===============
-R_FindShader
-
-Will always return a valid shader, but it might be the
-default shader if the real one can't be found.
-
-In the interest of not requiring an explicit shader text entry to
-be defined for every single image used in the game, three default
-shader behaviors can be auto-created for any image:
-
-If lightmapIndex == LIGHTMAP_NONE, then the image will have
-dynamic diffuse lighting applied to it, as apropriate for most
-entity skin surfaces.
-
-If lightmapIndex == LIGHTMAP_2D, then the image will be used
-for 2D rendering unless an explicit shader is found
-
-If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
-the vertex rgba modulate values, as apropriate for misc_model
-pre-lit surfaces.
-
-Other lightmapIndex values will have a lightmap stage created
-and src*dest blending applied with the texture, as apropriate for
-most world construction surfaces.
-
-===============
-*/
-shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) {
- char strippedName[MAX_QPATH];
- char fileName[MAX_QPATH];
- int i, hash;
- char *shaderText;
- image_t *image;
- shader_t *sh;
-
- if ( name[0] == 0 ) {
- return tr.defaultShader;
- }
-
- // use (fullbright) vertex lighting if the bsp file doesn't have
- // lightmaps
- if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
- lightmapIndex = LIGHTMAP_BY_VERTEX;
- }
-
- COM_StripExtension( name, strippedName );
-
- hash = generateHashValue(strippedName, FILE_HASH_SIZE);
-
- //
- // see if the shader is already loaded
- //
- for (sh = hashTable[hash]; sh; sh = sh->next) {
- // NOTE: if there was no shader or image available with the name strippedName
- // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
- // have to check all default shaders otherwise for every call to R_FindShader
- // with that same strippedName a new default shader is created.
- if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
- !Q_stricmp(sh->name, strippedName)) {
- // match found
- return sh;
- }
- }
-
- // make sure the render thread is stopped, because we are probably
- // going to have to upload an image
- if (r_smp->integer) {
- R_SyncRenderThread();
- }
-
- // clear the global shader
- Com_Memset( &shader, 0, sizeof( shader ) );
- Com_Memset( &stages, 0, sizeof( stages ) );
- Q_strncpyz(shader.name, strippedName, sizeof(shader.name));
- shader.lightmapIndex = lightmapIndex;
- for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
- stages[i].bundle[0].texMods = texMods[i];
- }
-
- // FIXME: set these "need" values apropriately
- shader.needsNormal = qtrue;
- shader.needsST1 = qtrue;
- shader.needsST2 = qtrue;
- shader.needsColor = qtrue;
-
- //
- // attempt to define shader from an explicit parameter file
- //
- shaderText = FindShaderInShaderText( strippedName );
- if ( shaderText ) {
- // enable this when building a pak file to get a global list
- // of all explicit shaders
- if ( r_printShaders->integer ) {
- ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
- }
-
- if ( !ParseShader( &shaderText ) ) {
- // had errors, so use default shader
- shader.defaultShader = qtrue;
- }
- sh = FinishShader();
- return sh;
- }
-
-
- //
- // if not defined in the in-memory shader descriptions,
- // look for a single TGA, BMP, or PCX
- //
- Q_strncpyz( fileName, name, sizeof( fileName ) );
- COM_DefaultExtension( fileName, sizeof( fileName ), ".tga" );
- image = R_FindImageFile( fileName, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP );
- if ( !image ) {
- ri.Printf( PRINT_DEVELOPER, "Couldn't find image for shader %s\n", name );
- shader.defaultShader = qtrue;
- return FinishShader();
- }
-
- //
- // create the default shading commands
- //
- if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
- // dynamic colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
- // explicit colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_EXACT_VERTEX;
- stages[0].alphaGen = AGEN_SKIP;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
- // GUI elements
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_VERTEX;
- stages[0].alphaGen = AGEN_VERTEX;
- stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
- GLS_SRCBLEND_SRC_ALPHA |
- GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
- // fullbright level
- stages[0].bundle[0].image[0] = tr.whiteImage;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- } else {
- // two pass lightmap
- stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
- stages[0].bundle[0].isLightmap = qtrue;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
- // for identitylight
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- }
-
- return FinishShader();
-}
-
-
-qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) {
- int i, hash;
- shader_t *sh;
-
- hash = generateHashValue(name, FILE_HASH_SIZE);
-
- //
- // see if the shader is already loaded
- //
- for (sh=hashTable[hash]; sh; sh=sh->next) {
- // NOTE: if there was no shader or image available with the name strippedName
- // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
- // have to check all default shaders otherwise for every call to R_FindShader
- // with that same strippedName a new default shader is created.
- if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
- // index by name
- !Q_stricmp(sh->name, name)) {
- // match found
- return sh->index;
- }
- }
-
- // make sure the render thread is stopped, because we are probably
- // going to have to upload an image
- if (r_smp->integer) {
- R_SyncRenderThread();
- }
-
- // clear the global shader
- Com_Memset( &shader, 0, sizeof( shader ) );
- Com_Memset( &stages, 0, sizeof( stages ) );
- Q_strncpyz(shader.name, name, sizeof(shader.name));
- shader.lightmapIndex = lightmapIndex;
- for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
- stages[i].bundle[0].texMods = texMods[i];
- }
-
- // FIXME: set these "need" values apropriately
- shader.needsNormal = qtrue;
- shader.needsST1 = qtrue;
- shader.needsST2 = qtrue;
- shader.needsColor = qtrue;
-
- //
- // create the default shading commands
- //
- if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
- // dynamic colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
- // explicit colors at vertexes
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_EXACT_VERTEX;
- stages[0].alphaGen = AGEN_SKIP;
- stages[0].stateBits = GLS_DEFAULT;
- } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
- // GUI elements
- stages[0].bundle[0].image[0] = image;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_VERTEX;
- stages[0].alphaGen = AGEN_VERTEX;
- stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
- GLS_SRCBLEND_SRC_ALPHA |
- GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
- // fullbright level
- stages[0].bundle[0].image[0] = tr.whiteImage;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- } else {
- // two pass lightmap
- stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
- stages[0].bundle[0].isLightmap = qtrue;
- stages[0].active = qtrue;
- stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
- // for identitylight
- stages[0].stateBits = GLS_DEFAULT;
-
- stages[1].bundle[0].image[0] = image;
- stages[1].active = qtrue;
- stages[1].rgbGen = CGEN_IDENTITY;
- stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- }
-
- sh = FinishShader();
- return sh->index;
-}
-
-
-/*
-====================
-RE_RegisterShader
-
-This is the exported shader entry point for the rest of the system
-It will always return an index that will be valid.
-
-This should really only be used for explicit shaders, because there is no
-way to ask for different implicit lighting modes (vertex, lightmap, etc)
-====================
-*/
-qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {
- shader_t *sh;
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Shader name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sh = R_FindShader( name, lightmapIndex, qtrue );
-
- // we want to return 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
- if ( sh->defaultShader ) {
- return 0;
- }
-
- return sh->index;
-}
-
-
-/*
-====================
-RE_RegisterShader
-
-This is the exported shader entry point for the rest of the system
-It will always return an index that will be valid.
-
-This should really only be used for explicit shaders, because there is no
-way to ask for different implicit lighting modes (vertex, lightmap, etc)
-====================
-*/
-qhandle_t RE_RegisterShader( const char *name ) {
- shader_t *sh;
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Shader name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sh = R_FindShader( name, LIGHTMAP_2D, qtrue );
-
- // we want to return 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
- if ( sh->defaultShader ) {
- return 0;
- }
-
- return sh->index;
-}
-
-
-/*
-====================
-RE_RegisterShaderNoMip
-
-For menu graphics that should never be picmiped
-====================
-*/
-qhandle_t RE_RegisterShaderNoMip( const char *name ) {
- shader_t *sh;
-
- if ( strlen( name ) >= MAX_QPATH ) {
- Com_Printf( "Shader name exceeds MAX_QPATH\n" );
- return 0;
- }
-
- sh = R_FindShader( name, LIGHTMAP_2D, qfalse );
-
- // we want to return 0 if the shader failed to
- // load for some reason, but R_FindShader should
- // still keep a name allocated for it, so if
- // something calls RE_RegisterShader again with
- // the same name, we don't try looking for it again
- if ( sh->defaultShader ) {
- return 0;
- }
-
- return sh->index;
-}
-
-
-/*
-====================
-R_GetShaderByHandle
-
-When a handle is passed in by another module, this range checks
-it and returns a valid (possibly default) shader_t to be used internally.
-====================
-*/
-shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
- if ( hShader < 0 ) {
- ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); // bk: FIXME name
- return tr.defaultShader;
- }
- if ( hShader >= tr.numShaders ) {
- ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
- return tr.defaultShader;
- }
- return tr.shaders[hShader];
-}
-
-/*
-===============
-R_ShaderList_f
-
-Dump information on all valid shaders to the console
-A second parameter will cause it to print in sorted order
-===============
-*/
-void R_ShaderList_f (void) {
- int i;
- int count;
- shader_t *shader;
-
- ri.Printf (PRINT_ALL, "-----------------------\n");
-
- count = 0;
- for ( i = 0 ; i < tr.numShaders ; i++ ) {
- if ( ri.Cmd_Argc() > 1 ) {
- shader = tr.sortedShaders[i];
- } else {
- shader = tr.shaders[i];
- }
-
- ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
-
- if (shader->lightmapIndex >= 0 ) {
- ri.Printf (PRINT_ALL, "L ");
- } else {
- ri.Printf (PRINT_ALL, " ");
- }
- if ( shader->multitextureEnv == GL_ADD ) {
- ri.Printf( PRINT_ALL, "MT(a) " );
- } else if ( shader->multitextureEnv == GL_MODULATE ) {
- ri.Printf( PRINT_ALL, "MT(m) " );
- } else if ( shader->multitextureEnv == GL_DECAL ) {
- ri.Printf( PRINT_ALL, "MT(d) " );
- } else {
- ri.Printf( PRINT_ALL, " " );
- }
- if ( shader->explicitlyDefined ) {
- ri.Printf( PRINT_ALL, "E " );
- } else {
- ri.Printf( PRINT_ALL, " " );
- }
-
- if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) {
- ri.Printf( PRINT_ALL, "gen " );
- } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) {
- ri.Printf( PRINT_ALL, "sky " );
- } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) {
- ri.Printf( PRINT_ALL, "lmmt" );
- } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) {
- ri.Printf( PRINT_ALL, "vlt " );
- } else {
- ri.Printf( PRINT_ALL, " " );
- }
-
- if ( shader->defaultShader ) {
- ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name);
- } else {
- ri.Printf (PRINT_ALL, ": %s\n", shader->name);
- }
- count++;
- }
- ri.Printf (PRINT_ALL, "%i total shaders\n", count);
- ri.Printf (PRINT_ALL, "------------------\n");
-}
-
-
-/*
-====================
-ScanAndLoadShaderFiles
-
-Finds and loads all .shader files, combining them into
-a single large text block that can be scanned for shader names
-=====================
-*/
-#define MAX_SHADER_FILES 4096
-static void ScanAndLoadShaderFiles( void )
-{
- char **shaderFiles;
- char *buffers[MAX_SHADER_FILES];
- char *p;
- int numShaders;
- int i;
- char *oldp, *token, *hashMem;
- int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
-
- long sum = 0;
- // scan for shader files
- shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaders );
-
- if ( !shaderFiles || !numShaders )
- {
- ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
- return;
- }
-
- if ( numShaders > MAX_SHADER_FILES ) {
- numShaders = MAX_SHADER_FILES;
- }
-
- // load and parse shader files
- for ( i = 0; i < numShaders; i++ )
- {
- char filename[MAX_QPATH];
-
- Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
- ri.Printf( PRINT_ALL, "...loading '%s'\n", filename );
- sum += ri.FS_ReadFile( filename, (void **)&buffers[i] );
- if ( !buffers[i] ) {
- ri.Error( ERR_DROP, "Couldn't load %s", filename );
- }
- }
-
- // build single large buffer
- s_shaderText = ri.Hunk_Alloc( sum + numShaders*2, h_low );
-
- // free in reverse order, so the temp files are all dumped
- for ( i = numShaders - 1; i >= 0 ; i-- ) {
- strcat( s_shaderText, "\n" );
- p = &s_shaderText[strlen(s_shaderText)];
- strcat( s_shaderText, buffers[i] );
- ri.FS_FreeFile( buffers[i] );
- buffers[i] = p;
- COM_Compress(p);
- }
-
- // free up memory
- ri.FS_FreeFileList( shaderFiles );
-
- Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
- size = 0;
- //
- for ( i = 0; i < numShaders; i++ ) {
- // pointer to the first shader file
- p = buffers[i];
- // look for label
- while ( 1 ) {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 ) {
- break;
- }
-
- hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
- shaderTextHashTableSizes[hash]++;
- size++;
- SkipBracedSection(&p);
- // if we passed the pointer to the next shader file
- if ( i < numShaders - 1 ) {
- if ( p > buffers[i+1] ) {
- break;
- }
- }
- }
- }
-
- size += MAX_SHADERTEXT_HASH;
-
- hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low );
-
- for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
- shaderTextHashTable[i] = (char **) hashMem;
- hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
- }
-
- Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
- //
- for ( i = 0; i < numShaders; i++ ) {
- // pointer to the first shader file
- p = buffers[i];
- // look for label
- while ( 1 ) {
- oldp = p;
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 ) {
- break;
- }
-
- hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
- shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
-
- SkipBracedSection(&p);
- // if we passed the pointer to the next shader file
- if ( i < numShaders - 1 ) {
- if ( p > buffers[i+1] ) {
- break;
- }
- }
- }
- }
-
- return;
-
-}
-
-
-/*
-====================
-CreateInternalShaders
-====================
-*/
-static void CreateInternalShaders( void ) {
- tr.numShaders = 0;
-
- // init the default shader
- Com_Memset( &shader, 0, sizeof( shader ) );
- Com_Memset( &stages, 0, sizeof( stages ) );
-
- Q_strncpyz( shader.name, "<default>", sizeof( shader.name ) );
-
- shader.lightmapIndex = LIGHTMAP_NONE;
- stages[0].bundle[0].image[0] = tr.defaultImage;
- stages[0].active = qtrue;
- stages[0].stateBits = GLS_DEFAULT;
- tr.defaultShader = FinishShader();
-
- // shadow shader is just a marker
- Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
- shader.sort = SS_STENCIL_SHADOW;
- tr.shadowShader = FinishShader();
-}
-
-static void CreateExternalShaders( void ) {
- tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue );
- tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue );
- tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue );
-}
-
-/*
-==================
-R_InitShaders
-==================
-*/
-void R_InitShaders( void ) {
- ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
-
- Com_Memset(hashTable, 0, sizeof(hashTable));
-
- deferLoad = qfalse;
-
- CreateInternalShaders();
-
- ScanAndLoadShaderFiles();
-
- CreateExternalShaders();
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "tr_local.h" + +// tr_shader.c -- this file deals with the parsing and definition of shaders + +static char *s_shaderText; + +// the shader is parsed into these global variables, then copied into +// dynamically allocated memory if it is valid. +static shaderStage_t stages[MAX_SHADER_STAGES]; +static shader_t shader; +static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS]; +static qboolean deferLoad; + +#define FILE_HASH_SIZE 1024 +static shader_t* hashTable[FILE_HASH_SIZE]; + +#define MAX_SHADERTEXT_HASH 2048 +static char **shaderTextHashTable[MAX_SHADERTEXT_HASH]; + +/* +================ +return a hash value for the filename +================ +*/ +static long generateHashValue( const char *fname, const int size ) { + int i; + long hash; + char letter; + + hash = 0; + i = 0; + while (fname[i] != '\0') { + letter = tolower(fname[i]); + if (letter =='.') break; // don't include extension + if (letter =='\\') letter = '/'; // damn path names + if (letter == PATH_SEP) letter = '/'; // damn path names + hash+=(long)(letter)*(i+119); + i++; + } + hash = (hash ^ (hash >> 10) ^ (hash >> 20)); + hash &= (size-1); + return hash; +} + +void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { + char strippedName[MAX_QPATH]; + int hash; + shader_t *sh, *sh2; + qhandle_t h; + + sh = R_FindShaderByName( shaderName ); + if (sh == NULL || sh == tr.defaultShader) { + h = RE_RegisterShaderLightMap(shaderName, 0); + sh = R_GetShaderByHandle(h); + } + if (sh == NULL || sh == tr.defaultShader) { + ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); + return; + } + + sh2 = R_FindShaderByName( newShaderName ); + if (sh2 == NULL || sh2 == tr.defaultShader) { + h = RE_RegisterShaderLightMap(newShaderName, 0); + sh2 = R_GetShaderByHandle(h); + } + + if (sh2 == NULL || sh2 == tr.defaultShader) { + ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); + return; + } + + // remap all the shaders with the given name + // even tho they might have different lightmaps + COM_StripExtension( shaderName, strippedName ); + hash = generateHashValue(strippedName, FILE_HASH_SIZE); + for (sh = hashTable[hash]; sh; sh = sh->next) { + if (Q_stricmp(sh->name, strippedName) == 0) { + if (sh != sh2) { + sh->remappedShader = sh2; + } else { + sh->remappedShader = NULL; + } + } + } + if (timeOffset) { + sh2->timeOffset = atof(timeOffset); + } +} + +/* +=============== +ParseVector +=============== +*/ +static qboolean ParseVector( char **text, int count, float *v ) { + char *token; + int i; + + // FIXME: spaces are currently required after parens, should change parseext... + token = COM_ParseExt( text, qfalse ); + if ( strcmp( token, "(" ) ) { + ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); + return qfalse; + } + + for ( i = 0 ; i < count ; i++ ) { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name ); + return qfalse; + } + v[i] = atof( token ); + } + + token = COM_ParseExt( text, qfalse ); + if ( strcmp( token, ")" ) ) { + ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); + return qfalse; + } + + return qtrue; +} + + +/* +=============== +NameToAFunc +=============== +*/ +static unsigned NameToAFunc( const char *funcname ) +{ + if ( !Q_stricmp( funcname, "GT0" ) ) + { + return GLS_ATEST_GT_0; + } + else if ( !Q_stricmp( funcname, "LT128" ) ) + { + return GLS_ATEST_LT_80; + } + else if ( !Q_stricmp( funcname, "GE128" ) ) + { + return GLS_ATEST_GE_80; + } + + ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name ); + return 0; +} + + +/* +=============== +NameToSrcBlendMode +=============== +*/ +static int NameToSrcBlendMode( const char *name ) +{ + if ( !Q_stricmp( name, "GL_ONE" ) ) + { + return GLS_SRCBLEND_ONE; + } + else if ( !Q_stricmp( name, "GL_ZERO" ) ) + { + return GLS_SRCBLEND_ZERO; + } + else if ( !Q_stricmp( name, "GL_DST_COLOR" ) ) + { + return GLS_SRCBLEND_DST_COLOR; + } + else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) ) + { + return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; + } + else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) + { + return GLS_SRCBLEND_SRC_ALPHA; + } + else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) + { + return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; + } + else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) + { + return GLS_SRCBLEND_DST_ALPHA; + } + else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) + { + return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; + } + else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) + { + return GLS_SRCBLEND_ALPHA_SATURATE; + } + + ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); + return GLS_SRCBLEND_ONE; +} + +/* +=============== +NameToDstBlendMode +=============== +*/ +static int NameToDstBlendMode( const char *name ) +{ + if ( !Q_stricmp( name, "GL_ONE" ) ) + { + return GLS_DSTBLEND_ONE; + } + else if ( !Q_stricmp( name, "GL_ZERO" ) ) + { + return GLS_DSTBLEND_ZERO; + } + else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) + { + return GLS_DSTBLEND_SRC_ALPHA; + } + else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) + { + return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + } + else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) + { + return GLS_DSTBLEND_DST_ALPHA; + } + else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) + { + return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; + } + else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) + { + return GLS_DSTBLEND_SRC_COLOR; + } + else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) ) + { + return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; + } + + ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); + return GLS_DSTBLEND_ONE; +} + +/* +=============== +NameToGenFunc +=============== +*/ +static genFunc_t NameToGenFunc( const char *funcname ) +{ + if ( !Q_stricmp( funcname, "sin" ) ) + { + return GF_SIN; + } + else if ( !Q_stricmp( funcname, "square" ) ) + { + return GF_SQUARE; + } + else if ( !Q_stricmp( funcname, "triangle" ) ) + { + return GF_TRIANGLE; + } + else if ( !Q_stricmp( funcname, "sawtooth" ) ) + { + return GF_SAWTOOTH; + } + else if ( !Q_stricmp( funcname, "inversesawtooth" ) ) + { + return GF_INVERSE_SAWTOOTH; + } + else if ( !Q_stricmp( funcname, "noise" ) ) + { + return GF_NOISE; + } + + ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name ); + return GF_SIN; +} + + +/* +=================== +ParseWaveForm +=================== +*/ +static void ParseWaveForm( char **text, waveForm_t *wave ) +{ + char *token; + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); + return; + } + wave->func = NameToGenFunc( token ); + + // BASE, AMP, PHASE, FREQ + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); + return; + } + wave->base = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); + return; + } + wave->amplitude = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); + return; + } + wave->phase = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); + return; + } + wave->frequency = atof( token ); +} + + +/* +=================== +ParseTexMod +=================== +*/ +static void ParseTexMod( char *_text, shaderStage_t *stage ) +{ + const char *token; + char **text = &_text; + texModInfo_t *tmi; + + if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) { + ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name ); + return; + } + + tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods]; + stage->bundle[0].numTexMods++; + + token = COM_ParseExt( text, qfalse ); + + // + // turb + // + if ( !Q_stricmp( token, "turb" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name ); + return; + } + tmi->wave.base = atof( token ); + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); + return; + } + tmi->wave.amplitude = atof( token ); + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); + return; + } + tmi->wave.phase = atof( token ); + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); + return; + } + tmi->wave.frequency = atof( token ); + + tmi->type = TMOD_TURBULENT; + } + // + // scale + // + else if ( !Q_stricmp( token, "scale" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); + return; + } + tmi->scale[0] = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); + return; + } + tmi->scale[1] = atof( token ); + tmi->type = TMOD_SCALE; + } + // + // scroll + // + else if ( !Q_stricmp( token, "scroll" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); + return; + } + tmi->scroll[0] = atof( token ); + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); + return; + } + tmi->scroll[1] = atof( token ); + tmi->type = TMOD_SCROLL; + } + // + // stretch + // + else if ( !Q_stricmp( token, "stretch" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); + return; + } + tmi->wave.func = NameToGenFunc( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); + return; + } + tmi->wave.base = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); + return; + } + tmi->wave.amplitude = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); + return; + } + tmi->wave.phase = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); + return; + } + tmi->wave.frequency = atof( token ); + + tmi->type = TMOD_STRETCH; + } + // + // transform + // + else if ( !Q_stricmp( token, "transform" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); + return; + } + tmi->matrix[0][0] = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); + return; + } + tmi->matrix[0][1] = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); + return; + } + tmi->matrix[1][0] = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); + return; + } + tmi->matrix[1][1] = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); + return; + } + tmi->translate[0] = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); + return; + } + tmi->translate[1] = atof( token ); + + tmi->type = TMOD_TRANSFORM; + } + // + // rotate + // + else if ( !Q_stricmp( token, "rotate" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name ); + return; + } + tmi->rotateSpeed = atof( token ); + tmi->type = TMOD_ROTATE; + } + // + // entityTranslate + // + else if ( !Q_stricmp( token, "entityTranslate" ) ) + { + tmi->type = TMOD_ENTITY_TRANSLATE; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name ); + } +} + + +/* +=================== +ParseStage +=================== +*/ +static qboolean ParseStage( shaderStage_t *stage, char **text ) +{ + char *token; + int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; + qboolean depthMaskExplicit = qfalse; + + stage->active = qtrue; + + while ( 1 ) + { + token = COM_ParseExt( text, qtrue ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); + return qfalse; + } + + if ( token[0] == '}' ) + { + break; + } + // + // map <name> + // + else if ( !Q_stricmp( token, "map" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + if ( !Q_stricmp( token, "$whiteimage" ) ) + { + stage->bundle[0].image[0] = tr.whiteImage; + continue; + } + else if ( !Q_stricmp( token, "$lightmap" ) ) + { + stage->bundle[0].isLightmap = qtrue; + if ( shader.lightmapIndex < 0 ) { + stage->bundle[0].image[0] = tr.whiteImage; + } else { + stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; + } + continue; + } + else + { + stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT ); + if ( !stage->bundle[0].image[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + } + } + // + // clampmap <name> + // + else if ( !Q_stricmp( token, "clampmap" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_CLAMP ); + if ( !stage->bundle[0].image[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + } + // + // animMap <frequency> <image1> .... <imageN> + // + else if ( !Q_stricmp( token, "animMap" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[0].imageAnimationSpeed = atof( token ); + + // parse up to MAX_IMAGE_ANIMATIONS animations + while ( 1 ) { + int num; + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + break; + } + num = stage->bundle[0].numImageAnimations; + if ( num < MAX_IMAGE_ANIMATIONS ) { + stage->bundle[0].image[num] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT ); + if ( !stage->bundle[0].image[num] ) + { + ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + stage->bundle[0].numImageAnimations++; + } + } + } + else if ( !Q_stricmp( token, "videoMap" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[0].videoMapHandle != -1) { + stage->bundle[0].isVideoMap = qtrue; + stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; + } + } + // + // alphafunc <func> + // + else if ( !Q_stricmp( token, "alphaFunc" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + atestBits = NameToAFunc( token ); + } + // + // depthFunc <func> + // + else if ( !Q_stricmp( token, "depthfunc" ) ) + { + token = COM_ParseExt( text, qfalse ); + + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + if ( !Q_stricmp( token, "lequal" ) ) + { + depthFuncBits = 0; + } + else if ( !Q_stricmp( token, "equal" ) ) + { + depthFuncBits = GLS_DEPTHFUNC_EQUAL; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // + // detail + // + else if ( !Q_stricmp( token, "detail" ) ) + { + stage->isDetail = qtrue; + } + // + // blendfunc <srcFactor> <dstFactor> + // or blendfunc <add|filter|blend> + // + else if ( !Q_stricmp( token, "blendfunc" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); + continue; + } + // check for "simple" blends first + if ( !Q_stricmp( token, "add" ) ) { + blendSrcBits = GLS_SRCBLEND_ONE; + blendDstBits = GLS_DSTBLEND_ONE; + } else if ( !Q_stricmp( token, "filter" ) ) { + blendSrcBits = GLS_SRCBLEND_DST_COLOR; + blendDstBits = GLS_DSTBLEND_ZERO; + } else if ( !Q_stricmp( token, "blend" ) ) { + blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; + blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + } else { + // complex double blends + blendSrcBits = NameToSrcBlendMode( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); + continue; + } + blendDstBits = NameToDstBlendMode( token ); + } + + // clear depth mask for blended surfaces + if ( !depthMaskExplicit ) + { + depthMaskBits = 0; + } + } + // + // rgbGen + // + else if ( !Q_stricmp( token, "rgbGen" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "wave" ) ) + { + ParseWaveForm( text, &stage->rgbWave ); + stage->rgbGen = CGEN_WAVEFORM; + } + else if ( !Q_stricmp( token, "const" ) ) + { + vec3_t color; + + ParseVector( text, 3, color ); + stage->constantColor[0] = 255 * color[0]; + stage->constantColor[1] = 255 * color[1]; + stage->constantColor[2] = 255 * color[2]; + + stage->rgbGen = CGEN_CONST; + } + else if ( !Q_stricmp( token, "identity" ) ) + { + stage->rgbGen = CGEN_IDENTITY; + } + else if ( !Q_stricmp( token, "identityLighting" ) ) + { + stage->rgbGen = CGEN_IDENTITY_LIGHTING; + } + else if ( !Q_stricmp( token, "entity" ) ) + { + stage->rgbGen = CGEN_ENTITY; + } + else if ( !Q_stricmp( token, "oneMinusEntity" ) ) + { + stage->rgbGen = CGEN_ONE_MINUS_ENTITY; + } + else if ( !Q_stricmp( token, "vertex" ) ) + { + stage->rgbGen = CGEN_VERTEX; + if ( stage->alphaGen == 0 ) { + stage->alphaGen = AGEN_VERTEX; + } + } + else if ( !Q_stricmp( token, "exactVertex" ) ) + { + stage->rgbGen = CGEN_EXACT_VERTEX; + } + else if ( !Q_stricmp( token, "lightingDiffuse" ) ) + { + stage->rgbGen = CGEN_LIGHTING_DIFFUSE; + } + else if ( !Q_stricmp( token, "oneMinusVertex" ) ) + { + stage->rgbGen = CGEN_ONE_MINUS_VERTEX; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // + // alphaGen + // + else if ( !Q_stricmp( token, "alphaGen" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "wave" ) ) + { + ParseWaveForm( text, &stage->alphaWave ); + stage->alphaGen = AGEN_WAVEFORM; + } + else if ( !Q_stricmp( token, "const" ) ) + { + token = COM_ParseExt( text, qfalse ); + stage->constantColor[3] = 255 * atof( token ); + stage->alphaGen = AGEN_CONST; + } + else if ( !Q_stricmp( token, "identity" ) ) + { + stage->alphaGen = AGEN_IDENTITY; + } + else if ( !Q_stricmp( token, "entity" ) ) + { + stage->alphaGen = AGEN_ENTITY; + } + else if ( !Q_stricmp( token, "oneMinusEntity" ) ) + { + stage->alphaGen = AGEN_ONE_MINUS_ENTITY; + } + else if ( !Q_stricmp( token, "vertex" ) ) + { + stage->alphaGen = AGEN_VERTEX; + } + else if ( !Q_stricmp( token, "lightingSpecular" ) ) + { + stage->alphaGen = AGEN_LIGHTING_SPECULAR; + } + else if ( !Q_stricmp( token, "oneMinusVertex" ) ) + { + stage->alphaGen = AGEN_ONE_MINUS_VERTEX; + } + else if ( !Q_stricmp( token, "portal" ) ) + { + stage->alphaGen = AGEN_PORTAL; + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + shader.portalRange = 256; + ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); + } + else + { + shader.portalRange = atof( token ); + } + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // + // tcGen <function> + // + else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "environment" ) ) + { + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; + } + else if ( !Q_stricmp( token, "lightmap" ) ) + { + stage->bundle[0].tcGen = TCGEN_LIGHTMAP; + } + else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) + { + stage->bundle[0].tcGen = TCGEN_TEXTURE; + } + else if ( !Q_stricmp( token, "vector" ) ) + { + ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); + ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); + + stage->bundle[0].tcGen = TCGEN_VECTOR; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); + } + } + // + // tcMod <type> <...> + // + else if ( !Q_stricmp( token, "tcMod" ) ) + { + char buffer[1024] = ""; + + while ( 1 ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + break; + strcat( buffer, token ); + strcat( buffer, " " ); + } + + ParseTexMod( buffer, stage ); + + continue; + } + // + // depthmask + // + else if ( !Q_stricmp( token, "depthwrite" ) ) + { + depthMaskBits = GLS_DEPTHMASK_TRUE; + depthMaskExplicit = qtrue; + + continue; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + } + + // + // if cgen isn't explicitly specified, use either identity or identitylighting + // + if ( stage->rgbGen == CGEN_BAD ) { + if ( blendSrcBits == 0 || + blendSrcBits == GLS_SRCBLEND_ONE || + blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { + stage->rgbGen = CGEN_IDENTITY_LIGHTING; + } else { + stage->rgbGen = CGEN_IDENTITY; + } + } + + + // + // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending + // + if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && + ( blendDstBits == GLS_DSTBLEND_ZERO ) ) + { + blendDstBits = blendSrcBits = 0; + depthMaskBits = GLS_DEPTHMASK_TRUE; + } + + // decide which agens we can skip + if ( stage->alphaGen == CGEN_IDENTITY ) { + if ( stage->rgbGen == CGEN_IDENTITY + || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) { + stage->alphaGen = AGEN_SKIP; + } + } + + // + // compute state bits + // + stage->stateBits = depthMaskBits | + blendSrcBits | blendDstBits | + atestBits | + depthFuncBits; + + return qtrue; +} + +/* +=============== +ParseDeform + +deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency> +deformVertexes normal <frequency> <amplitude> +deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency> +deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed> +deformVertexes projectionShadow +deformVertexes autoSprite +deformVertexes autoSprite2 +deformVertexes text[0-7] +=============== +*/ +static void ParseDeform( char **text ) { + char *token; + deformStage_t *ds; + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name ); + return; + } + + if ( shader.numDeforms == MAX_SHADER_DEFORMS ) { + ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name ); + return; + } + + ds = &shader.deforms[ shader.numDeforms ]; + shader.numDeforms++; + + if ( !Q_stricmp( token, "projectionShadow" ) ) { + ds->deformation = DEFORM_PROJECTION_SHADOW; + return; + } + + if ( !Q_stricmp( token, "autosprite" ) ) { + ds->deformation = DEFORM_AUTOSPRITE; + return; + } + + if ( !Q_stricmp( token, "autosprite2" ) ) { + ds->deformation = DEFORM_AUTOSPRITE2; + return; + } + + if ( !Q_stricmpn( token, "text", 4 ) ) { + int n; + + n = token[4] - '0'; + if ( n < 0 || n > 7 ) { + n = 0; + } + ds->deformation = DEFORM_TEXT0 + n; + return; + } + + if ( !Q_stricmp( token, "bulge" ) ) { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); + return; + } + ds->bulgeWidth = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); + return; + } + ds->bulgeHeight = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); + return; + } + ds->bulgeSpeed = atof( token ); + + ds->deformation = DEFORM_BULGE; + return; + } + + if ( !Q_stricmp( token, "wave" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); + return; + } + + if ( atof( token ) != 0 ) + { + ds->deformationSpread = 1.0f / atof( token ); + } + else + { + ds->deformationSpread = 100.0f; + ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name ); + } + + ParseWaveForm( text, &ds->deformationWave ); + ds->deformation = DEFORM_WAVE; + return; + } + + if ( !Q_stricmp( token, "normal" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); + return; + } + ds->deformationWave.amplitude = atof( token ); + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); + return; + } + ds->deformationWave.frequency = atof( token ); + + ds->deformation = DEFORM_NORMALS; + return; + } + + if ( !Q_stricmp( token, "move" ) ) { + int i; + + for ( i = 0 ; i < 3 ; i++ ) { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) { + ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); + return; + } + ds->moveVector[i] = atof( token ); + } + + ParseWaveForm( text, &ds->deformationWave ); + ds->deformation = DEFORM_MOVE; + return; + } + + ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name ); +} + + +/* +=============== +ParseSkyParms + +skyParms <outerbox> <cloudheight> <innerbox> +=============== +*/ +static void ParseSkyParms( char **text ) { + char *token; + static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; + char pathname[MAX_QPATH]; + int i; + + // outerbox + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) { + ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); + return; + } + if ( strcmp( token, "-" ) ) { + for (i=0 ; i<6 ; i++) { + Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" + , token, suf[i] ); + shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP ); + if ( !shader.sky.outerbox[i] ) { + shader.sky.outerbox[i] = tr.defaultImage; + } + } + } + + // cloudheight + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) { + ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); + return; + } + shader.sky.cloudHeight = atof( token ); + if ( !shader.sky.cloudHeight ) { + shader.sky.cloudHeight = 512; + } + R_InitSkyTexCoords( shader.sky.cloudHeight ); + + + // innerbox + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) { + ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); + return; + } + if ( strcmp( token, "-" ) ) { + for (i=0 ; i<6 ; i++) { + Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" + , token, suf[i] ); + shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT ); + if ( !shader.sky.innerbox[i] ) { + shader.sky.innerbox[i] = tr.defaultImage; + } + } + } + + shader.isSky = qtrue; +} + + +/* +================= +ParseSort +================= +*/ +void ParseSort( char **text ) { + char *token; + + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) { + ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name ); + return; + } + + if ( !Q_stricmp( token, "portal" ) ) { + shader.sort = SS_PORTAL; + } else if ( !Q_stricmp( token, "sky" ) ) { + shader.sort = SS_ENVIRONMENT; + } else if ( !Q_stricmp( token, "opaque" ) ) { + shader.sort = SS_OPAQUE; + }else if ( !Q_stricmp( token, "decal" ) ) { + shader.sort = SS_DECAL; + } else if ( !Q_stricmp( token, "seeThrough" ) ) { + shader.sort = SS_SEE_THROUGH; + } else if ( !Q_stricmp( token, "banner" ) ) { + shader.sort = SS_BANNER; + } else if ( !Q_stricmp( token, "additive" ) ) { + shader.sort = SS_BLEND1; + } else if ( !Q_stricmp( token, "nearest" ) ) { + shader.sort = SS_NEAREST; + } else if ( !Q_stricmp( token, "underwater" ) ) { + shader.sort = SS_UNDERWATER; + } else { + shader.sort = atof( token ); + } +} + + + +// this table is also present in q3map + +typedef struct { + char *name; + int clearSolid, surfaceFlags, contents; +} infoParm_t; + +infoParm_t infoParms[] = { + // server relevant contents + {"water", 1, 0, CONTENTS_WATER }, + {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging + {"lava", 1, 0, CONTENTS_LAVA }, // very damaging + {"playerclip", 1, 0, CONTENTS_PLAYERCLIP }, + {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP }, + {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc) + {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag + + // utility relevant attributes + {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes + {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces + {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp + {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas + {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas + {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots + {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots + + {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering + {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map + {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it + {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis + {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter + + // server attributes + {"slick", 0, SURF_SLICK, 0 }, + {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks + {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode + {"ladder", 0, SURF_LADDER, 0 }, + {"nodamage", 0, SURF_NODAMAGE, 0 }, + {"metalsteps", 0, SURF_METALSTEPS,0 }, + {"flesh", 0, SURF_FLESH, 0 }, + {"nosteps", 0, SURF_NOSTEPS, 0 }, + + // drawsurf attributes + {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap) + {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes + {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap + {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights + {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface +}; + + +/* +=============== +ParseSurfaceParm + +surfaceparm <name> +=============== +*/ +static void ParseSurfaceParm( char **text ) { + char *token; + int numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]); + int i; + + token = COM_ParseExt( text, qfalse ); + for ( i = 0 ; i < numInfoParms ; i++ ) { + if ( !Q_stricmp( token, infoParms[i].name ) ) { + shader.surfaceFlags |= infoParms[i].surfaceFlags; + shader.contentFlags |= infoParms[i].contents; +#if 0 + if ( infoParms[i].clearSolid ) { + si->contents &= ~CONTENTS_SOLID; + } +#endif + break; + } + } +} + +/* +================= +ParseShader + +The current text pointer is at the explicit text definition of the +shader. Parse it into the global shader variable. Later functions +will optimize it. +================= +*/ +static qboolean ParseShader( char **text ) +{ + char *token; + int s; + + s = 0; + + token = COM_ParseExt( text, qtrue ); + if ( token[0] != '{' ) + { + ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name ); + return qfalse; + } + + while ( 1 ) + { + token = COM_ParseExt( text, qtrue ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name ); + return qfalse; + } + + // end of shader definition + if ( token[0] == '}' ) + { + break; + } + // stage definition + else if ( token[0] == '{' ) + { + if ( !ParseStage( &stages[s], text ) ) + { + return qfalse; + } + stages[s].active = qtrue; + s++; + continue; + } + // skip stuff that only the QuakeEdRadient needs + else if ( !Q_stricmpn( token, "qer", 3 ) ) { + SkipRestOfLine( text ); + continue; + } + // sun parms + else if ( !Q_stricmp( token, "q3map_sun" ) ) { + float a, b; + + token = COM_ParseExt( text, qfalse ); + tr.sunLight[0] = atof( token ); + token = COM_ParseExt( text, qfalse ); + tr.sunLight[1] = atof( token ); + token = COM_ParseExt( text, qfalse ); + tr.sunLight[2] = atof( token ); + + VectorNormalize( tr.sunLight ); + + token = COM_ParseExt( text, qfalse ); + a = atof( token ); + VectorScale( tr.sunLight, a, tr.sunLight); + + token = COM_ParseExt( text, qfalse ); + a = atof( token ); + a = a / 180 * M_PI; + + token = COM_ParseExt( text, qfalse ); + b = atof( token ); + b = b / 180 * M_PI; + + tr.sunDirection[0] = cos( a ) * cos( b ); + tr.sunDirection[1] = sin( a ) * cos( b ); + tr.sunDirection[2] = sin( b ); + } + else if ( !Q_stricmp( token, "deformVertexes" ) ) { + ParseDeform( text ); + continue; + } + else if ( !Q_stricmp( token, "tesssize" ) ) { + SkipRestOfLine( text ); + continue; + } + else if ( !Q_stricmp( token, "clampTime" ) ) { + token = COM_ParseExt( text, qfalse ); + if (token[0]) { + shader.clampTime = atof(token); + } + } + // skip stuff that only the q3map needs + else if ( !Q_stricmpn( token, "q3map", 5 ) ) { + SkipRestOfLine( text ); + continue; + } + // skip stuff that only q3map or the server needs + else if ( !Q_stricmp( token, "surfaceParm" ) ) { + ParseSurfaceParm( text ); + continue; + } + // no mip maps + else if ( !Q_stricmp( token, "nomipmaps" ) ) + { + shader.noMipMaps = qtrue; + shader.noPicMip = qtrue; + continue; + } + // no picmip adjustment + else if ( !Q_stricmp( token, "nopicmip" ) ) + { + shader.noPicMip = qtrue; + continue; + } + // polygonOffset + else if ( !Q_stricmp( token, "polygonOffset" ) ) + { + shader.polygonOffset = qtrue; + continue; + } + // entityMergable, allowing sprite surfaces from multiple entities + // to be merged into one batch. This is a savings for smoke + // puffs and blood, but can't be used for anything where the + // shader calcs (not the surface function) reference the entity color or scroll + else if ( !Q_stricmp( token, "entityMergable" ) ) + { + shader.entityMergable = qtrue; + continue; + } + // fogParms + else if ( !Q_stricmp( token, "fogParms" ) ) + { + if ( !ParseVector( text, 3, shader.fogParms.color ) ) { + return qfalse; + } + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name ); + continue; + } + shader.fogParms.depthForOpaque = atof( token ); + + // skip any old gradient directions + SkipRestOfLine( text ); + continue; + } + // portal + else if ( !Q_stricmp(token, "portal") ) + { + shader.sort = SS_PORTAL; + continue; + } + // skyparms <cloudheight> <outerbox> <innerbox> + else if ( !Q_stricmp( token, "skyparms" ) ) + { + ParseSkyParms( text ); + continue; + } + // light <value> determines flaring in q3map, not needed here + else if ( !Q_stricmp(token, "light") ) + { + token = COM_ParseExt( text, qfalse ); + continue; + } + // cull <face> + else if ( !Q_stricmp( token, "cull") ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) ) + { + shader.cullType = CT_TWO_SIDED; + } + else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) ) + { + shader.cullType = CT_BACK_SIDED; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name ); + } + continue; + } + // sort + else if ( !Q_stricmp( token, "sort" ) ) + { + ParseSort( text ); + continue; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name ); + return qfalse; + } + } + + // + // ignore shaders that don't have any stages, unless it is a sky or fog + // + if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) { + return qfalse; + } + + shader.explicitlyDefined = qtrue; + + return qtrue; +} + +/* +======================================================================================== + +SHADER OPTIMIZATION AND FOGGING + +======================================================================================== +*/ + +/* +=================== +ComputeStageIteratorFunc + +See if we can use on of the simple fastpath stage functions, +otherwise set to the generic stage function +=================== +*/ +static void ComputeStageIteratorFunc( void ) +{ + shader.optimalStageIteratorFunc = RB_StageIteratorGeneric; + + // + // see if this should go into the sky path + // + if ( shader.isSky ) + { + shader.optimalStageIteratorFunc = RB_StageIteratorSky; + goto done; + } + + if ( r_ignoreFastPath->integer ) + { + return; + } + + // + // see if this can go into the vertex lit fast path + // + if ( shader.numUnfoggedPasses == 1 ) + { + if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE ) + { + if ( stages[0].alphaGen == AGEN_IDENTITY ) + { + if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE ) + { + if ( !shader.polygonOffset ) + { + if ( !shader.multitextureEnv ) + { + if ( !shader.numDeforms ) + { + shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture; + goto done; + } + } + } + } + } + } + } + + // + // see if this can go into an optimized LM, multitextured path + // + if ( shader.numUnfoggedPasses == 1 ) + { + if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) ) + { + if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE && + stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP ) + { + if ( !shader.polygonOffset ) + { + if ( !shader.numDeforms ) + { + if ( shader.multitextureEnv ) + { + shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture; + goto done; + } + } + } + } + } + } + +done: + return; +} + +typedef struct { + int blendA; + int blendB; + + int multitextureEnv; + int multitextureBlend; +} collapse_t; + +static collapse_t collapse[] = { + { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, + GL_MODULATE, 0 }, + + { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, + GL_MODULATE, 0 }, + + { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, + GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, + + { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, + GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, + + { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, + GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, + + { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, + GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, + + { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, + GL_ADD, 0 }, + + { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, + GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE }, +#if 0 + { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA, + GL_DECAL, 0 }, +#endif + { -1 } +}; + +/* +================ +CollapseMultitexture + +Attempt to combine two stages into a single multitexture stage +FIXME: I think modulated add + modulated add collapses incorrectly +================= +*/ +static qboolean CollapseMultitexture( void ) { + int abits, bbits; + int i; + textureBundle_t tmpBundle; + + if ( !qglActiveTextureARB ) { + return qfalse; + } + + // make sure both stages are active + if ( !stages[0].active || !stages[1].active ) { + return qfalse; + } + + // on voodoo2, don't combine different tmus + if ( glConfig.driverType == GLDRV_VOODOO ) { + if ( stages[0].bundle[0].image[0]->TMU == + stages[1].bundle[0].image[0]->TMU ) { + return qfalse; + } + } + + abits = stages[0].stateBits; + bbits = stages[1].stateBits; + + // make sure that both stages have identical state other than blend modes + if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) != + ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) { + return qfalse; + } + + abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); + bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); + + // search for a valid multitexture blend function + for ( i = 0; collapse[i].blendA != -1 ; i++ ) { + if ( abits == collapse[i].blendA + && bbits == collapse[i].blendB ) { + break; + } + } + + // nothing found + if ( collapse[i].blendA == -1 ) { + return qfalse; + } + + // GL_ADD is a separate extension + if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) { + return qfalse; + } + + // make sure waveforms have identical parameters + if ( ( stages[0].rgbGen != stages[1].rgbGen ) || + ( stages[0].alphaGen != stages[1].alphaGen ) ) { + return qfalse; + } + + // an add collapse can only have identity colors + if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) { + return qfalse; + } + + if ( stages[0].rgbGen == CGEN_WAVEFORM ) + { + if ( memcmp( &stages[0].rgbWave, + &stages[1].rgbWave, + sizeof( stages[0].rgbWave ) ) ) + { + return qfalse; + } + } + if ( stages[0].alphaGen == CGEN_WAVEFORM ) + { + if ( memcmp( &stages[0].alphaWave, + &stages[1].alphaWave, + sizeof( stages[0].alphaWave ) ) ) + { + return qfalse; + } + } + + + // make sure that lightmaps are in bundle 1 for 3dfx + if ( stages[0].bundle[0].isLightmap ) + { + tmpBundle = stages[0].bundle[0]; + stages[0].bundle[0] = stages[1].bundle[0]; + stages[0].bundle[1] = tmpBundle; + } + else + { + stages[0].bundle[1] = stages[1].bundle[0]; + } + + // set the new blend state bits + shader.multitextureEnv = collapse[i].multitextureEnv; + stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); + stages[0].stateBits |= collapse[i].multitextureBlend; + + // + // move down subsequent shaders + // + memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) ); + Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) ); + + return qtrue; +} + +/* +============= + +FixRenderCommandList +https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 +Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated +but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces +to be rendered with bad shaders. To fix this, need to go through all render commands and fix +sortedIndex. +============== +*/ +static void FixRenderCommandList( int newShader ) { + renderCommandList_t *cmdList = &backEndData[tr.smpFrame]->commands; + + if( cmdList ) { + const void *curCmd = cmdList->cmds; + + while ( 1 ) { + switch ( *(const int *)curCmd ) { + case RC_SET_COLOR: + { + const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd; + curCmd = (const void *)(sc_cmd + 1); + break; + } + case RC_STRETCH_PIC: + { + const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd; + curCmd = (const void *)(sp_cmd + 1); + break; + } + case RC_DRAW_SURFS: + { + int i; + drawSurf_t *drawSurf; + shader_t *shader; + int fogNum; + int entityNum; + int dlightMap; + int sortedIndex; + const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; + + for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { + R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap ); + sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); + if( sortedIndex >= newShader ) { + sortedIndex++; + drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; + } + } + curCmd = (const void *)(ds_cmd + 1); + break; + } + case RC_DRAW_BUFFER: + { + const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd; + curCmd = (const void *)(db_cmd + 1); + break; + } + case RC_SWAP_BUFFERS: + { + const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd; + curCmd = (const void *)(sb_cmd + 1); + break; + } + case RC_END_OF_LIST: + default: + return; + } + } + } +} + +/* +============== +SortNewShader + +Positions the most recently created shader in the tr.sortedShaders[] +array so that the shader->sort key is sorted reletive to the other +shaders. + +Sets shader->sortedIndex +============== +*/ +static void SortNewShader( void ) { + int i; + float sort; + shader_t *newShader; + + newShader = tr.shaders[ tr.numShaders - 1 ]; + sort = newShader->sort; + + for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) { + if ( tr.sortedShaders[ i ]->sort <= sort ) { + break; + } + tr.sortedShaders[i+1] = tr.sortedShaders[i]; + tr.sortedShaders[i+1]->sortedIndex++; + } + + // Arnout: fix rendercommandlist + // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 + FixRenderCommandList( i+1 ); + + newShader->sortedIndex = i+1; + tr.sortedShaders[i+1] = newShader; +} + + +/* +==================== +GeneratePermanentShader +==================== +*/ +static shader_t *GeneratePermanentShader( void ) { + shader_t *newShader; + int i, b; + int size, hash; + + if ( tr.numShaders == MAX_SHADERS ) { + ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n"); + return tr.defaultShader; + } + + newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low ); + + *newShader = shader; + + if ( shader.sort <= SS_OPAQUE ) { + newShader->fogPass = FP_EQUAL; + } else if ( shader.contentFlags & CONTENTS_FOG ) { + newShader->fogPass = FP_LE; + } + + tr.shaders[ tr.numShaders ] = newShader; + newShader->index = tr.numShaders; + + tr.sortedShaders[ tr.numShaders ] = newShader; + newShader->sortedIndex = tr.numShaders; + + tr.numShaders++; + + for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) { + if ( !stages[i].active ) { + break; + } + newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low ); + *newShader->stages[i] = stages[i]; + + for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) { + size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t ); + newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low ); + Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size ); + } + } + + SortNewShader(); + + hash = generateHashValue(newShader->name, FILE_HASH_SIZE); + newShader->next = hashTable[hash]; + hashTable[hash] = newShader; + + return newShader; +} + +/* +================= +VertexLightingCollapse + +If vertex lighting is enabled, only render a single +pass, trying to guess which is the correct one to best aproximate +what it is supposed to look like. +================= +*/ +static void VertexLightingCollapse( void ) { + int stage; + shaderStage_t *bestStage; + int bestImageRank; + int rank; + + // if we aren't opaque, just use the first pass + if ( shader.sort == SS_OPAQUE ) { + + // pick the best texture for the single pass + bestStage = &stages[0]; + bestImageRank = -999999; + + for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { + shaderStage_t *pStage = &stages[stage]; + + if ( !pStage->active ) { + break; + } + rank = 0; + + if ( pStage->bundle[0].isLightmap ) { + rank -= 100; + } + if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) { + rank -= 5; + } + if ( pStage->bundle[0].numTexMods ) { + rank -= 5; + } + if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) { + rank -= 3; + } + + if ( rank > bestImageRank ) { + bestImageRank = rank; + bestStage = pStage; + } + } + + stages[0].bundle[0] = bestStage->bundle[0]; + stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); + stages[0].stateBits |= GLS_DEPTHMASK_TRUE; + if ( shader.lightmapIndex == LIGHTMAP_NONE ) { + stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; + } else { + stages[0].rgbGen = CGEN_EXACT_VERTEX; + } + stages[0].alphaGen = AGEN_SKIP; + } else { + // don't use a lightmap (tesla coils) + if ( stages[0].bundle[0].isLightmap ) { + stages[0] = stages[1]; + } + + // if we were in a cross-fade cgen, hack it to normal + if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) { + stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; + } + if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH ) + && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) { + stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; + } + if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH ) + && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) { + stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; + } + } + + for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) { + shaderStage_t *pStage = &stages[stage]; + + if ( !pStage->active ) { + break; + } + + Com_Memset( pStage, 0, sizeof( *pStage ) ); + } +} + +/* +========================= +FinishShader + +Returns a freshly allocated shader with all the needed info +from the current global working shader +========================= +*/ +static shader_t *FinishShader( void ) { + int stage; + qboolean hasLightmapStage; + qboolean vertexLightmap; + + hasLightmapStage = qfalse; + vertexLightmap = qfalse; + + // + // set sky stuff appropriate + // + if ( shader.isSky ) { + shader.sort = SS_ENVIRONMENT; + } + + // + // set polygon offset + // + if ( shader.polygonOffset && !shader.sort ) { + shader.sort = SS_DECAL; + } + + // + // set appropriate stage information + // + for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { + shaderStage_t *pStage = &stages[stage]; + + if ( !pStage->active ) { + break; + } + + // check for a missing texture + if ( !pStage->bundle[0].image[0] ) { + ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name ); + pStage->active = qfalse; + continue; + } + + // + // ditch this stage if it's detail and detail textures are disabled + // + if ( pStage->isDetail && !r_detailTextures->integer ) { + if ( stage < ( MAX_SHADER_STAGES - 1 ) ) { + memmove( pStage, pStage + 1, sizeof( *pStage ) * ( MAX_SHADER_STAGES - stage - 1 ) ); + Com_Memset( pStage + 1, 0, sizeof( *pStage ) ); + } + continue; + } + + // + // default texture coordinate generation + // + if ( pStage->bundle[0].isLightmap ) { + if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { + pStage->bundle[0].tcGen = TCGEN_LIGHTMAP; + } + hasLightmapStage = qtrue; + } else { + if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { + pStage->bundle[0].tcGen = TCGEN_TEXTURE; + } + } + + + // not a true lightmap but we want to leave existing + // behaviour in place and not print out a warning + //if (pStage->rgbGen == CGEN_VERTEX) { + // vertexLightmap = qtrue; + //} + + + + // + // determine sort order and fog color adjustment + // + if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) && + ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) { + int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS; + int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS; + + // fog color adjustment only works for blend modes that have a contribution + // that aproaches 0 as the modulate values aproach 0 -- + // GL_ONE, GL_ONE + // GL_ZERO, GL_ONE_MINUS_SRC_COLOR + // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA + + // modulate, additive + if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) || + ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) { + pStage->adjustColorsForFog = ACFF_MODULATE_RGB; + } + // strict blend + else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) + { + pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA; + } + // premultiplied alpha + else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) + { + pStage->adjustColorsForFog = ACFF_MODULATE_RGBA; + } else { + // we can't adjust this one correctly, so it won't be exactly correct in fog + } + + // don't screw with sort order if this is a portal or environment + if ( !shader.sort ) { + // see through item, like a grill or grate + if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) { + shader.sort = SS_SEE_THROUGH; + } else { + shader.sort = SS_BLEND0; + } + } + } + } + + // there are times when you will need to manually apply a sort to + // opaque alpha tested shaders that have later blend passes + if ( !shader.sort ) { + shader.sort = SS_OPAQUE; + } + + // + // if we are in r_vertexLight mode, never use a lightmap texture + // + if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) { + VertexLightingCollapse(); + stage = 1; + hasLightmapStage = qfalse; + } + + // + // look for multitexture potential + // + if ( stage > 1 && CollapseMultitexture() ) { + stage--; + } + + if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { + if (vertexLightmap) { + ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name ); + } else { + ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name ); + shader.lightmapIndex = LIGHTMAP_NONE; + } + } + + + // + // compute number of passes + // + shader.numUnfoggedPasses = stage; + + // fogonly shaders don't have any normal passes + if ( stage == 0 ) { + shader.sort = SS_FOG; + } + + // determine which stage iterator function is appropriate + ComputeStageIteratorFunc(); + + return GeneratePermanentShader(); +} + +//======================================================================================== + +/* +==================== +FindShaderInShaderText + +Scans the combined text description of all the shader files for +the given shader name. + +return NULL if not found + +If found, it will return a valid shader +===================== +*/ +static char *FindShaderInShaderText( const char *shadername ) { + + char *token, *p; + + int i, hash; + + hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH); + + for (i = 0; shaderTextHashTable[hash][i]; i++) { + p = shaderTextHashTable[hash][i]; + token = COM_ParseExt(&p, qtrue); + if ( !Q_stricmp( token, shadername ) ) { + return p; + } + } + + p = s_shaderText; + + if ( !p ) { + return NULL; + } + + // look for label + while ( 1 ) { + token = COM_ParseExt( &p, qtrue ); + if ( token[0] == 0 ) { + break; + } + + if ( !Q_stricmp( token, shadername ) ) { + return p; + } + else { + // skip the definition + SkipBracedSection( &p ); + } + } + + return NULL; +} + + +/* +================== +R_FindShaderByName + +Will always return a valid shader, but it might be the +default shader if the real one can't be found. +================== +*/ +shader_t *R_FindShaderByName( const char *name ) { + char strippedName[MAX_QPATH]; + int hash; + shader_t *sh; + + if ( (name==NULL) || (name[0] == 0) ) { // bk001205 + return tr.defaultShader; + } + + COM_StripExtension( name, strippedName ); + + hash = generateHashValue(strippedName, FILE_HASH_SIZE); + + // + // see if the shader is already loaded + // + for (sh=hashTable[hash]; sh; sh=sh->next) { + // NOTE: if there was no shader or image available with the name strippedName + // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we + // have to check all default shaders otherwise for every call to R_FindShader + // with that same strippedName a new default shader is created. + if (Q_stricmp(sh->name, strippedName) == 0) { + // match found + return sh; + } + } + + return tr.defaultShader; +} + + +/* +=============== +R_FindShader + +Will always return a valid shader, but it might be the +default shader if the real one can't be found. + +In the interest of not requiring an explicit shader text entry to +be defined for every single image used in the game, three default +shader behaviors can be auto-created for any image: + +If lightmapIndex == LIGHTMAP_NONE, then the image will have +dynamic diffuse lighting applied to it, as apropriate for most +entity skin surfaces. + +If lightmapIndex == LIGHTMAP_2D, then the image will be used +for 2D rendering unless an explicit shader is found + +If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use +the vertex rgba modulate values, as apropriate for misc_model +pre-lit surfaces. + +Other lightmapIndex values will have a lightmap stage created +and src*dest blending applied with the texture, as apropriate for +most world construction surfaces. + +=============== +*/ +shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { + char strippedName[MAX_QPATH]; + char fileName[MAX_QPATH]; + int i, hash; + char *shaderText; + image_t *image; + shader_t *sh; + + if ( name[0] == 0 ) { + return tr.defaultShader; + } + + // use (fullbright) vertex lighting if the bsp file doesn't have + // lightmaps + if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) { + lightmapIndex = LIGHTMAP_BY_VERTEX; + } + + COM_StripExtension( name, strippedName ); + + hash = generateHashValue(strippedName, FILE_HASH_SIZE); + + // + // see if the shader is already loaded + // + for (sh = hashTable[hash]; sh; sh = sh->next) { + // NOTE: if there was no shader or image available with the name strippedName + // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we + // have to check all default shaders otherwise for every call to R_FindShader + // with that same strippedName a new default shader is created. + if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && + !Q_stricmp(sh->name, strippedName)) { + // match found + return sh; + } + } + + // make sure the render thread is stopped, because we are probably + // going to have to upload an image + if (r_smp->integer) { + R_SyncRenderThread(); + } + + // clear the global shader + Com_Memset( &shader, 0, sizeof( shader ) ); + Com_Memset( &stages, 0, sizeof( stages ) ); + Q_strncpyz(shader.name, strippedName, sizeof(shader.name)); + shader.lightmapIndex = lightmapIndex; + for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { + stages[i].bundle[0].texMods = texMods[i]; + } + + // FIXME: set these "need" values apropriately + shader.needsNormal = qtrue; + shader.needsST1 = qtrue; + shader.needsST2 = qtrue; + shader.needsColor = qtrue; + + // + // attempt to define shader from an explicit parameter file + // + shaderText = FindShaderInShaderText( strippedName ); + if ( shaderText ) { + // enable this when building a pak file to get a global list + // of all explicit shaders + if ( r_printShaders->integer ) { + ri.Printf( PRINT_ALL, "*SHADER* %s\n", name ); + } + + if ( !ParseShader( &shaderText ) ) { + // had errors, so use default shader + shader.defaultShader = qtrue; + } + sh = FinishShader(); + return sh; + } + + + // + // if not defined in the in-memory shader descriptions, + // look for a single TGA, BMP, or PCX + // + Q_strncpyz( fileName, name, sizeof( fileName ) ); + COM_DefaultExtension( fileName, sizeof( fileName ), ".tga" ); + image = R_FindImageFile( fileName, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP ); + if ( !image ) { + ri.Printf( PRINT_DEVELOPER, "Couldn't find image for shader %s\n", name ); + shader.defaultShader = qtrue; + return FinishShader(); + } + + // + // create the default shading commands + // + if ( shader.lightmapIndex == LIGHTMAP_NONE ) { + // dynamic colors at vertexes + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; + stages[0].stateBits = GLS_DEFAULT; + } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { + // explicit colors at vertexes + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_EXACT_VERTEX; + stages[0].alphaGen = AGEN_SKIP; + stages[0].stateBits = GLS_DEFAULT; + } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { + // GUI elements + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_VERTEX; + stages[0].alphaGen = AGEN_VERTEX; + stages[0].stateBits = GLS_DEPTHTEST_DISABLE | + GLS_SRCBLEND_SRC_ALPHA | + GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { + // fullbright level + stages[0].bundle[0].image[0] = tr.whiteImage; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; + stages[0].stateBits = GLS_DEFAULT; + + stages[1].bundle[0].image[0] = image; + stages[1].active = qtrue; + stages[1].rgbGen = CGEN_IDENTITY; + stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; + } else { + // two pass lightmap + stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; + stages[0].bundle[0].isLightmap = qtrue; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation + // for identitylight + stages[0].stateBits = GLS_DEFAULT; + + stages[1].bundle[0].image[0] = image; + stages[1].active = qtrue; + stages[1].rgbGen = CGEN_IDENTITY; + stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; + } + + return FinishShader(); +} + + +qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) { + int i, hash; + shader_t *sh; + + hash = generateHashValue(name, FILE_HASH_SIZE); + + // + // see if the shader is already loaded + // + for (sh=hashTable[hash]; sh; sh=sh->next) { + // NOTE: if there was no shader or image available with the name strippedName + // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we + // have to check all default shaders otherwise for every call to R_FindShader + // with that same strippedName a new default shader is created. + if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && + // index by name + !Q_stricmp(sh->name, name)) { + // match found + return sh->index; + } + } + + // make sure the render thread is stopped, because we are probably + // going to have to upload an image + if (r_smp->integer) { + R_SyncRenderThread(); + } + + // clear the global shader + Com_Memset( &shader, 0, sizeof( shader ) ); + Com_Memset( &stages, 0, sizeof( stages ) ); + Q_strncpyz(shader.name, name, sizeof(shader.name)); + shader.lightmapIndex = lightmapIndex; + for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { + stages[i].bundle[0].texMods = texMods[i]; + } + + // FIXME: set these "need" values apropriately + shader.needsNormal = qtrue; + shader.needsST1 = qtrue; + shader.needsST2 = qtrue; + shader.needsColor = qtrue; + + // + // create the default shading commands + // + if ( shader.lightmapIndex == LIGHTMAP_NONE ) { + // dynamic colors at vertexes + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; + stages[0].stateBits = GLS_DEFAULT; + } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { + // explicit colors at vertexes + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_EXACT_VERTEX; + stages[0].alphaGen = AGEN_SKIP; + stages[0].stateBits = GLS_DEFAULT; + } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { + // GUI elements + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_VERTEX; + stages[0].alphaGen = AGEN_VERTEX; + stages[0].stateBits = GLS_DEPTHTEST_DISABLE | + GLS_SRCBLEND_SRC_ALPHA | + GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { + // fullbright level + stages[0].bundle[0].image[0] = tr.whiteImage; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; + stages[0].stateBits = GLS_DEFAULT; + + stages[1].bundle[0].image[0] = image; + stages[1].active = qtrue; + stages[1].rgbGen = CGEN_IDENTITY; + stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; + } else { + // two pass lightmap + stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; + stages[0].bundle[0].isLightmap = qtrue; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation + // for identitylight + stages[0].stateBits = GLS_DEFAULT; + + stages[1].bundle[0].image[0] = image; + stages[1].active = qtrue; + stages[1].rgbGen = CGEN_IDENTITY; + stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; + } + + sh = FinishShader(); + return sh->index; +} + + +/* +==================== +RE_RegisterShader + +This is the exported shader entry point for the rest of the system +It will always return an index that will be valid. + +This should really only be used for explicit shaders, because there is no +way to ask for different implicit lighting modes (vertex, lightmap, etc) +==================== +*/ +qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) { + shader_t *sh; + + if ( strlen( name ) >= MAX_QPATH ) { + Com_Printf( "Shader name exceeds MAX_QPATH\n" ); + return 0; + } + + sh = R_FindShader( name, lightmapIndex, qtrue ); + + // we want to return 0 if the shader failed to + // load for some reason, but R_FindShader should + // still keep a name allocated for it, so if + // something calls RE_RegisterShader again with + // the same name, we don't try looking for it again + if ( sh->defaultShader ) { + return 0; + } + + return sh->index; +} + + +/* +==================== +RE_RegisterShader + +This is the exported shader entry point for the rest of the system +It will always return an index that will be valid. + +This should really only be used for explicit shaders, because there is no +way to ask for different implicit lighting modes (vertex, lightmap, etc) +==================== +*/ +qhandle_t RE_RegisterShader( const char *name ) { + shader_t *sh; + + if ( strlen( name ) >= MAX_QPATH ) { + Com_Printf( "Shader name exceeds MAX_QPATH\n" ); + return 0; + } + + sh = R_FindShader( name, LIGHTMAP_2D, qtrue ); + + // we want to return 0 if the shader failed to + // load for some reason, but R_FindShader should + // still keep a name allocated for it, so if + // something calls RE_RegisterShader again with + // the same name, we don't try looking for it again + if ( sh->defaultShader ) { + return 0; + } + + return sh->index; +} + + +/* +==================== +RE_RegisterShaderNoMip + +For menu graphics that should never be picmiped +==================== +*/ +qhandle_t RE_RegisterShaderNoMip( const char *name ) { + shader_t *sh; + + if ( strlen( name ) >= MAX_QPATH ) { + Com_Printf( "Shader name exceeds MAX_QPATH\n" ); + return 0; + } + + sh = R_FindShader( name, LIGHTMAP_2D, qfalse ); + + // we want to return 0 if the shader failed to + // load for some reason, but R_FindShader should + // still keep a name allocated for it, so if + // something calls RE_RegisterShader again with + // the same name, we don't try looking for it again + if ( sh->defaultShader ) { + return 0; + } + + return sh->index; +} + + +/* +==================== +R_GetShaderByHandle + +When a handle is passed in by another module, this range checks +it and returns a valid (possibly default) shader_t to be used internally. +==================== +*/ +shader_t *R_GetShaderByHandle( qhandle_t hShader ) { + if ( hShader < 0 ) { + ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); // bk: FIXME name + return tr.defaultShader; + } + if ( hShader >= tr.numShaders ) { + ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); + return tr.defaultShader; + } + return tr.shaders[hShader]; +} + +/* +=============== +R_ShaderList_f + +Dump information on all valid shaders to the console +A second parameter will cause it to print in sorted order +=============== +*/ +void R_ShaderList_f (void) { + int i; + int count; + shader_t *shader; + + ri.Printf (PRINT_ALL, "-----------------------\n"); + + count = 0; + for ( i = 0 ; i < tr.numShaders ; i++ ) { + if ( ri.Cmd_Argc() > 1 ) { + shader = tr.sortedShaders[i]; + } else { + shader = tr.shaders[i]; + } + + ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses ); + + if (shader->lightmapIndex >= 0 ) { + ri.Printf (PRINT_ALL, "L "); + } else { + ri.Printf (PRINT_ALL, " "); + } + if ( shader->multitextureEnv == GL_ADD ) { + ri.Printf( PRINT_ALL, "MT(a) " ); + } else if ( shader->multitextureEnv == GL_MODULATE ) { + ri.Printf( PRINT_ALL, "MT(m) " ); + } else if ( shader->multitextureEnv == GL_DECAL ) { + ri.Printf( PRINT_ALL, "MT(d) " ); + } else { + ri.Printf( PRINT_ALL, " " ); + } + if ( shader->explicitlyDefined ) { + ri.Printf( PRINT_ALL, "E " ); + } else { + ri.Printf( PRINT_ALL, " " ); + } + + if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) { + ri.Printf( PRINT_ALL, "gen " ); + } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) { + ri.Printf( PRINT_ALL, "sky " ); + } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) { + ri.Printf( PRINT_ALL, "lmmt" ); + } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) { + ri.Printf( PRINT_ALL, "vlt " ); + } else { + ri.Printf( PRINT_ALL, " " ); + } + + if ( shader->defaultShader ) { + ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name); + } else { + ri.Printf (PRINT_ALL, ": %s\n", shader->name); + } + count++; + } + ri.Printf (PRINT_ALL, "%i total shaders\n", count); + ri.Printf (PRINT_ALL, "------------------\n"); +} + + +/* +==================== +ScanAndLoadShaderFiles + +Finds and loads all .shader files, combining them into +a single large text block that can be scanned for shader names +===================== +*/ +#define MAX_SHADER_FILES 4096 +static void ScanAndLoadShaderFiles( void ) +{ + char **shaderFiles; + char *buffers[MAX_SHADER_FILES]; + char *p; + int numShaders; + int i; + char *oldp, *token, *hashMem; + int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; + + long sum = 0; + // scan for shader files + shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaders ); + + if ( !shaderFiles || !numShaders ) + { + ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" ); + return; + } + + if ( numShaders > MAX_SHADER_FILES ) { + numShaders = MAX_SHADER_FILES; + } + + // load and parse shader files + for ( i = 0; i < numShaders; i++ ) + { + char filename[MAX_QPATH]; + + Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); + ri.Printf( PRINT_ALL, "...loading '%s'\n", filename ); + sum += ri.FS_ReadFile( filename, (void **)&buffers[i] ); + if ( !buffers[i] ) { + ri.Error( ERR_DROP, "Couldn't load %s", filename ); + } + } + + // build single large buffer + s_shaderText = ri.Hunk_Alloc( sum + numShaders*2, h_low ); + + // free in reverse order, so the temp files are all dumped + for ( i = numShaders - 1; i >= 0 ; i-- ) { + strcat( s_shaderText, "\n" ); + p = &s_shaderText[strlen(s_shaderText)]; + strcat( s_shaderText, buffers[i] ); + ri.FS_FreeFile( buffers[i] ); + buffers[i] = p; + COM_Compress(p); + } + + // free up memory + ri.FS_FreeFileList( shaderFiles ); + + Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); + size = 0; + // + for ( i = 0; i < numShaders; i++ ) { + // pointer to the first shader file + p = buffers[i]; + // look for label + while ( 1 ) { + token = COM_ParseExt( &p, qtrue ); + if ( token[0] == 0 ) { + break; + } + + hash = generateHashValue(token, MAX_SHADERTEXT_HASH); + shaderTextHashTableSizes[hash]++; + size++; + SkipBracedSection(&p); + // if we passed the pointer to the next shader file + if ( i < numShaders - 1 ) { + if ( p > buffers[i+1] ) { + break; + } + } + } + } + + size += MAX_SHADERTEXT_HASH; + + hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low ); + + for (i = 0; i < MAX_SHADERTEXT_HASH; i++) { + shaderTextHashTable[i] = (char **) hashMem; + hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *)); + } + + Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); + // + for ( i = 0; i < numShaders; i++ ) { + // pointer to the first shader file + p = buffers[i]; + // look for label + while ( 1 ) { + oldp = p; + token = COM_ParseExt( &p, qtrue ); + if ( token[0] == 0 ) { + break; + } + + hash = generateHashValue(token, MAX_SHADERTEXT_HASH); + shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; + + SkipBracedSection(&p); + // if we passed the pointer to the next shader file + if ( i < numShaders - 1 ) { + if ( p > buffers[i+1] ) { + break; + } + } + } + } + + return; + +} + + +/* +==================== +CreateInternalShaders +==================== +*/ +static void CreateInternalShaders( void ) { + tr.numShaders = 0; + + // init the default shader + Com_Memset( &shader, 0, sizeof( shader ) ); + Com_Memset( &stages, 0, sizeof( stages ) ); + + Q_strncpyz( shader.name, "<default>", sizeof( shader.name ) ); + + shader.lightmapIndex = LIGHTMAP_NONE; + stages[0].bundle[0].image[0] = tr.defaultImage; + stages[0].active = qtrue; + stages[0].stateBits = GLS_DEFAULT; + tr.defaultShader = FinishShader(); + + // shadow shader is just a marker + Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) ); + shader.sort = SS_STENCIL_SHADOW; + tr.shadowShader = FinishShader(); +} + +static void CreateExternalShaders( void ) { + tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue ); + tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue ); + tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); +} + +/* +================== +R_InitShaders +================== +*/ +void R_InitShaders( void ) { + ri.Printf( PRINT_ALL, "Initializing Shaders\n" ); + + Com_Memset(hashTable, 0, sizeof(hashTable)); + + deferLoad = qfalse; + + CreateInternalShaders(); + + ScanAndLoadShaderFiles(); + + CreateExternalShaders(); +} diff --git a/code/renderer/tr_shadows.c b/code/renderer/tr_shadows.c index 4a74292..29caf10 100755 --- a/code/renderer/tr_shadows.c +++ b/code/renderer/tr_shadows.c @@ -1,341 +1,341 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-
-/*
-
- for a projection shadow:
-
- point[x] += light vector * ( z - shadow plane )
- point[y] +=
- point[z] = shadow plane
-
- 1 0 light[x] / light[z]
-
-*/
-
-typedef struct {
- int i2;
- int facing;
-} edgeDef_t;
-
-#define MAX_EDGE_DEFS 32
-
-static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
-static int numEdgeDefs[SHADER_MAX_VERTEXES];
-static int facing[SHADER_MAX_INDEXES/3];
-
-void R_AddEdgeDef( int i1, int i2, int facing ) {
- int c;
-
- c = numEdgeDefs[ i1 ];
- if ( c == MAX_EDGE_DEFS ) {
- return; // overflow
- }
- edgeDefs[ i1 ][ c ].i2 = i2;
- edgeDefs[ i1 ][ c ].facing = facing;
-
- numEdgeDefs[ i1 ]++;
-}
-
-void R_RenderShadowEdges( void ) {
- int i;
-
-#if 0
- int numTris;
-
- // dumb way -- render every triangle's edges
- numTris = tess.numIndexes / 3;
-
- for ( i = 0 ; i < numTris ; i++ ) {
- int i1, i2, i3;
-
- if ( !facing[i] ) {
- continue;
- }
-
- i1 = tess.indexes[ i*3 + 0 ];
- i2 = tess.indexes[ i*3 + 1 ];
- i3 = tess.indexes[ i*3 + 2 ];
-
- qglBegin( GL_TRIANGLE_STRIP );
- qglVertex3fv( tess.xyz[ i1 ] );
- qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i2 ] );
- qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i3 ] );
- qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i1 ] );
- qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
- qglEnd();
- }
-#else
- int c, c2;
- int j, k;
- int i2;
- int c_edges, c_rejected;
- int hit[2];
-
- // an edge is NOT a silhouette edge if its face doesn't face the light,
- // or if it has a reverse paired edge that also faces the light.
- // A well behaved polyhedron would have exactly two faces for each edge,
- // but lots of models have dangling edges or overfanned edges
- c_edges = 0;
- c_rejected = 0;
-
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- c = numEdgeDefs[ i ];
- for ( j = 0 ; j < c ; j++ ) {
- if ( !edgeDefs[ i ][ j ].facing ) {
- continue;
- }
-
- hit[0] = 0;
- hit[1] = 0;
-
- i2 = edgeDefs[ i ][ j ].i2;
- c2 = numEdgeDefs[ i2 ];
- for ( k = 0 ; k < c2 ; k++ ) {
- if ( edgeDefs[ i2 ][ k ].i2 == i ) {
- hit[ edgeDefs[ i2 ][ k ].facing ]++;
- }
- }
-
- // if it doesn't share the edge with another front facing
- // triangle, it is a sil edge
- if ( hit[ 1 ] == 0 ) {
- qglBegin( GL_TRIANGLE_STRIP );
- qglVertex3fv( tess.xyz[ i ] );
- qglVertex3fv( tess.xyz[ i + tess.numVertexes ] );
- qglVertex3fv( tess.xyz[ i2 ] );
- qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
- qglEnd();
- c_edges++;
- } else {
- c_rejected++;
- }
- }
- }
-#endif
-}
-
-/*
-=================
-RB_ShadowTessEnd
-
-triangleFromEdge[ v1 ][ v2 ]
-
-
- set triangle from edge( v1, v2, tri )
- if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
- }
-=================
-*/
-void RB_ShadowTessEnd( void ) {
- int i;
- int numTris;
- vec3_t lightDir;
-
- // we can only do this if we have enough space in the vertex buffers
- if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
- return;
- }
-
- if ( glConfig.stencilBits < 4 ) {
- return;
- }
-
- VectorCopy( backEnd.currentEntity->lightDir, lightDir );
-
- // project vertexes away from light direction
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
- }
-
- // decide which triangles face the light
- Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
-
- numTris = tess.numIndexes / 3;
- for ( i = 0 ; i < numTris ; i++ ) {
- int i1, i2, i3;
- vec3_t d1, d2, normal;
- float *v1, *v2, *v3;
- float d;
-
- i1 = tess.indexes[ i*3 + 0 ];
- i2 = tess.indexes[ i*3 + 1 ];
- i3 = tess.indexes[ i*3 + 2 ];
-
- v1 = tess.xyz[ i1 ];
- v2 = tess.xyz[ i2 ];
- v3 = tess.xyz[ i3 ];
-
- VectorSubtract( v2, v1, d1 );
- VectorSubtract( v3, v1, d2 );
- CrossProduct( d1, d2, normal );
-
- d = DotProduct( normal, lightDir );
- if ( d > 0 ) {
- facing[ i ] = 1;
- } else {
- facing[ i ] = 0;
- }
-
- // create the edges
- R_AddEdgeDef( i1, i2, facing[ i ] );
- R_AddEdgeDef( i2, i3, facing[ i ] );
- R_AddEdgeDef( i3, i1, facing[ i ] );
- }
-
- // draw the silhouette edges
-
- GL_Bind( tr.whiteImage );
- qglEnable( GL_CULL_FACE );
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
- qglColor3f( 0.2f, 0.2f, 0.2f );
-
- // don't write to the color buffer
- qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
-
- qglEnable( GL_STENCIL_TEST );
- qglStencilFunc( GL_ALWAYS, 1, 255 );
-
- // mirrors have the culling order reversed
- if ( backEnd.viewParms.isMirror ) {
- qglCullFace( GL_FRONT );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
-
- R_RenderShadowEdges();
-
- qglCullFace( GL_BACK );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
-
- R_RenderShadowEdges();
- } else {
- qglCullFace( GL_BACK );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
-
- R_RenderShadowEdges();
-
- qglCullFace( GL_FRONT );
- qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
-
- R_RenderShadowEdges();
- }
-
-
- // reenable writing to the color buffer
- qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
-}
-
-
-/*
-=================
-RB_ShadowFinish
-
-Darken everything that is is a shadow volume.
-We have to delay this until everything has been shadowed,
-because otherwise shadows from different body parts would
-overlap and double darken.
-=================
-*/
-void RB_ShadowFinish( void ) {
- if ( r_shadows->integer != 2 ) {
- return;
- }
- if ( glConfig.stencilBits < 4 ) {
- return;
- }
- qglEnable( GL_STENCIL_TEST );
- qglStencilFunc( GL_NOTEQUAL, 0, 255 );
-
- qglDisable (GL_CLIP_PLANE0);
- qglDisable (GL_CULL_FACE);
-
- GL_Bind( tr.whiteImage );
-
- qglLoadIdentity ();
-
- qglColor3f( 0.6f, 0.6f, 0.6f );
- GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
-
-// qglColor3f( 1, 0, 0 );
-// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
-
- qglBegin( GL_QUADS );
- qglVertex3f( -100, 100, -10 );
- qglVertex3f( 100, 100, -10 );
- qglVertex3f( 100, -100, -10 );
- qglVertex3f( -100, -100, -10 );
- qglEnd ();
-
- qglColor4f(1,1,1,1);
- qglDisable( GL_STENCIL_TEST );
-}
-
-
-/*
-=================
-RB_ProjectionShadowDeform
-
-=================
-*/
-void RB_ProjectionShadowDeform( void ) {
- float *xyz;
- int i;
- float h;
- vec3_t ground;
- vec3_t light;
- float groundDist;
- float d;
- vec3_t lightDir;
-
- xyz = ( float * ) tess.xyz;
-
- ground[0] = backEnd.or.axis[0][2];
- ground[1] = backEnd.or.axis[1][2];
- ground[2] = backEnd.or.axis[2][2];
-
- groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
-
- VectorCopy( backEnd.currentEntity->lightDir, lightDir );
- d = DotProduct( lightDir, ground );
- // don't let the shadows get too long or go negative
- if ( d < 0.5 ) {
- VectorMA( lightDir, (0.5 - d), ground, lightDir );
- d = DotProduct( lightDir, ground );
- }
- d = 1.0 / d;
-
- light[0] = lightDir[0] * d;
- light[1] = lightDir[1] * d;
- light[2] = lightDir[2] * d;
-
- for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
- h = DotProduct( xyz, ground ) + groundDist;
-
- xyz[0] -= light[0] * h;
- xyz[1] -= light[1] * h;
- xyz[2] -= light[2] * h;
- }
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "tr_local.h" + + +/* + + for a projection shadow: + + point[x] += light vector * ( z - shadow plane ) + point[y] += + point[z] = shadow plane + + 1 0 light[x] / light[z] + +*/ + +typedef struct { + int i2; + int facing; +} edgeDef_t; + +#define MAX_EDGE_DEFS 32 + +static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; +static int numEdgeDefs[SHADER_MAX_VERTEXES]; +static int facing[SHADER_MAX_INDEXES/3]; + +void R_AddEdgeDef( int i1, int i2, int facing ) { + int c; + + c = numEdgeDefs[ i1 ]; + if ( c == MAX_EDGE_DEFS ) { + return; // overflow + } + edgeDefs[ i1 ][ c ].i2 = i2; + edgeDefs[ i1 ][ c ].facing = facing; + + numEdgeDefs[ i1 ]++; +} + +void R_RenderShadowEdges( void ) { + int i; + +#if 0 + int numTris; + + // dumb way -- render every triangle's edges + numTris = tess.numIndexes / 3; + + for ( i = 0 ; i < numTris ; i++ ) { + int i1, i2, i3; + + if ( !facing[i] ) { + continue; + } + + i1 = tess.indexes[ i*3 + 0 ]; + i2 = tess.indexes[ i*3 + 1 ]; + i3 = tess.indexes[ i*3 + 2 ]; + + qglBegin( GL_TRIANGLE_STRIP ); + qglVertex3fv( tess.xyz[ i1 ] ); + qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); + qglVertex3fv( tess.xyz[ i2 ] ); + qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); + qglVertex3fv( tess.xyz[ i3 ] ); + qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); + qglVertex3fv( tess.xyz[ i1 ] ); + qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); + qglEnd(); + } +#else + int c, c2; + int j, k; + int i2; + int c_edges, c_rejected; + int hit[2]; + + // an edge is NOT a silhouette edge if its face doesn't face the light, + // or if it has a reverse paired edge that also faces the light. + // A well behaved polyhedron would have exactly two faces for each edge, + // but lots of models have dangling edges or overfanned edges + c_edges = 0; + c_rejected = 0; + + for ( i = 0 ; i < tess.numVertexes ; i++ ) { + c = numEdgeDefs[ i ]; + for ( j = 0 ; j < c ; j++ ) { + if ( !edgeDefs[ i ][ j ].facing ) { + continue; + } + + hit[0] = 0; + hit[1] = 0; + + i2 = edgeDefs[ i ][ j ].i2; + c2 = numEdgeDefs[ i2 ]; + for ( k = 0 ; k < c2 ; k++ ) { + if ( edgeDefs[ i2 ][ k ].i2 == i ) { + hit[ edgeDefs[ i2 ][ k ].facing ]++; + } + } + + // if it doesn't share the edge with another front facing + // triangle, it is a sil edge + if ( hit[ 1 ] == 0 ) { + qglBegin( GL_TRIANGLE_STRIP ); + qglVertex3fv( tess.xyz[ i ] ); + qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); + qglVertex3fv( tess.xyz[ i2 ] ); + qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); + qglEnd(); + c_edges++; + } else { + c_rejected++; + } + } + } +#endif +} + +/* +================= +RB_ShadowTessEnd + +triangleFromEdge[ v1 ][ v2 ] + + + set triangle from edge( v1, v2, tri ) + if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { + } +================= +*/ +void RB_ShadowTessEnd( void ) { + int i; + int numTris; + vec3_t lightDir; + + // we can only do this if we have enough space in the vertex buffers + if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { + return; + } + + if ( glConfig.stencilBits < 4 ) { + return; + } + + VectorCopy( backEnd.currentEntity->lightDir, lightDir ); + + // project vertexes away from light direction + for ( i = 0 ; i < tess.numVertexes ; i++ ) { + VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); + } + + // decide which triangles face the light + Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); + + numTris = tess.numIndexes / 3; + for ( i = 0 ; i < numTris ; i++ ) { + int i1, i2, i3; + vec3_t d1, d2, normal; + float *v1, *v2, *v3; + float d; + + i1 = tess.indexes[ i*3 + 0 ]; + i2 = tess.indexes[ i*3 + 1 ]; + i3 = tess.indexes[ i*3 + 2 ]; + + v1 = tess.xyz[ i1 ]; + v2 = tess.xyz[ i2 ]; + v3 = tess.xyz[ i3 ]; + + VectorSubtract( v2, v1, d1 ); + VectorSubtract( v3, v1, d2 ); + CrossProduct( d1, d2, normal ); + + d = DotProduct( normal, lightDir ); + if ( d > 0 ) { + facing[ i ] = 1; + } else { + facing[ i ] = 0; + } + + // create the edges + R_AddEdgeDef( i1, i2, facing[ i ] ); + R_AddEdgeDef( i2, i3, facing[ i ] ); + R_AddEdgeDef( i3, i1, facing[ i ] ); + } + + // draw the silhouette edges + + GL_Bind( tr.whiteImage ); + qglEnable( GL_CULL_FACE ); + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); + qglColor3f( 0.2f, 0.2f, 0.2f ); + + // don't write to the color buffer + qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); + + qglEnable( GL_STENCIL_TEST ); + qglStencilFunc( GL_ALWAYS, 1, 255 ); + + // mirrors have the culling order reversed + if ( backEnd.viewParms.isMirror ) { + qglCullFace( GL_FRONT ); + qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); + + R_RenderShadowEdges(); + + qglCullFace( GL_BACK ); + qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); + + R_RenderShadowEdges(); + } else { + qglCullFace( GL_BACK ); + qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); + + R_RenderShadowEdges(); + + qglCullFace( GL_FRONT ); + qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); + + R_RenderShadowEdges(); + } + + + // reenable writing to the color buffer + qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); +} + + +/* +================= +RB_ShadowFinish + +Darken everything that is is a shadow volume. +We have to delay this until everything has been shadowed, +because otherwise shadows from different body parts would +overlap and double darken. +================= +*/ +void RB_ShadowFinish( void ) { + if ( r_shadows->integer != 2 ) { + return; + } + if ( glConfig.stencilBits < 4 ) { + return; + } + qglEnable( GL_STENCIL_TEST ); + qglStencilFunc( GL_NOTEQUAL, 0, 255 ); + + qglDisable (GL_CLIP_PLANE0); + qglDisable (GL_CULL_FACE); + + GL_Bind( tr.whiteImage ); + + qglLoadIdentity (); + + qglColor3f( 0.6f, 0.6f, 0.6f ); + GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); + +// qglColor3f( 1, 0, 0 ); +// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); + + qglBegin( GL_QUADS ); + qglVertex3f( -100, 100, -10 ); + qglVertex3f( 100, 100, -10 ); + qglVertex3f( 100, -100, -10 ); + qglVertex3f( -100, -100, -10 ); + qglEnd (); + + qglColor4f(1,1,1,1); + qglDisable( GL_STENCIL_TEST ); +} + + +/* +================= +RB_ProjectionShadowDeform + +================= +*/ +void RB_ProjectionShadowDeform( void ) { + float *xyz; + int i; + float h; + vec3_t ground; + vec3_t light; + float groundDist; + float d; + vec3_t lightDir; + + xyz = ( float * ) tess.xyz; + + ground[0] = backEnd.or.axis[0][2]; + ground[1] = backEnd.or.axis[1][2]; + ground[2] = backEnd.or.axis[2][2]; + + groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; + + VectorCopy( backEnd.currentEntity->lightDir, lightDir ); + d = DotProduct( lightDir, ground ); + // don't let the shadows get too long or go negative + if ( d < 0.5 ) { + VectorMA( lightDir, (0.5 - d), ground, lightDir ); + d = DotProduct( lightDir, ground ); + } + d = 1.0 / d; + + light[0] = lightDir[0] * d; + light[1] = lightDir[1] * d; + light[2] = lightDir[2] * d; + + for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { + h = DotProduct( xyz, ground ) + groundDist; + + xyz[0] -= light[0] * h; + xyz[1] -= light[1] * h; + xyz[2] -= light[2] * h; + } +} diff --git a/code/renderer/tr_sky.c b/code/renderer/tr_sky.c index 0f8aa24..1f92378 100755 --- a/code/renderer/tr_sky.c +++ b/code/renderer/tr_sky.c @@ -1,845 +1,845 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_sky.c
-#include "tr_local.h"
-
-#define SKY_SUBDIVISIONS 8
-#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
-
-static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
-static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
-
-/*
-===================================================================================
-
-POLYGON TO BOX SIDE PROJECTION
-
-===================================================================================
-*/
-
-static vec3_t sky_clip[6] =
-{
- {1,1,0},
- {1,-1,0},
- {0,-1,1},
- {0,1,1},
- {1,0,1},
- {-1,0,1}
-};
-
-static float sky_mins[2][6], sky_maxs[2][6];
-static float sky_min, sky_max;
-
-/*
-================
-AddSkyPolygon
-================
-*/
-static void AddSkyPolygon (int nump, vec3_t vecs)
-{
- int i,j;
- vec3_t v, av;
- float s, t, dv;
- int axis;
- float *vp;
- // s = [0]/[2], t = [1]/[2]
- static 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}
- };
-
- // decide which face it maps to
- VectorCopy (vec3_origin, v);
- for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
- {
- VectorAdd (vp, v, v);
- }
- av[0] = fabs(v[0]);
- av[1] = fabs(v[1]);
- av[2] = fabs(v[2]);
- if (av[0] > 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<nump ; i++, vecs+=3)
- {
- j = vec_to_st[axis][2];
- if (j > 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 < sky_mins[0][axis])
- sky_mins[0][axis] = s;
- if (t < sky_mins[1][axis])
- sky_mins[1][axis] = t;
- if (s > sky_maxs[0][axis])
- sky_maxs[0][axis] = s;
- if (t > sky_maxs[1][axis])
- sky_maxs[1][axis] = t;
- }
-}
-
-#define ON_EPSILON 0.1f // point on plane side epsilon
-#define MAX_CLIP_VERTS 64
-/*
-================
-ClipSkyPolygon
-================
-*/
-static 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.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
- if (stage == 6)
- { // fully clipped, so draw it
- AddSkyPolygon (nump, vecs);
- return;
- }
-
- front = back = qfalse;
- norm = sky_clip[stage];
- for (i=0, v = vecs ; i<nump ; i++, v+=3)
- {
- d = DotProduct (v, norm);
- if (d > ON_EPSILON)
- {
- front = qtrue;
- sides[i] = SIDE_FRONT;
- }
- else if (d < -ON_EPSILON)
- {
- back = qtrue;
- 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 ; i<nump ; i++, v+=3)
- {
- switch (sides[i])
- {
- case SIDE_FRONT:
- VectorCopy (v, newv[0][newc[0]]);
- newc[0]++;
- break;
- case SIDE_BACK:
- VectorCopy (v, newv[1][newc[1]]);
- newc[1]++;
- break;
- case SIDE_ON:
- VectorCopy (v, newv[0][newc[0]]);
- newc[0]++;
- VectorCopy (v, newv[1][newc[1]]);
- newc[1]++;
- break;
- }
-
- if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- d = dists[i] / (dists[i] - dists[i+1]);
- for (j=0 ; j<3 ; j++)
- {
- e = v[j] + d*(v[j+3] - v[j]);
- newv[0][newc[0]][j] = e;
- newv[1][newc[1]][j] = e;
- }
- newc[0]++;
- newc[1]++;
- }
-
- // continue
- ClipSkyPolygon (newc[0], newv[0][0], stage+1);
- ClipSkyPolygon (newc[1], newv[1][0], stage+1);
-}
-
-/*
-==============
-ClearSkyBox
-==============
-*/
-static void ClearSkyBox (void) {
- int i;
-
- for (i=0 ; i<6 ; i++) {
- sky_mins[0][i] = sky_mins[1][i] = 9999;
- sky_maxs[0][i] = sky_maxs[1][i] = -9999;
- }
-}
-
-/*
-================
-RB_ClipSkyPolygons
-================
-*/
-void RB_ClipSkyPolygons( shaderCommands_t *input )
-{
- vec3_t p[5]; // need one extra point for clipping
- int i, j;
-
- ClearSkyBox();
-
- for ( i = 0; i < input->numIndexes; i += 3 )
- {
- for (j = 0 ; j < 3 ; j++)
- {
- VectorSubtract( input->xyz[input->indexes[i+j]],
- backEnd.viewParms.or.origin,
- p[j] );
- }
- ClipSkyPolygon( 3, p[0], 0 );
- }
-}
-
-/*
-===================================================================================
-
-CLOUD VERTEX GENERATION
-
-===================================================================================
-*/
-
-/*
-** MakeSkyVec
-**
-** Parms: s, t range from -1 to 1
-*/
-static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
-{
- // 1 = s, 2 = t, 3 = 2048
- static 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
- };
-
- vec3_t b;
- int j, k;
- float boxSize;
-
- boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
- b[0] = s*boxSize;
- b[1] = t*boxSize;
- b[2] = boxSize;
-
- for (j=0 ; j<3 ; j++)
- {
- k = st_to_vec[axis][j];
- if (k < 0)
- {
- outXYZ[j] = -b[-k - 1];
- }
- else
- {
- outXYZ[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;
-
-
- if ( outSt )
- {
- outSt[0] = s;
- outSt[1] = t;
- }
-}
-
-static int sky_texorder[6] = {0,2,1,3,4,5};
-static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
-static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
-
-static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
-{
- int s, t;
-
- GL_Bind( image );
-
- for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- qglBegin( GL_TRIANGLE_STRIP );
-
- for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- qglTexCoord2fv( s_skyTexCoords[t][s] );
- qglVertex3fv( s_skyPoints[t][s] );
-
- qglTexCoord2fv( s_skyTexCoords[t+1][s] );
- qglVertex3fv( s_skyPoints[t+1][s] );
- }
-
- qglEnd();
- }
-}
-
-static void DrawSkyBox( shader_t *shader )
-{
- int i;
-
- sky_min = 0;
- sky_max = 1;
-
- Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
-
- for (i=0 ; i<6 ; i++)
- {
- int sky_mins_subd[2], sky_maxs_subd[2];
- int s, t;
-
- sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
-
- if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
- ( sky_mins[1][i] >= sky_maxs[1][i] ) )
- {
- continue;
- }
-
- sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
- sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
- sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
- sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
-
- if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- //
- // iterate through the subdivisions
- //
- for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- s_skyTexCoords[t][s],
- s_skyPoints[t][s] );
- }
- }
-
- DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
- sky_mins_subd,
- sky_maxs_subd );
- }
-
-}
-
-static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
-{
- int s, t;
- int vertexStart = tess.numVertexes;
- int tHeight, sWidth;
-
- tHeight = maxs[1] - mins[1] + 1;
- sWidth = maxs[0] - mins[0] + 1;
-
- for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
- tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
-
- tess.numVertexes++;
-
- if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
- {
- ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" );
- }
- }
- }
-
- // only add indexes for one pass, otherwise it would draw multiple times for each pass
- if ( addIndexes ) {
- for ( t = 0; t < tHeight-1; t++ )
- {
- for ( s = 0; s < sWidth-1; s++ )
- {
- tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
- tess.numIndexes++;
-
- tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
- tess.numIndexes++;
- }
- }
- }
-}
-
-static void FillCloudBox( const shader_t *shader, int stage )
-{
- int i;
-
- for ( i =0; i < 6; i++ )
- {
- int sky_mins_subd[2], sky_maxs_subd[2];
- int s, t;
- float MIN_T;
-
- if ( 1 ) // FIXME? shader->sky.fullClouds )
- {
- MIN_T = -HALF_SKY_SUBDIVISIONS;
-
- // still don't want to draw the bottom, even if fullClouds
- if ( i == 5 )
- continue;
- }
- else
- {
- switch( i )
- {
- case 0:
- case 1:
- case 2:
- case 3:
- MIN_T = -1;
- break;
- case 5:
- // don't draw clouds beneath you
- continue;
- case 4: // top
- default:
- MIN_T = -HALF_SKY_SUBDIVISIONS;
- break;
- }
- }
-
- sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
-
- if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
- ( sky_mins[1][i] >= sky_maxs[1][i] ) )
- {
- continue;
- }
-
- sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
- sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
- sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
- sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
-
- if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_mins_subd[1] < MIN_T )
- sky_mins_subd[1] = MIN_T;
- else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_maxs_subd[1] < MIN_T )
- sky_maxs_subd[1] = MIN_T;
- else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- //
- // iterate through the subdivisions
- //
- for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- NULL,
- s_skyPoints[t][s] );
-
- s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
- s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
- }
- }
-
- // only add indexes for first stage
- FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
- }
-}
-
-/*
-** R_BuildCloudData
-*/
-void R_BuildCloudData( shaderCommands_t *input )
-{
- int i;
- shader_t *shader;
-
- shader = input->shader;
-
- assert( shader->isSky );
-
- sky_min = 1.0 / 256.0f; // FIXME: not correct?
- sky_max = 255.0 / 256.0f;
-
- // set up for drawing
- tess.numIndexes = 0;
- tess.numVertexes = 0;
-
- if ( input->shader->sky.cloudHeight )
- {
- for ( i = 0; i < MAX_SHADER_STAGES; i++ )
- {
- if ( !tess.xstages[i] ) {
- break;
- }
- FillCloudBox( input->shader, i );
- }
- }
-}
-
-/*
-** R_InitSkyTexCoords
-** Called when a sky shader is parsed
-*/
-#define SQR( a ) ((a)*(a))
-void R_InitSkyTexCoords( float heightCloud )
-{
- int i, s, t;
- float radiusWorld = 4096;
- float p;
- float sRad, tRad;
- vec3_t skyVec;
- vec3_t v;
-
- // init zfar so MakeSkyVec works even though
- // a world hasn't been bounded
- backEnd.viewParms.zFar = 1024;
-
- for ( i = 0; i < 6; i++ )
- {
- for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
- {
- for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
- {
- // compute vector from view origin to sky side integral point
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- NULL,
- skyVec );
-
- // compute parametric value 'p' that intersects with cloud layer
- p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
- ( -2 * skyVec[2] * radiusWorld +
- 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
- 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
- SQR( skyVec[0] ) * SQR( heightCloud ) +
- 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
- SQR( skyVec[1] ) * SQR( heightCloud ) +
- 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
- SQR( skyVec[2] ) * SQR( heightCloud ) ) );
-
- s_cloudTexP[i][t][s] = p;
-
- // compute intersection point based on p
- VectorScale( skyVec, p, v );
- v[2] += radiusWorld;
-
- // compute vector from world origin to intersection point 'v'
- VectorNormalize( v );
-
- sRad = Q_acos( v[0] );
- tRad = Q_acos( v[1] );
-
- s_cloudTexCoords[i][t][s][0] = sRad;
- s_cloudTexCoords[i][t][s][1] = tRad;
- }
- }
- }
-}
-
-//======================================================================================
-
-/*
-** RB_DrawSun
-*/
-void RB_DrawSun( void ) {
- float size;
- float dist;
- vec3_t origin, vec1, vec2;
- vec3_t temp;
-
- if ( !backEnd.skyRenderedThisView ) {
- return;
- }
- if ( !r_drawSun->integer ) {
- return;
- }
- qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
- qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
-
- dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
- size = dist * 0.4;
-
- VectorScale( tr.sunDirection, dist, origin );
- PerpendicularVector( vec1, tr.sunDirection );
- CrossProduct( tr.sunDirection, vec1, vec2 );
-
- VectorScale( vec1, size, vec1 );
- VectorScale( vec2, size, vec2 );
-
- // farthest depth range
- qglDepthRange( 1.0, 1.0 );
-
- // FIXME: use quad stamp
- RB_BeginSurface( tr.sunShader, tess.fogNum );
- VectorCopy( origin, temp );
- VectorSubtract( temp, vec1, temp );
- VectorSubtract( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorAdd( temp, vec1, temp );
- VectorSubtract( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorAdd( temp, vec1, temp );
- VectorAdd( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorSubtract( temp, vec1, temp );
- VectorAdd( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 1;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 3;
-
- RB_EndSurface();
-
- // back to normal depth range
- qglDepthRange( 0.0, 1.0 );
-}
-
-
-
-
-/*
-================
-RB_StageIteratorSky
-
-All of the visible sky triangles are in tess
-
-Other things could be stuck in here, like birds in the sky, etc
-================
-*/
-void RB_StageIteratorSky( void ) {
- if ( r_fastsky->integer ) {
- return;
- }
-
- // go through all the polygons and project them onto
- // the sky box to see which blocks on each side need
- // to be drawn
- RB_ClipSkyPolygons( &tess );
-
- // r_showsky will let all the sky blocks be drawn in
- // front of everything to allow developers to see how
- // much sky is getting sucked in
- if ( r_showsky->integer ) {
- qglDepthRange( 0.0, 0.0 );
- } else {
- qglDepthRange( 1.0, 1.0 );
- }
-
- // draw the outer skybox
- if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
- qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
-
- qglPushMatrix ();
- GL_State( 0 );
- qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
-
- DrawSkyBox( tess.shader );
-
- qglPopMatrix();
- }
-
- // generate the vertexes for all the clouds, which will be drawn
- // by the generic shader routine
- R_BuildCloudData( &tess );
-
- RB_StageIteratorGeneric();
-
- // draw the inner skybox
-
-
- // back to normal depth range
- qglDepthRange( 0.0, 1.0 );
-
- // note that sky was drawn so we will draw a sun later
- backEnd.skyRenderedThisView = qtrue;
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_sky.c +#include "tr_local.h" + +#define SKY_SUBDIVISIONS 8 +#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) + +static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; +static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; + +/* +=================================================================================== + +POLYGON TO BOX SIDE PROJECTION + +=================================================================================== +*/ + +static vec3_t sky_clip[6] = +{ + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; + +static float sky_mins[2][6], sky_maxs[2][6]; +static float sky_min, sky_max; + +/* +================ +AddSkyPolygon +================ +*/ +static void AddSkyPolygon (int nump, vec3_t vecs) +{ + int i,j; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + // s = [0]/[2], t = [1]/[2] + static 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} + }; + + // decide which face it maps to + VectorCopy (vec3_origin, v); + for (i=0, vp=vecs ; i<nump ; i++, vp+=3) + { + VectorAdd (vp, v, v); + } + av[0] = fabs(v[0]); + av[1] = fabs(v[1]); + av[2] = fabs(v[2]); + if (av[0] > 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<nump ; i++, vecs+=3) + { + j = vec_to_st[axis][2]; + if (j > 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 < sky_mins[0][axis]) + sky_mins[0][axis] = s; + if (t < sky_mins[1][axis]) + sky_mins[1][axis] = t; + if (s > sky_maxs[0][axis]) + sky_maxs[0][axis] = s; + if (t > sky_maxs[1][axis]) + sky_maxs[1][axis] = t; + } +} + +#define ON_EPSILON 0.1f // point on plane side epsilon +#define MAX_CLIP_VERTS 64 +/* +================ +ClipSkyPolygon +================ +*/ +static 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.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) + { // fully clipped, so draw it + AddSkyPolygon (nump, vecs); + return; + } + + front = back = qfalse; + norm = sky_clip[stage]; + for (i=0, v = vecs ; i<nump ; i++, v+=3) + { + d = DotProduct (v, norm); + if (d > ON_EPSILON) + { + front = qtrue; + sides[i] = SIDE_FRONT; + } + else if (d < -ON_EPSILON) + { + back = qtrue; + 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 ; i<nump ; i++, v+=3) + { + switch (sides[i]) + { + case SIDE_FRONT: + VectorCopy (v, newv[0][newc[0]]); + newc[0]++; + break; + case SIDE_BACK: + VectorCopy (v, newv[1][newc[1]]); + newc[1]++; + break; + case SIDE_ON: + VectorCopy (v, newv[0][newc[0]]); + newc[0]++; + VectorCopy (v, newv[1][newc[1]]); + newc[1]++; + break; + } + + if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + d = dists[i] / (dists[i] - dists[i+1]); + for (j=0 ; j<3 ; j++) + { + e = v[j] + d*(v[j+3] - v[j]); + newv[0][newc[0]][j] = e; + newv[1][newc[1]][j] = e; + } + newc[0]++; + newc[1]++; + } + + // continue + ClipSkyPolygon (newc[0], newv[0][0], stage+1); + ClipSkyPolygon (newc[1], newv[1][0], stage+1); +} + +/* +============== +ClearSkyBox +============== +*/ +static void ClearSkyBox (void) { + int i; + + for (i=0 ; i<6 ; i++) { + sky_mins[0][i] = sky_mins[1][i] = 9999; + sky_maxs[0][i] = sky_maxs[1][i] = -9999; + } +} + +/* +================ +RB_ClipSkyPolygons +================ +*/ +void RB_ClipSkyPolygons( shaderCommands_t *input ) +{ + vec3_t p[5]; // need one extra point for clipping + int i, j; + + ClearSkyBox(); + + for ( i = 0; i < input->numIndexes; i += 3 ) + { + for (j = 0 ; j < 3 ; j++) + { + VectorSubtract( input->xyz[input->indexes[i+j]], + backEnd.viewParms.or.origin, + p[j] ); + } + ClipSkyPolygon( 3, p[0], 0 ); + } +} + +/* +=================================================================================== + +CLOUD VERTEX GENERATION + +=================================================================================== +*/ + +/* +** MakeSkyVec +** +** Parms: s, t range from -1 to 1 +*/ +static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) +{ + // 1 = s, 2 = t, 3 = 2048 + static 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 + }; + + vec3_t b; + int j, k; + float boxSize; + + boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) + b[0] = s*boxSize; + b[1] = t*boxSize; + b[2] = boxSize; + + for (j=0 ; j<3 ; j++) + { + k = st_to_vec[axis][j]; + if (k < 0) + { + outXYZ[j] = -b[-k - 1]; + } + else + { + outXYZ[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; + + + if ( outSt ) + { + outSt[0] = s; + outSt[1] = t; + } +} + +static int sky_texorder[6] = {0,2,1,3,4,5}; +static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; +static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; + +static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) +{ + int s, t; + + GL_Bind( image ); + + for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + qglBegin( GL_TRIANGLE_STRIP ); + + for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + qglTexCoord2fv( s_skyTexCoords[t][s] ); + qglVertex3fv( s_skyPoints[t][s] ); + + qglTexCoord2fv( s_skyTexCoords[t+1][s] ); + qglVertex3fv( s_skyPoints[t+1][s] ); + } + + qglEnd(); + } +} + +static void DrawSkyBox( shader_t *shader ) +{ + int i; + + sky_min = 0; + sky_max = 1; + + Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); + + for (i=0 ; i<6 ; i++) + { + int sky_mins_subd[2], sky_maxs_subd[2]; + int s, t; + + sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + + if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || + ( sky_mins[1][i] >= sky_maxs[1][i] ) ) + { + continue; + } + + sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; + sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; + sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; + sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; + + if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; + + if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; + + // + // iterate through the subdivisions + // + for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + i, + s_skyTexCoords[t][s], + s_skyPoints[t][s] ); + } + } + + DrawSkySide( shader->sky.outerbox[sky_texorder[i]], + sky_mins_subd, + sky_maxs_subd ); + } + +} + +static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) +{ + int s, t; + int vertexStart = tess.numVertexes; + int tHeight, sWidth; + + tHeight = maxs[1] - mins[1] + 1; + sWidth = maxs[0] - mins[0] + 1; + + for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; + tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; + + tess.numVertexes++; + + if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) + { + ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" ); + } + } + } + + // only add indexes for one pass, otherwise it would draw multiple times for each pass + if ( addIndexes ) { + for ( t = 0; t < tHeight-1; t++ ) + { + for ( s = 0; s < sWidth-1; s++ ) + { + tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); + tess.numIndexes++; + + tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); + tess.numIndexes++; + } + } + } +} + +static void FillCloudBox( const shader_t *shader, int stage ) +{ + int i; + + for ( i =0; i < 6; i++ ) + { + int sky_mins_subd[2], sky_maxs_subd[2]; + int s, t; + float MIN_T; + + if ( 1 ) // FIXME? shader->sky.fullClouds ) + { + MIN_T = -HALF_SKY_SUBDIVISIONS; + + // still don't want to draw the bottom, even if fullClouds + if ( i == 5 ) + continue; + } + else + { + switch( i ) + { + case 0: + case 1: + case 2: + case 3: + MIN_T = -1; + break; + case 5: + // don't draw clouds beneath you + continue; + case 4: // top + default: + MIN_T = -HALF_SKY_SUBDIVISIONS; + break; + } + } + + sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + + if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || + ( sky_mins[1][i] >= sky_maxs[1][i] ) ) + { + continue; + } + + sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ); + sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ); + sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ); + sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ); + + if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_mins_subd[1] < MIN_T ) + sky_mins_subd[1] = MIN_T; + else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; + + if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_maxs_subd[1] < MIN_T ) + sky_maxs_subd[1] = MIN_T; + else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; + + // + // iterate through the subdivisions + // + for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + i, + NULL, + s_skyPoints[t][s] ); + + s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; + s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; + } + } + + // only add indexes for first stage + FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); + } +} + +/* +** R_BuildCloudData +*/ +void R_BuildCloudData( shaderCommands_t *input ) +{ + int i; + shader_t *shader; + + shader = input->shader; + + assert( shader->isSky ); + + sky_min = 1.0 / 256.0f; // FIXME: not correct? + sky_max = 255.0 / 256.0f; + + // set up for drawing + tess.numIndexes = 0; + tess.numVertexes = 0; + + if ( input->shader->sky.cloudHeight ) + { + for ( i = 0; i < MAX_SHADER_STAGES; i++ ) + { + if ( !tess.xstages[i] ) { + break; + } + FillCloudBox( input->shader, i ); + } + } +} + +/* +** R_InitSkyTexCoords +** Called when a sky shader is parsed +*/ +#define SQR( a ) ((a)*(a)) +void R_InitSkyTexCoords( float heightCloud ) +{ + int i, s, t; + float radiusWorld = 4096; + float p; + float sRad, tRad; + vec3_t skyVec; + vec3_t v; + + // init zfar so MakeSkyVec works even though + // a world hasn't been bounded + backEnd.viewParms.zFar = 1024; + + for ( i = 0; i < 6; i++ ) + { + for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) + { + for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) + { + // compute vector from view origin to sky side integral point + MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + i, + NULL, + skyVec ); + + // compute parametric value 'p' that intersects with cloud layer + p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) * + ( -2 * skyVec[2] * radiusWorld + + 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + + 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud + + SQR( skyVec[0] ) * SQR( heightCloud ) + + 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud + + SQR( skyVec[1] ) * SQR( heightCloud ) + + 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud + + SQR( skyVec[2] ) * SQR( heightCloud ) ) ); + + s_cloudTexP[i][t][s] = p; + + // compute intersection point based on p + VectorScale( skyVec, p, v ); + v[2] += radiusWorld; + + // compute vector from world origin to intersection point 'v' + VectorNormalize( v ); + + sRad = Q_acos( v[0] ); + tRad = Q_acos( v[1] ); + + s_cloudTexCoords[i][t][s][0] = sRad; + s_cloudTexCoords[i][t][s][1] = tRad; + } + } + } +} + +//====================================================================================== + +/* +** RB_DrawSun +*/ +void RB_DrawSun( void ) { + float size; + float dist; + vec3_t origin, vec1, vec2; + vec3_t temp; + + if ( !backEnd.skyRenderedThisView ) { + return; + } + if ( !r_drawSun->integer ) { + return; + } + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); + qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + + dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) + size = dist * 0.4; + + VectorScale( tr.sunDirection, dist, origin ); + PerpendicularVector( vec1, tr.sunDirection ); + CrossProduct( tr.sunDirection, vec1, vec2 ); + + VectorScale( vec1, size, vec1 ); + VectorScale( vec2, size, vec2 ); + + // farthest depth range + qglDepthRange( 1.0, 1.0 ); + + // FIXME: use quad stamp + RB_BeginSurface( tr.sunShader, tess.fogNum ); + VectorCopy( origin, temp ); + VectorSubtract( temp, vec1, temp ); + VectorSubtract( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + VectorCopy( origin, temp ); + VectorAdd( temp, vec1, temp ); + VectorSubtract( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + VectorCopy( origin, temp ); + VectorAdd( temp, vec1, temp ); + VectorAdd( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + VectorCopy( origin, temp ); + VectorSubtract( temp, vec1, temp ); + VectorAdd( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + RB_EndSurface(); + + // back to normal depth range + qglDepthRange( 0.0, 1.0 ); +} + + + + +/* +================ +RB_StageIteratorSky + +All of the visible sky triangles are in tess + +Other things could be stuck in here, like birds in the sky, etc +================ +*/ +void RB_StageIteratorSky( void ) { + if ( r_fastsky->integer ) { + return; + } + + // go through all the polygons and project them onto + // the sky box to see which blocks on each side need + // to be drawn + RB_ClipSkyPolygons( &tess ); + + // r_showsky will let all the sky blocks be drawn in + // front of everything to allow developers to see how + // much sky is getting sucked in + if ( r_showsky->integer ) { + qglDepthRange( 0.0, 0.0 ); + } else { + qglDepthRange( 1.0, 1.0 ); + } + + // draw the outer skybox + if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { + qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); + + qglPushMatrix (); + GL_State( 0 ); + qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + + DrawSkyBox( tess.shader ); + + qglPopMatrix(); + } + + // generate the vertexes for all the clouds, which will be drawn + // by the generic shader routine + R_BuildCloudData( &tess ); + + RB_StageIteratorGeneric(); + + // draw the inner skybox + + + // back to normal depth range + qglDepthRange( 0.0, 1.0 ); + + // note that sky was drawn so we will draw a sun later + backEnd.skyRenderedThisView = qtrue; +} + diff --git a/code/renderer/tr_surface.c b/code/renderer/tr_surface.c index 599896d..e3f0051 100755 --- a/code/renderer/tr_surface.c +++ b/code/renderer/tr_surface.c @@ -1,1215 +1,1215 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_surf.c
-#include "tr_local.h"
-
-/*
-
- THIS ENTIRE FILE IS BACK END
-
-backEnd.currentEntity will be valid.
-
-Tess_Begin has already been called for the surface's shader.
-
-The modelview matrix will be set.
-
-It is safe to actually issue drawing commands here if you don't want to
-use the shader system.
-*/
-
-
-//============================================================================
-
-
-/*
-==============
-RB_CheckOverflow
-==============
-*/
-void RB_CheckOverflow( int verts, int indexes ) {
- if (tess.numVertexes + verts < SHADER_MAX_VERTEXES
- && tess.numIndexes + indexes < SHADER_MAX_INDEXES) {
- return;
- }
-
- RB_EndSurface();
-
- if ( verts >= SHADER_MAX_VERTEXES ) {
- ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES );
- }
- if ( indexes >= SHADER_MAX_INDEXES ) {
- ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
- }
-
- RB_BeginSurface(tess.shader, tess.fogNum );
-}
-
-
-/*
-==============
-RB_AddQuadStampExt
-==============
-*/
-void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) {
- vec3_t normal;
- int ndx;
-
- RB_CHECKOVERFLOW( 4, 6 );
-
- ndx = tess.numVertexes;
-
- // triangle indexes for a simple quad
- tess.indexes[ tess.numIndexes ] = ndx;
- tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
- tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;
-
- tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
- tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
- tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;
-
- tess.xyz[ndx][0] = origin[0] + left[0] + up[0];
- tess.xyz[ndx][1] = origin[1] + left[1] + up[1];
- tess.xyz[ndx][2] = origin[2] + left[2] + up[2];
-
- tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];
- tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];
- tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];
-
- tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];
- tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];
- tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];
-
- tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];
- tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];
- tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];
-
-
- // constant normal all the way around
- VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal );
-
- tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0];
- tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1];
- tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2];
-
- // standard square texture coordinates
- tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1;
- tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1;
-
- tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2;
- tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1;
-
- tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2;
- tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2;
-
- tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1;
- tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2;
-
- // constant color all the way around
- // should this be identity and let the shader specify from entity?
- * ( unsigned int * ) &tess.vertexColors[ndx] =
- * ( unsigned int * ) &tess.vertexColors[ndx+1] =
- * ( unsigned int * ) &tess.vertexColors[ndx+2] =
- * ( unsigned int * ) &tess.vertexColors[ndx+3] =
- * ( unsigned int * )color;
-
-
- tess.numVertexes += 4;
- tess.numIndexes += 6;
-}
-
-/*
-==============
-RB_AddQuadStamp
-==============
-*/
-void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) {
- RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );
-}
-
-/*
-==============
-RB_SurfaceSprite
-==============
-*/
-static void RB_SurfaceSprite( void ) {
- vec3_t left, up;
- float radius;
-
- // calculate the xyz locations for the four corners
- radius = backEnd.currentEntity->e.radius;
- if ( backEnd.currentEntity->e.rotation == 0 ) {
- VectorScale( backEnd.viewParms.or.axis[1], radius, left );
- VectorScale( backEnd.viewParms.or.axis[2], radius, up );
- } else {
- float s, c;
- float ang;
-
- ang = M_PI * backEnd.currentEntity->e.rotation / 180;
- s = sin( ang );
- c = cos( ang );
-
- VectorScale( backEnd.viewParms.or.axis[1], c * radius, left );
- VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left );
-
- VectorScale( backEnd.viewParms.or.axis[2], c * radius, up );
- VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up );
- }
- if ( backEnd.viewParms.isMirror ) {
- VectorSubtract( vec3_origin, left, left );
- }
-
- RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
-}
-
-
-/*
-=============
-RB_SurfacePolychain
-=============
-*/
-void RB_SurfacePolychain( srfPoly_t *p ) {
- int i;
- int numv;
-
- RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
-
- // fan triangles into the tess array
- numv = tess.numVertexes;
- for ( i = 0; i < p->numVerts; i++ ) {
- VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
- tess.texCoords[numv][0][0] = p->verts[i].st[0];
- tess.texCoords[numv][0][1] = p->verts[i].st[1];
- *(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;
-
- numv++;
- }
-
- // generate fan indexes into the tess array
- for ( i = 0; i < p->numVerts-2; i++ ) {
- tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
- tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
- tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
- tess.numIndexes += 3;
- }
-
- tess.numVertexes = numv;
-}
-
-
-/*
-=============
-RB_SurfaceTriangles
-=============
-*/
-void RB_SurfaceTriangles( srfTriangles_t *srf ) {
- int i;
- drawVert_t *dv;
- float *xyz, *normal, *texCoords;
- byte *color;
- int dlightBits;
- qboolean needsNormal;
-
- dlightBits = srf->dlightBits[backEnd.smpFrame];
- tess.dlightBits |= dlightBits;
-
- RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes );
-
- for ( i = 0 ; i < srf->numIndexes ; i += 3 ) {
- tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ];
- tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ];
- tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ];
- }
- tess.numIndexes += srf->numIndexes;
-
- dv = srf->verts;
- xyz = tess.xyz[ tess.numVertexes ];
- normal = tess.normal[ tess.numVertexes ];
- texCoords = tess.texCoords[ tess.numVertexes ][0];
- color = tess.vertexColors[ tess.numVertexes ];
- needsNormal = tess.shader->needsNormal;
-
- for ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) {
- xyz[0] = dv->xyz[0];
- xyz[1] = dv->xyz[1];
- xyz[2] = dv->xyz[2];
-
- if ( needsNormal ) {
- normal[0] = dv->normal[0];
- normal[1] = dv->normal[1];
- normal[2] = dv->normal[2];
- }
-
- texCoords[0] = dv->st[0];
- texCoords[1] = dv->st[1];
-
- texCoords[2] = dv->lightmap[0];
- texCoords[3] = dv->lightmap[1];
-
- *(int *)color = *(int *)dv->color;
- }
-
- for ( i = 0 ; i < srf->numVerts ; i++ ) {
- tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits;
- }
-
- tess.numVertexes += srf->numVerts;
-}
-
-
-
-/*
-==============
-RB_SurfaceBeam
-==============
-*/
-void RB_SurfaceBeam( void )
-{
-#define NUM_BEAM_SEGS 6
- refEntity_t *e;
- 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;
-
- e = &backEnd.currentEntity->e;
-
- 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, 4, 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] );
- }
-
- GL_Bind( tr.whiteImage );
-
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
-
- qglColor3f( 1, 0, 0 );
-
- qglBegin( GL_TRIANGLE_STRIP );
- for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {
- qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] );
- qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] );
- }
- qglEnd();
-}
-
-//================================================================================
-
-static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth )
-{
- float spanWidth2;
- int vbase;
- float t = len / 256.0f;
-
- vbase = tess.numVertexes;
-
- spanWidth2 = -spanWidth;
-
- // FIXME: use quad stamp?
- VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25;
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25;
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25;
- tess.numVertexes++;
-
- VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] );
-
- tess.texCoords[tess.numVertexes][0][0] = t;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = t;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = vbase;
- tess.indexes[tess.numIndexes++] = vbase + 1;
- tess.indexes[tess.numIndexes++] = vbase + 2;
-
- tess.indexes[tess.numIndexes++] = vbase + 2;
- tess.indexes[tess.numIndexes++] = vbase + 1;
- tess.indexes[tess.numIndexes++] = vbase + 3;
-}
-
-static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up )
-{
- int i;
- vec3_t pos[4];
- vec3_t v;
- int spanWidth = r_railWidth->integer;
- float c, s;
- float scale;
-
- if ( numSegs > 1 )
- numSegs--;
- if ( !numSegs )
- return;
-
- scale = 0.25;
-
- for ( i = 0; i < 4; i++ )
- {
- c = cos( DEG2RAD( 45 + i * 90 ) );
- s = sin( DEG2RAD( 45 + i * 90 ) );
- v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth;
- v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth;
- v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth;
- VectorAdd( start, v, pos[i] );
-
- if ( numSegs > 1 )
- {
- // offset by 1 segment if we're doing a long distance shot
- VectorAdd( pos[i], dir, pos[i] );
- }
- }
-
- for ( i = 0; i < numSegs; i++ )
- {
- int j;
-
- RB_CHECKOVERFLOW( 4, 6 );
-
- for ( j = 0; j < 4; j++ )
- {
- VectorCopy( pos[j], tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = ( j < 2 );
- tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 );
- tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0];
- tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1];
- tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2];
- tess.numVertexes++;
-
- VectorAdd( pos[j], dir, pos[j] );
- }
-
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1;
- tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2;
- }
-}
-
-/*
-** RB_SurfaceRailRinges
-*/
-void RB_SurfaceRailRings( void ) {
- refEntity_t *e;
- int numSegs;
- int len;
- vec3_t vec;
- vec3_t right, up;
- vec3_t start, end;
-
- e = &backEnd.currentEntity->e;
-
- VectorCopy( e->oldorigin, start );
- VectorCopy( e->origin, end );
-
- // compute variables
- VectorSubtract( end, start, vec );
- len = VectorNormalize( vec );
- MakeNormalVectors( vec, right, up );
- numSegs = ( len ) / r_railSegmentLength->value;
- if ( numSegs <= 0 ) {
- numSegs = 1;
- }
-
- VectorScale( vec, r_railSegmentLength->value, vec );
-
- DoRailDiscs( numSegs, start, vec, right, up );
-}
-
-/*
-** RB_SurfaceRailCore
-*/
-void RB_SurfaceRailCore( void ) {
- refEntity_t *e;
- int len;
- vec3_t right;
- vec3_t vec;
- vec3_t start, end;
- vec3_t v1, v2;
-
- e = &backEnd.currentEntity->e;
-
- VectorCopy( e->oldorigin, start );
- VectorCopy( e->origin, end );
-
- VectorSubtract( end, start, vec );
- len = VectorNormalize( vec );
-
- // compute side vector
- VectorSubtract( start, backEnd.viewParms.or.origin, v1 );
- VectorNormalize( v1 );
- VectorSubtract( end, backEnd.viewParms.or.origin, v2 );
- VectorNormalize( v2 );
- CrossProduct( v1, v2, right );
- VectorNormalize( right );
-
- DoRailCore( start, end, right, len, r_railCoreWidth->integer );
-}
-
-/*
-** RB_SurfaceLightningBolt
-*/
-void RB_SurfaceLightningBolt( void ) {
- refEntity_t *e;
- int len;
- vec3_t right;
- vec3_t vec;
- vec3_t start, end;
- vec3_t v1, v2;
- int i;
-
- e = &backEnd.currentEntity->e;
-
- VectorCopy( e->oldorigin, end );
- VectorCopy( e->origin, start );
-
- // compute variables
- VectorSubtract( end, start, vec );
- len = VectorNormalize( vec );
-
- // compute side vector
- VectorSubtract( start, backEnd.viewParms.or.origin, v1 );
- VectorNormalize( v1 );
- VectorSubtract( end, backEnd.viewParms.or.origin, v2 );
- VectorNormalize( v2 );
- CrossProduct( v1, v2, right );
- VectorNormalize( right );
-
- for ( i = 0 ; i < 4 ; i++ ) {
- vec3_t temp;
-
- DoRailCore( start, end, right, len, 8 );
- RotatePointAroundVector( temp, vec, right, 45 );
- VectorCopy( temp, right );
- }
-}
-
-/*
-** VectorArrayNormalize
-*
-* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0)
-* This means that we don't have to worry about zero length or enormously long vectors.
-*/
-static void VectorArrayNormalize(vec4_t *normals, unsigned int count)
-{
-// assert(count);
-
-#if idppc
- {
- register float half = 0.5;
- register float one = 1.0;
- float *components = (float *)normals;
-
- // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction,
- // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson
- // refinement step to get a little more precision. This seems to yeild results
- // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5).
- // (That is, for the given input range of about 0.6 to 2.0).
- do {
- float x, y, z;
- float B, y0, y1;
-
- x = components[0];
- y = components[1];
- z = components[2];
- components += 4;
- B = x*x + y*y + z*z;
-
-#ifdef __GNUC__
- asm("frsqrte %0,%1" : "=f" (y0) : "f" (B));
-#else
- y0 = __frsqrte(B);
-#endif
- y1 = y0 + half*y0*(one - B*y0*y0);
-
- x = x * y1;
- y = y * y1;
- components[-4] = x;
- z = z * y1;
- components[-3] = y;
- components[-2] = z;
- } while(count--);
- }
-#else // No assembly version for this architecture, or C_ONLY defined
- // given the input, it's safe to call VectorNormalizeFast
- while (count--) {
- VectorNormalizeFast(normals[0]);
- normals++;
- }
-#endif
-
-}
-
-
-
-/*
-** LerpMeshVertexes
-*/
-static void LerpMeshVertexes (md3Surface_t *surf, float backlerp)
-{
- short *oldXyz, *newXyz, *oldNormals, *newNormals;
- float *outXyz, *outNormal;
- float oldXyzScale, newXyzScale;
- float oldNormalScale, newNormalScale;
- int vertNum;
- unsigned lat, lng;
- int numVerts;
-
- outXyz = tess.xyz[tess.numVertexes];
- outNormal = tess.normal[tess.numVertexes];
-
- newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
- + (backEnd.currentEntity->e.frame * surf->numVerts * 4);
- newNormals = newXyz + 3;
-
- newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
- newNormalScale = 1.0 - backlerp;
-
- numVerts = surf->numVerts;
-
- if ( backlerp == 0 ) {
-#if idppc_altivec
- vector signed short newNormalsVec0;
- vector signed short newNormalsVec1;
- vector signed int newNormalsIntVec;
- vector float newNormalsFloatVec;
- vector float newXyzScaleVec;
- vector unsigned char newNormalsLoadPermute;
- vector unsigned char newNormalsStorePermute;
- vector float zero;
-
- newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec);
- newXyzScaleVec = *(vector float *)&newXyzScale;
- newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute);
- newXyzScaleVec = vec_splat(newXyzScaleVec,0);
- newNormalsLoadPermute = vec_lvsl(0,newXyz);
- newNormalsStorePermute = vec_lvsr(0,outXyz);
- zero = (vector float)vec_splat_s8(0);
- //
- // just copy the vertexes
- //
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- newXyz += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
- newNormalsLoadPermute = vec_lvsl(0,newXyz);
- newNormalsStorePermute = vec_lvsr(0,outXyz);
- newNormalsVec0 = vec_ld(0,newXyz);
- newNormalsVec1 = vec_ld(16,newXyz);
- newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute);
- newNormalsIntVec = vec_unpackh(newNormalsVec0);
- newNormalsFloatVec = vec_ctf(newNormalsIntVec,0);
- newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero);
- newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute);
- //outXyz[0] = newXyz[0] * newXyzScale;
- //outXyz[1] = newXyz[1] * newXyzScale;
- //outXyz[2] = newXyz[2] * newXyzScale;
-
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= (FUNCTABLE_SIZE/256);
- lng *= (FUNCTABLE_SIZE/256);
-
- // decode X as cos( lat ) * sin( long )
- // decode Y as sin( lat ) * sin( long )
- // decode Z as cos( long )
-
- outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- vec_ste(newNormalsFloatVec,0,outXyz);
- vec_ste(newNormalsFloatVec,4,outXyz);
- vec_ste(newNormalsFloatVec,8,outXyz);
- }
-
-#else
- //
- // just copy the vertexes
- //
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- newXyz += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
-
- outXyz[0] = newXyz[0] * newXyzScale;
- outXyz[1] = newXyz[1] * newXyzScale;
- outXyz[2] = newXyz[2] * newXyzScale;
-
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= (FUNCTABLE_SIZE/256);
- lng *= (FUNCTABLE_SIZE/256);
-
- // decode X as cos( lat ) * sin( long )
- // decode Y as sin( lat ) * sin( long )
- // decode Z as cos( long )
-
- outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
- }
-#endif
- } else {
- //
- // interpolate and copy the vertex and normal
- //
- oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
- + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
- oldNormals = oldXyz + 3;
-
- oldXyzScale = MD3_XYZ_SCALE * backlerp;
- oldNormalScale = backlerp;
-
- for (vertNum=0 ; vertNum < numVerts ; vertNum++,
- oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
- outXyz += 4, outNormal += 4)
- {
- vec3_t uncompressedOldNormal, uncompressedNewNormal;
-
- // interpolate the xyz
- outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
- outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
- outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
-
- // FIXME: interpolate lat/long instead?
- lat = ( newNormals[0] >> 8 ) & 0xff;
- lng = ( newNormals[0] & 0xff );
- lat *= 4;
- lng *= 4;
- uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- lat = ( oldNormals[0] >> 8 ) & 0xff;
- lng = ( oldNormals[0] & 0xff );
- lat *= 4;
- lng *= 4;
-
- uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
- uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
- uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
-
- outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
- outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
- outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
-
-// VectorNormalize (outNormal);
- }
- VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
- }
-}
-
-/*
-=============
-RB_SurfaceMesh
-=============
-*/
-void RB_SurfaceMesh(md3Surface_t *surface) {
- int j;
- float backlerp;
- int *triangles;
- float *texCoords;
- int indexes;
- int Bob, Doug;
- int numVerts;
-
- if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
- backlerp = 0;
- } else {
- backlerp = backEnd.currentEntity->e.backlerp;
- }
-
- RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 );
-
- LerpMeshVertexes (surface, backlerp);
-
- triangles = (int *) ((byte *)surface + surface->ofsTriangles);
- indexes = surface->numTriangles * 3;
- Bob = tess.numIndexes;
- Doug = tess.numVertexes;
- for (j = 0 ; j < indexes ; j++) {
- tess.indexes[Bob + j] = Doug + triangles[j];
- }
- tess.numIndexes += indexes;
-
- texCoords = (float *) ((byte *)surface + surface->ofsSt);
-
- numVerts = surface->numVerts;
- for ( j = 0; j < numVerts; j++ ) {
- tess.texCoords[Doug + j][0][0] = texCoords[j*2+0];
- tess.texCoords[Doug + j][0][1] = texCoords[j*2+1];
- // FIXME: fill in lightmapST for completeness?
- }
-
- tess.numVertexes += surface->numVerts;
-
-}
-
-
-/*
-==============
-RB_SurfaceFace
-==============
-*/
-void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
- int i;
- unsigned *indices, *tessIndexes;
- float *v;
- float *normal;
- int ndx;
- int Bob;
- int numPoints;
- int dlightBits;
-
- RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices );
-
- dlightBits = surf->dlightBits[backEnd.smpFrame];
- tess.dlightBits |= dlightBits;
-
- indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices );
-
- Bob = tess.numVertexes;
- tessIndexes = tess.indexes + tess.numIndexes;
- for ( i = surf->numIndices-1 ; i >= 0 ; i-- ) {
- tessIndexes[i] = indices[i] + Bob;
- }
-
- tess.numIndexes += surf->numIndices;
-
- v = surf->points[0];
-
- ndx = tess.numVertexes;
-
- numPoints = surf->numPoints;
-
- if ( tess.shader->needsNormal ) {
- normal = surf->plane.normal;
- for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) {
- VectorCopy( normal, tess.normal[ndx] );
- }
- }
-
- for ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) {
- VectorCopy( v, tess.xyz[ndx]);
- tess.texCoords[ndx][0][0] = v[3];
- tess.texCoords[ndx][0][1] = v[4];
- tess.texCoords[ndx][1][0] = v[5];
- tess.texCoords[ndx][1][1] = v[6];
- * ( unsigned int * ) &tess.vertexColors[ndx] = * ( unsigned int * ) &v[7];
- tess.vertexDlightBits[ndx] = dlightBits;
- }
-
-
- tess.numVertexes += surf->numPoints;
-}
-
-
-static float LodErrorForVolume( vec3_t local, float radius ) {
- vec3_t world;
- float d;
-
- // never let it go negative
- if ( r_lodCurveError->value < 0 ) {
- return 0;
- }
-
- world[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] +
- local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0];
- world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] +
- local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1];
- world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] +
- local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2];
-
- VectorSubtract( world, backEnd.viewParms.or.origin, world );
- d = DotProduct( world, backEnd.viewParms.or.axis[0] );
-
- if ( d < 0 ) {
- d = -d;
- }
- d -= radius;
- if ( d < 1 ) {
- d = 1;
- }
-
- return r_lodCurveError->value / d;
-}
-
-/*
-=============
-RB_SurfaceGrid
-
-Just copy the grid of points and triangulate
-=============
-*/
-void RB_SurfaceGrid( srfGridMesh_t *cv ) {
- int i, j;
- float *xyz;
- float *texCoords;
- float *normal;
- unsigned char *color;
- drawVert_t *dv;
- int rows, irows, vrows;
- int used;
- int widthTable[MAX_GRID_SIZE];
- int heightTable[MAX_GRID_SIZE];
- float lodError;
- int lodWidth, lodHeight;
- int numVertexes;
- int dlightBits;
- int *vDlightBits;
- qboolean needsNormal;
-
- dlightBits = cv->dlightBits[backEnd.smpFrame];
- tess.dlightBits |= dlightBits;
-
- // determine the allowable discrepance
- lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius );
-
- // determine which rows and columns of the subdivision
- // we are actually going to use
- widthTable[0] = 0;
- lodWidth = 1;
- for ( i = 1 ; i < cv->width-1 ; i++ ) {
- if ( cv->widthLodError[i] <= lodError ) {
- widthTable[lodWidth] = i;
- lodWidth++;
- }
- }
- widthTable[lodWidth] = cv->width-1;
- lodWidth++;
-
- heightTable[0] = 0;
- lodHeight = 1;
- for ( i = 1 ; i < cv->height-1 ; i++ ) {
- if ( cv->heightLodError[i] <= lodError ) {
- heightTable[lodHeight] = i;
- lodHeight++;
- }
- }
- heightTable[lodHeight] = cv->height-1;
- lodHeight++;
-
-
- // very large grids may have more points or indexes than can be fit
- // in the tess structure, so we may have to issue it in multiple passes
-
- used = 0;
- rows = 0;
- while ( used < lodHeight - 1 ) {
- // see how many rows of both verts and indexes we can add without overflowing
- do {
- vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;
- irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );
-
- // if we don't have enough space for at least one strip, flush the buffer
- if ( vrows < 2 || irows < 1 ) {
- RB_EndSurface();
- RB_BeginSurface(tess.shader, tess.fogNum );
- } else {
- break;
- }
- } while ( 1 );
-
- rows = irows;
- if ( vrows < irows + 1 ) {
- rows = vrows - 1;
- }
- if ( used + rows > lodHeight ) {
- rows = lodHeight - used;
- }
-
- numVertexes = tess.numVertexes;
-
- xyz = tess.xyz[numVertexes];
- normal = tess.normal[numVertexes];
- texCoords = tess.texCoords[numVertexes][0];
- color = ( unsigned char * ) &tess.vertexColors[numVertexes];
- vDlightBits = &tess.vertexDlightBits[numVertexes];
- needsNormal = tess.shader->needsNormal;
-
- for ( i = 0 ; i < rows ; i++ ) {
- for ( j = 0 ; j < lodWidth ; j++ ) {
- dv = cv->verts + heightTable[ used + i ] * cv->width
- + widthTable[ j ];
-
- xyz[0] = dv->xyz[0];
- xyz[1] = dv->xyz[1];
- xyz[2] = dv->xyz[2];
- texCoords[0] = dv->st[0];
- texCoords[1] = dv->st[1];
- texCoords[2] = dv->lightmap[0];
- texCoords[3] = dv->lightmap[1];
- if ( needsNormal ) {
- normal[0] = dv->normal[0];
- normal[1] = dv->normal[1];
- normal[2] = dv->normal[2];
- }
- * ( unsigned int * ) color = * ( unsigned int * ) dv->color;
- *vDlightBits++ = dlightBits;
- xyz += 4;
- normal += 4;
- texCoords += 4;
- color += 4;
- }
- }
-
-
- // add the indexes
- {
- int numIndexes;
- int w, h;
-
- h = rows - 1;
- w = lodWidth - 1;
- numIndexes = tess.numIndexes;
- for (i = 0 ; i < h ; i++) {
- for (j = 0 ; j < w ; j++) {
- int v1, v2, v3, v4;
-
- // vertex order to be reckognized as tristrips
- v1 = numVertexes + i*lodWidth + j + 1;
- v2 = v1 - 1;
- v3 = v2 + lodWidth;
- v4 = v3 + 1;
-
- tess.indexes[numIndexes] = v2;
- tess.indexes[numIndexes+1] = v3;
- tess.indexes[numIndexes+2] = v1;
-
- tess.indexes[numIndexes+3] = v1;
- tess.indexes[numIndexes+4] = v3;
- tess.indexes[numIndexes+5] = v4;
- numIndexes += 6;
- }
- }
-
- tess.numIndexes = numIndexes;
- }
-
- tess.numVertexes += rows * lodWidth;
-
- used += rows - 1;
- }
-}
-
-
-/*
-===========================================================================
-
-NULL MODEL
-
-===========================================================================
-*/
-
-/*
-===================
-RB_SurfaceAxis
-
-Draws x/y/z lines from the origin for orientation debugging
-===================
-*/
-void RB_SurfaceAxis( void ) {
- GL_Bind( tr.whiteImage );
- qglLineWidth( 3 );
- qglBegin( GL_LINES );
- qglColor3f( 1,0,0 );
- qglVertex3f( 0,0,0 );
- qglVertex3f( 16,0,0 );
- qglColor3f( 0,1,0 );
- qglVertex3f( 0,0,0 );
- qglVertex3f( 0,16,0 );
- qglColor3f( 0,0,1 );
- qglVertex3f( 0,0,0 );
- qglVertex3f( 0,0,16 );
- qglEnd();
- qglLineWidth( 1 );
-}
-
-//===========================================================================
-
-/*
-====================
-RB_SurfaceEntity
-
-Entities that have a single procedurally generated surface
-====================
-*/
-void RB_SurfaceEntity( surfaceType_t *surfType ) {
- switch( backEnd.currentEntity->e.reType ) {
- case RT_SPRITE:
- RB_SurfaceSprite();
- break;
- case RT_BEAM:
- RB_SurfaceBeam();
- break;
- case RT_RAIL_CORE:
- RB_SurfaceRailCore();
- break;
- case RT_RAIL_RINGS:
- RB_SurfaceRailRings();
- break;
- case RT_LIGHTNING:
- RB_SurfaceLightningBolt();
- break;
- default:
- RB_SurfaceAxis();
- break;
- }
- return;
-}
-
-void RB_SurfaceBad( surfaceType_t *surfType ) {
- ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
-}
-
-#if 0
-
-void RB_SurfaceFlare( srfFlare_t *surf ) {
- vec3_t left, up;
- float radius;
- byte color[4];
- vec3_t dir;
- vec3_t origin;
- float d;
-
- // calculate the xyz locations for the four corners
- radius = 30;
- VectorScale( backEnd.viewParms.or.axis[1], radius, left );
- VectorScale( backEnd.viewParms.or.axis[2], radius, up );
- if ( backEnd.viewParms.isMirror ) {
- VectorSubtract( vec3_origin, left, left );
- }
-
- color[0] = color[1] = color[2] = color[3] = 255;
-
- VectorMA( surf->origin, 3, surf->normal, origin );
- VectorSubtract( origin, backEnd.viewParms.or.origin, dir );
- VectorNormalize( dir );
- VectorMA( origin, r_ignore->value, dir, origin );
-
- d = -DotProduct( dir, surf->normal );
- if ( d < 0 ) {
- return;
- }
-#if 0
- color[0] *= d;
- color[1] *= d;
- color[2] *= d;
-#endif
-
- RB_AddQuadStamp( origin, left, up, color );
-}
-
-#else
-
-void RB_SurfaceFlare( srfFlare_t *surf ) {
-#if 0
- vec3_t left, up;
- byte color[4];
-
- color[0] = surf->color[0] * 255;
- color[1] = surf->color[1] * 255;
- color[2] = surf->color[2] * 255;
- color[3] = 255;
-
- VectorClear( left );
- VectorClear( up );
-
- left[0] = r_ignore->value;
-
- up[1] = r_ignore->value;
-
- RB_AddQuadStampExt( surf->origin, left, up, color, 0, 0, 1, 1 );
-#endif
-}
-
-#endif
-
-
-
-void RB_SurfaceDisplayList( srfDisplayList_t *surf ) {
- // all apropriate state must be set in RB_BeginSurface
- // this isn't implemented yet...
- qglCallList( surf->listNum );
-}
-
-void RB_SurfaceSkip( void *surf ) {
-}
-
-
-void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
- (void(*)(void*))RB_SurfaceBad, // SF_BAD,
- (void(*)(void*))RB_SurfaceSkip, // SF_SKIP,
- (void(*)(void*))RB_SurfaceFace, // SF_FACE,
- (void(*)(void*))RB_SurfaceGrid, // SF_GRID,
- (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES,
- (void(*)(void*))RB_SurfacePolychain, // SF_POLY,
- (void(*)(void*))RB_SurfaceMesh, // SF_MD3,
- (void(*)(void*))RB_SurfaceAnim, // SF_MD4,
- (void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
- (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
- (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST
-};
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_surf.c +#include "tr_local.h" + +/* + + THIS ENTIRE FILE IS BACK END + +backEnd.currentEntity will be valid. + +Tess_Begin has already been called for the surface's shader. + +The modelview matrix will be set. + +It is safe to actually issue drawing commands here if you don't want to +use the shader system. +*/ + + +//============================================================================ + + +/* +============== +RB_CheckOverflow +============== +*/ +void RB_CheckOverflow( int verts, int indexes ) { + if (tess.numVertexes + verts < SHADER_MAX_VERTEXES + && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { + return; + } + + RB_EndSurface(); + + if ( verts >= SHADER_MAX_VERTEXES ) { + ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES ); + } + if ( indexes >= SHADER_MAX_INDEXES ) { + ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES ); + } + + RB_BeginSurface(tess.shader, tess.fogNum ); +} + + +/* +============== +RB_AddQuadStampExt +============== +*/ +void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) { + vec3_t normal; + int ndx; + + RB_CHECKOVERFLOW( 4, 6 ); + + ndx = tess.numVertexes; + + // triangle indexes for a simple quad + tess.indexes[ tess.numIndexes ] = ndx; + tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; + tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; + + tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; + tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; + tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; + + tess.xyz[ndx][0] = origin[0] + left[0] + up[0]; + tess.xyz[ndx][1] = origin[1] + left[1] + up[1]; + tess.xyz[ndx][2] = origin[2] + left[2] + up[2]; + + tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0]; + tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1]; + tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2]; + + tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0]; + tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1]; + tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2]; + + tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0]; + tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1]; + tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2]; + + + // constant normal all the way around + VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); + + tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0]; + tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1]; + tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2]; + + // standard square texture coordinates + tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1; + tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1; + + tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2; + tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1; + + tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2; + tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2; + + tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1; + tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2; + + // constant color all the way around + // should this be identity and let the shader specify from entity? + * ( unsigned int * ) &tess.vertexColors[ndx] = + * ( unsigned int * ) &tess.vertexColors[ndx+1] = + * ( unsigned int * ) &tess.vertexColors[ndx+2] = + * ( unsigned int * ) &tess.vertexColors[ndx+3] = + * ( unsigned int * )color; + + + tess.numVertexes += 4; + tess.numIndexes += 6; +} + +/* +============== +RB_AddQuadStamp +============== +*/ +void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) { + RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 ); +} + +/* +============== +RB_SurfaceSprite +============== +*/ +static void RB_SurfaceSprite( void ) { + vec3_t left, up; + float radius; + + // calculate the xyz locations for the four corners + radius = backEnd.currentEntity->e.radius; + if ( backEnd.currentEntity->e.rotation == 0 ) { + VectorScale( backEnd.viewParms.or.axis[1], radius, left ); + VectorScale( backEnd.viewParms.or.axis[2], radius, up ); + } else { + float s, c; + float ang; + + ang = M_PI * backEnd.currentEntity->e.rotation / 180; + s = sin( ang ); + c = cos( ang ); + + VectorScale( backEnd.viewParms.or.axis[1], c * radius, left ); + VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); + + VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); + VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up ); + } + if ( backEnd.viewParms.isMirror ) { + VectorSubtract( vec3_origin, left, left ); + } + + RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA ); +} + + +/* +============= +RB_SurfacePolychain +============= +*/ +void RB_SurfacePolychain( srfPoly_t *p ) { + int i; + int numv; + + RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) ); + + // fan triangles into the tess array + numv = tess.numVertexes; + for ( i = 0; i < p->numVerts; i++ ) { + VectorCopy( p->verts[i].xyz, tess.xyz[numv] ); + tess.texCoords[numv][0][0] = p->verts[i].st[0]; + tess.texCoords[numv][0][1] = p->verts[i].st[1]; + *(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate; + + numv++; + } + + // generate fan indexes into the tess array + for ( i = 0; i < p->numVerts-2; i++ ) { + tess.indexes[tess.numIndexes + 0] = tess.numVertexes; + tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1; + tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2; + tess.numIndexes += 3; + } + + tess.numVertexes = numv; +} + + +/* +============= +RB_SurfaceTriangles +============= +*/ +void RB_SurfaceTriangles( srfTriangles_t *srf ) { + int i; + drawVert_t *dv; + float *xyz, *normal, *texCoords; + byte *color; + int dlightBits; + qboolean needsNormal; + + dlightBits = srf->dlightBits[backEnd.smpFrame]; + tess.dlightBits |= dlightBits; + + RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes ); + + for ( i = 0 ; i < srf->numIndexes ; i += 3 ) { + tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ]; + tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ]; + tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ]; + } + tess.numIndexes += srf->numIndexes; + + dv = srf->verts; + xyz = tess.xyz[ tess.numVertexes ]; + normal = tess.normal[ tess.numVertexes ]; + texCoords = tess.texCoords[ tess.numVertexes ][0]; + color = tess.vertexColors[ tess.numVertexes ]; + needsNormal = tess.shader->needsNormal; + + for ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) { + xyz[0] = dv->xyz[0]; + xyz[1] = dv->xyz[1]; + xyz[2] = dv->xyz[2]; + + if ( needsNormal ) { + normal[0] = dv->normal[0]; + normal[1] = dv->normal[1]; + normal[2] = dv->normal[2]; + } + + texCoords[0] = dv->st[0]; + texCoords[1] = dv->st[1]; + + texCoords[2] = dv->lightmap[0]; + texCoords[3] = dv->lightmap[1]; + + *(int *)color = *(int *)dv->color; + } + + for ( i = 0 ; i < srf->numVerts ; i++ ) { + tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits; + } + + tess.numVertexes += srf->numVerts; +} + + + +/* +============== +RB_SurfaceBeam +============== +*/ +void RB_SurfaceBeam( void ) +{ +#define NUM_BEAM_SEGS 6 + refEntity_t *e; + 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; + + e = &backEnd.currentEntity->e; + + 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, 4, 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] ); + } + + GL_Bind( tr.whiteImage ); + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); + + qglColor3f( 1, 0, 0 ); + + qglBegin( GL_TRIANGLE_STRIP ); + for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) { + qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] ); + qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] ); + } + qglEnd(); +} + +//================================================================================ + +static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth ) +{ + float spanWidth2; + int vbase; + float t = len / 256.0f; + + vbase = tess.numVertexes; + + spanWidth2 = -spanWidth; + + // FIXME: use quad stamp? + VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25; + tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25; + tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25; + tess.numVertexes++; + + VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; + tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; + tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.numVertexes++; + + VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); + + tess.texCoords[tess.numVertexes][0][0] = t; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; + tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; + tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.numVertexes++; + + VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = t; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; + tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; + tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = vbase; + tess.indexes[tess.numIndexes++] = vbase + 1; + tess.indexes[tess.numIndexes++] = vbase + 2; + + tess.indexes[tess.numIndexes++] = vbase + 2; + tess.indexes[tess.numIndexes++] = vbase + 1; + tess.indexes[tess.numIndexes++] = vbase + 3; +} + +static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up ) +{ + int i; + vec3_t pos[4]; + vec3_t v; + int spanWidth = r_railWidth->integer; + float c, s; + float scale; + + if ( numSegs > 1 ) + numSegs--; + if ( !numSegs ) + return; + + scale = 0.25; + + for ( i = 0; i < 4; i++ ) + { + c = cos( DEG2RAD( 45 + i * 90 ) ); + s = sin( DEG2RAD( 45 + i * 90 ) ); + v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth; + v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth; + v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth; + VectorAdd( start, v, pos[i] ); + + if ( numSegs > 1 ) + { + // offset by 1 segment if we're doing a long distance shot + VectorAdd( pos[i], dir, pos[i] ); + } + } + + for ( i = 0; i < numSegs; i++ ) + { + int j; + + RB_CHECKOVERFLOW( 4, 6 ); + + for ( j = 0; j < 4; j++ ) + { + VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = ( j < 2 ); + tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 ); + tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; + tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; + tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; + tess.numVertexes++; + + VectorAdd( pos[j], dir, pos[j] ); + } + + tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0; + tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; + tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; + tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; + tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; + tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2; + } +} + +/* +** RB_SurfaceRailRinges +*/ +void RB_SurfaceRailRings( void ) { + refEntity_t *e; + int numSegs; + int len; + vec3_t vec; + vec3_t right, up; + vec3_t start, end; + + e = &backEnd.currentEntity->e; + + VectorCopy( e->oldorigin, start ); + VectorCopy( e->origin, end ); + + // compute variables + VectorSubtract( end, start, vec ); + len = VectorNormalize( vec ); + MakeNormalVectors( vec, right, up ); + numSegs = ( len ) / r_railSegmentLength->value; + if ( numSegs <= 0 ) { + numSegs = 1; + } + + VectorScale( vec, r_railSegmentLength->value, vec ); + + DoRailDiscs( numSegs, start, vec, right, up ); +} + +/* +** RB_SurfaceRailCore +*/ +void RB_SurfaceRailCore( void ) { + refEntity_t *e; + int len; + vec3_t right; + vec3_t vec; + vec3_t start, end; + vec3_t v1, v2; + + e = &backEnd.currentEntity->e; + + VectorCopy( e->oldorigin, start ); + VectorCopy( e->origin, end ); + + VectorSubtract( end, start, vec ); + len = VectorNormalize( vec ); + + // compute side vector + VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); + VectorNormalize( v1 ); + VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); + VectorNormalize( v2 ); + CrossProduct( v1, v2, right ); + VectorNormalize( right ); + + DoRailCore( start, end, right, len, r_railCoreWidth->integer ); +} + +/* +** RB_SurfaceLightningBolt +*/ +void RB_SurfaceLightningBolt( void ) { + refEntity_t *e; + int len; + vec3_t right; + vec3_t vec; + vec3_t start, end; + vec3_t v1, v2; + int i; + + e = &backEnd.currentEntity->e; + + VectorCopy( e->oldorigin, end ); + VectorCopy( e->origin, start ); + + // compute variables + VectorSubtract( end, start, vec ); + len = VectorNormalize( vec ); + + // compute side vector + VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); + VectorNormalize( v1 ); + VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); + VectorNormalize( v2 ); + CrossProduct( v1, v2, right ); + VectorNormalize( right ); + + for ( i = 0 ; i < 4 ; i++ ) { + vec3_t temp; + + DoRailCore( start, end, right, len, 8 ); + RotatePointAroundVector( temp, vec, right, 45 ); + VectorCopy( temp, right ); + } +} + +/* +** VectorArrayNormalize +* +* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) +* This means that we don't have to worry about zero length or enormously long vectors. +*/ +static void VectorArrayNormalize(vec4_t *normals, unsigned int count) +{ +// assert(count); + +#if idppc + { + register float half = 0.5; + register float one = 1.0; + float *components = (float *)normals; + + // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, + // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson + // refinement step to get a little more precision. This seems to yeild results + // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). + // (That is, for the given input range of about 0.6 to 2.0). + do { + float x, y, z; + float B, y0, y1; + + x = components[0]; + y = components[1]; + z = components[2]; + components += 4; + B = x*x + y*y + z*z; + +#ifdef __GNUC__ + asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); +#else + y0 = __frsqrte(B); +#endif + y1 = y0 + half*y0*(one - B*y0*y0); + + x = x * y1; + y = y * y1; + components[-4] = x; + z = z * y1; + components[-3] = y; + components[-2] = z; + } while(count--); + } +#else // No assembly version for this architecture, or C_ONLY defined + // given the input, it's safe to call VectorNormalizeFast + while (count--) { + VectorNormalizeFast(normals[0]); + normals++; + } +#endif + +} + + + +/* +** LerpMeshVertexes +*/ +static void LerpMeshVertexes (md3Surface_t *surf, float backlerp) +{ + short *oldXyz, *newXyz, *oldNormals, *newNormals; + float *outXyz, *outNormal; + float oldXyzScale, newXyzScale; + float oldNormalScale, newNormalScale; + int vertNum; + unsigned lat, lng; + int numVerts; + + outXyz = tess.xyz[tess.numVertexes]; + outNormal = tess.normal[tess.numVertexes]; + + newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) + + (backEnd.currentEntity->e.frame * surf->numVerts * 4); + newNormals = newXyz + 3; + + newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); + newNormalScale = 1.0 - backlerp; + + numVerts = surf->numVerts; + + if ( backlerp == 0 ) { +#if idppc_altivec + vector signed short newNormalsVec0; + vector signed short newNormalsVec1; + vector signed int newNormalsIntVec; + vector float newNormalsFloatVec; + vector float newXyzScaleVec; + vector unsigned char newNormalsLoadPermute; + vector unsigned char newNormalsStorePermute; + vector float zero; + + newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); + newXyzScaleVec = *(vector float *)&newXyzScale; + newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); + newXyzScaleVec = vec_splat(newXyzScaleVec,0); + newNormalsLoadPermute = vec_lvsl(0,newXyz); + newNormalsStorePermute = vec_lvsr(0,outXyz); + zero = (vector float)vec_splat_s8(0); + // + // just copy the vertexes + // + for (vertNum=0 ; vertNum < numVerts ; vertNum++, + newXyz += 4, newNormals += 4, + outXyz += 4, outNormal += 4) + { + newNormalsLoadPermute = vec_lvsl(0,newXyz); + newNormalsStorePermute = vec_lvsr(0,outXyz); + newNormalsVec0 = vec_ld(0,newXyz); + newNormalsVec1 = vec_ld(16,newXyz); + newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); + newNormalsIntVec = vec_unpackh(newNormalsVec0); + newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); + newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); + newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); + //outXyz[0] = newXyz[0] * newXyzScale; + //outXyz[1] = newXyz[1] * newXyzScale; + //outXyz[2] = newXyz[2] * newXyzScale; + + lat = ( newNormals[0] >> 8 ) & 0xff; + lng = ( newNormals[0] & 0xff ); + lat *= (FUNCTABLE_SIZE/256); + lng *= (FUNCTABLE_SIZE/256); + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + vec_ste(newNormalsFloatVec,0,outXyz); + vec_ste(newNormalsFloatVec,4,outXyz); + vec_ste(newNormalsFloatVec,8,outXyz); + } + +#else + // + // just copy the vertexes + // + for (vertNum=0 ; vertNum < numVerts ; vertNum++, + newXyz += 4, newNormals += 4, + outXyz += 4, outNormal += 4) + { + + outXyz[0] = newXyz[0] * newXyzScale; + outXyz[1] = newXyz[1] * newXyzScale; + outXyz[2] = newXyz[2] * newXyzScale; + + lat = ( newNormals[0] >> 8 ) & 0xff; + lng = ( newNormals[0] & 0xff ); + lat *= (FUNCTABLE_SIZE/256); + lng *= (FUNCTABLE_SIZE/256); + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + } +#endif + } else { + // + // interpolate and copy the vertex and normal + // + oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) + + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); + oldNormals = oldXyz + 3; + + oldXyzScale = MD3_XYZ_SCALE * backlerp; + oldNormalScale = backlerp; + + for (vertNum=0 ; vertNum < numVerts ; vertNum++, + oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, + outXyz += 4, outNormal += 4) + { + vec3_t uncompressedOldNormal, uncompressedNewNormal; + + // interpolate the xyz + outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; + outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; + outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; + + // FIXME: interpolate lat/long instead? + lat = ( newNormals[0] >> 8 ) & 0xff; + lng = ( newNormals[0] & 0xff ); + lat *= 4; + lng *= 4; + uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + lat = ( oldNormals[0] >> 8 ) & 0xff; + lng = ( oldNormals[0] & 0xff ); + lat *= 4; + lng *= 4; + + uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; + outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; + outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; + +// VectorNormalize (outNormal); + } + VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); + } +} + +/* +============= +RB_SurfaceMesh +============= +*/ +void RB_SurfaceMesh(md3Surface_t *surface) { + int j; + float backlerp; + int *triangles; + float *texCoords; + int indexes; + int Bob, Doug; + int numVerts; + + if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { + backlerp = 0; + } else { + backlerp = backEnd.currentEntity->e.backlerp; + } + + RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 ); + + LerpMeshVertexes (surface, backlerp); + + triangles = (int *) ((byte *)surface + surface->ofsTriangles); + indexes = surface->numTriangles * 3; + Bob = tess.numIndexes; + Doug = tess.numVertexes; + for (j = 0 ; j < indexes ; j++) { + tess.indexes[Bob + j] = Doug + triangles[j]; + } + tess.numIndexes += indexes; + + texCoords = (float *) ((byte *)surface + surface->ofsSt); + + numVerts = surface->numVerts; + for ( j = 0; j < numVerts; j++ ) { + tess.texCoords[Doug + j][0][0] = texCoords[j*2+0]; + tess.texCoords[Doug + j][0][1] = texCoords[j*2+1]; + // FIXME: fill in lightmapST for completeness? + } + + tess.numVertexes += surface->numVerts; + +} + + +/* +============== +RB_SurfaceFace +============== +*/ +void RB_SurfaceFace( srfSurfaceFace_t *surf ) { + int i; + unsigned *indices, *tessIndexes; + float *v; + float *normal; + int ndx; + int Bob; + int numPoints; + int dlightBits; + + RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices ); + + dlightBits = surf->dlightBits[backEnd.smpFrame]; + tess.dlightBits |= dlightBits; + + indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices ); + + Bob = tess.numVertexes; + tessIndexes = tess.indexes + tess.numIndexes; + for ( i = surf->numIndices-1 ; i >= 0 ; i-- ) { + tessIndexes[i] = indices[i] + Bob; + } + + tess.numIndexes += surf->numIndices; + + v = surf->points[0]; + + ndx = tess.numVertexes; + + numPoints = surf->numPoints; + + if ( tess.shader->needsNormal ) { + normal = surf->plane.normal; + for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) { + VectorCopy( normal, tess.normal[ndx] ); + } + } + + for ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) { + VectorCopy( v, tess.xyz[ndx]); + tess.texCoords[ndx][0][0] = v[3]; + tess.texCoords[ndx][0][1] = v[4]; + tess.texCoords[ndx][1][0] = v[5]; + tess.texCoords[ndx][1][1] = v[6]; + * ( unsigned int * ) &tess.vertexColors[ndx] = * ( unsigned int * ) &v[7]; + tess.vertexDlightBits[ndx] = dlightBits; + } + + + tess.numVertexes += surf->numPoints; +} + + +static float LodErrorForVolume( vec3_t local, float radius ) { + vec3_t world; + float d; + + // never let it go negative + if ( r_lodCurveError->value < 0 ) { + return 0; + } + + world[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + + local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0]; + world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + + local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1]; + world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + + local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2]; + + VectorSubtract( world, backEnd.viewParms.or.origin, world ); + d = DotProduct( world, backEnd.viewParms.or.axis[0] ); + + if ( d < 0 ) { + d = -d; + } + d -= radius; + if ( d < 1 ) { + d = 1; + } + + return r_lodCurveError->value / d; +} + +/* +============= +RB_SurfaceGrid + +Just copy the grid of points and triangulate +============= +*/ +void RB_SurfaceGrid( srfGridMesh_t *cv ) { + int i, j; + float *xyz; + float *texCoords; + float *normal; + unsigned char *color; + drawVert_t *dv; + int rows, irows, vrows; + int used; + int widthTable[MAX_GRID_SIZE]; + int heightTable[MAX_GRID_SIZE]; + float lodError; + int lodWidth, lodHeight; + int numVertexes; + int dlightBits; + int *vDlightBits; + qboolean needsNormal; + + dlightBits = cv->dlightBits[backEnd.smpFrame]; + tess.dlightBits |= dlightBits; + + // determine the allowable discrepance + lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius ); + + // determine which rows and columns of the subdivision + // we are actually going to use + widthTable[0] = 0; + lodWidth = 1; + for ( i = 1 ; i < cv->width-1 ; i++ ) { + if ( cv->widthLodError[i] <= lodError ) { + widthTable[lodWidth] = i; + lodWidth++; + } + } + widthTable[lodWidth] = cv->width-1; + lodWidth++; + + heightTable[0] = 0; + lodHeight = 1; + for ( i = 1 ; i < cv->height-1 ; i++ ) { + if ( cv->heightLodError[i] <= lodError ) { + heightTable[lodHeight] = i; + lodHeight++; + } + } + heightTable[lodHeight] = cv->height-1; + lodHeight++; + + + // very large grids may have more points or indexes than can be fit + // in the tess structure, so we may have to issue it in multiple passes + + used = 0; + rows = 0; + while ( used < lodHeight - 1 ) { + // see how many rows of both verts and indexes we can add without overflowing + do { + vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth; + irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 ); + + // if we don't have enough space for at least one strip, flush the buffer + if ( vrows < 2 || irows < 1 ) { + RB_EndSurface(); + RB_BeginSurface(tess.shader, tess.fogNum ); + } else { + break; + } + } while ( 1 ); + + rows = irows; + if ( vrows < irows + 1 ) { + rows = vrows - 1; + } + if ( used + rows > lodHeight ) { + rows = lodHeight - used; + } + + numVertexes = tess.numVertexes; + + xyz = tess.xyz[numVertexes]; + normal = tess.normal[numVertexes]; + texCoords = tess.texCoords[numVertexes][0]; + color = ( unsigned char * ) &tess.vertexColors[numVertexes]; + vDlightBits = &tess.vertexDlightBits[numVertexes]; + needsNormal = tess.shader->needsNormal; + + for ( i = 0 ; i < rows ; i++ ) { + for ( j = 0 ; j < lodWidth ; j++ ) { + dv = cv->verts + heightTable[ used + i ] * cv->width + + widthTable[ j ]; + + xyz[0] = dv->xyz[0]; + xyz[1] = dv->xyz[1]; + xyz[2] = dv->xyz[2]; + texCoords[0] = dv->st[0]; + texCoords[1] = dv->st[1]; + texCoords[2] = dv->lightmap[0]; + texCoords[3] = dv->lightmap[1]; + if ( needsNormal ) { + normal[0] = dv->normal[0]; + normal[1] = dv->normal[1]; + normal[2] = dv->normal[2]; + } + * ( unsigned int * ) color = * ( unsigned int * ) dv->color; + *vDlightBits++ = dlightBits; + xyz += 4; + normal += 4; + texCoords += 4; + color += 4; + } + } + + + // add the indexes + { + int numIndexes; + int w, h; + + h = rows - 1; + w = lodWidth - 1; + numIndexes = tess.numIndexes; + for (i = 0 ; i < h ; i++) { + for (j = 0 ; j < w ; j++) { + int v1, v2, v3, v4; + + // vertex order to be reckognized as tristrips + v1 = numVertexes + i*lodWidth + j + 1; + v2 = v1 - 1; + v3 = v2 + lodWidth; + v4 = v3 + 1; + + tess.indexes[numIndexes] = v2; + tess.indexes[numIndexes+1] = v3; + tess.indexes[numIndexes+2] = v1; + + tess.indexes[numIndexes+3] = v1; + tess.indexes[numIndexes+4] = v3; + tess.indexes[numIndexes+5] = v4; + numIndexes += 6; + } + } + + tess.numIndexes = numIndexes; + } + + tess.numVertexes += rows * lodWidth; + + used += rows - 1; + } +} + + +/* +=========================================================================== + +NULL MODEL + +=========================================================================== +*/ + +/* +=================== +RB_SurfaceAxis + +Draws x/y/z lines from the origin for orientation debugging +=================== +*/ +void RB_SurfaceAxis( void ) { + GL_Bind( tr.whiteImage ); + qglLineWidth( 3 ); + qglBegin( GL_LINES ); + qglColor3f( 1,0,0 ); + qglVertex3f( 0,0,0 ); + qglVertex3f( 16,0,0 ); + qglColor3f( 0,1,0 ); + qglVertex3f( 0,0,0 ); + qglVertex3f( 0,16,0 ); + qglColor3f( 0,0,1 ); + qglVertex3f( 0,0,0 ); + qglVertex3f( 0,0,16 ); + qglEnd(); + qglLineWidth( 1 ); +} + +//=========================================================================== + +/* +==================== +RB_SurfaceEntity + +Entities that have a single procedurally generated surface +==================== +*/ +void RB_SurfaceEntity( surfaceType_t *surfType ) { + switch( backEnd.currentEntity->e.reType ) { + case RT_SPRITE: + RB_SurfaceSprite(); + break; + case RT_BEAM: + RB_SurfaceBeam(); + break; + case RT_RAIL_CORE: + RB_SurfaceRailCore(); + break; + case RT_RAIL_RINGS: + RB_SurfaceRailRings(); + break; + case RT_LIGHTNING: + RB_SurfaceLightningBolt(); + break; + default: + RB_SurfaceAxis(); + break; + } + return; +} + +void RB_SurfaceBad( surfaceType_t *surfType ) { + ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" ); +} + +#if 0 + +void RB_SurfaceFlare( srfFlare_t *surf ) { + vec3_t left, up; + float radius; + byte color[4]; + vec3_t dir; + vec3_t origin; + float d; + + // calculate the xyz locations for the four corners + radius = 30; + VectorScale( backEnd.viewParms.or.axis[1], radius, left ); + VectorScale( backEnd.viewParms.or.axis[2], radius, up ); + if ( backEnd.viewParms.isMirror ) { + VectorSubtract( vec3_origin, left, left ); + } + + color[0] = color[1] = color[2] = color[3] = 255; + + VectorMA( surf->origin, 3, surf->normal, origin ); + VectorSubtract( origin, backEnd.viewParms.or.origin, dir ); + VectorNormalize( dir ); + VectorMA( origin, r_ignore->value, dir, origin ); + + d = -DotProduct( dir, surf->normal ); + if ( d < 0 ) { + return; + } +#if 0 + color[0] *= d; + color[1] *= d; + color[2] *= d; +#endif + + RB_AddQuadStamp( origin, left, up, color ); +} + +#else + +void RB_SurfaceFlare( srfFlare_t *surf ) { +#if 0 + vec3_t left, up; + byte color[4]; + + color[0] = surf->color[0] * 255; + color[1] = surf->color[1] * 255; + color[2] = surf->color[2] * 255; + color[3] = 255; + + VectorClear( left ); + VectorClear( up ); + + left[0] = r_ignore->value; + + up[1] = r_ignore->value; + + RB_AddQuadStampExt( surf->origin, left, up, color, 0, 0, 1, 1 ); +#endif +} + +#endif + + + +void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { + // all apropriate state must be set in RB_BeginSurface + // this isn't implemented yet... + qglCallList( surf->listNum ); +} + +void RB_SurfaceSkip( void *surf ) { +} + + +void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { + (void(*)(void*))RB_SurfaceBad, // SF_BAD, + (void(*)(void*))RB_SurfaceSkip, // SF_SKIP, + (void(*)(void*))RB_SurfaceFace, // SF_FACE, + (void(*)(void*))RB_SurfaceGrid, // SF_GRID, + (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES, + (void(*)(void*))RB_SurfacePolychain, // SF_POLY, + (void(*)(void*))RB_SurfaceMesh, // SF_MD3, + (void(*)(void*))RB_SurfaceAnim, // SF_MD4, + (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, + (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY + (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST +}; diff --git a/code/renderer/tr_world.c b/code/renderer/tr_world.c index 37de6af..7239b32 100755 --- a/code/renderer/tr_world.c +++ b/code/renderer/tr_world.c @@ -1,668 +1,668 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#include "tr_local.h"
-
-
-
-/*
-=================
-R_CullTriSurf
-
-Returns true if the grid is completely culled away.
-Also sets the clipped hint bit in tess
-=================
-*/
-static qboolean R_CullTriSurf( srfTriangles_t *cv ) {
- int boxCull;
-
- boxCull = R_CullLocalBox( cv->bounds );
-
- if ( boxCull == CULL_OUT ) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-=================
-R_CullGrid
-
-Returns true if the grid is completely culled away.
-Also sets the clipped hint bit in tess
-=================
-*/
-static qboolean R_CullGrid( srfGridMesh_t *cv ) {
- int boxCull;
- int sphereCull;
-
- if ( r_nocurves->integer ) {
- return qtrue;
- }
-
- if ( tr.currentEntityNum != ENTITYNUM_WORLD ) {
- sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius );
- } else {
- sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius );
- }
- boxCull = CULL_OUT;
-
- // check for trivial reject
- if ( sphereCull == CULL_OUT )
- {
- tr.pc.c_sphere_cull_patch_out++;
- return qtrue;
- }
- // check bounding box if necessary
- else if ( sphereCull == CULL_CLIP )
- {
- tr.pc.c_sphere_cull_patch_clip++;
-
- boxCull = R_CullLocalBox( cv->meshBounds );
-
- if ( boxCull == CULL_OUT )
- {
- tr.pc.c_box_cull_patch_out++;
- return qtrue;
- }
- else if ( boxCull == CULL_IN )
- {
- tr.pc.c_box_cull_patch_in++;
- }
- else
- {
- tr.pc.c_box_cull_patch_clip++;
- }
- }
- else
- {
- tr.pc.c_sphere_cull_patch_in++;
- }
-
- return qfalse;
-}
-
-
-/*
-================
-R_CullSurface
-
-Tries to back face cull surfaces before they are lighted or
-added to the sorting list.
-
-This will also allow mirrors on both sides of a model without recursion.
-================
-*/
-static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) {
- srfSurfaceFace_t *sface;
- float d;
-
- if ( r_nocull->integer ) {
- return qfalse;
- }
-
- if ( *surface == SF_GRID ) {
- return R_CullGrid( (srfGridMesh_t *)surface );
- }
-
- if ( *surface == SF_TRIANGLES ) {
- return R_CullTriSurf( (srfTriangles_t *)surface );
- }
-
- if ( *surface != SF_FACE ) {
- return qfalse;
- }
-
- if ( shader->cullType == CT_TWO_SIDED ) {
- return qfalse;
- }
-
- // face culling
- if ( !r_facePlaneCull->integer ) {
- return qfalse;
- }
-
- sface = ( srfSurfaceFace_t * ) surface;
- d = DotProduct (tr.or.viewOrigin, sface->plane.normal);
-
- // don't cull exactly on the plane, because there are levels of rounding
- // through the BSP, ICD, and hardware that may cause pixel gaps if an
- // epsilon isn't allowed here
- if ( shader->cullType == CT_FRONT_SIDED ) {
- if ( d < sface->plane.dist - 8 ) {
- return qtrue;
- }
- } else {
- if ( d > sface->plane.dist + 8 ) {
- return qtrue;
- }
- }
-
- return qfalse;
-}
-
-
-static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {
- float d;
- int i;
- dlight_t *dl;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- if ( ! ( dlightBits & ( 1 << i ) ) ) {
- continue;
- }
- dl = &tr.refdef.dlights[i];
- d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;
- if ( d < -dl->radius || d > dl->radius ) {
- // dlight doesn't reach the plane
- dlightBits &= ~( 1 << i );
- }
- }
-
- if ( !dlightBits ) {
- tr.pc.c_dlightSurfacesCulled++;
- }
-
- face->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-}
-
-static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {
- int i;
- dlight_t *dl;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- if ( ! ( dlightBits & ( 1 << i ) ) ) {
- continue;
- }
- dl = &tr.refdef.dlights[i];
- if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
- || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
- || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
- || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
- || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
- || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
- // dlight doesn't reach the bounds
- dlightBits &= ~( 1 << i );
- }
- }
-
- if ( !dlightBits ) {
- tr.pc.c_dlightSurfacesCulled++;
- }
-
- grid->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-}
-
-
-static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {
- // FIXME: more dlight culling to trisurfs...
- surf->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-#if 0
- int i;
- dlight_t *dl;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- if ( ! ( dlightBits & ( 1 << i ) ) ) {
- continue;
- }
- dl = &tr.refdef.dlights[i];
- if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
- || dl->origin[0] + dl->radius < grid->meshBounds[0][0]
- || dl->origin[1] - dl->radius > grid->meshBounds[1][1]
- || dl->origin[1] + dl->radius < grid->meshBounds[0][1]
- || dl->origin[2] - dl->radius > grid->meshBounds[1][2]
- || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
- // dlight doesn't reach the bounds
- dlightBits &= ~( 1 << i );
- }
- }
-
- if ( !dlightBits ) {
- tr.pc.c_dlightSurfacesCulled++;
- }
-
- grid->dlightBits[ tr.smpFrame ] = dlightBits;
- return dlightBits;
-#endif
-}
-
-/*
-====================
-R_DlightSurface
-
-The given surface is going to be drawn, and it touches a leaf
-that is touched by one or more dlights, so try to throw out
-more dlights if possible.
-====================
-*/
-static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
- if ( *surf->data == SF_FACE ) {
- dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );
- } else if ( *surf->data == SF_GRID ) {
- dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );
- } else if ( *surf->data == SF_TRIANGLES ) {
- dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );
- } else {
- dlightBits = 0;
- }
-
- if ( dlightBits ) {
- tr.pc.c_dlightSurfaces++;
- }
-
- return dlightBits;
-}
-
-
-
-/*
-======================
-R_AddWorldSurface
-======================
-*/
-static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) {
- if ( surf->viewCount == tr.viewCount ) {
- return; // already in this view
- }
-
- surf->viewCount = tr.viewCount;
- // FIXME: bmodel fog?
-
- // try to cull before dlighting or adding
- if ( R_CullSurface( surf->data, surf->shader ) ) {
- return;
- }
-
- // check for dlighting
- if ( dlightBits ) {
- dlightBits = R_DlightSurface( surf, dlightBits );
- dlightBits = ( dlightBits != 0 );
- }
-
- R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits );
-}
-
-/*
-=============================================================
-
- BRUSH MODELS
-
-=============================================================
-*/
-
-/*
-=================
-R_AddBrushModelSurfaces
-=================
-*/
-void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
- bmodel_t *bmodel;
- int clip;
- model_t *pModel;
- int i;
-
- pModel = R_GetModelByHandle( ent->e.hModel );
-
- bmodel = pModel->bmodel;
-
- clip = R_CullLocalBox( bmodel->bounds );
- if ( clip == CULL_OUT ) {
- return;
- }
-
- R_DlightBmodel( bmodel );
-
- for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
- R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights );
- }
-}
-
-
-/*
-=============================================================
-
- WORLD MODEL
-
-=============================================================
-*/
-
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) {
-
- do {
- int newDlights[2];
-
- // if the node wasn't marked as potentially visible, exit
- if (node->visframe != tr.visCount) {
- return;
- }
-
- // if the bounding volume is outside the frustum, nothing
- // inside can be visible OPTIMIZE: don't do this all the way to leafs?
-
- if ( !r_nocull->integer ) {
- int r;
-
- if ( planeBits & 1 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~1; // all descendants will also be in front
- }
- }
-
- if ( planeBits & 2 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~2; // all descendants will also be in front
- }
- }
-
- if ( planeBits & 4 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~4; // all descendants will also be in front
- }
- }
-
- if ( planeBits & 8 ) {
- r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
- if (r == 2) {
- return; // culled
- }
- if ( r == 1 ) {
- planeBits &= ~8; // all descendants will also be in front
- }
- }
-
- }
-
- if ( node->contents != -1 ) {
- break;
- }
-
- // node is just a decision point, so go down both sides
- // since we don't care about sort orders, just go positive to negative
-
- // determine which dlights are needed
- newDlights[0] = 0;
- newDlights[1] = 0;
- if ( dlightBits ) {
- int i;
-
- for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
- dlight_t *dl;
- float dist;
-
- if ( dlightBits & ( 1 << i ) ) {
- dl = &tr.refdef.dlights[i];
- dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
-
- if ( dist > -dl->radius ) {
- newDlights[0] |= ( 1 << i );
- }
- if ( dist < dl->radius ) {
- newDlights[1] |= ( 1 << i );
- }
- }
- }
- }
-
- // recurse down the children, front side first
- R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );
-
- // tail recurse
- node = node->children[1];
- dlightBits = newDlights[1];
- } while ( 1 );
-
- {
- // leaf node, so add mark surfaces
- int c;
- msurface_t *surf, **mark;
-
- tr.pc.c_leafs++;
-
- // add to z buffer bounds
- if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
- tr.viewParms.visBounds[0][0] = node->mins[0];
- }
- if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
- tr.viewParms.visBounds[0][1] = node->mins[1];
- }
- if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
- tr.viewParms.visBounds[0][2] = node->mins[2];
- }
-
- if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
- tr.viewParms.visBounds[1][0] = node->maxs[0];
- }
- if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
- tr.viewParms.visBounds[1][1] = node->maxs[1];
- }
- if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
- tr.viewParms.visBounds[1][2] = node->maxs[2];
- }
-
- // add the individual surfaces
- mark = node->firstmarksurface;
- c = node->nummarksurfaces;
- while (c--) {
- // the surface may have already been added if it
- // spans multiple leafs
- surf = *mark;
- R_AddWorldSurface( surf, dlightBits );
- mark++;
- }
- }
-
-}
-
-
-/*
-===============
-R_PointInLeaf
-===============
-*/
-static mnode_t *R_PointInLeaf( const vec3_t p ) {
- mnode_t *node;
- float d;
- cplane_t *plane;
-
- if ( !tr.world ) {
- ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
- }
-
- node = tr.world->nodes;
- while( 1 ) {
- if (node->contents != -1) {
- break;
- }
- plane = node->plane;
- d = DotProduct (p,plane->normal) - plane->dist;
- if (d > 0) {
- node = node->children[0];
- } else {
- node = node->children[1];
- }
- }
-
- return node;
-}
-
-/*
-==============
-R_ClusterPVS
-==============
-*/
-static const byte *R_ClusterPVS (int cluster) {
- if (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
- return tr.world->novis;
- }
-
- return tr.world->vis + cluster * tr.world->clusterBytes;
-}
-
-/*
-=================
-R_inPVS
-=================
-*/
-qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {
- mnode_t *leaf;
- byte *vis;
-
- leaf = R_PointInLeaf( p1 );
- vis = CM_ClusterPVS( leaf->cluster );
- leaf = R_PointInLeaf( p2 );
-
- if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-===============
-R_MarkLeaves
-
-Mark the leaves and nodes that are in the PVS for the current
-cluster
-===============
-*/
-static void R_MarkLeaves (void) {
- const byte *vis;
- mnode_t *leaf, *parent;
- int i;
- int cluster;
-
- // lockpvs lets designers walk around to determine the
- // extent of the current pvs
- if ( r_lockpvs->integer ) {
- return;
- }
-
- // current viewcluster
- leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
- cluster = leaf->cluster;
-
- // if the cluster is the same and the area visibility matrix
- // hasn't changed, we don't need to mark everything again
-
- // if r_showcluster was just turned on, remark everything
- if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified
- && !r_showcluster->modified ) {
- return;
- }
-
- if ( r_showcluster->modified || r_showcluster->integer ) {
- r_showcluster->modified = qfalse;
- if ( r_showcluster->integer ) {
- ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
- }
- }
-
- tr.visCount++;
- tr.viewCluster = cluster;
-
- if ( r_novis->integer || tr.viewCluster == -1 ) {
- for (i=0 ; i<tr.world->numnodes ; i++) {
- if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
- tr.world->nodes[i].visframe = tr.visCount;
- }
- }
- return;
- }
-
- vis = R_ClusterPVS (tr.viewCluster);
-
- for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
- cluster = leaf->cluster;
- if ( cluster < 0 || cluster >= tr.world->numClusters ) {
- continue;
- }
-
- // check general pvs
- if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {
- continue;
- }
-
- // check for door connection
- if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
- continue; // not visible
- }
-
- parent = leaf;
- do {
- if (parent->visframe == tr.visCount)
- break;
- parent->visframe = tr.visCount;
- parent = parent->parent;
- } while (parent);
- }
-}
-
-
-/*
-=============
-R_AddWorldSurfaces
-=============
-*/
-void R_AddWorldSurfaces (void) {
- if ( !r_drawworld->integer ) {
- return;
- }
-
- if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
- return;
- }
-
- tr.currentEntityNum = ENTITYNUM_WORLD;
- tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
-
- // determine which leaves are in the PVS / areamask
- R_MarkLeaves ();
-
- // clear out the visible min/max
- ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
-
- // perform frustum culling and add all the potentially visible surfaces
- if ( tr.refdef.num_dlights > 32 ) {
- tr.refdef.num_dlights = 32 ;
- }
- R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 );
-}
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "tr_local.h" + + + +/* +================= +R_CullTriSurf + +Returns true if the grid is completely culled away. +Also sets the clipped hint bit in tess +================= +*/ +static qboolean R_CullTriSurf( srfTriangles_t *cv ) { + int boxCull; + + boxCull = R_CullLocalBox( cv->bounds ); + + if ( boxCull == CULL_OUT ) { + return qtrue; + } + return qfalse; +} + +/* +================= +R_CullGrid + +Returns true if the grid is completely culled away. +Also sets the clipped hint bit in tess +================= +*/ +static qboolean R_CullGrid( srfGridMesh_t *cv ) { + int boxCull; + int sphereCull; + + if ( r_nocurves->integer ) { + return qtrue; + } + + if ( tr.currentEntityNum != ENTITYNUM_WORLD ) { + sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius ); + } else { + sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius ); + } + boxCull = CULL_OUT; + + // check for trivial reject + if ( sphereCull == CULL_OUT ) + { + tr.pc.c_sphere_cull_patch_out++; + return qtrue; + } + // check bounding box if necessary + else if ( sphereCull == CULL_CLIP ) + { + tr.pc.c_sphere_cull_patch_clip++; + + boxCull = R_CullLocalBox( cv->meshBounds ); + + if ( boxCull == CULL_OUT ) + { + tr.pc.c_box_cull_patch_out++; + return qtrue; + } + else if ( boxCull == CULL_IN ) + { + tr.pc.c_box_cull_patch_in++; + } + else + { + tr.pc.c_box_cull_patch_clip++; + } + } + else + { + tr.pc.c_sphere_cull_patch_in++; + } + + return qfalse; +} + + +/* +================ +R_CullSurface + +Tries to back face cull surfaces before they are lighted or +added to the sorting list. + +This will also allow mirrors on both sides of a model without recursion. +================ +*/ +static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) { + srfSurfaceFace_t *sface; + float d; + + if ( r_nocull->integer ) { + return qfalse; + } + + if ( *surface == SF_GRID ) { + return R_CullGrid( (srfGridMesh_t *)surface ); + } + + if ( *surface == SF_TRIANGLES ) { + return R_CullTriSurf( (srfTriangles_t *)surface ); + } + + if ( *surface != SF_FACE ) { + return qfalse; + } + + if ( shader->cullType == CT_TWO_SIDED ) { + return qfalse; + } + + // face culling + if ( !r_facePlaneCull->integer ) { + return qfalse; + } + + sface = ( srfSurfaceFace_t * ) surface; + d = DotProduct (tr.or.viewOrigin, sface->plane.normal); + + // don't cull exactly on the plane, because there are levels of rounding + // through the BSP, ICD, and hardware that may cause pixel gaps if an + // epsilon isn't allowed here + if ( shader->cullType == CT_FRONT_SIDED ) { + if ( d < sface->plane.dist - 8 ) { + return qtrue; + } + } else { + if ( d > sface->plane.dist + 8 ) { + return qtrue; + } + } + + return qfalse; +} + + +static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) { + float d; + int i; + dlight_t *dl; + + for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { + if ( ! ( dlightBits & ( 1 << i ) ) ) { + continue; + } + dl = &tr.refdef.dlights[i]; + d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist; + if ( d < -dl->radius || d > dl->radius ) { + // dlight doesn't reach the plane + dlightBits &= ~( 1 << i ); + } + } + + if ( !dlightBits ) { + tr.pc.c_dlightSurfacesCulled++; + } + + face->dlightBits[ tr.smpFrame ] = dlightBits; + return dlightBits; +} + +static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) { + int i; + dlight_t *dl; + + for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { + if ( ! ( dlightBits & ( 1 << i ) ) ) { + continue; + } + dl = &tr.refdef.dlights[i]; + if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0] + || dl->origin[0] + dl->radius < grid->meshBounds[0][0] + || dl->origin[1] - dl->radius > grid->meshBounds[1][1] + || dl->origin[1] + dl->radius < grid->meshBounds[0][1] + || dl->origin[2] - dl->radius > grid->meshBounds[1][2] + || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) { + // dlight doesn't reach the bounds + dlightBits &= ~( 1 << i ); + } + } + + if ( !dlightBits ) { + tr.pc.c_dlightSurfacesCulled++; + } + + grid->dlightBits[ tr.smpFrame ] = dlightBits; + return dlightBits; +} + + +static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) { + // FIXME: more dlight culling to trisurfs... + surf->dlightBits[ tr.smpFrame ] = dlightBits; + return dlightBits; +#if 0 + int i; + dlight_t *dl; + + for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { + if ( ! ( dlightBits & ( 1 << i ) ) ) { + continue; + } + dl = &tr.refdef.dlights[i]; + if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0] + || dl->origin[0] + dl->radius < grid->meshBounds[0][0] + || dl->origin[1] - dl->radius > grid->meshBounds[1][1] + || dl->origin[1] + dl->radius < grid->meshBounds[0][1] + || dl->origin[2] - dl->radius > grid->meshBounds[1][2] + || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) { + // dlight doesn't reach the bounds + dlightBits &= ~( 1 << i ); + } + } + + if ( !dlightBits ) { + tr.pc.c_dlightSurfacesCulled++; + } + + grid->dlightBits[ tr.smpFrame ] = dlightBits; + return dlightBits; +#endif +} + +/* +==================== +R_DlightSurface + +The given surface is going to be drawn, and it touches a leaf +that is touched by one or more dlights, so try to throw out +more dlights if possible. +==================== +*/ +static int R_DlightSurface( msurface_t *surf, int dlightBits ) { + if ( *surf->data == SF_FACE ) { + dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits ); + } else if ( *surf->data == SF_GRID ) { + dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits ); + } else if ( *surf->data == SF_TRIANGLES ) { + dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits ); + } else { + dlightBits = 0; + } + + if ( dlightBits ) { + tr.pc.c_dlightSurfaces++; + } + + return dlightBits; +} + + + +/* +====================== +R_AddWorldSurface +====================== +*/ +static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) { + if ( surf->viewCount == tr.viewCount ) { + return; // already in this view + } + + surf->viewCount = tr.viewCount; + // FIXME: bmodel fog? + + // try to cull before dlighting or adding + if ( R_CullSurface( surf->data, surf->shader ) ) { + return; + } + + // check for dlighting + if ( dlightBits ) { + dlightBits = R_DlightSurface( surf, dlightBits ); + dlightBits = ( dlightBits != 0 ); + } + + R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits ); +} + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +/* +================= +R_AddBrushModelSurfaces +================= +*/ +void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { + bmodel_t *bmodel; + int clip; + model_t *pModel; + int i; + + pModel = R_GetModelByHandle( ent->e.hModel ); + + bmodel = pModel->bmodel; + + clip = R_CullLocalBox( bmodel->bounds ); + if ( clip == CULL_OUT ) { + return; + } + + R_DlightBmodel( bmodel ); + + for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { + R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights ); + } +} + + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ + + +/* +================ +R_RecursiveWorldNode +================ +*/ +static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) { + + do { + int newDlights[2]; + + // if the node wasn't marked as potentially visible, exit + if (node->visframe != tr.visCount) { + return; + } + + // if the bounding volume is outside the frustum, nothing + // inside can be visible OPTIMIZE: don't do this all the way to leafs? + + if ( !r_nocull->integer ) { + int r; + + if ( planeBits & 1 ) { + r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]); + if (r == 2) { + return; // culled + } + if ( r == 1 ) { + planeBits &= ~1; // all descendants will also be in front + } + } + + if ( planeBits & 2 ) { + r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]); + if (r == 2) { + return; // culled + } + if ( r == 1 ) { + planeBits &= ~2; // all descendants will also be in front + } + } + + if ( planeBits & 4 ) { + r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]); + if (r == 2) { + return; // culled + } + if ( r == 1 ) { + planeBits &= ~4; // all descendants will also be in front + } + } + + if ( planeBits & 8 ) { + r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]); + if (r == 2) { + return; // culled + } + if ( r == 1 ) { + planeBits &= ~8; // all descendants will also be in front + } + } + + } + + if ( node->contents != -1 ) { + break; + } + + // node is just a decision point, so go down both sides + // since we don't care about sort orders, just go positive to negative + + // determine which dlights are needed + newDlights[0] = 0; + newDlights[1] = 0; + if ( dlightBits ) { + int i; + + for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { + dlight_t *dl; + float dist; + + if ( dlightBits & ( 1 << i ) ) { + dl = &tr.refdef.dlights[i]; + dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist; + + if ( dist > -dl->radius ) { + newDlights[0] |= ( 1 << i ); + } + if ( dist < dl->radius ) { + newDlights[1] |= ( 1 << i ); + } + } + } + } + + // recurse down the children, front side first + R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] ); + + // tail recurse + node = node->children[1]; + dlightBits = newDlights[1]; + } while ( 1 ); + + { + // leaf node, so add mark surfaces + int c; + msurface_t *surf, **mark; + + tr.pc.c_leafs++; + + // add to z buffer bounds + if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) { + tr.viewParms.visBounds[0][0] = node->mins[0]; + } + if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) { + tr.viewParms.visBounds[0][1] = node->mins[1]; + } + if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) { + tr.viewParms.visBounds[0][2] = node->mins[2]; + } + + if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) { + tr.viewParms.visBounds[1][0] = node->maxs[0]; + } + if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) { + tr.viewParms.visBounds[1][1] = node->maxs[1]; + } + if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) { + tr.viewParms.visBounds[1][2] = node->maxs[2]; + } + + // add the individual surfaces + mark = node->firstmarksurface; + c = node->nummarksurfaces; + while (c--) { + // the surface may have already been added if it + // spans multiple leafs + surf = *mark; + R_AddWorldSurface( surf, dlightBits ); + mark++; + } + } + +} + + +/* +=============== +R_PointInLeaf +=============== +*/ +static mnode_t *R_PointInLeaf( const vec3_t p ) { + mnode_t *node; + float d; + cplane_t *plane; + + if ( !tr.world ) { + ri.Error (ERR_DROP, "R_PointInLeaf: bad model"); + } + + node = tr.world->nodes; + while( 1 ) { + if (node->contents != -1) { + break; + } + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) { + node = node->children[0]; + } else { + node = node->children[1]; + } + } + + return node; +} + +/* +============== +R_ClusterPVS +============== +*/ +static const byte *R_ClusterPVS (int cluster) { + if (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { + return tr.world->novis; + } + + return tr.world->vis + cluster * tr.world->clusterBytes; +} + +/* +================= +R_inPVS +================= +*/ +qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) { + mnode_t *leaf; + byte *vis; + + leaf = R_PointInLeaf( p1 ); + vis = CM_ClusterPVS( leaf->cluster ); + leaf = R_PointInLeaf( p2 ); + + if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) { + return qfalse; + } + return qtrue; +} + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current +cluster +=============== +*/ +static void R_MarkLeaves (void) { + const byte *vis; + mnode_t *leaf, *parent; + int i; + int cluster; + + // lockpvs lets designers walk around to determine the + // extent of the current pvs + if ( r_lockpvs->integer ) { + return; + } + + // current viewcluster + leaf = R_PointInLeaf( tr.viewParms.pvsOrigin ); + cluster = leaf->cluster; + + // if the cluster is the same and the area visibility matrix + // hasn't changed, we don't need to mark everything again + + // if r_showcluster was just turned on, remark everything + if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified + && !r_showcluster->modified ) { + return; + } + + if ( r_showcluster->modified || r_showcluster->integer ) { + r_showcluster->modified = qfalse; + if ( r_showcluster->integer ) { + ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area ); + } + } + + tr.visCount++; + tr.viewCluster = cluster; + + if ( r_novis->integer || tr.viewCluster == -1 ) { + for (i=0 ; i<tr.world->numnodes ; i++) { + if (tr.world->nodes[i].contents != CONTENTS_SOLID) { + tr.world->nodes[i].visframe = tr.visCount; + } + } + return; + } + + vis = R_ClusterPVS (tr.viewCluster); + + for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) { + cluster = leaf->cluster; + if ( cluster < 0 || cluster >= tr.world->numClusters ) { + continue; + } + + // check general pvs + if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) { + continue; + } + + // check for door connection + if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) { + continue; // not visible + } + + parent = leaf; + do { + if (parent->visframe == tr.visCount) + break; + parent->visframe = tr.visCount; + parent = parent->parent; + } while (parent); + } +} + + +/* +============= +R_AddWorldSurfaces +============= +*/ +void R_AddWorldSurfaces (void) { + if ( !r_drawworld->integer ) { + return; + } + + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + return; + } + + tr.currentEntityNum = ENTITYNUM_WORLD; + tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; + + // determine which leaves are in the PVS / areamask + R_MarkLeaves (); + + // clear out the visible min/max + ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); + + // perform frustum culling and add all the potentially visible surfaces + if ( tr.refdef.num_dlights > 32 ) { + tr.refdef.num_dlights = 32 ; + } + R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 ); +} |