mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
In-progress POLYMOST2 work
git-svn-id: https://svn.eduke32.com/eduke32@6658 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
a2cf961591
commit
ff1d948d44
1 changed files with 797 additions and 0 deletions
|
@ -1,6 +1,8 @@
|
|||
/**************************************************************************************************
|
||||
"POLYMOST" code originally written by Ken Silverman
|
||||
Ken Silverman's official web site: http://www.advsys.net/ken
|
||||
|
||||
"POLYMOST2" changes Copyright (c) 2018, Alex Dawson
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
|
@ -45,6 +47,7 @@ static float dxb1[MAXWALLSB], dxb2[MAXWALLSB];
|
|||
float shadescale = 1.0f;
|
||||
int32_t shadescale_unbounded = 0;
|
||||
|
||||
int32_t r_enablepolymost2 = 0;
|
||||
int32_t r_usenewshading = 4;
|
||||
int32_t r_usetileshades = 2;
|
||||
int32_t r_npotwallmode = 0;
|
||||
|
@ -118,6 +121,20 @@ int32_t r_downsizevar = -1;
|
|||
static float fogresult, fogresult2;
|
||||
coltypef fogcol, fogtable[MAXPALOOKUPS];
|
||||
|
||||
static GLuint blankTextureID = 0;
|
||||
static GLuint quadVertsID = 0;
|
||||
static GLuint shaderProgramID = 0;
|
||||
static GLint texSamplerLoc = -1;
|
||||
static GLint fullBrightSamplerLoc = -1;
|
||||
static GLint projMatrixLoc = -1;
|
||||
static GLint mvMatrixLoc = -1;
|
||||
static GLint texOffsetLoc = -1;
|
||||
static GLint texScaleLoc = -1;
|
||||
static GLint tintLoc = -1;
|
||||
static GLint alphaLoc = -1;
|
||||
static GLint fogRangeLoc = -1;
|
||||
static GLint fogColorLoc = -1;
|
||||
|
||||
static inline float float_trans(uint32_t maskprops, uint8_t blend)
|
||||
{
|
||||
switch (maskprops)
|
||||
|
@ -279,6 +296,98 @@ float glox1, gloy1, glox2, gloy2;
|
|||
//Use this for both initialization and uninitialization of OpenGL.
|
||||
static int32_t gltexcacnum = -1;
|
||||
|
||||
//in-place multiply m0=m0*m1
|
||||
static float* multiplyMatrix4f(float m0[4*4], float m1[4*4])
|
||||
{
|
||||
float mR[4*4];
|
||||
|
||||
#define multMatrix4RowCol(r, c) mR[r*4+c] = m0[r*4]*m1[c] + m0[r*4+1]*m1[c+4] + m0[r*4+2]*m1[c+8] + m0[r*4+3]*m1[c+12]
|
||||
|
||||
multMatrix4RowCol(0, 0);
|
||||
multMatrix4RowCol(0, 1);
|
||||
multMatrix4RowCol(0, 2);
|
||||
multMatrix4RowCol(0, 3);
|
||||
|
||||
multMatrix4RowCol(1, 0);
|
||||
multMatrix4RowCol(1, 1);
|
||||
multMatrix4RowCol(1, 2);
|
||||
multMatrix4RowCol(1, 3);
|
||||
|
||||
multMatrix4RowCol(2, 0);
|
||||
multMatrix4RowCol(2, 1);
|
||||
multMatrix4RowCol(2, 2);
|
||||
multMatrix4RowCol(2, 3);
|
||||
|
||||
multMatrix4RowCol(3, 0);
|
||||
multMatrix4RowCol(3, 1);
|
||||
multMatrix4RowCol(3, 2);
|
||||
multMatrix4RowCol(3, 3);
|
||||
|
||||
Bmemcpy(m0, mR, sizeof(float)*4*4);
|
||||
|
||||
return m0;
|
||||
|
||||
#undef multMatrix4RowCol
|
||||
}
|
||||
|
||||
static void calcmat(vec3f_t a0, const vec2f_t *offset, float f, float mat[16], int16_t angle)
|
||||
{
|
||||
float g;
|
||||
float k0, k1, k2, k3, k4, k5, k6, k7;
|
||||
|
||||
k0 = a0.y;
|
||||
k1 = a0.x;
|
||||
a0.x += offset->x;
|
||||
a0.z += offset->y;
|
||||
f = gcosang2*gshang;
|
||||
g = gsinang2*gshang;
|
||||
k4 = (float)sintable[(angle+1024)&2047] * (1.f/16384.f);
|
||||
k5 = (float)sintable[(angle+512)&2047] * (1.f/16384.f);
|
||||
k2 = k0*(1-k4)+k1*k5;
|
||||
k3 = k1*(1-k4)-k0*k5;
|
||||
k6 = f*gstang - gsinang*gctang; k7 = g*gstang + gcosang*gctang;
|
||||
mat[0] = k4*k6 + k5*k7; mat[4] = gchang*gstang; mat[ 8] = k4*k7 - k5*k6; mat[12] = k2*k6 + k3*k7;
|
||||
k6 = f*gctang + gsinang*gstang; k7 = g*gctang - gcosang*gstang;
|
||||
mat[1] = k4*k6 + k5*k7; mat[5] = gchang*gctang; mat[ 9] = k4*k7 - k5*k6; mat[13] = k2*k6 + k3*k7;
|
||||
k6 = gcosang2*gchang; k7 = gsinang2*gchang;
|
||||
mat[2] = k4*k6 + k5*k7; mat[6] =-gshang; mat[10] = k4*k7 - k5*k6; mat[14] = k2*k6 + k3*k7;
|
||||
|
||||
mat[12] = (mat[12] + a0.y*mat[0]) + (a0.z*mat[4] + a0.x*mat[ 8]);
|
||||
mat[13] = (mat[13] + a0.y*mat[1]) + (a0.z*mat[5] + a0.x*mat[ 9]);
|
||||
mat[14] = (mat[14] + a0.y*mat[2]) + (a0.z*mat[6] + a0.x*mat[10]);
|
||||
}
|
||||
|
||||
static GLuint polymost2_compileShader(GLenum shaderType, const char* const source)
|
||||
{
|
||||
GLuint shaderID = glCreateShader(shaderType);
|
||||
if (shaderID == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* const sources[1] = {source};
|
||||
glShaderSource(shaderID,
|
||||
1,
|
||||
sources,
|
||||
NULL);
|
||||
glCompileShader(shaderID);
|
||||
|
||||
int compileStatus[1];
|
||||
glGetShaderiv(shaderID, GL_COMPILE_STATUS, compileStatus);
|
||||
OSD_Printf("Compile Status: %u\n", compileStatus[0]);
|
||||
|
||||
int logLength[1];
|
||||
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, logLength);
|
||||
if (logLength[0] > 0)
|
||||
{
|
||||
char infoLog[logLength[0]];
|
||||
glGetShaderInfoLog(shaderID, logLength[0], NULL, infoLog);
|
||||
OSD_Printf("Log:\n%s\n", infoLog);
|
||||
}
|
||||
|
||||
return shaderID;
|
||||
}
|
||||
|
||||
void polymost_glreset()
|
||||
{
|
||||
for (bssize_t i=0; i<=MAXPALOOKUPS-1; i++)
|
||||
|
@ -380,6 +489,117 @@ void polymost_glinit()
|
|||
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||||
//glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
const char blankTex[] = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0};
|
||||
glGenTextures(1, &blankTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, blankTextureID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, blankTex);
|
||||
|
||||
GLuint ids[1];
|
||||
glGenBuffers(1, ids);
|
||||
quadVertsID = ids[0];
|
||||
glBindBuffer(GL_ARRAY_BUFFER, quadVertsID);
|
||||
const float quadVerts[] =
|
||||
{
|
||||
-0.5f, 1.0f, 0.0f, 0.0f, 1.0f, //top-left
|
||||
-0.5f, 0.0f, 0.0f, 0.0f, 0.0f, //bottom-left
|
||||
0.5f, 1.0f, 0.0f, 1.0f, 1.0f, //top-right
|
||||
0.5f, 0.0f, 0.0f, 1.0f, 0.0f //bottom-right
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVerts), quadVerts, GL_STATIC_DRAW);
|
||||
|
||||
//specify format/arrangement for vertex positions:
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(float) * 5, 0);
|
||||
//specify format/arrangement for vertex texture coords:
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(float) * 5, (const void*) (sizeof(float) * 3));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
const char* const BASIC_VERTEX_SHADER_CODE =
|
||||
"#version 110\n\
|
||||
\n\
|
||||
// input\n\
|
||||
attribute vec3 i_vertPos;\n\
|
||||
attribute vec2 i_texCoord;\n\
|
||||
uniform mat4 u_mvMatrix;\n\
|
||||
uniform mat4 u_projMatrix;\n\
|
||||
uniform vec2 u_texOffset;\n\
|
||||
uniform vec2 u_texScale;\n\
|
||||
\n\
|
||||
// output\n\
|
||||
varying vec2 v_texCoord;\n\
|
||||
varying float v_distance;\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
vec4 eyeCoordPosition = u_mvMatrix * vec4(i_vertPos, 1.0);\n\
|
||||
gl_Position = u_projMatrix * eyeCoordPosition;\n\
|
||||
\n\
|
||||
//POGOTODO: temporary z-fighting hack for GL2 approach fighting with GL1\n\
|
||||
// Eventually adapt this into better decal z-buffer adjustment approach\n\
|
||||
//gl_Position.z -= (u_projMatrix * vec4(0.0, 0.0, 1.011, 1.0)).z;\n\
|
||||
\n\
|
||||
eyeCoordPosition.xyz /= eyeCoordPosition.w;\n\
|
||||
\n\
|
||||
v_texCoord = i_texCoord * u_texScale + u_texOffset;\n\
|
||||
v_distance = eyeCoordPosition.z;\n\
|
||||
}\n";
|
||||
const char* const BASIC_FRAGMENT_SHADER_CODE =
|
||||
"#version 110\n\
|
||||
\n\
|
||||
varying vec2 v_texCoord;\n\
|
||||
uniform sampler2D s_texture;\n\
|
||||
uniform sampler2D s_fullBright;\n\
|
||||
\n\
|
||||
uniform vec4 u_tint;\n\
|
||||
uniform float u_alpha;\n\
|
||||
\n\
|
||||
varying float v_distance;\n\
|
||||
uniform vec2 u_fogRange;\n\
|
||||
uniform vec4 u_fogColor;\n\
|
||||
\n\
|
||||
const float c_zero = 0.0;\n\
|
||||
const float c_one = 1.0;\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
vec4 color = texture2D(s_texture, v_texCoord);\n\
|
||||
vec4 fullBrightColor = texture2D(s_fullBright, v_texCoord);\n\
|
||||
\n\
|
||||
float fogFactor = clamp((u_fogRange.y-v_distance)/(u_fogRange.y-u_fogRange.x), c_zero, c_one);\n\
|
||||
\n\
|
||||
color.rgb = mix(u_fogColor.rgb, color.rgb, fogFactor);\n\
|
||||
color.rgb *= u_tint.rgb * u_tint.a * color.a;\n\
|
||||
color.rgb = mix(color.rgb, fullBrightColor.rgb, fullBrightColor.a);\n\
|
||||
\n\
|
||||
color.a *= u_alpha;\n\
|
||||
\n\
|
||||
gl_FragColor = color;\n\
|
||||
}\n";
|
||||
|
||||
shaderProgramID = glCreateProgram();
|
||||
GLuint basicVertexShaderID = polymost2_compileShader(GL_VERTEX_SHADER, BASIC_VERTEX_SHADER_CODE);
|
||||
GLuint basicFragmentShaderID = polymost2_compileShader(GL_FRAGMENT_SHADER, BASIC_FRAGMENT_SHADER_CODE);
|
||||
glBindAttribLocation(shaderProgramID, 0, "i_vertPos");
|
||||
glBindAttribLocation(shaderProgramID, 1, "i_texCoord");
|
||||
glAttachShader(shaderProgramID, basicVertexShaderID);
|
||||
glAttachShader(shaderProgramID, basicFragmentShaderID);
|
||||
glLinkProgram(shaderProgramID);
|
||||
|
||||
// Get the attribute/uniform locations
|
||||
texSamplerLoc = glGetUniformLocation(shaderProgramID, "s_texture");
|
||||
fullBrightSamplerLoc = glGetUniformLocation(shaderProgramID, "s_fullBright");
|
||||
projMatrixLoc = glGetUniformLocation(shaderProgramID, "u_projMatrix");
|
||||
mvMatrixLoc = glGetUniformLocation(shaderProgramID, "u_mvMatrix");
|
||||
texOffsetLoc = glGetUniformLocation(shaderProgramID, "u_texOffset");
|
||||
texScaleLoc = glGetUniformLocation(shaderProgramID, "u_texScale");
|
||||
tintLoc = glGetUniformLocation(shaderProgramID, "u_tint");
|
||||
alphaLoc = glGetUniformLocation(shaderProgramID, "u_alpha");
|
||||
fogRangeLoc = glGetUniformLocation(shaderProgramID, "u_fogRange");
|
||||
fogColorLoc = glGetUniformLocation(shaderProgramID, "u_fogColor");
|
||||
|
||||
#ifdef USE_GLEXT
|
||||
if (glmultisample > 0 && glinfo.multisample)
|
||||
{
|
||||
|
@ -509,6 +729,34 @@ static inline void fogcalc(int32_t tile, int32_t shade, int32_t vis, int32_t pal
|
|||
|
||||
#define GL_FOG_MAX 1.0e37f
|
||||
|
||||
void polymost2_calc_fog(int32_t shade, int32_t vis, int32_t pal)
|
||||
{
|
||||
if (nofog) return;
|
||||
|
||||
fogresult = 0.f;
|
||||
fogresult2 = -GL_FOG_MAX; // hide fog behind the camera
|
||||
fogcol = fogtable[pal];
|
||||
|
||||
if (((uint8_t)(vis + 16)) > 0 && g_visibility > 0)
|
||||
{
|
||||
GLfloat glfogconstant = 262144.f;
|
||||
GLfloat fogrange = (frealmaxshade * glfogconstant) / (((uint8_t)(vis + 16)) * globalvisibility);
|
||||
GLfloat normalizedshade = shade / frealmaxshade;
|
||||
GLfloat fogshade = normalizedshade * fogrange;
|
||||
|
||||
fogresult = -fogshade;
|
||||
fogresult2 = fogrange - fogshade;
|
||||
|
||||
// substract shade from fog
|
||||
if (shade > 0 && shade < realmaxshade)
|
||||
{
|
||||
fogresult = 1.f - (fogresult2 / (fogresult2 - fogresult));
|
||||
fogresult = (fogresult - normalizedshade) / (1.f - normalizedshade);
|
||||
fogresult = -((fogresult2 / (1.f - fogresult)) - fogresult2) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void calc_and_apply_fog(int32_t tile, int32_t shade, int32_t vis, int32_t pal)
|
||||
{
|
||||
if (nofog) return;
|
||||
|
@ -1742,6 +1990,169 @@ static inline pthtyp *our_texcache_fetch(int32_t dameth)
|
|||
return texcache_fetch(globalpicnum, globalpal, getpalookup((r_usetileshades == 1 && !(globalflags & GLOBAL_NO_GL_TILESHADES)) ? globvis>>3 : 0, globalshade), dameth);
|
||||
}
|
||||
|
||||
static void polymost2_drawVBO(GLenum mode,
|
||||
int32_t vertexBufferID,
|
||||
int32_t indexBufferID,
|
||||
const int32_t numElements,
|
||||
float projectionMatrix[4*4],
|
||||
float modelViewMatrix[4*4],
|
||||
int32_t dameth,
|
||||
float texScale[2],
|
||||
float texOffset[2],
|
||||
char cullFaces)
|
||||
{
|
||||
if (dameth == DAMETH_BACKFACECULL ||
|
||||
#ifdef YAX_ENABLE
|
||||
g_nodraw ||
|
||||
#endif
|
||||
(uint32_t)globalpicnum >= MAXTILES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (cullFaces)
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
//POGOTODO: this is temporary, the permanent fix is to not allow the transform to affect the windings in the first place in polymost2_drawSprite()
|
||||
if (cullFaces == 1)
|
||||
{
|
||||
glCullFace(GL_BACK);
|
||||
} else
|
||||
{
|
||||
glCullFace(GL_FRONT);
|
||||
}
|
||||
|
||||
//POGOTODO: in the future, state changes like binding these buffers can be batched. For now, just switch on every VBO rendered
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
if (palookup[globalpal] == NULL)
|
||||
{
|
||||
globalpal = 0;
|
||||
}
|
||||
|
||||
//Load texture (globalpicnum)
|
||||
setgotpic(globalpicnum);
|
||||
if (!waloff[globalpicnum])
|
||||
{
|
||||
loadtile(globalpicnum);
|
||||
}
|
||||
|
||||
pthtyp *pth = our_texcache_fetch(dameth);
|
||||
|
||||
if (!pth)
|
||||
{
|
||||
if (editstatus)
|
||||
{
|
||||
Bsprintf(ptempbuf, "pth==NULL! (bad pal?) pic=%d pal=%d", globalpicnum, globalpal);
|
||||
polymost_printext256(8,8, editorcolors[15],editorcolors[5], ptempbuf, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, (pth && pth->flags & PTH_HASFULLBRIGHT && r_fullbrights) ? pth->ofb->glpic : blankTextureID);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, pth ? pth->glpic : blankTextureID);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
|
||||
|
||||
//POGOTODO: handle tinting & shading completely with fragment shader
|
||||
//POGOTODO: handle fullbright & glow completely with fragment shader
|
||||
|
||||
//POGOTODO: glAlphaFunc is deprecated, move this into the fragment shader
|
||||
float const al = waloff[globalpicnum] ? alphahackarray[globalpicnum] != 0 ? alphahackarray[globalpicnum] * (1.f/255.f):
|
||||
(pth && pth->hicr && pth->hicr->alphacut >= 0.f ? pth->hicr->alphacut : 0.f) : 0.f;
|
||||
glAlphaFunc(GL_GREATER, al);
|
||||
//POGOTODO: batch this, only apply it to sprites that actually need blending
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
|
||||
handle_blend((dameth & DAMETH_MASKPROPS) > DAMETH_MASK, drawpoly_blend, (dameth & DAMETH_MASKPROPS) == DAMETH_TRANS2);
|
||||
|
||||
glUseProgram(shaderProgramID);
|
||||
|
||||
//POGOTODO: batch uniform binding
|
||||
float tint[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
polytint_t const & polytint = hictinting[globalpal];
|
||||
//POGOTODO: full bright pass uses its own globalshade...
|
||||
tint[0] = (1.f-(polytint.sr*(1.f/255.f)))*getshadefactor(globalshade)+(polytint.sr*(1.f/255.f));
|
||||
tint[1] = (1.f-(polytint.sg*(1.f/255.f)))*getshadefactor(globalshade)+(polytint.sg*(1.f/255.f));
|
||||
tint[2] = (1.f-(polytint.sb*(1.f/255.f)))*getshadefactor(globalshade)+(polytint.sb*(1.f/255.f));
|
||||
|
||||
// spriteext full alpha control
|
||||
float alpha = float_trans(dameth & DAMETH_MASKPROPS, drawpoly_blend) * (1.f - drawpoly_alpha);
|
||||
|
||||
if (pth)
|
||||
{
|
||||
// tinting
|
||||
polytintflags_t const tintflags = hictinting[globalpal].f;
|
||||
if (!(tintflags & HICTINT_PRECOMPUTED))
|
||||
{
|
||||
if (pth->flags & PTH_HIGHTILE)
|
||||
{
|
||||
if (pth->palnum != globalpal || (pth->effects & HICTINT_IN_MEMORY) || (tintflags & HICTINT_APPLYOVERALTPAL))
|
||||
hictinting_apply(tint, globalpal);
|
||||
}
|
||||
else if (tintflags & (HICTINT_USEONART|HICTINT_ALWAYSUSEART))
|
||||
hictinting_apply(tint, globalpal);
|
||||
}
|
||||
|
||||
// global tinting
|
||||
if ((pth->flags & PTH_HIGHTILE) && have_basepal_tint())
|
||||
hictinting_apply(tint, MAXPALOOKUPS-1);
|
||||
}
|
||||
|
||||
glUniformMatrix4fv(projMatrixLoc, 1, false, projectionMatrix);
|
||||
glUniformMatrix4fv(mvMatrixLoc, 1, false, modelViewMatrix);
|
||||
glUniform1i(texSamplerLoc, 0);
|
||||
glUniform1i(fullBrightSamplerLoc, 1);
|
||||
glUniform2fv(texOffsetLoc, 1, texOffset);
|
||||
glUniform2fv(texScaleLoc, 1, texScale);
|
||||
glUniform4fv(tintLoc, 1, tint);
|
||||
glUniform1f(alphaLoc, alpha);
|
||||
const float fogRange[2] = {fogresult, fogresult2};
|
||||
glUniform2fv(fogRangeLoc, 1, fogRange);
|
||||
glUniform4fv(fogColorLoc, 1, (GLfloat*) &fogcol);
|
||||
|
||||
if (indexBufferID == 0)
|
||||
{
|
||||
glDrawArrays(mode,
|
||||
0,
|
||||
numElements);
|
||||
} else
|
||||
{
|
||||
glDrawElements(mode,
|
||||
numElements,
|
||||
GL_UNSIGNED_SHORT,
|
||||
0);
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
|
||||
//POGOTODO: again, these state changes should be batched in the future, rather than on each VBO rendered
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32_t method)
|
||||
{
|
||||
if (method == DAMETH_BACKFACECULL ||
|
||||
|
@ -4517,8 +4928,393 @@ int32_t polymost_lintersect(int32_t x1, int32_t y1, int32_t x2, int32_t y2,
|
|||
#define TSPR_OFFSET_FACTOR .000008f
|
||||
#define TSPR_OFFSET(tspr) ((TSPR_OFFSET_FACTOR + ((tspr->owner != -1 ? tspr->owner & 63 : 1) * TSPR_OFFSET_FACTOR)) * (float)sepdist(globalposx - tspr->x, globalposy - tspr->y, globalposz - tspr->z) * 0.025f)
|
||||
|
||||
void polymost2_drawsprite(int32_t snum)
|
||||
{
|
||||
uspritetype *const tspr = tspriteptr[snum];
|
||||
|
||||
if (EDUKE32_PREDICT_FALSE(bad_tspr(tspr)))
|
||||
return;
|
||||
|
||||
const usectortype *sec;
|
||||
|
||||
int32_t spritenum = tspr->owner;
|
||||
|
||||
DO_TILE_ANIM(tspr->picnum, spritenum + 32768);
|
||||
|
||||
globalpicnum = tspr->picnum;
|
||||
globalshade = tspr->shade;
|
||||
globalpal = tspr->pal;
|
||||
globalorientation = tspr->cstat;
|
||||
globvis = globalvisibility;
|
||||
|
||||
if (sector[tspr->sectnum].visibility != 0)
|
||||
globvis = mulscale4(globvis, (uint8_t)(sector[tspr->sectnum].visibility + 16));
|
||||
|
||||
vec2f_t off = { 0.f, 0.f };
|
||||
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB) // only non-voxel sprites should do this
|
||||
{
|
||||
int const flag = usehightile && h_xsize[globalpicnum];
|
||||
off.x = (int32_t)tspr->xoffset + (flag ? h_xoffs[globalpicnum] : picanm[globalpicnum].xofs);
|
||||
off.y = (int32_t)tspr->yoffset + (flag ? h_yoffs[globalpicnum] : picanm[globalpicnum].yofs);
|
||||
}
|
||||
|
||||
int32_t method = DAMETH_MASK | DAMETH_CLAMPED;
|
||||
|
||||
if (tspr->cstat & CSTAT_SPRITE_TRANSLUCENT)
|
||||
method = DAMETH_CLAMPED | ((tspr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT) ? DAMETH_TRANS2 : DAMETH_TRANS1);
|
||||
|
||||
handle_blend(!!(tspr->cstat & CSTAT_SPRITE_TRANSLUCENT), tspr->blend, !!(tspr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));
|
||||
|
||||
drawpoly_alpha = spriteext[spritenum].alpha;
|
||||
drawpoly_blend = tspr->blend;
|
||||
|
||||
sec = (usectortype *)§or[tspr->sectnum];
|
||||
|
||||
polymost2_calc_fog(fogshade(globalshade, globalpal), sec->visibility, get_floor_fogpal(sec));
|
||||
|
||||
//POGOTODO: this while is an if statement
|
||||
while (!(spriteext[spritenum].flags & SPREXT_NOTMD))
|
||||
{
|
||||
//POGOTODO: switch these to if/else for readability and rearrange for performance
|
||||
if (usemodels && tile2model[Ptile2tile(tspr->picnum, tspr->pal)].modelid >= 0 &&
|
||||
tile2model[Ptile2tile(tspr->picnum, tspr->pal)].framenum >= 0)
|
||||
{
|
||||
if (polymost_mddraw(tspr)) return;
|
||||
break; // else, render as flat sprite
|
||||
}
|
||||
|
||||
if (usevoxels && (tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]])
|
||||
{
|
||||
if (polymost_voxdraw(voxmodels[tiletovox[tspr->picnum]], tspr)) return;
|
||||
break; // else, render as flat sprite
|
||||
}
|
||||
|
||||
if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB && voxmodels[tspr->picnum])
|
||||
{
|
||||
polymost_voxdraw(voxmodels[tspr->picnum], tspr);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//POGO: some comments seem to indicate that spinning sprites were intended to be supported before the
|
||||
// decision was made to implement that behaviour with voxels.
|
||||
// Skip SPIN aligned sprites when not rendering as voxels.
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vec2_t pos = *(vec2_t *)tspr;
|
||||
|
||||
if (spriteext[spritenum].flags & SPREXT_AWAY1)
|
||||
{
|
||||
pos.x += (sintable[(tspr->ang + 512) & 2047] >> 13);
|
||||
pos.y += (sintable[(tspr->ang) & 2047] >> 13);
|
||||
}
|
||||
else if (spriteext[spritenum].flags & SPREXT_AWAY2)
|
||||
{
|
||||
pos.x -= (sintable[(tspr->ang + 512) & 2047] >> 13);
|
||||
pos.y -= (sintable[(tspr->ang) & 2047] >> 13);
|
||||
}
|
||||
|
||||
vec2s_t const oldsiz = tilesiz[globalpicnum];
|
||||
vec2_t tsiz = { oldsiz.x, oldsiz.y };
|
||||
|
||||
if (usehightile && h_xsize[globalpicnum])
|
||||
{
|
||||
tsiz.x = h_xsize[globalpicnum];
|
||||
tsiz.y = h_ysize[globalpicnum];
|
||||
}
|
||||
|
||||
if (tsiz.x <= 0 || tsiz.y <= 0)
|
||||
return;
|
||||
|
||||
vec2f_t const ftsiz = { (float) tsiz.x, (float) tsiz.y };
|
||||
|
||||
//POGOTODO: some of these cases where we return could be done further up in order to skip doing throw away computation
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT_FLOOR) &&
|
||||
(globalorientation & CSTAT_SPRITE_ONE_SIDED) != 0 &&
|
||||
(globalposz > tspr->z) == (!(globalorientation & CSTAT_SPRITE_YFLIP)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//POGOTODO: in polymost1 any sprites that are too close are pre-clipped here before any calculation
|
||||
|
||||
tilesiz[globalpicnum].x = tsiz.x;
|
||||
tilesiz[globalpicnum].y = tsiz.y;
|
||||
|
||||
float texScale[2] = {1.0f, -1.0f};
|
||||
float texOffset[2] = {((float) (spriteext[spritenum].xpanning) * (1.0f / 255.f)),
|
||||
((float) (spriteext[spritenum].ypanning) * (1.0f / 255.f))};
|
||||
|
||||
float transformMatrix[4*4] =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
float modelViewMatrix[4*4] =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
float f = (65536.f*512.f) / (fxdimen*viewingrange);
|
||||
float g = 32.f / (fxdimen*gxyaspect);
|
||||
|
||||
float horzScale = ftsiz.x*(1.f/64.f);
|
||||
float vertScale = ftsiz.y*(1.f/64.f);
|
||||
|
||||
horzScale *= ((float)tspr->xrepeat) * (1.f/64.f);
|
||||
vertScale *= ((float)tspr->yrepeat) * (1.f/64.f);
|
||||
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT)==CSTAT_SPRITE_ALIGNMENT_FACING)
|
||||
{
|
||||
horzScale *= 256.f/320.f;
|
||||
} else if ((globalorientation & CSTAT_SPRITE_ALIGNMENT)==CSTAT_SPRITE_ALIGNMENT_FLOOR)
|
||||
{
|
||||
//POGOTODO: fix floor sprites to be scaled up slightly by the right amount, and note their tex is slightly clipped on the leading edges
|
||||
vertScale += 1.f/320.f;
|
||||
}
|
||||
|
||||
horzScale *= f;
|
||||
vertScale *= g;
|
||||
|
||||
//handle sprite flipping
|
||||
horzScale *= -2.f*((globalorientation & CSTAT_SPRITE_XFLIP) != 0) + 1.f;
|
||||
vertScale *= -2.f*((globalorientation & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_FLOOR &
|
||||
(globalorientation & CSTAT_SPRITE_YFLIP) != 0) + 1.f;
|
||||
|
||||
//POGOTODO: replace this with simply using off.x and a different float for z offsets
|
||||
// switching that over should fix floor sprite offsets so that they flip properly when yflip/xflip is applied
|
||||
//handle orientation offsets
|
||||
vec2f_t orientationOffset = {0.f, 0.f};
|
||||
vec3f_t offs = { 0.f, 0.f, 0.f };
|
||||
|
||||
off.x = 0.2f * ((float)tspr->xrepeat) * (((float) off.x) + (tsiz.x & 1)*0.5f*(((globalorientation & CSTAT_SPRITE_XFLIP) == 0)*-2.f + 1.f));
|
||||
off.y = 4.f * ((float)tspr->yrepeat) * (((float) off.y) + (((globalorientation & CSTAT_SPRITE_YCENTER) != 0) & tsiz.y & 1)*0.5f);
|
||||
|
||||
int16_t angle = globalang;
|
||||
float combinedClipScale = 1.f;
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT)==CSTAT_SPRITE_ALIGNMENT_FACING)
|
||||
{
|
||||
int const ang = (getangle(tspr->x - globalposx, tspr->y - globalposy) + 1024) & 2047;
|
||||
float const foffs = TSPR_OFFSET(tspr);
|
||||
offs = { (float) (sintable[(ang + 512) & 2047] >> 6) * foffs,
|
||||
(float) (sintable[(ang) & 2047] >> 6) * foffs,
|
||||
0.f};
|
||||
} else if ((globalorientation & CSTAT_SPRITE_ALIGNMENT)==CSTAT_SPRITE_ALIGNMENT_WALL)
|
||||
{
|
||||
angle = (tspr->ang+1024)&2047;
|
||||
/*float const foffs = TSPR_OFFSET(tspr);
|
||||
offs = { (float) (sintable[(tspr->ang + 512) & 2047] >> 6) * foffs,
|
||||
(float) (sintable[(tspr->ang) & 2047] >> 6) * foffs};*/
|
||||
|
||||
//POGOTODO: For now, just handle this exactly the same way as in polymost1.
|
||||
// Eventually, I should change how all sprites avoid z-fighting by offsetting the z-buffer depth
|
||||
// rather than offsetting the entire object in space.
|
||||
vec2f_t const extent = { (float)tspr->xrepeat * (float)sintable[(tspr->ang) & 2047] * (1.0f / 65536.f),
|
||||
(float)tspr->xrepeat * (float)sintable[(tspr->ang + 1536) & 2047] * (1.0f / 65536.f) };
|
||||
//POGOTODO: this needs to be calculated before I make my adjustments to off.x above!
|
||||
float f = (float)(tsiz.x >> 1) + (float)off.x;
|
||||
vec2f_t const vf = { extent.x * f, extent.y * f };
|
||||
|
||||
int32_t const s = tspr->owner;
|
||||
int32_t walldist = 1;
|
||||
int32_t w = (s == -1) ? -1 : wsprinfo[s].wall;
|
||||
|
||||
// find the wall most likely to be what the sprite is supposed to be ornamented against
|
||||
// this is really slow, so cache the result
|
||||
if (s == -1 || !wsprinfo[s].wall || (spritechanged[s] != wsprinfo[s].srev) ||
|
||||
(w != -1 && wallchanged[w] != wsprinfo[s].wrev))
|
||||
{
|
||||
w = polymost_findwall(tspr, &tsiz, &walldist);
|
||||
|
||||
if (s != -1)
|
||||
{
|
||||
wallspriteinfo_t *ws = &wsprinfo[s];
|
||||
ws->wall = w;
|
||||
|
||||
if (w != -1)
|
||||
{
|
||||
ws->wdist = walldist;
|
||||
ws->wrev = wallchanged[w];
|
||||
ws->srev = spritechanged[s];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (s != -1)
|
||||
walldist = wsprinfo[s].wdist;
|
||||
|
||||
// detect if the sprite is either on the wall line or the wall line and sprite intersect
|
||||
if (w != -1)
|
||||
{
|
||||
vec2_t v = { /*Blrintf(vf.x)*/(int)vf.x, /*Blrintf(vf.y)*/(int)vf.y };
|
||||
|
||||
if (walldist <= 2 || ((pos.x - v.x) + (pos.x + v.x)) == (wall[w].x + POINT2(w).x) ||
|
||||
((pos.y - v.y) + (pos.y + v.y)) == (wall[w].y + POINT2(w).y) ||
|
||||
polymost_lintersect(pos.x - v.x, pos.y - v.y, pos.x + v.x, pos.y + v.y, wall[w].x, wall[w].y,
|
||||
POINT2(w).x, POINT2(w).y))
|
||||
{
|
||||
int32_t const ang = getangle(wall[w].x - POINT2(w).x, wall[w].y - POINT2(w).y);
|
||||
float const foffs = TSPR_OFFSET(tspr);
|
||||
offs = { -(float)(sintable[(ang + 1024) & 2047] >> 6) * foffs,
|
||||
-(float)(sintable[(ang + 512) & 2047] >> 6) * foffs,
|
||||
0.f};
|
||||
}
|
||||
}
|
||||
|
||||
//POGO: for full compatibility, facing sprites should also clip similarly (see polymost_drawsprite())
|
||||
// Clip sprites to ceilings/floors when no parallaxing
|
||||
float fullCenterYOff = off.y + (((globalorientation & CSTAT_SPRITE_YCENTER) != 0) * 2.f)
|
||||
* ftsiz.y * ((float)tspr->yrepeat);
|
||||
if ((!(sector[tspr->sectnum].ceilingstat & 1)) &&
|
||||
sector[tspr->sectnum].ceilingz > tspr->z + fullCenterYOff - ((tspr->yrepeat * tsiz.y) << 2))
|
||||
{
|
||||
float clipScale = ((float) (tspr->z + fullCenterYOff - sector[tspr->sectnum].ceilingz))/((float)((tspr->yrepeat * tsiz.y) << 2));
|
||||
if (clipScale <= 0.f)
|
||||
{
|
||||
//don't draw sprites fully clipped by the ceiling
|
||||
return;
|
||||
}
|
||||
|
||||
texScale[1] *= clipScale;
|
||||
texOffset[1] += (1.f-clipScale)*(-1.f*((globalorientation & CSTAT_SPRITE_YFLIP) == CSTAT_SPRITE_YFLIP));
|
||||
vertScale *= clipScale;
|
||||
combinedClipScale *= clipScale;
|
||||
}
|
||||
if ((!(sector[tspr->sectnum].floorstat & 1)) &&
|
||||
sector[tspr->sectnum].floorz < tspr->z + fullCenterYOff)
|
||||
{
|
||||
float span = ((tspr->yrepeat * tsiz.y) << 2) - (tspr->z + fullCenterYOff - sector[tspr->sectnum].floorz);
|
||||
float clipScale = span/((float)((tspr->yrepeat * tsiz.y) << 2));
|
||||
if (clipScale <= 0.f)
|
||||
{
|
||||
//don't draw sprites fully clipped by the floor
|
||||
return;
|
||||
}
|
||||
|
||||
texScale[1] *= clipScale;
|
||||
texOffset[1] += (1.f-clipScale)*(-1.f*((globalorientation & CSTAT_SPRITE_YFLIP) != CSTAT_SPRITE_YFLIP));
|
||||
vertScale *= clipScale;
|
||||
combinedClipScale *= clipScale;
|
||||
off.y += (float) (((tspr->yrepeat * tsiz.y) << 2) - span);
|
||||
}
|
||||
if (globalorientation & CSTAT_SPRITE_YCENTER)
|
||||
{
|
||||
combinedClipScale = 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
off.x *= ((float) ((globalorientation & CSTAT_SPRITE_XFLIP) != 0))*-2.f + 1.f;
|
||||
off.y *= ((float) ((globalorientation & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_FACING &
|
||||
(globalorientation & (CSTAT_SPRITE_YFLIP)) != 0))*-2.f + 1.f;
|
||||
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT)==CSTAT_SPRITE_ALIGNMENT_FLOOR)
|
||||
{
|
||||
vertScale = -vertScale;
|
||||
orientationOffset.x += ftsiz.y*((float) tspr->yrepeat)*(1.f/8.f);
|
||||
|
||||
// unfortunately, offsetting by only 1 isn't enough on most Android devices
|
||||
if (tspr->z == sec->ceilingz || tspr->z == sec->ceilingz + 1)
|
||||
tspr->z = sec->ceilingz + 2, orientationOffset.y += (tspr->owner & 31);
|
||||
|
||||
if (tspr->z == sec->floorz || tspr->z == sec->floorz - 1)
|
||||
tspr->z = sec->floorz - 2, orientationOffset.y -= ((tspr->owner & 31));
|
||||
|
||||
angle = tspr->ang;
|
||||
} else
|
||||
{
|
||||
off.y -= (((globalorientation & CSTAT_SPRITE_YCENTER) != 0) * 2.f +
|
||||
((globalorientation & CSTAT_SPRITE_YFLIP) != 0)*-4.f)
|
||||
* combinedClipScale * ftsiz.y * ((float)tspr->yrepeat);
|
||||
}
|
||||
|
||||
vec3f_t a0;
|
||||
a0.x = ((float)(pos.y-globalposy)+offs.y) * -(1.f/1024.f)*-f;
|
||||
a0.y = ((float)(pos.x-globalposx)+offs.x) * (1.f/1024.f)*f;
|
||||
a0.z = ((float)(tspr->z-globalposz)+offs.z) * -(1.f/16384.f)*g;
|
||||
orientationOffset.x *= -(1.f/1024.f)*-f;
|
||||
orientationOffset.y *= -(1.f/16384.f)*g;
|
||||
calcmat(a0, &orientationOffset, f, modelViewMatrix, angle);
|
||||
|
||||
if ((globalorientation & CSTAT_SPRITE_ALIGNMENT)==CSTAT_SPRITE_ALIGNMENT_FLOOR)
|
||||
{
|
||||
float temp = modelViewMatrix[4]; modelViewMatrix[4] = modelViewMatrix[8]*16.f; modelViewMatrix[8] = -temp*(1.f/16.f);
|
||||
temp = modelViewMatrix[5]; modelViewMatrix[5] = modelViewMatrix[9]*16.f; modelViewMatrix[9] = -temp*(1.f/16.f);
|
||||
temp = modelViewMatrix[6]; modelViewMatrix[6] = modelViewMatrix[10]*16.f; modelViewMatrix[10] = -temp*(1.f/16.f);
|
||||
}
|
||||
|
||||
// mirrors
|
||||
if (grhalfxdown10x < 0)
|
||||
{
|
||||
modelViewMatrix[0] = -modelViewMatrix[0]; modelViewMatrix[4] = -modelViewMatrix[4]; modelViewMatrix[8] = -modelViewMatrix[8]; modelViewMatrix[12] = -modelViewMatrix[12];
|
||||
}
|
||||
|
||||
float ratio = 1.0f/get_projhack_ratio();
|
||||
float projectionMatrix[4*4] =
|
||||
{
|
||||
fydimen * ratio, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, fxdimen, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, fydimen * ratio,
|
||||
0.0f, 0.0f, -1.0f, 0.0f
|
||||
};
|
||||
|
||||
float scaleMatrix[4*4] =
|
||||
{
|
||||
horzScale, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, vertScale, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
float offsetMatrix[4*4] =
|
||||
{
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
-off.x*(1.f/1024.f)*f, off.y * (1.f/16384.f)*g, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
multiplyMatrix4f(transformMatrix, scaleMatrix);
|
||||
multiplyMatrix4f(transformMatrix, offsetMatrix);
|
||||
//POGOTODO: for later optimization purposes (batching/caching), I need to split the modelViewMatrix into modelMatrix and viewMatrix
|
||||
multiplyMatrix4f(transformMatrix, modelViewMatrix);
|
||||
|
||||
//POGOTODO: I should instead implement one-sided sprites & culling by switching the xflip/yflip from flipping scale to instead flipping texScale
|
||||
// Doing that will allow me to simplify a lot of this code, but it will require a lot of changes
|
||||
polymost2_drawVBO(GL_TRIANGLE_STRIP,
|
||||
quadVertsID,
|
||||
0,
|
||||
4,
|
||||
projectionMatrix,
|
||||
transformMatrix,
|
||||
method,
|
||||
texScale,
|
||||
texOffset,
|
||||
((globalorientation & CSTAT_SPRITE_ONE_SIDED) != 0)*3 & ((globalorientation & CSTAT_SPRITE_XFLIP) != 0 ^ (globalorientation & CSTAT_SPRITE_YFLIP) != 0)+1);
|
||||
|
||||
drawpoly_srepeat = 0;
|
||||
drawpoly_trepeat = 0;
|
||||
|
||||
tilesiz[globalpicnum] = oldsiz;
|
||||
}
|
||||
|
||||
void polymost_drawsprite(int32_t snum)
|
||||
{
|
||||
if (r_enablepolymost2)
|
||||
{
|
||||
polymost2_drawsprite(snum);
|
||||
return;
|
||||
}
|
||||
|
||||
uspritetype *const tspr = tspriteptr[snum];
|
||||
|
||||
if (EDUKE32_PREDICT_FALSE(bad_tspr(tspr)))
|
||||
|
@ -6170,6 +6966,7 @@ void polymost_initosdfuncs(void)
|
|||
|
||||
static osdcvardata_t cvars_polymost[] =
|
||||
{
|
||||
{ "r_enablepolymost2","enable/disable polymost2",(void *) &r_enablepolymost2, CVAR_BOOL, 0, 1 },
|
||||
{ "r_animsmoothing","enable/disable model animation smoothing",(void *) &r_animsmoothing, CVAR_BOOL, 0, 1 },
|
||||
{ "r_downsize","controls downsizing factor (quality) for hires textures",(void *) &r_downsize, CVAR_INT|CVAR_FUNCPTR, 0, 5 },
|
||||
{ "r_fullbrights","enable/disable fullbright textures",(void *) &r_fullbrights, CVAR_BOOL, 0, 1 },
|
||||
|
|
Loading…
Reference in a new issue