Implemented the lighting formula used by the DS + shininess table + fixed gfx3d_glGetDirectionalMatrix (I'm REALLY astonished that nobody ever seen how this function was incorrectly coded)
This commit is contained in:
parent
ab7c20492b
commit
bae065318f
|
@ -23,6 +23,7 @@
|
||||||
// plugin responsible only for drawing primitives.
|
// plugin responsible only for drawing primitives.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <math.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "gfx3d.h"
|
#include "gfx3d.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
|
@ -115,6 +116,9 @@ static u32 lightColor[4] = {0,0,0,0};
|
||||||
static u32 lightDirection[4] = {0,0,0,0};
|
static u32 lightDirection[4] = {0,0,0,0};
|
||||||
//material state:
|
//material state:
|
||||||
static u16 dsDiffuse, dsAmbient, dsSpecular, dsEmission;
|
static u16 dsDiffuse, dsAmbient, dsSpecular, dsEmission;
|
||||||
|
/* Shininess */
|
||||||
|
static float shininessTable[128] = {0};
|
||||||
|
static int shininessInd = 0;
|
||||||
|
|
||||||
|
|
||||||
//-----------cached things:
|
//-----------cached things:
|
||||||
|
@ -126,7 +130,8 @@ static u32 envMode=0;
|
||||||
static u32 lightMask=0;
|
static u32 lightMask=0;
|
||||||
//other things:
|
//other things:
|
||||||
static int texCoordinateTransform = 0;
|
static int texCoordinateTransform = 0;
|
||||||
static float cacheLightDirection[4][4];
|
static ALIGN(16) float cacheLightDirection[4][4];
|
||||||
|
static ALIGN(16) float cacheHalfVector[4][4];
|
||||||
//------------------
|
//------------------
|
||||||
|
|
||||||
#define RENDER_FRONT_SURFACE 0x80
|
#define RENDER_FRONT_SURFACE 0x80
|
||||||
|
@ -701,7 +706,13 @@ void gfx3d_glMaterial1(unsigned long val)
|
||||||
|
|
||||||
void gfx3d_glShininess (unsigned long val)
|
void gfx3d_glShininess (unsigned long val)
|
||||||
{
|
{
|
||||||
//INFO("Shininess=%i\n",val);
|
shininessTable[shininessInd++] = ((val & 0xFF) / 256.0f);
|
||||||
|
shininessTable[shininessInd++] = (((val >> 8) & 0xFF) / 256.0f);
|
||||||
|
shininessTable[shininessInd++] = (((val >> 16) & 0xFF) / 256.0f);
|
||||||
|
shininessTable[shininessInd++] = (((val >> 24) & 0xFF) / 256.0f);
|
||||||
|
|
||||||
|
if(shininessInd >= 128)
|
||||||
|
shininessInd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx3d_UpdateToonTable(void* toonTable)
|
void gfx3d_UpdateToonTable(void* toonTable)
|
||||||
|
@ -752,6 +763,8 @@ void gfx3d_glTexCoord(unsigned long val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define vec3dot(a, b) (((a[0]) * (b[0])) + ((a[1]) * (b[1])) + ((a[2]) * (b[2])))
|
||||||
|
|
||||||
void gfx3d_glNormal(unsigned long v)
|
void gfx3d_glNormal(unsigned long v)
|
||||||
{
|
{
|
||||||
int i,c;
|
int i,c;
|
||||||
|
@ -759,11 +772,6 @@ void gfx3d_glNormal(unsigned long v)
|
||||||
normalTable[(v>>10)&1023],
|
normalTable[(v>>10)&1023],
|
||||||
normalTable[(v>>20)&1023]};
|
normalTable[(v>>20)&1023]};
|
||||||
|
|
||||||
//find the line of sight vector
|
|
||||||
//TODO - only do this when the projection matrix changes
|
|
||||||
ALIGN(16) float lineOfSight[4] = { 0, 0, -1, 0 };
|
|
||||||
MatrixMultVec4x4 (mtxCurrent[0], lineOfSight);
|
|
||||||
|
|
||||||
if (texCoordinateTransform == 2)
|
if (texCoordinateTransform == 2)
|
||||||
{
|
{
|
||||||
last_s =( (normal[0] *mtxCurrent[3][0] + normal[1] *mtxCurrent[3][4] +
|
last_s =( (normal[0] *mtxCurrent[3][0] + normal[1] *mtxCurrent[3][4] +
|
||||||
|
@ -799,9 +807,6 @@ void gfx3d_glNormal(unsigned long v)
|
||||||
|
|
||||||
int vertexColor[3] = { emission[0], emission[1], emission[2] };
|
int vertexColor[3] = { emission[0], emission[1], emission[2] };
|
||||||
|
|
||||||
//do we need to normalize lineOfSight?
|
|
||||||
Vector3Normalize(lineOfSight);
|
|
||||||
|
|
||||||
for(i=0;i<4;i++) {
|
for(i=0;i<4;i++) {
|
||||||
if(!((lightMask>>i)&1))
|
if(!((lightMask>>i)&1))
|
||||||
continue;
|
continue;
|
||||||
|
@ -812,43 +817,22 @@ void gfx3d_glNormal(unsigned long v)
|
||||||
(lightColor[i]>>5)&0x1F,
|
(lightColor[i]>>5)&0x1F,
|
||||||
(lightColor[i]>>10)&0x1F };
|
(lightColor[i]>>10)&0x1F };
|
||||||
|
|
||||||
float dot = Vector3Dot(cacheLightDirection[i],normal);
|
/* This formula is the one used by the DS */
|
||||||
float diffuseComponent = std::max(0.f,dot);
|
/* Reference : http://nocash.emubase.de/gbatek.htm#ds3dpolygonlightparameters */
|
||||||
float specularComponent;
|
|
||||||
|
|
||||||
//a specular formula which I couldnt get working
|
float diffuseLevel = std::max(0.0f, -vec3dot(cacheLightDirection[i], normal));
|
||||||
//float halfAngle[3] = {
|
float shininessLevel = pow(std::max(0.0f, vec3dot(-cacheHalfVector[i], normal)), 2);
|
||||||
// (lineOfSight[0] + g_lightInfo[i].floatDirection[0])/2,
|
|
||||||
// (lineOfSight[1] + g_lightInfo[i].floatDirection[1])/2,
|
|
||||||
// (lineOfSight[2] + g_lightInfo[i].floatDirection[2])/2};
|
|
||||||
//float halfAngleLength = sqrt(halfAngle[0]*halfAngle[0]+halfAngle[1]*halfAngle[1]+halfAngle[2]*halfAngle[2]);
|
|
||||||
//float halfAngleNormalized[3] = {
|
|
||||||
// halfAngle[0]/halfAngleLength,
|
|
||||||
// halfAngle[1]/halfAngleLength,
|
|
||||||
// halfAngle[2]/halfAngleLength
|
|
||||||
//};
|
|
||||||
//
|
|
||||||
//float specularAngle = -Vector3Dot(halfAngleNormalized,normal);
|
|
||||||
//specularComponent = max(0,cos(specularAngle));
|
|
||||||
|
|
||||||
//a specular formula which seems to work
|
if(dsSpecular & 0x8000)
|
||||||
float temp[4];
|
{
|
||||||
float diff = Vector3Dot(normal,cacheLightDirection[i]);
|
shininessLevel = shininessTable[(int)(shininessLevel * 128)];
|
||||||
Vector3Copy(temp,normal);
|
}
|
||||||
Vector3Scale(temp,-2*diff);
|
|
||||||
Vector3Add(temp,cacheLightDirection[i]);
|
|
||||||
Vector3Scale(temp,-1);
|
|
||||||
specularComponent = std::max(0.f,Vector3Dot(lineOfSight,temp));
|
|
||||||
|
|
||||||
//if the game isnt producing unit normals, then we can accidentally out of range components. so lets saturate them here
|
for(c = 0; c < 3; c++)
|
||||||
//so we can at least keep for crashing. we're not sure what the hardware does in this case, but the game shouldnt be doing this.
|
{
|
||||||
specularComponent = std::max(0.f,std::min(1.f,specularComponent));
|
vertexColor[c] += ((specular[c] * _lightColor[c] * shininessLevel) / 31.0f);
|
||||||
diffuseComponent = std::max(0.f,std::min(1.f,diffuseComponent));
|
vertexColor[c] += ((diffuse[c] * _lightColor[c] * diffuseLevel) / 31.0f);
|
||||||
|
vertexColor[c] += ((ambient[c] * _lightColor[c]) / 31.0f);
|
||||||
for(c=0;c<3;c++) {
|
|
||||||
vertexColor[c] += (diffuseComponent*_lightColor[c]*diffuse[c])/31;
|
|
||||||
vertexColor[c] += (specularComponent*_lightColor[c]*specular[c])/31;
|
|
||||||
vertexColor[c] += ((float)_lightColor[c]*ambient[c])/31;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -870,9 +854,9 @@ signed long gfx3d_GetClipMatrix (unsigned int index)
|
||||||
|
|
||||||
signed long gfx3d_GetDirectionalMatrix (unsigned int index)
|
signed long gfx3d_GetDirectionalMatrix (unsigned int index)
|
||||||
{
|
{
|
||||||
index += (index/3);
|
int _index = (((index / 3) * 4) + (index % 3));
|
||||||
|
|
||||||
return (signed long)(mtxCurrent[2][(index)*(1<<12)]);
|
return (signed long)(mtxCurrent[2][_index]*(1<<12));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx3d_glLightDirection_cache(int index)
|
static void gfx3d_glLightDirection_cache(int index)
|
||||||
|
@ -880,10 +864,20 @@ static void gfx3d_glLightDirection_cache(int index)
|
||||||
u32 v = lightDirection[index];
|
u32 v = lightDirection[index];
|
||||||
|
|
||||||
// Convert format into floating point value
|
// Convert format into floating point value
|
||||||
cacheLightDirection[index][0] = -normalTable[v&1023];
|
cacheLightDirection[index][0] = normalTable[v&1023];
|
||||||
cacheLightDirection[index][1] = -normalTable[(v>>10)&1023];
|
cacheLightDirection[index][1] = normalTable[(v>>10)&1023];
|
||||||
cacheLightDirection[index][2] = -normalTable[(v>>20)&1023];
|
cacheLightDirection[index][2] = normalTable[(v>>20)&1023];
|
||||||
cacheLightDirection[index][3] = 0;
|
cacheLightDirection[index][3] = 0;
|
||||||
|
|
||||||
|
/* Multiply the vector by the directional matrix */
|
||||||
|
MatrixMultVec3x3(mtxCurrent[2], cacheLightDirection[index]);
|
||||||
|
|
||||||
|
/* Calculate the half vector */
|
||||||
|
float lineOfSight[4] = {0.0f, 0.0f, -1.0f, 0.0f};
|
||||||
|
for(int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
cacheHalfVector[index][i] = ((cacheLightDirection[index][i] + lineOfSight[i]) / 2.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1464,7 +1458,7 @@ void gfx3d_glGetLightColor(unsigned int index, unsigned int* dest)
|
||||||
//consider building a little state structure that looks exactly like this describes
|
//consider building a little state structure that looks exactly like this describes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SFORMAT SF_GFX3D[]={
|
SFORMAT SF_GFX3D[]={
|
||||||
{ "GCTL", 4, 1, &control},
|
{ "GCTL", 4, 1, &control},
|
||||||
{ "GPAT", 4, 1, &polyAttr},
|
{ "GPAT", 4, 1, &polyAttr},
|
||||||
|
@ -1562,4 +1556,4 @@ bool gfx3d_loadstate(std::istream* is)
|
||||||
gfx3d.vertlist->count=0;
|
gfx3d.vertlist->count=0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue