Implement projective texture mapping. It's not used a great deal but good to have.

This commit is contained in:
Henrik Rydgard 2013-04-17 21:41:47 +02:00
parent 06cbcd07a6
commit c04ce5a64e
5 changed files with 50 additions and 15 deletions

View File

@ -85,6 +85,7 @@ void ComputeFragmentShaderID(FragmentShaderID *id) {
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue();
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
int lmode = (gstate.lmode & 1) && gstate.isLightingEnabled();
bool doTextureProjection = gstate.getUVGenMode() == 1;
// id->d[0] |= (gstate.clearmode & 1);
if (gstate.isTextureMapEnabled()) {
@ -101,6 +102,7 @@ void ComputeFragmentShaderID(FragmentShaderID *id) {
if (enableColorTest)
id->d[0] |= (gstate.colortest & 0x3) << 13; // color test func
id->d[0] |= (enableFog & 1) << 15;
id->d[0] |= (doTextureProjection & 1) << 16;
}
}
@ -117,11 +119,11 @@ void GenerateFragmentShader(char *buffer) {
int lmode = (gstate.lmode & 1) && gstate.isLightingEnabled();
int doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !gstate.isModeClear();
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && !gstate.isModeClear();
bool enableColorDoubling = (gstate.texfunc & 0x10000) != 0;
bool doTextureProjection = gstate.getUVGenMode() == 1;
if (doTexture)
WRITE(p, "uniform sampler2D tex;\n");
@ -145,7 +147,12 @@ void GenerateFragmentShader(char *buffer) {
#endif
}
if (doTexture)
WRITE(p, "varying vec2 v_texcoord;\n");
{
if (doTextureProjection)
WRITE(p, "varying vec3 v_texcoord;\n");
else
WRITE(p, "varying vec2 v_texcoord;\n");
}
WRITE(p, "void main() {\n");
@ -163,7 +170,11 @@ void GenerateFragmentShader(char *buffer) {
}
if (gstate.textureMapEnable & 1) {
WRITE(p, " vec4 t = texture2D(tex, v_texcoord);\n");
if (doTextureProjection) {
WRITE(p, " vec4 t = texture2DProj(tex, v_texcoord);\n");
} else {
WRITE(p, " vec4 t = texture2D(tex, v_texcoord);\n");
}
WRITE(p, " vec4 p = v_color0;\n");
if (gstate.texfunc & 0x100) { // texfmt == RGBA
@ -234,7 +245,7 @@ void GenerateFragmentShader(char *buffer) {
#ifdef DEBUG_SHADER
if (doTexture) {
WRITE(p, " gl_FragColor = texture2D(tex, v_texcoord);\n");
WRITE(p, " gl_FragColor = texture2D(tex, v_texcoord.xy);\n");
} else {
WRITE(p, " gl_FragColor = vec4(1,0,1,1);\n");
}

View File

@ -77,6 +77,11 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs)
ERROR_LOG(G3D, "Could not link program:\n %s", buf);
ERROR_LOG(G3D, "VS:\n%s", vs->source().c_str());
ERROR_LOG(G3D, "FS:\n%s", fs->source().c_str());
#ifdef SHADERLOG
OutputDebugString(buf);
OutputDebugString(vs->source().c_str());
OutputDebugString(fs->source().c_str());
#endif
delete [] buf; // we're dead!
}
return;

View File

@ -486,7 +486,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
float v[3] = {0, 0, 0};
float c0[4] = {1, 1, 1, 1};
float c1[4] = {0, 0, 0, 0};
float uv[2] = {0, 0};
float uv[3] = {0, 0, 0};
float fogCoef = 1.0f;
if (throughmode) {
@ -615,6 +615,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
// Texture scale/offset is only performed in this mode.
uv[0] = uscale * (ruv[0]*gstate_c.uScale + gstate_c.uOff);
uv[1] = vscale * (ruv[1]*gstate_c.vScale + gstate_c.vOff);
uv[2] = 1.0f;
break;
case 1:
{
@ -640,6 +641,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
Vec3ByMatrix43(uvw, &source.x, gstate.tgenMatrix);
uv[0] = uvw[0];
uv[1] = uvw[1];
uv[2] = uvw[2];
}
break;
case 2:
@ -650,6 +652,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
uv[0] = (1.0f + (lightpos0 * normal))/2.0f;
uv[1] = (1.0f - (lightpos1 * normal))/2.0f;
uv[2] = 1.0f;
}
break;
case 3:
@ -665,7 +668,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
// TODO: Write to a flexible buffer, we don't always need all four components.
memcpy(&transformed[index].x, v, 3 * sizeof(float));
transformed[index].fog = fogCoef;
memcpy(&transformed[index].u, uv, 2 * sizeof(float));
memcpy(&transformed[index].u, uv, 3 * sizeof(float));
if (gstate_c.flipTexture) {
if (throughmode)
transformed[index].v = 1.0f - transformed[index].v;
@ -763,11 +766,12 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
glBindBuffer(GL_ARRAY_BUFFER, vbo_[curVbo_]);
glBufferData(GL_ARRAY_BUFFER, vertexSize * numTrans, drawBuffer, GL_STREAM_DRAW);
drawBuffer = 0; // so that the calls use offsets instead.
}
}
bool doTextureProjection = gstate.getUVGenMode() == 1;
glVertexAttribPointer(program->a_position, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
if (program->a_texcoord != -1) glVertexAttribPointer(program->a_texcoord, 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 4);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 6 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 7 * 4);
if (program->a_texcoord != -1) glVertexAttribPointer(program->a_texcoord, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 4);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 7 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 8 * 4);
if (drawIndexed) {
if (useVBO) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_[curVbo_]);

View File

@ -63,7 +63,7 @@ struct DecVtxFormat {
struct TransformedVertex
{
float x, y, z, fog; // in case of morph, preblend during decode
float u; float v; // scaled by uscale, vscale, if there
float u; float v; float w; // scaled by uscale, vscale, if there
u8 color0[4]; // prelit
u8 color1[3]; // prelit
};

View File

@ -45,6 +45,7 @@ bool CanUseHardwareTransform(int prim) {
// prim so we can special case for RECTANGLES :(
void ComputeVertexShaderID(VertexShaderID *id, int prim) {
int doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doTextureProjection = gstate.getUVGenMode() == 1;
bool hasColor = (gstate.vertType & GE_VTYPE_COL_MASK) != 0;
bool hasNormal = (gstate.vertType & GE_VTYPE_NRM_MASK) != 0;
@ -59,7 +60,10 @@ void ComputeVertexShaderID(VertexShaderID *id, int prim) {
id->d[0] |= doTexture << 3;
id->d[0] |= (hasColor & 1) << 4;
if (doTexture)
{
id->d[0] |= (gstate_c.flipTexture & 1) << 5;
id->d[0] |= (doTextureProjection & 1) << 6;
}
if (CanUseHardwareTransform(prim)) {
id->d[0] |= 1 << 8;
@ -149,6 +153,7 @@ void GenerateVertexShader(int prim, char *buffer) {
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
bool throughmode = (gstate.vertType & GE_VTYPE_THROUGH_MASK) != 0;
bool flipV = gstate_c.flipTexture;
bool doTextureProjection = gstate.getUVGenMode() == 1;
DoLightComputation doLight[4] = {LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF};
if (hwXForm) {
@ -173,7 +178,12 @@ void GenerateVertexShader(int prim, char *buffer) {
else
WRITE(p, "attribute vec4 a_position;\n"); // need to pass the fog coord in w
if (doTexture) WRITE(p, "attribute vec2 a_texcoord;\n");
if (doTexture) {
if (!hwXForm && doTextureProjection)
WRITE(p, "attribute vec3 a_texcoord;\n");
else
WRITE(p, "attribute vec2 a_texcoord;\n");
}
if (hasColor) {
WRITE(p, "attribute lowp vec4 a_color0;\n");
if (lmode && !hwXForm) // only software transform supplies color1 as vertex data
@ -240,7 +250,12 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, "varying lowp vec4 v_color0;\n");
if (lmode) WRITE(p, "varying lowp vec3 v_color1;\n");
if (doTexture) WRITE(p, "varying vec2 v_texcoord;\n");
if (doTexture) {
if (doTextureProjection)
WRITE(p, "varying vec3 v_texcoord;\n");
else
WRITE(p, "varying vec2 v_texcoord;\n");
}
if (enableFog) WRITE(p, "varying float v_fogdepth;\n");
WRITE(p, "void main() {\n");
@ -410,8 +425,8 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, " vec3 temp_tc = a_normal;\n");
break;
}
// Transform by texture matrix
WRITE(p, " v_texcoord = (u_texmtx * vec4(temp_tc, 1.0)).xy;\n");
// Transform by texture matrix. XYZ as we are doing projection mapping.
WRITE(p, " v_texcoord = (u_texmtx * vec4(temp_tc, 1.0)).xyz;\n");
break;
case 2: // Shade mapping - use dots from light sources.