raze/polymer/eduke32/build/src/polymer.c
hendricks266 b3639ae8e7 Replace most instances of casting byte arrays to wider integral types with the B_(UN)BUF functions in compat.h that were previously used only in the netcode.
I have commented out the versions of these functions that perform bitmasks and shifts and replaced them with versions that cast to and from integral types, pending performance and compatibility research across platforms.

git-svn-id: https://svn.eduke32.com/eduke32@5174 1a8010ca-5511-0410-912e-c29ae57300e0
2015-05-03 07:03:48 +00:00

5975 lines
190 KiB
C

// blah
#ifdef USE_OPENGL
#include <math.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_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 r_pr_maxlightpasses = 5; // value of the cvar (not live value), used to detect changes
GLenum mapvbousage = GL_STREAM_DRAW_ARB;
GLenum modelvbousage = GL_STATIC_DRAW_ARB;
// 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];
static const GLfloat vertsprite[4 * 5] =
{
-0.5f, 0.0f, 0.0f,
0.0f, 1.0f,
0.5f, 0.0f, 0.0f,
1.0f, 1.0f,
0.5f, 1.0f, 0.0f,
1.0f, 0.0f,
-0.5f, 1.0f, 0.0f,
0.0f, 0.0f,
};
static const GLfloat horizsprite[4 * 5] =
{
-0.5f, 0.0f, 0.5f,
0.0f, 0.0f,
0.5f, 0.0f, 0.5f,
1.0f, 0.0f,
0.5f, 0.0f, -0.5f,
1.0f, 1.0f,
-0.5f, 0.0f, -0.5f,
0.0f, 1.0f,
};
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
// 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.
" float shadeLookup = length(horizDistance) / 1.07 * 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 * 4.0;\n"
"\n"
" if (isLightingPass == 0) {\n"
" result.rgb = mix(texelNear, texelFar, fract(shadeLookup)) * 4.0;\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 / 35.0;\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
/* 0.65127==150/230, another constant found out by experiment. :/
* (150 is Polymost's old FOGDISTCONST.) */
" } else {\n"
" fogFactor = gl_Fog.scale * (gl_Fog.end - fragDepth*0.65217);\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;
int16_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)
{
bglGenTextures(1, &prhighpalookups[i][j].map);
bglBindTexture(GL_TEXTURE_3D, prhighpalookups[i][j].map);
bglTexImage3D(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
bglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
bglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
bglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglBindTexture(GL_TEXTURE_3D, 0);
}
j++;
}
i++;
}
#ifndef __APPLE__
if (glinfo.debugoutput) {
// Enable everything.
bglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
bglDebugMessageCallbackARB(polymer_debugoutputcallback, NULL);
}
#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) {
// Bfree(prhighpalookups[i][j].data);
// prhighpalookups[i][j].data = NULL;
// }
if (prhighpalookups[i][j].map) {
bglDeleteTextures(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((float)viewingrange/65536.0f)/(PI/4);
if (pr_customaspect != 0.0f)
aspect = pr_customaspect;
else
aspect = (float)(windowx2-windowx1+1) /
(float)(windowy2-windowy1+1);
bglMatrixMode(GL_PROJECTION);
bglLoadIdentity();
bgluPerspective(fang / (2048.0f / 360.0f), aspect, 0.01f, 100.0f);
}
void polymer_glinit(void)
{
bglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
bglClearStencil(0);
bglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
bglViewport(windowx1, yres-(windowy2+1),windowx2-windowx1+1, windowy2-windowy1+1);
// texturing
bglEnable(GL_TEXTURE_2D);
bglEnable(GL_DEPTH_TEST);
bglDepthFunc(GL_LEQUAL);
bglDisable(GL_BLEND);
bglDisable(GL_ALPHA_TEST);
if (pr_wireframe)
bglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
bglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
polymer_setaspect(pr_fov);
bglMatrixMode(GL_MODELVIEW);
bglLoadIdentity();
bglEnableClientState(GL_VERTEX_ARRAY);
bglEnableClientState(GL_TEXTURE_COORD_ARRAY);
bglDisable(GL_FOG);
culledface = GL_BACK;
bglCullFace(GL_BACK);
bglFrontFace(GL_CCW);
bglEnable(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();
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, int16_t daang, int32_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 + windowy1*bytesperline + windowx1;
if (pr_verbosity >= 3) OSD_Printf("PR : Drawing rooms...\n");
// fogcalc needs this
gvisibility = ((float)globalvisibility)*FOGSCALE;
ang = (float)(daang) / (2048.0f / 360.0f);
horizang = (float)(-getangle(128, dahoriz-100)) / (2048.0f / 360.0f);
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, 0);
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;
bglMatrixMode(GL_MODELVIEW);
bglLoadIdentity();
bglRotatef(tiltang, 0.0f, 0.0f, -1.0f);
bglRotatef(skyhoriz, 1.0f, 0.0f, 0.0f);
bglRotatef(ang, 0.0f, 1.0f, 0.0f);
bglScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
bglTranslatef(-pos[0], -pos[1], -pos[2]);
bglGetFloatv(GL_MODELVIEW_MATRIX, rootskymodelviewmatrix);
curskymodelviewmatrix = rootskymodelviewmatrix;
bglMatrixMode(GL_MODELVIEW);
bglLoadIdentity();
bglRotatef(tiltang, 0.0f, 0.0f, -1.0f);
bglRotatef(horizang, 1.0f, 0.0f, 0.0f);
bglRotatef(ang, 0.0f, 1.0f, 0.0f);
bglScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
bglTranslatef(-pos[0], -pos[1], -pos[2]);
bglGetFloatv(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))
{
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--;
}
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 = ((float)cosglobalang)/262144.f;
gsinang = ((float)singlobalang)/262144.f;
gcosang2 = gcosang*((float)viewingrange)/65536.f;
gsinang2 = gsinang*((float)viewingrange)/65536.f;
if (pr_verbosity >= 3) OSD_Printf("PR : Rooms drawn.\n");
enddrawing();
}
void polymer_drawmasks(void)
{
bglEnable(GL_ALPHA_TEST);
bglEnable(GL_BLEND);
// bglEnable(GL_POLYGON_OFFSET_FILL);
// while (--spritesortcnt)
// {
// tspriteptr[spritesortcnt] = &tsprite[spritesortcnt];
// polymer_drawsprite(spritesortcnt);
// }
bglEnable(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.
Bfree(cursectormaskcount);
cursectormaskcount = NULL;
Bfree(cursectormasks);
cursectormasks = NULL;
}
bglDisable(GL_CULL_FACE);
// bglDisable(GL_POLYGON_OFFSET_FILL);
bglDisable(GL_BLEND);
bglDisable(GL_ALPHA_TEST);
}
void polymer_editorpick(void)
{
GLubyte picked[3];
int16_t num;
bglReadPixels(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;
bglGetDoublev(GL_MODELVIEW_MATRIX, model);
bglGetDoublev(GL_PROJECTION_MATRIX, proj);
bglGetIntegerv(GL_VIEWPORT, view);
bglReadPixels(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)
{
_prmaterial rotatespritematerial;
polymer_getbuildmaterial(&rotatespritematerial, tilenum, pal, shade, 0, DAMETH_CLAMPED);
rotatespritematerialbits = polymer_bindmaterial(&rotatespritematerial, NULL, 0);
}
void polymer_postrotatesprite(void)
{
polymer_unbindmaterial(rotatespritematerialbits);
}
static void polymer_drawsearchplane(_prplane *plane, GLubyte *oldcolor, GLubyte modulation, GLubyte *data)
{
if (oldcolor)
Bmemcpy(oldcolor, plane->material.diffusemodulation, sizeof(GLubyte) * 4);
plane->material.diffusemodulation[0] = modulation;
plane->material.diffusemodulation[1] = ((GLubyte *) data)[0];
plane->material.diffusemodulation[2] = ((GLubyte *) data)[1];
plane->material.diffusemodulation[3] = 0xFF;
polymer_drawplane(plane);
if (oldcolor)
Bmemcpy(plane->material.diffusemodulation, oldcolor, sizeof(GLubyte) * 4);
}
void polymer_drawmaskwall(int32_t damaskwallcnt)
{
tsectortype *sec;
walltype *wal;
_prwall *w;
GLubyte oldcolor[4];
if (pr_verbosity >= 3) OSD_Printf("PR : Masked wall %i...\n", damaskwallcnt);
sec = (tsectortype *)&sector[sectorofwall(maskwall[damaskwallcnt])];
wal = &wall[maskwall[damaskwallcnt]];
w = prwalls[maskwall[damaskwallcnt]];
bglEnable(GL_CULL_FACE);
if (searchit == 2) {
polymer_drawsearchplane(&w->mask, oldcolor, 0x04, (GLubyte *)&maskwall[damaskwallcnt]);
} else {
calc_and_apply_fog(wal->picnum, fogpal_shade(sec, wal->shade), sec->visibility, get_floor_fogpal(sec));
polymer_drawplane(&w->mask);
}
bglDisable(GL_CULL_FACE);
}
void polymer_drawsprite(int32_t snum)
{
int32_t i, j, cs;
_prsprite *s;
tspritetype *const tspr = tspriteptr[snum];
const tsectortype *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 = (tsectortype *)&sector[tspr->sectnum];
calc_and_apply_fog(tspr->picnum, fogpal_shade(sec, tspr->shade), sec->visibility,
get_floor_fogpal((tsectortype *)&sector[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))
{
bglEnable(GL_CULL_FACE);
SWITCH_CULL_DIRECTION;
polymer_drawmdsprite(tspr);
SWITCH_CULL_DIRECTION;
bglDisable(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)
bglPolygonOffset(-1.0f, -1.0f);
break;
case 2:
prsectors[tspr->sectnum]->floorsproffset += 0.5f;
if (!depth || mirrors[depth-1].plane)
bglPolygonOffset(-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;
bglEnable(GL_CULL_FACE);
}
if ((!depth || mirrors[depth-1].plane) && !pr_ati_nodepthoffset)
bglEnable(GL_POLYGON_OFFSET_FILL);
polymer_drawplane(&s->plane);
if ((!depth || mirrors[depth-1].plane) && !pr_ati_nodepthoffset)
bglDisable(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;
bglDisable(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, 0);
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)
{
tsectortype *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;
tspritetype 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;
bglGetFloatv(GL_MODELVIEW_MATRIX, localmodelviewmatrix);
bglGetFloatv(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;
bglDisable(GL_DEPTH_TEST);
bglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
polymer_drawsky(cursky, curskypal, curskyshade);
bglEnable(GL_DEPTH_TEST);
// depth-only occlusion testing pass
// overridematerial = 0;
while (front != back)
{
sec = (tsectortype *)&sector[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)
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 * 5) + 1] >= w->mask.buffer[(3 * 5) + 1]) &&
(w->mask.buffer[(1 * 5) + 1] >= w->mask.buffer[(2 * 5) + 1]))
{
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] = (float)globalposy;
pos[1] = -(float)(globalposz) / 16.0f;
pos[2] = -(float)globalposx;
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];
bglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
bglDepthMask(GL_FALSE);
bglGenQueriesARB(1, &queryid[sec->wallptr + i]);
bglBeginQueryARB(GL_SAMPLES_PASSED_ARB, 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;
bglEndQueryARB(GL_SAMPLES_PASSED_ARB);
bglDepthMask(GL_TRUE);
bglColorMask(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))
{
bglGetQueryObjectivARB(queryid[sec->wallptr + i],
GL_QUERY_RESULT_ARB,
&result);
bglDeleteQueriesARB(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)
{
bglDeleteQueriesARB(1, &queryid[sec->wallptr + i]);
queryid[sec->wallptr + i] = 0;
}
}
while (--i >= 0);
front++;
}
// do the actual shaded drawing
// overridematerial = 0xFFFFFFFF;
// go through the sector queue again
// front = 0;
// while (front < back)
// {
// sec = &sector[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)
{
bglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[0].fbo);
bglPushAttrib(GL_VIEWPORT_BIT);
bglViewport(windowx1, yres-(windowy2+1),windowx2-windowx1+1, windowy2-windowy1+1);
bglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Bmemcpy(localskymodelviewmatrix, curskymodelviewmatrix, sizeof(GLfloat) * 16);
curskymodelviewmatrix = localskymodelviewmatrix;
bglMatrixMode(GL_MODELVIEW);
bglPushMatrix();
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];
bglClipPlane(GL_CLIP_PLANE0, plane);
polymer_inb4mirror(mirrorlist[i].plane->buffer, mirrorlist[i].plane->plane);
SWITCH_CULL_DIRECTION;
//bglEnable(GL_CLIP_PLANE0);
if (mirrorlist[i].wallnum >= 0)
preparemirror(globalposx, globalposy, globalang,
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);
bglDisable(GL_CLIP_PLANE0);
SWITCH_CULL_DIRECTION;
bglMatrixMode(GL_MODELVIEW);
bglPopMatrix();
bglPopAttrib();
bglBindFramebufferEXT(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;
bglDisable(GL_CULL_FACE);
drawmasks();
bglEnable(GL_CULL_FACE);
}
return;
}
static void polymer_drawplane(_prplane* plane)
{
int32_t materialbits;
// debug code for drawing plane inverse TBN
// bglDisable(GL_TEXTURE_2D);
// bglBegin(GL_LINES);
// bglColor4f(1.0, 0.0, 0.0, 1.0);
// bglVertex3f(plane->buffer[0],
// plane->buffer[1],
// plane->buffer[2]);
// bglVertex3f(plane->buffer[0] + plane->t[0] * 50,
// plane->buffer[1] + plane->t[1] * 50,
// plane->buffer[2] + plane->t[2] * 50);
// bglColor4f(0.0, 1.0, 0.0, 1.0);
// bglVertex3f(plane->buffer[0],
// plane->buffer[1],
// plane->buffer[2]);
// bglVertex3f(plane->buffer[0] + plane->b[0] * 50,
// plane->buffer[1] + plane->b[1] * 50,
// plane->buffer[2] + plane->b[2] * 50);
// bglColor4f(0.0, 0.0, 1.0, 1.0);
// bglVertex3f(plane->buffer[0],
// plane->buffer[1],
// plane->buffer[2]);
// bglVertex3f(plane->buffer[0] + plane->n[0] * 50,
// plane->buffer[1] + plane->n[1] * 50,
// plane->buffer[2] + plane->n[2] * 50);
// bglEnd();
// bglEnable(GL_TEXTURE_2D);
// debug code for drawing plane normals
// bglDisable(GL_TEXTURE_2D);
// bglBegin(GL_LINES);
// bglColor4f(1.0, 1.0, 1.0, 1.0);
// bglVertex3f(plane->buffer[0],
// plane->buffer[1],
// plane->buffer[2]);
// bglVertex3f(plane->buffer[0] + plane->plane[0] * 50,
// plane->buffer[1] + plane->plane[1] * 50,
// plane->buffer[2] + plane->plane[2] * 50);
// bglEnd();
// bglEnable(GL_TEXTURE_2D);
bglNormal3f((float)(plane->plane[0]), (float)(plane->plane[1]), (float)(plane->plane[2]));
if (plane->vbo && (pr_vbos > 0))
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, plane->vbo);
bglVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), NULL);
bglTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(3 * sizeof(GLfloat)));
if (plane->indices)
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, plane->ivbo);
} else {
bglVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), plane->buffer);
bglTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &plane->buffer[3]);
}
curlight = 0;
do {
materialbits = polymer_bindmaterial(&plane->material, plane->lights, plane->lightcount);
if (materialbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
{
bglVertexAttrib3fvARB(prprograms[materialbits].attrib_T, &plane->tbn[0][0]);
bglVertexAttrib3fvARB(prprograms[materialbits].attrib_B, &plane->tbn[1][0]);
bglVertexAttrib3fvARB(prprograms[materialbits].attrib_N, &plane->tbn[2][0]);
}
if (plane->indices)
{
if (plane->vbo && (pr_vbos > 0))
bglDrawElements(GL_TRIANGLES, plane->indicescount, GL_UNSIGNED_SHORT, NULL);
else
bglDrawElements(GL_TRIANGLES, plane->indicescount, GL_UNSIGNED_SHORT, plane->indices);
} else
bglDrawArrays(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 (plane->vbo && (pr_vbos > 0))
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
if (plane->indices)
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
}
static inline void polymer_inb4mirror(GLfloat* buffer, GLfloat* plane)
{
float pv;
float reflectionmatrix[16];
pv = buffer[0] * plane[0] +
buffer[1] * plane[1] +
buffer[2] * 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;
bglMultMatrixf(reflectionmatrix);
bglPushMatrix();
bglLoadMatrixf(curskymodelviewmatrix);
bglMultMatrixf(reflectionmatrix);
bglGetFloatv(GL_MODELVIEW_MATRIX, curskymodelviewmatrix);
bglPopMatrix();
}
static void polymer_animatesprites(void)
{
if (asi.animatesprites)
asi.animatesprites(globalposx, globalposy, viewangle, asi.smoothratio);
}
static void polymer_freeboard(void)
{
int32_t i;
i = 0;
while (i < MAXSECTORS)
{
if (prsectors[i])
{
if (prsectors[i]->verts) Bfree(prsectors[i]->verts);
if (prsectors[i]->floor.buffer) Bfree(prsectors[i]->floor.buffer);
if (prsectors[i]->ceil.buffer) Bfree(prsectors[i]->ceil.buffer);
if (prsectors[i]->floor.indices) Bfree(prsectors[i]->floor.indices);
if (prsectors[i]->ceil.indices) Bfree(prsectors[i]->ceil.indices);
if (prsectors[i]->ceil.vbo) bglDeleteBuffersARB(1, &prsectors[i]->ceil.vbo);
if (prsectors[i]->ceil.ivbo) bglDeleteBuffersARB(1, &prsectors[i]->ceil.ivbo);
if (prsectors[i]->floor.vbo) bglDeleteBuffersARB(1, &prsectors[i]->floor.vbo);
if (prsectors[i]->floor.ivbo) bglDeleteBuffersARB(1, &prsectors[i]->floor.ivbo);
Bfree(prsectors[i]);
prsectors[i] = NULL;
}
i++;
}
i = 0;
while (i < MAXWALLS)
{
if (prwalls[i])
{
if (prwalls[i]->bigportal) Bfree(prwalls[i]->bigportal);
if (prwalls[i]->mask.buffer) Bfree(prwalls[i]->mask.buffer);
if (prwalls[i]->over.buffer) Bfree(prwalls[i]->over.buffer);
if (prwalls[i]->cap) Bfree(prwalls[i]->cap);
if (prwalls[i]->wall.buffer) Bfree(prwalls[i]->wall.buffer);
if (prwalls[i]->wall.vbo) bglDeleteBuffersARB(1, &prwalls[i]->wall.vbo);
if (prwalls[i]->over.vbo) bglDeleteBuffersARB(1, &prwalls[i]->over.vbo);
if (prwalls[i]->mask.vbo) bglDeleteBuffersARB(1, &prwalls[i]->mask.vbo);
if (prwalls[i]->stuffvbo) bglDeleteBuffersARB(1, &prwalls[i]->stuffvbo);
Bfree(prwalls[i]);
prwalls[i] = NULL;
}
i++;
}
i = 0;
while (i < MAXSPRITES)
{
if (prsprites[i])
{
if (prsprites[i]->plane.buffer) Bfree(prsprites[i]->plane.buffer);
if (prsprites[i]->plane.vbo) bglDeleteBuffersARB(1, &prsprites[i]->plane.vbo);
Bfree(prsprites[i]);
prsprites[i] = NULL;
}
i++;
}
i = 0;
while (i < MAXTILES)
{
polymer_invalidateartmap(i);
i++;
}
i = 0;
while (i < MAXBASEPALS)
{
if (prbasepalmaps[i])
{
bglDeleteTextures(1, &prbasepalmaps[i]);
prbasepalmaps[i] = 0;
}
i++;
}
i = 0;
while (i < MAXPALOOKUPS)
{
if (prlookups[i])
{
bglDeleteTextures(1, &prlookups[i]);
prlookups[i] = 0;
}
i++;
}
}
// SECTORS
static int32_t polymer_initsector(int16_t sectnum)
{
tsectortype *sec;
_prsector* s;
if (pr_verbosity >= 2) OSD_Printf("PR : Initializing sector %i...\n", sectnum);
sec = (tsectortype *)&sector[sectnum];
s = (_prsector *)Xcalloc(1, sizeof(_prsector));
s->verts = (GLdouble *)Xcalloc(sec->wallnum, sizeof(GLdouble) * 3);
s->floor.buffer = (GLfloat *)Xcalloc(sec->wallnum, sizeof(GLfloat) * 5);
s->floor.vertcount = sec->wallnum;
s->ceil.buffer = (GLfloat *)Xcalloc(sec->wallnum, sizeof(GLfloat) * 5);
s->ceil.vertcount = sec->wallnum;
bglGenBuffersARB(1, &s->floor.vbo);
bglGenBuffersARB(1, &s->ceil.vbo);
bglGenBuffersARB(1, &s->floor.ivbo);
bglGenBuffersARB(1, &s->ceil.ivbo);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, s->floor.vbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, sec->wallnum * sizeof(GLfloat) * 5, NULL, mapvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, s->ceil.vbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, sec->wallnum * sizeof(GLfloat) * 5, NULL, mapvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 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;
tsectortype *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;
GLfloat* curbuffer;
s = prsectors[sectnum];
sec = (tsectortype *)&sector[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*5)+2] = s->ceil.buffer[(i*5)+2] = -(float)wal->x;
needfloor = wallinvalidate = 1;
}
if ((wal->y != s->verts[i*3]))
{
s->verts[i*3] = s->floor.buffer[i*5] = s->ceil.buffer[i*5] = (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*5)+1] = -(float)(florz) / 16.0f;
s->ceil.buffer[(i*5)+1] = -(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) &&
!Bmemcmp(&s->ceilingstat, &sec->ceilingstat, offsetof(sectortype, visibility) - offsetof(sectortype, ceilingstat)))
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*5)+1] - curbuffer[1]);
// 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*5)+3] = ((float)(tex) / (scalecoef * tilesiz[curpicnum].x)) + xpancoef;
curbuffer[(i*5)+4] = ((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;
i = -1;
attributes:
if ((pr_vbos > 0) && ((i == -1) || (wallinvalidate)))
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, s->floor.vbo);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sec->wallnum * sizeof(GLfloat) * 5, s->floor.buffer);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, s->ceil.vbo);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sec->wallnum * sizeof(GLfloat) * 5, s->ceil.buffer);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
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;
polymer_getbuildmaterial(&s->floor.material, floorpicnum, sec->floorpal, sec->floorshade, sec->visibility, 0);
if (sec->floorstat & 256) {
if (sec->floorstat & 128) {
s->floor.material.diffusemodulation[3] = 0x55;
} else {
s->floor.material.diffusemodulation[3] = 0xAA;
}
}
polymer_getbuildmaterial(&s->ceil.material, ceilingpicnum, sec->ceilingpal, sec->ceilingshade, sec->visibility, 0);
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 (s->oldindicescount < s->indicescount)
{
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->floor.ivbo);
bglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->indicescount * sizeof(GLushort), NULL, mapvbousage);
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->ceil.ivbo);
bglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->indicescount * sizeof(GLushort), NULL, mapvbousage);
s->oldindicescount = s->indicescount;
}
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->floor.ivbo);
bglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, s->indicescount * sizeof(GLushort), s->floor.indices);
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->ceil.ivbo);
bglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, s->indicescount * sizeof(GLushort), s->ceil.indices);
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 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;
tsectortype *sec;
intptr_t i;
if (pr_verbosity >= 2) OSD_Printf("PR : Tesselating floor of sector %i...\n", sectnum);
s = prsectors[sectnum];
sec = (tsectortype *)&sector[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)
{
tsectortype *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 = (tsectortype *)&sector[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 *) &sectnum);
}
else {
calc_and_apply_fog(sec->floorpicnum, fogpal_shade(sec, sec->floorshade),
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 *) &sectnum);
}
else {
calc_and_apply_fog(sec->ceilingpicnum, fogpal_shade(sec, sec->ceilingshade),
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 = (GLfloat *)Xmalloc(4 * sizeof(GLfloat) * 5);
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);
bglGenBuffersARB(1, &w->wall.vbo);
bglGenBuffersARB(1, &w->over.vbo);
bglGenBuffersARB(1, &w->mask.vbo);
bglGenBuffersARB(1, &w->stuffvbo);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->wall.vbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->over.vbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->mask.vbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->stuffvbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, 8 * sizeof(GLfloat) * 5, NULL, mapvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 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);
// yes, this function is messy and unefficient
// it also works, bitches
sec = &sector[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 = &sector[wal->nextsector];
}
else
{
ns = NULL;
nsec = NULL;
}
if (w->wall.buffer == NULL) {
w->wall.buffer = (GLfloat *)Xcalloc(4, sizeof(GLfloat) * 5); // 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) &&
!Bmemcmp(&wal->cstat, &w->cstat, NBYTES_WALL_CSTAT_THROUGH_YPANNING) &&
((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;
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) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->wall.buffer[5], &s->floor.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->wall.buffer[10], &s->ceil.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->wall.buffer[15], &s->ceil.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 3);
if (wal->nextsector < 0)
curpicnum = wallpicnum;
else
curpicnum = walloverpicnum;
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 * 5) + 3] = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
w->wall.buffer[(i * 5) + 4] = (-(float)(yref + (w->wall.buffer[(i * 5) + 1] * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
if (wal->cstat & 256) w->wall.buffer[(i * 5) + 4] = -w->wall.buffer[(i * 5) + 4];
i++;
}
w->underover |= 1;
}
else
{
nnwallnum = wall[nwallnum].point2;
if ((s->floor.buffer[((wallnum - sec->wallptr) * 5) + 1] < ns->floor.buffer[((nnwallnum - nsec->wallptr) * 5) + 1]) ||
(s->floor.buffer[((wal->point2 - sec->wallptr) * 5) + 1] < ns->floor.buffer[((nwallnum - nsec->wallptr) * 5) + 1]))
underwall = 1;
if ((underwall) || (wal->cstat & 16) || (wal->cstat & 32))
{
int32_t refwall;
if (s->floor.buffer[((wallnum - sec->wallptr) * 5) + 1] < ns->floor.buffer[((nnwallnum - nsec->wallptr) * 5) + 1])
Bmemcpy(w->wall.buffer, &s->floor.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 3);
else
Bmemcpy(w->wall.buffer, &ns->floor.buffer[(nnwallnum - nsec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->wall.buffer[5], &s->floor.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->wall.buffer[10], &ns->floor.buffer[(nwallnum - nsec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->wall.buffer[15], &ns->floor.buffer[(nnwallnum - nsec->wallptr) * 5], 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;
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 * 5) + 3] = ((dist * 8.0f * wal->xrepeat) + curxpanning) / (float)(tilesiz[curpicnum].x);
w->wall.buffer[(i * 5) + 4] = (-(float)(yref + (w->wall.buffer[(i * 5) + 1] * 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 * 5) + 4] = -w->wall.buffer[(i * 5) + 4];
i++;
}
if (underwall)
w->underover |= 1;
Bmemcpy(w->mask.buffer, &w->wall.buffer[15], sizeof(GLfloat) * 5);
Bmemcpy(&w->mask.buffer[5], &w->wall.buffer[10], sizeof(GLfloat) * 5);
}
else
{
Bmemcpy(w->mask.buffer, &s->floor.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 5);
Bmemcpy(&w->mask.buffer[5], &s->floor.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 5);
}
if ((s->ceil.buffer[((wallnum - sec->wallptr) * 5) + 1] > ns->ceil.buffer[((nnwallnum - nsec->wallptr) * 5) + 1]) ||
(s->ceil.buffer[((wal->point2 - sec->wallptr) * 5) + 1] > ns->ceil.buffer[((nwallnum - nsec->wallptr) * 5) + 1]))
overwall = 1;
if ((overwall) || (wal->cstat & 16) || (wal->cstat & 32))
{
if (w->over.buffer == NULL) {
w->over.buffer = (GLfloat *)Xmalloc(4 * sizeof(GLfloat) * 5);
w->over.vertcount = 4;
}
Bmemcpy(w->over.buffer, &ns->ceil.buffer[(nnwallnum - nsec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->over.buffer[5], &ns->ceil.buffer[(nwallnum - nsec->wallptr) * 5], sizeof(GLfloat) * 3);
if (s->ceil.buffer[((wal->point2 - sec->wallptr) * 5) + 1] > ns->ceil.buffer[((nwallnum - nsec->wallptr) * 5) + 1])
Bmemcpy(&w->over.buffer[10], &s->ceil.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
else
Bmemcpy(&w->over.buffer[10], &ns->ceil.buffer[(nwallnum - nsec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->over.buffer[15], &s->ceil.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 3);
if ((wal->cstat & 16) || (wal->overpicnum == 0))
curpicnum = wallpicnum;
else
curpicnum = wallpicnum;
polymer_getbuildmaterial(&w->over.material, curpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL);
if ((wal->cstat & 16) || (wal->cstat & 32))
{
// mask
polymer_getbuildmaterial(&w->mask.material, walloverpicnum, wal->pal, wal->shade, sec->visibility, DAMETH_WALL);
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 * 5) + 3] = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
w->over.buffer[(i * 5) + 4] = (-(float)(yref + (w->over.buffer[(i * 5) + 1] * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
if (wal->cstat & 256) w->over.buffer[(i * 5) + 4] = -w->over.buffer[(i * 5) + 4];
i++;
}
if (overwall)
w->underover |= 2;
Bmemcpy(&w->mask.buffer[10], &w->over.buffer[5], sizeof(GLfloat) * 5);
Bmemcpy(&w->mask.buffer[15], &w->over.buffer[0], sizeof(GLfloat) * 5);
if ((wal->cstat & 16) || (wal->cstat & 32))
{
// mask wall pass
if (wal->cstat & 4)
yref = min(sec->floorz, nsec->floorz);
else
yref = max(sec->ceilingz, nsec->ceilingz);
if (wal->cstat & 32)
{
if ((!(wal->cstat & 2) && (wal->cstat & 4)) || ((wal->cstat & 2) && (wall[nwallnum].cstat & 4)))
yref = sec->ceilingz;
else
yref = 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 * 5) + 3] = ((dist * 8.0f * wal->xrepeat) + wal->xpanning) / (float)(tilesiz[curpicnum].x);
w->mask.buffer[(i * 5) + 4] = (-(float)(yref + (w->mask.buffer[(i * 5) + 1] * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
if (wal->cstat & 256) w->mask.buffer[(i * 5) + 4] = -w->mask.buffer[(i * 5) + 4];
i++;
}
}
}
else
{
Bmemcpy(&w->mask.buffer[10], &s->ceil.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 5);
Bmemcpy(&w->mask.buffer[15], &s->ceil.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 5);
}
}
if (wal->nextsector < 0)
Bmemcpy(w->mask.buffer, w->wall.buffer, sizeof(GLfloat) * 4 * 5);
Bmemcpy(w->bigportal, &s->floor.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->bigportal[5], &s->floor.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->bigportal[10], &s->ceil.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->bigportal[15], &s->ceil.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->cap[0], &s->ceil.buffer[(wallnum - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->cap[3], &s->ceil.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->cap[6], &s->ceil.buffer[(wal->point2 - sec->wallptr) * 5], sizeof(GLfloat) * 3);
Bmemcpy(&w->cap[9], &s->ceil.buffer[(wallnum - sec->wallptr) * 5], 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))
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->wall.vbo);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 4 * sizeof(GLfloat) * 5, w->wall.buffer);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->over.vbo);
if (w->over.buffer)
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 4 * sizeof(GLfloat) * 5, w->over.buffer);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->mask.vbo);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 4 * sizeof(GLfloat) * 5, w->mask.buffer);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->stuffvbo);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 4 * sizeof(GLfloat) * 5, w->bigportal);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 4 * sizeof(GLfloat) * 5, 4 * sizeof(GLfloat) * 3, w->cap);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
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)
{
tsectortype *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 = (tsectortype *)&sector[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, fogpal_shade(sec, wal->shade), 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)))
{
bglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
if (pr_vbos)
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, w->stuffvbo);
bglVertexPointer(3, GL_FLOAT, 0, (const GLvoid*)(4 * sizeof(GLfloat) * 5));
}
else
bglVertexPointer(3, GL_FLOAT, 0, w->cap);
bglDrawArrays(GL_QUADS, 0, 4);
if (pr_vbos)
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
bglColorMask(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;
GLfloat* 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)) + 0] - buffer[(INDICE(0)) + 0]; //x1
vec1[1] = buffer[(INDICE(1)) + 1] - buffer[(INDICE(0)) + 1]; //y1
vec1[2] = buffer[(INDICE(1)) + 2] - buffer[(INDICE(0)) + 2]; //z1
vec1[3] = buffer[(INDICE(1)) + 3] - buffer[(INDICE(0)) + 3]; //s1
vec1[4] = buffer[(INDICE(1)) + 4] - buffer[(INDICE(0)) + 4]; //t1
vec2[0] = buffer[(INDICE(2)) + 0] - buffer[(INDICE(1)) + 0]; //x2
vec2[1] = buffer[(INDICE(2)) + 1] - buffer[(INDICE(1)) + 1]; //y2
vec2[2] = buffer[(INDICE(2)) + 2] - buffer[(INDICE(1)) + 2]; //z2
vec2[3] = buffer[(INDICE(2)) + 3] - buffer[(INDICE(1)) + 3]; //s2
vec2[4] = buffer[(INDICE(2)) + 4] - buffer[(INDICE(1)) + 4]; //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[0] + plane[1] * buffer[1] + plane[2] * buffer[2]);
// 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 = &sector[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;
bglMatrixMode(GL_TEXTURE);
bglLoadMatrixf(projection);
bglMultMatrixf(modelview);
bglGetFloatv(GL_TEXTURE_MATRIX, matrix);
bglLoadIdentity();
bglMatrixMode(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 << 2;
j = k = plane->vertcount - 1;
do
{
uint32_t jj = j + (j << 2);
k -= ((frustum[ii + 0] * plane->buffer[jj + 0] +
frustum[ii + 1] * plane->buffer[jj + 1] +
frustum[ii + 2] * plane->buffer[jj + 2] +
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, tspritetype* 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)++].owner = i;
}
}
}
void polymer_updatesprite(int32_t snum)
{
int32_t curpicnum, xsize, ysize, i, j;
int32_t tilexoff, tileyoff, xoff, yoff, centeryoff=0;
tspritetype *tspr = tspriteptr[snum];
float xratio, yratio, ang, f;
float spos[3];
const GLfloat *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_verbosity >= 3) OSD_Printf("PR : Updating sprite %i...\n", snum);
if (tspr->owner < 0 || tspr->picnum < 0) return;
if (prsprites[tspr->owner] == NULL)
{
prsprites[tspr->owner] = (_prsprite *)Xcalloc(sizeof(_prsprite), 1);
prsprites[tspr->owner]->plane.buffer = (GLfloat *)Xcalloc(4, sizeof(GLfloat) * 5); // XXX
prsprites[tspr->owner]->plane.vertcount = 4;
}
if ((tspr->cstat & 48) && (pr_vbos > 0) && !prsprites[tspr->owner]->plane.vbo)
{
bglGenBuffersARB(1, &prsprites[tspr->owner]->plane.vbo);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, prsprites[tspr->owner]->plane.vbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, 4 * sizeof(GLfloat) * 5, NULL, mapvbousage);
}
s = prsprites[tspr->owner];
curpicnum = tspr->picnum;
DO_TILE_ANIM(curpicnum, tspr->owner+32768);
if (tspr->cstat & 48 && searchit != 2)
{
uint32_t xxhash = XXH32((uint8_t *)tspr, offsetof(spritetype, owner), 0xDEADBEEF);
if (xxhash == s->hash && tspr->picnum == curpicnum)
return;
s->hash = xxhash;
}
polymer_getbuildmaterial(&s->plane.material, curpicnum, tspr->pal, tspr->shade,
sector[tspr->sectnum].visibility, DAMETH_CLAMPED);
if (tspr->cstat & 2)
{
if (tspr->cstat & 512)
s->plane.material.diffusemodulation[3] = 0x55;
else
s->plane.material.diffusemodulation[3] = 0xAA;
}
f = s->plane.material.diffusemodulation[3] * (1.0f - spriteext[tspr->owner].alpha);
s->plane.material.diffusemodulation[3] = (GLubyte)f;
if (searchit == 2)
{
polymer_drawsearchplane(&s->plane, NULL, 0x03, (GLubyte *) &tspr->owner);
s->hash = 0xDEADBEEF;
}
curpicnum = tspr->picnum;
DO_TILE_ANIM(curpicnum, tspr->owner+32768);
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;
bglMatrixMode(GL_MODELVIEW);
bglPushMatrix();
bglLoadIdentity();
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 = (viewangle + 1024) & 2047;
}
if (flipu)
xoff = -xoff;
if (yflip && alignmask!=0)
yoff = -yoff;
}
switch (tspr->cstat & SPR_ALIGN_MASK)
{
case 0:
ang = (float)((viewangle) & 2047) / (2048.0f / 360.0f);
bglTranslatef(spos[0], spos[1], spos[2]);
bglRotatef(-ang, 0.0f, 1.0f, 0.0f);
bglRotatef(-horizang, 1.0f, 0.0f, 0.0f);
bglTranslatef((float)(-xoff), (float)(yoff), 0.0f);
bglScalef((float)(xsize), (float)(ysize), 1.0f);
break;
case SPR_WALL:
ang = (float)((tspr->ang + 1024) & 2047) / (2048.0f / 360.0f);
bglTranslatef(spos[0], spos[1], spos[2]);
bglRotatef(-ang, 0.0f, 1.0f, 0.0f);
bglTranslatef((float)(-xoff), (float)(yoff-centeryoff), 0.0f);
bglScalef((float)(xsize), (float)(ysize), 1.0f);
break;
case SPR_FLOOR:
ang = (float)((tspr->ang + 1024) & 2047) / (2048.0f / 360.0f);
bglTranslatef(spos[0], spos[1], spos[2]);
bglRotatef(-ang, 0.0f, 1.0f, 0.0f);
bglTranslatef((float)(-xoff), 1.0f, (float)(yoff));
bglScalef((float)(xsize), 1.0f, (float)(ysize));
inbuffer = horizsprite;
break;
}
bglGetFloatv(GL_MODELVIEW_MATRIX, spritemodelview);
bglPopMatrix();
Bmemcpy(s->plane.buffer, inbuffer, sizeof(GLfloat) * 4 * 5);
if (flipu || flipv)
{
i = 0;
do
{
if (flipu)
s->plane.buffer[(i * 5) + 3] =
(s->plane.buffer[(i * 5) + 3] - 1.0f) * -1.0f;
if (flipv)
s->plane.buffer[(i * 5) + 4] =
(s->plane.buffer[(i * 5) + 4] - 1.0f) * -1.0f;
}
while (++i < 4);
}
i = 0;
do
polymer_transformpoint(&inbuffer[i * 5], &s->plane.buffer[i * 5], spritemodelview);
while (++i < 4);
polymer_computeplane(&s->plane);
if (alignmask && (pr_vbos > 0))
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, s->plane.vbo);
bglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 4 * sizeof(GLfloat) * 5, s->plane.buffer);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
else if (s->plane.vbo) // clean up the vbo if a wall/floor sprite becomes a face sprite
{
bglDeleteBuffersARB(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);
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] = (float)globalposy;
pos[1] = -(float)(globalposz) / 16.0f;
pos[2] = -(float)globalposx;
bglPushMatrix();
bglLoadIdentity();
bglLoadMatrixf(curskymodelviewmatrix);
bglTranslatef(pos[0], pos[1], pos[2]);
bglScalef(1000.0f, 1000.0f, 1000.0f);
drawingskybox = 1;
pth = texcache_fetch(tilenum,0,0,0);
drawingskybox = 0;
if (pth && (pth->flags & PTH_SKYBOX))
polymer_drawskybox(tilenum, palnum, shade);
else
polymer_drawartsky(tilenum, palnum, shade);
bglPopMatrix();
}
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);
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, 0);
glpics[i] = pth ? pth->glpic : 0;
glcolors[i][0] = glcolors[i][1] = glcolors[i][2] = getshadefactor(shade);
if (pth)
{
// tinting
if (!(hictinting[palnum].f & HICTINT_PRECOMPUTED))
{
if (pth->flags & PTH_HIGHTILE)
{
if (pth->palnum != palnum || (pth->effects & HICTINT_IN_MEMORY) || (hictinting[palnum].f & HICTINT_APPLYOVERALTPAL))
hictinting_apply(glcolors[i], palnum);
}
else if (hictinting[palnum].f & HICTINT_USEONART)
hictinting_apply(glcolors[i], palnum);
}
// global tinting
if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
hictinting_apply(glcolors[i], MAXPALOOKUPS-1);
}
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];
bglColor4f(glcolors[tileofs][0], glcolors[tileofs][1], glcolors[tileofs][2], 1.0f);
bglBindTexture(GL_TEXTURE_2D, glpics[tileofs]);
bglGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &oldswrap);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
polymer_drawartskyquad(i, (i + 1) & (j - 1), height);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, oldswrap);
i++;
}
}
static void polymer_drawartskyquad(int32_t p1, int32_t p2, GLfloat height)
{
bglBegin(GL_QUADS);
bglTexCoord2f(0.0f, 0.0f);
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p1 * 2) + 1], height, skybox[p1 * 2]);
bglVertex3f(artskydata[(p1 * 2) + 1], height, artskydata[p1 * 2]);
bglTexCoord2f(0.0f, 1.0f);
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p1 * 2) + 1], -height, skybox[p1 * 2]);
bglVertex3f(artskydata[(p1 * 2) + 1], -height, artskydata[p1 * 2]);
bglTexCoord2f(1.0f, 1.0f);
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p2 * 2) + 1], -height, skybox[p2 * 2]);
bglVertex3f(artskydata[(p2 * 2) + 1], -height, artskydata[p2 * 2]);
bglTexCoord2f(1.0f, 0.0f);
//OSD_Printf("PR: drawing %f %f %f\n", skybox[(p2 * 2) + 1], height, skybox[p2 * 2]);
bglVertex3f(artskydata[(p2 * 2) + 1], height, artskydata[p2 * 2]);
bglEnd();
}
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))
{
bglGenBuffersARB(1, &skyboxdatavbo);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, skyboxdatavbo);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, 4 * sizeof(GLfloat) * 5 * 6, skyboxdata, modelvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
if (pr_vbos > 0)
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 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
if (!(hictinting[palnum].f & HICTINT_PRECOMPUTED))
{
if (pth->flags & PTH_HIGHTILE)
{
if (pth->palnum != palnum || (pth->effects & HICTINT_IN_MEMORY) || (hictinting[palnum].f & HICTINT_APPLYOVERALTPAL))
hictinting_apply(color, palnum);
}
else if (hictinting[palnum].f & HICTINT_USEONART)
hictinting_apply(color, palnum);
}
// global tinting
if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
hictinting_apply(color, MAXPALOOKUPS-1);
}
bglColor4f(color[0], color[1], color[2], 1.0);
bglBindTexture(GL_TEXTURE_2D, pth ? pth->glpic : 0);
if (pr_vbos > 0)
{
bglVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(4 * 5 * i * sizeof(GLfloat)));
bglTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), (GLfloat*)(((4 * 5 * i) + 3) * sizeof(GLfloat)));
} else {
bglVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), &skyboxdata[4 * 5 * i]);
bglTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), &skyboxdata[3 + (4 * 5 * i)]);
}
bglDrawArrays(GL_QUADS, 0, 4);
i++;
}
drawingskybox = 0;
if (pr_vbos > 0)
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
return;
}
// MDSPRITES
static void polymer_drawmdsprite(tspritetype *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] = (float)globalposy;
spos[1] = -(float)(globalposz) / 16.0f;
spos[2] = -(float)globalposx;
// 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] = (float)y - globalposy;
spos2[1] = -(float)(z - globalposz) / 16.0f;
spos2[2] = -(float)(x - globalposx);
} 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) / (2048.0f / 360.0f);
ang -= 90.0f;
if (((tspr->cstat>>4) & 3) == 2)
ang -= 90.0f;
bglMatrixMode(GL_MODELVIEW);
bglPushMatrix();
bglLoadIdentity();
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) / (2048.0f / 360.0f) - 90.0f;
radplayerang = (globalang & 2047) * 2.0f * PI / 2048.0f;
cosminusradplayerang = cos(-radplayerang);
sinminusradplayerang = sin(-radplayerang);
hudzoom = 65536.0 / spriteext[tspr->owner].offset.z;
bglTranslatef(spos[0], spos[1], spos[2]);
bglRotatef(horizang, -cosminusradplayerang, 0.0f, sinminusradplayerang);
bglRotatef(spriteext[tspr->owner].roll / (2048.0f / 360.0f), sinminusradplayerang, 0.0f, cosminusradplayerang);
bglRotatef(-playerang, 0.0f, 1.0f, 0.0f);
bglScalef(hudzoom, 1.0f, 1.0f);
bglRotatef(playerang, 0.0f, 1.0f, 0.0f);
bglTranslatef(spos2[0], spos2[1], spos2[2]);
bglRotatef(-ang, 0.0f, 1.0f, 0.0f);
} else {
bglTranslatef(spos[0], spos[1], spos[2]);
bglRotatef(-ang, 0.0f, 1.0f, 0.0f);
}
if (((tspr->cstat>>4) & 3) == 2)
{
bglTranslatef(0.0f, 0.0, -(float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 8.0f);
bglRotatef(90.0f, 0.0f, 0.0f, 1.0f);
}
else
bglRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
if ((tspr->cstat & 128) && (((tspr->cstat>>4) & 3) != 2))
bglTranslatef(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
bglTranslatef(0.0f, 0.0, m->yoffset * 64 * scale * tspr->yrepeat);
if (tspr->cstat & 8)
{
bglTranslatef(0.0f, 0.0, (float)(tilesiz[tspr->picnum].y * tspr->yrepeat) / 4.0f);
bglScalef(1.0f, 1.0f, -1.0f);
}
if (tspr->cstat & 4)
bglScalef(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;
}
bglScalef(scale * tspr->xrepeat, scale * tspr->xrepeat, scale * tspr->yrepeat);
bglTranslatef(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) / (2048.0f / 360.0f);
rollang = (float)(spriteext[tspr->owner].roll) / (2048.0f / 360.0f);
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);
bglTranslatef(-offsets[0], -offsets[1], -offsets[2]);
bglRotatef(pitchang, 0.0f, 1.0f, 0.0f);
bglRotatef(rollang, -1.0f, 0.0f, 0.0f);
bglTranslatef(offsets[0], offsets[1], offsets[2]);
}
bglGetFloatv(GL_MODELVIEW_MATRIX, spritemodelview);
bglPopMatrix();
bglPushMatrix();
bglMultMatrixf(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
// bglDisable(GL_TEXTURE_2D);
// bglBegin(GL_LINES);
// bglColor4f(1.0, 0.0, 0.0, 1.0);
// bglVertex3f(m->head.frames[m->cframe].cen.x,
// m->head.frames[m->cframe].cen.y,
// m->head.frames[m->cframe].cen.z);
// bglVertex3f(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);
// bglColor4f(0.0, 1.0, 0.0, 1.0);
// bglVertex3f(m->head.frames[m->cframe].cen.x,
// m->head.frames[m->cframe].cen.y,
// m->head.frames[m->cframe].cen.z);
// bglVertex3f(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);
// bglColor4f(0.0, 0.0, 1.0, 1.0);
// bglVertex3f(m->head.frames[m->cframe].cen.x,
// m->head.frames[m->cframe].cen.y,
// m->head.frames[m->cframe].cen.z);
// bglVertex3f(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);
// bglEnd();
// bglEnable(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
if (!usinghighpal && !(hictinting[tspr->pal].f & 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);
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
// bglDisable(GL_TEXTURE_2D);
// bglBegin(GL_LINES);
// bglColor4f(1.0, 1.0, 1.0, 1.0);
//
// int i = 0;
// while (i < s->numverts)
// {
// bglVertex3f(v0[(i * 6) + 0],
// v0[(i * 6) + 1],
// v0[(i * 6) + 2]);
// bglVertex3f(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++;
// }
// bglEnd();
// bglEnable(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->cstat&CSTAT_SPRITE_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;
}
if (!(tspr->cstat&CSTAT_SPRITE_MDHACK))
{
mdspritematerial.specmap =
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,SPECULARPAL,surfi);
}
if (!(tspr->cstat&CSTAT_SPRITE_MDHACK))
{
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;
}
}
if (!(tspr->cstat&CSTAT_SPRITE_MDHACK))
{
mdspritematerial.glowmap =
mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,GLOWPAL,surfi);
}
bglEnableClientState(GL_NORMAL_ARRAY);
if (pr_vbos > 1)
{
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, m->texcoords[surfi]);
bglTexCoordPointer(2, GL_FLOAT, 0, 0);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, m->geometry[surfi]);
bglVertexPointer(3, GL_FLOAT, sizeof(float) * 15, (GLfloat*)(m->cframe * s->numverts * sizeof(float) * 15));
bglNormalPointer(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);
}
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m->indices[surfi]);
curlight = 0;
do {
materialbits = polymer_bindmaterial(&mdspritematerial, modellights, modellightcount);
bglDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_INT, 0);
polymer_unbindmaterial(materialbits);
} while ((++curlight < modellightcount) && (curlight < pr_maxlightpasses));
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
else
{
bglVertexPointer(3, GL_FLOAT, sizeof(float) * 15, v0);
bglNormalPointer(GL_FLOAT, sizeof(float) * 15, v0 + 3);
bglTexCoordPointer(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);
bglDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_INT, s->tris);
polymer_unbindmaterial(materialbits);
} while ((++curlight < modellightcount) && (curlight < pr_maxlightpasses));
}
bglDisableClientState(GL_NORMAL_ARRAY);
}
bglPopMatrix();
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));
bglGenBuffersARB(m->head.numsurfs, m->indices);
bglGenBuffersARB(m->head.numsurfs, m->texcoords);
bglGenBuffersARB(m->head.numsurfs, m->geometry);
i = 0;
while (i < m->head.numsurfs)
{
s = &m->head.surfs[i];
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m->indices[i]);
bglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, s->numtris * sizeof(md3tri_t), s->tris, modelvbousage);
bglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, m->texcoords[i]);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, s->numverts * sizeof(md3uv_t), s->uv, modelvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, m->geometry[i]);
bglBufferDataARB(GL_ARRAY_BUFFER_ARB, s->numframes * s->numverts * sizeof(float) * (15), s->geometry, modelvbousage);
bglBindBufferARB(GL_ARRAY_BUFFER_ARB, 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_getbuildmaterial(_prmaterial* material, int16_t tilenum, char pal, int8_t shade, int8_t vis, int32_t cmeth)
{
pthtyp* pth;
int32_t usinghighpal = 0;
polymer_getscratchmaterial(material);
if (!waloff[tilenum])
loadtile(tilenum);
// PR_BIT_DIFFUSE_MAP
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;
}
}
// 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)) {
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++;
}
bglGenTextures(1, &prartmaps[tilenum]);
bglBindTexture(GL_TEXTURE_2D, prartmaps[tilenum]);
bglTexImage2D(GL_TEXTURE_2D,
0,
GL_R8,
tilesiz[tilenum].x,
tilesiz[tilenum].y,
0,
GL_RED,
GL_UNSIGNED_BYTE,
tempbuffer);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
bglBindTexture(GL_TEXTURE_2D, 0);
Bfree(tempbuffer);
}
if (!prbasepalmaps[curbasepal]) {
bglGenTextures(1, &prbasepalmaps[curbasepal]);
bglBindTexture(GL_TEXTURE_2D, prbasepalmaps[curbasepal]);
bglTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
256,
1,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
basepaltableptr[curbasepal]);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglBindTexture(GL_TEXTURE_2D, 0);
}
if (!prlookups[pal]) {
bglGenTextures(1, &prlookups[pal]);
bglBindTexture(GL_TEXTURE_RECTANGLE, prlookups[pal]);
bglTexImage2D(GL_TEXTURE_RECTANGLE,
0,
GL_R8,
256,
numshades,
0,
GL_RED,
GL_UNSIGNED_BYTE,
palookup[pal]);
bglTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglBindTexture(GL_TEXTURE_RECTANGLE, 0);
}
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) / 16.0f);
return;
}
// 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
if (!(hictinting[pal].f & HICTINT_PRECOMPUTED))
{
if (pth->flags & PTH_HIGHTILE)
{
if (pth->palnum != pal || (pth->effects & HICTINT_IN_MEMORY) || (hictinting[pal].f & HICTINT_APPLYOVERALTPAL))
hictinting_apply_ub(material->diffusemodulation, pal);
}
else if (hictinting[pal].f & HICTINT_USEONART)
hictinting_apply_ub(material->diffusemodulation, pal);
}
// global tinting
if ((pth->flags & PTH_HIGHTILE) && !usinghighpal && have_basepal_tint())
hictinting_apply_ub(material->diffusemodulation, MAXPALOOKUPS-1);
// 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) && (pth = texcache_fetch(tilenum, DETAILPAL, 0, 0)) &&
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) && (pth = texcache_fetch(tilenum, GLOWPAL, 0, 0)) &&
pth->hicr && (pth->hicr->palnum == GLOWPAL))
material->glowmap = pth->glpic;
// PR_BIT_SPECULAR_MAP
if (hicfindsubst(tilenum, SPECULARPAL) && (pth = texcache_fetch(tilenum, SPECULARPAL, 0, 0)) &&
pth->hicr && (pth->hicr->palnum == SPECULARPAL))
material->specmap = pth->glpic;
// PR_BIT_NORMAL_MAP
if (hicfindsubst(tilenum, NORMALPAL) && (pth = texcache_fetch(tilenum, NORMALPAL, 0, 0)) &&
pth->hicr && (pth->hicr->palnum == NORMALPAL))
{
material->normalmap = pth->glpic;
material->normalbias[0] = pth->hicr->specpower;
material->normalbias[1] = pth->hicr->specfactor;
}
}
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);
bglUseProgramObjectARB(prprograms[programbits].handle);
// --------- bit setup
texunit = 0;
// PR_BIT_ANIM_INTERPOLATION
if (programbits & prprogrambits[PR_BIT_ANIM_INTERPOLATION].bit)
{
bglEnableVertexAttribArrayARB(prprograms[programbits].attrib_nextFrameData);
if (prprograms[programbits].attrib_nextFrameNormal != -1)
bglEnableVertexAttribArrayARB(prprograms[programbits].attrib_nextFrameNormal);
bglVertexAttribPointerARB(prprograms[programbits].attrib_nextFrameData,
3, GL_FLOAT, GL_FALSE,
sizeof(float) * 15,
material->nextframedata);
if (prprograms[programbits].attrib_nextFrameNormal != -1)
bglVertexAttribPointerARB(prprograms[programbits].attrib_nextFrameNormal,
3, GL_FLOAT, GL_FALSE,
sizeof(float) * 15,
material->nextframedata + 3);
bglUniform1fARB(prprograms[programbits].uniform_frameProgress, material->frameprogress);
}
// PR_BIT_LIGHTING_PASS
if (programbits & prprogrambits[PR_BIT_LIGHTING_PASS].bit)
{
bglPushAttrib(GL_COLOR_BUFFER_BIT);
bglEnable(GL_BLEND);
bglBlendFunc(GL_ONE, GL_ONE);
if (prlights[lights[curlight]].publicflags.negative) {
bglBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
}
}
// PR_BIT_NORMAL_MAP
if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
{
float pos[3], bias[2];
pos[0] = (float)globalposy;
pos[1] = -(float)(globalposz) / 16.0f;
pos[2] = -(float)globalposx;
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->normalmap);
if (material->mdspritespace == GL_TRUE) {
float mdspritespacepos[3];
polymer_transformpoint(pos, mdspritespacepos, (float *)mdspritespace);
bglUniform3fvARB(prprograms[programbits].uniform_eyePosition, 1, mdspritespacepos);
} else
bglUniform3fvARB(prprograms[programbits].uniform_eyePosition, 1, pos);
bglUniform1iARB(prprograms[programbits].uniform_normalMap, texunit);
if (pr_overrideparallax) {
bias[0] = pr_parallaxscale;
bias[1] = pr_parallaxbias;
bglUniform2fvARB(prprograms[programbits].uniform_normalBias, 1, bias);
} else
bglUniform2fvARB(prprograms[programbits].uniform_normalBias, 1, material->normalbias);
if (material->tbn) {
bglEnableVertexAttribArrayARB(prprograms[programbits].attrib_T);
bglEnableVertexAttribArrayARB(prprograms[programbits].attrib_B);
bglEnableVertexAttribArrayARB(prprograms[programbits].attrib_N);
bglVertexAttribPointerARB(prprograms[programbits].attrib_T,
3, GL_FLOAT, GL_FALSE,
sizeof(float) * 15,
material->tbn);
bglVertexAttribPointerARB(prprograms[programbits].attrib_B,
3, GL_FLOAT, GL_FALSE,
sizeof(float) * 15,
material->tbn + 3);
bglVertexAttribPointerARB(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)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->artmap);
bglUniform1iARB(prprograms[programbits].uniform_artMap, texunit);
texunit++;
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->basepalmap);
bglUniform1iARB(prprograms[programbits].uniform_basePalMap, texunit);
texunit++;
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_RECTANGLE, material->lookupmap);
bglUniform1iARB(prprograms[programbits].uniform_lookupMap, texunit);
texunit++;
bglUniform1fARB(prprograms[programbits].uniform_shadeOffset, (GLfloat)material->shadeoffset);
bglUniform1fARB(prprograms[programbits].uniform_visibility, globalvisibility/2048.0 * material->visibility);
}
// PR_BIT_DIFFUSE_MAP
if (programbits & prprogrambits[PR_BIT_DIFFUSE_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->diffusemap);
bglUniform1iARB(prprograms[programbits].uniform_diffuseMap, texunit);
bglUniform2fvARB(prprograms[programbits].uniform_diffuseScale, 1, material->diffusescale);
texunit++;
}
// PR_BIT_HIGHPALOOKUP_MAP
if (programbits & prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_3D, material->highpalookupmap);
bglUniform1iARB(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];
}
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->detailmap);
bglUniform1iARB(prprograms[programbits].uniform_detailMap, texunit);
bglUniform2fvARB(prprograms[programbits].uniform_detailScale, 1, scale);
texunit++;
}
// PR_BIT_DIFFUSE_MODULATION
if (programbits & prprogrambits[PR_BIT_DIFFUSE_MODULATION].bit)
{
bglColor4ub(material->diffusemodulation[0],
material->diffusemodulation[1],
material->diffusemodulation[2],
material->diffusemodulation[3]);
}
// PR_BIT_SPECULAR_MAP
if (programbits & prprogrambits[PR_BIT_SPECULAR_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->specmap);
bglUniform1iARB(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;
bglUniform2fvARB(prprograms[programbits].uniform_specMaterial, 1, specmaterial);
} else
bglUniform2fvARB(prprograms[programbits].uniform_specMaterial, 1, material->specmaterial);
}
// PR_BIT_MIRROR_MAP
if (programbits & prprogrambits[PR_BIT_MIRROR_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_RECTANGLE, material->mirrormap);
bglUniform1iARB(prprograms[programbits].uniform_mirrorMap, texunit);
texunit++;
}
#ifdef PR_LINEAR_FOG
if (programbits & prprogrambits[PR_BIT_FOG].bit)
{
bglUniform1iARB(prprograms[programbits].uniform_linearFog, r_usenewshading >= 2);
}
#endif
// PR_BIT_GLOW_MAP
if (programbits & prprogrambits[PR_BIT_GLOW_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, material->glowmap);
bglUniform1iARB(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]);
bglUniform3fvARB(prprograms[programbits].uniform_spotDir, 1, dir);
bglUniform2fvARB(prprograms[programbits].uniform_spotRadius, 1, indir);
// PR_BIT_PROJECTION_MAP
if (programbits & prprogrambits[PR_BIT_PROJECTION_MAP].bit)
{
GLfloat matrix[16];
bglMatrixMode(GL_TEXTURE);
bglLoadMatrixf(shadowBias);
bglMultMatrixf(prlights[lights[curlight]].proj);
bglMultMatrixf(prlights[lights[curlight]].transform);
if (material->mdspritespace == GL_TRUE)
bglMultMatrixf(spritemodelview);
bglGetFloatv(GL_TEXTURE_MATRIX, matrix);
bglLoadIdentity();
bglMatrixMode(GL_MODELVIEW);
bglUniformMatrix4fvARB(prprograms[programbits].uniform_shadowProjMatrix, 1, GL_FALSE, matrix);
// PR_BIT_SHADOW_MAP
if (programbits & prprogrambits[PR_BIT_SHADOW_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(prrts[prlights[lights[curlight]].rtindex].target, prrts[prlights[lights[curlight]].rtindex].z);
bglUniform1iARB(prprograms[programbits].uniform_shadowMap, texunit);
texunit++;
}
// PR_BIT_LIGHT_MAP
if (programbits & prprogrambits[PR_BIT_LIGHT_MAP].bit)
{
bglActiveTextureARB(texunit + GL_TEXTURE0_ARB);
bglBindTexture(GL_TEXTURE_2D, prlights[lights[curlight]].lightmap);
bglUniform1iARB(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];
}
bglLightfv(GL_LIGHT0, GL_AMBIENT, pos);
bglLightfv(GL_LIGHT0, GL_DIFFUSE, color);
if (material->mdspritespace == GL_TRUE) {
float mdspritespacepos[3];
polymer_transformpoint(inpos, mdspritespacepos, (float *)mdspritespace);
bglLightfv(GL_LIGHT0, GL_SPECULAR, mdspritespacepos);
} else {
bglLightfv(GL_LIGHT0, GL_SPECULAR, inpos);
}
bglLightfv(GL_LIGHT0, GL_LINEAR_ATTENUATION, &range[1]);
}
bglActiveTextureARB(GL_TEXTURE0_ARB);
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)
bglDisableVertexAttribArrayARB(prprograms[programbits].attrib_nextFrameNormal);
bglDisableVertexAttribArrayARB(prprograms[programbits].attrib_nextFrameData);
}
// PR_BIT_LIGHTING_PASS
if (programbits & prprogrambits[PR_BIT_LIGHTING_PASS].bit)
{
bglPopAttrib();
}
// PR_BIT_NORMAL_MAP
if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
{
bglDisableVertexAttribArrayARB(prprograms[programbits].attrib_T);
bglDisableVertexAttribArrayARB(prprograms[programbits].attrib_B);
bglDisableVertexAttribArrayARB(prprograms[programbits].attrib_N);
}
bglUseProgramObjectARB(0);
}
static void polymer_compileprogram(int32_t programbits)
{
int32_t i, enabledbits;
GLhandleARB vert, frag, program;
const GLcharARB* source[PR_BIT_COUNT * 2];
GLcharARB infobuffer[PR_INFO_LOG_BUFFER_SIZE];
GLint linkstatus;
// --------- VERTEX
vert = bglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
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++;
}
bglShaderSourceARB(vert, enabledbits, source, NULL);
bglCompileShaderARB(vert);
// --------- FRAGMENT
frag = bglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
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++;
}
bglShaderSourceARB(frag, enabledbits, (const GLcharARB**)source, NULL);
bglCompileShaderARB(frag);
// --------- PROGRAM
program = bglCreateProgramObjectARB();
bglAttachObjectARB(program, vert);
bglAttachObjectARB(program, frag);
bglLinkProgramARB(program);
bglGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linkstatus);
bglGetInfoLogARB(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);
bglGetShaderSourceARB(vert, PR_INFO_LOG_BUFFER_SIZE, NULL, infobuffer);
if (pr_verbosity >= 1) OSD_Printf("PR : Vertex source dump:\n%s\n", infobuffer);
bglGetShaderSourceARB(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 = bglGetAttribLocationARB(program, "nextFrameData");
prprograms[programbits].attrib_nextFrameNormal = bglGetAttribLocationARB(program, "nextFrameNormal");
prprograms[programbits].uniform_frameProgress = bglGetUniformLocationARB(program, "frameProgress");
}
// PR_BIT_NORMAL_MAP
if (programbits & prprogrambits[PR_BIT_NORMAL_MAP].bit)
{
prprograms[programbits].attrib_T = bglGetAttribLocationARB(program, "T");
prprograms[programbits].attrib_B = bglGetAttribLocationARB(program, "B");
prprograms[programbits].attrib_N = bglGetAttribLocationARB(program, "N");
prprograms[programbits].uniform_eyePosition = bglGetUniformLocationARB(program, "eyePosition");
prprograms[programbits].uniform_normalMap = bglGetUniformLocationARB(program, "normalMap");
prprograms[programbits].uniform_normalBias = bglGetUniformLocationARB(program, "normalBias");
}
// PR_BIT_ART_MAP
if (programbits & prprogrambits[PR_BIT_ART_MAP].bit)
{
prprograms[programbits].uniform_artMap = bglGetUniformLocationARB(program, "artMap");
prprograms[programbits].uniform_basePalMap = bglGetUniformLocationARB(program, "basePalMap");
prprograms[programbits].uniform_lookupMap = bglGetUniformLocationARB(program, "lookupMap");
prprograms[programbits].uniform_shadeOffset = bglGetUniformLocationARB(program, "shadeOffset");
prprograms[programbits].uniform_visibility = bglGetUniformLocationARB(program, "visibility");
}
// PR_BIT_DIFFUSE_MAP
if (programbits & prprogrambits[PR_BIT_DIFFUSE_MAP].bit)
{
prprograms[programbits].uniform_diffuseMap = bglGetUniformLocationARB(program, "diffuseMap");
prprograms[programbits].uniform_diffuseScale = bglGetUniformLocationARB(program, "diffuseScale");
}
// PR_BIT_HIGHPALOOKUP_MAP
if (programbits & prprogrambits[PR_BIT_HIGHPALOOKUP_MAP].bit)
{
prprograms[programbits].uniform_highPalookupMap = bglGetUniformLocationARB(program, "highPalookupMap");
}
// PR_BIT_DIFFUSE_DETAIL_MAP
if (programbits & prprogrambits[PR_BIT_DIFFUSE_DETAIL_MAP].bit)
{
prprograms[programbits].uniform_detailMap = bglGetUniformLocationARB(program, "detailMap");
prprograms[programbits].uniform_detailScale = bglGetUniformLocationARB(program, "detailScale");
}
// PR_BIT_SPECULAR_MAP
if (programbits & prprogrambits[PR_BIT_SPECULAR_MAP].bit)
{
prprograms[programbits].uniform_specMap = bglGetUniformLocationARB(program, "specMap");
}
// PR_BIT_SPECULAR_MATERIAL
if (programbits & prprogrambits[PR_BIT_SPECULAR_MATERIAL].bit)
{
prprograms[programbits].uniform_specMaterial = bglGetUniformLocationARB(program, "specMaterial");
}
// PR_BIT_MIRROR_MAP
if (programbits & prprogrambits[PR_BIT_MIRROR_MAP].bit)
{
prprograms[programbits].uniform_mirrorMap = bglGetUniformLocationARB(program, "mirrorMap");
}
#ifdef PR_LINEAR_FOG
if (programbits & prprogrambits[PR_BIT_FOG].bit)
{
prprograms[programbits].uniform_linearFog = bglGetUniformLocationARB(program, "linearFog");
}
#endif
// PR_BIT_GLOW_MAP
if (programbits & prprogrambits[PR_BIT_GLOW_MAP].bit)
{
prprograms[programbits].uniform_glowMap = bglGetUniformLocationARB(program, "glowMap");
}
// PR_BIT_PROJECTION_MAP
if (programbits & prprogrambits[PR_BIT_PROJECTION_MAP].bit)
{
prprograms[programbits].uniform_shadowProjMatrix = bglGetUniformLocationARB(program, "shadowProjMatrix");
}
// PR_BIT_SHADOW_MAP
if (programbits & prprogrambits[PR_BIT_SHADOW_MAP].bit)
{
prprograms[programbits].uniform_shadowMap = bglGetUniformLocationARB(program, "shadowMap");
}
// PR_BIT_LIGHT_MAP
if (programbits & prprogrambits[PR_BIT_LIGHT_MAP].bit)
{
prprograms[programbits].uniform_lightMap = bglGetUniformLocationARB(program, "lightMap");
}
// PR_BIT_SPOT_LIGHT
if (programbits & prprogrambits[PR_BIT_SPOT_LIGHT].bit)
{
prprograms[programbits].uniform_spotDir = bglGetUniformLocationARB(program, "spotDir");
prprograms[programbits].uniform_spotRadius = bglGetUniformLocationARB(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, 0);
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 * 5) + i] > (lightpos[i] + light->range)) k++;
if (plane->buffer[(j * 5) + 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 = &sector[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) / (2048.0f / 360.0f);
ang = (float)(light->angle) / (2048.0f / 360.0f);
horizang = (float)(-getangle(128, light->horiz-100)) / (2048.0f / 360.0f);
bglMatrixMode(GL_PROJECTION);
bglPushMatrix();
bglLoadIdentity();
bgluPerspective(radius * 2, 1, 0.1f, light->range / 1000.0f);
bglGetFloatv(GL_PROJECTION_MATRIX, light->proj);
bglPopMatrix();
bglMatrixMode(GL_MODELVIEW);
bglPushMatrix();
bglLoadIdentity();
bglRotatef(horizang, 1.0f, 0.0f, 0.0f);
bglRotatef(ang, 0.0f, 1.0f, 0.0f);
bglScalef(1.0f / 1000.0f, 1.0f / 1000.0f, 1.0f / 1000.0f);
bglTranslatef(-lightpos[0], -lightpos[1], -lightpos[2]);
bglGetFloatv(GL_MODELVIEW_MATRIX, light->transform);
bglPopMatrix();
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 = &sector[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 * 5) + 1] >= w->mask.buffer[(3 * 5) + 1]) &&
(w->mask.buffer[(1 * 5) + 1] >= w->mask.buffer[(2 * 5) + 1]))
{
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)
{
int16_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 = globalang;
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);
bglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[prlights[i].rtindex].fbo);
bglPushAttrib(GL_VIEWPORT_BIT);
bglViewport(0, 0, prrts[prlights[i].rtindex].xdim, prrts[prlights[i].rtindex].ydim);
bglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
bglMatrixMode(GL_PROJECTION);
bglPushMatrix();
bglLoadMatrixf(prlights[i].proj);
bglMatrixMode(GL_MODELVIEW);
bglLoadMatrixf(prlights[i].transform);
bglEnable(GL_POLYGON_OFFSET_FILL);
bglPolygonOffset(5, SHADOW_DEPTH_OFFSET);
set_globalpos(prlights[i].x, prlights[i].y, prlights[i].z);
// build globals used by rotatesprite
viewangle = prlights[i].angle;
set_globalang(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;
bglDisable(GL_POLYGON_OFFSET_FILL);
bglMatrixMode(GL_PROJECTION);
bglPopMatrix();
bglPopAttrib();
bglBindFramebufferEXT(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)
{
bglDeleteTextures(1, &prrts[i].color);
prrts[i].color = 0;
}
bglDeleteTextures(1, &prrts[i].z);
prrts[i].z = 0;
bglDeleteFramebuffersEXT(1, &prrts[i].fbo);
prrts[i].fbo = 0;
}
Bfree(prrts);
prrts = NULL;
}
ocount = 0;
return;
}
ocount = count;
//////////
prrts = (_prrt *)Xcalloc(count, sizeof(_prrt));
i = 0;
while (i < count)
{
if (!i) {
prrts[i].target = GL_TEXTURE_RECTANGLE;
prrts[i].xdim = xdim;
prrts[i].ydim = ydim;
bglGenTextures(1, &prrts[i].color);
bglBindTexture(prrts[i].target, prrts[i].color);
bglTexImage2D(prrts[i].target, 0, GL_RGB, prrts[i].xdim, prrts[i].ydim, 0, GL_RGB, GL_SHORT, NULL);
bglTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bglTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bglTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(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) {
bglGenTextures(1, &prrts[i].color);
bglBindTexture(prrts[i].target, prrts[i].color);
bglTexImage2D(prrts[i].target, 0, GL_RGB, prrts[i].xdim, prrts[i].ydim, 0, GL_RGB, GL_SHORT, NULL);
bglTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bglTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bglTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
}
}
bglGenTextures(1, &prrts[i].z);
bglBindTexture(prrts[i].target, prrts[i].z);
bglTexImage2D(prrts[i].target, 0, GL_DEPTH_COMPONENT, prrts[i].xdim, prrts[i].ydim, 0, GL_DEPTH_COMPONENT, GL_SHORT, NULL);
bglTexParameteri(prrts[i].target, GL_TEXTURE_MIN_FILTER, pr_shadowfiltering ? GL_LINEAR : GL_NEAREST);
bglTexParameteri(prrts[i].target, GL_TEXTURE_MAG_FILTER, pr_shadowfiltering ? GL_LINEAR : GL_NEAREST);
bglTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(prrts[i].target, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
bglTexParameteri(prrts[i].target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
bglTexParameteri(prrts[i].target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
bglTexParameteri(prrts[i].target, GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
bglGenFramebuffersEXT(1, &prrts[i].fbo);
bglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prrts[i].fbo);
if (prrts[i].color)
bglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
prrts[i].target, prrts[i].color, 0);
else {
bglDrawBuffer(GL_NONE);
bglReadBuffer(GL_NONE);
}
bglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, prrts[i].target, prrts[i].z, 0);
if (bglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
OSD_Printf("PR : FBO #%d initialization failed.\n", i);
}
bglBindTexture(prrts[i].target, 0);
bglBindFramebufferEXT(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);
OSD_Printf("PR : Received OpenGL debug message: %s\n", message);
}
#endif