// 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
= *(int16_t *)(&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
)
{
sectortype
*sec
;
walltype
*wal
;
_prwall
*w
;
GLubyte oldcolor
[4];
if (pr_verbosity
>= 3) OSD_Printf
("PR : Masked wall %i...\n", damaskwallcnt
);
sec
= §or
[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 sectortype
*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
= §or
[tspr
->sectnum
];
calc_and_apply_fog
(tspr
->picnum
, fogpal_shade
(sec
, tspr
->shade
), sec
->visibility
,
get_floor_fogpal
(§or
[tspr
->sectnum
]));
if (usemodels
&& tile2model
[Ptile2tile
(tspr
->picnum
,tspr
->pal
)].
modelid >= 0 &&
tile2model
[Ptile2tile
(tspr
->picnum
,tspr
->pal
)].
framenum >= 0 &&
!(spriteext
[tspr
->owner
].
flags & SPREXT_NOTMD
))
{
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
)
{
sectortype
*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
= §or
[sectorqueue
[front
]];
polymer_pokesector
(sectorqueue
[front
]);
polymer_drawsector
(sectorqueue
[front
], FALSE
);
polymer_scansprites
(sectorqueue
[front
], localtsprite
, &localspritesortcnt
);
doquery
= 0;
i
= sec
->wallnum
-1;
do
{
// if we have a level boundary somewhere in the sector,
// consider these walls as visportals
if (wall
[sec
->wallptr
+ i
].
nextsector < 0)
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 = §or[sectorqueue[front]];
//
// polymer_drawsector(sectorqueue[front]);
//
// i = 0;
// while (i < sec->wallnum)
// {
// polymer_drawwall(sectorqueue[front], sec->wallptr + i);
//
// i++;
// }
//
// front++;
// }
i
= mirrorcount
-1;
while (i
>= 0)
{
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
)
{
sectortype
*sec
;
_prsector
* s
;
if (pr_verbosity
>= 2) OSD_Printf
("PR : Initializing sector %i...\n", sectnum
);
sec
= §or
[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
;
sectortype
*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
= §or
[sectnum
];
secangcos
= secangsin
= 2;
if (s
== NULL
)
{
if (pr_verbosity
>= 1) OSD_Printf
("PR : Can't update uninitialized sector %i.\n", sectnum
);
return (-1);
}
needfloor
= wallinvalidate
= 0;
// geometry
wal
= &wall
[sec
->wallptr
];
i
= 0;
while (i
< sec
->wallnum
)
{
if ((-wal
->x
!= s
->verts
[(i
*3)+2]))
{
s
->verts
[(i
*3)+2] = s
->floor.
buffer[(i
*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
;
sectortype
*sec
;
intptr_t i
;
if (pr_verbosity
>= 2) OSD_Printf
("PR : Tesselating floor of sector %i...\n", sectnum
);
s
= prsectors
[sectnum
];
sec
= §or
[sectnum
];
if (s
== NULL
)
return (-1);
if (s
->floor.
indices == NULL
)
{
s
->indicescount
= (max
(3, sec
->wallnum
) - 2) * 3;
s
->floor.
indices = (GLushort
*)Xcalloc
(s
->indicescount
, sizeof(GLushort
));
s
->ceil.
indices = (GLushort
*)Xcalloc
(s
->indicescount
, sizeof(GLushort
));
}
s
->curindice
= 0;
bgluTessCallback
(prtess
, GLU_TESS_VERTEX_DATA
, (void (PR_CALLBACK
*)(void))polymer_tessvertex
);
bgluTessCallback
(prtess
, GLU_TESS_EDGE_FLAG
, (void (PR_CALLBACK
*)(void))polymer_tessedgeflag
);
bgluTessCallback
(prtess
, GLU_TESS_ERROR
, (void (PR_CALLBACK
*)(void))polymer_tesserror
);
bgluTessProperty
(prtess
, GLU_TESS_WINDING_RULE
, GLU_TESS_WINDING_POSITIVE
);
bgluTessBeginPolygon
(prtess
, s
);
bgluTessBeginContour
(prtess
);
i
= 0;
while (i
< sec
->wallnum
)
{
bgluTessVertex
(prtess
, s
->verts
+ (3 * i
), (void *)i
);
if ((i
!= (sec
->wallnum
- 1)) && ((sec
->wallptr
+ i
) > wall
[sec
->wallptr
+ i
].
point2))
{
bgluTessEndContour
(prtess
);
bgluTessBeginContour
(prtess
);
}
i
++;
}
bgluTessEndContour
(prtess
);
bgluTessEndPolygon
(prtess
);
i
= 0;
while (i
< s
->indicescount
)
{
s
->floor.
indices[s
->indicescount
- i
- 1] = s
->ceil.
indices[i
];
i
++;
}
s
->floor.
indicescount = s
->ceil.
indicescount = s
->indicescount
;
if (pr_verbosity
>= 2) OSD_Printf
("PR : Tesselated floor of sector %i.\n", sectnum
);
return (1);
}
static void polymer_drawsector
(int16_t sectnum
, int32_t domasks
)
{
sectortype
*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
= §or
[sectnum
];
s
= prsectors
[sectnum
];
queuedmask
= FALSE
;
// If you're thinking of 'optimizing' the following logic, you'd better
// provide compelling evidence that the generated code is more efficient
// than what GCC can come up with on its own.
draw
= TRUE
;
// Draw masks regardless; avoid all non-masks TROR links
if (sec
->floorstat
& 384) {
draw
= domasks
;
} else if (yax_getbunch
(sectnum
, YAX_FLOOR
) >= 0) {
draw
= FALSE
;
}
// Parallaxed
if (sec
->floorstat
& 1) {
draw
= FALSE
;
}
if (draw
|| (searchit
== 2)) {
if (searchit
== 2) {
polymer_drawsearchplane
(&s
->floor, oldcolor
, 0x02, (GLubyte
*) §num
);
}
else {
calc_and_apply_fog
(sec
->floorpicnum
, 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
*) §num
);
}
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
= §or
[sectofwall
];
if (sectofwall
< 0 || sectofwall
>= numsectors
||
wallnum
< 0 || wallnum
> numwalls
||
sec
->wallptr
> wallnum
|| wallnum
>= (sec
->wallptr
+ sec
->wallnum
))
return; // yay, corrupt map
wal
= &wall
[wallnum
];
nwallnum
= wal
->nextwall
;
w
= prwalls
[wallnum
];
s
= prsectors
[sectofwall
];
invalid
= s
->invalidid
;
if (nwallnum
>= 0 && nwallnum
< numwalls
&& wal
->nextsector
>= 0 && wal
->nextsector
< numsectors
)
{
ns
= prsectors
[wal
->nextsector
];
invalid
+= ns
->invalidid
;
nsec
= §or
[wal
->nextsector
];
}
else
{
ns
= NULL
;
nsec
= NULL
;
}
if (w
->wall.
buffer == NULL
) {
w
->wall.
buffer = (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
)
{
sectortype
*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
= §or
[sectnum
];
wal
= &wall
[wallnum
];
w
= prwalls
[wallnum
];
if ((sec
->floorstat
& 1) && (wal
->nextsector
>= 0) &&
(sector
[wal
->nextsector
].
floorstat & 1))
parallaxedfloor
= 1;
if ((sec
->ceilingstat
& 1) && (wal
->nextsector
>= 0) &&
(sector
[wal
->nextsector
].
ceilingstat & 1))
parallaxedceiling
= 1;
calc_and_apply_fog
(wal
->picnum
, 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
= §or
[sectnum
];
_prsector
*s
= prsectors
[sectnum
];
walltype
*wal
= &wall
[sec
->wallptr
];
int32_t i
= 0;
if (!s
->flags.
uptodate)
polymer_updatesector
(sectnum
);
do
{
if ((wal
->nextsector
>= 0) && (!prsectors
[wal
->nextsector
]->flags.
uptodate))
polymer_updatesector
(wal
->nextsector
);
if (!prwalls
[sec
->wallptr
+ i
]->flags.
uptodate)
polymer_updatewall
(sec
->wallptr
+ i
);
i
++;
wal
= &wall
[sec
->wallptr
+ i
];
}
while (i
< sec
->wallnum
);
}
static void polymer_extractfrustum
(GLfloat
* modelview
, GLfloat
* projection
, float* frustum
)
{
GLfloat matrix
[16];
int32_t i
;
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
&& (pth
->flags
& PTH_HIGHTILE
))
{
if (pth
->palnum
!= palnum
)
hictinting_apply
(glcolors
[i
], palnum
);
if (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
&& (pth
->flags
& PTH_HIGHTILE
))
{
if (pth
->palnum
!= palnum
)
hictinting_apply
(color
, palnum
);
if (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);
// If that palette has a highpalookup, we'll never use tinting. We might use
// alternate skins if they exist later, though.
if (!usinghighpal
&& !(hictinting
[tspr
->pal
].
f & HICTINT_COLORIZE
))
{
if (!(m
->flags
&1) || (!(tspr
->owner
>= MAXSPRITES
) && sector
[sprite
[tspr
->owner
].
sectnum].
floorpal!=0))
hictinting_apply_ub
(color
, tspr
->pal
);
else globalnoeffect
=1; //mdloadskin reads this
}
// fullscreen tint on global palette change
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
]