mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2024-11-25 05:31:21 +00:00
Removing a old version of our Renderer. The history of the renderergl2
folder is that when we added it to Reaction we called it renderergl2 but months later it was also added to ioq3 under the name rend2. To stay compatible with ioq3 we made the same change here. However we neglected to remove the old renderergl2 folder which has now become an issue since ioq3 has now decided to rename rend2 back to renderergl2 :)
This commit is contained in:
parent
9d88001ba8
commit
e7dbd29c6c
37 changed files with 1 additions and 40981 deletions
|
@ -405,7 +405,7 @@
|
||||||
//
|
//
|
||||||
#include "../qcommon/q_shared.h"
|
#include "../qcommon/q_shared.h"
|
||||||
#include "../renderer/tr_types.h"
|
#include "../renderer/tr_types.h"
|
||||||
#include "../renderergl2/tr_extratypes.h"
|
#include "../rend2/tr_extratypes.h"
|
||||||
#include "../game/bg_public.h"
|
#include "../game/bg_public.h"
|
||||||
#include "cg_public.h"
|
#include "cg_public.h"
|
||||||
|
|
||||||
|
|
|
@ -1,755 +0,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 Quake III Arena source code; 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__
|
|
||||||
|
|
||||||
#ifdef USE_LOCAL_HEADERS
|
|
||||||
# include "SDL_opengl.h"
|
|
||||||
#else
|
|
||||||
# include <SDL_opengl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void (APIENTRYP qglActiveTextureARB) (GLenum texture);
|
|
||||||
extern void (APIENTRYP qglClientActiveTextureARB) (GLenum texture);
|
|
||||||
extern void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t);
|
|
||||||
|
|
||||||
extern void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count);
|
|
||||||
extern void (APIENTRYP qglUnlockArraysEXT) (void);
|
|
||||||
|
|
||||||
// GL_EXT_draw_range_elements
|
|
||||||
extern void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
|
|
||||||
|
|
||||||
// GL_EXT_multi_draw_arrays
|
|
||||||
extern void (APIENTRY * qglMultiDrawArraysEXT) (GLenum, GLint *, GLsizei *, GLsizei);
|
|
||||||
extern void (APIENTRY * qglMultiDrawElementsEXT) (GLenum, const GLsizei *, GLenum, const GLvoid **, GLsizei);
|
|
||||||
|
|
||||||
// GL_ARB_shading_language_100
|
|
||||||
#ifndef GL_ARB_shading_language_100
|
|
||||||
#define GL_ARB_shading_language_100
|
|
||||||
#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_ARB_vertex_program
|
|
||||||
extern void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
|
|
||||||
extern void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *);
|
|
||||||
extern void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized,
|
|
||||||
GLsizei stride, const GLvoid * pointer);
|
|
||||||
extern void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index);
|
|
||||||
extern void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index);
|
|
||||||
|
|
||||||
// GL_ARB_vertex_buffer_object
|
|
||||||
extern void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer);
|
|
||||||
extern void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers);
|
|
||||||
extern void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers);
|
|
||||||
extern GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer);
|
|
||||||
extern void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage);
|
|
||||||
extern void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data);
|
|
||||||
extern void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data);
|
|
||||||
extern void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params);
|
|
||||||
extern void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params);
|
|
||||||
|
|
||||||
// GL_ARB_shader_objects
|
|
||||||
extern void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj);
|
|
||||||
extern GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname);
|
|
||||||
extern void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj);
|
|
||||||
extern GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType);
|
|
||||||
extern void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string,
|
|
||||||
const GLint * length);
|
|
||||||
extern void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj);
|
|
||||||
extern GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void);
|
|
||||||
extern void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj);
|
|
||||||
extern void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj);
|
|
||||||
extern void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj);
|
|
||||||
extern void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj);
|
|
||||||
extern void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0);
|
|
||||||
extern void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1);
|
|
||||||
extern void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
|
||||||
extern void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
|
||||||
extern void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0);
|
|
||||||
extern void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1);
|
|
||||||
extern void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2);
|
|
||||||
extern void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
|
||||||
extern void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value);
|
|
||||||
extern void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value);
|
|
||||||
extern void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value);
|
|
||||||
extern void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
|
||||||
extern void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params);
|
|
||||||
extern void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params);
|
|
||||||
extern void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog);
|
|
||||||
extern void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count,
|
|
||||||
GLhandleARB * obj);
|
|
||||||
extern GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
|
||||||
extern void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length,
|
|
||||||
GLint * size, GLenum * type, GLcharARB * name);
|
|
||||||
extern void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params);
|
|
||||||
extern void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params);
|
|
||||||
extern void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source);
|
|
||||||
|
|
||||||
// GL_ARB_vertex_shader
|
|
||||||
extern void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name);
|
|
||||||
extern void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length,
|
|
||||||
GLint * size, GLenum * type, GLcharARB * name);
|
|
||||||
extern GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
|
||||||
|
|
||||||
// GL_ARB_texture_compression
|
|
||||||
extern void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
|
|
||||||
GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
|
|
||||||
extern void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
|
|
||||||
GLint border, GLsizei imageSize, const GLvoid *data);
|
|
||||||
extern void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border,
|
|
||||||
GLsizei imageSize, const GLvoid *data);
|
|
||||||
extern void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
|
||||||
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
|
|
||||||
extern void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
|
||||||
GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
|
|
||||||
extern void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format,
|
|
||||||
GLsizei imageSize, const GLvoid *data);
|
|
||||||
extern void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod,
|
|
||||||
GLvoid *img);
|
|
||||||
|
|
||||||
// GL_NVX_gpu_memory_info
|
|
||||||
#ifndef GL_NVX_gpu_memory_info
|
|
||||||
#define GL_NVX_gpu_memory_info
|
|
||||||
#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
|
|
||||||
#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
|
|
||||||
#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
|
|
||||||
#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
|
|
||||||
#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_ATI_meminfo
|
|
||||||
#ifndef GL_ATI_meminfo
|
|
||||||
#define GL_ATI_meminfo
|
|
||||||
#define GL_VBO_FREE_MEMORY_ATI 0x87FB
|
|
||||||
#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC
|
|
||||||
#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_ARB_texture_float
|
|
||||||
#ifndef GL_ARB_texture_float
|
|
||||||
#define GL_ARB_texture_float
|
|
||||||
#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
|
|
||||||
#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11
|
|
||||||
#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12
|
|
||||||
#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13
|
|
||||||
#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14
|
|
||||||
#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15
|
|
||||||
#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16
|
|
||||||
#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17
|
|
||||||
#define GL_RGBA32F_ARB 0x8814
|
|
||||||
#define GL_RGB32F_ARB 0x8815
|
|
||||||
#define GL_ALPHA32F_ARB 0x8816
|
|
||||||
#define GL_INTENSITY32F_ARB 0x8817
|
|
||||||
#define GL_LUMINANCE32F_ARB 0x8818
|
|
||||||
#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
|
|
||||||
#define GL_RGBA16F_ARB 0x881A
|
|
||||||
#define GL_RGB16F_ARB 0x881B
|
|
||||||
#define GL_ALPHA16F_ARB 0x881C
|
|
||||||
#define GL_INTENSITY16F_ARB 0x881D
|
|
||||||
#define GL_LUMINANCE16F_ARB 0x881E
|
|
||||||
#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_ARB_half_float_pixel
|
|
||||||
#define GL_ARB_half_float_pixel
|
|
||||||
#define GL_HALF_FLOAT_ARB 0x140B
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_object
|
|
||||||
extern GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer);
|
|
||||||
extern void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
|
|
||||||
extern void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers);
|
|
||||||
extern void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers);
|
|
||||||
extern void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
|
||||||
extern void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params);
|
|
||||||
extern GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer);
|
|
||||||
extern void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer);
|
|
||||||
extern void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers);
|
|
||||||
extern void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers);
|
|
||||||
extern GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target);
|
|
||||||
extern void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
|
||||||
GLint level);
|
|
||||||
extern void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
|
||||||
GLint level);
|
|
||||||
extern void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
|
||||||
GLint level, GLint zoffset);
|
|
||||||
extern void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
|
||||||
GLuint renderbuffer);
|
|
||||||
extern void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
|
|
||||||
extern void (APIENTRY * qglGenerateMipmapEXT)(GLenum target);
|
|
||||||
|
|
||||||
#ifndef GL_EXT_framebuffer_object
|
|
||||||
#define GL_EXT_framebuffer_object
|
|
||||||
#define GL_FRAMEBUFFER_EXT 0x8D40
|
|
||||||
#define GL_RENDERBUFFER_EXT 0x8D41
|
|
||||||
#define GL_STENCIL_INDEX1_EXT 0x8D46
|
|
||||||
#define GL_STENCIL_INDEX4_EXT 0x8D47
|
|
||||||
#define GL_STENCIL_INDEX8_EXT 0x8D48
|
|
||||||
#define GL_STENCIL_INDEX16_EXT 0x8D49
|
|
||||||
#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
|
|
||||||
#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
|
|
||||||
#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
|
|
||||||
#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
|
|
||||||
#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
|
|
||||||
#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
|
|
||||||
#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
|
|
||||||
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
|
|
||||||
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
|
|
||||||
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
|
|
||||||
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
|
|
||||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
|
|
||||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
|
|
||||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
|
|
||||||
#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
|
|
||||||
#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
|
|
||||||
#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
|
|
||||||
#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
|
|
||||||
#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
|
|
||||||
#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
|
|
||||||
#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
|
|
||||||
#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
|
|
||||||
#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
|
|
||||||
#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
|
|
||||||
#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
|
|
||||||
#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
|
|
||||||
#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
|
|
||||||
#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
|
|
||||||
#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
|
|
||||||
#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
|
|
||||||
#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
|
|
||||||
#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
|
|
||||||
#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
|
|
||||||
#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
|
|
||||||
#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
|
|
||||||
#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
|
|
||||||
#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
|
|
||||||
#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
|
|
||||||
#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_EXT_packed_depth_stencil
|
|
||||||
#ifndef GL_EXT_packed_depth_stencil
|
|
||||||
#define GL_EXT_packed_depth_stencil
|
|
||||||
#define GL_DEPTH_STENCIL_EXT 0x84F9
|
|
||||||
#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
|
|
||||||
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
|
|
||||||
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_ARB_occlusion_query
|
|
||||||
extern void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids);
|
|
||||||
extern void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
|
|
||||||
extern GLboolean (APIENTRY * qglIsQueryARB)(GLuint id);
|
|
||||||
extern void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id);
|
|
||||||
extern void (APIENTRY * qglEndQueryARB)(GLenum target);
|
|
||||||
extern void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
|
|
||||||
extern void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params);
|
|
||||||
extern void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params);
|
|
||||||
|
|
||||||
#ifndef GL_ARB_occlusion_query
|
|
||||||
#define GL_ARB_occlusion_query
|
|
||||||
#define GL_SAMPLES_PASSED_ARB 0x8914
|
|
||||||
#define GL_QUERY_COUNTER_BITS_ARB 0x8864
|
|
||||||
#define GL_CURRENT_QUERY_ARB 0x8865
|
|
||||||
#define GL_QUERY_RESULT_ARB 0x8866
|
|
||||||
#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_blit
|
|
||||||
extern void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
|
||||||
GLbitfield mask, GLenum filter);
|
|
||||||
|
|
||||||
#ifndef GL_EXT_framebuffer_blit
|
|
||||||
#define GL_EXT_framebuffer_blit
|
|
||||||
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
|
|
||||||
#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
|
|
||||||
#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
|
|
||||||
#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_multisample
|
|
||||||
extern void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples,
|
|
||||||
GLenum internalformat, GLsizei width, GLsizei height);
|
|
||||||
|
|
||||||
#ifndef GL_EXT_framebuffer_multisample
|
|
||||||
#define GL_EXT_framebuffer_multisample
|
|
||||||
#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
|
|
||||||
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
|
|
||||||
#define GL_MAX_SAMPLES_EXT 0x8D57
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_EXT_texture_sRGB
|
|
||||||
#define GL_EXT_texture_sRGB
|
|
||||||
#define GL_SRGB_EXT 0x8C40
|
|
||||||
#define GL_SRGB8_EXT 0x8C41
|
|
||||||
#define GL_SRGB_ALPHA_EXT 0x8C42
|
|
||||||
#define GL_SRGB8_ALPHA8_EXT 0x8C43
|
|
||||||
#define GL_SLUMINANCE_ALPHA_EXT 0x8C44
|
|
||||||
#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45
|
|
||||||
#define GL_SLUMINANCE_EXT 0x8C46
|
|
||||||
#define GL_SLUMINANCE8_EXT 0x8C47
|
|
||||||
#define GL_COMPRESSED_SRGB_EXT 0x8C48
|
|
||||||
#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49
|
|
||||||
#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A
|
|
||||||
#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
|
|
||||||
#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
|
|
||||||
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
|
|
||||||
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
|
|
||||||
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_EXT_framebuffer_sRGB
|
|
||||||
#define GL_EXT_framebuffer_sRGB
|
|
||||||
#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_EXT_texture_compression_latc
|
|
||||||
#define GL_EXT_texture_compression_latc
|
|
||||||
#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70
|
|
||||||
#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71
|
|
||||||
#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72
|
|
||||||
#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_ARB_texture_compression_bptc
|
|
||||||
#define GL_ARB_texture_compression_bptc
|
|
||||||
#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
|
|
||||||
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
|
|
||||||
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
|
|
||||||
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GL_ARB_draw_buffers
|
|
||||||
extern void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs);
|
|
||||||
#ifndef GL_ARB_draw_buffers
|
|
||||||
#define GL_ARB_draw_buffers
|
|
||||||
#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
|
|
||||||
#define GL_DRAW_BUFFER0_ARB 0x8825
|
|
||||||
#define GL_DRAW_BUFFER1_ARB 0x8826
|
|
||||||
#define GL_DRAW_BUFFER2_ARB 0x8827
|
|
||||||
#define GL_DRAW_BUFFER3_ARB 0x8828
|
|
||||||
#define GL_DRAW_BUFFER4_ARB 0x8829
|
|
||||||
#define GL_DRAW_BUFFER5_ARB 0x882A
|
|
||||||
#define GL_DRAW_BUFFER6_ARB 0x882B
|
|
||||||
#define GL_DRAW_BUFFER7_ARB 0x882C
|
|
||||||
#define GL_DRAW_BUFFER8_ARB 0x882D
|
|
||||||
#define GL_DRAW_BUFFER9_ARB 0x882E
|
|
||||||
#define GL_DRAW_BUFFER10_ARB 0x882F
|
|
||||||
#define GL_DRAW_BUFFER11_ARB 0x8830
|
|
||||||
#define GL_DRAW_BUFFER12_ARB 0x8831
|
|
||||||
#define GL_DRAW_BUFFER13_ARB 0x8832
|
|
||||||
#define GL_DRAW_BUFFER14_ARB 0x8833
|
|
||||||
#define GL_DRAW_BUFFER15_ARB 0x8834
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GL_ARB_depth_clamp
|
|
||||||
#define GL_ARB_depth_clamp
|
|
||||||
#define GL_DEPTH_CLAMP 0x864F
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
// WGL_ARB_create_context
|
|
||||||
#ifndef WGL_ARB_create_context
|
|
||||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
||||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
||||||
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
|
||||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
|
||||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
||||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
|
||||||
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
|
||||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
||||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
|
||||||
#define ERROR_INVALID_VERSION_ARB 0x2095
|
|
||||||
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern HGLRC(APIENTRY * qwglCreateContextAttribsARB) (HDC hdC, HGLRC hShareContext, const int *attribList);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0 //defined(__linux__)
|
|
||||||
// GLX_ARB_create_context
|
|
||||||
#ifndef GLX_ARB_create_context
|
|
||||||
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
|
||||||
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
|
||||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
||||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
||||||
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern GLXContext (APIENTRY * qglXCreateContextAttribsARB) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,658 +0,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 Quake III Arena source code; 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 = (md4Header_t *) tr.currentModel->modelData;
|
|
||||||
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, 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 = (size_t)( &((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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef RAVENMD4
|
|
||||||
|
|
||||||
// copied and adapted from tr_mesh.c
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
R_MDRCullModel
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
|
|
||||||
vec3_t bounds[2];
|
|
||||||
mdrFrame_t *oldFrame, *newFrame;
|
|
||||||
int i, frameSize;
|
|
||||||
|
|
||||||
frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
|
|
||||||
|
|
||||||
// compute frame pointers
|
|
||||||
newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
|
|
||||||
oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * 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 ) )
|
|
||||||
{
|
|
||||||
// Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
|
|
||||||
// we do. After all, the purpose of md4s are not that different, are they?
|
|
||||||
|
|
||||||
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_MDRComputeFogNum
|
|
||||||
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
|
|
||||||
int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
|
|
||||||
int i, j;
|
|
||||||
fog_t *fog;
|
|
||||||
mdrFrame_t *mdrFrame;
|
|
||||||
vec3_t localOrigin;
|
|
||||||
int frameSize;
|
|
||||||
|
|
||||||
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
|
|
||||||
|
|
||||||
// FIXME: non-normalized axis issues
|
|
||||||
mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
|
|
||||||
VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
|
|
||||||
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
|
|
||||||
fog = &tr.world->fogs[i];
|
|
||||||
for ( j = 0 ; j < 3 ; j++ ) {
|
|
||||||
if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( j == 3 ) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
R_MDRAddAnimSurfaces
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
|
|
||||||
// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
|
|
||||||
|
|
||||||
void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
|
|
||||||
mdrHeader_t *header;
|
|
||||||
mdrSurface_t *surface;
|
|
||||||
mdrLOD_t *lod;
|
|
||||||
shader_t *shader;
|
|
||||||
skin_t *skin;
|
|
||||||
int i, j;
|
|
||||||
int lodnum = 0;
|
|
||||||
int fogNum = 0;
|
|
||||||
int cull;
|
|
||||||
qboolean personalModel;
|
|
||||||
|
|
||||||
header = (mdrHeader_t *) tr.currentModel->modelData;
|
|
||||||
|
|
||||||
personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
|
|
||||||
|
|
||||||
if ( ent->e.renderfx & RF_WRAP_FRAMES )
|
|
||||||
{
|
|
||||||
ent->e.frame %= header->numFrames;
|
|
||||||
ent->e.oldframe %= header->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 >= header->numFrames)
|
|
||||||
|| (ent->e.frame < 0)
|
|
||||||
|| (ent->e.oldframe >= header->numFrames)
|
|
||||||
|| (ent->e.oldframe < 0) )
|
|
||||||
{
|
|
||||||
ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// cull the entire model if merged bounding box of both frames
|
|
||||||
// is outside the view frustum.
|
|
||||||
//
|
|
||||||
cull = R_MDRCullModel (header, ent);
|
|
||||||
if ( cull == CULL_OUT ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
|
|
||||||
lodnum = R_ComputeLOD(ent);
|
|
||||||
// check whether this model has as that many LODs at all. If not, try the closest thing we got.
|
|
||||||
if(header->numLODs <= 0)
|
|
||||||
return;
|
|
||||||
if(header->numLODs <= lodnum)
|
|
||||||
lodnum = header->numLODs - 1;
|
|
||||||
|
|
||||||
lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
|
|
||||||
for(i = 0; i < lodnum; i++)
|
|
||||||
{
|
|
||||||
lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up lighting
|
|
||||||
if ( !personalModel || r_shadows->integer > 1 )
|
|
||||||
{
|
|
||||||
R_SetupEntityLighting( &tr.refdef, ent );
|
|
||||||
}
|
|
||||||
|
|
||||||
// fogNum?
|
|
||||||
fogNum = R_MDRComputeFogNum( header, ent );
|
|
||||||
|
|
||||||
surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
|
|
||||||
|
|
||||||
for ( i = 0 ; i < lod->numSurfaces ; i++ )
|
|
||||||
{
|
|
||||||
|
|
||||||
if(ent->e.customShader)
|
|
||||||
shader = R_GetShaderByHandle(ent->e.customShader);
|
|
||||||
else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
|
|
||||||
{
|
|
||||||
skin = R_GetSkinByHandle(ent->e.customSkin);
|
|
||||||
shader = tr.defaultShader;
|
|
||||||
|
|
||||||
for(j = 0; j < skin->numSurfaces; j++)
|
|
||||||
{
|
|
||||||
if (!strcmp(skin->surfaces[j]->name, surface->name))
|
|
||||||
{
|
|
||||||
shader = skin->surfaces[j]->shader;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(surface->shaderIndex > 0)
|
|
||||||
shader = R_GetShaderByHandle( surface->shaderIndex );
|
|
||||||
else
|
|
||||||
shader = tr.defaultShader;
|
|
||||||
|
|
||||||
// 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, 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, qfalse );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!personalModel)
|
|
||||||
R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse );
|
|
||||||
|
|
||||||
surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
RB_MDRSurfaceAnim
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void RB_MDRSurfaceAnim( md4Surface_t *surface )
|
|
||||||
{
|
|
||||||
int i, j, k;
|
|
||||||
float frontlerp, backlerp;
|
|
||||||
int *triangles;
|
|
||||||
int indexes;
|
|
||||||
int baseIndex, baseVertex;
|
|
||||||
int numVerts;
|
|
||||||
mdrVertex_t *v;
|
|
||||||
mdrHeader_t *header;
|
|
||||||
mdrFrame_t *frame;
|
|
||||||
mdrFrame_t *oldFrame;
|
|
||||||
mdrBone_t bones[MD4_MAX_BONES], *bonePtr, *bone;
|
|
||||||
|
|
||||||
int frameSize;
|
|
||||||
|
|
||||||
// don't lerp if lerping off, or this is the only frame, or the last frame...
|
|
||||||
//
|
|
||||||
if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
|
|
||||||
{
|
|
||||||
backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used
|
|
||||||
frontlerp = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
backlerp = backEnd.currentEntity->e.backlerp;
|
|
||||||
frontlerp = 1.0f - backlerp;
|
|
||||||
}
|
|
||||||
|
|
||||||
header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
|
|
||||||
|
|
||||||
frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
|
|
||||||
|
|
||||||
frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
|
|
||||||
backEnd.currentEntity->e.frame * frameSize );
|
|
||||||
oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
|
|
||||||
backEnd.currentEntity->e.oldframe * frameSize );
|
|
||||||
|
|
||||||
RB_CheckOverflow( surface->numVerts, surface->numTriangles );
|
|
||||||
|
|
||||||
triangles = (int *) ((byte *)surface + surface->ofsTriangles);
|
|
||||||
indexes = surface->numTriangles * 3;
|
|
||||||
baseIndex = tess.numIndexes;
|
|
||||||
baseVertex = tess.numVertexes;
|
|
||||||
|
|
||||||
// Set up all triangles.
|
|
||||||
for (j = 0 ; j < indexes ; j++)
|
|
||||||
{
|
|
||||||
tess.indexes[baseIndex + j] = baseVertex + 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;
|
|
||||||
v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
|
|
||||||
for ( j = 0; j < numVerts; j++ )
|
|
||||||
{
|
|
||||||
vec3_t tempVert, tempNormal;
|
|
||||||
mdrWeight_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];
|
|
||||||
|
|
||||||
v = (mdrVertex_t *)&v->weights[v->numWeights];
|
|
||||||
}
|
|
||||||
|
|
||||||
tess.numVertexes += surface->numVerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define MC_MASK_X ((1<<(MC_BITS_X))-1)
|
|
||||||
#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
|
|
||||||
#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
|
|
||||||
#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
|
|
||||||
|
|
||||||
#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
|
|
||||||
|
|
||||||
#define MC_POS_X (0)
|
|
||||||
#define MC_SHIFT_X (0)
|
|
||||||
|
|
||||||
#define MC_POS_Y ((((MC_BITS_X))/8))
|
|
||||||
#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
|
|
||||||
#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
|
|
||||||
#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
|
|
||||||
#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
|
|
||||||
#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
|
|
||||||
#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
|
|
||||||
#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
|
|
||||||
#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
|
|
||||||
#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
|
|
||||||
#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
|
|
||||||
|
|
||||||
#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
|
|
||||||
#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
|
|
||||||
|
|
||||||
void MC_UnCompress(float mat[3][4],const unsigned char * comp)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[0];
|
|
||||||
val-=1<<(MC_BITS_X-1);
|
|
||||||
mat[0][3]=((float)(val))*MC_SCALE_X;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[1];
|
|
||||||
val-=1<<(MC_BITS_Y-1);
|
|
||||||
mat[1][3]=((float)(val))*MC_SCALE_Y;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[2];
|
|
||||||
val-=1<<(MC_BITS_Z-1);
|
|
||||||
mat[2][3]=((float)(val))*MC_SCALE_Z;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[3];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[0][0]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[4];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[0][1]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[5];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[0][2]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[6];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[1][0]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[7];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[1][1]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[8];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[1][2]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[9];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[2][0]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[10];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[2][1]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
|
|
||||||
val=(int)((unsigned short *)(comp))[11];
|
|
||||||
val-=1<<(MC_BITS_VECT-1);
|
|
||||||
mat[2][2]=((float)(val))*MC_SCALE_VECT;
|
|
||||||
}
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,667 +0,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 Quake III Arena source code; 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/%i shaders/batches/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
|
|
||||||
backEnd.pc.c_shaders, backEnd.pc.c_surfBatches, 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 );
|
|
||||||
}
|
|
||||||
else if (r_speeds->integer == 7 )
|
|
||||||
{
|
|
||||||
ri.Printf( PRINT_ALL, "VBO draws: static %i dynamic %i\nMultidraws: %i merged %i\n",
|
|
||||||
backEnd.pc.c_staticVboDraws, backEnd.pc.c_dynamicVboDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged );
|
|
||||||
ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n",
|
|
||||||
backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
// 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 its 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;
|
|
||||||
bytes = PAD(bytes, sizeof(void *));
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
R_AddCapShadowmapCmd
|
|
||||||
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
void R_AddCapShadowmapCmd( int map, int cubeSide ) {
|
|
||||||
capShadowmapCommand_t *cmd;
|
|
||||||
|
|
||||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
|
||||||
if ( !cmd ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cmd->commandId = RC_CAPSHADOWMAP;
|
|
||||||
|
|
||||||
cmd->map = map;
|
|
||||||
cmd->cubeSide = cubeSide;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
R_PostProcessingCmd
|
|
||||||
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
void R_AddPostProcessCmd( ) {
|
|
||||||
postProcessCommand_t *cmd;
|
|
||||||
|
|
||||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
|
||||||
if ( !cmd ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cmd->commandId = RC_POSTPROCESS;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MODE_RED_CYAN 1
|
|
||||||
#define MODE_RED_BLUE 2
|
|
||||||
#define MODE_RED_GREEN 3
|
|
||||||
#define MODE_GREEN_MAGENTA 4
|
|
||||||
#define MODE_MAX MODE_GREEN_MAGENTA
|
|
||||||
|
|
||||||
void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
|
|
||||||
{
|
|
||||||
rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
|
|
||||||
|
|
||||||
if(colormode > MODE_MAX)
|
|
||||||
{
|
|
||||||
if(stereoFrame == STEREO_LEFT)
|
|
||||||
stereoFrame = STEREO_RIGHT;
|
|
||||||
else if(stereoFrame == STEREO_RIGHT)
|
|
||||||
stereoFrame = STEREO_LEFT;
|
|
||||||
|
|
||||||
colormode -= MODE_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(colormode == MODE_GREEN_MAGENTA)
|
|
||||||
{
|
|
||||||
if(stereoFrame == STEREO_LEFT)
|
|
||||||
rgba[0] = rgba[2] = GL_FALSE;
|
|
||||||
else if(stereoFrame == STEREO_RIGHT)
|
|
||||||
rgba[1] = GL_FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(stereoFrame == STEREO_LEFT)
|
|
||||||
rgba[1] = rgba[2] = GL_FALSE;
|
|
||||||
else if(stereoFrame == STEREO_RIGHT)
|
|
||||||
{
|
|
||||||
rgba[0] = GL_FALSE;
|
|
||||||
|
|
||||||
if(colormode == MODE_RED_BLUE)
|
|
||||||
rgba[1] = GL_FALSE;
|
|
||||||
else if(colormode == MODE_RED_GREEN)
|
|
||||||
rgba[2] = GL_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
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 = NULL;
|
|
||||||
colorMaskCommand_t *colcmd = NULL;
|
|
||||||
|
|
||||||
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)!", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glConfig.stereoEnabled) {
|
|
||||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
cmd->commandId = RC_DRAW_BUFFER;
|
|
||||||
|
|
||||||
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(r_anaglyphMode->integer)
|
|
||||||
{
|
|
||||||
if(r_anaglyphMode->modified)
|
|
||||||
{
|
|
||||||
// clear both, front and backbuffer.
|
|
||||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
backEnd.colorMask[0] = GL_FALSE;
|
|
||||||
backEnd.colorMask[1] = GL_FALSE;
|
|
||||||
backEnd.colorMask[2] = GL_FALSE;
|
|
||||||
backEnd.colorMask[3] = GL_FALSE;
|
|
||||||
qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
qglDrawBuffer(GL_FRONT);
|
|
||||||
qglClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
qglDrawBuffer(GL_BACK);
|
|
||||||
qglClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
if (glRefConfig.framebufferObject)
|
|
||||||
{
|
|
||||||
// clear all framebuffers
|
|
||||||
// FIXME: must be a better way to do this
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (i == 1 && !tr.msaaResolveFbo)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch(i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
FBO_Bind(tr.renderFbo);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
FBO_Bind(tr.msaaResolveFbo);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
FBO_Bind(tr.screenScratchFbo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglDrawBuffer(GL_FRONT);
|
|
||||||
qglClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
qglDrawBuffer(GL_BACK);
|
|
||||||
qglClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
FBO_Bind(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
r_anaglyphMode->modified = qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stereoFrame == STEREO_LEFT)
|
|
||||||
{
|
|
||||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(stereoFrame == STEREO_RIGHT)
|
|
||||||
{
|
|
||||||
clearDepthCommand_t *cldcmd;
|
|
||||||
|
|
||||||
if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
cldcmd->commandId = RC_CLEARDEPTH;
|
|
||||||
|
|
||||||
if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
|
|
||||||
|
|
||||||
R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
|
|
||||||
colcmd->commandId = RC_COLORMASK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(stereoFrame != STEREO_CENTER)
|
|
||||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
|
|
||||||
|
|
||||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cmd)
|
|
||||||
{
|
|
||||||
cmd->commandId = RC_DRAW_BUFFER;
|
|
||||||
|
|
||||||
if(r_anaglyphMode->modified)
|
|
||||||
{
|
|
||||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
backEnd.colorMask[0] = 0;
|
|
||||||
backEnd.colorMask[1] = 0;
|
|
||||||
backEnd.colorMask[2] = 0;
|
|
||||||
backEnd.colorMask[3] = 0;
|
|
||||||
r_anaglyphMode->modified = qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
|
|
||||||
cmd->buffer = (int)GL_FRONT;
|
|
||||||
else
|
|
||||||
cmd->buffer = (int)GL_BACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.refdef.stereoFrame = stereoFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
RE_TakeVideoFrame
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
void RE_TakeVideoFrame( int width, int height,
|
|
||||||
byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg )
|
|
||||||
{
|
|
||||||
videoFrameCommand_t *cmd;
|
|
||||||
|
|
||||||
if( !tr.registered ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
|
||||||
if( !cmd ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->commandId = RC_VIDEOFRAME;
|
|
||||||
|
|
||||||
cmd->width = width;
|
|
||||||
cmd->height = height;
|
|
||||||
cmd->captureBuffer = captureBuffer;
|
|
||||||
cmd->encodeBuffer = encodeBuffer;
|
|
||||||
cmd->motionJpeg = motionJpeg;
|
|
||||||
}
|
|
|
@ -1,806 +0,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 Quake III Arena source code; 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,
|
|
||||||
srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
LerpDrawVert
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_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->vertexColors[0] = 0.5f * (a->vertexColors[0] + b->vertexColors[0]);
|
|
||||||
out->vertexColors[1] = 0.5f * (a->vertexColors[1] + b->vertexColors[1]);
|
|
||||||
out->vertexColors[2] = 0.5f * (a->vertexColors[2] + b->vertexColors[2]);
|
|
||||||
out->vertexColors[3] = 0.5f * (a->vertexColors[3] + b->vertexColors[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
Transpose
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
static void Transpose( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
|
|
||||||
int i, j;
|
|
||||||
srfVert_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, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
|
|
||||||
int i, j, k, dist;
|
|
||||||
vec3_t normal;
|
|
||||||
vec3_t sum;
|
|
||||||
int count = 0;
|
|
||||||
vec3_t base;
|
|
||||||
vec3_t delta;
|
|
||||||
int x, y;
|
|
||||||
srfVert_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");
|
|
||||||
//}
|
|
||||||
VectorNormalize2( sum, dv->normal );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numTriangles,
|
|
||||||
srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2])
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
srfVert_t *dv[3];
|
|
||||||
static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
|
|
||||||
srfTriangle_t *tri;
|
|
||||||
|
|
||||||
// FIXME: use more elegant way
|
|
||||||
for(i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
dv[0] = &ctrl2[j * width + i];
|
|
||||||
*dv[0] = ctrl[j][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0, tri = triangles; i < numTriangles; i++, tri++)
|
|
||||||
{
|
|
||||||
dv[0] = &ctrl2[tri->indexes[0]];
|
|
||||||
dv[1] = &ctrl2[tri->indexes[1]];
|
|
||||||
dv[2] = &ctrl2[tri->indexes[2]];
|
|
||||||
|
|
||||||
R_CalcTangentVectors(dv);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
for(i = 0; i < (width * height); i++)
|
|
||||||
{
|
|
||||||
dv0 = &ctrl2[i];
|
|
||||||
|
|
||||||
VectorNormalize(dv0->normal);
|
|
||||||
#if 0
|
|
||||||
VectorNormalize(dv0->tangent);
|
|
||||||
VectorNormalize(dv0->bitangent);
|
|
||||||
#else
|
|
||||||
d = DotProduct(dv0->tangent, dv0->normal);
|
|
||||||
VectorMA(dv0->tangent, -d, dv0->normal, dv0->tangent);
|
|
||||||
VectorNormalize(dv0->tangent);
|
|
||||||
|
|
||||||
d = DotProduct(dv0->bitangent, dv0->normal);
|
|
||||||
VectorMA(dv0->bitangent, -d, dv0->normal, dv0->bitangent);
|
|
||||||
VectorNormalize(dv0->bitangent);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// do another extra smoothing for normals to avoid flat shading
|
|
||||||
for(i = 0; i < (width * height); i++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < (width * height); j++)
|
|
||||||
{
|
|
||||||
if(R_CompareVert(&ctrl2[i], &ctrl2[j], qfalse))
|
|
||||||
{
|
|
||||||
VectorAdd(ctrl2[i].normal, ctrl2[j].normal, ctrl2[i].normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorNormalize(ctrl2[i].normal);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
dv[0] = &ctrl2[j * width + i];
|
|
||||||
dv[1] = &ctrl[j][i];
|
|
||||||
|
|
||||||
VectorCopy(dv[0]->tangent, dv[1]->tangent);
|
|
||||||
VectorCopy(dv[0]->bitangent, dv[1]->bitangent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int MakeMeshTriangles(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
|
|
||||||
srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2])
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
int numTriangles;
|
|
||||||
int w, h;
|
|
||||||
srfVert_t *dv;
|
|
||||||
static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
|
|
||||||
|
|
||||||
h = height - 1;
|
|
||||||
w = width - 1;
|
|
||||||
numTriangles = 0;
|
|
||||||
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 = i * width + j + 1;
|
|
||||||
v2 = v1 - 1;
|
|
||||||
v3 = v2 + width;
|
|
||||||
v4 = v3 + 1;
|
|
||||||
|
|
||||||
triangles[numTriangles].indexes[0] = v2;
|
|
||||||
triangles[numTriangles].indexes[1] = v3;
|
|
||||||
triangles[numTriangles].indexes[2] = v1;
|
|
||||||
numTriangles++;
|
|
||||||
|
|
||||||
triangles[numTriangles].indexes[0] = v1;
|
|
||||||
triangles[numTriangles].indexes[1] = v3;
|
|
||||||
triangles[numTriangles].indexes[2] = v4;
|
|
||||||
numTriangles++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
R_CalcSurfaceTriangleNeighbors(numTriangles, triangles);
|
|
||||||
|
|
||||||
// FIXME: use more elegant way
|
|
||||||
for(i = 0; i < width; i++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < height; j++)
|
|
||||||
{
|
|
||||||
dv = &ctrl2[j * width + i];
|
|
||||||
*dv = ctrl[j][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
R_CalcSurfaceTrianglePlanes(numTriangles, triangles, ctrl2);
|
|
||||||
|
|
||||||
return numTriangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
InvertCtrl
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
static void InvertCtrl( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
|
|
||||||
int i, j;
|
|
||||||
srfVert_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( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
|
|
||||||
int width, int height ) {
|
|
||||||
int i, j;
|
|
||||||
srfVert_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,
|
|
||||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE],
|
|
||||||
int numTriangles, srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]) {
|
|
||||||
int i, j, size;
|
|
||||||
srfVert_t *vert;
|
|
||||||
vec3_t tmpVec;
|
|
||||||
srfGridMesh_t *grid;
|
|
||||||
|
|
||||||
// copy the results out to a grid
|
|
||||||
size = (width * height - 1) * sizeof( srfVert_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 );
|
|
||||||
|
|
||||||
grid->numTriangles = numTriangles;
|
|
||||||
grid->triangles = ri.Malloc(grid->numTriangles * sizeof(srfTriangle_t));
|
|
||||||
Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t));
|
|
||||||
|
|
||||||
grid->numVerts = (width * height);
|
|
||||||
grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t));
|
|
||||||
#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 );
|
|
||||||
|
|
||||||
grid->numTriangles = numTriangles;
|
|
||||||
grid->triangles = ri.Hunk_Alloc(grid->numTriangles * sizeof(srfTriangle_t), h_low);
|
|
||||||
Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t));
|
|
||||||
|
|
||||||
grid->numVerts = (width * height);
|
|
||||||
grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
|
|
||||||
#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->triangles);
|
|
||||||
ri.Free(grid->verts);
|
|
||||||
ri.Free(grid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_SubdividePatchToGrid
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
|
|
||||||
srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
|
|
||||||
int i, j, k, l;
|
|
||||||
srfVert_t_cleared( prev );
|
|
||||||
srfVert_t_cleared( next );
|
|
||||||
srfVert_t_cleared( mid );
|
|
||||||
float len, maxLen;
|
|
||||||
int dir;
|
|
||||||
int t;
|
|
||||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
|
|
||||||
float errorTable[2][MAX_GRID_SIZE];
|
|
||||||
int numTriangles;
|
|
||||||
static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2];
|
|
||||||
int consecutiveComplete;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
consecutiveComplete = 0;
|
|
||||||
|
|
||||||
// horizontal subdivisions
|
|
||||||
for ( j = 0 ; ; j = (j + 2) % (width - 1) ) {
|
|
||||||
// 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;
|
|
||||||
// if we go over the whole grid twice without adding any columns, stop
|
|
||||||
if (++consecutiveComplete >= width)
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if we want to insert subdivided columns
|
|
||||||
if ( width + 2 > MAX_GRID_SIZE ) {
|
|
||||||
errorTable[dir][j+1] = 1.0f/maxLen;
|
|
||||||
break; // can't subdivide any more
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( maxLen <= r_subdivisions->value ) {
|
|
||||||
errorTable[dir][j+1] = 1.0f/maxLen;
|
|
||||||
// if we go over the whole grid twice without adding any columns, stop
|
|
||||||
if (++consecutiveComplete >= width)
|
|
||||||
break;
|
|
||||||
continue; // didn't need subdivision
|
|
||||||
}
|
|
||||||
|
|
||||||
errorTable[dir][j+2] = 1.0f/maxLen;
|
|
||||||
|
|
||||||
consecutiveComplete = 0;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip the new one, we'll get it on the next pass
|
|
||||||
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 triangles
|
|
||||||
numTriangles = MakeMeshTriangles(width, height, ctrl, triangles);
|
|
||||||
|
|
||||||
// calculate normals
|
|
||||||
MakeMeshNormals( width, height, ctrl );
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
MakeMeshTangentVectors(width, height, ctrl, numTriangles, triangles);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
===============
|
|
||||||
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;
|
|
||||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
|
|
||||||
float errorTable[2][MAX_GRID_SIZE];
|
|
||||||
float lodRadius;
|
|
||||||
vec3_t lodOrigin;
|
|
||||||
int numTriangles;
|
|
||||||
static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2];
|
|
||||||
|
|
||||||
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 triangles
|
|
||||||
numTriangles = MakeMeshTriangles(width, height, ctrl, triangles);
|
|
||||||
|
|
||||||
// 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, numTriangles, triangles);
|
|
||||||
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;
|
|
||||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
|
|
||||||
float errorTable[2][MAX_GRID_SIZE];
|
|
||||||
float lodRadius;
|
|
||||||
vec3_t lodOrigin;
|
|
||||||
int numTriangles;
|
|
||||||
static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2];
|
|
||||||
|
|
||||||
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 triangles
|
|
||||||
numTriangles = MakeMeshTriangles(width, height, ctrl, triangles);
|
|
||||||
|
|
||||||
// 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, numTriangles, triangles);
|
|
||||||
grid->lodRadius = lodRadius;
|
|
||||||
VectorCopy(lodOrigin, grid->lodOrigin);
|
|
||||||
return grid;
|
|
||||||
}
|
|
|
@ -1,682 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2011 James Canete (use.less01@gmail.com)
|
|
||||||
|
|
||||||
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 Quake III Arena source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_extensions.c - extensions needed by the renderer not in sdl_glimp.c
|
|
||||||
|
|
||||||
#ifdef USE_LOCAL_HEADERS
|
|
||||||
# include "SDL.h"
|
|
||||||
#else
|
|
||||||
# include <SDL.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
// GL_EXT_draw_range_elements
|
|
||||||
void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
|
|
||||||
|
|
||||||
// GL_EXT_multi_draw_arrays
|
|
||||||
void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
|
|
||||||
void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount);
|
|
||||||
|
|
||||||
// GL_ARB_vertex_shader
|
|
||||||
void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name);
|
|
||||||
void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length,
|
|
||||||
GLint * size, GLenum * type, GLcharARB * name);
|
|
||||||
GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
|
||||||
|
|
||||||
// GL_ARB_vertex_program
|
|
||||||
void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
|
|
||||||
void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *);
|
|
||||||
void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized,
|
|
||||||
GLsizei stride, const GLvoid * pointer);
|
|
||||||
void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index);
|
|
||||||
void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index);
|
|
||||||
|
|
||||||
// GL_ARB_vertex_buffer_object
|
|
||||||
void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer);
|
|
||||||
void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers);
|
|
||||||
void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers);
|
|
||||||
|
|
||||||
GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer);
|
|
||||||
void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage);
|
|
||||||
void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data);
|
|
||||||
void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data);
|
|
||||||
|
|
||||||
void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params);
|
|
||||||
void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params);
|
|
||||||
|
|
||||||
// GL_ARB_shader_objects
|
|
||||||
void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj);
|
|
||||||
|
|
||||||
GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname);
|
|
||||||
void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj);
|
|
||||||
|
|
||||||
GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType);
|
|
||||||
void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string,
|
|
||||||
const GLint * length);
|
|
||||||
void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj);
|
|
||||||
|
|
||||||
GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void);
|
|
||||||
void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj);
|
|
||||||
void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj);
|
|
||||||
void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj);
|
|
||||||
void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj);
|
|
||||||
void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0);
|
|
||||||
void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1);
|
|
||||||
void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
|
||||||
void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
|
||||||
void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0);
|
|
||||||
void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1);
|
|
||||||
void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2);
|
|
||||||
void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
|
||||||
void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value);
|
|
||||||
void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value);
|
|
||||||
void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value);
|
|
||||||
void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
|
||||||
void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params);
|
|
||||||
void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params);
|
|
||||||
void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog);
|
|
||||||
void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count,
|
|
||||||
GLhandleARB * obj);
|
|
||||||
GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
|
||||||
void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length,
|
|
||||||
GLint * size, GLenum * type, GLcharARB * name);
|
|
||||||
void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params);
|
|
||||||
void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params);
|
|
||||||
void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source);
|
|
||||||
|
|
||||||
// GL_ARB_texture_compression
|
|
||||||
void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
|
|
||||||
GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
|
|
||||||
void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
|
|
||||||
GLint border, GLsizei imageSize, const GLvoid *data);
|
|
||||||
void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border,
|
|
||||||
GLsizei imageSize, const GLvoid *data);
|
|
||||||
void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
|
||||||
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
|
|
||||||
void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
|
||||||
GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
|
|
||||||
void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format,
|
|
||||||
GLsizei imageSize, const GLvoid *data);
|
|
||||||
void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod,
|
|
||||||
GLvoid *img);
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_object
|
|
||||||
GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer);
|
|
||||||
void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
|
|
||||||
void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers);
|
|
||||||
void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers);
|
|
||||||
|
|
||||||
void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
|
||||||
|
|
||||||
void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params);
|
|
||||||
|
|
||||||
GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer);
|
|
||||||
void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer);
|
|
||||||
void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers);
|
|
||||||
void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers);
|
|
||||||
|
|
||||||
GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target);
|
|
||||||
|
|
||||||
void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
|
||||||
GLint level);
|
|
||||||
void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
|
||||||
GLint level);
|
|
||||||
void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
|
||||||
GLint level, GLint zoffset);
|
|
||||||
|
|
||||||
void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
|
||||||
GLuint renderbuffer);
|
|
||||||
|
|
||||||
void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
|
|
||||||
|
|
||||||
void (APIENTRY * qglGenerateMipmapEXT)(GLenum target);
|
|
||||||
|
|
||||||
// GL_ARB_occlusion_query
|
|
||||||
void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids);
|
|
||||||
void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
|
|
||||||
GLboolean (APIENTRY * qglIsQueryARB)(GLuint id);
|
|
||||||
void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id);
|
|
||||||
void (APIENTRY * qglEndQueryARB)(GLenum target);
|
|
||||||
void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
|
|
||||||
void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params);
|
|
||||||
void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params);
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_blit
|
|
||||||
void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
|
||||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
|
||||||
GLbitfield mask, GLenum filter);
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_multisample
|
|
||||||
void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples,
|
|
||||||
GLenum internalformat, GLsizei width, GLsizei height);
|
|
||||||
|
|
||||||
// GL_ARB_draw_buffers
|
|
||||||
void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs);
|
|
||||||
|
|
||||||
static qboolean GLimp_HaveExtension(const char *ext)
|
|
||||||
{
|
|
||||||
const char *ptr = Q_stristr( glConfig.extensions_string, ext );
|
|
||||||
if (ptr == NULL)
|
|
||||||
return qfalse;
|
|
||||||
ptr += strlen(ext);
|
|
||||||
return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string.
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLimp_InitExtraExtensions()
|
|
||||||
{
|
|
||||||
char *extension;
|
|
||||||
const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" };
|
|
||||||
|
|
||||||
// GL_EXT_draw_range_elements
|
|
||||||
extension = "GL_EXT_draw_range_elements";
|
|
||||||
glRefConfig.drawRangeElements = qfalse;
|
|
||||||
qglMultiDrawArraysEXT = NULL;
|
|
||||||
qglMultiDrawElementsEXT = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
qglDrawRangeElementsEXT = (void *) SDL_GL_GetProcAddress("glDrawRangeElementsEXT");
|
|
||||||
|
|
||||||
if ( r_ext_draw_range_elements->integer)
|
|
||||||
glRefConfig.drawRangeElements = qtrue;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.drawRangeElements], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_multi_draw_arrays
|
|
||||||
extension = "GL_EXT_multi_draw_arrays";
|
|
||||||
glRefConfig.multiDrawArrays = qfalse;
|
|
||||||
qglMultiDrawArraysEXT = NULL;
|
|
||||||
qglMultiDrawElementsEXT = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
qglMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawArraysEXT");
|
|
||||||
qglMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawElementsEXT");
|
|
||||||
|
|
||||||
if ( r_ext_multi_draw_arrays->integer )
|
|
||||||
glRefConfig.multiDrawArrays = qtrue;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.multiDrawArrays], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_vertex_program
|
|
||||||
//glRefConfig.vertexProgram = qfalse;
|
|
||||||
extension = "GL_ARB_vertex_program";
|
|
||||||
qglVertexAttrib4fARB = NULL;
|
|
||||||
qglVertexAttrib4fvARB = NULL;
|
|
||||||
qglVertexAttribPointerARB = NULL;
|
|
||||||
qglEnableVertexAttribArrayARB = NULL;
|
|
||||||
qglDisableVertexAttribArrayARB = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
qglVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fARB");
|
|
||||||
qglVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fvARB");
|
|
||||||
qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) SDL_GL_GetProcAddress("glVertexAttribPointerARB");
|
|
||||||
qglEnableVertexAttribArrayARB =
|
|
||||||
(PFNGLENABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArrayARB");
|
|
||||||
qglDisableVertexAttribArrayARB =
|
|
||||||
(PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArrayARB");
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[1], extension);
|
|
||||||
//glRefConfig.vertexProgram = qtrue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Error(ERR_FATAL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_vertex_buffer_object
|
|
||||||
//glRefConfig.vertexBufferObject = qfalse;
|
|
||||||
extension = "GL_ARB_vertex_buffer_object";
|
|
||||||
qglBindBufferARB = NULL;
|
|
||||||
qglDeleteBuffersARB = NULL;
|
|
||||||
qglGenBuffersARB = NULL;
|
|
||||||
qglIsBufferARB = NULL;
|
|
||||||
qglBufferDataARB = NULL;
|
|
||||||
qglBufferSubDataARB = NULL;
|
|
||||||
qglGetBufferSubDataARB = NULL;
|
|
||||||
qglGetBufferParameterivARB = NULL;
|
|
||||||
qglGetBufferPointervARB = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
qglBindBufferARB = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB");
|
|
||||||
qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB");
|
|
||||||
qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB");
|
|
||||||
qglIsBufferARB = (PFNGLISBUFFERARBPROC) SDL_GL_GetProcAddress("glIsBufferARB");
|
|
||||||
qglBufferDataARB = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB");
|
|
||||||
qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB");
|
|
||||||
qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glGetBufferSubDataARB");
|
|
||||||
qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetBufferParameterivARB");
|
|
||||||
qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) SDL_GL_GetProcAddress("glGetBufferPointervARB");
|
|
||||||
ri.Printf(PRINT_ALL, result[1], extension);
|
|
||||||
//glRefConfig.vertexBufferObject = qtrue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Error(ERR_FATAL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_shader_objects
|
|
||||||
extension = "GL_ARB_shader_objects";
|
|
||||||
//glRefConfig.shaderObjects = qfalse;
|
|
||||||
qglDeleteObjectARB = NULL;
|
|
||||||
qglGetHandleARB = NULL;
|
|
||||||
qglDetachObjectARB = NULL;
|
|
||||||
qglCreateShaderObjectARB = NULL;
|
|
||||||
qglShaderSourceARB = NULL;
|
|
||||||
qglCompileShaderARB = NULL;
|
|
||||||
qglCreateProgramObjectARB = NULL;
|
|
||||||
qglAttachObjectARB = NULL;
|
|
||||||
qglLinkProgramARB = NULL;
|
|
||||||
qglUseProgramObjectARB = NULL;
|
|
||||||
qglValidateProgramARB = NULL;
|
|
||||||
qglUniform1fARB = NULL;
|
|
||||||
qglUniform2fARB = NULL;
|
|
||||||
qglUniform3fARB = NULL;
|
|
||||||
qglUniform4fARB = NULL;
|
|
||||||
qglUniform1iARB = NULL;
|
|
||||||
qglUniform2iARB = NULL;
|
|
||||||
qglUniform3iARB = NULL;
|
|
||||||
qglUniform4iARB = NULL;
|
|
||||||
qglUniform1fvARB = NULL;
|
|
||||||
qglUniform2fvARB = NULL;
|
|
||||||
qglUniform3fvARB = NULL;
|
|
||||||
qglUniform4fvARB = NULL;
|
|
||||||
qglUniform2ivARB = NULL;
|
|
||||||
qglUniform3ivARB = NULL;
|
|
||||||
qglUniform4ivARB = NULL;
|
|
||||||
qglUniformMatrix2fvARB = NULL;
|
|
||||||
qglUniformMatrix3fvARB = NULL;
|
|
||||||
qglUniformMatrix4fvARB = NULL;
|
|
||||||
qglGetObjectParameterfvARB = NULL;
|
|
||||||
qglGetObjectParameterivARB = NULL;
|
|
||||||
qglGetInfoLogARB = NULL;
|
|
||||||
qglGetAttachedObjectsARB = NULL;
|
|
||||||
qglGetUniformLocationARB = NULL;
|
|
||||||
qglGetActiveUniformARB = NULL;
|
|
||||||
qglGetUniformfvARB = NULL;
|
|
||||||
qglGetUniformivARB = NULL;
|
|
||||||
qglGetShaderSourceARB = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
|
|
||||||
qglGetHandleARB = (PFNGLGETHANDLEARBPROC) SDL_GL_GetProcAddress("glGetHandleARB");
|
|
||||||
qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) SDL_GL_GetProcAddress("glDetachObjectARB");
|
|
||||||
qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
|
|
||||||
qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
|
|
||||||
qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
|
|
||||||
qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
|
|
||||||
qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
|
|
||||||
qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
|
|
||||||
qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
|
|
||||||
qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) SDL_GL_GetProcAddress("glValidateProgramARB");
|
|
||||||
qglUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
|
|
||||||
qglUniform2fARB = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB");
|
|
||||||
qglUniform3fARB = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB");
|
|
||||||
qglUniform4fARB = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB");
|
|
||||||
qglUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
|
|
||||||
qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB");
|
|
||||||
qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB");
|
|
||||||
qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB");
|
|
||||||
qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB");
|
|
||||||
qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB");
|
|
||||||
qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB");
|
|
||||||
qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB");
|
|
||||||
qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) SDL_GL_GetProcAddress("glUniform2ivARB");
|
|
||||||
qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) SDL_GL_GetProcAddress("glUniform3ivARB");
|
|
||||||
qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) SDL_GL_GetProcAddress("glUniform4ivARB");
|
|
||||||
qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix2fvARB");
|
|
||||||
qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix3fvARB");
|
|
||||||
qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix4fvARB");
|
|
||||||
qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterfvARB");
|
|
||||||
qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
|
|
||||||
qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
|
|
||||||
qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) SDL_GL_GetProcAddress("glGetAttachedObjectsARB");
|
|
||||||
qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
|
|
||||||
qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB");
|
|
||||||
qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) SDL_GL_GetProcAddress("glGetUniformfvARB");
|
|
||||||
qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) SDL_GL_GetProcAddress("glGetUniformivARB");
|
|
||||||
qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glGetShaderSourceARB");
|
|
||||||
ri.Printf(PRINT_ALL, result[1], extension);
|
|
||||||
//glRefConfig.shaderObjects = qtrue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Error(ERR_FATAL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_vertex_shader
|
|
||||||
//glRefConfig.vertexShader = qfalse;
|
|
||||||
extension = "GL_ARB_vertex_shader";
|
|
||||||
qglBindAttribLocationARB = NULL;
|
|
||||||
qglGetActiveAttribARB = NULL;
|
|
||||||
qglGetAttribLocationARB = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
//int reservedComponents;
|
|
||||||
|
|
||||||
//qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.maxVertexUniforms);
|
|
||||||
//qglGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats);
|
|
||||||
//qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.maxVertexAttribs);
|
|
||||||
|
|
||||||
//reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if(glConfig.driverType == GLDRV_MESA)
|
|
||||||
{
|
|
||||||
// HACK
|
|
||||||
// restrict to number of vertex uniforms to 512 because of:
|
|
||||||
// xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed
|
|
||||||
|
|
||||||
glConfig.maxVertexUniforms = Q_bound(0, glConfig.maxVertexUniforms, 512);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//glConfig.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES);
|
|
||||||
//glConfig.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig.maxVertexSkinningBones >= 12) ? qtrue : qfalse);
|
|
||||||
|
|
||||||
qglBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB");
|
|
||||||
qglGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) SDL_GL_GetProcAddress("glGetActiveAttribARB");
|
|
||||||
qglGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetAttribLocationARB");
|
|
||||||
ri.Printf(PRINT_ALL, result[1], extension);
|
|
||||||
//glRefConfig.vertexShader = qtrue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Error(ERR_FATAL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_shading_language_100
|
|
||||||
extension = "GL_ARB_shading_language_100";
|
|
||||||
glRefConfig.textureFloat = qfalse;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
char version[256];
|
|
||||||
|
|
||||||
Q_strncpyz( version, (char *) qglGetString (GL_SHADING_LANGUAGE_VERSION_ARB), sizeof( version ) );
|
|
||||||
|
|
||||||
sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Error(ERR_FATAL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
glRefConfig.memInfo = MI_NONE;
|
|
||||||
|
|
||||||
if( GLimp_HaveExtension( "GL_NVX_gpu_memory_info" ) )
|
|
||||||
{
|
|
||||||
glRefConfig.memInfo = MI_NVX;
|
|
||||||
}
|
|
||||||
else if( GLimp_HaveExtension( "GL_ATI_meminfo" ) )
|
|
||||||
{
|
|
||||||
glRefConfig.memInfo = MI_ATI;
|
|
||||||
}
|
|
||||||
|
|
||||||
extension = "GL_ARB_texture_non_power_of_two";
|
|
||||||
glRefConfig.textureNonPowerOfTwo = qfalse;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
if(1) //(r_ext_texture_non_power_of_two->integer)
|
|
||||||
{
|
|
||||||
glRefConfig.textureNonPowerOfTwo = qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.textureNonPowerOfTwo], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_texture_float
|
|
||||||
extension = "GL_ARB_texture_float";
|
|
||||||
glRefConfig.textureFloat = qfalse;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
if( r_ext_texture_float->integer )
|
|
||||||
{
|
|
||||||
glRefConfig.textureFloat = qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_half_float_pixel
|
|
||||||
extension = "GL_ARB_half_float_pixel";
|
|
||||||
glRefConfig.halfFloatPixel = qfalse;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
if( r_arb_half_float_pixel->integer )
|
|
||||||
glRefConfig.halfFloatPixel = qtrue;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.halfFloatPixel], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_object
|
|
||||||
extension = "GL_EXT_framebuffer_object";
|
|
||||||
glRefConfig.framebufferObject = qfalse;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glRefConfig.maxRenderbufferSize);
|
|
||||||
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glRefConfig.maxColorAttachments);
|
|
||||||
|
|
||||||
qglIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsRenderbufferEXT");
|
|
||||||
qglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindRenderbufferEXT");
|
|
||||||
qglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT");
|
|
||||||
qglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenRenderbuffersEXT");
|
|
||||||
qglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) SDL_GL_GetProcAddress("glRenderbufferStorageEXT");
|
|
||||||
qglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT");
|
|
||||||
qglIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsFramebufferEXT");
|
|
||||||
qglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindFramebufferEXT");
|
|
||||||
qglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
|
|
||||||
qglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenFramebuffersEXT");
|
|
||||||
qglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
|
|
||||||
qglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture1DEXT");
|
|
||||||
qglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
|
|
||||||
qglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture3DEXT");
|
|
||||||
qglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT");
|
|
||||||
qglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT");
|
|
||||||
qglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) SDL_GL_GetProcAddress("glGenerateMipmapEXT");
|
|
||||||
|
|
||||||
if(r_ext_framebuffer_object->value)
|
|
||||||
glRefConfig.framebufferObject = qtrue;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_packed_depth_stencil
|
|
||||||
extension = "GL_EXT_packed_depth_stencil";
|
|
||||||
glRefConfig.packedDepthStencil = qfalse;
|
|
||||||
if( GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
glRefConfig.packedDepthStencil = qtrue;
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.packedDepthStencil], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_occlusion_query
|
|
||||||
extension = "GL_ARB_occlusion_query";
|
|
||||||
glRefConfig.occlusionQuery = qfalse;
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
qglGenQueriesARB = (PFNGLGENQUERIESARBPROC) SDL_GL_GetProcAddress("glGenQueriesARB");
|
|
||||||
qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) SDL_GL_GetProcAddress("glDeleteQueriesARB");
|
|
||||||
qglIsQueryARB = (PFNGLISQUERYARBPROC) SDL_GL_GetProcAddress("glIsQueryARB");
|
|
||||||
qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC) SDL_GL_GetProcAddress("glBeginQueryARB");
|
|
||||||
qglEndQueryARB = (PFNGLENDQUERYARBPROC) SDL_GL_GetProcAddress("glEndQueryARB");
|
|
||||||
qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC) SDL_GL_GetProcAddress("glGetQueryivARB");
|
|
||||||
qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectivARB");
|
|
||||||
qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectuivARB");
|
|
||||||
glRefConfig.occlusionQuery = qtrue;
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_blit
|
|
||||||
extension = "GL_EXT_framebuffer_blit";
|
|
||||||
glRefConfig.framebufferBlit = qfalse;
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
qglBlitFramebufferEXT = (void *)SDL_GL_GetProcAddress("glBlitFramebufferEXT");
|
|
||||||
glRefConfig.framebufferBlit = qtrue;
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferBlit], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_multisample
|
|
||||||
extension = "GL_EXT_framebuffer_multisample";
|
|
||||||
glRefConfig.framebufferMultisample = qfalse;
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
qglRenderbufferStorageMultisampleEXT = (void *)SDL_GL_GetProcAddress("glRenderbufferStorageMultisampleEXT");
|
|
||||||
glRefConfig.framebufferMultisample = qtrue;
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferMultisample], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_texture_sRGB
|
|
||||||
extension = "GL_EXT_texture_sRGB";
|
|
||||||
glRefConfig.texture_srgb = qfalse;
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
if (r_srgb->integer)
|
|
||||||
glRefConfig.texture_srgb = qtrue;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.texture_srgb], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_EXT_framebuffer_sRGB
|
|
||||||
extension = "GL_EXT_framebuffer_sRGB";
|
|
||||||
glRefConfig.framebuffer_srgb = qfalse;
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
if (r_srgb->integer)
|
|
||||||
glRefConfig.framebuffer_srgb = qtrue;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebuffer_srgb], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
glRefConfig.textureCompression = TCR_NONE;
|
|
||||||
|
|
||||||
// GL_EXT_texture_compression_latc
|
|
||||||
extension = "GL_EXT_texture_compression_latc";
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
if (r_ext_compressed_textures->integer)
|
|
||||||
glRefConfig.textureCompression |= TCR_LATC;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_texture_compression_bptc
|
|
||||||
extension = "GL_ARB_texture_compression_bptc";
|
|
||||||
if (GLimp_HaveExtension(extension))
|
|
||||||
{
|
|
||||||
if (r_ext_compressed_textures->integer >= 2)
|
|
||||||
glRefConfig.textureCompression |= TCR_BPTC;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[(r_ext_compressed_textures->integer >= 2) ? 1 : 0], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_draw_buffers
|
|
||||||
extension = "GL_ARB_draw_buffers";
|
|
||||||
qglDrawBuffersARB = NULL;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
qglDrawBuffersARB = (void *) SDL_GL_GetProcAddress("glDrawBuffersARB");
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, result[1], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL_ARB_depth_clamp
|
|
||||||
extension = "GL_ARB_depth_clamp";
|
|
||||||
glRefConfig.depthClamp = qfalse;
|
|
||||||
if( GLimp_HaveExtension( extension ) )
|
|
||||||
{
|
|
||||||
glRefConfig.depthClamp = qtrue;
|
|
||||||
ri.Printf(PRINT_ALL, result[1], extension);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,240 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
|
||||||
|
|
||||||
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 Quake III Arena source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_extramath.c - extra math needed by the renderer not in qmath.c
|
|
||||||
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
// Some matrix helper functions
|
|
||||||
// FIXME: do these already exist in ioq3 and I don't know about them?
|
|
||||||
|
|
||||||
void Matrix16Zero( matrix_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f;
|
|
||||||
out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f;
|
|
||||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 0.0f; out[14] = 0.0f;
|
|
||||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Identity( matrix_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f;
|
|
||||||
out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f;
|
|
||||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = 0.0f;
|
|
||||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Copy( const matrix_t in, matrix_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12];
|
|
||||||
out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13];
|
|
||||||
out[ 2] = in[ 2]; out[ 6] = in[ 6]; out[10] = in[10]; out[14] = in[14];
|
|
||||||
out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3];
|
|
||||||
out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3];
|
|
||||||
out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3];
|
|
||||||
out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3];
|
|
||||||
|
|
||||||
out[ 4] = in1[ 0] * in2[ 4] + in1[ 4] * in2[ 5] + in1[ 8] * in2[ 6] + in1[12] * in2[ 7];
|
|
||||||
out[ 5] = in1[ 1] * in2[ 4] + in1[ 5] * in2[ 5] + in1[ 9] * in2[ 6] + in1[13] * in2[ 7];
|
|
||||||
out[ 6] = in1[ 2] * in2[ 4] + in1[ 6] * in2[ 5] + in1[10] * in2[ 6] + in1[14] * in2[ 7];
|
|
||||||
out[ 7] = in1[ 3] * in2[ 4] + in1[ 7] * in2[ 5] + in1[11] * in2[ 6] + in1[15] * in2[ 7];
|
|
||||||
|
|
||||||
out[ 8] = in1[ 0] * in2[ 8] + in1[ 4] * in2[ 9] + in1[ 8] * in2[10] + in1[12] * in2[11];
|
|
||||||
out[ 9] = in1[ 1] * in2[ 8] + in1[ 5] * in2[ 9] + in1[ 9] * in2[10] + in1[13] * in2[11];
|
|
||||||
out[10] = in1[ 2] * in2[ 8] + in1[ 6] * in2[ 9] + in1[10] * in2[10] + in1[14] * in2[11];
|
|
||||||
out[11] = in1[ 3] * in2[ 8] + in1[ 7] * in2[ 9] + in1[11] * in2[10] + in1[15] * in2[11];
|
|
||||||
|
|
||||||
out[12] = in1[ 0] * in2[12] + in1[ 4] * in2[13] + in1[ 8] * in2[14] + in1[12] * in2[15];
|
|
||||||
out[13] = in1[ 1] * in2[12] + in1[ 5] * in2[13] + in1[ 9] * in2[14] + in1[13] * in2[15];
|
|
||||||
out[14] = in1[ 2] * in2[12] + in1[ 6] * in2[13] + in1[10] * in2[14] + in1[14] * in2[15];
|
|
||||||
out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3];
|
|
||||||
out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3];
|
|
||||||
out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3];
|
|
||||||
out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
qboolean Matrix16Compare( const matrix_t a, const matrix_t b )
|
|
||||||
{
|
|
||||||
return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] ||
|
|
||||||
a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] ||
|
|
||||||
a[ 2] != b[ 2] || a[ 6] != b[ 6] || a[10] != b[10] || a[14] != b[14] ||
|
|
||||||
a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Dump( const matrix_t in )
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]);
|
|
||||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]);
|
|
||||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]);
|
|
||||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Translation( vec3_t vec, matrix_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0];
|
|
||||||
out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1];
|
|
||||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = vec[2];
|
|
||||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out )
|
|
||||||
{
|
|
||||||
out[ 0] = 2.0f / (right - left); out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = -(right + left) / (right - left);
|
|
||||||
out[ 1] = 0.0f; out[ 5] = 2.0f / (top - bottom); out[ 9] = 0.0f; out[13] = -(top + bottom) / (top - bottom);
|
|
||||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 2.0f / (zfar - znear); out[14] = -(zfar + znear) / (zfar - znear);
|
|
||||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out)
|
|
||||||
{
|
|
||||||
out[0] = axes[0][0];
|
|
||||||
out[1] = axes[1][0];
|
|
||||||
out[2] = axes[2][0];
|
|
||||||
out[3] = 0;
|
|
||||||
|
|
||||||
out[4] = axes[0][1];
|
|
||||||
out[5] = axes[1][1];
|
|
||||||
out[6] = axes[2][1];
|
|
||||||
out[7] = 0;
|
|
||||||
|
|
||||||
out[8] = axes[0][2];
|
|
||||||
out[9] = axes[1][2];
|
|
||||||
out[10] = axes[2][2];
|
|
||||||
out[11] = 0;
|
|
||||||
|
|
||||||
out[12] = -DotProduct(origin, axes[0]);
|
|
||||||
out[13] = -DotProduct(origin, axes[1]);
|
|
||||||
out[14] = -DotProduct(origin, axes[2]);
|
|
||||||
out[15] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix16SimpleInverse( const matrix_t in, matrix_t out)
|
|
||||||
{
|
|
||||||
vec3_t v;
|
|
||||||
float invSqrLen;
|
|
||||||
|
|
||||||
VectorCopy(in + 0, v);
|
|
||||||
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
|
|
||||||
out[ 0] = v[0]; out[ 4] = v[1]; out[ 8] = v[2]; out[12] = -DotProduct(v, &in[12]);
|
|
||||||
|
|
||||||
VectorCopy(in + 4, v);
|
|
||||||
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
|
|
||||||
out[ 1] = v[0]; out[ 5] = v[1]; out[ 9] = v[2]; out[13] = -DotProduct(v, &in[12]);
|
|
||||||
|
|
||||||
VectorCopy(in + 8, v);
|
|
||||||
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
|
|
||||||
out[ 2] = v[0]; out[ 6] = v[1]; out[10] = v[2]; out[14] = -DotProduct(v, &in[12]);
|
|
||||||
|
|
||||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c)
|
|
||||||
{
|
|
||||||
c[0] = a[0] * (1.0f - lerp) + b[0] * lerp;
|
|
||||||
c[1] = a[1] * (1.0f - lerp) + b[1] * lerp;
|
|
||||||
c[2] = a[2] * (1.0f - lerp) + b[2] * lerp;
|
|
||||||
}
|
|
||||||
|
|
||||||
qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2)
|
|
||||||
{
|
|
||||||
float radiusSum = radius1 + radius2;
|
|
||||||
vec3_t diff;
|
|
||||||
|
|
||||||
VectorSubtract(origin1, origin2, diff);
|
|
||||||
|
|
||||||
if (DotProduct(diff, diff) <= radiusSum * radiusSum)
|
|
||||||
{
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3)
|
|
||||||
{
|
|
||||||
vec3_t diff;
|
|
||||||
|
|
||||||
VectorScale(origin1, 0.5f, origin3);
|
|
||||||
VectorMA(origin3, 0.5f, origin2, origin3);
|
|
||||||
|
|
||||||
VectorSubtract(origin1, origin2, diff);
|
|
||||||
*radius3 = VectorLength(diff) * 0.5f + MAX(radius1, radius2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int NextPowerOfTwo(int in)
|
|
||||||
{
|
|
||||||
int out;
|
|
||||||
|
|
||||||
for (out = 1; out < in; out <<= 1)
|
|
||||||
;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short FloatToHalf(float in)
|
|
||||||
{
|
|
||||||
unsigned short out;
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
float f;
|
|
||||||
unsigned int i;
|
|
||||||
} f32;
|
|
||||||
|
|
||||||
int sign, inExponent, inFraction;
|
|
||||||
int outExponent, outFraction;
|
|
||||||
|
|
||||||
f32.f = in;
|
|
||||||
|
|
||||||
sign = (f32.i & 0x80000000) >> 31;
|
|
||||||
inExponent = (f32.i & 0x7F800000) >> 23;
|
|
||||||
inFraction = f32.i & 0x007FFFFF;
|
|
||||||
|
|
||||||
outExponent = CLAMP(inExponent - 127, -15, 16) + 15;
|
|
||||||
|
|
||||||
outFraction = 0;
|
|
||||||
if (outExponent == 0x1F)
|
|
||||||
{
|
|
||||||
if (inExponent == 0xFF && inFraction != 0)
|
|
||||||
outFraction = 0x3FF;
|
|
||||||
}
|
|
||||||
else if (outExponent == 0x00)
|
|
||||||
{
|
|
||||||
if (inExponent == 0x00 && inFraction != 0)
|
|
||||||
outFraction = 0x3FF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
outFraction = inFraction >> 13;
|
|
||||||
|
|
||||||
out = (sign << 15) | (outExponent << 10) | outFraction;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
|
||||||
|
|
||||||
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 Quake III Arena source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_extramath.h
|
|
||||||
|
|
||||||
#ifndef __TR_EXTRAMATH_H__
|
|
||||||
#define __TR_EXTRAMATH_H__
|
|
||||||
|
|
||||||
typedef vec_t matrix_t[16];
|
|
||||||
typedef int vec2i_t[2];
|
|
||||||
typedef int vec3i_t[3];
|
|
||||||
typedef int vec4i_t[4];
|
|
||||||
|
|
||||||
void Matrix16Zero( matrix_t out );
|
|
||||||
void Matrix16Identity( matrix_t out );
|
|
||||||
void Matrix16Copy( const matrix_t in, matrix_t out );
|
|
||||||
void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out );
|
|
||||||
void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out );
|
|
||||||
qboolean Matrix16Compare(const matrix_t a, const matrix_t b);
|
|
||||||
void Matrix16Dump( const matrix_t in );
|
|
||||||
void Matrix16Translation( vec3_t vec, matrix_t out );
|
|
||||||
void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out );
|
|
||||||
void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out);
|
|
||||||
void Matrix16SimpleInverse( const matrix_t in, matrix_t out);
|
|
||||||
|
|
||||||
#define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
|
|
||||||
|
|
||||||
#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
|
|
||||||
#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w))
|
|
||||||
#define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3])
|
|
||||||
#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b))
|
|
||||||
|
|
||||||
#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4])
|
|
||||||
|
|
||||||
#define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f)
|
|
||||||
#define FloatToOffsetByte(a) (byte)(((a) + 1.0f) * 127.5f)
|
|
||||||
#define ByteToFloat(a) ((float)(a) * 1.0f/255.0f)
|
|
||||||
#define FloatToByte(a) (byte)((a) * 255.0f)
|
|
||||||
|
|
||||||
#define RGBtosRGB(a) (((a) < 0.0031308f) ? (12.92f * (a)) : (1.055f * pow((a), 0.41666f) - 0.055f))
|
|
||||||
#define sRGBtoRGB(a) (((a) <= 0.04045f) ? ((a) / 12.92f) : (pow((((a) + 0.055f) / 1.055f), 2.4)) )
|
|
||||||
|
|
||||||
static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2)
|
|
||||||
{
|
|
||||||
if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3])
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2)
|
|
||||||
{
|
|
||||||
if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4])
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c);
|
|
||||||
|
|
||||||
|
|
||||||
qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2);
|
|
||||||
void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3);
|
|
||||||
|
|
||||||
#ifndef SGN
|
|
||||||
#define SGN(x) (((x) >= 0) ? !!(x) : -1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MAX
|
|
||||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CLAMP
|
|
||||||
#define CLAMP(a,b,c) MIN(MAX((a),(b)),(c))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int NextPowerOfTwo(int in);
|
|
||||||
unsigned short FloatToHalf(float in);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2009-2011 Andrei Drexler, Richard Allen, James Canete
|
|
||||||
|
|
||||||
This file is part of Reaction source code.
|
|
||||||
|
|
||||||
Reaction 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.
|
|
||||||
|
|
||||||
Reaction 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 Reaction source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __TR_EXTRATYPES_H__
|
|
||||||
#define __TR_EXTRATYPES_H__
|
|
||||||
|
|
||||||
// tr_extratypes.h, for mods that want to extend tr_types.h without losing compatibility with original VMs
|
|
||||||
|
|
||||||
// extra renderfx flags start at 0x0400
|
|
||||||
#define RF_SUNFLARE 0x0400
|
|
||||||
|
|
||||||
// extra refdef flags start at 0x0008
|
|
||||||
#define RDF_NOFOG 0x0008 // don't apply fog
|
|
||||||
#define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t
|
|
||||||
#define RDF_SUNLIGHT 0x0020 // SmileTheory - render sunlight and shadows
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float blurFactor;
|
|
||||||
float sunDir[3];
|
|
||||||
float sunCol[3];
|
|
||||||
float sunAmbCol[3];
|
|
||||||
} refdefex_t;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,822 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2006 Kirk Barnes
|
|
||||||
Copyright (C) 2006-2008 Robert Beckebans <trebor_7@users.sourceforge.net>
|
|
||||||
|
|
||||||
This file is part of XreaL source code.
|
|
||||||
|
|
||||||
XreaL 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.
|
|
||||||
|
|
||||||
XreaL 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 XreaL source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_fbo.c
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
R_CheckFBO
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
qboolean R_CheckFBO(const FBO_t * fbo)
|
|
||||||
{
|
|
||||||
int code;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id);
|
|
||||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
|
|
||||||
|
|
||||||
code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
|
||||||
|
|
||||||
if(code == GL_FRAMEBUFFER_COMPLETE_EXT)
|
|
||||||
{
|
|
||||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// an error occured
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
|
|
||||||
// ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, duplicate attachment\n", fbo->name);
|
|
||||||
// break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same dimensions\n",
|
|
||||||
fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same format\n",
|
|
||||||
fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code);
|
|
||||||
//ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code);
|
|
||||||
//assert(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
|
|
||||||
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
FBO_Create
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
FBO_t *FBO_Create(const char *name, int width, int height)
|
|
||||||
{
|
|
||||||
FBO_t *fbo;
|
|
||||||
|
|
||||||
if(strlen(name) >= MAX_QPATH)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(width <= 0 || width > glRefConfig.maxRenderbufferSize)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "FBO_Create: bad width %i", width);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(height <= 0 || height > glRefConfig.maxRenderbufferSize)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "FBO_Create: bad height %i", height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(tr.numFBOs == MAX_FBOS)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "FBO_Create: MAX_FBOS hit");
|
|
||||||
}
|
|
||||||
|
|
||||||
fbo = tr.fbos[tr.numFBOs] = ri.Hunk_Alloc(sizeof(*fbo), h_low);
|
|
||||||
Q_strncpyz(fbo->name, name, sizeof(fbo->name));
|
|
||||||
fbo->index = tr.numFBOs++;
|
|
||||||
fbo->width = width;
|
|
||||||
fbo->height = height;
|
|
||||||
|
|
||||||
qglGenFramebuffersEXT(1, &fbo->frameBuffer);
|
|
||||||
|
|
||||||
return fbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
|
|
||||||
{
|
|
||||||
uint32_t *pRenderBuffer;
|
|
||||||
GLenum attachment;
|
|
||||||
qboolean absent;
|
|
||||||
|
|
||||||
switch(format)
|
|
||||||
{
|
|
||||||
case GL_RGB:
|
|
||||||
case GL_RGBA:
|
|
||||||
case GL_RGB8:
|
|
||||||
case GL_RGBA8:
|
|
||||||
case GL_RGB16F_ARB:
|
|
||||||
case GL_RGBA16F_ARB:
|
|
||||||
case GL_RGB32F_ARB:
|
|
||||||
case GL_RGBA32F_ARB:
|
|
||||||
fbo->colorFormat = format;
|
|
||||||
pRenderBuffer = &fbo->colorBuffers[index];
|
|
||||||
attachment = GL_COLOR_ATTACHMENT0_EXT + index;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_DEPTH_COMPONENT:
|
|
||||||
case GL_DEPTH_COMPONENT16_ARB:
|
|
||||||
case GL_DEPTH_COMPONENT24_ARB:
|
|
||||||
case GL_DEPTH_COMPONENT32_ARB:
|
|
||||||
fbo->depthFormat = format;
|
|
||||||
pRenderBuffer = &fbo->depthBuffer;
|
|
||||||
attachment = GL_DEPTH_ATTACHMENT_EXT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_STENCIL_INDEX:
|
|
||||||
case GL_STENCIL_INDEX1_EXT:
|
|
||||||
case GL_STENCIL_INDEX4_EXT:
|
|
||||||
case GL_STENCIL_INDEX8_EXT:
|
|
||||||
case GL_STENCIL_INDEX16_EXT:
|
|
||||||
fbo->stencilFormat = format;
|
|
||||||
pRenderBuffer = &fbo->stencilBuffer;
|
|
||||||
attachment = GL_STENCIL_ATTACHMENT_EXT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GL_DEPTH_STENCIL_EXT:
|
|
||||||
case GL_DEPTH24_STENCIL8_EXT:
|
|
||||||
fbo->packedDepthStencilFormat = format;
|
|
||||||
pRenderBuffer = &fbo->packedDepthStencilBuffer;
|
|
||||||
attachment = 0; // special for stencil and depth
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ri.Printf(PRINT_WARNING, "FBO_CreateBuffer: invalid format %d\n", format);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
absent = *pRenderBuffer == 0;
|
|
||||||
if (absent)
|
|
||||||
qglGenRenderbuffersEXT(1, pRenderBuffer);
|
|
||||||
|
|
||||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
|
||||||
if (multisample && glRefConfig.framebufferMultisample)
|
|
||||||
{
|
|
||||||
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(absent)
|
|
||||||
{
|
|
||||||
if (attachment == 0)
|
|
||||||
{
|
|
||||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
|
||||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_AttachFBOTexture1D
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void R_AttachFBOTexture1D(int texId, int index)
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= glRefConfig.maxColorAttachments)
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_AttachFBOTexture2D
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void R_AttachFBOTexture2D(int target, int texId, int index)
|
|
||||||
{
|
|
||||||
if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB))
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(index < 0 || index >= glRefConfig.maxColorAttachments)
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_AttachFBOTexture3D
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void R_AttachFBOTexture3D(int texId, int index, int zOffset)
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= glRefConfig.maxColorAttachments)
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_AttachFBOTextureDepth
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void R_AttachFBOTextureDepth(int texId)
|
|
||||||
{
|
|
||||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_AttachFBOTexturePackedDepthStencil
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void R_AttachFBOTexturePackedDepthStencil(int texId)
|
|
||||||
{
|
|
||||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
|
|
||||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FBO_AttachTextureImage(image_t *img, int index)
|
|
||||||
{
|
|
||||||
if (!glState.currentFBO)
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index);
|
|
||||||
glState.currentFBO->colorImage[index] = img;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
FBO_Bind
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void FBO_Bind(FBO_t * fbo)
|
|
||||||
{
|
|
||||||
if (fbo && glState.currentFBO == fbo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (r_logFile->integer)
|
|
||||||
{
|
|
||||||
// don't just call LogComment, or we will get a call to va() every frame!
|
|
||||||
if (fbo)
|
|
||||||
GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name));
|
|
||||||
else
|
|
||||||
GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fbo)
|
|
||||||
{
|
|
||||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
//qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
|
||||||
glState.currentFBO = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(fbo->colorBuffers[0])
|
|
||||||
{
|
|
||||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(fbo->depthBuffer)
|
|
||||||
{
|
|
||||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer);
|
|
||||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
glState.currentFBO = fbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
FBO_Init
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void FBO_Init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
// int width, height, hdrFormat, multisample;
|
|
||||||
int hdrFormat, multisample;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
|
|
||||||
|
|
||||||
if(!glRefConfig.framebufferObject)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tr.numFBOs = 0;
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
|
|
||||||
// make sure the render thread is stopped
|
|
||||||
R_SyncRenderThread();
|
|
||||||
|
|
||||||
/* if(glRefConfig.textureNonPowerOfTwo)
|
|
||||||
{
|
|
||||||
width = glConfig.vidWidth;
|
|
||||||
height = glConfig.vidHeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
width = NextPowerOfTwo(glConfig.vidWidth);
|
|
||||||
height = NextPowerOfTwo(glConfig.vidHeight);
|
|
||||||
} */
|
|
||||||
|
|
||||||
hdrFormat = GL_RGBA8;
|
|
||||||
if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
|
|
||||||
{
|
|
||||||
hdrFormat = GL_RGB16F_ARB;
|
|
||||||
}
|
|
||||||
|
|
||||||
qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample);
|
|
||||||
|
|
||||||
if (r_ext_framebuffer_multisample->integer < multisample)
|
|
||||||
{
|
|
||||||
multisample = r_ext_framebuffer_multisample->integer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multisample < 2 || !glRefConfig.framebufferBlit)
|
|
||||||
multisample = 0;
|
|
||||||
|
|
||||||
if (multisample != r_ext_framebuffer_multisample->integer)
|
|
||||||
{
|
|
||||||
ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multisample && glRefConfig.framebufferMultisample)
|
|
||||||
{
|
|
||||||
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
|
||||||
FBO_Bind(tr.renderFbo);
|
|
||||||
|
|
||||||
FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
|
|
||||||
FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.renderFbo);
|
|
||||||
|
|
||||||
|
|
||||||
tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
|
||||||
FBO_Bind(tr.msaaResolveFbo);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.renderImage, 0);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
|
||||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.msaaResolveFbo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
|
||||||
FBO_Bind(tr.renderFbo);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.renderImage, 0);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
|
||||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.renderFbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear render buffer
|
|
||||||
// this fixes the corrupt screen bug with r_hdr 1 on older hardware
|
|
||||||
FBO_Bind(tr.renderFbo);
|
|
||||||
qglClearColor( 1, 0, 0.5, 1 );
|
|
||||||
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
|
||||||
FBO_Bind(NULL);
|
|
||||||
|
|
||||||
#ifdef REACTION
|
|
||||||
{
|
|
||||||
tr.godRaysFbo = FBO_Create("_godRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
|
||||||
FBO_Bind(tr.godRaysFbo);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.godRaysFbo, GL_RGBA8, 0, multisample);
|
|
||||||
FBO_AttachTextureImage(tr.godRaysImage, 0);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.godRaysFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);
|
|
||||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.godRaysFbo);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// FIXME: Don't use separate color/depth buffers for a shadow buffer
|
|
||||||
for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
|
|
||||||
{
|
|
||||||
tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
|
|
||||||
FBO_Bind(tr.pshadowFbos[i]);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.pshadowMaps[i], 0);
|
|
||||||
|
|
||||||
FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
|
||||||
//R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.pshadowFbos[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
|
|
||||||
FBO_Bind(tr.sunShadowFbo[i]);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
|
|
||||||
//FBO_AttachTextureImage(tr.sunShadowImage, 0);
|
|
||||||
qglDrawBuffer(GL_NONE);
|
|
||||||
qglReadBuffer(GL_NONE);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
|
||||||
R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.sunShadowFbo[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
|
|
||||||
FBO_Bind(tr.textureScratchFbo[i]);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.textureScratchImage[i], 0);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.textureScratchFbo[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
|
|
||||||
FBO_Bind(tr.calcLevelsFbo);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.calcLevelsImage, 0);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.calcLevelsFbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
|
|
||||||
FBO_Bind(tr.targetLevelsFbo);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.targetLevelsImage, 0);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.targetLevelsFbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
//tr.screenScratchFbo = FBO_Create("_screenscratch", width, height);
|
|
||||||
tr.screenScratchFbo = FBO_Create("_screenscratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
|
|
||||||
FBO_Bind(tr.screenScratchFbo);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.screenScratchFbo, format, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.screenScratchImage, 0);
|
|
||||||
|
|
||||||
// FIXME: hack: share zbuffer between render fbo and pre-screen fbo
|
|
||||||
//FBO_CreateBuffer(tr.screenScratchFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
|
||||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.screenScratchFbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
|
|
||||||
FBO_Bind(tr.quarterFbo[i]);
|
|
||||||
|
|
||||||
//FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0);
|
|
||||||
FBO_AttachTextureImage(tr.quarterImage[i], 0);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.quarterFbo[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
|
|
||||||
FBO_Bind(tr.screenShadowFbo);
|
|
||||||
|
|
||||||
FBO_AttachTextureImage(tr.screenShadowImage, 0);
|
|
||||||
|
|
||||||
R_CheckFBO(tr.screenShadowFbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
|
|
||||||
FBO_Bind(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
FBO_Shutdown
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void FBO_Shutdown(void)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
FBO_t *fbo;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "------- FBO_Shutdown -------\n");
|
|
||||||
|
|
||||||
if(!glRefConfig.framebufferObject)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FBO_Bind(NULL);
|
|
||||||
|
|
||||||
for(i = 0; i < tr.numFBOs; i++)
|
|
||||||
{
|
|
||||||
fbo = tr.fbos[i];
|
|
||||||
|
|
||||||
for(j = 0; j < glRefConfig.maxColorAttachments; j++)
|
|
||||||
{
|
|
||||||
if(fbo->colorBuffers[j])
|
|
||||||
qglDeleteRenderbuffersEXT(1, &fbo->colorBuffers[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fbo->depthBuffer)
|
|
||||||
qglDeleteRenderbuffersEXT(1, &fbo->depthBuffer);
|
|
||||||
|
|
||||||
if(fbo->stencilBuffer)
|
|
||||||
qglDeleteRenderbuffersEXT(1, &fbo->stencilBuffer);
|
|
||||||
|
|
||||||
if(fbo->frameBuffer)
|
|
||||||
qglDeleteFramebuffersEXT(1, &fbo->frameBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_FBOList_f
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_FBOList_f(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
FBO_t *fbo;
|
|
||||||
|
|
||||||
if(!glRefConfig.framebufferObject)
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, "GL_EXT_framebuffer_object is not available.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, " size name\n");
|
|
||||||
ri.Printf(PRINT_ALL, "----------------------------------------------------------\n");
|
|
||||||
|
|
||||||
for(i = 0; i < tr.numFBOs; i++)
|
|
||||||
{
|
|
||||||
fbo = tr.fbos[i];
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, " %4i: %4i %4i %s\n", i, fbo->width, fbo->height, fbo->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
extern void RB_SetGL2D (void);
|
|
||||||
|
|
||||||
void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, vec4i_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend)
|
|
||||||
{
|
|
||||||
vec4i_t dstBox, srcBox;
|
|
||||||
vec2_t srcTexScale;
|
|
||||||
vec4_t color;
|
|
||||||
vec4_t quadVerts[4];
|
|
||||||
vec2_t texCoords[4];
|
|
||||||
vec2_t invTexRes;
|
|
||||||
|
|
||||||
if (!src)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (inSrcBox)
|
|
||||||
{
|
|
||||||
VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(srcBox, 0, 0, src->width, src->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// framebuffers are 0 bottom, Y up.
|
|
||||||
if (inDstBox)
|
|
||||||
{
|
|
||||||
if (dst)
|
|
||||||
{
|
|
||||||
dstBox[0] = inDstBox[0];
|
|
||||||
dstBox[1] = dst->height - inDstBox[1] - inDstBox[3];
|
|
||||||
dstBox[2] = inDstBox[0] + inDstBox[2];
|
|
||||||
dstBox[3] = dst->height - inDstBox[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstBox[0] = inDstBox[0];
|
|
||||||
dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3];
|
|
||||||
dstBox[2] = inDstBox[0] + inDstBox[2];
|
|
||||||
dstBox[3] = glConfig.vidHeight - inDstBox[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dst)
|
|
||||||
{
|
|
||||||
VectorSet4(dstBox, 0, dst->height, dst->width, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inSrcTexScale)
|
|
||||||
{
|
|
||||||
VectorCopy2(inSrcTexScale, srcTexScale);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcTexScale[0] = srcTexScale[1] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inColor)
|
|
||||||
{
|
|
||||||
VectorCopy4(inColor, color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
color[0] = color[1] = color[2] = color[3] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!shaderProgram)
|
|
||||||
{
|
|
||||||
shaderProgram = &tr.textureColorShader;
|
|
||||||
}
|
|
||||||
|
|
||||||
FBO_Bind(dst);
|
|
||||||
|
|
||||||
RB_SetGL2D();
|
|
||||||
|
|
||||||
GL_SelectTexture(TB_COLORMAP);
|
|
||||||
|
|
||||||
GL_Bind(src);
|
|
||||||
|
|
||||||
VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1);
|
|
||||||
VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1);
|
|
||||||
VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1);
|
|
||||||
VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1);
|
|
||||||
|
|
||||||
texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height;
|
|
||||||
texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height;
|
|
||||||
texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height;
|
|
||||||
texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height;
|
|
||||||
|
|
||||||
invTexRes[0] = 1.0f / src->width * srcTexScale[0];
|
|
||||||
invTexRes[1] = 1.0f / src->height * srcTexScale[1];
|
|
||||||
|
|
||||||
GL_State( blend );
|
|
||||||
|
|
||||||
GLSL_BindProgram(shaderProgram);
|
|
||||||
|
|
||||||
GLSL_SetUniformMatrix16(shaderProgram, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
||||||
GLSL_SetUniformVec4(shaderProgram, TEXTURECOLOR_UNIFORM_COLOR, color);
|
|
||||||
GLSL_SetUniformVec2(shaderProgram, TEXTURECOLOR_UNIFORM_INVTEXRES, invTexRes);
|
|
||||||
GLSL_SetUniformVec2(shaderProgram, TEXTURECOLOR_UNIFORM_AUTOEXPOSUREMINMAX, tr.autoExposureMinMax);
|
|
||||||
|
|
||||||
RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FBO_Blit(FBO_t *src, vec4i_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend)
|
|
||||||
{
|
|
||||||
vec4i_t srcBox;
|
|
||||||
|
|
||||||
if (!src)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// framebuffers are 0 bottom, Y up.
|
|
||||||
if (inSrcBox)
|
|
||||||
{
|
|
||||||
srcBox[0] = inSrcBox[0];
|
|
||||||
srcBox[1] = src->height - inSrcBox[1] - inSrcBox[3];
|
|
||||||
srcBox[2] = inSrcBox[2];
|
|
||||||
srcBox[3] = inSrcBox[3];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(srcBox, 0, src->height, src->width, -src->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int buffers, int filter)
|
|
||||||
{
|
|
||||||
vec4i_t srcBoxFinal, dstBoxFinal;
|
|
||||||
GLuint srcFb, dstFb;
|
|
||||||
|
|
||||||
if (!glRefConfig.framebufferBlit)
|
|
||||||
{
|
|
||||||
FBO_Blit(src, srcBox, NULL, dst, dstBox, NULL, NULL, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get to a neutral state first
|
|
||||||
FBO_Bind(NULL);
|
|
||||||
|
|
||||||
srcFb = src ? src->frameBuffer : 0;
|
|
||||||
dstFb = dst ? dst->frameBuffer : 0;
|
|
||||||
|
|
||||||
if (!srcBox)
|
|
||||||
{
|
|
||||||
if (src)
|
|
||||||
{
|
|
||||||
VectorSet4(srcBoxFinal, 0, 0, src->width, src->height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(srcBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(srcBoxFinal, srcBox[0], srcBox[1], srcBox[0] + srcBox[2], srcBox[1] + srcBox[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dstBox)
|
|
||||||
{
|
|
||||||
if (dst)
|
|
||||||
{
|
|
||||||
VectorSet4(dstBoxFinal, 0, 0, dst->width, dst->height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(dstBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb);
|
|
||||||
qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
|
|
||||||
qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
|
|
||||||
dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
|
|
||||||
buffers, filter);
|
|
||||||
|
|
||||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
glState.currentFBO = NULL;
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
|
||||||
|
|
||||||
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 Quake III Arena source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_fbo.h
|
|
||||||
|
|
||||||
#ifndef __TR_FBO_H__
|
|
||||||
#define __TR_FBO_H__
|
|
||||||
|
|
||||||
struct image_s;
|
|
||||||
struct shaderProgram_s;
|
|
||||||
|
|
||||||
typedef struct FBO_s
|
|
||||||
{
|
|
||||||
char name[MAX_QPATH];
|
|
||||||
|
|
||||||
int index;
|
|
||||||
|
|
||||||
uint32_t frameBuffer;
|
|
||||||
|
|
||||||
uint32_t colorBuffers[16];
|
|
||||||
int colorFormat;
|
|
||||||
struct image_s *colorImage[16];
|
|
||||||
|
|
||||||
uint32_t depthBuffer;
|
|
||||||
int depthFormat;
|
|
||||||
|
|
||||||
uint32_t stencilBuffer;
|
|
||||||
int stencilFormat;
|
|
||||||
|
|
||||||
uint32_t packedDepthStencilBuffer;
|
|
||||||
int packedDepthStencilFormat;
|
|
||||||
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
} FBO_t;
|
|
||||||
|
|
||||||
void FBO_Bind(FBO_t *fbo);
|
|
||||||
void FBO_Init(void);
|
|
||||||
void FBO_Shutdown(void);
|
|
||||||
|
|
||||||
void FBO_BlitFromTexture(struct image_s *src, vec4i_t srcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend);
|
|
||||||
void FBO_Blit(FBO_t *src, vec4i_t srcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend);
|
|
||||||
void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int buffers, int filter);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,532 +0,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 Quake III Arena source code; 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 its 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 origin;
|
|
||||||
vec3_t color;
|
|
||||||
} flare_t;
|
|
||||||
|
|
||||||
#define MAX_FLARES 128
|
|
||||||
|
|
||||||
flare_t r_flareStructs[MAX_FLARES];
|
|
||||||
flare_t *r_activeFlares, *r_inactiveFlares;
|
|
||||||
|
|
||||||
int flareCoeff;
|
|
||||||
|
|
||||||
/*
|
|
||||||
==================
|
|
||||||
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;
|
|
||||||
vec3_t local;
|
|
||||||
float d = 1;
|
|
||||||
vec4_t eye, clip, normalized, window;
|
|
||||||
|
|
||||||
backEnd.pc.c_flareAdds++;
|
|
||||||
|
|
||||||
if(normal && (normal[0] || normal[1] || normal[2]))
|
|
||||||
{
|
|
||||||
VectorSubtract( backEnd.viewParms.or.origin, point, local );
|
|
||||||
VectorNormalizeFast(local);
|
|
||||||
d = DotProduct(local, normal);
|
|
||||||
|
|
||||||
// If the viewer is behind the flare don't add it.
|
|
||||||
if(d < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
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(point, f->origin);
|
|
||||||
VectorCopy( color, f->color );
|
|
||||||
|
|
||||||
// fade the intensity of the flare down as the
|
|
||||||
// light surface turns away from the viewer
|
|
||||||
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 = NULL;
|
|
||||||
|
|
||||||
if ( !r_flares->integer ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
l = backEnd.refdef.dlights;
|
|
||||||
|
|
||||||
if(tr.world)
|
|
||||||
fog = tr.world->fogs;
|
|
||||||
|
|
||||||
for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
|
|
||||||
|
|
||||||
if(fog)
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
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];
|
|
||||||
float distance, intensity, factor;
|
|
||||||
byte fogFactors[3] = {255, 255, 255};
|
|
||||||
|
|
||||||
backEnd.pc.c_flareRenders++;
|
|
||||||
|
|
||||||
// We don't want too big values anyways when dividing by distance.
|
|
||||||
if(f->eyeZ > -1.0f)
|
|
||||||
distance = 1.0f;
|
|
||||||
else
|
|
||||||
distance = -f->eyeZ;
|
|
||||||
|
|
||||||
// calculate the flare size..
|
|
||||||
size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is an alternative to intensity scaling. It changes the size of the flare on screen instead
|
|
||||||
* with growing distance. See in the description at the top why this is not the way to go.
|
|
||||||
// size will change ~ 1/r.
|
|
||||||
size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* As flare sizes stay nearly constant with increasing distance we must decrease the intensity
|
|
||||||
* to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
|
|
||||||
* got by considering the ratio of
|
|
||||||
* (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
|
|
||||||
* An important requirement is:
|
|
||||||
* intensity <= 1 for all distances.
|
|
||||||
*
|
|
||||||
* The formula used here to compute the intensity is as follows:
|
|
||||||
* intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
|
|
||||||
* As you can see, the intensity will have a max. of 1 when the distance is 0.
|
|
||||||
* The coefficient flareCoeff will determine the falloff speed with increasing distance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
factor = distance + size * sqrt(flareCoeff);
|
|
||||||
|
|
||||||
intensity = flareCoeff * size * size / (factor * factor);
|
|
||||||
|
|
||||||
VectorScale(f->color, f->drawIntensity * intensity, color);
|
|
||||||
|
|
||||||
// Calculations for fogging
|
|
||||||
if(tr.world && f->fogNum < tr.world->numfogs)
|
|
||||||
{
|
|
||||||
tess.numVertexes = 1;
|
|
||||||
VectorCopy(f->origin, tess.xyz[0]);
|
|
||||||
tess.fogNum = f->fogNum;
|
|
||||||
|
|
||||||
RB_CalcModulateColorsByFog(fogFactors);
|
|
||||||
|
|
||||||
// We don't need to render the flare if colors are 0 anyways.
|
|
||||||
if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
iColor[0] = color[0] * fogFactors[0];
|
|
||||||
iColor[1] = color[1] * fogFactors[1];
|
|
||||||
iColor[2] = color[2] * fogFactors[2];
|
|
||||||
|
|
||||||
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] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
|
||||||
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] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
|
||||||
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] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
|
||||||
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] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
|
||||||
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;
|
|
||||||
matrix_t oldmodelview, oldprojection, matrix;
|
|
||||||
|
|
||||||
if ( !r_flares->integer ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r_flareCoeff->modified)
|
|
||||||
{
|
|
||||||
if(r_flareCoeff->value == 0.0f)
|
|
||||||
flareCoeff = atof(FLARE_STDCOEFF);
|
|
||||||
else
|
|
||||||
flareCoeff = r_flareCoeff->value;
|
|
||||||
|
|
||||||
r_flareCoeff->modified = qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset currentEntity to world so that any previously referenced entities
|
|
||||||
// don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
|
|
||||||
backEnd.currentEntity = &tr.worldEntity;
|
|
||||||
backEnd.or = backEnd.viewParms.world;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix16Copy(glState.projection, oldprojection);
|
|
||||||
Matrix16Copy(glState.modelview, oldmodelview);
|
|
||||||
Matrix16Identity(matrix);
|
|
||||||
GL_SetModelviewMatrix(matrix);
|
|
||||||
Matrix16Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
|
|
||||||
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
|
|
||||||
-99999, 99999, matrix );
|
|
||||||
GL_SetProjectionMatrix(matrix);
|
|
||||||
|
|
||||||
for ( f = r_activeFlares ; f ; f = f->next ) {
|
|
||||||
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
|
|
||||||
&& f->inPortal == backEnd.viewParms.isPortal
|
|
||||||
&& f->drawIntensity ) {
|
|
||||||
RB_RenderFlare( f );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_SetProjectionMatrix(oldprojection);
|
|
||||||
GL_SetModelviewMatrix(oldmodelview);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,552 +0,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 Quake III Arena source code; 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. 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.
|
|
||||||
// 6. 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 <ft2build.h>
|
|
||||||
#include FT_ERRORS_H
|
|
||||||
#include FT_SYSTEM_H
|
|
||||||
#include FT_IMAGE_H
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include FT_OUTLINE_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 = ri.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 = ri.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;
|
|
||||||
int row;
|
|
||||||
unsigned char *flip;
|
|
||||||
unsigned char *src, *dst;
|
|
||||||
|
|
||||||
buffer = ri.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
|
|
||||||
}
|
|
||||||
|
|
||||||
// flip upside down
|
|
||||||
flip = (unsigned char *)ri.Malloc(width*4);
|
|
||||||
for(row = 0; row < height/2; row++)
|
|
||||||
{
|
|
||||||
src = buffer + 18 + row * 4 * width;
|
|
||||||
dst = buffer + 18 + (height - row - 1) * 4 * width;
|
|
||||||
|
|
||||||
Com_Memcpy(flip, src, width*4);
|
|
||||||
Com_Memcpy(src, dst, width*4);
|
|
||||||
Com_Memcpy(dst, flip, width*4);
|
|
||||||
}
|
|
||||||
ri.Free(flip);
|
|
||||||
|
|
||||||
ri.FS_WriteFile(filename, buffer, c);
|
|
||||||
|
|
||||||
//f = fopen (filename, "wb");
|
|
||||||
//fwrite (buffer, 1, c, f);
|
|
||||||
//fclose (f);
|
|
||||||
|
|
||||||
ri.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) {
|
|
||||||
ri.Free(bitmap->buffer);
|
|
||||||
ri.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) {
|
|
||||||
*xOut = 0;
|
|
||||||
*yOut += *maxHeight + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*yOut + *maxHeight + 1 >= 255) {
|
|
||||||
*yOut = -1;
|
|
||||||
*xOut = -1;
|
|
||||||
ri.Free(bitmap->buffer);
|
|
||||||
ri.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Free(bitmap->buffer);
|
|
||||||
ri.Free(bitmap);
|
|
||||||
|
|
||||||
return &glyph;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int fdOffset;
|
|
||||||
static byte *fdFile;
|
|
||||||
|
|
||||||
int readInt( void ) {
|
|
||||||
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( void ) {
|
|
||||||
poor me;
|
|
||||||
#if defined Q3_BIG_ENDIAN
|
|
||||||
me.fred[0] = fdFile[fdOffset+3];
|
|
||||||
me.fred[1] = fdFile[fdOffset+2];
|
|
||||||
me.fred[2] = fdFile[fdOffset+1];
|
|
||||||
me.fred[3] = fdFile[fdOffset+0];
|
|
||||||
#elif defined Q3_LITTLE_ENDIAN
|
|
||||||
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;
|
|
||||||
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 (!fontName) {
|
|
||||||
ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_WARNING, "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();
|
|
||||||
Q_strncpyz(font->glyphs[i].shaderName, (const char *)&fdFile[fdOffset], sizeof(font->glyphs[i].shaderName));
|
|
||||||
fdOffset += sizeof(font->glyphs[i].shaderName);
|
|
||||||
}
|
|
||||||
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_WARNING, "RE_RegisterFont: FreeType code not available\n");
|
|
||||||
#else
|
|
||||||
if (ftLibrary == NULL) {
|
|
||||||
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType not initialized.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = ri.FS_ReadFile(fontName, &faceData);
|
|
||||||
if (len <= 0) {
|
|
||||||
ri.Printf(PRINT_WARNING, "RE_RegisterFont: Unable to read font file '%s'\n", fontName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate on the stack first in case we fail
|
|
||||||
if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) {
|
|
||||||
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to allocate new face.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) {
|
|
||||||
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, 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 = ri.Malloc(1024*1024);
|
|
||||||
if (out == NULL) {
|
|
||||||
ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.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 = ri.Malloc(newSize);
|
|
||||||
left = 0;
|
|
||||||
max = 0;
|
|
||||||
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_TO_EDGE);
|
|
||||||
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;
|
|
||||||
ri.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));
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Free(out);
|
|
||||||
|
|
||||||
ri.FS_FreeFile(faceData);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void R_InitFreeType(void) {
|
|
||||||
#ifdef BUILD_FREETYPE
|
|
||||||
if (FT_Init_FreeType( &ftLibrary )) {
|
|
||||||
ri.Printf(PRINT_WARNING, "R_InitFreeType: Unable to initialize FreeType.\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
registeredFontCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void R_DoneFreeType(void) {
|
|
||||||
#ifdef BUILD_FREETYPE
|
|
||||||
if (ftLibrary) {
|
|
||||||
FT_Done_FreeType( ftLibrary );
|
|
||||||
ftLibrary = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
registeredFontCount = 0;
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,455 +0,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 Quake III Arena source code; 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 = tr.world->surfaces + 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, world_t *world ) {
|
|
||||||
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, world->lightGridOrigin, lightOrigin );
|
|
||||||
for ( i = 0 ; i < 3 ; i++ ) {
|
|
||||||
float v;
|
|
||||||
|
|
||||||
v = lightOrigin[i]*world->lightGridInverseSize[i];
|
|
||||||
pos[i] = floor( v );
|
|
||||||
frac[i] = v - pos[i];
|
|
||||||
if ( pos[i] < 0 ) {
|
|
||||||
pos[i] = 0;
|
|
||||||
} else if ( pos[i] >= world->lightGridBounds[i] - 1 ) {
|
|
||||||
pos[i] = world->lightGridBounds[i] - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorClear( ent->ambientLight );
|
|
||||||
VectorClear( ent->directedLight );
|
|
||||||
VectorClear( direction );
|
|
||||||
|
|
||||||
assert( world->lightGridData ); // NULL with -nolight maps
|
|
||||||
|
|
||||||
// trilerp the light value
|
|
||||||
gridStep[0] = 8;
|
|
||||||
gridStep[1] = 8 * world->lightGridBounds[0];
|
|
||||||
gridStep[2] = 8 * world->lightGridBounds[0] * world->lightGridBounds[1];
|
|
||||||
gridData = 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;
|
|
||||||
qboolean ignore;
|
|
||||||
#if idppc
|
|
||||||
float d0, d1, d2, d3, d4, d5;
|
|
||||||
#endif
|
|
||||||
factor = 1.0;
|
|
||||||
data = gridData;
|
|
||||||
ignore = qfalse;
|
|
||||||
for ( j = 0 ; j < 3 ; j++ ) {
|
|
||||||
if ( i & (1<<j) ) {
|
|
||||||
if ((pos[j] + 1) >= world->lightGridBounds[j] - 1)
|
|
||||||
{
|
|
||||||
ignore = qtrue; // ignore values outside lightgrid
|
|
||||||
}
|
|
||||||
factor *= frac[j];
|
|
||||||
data += gridStep[j];
|
|
||||||
} else {
|
|
||||||
factor *= (1.0f - frac[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ignore )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (world->hdrLightGrid)
|
|
||||||
{
|
|
||||||
float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6;
|
|
||||||
if (!(hdrData[0]+hdrData[1]+hdrData[2]+hdrData[3]+hdrData[4]+hdrData[5]) ) {
|
|
||||||
continue; // ignore samples in walls
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) {
|
|
||||||
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
|
|
||||||
if (world->hdrLightGrid)
|
|
||||||
{
|
|
||||||
// FIXME: this is hideous
|
|
||||||
float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6;
|
|
||||||
|
|
||||||
ent->ambientLight[0] += factor * hdrData[0];
|
|
||||||
ent->ambientLight[1] += factor * hdrData[1];
|
|
||||||
ent->ambientLight[2] += factor * hdrData[2];
|
|
||||||
|
|
||||||
ent->directedLight[0] += factor * hdrData[3];
|
|
||||||
ent->directedLight[1] += factor * hdrData[4];
|
|
||||||
ent->directedLight[2] += factor * hdrData[5];
|
|
||||||
}
|
|
||||||
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, tr.world );
|
|
||||||
} 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 ( !r_hdr->integer /* 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
|
|
||||||
if ( !r_hdr->integer )
|
|
||||||
{
|
|
||||||
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] = ri.ftol(ent->ambientLight[0]);
|
|
||||||
((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]);
|
|
||||||
((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]);
|
|
||||||
((byte *)&ent->ambientLightInt)[3] = 0xff;
|
|
||||||
|
|
||||||
// transform the direction to local space
|
|
||||||
// no need to do this if using lightentity glsl shader
|
|
||||||
VectorNormalize( lightDir );
|
|
||||||
VectorCopy(lightDir, ent->lightDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_LightForPoint
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
|
|
||||||
{
|
|
||||||
trRefEntity_t ent;
|
|
||||||
|
|
||||||
if ( tr.world->lightGridData == NULL )
|
|
||||||
return qfalse;
|
|
||||||
|
|
||||||
Com_Memset(&ent, 0, sizeof(ent));
|
|
||||||
VectorCopy( point, ent.e.origin );
|
|
||||||
R_SetupEntityLightingGrid( &ent, tr.world );
|
|
||||||
VectorCopy(ent.ambientLight, ambientLight);
|
|
||||||
VectorCopy(ent.directedLight, directedLight);
|
|
||||||
VectorCopy(ent.lightDir, lightDir);
|
|
||||||
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world )
|
|
||||||
{
|
|
||||||
trRefEntity_t ent;
|
|
||||||
|
|
||||||
if ( world->lightGridData == NULL )
|
|
||||||
return qfalse;
|
|
||||||
|
|
||||||
Com_Memset(&ent, 0, sizeof(ent));
|
|
||||||
VectorCopy( point, ent.e.origin );
|
|
||||||
R_SetupEntityLightingGrid( &ent, world );
|
|
||||||
|
|
||||||
if ((DotProduct(ent.lightDir, ent.lightDir) < 0.9f) || (DotProduct(ent.lightDir, normal) < 0.1f))
|
|
||||||
{
|
|
||||||
VectorCopy(normal, lightDir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorCopy(ent.lightDir, lightDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,466 +0,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 Quake III Arena source code; 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;
|
|
||||||
int *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 = tr.world->marksurfaces + node->firstmarksurface;
|
|
||||||
c = node->nummarksurfaces;
|
|
||||||
while (c--) {
|
|
||||||
int *surfViewCount;
|
|
||||||
//
|
|
||||||
if (*listlength >= listsize) break;
|
|
||||||
//
|
|
||||||
surfViewCount = &tr.world->surfacesViewCount[*mark];
|
|
||||||
surf = tr.world->surfaces + *mark;
|
|
||||||
// check if the surface has NOIMPACT or NOMARKS set
|
|
||||||
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
|
|
||||||
|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
|
|
||||||
*surfViewCount = 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, &surf->cullinfo.plane );
|
|
||||||
if (s == 1 || s == 2) {
|
|
||||||
*surfViewCount = tr.viewCount;
|
|
||||||
} else if (DotProduct(surf->cullinfo.plane.normal, dir) > -0.5) {
|
|
||||||
// don't add faces that make sharp angles with the projection direction
|
|
||||||
*surfViewCount = tr.viewCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*(surf->data) != SF_GRID &&
|
|
||||||
*(surf->data) != SF_TRIANGLES)
|
|
||||||
*surfViewCount = tr.viewCount;
|
|
||||||
// check the viewCount because the surface may have
|
|
||||||
// already been added if it spans multiple leafs
|
|
||||||
if (*surfViewCount != tr.viewCount) {
|
|
||||||
*surfViewCount = tr.viewCount;
|
|
||||||
list[*listlength] = 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;
|
|
||||||
srfGridMesh_t *cv;
|
|
||||||
srfTriangle_t *tri;
|
|
||||||
srfVert_t *dv;
|
|
||||||
vec3_t normal;
|
|
||||||
vec3_t projectionDir;
|
|
||||||
vec3_t v1, v2;
|
|
||||||
|
|
||||||
if (numPoints <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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) {
|
|
||||||
|
|
||||||
srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
|
|
||||||
|
|
||||||
// check the normal of this face
|
|
||||||
if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
v = surf->verts[tri->indexes[j]].xyz;
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
|
|
||||||
|
|
||||||
srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
|
|
||||||
|
|
||||||
for(k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
v = surf->verts[tri->indexes[j]].xyz;
|
|
||||||
VectorMA(v, MARKER_OFFSET, surf->verts[tri->indexes[j]].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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return returnedFragments;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,405 +0,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 Quake III Arena source code; 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( mdvModel_t *model, trRefEntity_t *ent ) {
|
|
||||||
vec3_t bounds[2];
|
|
||||||
mdvFrame_t *oldFrame, *newFrame;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// compute frame pointers
|
|
||||||
newFrame = model->frames + ent->e.frame;
|
|
||||||
oldFrame = model->frames + 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;
|
|
||||||
mdvFrame_t *frame;
|
|
||||||
#ifdef RAVENMD4
|
|
||||||
mdrHeader_t *mdr;
|
|
||||||
mdrFrame_t *mdrframe;
|
|
||||||
#endif
|
|
||||||
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
|
|
||||||
|
|
||||||
#ifdef RAVENMD4
|
|
||||||
if(tr.currentModel->type == MOD_MDR)
|
|
||||||
{
|
|
||||||
int frameSize;
|
|
||||||
mdr = (mdrHeader_t *) tr.currentModel->modelData;
|
|
||||||
frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
|
|
||||||
|
|
||||||
mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
|
|
||||||
|
|
||||||
radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
//frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
|
|
||||||
frame = tr.currentModel->mdv[0]->frames;
|
|
||||||
|
|
||||||
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 = ri.ftol(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( mdvModel_t *model, trRefEntity_t *ent ) {
|
|
||||||
int i, j;
|
|
||||||
fog_t *fog;
|
|
||||||
mdvFrame_t *mdvFrame;
|
|
||||||
vec3_t localOrigin;
|
|
||||||
|
|
||||||
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: non-normalized axis issues
|
|
||||||
mdvFrame = model->frames + ent->e.frame;
|
|
||||||
VectorAdd( ent->e.origin, mdvFrame->localOrigin, localOrigin );
|
|
||||||
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
|
|
||||||
fog = &tr.world->fogs[i];
|
|
||||||
for ( j = 0 ; j < 3 ; j++ ) {
|
|
||||||
if ( localOrigin[j] - mdvFrame->radius >= fog->bounds[1][j] ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( localOrigin[j] + mdvFrame->radius <= fog->bounds[0][j] ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( j == 3 ) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
R_AddMD3Surfaces
|
|
||||||
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
|
||||||
int i;
|
|
||||||
mdvModel_t *model = NULL;
|
|
||||||
mdvSurface_t *surface = NULL;
|
|
||||||
shader_t *shader = NULL;
|
|
||||||
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
|
|
||||||
|| (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
|
|
||||||
|
|
||||||
if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
|
|
||||||
ent->e.frame %= tr.currentModel->mdv[0]->numFrames;
|
|
||||||
ent->e.oldframe %= tr.currentModel->mdv[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->mdv[0]->numFrames)
|
|
||||||
|| (ent->e.frame < 0)
|
|
||||||
|| (ent->e.oldframe >= tr.currentModel->mdv[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 );
|
|
||||||
|
|
||||||
model = tr.currentModel->mdv[lod];
|
|
||||||
|
|
||||||
//
|
|
||||||
// cull the entire model if merged bounding box of both frames
|
|
||||||
// is outside the view frustum.
|
|
||||||
//
|
|
||||||
cull = R_CullModel ( model, 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( model, ent );
|
|
||||||
|
|
||||||
//
|
|
||||||
// draw all surfaces
|
|
||||||
//
|
|
||||||
surface = model->surfaces;
|
|
||||||
for ( i = 0 ; i < model->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 ];
|
|
||||||
shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ];
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't add third_person objects if not viewing through a portal
|
|
||||||
if(!personalModel)
|
|
||||||
{
|
|
||||||
srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i];
|
|
||||||
|
|
||||||
R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse );
|
|
||||||
}
|
|
||||||
|
|
||||||
surface++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,490 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete
|
|
||||||
|
|
||||||
This file is part of Reaction source code.
|
|
||||||
|
|
||||||
Reaction 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.
|
|
||||||
|
|
||||||
Reaction 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 Reaction source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
void RB_ToneMap(FBO_t *hdrFbo, int autoExposure)
|
|
||||||
{
|
|
||||||
vec4i_t srcBox, dstBox;
|
|
||||||
vec4_t color;
|
|
||||||
static int lastFrameCount = 0;
|
|
||||||
|
|
||||||
if (autoExposure)
|
|
||||||
{
|
|
||||||
if (lastFrameCount == 0 || tr.frameCount < lastFrameCount || tr.frameCount - lastFrameCount > 5)
|
|
||||||
{
|
|
||||||
// determine average log luminance
|
|
||||||
FBO_t *srcFbo, *dstFbo, *tmp;
|
|
||||||
int size = 256;
|
|
||||||
|
|
||||||
lastFrameCount = tr.frameCount;
|
|
||||||
|
|
||||||
VectorSet4(dstBox, 0, 0, size, size);
|
|
||||||
|
|
||||||
srcFbo = hdrFbo;
|
|
||||||
dstFbo = tr.textureScratchFbo[0];
|
|
||||||
FBO_Blit(srcFbo, NULL, NULL, dstFbo, dstBox, &tr.calclevels4xShader[0], NULL, 0);
|
|
||||||
|
|
||||||
srcFbo = tr.textureScratchFbo[0];
|
|
||||||
dstFbo = tr.textureScratchFbo[1];
|
|
||||||
|
|
||||||
// downscale to 1x1 texture
|
|
||||||
while (size > 1)
|
|
||||||
{
|
|
||||||
VectorSet4(srcBox, 0, 0, size, size);
|
|
||||||
//size >>= 2;
|
|
||||||
size >>= 1;
|
|
||||||
VectorSet4(dstBox, 0, 0, size, size);
|
|
||||||
|
|
||||||
if (size == 1)
|
|
||||||
dstFbo = tr.targetLevelsFbo;
|
|
||||||
|
|
||||||
//FBO_Blit(targetFbo, srcBox, NULL, tr.textureScratchFbo[nextScratch], dstBox, &tr.calclevels4xShader[1], NULL, 0);
|
|
||||||
FBO_FastBlit(srcFbo, srcBox, dstFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
||||||
|
|
||||||
tmp = srcFbo;
|
|
||||||
srcFbo = dstFbo;
|
|
||||||
dstFbo = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// blend with old log luminance for gradual change
|
|
||||||
VectorSet4(srcBox, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] = 1.0f;
|
|
||||||
if (glRefConfig.textureFloat)
|
|
||||||
color[3] = 0.03f;
|
|
||||||
else
|
|
||||||
color[3] = 0.1f;
|
|
||||||
|
|
||||||
FBO_Blit(tr.targetLevelsFbo, srcBox, NULL, tr.calcLevelsFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tonemap
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value);
|
|
||||||
color[3] = 1.0f;
|
|
||||||
|
|
||||||
if (autoExposure)
|
|
||||||
GL_BindToTMU(tr.calcLevelsImage, TB_LEVELSMAP);
|
|
||||||
else
|
|
||||||
GL_BindToTMU(tr.fixedLevelsImage, TB_LEVELSMAP);
|
|
||||||
|
|
||||||
FBO_Blit(hdrFbo, NULL, NULL, tr.screenScratchFbo, NULL, &tr.tonemapShader, color, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RB_BokehBlur(float blur)
|
|
||||||
{
|
|
||||||
// vec4i_t srcBox, dstBox;
|
|
||||||
vec4_t color;
|
|
||||||
|
|
||||||
blur *= 10.0f;
|
|
||||||
|
|
||||||
if (blur < 0.004f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (glRefConfig.framebufferObject)
|
|
||||||
{
|
|
||||||
// bokeh blur
|
|
||||||
if (blur > 0.0f)
|
|
||||||
{
|
|
||||||
// create a quarter texture
|
|
||||||
FBO_Blit(tr.screenScratchFbo, NULL, NULL, tr.quarterFbo[0], NULL, NULL, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef HQ_BLUR
|
|
||||||
if (blur > 1.0f)
|
|
||||||
{
|
|
||||||
// create a 1/16th texture
|
|
||||||
FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, NULL, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (blur > 0.0f && blur <= 1.0f)
|
|
||||||
{
|
|
||||||
// Crossfade original with quarter texture
|
|
||||||
VectorSet4(color, 1, 1, 1, blur);
|
|
||||||
|
|
||||||
FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.screenScratchFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
#ifndef HQ_BLUR
|
|
||||||
// ok blur, but can see some pixelization
|
|
||||||
else if (blur > 1.0f && blur <= 2.0f)
|
|
||||||
{
|
|
||||||
// crossfade quarter texture with 1/16th texture
|
|
||||||
FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.screenScratchFbo, NULL, NULL, NULL, 0);
|
|
||||||
|
|
||||||
VectorSet4(color, 1, 1, 1, blur - 1.0f);
|
|
||||||
|
|
||||||
FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, tr.screenScratchFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
else if (blur > 2.0f)
|
|
||||||
{
|
|
||||||
// blur 1/16th texture then replace
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
vec2_t blurTexScale;
|
|
||||||
float subblur;
|
|
||||||
|
|
||||||
subblur = ((blur - 2.0f) / 2.0f) / 3.0f * (float)(i + 1);
|
|
||||||
|
|
||||||
blurTexScale[0] =
|
|
||||||
blurTexScale[1] = subblur;
|
|
||||||
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] = 0.5f;
|
|
||||||
color[3] = 1.0f;
|
|
||||||
|
|
||||||
if (i != 0)
|
|
||||||
FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
|
||||||
else
|
|
||||||
FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, tr.screenScratchFbo, NULL, &tr.textureColorShader, NULL, 0);
|
|
||||||
}
|
|
||||||
#else // higher quality blur, but slower
|
|
||||||
else if (blur > 1.0f)
|
|
||||||
{
|
|
||||||
// blur quarter texture then replace
|
|
||||||
int i;
|
|
||||||
|
|
||||||
src = tr.quarterFbo[0];
|
|
||||||
dst = tr.quarterFbo[1];
|
|
||||||
|
|
||||||
VectorSet4(color, 0.5f, 0.5f, 0.5f, 1);
|
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
vec2_t blurTexScale;
|
|
||||||
float subblur;
|
|
||||||
|
|
||||||
subblur = (blur - 1.0f) / 2.0f * (float)(i + 1);
|
|
||||||
|
|
||||||
blurTexScale[0] =
|
|
||||||
blurTexScale[1] = subblur;
|
|
||||||
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] = 1.0f;
|
|
||||||
if (i != 0)
|
|
||||||
color[3] = 1.0f;
|
|
||||||
else
|
|
||||||
color[3] = 0.5f;
|
|
||||||
|
|
||||||
FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
FBO_Blit(tr.quarterFbo[1], NULL, NULL, tr.screenScratchFbo, NULL, &tr.textureColorShader, NULL, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef REACTION
|
|
||||||
static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha)
|
|
||||||
{
|
|
||||||
vec4i_t srcBox, dstBox;
|
|
||||||
vec4_t color;
|
|
||||||
const float inc = 1.f / passes;
|
|
||||||
const float mul = powf(stretch, inc);
|
|
||||||
float scale;
|
|
||||||
|
|
||||||
{
|
|
||||||
vec2_t texScale;
|
|
||||||
|
|
||||||
texScale[0] =
|
|
||||||
texScale[1] = 1.0f;
|
|
||||||
|
|
||||||
alpha *= inc;
|
|
||||||
VectorSet4(color, alpha, alpha, alpha, 1.0f);
|
|
||||||
|
|
||||||
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
|
|
||||||
VectorSet4(dstBox, x, y, w, h);
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0);
|
|
||||||
|
|
||||||
--passes;
|
|
||||||
scale = mul;
|
|
||||||
while (passes > 0)
|
|
||||||
{
|
|
||||||
float iscale = 1.f / scale;
|
|
||||||
float s0 = xcenter * (1.f - iscale);
|
|
||||||
float t0 = (1.0f - ycenter) * (1.f - iscale);
|
|
||||||
float s1 = iscale + s0;
|
|
||||||
float t1 = iscale + t0;
|
|
||||||
|
|
||||||
srcBox[0] = s0 * srcFbo->width;
|
|
||||||
srcBox[1] = t0 * srcFbo->height;
|
|
||||||
srcBox[2] = (s1 - s0) * srcFbo->width;
|
|
||||||
srcBox[3] = (t1 - t0) * srcFbo->height;
|
|
||||||
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
|
||||||
|
|
||||||
scale *= mul;
|
|
||||||
--passes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static qboolean RB_UpdateSunFlareVis(void)
|
|
||||||
{
|
|
||||||
GLuint sampleCount = 0;
|
|
||||||
if (!glRefConfig.occlusionQuery)
|
|
||||||
return qtrue;
|
|
||||||
|
|
||||||
tr.sunFlareQueryIndex ^= 1;
|
|
||||||
if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex])
|
|
||||||
return qtrue;
|
|
||||||
|
|
||||||
/* debug code */
|
|
||||||
if (0)
|
|
||||||
{
|
|
||||||
int iter;
|
|
||||||
for (iter=0 ; ; ++iter)
|
|
||||||
{
|
|
||||||
GLint available = 0;
|
|
||||||
qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
|
|
||||||
if (available)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount);
|
|
||||||
return sampleCount > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RB_GodRays(void)
|
|
||||||
{
|
|
||||||
vec4i_t srcBox, dstBox;
|
|
||||||
vec4_t color;
|
|
||||||
vec3_t dir;
|
|
||||||
float dot;
|
|
||||||
const float cutoff = 0.25f;
|
|
||||||
qboolean colorize = qtrue;
|
|
||||||
|
|
||||||
// float w, h, w2, h2;
|
|
||||||
matrix_t mvp;
|
|
||||||
vec4_t pos, hpos;
|
|
||||||
|
|
||||||
if (!backEnd.viewHasSunFlare)
|
|
||||||
return;
|
|
||||||
|
|
||||||
VectorSubtract(backEnd.sunFlarePos, backEnd.viewParms.or.origin, dir);
|
|
||||||
VectorNormalize(dir);
|
|
||||||
|
|
||||||
dot = DotProduct(dir, backEnd.viewParms.or.axis[0]);
|
|
||||||
if (dot < cutoff)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!RB_UpdateSunFlareVis())
|
|
||||||
return;
|
|
||||||
|
|
||||||
VectorCopy(backEnd.sunFlarePos, pos);
|
|
||||||
pos[3] = 1.f;
|
|
||||||
|
|
||||||
// project sun point
|
|
||||||
Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp);
|
|
||||||
Matrix16Transform(mvp, pos, hpos);
|
|
||||||
|
|
||||||
// transform to UV coords
|
|
||||||
hpos[3] = 0.5f / hpos[3];
|
|
||||||
|
|
||||||
pos[0] = 0.5f + hpos[0] * hpos[3];
|
|
||||||
pos[1] = 0.5f - hpos[1] * hpos[3];
|
|
||||||
|
|
||||||
// viewport dimensions
|
|
||||||
// JBravo: Apparently not used
|
|
||||||
/* w = glConfig.vidWidth;
|
|
||||||
h = glConfig.vidHeight;
|
|
||||||
w2 = glConfig.vidWidth / 2;
|
|
||||||
h2 = glConfig.vidHeight / 2; */
|
|
||||||
|
|
||||||
// initialize quarter buffers
|
|
||||||
{
|
|
||||||
float mul = 1.f;
|
|
||||||
vec2_t texScale;
|
|
||||||
|
|
||||||
texScale[0] =
|
|
||||||
texScale[1] = 1.0f;
|
|
||||||
|
|
||||||
VectorSet4(color, mul, mul, mul, 1);
|
|
||||||
|
|
||||||
// first, downsample the framebuffer
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.godRaysFbo->width, tr.godRaysFbo->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
|
|
||||||
FBO_Blit(tr.godRaysFbo, srcBox, texScale, tr.quarterFbo[0], dstBox, &tr.textureColorShader, color, 0);
|
|
||||||
|
|
||||||
if (colorize)
|
|
||||||
{
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height);
|
|
||||||
FBO_Blit(tr.screenScratchFbo, srcBox, texScale, tr.quarterFbo[0], dstBox, &tr.textureColorShader, color,
|
|
||||||
GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// radial blur passes, ping-ponging between the two quarter-size buffers
|
|
||||||
{
|
|
||||||
const float stretch_add = 2.f/3.f;
|
|
||||||
float stretch = 1.f + stretch_add;
|
|
||||||
int i;
|
|
||||||
for (i=0; i<2; ++i)
|
|
||||||
{
|
|
||||||
RB_RadialBlur(tr.quarterFbo[i&1], tr.quarterFbo[(~i) & 1], 5, stretch, 0.f, 0.f, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height, pos[0], pos[1], 1.125f);
|
|
||||||
stretch += stretch_add;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add result back on top of the main buffer
|
|
||||||
{
|
|
||||||
float mul = 1.f;
|
|
||||||
vec2_t texScale;
|
|
||||||
|
|
||||||
texScale[0] =
|
|
||||||
texScale[1] = 1.0f;
|
|
||||||
|
|
||||||
VectorSet4(color, mul, mul, mul, 1);
|
|
||||||
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height);
|
|
||||||
FBO_Blit(tr.quarterFbo[0], srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean horizontal)
|
|
||||||
{
|
|
||||||
float dx, dy;
|
|
||||||
float xmul, ymul;
|
|
||||||
float weights[3] = {
|
|
||||||
0.227027027f,
|
|
||||||
0.316216216f,
|
|
||||||
0.070270270f,
|
|
||||||
};
|
|
||||||
float offsets[3] = {
|
|
||||||
0.f,
|
|
||||||
1.3846153846f,
|
|
||||||
3.2307692308f,
|
|
||||||
};
|
|
||||||
|
|
||||||
xmul = horizontal;
|
|
||||||
ymul = 1.f - xmul;
|
|
||||||
|
|
||||||
xmul *= strength;
|
|
||||||
ymul *= strength;
|
|
||||||
|
|
||||||
{
|
|
||||||
vec4i_t srcBox, dstBox;
|
|
||||||
vec4_t color;
|
|
||||||
vec2_t texScale;
|
|
||||||
|
|
||||||
texScale[0] =
|
|
||||||
texScale[1] = 1.0f;
|
|
||||||
|
|
||||||
VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
|
|
||||||
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height);
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 );
|
|
||||||
|
|
||||||
VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
|
|
||||||
dx = offsets[1] * xmul;
|
|
||||||
dy = offsets[1] * ymul;
|
|
||||||
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
|
||||||
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
|
||||||
|
|
||||||
VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
|
|
||||||
dx = offsets[2] * xmul;
|
|
||||||
dy = offsets[2] * ymul;
|
|
||||||
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
|
||||||
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
|
|
||||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RB_HBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength)
|
|
||||||
{
|
|
||||||
RB_BlurAxis(srcFbo, dstFbo, strength, qtrue);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RB_VBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength)
|
|
||||||
{
|
|
||||||
RB_BlurAxis(srcFbo, dstFbo, strength, qfalse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RB_GaussianBlur(float blur)
|
|
||||||
{
|
|
||||||
//float mul = 1.f;
|
|
||||||
float factor = Com_Clamp(0.f, 1.f, blur);
|
|
||||||
|
|
||||||
if (factor <= 0.f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
{
|
|
||||||
vec4i_t srcBox, dstBox;
|
|
||||||
vec4_t color;
|
|
||||||
vec2_t texScale;
|
|
||||||
|
|
||||||
texScale[0] =
|
|
||||||
texScale[1] = 1.0f;
|
|
||||||
|
|
||||||
VectorSet4(color, 1, 1, 1, 1);
|
|
||||||
|
|
||||||
// first, downsample the framebuffer
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
|
|
||||||
FBO_Blit(tr.screenScratchFbo, srcBox, texScale, tr.quarterFbo[0], dstBox, &tr.textureColorShader, color, 0);
|
|
||||||
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
|
|
||||||
FBO_Blit(tr.quarterFbo[0], srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, 0);
|
|
||||||
|
|
||||||
// set the alpha channel
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
|
|
||||||
qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
|
||||||
FBO_BlitFromTexture(tr.whiteImage, srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, GLS_DEPTHTEST_DISABLE);
|
|
||||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
|
|
||||||
// blur the tiny buffer horizontally and vertically
|
|
||||||
RB_HBlur(tr.textureScratchFbo[0], tr.textureScratchFbo[1], factor);
|
|
||||||
RB_VBlur(tr.textureScratchFbo[1], tr.textureScratchFbo[0], factor);
|
|
||||||
|
|
||||||
// finally, merge back to framebuffer
|
|
||||||
VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
|
|
||||||
VectorSet4(dstBox, 0, 0, tr.screenScratchFbo->width, tr.screenScratchFbo->height);
|
|
||||||
color[3] = factor;
|
|
||||||
FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete
|
|
||||||
|
|
||||||
This file is part of Reaction source code.
|
|
||||||
|
|
||||||
Reaction 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.
|
|
||||||
|
|
||||||
Reaction 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 Reaction source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TR_POSTPROCESS_H
|
|
||||||
#define TR_POSTPROCESS_H
|
|
||||||
|
|
||||||
#include "tr_fbo.h"
|
|
||||||
|
|
||||||
void RB_ToneMap(FBO_t *hdrFbo, int autoExposure);
|
|
||||||
void RB_BokehBlur(float blur);
|
|
||||||
void RB_GodRays(void);
|
|
||||||
void RB_GaussianBlur(float blur);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,515 +0,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 Quake III Arena source code; 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;
|
|
||||||
// JBravo: Fog fixes
|
|
||||||
int fogMask;
|
|
||||||
|
|
||||||
tr.currentEntityNum = ENTITYNUM_WORLD;
|
|
||||||
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT;
|
|
||||||
fogMask = -((tr.refdef.rdflags & RDF_NOFOG) == 0);
|
|
||||||
|
|
||||||
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 & fogMask, qfalse, 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 ) {
|
|
||||||
// This isn't a useful warning, and an hShader of zero isn't a null shader, it's
|
|
||||||
// the default shader.
|
|
||||||
//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 ) {
|
|
||||||
#ifdef REACTION
|
|
||||||
// JBravo: Mirrored models
|
|
||||||
vec3_t cross;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( !tr.registered ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( r_numentities >= MAX_ENTITIES ) {
|
|
||||||
ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_ENTITIES\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
|
|
||||||
static qboolean firstTime = qtrue;
|
|
||||||
if (firstTime) {
|
|
||||||
firstTime = qfalse;
|
|
||||||
ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( (int)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;
|
|
||||||
|
|
||||||
#ifdef REACTION
|
|
||||||
// JBravo: Mirrored models
|
|
||||||
CrossProduct(ent->axis[0], ent->axis[1], cross);
|
|
||||||
backEndData[tr.smpFrame]->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.refdef.sunDir[3] = 0.0f;
|
|
||||||
tr.refdef.sunCol[3] = 1.0f;
|
|
||||||
tr.refdef.sunAmbCol[3] = 1.0f;
|
|
||||||
|
|
||||||
VectorCopy(tr.sunDirection, tr.refdef.sunDir);
|
|
||||||
if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){
|
|
||||||
tr.refdef.colorScale = 1.0f;
|
|
||||||
VectorSet(tr.refdef.sunCol, 0, 0, 0);
|
|
||||||
VectorSet(tr.refdef.sunAmbCol, 0, 0, 0);
|
|
||||||
}
|
|
||||||
else if (r_forceSun->integer == 1)
|
|
||||||
{
|
|
||||||
float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
|
|
||||||
tr.refdef.colorScale = r_forceSunMapLightScale->value;
|
|
||||||
VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
|
|
||||||
VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
|
|
||||||
tr.refdef.colorScale = tr.mapLightScale;
|
|
||||||
VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
|
|
||||||
VectorScale(tr.sunAmbient, scale, tr.refdef.sunAmbCol);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#ifdef REACTION
|
|
||||||
// Makro - copy exta info if present
|
|
||||||
if (fd->rdflags & RDF_EXTRA) {
|
|
||||||
const refdefex_t* extra = (const refdefex_t*) (fd+1);
|
|
||||||
|
|
||||||
tr.refdef.blurFactor = extra->blurFactor;
|
|
||||||
|
|
||||||
if (fd->rdflags & RDF_SUNLIGHT)
|
|
||||||
{
|
|
||||||
VectorCopy(extra->sunDir, tr.refdef.sunDir);
|
|
||||||
VectorCopy(extra->sunCol, tr.refdef.sunCol);
|
|
||||||
VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tr.refdef.blurFactor = 0.0f;
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
// 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];
|
|
||||||
|
|
||||||
tr.refdef.num_pshadows = 0;
|
|
||||||
tr.refdef.pshadows = &backEndData[tr.smpFrame]->pshadows[0];
|
|
||||||
|
|
||||||
// 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++;
|
|
||||||
|
|
||||||
// SmileTheory: playing with shadow mapping
|
|
||||||
if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2)
|
|
||||||
{
|
|
||||||
R_RenderDlightCubemaps(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* playing with more shadows */
|
|
||||||
if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4)
|
|
||||||
{
|
|
||||||
R_RenderPshadowMaps(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// playing with even more shadows
|
|
||||||
if(!( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows))
|
|
||||||
{
|
|
||||||
R_RenderSunShadowMaps(fd, 0);
|
|
||||||
R_RenderSunShadowMaps(fd, 1);
|
|
||||||
R_RenderSunShadowMaps(fd, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
parms.stereoFrame = tr.refdef.stereoFrame;
|
|
||||||
|
|
||||||
if (glRefConfig.framebufferObject)
|
|
||||||
{
|
|
||||||
parms.targetFbo = tr.renderFbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
|
|
||||||
{
|
|
||||||
parms.flags = VPF_USESUNLIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
R_RenderView( &parms );
|
|
||||||
|
|
||||||
if(!( fd->rdflags & RDF_NOWORLDMODEL ))
|
|
||||||
R_AddPostProcessCmd();
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,343 +0,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 Quake III Arena source code; 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;
|
|
||||||
GLboolean rgba[4];
|
|
||||||
|
|
||||||
// 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
|
|
||||||
qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
|
|
||||||
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(rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,955 +0,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 Quake III Arena source code; 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;
|
|
||||||
int firstVertex = tess.numVertexes;
|
|
||||||
//int firstIndex = tess.numIndexes;
|
|
||||||
vec4_t color;
|
|
||||||
|
|
||||||
//tess.numVertexes = 0;
|
|
||||||
//tess.numIndexes = 0;
|
|
||||||
tess.firstIndex = tess.numIndexes;
|
|
||||||
|
|
||||||
GL_Bind( image );
|
|
||||||
GL_Cull( CT_TWO_SIDED );
|
|
||||||
|
|
||||||
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++ )
|
|
||||||
{
|
|
||||||
tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0];
|
|
||||||
tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1];
|
|
||||||
tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2];
|
|
||||||
tess.xyz[tess.numVertexes][3] = 1.0;
|
|
||||||
|
|
||||||
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 DrawSkySideVBO()\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( t = 0; t < maxs[1] - mins[1]; t++ )
|
|
||||||
{
|
|
||||||
for ( s = 0; s < maxs[0] - mins[0]; s++ )
|
|
||||||
{
|
|
||||||
if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex;
|
|
||||||
tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
|
|
||||||
tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex;
|
|
||||||
|
|
||||||
tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex;
|
|
||||||
tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
|
|
||||||
tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
|
|
||||||
RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD);
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
shaderProgram_t *sp = &tr.textureColorShader;
|
|
||||||
|
|
||||||
GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD);
|
|
||||||
GLSL_BindProgram(sp);
|
|
||||||
|
|
||||||
GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
||||||
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] = tr.identityLight;
|
|
||||||
color[3] = 1.0f;
|
|
||||||
GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
shaderProgram_t *sp = &tr.lightallShader[0];
|
|
||||||
matrix_t matrix;
|
|
||||||
|
|
||||||
GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD);
|
|
||||||
GLSL_BindProgram(sp);
|
|
||||||
|
|
||||||
GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
||||||
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] = tr.identityLight;
|
|
||||||
color[3] = 1.0f;
|
|
||||||
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, color);
|
|
||||||
|
|
||||||
color[0] =
|
|
||||||
color[1] =
|
|
||||||
color[2] =
|
|
||||||
color[3] = 0.0f;
|
|
||||||
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, color);
|
|
||||||
|
|
||||||
Matrix16Identity(matrix);
|
|
||||||
GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex);
|
|
||||||
|
|
||||||
//qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(GL_INDEX_TYPE)));
|
|
||||||
|
|
||||||
//R_BindNullVBO();
|
|
||||||
//R_BindNullIBO();
|
|
||||||
|
|
||||||
tess.numIndexes = tess.firstIndex;
|
|
||||||
tess.numVertexes = firstVertex;
|
|
||||||
tess.firstIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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()" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS);
|
|
||||||
sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS);
|
|
||||||
sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS);
|
|
||||||
sky_maxs_subd[1] = ri.ftol(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;
|
|
||||||
tess.firstIndex = 0;
|
|
||||||
|
|
||||||
if ( shader->sky.cloudHeight )
|
|
||||||
{
|
|
||||||
for ( i = 0; i < MAX_SHADER_STAGES; i++ )
|
|
||||||
{
|
|
||||||
if ( !tess.xstages[i] ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FillCloudBox( 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]);
|
|
||||||
{
|
|
||||||
// FIXME: this could be a lot cleaner
|
|
||||||
matrix_t trans, product;
|
|
||||||
|
|
||||||
Matrix16Translation( backEnd.viewParms.or.origin, trans );
|
|
||||||
Matrix16Multiply( backEnd.viewParms.world.modelMatrix, trans, product );
|
|
||||||
GL_SetModelviewMatrix( product );
|
|
||||||
}
|
|
||||||
|
|
||||||
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] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = 1.0f;
|
|
||||||
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] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = 1.0f;
|
|
||||||
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] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = 1.0f;
|
|
||||||
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] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][1] = 1.0f;
|
|
||||||
tess.vertexColors[tess.numVertexes][2] = 1.0f;
|
|
||||||
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 ) {
|
|
||||||
matrix_t oldmodelview;
|
|
||||||
|
|
||||||
GL_State( 0 );
|
|
||||||
//qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
|
||||||
|
|
||||||
{
|
|
||||||
// FIXME: this could be a lot cleaner
|
|
||||||
matrix_t trans, product;
|
|
||||||
|
|
||||||
Matrix16Copy( glState.modelview, oldmodelview );
|
|
||||||
Matrix16Translation( backEnd.viewParms.or.origin, trans );
|
|
||||||
Matrix16Multiply( glState.modelview, trans, product );
|
|
||||||
GL_SetModelviewMatrix( product );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawSkyBox( tess.shader );
|
|
||||||
|
|
||||||
GL_SetModelviewMatrix( oldmodelview );
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
|
||||||
|
|
||||||
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 Quake III Arena source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_subs.c - common function replacements for modular renderer
|
|
||||||
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
void QDECL Com_Printf( const char *msg, ... )
|
|
||||||
{
|
|
||||||
va_list argptr;
|
|
||||||
char text[1024];
|
|
||||||
|
|
||||||
va_start(argptr, msg);
|
|
||||||
Q_vsnprintf(text, sizeof(text), msg, argptr);
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "%s", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QDECL Com_Error( int level, const char *error, ... )
|
|
||||||
{
|
|
||||||
va_list argptr;
|
|
||||||
char text[1024];
|
|
||||||
|
|
||||||
va_start(argptr, error);
|
|
||||||
Q_vsnprintf(text, sizeof(text), error, argptr);
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
ri.Error(level, "%s", text);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,932 +0,0 @@
|
||||||
/*
|
|
||||||
===========================================================================
|
|
||||||
Copyright (C) 2007-2009 Robert Beckebans <trebor_7@users.sourceforge.net>
|
|
||||||
|
|
||||||
This file is part of XreaL source code.
|
|
||||||
|
|
||||||
XreaL 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.
|
|
||||||
|
|
||||||
XreaL 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 XreaL source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
// tr_vbo.c
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_CreateVBO
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage)
|
|
||||||
{
|
|
||||||
VBO_t *vbo;
|
|
||||||
int glUsage;
|
|
||||||
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case VBO_USAGE_STATIC:
|
|
||||||
glUsage = GL_STATIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VBO_USAGE_DYNAMIC:
|
|
||||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strlen(name) >= MAX_QPATH)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tr.numVBOs == MAX_VBOS ) {
|
|
||||||
ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the render thread is stopped
|
|
||||||
R_SyncRenderThread();
|
|
||||||
|
|
||||||
vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
|
|
||||||
tr.numVBOs++;
|
|
||||||
|
|
||||||
memset(vbo, 0, sizeof(*vbo));
|
|
||||||
|
|
||||||
Q_strncpyz(vbo->name, name, sizeof(vbo->name));
|
|
||||||
|
|
||||||
vbo->vertexesSize = vertexesSize;
|
|
||||||
|
|
||||||
qglGenBuffersARB(1, &vbo->vertexesVBO);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
|
|
||||||
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
|
||||||
|
|
||||||
glState.currentVBO = NULL;
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
|
|
||||||
return vbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_CreateVBO2
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage)
|
|
||||||
{
|
|
||||||
VBO_t *vbo;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
byte *data;
|
|
||||||
int dataSize;
|
|
||||||
int dataOfs;
|
|
||||||
|
|
||||||
int glUsage;
|
|
||||||
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case VBO_USAGE_STATIC:
|
|
||||||
glUsage = GL_STATIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VBO_USAGE_DYNAMIC:
|
|
||||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!numVertexes)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if(strlen(name) >= MAX_QPATH)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tr.numVBOs == MAX_VBOS ) {
|
|
||||||
ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the render thread is stopped
|
|
||||||
R_SyncRenderThread();
|
|
||||||
|
|
||||||
vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
|
|
||||||
tr.numVBOs++;
|
|
||||||
|
|
||||||
memset(vbo, 0, sizeof(*vbo));
|
|
||||||
|
|
||||||
Q_strncpyz(vbo->name, name, sizeof(vbo->name));
|
|
||||||
|
|
||||||
if (usage == VBO_USAGE_STATIC)
|
|
||||||
{
|
|
||||||
// since these vertex attributes are never altered, interleave them
|
|
||||||
vbo->ofs_xyz = 0;
|
|
||||||
dataSize = sizeof(verts[0].xyz);
|
|
||||||
|
|
||||||
if(stateBits & ATTR_NORMAL)
|
|
||||||
{
|
|
||||||
vbo->ofs_normal = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
if(stateBits & ATTR_TANGENT)
|
|
||||||
{
|
|
||||||
vbo->ofs_tangent = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].tangent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_BITANGENT)
|
|
||||||
{
|
|
||||||
vbo->ofs_bitangent = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].bitangent);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(stateBits & ATTR_TEXCOORD)
|
|
||||||
{
|
|
||||||
vbo->ofs_st = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].st);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_LIGHTCOORD)
|
|
||||||
{
|
|
||||||
vbo->ofs_lightmap = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].lightmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_COLOR)
|
|
||||||
{
|
|
||||||
vbo->ofs_vertexcolor = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].vertexColors);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
|
||||||
{
|
|
||||||
vbo->ofs_lightdir = dataSize;
|
|
||||||
dataSize += sizeof(verts[0].lightdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
vbo->stride_xyz = dataSize;
|
|
||||||
vbo->stride_normal = dataSize;
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
vbo->stride_tangent = dataSize;
|
|
||||||
vbo->stride_bitangent = dataSize;
|
|
||||||
#endif
|
|
||||||
vbo->stride_st = dataSize;
|
|
||||||
vbo->stride_lightmap = dataSize;
|
|
||||||
vbo->stride_vertexcolor = dataSize;
|
|
||||||
vbo->stride_lightdir = dataSize;
|
|
||||||
|
|
||||||
// create VBO
|
|
||||||
dataSize *= numVertexes;
|
|
||||||
data = ri.Hunk_AllocateTempMemory(dataSize);
|
|
||||||
dataOfs = 0;
|
|
||||||
|
|
||||||
//ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
|
|
||||||
//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);
|
|
||||||
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
// xyz
|
|
||||||
memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
|
|
||||||
dataOfs += sizeof(verts[i].xyz);
|
|
||||||
|
|
||||||
// normal
|
|
||||||
if(stateBits & ATTR_NORMAL)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
|
|
||||||
dataOfs += sizeof(verts[i].normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
// tangent
|
|
||||||
if(stateBits & ATTR_TANGENT)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
|
|
||||||
dataOfs += sizeof(verts[i].tangent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bitangent
|
|
||||||
if(stateBits & ATTR_BITANGENT)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent));
|
|
||||||
dataOfs += sizeof(verts[i].bitangent);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// vertex texcoords
|
|
||||||
if(stateBits & ATTR_TEXCOORD)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
|
|
||||||
dataOfs += sizeof(verts[i].st);
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed vertex lightmap texcoords
|
|
||||||
if(stateBits & ATTR_LIGHTCOORD)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
|
|
||||||
dataOfs += sizeof(verts[i].lightmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed vertex colors
|
|
||||||
if(stateBits & ATTR_COLOR)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
|
|
||||||
dataOfs += sizeof(verts[i].vertexColors);
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed vertex light directions
|
|
||||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
|
|
||||||
dataOfs += sizeof(verts[i].lightdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// since these vertex attributes may be changed, put them in flat arrays
|
|
||||||
dataSize = sizeof(verts[0].xyz);
|
|
||||||
|
|
||||||
if(stateBits & ATTR_NORMAL)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
if(stateBits & ATTR_TANGENT)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].tangent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_BITANGENT)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].bitangent);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(stateBits & ATTR_TEXCOORD)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].st);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_LIGHTCOORD)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].lightmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_COLOR)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].vertexColors);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
|
||||||
{
|
|
||||||
dataSize += sizeof(verts[0].lightdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create VBO
|
|
||||||
dataSize *= numVertexes;
|
|
||||||
data = ri.Hunk_AllocateTempMemory(dataSize);
|
|
||||||
dataOfs = 0;
|
|
||||||
|
|
||||||
vbo->ofs_xyz = 0;
|
|
||||||
vbo->ofs_normal = 0;
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
vbo->ofs_tangent = 0;
|
|
||||||
vbo->ofs_bitangent = 0;
|
|
||||||
#endif
|
|
||||||
vbo->ofs_st = 0;
|
|
||||||
vbo->ofs_lightmap = 0;
|
|
||||||
vbo->ofs_vertexcolor = 0;
|
|
||||||
vbo->ofs_lightdir = 0;
|
|
||||||
|
|
||||||
vbo->stride_xyz = sizeof(verts[0].xyz);
|
|
||||||
vbo->stride_normal = sizeof(verts[0].normal);
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
vbo->stride_tangent = sizeof(verts[0].tangent);
|
|
||||||
vbo->stride_bitangent = sizeof(verts[0].bitangent);
|
|
||||||
#endif
|
|
||||||
vbo->stride_vertexcolor = sizeof(verts[0].vertexColors);
|
|
||||||
vbo->stride_st = sizeof(verts[0].st);
|
|
||||||
vbo->stride_lightmap = sizeof(verts[0].lightmap);
|
|
||||||
vbo->stride_lightdir = sizeof(verts[0].lightdir);
|
|
||||||
|
|
||||||
//ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
|
|
||||||
//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);
|
|
||||||
|
|
||||||
// xyz
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
|
|
||||||
dataOfs += sizeof(verts[i].xyz);
|
|
||||||
}
|
|
||||||
|
|
||||||
// normal
|
|
||||||
if(stateBits & ATTR_NORMAL)
|
|
||||||
{
|
|
||||||
vbo->ofs_normal = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
|
|
||||||
dataOfs += sizeof(verts[i].normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
// tangent
|
|
||||||
if(stateBits & ATTR_TANGENT)
|
|
||||||
{
|
|
||||||
vbo->ofs_tangent = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
|
|
||||||
dataOfs += sizeof(verts[i].tangent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bitangent
|
|
||||||
if(stateBits & ATTR_BITANGENT)
|
|
||||||
{
|
|
||||||
vbo->ofs_bitangent = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent));
|
|
||||||
dataOfs += sizeof(verts[i].bitangent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// vertex texcoords
|
|
||||||
if(stateBits & ATTR_TEXCOORD)
|
|
||||||
{
|
|
||||||
vbo->ofs_st = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
|
|
||||||
dataOfs += sizeof(verts[i].st);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed vertex lightmap texcoords
|
|
||||||
if(stateBits & ATTR_LIGHTCOORD)
|
|
||||||
{
|
|
||||||
vbo->ofs_lightmap = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
|
|
||||||
dataOfs += sizeof(verts[i].lightmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed vertex colors
|
|
||||||
if(stateBits & ATTR_COLOR)
|
|
||||||
{
|
|
||||||
vbo->ofs_vertexcolor = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
|
|
||||||
dataOfs += sizeof(verts[i].vertexColors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// feed vertex lightdirs
|
|
||||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
|
||||||
{
|
|
||||||
vbo->ofs_lightdir = dataOfs;
|
|
||||||
for (i = 0; i < numVertexes; i++)
|
|
||||||
{
|
|
||||||
memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
|
|
||||||
dataOfs += sizeof(verts[i].lightdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vbo->vertexesSize = dataSize;
|
|
||||||
|
|
||||||
qglGenBuffersARB(1, &vbo->vertexesVBO);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
|
|
||||||
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
|
||||||
|
|
||||||
glState.currentVBO = NULL;
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
|
|
||||||
ri.Hunk_FreeTempMemory(data);
|
|
||||||
|
|
||||||
return vbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_CreateIBO
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage)
|
|
||||||
{
|
|
||||||
IBO_t *ibo;
|
|
||||||
int glUsage;
|
|
||||||
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case VBO_USAGE_STATIC:
|
|
||||||
glUsage = GL_STATIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VBO_USAGE_DYNAMIC:
|
|
||||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strlen(name) >= MAX_QPATH)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tr.numIBOs == MAX_IBOS ) {
|
|
||||||
ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the render thread is stopped
|
|
||||||
R_SyncRenderThread();
|
|
||||||
|
|
||||||
ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
|
|
||||||
tr.numIBOs++;
|
|
||||||
|
|
||||||
Q_strncpyz(ibo->name, name, sizeof(ibo->name));
|
|
||||||
|
|
||||||
ibo->indexesSize = indexesSize;
|
|
||||||
|
|
||||||
qglGenBuffersARB(1, &ibo->indexesVBO);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
|
|
||||||
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
|
||||||
|
|
||||||
glState.currentIBO = NULL;
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
|
|
||||||
return ibo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_CreateIBO2
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * triangles, vboUsage_t usage)
|
|
||||||
{
|
|
||||||
IBO_t *ibo;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
byte *indexes;
|
|
||||||
int indexesSize;
|
|
||||||
int indexesOfs;
|
|
||||||
|
|
||||||
srfTriangle_t *tri;
|
|
||||||
glIndex_t index;
|
|
||||||
int glUsage;
|
|
||||||
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case VBO_USAGE_STATIC:
|
|
||||||
glUsage = GL_STATIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VBO_USAGE_DYNAMIC:
|
|
||||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!numTriangles)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if(strlen(name) >= MAX_QPATH)
|
|
||||||
{
|
|
||||||
ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tr.numIBOs == MAX_IBOS ) {
|
|
||||||
ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the render thread is stopped
|
|
||||||
R_SyncRenderThread();
|
|
||||||
|
|
||||||
ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
|
|
||||||
tr.numIBOs++;
|
|
||||||
|
|
||||||
Q_strncpyz(ibo->name, name, sizeof(ibo->name));
|
|
||||||
|
|
||||||
indexesSize = numTriangles * 3 * sizeof(int);
|
|
||||||
indexes = ri.Hunk_AllocateTempMemory(indexesSize);
|
|
||||||
indexesOfs = 0;
|
|
||||||
|
|
||||||
for(i = 0, tri = triangles; i < numTriangles; i++, tri++)
|
|
||||||
{
|
|
||||||
for(j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
index = tri->indexes[j];
|
|
||||||
memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t));
|
|
||||||
indexesOfs += sizeof(glIndex_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ibo->indexesSize = indexesSize;
|
|
||||||
|
|
||||||
qglGenBuffersARB(1, &ibo->indexesVBO);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
|
|
||||||
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage);
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
|
||||||
|
|
||||||
glState.currentIBO = NULL;
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
|
|
||||||
ri.Hunk_FreeTempMemory(indexes);
|
|
||||||
|
|
||||||
return ibo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_BindVBO
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_BindVBO(VBO_t * vbo)
|
|
||||||
{
|
|
||||||
if(!vbo)
|
|
||||||
{
|
|
||||||
//R_BindNullVBO();
|
|
||||||
ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r_logFile->integer)
|
|
||||||
{
|
|
||||||
// don't just call LogComment, or we will get a call to va() every frame!
|
|
||||||
GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(glState.currentVBO != vbo)
|
|
||||||
{
|
|
||||||
glState.currentVBO = vbo;
|
|
||||||
glState.vertexAttribPointersSet = 0;
|
|
||||||
|
|
||||||
glState.vertexAttribsInterpolation = 0;
|
|
||||||
glState.vertexAttribsOldFrame = 0;
|
|
||||||
glState.vertexAttribsNewFrame = 0;
|
|
||||||
|
|
||||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
|
|
||||||
|
|
||||||
backEnd.pc.c_vboVertexBuffers++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_BindNullVBO
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_BindNullVBO(void)
|
|
||||||
{
|
|
||||||
GLimp_LogComment("--- R_BindNullVBO ---\n");
|
|
||||||
|
|
||||||
if(glState.currentVBO)
|
|
||||||
{
|
|
||||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
|
||||||
glState.currentVBO = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_BindIBO
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_BindIBO(IBO_t * ibo)
|
|
||||||
{
|
|
||||||
if(!ibo)
|
|
||||||
{
|
|
||||||
//R_BindNullIBO();
|
|
||||||
ri.Error(ERR_DROP, "R_BindIBO: NULL ibo");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r_logFile->integer)
|
|
||||||
{
|
|
||||||
// don't just call LogComment, or we will get a call to va() every frame!
|
|
||||||
GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(glState.currentIBO != ibo)
|
|
||||||
{
|
|
||||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
|
|
||||||
|
|
||||||
glState.currentIBO = ibo;
|
|
||||||
|
|
||||||
backEnd.pc.c_vboIndexBuffers++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_BindNullIBO
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_BindNullIBO(void)
|
|
||||||
{
|
|
||||||
GLimp_LogComment("--- R_BindNullIBO ---\n");
|
|
||||||
|
|
||||||
if(glState.currentIBO)
|
|
||||||
{
|
|
||||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
|
||||||
glState.currentIBO = NULL;
|
|
||||||
glState.vertexAttribPointersSet = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_InitVBOs
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_InitVBOs(void)
|
|
||||||
{
|
|
||||||
int dataSize;
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n");
|
|
||||||
|
|
||||||
tr.numVBOs = 0;
|
|
||||||
tr.numIBOs = 0;
|
|
||||||
|
|
||||||
dataSize = sizeof(tess.xyz[0]);
|
|
||||||
dataSize += sizeof(tess.normal[0]);
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
dataSize += sizeof(tess.tangent[0]);
|
|
||||||
dataSize += sizeof(tess.bitangent[0]);
|
|
||||||
#endif
|
|
||||||
dataSize += sizeof(tess.vertexColors[0]);
|
|
||||||
dataSize += sizeof(tess.texCoords[0][0]) * 2;
|
|
||||||
dataSize += sizeof(tess.lightdir[0]);
|
|
||||||
dataSize *= SHADER_MAX_VERTEXES;
|
|
||||||
|
|
||||||
tess.vbo = R_CreateVBO("tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC);
|
|
||||||
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
tess.vbo->ofs_xyz = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES;
|
|
||||||
tess.vbo->ofs_normal = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES;
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
tess.vbo->ofs_tangent = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES;
|
|
||||||
tess.vbo->ofs_bitangent = offset; offset += sizeof(tess.bitangent[0]) * SHADER_MAX_VERTEXES;
|
|
||||||
#endif
|
|
||||||
// these next two are actually interleaved
|
|
||||||
tess.vbo->ofs_st = offset;
|
|
||||||
tess.vbo->ofs_lightmap = offset + sizeof(tess.texCoords[0][0]);
|
|
||||||
offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES;
|
|
||||||
|
|
||||||
tess.vbo->ofs_vertexcolor = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES;
|
|
||||||
tess.vbo->ofs_lightdir = offset;
|
|
||||||
|
|
||||||
tess.vbo->stride_xyz = sizeof(tess.xyz[0]);
|
|
||||||
tess.vbo->stride_normal = sizeof(tess.normal[0]);
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
tess.vbo->stride_tangent = sizeof(tess.tangent[0]);
|
|
||||||
tess.vbo->stride_bitangent = sizeof(tess.bitangent[0]);
|
|
||||||
#endif
|
|
||||||
tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]);
|
|
||||||
tess.vbo->stride_st = sizeof(tess.texCoords[0][0]) * 2;
|
|
||||||
tess.vbo->stride_lightmap = sizeof(tess.texCoords[0][0]) * 2;
|
|
||||||
tess.vbo->stride_lightdir = sizeof(tess.lightdir[0]);
|
|
||||||
|
|
||||||
dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES;
|
|
||||||
|
|
||||||
tess.ibo = R_CreateIBO("tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC);
|
|
||||||
|
|
||||||
R_BindNullVBO();
|
|
||||||
R_BindNullIBO();
|
|
||||||
|
|
||||||
GL_CheckErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_ShutdownVBOs
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_ShutdownVBOs(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
VBO_t *vbo;
|
|
||||||
IBO_t *ibo;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "------- R_ShutdownVBOs -------\n");
|
|
||||||
|
|
||||||
R_BindNullVBO();
|
|
||||||
R_BindNullIBO();
|
|
||||||
|
|
||||||
|
|
||||||
for(i = 0; i < tr.numVBOs; i++)
|
|
||||||
{
|
|
||||||
vbo = tr.vbos[i];
|
|
||||||
|
|
||||||
if(vbo->vertexesVBO)
|
|
||||||
{
|
|
||||||
qglDeleteBuffersARB(1, &vbo->vertexesVBO);
|
|
||||||
}
|
|
||||||
|
|
||||||
//ri.Free(vbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < tr.numIBOs; i++)
|
|
||||||
{
|
|
||||||
ibo = tr.ibos[i];
|
|
||||||
|
|
||||||
if(ibo->indexesVBO)
|
|
||||||
{
|
|
||||||
qglDeleteBuffersARB(1, &ibo->indexesVBO);
|
|
||||||
}
|
|
||||||
|
|
||||||
//ri.Free(ibo);
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.numVBOs = 0;
|
|
||||||
tr.numIBOs = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
R_VBOList_f
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void R_VBOList_f(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
VBO_t *vbo;
|
|
||||||
IBO_t *ibo;
|
|
||||||
int vertexesSize = 0;
|
|
||||||
int indexesSize = 0;
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, " size name\n");
|
|
||||||
ri.Printf(PRINT_ALL, "----------------------------------------------------------\n");
|
|
||||||
|
|
||||||
for(i = 0; i < tr.numVBOs; i++)
|
|
||||||
{
|
|
||||||
vbo = tr.vbos[i];
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vbo->vertexesSize / (1024 * 1024),
|
|
||||||
(vbo->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vbo->name);
|
|
||||||
|
|
||||||
vertexesSize += vbo->vertexesSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < tr.numIBOs; i++)
|
|
||||||
{
|
|
||||||
ibo = tr.ibos[i];
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", ibo->indexesSize / (1024 * 1024),
|
|
||||||
(ibo->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), ibo->name);
|
|
||||||
|
|
||||||
indexesSize += ibo->indexesSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, " %i total VBOs\n", tr.numVBOs);
|
|
||||||
ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024),
|
|
||||||
(vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, " %i total IBOs\n", tr.numIBOs);
|
|
||||||
ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024),
|
|
||||||
(indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
RB_UpdateVBOs
|
|
||||||
|
|
||||||
Adapted from Tess_UpdateVBOs from xreal
|
|
||||||
|
|
||||||
Tr3B: update the default VBO to replace the client side vertex arrays
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void RB_UpdateVBOs(unsigned int attribBits)
|
|
||||||
{
|
|
||||||
GLimp_LogComment("--- RB_UpdateVBOs ---\n");
|
|
||||||
|
|
||||||
backEnd.pc.c_dynamicVboDraws++;
|
|
||||||
|
|
||||||
// update the default VBO
|
|
||||||
if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES)
|
|
||||||
{
|
|
||||||
R_BindVBO(tess.vbo);
|
|
||||||
|
|
||||||
if(attribBits & ATTR_BITS)
|
|
||||||
{
|
|
||||||
if(attribBits & ATTR_POSITION)
|
|
||||||
{
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]));
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD)
|
|
||||||
{
|
|
||||||
// these are interleaved, so we update both if either need it
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2);
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attribBits & ATTR_NORMAL)
|
|
||||||
{
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]));
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
if(attribBits & ATTR_TANGENT)
|
|
||||||
{
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]));
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attribBits & ATTR_BITANGENT)
|
|
||||||
{
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]));
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(attribBits & ATTR_COLOR)
|
|
||||||
{
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]));
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attribBits & ATTR_LIGHTDIRECTION)
|
|
||||||
{
|
|
||||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]));
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz);
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords);
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal);
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent);
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent);
|
|
||||||
#endif
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors);
|
|
||||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the default IBO
|
|
||||||
if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES)
|
|
||||||
{
|
|
||||||
R_BindIBO(tess.ibo);
|
|
||||||
|
|
||||||
qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,851 +0,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 Quake III Arena source code; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
===========================================================================
|
|
||||||
*/
|
|
||||||
#include "tr_local.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
R_CullSurface
|
|
||||||
|
|
||||||
Tries to cull surfaces before they are lighted or
|
|
||||||
added to the sorting list.
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
static qboolean R_CullSurface( msurface_t *surf ) {
|
|
||||||
if ( r_nocull->integer || surf->cullinfo.type == CULLINFO_NONE) {
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surf->cullinfo.type & CULLINFO_PLANE)
|
|
||||||
{
|
|
||||||
// Only true for SF_FACE, so treat like its own function
|
|
||||||
float d;
|
|
||||||
cullType_t ct;
|
|
||||||
|
|
||||||
if ( !r_facePlaneCull->integer ) {
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
ct = surf->shader->cullType;
|
|
||||||
|
|
||||||
if (ct == CT_TWO_SIDED)
|
|
||||||
{
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't cull for depth shadow
|
|
||||||
/*
|
|
||||||
if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
|
|
||||||
{
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// shadowmaps draw back surfaces
|
|
||||||
if ( tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW) )
|
|
||||||
{
|
|
||||||
if (ct == CT_FRONT_SIDED)
|
|
||||||
{
|
|
||||||
ct = CT_BACK_SIDED;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ct = CT_FRONT_SIDED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// do proper cull for orthographic projection
|
|
||||||
if (tr.viewParms.flags & VPF_ORTHOGRAPHIC) {
|
|
||||||
d = DotProduct(tr.viewParms.or.axis[0], surf->cullinfo.plane.normal);
|
|
||||||
if ( ct == CT_FRONT_SIDED ) {
|
|
||||||
if (d > 0)
|
|
||||||
return qtrue;
|
|
||||||
} else {
|
|
||||||
if (d < 0)
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
d = DotProduct (tr.or.viewOrigin, surf->cullinfo.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 ( ct == CT_FRONT_SIDED ) {
|
|
||||||
if ( d < surf->cullinfo.plane.dist - 8 ) {
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ( d > surf->cullinfo.plane.dist + 8 ) {
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surf->cullinfo.type & CULLINFO_SPHERE)
|
|
||||||
{
|
|
||||||
int sphereCull;
|
|
||||||
|
|
||||||
if ( tr.currentEntityNum != ENTITYNUM_WORLD ) {
|
|
||||||
sphereCull = R_CullLocalPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
|
|
||||||
} else {
|
|
||||||
sphereCull = R_CullPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sphereCull == CULL_OUT )
|
|
||||||
{
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sphereCull == CULL_IN )
|
|
||||||
{
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surf->cullinfo.type & CULLINFO_BOX)
|
|
||||||
{
|
|
||||||
int boxCull;
|
|
||||||
|
|
||||||
if ( tr.currentEntityNum != ENTITYNUM_WORLD ) {
|
|
||||||
boxCull = R_CullLocalBox( surf->cullinfo.bounds );
|
|
||||||
} else {
|
|
||||||
boxCull = R_CullBox( surf->cullinfo.bounds );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( boxCull == CULL_OUT )
|
|
||||||
{
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( boxCull == CULL_IN )
|
|
||||||
{
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return qfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
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 ) {
|
|
||||||
float d;
|
|
||||||
int i;
|
|
||||||
dlight_t *dl;
|
|
||||||
|
|
||||||
if ( surf->cullinfo.type & CULLINFO_PLANE )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
|
|
||||||
if ( ! ( dlightBits & ( 1 << i ) ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dl = &tr.refdef.dlights[i];
|
|
||||||
d = DotProduct( dl->origin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
|
|
||||||
if ( d < -dl->radius || d > dl->radius ) {
|
|
||||||
// dlight doesn't reach the plane
|
|
||||||
dlightBits &= ~( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( surf->cullinfo.type & CULLINFO_BOX )
|
|
||||||
{
|
|
||||||
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 > surf->cullinfo.bounds[1][0]
|
|
||||||
|| dl->origin[0] + dl->radius < surf->cullinfo.bounds[0][0]
|
|
||||||
|| dl->origin[1] - dl->radius > surf->cullinfo.bounds[1][1]
|
|
||||||
|| dl->origin[1] + dl->radius < surf->cullinfo.bounds[0][1]
|
|
||||||
|| dl->origin[2] - dl->radius > surf->cullinfo.bounds[1][2]
|
|
||||||
|| dl->origin[2] + dl->radius < surf->cullinfo.bounds[0][2] ) {
|
|
||||||
// dlight doesn't reach the bounds
|
|
||||||
dlightBits &= ~( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( surf->cullinfo.type & CULLINFO_SPHERE )
|
|
||||||
{
|
|
||||||
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
|
|
||||||
if ( ! ( dlightBits & ( 1 << i ) ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dl = &tr.refdef.dlights[i];
|
|
||||||
if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius))
|
|
||||||
{
|
|
||||||
// dlight doesn't reach the bounds
|
|
||||||
dlightBits &= ~( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( *surf->data == SF_FACE ) {
|
|
||||||
((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits;
|
|
||||||
} else if ( *surf->data == SF_GRID ) {
|
|
||||||
((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits;
|
|
||||||
} else if ( *surf->data == SF_TRIANGLES ) {
|
|
||||||
((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits;
|
|
||||||
} else if ( *surf->data == SF_VBO_MESH ) {
|
|
||||||
((srfVBOMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits;
|
|
||||||
} else {
|
|
||||||
dlightBits = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( dlightBits ) {
|
|
||||||
tr.pc.c_dlightSurfaces++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dlightBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
R_PshadowSurface
|
|
||||||
|
|
||||||
Just like R_DlightSurface, cull any we can
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) {
|
|
||||||
float d;
|
|
||||||
int i;
|
|
||||||
pshadow_t *ps;
|
|
||||||
|
|
||||||
if ( surf->cullinfo.type & CULLINFO_PLANE )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
|
||||||
if ( ! ( pshadowBits & ( 1 << i ) ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ps = &tr.refdef.pshadows[i];
|
|
||||||
d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
|
|
||||||
if ( d < -ps->lightRadius || d > ps->lightRadius ) {
|
|
||||||
// pshadow doesn't reach the plane
|
|
||||||
pshadowBits &= ~( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( surf->cullinfo.type & CULLINFO_BOX )
|
|
||||||
{
|
|
||||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
|
||||||
if ( ! ( pshadowBits & ( 1 << i ) ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ps = &tr.refdef.pshadows[i];
|
|
||||||
if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0]
|
|
||||||
|| ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0]
|
|
||||||
|| ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1]
|
|
||||||
|| ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1]
|
|
||||||
|| ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2]
|
|
||||||
|| ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2]
|
|
||||||
|| BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) {
|
|
||||||
// pshadow doesn't reach the bounds
|
|
||||||
pshadowBits &= ~( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( surf->cullinfo.type & CULLINFO_SPHERE )
|
|
||||||
{
|
|
||||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
|
||||||
if ( ! ( pshadowBits & ( 1 << i ) ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ps = &tr.refdef.pshadows[i];
|
|
||||||
if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius)
|
|
||||||
|| DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius)
|
|
||||||
{
|
|
||||||
// pshadow doesn't reach the bounds
|
|
||||||
pshadowBits &= ~( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( *surf->data == SF_FACE ) {
|
|
||||||
((srfSurfaceFace_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits;
|
|
||||||
} else if ( *surf->data == SF_GRID ) {
|
|
||||||
((srfGridMesh_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits;
|
|
||||||
} else if ( *surf->data == SF_TRIANGLES ) {
|
|
||||||
((srfTriangles_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits;
|
|
||||||
} else if ( *surf->data == SF_VBO_MESH ) {
|
|
||||||
((srfVBOMesh_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits;
|
|
||||||
} else {
|
|
||||||
pshadowBits = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pshadowBits ) {
|
|
||||||
//tr.pc.c_dlightSurfaces++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pshadowBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
======================
|
|
||||||
R_AddWorldSurface
|
|
||||||
======================
|
|
||||||
*/
|
|
||||||
static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) {
|
|
||||||
// FIXME: bmodel fog?
|
|
||||||
|
|
||||||
// try to cull before dlighting or adding
|
|
||||||
if ( R_CullSurface( surf ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for dlighting
|
|
||||||
if ( dlightBits ) {
|
|
||||||
dlightBits = R_DlightSurface( surf, dlightBits );
|
|
||||||
dlightBits = ( dlightBits != 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for pshadows
|
|
||||||
/*if ( pshadowBits ) */{
|
|
||||||
pshadowBits = R_PshadowSurface( surf, pshadowBits);
|
|
||||||
pshadowBits = ( pshadowBits != 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============================================================
|
|
||||||
|
|
||||||
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_SetupEntityLighting( &tr.refdef, ent );
|
|
||||||
R_DlightBmodel( bmodel );
|
|
||||||
|
|
||||||
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
|
|
||||||
int surf = bmodel->firstSurface + i;
|
|
||||||
|
|
||||||
if (tr.world->surfacesViewCount[surf] != tr.viewCount)
|
|
||||||
{
|
|
||||||
tr.world->surfacesViewCount[surf] = tr.viewCount;
|
|
||||||
R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============================================================
|
|
||||||
|
|
||||||
WORLD MODEL
|
|
||||||
|
|
||||||
=============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
R_RecursiveWorldNode
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) {
|
|
||||||
|
|
||||||
do {
|
|
||||||
int newDlights[2];
|
|
||||||
unsigned int newPShadows[2];
|
|
||||||
|
|
||||||
// if the node wasn't marked as potentially visible, exit
|
|
||||||
// pvs is skipped for depth shadows
|
|
||||||
if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) {
|
|
||||||
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 ( planeBits & 16 ) {
|
|
||||||
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]);
|
|
||||||
if (r == 2) {
|
|
||||||
return; // culled
|
|
||||||
}
|
|
||||||
if ( r == 1 ) {
|
|
||||||
planeBits &= ~16; // 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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newPShadows[0] = 0;
|
|
||||||
newPShadows[1] = 0;
|
|
||||||
if ( pshadowBits ) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
|
||||||
pshadow_t *shadow;
|
|
||||||
float dist;
|
|
||||||
|
|
||||||
if ( pshadowBits & ( 1 << i ) ) {
|
|
||||||
shadow = &tr.refdef.pshadows[i];
|
|
||||||
dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist;
|
|
||||||
|
|
||||||
if ( dist > -shadow->lightRadius ) {
|
|
||||||
newPShadows[0] |= ( 1 << i );
|
|
||||||
}
|
|
||||||
if ( dist < shadow->lightRadius ) {
|
|
||||||
newPShadows[1] |= ( 1 << i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// recurse down the children, front side first
|
|
||||||
R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] );
|
|
||||||
|
|
||||||
// tail recurse
|
|
||||||
node = node->children[1];
|
|
||||||
dlightBits = newDlights[1];
|
|
||||||
pshadowBits = newPShadows[1];
|
|
||||||
} while ( 1 );
|
|
||||||
|
|
||||||
{
|
|
||||||
// leaf node, so add mark surfaces
|
|
||||||
int c;
|
|
||||||
int surf, *view;
|
|
||||||
|
|
||||||
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 merged and unmerged surfaces
|
|
||||||
if (tr.world->viewSurfaces)
|
|
||||||
view = tr.world->viewSurfaces + node->firstmarksurface;
|
|
||||||
else
|
|
||||||
view = tr.world->marksurfaces + node->firstmarksurface;
|
|
||||||
|
|
||||||
c = node->nummarksurfaces;
|
|
||||||
while (c--) {
|
|
||||||
// just mark it as visible, so we don't jump out of the cache derefencing the surface
|
|
||||||
surf = *view;
|
|
||||||
if (surf < 0)
|
|
||||||
{
|
|
||||||
if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount)
|
|
||||||
{
|
|
||||||
tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount;
|
|
||||||
tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits;
|
|
||||||
tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits;
|
|
||||||
tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (tr.world->surfacesViewCount[surf] != tr.viewCount)
|
|
||||||
{
|
|
||||||
tr.world->surfacesViewCount[surf] = tr.viewCount;
|
|
||||||
tr.world->surfacesDlightBits[surf] = dlightBits;
|
|
||||||
tr.world->surfacesPshadowBits[surf] = pshadowBits;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tr.world->surfacesDlightBits[surf] |= dlightBits;
|
|
||||||
tr.world->surfacesPshadowBits[surf] |= pshadowBits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
view++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
===============
|
|
||||||
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 = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ??
|
|
||||||
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
|
|
||||||
|
|
||||||
for(i = 0; i < MAX_VISCOUNTS; i++)
|
|
||||||
{
|
|
||||||
if(tr.visClusters[i] == cluster)
|
|
||||||
{
|
|
||||||
//tr.visIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if r_showcluster was just turned on, remark everything
|
|
||||||
if(i != MAX_VISCOUNTS && !tr.refdef.areamaskModified && !r_showcluster->modified)// && !r_dynamicBspOcclusionCulling->modified)
|
|
||||||
{
|
|
||||||
if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer)
|
|
||||||
{
|
|
||||||
ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i);
|
|
||||||
}
|
|
||||||
tr.visIndex = i;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the areamask was modified, invalidate all visclusters
|
|
||||||
// this caused doors to open into undrawn areas
|
|
||||||
if (tr.refdef.areamaskModified)
|
|
||||||
{
|
|
||||||
memset(tr.visClusters, -2, sizeof(tr.visClusters));
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS;
|
|
||||||
tr.visCounts[tr.visIndex]++;
|
|
||||||
tr.visClusters[tr.visIndex] = cluster;
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set all nodes to visible if there is no vis
|
|
||||||
// this caused some levels to simply not render
|
|
||||||
if (r_novis->integer || !tr.world->vis || tr.visClusters[tr.visIndex] == -1) {
|
|
||||||
for (i=0 ; i<tr.world->numnodes ; i++) {
|
|
||||||
if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
|
|
||||||
tr.world->nodes[i].visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vis = R_ClusterPVS(tr.visClusters[tr.visIndex]);
|
|
||||||
|
|
||||||
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->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex])
|
|
||||||
break;
|
|
||||||
parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
|
|
||||||
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
|
|
||||||
if (!(tr.viewParms.flags & VPF_DEPTHSHADOW))
|
|
||||||
R_MarkLeaves ();
|
|
||||||
|
|
||||||
// clear out the visible min/max
|
|
||||||
ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
|
|
||||||
|
|
||||||
// perform frustum culling and flag all the potentially visible surfaces
|
|
||||||
if ( tr.refdef.num_dlights > 32 ) {
|
|
||||||
tr.refdef.num_dlights = 32 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tr.refdef.num_pshadows > 32 ) {
|
|
||||||
tr.refdef.num_pshadows = 32 ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
|
|
||||||
{
|
|
||||||
R_RecursiveWorldNode( tr.world->nodes, 31, 0, 0);
|
|
||||||
}
|
|
||||||
else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) )
|
|
||||||
{
|
|
||||||
R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1, ( 1 << tr.refdef.num_pshadows ) - 1 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
R_RecursiveWorldNode( tr.world->nodes, 31, ( 1 << tr.refdef.num_dlights ) - 1, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// now add all the potentially visible surfaces
|
|
||||||
// also mask invisible dlights for next frame
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
tr.refdef.dlightMask = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < tr.world->numWorldSurfaces; i++)
|
|
||||||
{
|
|
||||||
if (tr.world->surfacesViewCount[i] != tr.viewCount)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] );
|
|
||||||
tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i];
|
|
||||||
}
|
|
||||||
for (i = 0; i < tr.world->numMergedSurfaces; i++)
|
|
||||||
{
|
|
||||||
if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] );
|
|
||||||
tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.refdef.dlightMask = ~tr.refdef.dlightMask;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue