This commit is contained in:
lerabot 2020-05-13 19:05:29 -04:00
commit 294819108d
3 changed files with 99 additions and 98 deletions

View File

@ -114,14 +114,8 @@ typedef void (*FloatParseFunc)(GLfloat* out, const GLubyte* in);
typedef void (*ByteParseFunc)(GLubyte* out, const GLubyte* in); typedef void (*ByteParseFunc)(GLubyte* out, const GLubyte* in);
typedef void (*PolyBuildFunc)(Vertex* first, Vertex* previous, Vertex* vertex, Vertex* next, const GLsizei i); typedef void (*PolyBuildFunc)(Vertex* first, Vertex* previous, Vertex* vertex, Vertex* next, const GLsizei i);
GL_FORCE_INLINE float clamp(float d, float min, float max) {
const float t = d < min ? min : d;
return t > max ? max : t;
}
static void _readVertexData3f3f(const GLubyte* in, GLubyte* out) { static void _readVertexData3f3f(const GLubyte* in, GLubyte* out) {
memcpy(out, in, sizeof(float) * 12); vec3cpy(out, in);
} }
// 10:10:10:2REV format // 10:10:10:2REV format
@ -177,15 +171,14 @@ static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) {
} }
static void _readVertexData2f2f(const GLubyte* in, GLubyte* out) { static void _readVertexData2f2f(const GLubyte* in, GLubyte* out) {
memcpy(out, in, sizeof(float) * 2); vec2cpy(out, in);
} }
static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) { static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) {
const float* input = (const float*) in; const float* input = (const float*) in;
float* output = (float*) out; float* output = (float*) out;
output[0] = input[0]; vec2cpy(output, input);
output[1] = input[1];
output[2] = 0.0f; output[2] = 0.0f;
} }
@ -937,36 +930,34 @@ static void light(SubmissionTarget* target) {
_glPerformLighting(vertex, ES, target->count); _glPerformLighting(vertex, ES, target->count);
} }
#define PVR_MIN_Z 0.2f
#define PVR_MAX_Z 1.0 + PVR_MIN_Z
GL_FORCE_INLINE void divide(SubmissionTarget* target) { GL_FORCE_INLINE void divide(SubmissionTarget* target) {
TRACE(); TRACE();
/* Perform perspective divide on each vertex */ /* Perform perspective divide on each vertex */
Vertex* vertex = _glSubmissionTargetStart(target); Vertex* vertex = _glSubmissionTargetStart(target);
/* PVR expects with invW or invZ as the final depth coordinate,
* but there are issues with that. Using invW means that orthographic
* projections fail (because W is always 1). invZ fails when stuff is near
* the near plane (because it ends up <= 0) so what we do is take invZ
* and add the near-plane distance (plus an epsilon value) to take it above 0
* then invert that. */
Matrix4x4* proj = _glGetProjectionMatrix();
float m22 = (*proj)[10];
float m32 = (*proj)[14];
float zNear = MATH_Fast_Divide((2.0f * m32), (2.0f * m22 - 2.0f));
ITERATE(target->count) { ITERATE(target->count) {
float f = MATH_Fast_Invert(vertex->w); float f = MATH_Fast_Invert(vertex->w);
vertex->xyz[0] *= f; vertex->xyz[0] *= f;
vertex->xyz[1] *= f; vertex->xyz[1] *= f;
vertex->xyz[2] = MATH_Fast_Invert(
/* Unlike normal GL graphics, the PVR takes Z coordinates from +EPSILON to +inf vertex->xyz[2] + zNear + 0.05f
* this is annoying because a traditional Z divide plus shift may end up with );
* a coordinate of 0 which isn't valid. This is because the PVR
* expects invW as the coordinate, but that breaks orthographic projections
*
* So instead, we do a normal z/w divide, but shift from -1 to +1, and
* make it 0.001f to 2.001f, then we divide by 0.5 to bring it to
* 0.0005 to 1.0005 and finally we invert by subtracting from 1.001
* to just ensure we never end up with a value at 0.0 due to rounding
* errors */
vertex->xyz[2] = 1.001f - (((vertex->xyz[2] * f) + 1.001f) * 0.5f);
/* FIXME: Consider taking glDepthRange into account. PVR is designed to use 1/w
* which is unlike most GPUs - this apparently provides advantages.
*
* This can be done (if Z is between -1 and 1) with:
*
* //((DEPTH_RANGE_MULTIPLIER_L * vertex->xyz[2] * f) + DEPTH_RANGE_MULTIPLIER_H);
*/
++vertex; ++vertex;
} }
} }

View File

@ -78,27 +78,29 @@ void _glEnableLight(GLubyte light, GLboolean value) {
} }
GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask) { GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask) {
float baseColour[4];
/* Pre-calculate lighting values */ /* Pre-calculate lighting values */
GLubyte i; GLshort i;
for(i = 0; i < MAX_LIGHTS; ++i) { if(mask & AMBIENT_MASK) {
if(mask & AMBIENT_MASK) { for(i = 0; i < MAX_LIGHTS; ++i) {
LIGHTS[i].ambientMaterial[0] = LIGHTS[i].ambient[0] * MATERIAL.ambient[0]; LIGHTS[i].ambientMaterial[0] = LIGHTS[i].ambient[0] * MATERIAL.ambient[0];
LIGHTS[i].ambientMaterial[1] = LIGHTS[i].ambient[1] * MATERIAL.ambient[1]; LIGHTS[i].ambientMaterial[1] = LIGHTS[i].ambient[1] * MATERIAL.ambient[1];
LIGHTS[i].ambientMaterial[2] = LIGHTS[i].ambient[2] * MATERIAL.ambient[2]; LIGHTS[i].ambientMaterial[2] = LIGHTS[i].ambient[2] * MATERIAL.ambient[2];
LIGHTS[i].ambientMaterial[3] = LIGHTS[i].ambient[3] * MATERIAL.ambient[3]; LIGHTS[i].ambientMaterial[3] = LIGHTS[i].ambient[3] * MATERIAL.ambient[3];
} }
}
if(mask & DIFFUSE_MASK) { if(mask & DIFFUSE_MASK) {
for(i = 0; i < MAX_LIGHTS; ++i) {
LIGHTS[i].diffuseMaterial[0] = LIGHTS[i].diffuse[0] * MATERIAL.diffuse[0]; LIGHTS[i].diffuseMaterial[0] = LIGHTS[i].diffuse[0] * MATERIAL.diffuse[0];
LIGHTS[i].diffuseMaterial[1] = LIGHTS[i].diffuse[1] * MATERIAL.diffuse[1]; LIGHTS[i].diffuseMaterial[1] = LIGHTS[i].diffuse[1] * MATERIAL.diffuse[1];
LIGHTS[i].diffuseMaterial[2] = LIGHTS[i].diffuse[2] * MATERIAL.diffuse[2]; LIGHTS[i].diffuseMaterial[2] = LIGHTS[i].diffuse[2] * MATERIAL.diffuse[2];
LIGHTS[i].diffuseMaterial[3] = LIGHTS[i].diffuse[3] * MATERIAL.diffuse[3]; LIGHTS[i].diffuseMaterial[3] = LIGHTS[i].diffuse[3] * MATERIAL.diffuse[3];
} }
}
if(mask & SPECULAR_MASK) { if(mask & SPECULAR_MASK) {
for(i = 0; i < MAX_LIGHTS; ++i) {
LIGHTS[i].specularMaterial[0] = LIGHTS[i].specular[0] * MATERIAL.specular[0]; LIGHTS[i].specularMaterial[0] = LIGHTS[i].specular[0] * MATERIAL.specular[0];
LIGHTS[i].specularMaterial[1] = LIGHTS[i].specular[1] * MATERIAL.specular[1]; LIGHTS[i].specularMaterial[1] = LIGHTS[i].specular[1] * MATERIAL.specular[1];
LIGHTS[i].specularMaterial[2] = LIGHTS[i].specular[2] * MATERIAL.specular[2]; LIGHTS[i].specularMaterial[2] = LIGHTS[i].specular[2] * MATERIAL.specular[2];
@ -109,15 +111,10 @@ GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask) {
/* If ambient or emission are updated, we need to update /* If ambient or emission are updated, we need to update
* the base colour. */ * the base colour. */
if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) { if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) {
baseColour[0] = SCENE_AMBIENT[0] * MATERIAL.ambient[0] + MATERIAL.emissive[0]; MATERIAL.baseColour[0] = MATH_fmac(SCENE_AMBIENT[0], MATERIAL.ambient[0], MATERIAL.emissive[0]);
baseColour[1] = SCENE_AMBIENT[1] * MATERIAL.ambient[1] + MATERIAL.emissive[1]; MATERIAL.baseColour[1] = MATH_fmac(SCENE_AMBIENT[1], MATERIAL.ambient[1], MATERIAL.emissive[1]);
baseColour[2] = SCENE_AMBIENT[2] * MATERIAL.ambient[2] + MATERIAL.emissive[2]; MATERIAL.baseColour[2] = MATH_fmac(SCENE_AMBIENT[2], MATERIAL.ambient[2], MATERIAL.emissive[2]);
baseColour[3] = SCENE_AMBIENT[3] * MATERIAL.ambient[3] + MATERIAL.emissive[3]; MATERIAL.baseColour[3] = MATH_fmac(SCENE_AMBIENT[3], MATERIAL.ambient[3], MATERIAL.emissive[3]);
MATERIAL.baseColour[R8IDX] = (uint8_t)(_MIN(baseColour[0] * 255.0f, 255.0f));
MATERIAL.baseColour[G8IDX] = (uint8_t)(_MIN(baseColour[1] * 255.0f, 255.0f));
MATERIAL.baseColour[B8IDX] = (uint8_t)(_MIN(baseColour[2] * 255.0f, 255.0f));
MATERIAL.baseColour[A8IDX] = (uint8_t)(_MIN(baseColour[3] * 255.0f, 255.0f));
} }
} }
@ -326,11 +323,23 @@ void APIENTRY glColorMaterial(GLenum face, GLenum mode) {
COLOR_MATERIAL_MODE = mode; COLOR_MATERIAL_MODE = mode;
} }
void _glUpdateColourMaterial(GLfloat* colour) { GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) {
static const float scale = 1.0f / 255.0f;
output[0] = ((float) input[R8IDX]) * scale;
output[1] = ((float) input[G8IDX]) * scale;
output[2] = ((float) input[B8IDX]) * scale;
output[3] = ((float) input[A8IDX]) * scale;
}
void _glUpdateColourMaterial(const GLubyte* argb) {
if(!_glIsColorMaterialEnabled()) { if(!_glIsColorMaterialEnabled()) {
return; return;
} }
float colour[4];
bgra_to_float(argb, colour);
switch(COLOR_MATERIAL_MODE) { switch(COLOR_MATERIAL_MODE) {
case GL_AMBIENT: case GL_AMBIENT:
vec4cpy(MATERIAL.ambient, colour); vec4cpy(MATERIAL.ambient, colour);
@ -396,76 +405,56 @@ GL_FORCE_INLINE float faster_pow(const float x, const float p) {
} }
GL_FORCE_INLINE void _glLightVertexDirectional( GL_FORCE_INLINE void _glLightVertexDirectional(
uint8_t* final, uint8_t lid, float* final, uint8_t lid,
float LdotN, float NdotH) { float LdotN, float NdotH) {
float FI = (MATERIAL.exponent) ? float FI = (MATERIAL.exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f; faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f;
#define _PROCESS_COMPONENT(T, X) \ #define _PROCESS_COMPONENT(X) \
do { \ final[X] += (LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \
float F = (LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \ + (FI * LIGHTS[lid].specularMaterial[X]); \
+ (FI * LIGHTS[lid].specularMaterial[X]); \
uint8_t FO = (uint8_t) (_MIN(F * 255.0f, 255.0f)); \
final[T] += _MIN(FO, 255 - final[T]); \
} while(0);
_PROCESS_COMPONENT(R8IDX, 0); _PROCESS_COMPONENT(0);
_PROCESS_COMPONENT(G8IDX, 1); _PROCESS_COMPONENT(1);
_PROCESS_COMPONENT(B8IDX, 2); _PROCESS_COMPONENT(2);
#undef _PROCESS_COMPONENT #undef _PROCESS_COMPONENT
} }
GL_FORCE_INLINE void _glLightVertexPoint( GL_FORCE_INLINE void _glLightVertexPoint(
uint8_t* final, uint8_t lid, float* final, uint8_t lid,
float LdotN, float NdotH, float att) { float LdotN, float NdotH, float att) {
float FI = (MATERIAL.exponent) ? float FI = (MATERIAL.exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f; faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f;
#define _PROCESS_COMPONENT(T, X) \ #define _PROCESS_COMPONENT(X) \
do { \ final[X] += ((LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \
float F = (LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \ + (FI * LIGHTS[lid].specularMaterial[X])) * att; \
+ (FI * LIGHTS[lid].specularMaterial[X]); \
uint8_t FO = (uint8_t) (_MIN(F * att * 255.0f, 255.0f)); \
final[T] += _MIN(FO, 255 - final[T]); \
} while(0); \
_PROCESS_COMPONENT(R8IDX, 0); _PROCESS_COMPONENT(0);
_PROCESS_COMPONENT(G8IDX, 1); _PROCESS_COMPONENT(1);
_PROCESS_COMPONENT(B8IDX, 2); _PROCESS_COMPONENT(2);
#undef _PROCESS_COMPONENT #undef _PROCESS_COMPONENT
} }
GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) {
static const float scale = 1.0f / 255.0f;
output[0] = ((float) input[R8IDX]) * scale;
output[1] = ((float) input[G8IDX]) * scale;
output[2] = ((float) input[B8IDX]) * scale;
output[3] = ((float) input[A8IDX]) * scale;
}
void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t count) { void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t count) {
uint8_t i; int16_t i;
int32_t j; int32_t j;
Vertex* vertex = vertices; Vertex* vertex = vertices;
const EyeSpaceData* data = es; const EyeSpaceData* data = es;
/* This is the original vertex colour, before we replace it. It's /* Final colour of lighting output (will be clamped to argb) */
* used for colour material */ float final[4];
float vdiffuse[4];
for(j = 0; j < count; ++j, ++vertex, ++data) { for(j = 0; j < count; ++j, ++vertex, ++data) {
/* Unpack the colour for use in glColorMaterial */ _glUpdateColourMaterial(vertex->bgra);
bgra_to_float(vertex->bgra, vdiffuse);
_glUpdateColourMaterial(vdiffuse);
/* Copy the base colour across */ /* Copy the base colour across */
argbcpy(vertex->bgra, MATERIAL.baseColour); vec4cpy(final, MATERIAL.baseColour);
/* Direction to vertex in eye space */ /* Direction to vertex in eye space */
float Vx = -data->xyz[0]; float Vx = -data->xyz[0];
@ -505,7 +494,7 @@ void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t
if(NdotH < 0.0f) NdotH = 0.0f; if(NdotH < 0.0f) NdotH = 0.0f;
_glLightVertexDirectional( _glLightVertexDirectional(
vertex->bgra, final,
i, LdotN, NdotH i, LdotN, NdotH
); );
} else { } else {
@ -545,12 +534,17 @@ void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t
if(NdotH < 0.0f) NdotH = 0.0f; if(NdotH < 0.0f) NdotH = 0.0f;
_glLightVertexPoint( _glLightVertexPoint(
vertex->bgra, final,
i, LdotN, NdotH, att i, LdotN, NdotH, att
); );
} }
} }
} }
vertex->bgra[R8IDX] = clamp(final[0] * 255.0f, 0, 255);
vertex->bgra[G8IDX] = clamp(final[1] * 255.0f, 0, 255);
vertex->bgra[B8IDX] = clamp(final[2] * 255.0f, 0, 255);
vertex->bgra[A8IDX] = clamp(final[3] * 255.0f, 0, 255);
} }
} }

View File

@ -166,7 +166,7 @@ typedef struct {
/* Base ambient + emission colour for /* Base ambient + emission colour for
* the current material + light */ * the current material + light */
GLubyte baseColour[4]; GLfloat baseColour[4];
} Material; } Material;
typedef struct { typedef struct {
@ -206,18 +206,34 @@ typedef struct {
} Vertex; } Vertex;
#define argbcpy(src, dst) \ #define argbcpy(dst, src) \
*((GLuint*) src) = *((GLuint*) dst) \ *((GLuint*) dst) = *((GLuint*) src) \
#define vec4cpy(src, dst) \ typedef struct {
do { \ float xy[2];
src[0] = dst[0]; \ } _glvec2;
src[1] = dst[1]; \
src[2] = dst[2]; \
src[3] = dst[3]; \
} while(0) \
typedef struct {
float xyz[3];
} _glvec3;
typedef struct {
float xyzw[4];
} _glvec4;
#define vec2cpy(dst, src) \
*((_glvec2*) dst) = *((_glvec2*) src)
#define vec3cpy(dst, src) \
*((_glvec3*) dst) = *((_glvec3*) src)
#define vec4cpy(dst, src) \
*((_glvec4*) dst) = *((_glvec4*) src)
GL_FORCE_INLINE float clamp(float d, float min, float max) {
return (d < min) ? min : (d > max) ? max : d;
}
#define swapVertex(a, b) \ #define swapVertex(a, b) \
do { \ do { \