mirror of
https://github.com/DrBeef/Raze.git
synced 2024-12-14 06:31:17 +00:00
491783d81e
git-svn-id: https://svn.eduke32.com/eduke32@6760 1a8010ca-5511-0410-912e-c29ae57300e0
6336 lines
198 KiB
C++
6336 lines
198 KiB
C++
// blah
|
|
|
|
#if defined USE_OPENGL && defined POLYMER
|
|
|
|
#include "compat.h"
|
|
|
|
#define POLYMER_C
|
|
#include "polymer.h"
|
|
#include "engine_priv.h"
|
|
#include "xxhash.h"
|
|
#include "texcache.h"
|
|
|
|
// CVARS
|
|
int32_t pr_lighting = 1;
|
|
int32_t pr_normalmapping = 1;
|
|
int32_t pr_specularmapping = 1;
|
|
int32_t pr_shadows = 1;
|
|
int32_t pr_shadowcount = 5;
|
|
int32_t pr_shadowdetail = 4;
|
|
int32_t pr_shadowfiltering = 1;
|
|
int32_t pr_maxlightpasses = 10;
|
|
int32_t pr_maxlightpriority = PR_MAXLIGHTPRIORITY;
|
|
int32_t pr_fov = 426; // appears to be the classic setting.
|
|
double pr_customaspect = 0.0f;
|
|
int32_t pr_billboardingmode = 1;
|
|
int32_t pr_verbosity = 1; // 0: silent, 1: errors and one-times, 2: multiple-times, 3: flood
|
|
int32_t pr_wireframe = 0;
|
|
int32_t pr_vbos = 2;
|
|
int32_t pr_buckets = 0;
|
|
int32_t pr_gpusmoothing = 1;
|
|
int32_t pr_overrideparallax = 0;
|
|
float pr_parallaxscale = 0.1f;
|
|
float pr_parallaxbias = 0.0f;
|
|
int32_t pr_overridespecular = 0;
|
|
float pr_specularpower = 15.0f;
|
|
float pr_specularfactor = 1.0f;
|
|
int32_t pr_highpalookups = 1;
|
|
int32_t pr_artmapping = 1;
|
|
int32_t pr_overridehud = 0;
|
|
float pr_hudxadd = 0.0f;
|
|
float pr_hudyadd = 0.0f;
|
|
float pr_hudzadd = 0.0f;
|
|
int32_t pr_hudangadd = 0;
|
|
int32_t pr_hudfov = 426;
|
|
float pr_overridemodelscale = 0.0f;
|
|
int32_t pr_ati_fboworkaround = 0;
|
|
int32_t pr_ati_nodepthoffset = 0;
|
|
#ifdef __APPLE__
|
|
int32_t pr_ati_textureformat_one = 0;
|
|
#endif
|
|
int32_t pr_nullrender = 0; // 1: no draw, 2: no draw or updates
|
|
|
|
int32_t r_pr_maxlightpasses = 5; // value of the cvar (not live value), used to detect changes
|
|
|
|
GLenum mapvbousage = GL_STREAM_DRAW;
|
|
GLenum modelvbousage = GL_STATIC_DRAW;
|
|
|
|
// BUILD DATA
|
|
_prsector *prsectors[MAXSECTORS];
|
|
_prwall *prwalls[MAXWALLS];
|
|
_prsprite *prsprites[MAXSPRITES];
|
|
_prmaterial mdspritematerial;
|
|
_prhighpalookup prhighpalookups[MAXBASEPALS][MAXPALOOKUPS];
|
|
|
|
// One U8 texture per tile
|
|
GLuint prartmaps[MAXTILES];
|
|
// 256 U8U8U8 values per basepal
|
|
GLuint prbasepalmaps[MAXBASEPALS];
|
|
// numshades full indirections (32*256) per lookup
|
|
GLuint prlookups[MAXPALOOKUPS];
|
|
|
|
GLuint prmapvbo;
|
|
const GLsizeiptr proneplanesize = sizeof(_prvert) * 4;
|
|
const GLintptr prwalldatasize = sizeof(_prvert)* 4 * 3; // wall, over and mask planes for every wall
|
|
GLintptr prwalldataoffset;
|
|
|
|
GLuint prindexringvbo;
|
|
GLuint *prindexring;
|
|
const GLsizeiptr prindexringsize = 65535;
|
|
GLintptr prindexringoffset;
|
|
|
|
const GLbitfield prindexringmapflags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
|
|
|
|
_prbucket *prbuckethead;
|
|
int32_t prcanbucket;
|
|
|
|
static const _prvert vertsprite[4] =
|
|
{
|
|
{
|
|
-0.5f, 0.0f, 0.0f,
|
|
0.0f, 1.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
{
|
|
0.5f, 0.0f, 0.0f,
|
|
1.0f, 1.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
{
|
|
0.5f, 1.0f, 0.0f,
|
|
1.0f, 0.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
{
|
|
-0.5f, 1.0f, 0.0f,
|
|
0.0f, 0.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
};
|
|
|
|
static const _prvert horizsprite[4] =
|
|
{
|
|
{
|
|
-0.5f, 0.0f, 0.5f,
|
|
0.0f, 0.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
{
|
|
0.5f, 0.0f, 0.5f,
|
|
1.0f, 0.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
{
|
|
0.5f, 0.0f, -0.5f,
|
|
1.0f, 1.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
{
|
|
-0.5f, 0.0f, -0.5f,
|
|
0.0f, 1.0f,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
},
|
|
};
|
|
|
|
static const GLfloat skyboxdata[4 * 5 * 6] =
|
|
{
|
|
// -ZY
|
|
-0.5f, -0.5f, 0.5f,
|
|
0.0f, 1.0f,
|
|
-0.5f, -0.5f, -0.5f,
|
|
1.0f, 1.0f,
|
|
-0.5f, 0.5f, -0.5f,
|
|
1.0f, 0.0f,
|
|
-0.5f, 0.5f, 0.5f,
|
|
0.0f, 0.0f,
|
|
|
|
// XY
|
|
-0.5f, -0.5f, -0.5f,
|
|
0.0f, 1.0f,
|
|
0.5f, -0.5f, -0.5f,
|
|
1.0f, 1.0f,
|
|
0.5f, 0.5f, -0.5f,
|
|
1.0f, 0.0f,
|
|
-0.5f, 0.5f, -0.5f,
|
|
0.0f, 0.0f,
|
|
|
|
// ZY
|
|
0.5f, -0.5f, -0.5f,
|
|
0.0f, 1.0f,
|
|
0.5f, -0.5f, 0.5f,
|
|
1.0f, 1.0f,
|
|
0.5f, 0.5f, 0.5f,
|
|
1.0f, 0.0f,
|
|
0.5f, 0.5f, -0.5f,
|
|
0.0f, 0.0f,
|
|
|
|
// -XY
|
|
0.5f, -0.5f, 0.5f,
|
|
0.0f, 1.0f,
|
|
-0.5f, -0.5f, 0.5f,
|
|
1.0f, 1.0f,
|
|
-0.5f, 0.5f, 0.5f,
|
|
1.0f, 0.0f,
|
|
0.5f, 0.5f, 0.5f,
|
|
0.0f, 0.0f,
|
|
|
|
// XZ
|
|
-0.5f, 0.5f, -0.5f,
|
|
1.0f, 1.0f,
|
|
0.5f, 0.5f, -0.5f,
|
|
1.0f, 0.0f,
|
|
0.5f, 0.5f, 0.5f,
|
|
0.0f, 0.0f,
|
|
-0.5f, 0.5f, 0.5f,
|
|
0.0f, 1.0f,
|
|
|
|
// X-Z
|
|
-0.5f, -0.5f, 0.5f,
|
|
0.0f, 0.0f,
|
|
0.5f, -0.5f, 0.5f,
|
|
0.0f, 1.0f,
|
|
0.5f, -0.5f, -0.5f,
|
|
1.0f, 1.0f,
|
|
-0.5f, -0.5f, -0.5f,
|
|
1.0f, 0.0f,
|
|
};
|
|
|
|
GLuint skyboxdatavbo;
|
|
|
|
GLfloat artskydata[16];
|
|
|
|
// LIGHTS
|
|
static _prplanelist *plpool;
|
|
#pragma pack(push,1)
|
|
_prlight prlights[PR_MAXLIGHTS];
|
|
int32_t lightcount;
|
|
int32_t curlight;
|
|
#pragma pack(pop)
|
|
|
|
static const GLfloat shadowBias[] =
|
|
{
|
|
0.5, 0.0, 0.0, 0.0,
|
|
0.0, 0.5, 0.0, 0.0,
|
|
0.0, 0.0, 0.5, 0.0,
|
|
0.5, 0.5, 0.5, 1.0
|
|
};
|
|
|
|
// MATERIALS
|
|
static const _prprogrambit prprogrambits[PR_BIT_COUNT] = {
|
|
{
|
|
1 << PR_BIT_HEADER,
|
|
// vert_def
|
|
"#version 120\n"
|
|
"#extension GL_ARB_texture_rectangle : enable\n"
|
|
"\n",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"#version 120\n"
|
|
"#extension GL_ARB_texture_rectangle : enable\n"
|
|
"\n",
|
|
// frag_prog
|
|
"",
|
|
},
|
|
{
|
|
1 << PR_BIT_ANIM_INTERPOLATION,
|
|
// vert_def
|
|
"attribute vec4 nextFrameData;\n"
|
|
"attribute vec4 nextFrameNormal;\n"
|
|
"uniform float frameProgress;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" vec4 currentFramePosition;\n"
|
|
" vec4 nextFramePosition;\n"
|
|
"\n"
|
|
" currentFramePosition = curVertex * (1.0 - frameProgress);\n"
|
|
" nextFramePosition = nextFrameData * frameProgress;\n"
|
|
" curVertex = currentFramePosition + nextFramePosition;\n"
|
|
"\n"
|
|
" currentFramePosition = vec4(curNormal, 1.0) * (1.0 - frameProgress);\n"
|
|
" nextFramePosition = nextFrameNormal * frameProgress;\n"
|
|
" curNormal = vec3(currentFramePosition + nextFramePosition);\n"
|
|
"\n",
|
|
// frag_def
|
|
"",
|
|
// frag_prog
|
|
"",
|
|
},
|
|
{
|
|
1 << PR_BIT_LIGHTING_PASS,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"",
|
|
// frag_prog
|
|
" isLightingPass = 1;\n"
|
|
" result = vec4(0.0, 0.0, 0.0, 1.0);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_NORMAL_MAP,
|
|
// vert_def
|
|
"attribute vec3 T;\n"
|
|
"attribute vec3 B;\n"
|
|
"attribute vec3 N;\n"
|
|
"uniform vec3 eyePosition;\n"
|
|
"varying vec3 tangentSpaceEyeVec;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" TBN = mat3(T, B, N);\n"
|
|
" tangentSpaceEyeVec = eyePosition - vec3(curVertex);\n"
|
|
" tangentSpaceEyeVec = TBN * tangentSpaceEyeVec;\n"
|
|
"\n"
|
|
" isNormalMapped = 1;\n"
|
|
"\n",
|
|
// frag_def
|
|
"uniform sampler2D normalMap;\n"
|
|
"uniform vec2 normalBias;\n"
|
|
"varying vec3 tangentSpaceEyeVec;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" vec4 normalStep;\n"
|
|
" float biasedHeight;\n"
|
|
"\n"
|
|
" eyeVec = normalize(tangentSpaceEyeVec);\n"
|
|
"\n"
|
|
" for (int i = 0; i < 4; i++) {\n"
|
|
" normalStep = texture2D(normalMap, commonTexCoord.st);\n"
|
|
" biasedHeight = normalStep.a * normalBias.x - normalBias.y;\n"
|
|
" commonTexCoord += (biasedHeight - commonTexCoord.z) * normalStep.z * eyeVec;\n"
|
|
" }\n"
|
|
"\n"
|
|
" normalTexel = texture2D(normalMap, commonTexCoord.st);\n"
|
|
"\n"
|
|
" isNormalMapped = 1;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_ART_MAP,
|
|
// vert_def
|
|
"varying vec3 horizDistance;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
|
|
" horizDistance = vec3(gl_ModelViewMatrix * curVertex);\n"
|
|
"\n",
|
|
// frag_def
|
|
"uniform sampler2D artMap;\n"
|
|
"uniform sampler2D basePalMap;\n"
|
|
"uniform sampler2DRect lookupMap;\n"
|
|
"uniform float shadeOffset;\n"
|
|
"uniform float visibility;\n"
|
|
"varying vec3 horizDistance;\n"
|
|
"\n",
|
|
// frag_prog
|
|
|
|
" float shadeLookup = length(horizDistance) / 1.024 * visibility;\n"
|
|
" shadeLookup = shadeLookup + shadeOffset;\n"
|
|
"\n"
|
|
" float colorIndex = texture2D(artMap, commonTexCoord.st).r * 256.0;\n"
|
|
" float colorIndexNear = texture2DRect(lookupMap, vec2(colorIndex, floor(shadeLookup))).r;\n"
|
|
" float colorIndexFar = texture2DRect(lookupMap, vec2(colorIndex, floor(shadeLookup + 1.0))).r;\n"
|
|
" float colorIndexFullbright = texture2DRect(lookupMap, vec2(colorIndex, 0.0)).r;\n"
|
|
"\n"
|
|
" vec3 texelNear = texture2D(basePalMap, vec2(colorIndexNear, 0.5)).rgb;\n"
|
|
" vec3 texelFar = texture2D(basePalMap, vec2(colorIndexFar, 0.5)).rgb;\n"
|
|
" diffuseTexel.rgb = texture2D(basePalMap, vec2(colorIndexFullbright, 0.5)).rgb;\n"
|
|
"\n"
|
|
" if (isLightingPass == 0) {\n"
|
|
" result.rgb = mix(texelNear, texelFar, fract(shadeLookup));\n"
|
|
" result.a = 1.0;\n"
|
|
" if (colorIndex == 256.0)\n"
|
|
" result.a = 0.0;\n"
|
|
" }\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_DIFFUSE_MAP,
|
|
// vert_def
|
|
"uniform vec2 diffuseScale;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" gl_TexCoord[0] = vec4(diffuseScale, 1.0, 1.0) * gl_MultiTexCoord0;\n"
|
|
"\n",
|
|
// frag_def
|
|
"uniform sampler2D diffuseMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" diffuseTexel = texture2D(diffuseMap, commonTexCoord.st);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_DIFFUSE_DETAIL_MAP,
|
|
// vert_def
|
|
"uniform vec2 detailScale;\n"
|
|
"varying vec2 fragDetailScale;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" fragDetailScale = detailScale;\n"
|
|
" if (isNormalMapped == 0)\n"
|
|
" gl_TexCoord[1] = vec4(detailScale, 1.0, 1.0) * gl_MultiTexCoord0;\n"
|
|
"\n",
|
|
// frag_def
|
|
"uniform sampler2D detailMap;\n"
|
|
"varying vec2 fragDetailScale;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" if (isNormalMapped == 0)\n"
|
|
" diffuseTexel *= texture2D(detailMap, gl_TexCoord[1].st);\n"
|
|
" else\n"
|
|
" diffuseTexel *= texture2D(detailMap, commonTexCoord.st * fragDetailScale);\n"
|
|
" diffuseTexel.rgb *= 2.0;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_DIFFUSE_MODULATION,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
" gl_FrontColor = gl_Color;\n"
|
|
"\n",
|
|
// frag_def
|
|
"",
|
|
// frag_prog
|
|
" if (isLightingPass == 0)\n"
|
|
" result *= vec4(gl_Color);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_DIFFUSE_MAP2,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"",
|
|
// frag_prog
|
|
" if (isLightingPass == 0)\n"
|
|
" result *= diffuseTexel;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_HIGHPALOOKUP_MAP,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform sampler3D highPalookupMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" float highPalScale = 0.9921875; // for 6 bits\n"
|
|
" float highPalBias = 0.00390625;\n"
|
|
"\n"
|
|
" if (isLightingPass == 0)\n"
|
|
" result.rgb = texture3D(highPalookupMap, result.rgb * highPalScale + highPalBias).rgb;\n"
|
|
" diffuseTexel.rgb = texture3D(highPalookupMap, diffuseTexel.rgb * highPalScale + highPalBias).rgb;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_SPECULAR_MAP,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform sampler2D specMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" specTexel = texture2D(specMap, commonTexCoord.st);\n"
|
|
"\n"
|
|
" isSpecularMapped = 1;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_SPECULAR_MATERIAL,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform vec2 specMaterial;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" specularMaterial = specMaterial;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_MIRROR_MAP,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform sampler2DRect mirrorMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" vec4 mirrorTexel;\n"
|
|
" vec2 mirrorCoords;\n"
|
|
"\n"
|
|
" mirrorCoords = gl_FragCoord.st;\n"
|
|
" if (isNormalMapped == 1) {\n"
|
|
" mirrorCoords += 100.0 * (normalTexel.rg - 0.5);\n"
|
|
" }\n"
|
|
" mirrorTexel = texture2DRect(mirrorMap, mirrorCoords);\n"
|
|
" result = vec4((result.rgb * (1.0 - specTexel.a)) + (mirrorTexel.rgb * specTexel.rgb * specTexel.a), result.a);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_FOG,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
#ifdef PR_LINEAR_FOG
|
|
"uniform bool linearFog;\n"
|
|
#endif
|
|
"",
|
|
// frag_prog
|
|
" float fragDepth;\n"
|
|
" float fogFactor;\n"
|
|
"\n"
|
|
" fragDepth = gl_FragCoord.z / gl_FragCoord.w;\n"
|
|
#ifdef PR_LINEAR_FOG
|
|
" if (!linearFog) {\n"
|
|
#endif
|
|
" fragDepth *= fragDepth;\n"
|
|
" fogFactor = exp2(-gl_Fog.density * gl_Fog.density * fragDepth * 1.442695);\n"
|
|
#ifdef PR_LINEAR_FOG
|
|
" } else {\n"
|
|
" fogFactor = gl_Fog.scale * (gl_Fog.end - fragDepth);\n"
|
|
" fogFactor = clamp(fogFactor, 0.0, 1.0);"
|
|
" }\n"
|
|
#endif
|
|
" result.rgb = mix(gl_Fog.color.rgb, result.rgb, fogFactor);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_GLOW_MAP,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform sampler2D glowMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" vec4 glowTexel;\n"
|
|
"\n"
|
|
" glowTexel = texture2D(glowMap, commonTexCoord.st);\n"
|
|
" result = vec4((result.rgb * (1.0 - glowTexel.a)) + (glowTexel.rgb * glowTexel.a), result.a);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_PROJECTION_MAP,
|
|
// vert_def
|
|
"uniform mat4 shadowProjMatrix;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" gl_TexCoord[2] = shadowProjMatrix * curVertex;\n"
|
|
"\n",
|
|
// frag_def
|
|
"",
|
|
// frag_prog
|
|
"",
|
|
},
|
|
{
|
|
1 << PR_BIT_SHADOW_MAP,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform sampler2DShadow shadowMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" shadowResult = shadow2DProj(shadowMap, gl_TexCoord[2]).a;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_LIGHT_MAP,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform sampler2D lightMap;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" lightTexel = texture2D(lightMap, vec2(gl_TexCoord[2].s, -gl_TexCoord[2].t) / gl_TexCoord[2].q).rgb;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_SPOT_LIGHT,
|
|
// vert_def
|
|
"",
|
|
// vert_prog
|
|
"",
|
|
// frag_def
|
|
"uniform vec3 spotDir;\n"
|
|
"uniform vec2 spotRadius;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" spotVector = spotDir;\n"
|
|
" spotCosRadius = spotRadius;\n"
|
|
" isSpotLight = 1;\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_POINT_LIGHT,
|
|
// vert_def
|
|
"varying vec3 vertexNormal;\n"
|
|
"varying vec3 eyeVector;\n"
|
|
"varying vec3 lightVector;\n"
|
|
"varying vec3 tangentSpaceLightVector;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" vec3 vertexPos;\n"
|
|
"\n"
|
|
" vertexPos = vec3(gl_ModelViewMatrix * curVertex);\n"
|
|
" eyeVector = -vertexPos;\n"
|
|
" lightVector = gl_LightSource[0].ambient.rgb - vertexPos;\n"
|
|
"\n"
|
|
" if (isNormalMapped == 1) {\n"
|
|
" tangentSpaceLightVector = gl_LightSource[0].specular.rgb - vec3(curVertex);\n"
|
|
" tangentSpaceLightVector = TBN * tangentSpaceLightVector;\n"
|
|
" } else\n"
|
|
" vertexNormal = normalize(gl_NormalMatrix * curNormal);\n"
|
|
"\n",
|
|
// frag_def
|
|
"varying vec3 vertexNormal;\n"
|
|
"varying vec3 eyeVector;\n"
|
|
"varying vec3 lightVector;\n"
|
|
"varying vec3 tangentSpaceLightVector;\n"
|
|
"\n",
|
|
// frag_prog
|
|
" float pointLightDistance;\n"
|
|
" float lightAttenuation;\n"
|
|
" float spotAttenuation;\n"
|
|
" vec3 N, L, E, R, D;\n"
|
|
" vec3 lightDiffuse;\n"
|
|
" float lightSpecular;\n"
|
|
" float NdotL;\n"
|
|
" float spotCosAngle;\n"
|
|
"\n"
|
|
" L = normalize(lightVector);\n"
|
|
"\n"
|
|
" pointLightDistance = dot(lightVector,lightVector);\n"
|
|
" lightAttenuation = clamp(1.0 - pointLightDistance * gl_LightSource[0].linearAttenuation, 0.0, 1.0);\n"
|
|
" spotAttenuation = 1.0;\n"
|
|
"\n"
|
|
" if (isSpotLight == 1) {\n"
|
|
" D = normalize(spotVector);\n"
|
|
" spotCosAngle = dot(-L, D);\n"
|
|
" spotAttenuation = clamp((spotCosAngle - spotCosRadius.x) * spotCosRadius.y, 0.0, 1.0);\n"
|
|
" }\n"
|
|
"\n"
|
|
" if (isNormalMapped == 1) {\n"
|
|
" E = eyeVec;\n"
|
|
" N = normalize(2.0 * (normalTexel.rgb - 0.5));\n"
|
|
" L = normalize(tangentSpaceLightVector);\n"
|
|
" } else {\n"
|
|
" E = normalize(eyeVector);\n"
|
|
" N = normalize(vertexNormal);\n"
|
|
" }\n"
|
|
" NdotL = max(dot(N, L), 0.0);\n"
|
|
"\n"
|
|
" R = reflect(-L, N);\n"
|
|
"\n"
|
|
" lightDiffuse = gl_Color.a * shadowResult * lightTexel *\n"
|
|
" gl_LightSource[0].diffuse.rgb * lightAttenuation * spotAttenuation;\n"
|
|
" result += vec4(lightDiffuse * diffuseTexel.a * diffuseTexel.rgb * NdotL, 0.0);\n"
|
|
"\n"
|
|
" if (isSpecularMapped == 0)\n"
|
|
" specTexel.rgb = diffuseTexel.rgb * diffuseTexel.a;\n"
|
|
"\n"
|
|
" lightSpecular = pow( max(dot(R, E), 0.0), specularMaterial.x * specTexel.a) * specularMaterial.y;\n"
|
|
" result += vec4(lightDiffuse * specTexel.rgb * lightSpecular, 0.0);\n"
|
|
"\n",
|
|
},
|
|
{
|
|
1 << PR_BIT_FOOTER,
|
|
// vert_def
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" vec4 curVertex = gl_Vertex;\n"
|
|
" vec3 curNormal = gl_Normal;\n"
|
|
" int isNormalMapped = 0;\n"
|
|
" mat3 TBN;\n"
|
|
"\n"
|
|
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
|
|
"\n",
|
|
// vert_prog
|
|
" gl_Position = gl_ModelViewProjectionMatrix * curVertex;\n"
|
|
"}\n",
|
|
// frag_def
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" vec3 commonTexCoord = vec3(gl_TexCoord[0].st, 0.0);\n"
|
|
" vec4 result = vec4(1.0, 1.0, 1.0, 1.0);\n"
|
|
" vec4 diffuseTexel = vec4(1.0, 1.0, 1.0, 1.0);\n"
|
|
" vec4 specTexel = vec4(1.0, 1.0, 1.0, 1.0);\n"
|
|
" vec4 normalTexel;\n"
|
|
" int isLightingPass = 0;\n"
|
|
" int isNormalMapped = 0;\n"
|
|
" int isSpecularMapped = 0;\n"
|
|
" vec3 eyeVec;\n"
|
|
" int isSpotLight = 0;\n"
|
|
" vec3 spotVector;\n"
|
|
" vec2 spotCosRadius;\n"
|
|
" float shadowResult = 1.0;\n"
|
|
" vec2 specularMaterial = vec2(15.0, 1.0);\n"
|
|
" vec3 lightTexel = vec3(1.0, 1.0, 1.0);\n"
|
|
"\n",
|
|
// frag_prog
|
|
" gl_FragColor = result;\n"
|
|
"}\n",
|
|
}
|
|
};
|
|
|
|
_prprograminfo prprograms[1 << PR_BIT_COUNT];
|
|
|
|
int32_t overridematerial;
|
|
int32_t globaloldoverridematerial;
|
|
|
|
int32_t rotatespritematerialbits;
|
|
|
|
// RENDER TARGETS
|
|
_prrt *prrts;
|
|
|
|
// CONTROL
|
|
GLfloat spritemodelview[16];
|
|
GLfloat mdspritespace[4][4];
|
|
GLfloat rootmodelviewmatrix[16];
|
|
GLfloat *curmodelviewmatrix;
|
|
GLfloat rootskymodelviewmatrix[16];
|
|
GLfloat *curskymodelviewmatrix;
|
|
|
|
static int16_t sectorqueue[MAXSECTORS];
|
|
static int16_t querydelay[MAXSECTORS];
|
|
static GLuint queryid[MAXWALLS];
|
|
static int16_t drawingstate[MAXSECTORS];
|
|
|
|
int16_t *cursectormasks;
|
|
int16_t *cursectormaskcount;
|
|
|
|
float horizang;
|
|
fix16_t viewangle;
|
|
|
|
int32_t depth;
|
|
_prmirror mirrors[10];
|
|
|
|
#if defined __clang__ && defined __APPLE__
|
|
// XXX: OS X 10.9 deprecated GLUtesselator.
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
#endif
|
|
GLUtesselator* prtess;
|
|
#if defined __clang__ && defined __APPLE__
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
static int16_t cursky;
|
|
static char curskypal;
|
|
static int8_t curskyshade;
|
|
static float curskyangmul = 1;
|
|
|
|
_pranimatespritesinfo asi;
|
|
|
|
int32_t polymersearching;
|
|
|
|
int32_t culledface;
|
|
|
|
// EXTERNAL FUNCTIONS
|
|
int32_t polymer_init(void)
|
|
{
|
|
int32_t i, j, t = getticks();
|
|
|
|
if (pr_verbosity >= 1) OSD_Printf("Initializing Polymer subsystem...\n");
|
|
|
|
if (!glinfo.texnpot ||
|
|
!glinfo.depthtex ||
|
|
!glinfo.shadow ||
|
|
!glinfo.fbos ||
|
|
!glinfo.rect ||
|
|
!glinfo.multitex ||
|
|
!glinfo.vbos ||
|
|
!glinfo.occlusionqueries ||
|
|
!glinfo.glsl)
|
|
{
|
|
OSD_Printf("PR : Your video card driver/combo doesn't support the necessary features!\n");
|
|
OSD_Printf("PR : Disabling Polymer...\n");
|
|
return 0;
|
|
}
|
|
|
|
// clean up existing stuff since it will be initialized again if we're re-entering here
|
|
polymer_uninit();
|
|
|
|
Bmemset(&prsectors[0], 0, sizeof(prsectors[0]) * MAXSECTORS);
|
|
Bmemset(&prwalls[0], 0, sizeof(prwalls[0]) * MAXWALLS);
|
|
|
|
prtess = bgluNewTess();
|
|
if (prtess == 0)
|
|
{
|
|
OSD_Printf("PR : Tessellation object initialization failed!\n");
|
|
return 0;
|
|
}
|
|
|
|
polymer_loadboard();
|
|
|
|
polymer_initartsky();
|
|
skyboxdatavbo = 0;
|
|
|
|
i = 0;
|
|
while (i < nextmodelid)
|
|
{
|
|
if (models[i])
|
|
{
|
|
md3model_t* m;
|
|
|
|
m = (md3model_t*)models[i];
|
|
m->indices = NULL;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < (1 << PR_BIT_COUNT))
|
|
{
|
|
prprograms[i].handle = 0;
|
|
i++;
|
|
}
|
|
|
|
overridematerial = 0xFFFFFFFF;
|
|
|
|
polymersearching = FALSE;
|
|
|
|
polymer_initrendertargets(pr_shadowcount + 1);
|
|
|
|
// Prime highpalookup maps
|
|
i = 0;
|
|
while (i < MAXBASEPALS)
|
|
{
|
|
j = 0;
|
|
while (j < MAXPALOOKUPS)
|
|
{
|
|
if (prhighpalookups[i][j].data)
|
|
{
|
|
glGenTextures(1, &prhighpalookups[i][j].map);
|
|
glBindTexture(GL_TEXTURE_3D, prhighpalookups[i][j].map);
|
|
glTexImage3D(GL_TEXTURE_3D, // target
|
|
0, // mip level
|
|
GL_RGBA, // internalFormat
|
|
PR_HIGHPALOOKUP_DIM, // width
|
|
PR_HIGHPALOOKUP_DIM, // height
|
|
PR_HIGHPALOOKUP_DIM, // depth
|
|
0, // border
|
|
GL_BGRA, // upload format
|
|
GL_UNSIGNED_BYTE, // upload component type
|
|
prhighpalookups[i][j].data); // data pointer
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glBindTexture(GL_TEXTURE_3D, 0);
|
|
}
|
|
j++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
#ifndef __APPLE__
|
|
if (glinfo.debugoutput) {
|
|
// Enable everything.
|
|
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
|
|
glDebugMessageCallbackARB((GLDEBUGPROCARB)polymer_debugoutputcallback, NULL);
|
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
|
}
|
|
#endif
|
|
|
|
if (pr_verbosity >= 1) OSD_Printf("PR : Initialization complete in %d ms.\n", getticks()-t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void polymer_uninit(void)
|
|
{
|
|
int32_t i, j;
|
|
|
|
if (prtess)
|
|
{
|
|
bgluDeleteTess(prtess);
|
|
prtess = NULL;
|
|
}
|
|
|
|
polymer_freeboard();
|
|
|
|
polymer_initrendertargets(0);
|
|
|
|
i = 0;
|
|
while (i < MAXBASEPALS)
|
|
{
|
|
j = 0;
|
|
while (j < MAXPALOOKUPS)
|
|
{
|
|
// if (prhighpalookups[i][j].data) {
|
|
// DO_FREE_AND_NULL(prhighpalookups[i][j].data);
|
|
// }
|
|
if (prhighpalookups[i][j].map) {
|
|
glDeleteTextures(1, &prhighpalookups[i][j].map);
|
|
prhighpalookups[i][j].map = 0;
|
|
}
|
|
j++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (plpool)
|
|
{
|
|
_prplanelist* next = plpool->n;
|
|
|
|
Bfree(plpool);
|
|
plpool = next;
|
|
i++;
|
|
}
|
|
|
|
if (pr_verbosity >= 3)
|
|
OSD_Printf("PR: freed %d planelists\n", i);
|
|
}
|
|
|
|
void polymer_setaspect(int32_t ang)
|
|
{
|
|
float aspect;
|
|
float fang = (float)ang * atanf(fviewingrange*(1.f/65536.f)) * (4.f/fPI);
|
|
|
|
if (pr_customaspect != 0.0f)
|
|
aspect = pr_customaspect;
|
|
else
|
|
aspect = (float)(windowxy2.x-windowxy1.x+1) /
|
|
(float)(windowxy2.y-windowxy1.y+1);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
bgluPerspective(fang * (360.f/2048.f), aspect, 0.01f, 100.0f);
|
|
}
|
|
|
|
void polymer_glinit(void)
|
|
{
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClearStencil(0);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
glViewport(windowxy1.x, yres-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
|
|
|
|
// texturing
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
if (pr_wireframe)
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
else
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
|
|
polymer_setaspect(pr_fov);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
glDisable(GL_FOG);
|
|
|
|
culledface = GL_BACK;
|
|
glCullFace(GL_BACK);
|
|
glFrontFace(GL_CCW);
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
void polymer_resetlights(void)
|
|
{
|
|
int32_t i;
|
|
_prsector *s;
|
|
_prwall *w;
|
|
|
|
i = 0;
|
|
while (i < numsectors)
|
|
{
|
|
s = prsectors[i];
|
|
|
|
if (!s) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
polymer_resetplanelights(&s->floor);
|
|
polymer_resetplanelights(&s->ceil);
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < numwalls)
|
|
{
|
|
w = prwalls[i];
|
|
|
|
if (!w) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
polymer_resetplanelights(&w->wall);
|
|
polymer_resetplanelights(&w->over);
|
|
polymer_resetplanelights(&w->mask);
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < PR_MAXLIGHTS)
|
|
{
|
|
prlights[i].flags.active = 0;
|
|
i++;
|
|
}
|
|
|
|
lightcount = 0;
|
|
|
|
if (!loadmaphack(NULL))
|
|
OSD_Printf("polymer_resetlights: reloaded maphack\n");
|
|
}
|
|
|
|
void polymer_loadboard(void)
|
|
{
|
|
int32_t i;
|
|
|
|
polymer_freeboard();
|
|
|
|
// in the big map buffer, sectors have floor and ceiling vertices for each wall first, then walls
|
|
prwalldataoffset = numwalls * 2 * sizeof(_prvert);
|
|
|
|
glGenBuffers(1, &prmapvbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
|
|
glBufferData(GL_ARRAY_BUFFER, prwalldataoffset + (numwalls * prwalldatasize), NULL, mapvbousage);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
glGenBuffers(1, &prindexringvbo);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prindexringvbo);
|
|
|
|
if (pr_buckets)
|
|
{
|
|
glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, prindexringsize * sizeof(GLuint), NULL, prindexringmapflags | GL_DYNAMIC_STORAGE_BIT);
|
|
prindexring = (GLuint*)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, prindexringsize * sizeof(GLuint), prindexringmapflags);
|
|
}
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
i = 0;
|
|
while (i < numsectors)
|
|
{
|
|
polymer_initsector(i);
|
|
polymer_updatesector(i);
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < numwalls)
|
|
{
|
|
polymer_initwall(i);
|
|
polymer_updatewall(i);
|
|
i++;
|
|
}
|
|
|
|
polymer_getsky();
|
|
|
|
polymer_resetlights();
|
|
|
|
if (pr_verbosity >= 1 && numsectors) OSD_Printf("PR : Board loaded.\n");
|
|
}
|
|
|
|
// The parallaxed ART sky angle divisor corresponding to a horizfrac of 32768.
|
|
#define DEFAULT_ARTSKY_ANGDIV 4.3027f
|
|
|
|
void polymer_drawrooms(int32_t daposx, int32_t daposy, int32_t daposz, fix16_t daang, fix16_t dahoriz, int16_t dacursectnum)
|
|
{
|
|
int16_t cursectnum;
|
|
int32_t i, cursectflorz, cursectceilz;
|
|
float skyhoriz, ang, tiltang;
|
|
float pos[3];
|
|
pthtyp* pth;
|
|
|
|
if (getrendermode() == REND_CLASSIC) return;
|
|
|
|
begindrawing();
|
|
|
|
// TODO: support for screen resizing
|
|
// frameoffset = frameplace + windowxy1.y*bytesperline + windowxy1.x;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Drawing rooms...\n");
|
|
|
|
// fogcalc_old needs this
|
|
gvisibility = ((float)globalvisibility)*FOGSCALE;
|
|
|
|
ang = fix16_to_float(daang) * (360.f/2048.f);
|
|
horizang = (float)(-getangle(128, fix16_to_int(dahoriz)-100)) * (360.f/2048.f);
|
|
tiltang = (gtang * 90.0f);
|
|
|
|
pos[0] = (float)daposy;
|
|
pos[1] = -(float)(daposz) / 16.0f;
|
|
pos[2] = -(float)daposx;
|
|
|
|
polymer_updatelights();
|
|
|
|
// polymer_resetlights();
|
|
// if (pr_lighting)
|
|
// polymer_applylights();
|
|
|
|
depth = 0;
|
|
|
|
if (pr_shadows && lightcount && (pr_shadowcount > 0))
|
|
polymer_prepareshadows();
|
|
|
|
// hack for parallax skies
|
|
skyhoriz = horizang;
|
|
if (skyhoriz < -180.0f)
|
|
skyhoriz += 360.0f;
|
|
|
|
drawingskybox = 1;
|
|
pth = texcache_fetch(cursky, 0, 0, DAMETH_NOMASK);
|
|
drawingskybox = 0;
|
|
|
|
// if it's not a skybox, make the sky parallax
|
|
// DEFAULT_ARTSKY_ANGDIV is computed from eyeballed values
|
|
// need to recompute it if we ever change the max horiz amplitude
|
|
if (!pth || !(pth->flags & PTH_SKYBOX))
|
|
skyhoriz *= curskyangmul;
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glRotatef(tiltang, 0.0f, 0.0f, -1.0f);
|
|
glRotatef(skyhoriz, 1.0f, 0.0f, 0.0f);
|
|
glRotatef(ang, 0.0f, 1.0f, 0.0f);
|
|
|
|
glScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
|
|
glTranslatef(-pos[0], -pos[1], -pos[2]);
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, rootskymodelviewmatrix);
|
|
|
|
curskymodelviewmatrix = rootskymodelviewmatrix;
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glRotatef(tiltang, 0.0f, 0.0f, -1.0f);
|
|
glRotatef(horizang, 1.0f, 0.0f, 0.0f);
|
|
glRotatef(ang, 0.0f, 1.0f, 0.0f);
|
|
|
|
glScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
|
|
glTranslatef(-pos[0], -pos[1], -pos[2]);
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, rootmodelviewmatrix);
|
|
|
|
cursectnum = dacursectnum;
|
|
updatesectorbreadth(daposx, daposy, &cursectnum);
|
|
|
|
if (cursectnum >= 0 && cursectnum < numsectors)
|
|
dacursectnum = cursectnum;
|
|
else if (pr_verbosity>=2)
|
|
OSD_Printf("PR : got sector %d after update!\n", cursectnum);
|
|
|
|
// unflag all sectors
|
|
i = numsectors-1;
|
|
while (i >= 0)
|
|
{
|
|
prsectors[i]->flags.uptodate = 0;
|
|
prsectors[i]->wallsproffset = 0.0f;
|
|
prsectors[i]->floorsproffset = 0.0f;
|
|
i--;
|
|
}
|
|
i = numwalls-1;
|
|
while (i >= 0)
|
|
{
|
|
prwalls[i]->flags.uptodate = 0;
|
|
i--;
|
|
}
|
|
|
|
if (searchit == 2 && !polymersearching)
|
|
{
|
|
globaloldoverridematerial = overridematerial;
|
|
overridematerial = prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit;
|
|
overridematerial |= prprogrambits[PR_BIT_DIFFUSE_MAP2].bit;
|
|
polymersearching = TRUE;
|
|
}
|
|
if (!searchit && polymersearching) {
|
|
overridematerial = globaloldoverridematerial;
|
|
polymersearching = FALSE;
|
|
}
|
|
|
|
if (dacursectnum > -1 && dacursectnum < numsectors)
|
|
getzsofslope(dacursectnum, daposx, daposy, &cursectceilz, &cursectflorz);
|
|
|
|
// external view (editor)
|
|
if ((dacursectnum < 0) || (dacursectnum >= numsectors) ||
|
|
(daposz > cursectflorz) ||
|
|
(daposz < cursectceilz))
|
|
{
|
|
prcanbucket = 1;
|
|
|
|
if (!editstatus && pr_verbosity>=1)
|
|
{
|
|
if ((unsigned)dacursectnum < (unsigned)numsectors)
|
|
OSD_Printf("PR : EXT sec=%d z=%d (%d, %d)\n", dacursectnum, daposz, cursectflorz, cursectceilz);
|
|
else
|
|
OSD_Printf("PR : EXT sec=%d z=%d\n", dacursectnum, daposz);
|
|
}
|
|
|
|
curmodelviewmatrix = rootmodelviewmatrix;
|
|
i = numsectors-1;
|
|
while (i >= 0)
|
|
{
|
|
polymer_updatesector(i);
|
|
polymer_drawsector(i, FALSE);
|
|
polymer_scansprites(i, tsprite, &spritesortcnt);
|
|
i--;
|
|
}
|
|
|
|
i = numwalls-1;
|
|
while (i >= 0)
|
|
{
|
|
polymer_updatewall(i);
|
|
polymer_drawwall(sectorofwall(i), i);
|
|
i--;
|
|
}
|
|
|
|
polymer_emptybuckets();
|
|
|
|
viewangle = daang;
|
|
enddrawing();
|
|
return;
|
|
}
|
|
|
|
// GO!
|
|
polymer_displayrooms(dacursectnum);
|
|
|
|
curmodelviewmatrix = rootmodelviewmatrix;
|
|
|
|
// build globals used by rotatesprite
|
|
viewangle = daang;
|
|
set_globalang(daang);
|
|
|
|
// polymost globals used by polymost_dorotatesprite
|
|
gcosang = fcosglobalang*(1./262144.f);
|
|
gsinang = fsinglobalang*(1./262144.f);
|
|
gcosang2 = gcosang*fviewingrange*(1./65536.f);
|
|
gsinang2 = gsinang*fviewingrange*(1./65536.f);
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Rooms drawn.\n");
|
|
enddrawing();
|
|
}
|
|
|
|
void polymer_drawmasks(void)
|
|
{
|
|
glEnable(GL_ALPHA_TEST);
|
|
glEnable(GL_BLEND);
|
|
// glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
// while (--spritesortcnt)
|
|
// {
|
|
// tspriteptr[spritesortcnt] = &tsprite[spritesortcnt];
|
|
// polymer_drawsprite(spritesortcnt);
|
|
// }
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
if (cursectormaskcount) {
|
|
// We (kind of) queue sector masks near to far, so drawing them in reverse
|
|
// order is the sane approach here. Of course impossible cases will arise.
|
|
while (*cursectormaskcount) {
|
|
polymer_drawsector(cursectormasks[--(*cursectormaskcount)], TRUE);
|
|
}
|
|
|
|
// This should _always_ be called after a corresponding pr_displayrooms()
|
|
// unless we're in "external view" mode, which was checked above.
|
|
// Both the top-level game drawrooms and the recursive internal passes
|
|
// should be accounted for here. If these free cause corruption, there's
|
|
// an accounting bug somewhere.
|
|
DO_FREE_AND_NULL(cursectormaskcount);
|
|
DO_FREE_AND_NULL(cursectormasks);
|
|
}
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
// glDisable(GL_POLYGON_OFFSET_FILL);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
void polymer_editorpick(void)
|
|
{
|
|
GLubyte picked[3];
|
|
int16_t num;
|
|
|
|
glReadPixels(searchx, ydim - searchy, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, picked);
|
|
|
|
num = B_UNBUF16(&picked[1]);
|
|
|
|
searchstat = picked[0];
|
|
|
|
switch (searchstat) {
|
|
case 0: // wall
|
|
case 5: // botomwall
|
|
case 4: // 1-way/masked wall
|
|
searchsector = sectorofwall(num);
|
|
searchbottomwall = searchwall = num;
|
|
searchisbottom = (searchstat==5);
|
|
if (searchstat == 5) {
|
|
searchstat = 0;
|
|
if (wall[num].nextwall >= 0 && (wall[num].cstat & 2)) {
|
|
searchbottomwall = wall[num].nextwall;
|
|
}
|
|
}
|
|
break;
|
|
case 1: // floor
|
|
case 2: // ceiling
|
|
searchsector = num;
|
|
|
|
// Apologies to Plagman for littering here, but this feature is quite essential
|
|
{
|
|
GLdouble model[16];
|
|
GLdouble proj[16];
|
|
GLint view[4];
|
|
|
|
GLdouble x,y,z;
|
|
GLfloat scr[3], scrv[3];
|
|
GLdouble scrx,scry,scrz;
|
|
GLfloat dadepth;
|
|
|
|
int16_t k, bestk=0;
|
|
GLfloat bestwdistsq = (GLfloat)3.4e38, wdistsq;
|
|
GLfloat w1[2], w2[2], w21[2], pw1[2], pw2[2];
|
|
GLfloat ptonline[2];
|
|
GLfloat scrvxz[2];
|
|
GLfloat scrvxznorm, scrvxzn[2], scrpxz[2];
|
|
GLfloat w1d, w2d;
|
|
walltype *wal = &wall[sector[searchsector].wallptr];
|
|
|
|
GLfloat t, svcoeff, p[2];
|
|
GLfloat *pl;
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, model);
|
|
glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
|
glGetIntegerv(GL_VIEWPORT, view);
|
|
|
|
glReadPixels(searchx, ydim-searchy, 1,1, GL_DEPTH_COMPONENT, GL_FLOAT, &dadepth);
|
|
bgluUnProject(searchx, ydim-searchy, dadepth, model, proj, view, &x, &y, &z);
|
|
bgluUnProject(searchx, ydim-searchy, 0.0, model, proj, view, &scrx, &scry, &scrz);
|
|
|
|
scr[0]=scrx, scr[1]=scry, scr[2]=scrz;
|
|
|
|
scrv[0] = x-scrx;
|
|
scrv[1] = y-scry;
|
|
scrv[2] = z-scrz;
|
|
|
|
scrvxz[0] = x-scrx;
|
|
scrvxz[1] = z-scrz;
|
|
|
|
if (prsectors[searchsector]==NULL)
|
|
{
|
|
//OSD_Printf("polymer_editorpick: prsectors[searchsector]==NULL !!!\n");
|
|
searchwall = sector[num].wallptr;
|
|
}
|
|
else
|
|
{
|
|
if (searchstat==1)
|
|
pl = prsectors[searchsector]->ceil.plane;
|
|
else
|
|
pl = prsectors[searchsector]->floor.plane;
|
|
|
|
if (pl == NULL)
|
|
{
|
|
searchwall = sector[num].wallptr;
|
|
return;
|
|
}
|
|
|
|
t = dot3f(pl,scrv);
|
|
svcoeff = -(dot3f(pl,scr)+pl[3])/t;
|
|
|
|
// point on plane (x and z)
|
|
p[0] = scrx + svcoeff*scrv[0];
|
|
p[1] = scrz + svcoeff*scrv[2];
|
|
|
|
for (k=0; k<sector[searchsector].wallnum; k++)
|
|
{
|
|
w1[1] = -(float)wal[k].x;
|
|
w1[0] = (float)wal[k].y;
|
|
w2[1] = -(float)wall[wal[k].point2].x;
|
|
w2[0] = (float)wall[wal[k].point2].y;
|
|
|
|
scrvxznorm = sqrt(dot2f(scrvxz,scrvxz));
|
|
scrvxzn[0] = scrvxz[1]/scrvxznorm;
|
|
scrvxzn[1] = -scrvxz[0]/scrvxznorm;
|
|
|
|
relvec2f(p,w1, pw1);
|
|
relvec2f(p,w2, pw2);
|
|
relvec2f(w2,w1, w21);
|
|
|
|
w1d = dot2f(scrvxzn,pw1);
|
|
w2d = dot2f(scrvxzn,pw2);
|
|
w2d = -w2d;
|
|
if (w1d <= 0 || w2d <= 0)
|
|
continue;
|
|
|
|
ptonline[0] = w2[0]+(w2d/(w1d+w2d))*w21[0];
|
|
ptonline[1] = w2[1]+(w2d/(w1d+w2d))*w21[1];
|
|
relvec2f(p,ptonline, scrpxz);
|
|
if (dot2f(scrvxz,scrpxz)<0)
|
|
continue;
|
|
|
|
wdistsq = dot2f(scrpxz,scrpxz);
|
|
if (wdistsq < bestwdistsq)
|
|
{
|
|
bestk = k;
|
|
bestwdistsq = wdistsq;
|
|
}
|
|
}
|
|
|
|
searchwall = sector[searchsector].wallptr + bestk;
|
|
}
|
|
}
|
|
// :P
|
|
|
|
// searchwall = sector[num].wallptr;
|
|
break;
|
|
case 3:
|
|
// sprite
|
|
searchsector = sprite[num].sectnum;
|
|
searchwall = num;
|
|
break;
|
|
}
|
|
|
|
searchit = 0;
|
|
}
|
|
|
|
void polymer_inb4rotatesprite(int16_t tilenum, char pal, int8_t shade, int32_t method)
|
|
{
|
|
_prmaterial rotatespritematerial;
|
|
|
|
polymer_getbuildmaterial(&rotatespritematerial, tilenum, pal, shade, 0, method);
|
|
|
|
rotatespritematerialbits = polymer_bindmaterial(&rotatespritematerial, NULL, 0);
|
|
}
|
|
|
|
void polymer_postrotatesprite(void)
|
|
{
|
|
polymer_unbindmaterial(rotatespritematerialbits);
|
|
}
|
|
|
|
static void polymer_setupdiffusemodulation(_prplane *plane, GLubyte modulation, GLubyte *data)
|
|
{
|
|
plane->material.diffusemodulation[0] = modulation;
|
|
plane->material.diffusemodulation[1] = ((GLubyte *) data)[0];
|
|
plane->material.diffusemodulation[2] = ((GLubyte *) data)[1];
|
|
plane->material.diffusemodulation[3] = 0xFF;
|
|
}
|
|
|
|
static void polymer_drawsearchplane(_prplane *plane, GLubyte *oldcolor, GLubyte modulation, GLubyte *data)
|
|
{
|
|
Bmemcpy(oldcolor, plane->material.diffusemodulation, sizeof(GLubyte) * 4);
|
|
|
|
polymer_setupdiffusemodulation(plane, modulation, data);
|
|
|
|
polymer_drawplane(plane);
|
|
|
|
Bmemcpy(plane->material.diffusemodulation, oldcolor, sizeof(GLubyte) * 4);
|
|
}
|
|
|
|
void polymer_drawmaskwall(int32_t damaskwallcnt)
|
|
{
|
|
usectortype *sec;
|
|
walltype *wal;
|
|
_prwall *w;
|
|
GLubyte oldcolor[4];
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Masked wall %i...\n", damaskwallcnt);
|
|
|
|
sec = (usectortype *)§or[sectorofwall(maskwall[damaskwallcnt])];
|
|
wal = &wall[maskwall[damaskwallcnt]];
|
|
w = prwalls[maskwall[damaskwallcnt]];
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
if (searchit == 2) {
|
|
polymer_drawsearchplane(&w->mask, oldcolor, 0x04, (GLubyte *)&maskwall[damaskwallcnt]);
|
|
} else {
|
|
calc_and_apply_fog(wal->picnum, fogshade(wal->shade, wal->pal), sec->visibility, get_floor_fogpal(sec));
|
|
polymer_drawplane(&w->mask);
|
|
}
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
}
|
|
|
|
void polymer_drawsprite(int32_t snum)
|
|
{
|
|
int32_t i, j, cs;
|
|
_prsprite *s;
|
|
|
|
uspritetype *const tspr = tspriteptr[snum];
|
|
const usectortype *sec;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Sprite %i...\n", snum);
|
|
|
|
if (bad_tspr(tspr))
|
|
return;
|
|
|
|
if ((tspr->cstat & 8192) && (depth && !mirrors[depth-1].plane))
|
|
return;
|
|
|
|
if ((tspr->cstat & 16384) && (!depth || mirrors[depth-1].plane))
|
|
return;
|
|
|
|
DO_TILE_ANIM(tspr->picnum, tspr->owner+32768);
|
|
|
|
sec = (usectortype *)§or[tspr->sectnum];
|
|
calc_and_apply_fog(tspr->picnum, fogshade(tspr->shade, tspr->pal), sec->visibility,
|
|
get_floor_fogpal((usectortype *)§or[tspr->sectnum]));
|
|
|
|
if (usemodels && tile2model[Ptile2tile(tspr->picnum,tspr->pal)].modelid >= 0 &&
|
|
tile2model[Ptile2tile(tspr->picnum,tspr->pal)].framenum >= 0 &&
|
|
!(spriteext[tspr->owner].flags & SPREXT_NOTMD))
|
|
{
|
|
glEnable(GL_CULL_FACE);
|
|
SWITCH_CULL_DIRECTION;
|
|
polymer_drawmdsprite(tspr);
|
|
SWITCH_CULL_DIRECTION;
|
|
glDisable(GL_CULL_FACE);
|
|
return;
|
|
}
|
|
|
|
cs = tspr->cstat;
|
|
|
|
// I think messing with the tspr is safe at this point?
|
|
// If not, change that to modify a temp position in updatesprite itself.
|
|
// I don't think this flags are meant to change on the fly so it'd possibly
|
|
// be safe to cache a plane that has them applied.
|
|
if (spriteext[tspr->owner].flags & SPREXT_AWAY1)
|
|
{
|
|
tspr->x += sintable[(tspr->ang + 512) & 2047] >> 13;
|
|
tspr->y += sintable[tspr->ang & 2047] >> 13;
|
|
}
|
|
else if (spriteext[tspr->owner].flags & SPREXT_AWAY2)
|
|
{
|
|
tspr->x -= sintable[(tspr->ang + 512) & 2047] >> 13;
|
|
tspr->y -= sintable[tspr->ang & 2047] >> 13;
|
|
}
|
|
|
|
polymer_updatesprite(snum);
|
|
|
|
Bassert(tspr->owner < MAXSPRITES);
|
|
s = prsprites[tspr->owner];
|
|
|
|
if (s == NULL)
|
|
return;
|
|
|
|
switch ((tspr->cstat>>4) & 3)
|
|
{
|
|
case 1:
|
|
prsectors[tspr->sectnum]->wallsproffset += 0.5f;
|
|
if (!depth || mirrors[depth-1].plane)
|
|
glPolygonOffset(-1.0f, -1.0f);
|
|
break;
|
|
case 2:
|
|
prsectors[tspr->sectnum]->floorsproffset += 0.5f;
|
|
if (!depth || mirrors[depth-1].plane)
|
|
glPolygonOffset(-1.0f, -1.0f);
|
|
break;
|
|
}
|
|
|
|
if ((cs & 48) == 0)
|
|
{
|
|
int32_t curpriority = 0;
|
|
|
|
s->plane.lightcount = 0;
|
|
|
|
while ((curpriority < pr_maxlightpriority) && (!depth || mirrors[depth-1].plane))
|
|
{
|
|
i = j = 0;
|
|
while (j < lightcount)
|
|
{
|
|
while (!prlights[i].flags.active)
|
|
i++;
|
|
|
|
if (prlights[i].priority != curpriority)
|
|
{
|
|
i++;
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
if (polymer_planeinlight(&s->plane, &prlights[i]))
|
|
s->plane.lights[s->plane.lightcount++] = i;
|
|
|
|
i++;
|
|
j++;
|
|
}
|
|
curpriority++;
|
|
}
|
|
}
|
|
|
|
if ((tspr->cstat & 64) && (tspr->cstat & SPR_ALIGN_MASK))
|
|
{
|
|
if ((tspr->cstat & SPR_ALIGN_MASK)==SPR_FLOOR && (tspr->cstat & SPR_YFLIP))
|
|
SWITCH_CULL_DIRECTION;
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
|
|
if ((!depth || mirrors[depth-1].plane) && !pr_ati_nodepthoffset)
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
polymer_drawplane(&s->plane);
|
|
|
|
if ((!depth || mirrors[depth-1].plane) && !pr_ati_nodepthoffset)
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
if ((tspr->cstat & 64) && (tspr->cstat & SPR_ALIGN_MASK))
|
|
{
|
|
if ((tspr->cstat & SPR_ALIGN_MASK)==SPR_FLOOR && (tspr->cstat & SPR_YFLIP))
|
|
SWITCH_CULL_DIRECTION;
|
|
glDisable(GL_CULL_FACE);
|
|
}
|
|
}
|
|
|
|
void polymer_setanimatesprites(animatespritesptr animatesprites, int32_t x, int32_t y, int32_t a, int32_t smoothratio)
|
|
{
|
|
asi.animatesprites = animatesprites;
|
|
asi.x = x;
|
|
asi.y = y;
|
|
asi.a = a;
|
|
asi.smoothratio = smoothratio;
|
|
}
|
|
|
|
int16_t polymer_addlight(_prlight* light)
|
|
{
|
|
int32_t lighti;
|
|
|
|
if (lightcount >= PR_MAXLIGHTS || light->priority > pr_maxlightpriority || !pr_lighting)
|
|
return -1;
|
|
|
|
if ((light->sector == -1) || (light->sector >= numsectors))
|
|
return -1;
|
|
|
|
lighti = 0;
|
|
while ((lighti < PR_MAXLIGHTS) && (prlights[lighti].flags.active))
|
|
lighti++;
|
|
|
|
if (lighti == PR_MAXLIGHTS)
|
|
return -1;
|
|
#if 0
|
|
// Spot lights disabled on ATI cards because they cause crashes with
|
|
// Catalyst 12.8 drivers.
|
|
// See: http://forums.duke4.net/topic/5723-hrp-polymer-crash/
|
|
if (pr_ati_fboworkaround && light->radius)
|
|
return -1;
|
|
#endif
|
|
Bmemcpy(&prlights[lighti], light, sizeof(_prlight));
|
|
|
|
if (light->radius) {
|
|
polymer_processspotlight(&prlights[lighti]);
|
|
|
|
// get the texture handle for the lightmap
|
|
if (light->tilenum > 0) {
|
|
int16_t picnum = light->tilenum;
|
|
pthtyp* pth;
|
|
|
|
DO_TILE_ANIM(picnum, 0);
|
|
|
|
if (!waloff[picnum])
|
|
loadtile(picnum);
|
|
|
|
pth = NULL;
|
|
pth = texcache_fetch(picnum, 0, 0, DAMETH_NOMASK);
|
|
|
|
if (pth)
|
|
light->lightmap = pth->glpic;
|
|
}
|
|
}
|
|
|
|
prlights[lighti].flags.isinview = 0;
|
|
prlights[lighti].flags.active = 1;
|
|
|
|
prlights[lighti].flags.invalidate = 0;
|
|
|
|
prlights[lighti].planecount = 0;
|
|
prlights[lighti].planelist = NULL;
|
|
|
|
polymer_culllight(lighti);
|
|
|
|
lightcount++;
|
|
|
|
return lighti;
|
|
}
|
|
|
|
void polymer_deletelight(int16_t lighti)
|
|
{
|
|
if (!prlights[lighti].flags.active)
|
|
{
|
|
#ifdef DEBUGGINGAIDS
|
|
if (pr_verbosity >= 2)
|
|
OSD_Printf("PR : Called polymer_deletelight on inactive light\n");
|
|
// currently known cases: when reloading maphack lights (didn't set maphacklightcnt=0
|
|
// but did loadmaphack()->delete_maphack_lights() after polymer_resetlights())
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
polymer_removelight(lighti);
|
|
|
|
prlights[lighti].flags.active = 0;
|
|
|
|
lightcount--;
|
|
}
|
|
|
|
void polymer_invalidatelights(void)
|
|
{
|
|
int32_t i = PR_MAXLIGHTS-1;
|
|
|
|
do
|
|
prlights[i].flags.invalidate = prlights[i].flags.active;
|
|
while (i--);
|
|
}
|
|
|
|
void polymer_texinvalidate(void)
|
|
{
|
|
int32_t i;
|
|
|
|
i = 0;
|
|
|
|
while (i < MAXSPRITES) {
|
|
polymer_invalidatesprite(i);
|
|
i++;
|
|
}
|
|
|
|
i = numsectors - 1;
|
|
|
|
if (!numsectors || !prsectors[i])
|
|
return;
|
|
|
|
do
|
|
prsectors[i--]->flags.invalidtex = 1;
|
|
while (i >= 0);
|
|
|
|
i = numwalls - 1;
|
|
do
|
|
prwalls[i--]->flags.invalidtex = 1;
|
|
while (i >= 0);
|
|
}
|
|
|
|
void polymer_definehighpalookup(char basepalnum, char palnum, char *data)
|
|
{
|
|
prhighpalookups[basepalnum][palnum].data = (char *)Xmalloc(PR_HIGHPALOOKUP_DATA_SIZE);
|
|
|
|
Bmemcpy(prhighpalookups[basepalnum][palnum].data, data, PR_HIGHPALOOKUP_DATA_SIZE);
|
|
}
|
|
|
|
int32_t polymer_havehighpalookup(int32_t basepalnum, int32_t palnum)
|
|
{
|
|
if ((uint32_t)basepalnum >= MAXBASEPALS || (uint32_t)palnum >= MAXPALOOKUPS)
|
|
return 0;
|
|
|
|
return (prhighpalookups[basepalnum][palnum].data != NULL);
|
|
}
|
|
|
|
|
|
// CORE
|
|
static void polymer_displayrooms(const int16_t dacursectnum)
|
|
{
|
|
usectortype *sec;
|
|
int32_t i;
|
|
int16_t bunchnum;
|
|
int16_t ns;
|
|
GLint result;
|
|
int16_t doquery;
|
|
int32_t front;
|
|
int32_t back;
|
|
GLfloat localskymodelviewmatrix[16];
|
|
GLfloat localmodelviewmatrix[16];
|
|
GLfloat localprojectionmatrix[16];
|
|
float frustum[5 * 4];
|
|
int32_t localspritesortcnt;
|
|
uspritetype localtsprite[MAXSPRITESONSCREEN];
|
|
int16_t localmaskwall[MAXWALLSB];
|
|
int16_t localmaskwallcnt;
|
|
_prmirror mirrorlist[10];
|
|
int mirrorcount;
|
|
int16_t *localsectormasks;
|
|
int16_t *localsectormaskcount;
|
|
int32_t gx, gy, gz, px, py, pz;
|
|
GLdouble plane[4];
|
|
float coeff;
|
|
|
|
curmodelviewmatrix = localmodelviewmatrix;
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, localmodelviewmatrix);
|
|
glGetFloatv(GL_PROJECTION_MATRIX, localprojectionmatrix);
|
|
|
|
polymer_extractfrustum(localmodelviewmatrix, localprojectionmatrix, frustum);
|
|
|
|
Bmemset(querydelay, 0, sizeof(int16_t) * numsectors);
|
|
Bmemset(queryid, 0, sizeof(GLuint) * numwalls);
|
|
Bmemset(drawingstate, 0, sizeof(int16_t) * numsectors);
|
|
|
|
front = 0;
|
|
back = 1;
|
|
sectorqueue[0] = dacursectnum;
|
|
drawingstate[dacursectnum] = 1;
|
|
|
|
localspritesortcnt = localmaskwallcnt = 0;
|
|
|
|
mirrorcount = 0;
|
|
|
|
localsectormasks = (int16_t *)Xmalloc(sizeof(int16_t) * numsectors);
|
|
localsectormaskcount = (int16_t *)Xcalloc(sizeof(int16_t), 1);
|
|
cursectormasks = localsectormasks;
|
|
cursectormaskcount = localsectormaskcount;
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
polymer_drawsky(cursky, curskypal, curskyshade);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
// depth-only occlusion testing pass
|
|
// overridematerial = 0;
|
|
|
|
prcanbucket = 1;
|
|
|
|
while (front != back)
|
|
{
|
|
sec = (usectortype *)§or[sectorqueue[front]];
|
|
|
|
polymer_pokesector(sectorqueue[front]);
|
|
polymer_drawsector(sectorqueue[front], FALSE);
|
|
polymer_scansprites(sectorqueue[front], localtsprite, &localspritesortcnt);
|
|
|
|
doquery = 0;
|
|
|
|
i = sec->wallnum-1;
|
|
do
|
|
{
|
|
// if we have a level boundary somewhere in the sector,
|
|
// consider these walls as visportals
|
|
if (wall[sec->wallptr + i].nextsector < 0 && pr_buckets == 0)
|
|
doquery = 1;
|
|
}
|
|
while (--i >= 0);
|
|
|
|
i = sec->wallnum-1;
|
|
while (i >= 0)
|
|
{
|
|
if ((wall[sec->wallptr + i].nextsector >= 0) &&
|
|
(wallvisible(globalposx, globalposy, sec->wallptr + i)) &&
|
|
(polymer_planeinfrustum(&prwalls[sec->wallptr + i]->mask, frustum)))
|
|
{
|
|
if ((prwalls[sec->wallptr + i]->mask.vertcount == 4) &&
|
|
!(prwalls[sec->wallptr + i]->underover & 4) &&
|
|
!(prwalls[sec->wallptr + i]->underover & 8))
|
|
{
|
|
// early exit for closed sectors
|
|
_prwall *w;
|
|
|
|
w = prwalls[sec->wallptr + i];
|
|
|
|
if ((w->mask.buffer[0].y >= w->mask.buffer[3].y) &&
|
|
(w->mask.buffer[1].y >= w->mask.buffer[2].y))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ((wall[sec->wallptr + i].cstat & 48) == 16)
|
|
{
|
|
int pic = wall[sec->wallptr + i].overpicnum;
|
|
|
|
if (tilesiz[pic].x > 0 && tilesiz[pic].y > 0)
|
|
localmaskwall[localmaskwallcnt++] = sec->wallptr + i;
|
|
}
|
|
|
|
if (!depth && (overridematerial & prprogrambits[PR_BIT_MIRROR_MAP].bit) &&
|
|
wall[sec->wallptr + i].overpicnum == 560 &&
|
|
wall[sec->wallptr + i].cstat & 32)
|
|
{
|
|
mirrorlist[mirrorcount].plane = &prwalls[sec->wallptr + i]->mask;
|
|
mirrorlist[mirrorcount].sectnum = sectorqueue[front];
|
|
mirrorlist[mirrorcount].wallnum = sec->wallptr + i;
|
|
mirrorcount++;
|
|
}
|
|
|
|
if (!(wall[sec->wallptr + i].cstat & 32)) {
|
|
if (doquery && (!drawingstate[wall[sec->wallptr + i].nextsector]))
|
|
{
|
|
float pos[3], sqdist;
|
|
int32_t oldoverridematerial;
|
|
|
|
pos[0] = fglobalposy;
|
|
pos[1] = fglobalposz * (-1.f/16.f);
|
|
pos[2] = -fglobalposx;
|
|
|
|
sqdist = prwalls[sec->wallptr + i]->mask.plane[0] * pos[0] +
|
|
prwalls[sec->wallptr + i]->mask.plane[1] * pos[1] +
|
|
prwalls[sec->wallptr + i]->mask.plane[2] * pos[2] +
|
|
prwalls[sec->wallptr + i]->mask.plane[3];
|
|
|
|
// hack to avoid occlusion querying portals that are too close to the viewpoint
|
|
// this is needed because of the near z-clipping plane;
|
|
if (sqdist < 100)
|
|
queryid[sec->wallptr + i] = 0xFFFFFFFF;
|
|
else {
|
|
_prwall *w;
|
|
|
|
w = prwalls[sec->wallptr + i];
|
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glGenQueries(1, &queryid[sec->wallptr + i]);
|
|
glBeginQuery(GL_SAMPLES_PASSED, queryid[sec->wallptr + i]);
|
|
|
|
oldoverridematerial = overridematerial;
|
|
overridematerial = 0;
|
|
|
|
if ((w->underover & 4) && (w->underover & 1))
|
|
polymer_drawplane(&w->wall);
|
|
polymer_drawplane(&w->mask);
|
|
if ((w->underover & 8) && (w->underover & 2))
|
|
polymer_drawplane(&w->over);
|
|
|
|
overridematerial = oldoverridematerial;
|
|
|
|
glEndQuery(GL_SAMPLES_PASSED);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
}
|
|
} else
|
|
queryid[sec->wallptr + i] = 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
i--;
|
|
}
|
|
|
|
// Cram as much CPU or GPU work as we can between queuing the
|
|
// occlusion queries and reaping them.
|
|
i = sec->wallnum-1;
|
|
do
|
|
{
|
|
if (wallvisible(globalposx, globalposy, sec->wallptr + i))
|
|
polymer_drawwall(sectorqueue[front], sec->wallptr + i);
|
|
}
|
|
while (--i >= 0);
|
|
#ifdef YAX_ENABLE
|
|
// queue ROR neighbors
|
|
if ((bunchnum = yax_getbunch(sectorqueue[front], YAX_FLOOR)) >= 0) {
|
|
|
|
for (SECTORS_OF_BUNCH(bunchnum, YAX_CEILING, ns)) {
|
|
|
|
if (ns >= 0 && !drawingstate[ns] &&
|
|
polymer_planeinfrustum(&prsectors[ns]->ceil, frustum)) {
|
|
|
|
sectorqueue[back++] = ns;
|
|
drawingstate[ns] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((bunchnum = yax_getbunch(sectorqueue[front], YAX_CEILING)) >= 0) {
|
|
|
|
for (SECTORS_OF_BUNCH(bunchnum, YAX_FLOOR, ns)) {
|
|
|
|
if (ns >= 0 && !drawingstate[ns] &&
|
|
polymer_planeinfrustum(&prsectors[ns]->floor, frustum)) {
|
|
|
|
sectorqueue[back++] = ns;
|
|
drawingstate[ns] = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
i = sec->wallnum-1;
|
|
do
|
|
{
|
|
if ((queryid[sec->wallptr + i]) &&
|
|
(!drawingstate[wall[sec->wallptr + i].nextsector]))
|
|
{
|
|
// REAP
|
|
result = 0;
|
|
if (doquery && (queryid[sec->wallptr + i] != 0xFFFFFFFF))
|
|
{
|
|
glGetQueryObjectiv(queryid[sec->wallptr + i],
|
|
GL_QUERY_RESULT,
|
|
&result);
|
|
glDeleteQueries(1, &queryid[sec->wallptr + i]);
|
|
} else if (queryid[sec->wallptr + i] == 0xFFFFFFFF)
|
|
result = 1;
|
|
|
|
queryid[sec->wallptr + i] = 0;
|
|
|
|
if (result || !doquery)
|
|
{
|
|
sectorqueue[back++] = wall[sec->wallptr + i].nextsector;
|
|
drawingstate[wall[sec->wallptr + i].nextsector] = 1;
|
|
}
|
|
} else if (queryid[sec->wallptr + i] &&
|
|
queryid[sec->wallptr + i] != 0xFFFFFFFF)
|
|
{
|
|
glDeleteQueries(1, &queryid[sec->wallptr + i]);
|
|
queryid[sec->wallptr + i] = 0;
|
|
}
|
|
}
|
|
while (--i >= 0);
|
|
|
|
front++;
|
|
}
|
|
|
|
polymer_emptybuckets();
|
|
|
|
// do the actual shaded drawing
|
|
// overridematerial = 0xFFFFFFFF;
|
|
|
|
// go through the sector queue again
|
|
// front = 0;
|
|
// while (front < back)
|
|
// {
|
|
// sec = §or[sectorqueue[front]];
|
|
//
|
|
// polymer_drawsector(sectorqueue[front]);
|
|
//
|
|
// i = 0;
|
|
// while (i < sec->wallnum)
|
|
// {
|
|
// polymer_drawwall(sectorqueue[front], sec->wallptr + i);
|
|
//
|
|
// i++;
|
|
// }
|
|
//
|
|
// front++;
|
|
// }
|
|
|
|
i = mirrorcount-1;
|
|
while (i >= 0)
|
|
{
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[0].fbo);
|
|
glPushAttrib(GL_VIEWPORT_BIT);
|
|
glViewport(windowxy1.x, yres-(windowxy2.y+1),windowxy2.x-windowxy1.x+1, windowxy2.y-windowxy1.y+1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
Bmemcpy(localskymodelviewmatrix, curskymodelviewmatrix, sizeof(GLfloat) * 16);
|
|
curskymodelviewmatrix = localskymodelviewmatrix;
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
|
|
plane[0] = mirrorlist[i].plane->plane[0];
|
|
plane[1] = mirrorlist[i].plane->plane[1];
|
|
plane[2] = mirrorlist[i].plane->plane[2];
|
|
plane[3] = mirrorlist[i].plane->plane[3];
|
|
|
|
glClipPlane(GL_CLIP_PLANE0, plane);
|
|
polymer_inb4mirror(mirrorlist[i].plane->buffer, mirrorlist[i].plane->plane);
|
|
SWITCH_CULL_DIRECTION;
|
|
//glEnable(GL_CLIP_PLANE0);
|
|
|
|
if (mirrorlist[i].wallnum >= 0)
|
|
preparemirror(globalposx, globalposy, qglobalang,
|
|
mirrorlist[i].wallnum, &gx, &gy, &viewangle);
|
|
|
|
gx = globalposx;
|
|
gy = globalposy;
|
|
gz = globalposz;
|
|
|
|
// map the player pos from build to polymer
|
|
px = globalposy;
|
|
py = -globalposz / 16;
|
|
pz = -globalposx;
|
|
|
|
// calculate new player position on the other side of the mirror
|
|
// this way the basic build visibility shit can be used (wallvisible)
|
|
coeff = mirrorlist[i].plane->plane[0] * px +
|
|
mirrorlist[i].plane->plane[1] * py +
|
|
mirrorlist[i].plane->plane[2] * pz +
|
|
mirrorlist[i].plane->plane[3];
|
|
|
|
coeff /= (float)(mirrorlist[i].plane->plane[0] * mirrorlist[i].plane->plane[0] +
|
|
mirrorlist[i].plane->plane[1] * mirrorlist[i].plane->plane[1] +
|
|
mirrorlist[i].plane->plane[2] * mirrorlist[i].plane->plane[2]);
|
|
|
|
px = (int32_t)(-coeff*mirrorlist[i].plane->plane[0]*2 + px);
|
|
py = (int32_t)(-coeff*mirrorlist[i].plane->plane[1]*2 + py);
|
|
pz = (int32_t)(-coeff*mirrorlist[i].plane->plane[2]*2 + pz);
|
|
|
|
// map back from polymer to build
|
|
set_globalpos(-pz, px, -py * 16);
|
|
|
|
mirrors[depth++] = mirrorlist[i];
|
|
polymer_displayrooms(mirrorlist[i].sectnum);
|
|
depth--;
|
|
|
|
cursectormasks = localsectormasks;
|
|
cursectormaskcount = localsectormaskcount;
|
|
|
|
set_globalpos(gx, gy, gz);
|
|
|
|
glDisable(GL_CLIP_PLANE0);
|
|
SWITCH_CULL_DIRECTION;
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
|
|
glPopAttrib();
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
|
|
mirrorlist[i].plane->material.mirrormap = prrts[0].color;
|
|
polymer_drawplane(mirrorlist[i].plane);
|
|
mirrorlist[i].plane->material.mirrormap = 0;
|
|
|
|
i--;
|
|
}
|
|
|
|
spritesortcnt = localspritesortcnt;
|
|
Bmemcpy(tsprite, localtsprite, sizeof(spritetype) * spritesortcnt);
|
|
maskwallcnt = localmaskwallcnt;
|
|
Bmemcpy(maskwall, localmaskwall, sizeof(int16_t) * maskwallcnt);
|
|
|
|
if (depth)
|
|
{
|
|
set_globalang(viewangle);
|
|
|
|
if (mirrors[depth - 1].plane)
|
|
display_mirror = 1;
|
|
polymer_animatesprites();
|
|
if (mirrors[depth - 1].plane)
|
|
display_mirror = 0;
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
drawmasks();
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void polymer_emptybuckets(void)
|
|
{
|
|
_prbucket *bucket = prbuckethead;
|
|
|
|
if (pr_buckets == 0)
|
|
return;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
|
|
glVertexPointer(3, GL_FLOAT, sizeof(_prvert), NULL);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(_prvert), (GLvoid *)(3 * sizeof(GLfloat)));
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prindexringvbo);
|
|
|
|
uint32_t indexcount = 0;
|
|
while (bucket != NULL)
|
|
{
|
|
indexcount += bucket->count;
|
|
|
|
bucket = bucket->next;
|
|
}
|
|
|
|
// ensure space in index ring, wrap otherwise
|
|
if (indexcount + prindexringoffset >= (unsigned)prindexringsize)
|
|
{
|
|
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
|
prindexring = (GLuint *)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, prindexringsize * sizeof(GLuint), GL_MAP_INVALIDATE_BUFFER_BIT | prindexringmapflags);
|
|
prindexringoffset = 0;
|
|
}
|
|
|
|
// put indices in the ring, all at once
|
|
bucket = prbuckethead;
|
|
|
|
while (bucket != NULL)
|
|
{
|
|
if (bucket->count == 0)
|
|
{
|
|
bucket = bucket->next;
|
|
continue;
|
|
}
|
|
|
|
memcpy(&prindexring[prindexringoffset], bucket->indices, bucket->count * sizeof(GLuint));
|
|
|
|
bucket->indiceoffset = (GLuint*)(prindexringoffset * sizeof(GLuint));
|
|
|
|
prindexringoffset += bucket->count;
|
|
|
|
bucket = bucket->next;
|
|
}
|
|
|
|
bucket = prbuckethead;
|
|
|
|
while (bucket != NULL)
|
|
{
|
|
if (bucket->count == 0)
|
|
{
|
|
bucket = bucket->next;
|
|
continue;
|
|
}
|
|
|
|
int32_t materialbits = polymer_bindmaterial(&bucket->material, NULL, 0);
|
|
|
|
glDrawElements(GL_TRIANGLES, bucket->count, GL_UNSIGNED_INT, bucket->indiceoffset);
|
|
|
|
polymer_unbindmaterial(materialbits);
|
|
|
|
bucket->count = 0;
|
|
|
|
bucket = bucket->next;
|
|
}
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
prcanbucket = 0;
|
|
}
|
|
|
|
static hashtable_t h_buckets = { 2048, NULL };
|
|
|
|
static _prbucket* polymer_findbucket(int16_t tilenum, char pal)
|
|
{
|
|
char propstr[16];
|
|
|
|
Bsprintf(propstr, "%d_%d", tilenum, pal);
|
|
|
|
_prbucket *bucketptr = prbuckethead ? (_prbucket *)hash_find(&h_buckets, propstr) : NULL;
|
|
|
|
// find bucket
|
|
|
|
// no buckets or no bucket found, create one
|
|
if (bucketptr == NULL || (intptr_t)bucketptr == -1)
|
|
{
|
|
bucketptr = (_prbucket *)Xmalloc(sizeof (_prbucket));
|
|
|
|
if (h_buckets.items == NULL)
|
|
hash_init(&h_buckets);
|
|
|
|
// insert, since most likely to use same pattern next frame
|
|
// will need to reorder by MRU first every once in a while
|
|
// or move to hashing lookup
|
|
bucketptr->next = prbuckethead;
|
|
prbuckethead = bucketptr;
|
|
|
|
bucketptr->tilenum = tilenum;
|
|
bucketptr->pal = pal;
|
|
|
|
bucketptr->invalidmaterial = 1;
|
|
|
|
bucketptr->count = 0;
|
|
bucketptr->buffersize = 1024;
|
|
bucketptr->indices = (GLuint *)Xmalloc(bucketptr->buffersize * sizeof(GLuint));
|
|
|
|
hash_add(&h_buckets, propstr, (intptr_t)bucketptr, 1);
|
|
}
|
|
|
|
return bucketptr;
|
|
}
|
|
|
|
static void polymer_bucketplane(_prplane* plane)
|
|
{
|
|
_prbucket *bucketptr = plane->bucket;
|
|
uint32_t neededindicecount;
|
|
int32_t i;
|
|
|
|
// we don't keep buffers for quads
|
|
neededindicecount = (plane->indicescount == 0) ? 6 : plane->indicescount;
|
|
|
|
// ensure size
|
|
while (bucketptr->count + neededindicecount >= bucketptr->buffersize)
|
|
{
|
|
bucketptr->buffersize *= 2;
|
|
bucketptr->indices = (GLuint *)Xrealloc(bucketptr->indices, bucketptr->buffersize * sizeof(GLuint));
|
|
}
|
|
|
|
// queue indices
|
|
i = 0;
|
|
|
|
if (plane->indicescount > 0)
|
|
{
|
|
while (i < plane->indicescount)
|
|
{
|
|
bucketptr->indices[bucketptr->count] = plane->indices[i] + plane->mapvbo_vertoffset;
|
|
bucketptr->count++;
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const uint32_t quadindices[6] = { 0, 1, 2, 0, 2, 3 };
|
|
|
|
while (i < 6)
|
|
{
|
|
bucketptr->indices[bucketptr->count] = quadindices[i] + plane->mapvbo_vertoffset;
|
|
bucketptr->count++;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void polymer_drawplane(_prplane* plane)
|
|
{
|
|
int32_t materialbits;
|
|
|
|
if (pr_nullrender >= 1) return;
|
|
|
|
// debug code for drawing plane inverse TBN
|
|
// glDisable(GL_TEXTURE_2D);
|
|
// glBegin(GL_LINES);
|
|
// glColor4f(1.0, 0.0, 0.0, 1.0);
|
|
// glVertex3f(plane->buffer[0],
|
|
// plane->buffer[1],
|
|
// plane->buffer[2]);
|
|
// glVertex3f(plane->buffer[0] + plane->t[0] * 50,
|
|
// plane->buffer[1] + plane->t[1] * 50,
|
|
// plane->buffer[2] + plane->t[2] * 50);
|
|
// glColor4f(0.0, 1.0, 0.0, 1.0);
|
|
// glVertex3f(plane->buffer[0],
|
|
// plane->buffer[1],
|
|
// plane->buffer[2]);
|
|
// glVertex3f(plane->buffer[0] + plane->b[0] * 50,
|
|
// plane->buffer[1] + plane->b[1] * 50,
|
|
// plane->buffer[2] + plane->b[2] * 50);
|
|
// glColor4f(0.0, 0.0, 1.0, 1.0);
|
|
// glVertex3f(plane->buffer[0],
|
|
// plane->buffer[1],
|
|
// plane->buffer[2]);
|
|
// glVertex3f(plane->buffer[0] + plane->n[0] * 50,
|
|
// plane->buffer[1] + plane->n[1] * 50,
|
|
// plane->buffer[2] + plane->n[2] * 50);
|
|
// glEnd();
|
|
// glEnable(GL_TEXTURE_2D);
|
|
|
|
// debug code for drawing plane normals
|
|
// glDisable(GL_TEXTURE_2D);
|
|
// glBegin(GL_LINES);
|
|
// glColor4f(1.0, 1.0, 1.0, 1.0);
|
|
// glVertex3f(plane->buffer[0],
|
|
// plane->buffer[1],
|
|
// plane->buffer[2]);
|
|
// glVertex3f(plane->buffer[0] + plane->plane[0] * 50,
|
|
// plane->buffer[1] + plane->plane[1] * 50,
|
|
// plane->buffer[2] + plane->plane[2] * 50);
|
|
// glEnd();
|
|
// glEnable(GL_TEXTURE_2D);
|
|
|
|
if (pr_buckets && pr_vbos > 0 && prcanbucket && plane->bucket)
|
|
{
|
|
polymer_bucketplane(plane);
|
|
return;
|
|
}
|
|
|
|
glNormal3f((float)(plane->plane[0]), (float)(plane->plane[1]), (float)(plane->plane[2]));
|
|
|
|
GLuint planevbo;
|
|
GLintptr geomfbooffset;
|
|
|
|
if (plane->mapvbo_vertoffset != (uint32_t)-1)
|
|
{
|
|
planevbo = prmapvbo;
|
|
geomfbooffset = plane->mapvbo_vertoffset * sizeof(_prvert);
|
|
}
|
|
else
|
|
{
|
|
planevbo = plane->vbo;
|
|
geomfbooffset = 0;
|
|
}
|
|
|
|
if (planevbo && (pr_vbos > 0))
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER, planevbo);
|
|
glVertexPointer(3, GL_FLOAT, sizeof(_prvert), (GLvoid *)(geomfbooffset));
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(_prvert), (GLvoid *)(geomfbooffset + (3 * sizeof(GLfloat))));
|
|
if (plane->indices)
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ivbo);
|
|
} else {
|
|
glVertexPointer(3, GL_FLOAT, sizeof(_prvert), &plane->buffer->x);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(_prvert), &plane->buffer->u);
|
|
}
|
|
|
|
curlight = 0;
|
|
do {
|
|
materialbits = polymer_bindmaterial(&plane->material, plane->lights, plane->lightcount);
|
|
|
|
if (materialbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
|
|
{
|
|
glVertexAttrib3fv(prprograms[materialbits].attrib_T, &plane->tbn[0][0]);
|
|
glVertexAttrib3fv(prprograms[materialbits].attrib_B, &plane->tbn[1][0]);
|
|
glVertexAttrib3fv(prprograms[materialbits].attrib_N, &plane->tbn[2][0]);
|
|
}
|
|
|
|
if (plane->indices)
|
|
{
|
|
if (planevbo && (pr_vbos > 0))
|
|
glDrawElements(GL_TRIANGLES, plane->indicescount, GL_UNSIGNED_SHORT, NULL);
|
|
else
|
|
glDrawElements(GL_TRIANGLES, plane->indicescount, GL_UNSIGNED_SHORT, plane->indices);
|
|
} else
|
|
glDrawArrays(GL_QUADS, 0, 4);
|
|
|
|
polymer_unbindmaterial(materialbits);
|
|
|
|
if (plane->lightcount && (!depth || mirrors[depth-1].plane))
|
|
prlights[plane->lights[curlight]].flags.isinview = 1;
|
|
|
|
curlight++;
|
|
} while ((curlight < plane->lightcount) && (curlight < pr_maxlightpasses) && (!depth || mirrors[depth-1].plane));
|
|
|
|
if (planevbo && (pr_vbos > 0))
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
if (plane->indices)
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
}
|
|
|
|
static inline void polymer_inb4mirror(_prvert* buffer, GLfloat* plane)
|
|
{
|
|
float pv;
|
|
float reflectionmatrix[16];
|
|
|
|
pv = buffer->x * plane[0] +
|
|
buffer->y * plane[1] +
|
|
buffer->z * plane[2];
|
|
|
|
reflectionmatrix[0] = 1 - (2 * plane[0] * plane[0]);
|
|
reflectionmatrix[1] = -2 * plane[0] * plane[1];
|
|
reflectionmatrix[2] = -2 * plane[0] * plane[2];
|
|
reflectionmatrix[3] = 0;
|
|
|
|
reflectionmatrix[4] = -2 * plane[0] * plane[1];
|
|
reflectionmatrix[5] = 1 - (2 * plane[1] * plane[1]);
|
|
reflectionmatrix[6] = -2 * plane[1] * plane[2];
|
|
reflectionmatrix[7] = 0;
|
|
|
|
reflectionmatrix[8] = -2 * plane[0] * plane[2];
|
|
reflectionmatrix[9] = -2 * plane[1] * plane[2];
|
|
reflectionmatrix[10] = 1 - (2 * plane[2] * plane[2]);
|
|
reflectionmatrix[11] = 0;
|
|
|
|
reflectionmatrix[12] = 2 * pv * plane[0];
|
|
reflectionmatrix[13] = 2 * pv * plane[1];
|
|
reflectionmatrix[14] = 2 * pv * plane[2];
|
|
reflectionmatrix[15] = 1;
|
|
|
|
glMultMatrixf(reflectionmatrix);
|
|
|
|
glPushMatrix();
|
|
glLoadMatrixf(curskymodelviewmatrix);
|
|
glMultMatrixf(reflectionmatrix);
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, curskymodelviewmatrix);
|
|
glPopMatrix();
|
|
}
|
|
|
|
static void polymer_animatesprites(void)
|
|
{
|
|
if (asi.animatesprites)
|
|
asi.animatesprites(globalposx, globalposy, fix16_to_int(viewangle), asi.smoothratio);
|
|
}
|
|
|
|
static void polymer_freeboard(void)
|
|
{
|
|
int32_t i;
|
|
|
|
i = 0;
|
|
while (i < MAXSECTORS)
|
|
{
|
|
if (prsectors[i])
|
|
{
|
|
Bfree(prsectors[i]->verts);
|
|
Bfree(prsectors[i]->floor.buffer);
|
|
Bfree(prsectors[i]->ceil.buffer);
|
|
Bfree(prsectors[i]->floor.indices);
|
|
Bfree(prsectors[i]->ceil.indices);
|
|
if (prsectors[i]->ceil.vbo) glDeleteBuffers(1, &prsectors[i]->ceil.vbo);
|
|
if (prsectors[i]->ceil.ivbo) glDeleteBuffers(1, &prsectors[i]->ceil.ivbo);
|
|
if (prsectors[i]->floor.vbo) glDeleteBuffers(1, &prsectors[i]->floor.vbo);
|
|
if (prsectors[i]->floor.ivbo) glDeleteBuffers(1, &prsectors[i]->floor.ivbo);
|
|
|
|
DO_FREE_AND_NULL(prsectors[i]);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < MAXWALLS)
|
|
{
|
|
if (prwalls[i])
|
|
{
|
|
Bfree(prwalls[i]->bigportal);
|
|
Bfree(prwalls[i]->mask.buffer);
|
|
Bfree(prwalls[i]->over.buffer);
|
|
// Bfree(prwalls[i]->cap);
|
|
Bfree(prwalls[i]->wall.buffer);
|
|
if (prwalls[i]->wall.vbo) glDeleteBuffers(1, &prwalls[i]->wall.vbo);
|
|
if (prwalls[i]->over.vbo) glDeleteBuffers(1, &prwalls[i]->over.vbo);
|
|
if (prwalls[i]->mask.vbo) glDeleteBuffers(1, &prwalls[i]->mask.vbo);
|
|
if (prwalls[i]->stuffvbo) glDeleteBuffers(1, &prwalls[i]->stuffvbo);
|
|
|
|
DO_FREE_AND_NULL(prwalls[i]);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < MAXSPRITES)
|
|
{
|
|
if (prsprites[i])
|
|
{
|
|
Bfree(prsprites[i]->plane.buffer);
|
|
if (prsprites[i]->plane.vbo) glDeleteBuffers(1, &prsprites[i]->plane.vbo);
|
|
DO_FREE_AND_NULL(prsprites[i]);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < MAXTILES)
|
|
{
|
|
polymer_invalidateartmap(i);
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < MAXBASEPALS)
|
|
{
|
|
if (prbasepalmaps[i])
|
|
{
|
|
glDeleteTextures(1, &prbasepalmaps[i]);
|
|
prbasepalmaps[i] = 0;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < MAXPALOOKUPS)
|
|
{
|
|
if (prlookups[i])
|
|
{
|
|
glDeleteTextures(1, &prlookups[i]);
|
|
prlookups[i] = 0;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// SECTORS
|
|
static int32_t polymer_initsector(int16_t sectnum)
|
|
{
|
|
usectortype *sec;
|
|
_prsector* s;
|
|
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Initializing sector %i...\n", sectnum);
|
|
|
|
sec = (usectortype *)§or[sectnum];
|
|
s = (_prsector *)Xcalloc(1, sizeof(_prsector));
|
|
|
|
s->verts = (GLdouble *)Xcalloc(sec->wallnum, sizeof(GLdouble) * 3);
|
|
s->floor.buffer = (_prvert *)Xcalloc(sec->wallnum, sizeof(_prvert));
|
|
s->floor.vertcount = sec->wallnum;
|
|
s->ceil.buffer = (_prvert *)Xcalloc(sec->wallnum, sizeof(_prvert));
|
|
s->ceil.vertcount = sec->wallnum;
|
|
|
|
glGenBuffers(1, &s->floor.vbo);
|
|
glGenBuffers(1, &s->ceil.vbo);
|
|
glGenBuffers(1, &s->floor.ivbo);
|
|
glGenBuffers(1, &s->ceil.ivbo);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, s->floor.vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sec->wallnum * sizeof(GLfloat) * 5, NULL, mapvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, s->ceil.vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sec->wallnum * sizeof(GLfloat) * 5, NULL, mapvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
s->flags.empty = 1; // let updatesector know that everything needs to go
|
|
|
|
prsectors[sectnum] = s;
|
|
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Initialized sector %i.\n", sectnum);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int32_t polymer_updatesector(int16_t sectnum)
|
|
{
|
|
_prsector* s;
|
|
usectortype *sec;
|
|
walltype *wal;
|
|
int32_t i, j;
|
|
int32_t ceilz, florz;
|
|
int32_t tex, tey, heidiff;
|
|
float secangcos, secangsin, scalecoef, xpancoef, ypancoef;
|
|
int32_t ang, needfloor, wallinvalidate;
|
|
int16_t curstat, curpicnum, floorpicnum, ceilingpicnum;
|
|
char curxpanning, curypanning;
|
|
_prvert* curbuffer;
|
|
|
|
if (pr_nullrender >= 3) return 0;
|
|
|
|
s = prsectors[sectnum];
|
|
sec = (usectortype *)§or[sectnum];
|
|
|
|
secangcos = secangsin = 2;
|
|
|
|
if (s == NULL)
|
|
{
|
|
if (pr_verbosity >= 1) OSD_Printf("PR : Can't update uninitialized sector %i.\n", sectnum);
|
|
return -1;
|
|
}
|
|
|
|
needfloor = wallinvalidate = 0;
|
|
|
|
// geometry
|
|
wal = &wall[sec->wallptr];
|
|
i = 0;
|
|
while (i < sec->wallnum)
|
|
{
|
|
if ((-wal->x != s->verts[(i*3)+2]))
|
|
{
|
|
s->verts[(i*3)+2] = s->floor.buffer[i].z = s->ceil.buffer[i].z = -(float)wal->x;
|
|
needfloor = wallinvalidate = 1;
|
|
}
|
|
if ((wal->y != s->verts[i*3]))
|
|
{
|
|
s->verts[i*3] = s->floor.buffer[i].x = s->ceil.buffer[i].x = (float)wal->y;
|
|
needfloor = wallinvalidate = 1;
|
|
}
|
|
|
|
i++;
|
|
wal = &wall[sec->wallptr + i];
|
|
}
|
|
|
|
if ((s->flags.empty) ||
|
|
needfloor ||
|
|
(sec->floorz != s->floorz) ||
|
|
(sec->ceilingz != s->ceilingz) ||
|
|
(sec->floorheinum != s->floorheinum) ||
|
|
(sec->ceilingheinum != s->ceilingheinum))
|
|
{
|
|
wallinvalidate = 1;
|
|
|
|
wal = &wall[sec->wallptr];
|
|
i = 0;
|
|
while (i < sec->wallnum)
|
|
{
|
|
getzsofslope(sectnum, wal->x, wal->y, &ceilz, &florz);
|
|
s->floor.buffer[i].y = -(float)(florz) / 16.0f;
|
|
s->ceil.buffer[i].y = -(float)(ceilz) / 16.0f;
|
|
|
|
i++;
|
|
wal = &wall[sec->wallptr + i];
|
|
}
|
|
|
|
s->floorz = sec->floorz;
|
|
s->ceilingz = sec->ceilingz;
|
|
s->floorheinum = sec->floorheinum;
|
|
s->ceilingheinum = sec->ceilingheinum;
|
|
}
|
|
else if (sec->visibility != s->visibility)
|
|
wallinvalidate = 1;
|
|
|
|
floorpicnum = sec->floorpicnum;
|
|
DO_TILE_ANIM(floorpicnum, sectnum);
|
|
ceilingpicnum = sec->ceilingpicnum;
|
|
DO_TILE_ANIM(ceilingpicnum, sectnum);
|
|
|
|
if ((!s->flags.empty) && (!needfloor) &&
|
|
(floorpicnum == s->floorpicnum_anim) &&
|
|
(ceilingpicnum == s->ceilingpicnum_anim) &&
|
|
#ifndef UNTRACKED_STRUCTS
|
|
(s->trackedrev == sectorchanged[sectnum]))
|
|
#else
|
|
!Bmemcmp(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat)))
|
|
#endif
|
|
goto attributes;
|
|
|
|
wal = &wall[sec->wallptr];
|
|
i = 0;
|
|
while (i < sec->wallnum)
|
|
{
|
|
j = 2;
|
|
curstat = sec->floorstat;
|
|
curbuffer = s->floor.buffer;
|
|
curpicnum = floorpicnum;
|
|
curxpanning = sec->floorxpanning;
|
|
curypanning = sec->floorypanning;
|
|
|
|
while (j)
|
|
{
|
|
if (j == 1)
|
|
{
|
|
curstat = sec->ceilingstat;
|
|
curbuffer = s->ceil.buffer;
|
|
curpicnum = ceilingpicnum;
|
|
curxpanning = sec->ceilingxpanning;
|
|
curypanning = sec->ceilingypanning;
|
|
}
|
|
|
|
if (!waloff[curpicnum])
|
|
loadtile(curpicnum);
|
|
|
|
if (((sec->floorstat & 64) || (sec->ceilingstat & 64)) &&
|
|
((secangcos == 2) && (secangsin == 2)))
|
|
{
|
|
ang = (getangle(wall[wal->point2].x - wal->x, wall[wal->point2].y - wal->y) + 512) & 2047;
|
|
secangcos = (float)(sintable[(ang+512)&2047]) / 16383.0f;
|
|
secangsin = (float)(sintable[ang&2047]) / 16383.0f;
|
|
}
|
|
|
|
// relative texturing
|
|
if (curstat & 64)
|
|
{
|
|
xpancoef = (float)(wal->x - wall[sec->wallptr].x);
|
|
ypancoef = (float)(wall[sec->wallptr].y - wal->y);
|
|
|
|
tex = (int32_t)(xpancoef * secangsin + ypancoef * secangcos);
|
|
tey = (int32_t)(xpancoef * secangcos - ypancoef * secangsin);
|
|
} else {
|
|
tex = wal->x;
|
|
tey = -wal->y;
|
|
}
|
|
|
|
if ((curstat & (2+64)) == (2+64))
|
|
{
|
|
heidiff = (int32_t)(curbuffer[i].y - curbuffer[0].y);
|
|
// don't forget the sign, tey could be negative with concave sectors
|
|
if (tey >= 0)
|
|
tey = (int32_t)sqrt((double)((tey * tey) + (heidiff * heidiff)));
|
|
else
|
|
tey = -(int32_t)sqrt((double)((tey * tey) + (heidiff * heidiff)));
|
|
}
|
|
|
|
if (curstat & 4)
|
|
swaplong(&tex, &tey);
|
|
|
|
if (curstat & 16) tex = -tex;
|
|
if (curstat & 32) tey = -tey;
|
|
|
|
scalecoef = (curstat & 8) ? 8.0f : 16.0f;
|
|
|
|
if (curxpanning)
|
|
{
|
|
xpancoef = (float)(pow2long[picsiz[curpicnum] & 15]);
|
|
xpancoef *= (float)(curxpanning) / (256.0f * (float)(tilesiz[curpicnum].x));
|
|
}
|
|
else
|
|
xpancoef = 0;
|
|
|
|
if (curypanning)
|
|
{
|
|
ypancoef = (float)(pow2long[picsiz[curpicnum] >> 4]);
|
|
ypancoef *= (float)(curypanning) / (256.0f * (float)(tilesiz[curpicnum].y));
|
|
}
|
|
else
|
|
ypancoef = 0;
|
|
|
|
curbuffer[i].u = ((float)(tex) / (scalecoef * tilesiz[curpicnum].x)) + xpancoef;
|
|
curbuffer[i].v = ((float)(tey) / (scalecoef * tilesiz[curpicnum].y)) + ypancoef;
|
|
|
|
j--;
|
|
}
|
|
i++;
|
|
wal = &wall[sec->wallptr + i];
|
|
}
|
|
|
|
s->floorxpanning = sec->floorxpanning;
|
|
s->ceilingxpanning = sec->ceilingxpanning;
|
|
s->floorypanning = sec->floorypanning;
|
|
s->ceilingypanning = sec->ceilingypanning;
|
|
#ifndef UNTRACKED_STRUCTS
|
|
s->trackedrev = sectorchanged[sectnum];
|
|
#endif
|
|
|
|
i = -1;
|
|
|
|
attributes:
|
|
if ((pr_vbos > 0) && ((i == -1) || (wallinvalidate)))
|
|
{
|
|
if (pr_vbos > 0)
|
|
{
|
|
if (pr_nullrender < 2)
|
|
{
|
|
/*glBindBuffer(GL_ARRAY_BUFFER, s->floor.vbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sec->wallnum * sizeof(GLfloat)* 5, s->floor.buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, s->ceil.vbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sec->wallnum * sizeof(GLfloat)* 5, s->ceil.buffer);
|
|
*/
|
|
|
|
s->floor.mapvbo_vertoffset = sec->wallptr * 2;
|
|
s->ceil.mapvbo_vertoffset = s->floor.mapvbo_vertoffset + sec->wallnum;
|
|
|
|
GLintptr sector_offset = s->floor.mapvbo_vertoffset * sizeof(_prvert);
|
|
GLsizeiptr cur_sector_size = sec->wallnum * sizeof(_prvert);
|
|
glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
|
|
// floor
|
|
glBufferSubData(GL_ARRAY_BUFFER, sector_offset, cur_sector_size, s->floor.buffer);
|
|
// ceiling
|
|
glBufferSubData(GL_ARRAY_BUFFER, sector_offset + cur_sector_size, cur_sector_size, s->ceil.buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
s->floor.mapvbo_vertoffset = -1;
|
|
s->ceil.mapvbo_vertoffset = -1;
|
|
}
|
|
}
|
|
|
|
if ((!s->flags.empty) && (!s->flags.invalidtex) &&
|
|
(floorpicnum == s->floorpicnum_anim) &&
|
|
(ceilingpicnum == s->ceilingpicnum_anim) &&
|
|
!Bmemcmp(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat)))
|
|
goto finish;
|
|
|
|
s->floor.bucket = polymer_getbuildmaterial(&s->floor.material, floorpicnum, sec->floorpal, sec->floorshade, sec->visibility, (sec->floorstat & 384) ? DAMETH_MASK : DAMETH_NOMASK);
|
|
|
|
if (sec->floorstat & 256) {
|
|
if (sec->floorstat & 128) {
|
|
s->floor.material.diffusemodulation[3] = 0x55;
|
|
} else {
|
|
s->floor.material.diffusemodulation[3] = 0xAA;
|
|
}
|
|
}
|
|
|
|
s->ceil.bucket = polymer_getbuildmaterial(&s->ceil.material, ceilingpicnum, sec->ceilingpal, sec->ceilingshade, sec->visibility, (sec->ceilingstat & 384) ? DAMETH_MASK : DAMETH_NOMASK);
|
|
|
|
if (sec->ceilingstat & 256) {
|
|
if (sec->ceilingstat & 128) {
|
|
s->ceil.material.diffusemodulation[3] = 0x55;
|
|
} else {
|
|
s->ceil.material.diffusemodulation[3] = 0xAA;
|
|
}
|
|
}
|
|
|
|
s->flags.invalidtex = 0;
|
|
|
|
// copy ceilingstat through visibility members
|
|
Bmemcpy(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat));
|
|
s->floorpicnum_anim = floorpicnum;
|
|
s->ceilingpicnum_anim = ceilingpicnum;
|
|
|
|
finish:
|
|
|
|
if (needfloor)
|
|
{
|
|
polymer_buildfloor(sectnum);
|
|
if ((pr_vbos > 0))
|
|
{
|
|
if (pr_nullrender < 2)
|
|
{
|
|
if (s->oldindicescount < s->indicescount)
|
|
{
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->floor.ivbo);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, s->indicescount * sizeof(GLushort), NULL, mapvbousage);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->ceil.ivbo);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, s->indicescount * sizeof(GLushort), NULL, mapvbousage);
|
|
s->oldindicescount = s->indicescount;
|
|
}
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->floor.ivbo);
|
|
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s->indicescount * sizeof(GLushort), s->floor.indices);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->ceil.ivbo);
|
|
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s->indicescount * sizeof(GLushort), s->ceil.indices);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wallinvalidate)
|
|
{
|
|
s->invalidid++;
|
|
polymer_invalidatesectorlights(sectnum);
|
|
polymer_computeplane(&s->floor);
|
|
polymer_computeplane(&s->ceil);
|
|
}
|
|
|
|
s->flags.empty = 0;
|
|
s->flags.uptodate = 1;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Updated sector %i.\n", sectnum);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void PR_CALLBACK polymer_tesserror(GLenum error)
|
|
{
|
|
/* This callback is called by the tesselator whenever it raises an error.
|
|
GLU_TESS_ERROR6 is the "no error"/"null" error spam in e1l1 and others. */
|
|
|
|
if (pr_verbosity >= 1 && error != GLU_TESS_ERROR6) OSD_Printf("PR : Tesselation error number %i reported : %s.\n", error, bgluErrorString(errno));
|
|
}
|
|
|
|
void PR_CALLBACK polymer_tessedgeflag(GLenum error)
|
|
{
|
|
// Passing an edgeflag callback forces the tesselator to output a triangle list
|
|
UNREFERENCED_PARAMETER(error);
|
|
return;
|
|
}
|
|
|
|
void PR_CALLBACK polymer_tessvertex(void* vertex, void* sector)
|
|
{
|
|
_prsector* s;
|
|
|
|
s = (_prsector*)sector;
|
|
|
|
if (s->curindice >= s->indicescount)
|
|
{
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Indice overflow, extending the indices list... !\n");
|
|
s->indicescount++;
|
|
s->floor.indices = (GLushort *)Xrealloc(s->floor.indices, s->indicescount * sizeof(GLushort));
|
|
s->ceil.indices = (GLushort *)Xrealloc(s->ceil.indices, s->indicescount * sizeof(GLushort));
|
|
}
|
|
s->ceil.indices[s->curindice] = (intptr_t)vertex;
|
|
s->curindice++;
|
|
}
|
|
|
|
static int32_t polymer_buildfloor(int16_t sectnum)
|
|
{
|
|
// This function tesselates the floor/ceiling of a sector and stores the triangles in a display list.
|
|
_prsector* s;
|
|
usectortype *sec;
|
|
intptr_t i;
|
|
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Tesselating floor of sector %i...\n", sectnum);
|
|
|
|
s = prsectors[sectnum];
|
|
sec = (usectortype *)§or[sectnum];
|
|
|
|
if (s == NULL)
|
|
return -1;
|
|
|
|
if (s->floor.indices == NULL)
|
|
{
|
|
s->indicescount = (max(3, sec->wallnum) - 2) * 3;
|
|
s->floor.indices = (GLushort *)Xcalloc(s->indicescount, sizeof(GLushort));
|
|
s->ceil.indices = (GLushort *)Xcalloc(s->indicescount, sizeof(GLushort));
|
|
}
|
|
|
|
s->curindice = 0;
|
|
|
|
bgluTessCallback(prtess, GLU_TESS_VERTEX_DATA, (void (PR_CALLBACK *)(void))polymer_tessvertex);
|
|
bgluTessCallback(prtess, GLU_TESS_EDGE_FLAG, (void (PR_CALLBACK *)(void))polymer_tessedgeflag);
|
|
bgluTessCallback(prtess, GLU_TESS_ERROR, (void (PR_CALLBACK *)(void))polymer_tesserror);
|
|
|
|
bgluTessProperty(prtess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE);
|
|
|
|
bgluTessBeginPolygon(prtess, s);
|
|
bgluTessBeginContour(prtess);
|
|
|
|
i = 0;
|
|
while (i < sec->wallnum)
|
|
{
|
|
bgluTessVertex(prtess, s->verts + (3 * i), (void *)i);
|
|
if ((i != (sec->wallnum - 1)) && ((sec->wallptr + i) > wall[sec->wallptr + i].point2))
|
|
{
|
|
bgluTessEndContour(prtess);
|
|
bgluTessBeginContour(prtess);
|
|
}
|
|
i++;
|
|
}
|
|
bgluTessEndContour(prtess);
|
|
bgluTessEndPolygon(prtess);
|
|
|
|
i = 0;
|
|
while (i < s->indicescount)
|
|
{
|
|
s->floor.indices[s->indicescount - i - 1] = s->ceil.indices[i];
|
|
|
|
i++;
|
|
}
|
|
s->floor.indicescount = s->ceil.indicescount = s->indicescount;
|
|
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Tesselated floor of sector %i.\n", sectnum);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void polymer_drawsector(int16_t sectnum, int32_t domasks)
|
|
{
|
|
usectortype *sec;
|
|
_prsector* s;
|
|
GLubyte oldcolor[4];
|
|
int32_t draw;
|
|
int32_t queuedmask;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Drawing sector %i...\n", sectnum);
|
|
|
|
sec = (usectortype *)§or[sectnum];
|
|
s = prsectors[sectnum];
|
|
|
|
queuedmask = FALSE;
|
|
|
|
// If you're thinking of 'optimizing' the following logic, you'd better
|
|
// provide compelling evidence that the generated code is more efficient
|
|
// than what GCC can come up with on its own.
|
|
|
|
draw = TRUE;
|
|
// Draw masks regardless; avoid all non-masks TROR links
|
|
if (sec->floorstat & 384) {
|
|
draw = domasks;
|
|
} else if (yax_getbunch(sectnum, YAX_FLOOR) >= 0) {
|
|
draw = FALSE;
|
|
}
|
|
// Parallaxed
|
|
if (sec->floorstat & 1) {
|
|
draw = FALSE;
|
|
}
|
|
|
|
if (draw || (searchit == 2)) {
|
|
if (searchit == 2) {
|
|
polymer_drawsearchplane(&s->floor, oldcolor, 0x02, (GLubyte *) §num);
|
|
}
|
|
else {
|
|
calc_and_apply_fog(sec->floorpicnum, fogshade(sec->floorshade, sec->floorpal),
|
|
sec->visibility, get_floor_fogpal(sec));
|
|
polymer_drawplane(&s->floor);
|
|
}
|
|
} else if (!domasks && cursectormaskcount && sec->floorstat & 384) {
|
|
// If we just skipped a mask, queue it for later
|
|
cursectormasks[(*cursectormaskcount)++] = sectnum;
|
|
// Don't queue it twice if the ceiling is also a mask, though.
|
|
queuedmask = TRUE;
|
|
}
|
|
|
|
draw = TRUE;
|
|
// Draw masks regardless; avoid all non-masks TROR links
|
|
if (sec->ceilingstat & 384) {
|
|
draw = domasks;
|
|
} else if (yax_getbunch(sectnum, YAX_CEILING) >= 0) {
|
|
draw = FALSE;
|
|
}
|
|
// Parallaxed
|
|
if (sec->ceilingstat & 1) {
|
|
draw = FALSE;
|
|
}
|
|
|
|
if (draw || (searchit == 2)) {
|
|
if (searchit == 2) {
|
|
polymer_drawsearchplane(&s->ceil, oldcolor, 0x01, (GLubyte *) §num);
|
|
}
|
|
else {
|
|
calc_and_apply_fog(sec->ceilingpicnum, fogshade(sec->ceilingshade, sec->ceilingpal),
|
|
sec->visibility, get_ceiling_fogpal(sec));
|
|
polymer_drawplane(&s->ceil);
|
|
}
|
|
} else if (!domasks && !queuedmask && cursectormaskcount &&
|
|
(sec->ceilingstat & 384)) {
|
|
// If we just skipped a mask, queue it for later
|
|
cursectormasks[(*cursectormaskcount)++] = sectnum;
|
|
}
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Finished drawing sector %i...\n", sectnum);
|
|
}
|
|
|
|
// WALLS
|
|
static int32_t polymer_initwall(int16_t wallnum)
|
|
{
|
|
_prwall *w;
|
|
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Initializing wall %i...\n", wallnum);
|
|
|
|
w = (_prwall *)Xcalloc(1, sizeof(_prwall));
|
|
|
|
if (w->mask.buffer == NULL) {
|
|
w->mask.buffer = (_prvert *)Xmalloc(4 * sizeof(_prvert));
|
|
w->mask.vertcount = 4;
|
|
}
|
|
if (w->bigportal == NULL)
|
|
w->bigportal = (GLfloat *)Xmalloc(4 * sizeof(GLfloat) * 5);
|
|
//if (w->cap == NULL)
|
|
// w->cap = (GLfloat *)Xmalloc(4 * sizeof(GLfloat) * 3);
|
|
|
|
glGenBuffers(1, &w->wall.vbo);
|
|
glGenBuffers(1, &w->over.vbo);
|
|
glGenBuffers(1, &w->mask.vbo);
|
|
glGenBuffers(1, &w->stuffvbo);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, w->wall.vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, w->over.vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, w->mask.vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, w->stuffvbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat) * 5, NULL, mapvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
w->flags.empty = 1;
|
|
|
|
prwalls[wallnum] = w;
|
|
|
|
if (pr_verbosity >= 2) OSD_Printf("PR : Initialized wall %i.\n", wallnum);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// TODO: r_npotwallmode. Needs polymost_is_npotmode() handling among others.
|
|
#define DAMETH_WALL 0
|
|
|
|
static float calc_ypancoef(char curypanning, int16_t curpicnum, int32_t dopancor)
|
|
{
|
|
#ifdef NEW_MAP_FORMAT
|
|
if (g_loadedMapVersion >= 10)
|
|
return curypanning / 256.0f;
|
|
#endif
|
|
{
|
|
float ypancoef = (float)(pow2long[picsiz[curpicnum] >> 4]);
|
|
|
|
if (ypancoef < tilesiz[curpicnum].y)
|
|
ypancoef *= 2;
|
|
|
|
if (dopancor)
|
|
{
|
|
int32_t yoffs = Blrintf((ypancoef - tilesiz[curpicnum].y) * (255.0f / ypancoef));
|
|
if (curypanning > 256 - yoffs)
|
|
curypanning -= yoffs;
|
|
}
|
|
|
|
ypancoef *= (float)curypanning / (256.0f * (float)tilesiz[curpicnum].y);
|
|
|
|
return ypancoef;
|
|
}
|
|
}
|
|
|
|
#define NBYTES_WALL_CSTAT_THROUGH_YPANNING \
|
|
(offsetof(walltype, ypanning)+sizeof(wall[0].ypanning) - offsetof(walltype, cstat))
|
|
|
|
static void polymer_updatewall(int16_t wallnum)
|
|
{
|
|
int16_t nwallnum, nnwallnum, curpicnum, wallpicnum, walloverpicnum, nwallpicnum;
|
|
char curxpanning, curypanning, underwall, overwall, curpal;
|
|
int8_t curshade;
|
|
walltype *wal;
|
|
sectortype *sec, *nsec;
|
|
_prwall *w;
|
|
_prsector *s, *ns;
|
|
int32_t xref, yref;
|
|
float ypancoef, dist;
|
|
int32_t i;
|
|
uint32_t invalid;
|
|
int32_t sectofwall = sectorofwall(wallnum);
|
|
|
|
if (pr_nullrender >= 3) return;
|
|
|
|
// yes, this function is messy and unefficient
|
|
// it also works, bitches
|
|
sec = §or[sectofwall];
|
|
|
|
if (sectofwall < 0 || sectofwall >= numsectors ||
|
|
wallnum < 0 || wallnum > numwalls ||
|
|
sec->wallptr > wallnum || wallnum >= (sec->wallptr + sec->wallnum))
|
|
return; // yay, corrupt map
|
|
|
|
wal = &wall[wallnum];
|
|
nwallnum = wal->nextwall;
|
|
|
|
w = prwalls[wallnum];
|
|
s = prsectors[sectofwall];
|
|
invalid = s->invalidid;
|
|
if (nwallnum >= 0 && nwallnum < numwalls && wal->nextsector >= 0 && wal->nextsector < numsectors)
|
|
{
|
|
ns = prsectors[wal->nextsector];
|
|
invalid += ns->invalidid;
|
|
nsec = §or[wal->nextsector];
|
|
}
|
|
else
|
|
{
|
|
ns = NULL;
|
|
nsec = NULL;
|
|
}
|
|
|
|
if (w->wall.buffer == NULL) {
|
|
w->wall.buffer = (_prvert *)Xcalloc(4, sizeof(_prvert)); // XXX
|
|
w->wall.vertcount = 4;
|
|
}
|
|
|
|
wallpicnum = wal->picnum;
|
|
DO_TILE_ANIM(wallpicnum, wallnum+16384);
|
|
|
|
walloverpicnum = wal->overpicnum;
|
|
if (walloverpicnum>=0)
|
|
DO_TILE_ANIM(walloverpicnum, wallnum+16384);
|
|
|
|
if (nwallnum >= 0 && nwallnum < numwalls)
|
|
{
|
|
nwallpicnum = wall[nwallnum].picnum;
|
|
DO_TILE_ANIM(nwallpicnum, wallnum+16384);
|
|
}
|
|
else
|
|
nwallpicnum = 0;
|
|
|
|
if ((!w->flags.empty) && (!w->flags.invalidtex) &&
|
|
(w->invalidid == invalid) &&
|
|
(wallpicnum == w->picnum_anim) &&
|
|
(walloverpicnum == w->overpicnum_anim) &&
|
|
#ifndef UNTRACKED_STRUCTS
|
|
(w->trackedrev == wallchanged[wallnum]) &&
|
|
#else
|
|
!Bmemcmp(&wal->cstat, &w->cstat, NBYTES_WALL_CSTAT_THROUGH_YPANNING) &&
|
|
#endif
|
|
((nwallnum < 0 || nwallnum > numwalls) ||
|
|
((nwallpicnum == w->nwallpicnum) &&
|
|
(wall[nwallnum].xpanning == w->nwallxpanning) &&
|
|
(wall[nwallnum].ypanning == w->nwallypanning) &&
|
|
(wall[nwallnum].cstat == w->nwallcstat) &&
|
|
(wall[nwallnum].shade == w->nwallshade))))
|
|
{
|
|
w->flags.uptodate = 1;
|
|
return; // screw you guys I'm going home
|
|
}
|
|
else
|
|
{
|
|
w->invalidid = invalid;
|
|
|
|
Bmemcpy(&w->cstat, &wal->cstat, NBYTES_WALL_CSTAT_THROUGH_YPANNING);
|
|
|
|
w->picnum_anim = wallpicnum;
|
|
w->overpicnum_anim = walloverpicnum;
|
|
#ifndef UNTRACKED_STRUCTS
|
|
w->trackedrev = wallchanged[wallnum];
|
|
#endif
|
|
if (nwallnum >= 0 && nwallnum < numwalls)
|
|
{
|
|
w->nwallpicnum = nwallpicnum;
|
|
w->nwallxpanning = wall[nwallnum].xpanning;
|
|
w->nwallypanning = wall[nwallnum].ypanning;
|
|
w->nwallcstat = wall[nwallnum].cstat;
|
|
w->nwallshade = wall[nwallnum].shade;
|
|
}
|
|
}
|
|
|
|
w->underover = underwall = overwall = 0;
|
|
|
|
if (wal->cstat & 8)
|
|
xref = 1;
|
|
else
|
|
xref = 0;
|
|
|
|
if ((unsigned)wal->nextsector >= (unsigned)numsectors || !ns)
|
|
{
|
|
Bmemcpy(w->wall.buffer, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->wall.buffer[1], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->wall.buffer[2], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->wall.buffer[3], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
|
|
if (wal->nextsector < 0)
|
|
curpicnum = wallpicnum;
|
|
else
|
|
curpicnum = walloverpicnum;
|
|
|
|
w->wall.bucket = polymer_getbuildmaterial(&w->wall.material, curpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL);
|
|
|
|
if (wal->cstat & 4)
|
|
yref = sec->floorz;
|
|
else
|
|
yref = sec->ceilingz;
|
|
|
|
if ((wal->cstat & 32) && (wal->nextsector >= 0))
|
|
{
|
|
if ((!(wal->cstat & 2) && (wal->cstat & 4)) || ((wal->cstat & 2) && (wall[nwallnum].cstat & 4)))
|
|
yref = sec->ceilingz;
|
|
else
|
|
yref = nsec->floorz;
|
|
}
|
|
|
|
if (wal->ypanning)
|
|
// white (but not 1-way)
|
|
ypancoef = calc_ypancoef(wal->ypanning, curpicnum, !(wal->cstat & 4));
|
|
else
|
|
ypancoef = 0;
|
|
|
|
i = 0;
|
|
while (i < 4)
|
|
{
|
|
if ((i == 0) || (i == 3))
|
|
dist = (float)xref;
|
|
else
|
|
dist = (float)(xref == 0);
|
|
|
|
w->wall.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
|
|
w->wall.buffer[i].v = (-(float)(yref + (w->wall.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
|
|
|
|
if (wal->cstat & 256) w->wall.buffer[i].v = -w->wall.buffer[i].v;
|
|
|
|
i++;
|
|
}
|
|
|
|
w->underover |= 1;
|
|
}
|
|
else
|
|
{
|
|
nnwallnum = wall[nwallnum].point2;
|
|
|
|
if ((s->floor.buffer[wallnum - sec->wallptr].y < ns->floor.buffer[nnwallnum - nsec->wallptr].y) ||
|
|
(s->floor.buffer[wal->point2 - sec->wallptr].y < ns->floor.buffer[nwallnum - nsec->wallptr].y))
|
|
underwall = 1;
|
|
|
|
if ((underwall) || (wal->cstat & 16) || (wal->cstat & 32))
|
|
{
|
|
int32_t refwall;
|
|
|
|
if (s->floor.buffer[wallnum - sec->wallptr].y < ns->floor.buffer[nnwallnum - nsec->wallptr].y)
|
|
Bmemcpy(w->wall.buffer, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
else
|
|
Bmemcpy(w->wall.buffer, &ns->floor.buffer[nnwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->wall.buffer[1], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->wall.buffer[2], &ns->floor.buffer[nwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->wall.buffer[3], &ns->floor.buffer[nnwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
|
|
|
|
if (wal->cstat & 2)
|
|
refwall = nwallnum;
|
|
else
|
|
refwall = wallnum;
|
|
|
|
curpicnum = (wal->cstat & 2) ? nwallpicnum : wallpicnum;
|
|
curpal = wall[refwall].pal;
|
|
curshade = wall[refwall].shade;
|
|
curxpanning = wall[refwall].xpanning;
|
|
curypanning = wall[refwall].ypanning;
|
|
|
|
w->wall.bucket = polymer_getbuildmaterial(&w->wall.material, curpicnum, curpal, curshade, sec->visibility, DAMETH_WALL);
|
|
|
|
if (!(wall[refwall].cstat&4))
|
|
yref = nsec->floorz;
|
|
else
|
|
yref = sec->ceilingz;
|
|
|
|
if (curypanning)
|
|
// under
|
|
ypancoef = calc_ypancoef(curypanning, curpicnum, !(wall[refwall].cstat & 4));
|
|
else
|
|
ypancoef = 0;
|
|
|
|
i = 0;
|
|
while (i < 4)
|
|
{
|
|
if ((i == 0) || (i == 3))
|
|
dist = (float)xref;
|
|
else
|
|
dist = (float)(xref == 0);
|
|
|
|
w->wall.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + curxpanning) / (float)(tilesiz[curpicnum].x);
|
|
w->wall.buffer[i].v = (-(float)(yref + (w->wall.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
|
|
|
|
if ((!(wal->cstat & 2) && (wal->cstat & 256)) ||
|
|
((wal->cstat & 2) && (wall[nwallnum].cstat & 256)))
|
|
w->wall.buffer[i].v = -w->wall.buffer[i].v;
|
|
|
|
i++;
|
|
}
|
|
|
|
if (underwall)
|
|
w->underover |= 1;
|
|
|
|
Bmemcpy(w->mask.buffer, &w->wall.buffer[3], sizeof(GLfloat) * 5);
|
|
Bmemcpy(&w->mask.buffer[1], &w->wall.buffer[2], sizeof(GLfloat) * 5);
|
|
}
|
|
else
|
|
{
|
|
Bmemcpy(w->mask.buffer, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 5);
|
|
Bmemcpy(&w->mask.buffer[1], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 5);
|
|
}
|
|
|
|
if ((s->ceil.buffer[wallnum - sec->wallptr].y > ns->ceil.buffer[nnwallnum - nsec->wallptr].y) ||
|
|
(s->ceil.buffer[wal->point2 - sec->wallptr].y > ns->ceil.buffer[nwallnum - nsec->wallptr].y))
|
|
overwall = 1;
|
|
|
|
if ((overwall) || (wal->cstat & 48))
|
|
{
|
|
if (w->over.buffer == NULL) {
|
|
w->over.buffer = (_prvert *)Xmalloc(4 * sizeof(_prvert));
|
|
w->over.vertcount = 4;
|
|
}
|
|
|
|
Bmemcpy(w->over.buffer, &ns->ceil.buffer[nnwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->over.buffer[1], &ns->ceil.buffer[nwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
|
|
if (s->ceil.buffer[wal->point2 - sec->wallptr].y > ns->ceil.buffer[nwallnum - nsec->wallptr].y)
|
|
Bmemcpy(&w->over.buffer[2], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
else
|
|
Bmemcpy(&w->over.buffer[2], &ns->ceil.buffer[nwallnum - nsec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->over.buffer[3], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
|
|
if ((wal->cstat & 16) || (wal->overpicnum == 0))
|
|
curpicnum = wallpicnum;
|
|
else
|
|
curpicnum = wallpicnum;
|
|
|
|
w->over.bucket = polymer_getbuildmaterial(&w->over.material, curpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL);
|
|
|
|
if (wal->cstat & 48)
|
|
{
|
|
// mask
|
|
w->mask.bucket = polymer_getbuildmaterial(&w->mask.material, walloverpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL | ((wal->cstat & 48) == 48 ? DAMETH_NOMASK : DAMETH_MASK));
|
|
|
|
if (wal->cstat & 128)
|
|
{
|
|
if (wal->cstat & 512)
|
|
w->mask.material.diffusemodulation[3] = 0x55;
|
|
else
|
|
w->mask.material.diffusemodulation[3] = 0xAA;
|
|
}
|
|
}
|
|
|
|
if (wal->cstat & 4)
|
|
yref = sec->ceilingz;
|
|
else
|
|
yref = nsec->ceilingz;
|
|
|
|
if (wal->ypanning)
|
|
// over
|
|
ypancoef = calc_ypancoef(wal->ypanning, curpicnum, wal->cstat & 4);
|
|
else
|
|
ypancoef = 0;
|
|
|
|
i = 0;
|
|
while (i < 4)
|
|
{
|
|
if ((i == 0) || (i == 3))
|
|
dist = (float)xref;
|
|
else
|
|
dist = (float)(xref == 0);
|
|
|
|
w->over.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
|
|
w->over.buffer[i].v = (-(float)(yref + (w->over.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
|
|
|
|
if (wal->cstat & 256) w->over.buffer[i].v = -w->over.buffer[i].v;
|
|
|
|
i++;
|
|
}
|
|
|
|
if (overwall)
|
|
w->underover |= 2;
|
|
|
|
Bmemcpy(&w->mask.buffer[2], &w->over.buffer[1], sizeof(GLfloat) * 5);
|
|
Bmemcpy(&w->mask.buffer[3], &w->over.buffer[0], sizeof(GLfloat) * 5);
|
|
|
|
if ((wal->cstat & 16) || (wal->cstat & 32))
|
|
{
|
|
const int botSwap = (wal->cstat & 4);
|
|
|
|
if (wal->cstat & 32)
|
|
{
|
|
// 1-sided wall
|
|
if (nsec)
|
|
yref = botSwap ? sec->ceilingz : nsec->ceilingz;
|
|
else
|
|
yref = botSwap ? sec->floorz : sec->ceilingz;
|
|
}
|
|
else
|
|
{
|
|
// masked wall
|
|
if (botSwap)
|
|
yref = min(sec->floorz, nsec->floorz);
|
|
else
|
|
yref = max(sec->ceilingz, nsec->ceilingz);
|
|
}
|
|
|
|
curpicnum = walloverpicnum;
|
|
|
|
if (wal->ypanning)
|
|
// mask / 1-way
|
|
ypancoef = calc_ypancoef(wal->ypanning, curpicnum, 0);
|
|
else
|
|
ypancoef = 0;
|
|
|
|
i = 0;
|
|
while (i < 4)
|
|
{
|
|
if ((i == 0) || (i == 3))
|
|
dist = (float)xref;
|
|
else
|
|
dist = (float)(xref == 0);
|
|
|
|
w->mask.buffer[i].u = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
|
|
w->mask.buffer[i].v = (-(float)(yref + (w->mask.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
|
|
|
|
if (wal->cstat & 256) w->mask.buffer[i].v = -w->mask.buffer[i].v;
|
|
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Bmemcpy(&w->mask.buffer[2], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 5);
|
|
Bmemcpy(&w->mask.buffer[3], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 5);
|
|
}
|
|
}
|
|
|
|
// make sure shade color handling is correct below XXX
|
|
if (wal->nextsector < 0)
|
|
Bmemcpy(w->mask.buffer, w->wall.buffer, sizeof(_prvert) * 4);
|
|
|
|
Bmemcpy(w->bigportal, &s->floor.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->bigportal[5], &s->floor.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->bigportal[10], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
Bmemcpy(&w->bigportal[15], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
|
|
//Bmemcpy(&w->cap[0], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
//Bmemcpy(&w->cap[3], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
//Bmemcpy(&w->cap[6], &s->ceil.buffer[wal->point2 - sec->wallptr], sizeof(GLfloat) * 3);
|
|
//Bmemcpy(&w->cap[9], &s->ceil.buffer[wallnum - sec->wallptr], sizeof(GLfloat) * 3);
|
|
//w->cap[7] += 1048576; // this number is the result of 1048574 + 2
|
|
//w->cap[10] += 1048576; // this one is arbitrary
|
|
|
|
if (w->underover & 1)
|
|
polymer_computeplane(&w->wall);
|
|
if (w->underover & 2)
|
|
polymer_computeplane(&w->over);
|
|
polymer_computeplane(&w->mask);
|
|
|
|
if ((pr_vbos > 0))
|
|
{
|
|
if (pr_nullrender < 2)
|
|
{
|
|
const GLintptr thiswalloffset = prwalldataoffset + (prwalldatasize * wallnum);
|
|
const GLintptr thisoveroffset = thiswalloffset + proneplanesize;
|
|
const GLintptr thismaskoffset = thisoveroffset + proneplanesize;
|
|
glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, thiswalloffset, proneplanesize, w->wall.buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
|
|
if (w->over.buffer)
|
|
glBufferSubData(GL_ARRAY_BUFFER, thisoveroffset, proneplanesize, w->over.buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, prmapvbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, thismaskoffset, proneplanesize, w->mask.buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, w->stuffvbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(GLfloat)* 5, w->bigportal);
|
|
//glBufferSubData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat)* 5, 4 * sizeof(GLfloat)* 3, w->cap);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
w->wall.mapvbo_vertoffset = thiswalloffset / sizeof(_prvert);
|
|
w->over.mapvbo_vertoffset = thisoveroffset / sizeof(_prvert);
|
|
w->mask.mapvbo_vertoffset = thismaskoffset / sizeof(_prvert);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
w->wall.mapvbo_vertoffset = -1;
|
|
w->over.mapvbo_vertoffset = -1;
|
|
w->mask.mapvbo_vertoffset = -1;
|
|
}
|
|
|
|
w->flags.empty = 0;
|
|
w->flags.uptodate = 1;
|
|
w->flags.invalidtex = 0;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Updated wall %i.\n", wallnum);
|
|
}
|
|
|
|
static void polymer_drawwall(int16_t sectnum, int16_t wallnum)
|
|
{
|
|
usectortype *sec;
|
|
walltype *wal;
|
|
_prwall *w;
|
|
GLubyte oldcolor[4];
|
|
int32_t parallaxedfloor = 0, parallaxedceiling = 0;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Drawing wall %i...\n", wallnum);
|
|
|
|
sec = (usectortype *)§or[sectnum];
|
|
wal = &wall[wallnum];
|
|
w = prwalls[wallnum];
|
|
|
|
if ((sec->floorstat & 1) && (wal->nextsector >= 0) &&
|
|
(sector[wal->nextsector].floorstat & 1))
|
|
parallaxedfloor = 1;
|
|
|
|
if ((sec->ceilingstat & 1) && (wal->nextsector >= 0) &&
|
|
(sector[wal->nextsector].ceilingstat & 1))
|
|
parallaxedceiling = 1;
|
|
|
|
calc_and_apply_fog(wal->picnum, fogshade(wal->shade, wal->pal), sec->visibility, get_floor_fogpal(sec));
|
|
|
|
if ((w->underover & 1) && (!parallaxedfloor || (searchit == 2)))
|
|
{
|
|
if (searchit == 2) {
|
|
polymer_drawsearchplane(&w->wall, oldcolor, 0x05, (GLubyte *) &wallnum);
|
|
}
|
|
else
|
|
polymer_drawplane(&w->wall);
|
|
}
|
|
|
|
if ((w->underover & 2) && (!parallaxedceiling || (searchit == 2)))
|
|
{
|
|
if (searchit == 2) {
|
|
polymer_drawsearchplane(&w->over, oldcolor, 0x00, (GLubyte *) &wallnum);
|
|
}
|
|
else
|
|
polymer_drawplane(&w->over);
|
|
}
|
|
|
|
if ((wall[wallnum].cstat & 32) && (wall[wallnum].nextsector >= 0))
|
|
{
|
|
if (searchit == 2) {
|
|
polymer_drawsearchplane(&w->mask, oldcolor, 0x04, (GLubyte *) &wallnum);
|
|
}
|
|
else
|
|
polymer_drawplane(&w->mask);
|
|
}
|
|
|
|
//if (!searchit && (sector[sectnum].ceilingstat & 1) &&
|
|
// ((wall[wallnum].nextsector < 0) ||
|
|
// !(sector[wall[wallnum].nextsector].ceilingstat & 1)))
|
|
//{
|
|
// glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
|
|
// if (pr_vbos)
|
|
// {
|
|
// glBindBuffer(GL_ARRAY_BUFFER, w->stuffvbo);
|
|
// glVertexPointer(3, GL_FLOAT, 0, (const GLvoid*)(4 * sizeof(GLfloat) * 5));
|
|
// }
|
|
// else
|
|
// glVertexPointer(3, GL_FLOAT, 0, w->cap);
|
|
|
|
// glDrawArrays(GL_QUADS, 0, 4);
|
|
|
|
// if (pr_vbos)
|
|
// glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
//}
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Finished drawing wall %i...\n", wallnum);
|
|
}
|
|
|
|
// HSR
|
|
static void polymer_computeplane(_prplane* p)
|
|
{
|
|
GLfloat vec1[5], vec2[5], norm, r;// BxN[3], NxT[3], TxB[3];
|
|
int32_t i;
|
|
_prvert* buffer;
|
|
GLfloat* plane;
|
|
|
|
if (p->indices && (p->indicescount < 3))
|
|
return; // corrupt sector (E3L4, I'm looking at you)
|
|
|
|
buffer = p->buffer;
|
|
plane = p->plane;
|
|
|
|
i = 0;
|
|
do
|
|
{
|
|
vec1[0] = buffer[(INDICE(1))].x - buffer[(INDICE(0))].x; //x1
|
|
vec1[1] = buffer[(INDICE(1))].y - buffer[(INDICE(0))].y; //y1
|
|
vec1[2] = buffer[(INDICE(1))].z - buffer[(INDICE(0))].z; //z1
|
|
vec1[3] = buffer[(INDICE(1))].u - buffer[(INDICE(0))].u; //s1
|
|
vec1[4] = buffer[(INDICE(1))].v - buffer[(INDICE(0))].v; //t1
|
|
|
|
vec2[0] = buffer[(INDICE(2))].x - buffer[(INDICE(1))].x; //x2
|
|
vec2[1] = buffer[(INDICE(2))].y - buffer[(INDICE(1))].y; //y2
|
|
vec2[2] = buffer[(INDICE(2))].z - buffer[(INDICE(1))].z; //z2
|
|
vec2[3] = buffer[(INDICE(2))].u - buffer[(INDICE(1))].u; //s2
|
|
vec2[4] = buffer[(INDICE(2))].v - buffer[(INDICE(1))].v; //t2
|
|
|
|
polymer_crossproduct(vec2, vec1, plane);
|
|
|
|
norm = plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2];
|
|
|
|
// hack to work around a precision issue with slopes
|
|
if (norm >= 15000)
|
|
{
|
|
float tangent[3][3];
|
|
double det;
|
|
|
|
// normalize the normal/plane equation and calculate its plane norm
|
|
norm = -sqrt(norm);
|
|
norm = 1.0 / norm;
|
|
plane[0] *= norm;
|
|
plane[1] *= norm;
|
|
plane[2] *= norm;
|
|
plane[3] = -(plane[0] * buffer->x + plane[1] * buffer->y + plane[2] * buffer->z);
|
|
|
|
// calculate T and B
|
|
r = 1.0 / (vec1[3] * vec2[4] - vec2[3] * vec1[4]);
|
|
|
|
// tangent
|
|
tangent[0][0] = (vec2[4] * vec1[0] - vec1[4] * vec2[0]) * r;
|
|
tangent[0][1] = (vec2[4] * vec1[1] - vec1[4] * vec2[1]) * r;
|
|
tangent[0][2] = (vec2[4] * vec1[2] - vec1[4] * vec2[2]) * r;
|
|
|
|
polymer_normalize(&tangent[0][0]);
|
|
|
|
// bitangent
|
|
tangent[1][0] = (vec1[3] * vec2[0] - vec2[3] * vec1[0]) * r;
|
|
tangent[1][1] = (vec1[3] * vec2[1] - vec2[3] * vec1[1]) * r;
|
|
tangent[1][2] = (vec1[3] * vec2[2] - vec2[3] * vec1[2]) * r;
|
|
|
|
polymer_normalize(&tangent[1][0]);
|
|
|
|
// normal
|
|
tangent[2][0] = plane[0];
|
|
tangent[2][1] = plane[1];
|
|
tangent[2][2] = plane[2];
|
|
|
|
INVERT_3X3(p->tbn, det, tangent);
|
|
|
|
break;
|
|
}
|
|
i+= (p->indices) ? 3 : 1;
|
|
}
|
|
while ((p->indices && i < p->indicescount) ||
|
|
(!p->indices && i < p->vertcount));
|
|
}
|
|
|
|
static inline void polymer_crossproduct(GLfloat* in_a, GLfloat* in_b, GLfloat* out)
|
|
{
|
|
out[0] = in_a[1] * in_b[2] - in_a[2] * in_b[1];
|
|
out[1] = in_a[2] * in_b[0] - in_a[0] * in_b[2];
|
|
out[2] = in_a[0] * in_b[1] - in_a[1] * in_b[0];
|
|
}
|
|
|
|
static inline void polymer_transformpoint(const float* inpos, float* pos, float* matrix)
|
|
{
|
|
pos[0] = inpos[0] * matrix[0] +
|
|
inpos[1] * matrix[4] +
|
|
inpos[2] * matrix[8] +
|
|
+ matrix[12];
|
|
pos[1] = inpos[0] * matrix[1] +
|
|
inpos[1] * matrix[5] +
|
|
inpos[2] * matrix[9] +
|
|
+ matrix[13];
|
|
pos[2] = inpos[0] * matrix[2] +
|
|
inpos[1] * matrix[6] +
|
|
inpos[2] * matrix[10] +
|
|
+ matrix[14];
|
|
}
|
|
|
|
static inline void polymer_normalize(float* vec)
|
|
{
|
|
double norm;
|
|
|
|
norm = vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2];
|
|
|
|
norm = sqrt(norm);
|
|
norm = 1.0 / norm;
|
|
vec[0] *= norm;
|
|
vec[1] *= norm;
|
|
vec[2] *= norm;
|
|
}
|
|
|
|
static inline void polymer_pokesector(int16_t sectnum)
|
|
{
|
|
sectortype *sec = §or[sectnum];
|
|
_prsector *s = prsectors[sectnum];
|
|
walltype *wal = &wall[sec->wallptr];
|
|
int32_t i = 0;
|
|
|
|
if (!s->flags.uptodate)
|
|
polymer_updatesector(sectnum);
|
|
|
|
do
|
|
{
|
|
if ((wal->nextsector >= 0) && (!prsectors[wal->nextsector]->flags.uptodate))
|
|
polymer_updatesector(wal->nextsector);
|
|
if (!prwalls[sec->wallptr + i]->flags.uptodate)
|
|
polymer_updatewall(sec->wallptr + i);
|
|
|
|
i++;
|
|
wal = &wall[sec->wallptr + i];
|
|
}
|
|
while (i < sec->wallnum);
|
|
}
|
|
|
|
static void polymer_extractfrustum(GLfloat* modelview, GLfloat* projection, float* frustum)
|
|
{
|
|
GLfloat matrix[16];
|
|
int32_t i;
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadMatrixf(projection);
|
|
glMultMatrixf(modelview);
|
|
glGetFloatv(GL_TEXTURE_MATRIX, matrix);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
i = 0;
|
|
do
|
|
{
|
|
uint32_t ii = i<<2, iii = (i<<2) + 3;
|
|
|
|
frustum[i] = matrix[iii] + matrix[ii]; // left
|
|
frustum[i + 4] = matrix[iii] - matrix[ii]; // right
|
|
frustum[i + 8] = matrix[iii] - matrix[ii + 1]; // top
|
|
frustum[i + 12] = matrix[iii] + matrix[ii + 1]; // bottom
|
|
frustum[i + 16] = matrix[iii] - matrix[ii + 2]; // far
|
|
}
|
|
while (++i < 4);
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Frustum extracted.\n");
|
|
}
|
|
|
|
static inline int32_t polymer_planeinfrustum(_prplane *plane, float* frustum)
|
|
{
|
|
int32_t i, j, k = -1;
|
|
i = 4;
|
|
|
|
|
|
do
|
|
{
|
|
int32_t ii = i * 4;
|
|
j = k = plane->vertcount - 1;
|
|
|
|
do
|
|
{
|
|
k -= ((frustum[ii + 0] * plane->buffer[j].x +
|
|
frustum[ii + 1] * plane->buffer[j].y +
|
|
frustum[ii + 2] * plane->buffer[j].z +
|
|
frustum[ii + 3]) < 0.f);
|
|
}
|
|
while (j--);
|
|
|
|
if (k == -1)
|
|
return 0; // OUT !
|
|
}
|
|
while (i--);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static inline void polymer_scansprites(int16_t sectnum, uspritetype* localtsprite, int32_t* localspritesortcnt)
|
|
{
|
|
int32_t i;
|
|
spritetype *spr;
|
|
|
|
for (i = headspritesect[sectnum];i >=0;i = nextspritesect[i])
|
|
{
|
|
spr = &sprite[i];
|
|
if ((((spr->cstat&0x8000) == 0) || (showinvisibility)) &&
|
|
(spr->xrepeat > 0) && (spr->yrepeat > 0) &&
|
|
(*localspritesortcnt < maxspritesonscreen))
|
|
{
|
|
// this function's localtsprite is either the tsprite global or
|
|
// polymer_drawroom's locattsprite, so no aliasing
|
|
Bmemcpy(&localtsprite[*localspritesortcnt], spr, sizeof(spritetype));
|
|
localtsprite[*localspritesortcnt].extra = 0;
|
|
localtsprite[(*localspritesortcnt)++].owner = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void polymer_updatesprite(int32_t snum)
|
|
{
|
|
int32_t xsize, ysize, i, j;
|
|
int32_t tilexoff, tileyoff, xoff, yoff, centeryoff=0;
|
|
uspritetype *tspr = tspriteptr[snum];
|
|
float xratio, yratio, ang;
|
|
float spos[3];
|
|
const _prvert *inbuffer;
|
|
uint8_t flipu, flipv;
|
|
_prsprite *s;
|
|
|
|
const uint32_t cs = tspr->cstat;
|
|
const uint32_t alignmask = (cs & SPR_ALIGN_MASK);
|
|
const uint8_t flooraligned = (alignmask==SPR_FLOOR);
|
|
|
|
if (pr_nullrender >= 3) return;
|
|
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Updating sprite %i...\n", snum);
|
|
|
|
int32_t const curpicnum = tspr->picnum;
|
|
|
|
if (tspr->owner < 0 || curpicnum < 0) return;
|
|
|
|
s = prsprites[tspr->owner];
|
|
|
|
if (s == NULL)
|
|
{
|
|
s = prsprites[tspr->owner] = (_prsprite *)Xcalloc(sizeof(_prsprite), 1);
|
|
|
|
s->plane.buffer = (_prvert *)Xcalloc(4, sizeof(_prvert)); // XXX
|
|
s->plane.vertcount = 4;
|
|
s->plane.mapvbo_vertoffset = -1;
|
|
s->hash = 0xDEADBEEF;
|
|
}
|
|
|
|
if ((tspr->cstat & 48) && (pr_vbos > 0) && !s->plane.vbo)
|
|
{
|
|
if (pr_nullrender < 2)
|
|
{
|
|
glGenBuffers(1, &s->plane.vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, s->plane.vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(_prvert), NULL, mapvbousage);
|
|
}
|
|
}
|
|
|
|
if (tspr->cstat & 48 && searchit != 2)
|
|
{
|
|
uint32_t const changed = XXH32((uint8_t *) tspr, offsetof(spritetype, owner), 0xDEADBEEF);
|
|
|
|
if (changed == s->hash)
|
|
return;
|
|
|
|
s->hash = changed;
|
|
}
|
|
|
|
polymer_getbuildmaterial(&s->plane.material, curpicnum, tspr->pal, tspr->shade,
|
|
sector[tspr->sectnum].visibility, DAMETH_MASK | DAMETH_CLAMPED);
|
|
|
|
if (tspr->cstat & 2)
|
|
{
|
|
if (tspr->cstat & 512)
|
|
s->plane.material.diffusemodulation[3] = 0x55;
|
|
else
|
|
s->plane.material.diffusemodulation[3] = 0xAA;
|
|
}
|
|
|
|
float f = s->plane.material.diffusemodulation[3] * (1.0f - spriteext[tspr->owner].alpha);
|
|
s->plane.material.diffusemodulation[3] = (GLubyte)f;
|
|
|
|
if (searchit == 2)
|
|
{
|
|
polymer_setupdiffusemodulation(&s->plane, 0x03, (GLubyte *) &tspr->owner);
|
|
s->hash = 0xDEADBEEF;
|
|
}
|
|
|
|
if (((tspr->cstat>>4) & 3) == 0)
|
|
xratio = (float)(tspr->xrepeat) * 0.20f; // 32 / 160
|
|
else
|
|
xratio = (float)(tspr->xrepeat) * 0.25f;
|
|
|
|
yratio = (float)(tspr->yrepeat) * 0.25f;
|
|
|
|
xsize = tilesiz[curpicnum].x;
|
|
ysize = tilesiz[curpicnum].y;
|
|
|
|
if (usehightile && h_xsize[curpicnum])
|
|
{
|
|
xsize = h_xsize[curpicnum];
|
|
ysize = h_ysize[curpicnum];
|
|
}
|
|
|
|
xsize = (int32_t)(xsize * xratio);
|
|
ysize = (int32_t)(ysize * yratio);
|
|
|
|
tilexoff = (int32_t)tspr->xoffset;
|
|
tileyoff = (int32_t)tspr->yoffset;
|
|
tilexoff += (usehightile && h_xsize[curpicnum]) ? h_xoffs[curpicnum] : picanm[curpicnum].xofs;
|
|
tileyoff += (usehightile && h_xsize[curpicnum]) ? h_yoffs[curpicnum] : picanm[curpicnum].yofs;
|
|
|
|
xoff = (int32_t)(tilexoff * xratio);
|
|
yoff = (int32_t)(tileyoff * yratio);
|
|
|
|
if ((tspr->cstat & 128) && !flooraligned)
|
|
{
|
|
if (alignmask == 0)
|
|
yoff -= ysize / 2;
|
|
else
|
|
centeryoff = ysize / 2;
|
|
}
|
|
|
|
spos[0] = (float)tspr->y;
|
|
spos[1] = -(float)(tspr->z) / 16.0f;
|
|
spos[2] = -(float)tspr->x;
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
inbuffer = vertsprite;
|
|
|
|
{
|
|
const uint8_t xflip = !!(cs & SPR_XFLIP);
|
|
const uint8_t yflip = !!(cs & SPR_YFLIP);
|
|
|
|
// Initially set flipu and flipv.
|
|
flipu = (xflip ^ flooraligned);
|
|
flipv = (yflip && !flooraligned);
|
|
|
|
if (pr_billboardingmode && alignmask==0)
|
|
{
|
|
// do surgery on the face tspr to make it look like a wall sprite
|
|
tspr->cstat |= 16;
|
|
tspr->ang = (fix16_to_int(viewangle) + 1024) & 2047;
|
|
}
|
|
|
|
if (flipu)
|
|
xoff = -xoff;
|
|
|
|
if (yflip && alignmask!=0)
|
|
yoff = -yoff;
|
|
}
|
|
|
|
switch (tspr->cstat & SPR_ALIGN_MASK)
|
|
{
|
|
case 0:
|
|
ang = (float)((fix16_to_int(viewangle)) & 2047) * (360.f/2048.f);
|
|
|
|
glTranslatef(spos[0], spos[1], spos[2]);
|
|
glRotatef(-ang, 0.0f, 1.0f, 0.0f);
|
|
glRotatef(-horizang, 1.0f, 0.0f, 0.0f);
|
|
glTranslatef((float)(-xoff), (float)(yoff), 0.0f);
|
|
glScalef((float)(xsize), (float)(ysize), 1.0f);
|
|
break;
|
|
case SPR_WALL:
|
|
ang = (float)((tspr->ang + 1024) & 2047) * (360.f/2048.f);
|
|
|
|
glTranslatef(spos[0], spos[1], spos[2]);
|
|
glRotatef(-ang, 0.0f, 1.0f, 0.0f);
|
|
glTranslatef((float)(-xoff), (float)(yoff-centeryoff), 0.0f);
|
|
glScalef((float)(xsize), (float)(ysize), 1.0f);
|
|
break;
|
|
case SPR_FLOOR:
|
|
ang = (float)((tspr->ang + 1024) & 2047) * (360.f/2048.f);
|
|
|
|
glTranslatef(spos[0], spos[1], spos[2]);
|
|
glRotatef(-ang, 0.0f, 1.0f, 0.0f);
|
|
glTranslatef((float)(-xoff), 1.0f, (float)(yoff));
|
|
glScalef((float)(xsize), 1.0f, (float)(ysize));
|
|
|
|
inbuffer = horizsprite;
|
|
break;
|
|
}
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, spritemodelview);
|
|
glPopMatrix();
|
|
|
|
Bmemcpy(s->plane.buffer, inbuffer, sizeof(_prvert) * 4);
|
|
|
|
if (flipu || flipv)
|
|
{
|
|
i = 0;
|
|
do
|
|
{
|
|
if (flipu)
|
|
s->plane.buffer[i].u =
|
|
(s->plane.buffer[i].u - 1.0f) * -1.0f;
|
|
if (flipv)
|
|
s->plane.buffer[i].v =
|
|
(s->plane.buffer[i].v - 1.0f) * -1.0f;
|
|
}
|
|
while (++i < 4);
|
|
}
|
|
|
|
i = 0;
|
|
do
|
|
polymer_transformpoint(&inbuffer[i].x, &s->plane.buffer[i].x, spritemodelview);
|
|
while (++i < 4);
|
|
|
|
polymer_computeplane(&s->plane);
|
|
|
|
if (pr_nullrender < 2)
|
|
{
|
|
if (alignmask && (pr_vbos > 0))
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER, s->plane.vbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(_prvert), s->plane.buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
else if (s->plane.vbo) // clean up the vbo if a wall/floor sprite becomes a face sprite
|
|
{
|
|
glDeleteBuffers(1, &s->plane.vbo);
|
|
s->plane.vbo = 0;
|
|
}
|
|
}
|
|
|
|
if (alignmask)
|
|
{
|
|
int32_t curpriority = 0;
|
|
|
|
polymer_resetplanelights(&s->plane);
|
|
|
|
while (curpriority < pr_maxlightpriority)
|
|
{
|
|
i = j = 0;
|
|
while (j < lightcount)
|
|
{
|
|
while (!prlights[i].flags.active)
|
|
i++;
|
|
|
|
if (prlights[i].priority != curpriority)
|
|
{
|
|
i++;
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
if (polymer_planeinlight(&s->plane, &prlights[i]))
|
|
polymer_addplanelight(&s->plane, i);
|
|
i++;
|
|
j++;
|
|
}
|
|
curpriority++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// SKIES
|
|
static void polymer_getsky(void)
|
|
{
|
|
int32_t i;
|
|
|
|
i = 0;
|
|
while (i < numsectors)
|
|
{
|
|
if (sector[i].ceilingstat & 1)
|
|
{
|
|
int32_t horizfrac;
|
|
|
|
cursky = sector[i].ceilingpicnum;
|
|
curskypal = sector[i].ceilingpal;
|
|
curskyshade = sector[i].ceilingshade;
|
|
|
|
getpsky(cursky, &horizfrac, NULL, NULL, NULL);
|
|
|
|
switch (horizfrac)
|
|
{
|
|
case 0:
|
|
// psky always at same level wrt screen
|
|
curskyangmul = 0.f;
|
|
break;
|
|
case 65536:
|
|
// psky horiz follows camera horiz
|
|
curskyangmul = 1.f;
|
|
break;
|
|
default:
|
|
// sky has hard-coded parallax
|
|
curskyangmul = 1/DEFAULT_ARTSKY_ANGDIV;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void polymer_drawsky(int16_t tilenum, char palnum, int8_t shade)
|
|
{
|
|
float pos[3];
|
|
pthtyp* pth;
|
|
|
|
pos[0] = fglobalposy;
|
|
pos[1] = fglobalposz * (-1.f/16.f);
|
|
pos[2] = -fglobalposx;
|
|
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
glLoadMatrixf(curskymodelviewmatrix);
|
|
|
|
glTranslatef(pos[0], pos[1], pos[2]);
|
|
glScalef(1000.0f, 1000.0f, 1000.0f);
|
|
|
|
drawingskybox = 1;
|
|
pth = texcache_fetch(tilenum, 0, 0, DAMETH_NOMASK);
|
|
drawingskybox = 0;
|
|
|
|
if (pth && (pth->flags & PTH_SKYBOX))
|
|
polymer_drawskybox(tilenum, palnum, shade);
|
|
else
|
|
polymer_drawartsky(tilenum, palnum, shade);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
static void polymer_initartsky(void)
|
|
{
|
|
GLfloat halfsqrt2 = 0.70710678f;
|
|
|
|
artskydata[0] = -1.0f; artskydata[1] = 0.0f; // 0
|
|
artskydata[2] = -halfsqrt2; artskydata[3] = halfsqrt2; // 1
|
|
artskydata[4] = 0.0f; artskydata[5] = 1.0f; // 2
|
|
artskydata[6] = halfsqrt2; artskydata[7] = halfsqrt2; // 3
|
|
artskydata[8] = 1.0f; artskydata[9] = 0.0f; // 4
|
|
artskydata[10] = halfsqrt2; artskydata[11] = -halfsqrt2; // 5
|
|
artskydata[12] = 0.0f; artskydata[13] = -1.0f; // 6
|
|
artskydata[14] = -halfsqrt2; artskydata[15] = -halfsqrt2; // 7
|
|
}
|
|
|
|
static void polymer_drawartsky(int16_t tilenum, char palnum, int8_t shade)
|
|
{
|
|
pthtyp* pth;
|
|
GLuint glpics[PSKYOFF_MAX+1];
|
|
GLfloat glcolors[PSKYOFF_MAX+1][3];
|
|
int32_t i, j;
|
|
GLfloat height = 2.45f / 2.0f;
|
|
|
|
int32_t dapskybits;
|
|
const int8_t *dapskyoff = getpsky(tilenum, NULL, &dapskybits, NULL, NULL);
|
|
const int32_t numskytilesm1 = (1<<dapskybits)-1;
|
|
|
|
i = 0;
|
|
while (i <= PSKYOFF_MAX)
|
|
{
|
|
int16_t picnum = tilenum + i;
|
|
// Prevent oob by bad user input:
|
|
if (picnum >= MAXTILES)
|
|
picnum = MAXTILES-1;
|
|
|
|
DO_TILE_ANIM(picnum, 0);
|
|
if (!waloff[picnum])
|
|
loadtile(picnum);
|
|
pth = texcache_fetch(picnum, palnum, 0, DAMETH_NOMASK);
|
|
glpics[i] = pth ? pth->glpic : 0;
|
|
|
|
glcolors[i][0] = glcolors[i][1] = glcolors[i][2] = getshadefactor(shade);
|
|
|
|
if (pth)
|
|
{
|
|
// tinting
|
|
polytintflags_t const tintflags = hictinting[palnum].f;
|
|
if (!(tintflags & HICTINT_PRECOMPUTED))
|
|
{
|
|
if (pth->flags & PTH_HIGHTILE)
|
|
{
|
|
if (pth->palnum != palnum || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
|
|
hictinting_apply(glcolors[i], palnum);
|
|
}
|
|
else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
|
|
hictinting_apply(glcolors[i], palnum);
|
|
}
|
|
|
|
// global tinting
|
|
if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
|
|
hictinting_apply(glcolors[i], MAXPALOOKUPS-1);
|
|
|
|
globaltinting_apply(glcolors[i]);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
i = 0;
|
|
j = 8; // In Polymer, an ART sky has always 8 sides...
|
|
while (i < j)
|
|
{
|
|
GLint oldswrap;
|
|
// ... but in case a multi-psky specifies less than 8, repeat cyclically:
|
|
const int8_t tileofs = dapskyoff[i&numskytilesm1];
|
|
|
|
glColor4f(glcolors[tileofs][0], glcolors[tileofs][1], glcolors[tileofs][2], 1.0f);
|
|
glBindTexture(GL_TEXTURE_2D, glpics[tileofs]);
|
|
|
|
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &oldswrap);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
|
|
polymer_drawartskyquad(i, (i + 1) & (j - 1), height);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, oldswrap);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static void polymer_drawartskyquad(int32_t p1, int32_t p2, GLfloat height)
|
|
{
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0.0f, 0.0f);
|
|
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p1 * 2) + 1], height, skybox[p1 * 2]);
|
|
glVertex3f(artskydata[(p1 * 2) + 1], height, artskydata[p1 * 2]);
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p1 * 2) + 1], -height, skybox[p1 * 2]);
|
|
glVertex3f(artskydata[(p1 * 2) + 1], -height, artskydata[p1 * 2]);
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p2 * 2) + 1], -height, skybox[p2 * 2]);
|
|
glVertex3f(artskydata[(p2 * 2) + 1], -height, artskydata[p2 * 2]);
|
|
glTexCoord2f(1.0f, 0.0f);
|
|
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p2 * 2) + 1], height, skybox[p2 * 2]);
|
|
glVertex3f(artskydata[(p2 * 2) + 1], height, artskydata[p2 * 2]);
|
|
glEnd();
|
|
}
|
|
|
|
static void polymer_drawskybox(int16_t tilenum, char palnum, int8_t shade)
|
|
{
|
|
pthtyp* pth;
|
|
int32_t i;
|
|
GLfloat color[3];
|
|
|
|
if ((pr_vbos > 0) && (skyboxdatavbo == 0))
|
|
{
|
|
glGenBuffers(1, &skyboxdatavbo);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, skyboxdatavbo);
|
|
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat) * 5 * 6, skyboxdata, modelvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
if (pr_vbos > 0)
|
|
glBindBuffer(GL_ARRAY_BUFFER, skyboxdatavbo);
|
|
|
|
DO_TILE_ANIM(tilenum, 0);
|
|
|
|
i = 0;
|
|
while (i < 6)
|
|
{
|
|
drawingskybox = i + 1;
|
|
pth = texcache_fetch(tilenum, palnum, 0, DAMETH_CLAMPED);
|
|
|
|
color[0] = color[1] = color[2] = getshadefactor(shade);
|
|
|
|
if (pth)
|
|
{
|
|
// tinting
|
|
polytintflags_t const tintflags = hictinting[palnum].f;
|
|
if (!(tintflags & HICTINT_PRECOMPUTED))
|
|
{
|
|
if (pth->flags & PTH_HIGHTILE)
|
|
{
|
|
if (pth->palnum != palnum || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
|
|
hictinting_apply(color, palnum);
|
|
}
|
|
else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
|
|
hictinting_apply(color, palnum);
|
|
}
|
|
|
|
// global tinting
|
|
if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
|
|
hictinting_apply(color, MAXPALOOKUPS-1);
|
|
|
|
globaltinting_apply(color);
|
|
}
|
|
|
|
glColor4f(color[0], color[1], color[2], 1.0);
|
|
glBindTexture(GL_TEXTURE_2D, pth ? pth->glpic : 0);
|
|
if (pr_vbos > 0)
|
|
{
|
|
glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(4 * 5 * i * sizeof(GLfloat)));
|
|
glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(((4 * 5 * i) + 3) * sizeof(GLfloat)));
|
|
} else {
|
|
glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), &skyboxdata[4 * 5 * i]);
|
|
glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &skyboxdata[3 + (4 * 5 * i)]);
|
|
}
|
|
glDrawArrays(GL_QUADS, 0, 4);
|
|
|
|
i++;
|
|
}
|
|
drawingskybox = 0;
|
|
|
|
if (pr_vbos > 0)
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
// MDSPRITES
|
|
static void polymer_drawmdsprite(uspritetype *tspr)
|
|
{
|
|
md3model_t* m;
|
|
mdskinmap_t* sk;
|
|
float *v0, *v1;
|
|
md3surf_t *s;
|
|
char targetpal, usinghighpal, foundpalskin;
|
|
float spos2[3], spos[3], tspos[3], lpos[3], tlpos[3], vec[3], mat[4][4];
|
|
float ang;
|
|
float scale;
|
|
double det;
|
|
int32_t surfi, i, j;
|
|
GLubyte* color;
|
|
int32_t materialbits;
|
|
float sradius, lradius;
|
|
int16_t modellights[PR_MAXLIGHTS];
|
|
char modellightcount;
|
|
uint8_t curpriority;
|
|
|
|
uint8_t lpal = (tspr->owner >= MAXSPRITES) ? tspr->pal : sprite[tspr->owner].pal;
|
|
|
|
m = (md3model_t*)models[tile2model[Ptile2tile(tspr->picnum,lpal)].modelid];
|
|
updateanimation((md2model_t *)m,tspr,lpal);
|
|
|
|
if ((pr_vbos > 1) && (m->indices == NULL))
|
|
polymer_loadmodelvbos(m);
|
|
|
|
// Hackish, but that means it's a model drawn by rotatesprite.
|
|
if (tspriteptr[maxspritesonscreen] == tspr) {
|
|
float x, y, z;
|
|
|
|
spos[0] = fglobalposy;
|
|
spos[1] = fglobalposz * (-1.f/16.f);
|
|
spos[2] = -fglobalposx;
|
|
|
|
// The coordinates are actually floats disguised as int in this case
|
|
memcpy(&x, &tspr->x, sizeof(float));
|
|
memcpy(&y, &tspr->y, sizeof(float));
|
|
memcpy(&z, &tspr->z, sizeof(float));
|
|
|
|
spos2[0] = y - globalposy;
|
|
spos2[1] = (z - fglobalposz) * (-1.f/16.f);
|
|
spos2[2] = fglobalposx - x;
|
|
} else {
|
|
spos[0] = (float)tspr->y;
|
|
spos[1] = -(float)(tspr->z) / 16.0f;
|
|
spos[2] = -(float)tspr->x;
|
|
|
|
spos2[0] = spos2[1] = spos2[2] = 0.0f;
|
|
}
|
|
|
|
ang = (float)((tspr->ang+spriteext[tspr->owner].angoff) & 2047) * (360.f/2048.f);
|
|
ang -= 90.0f;
|
|
if (((tspr->cstat>>4) & 3) == 2)
|
|
ang -= 90.0f;
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
scale = (1.0/4.0);
|
|
scale *= m->scale;
|
|
if (pr_overridemodelscale) {
|
|
scale *= pr_overridemodelscale;
|
|
} else {
|
|
scale *= m->bscale;
|
|
}
|
|
|
|
if (tspriteptr[maxspritesonscreen] == tspr) {
|
|
float playerang, radplayerang, cosminusradplayerang, sinminusradplayerang, hudzoom;
|
|
|
|
playerang = (globalang & 2047) * (360.f/2048.f) - 90.0f;
|
|
radplayerang = (globalang & 2047) * (2.0f * fPI / 2048.0f);
|
|
cosminusradplayerang = cos(-radplayerang);
|
|
sinminusradplayerang = sin(-radplayerang);
|
|
hudzoom = 65536.0 / spriteext[tspr->owner].offset.z;
|
|
|
|
glTranslatef(spos[0], spos[1], spos[2]);
|
|
glRotatef(horizang, -cosminusradplayerang, 0.0f, sinminusradplayerang);
|
|
glRotatef(spriteext[tspr->owner].roll * (360.f/2048.f), sinminusradplayerang, 0.0f, cosminusradplayerang);
|
|
glRotatef(-playerang, 0.0f, 1.0f, 0.0f);
|
|
glScalef(hudzoom, 1.0f, 1.0f);
|
|
glRotatef(playerang, 0.0f, 1.0f, 0.0f);
|
|
glTranslatef(spos2[0], spos2[1], spos2[2]);
|
|
glRotatef(-ang, 0.0f, 1.0f, 0.0f);
|
|
} else {
|
|
glTranslatef(spos[0], spos[1], spos[2]);
|
|
glRotatef(-ang, 0.0f, 1.0f, 0.0f);
|
|
}
|
|
if (((tspr->cstat>>4) & 3) == 2)
|
|
{
|
|
glTranslatef(0.0f, 0.0, -(float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 8.0f);
|
|
glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
|
|
}
|
|
else
|
|
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
|
|
|
|
if ((tspr->cstat & 128) && (((tspr->cstat>>4) & 3) != 2))
|
|
glTranslatef(0.0f, 0.0, -(float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 8.0f);
|
|
|
|
// yoffset differs from zadd in that it does not follow cstat&8 y-flipping
|
|
glTranslatef(0.0f, 0.0, m->yoffset * 64 * scale * tspr->yrepeat);
|
|
|
|
if (tspr->cstat & 8)
|
|
{
|
|
glTranslatef(0.0f, 0.0, (float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 4.0f);
|
|
glScalef(1.0f, 1.0f, -1.0f);
|
|
}
|
|
|
|
if (tspr->cstat & 4)
|
|
glScalef(1.0f, -1.0f, 1.0f);
|
|
|
|
if (!(tspr->cstat & 4) != !(tspr->cstat & 8)) {
|
|
// Only inverting one coordinate will reverse the winding order of
|
|
// faces, so we need to account for that when culling.
|
|
SWITCH_CULL_DIRECTION;
|
|
}
|
|
|
|
glScalef(scale * tspr->xrepeat, scale * tspr->xrepeat, scale * tspr->yrepeat);
|
|
glTranslatef(0.0f, 0.0, m->zadd * 64);
|
|
|
|
// scripted model rotation
|
|
if (tspr->owner < MAXSPRITES &&
|
|
(spriteext[tspr->owner].pitch || spriteext[tspr->owner].roll))
|
|
{
|
|
float pitchang, rollang, offsets[3];
|
|
|
|
pitchang = (float)(spriteext[tspr->owner].pitch) * (360.f/2048.f);
|
|
rollang = (float)(spriteext[tspr->owner].roll) * (360.f/2048.f);
|
|
|
|
offsets[0] = -spriteext[tspr->owner].offset.x / (scale * tspr->xrepeat);
|
|
offsets[1] = -spriteext[tspr->owner].offset.y / (scale * tspr->xrepeat);
|
|
offsets[2] = (float)(spriteext[tspr->owner].offset.z) / 16.0f / (scale * tspr->yrepeat);
|
|
|
|
glTranslatef(-offsets[0], -offsets[1], -offsets[2]);
|
|
|
|
glRotatef(pitchang, 0.0f, 1.0f, 0.0f);
|
|
glRotatef(rollang, -1.0f, 0.0f, 0.0f);
|
|
|
|
glTranslatef(offsets[0], offsets[1], offsets[2]);
|
|
}
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, spritemodelview);
|
|
|
|
glPopMatrix();
|
|
glPushMatrix();
|
|
glMultMatrixf(spritemodelview);
|
|
|
|
// invert this matrix to get the polymer -> mdsprite space
|
|
memcpy(mat, spritemodelview, sizeof(float) * 16);
|
|
INVERT_4X4(mdspritespace, det, mat);
|
|
|
|
// debug code for drawing the model bounding sphere
|
|
// glDisable(GL_TEXTURE_2D);
|
|
// glBegin(GL_LINES);
|
|
// glColor4f(1.0, 0.0, 0.0, 1.0);
|
|
// glVertex3f(m->head.frames[m->cframe].cen.x,
|
|
// m->head.frames[m->cframe].cen.y,
|
|
// m->head.frames[m->cframe].cen.z);
|
|
// glVertex3f(m->head.frames[m->cframe].cen.x + m->head.frames[m->cframe].r,
|
|
// m->head.frames[m->cframe].cen.y,
|
|
// m->head.frames[m->cframe].cen.z);
|
|
// glColor4f(0.0, 1.0, 0.0, 1.0);
|
|
// glVertex3f(m->head.frames[m->cframe].cen.x,
|
|
// m->head.frames[m->cframe].cen.y,
|
|
// m->head.frames[m->cframe].cen.z);
|
|
// glVertex3f(m->head.frames[m->cframe].cen.x,
|
|
// m->head.frames[m->cframe].cen.y + m->head.frames[m->cframe].r,
|
|
// m->head.frames[m->cframe].cen.z);
|
|
// glColor4f(0.0, 0.0, 1.0, 1.0);
|
|
// glVertex3f(m->head.frames[m->cframe].cen.x,
|
|
// m->head.frames[m->cframe].cen.y,
|
|
// m->head.frames[m->cframe].cen.z);
|
|
// glVertex3f(m->head.frames[m->cframe].cen.x,
|
|
// m->head.frames[m->cframe].cen.y,
|
|
// m->head.frames[m->cframe].cen.z + m->head.frames[m->cframe].r);
|
|
// glEnd();
|
|
// glEnable(GL_TEXTURE_2D);
|
|
|
|
polymer_getscratchmaterial(&mdspritematerial);
|
|
|
|
color = mdspritematerial.diffusemodulation;
|
|
|
|
color[0] = color[1] = color[2] =
|
|
(GLubyte)(((float)(numshades-min(max((tspr->shade * shadescale)+m->shadeoff,0),numshades)))/((float)numshades) * 0xFF);
|
|
|
|
usinghighpal = (pr_highpalookups &&
|
|
prhighpalookups[curbasepal][tspr->pal].map);
|
|
|
|
// tinting
|
|
polytintflags_t const tintflags = hictinting[tspr->pal].f;
|
|
if (!usinghighpal && !(tintflags & HICTINT_PRECOMPUTED))
|
|
{
|
|
if (!(m->flags&1))
|
|
hictinting_apply_ub(color, tspr->pal);
|
|
else globalnoeffect=1; //mdloadskin reads this
|
|
}
|
|
|
|
// global tinting
|
|
if (!usinghighpal && have_basepal_tint())
|
|
hictinting_apply_ub(color, MAXPALOOKUPS-1);
|
|
|
|
globaltinting_apply_ub(color);
|
|
|
|
if (tspr->cstat & 2)
|
|
{
|
|
if (!(tspr->cstat&512))
|
|
color[3] = 0xAA;
|
|
else
|
|
color[3] = 0x55;
|
|
} else
|
|
color[3] = 0xFF;
|
|
|
|
{
|
|
double f = color[3] * (1.0f - spriteext[tspr->owner].alpha);
|
|
color[3] = (GLubyte)f;
|
|
}
|
|
|
|
if (searchit == 2)
|
|
{
|
|
color[0] = 0x03;
|
|
color[1] = ((GLubyte *)(&tspr->owner))[0];
|
|
color[2] = ((GLubyte *)(&tspr->owner))[1];
|
|
color[3] = 0xFF;
|
|
}
|
|
|
|
if (pr_gpusmoothing)
|
|
mdspritematerial.frameprogress = m->interpol;
|
|
|
|
mdspritematerial.mdspritespace = GL_TRUE;
|
|
|
|
modellightcount = 0;
|
|
curpriority = 0;
|
|
|
|
// light culling
|
|
if (lightcount && (!depth || mirrors[depth-1].plane))
|
|
{
|
|
sradius = (m->head.frames[m->cframe].r * (1 - m->interpol)) +
|
|
(m->head.frames[m->nframe].r * m->interpol);
|
|
|
|
sradius *= max(scale * tspr->xrepeat, scale * tspr->yrepeat);
|
|
sradius /= 1000.0f;
|
|
|
|
spos[0] = (m->head.frames[m->cframe].cen.x * (1 - m->interpol)) +
|
|
(m->head.frames[m->nframe].cen.x * m->interpol);
|
|
spos[1] = (m->head.frames[m->cframe].cen.y * (1 - m->interpol)) +
|
|
(m->head.frames[m->nframe].cen.y * m->interpol);
|
|
spos[2] = (m->head.frames[m->cframe].cen.z * (1 - m->interpol)) +
|
|
(m->head.frames[m->nframe].cen.z * m->interpol);
|
|
|
|
polymer_transformpoint(spos, tspos, spritemodelview);
|
|
polymer_transformpoint(tspos, spos, rootmodelviewmatrix);
|
|
|
|
while (curpriority < pr_maxlightpriority)
|
|
{
|
|
i = j = 0;
|
|
while (j < lightcount)
|
|
{
|
|
while (!prlights[i].flags.active)
|
|
i++;
|
|
|
|
if (prlights[i].priority != curpriority)
|
|
{
|
|
i++;
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
lradius = prlights[i].range / 1000.0f;
|
|
|
|
lpos[0] = (float)prlights[i].y;
|
|
lpos[1] = -(float)prlights[i].z / 16.0f;
|
|
lpos[2] = -(float)prlights[i].x;
|
|
|
|
polymer_transformpoint(lpos, tlpos, rootmodelviewmatrix);
|
|
|
|
vec[0] = tlpos[0] - spos[0];
|
|
vec[0] *= vec[0];
|
|
vec[1] = tlpos[1] - spos[1];
|
|
vec[1] *= vec[1];
|
|
vec[2] = tlpos[2] - spos[2];
|
|
vec[2] *= vec[2];
|
|
|
|
if ((vec[0] + vec[1] + vec[2]) <= ((sradius+lradius) * (sradius+lradius)))
|
|
modellights[modellightcount++] = i;
|
|
|
|
i++;
|
|
j++;
|
|
}
|
|
curpriority++;
|
|
}
|
|
}
|
|
|
|
for (surfi=0;surfi<m->head.numsurfs;surfi++)
|
|
{
|
|
s = &m->head.surfs[surfi];
|
|
v0 = &s->geometry[m->cframe*s->numverts*15];
|
|
v1 = &s->geometry[m->nframe*s->numverts*15];
|
|
|
|
// debug code for drawing model normals
|
|
// glDisable(GL_TEXTURE_2D);
|
|
// glBegin(GL_LINES);
|
|
// glColor4f(1.0, 1.0, 1.0, 1.0);
|
|
//
|
|
// int i = 0;
|
|
// while (i < s->numverts)
|
|
// {
|
|
// glVertex3f(v0[(i * 6) + 0],
|
|
// v0[(i * 6) + 1],
|
|
// v0[(i * 6) + 2]);
|
|
// glVertex3f(v0[(i * 6) + 0] + v0[(i * 6) + 3] * 100,
|
|
// v0[(i * 6) + 1] + v0[(i * 6) + 4] * 100,
|
|
// v0[(i * 6) + 2] + v0[(i * 6) + 5] * 100);
|
|
// i++;
|
|
// }
|
|
// glEnd();
|
|
// glEnable(GL_TEXTURE_2D);
|
|
|
|
|
|
targetpal = tspr->pal;
|
|
foundpalskin = 0;
|
|
|
|
for (sk = m->skinmap; sk; sk = sk->next)
|
|
if ((int32_t)sk->palette == tspr->pal &&
|
|
sk->skinnum == tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum &&
|
|
sk->surfnum == surfi)
|
|
{
|
|
if (sk->specpower != 1.0)
|
|
mdspritematerial.specmaterial[0] = sk->specpower;
|
|
mdspritematerial.specmaterial[1] = sk->specfactor;
|
|
foundpalskin = 1;
|
|
}
|
|
|
|
// If we have a global palette tint, the palskin won't do us any good
|
|
if (curbasepal)
|
|
foundpalskin = 0;
|
|
|
|
if (!foundpalskin && usinghighpal) {
|
|
// We don't have a specific skin defined for this palette
|
|
// Use the base skin instead and plug in our highpalookup map
|
|
targetpal = 0;
|
|
mdspritematerial.highpalookupmap = prhighpalookups[curbasepal][tspr->pal].map;
|
|
}
|
|
|
|
mdspritematerial.diffusemap =
|
|
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,targetpal,surfi);
|
|
if (!mdspritematerial.diffusemap)
|
|
continue;
|
|
|
|
if (!(tspr->extra&TSPR_EXTRA_MDHACK))
|
|
{
|
|
mdspritematerial.detailmap =
|
|
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,DETAILPAL,surfi);
|
|
|
|
for (sk = m->skinmap; sk; sk = sk->next)
|
|
if ((int32_t)sk->palette == DETAILPAL &&
|
|
sk->skinnum == tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum &&
|
|
sk->surfnum == surfi)
|
|
mdspritematerial.detailscale[0] = mdspritematerial.detailscale[1] = sk->param;
|
|
|
|
mdspritematerial.specmap =
|
|
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,SPECULARPAL,surfi);
|
|
|
|
mdspritematerial.normalmap =
|
|
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,NORMALPAL,surfi);
|
|
|
|
for (sk = m->skinmap; sk; sk = sk->next)
|
|
if ((int32_t)sk->palette == NORMALPAL &&
|
|
sk->skinnum == tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum &&
|
|
sk->surfnum == surfi) {
|
|
mdspritematerial.normalbias[0] = sk->specpower;
|
|
mdspritematerial.normalbias[1] = sk->specfactor;
|
|
}
|
|
|
|
mdspritematerial.glowmap =
|
|
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,GLOWPAL,surfi);
|
|
}
|
|
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
|
|
if (pr_vbos > 1)
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER, m->texcoords[surfi]);
|
|
glTexCoordPointer(2, GL_FLOAT, 0, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m->geometry[surfi]);
|
|
glVertexPointer(3, GL_FLOAT, sizeof(float) * 15, (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15));
|
|
glNormalPointer(GL_FLOAT, sizeof(float) * 15, (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15) + 3);
|
|
|
|
mdspritematerial.tbn = (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15) + 6;
|
|
|
|
if (pr_gpusmoothing) {
|
|
mdspritematerial.nextframedata = (GLfloat*)(m->nframe * s->numverts * sizeof(float) * 15);
|
|
}
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->indices[surfi]);
|
|
|
|
curlight = 0;
|
|
do {
|
|
materialbits = polymer_bindmaterial(&mdspritematerial, modellights, modellightcount);
|
|
glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_INT, 0);
|
|
polymer_unbindmaterial(materialbits);
|
|
} while ((++curlight < modellightcount) && (curlight < pr_maxlightpasses));
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
else
|
|
{
|
|
glVertexPointer(3, GL_FLOAT, sizeof(float) * 15, v0);
|
|
glNormalPointer(GL_FLOAT, sizeof(float) * 15, v0 + 3);
|
|
glTexCoordPointer(2, GL_FLOAT, 0, s->uv);
|
|
|
|
mdspritematerial.tbn = v0 + 6;
|
|
|
|
if (pr_gpusmoothing) {
|
|
mdspritematerial.nextframedata = (GLfloat*)(v1);
|
|
}
|
|
|
|
curlight = 0;
|
|
do {
|
|
materialbits = polymer_bindmaterial(&mdspritematerial, modellights, modellightcount);
|
|
glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_INT, s->tris);
|
|
polymer_unbindmaterial(materialbits);
|
|
} while ((++curlight < modellightcount) && (curlight < pr_maxlightpasses));
|
|
}
|
|
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
}
|
|
|
|
glPopMatrix();
|
|
|
|
if (!(tspr->cstat & 4) != !(tspr->cstat & 8)) {
|
|
SWITCH_CULL_DIRECTION;
|
|
}
|
|
|
|
globalnoeffect = 0;
|
|
}
|
|
|
|
static void polymer_loadmodelvbos(md3model_t* m)
|
|
{
|
|
int32_t i;
|
|
md3surf_t *s;
|
|
|
|
m->indices = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
|
|
m->texcoords = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
|
|
m->geometry = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
|
|
|
|
glGenBuffers(m->head.numsurfs, m->indices);
|
|
glGenBuffers(m->head.numsurfs, m->texcoords);
|
|
glGenBuffers(m->head.numsurfs, m->geometry);
|
|
|
|
i = 0;
|
|
while (i < m->head.numsurfs)
|
|
{
|
|
s = &m->head.surfs[i];
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->indices[i]);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, s->numtris * sizeof(md3tri_t), s->tris, modelvbousage);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m->texcoords[i]);
|
|
glBufferData(GL_ARRAY_BUFFER, s->numverts * sizeof(md3uv_t), s->uv, modelvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m->geometry[i]);
|
|
glBufferData(GL_ARRAY_BUFFER, s->numframes * s->numverts * sizeof(float) * (15), s->geometry, modelvbousage);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// MATERIALS
|
|
static void polymer_getscratchmaterial(_prmaterial* material)
|
|
{
|
|
// this function returns a material that won't validate any bits
|
|
// make sure to keep it up to date with the validation logic in bindmaterial
|
|
|
|
// PR_BIT_ANIM_INTERPOLATION
|
|
material->frameprogress = 0.0f;
|
|
material->nextframedata = (float*)-1;
|
|
// PR_BIT_NORMAL_MAP
|
|
material->normalmap = 0;
|
|
material->normalbias[0] = material->normalbias[1] = 0.0f;
|
|
material->tbn = NULL;
|
|
// PR_BIT_ART_MAP
|
|
material->artmap = 0;
|
|
material->basepalmap = 0;
|
|
material->lookupmap = 0;
|
|
// PR_BIT_DIFFUSE_MAP
|
|
material->diffusemap = 0;
|
|
material->diffusescale[0] = material->diffusescale[1] = 1.0f;
|
|
// PR_BIT_HIGHPALOOKUP_MAP
|
|
material->highpalookupmap = 0;
|
|
// PR_BIT_DIFFUSE_DETAIL_MAP
|
|
material->detailmap = 0;
|
|
material->detailscale[0] = material->detailscale[1] = 1.0f;
|
|
// PR_BIT_DIFFUSE_MODULATION
|
|
material->diffusemodulation[0] =
|
|
material->diffusemodulation[1] =
|
|
material->diffusemodulation[2] =
|
|
material->diffusemodulation[3] = 0xFF;
|
|
// PR_BIT_SPECULAR_MAP
|
|
material->specmap = 0;
|
|
// PR_BIT_SPECULAR_MATERIAL
|
|
material->specmaterial[0] = 15.0f;
|
|
material->specmaterial[1] = 1.0f;
|
|
// PR_BIT_MIRROR_MAP
|
|
material->mirrormap = 0;
|
|
// PR_BIT_GLOW_MAP
|
|
material->glowmap = 0;
|
|
// PR_BIT_PROJECTION_MAP
|
|
material->mdspritespace = GL_FALSE;
|
|
}
|
|
|
|
static void polymer_setupartmap(int16_t tilenum, char pal)
|
|
{
|
|
if (!prartmaps[tilenum]) {
|
|
char *tilebuffer = (char *) waloff[tilenum];
|
|
char *tempbuffer = (char *) Xmalloc(tilesiz[tilenum].x * tilesiz[tilenum].y);
|
|
int i, j, k;
|
|
|
|
i = k = 0;
|
|
while (i < tilesiz[tilenum].y) {
|
|
j = 0;
|
|
while (j < tilesiz[tilenum].x) {
|
|
tempbuffer[k] = tilebuffer[(j * tilesiz[tilenum].y) + i];
|
|
k++;
|
|
j++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
glGenTextures(1, &prartmaps[tilenum]);
|
|
glBindTexture(GL_TEXTURE_2D, prartmaps[tilenum]);
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
0,
|
|
GL_RED,
|
|
tilesiz[tilenum].x,
|
|
tilesiz[tilenum].y,
|
|
0,
|
|
GL_RED,
|
|
GL_UNSIGNED_BYTE,
|
|
tempbuffer);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
Bfree(tempbuffer);
|
|
}
|
|
|
|
if (!prbasepalmaps[curbasepal]) {
|
|
glGenTextures(1, &prbasepalmaps[curbasepal]);
|
|
glBindTexture(GL_TEXTURE_2D, prbasepalmaps[curbasepal]);
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
0,
|
|
GL_RGB,
|
|
256,
|
|
1,
|
|
0,
|
|
GL_RGB,
|
|
GL_UNSIGNED_BYTE,
|
|
basepaltable[curbasepal]);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
if (!prlookups[pal]) {
|
|
glGenTextures(1, &prlookups[pal]);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, prlookups[pal]);
|
|
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
|
|
0,
|
|
GL_RED,
|
|
256,
|
|
numshades,
|
|
0,
|
|
GL_RED,
|
|
GL_UNSIGNED_BYTE,
|
|
palookup[pal]);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, glinfo.clamptoedge ? GL_CLAMP_TO_EDGE : GL_CLAMP);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
}
|
|
}
|
|
|
|
static _prbucket* polymer_getbuildmaterial(_prmaterial* material, int16_t tilenum, char pal, int8_t shade, int8_t vis, int32_t cmeth)
|
|
{
|
|
// find corresponding bucket; XXX key that with pr_buckets later, need to be tied to restartvid
|
|
_prbucket *bucketptr = polymer_findbucket(tilenum, pal);
|
|
|
|
polymer_getscratchmaterial(material);
|
|
|
|
if (!waloff[tilenum])
|
|
loadtile(tilenum);
|
|
|
|
// PR_BIT_DIFFUSE_MAP
|
|
pthtyp *pth = texcache_fetch(tilenum, pal, 0, cmeth);
|
|
|
|
if (pth)
|
|
{
|
|
material->diffusemap = pth->glpic;
|
|
|
|
if (pth->hicr)
|
|
{
|
|
material->diffusescale[0] = pth->hicr->scale.x;
|
|
material->diffusescale[1] = pth->hicr->scale.y;
|
|
}
|
|
}
|
|
|
|
int32_t usinghighpal = 0;
|
|
|
|
// Lazily fill in all the textures we need, move this to precaching later
|
|
if (pr_artmapping && !(globalflags & GLOBAL_NO_GL_TILESHADES) && polymer_eligible_for_artmap(tilenum, pth))
|
|
{
|
|
polytintflags_t const tintflags = hictinting[pal].f;
|
|
|
|
if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
|
|
{
|
|
if (!(tintflags & HICTINT_APPLYOVERPALSWAP))
|
|
pal = 0;
|
|
}
|
|
|
|
if (!prartmaps[tilenum] || !prbasepalmaps[curbasepal] || !prlookups[pal])
|
|
polymer_setupartmap(tilenum, pal);
|
|
|
|
material->artmap = prartmaps[tilenum];
|
|
material->basepalmap = prbasepalmaps[curbasepal];
|
|
material->lookupmap = prlookups[pal];
|
|
|
|
if (!material->basepalmap || !material->lookupmap) {
|
|
material->artmap = 0;
|
|
}
|
|
|
|
material->shadeoffset = shade;
|
|
material->visibility = (uint8_t)(vis+16);
|
|
|
|
globaltinting_apply_ub(material->diffusemodulation);
|
|
// all the stuff below is mutually exclusive with artmapping
|
|
goto done;
|
|
}
|
|
|
|
// PR_BIT_HIGHPALOOKUP_MAP
|
|
if (pr_highpalookups && prhighpalookups[curbasepal][pal].map &&
|
|
hicfindsubst(tilenum, 0) &&
|
|
(curbasepal || (hicfindsubst(tilenum, pal)->palnum != pal)))
|
|
{
|
|
material->highpalookupmap = prhighpalookups[curbasepal][pal].map;
|
|
pal = 0;
|
|
usinghighpal = 1;
|
|
}
|
|
|
|
if (pth)
|
|
{
|
|
if (pth->hicr)
|
|
{
|
|
// PR_BIT_SPECULAR_MATERIAL
|
|
if (pth->hicr->specpower != 1.0f)
|
|
material->specmaterial[0] = pth->hicr->specpower;
|
|
material->specmaterial[1] = pth->hicr->specfactor;
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_MODULATION
|
|
material->diffusemodulation[0] =
|
|
material->diffusemodulation[1] =
|
|
material->diffusemodulation[2] =
|
|
(GLubyte)(getshadefactor(shade) * 0xFF);
|
|
|
|
// tinting
|
|
polytintflags_t const tintflags = hictinting[pal].f;
|
|
if (!(tintflags & HICTINT_PRECOMPUTED))
|
|
{
|
|
if (pth->flags & PTH_HIGHTILE)
|
|
{
|
|
if (pth->palnum != pal || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
|
|
hictinting_apply_ub(material->diffusemodulation, pal);
|
|
}
|
|
else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
|
|
hictinting_apply_ub(material->diffusemodulation, pal);
|
|
}
|
|
|
|
// global tinting
|
|
if ((pth->flags & PTH_HIGHTILE) && !usinghighpal && have_basepal_tint())
|
|
hictinting_apply_ub(material->diffusemodulation, MAXPALOOKUPS-1);
|
|
|
|
globaltinting_apply_ub(material->diffusemodulation);
|
|
|
|
// PR_BIT_GLOW_MAP
|
|
if (r_fullbrights && pth->flags & PTH_HASFULLBRIGHT)
|
|
material->glowmap = pth->ofb->glpic;
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_DETAIL_MAP
|
|
if (hicfindsubst(tilenum, DETAILPAL, 1) && (pth = texcache_fetch(tilenum, DETAILPAL, 0, DAMETH_NOMASK)) &&
|
|
pth->hicr && (pth->hicr->palnum == DETAILPAL))
|
|
{
|
|
material->detailmap = pth->glpic;
|
|
material->detailscale[0] = pth->hicr->scale.x;
|
|
material->detailscale[1] = pth->hicr->scale.y;
|
|
}
|
|
|
|
// PR_BIT_GLOW_MAP
|
|
if (hicfindsubst(tilenum, GLOWPAL, 1) && (pth = texcache_fetch(tilenum, GLOWPAL, 0, DAMETH_MASK)) &&
|
|
pth->hicr && (pth->hicr->palnum == GLOWPAL))
|
|
material->glowmap = pth->glpic;
|
|
|
|
// PR_BIT_SPECULAR_MAP
|
|
if (hicfindsubst(tilenum, SPECULARPAL, 1) && (pth = texcache_fetch(tilenum, SPECULARPAL, 0, DAMETH_NOMASK)) &&
|
|
pth->hicr && (pth->hicr->palnum == SPECULARPAL))
|
|
material->specmap = pth->glpic;
|
|
|
|
// PR_BIT_NORMAL_MAP
|
|
if (hicfindsubst(tilenum, NORMALPAL, 1) && (pth = texcache_fetch(tilenum, NORMALPAL, 0, DAMETH_NOMASK)) &&
|
|
pth->hicr && (pth->hicr->palnum == NORMALPAL))
|
|
{
|
|
material->normalmap = pth->glpic;
|
|
material->normalbias[0] = pth->hicr->specpower;
|
|
material->normalbias[1] = pth->hicr->specfactor;
|
|
}
|
|
|
|
done:
|
|
if (bucketptr->invalidmaterial != 0)
|
|
{
|
|
bucketptr->material = *material;
|
|
bucketptr->invalidmaterial = 0;
|
|
}
|
|
|
|
return bucketptr;
|
|
}
|
|
|
|
static int32_t polymer_bindmaterial(const _prmaterial *material, int16_t* lights, int matlightcount)
|
|
{
|
|
int32_t programbits;
|
|
int32_t texunit;
|
|
|
|
programbits = 0;
|
|
|
|
// --------- bit validation
|
|
|
|
// PR_BIT_ANIM_INTERPOLATION
|
|
if (material->nextframedata != ((float*)-1))
|
|
programbits |= prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit;
|
|
|
|
// PR_BIT_LIGHTING_PASS
|
|
if (curlight && matlightcount)
|
|
programbits |= prprogrambits[PR_BIT_LIGHTING_PASS].bit;
|
|
|
|
// PR_BIT_NORMAL_MAP
|
|
if (pr_normalmapping && material->normalmap)
|
|
programbits |= prprogrambits[PR_BIT_NORMAL_MAP].bit;
|
|
|
|
// PR_BIT_ART_MAP
|
|
if (pr_artmapping && material->artmap &&
|
|
!(globalflags & GLOBAL_NO_GL_TILESHADES) &&
|
|
(overridematerial & prprogrambits[PR_BIT_ART_MAP].bit)) {
|
|
programbits |= prprogrambits[PR_BIT_ART_MAP].bit;
|
|
} else
|
|
// PR_BIT_DIFFUSE_MAP
|
|
if (material->diffusemap) {
|
|
programbits |= prprogrambits[PR_BIT_DIFFUSE_MAP].bit;
|
|
programbits |= prprogrambits[PR_BIT_DIFFUSE_MAP2].bit;
|
|
}
|
|
|
|
// PR_BIT_HIGHPALOOKUP_MAP
|
|
if (material->highpalookupmap)
|
|
programbits |= prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit;
|
|
|
|
// PR_BIT_DIFFUSE_DETAIL_MAP
|
|
if (r_detailmapping && material->detailmap)
|
|
programbits |= prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit;
|
|
|
|
// PR_BIT_DIFFUSE_MODULATION
|
|
programbits |= prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit;
|
|
|
|
// PR_BIT_SPECULAR_MAP
|
|
if (pr_specularmapping && material->specmap)
|
|
programbits |= prprogrambits[PR_BIT_SPECULAR_MAP].bit;
|
|
|
|
// PR_BIT_SPECULAR_MATERIAL
|
|
if ((material->specmaterial[0] != 15.0) || (material->specmaterial[1] != 1.0) || pr_overridespecular)
|
|
programbits |= prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit;
|
|
|
|
// PR_BIT_MIRROR_MAP
|
|
if (!curlight && material->mirrormap)
|
|
programbits |= prprogrambits[PR_BIT_MIRROR_MAP].bit;
|
|
|
|
// PR_BIT_FOG
|
|
if (!material->artmap && !curlight && !material->mirrormap)
|
|
programbits |= prprogrambits[PR_BIT_FOG].bit;
|
|
|
|
// PR_BIT_GLOW_MAP
|
|
if (!curlight && r_glowmapping && material->glowmap)
|
|
programbits |= prprogrambits[PR_BIT_GLOW_MAP].bit;
|
|
|
|
// PR_BIT_POINT_LIGHT
|
|
if (matlightcount) {
|
|
programbits |= prprogrambits[PR_BIT_POINT_LIGHT].bit;
|
|
// PR_BIT_SPOT_LIGHT
|
|
if (prlights[lights[curlight]].radius) {
|
|
programbits |= prprogrambits[PR_BIT_SPOT_LIGHT].bit;
|
|
// PR_BIT_SHADOW_MAP
|
|
if (prlights[lights[curlight]].rtindex != -1) {
|
|
programbits |= prprogrambits[PR_BIT_SHADOW_MAP].bit;
|
|
programbits |= prprogrambits[PR_BIT_PROJECTION_MAP].bit;
|
|
}
|
|
// PR_BIT_LIGHT_MAP
|
|
if (prlights[lights[curlight]].lightmap) {
|
|
programbits |= prprogrambits[PR_BIT_LIGHT_MAP].bit;
|
|
programbits |= prprogrambits[PR_BIT_PROJECTION_MAP].bit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// material override
|
|
programbits &= overridematerial;
|
|
|
|
programbits |= prprogrambits[PR_BIT_HEADER].bit;
|
|
programbits |= prprogrambits[PR_BIT_FOOTER].bit;
|
|
|
|
// --------- program compiling
|
|
if (!prprograms[programbits].handle)
|
|
polymer_compileprogram(programbits);
|
|
|
|
glUseProgram(prprograms[programbits].handle);
|
|
|
|
// --------- bit setup
|
|
|
|
texunit = 0;
|
|
|
|
// PR_BIT_ANIM_INTERPOLATION
|
|
if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
|
|
{
|
|
glEnableVertexAttribArray(prprograms[programbits].attrib_nextFrameData);
|
|
if (prprograms[programbits].attrib_nextFrameNormal != -1)
|
|
glEnableVertexAttribArray(prprograms[programbits].attrib_nextFrameNormal);
|
|
glVertexAttribPointer(prprograms[programbits].attrib_nextFrameData,
|
|
3, GL_FLOAT, GL_FALSE,
|
|
sizeof(float) * 15,
|
|
material->nextframedata);
|
|
if (prprograms[programbits].attrib_nextFrameNormal != -1)
|
|
glVertexAttribPointer(prprograms[programbits].attrib_nextFrameNormal,
|
|
3, GL_FLOAT, GL_FALSE,
|
|
sizeof(float) * 15,
|
|
material->nextframedata + 3);
|
|
|
|
glUniform1f(prprograms[programbits].uniform_frameProgress, material->frameprogress);
|
|
}
|
|
|
|
// PR_BIT_LIGHTING_PASS
|
|
if (programbits & prprogrambits[PR_BIT_LIGHTING_PASS].bit)
|
|
{
|
|
glPushAttrib(GL_COLOR_BUFFER_BIT);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
|
|
if (prlights[lights[curlight]].publicflags.negative) {
|
|
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
|
}
|
|
}
|
|
|
|
// PR_BIT_NORMAL_MAP
|
|
if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
|
|
{
|
|
float pos[3], bias[2];
|
|
|
|
pos[0] = fglobalposy;
|
|
pos[1] = fglobalposz * (-1.f/16.f);
|
|
pos[2] = -fglobalposx;
|
|
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->normalmap);
|
|
|
|
if (material->mdspritespace == GL_TRUE) {
|
|
float mdspritespacepos[3];
|
|
polymer_transformpoint(pos, mdspritespacepos, (float *)mdspritespace);
|
|
glUniform3fv(prprograms[programbits].uniform_eyePosition, 1, mdspritespacepos);
|
|
} else
|
|
glUniform3fv(prprograms[programbits].uniform_eyePosition, 1, pos);
|
|
glUniform1i(prprograms[programbits].uniform_normalMap, texunit);
|
|
if (pr_overrideparallax) {
|
|
bias[0] = pr_parallaxscale;
|
|
bias[1] = pr_parallaxbias;
|
|
glUniform2fv(prprograms[programbits].uniform_normalBias, 1, bias);
|
|
} else
|
|
glUniform2fv(prprograms[programbits].uniform_normalBias, 1, material->normalbias);
|
|
|
|
if (material->tbn) {
|
|
glEnableVertexAttribArray(prprograms[programbits].attrib_T);
|
|
glEnableVertexAttribArray(prprograms[programbits].attrib_B);
|
|
glEnableVertexAttribArray(prprograms[programbits].attrib_N);
|
|
|
|
glVertexAttribPointer(prprograms[programbits].attrib_T,
|
|
3, GL_FLOAT, GL_FALSE,
|
|
sizeof(float) * 15,
|
|
material->tbn);
|
|
glVertexAttribPointer(prprograms[programbits].attrib_B,
|
|
3, GL_FLOAT, GL_FALSE,
|
|
sizeof(float) * 15,
|
|
material->tbn + 3);
|
|
glVertexAttribPointer(prprograms[programbits].attrib_N,
|
|
3, GL_FLOAT, GL_FALSE,
|
|
sizeof(float) * 15,
|
|
material->tbn + 6);
|
|
}
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_ART_MAP
|
|
if (programbits & prprogrambits[PR_BIT_ART_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->artmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_artMap, texunit);
|
|
|
|
texunit++;
|
|
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->basepalmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_basePalMap, texunit);
|
|
|
|
texunit++;
|
|
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, material->lookupmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_lookupMap, texunit);
|
|
|
|
texunit++;
|
|
|
|
glUniform1f(prprograms[programbits].uniform_shadeOffset, (GLfloat)material->shadeoffset);
|
|
if (r_usenewshading == 4)
|
|
{
|
|
// the fog in Polymer is a sphere insted of a plane, the furthest visible point should be the same as Polymost
|
|
glUniform1f(prprograms[programbits].uniform_visibility, globalvisibility / 262144.f * material->visibility);
|
|
}
|
|
else
|
|
{
|
|
static constexpr float material_visibility_divisor = 16.f;
|
|
|
|
// NOTE: the denominator was 1.024, but we increase it towards a bit
|
|
// farther far clipoff distance to account for the fact that the
|
|
// distance to the fragment is the common Euclidean one, as opposed to
|
|
// the "ortho" distance of Build.
|
|
static constexpr float factor_new = 1.f / ((2048.f * (1.07f / 1.024f) * (150.f / 230.f) / 35.f) * material_visibility_divisor);
|
|
|
|
static constexpr float factor_old = 1.f / ((2048.f * (1.07f / 1.024f) / 35.f) * material_visibility_divisor);
|
|
|
|
glUniform1f(prprograms[programbits].uniform_visibility, globalvisibility * material->visibility * r_usenewshading > 1 ? factor_new : factor_old);
|
|
}
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_MAP
|
|
if (programbits & prprogrambits[PR_BIT_DIFFUSE_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->diffusemap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_diffuseMap, texunit);
|
|
glUniform2fv(prprograms[programbits].uniform_diffuseScale, 1, material->diffusescale);
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_HIGHPALOOKUP_MAP
|
|
if (programbits & prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_3D, material->highpalookupmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_highPalookupMap, texunit);
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_DETAIL_MAP
|
|
if (programbits & prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit)
|
|
{
|
|
float scale[2];
|
|
|
|
// scale by the diffuse map scale if we're not doing normal mapping
|
|
if (!(programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit))
|
|
{
|
|
scale[0] = material->diffusescale[0] * material->detailscale[0];
|
|
scale[1] = material->diffusescale[1] * material->detailscale[1];
|
|
} else {
|
|
scale[0] = material->detailscale[0];
|
|
scale[1] = material->detailscale[1];
|
|
}
|
|
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->detailmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_detailMap, texunit);
|
|
glUniform2fv(prprograms[programbits].uniform_detailScale, 1, scale);
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_MODULATION
|
|
if (programbits & prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit)
|
|
{
|
|
glColor4ub(material->diffusemodulation[0],
|
|
material->diffusemodulation[1],
|
|
material->diffusemodulation[2],
|
|
material->diffusemodulation[3]);
|
|
}
|
|
|
|
// PR_BIT_SPECULAR_MAP
|
|
if (programbits & prprogrambits[PR_BIT_SPECULAR_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->specmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_specMap, texunit);
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_SPECULAR_MATERIAL
|
|
if (programbits & prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit)
|
|
{
|
|
float specmaterial[2];
|
|
|
|
if (pr_overridespecular) {
|
|
specmaterial[0] = pr_specularpower;
|
|
specmaterial[1] = pr_specularfactor;
|
|
glUniform2fv(prprograms[programbits].uniform_specMaterial, 1, specmaterial);
|
|
} else
|
|
glUniform2fv(prprograms[programbits].uniform_specMaterial, 1, material->specmaterial);
|
|
}
|
|
|
|
// PR_BIT_MIRROR_MAP
|
|
if (programbits & prprogrambits[PR_BIT_MIRROR_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, material->mirrormap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_mirrorMap, texunit);
|
|
|
|
texunit++;
|
|
}
|
|
#ifdef PR_LINEAR_FOG
|
|
if (programbits & prprogrambits[PR_BIT_FOG].bit)
|
|
{
|
|
glUniform1i(prprograms[programbits].uniform_linearFog, r_usenewshading >= 2);
|
|
}
|
|
#endif
|
|
// PR_BIT_GLOW_MAP
|
|
if (programbits & prprogrambits[PR_BIT_GLOW_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, material->glowmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_glowMap, texunit);
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_POINT_LIGHT
|
|
if (programbits & prprogrambits[PR_BIT_POINT_LIGHT].bit)
|
|
{
|
|
float inpos[4], pos[4];
|
|
float range[2];
|
|
float color[4];
|
|
|
|
inpos[0] = (float)prlights[lights[curlight]].y;
|
|
inpos[1] = -(float)prlights[lights[curlight]].z / 16.0f;
|
|
inpos[2] = -(float)prlights[lights[curlight]].x;
|
|
|
|
polymer_transformpoint(inpos, pos, curmodelviewmatrix);
|
|
|
|
// PR_BIT_SPOT_LIGHT
|
|
if (programbits & prprogrambits[PR_BIT_SPOT_LIGHT].bit)
|
|
{
|
|
float sinang, cosang, sinhorizang, coshorizangs;
|
|
float indir[3], dir[3];
|
|
|
|
cosang = (float)(sintable[(-prlights[lights[curlight]].angle+1024)&2047]) / 16383.0f;
|
|
sinang = (float)(sintable[(-prlights[lights[curlight]].angle+512)&2047]) / 16383.0f;
|
|
coshorizangs = (float)(sintable[(getangle(128, prlights[lights[curlight]].horiz-100)+1024)&2047]) / 16383.0f;
|
|
sinhorizang = (float)(sintable[(getangle(128, prlights[lights[curlight]].horiz-100)+512)&2047]) / 16383.0f;
|
|
|
|
indir[0] = inpos[0] + sinhorizang * cosang;
|
|
indir[1] = inpos[1] - coshorizangs;
|
|
indir[2] = inpos[2] - sinhorizang * sinang;
|
|
|
|
polymer_transformpoint(indir, dir, curmodelviewmatrix);
|
|
|
|
dir[0] -= pos[0];
|
|
dir[1] -= pos[1];
|
|
dir[2] -= pos[2];
|
|
|
|
indir[0] = (float)(sintable[(prlights[lights[curlight]].radius+512)&2047]) / 16383.0f;
|
|
indir[1] = (float)(sintable[(prlights[lights[curlight]].faderadius+512)&2047]) / 16383.0f;
|
|
indir[1] = 1.0 / (indir[1] - indir[0]);
|
|
|
|
glUniform3fv(prprograms[programbits].uniform_spotDir, 1, dir);
|
|
glUniform2fv(prprograms[programbits].uniform_spotRadius, 1, indir);
|
|
|
|
// PR_BIT_PROJECTION_MAP
|
|
if (programbits & prprogrambits[PR_BIT_PROJECTION_MAP].bit)
|
|
{
|
|
GLfloat matrix[16];
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadMatrixf(shadowBias);
|
|
glMultMatrixf(prlights[lights[curlight]].proj);
|
|
glMultMatrixf(prlights[lights[curlight]].transform);
|
|
if (material->mdspritespace == GL_TRUE)
|
|
glMultMatrixf(spritemodelview);
|
|
glGetFloatv(GL_TEXTURE_MATRIX, matrix);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glUniformMatrix4fv(prprograms[programbits].uniform_shadowProjMatrix, 1, GL_FALSE, matrix);
|
|
|
|
// PR_BIT_SHADOW_MAP
|
|
if (programbits & prprogrambits[PR_BIT_SHADOW_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(prrts[prlights[lights[curlight]].rtindex].target, prrts[prlights[lights[curlight]].rtindex].z);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_shadowMap, texunit);
|
|
|
|
texunit++;
|
|
}
|
|
|
|
// PR_BIT_LIGHT_MAP
|
|
if (programbits & prprogrambits[PR_BIT_LIGHT_MAP].bit)
|
|
{
|
|
glActiveTexture(texunit + GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, prlights[lights[curlight]].lightmap);
|
|
|
|
glUniform1i(prprograms[programbits].uniform_lightMap, texunit);
|
|
|
|
texunit++;
|
|
}
|
|
}
|
|
}
|
|
|
|
range[0] = prlights[lights[curlight]].range / 1000.0f;
|
|
range[1] = 1 / (range[0] * range[0]);
|
|
|
|
color[0] = prlights[lights[curlight]].color[0] / 255.0f;
|
|
color[1] = prlights[lights[curlight]].color[1] / 255.0f;
|
|
color[2] = prlights[lights[curlight]].color[2] / 255.0f;
|
|
|
|
// If this isn't a lighting-only pass, just negate the components
|
|
if (!curlight && prlights[lights[curlight]].publicflags.negative) {
|
|
color[0] = -color[0];
|
|
color[1] = -color[1];
|
|
color[2] = -color[2];
|
|
}
|
|
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, pos);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, color);
|
|
if (material->mdspritespace == GL_TRUE) {
|
|
float mdspritespacepos[3];
|
|
polymer_transformpoint(inpos, mdspritespacepos, (float *)mdspritespace);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, mdspritespacepos);
|
|
} else {
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, inpos);
|
|
}
|
|
glLightfv(GL_LIGHT0, GL_LINEAR_ATTENUATION, &range[1]);
|
|
}
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
return programbits;
|
|
}
|
|
|
|
static void polymer_unbindmaterial(int32_t programbits)
|
|
{
|
|
// repair any dirty GL state here
|
|
|
|
// PR_BIT_ANIM_INTERPOLATION
|
|
if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
|
|
{
|
|
if (prprograms[programbits].attrib_nextFrameNormal != -1)
|
|
glDisableVertexAttribArray(prprograms[programbits].attrib_nextFrameNormal);
|
|
glDisableVertexAttribArray(prprograms[programbits].attrib_nextFrameData);
|
|
}
|
|
|
|
// PR_BIT_LIGHTING_PASS
|
|
if (programbits & prprogrambits[PR_BIT_LIGHTING_PASS].bit)
|
|
{
|
|
glPopAttrib();
|
|
}
|
|
|
|
// PR_BIT_NORMAL_MAP
|
|
if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
|
|
{
|
|
glDisableVertexAttribArray(prprograms[programbits].attrib_T);
|
|
glDisableVertexAttribArray(prprograms[programbits].attrib_B);
|
|
glDisableVertexAttribArray(prprograms[programbits].attrib_N);
|
|
}
|
|
|
|
glUseProgram(0);
|
|
}
|
|
|
|
static void polymer_compileprogram(int32_t programbits)
|
|
{
|
|
int32_t i, enabledbits;
|
|
GLuint vert, frag, program;
|
|
const GLchar* source[PR_BIT_COUNT * 2];
|
|
GLchar infobuffer[PR_INFO_LOG_BUFFER_SIZE];
|
|
GLint linkstatus;
|
|
|
|
// --------- VERTEX
|
|
vert = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
enabledbits = i = 0;
|
|
while (i < PR_BIT_COUNT)
|
|
{
|
|
if (programbits & prprogrambits[i].bit)
|
|
source[enabledbits++] = prprogrambits[i].vert_def;
|
|
i++;
|
|
}
|
|
i = 0;
|
|
while (i < PR_BIT_COUNT)
|
|
{
|
|
if (programbits & prprogrambits[i].bit)
|
|
source[enabledbits++] = prprogrambits[i].vert_prog;
|
|
i++;
|
|
}
|
|
|
|
glShaderSource(vert, enabledbits, source, NULL);
|
|
|
|
glCompileShader(vert);
|
|
|
|
// --------- FRAGMENT
|
|
frag = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
enabledbits = i = 0;
|
|
while (i < PR_BIT_COUNT)
|
|
{
|
|
if (programbits & prprogrambits[i].bit)
|
|
source[enabledbits++] = prprogrambits[i].frag_def;
|
|
i++;
|
|
}
|
|
i = 0;
|
|
while (i < PR_BIT_COUNT)
|
|
{
|
|
if (programbits & prprogrambits[i].bit)
|
|
source[enabledbits++] = prprogrambits[i].frag_prog;
|
|
i++;
|
|
}
|
|
|
|
glShaderSource(frag, enabledbits, (const GLchar**)source, NULL);
|
|
|
|
glCompileShader(frag);
|
|
|
|
// --------- PROGRAM
|
|
program = glCreateProgram();
|
|
|
|
glAttachShader(program, vert);
|
|
glAttachShader(program, frag);
|
|
|
|
glLinkProgram(program);
|
|
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linkstatus);
|
|
|
|
glGetProgramInfoLog(program, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
|
|
|
|
prprograms[programbits].handle = program;
|
|
|
|
#ifdef DEBUGGINGAIDS
|
|
if (pr_verbosity >= 1)
|
|
#else
|
|
if (pr_verbosity >= 2)
|
|
#endif
|
|
OSD_Printf("PR : Compiling GPU program with bits (octal) %o...\n", (unsigned)programbits);
|
|
if (!linkstatus) {
|
|
OSD_Printf("PR : Failed to compile GPU program with bits (octal) %o!\n", (unsigned)programbits);
|
|
if (pr_verbosity >= 1) OSD_Printf("PR : Compilation log:\n%s\n", infobuffer);
|
|
glGetShaderSource(vert, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
|
|
if (pr_verbosity >= 1) OSD_Printf("PR : Vertex source dump:\n%s\n", infobuffer);
|
|
glGetShaderSource(frag, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
|
|
if (pr_verbosity >= 1) OSD_Printf("PR : Fragment source dump:\n%s\n", infobuffer);
|
|
}
|
|
|
|
// --------- ATTRIBUTE/UNIFORM LOCATIONS
|
|
|
|
// PR_BIT_ANIM_INTERPOLATION
|
|
if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
|
|
{
|
|
prprograms[programbits].attrib_nextFrameData = glGetAttribLocation(program, "nextFrameData");
|
|
prprograms[programbits].attrib_nextFrameNormal = glGetAttribLocation(program, "nextFrameNormal");
|
|
prprograms[programbits].uniform_frameProgress = glGetUniformLocation(program, "frameProgress");
|
|
}
|
|
|
|
// PR_BIT_NORMAL_MAP
|
|
if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
|
|
{
|
|
prprograms[programbits].attrib_T = glGetAttribLocation(program, "T");
|
|
prprograms[programbits].attrib_B = glGetAttribLocation(program, "B");
|
|
prprograms[programbits].attrib_N = glGetAttribLocation(program, "N");
|
|
prprograms[programbits].uniform_eyePosition = glGetUniformLocation(program, "eyePosition");
|
|
prprograms[programbits].uniform_normalMap = glGetUniformLocation(program, "normalMap");
|
|
prprograms[programbits].uniform_normalBias = glGetUniformLocation(program, "normalBias");
|
|
}
|
|
|
|
// PR_BIT_ART_MAP
|
|
if (programbits & prprogrambits[PR_BIT_ART_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_artMap = glGetUniformLocation(program, "artMap");
|
|
prprograms[programbits].uniform_basePalMap = glGetUniformLocation(program, "basePalMap");
|
|
prprograms[programbits].uniform_lookupMap = glGetUniformLocation(program, "lookupMap");
|
|
prprograms[programbits].uniform_shadeOffset = glGetUniformLocation(program, "shadeOffset");
|
|
prprograms[programbits].uniform_visibility = glGetUniformLocation(program, "visibility");
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_MAP
|
|
if (programbits & prprogrambits[PR_BIT_DIFFUSE_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_diffuseMap = glGetUniformLocation(program, "diffuseMap");
|
|
prprograms[programbits].uniform_diffuseScale = glGetUniformLocation(program, "diffuseScale");
|
|
}
|
|
|
|
// PR_BIT_HIGHPALOOKUP_MAP
|
|
if (programbits & prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_highPalookupMap = glGetUniformLocation(program, "highPalookupMap");
|
|
}
|
|
|
|
// PR_BIT_DIFFUSE_DETAIL_MAP
|
|
if (programbits & prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_detailMap = glGetUniformLocation(program, "detailMap");
|
|
prprograms[programbits].uniform_detailScale = glGetUniformLocation(program, "detailScale");
|
|
}
|
|
|
|
// PR_BIT_SPECULAR_MAP
|
|
if (programbits & prprogrambits[PR_BIT_SPECULAR_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_specMap = glGetUniformLocation(program, "specMap");
|
|
}
|
|
|
|
// PR_BIT_SPECULAR_MATERIAL
|
|
if (programbits & prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit)
|
|
{
|
|
prprograms[programbits].uniform_specMaterial = glGetUniformLocation(program, "specMaterial");
|
|
}
|
|
|
|
// PR_BIT_MIRROR_MAP
|
|
if (programbits & prprogrambits[PR_BIT_MIRROR_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_mirrorMap = glGetUniformLocation(program, "mirrorMap");
|
|
}
|
|
#ifdef PR_LINEAR_FOG
|
|
if (programbits & prprogrambits[PR_BIT_FOG].bit)
|
|
{
|
|
prprograms[programbits].uniform_linearFog = glGetUniformLocation(program, "linearFog");
|
|
}
|
|
#endif
|
|
// PR_BIT_GLOW_MAP
|
|
if (programbits & prprogrambits[PR_BIT_GLOW_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_glowMap = glGetUniformLocation(program, "glowMap");
|
|
}
|
|
|
|
// PR_BIT_PROJECTION_MAP
|
|
if (programbits & prprogrambits[PR_BIT_PROJECTION_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_shadowProjMatrix = glGetUniformLocation(program, "shadowProjMatrix");
|
|
}
|
|
|
|
// PR_BIT_SHADOW_MAP
|
|
if (programbits & prprogrambits[PR_BIT_SHADOW_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_shadowMap = glGetUniformLocation(program, "shadowMap");
|
|
}
|
|
|
|
// PR_BIT_LIGHT_MAP
|
|
if (programbits & prprogrambits[PR_BIT_LIGHT_MAP].bit)
|
|
{
|
|
prprograms[programbits].uniform_lightMap = glGetUniformLocation(program, "lightMap");
|
|
}
|
|
|
|
// PR_BIT_SPOT_LIGHT
|
|
if (programbits & prprogrambits[PR_BIT_SPOT_LIGHT].bit)
|
|
{
|
|
prprograms[programbits].uniform_spotDir = glGetUniformLocation(program, "spotDir");
|
|
prprograms[programbits].uniform_spotRadius = glGetUniformLocation(program, "spotRadius");
|
|
}
|
|
}
|
|
|
|
// LIGHTS
|
|
static void polymer_removelight(int16_t lighti)
|
|
{
|
|
_prplanelist* oldhead;
|
|
|
|
while (prlights[lighti].planelist)
|
|
{
|
|
polymer_deleteplanelight(prlights[lighti].planelist->plane, lighti);
|
|
oldhead = prlights[lighti].planelist;
|
|
prlights[lighti].planelist = prlights[lighti].planelist->n;
|
|
oldhead->n = plpool;
|
|
plpool = oldhead;
|
|
plpool->plane = NULL;
|
|
}
|
|
prlights[lighti].planecount = 0;
|
|
prlights[lighti].planelist = NULL;
|
|
}
|
|
|
|
static void polymer_updatelights(void)
|
|
{
|
|
int32_t i = 0;
|
|
|
|
do
|
|
{
|
|
_prlight* light = &prlights[i];
|
|
|
|
if (light->flags.active && light->flags.invalidate) {
|
|
// highly suboptimal
|
|
polymer_removelight(i);
|
|
|
|
if (light->radius)
|
|
polymer_processspotlight(light);
|
|
|
|
polymer_culllight(i);
|
|
|
|
light->flags.invalidate = 0;
|
|
}
|
|
|
|
if (light->flags.active) {
|
|
// get the texture handle for the lightmap
|
|
if (light->radius && light->tilenum > 0)
|
|
{
|
|
int16_t picnum = light->tilenum;
|
|
pthtyp* pth;
|
|
|
|
DO_TILE_ANIM(picnum, 0);
|
|
|
|
if (!waloff[picnum])
|
|
loadtile(picnum);
|
|
|
|
pth = NULL;
|
|
pth = texcache_fetch(picnum, 0, 0, DAMETH_NOMASK);
|
|
|
|
if (pth)
|
|
light->lightmap = pth->glpic;
|
|
}
|
|
|
|
light->rtindex = -1;
|
|
}
|
|
}
|
|
while (++i < PR_MAXLIGHTS);
|
|
}
|
|
|
|
static inline void polymer_resetplanelights(_prplane* plane)
|
|
{
|
|
Bmemset(&plane->lights[0], -1, sizeof(plane->lights[0]) * plane->lightcount);
|
|
plane->lightcount = 0;
|
|
}
|
|
|
|
static void polymer_addplanelight(_prplane* plane, int16_t lighti)
|
|
{
|
|
_prplanelist* oldhead;
|
|
int32_t i = 0;
|
|
|
|
if (plane->lightcount)
|
|
{
|
|
if (plane->lightcount == PR_MAXLIGHTS - 1)
|
|
return;
|
|
|
|
do
|
|
{
|
|
if (plane->lights[i++] == lighti)
|
|
goto out;
|
|
}
|
|
while (i < plane->lightcount);
|
|
|
|
i = 0;
|
|
while (i < plane->lightcount && prlights[plane->lights[i]].priority < prlights[lighti].priority)
|
|
i++;
|
|
Bmemmove(&plane->lights[i+1], &plane->lights[i], sizeof(int16_t) * (plane->lightcount - i));
|
|
}
|
|
|
|
plane->lights[i] = lighti;
|
|
plane->lightcount++;
|
|
|
|
out:
|
|
oldhead = prlights[lighti].planelist;
|
|
while (oldhead != NULL)
|
|
{
|
|
if (oldhead->plane == plane) return;
|
|
oldhead = oldhead->n;
|
|
}
|
|
|
|
oldhead = prlights[lighti].planelist;
|
|
if (plpool == NULL)
|
|
{
|
|
prlights[lighti].planelist = (_prplanelist *) Xmalloc(sizeof(_prplanelist));
|
|
prlights[lighti].planelist->n = oldhead;
|
|
}
|
|
else
|
|
{
|
|
prlights[lighti].planelist = plpool;
|
|
plpool = plpool->n;
|
|
prlights[lighti].planelist->n = oldhead;
|
|
}
|
|
|
|
prlights[lighti].planelist->plane = plane;
|
|
prlights[lighti].planecount++;
|
|
}
|
|
|
|
static inline void polymer_deleteplanelight(_prplane* plane, int16_t lighti)
|
|
{
|
|
int32_t i = plane->lightcount-1;
|
|
|
|
while (i >= 0)
|
|
{
|
|
if (plane->lights[i] == lighti)
|
|
{
|
|
Bmemmove(&plane->lights[i], &plane->lights[i+1], sizeof(int16_t) * (plane->lightcount - i));
|
|
plane->lightcount--;
|
|
return;
|
|
}
|
|
i--;
|
|
}
|
|
}
|
|
|
|
static int32_t polymer_planeinlight(_prplane* plane, _prlight* light)
|
|
{
|
|
float lightpos[3];
|
|
int32_t i, j, k, l;
|
|
|
|
if (!plane->vertcount)
|
|
return 0;
|
|
|
|
if (light->radius)
|
|
return polymer_planeinfrustum(plane, light->frustum);
|
|
|
|
lightpos[0] = (float)light->y;
|
|
lightpos[1] = -(float)light->z / 16.0f;
|
|
lightpos[2] = -(float)light->x;
|
|
|
|
i = 0;
|
|
|
|
do
|
|
{
|
|
j = k = l = 0;
|
|
|
|
do
|
|
{
|
|
if ((&plane->buffer[j].x)[i] > (lightpos[i] + light->range)) k++;
|
|
if ((&plane->buffer[j].x)[i] < (lightpos[i] - light->range)) l++;
|
|
}
|
|
while (++j < plane->vertcount);
|
|
|
|
if ((k == plane->vertcount) || (l == plane->vertcount))
|
|
return 0;
|
|
}
|
|
while (++i < 3);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void polymer_invalidateplanelights(_prplane* plane)
|
|
{
|
|
int32_t i = plane->lightcount;
|
|
|
|
while (i--)
|
|
{
|
|
if (((unsigned)plane->lights[i] < PR_MAXLIGHTS) && (prlights[plane->lights[i]].flags.active))
|
|
prlights[plane->lights[i]].flags.invalidate = 1;
|
|
}
|
|
}
|
|
|
|
static void polymer_invalidatesectorlights(int16_t sectnum)
|
|
{
|
|
int32_t i;
|
|
_prsector *s = prsectors[sectnum];
|
|
sectortype *sec = §or[sectnum];
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
polymer_invalidateplanelights(&s->floor);
|
|
polymer_invalidateplanelights(&s->ceil);
|
|
|
|
i = sec->wallnum;
|
|
|
|
while (i--)
|
|
{
|
|
_prwall *w;
|
|
if (!(w = prwalls[sec->wallptr + i])) continue;
|
|
|
|
polymer_invalidateplanelights(&w->wall);
|
|
polymer_invalidateplanelights(&w->over);
|
|
polymer_invalidateplanelights(&w->mask);
|
|
}
|
|
}
|
|
|
|
static void polymer_processspotlight(_prlight* light)
|
|
{
|
|
float radius, ang, horizang, lightpos[3];
|
|
|
|
// hack to avoid lights beams perpendicular to walls
|
|
if ((light->horiz <= 100) && (light->horiz > 90))
|
|
light->horiz = 90;
|
|
if ((light->horiz > 100) && (light->horiz < 110))
|
|
light->horiz = 110;
|
|
|
|
lightpos[0] = (float)light->y;
|
|
lightpos[1] = -(float)light->z / 16.0f;
|
|
lightpos[2] = -(float)light->x;
|
|
|
|
// calculate the spot light transformations and matrices
|
|
radius = (float)(light->radius) * (360.f/2048.f);
|
|
ang = (float)(light->angle) * (360.f/2048.f);
|
|
horizang = (float)(-getangle(128, light->horiz-100)) * (360.f/2048.f);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
bgluPerspective(radius * 2, 1, 0.1f, light->range * (1.f/1000.f));
|
|
glGetFloatv(GL_PROJECTION_MATRIX, light->proj);
|
|
glPopMatrix();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glRotatef(horizang, 1.0f, 0.0f, 0.0f);
|
|
glRotatef(ang, 0.0f, 1.0f, 0.0f);
|
|
glScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
|
|
glTranslatef(-lightpos[0], -lightpos[1], -lightpos[2]);
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, light->transform);
|
|
glPopMatrix();
|
|
|
|
polymer_extractfrustum(light->transform, light->proj, light->frustum);
|
|
|
|
light->rtindex = -1;
|
|
light->lightmap = 0;
|
|
}
|
|
|
|
static inline void polymer_culllight(int16_t lighti)
|
|
{
|
|
_prlight* light = &prlights[lighti];
|
|
int32_t front = 0;
|
|
int32_t back = 1;
|
|
int32_t i;
|
|
int32_t j;
|
|
int32_t zdiff;
|
|
int32_t checkror;
|
|
int16_t bunchnum;
|
|
int16_t ns;
|
|
_prsector *s;
|
|
_prwall *w;
|
|
sectortype *sec;
|
|
|
|
Bmemset(drawingstate, 0, sizeof(int16_t) * numsectors);
|
|
drawingstate[light->sector] = 1;
|
|
|
|
sectorqueue[0] = light->sector;
|
|
|
|
do
|
|
{
|
|
s = prsectors[sectorqueue[front]];
|
|
sec = §or[sectorqueue[front]];
|
|
|
|
polymer_pokesector(sectorqueue[front]);
|
|
|
|
checkror = FALSE;
|
|
|
|
zdiff = light->z - s->floorz;
|
|
if (zdiff < 0)
|
|
zdiff = -zdiff;
|
|
zdiff >>= 4;
|
|
|
|
if (!light->radius && !(sec->floorstat & 1)) {
|
|
if (zdiff < light->range) {
|
|
polymer_addplanelight(&s->floor, lighti);
|
|
checkror = TRUE;
|
|
}
|
|
} else if (polymer_planeinlight(&s->floor, light)) {
|
|
polymer_addplanelight(&s->floor, lighti);
|
|
checkror = TRUE;
|
|
}
|
|
|
|
#ifdef YAX_ENABLE
|
|
// queue ROR neighbors
|
|
if (checkror &&
|
|
(bunchnum = yax_getbunch(sectorqueue[front], YAX_FLOOR)) >= 0) {
|
|
|
|
for (SECTORS_OF_BUNCH(bunchnum, YAX_CEILING, ns)) {
|
|
|
|
if (ns >= 0 && !drawingstate[ns] &&
|
|
polymer_planeinlight(&prsectors[ns]->ceil, light)) {
|
|
|
|
sectorqueue[back++] = ns;
|
|
drawingstate[ns] = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
checkror = FALSE;
|
|
|
|
zdiff = light->z - s->ceilingz;
|
|
if (zdiff < 0)
|
|
zdiff = -zdiff;
|
|
zdiff >>= 4;
|
|
|
|
if (!light->radius && !(sec->ceilingstat & 1)) {
|
|
if (zdiff < light->range) {
|
|
polymer_addplanelight(&s->ceil, lighti);
|
|
checkror = TRUE;
|
|
}
|
|
} else if (polymer_planeinlight(&s->ceil, light)) {
|
|
polymer_addplanelight(&s->ceil, lighti);
|
|
checkror = TRUE;
|
|
}
|
|
|
|
#ifdef YAX_ENABLE
|
|
// queue ROR neighbors
|
|
if (checkror &&
|
|
(bunchnum = yax_getbunch(sectorqueue[front], YAX_CEILING)) >= 0) {
|
|
|
|
for (SECTORS_OF_BUNCH(bunchnum, YAX_FLOOR, ns)) {
|
|
|
|
if (ns >= 0 && !drawingstate[ns] &&
|
|
polymer_planeinlight(&prsectors[ns]->floor, light)) {
|
|
|
|
sectorqueue[back++] = ns;
|
|
drawingstate[ns] = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
i = 0;
|
|
while (i < sec->wallnum)
|
|
{
|
|
w = prwalls[sec->wallptr + i];
|
|
|
|
j = 0;
|
|
|
|
if (polymer_planeinlight(&w->wall, light)) {
|
|
polymer_addplanelight(&w->wall, lighti);
|
|
j++;
|
|
}
|
|
|
|
if (polymer_planeinlight(&w->over, light)) {
|
|
polymer_addplanelight(&w->over, lighti);
|
|
j++;
|
|
}
|
|
|
|
// assume the light hits the middle section if it hits the top and bottom
|
|
if (wallvisible(light->x, light->y, sec->wallptr + i) &&
|
|
(j == 2 || polymer_planeinlight(&w->mask, light))) {
|
|
if ((w->mask.vertcount == 4) &&
|
|
(w->mask.buffer[0].y >= w->mask.buffer[3].y) &&
|
|
(w->mask.buffer[1].y >= w->mask.buffer[2].y))
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
polymer_addplanelight(&w->mask, lighti);
|
|
|
|
if ((wall[sec->wallptr + i].nextsector >= 0) &&
|
|
(!drawingstate[wall[sec->wallptr + i].nextsector])) {
|
|
drawingstate[wall[sec->wallptr + i].nextsector] = 1;
|
|
sectorqueue[back] = wall[sec->wallptr + i].nextsector;
|
|
back++;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
front++;
|
|
}
|
|
while (front != back);
|
|
|
|
i = MAXSPRITES-1;
|
|
|
|
do
|
|
{
|
|
_prsprite *s = prsprites[i];
|
|
|
|
if ((sprite[i].cstat & 48) == 0 || s == NULL || sprite[i].statnum == MAXSTATUS || sprite[i].sectnum == MAXSECTORS)
|
|
continue;
|
|
|
|
if (polymer_planeinlight(&s->plane, light))
|
|
polymer_addplanelight(&s->plane, lighti);
|
|
}
|
|
while (i--);
|
|
}
|
|
|
|
static void polymer_prepareshadows(void)
|
|
{
|
|
fix16_t oviewangle, oglobalang;
|
|
int32_t i, j, k;
|
|
int32_t gx, gy, gz;
|
|
int32_t oldoverridematerial;
|
|
|
|
// for wallvisible()
|
|
gx = globalposx;
|
|
gy = globalposy;
|
|
gz = globalposz;
|
|
// build globals used by drawmasks
|
|
oviewangle = viewangle;
|
|
oglobalang = qglobalang;
|
|
|
|
i = j = k = 0;
|
|
|
|
while ((k < lightcount) && (j < pr_shadowcount))
|
|
{
|
|
while (!prlights[i].flags.active)
|
|
i++;
|
|
|
|
if (prlights[i].radius && prlights[i].publicflags.emitshadow &&
|
|
prlights[i].flags.isinview)
|
|
{
|
|
prlights[i].flags.isinview = 0;
|
|
prlights[i].rtindex = j + 1;
|
|
if (pr_verbosity >= 3) OSD_Printf("PR : Drawing shadow %i...\n", i);
|
|
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[prlights[i].rtindex].fbo);
|
|
glPushAttrib(GL_VIEWPORT_BIT);
|
|
glViewport(0, 0, prrts[prlights[i].rtindex].xdim, prrts[prlights[i].rtindex].ydim);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadMatrixf(prlights[i].proj);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadMatrixf(prlights[i].transform);
|
|
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
glPolygonOffset(5, SHADOW_DEPTH_OFFSET);
|
|
|
|
set_globalpos(prlights[i].x, prlights[i].y, prlights[i].z);
|
|
|
|
// build globals used by rotatesprite
|
|
viewangle = fix16_from_int(prlights[i].angle);
|
|
set_globalang(fix16_from_int(prlights[i].angle));
|
|
|
|
oldoverridematerial = overridematerial;
|
|
// smooth model shadows
|
|
overridematerial = prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit;
|
|
// used by alpha-testing for sprite silhouette
|
|
overridematerial |= prprogrambits[PR_BIT_DIFFUSE_MAP].bit;
|
|
overridematerial |= prprogrambits[PR_BIT_DIFFUSE_MAP2].bit;
|
|
|
|
// to force sprite drawing
|
|
mirrors[depth++].plane = NULL;
|
|
polymer_displayrooms(prlights[i].sector);
|
|
depth--;
|
|
|
|
overridematerial = oldoverridematerial;
|
|
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
|
|
glPopAttrib();
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
|
|
j++;
|
|
}
|
|
i++;
|
|
k++;
|
|
}
|
|
|
|
set_globalpos(gx, gy, gz);
|
|
|
|
viewangle = oviewangle;
|
|
set_globalang(oglobalang);
|
|
}
|
|
|
|
// RENDER TARGETS
|
|
static void polymer_initrendertargets(int32_t count)
|
|
{
|
|
int32_t i;
|
|
|
|
static int32_t ocount;
|
|
|
|
if (count == 0) // uninit
|
|
{
|
|
if (prrts)
|
|
{
|
|
for (i=0; i<ocount; i++)
|
|
{
|
|
if (prrts[i].color)
|
|
{
|
|
glDeleteTextures(1, &prrts[i].color);
|
|
prrts[i].color = 0;
|
|
}
|
|
glDeleteTextures(1, &prrts[i].z);
|
|
prrts[i].z = 0;
|
|
|
|
glDeleteFramebuffersEXT(1, &prrts[i].fbo);
|
|
prrts[i].fbo = 0;
|
|
}
|
|
DO_FREE_AND_NULL(prrts);
|
|
}
|
|
|
|
ocount = 0;
|
|
return;
|
|
}
|
|
|
|
ocount = count;
|
|
//////////
|
|
|
|
prrts = (_prrt *)Xcalloc(count, sizeof(_prrt));
|
|
|
|
i = 0;
|
|
while (i < count)
|
|
{
|
|
if (!i) {
|
|
prrts[i].target = GL_TEXTURE_RECTANGLE_ARB;
|
|
prrts[i].xdim = xdim;
|
|
prrts[i].ydim = ydim;
|
|
|
|
glGenTextures(1, &prrts[i].color);
|
|
glBindTexture(prrts[i].target, prrts[i].color);
|
|
|
|
glTexImage2D(prrts[i].target, 0, GL_RGB, prrts[i].xdim, prrts[i].ydim, 0, GL_RGB, GL_SHORT, NULL);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
} else {
|
|
prrts[i].target = GL_TEXTURE_2D;
|
|
prrts[i].xdim = 128 << pr_shadowdetail;
|
|
prrts[i].ydim = 128 << pr_shadowdetail;
|
|
prrts[i].color = 0;
|
|
|
|
if (pr_ati_fboworkaround) {
|
|
glGenTextures(1, &prrts[i].color);
|
|
glBindTexture(prrts[i].target, prrts[i].color);
|
|
|
|
glTexImage2D(prrts[i].target, 0, GL_RGB, prrts[i].xdim, prrts[i].ydim, 0, GL_RGB, GL_SHORT, NULL);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
}
|
|
}
|
|
|
|
glGenTextures(1, &prrts[i].z);
|
|
glBindTexture(prrts[i].target, prrts[i].z);
|
|
|
|
glTexImage2D(prrts[i].target, 0, GL_DEPTH_COMPONENT, prrts[i].xdim, prrts[i].ydim, 0, GL_DEPTH_COMPONENT, GL_SHORT, NULL);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, pr_shadowfiltering ? GL_LINEAR : GL_NEAREST);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, pr_shadowfiltering ? GL_LINEAR : GL_NEAREST);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
|
glTexParameteri(prrts[i].target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
|
glTexParameteri(prrts[i].target, GL_DEPTH_TEXTURE_MODE, GL_ALPHA);
|
|
|
|
glGenFramebuffersEXT(1, &prrts[i].fbo);
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[i].fbo);
|
|
|
|
if (prrts[i].color)
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
|
prrts[i].target, prrts[i].color, 0);
|
|
else {
|
|
glDrawBuffer(GL_NONE);
|
|
glReadBuffer(GL_NONE);
|
|
}
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, prrts[i].target, prrts[i].z, 0);
|
|
|
|
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
|
|
{
|
|
OSD_Printf("PR : FBO #%d initialization failed.\n", i);
|
|
}
|
|
|
|
glBindTexture(prrts[i].target, 0);
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// DEBUG OUTPUT
|
|
void PR_CALLBACK polymer_debugoutputcallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(source);
|
|
UNREFERENCED_PARAMETER(type);
|
|
UNREFERENCED_PARAMETER(id);
|
|
UNREFERENCED_PARAMETER(severity);
|
|
UNREFERENCED_PARAMETER(length);
|
|
UNREFERENCED_PARAMETER(userParam);
|
|
|
|
if (type == GL_DEBUG_TYPE_ERROR_ARB)
|
|
{
|
|
OSD_Printf("PR : Received OpenGL debug message: %s\n", message);
|
|
}
|
|
}
|
|
|
|
#endif
|