From cdaec9de8d74b88df6bec85289b54f36d8c43337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Ko=C5=82odziejski?= Date: Sun, 5 Jun 2022 20:59:38 +0200 Subject: [PATCH] TINYGL: Added fog support. --- graphics/module.mk | 1 + graphics/tinygl/api.cpp | 78 +++++++++++++++++++ graphics/tinygl/clip.cpp | 6 ++ graphics/tinygl/fog.cpp | 91 ++++++++++++++++++++++ graphics/tinygl/gl.h | 5 ++ graphics/tinygl/init.cpp | 8 ++ graphics/tinygl/misc.cpp | 3 + graphics/tinygl/opinfo.h | 2 + graphics/tinygl/vertex.cpp | 10 ++- graphics/tinygl/zbuffer.h | 99 +++++++++++++++++------ graphics/tinygl/zdirtyrect.cpp | 12 +++ graphics/tinygl/zdirtyrect.h | 4 + graphics/tinygl/zgl.h | 9 +++ graphics/tinygl/ztriangle.cpp | 138 ++++++++++++++++++++++----------- 14 files changed, 396 insertions(+), 70 deletions(-) create mode 100644 graphics/tinygl/fog.cpp diff --git a/graphics/module.mk b/graphics/module.mk index 5fdeb840398..40369cad9f2 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -57,6 +57,7 @@ MODULE_OBJS += \ tinygl/arrays.o \ tinygl/clear.o \ tinygl/clip.o \ + tinygl/fog.o \ tinygl/get.o \ tinygl/image_util.o \ tinygl/init.o \ diff --git a/graphics/tinygl/api.cpp b/graphics/tinygl/api.cpp index 5773a8c3028..1f03e394247 100644 --- a/graphics/tinygl/api.cpp +++ b/graphics/tinygl/api.cpp @@ -976,6 +976,84 @@ void tglTexCoordPointer(TGLint size, TGLenum type, TGLsizei stride, const TGLvoi c->gl_add_op(p); } +// fog + +void tglFogfv(TGLenum pname, const TGLfloat *params) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + TinyGL::GLParam p[6]; + + p[0].op = TinyGL::OP_Fog; + p[1].i = pname; + switch (pname) { + case TGL_FOG_MODE: + case TGL_FOG_DENSITY: + case TGL_FOG_START: + case TGL_FOG_END: + p[2].f = params[0]; + break; + case TGL_FOG_COLOR: + p[2].f = params[0]; + p[3].f = params[1]; + p[4].f = params[2]; + p[5].f = params[3]; + break; + default: + warning("tglFogfv: Unknown param"); + return; + } + + c->gl_add_op(p); +} + +void tglFogf(TGLenum pname, TGLfloat param) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + TinyGL::GLParam p[3]; + + p[0].op = TinyGL::OP_Fog; + p[1].i = pname; + p[2].f = param; + + c->gl_add_op(p); +} + +void tglFogiv(TGLenum pname, const TGLint *params) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + TinyGL::GLParam p[6]; + + p[0].op = TinyGL::OP_Fog; + p[1].i = pname; + switch (pname) { + case TGL_FOG_MODE: + case TGL_FOG_DENSITY: + case TGL_FOG_START: + case TGL_FOG_END: + p[2].f = (float)params[0]; + break; + case TGL_FOG_COLOR: + p[2].f = (float)params[0]; + p[3].f = (float)params[1]; + p[4].f = (float)params[2]; + p[5].f = (float)params[3]; + break; + default: + warning("tglFogiv: Unknown param"); + return; + } + + c->gl_add_op(p); +} + +void tglFogi(TGLenum pname, TGLint param) { + TinyGL::GLContext *c = TinyGL::gl_get_context(); + TinyGL::GLParam p[6]; + + p[0].op = TinyGL::OP_Fog; + p[1].i = pname; + p[2].i = (float)param; + + c->gl_add_op(p); +} + // gets void tglGetIntegerv(TGLenum pname, TGLint *data) { diff --git a/graphics/tinygl/clip.cpp b/graphics/tinygl/clip.cpp index c2b0dae2db3..a5c05cef690 100644 --- a/graphics/tinygl/clip.cpp +++ b/graphics/tinygl/clip.cpp @@ -47,6 +47,7 @@ void GLContext::gl_transform_to_viewport(GLVertex *v) { v->zp.x = (int)(v->pc.X * winv * viewport.scale.X + viewport.trans.X); v->zp.y = (int)(v->pc.Y * winv * viewport.scale.Y + viewport.trans.Y); v->zp.z = (int)(v->pc.Z * winv * viewport.scale.Z + viewport.trans.Z); + // color v->zp.r = (int)(v->color.X * ZB_POINT_RED_MAX); v->zp.g = (int)(v->color.Y * ZB_POINT_GREEN_MAX); @@ -58,6 +59,11 @@ void GLContext::gl_transform_to_viewport(GLVertex *v) { v->zp.s = (int)(v->tex_coord.X * ZB_POINT_ST_MAX); v->zp.t = (int)(v->tex_coord.Y * ZB_POINT_ST_MAX); } + + // fog + if (fog_enabled) { + v->zp.f = (int)(v->fog_factor * ZB_FOG_MAX); + } } void GLContext::gl_add_select1(int z1, int z2, int z3) { diff --git a/graphics/tinygl/fog.cpp b/graphics/tinygl/fog.cpp new file mode 100644 index 00000000000..3a5b664ddf4 --- /dev/null +++ b/graphics/tinygl/fog.cpp @@ -0,0 +1,91 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "graphics/tinygl/zgl.h" + +namespace TinyGL { + +void GLContext::glopFog(GLParam *p) { + int pname = p[1].i; + + switch (pname) { + case TGL_FOG_MODE: + switch (p[2].i) { + case TGL_LINEAR: + case TGL_EXP: + case TGL_EXP2: + fog_mode = p[2].i; + break; + default: + error("tglFog: unknown fog mode"); + return; + } + break; + case TGL_FOG_DENSITY: + if (p[2].f < 0.0f) { + error("tglFog: fog density negate param"); + return; + } + fog_density = p[2].f; + break; + case TGL_FOG_START: + fog_start = p[2].f; + break; + case TGL_FOG_END: + fog_end = p[2].f; + break; + case TGL_FOG_COLOR: + fog_color = Vector4(clampf(p[2].f, 0.0f, 1.0f), + clampf(p[3].f, 0.0f, 1.0f), + clampf(p[4].f, 0.0f, 1.0f), + clampf(p[5].f, 0.0f, 1.0f)); + break; + default: + error("tglFog: param not implemented"); + return; + } +} + +void GLContext::gl_calc_fog_factor(GLVertex *v) { + float eye_distance = sqrtf(v->ec.X * v->ec.X + v->ec.Y * v->ec.Y + v->ec.Z * v->ec.Z); + + switch (fog_mode) { + case TGL_LINEAR: { + float fog_distance = 1.0f; + if (fog_start != fog_end) + fog_distance /= (fog_end - fog_start); + v->fog_factor = (fog_end - eye_distance) * fog_distance; + } + break; + case TGL_EXP: + v->fog_factor = expf(-fog_density * eye_distance); + break; + case TGL_EXP2: + v->fog_factor = expf(-(fog_density * fog_density * eye_distance * eye_distance)); + break; + default: + break; + } + + clampf(v->fog_factor, 0.0f, 1.0f); +} + +} // end of namespace TinyGL diff --git a/graphics/tinygl/gl.h b/graphics/tinygl/gl.h index 78e095fd19a..c204f0e9508 100644 --- a/graphics/tinygl/gl.h +++ b/graphics/tinygl/gl.h @@ -832,6 +832,11 @@ void tglLightf(TGLenum light, TGLenum type, const TGLfloat v); void tglLightModeli(TGLenum pname, TGLint param); void tglLightModelfv(TGLenum pname, const TGLfloat *param); +// fog +void tglFogfv(TGLenum pname, const TGLfloat *params); +void tglFogf(TGLenum pname, TGLfloat param); +void tglFogiv(TGLenum pname, const TGLint *params); +void tglFogi(TGLenum pname, TGLint param); // misc void tglFlush(); diff --git a/graphics/tinygl/init.cpp b/graphics/tinygl/init.cpp index dea9d886e7e..bd977f45f19 100644 --- a/graphics/tinygl/init.cpp +++ b/graphics/tinygl/init.cpp @@ -178,6 +178,14 @@ void GLContext::init(int screenW, int screenH, Graphics::PixelFormat pixelFormat current_shade_model = TGL_SMOOTH; cull_face_enabled = 0; + // fog + fog_enabled = false; + fog_mode = TGL_EXP; + fog_color = Vector4(0.0f, 0.0f, 0.0f, 0.0f); + fog_density = 1.0f; + fog_start = 0.0f; + fog_end = 0.0f; + // clear clear_color = Vector4(0.0f, 0.0f, 0.0f, 0.0f); clear_depth = 1.0f; diff --git a/graphics/tinygl/misc.cpp b/graphics/tinygl/misc.cpp index e5213f3b884..511f473fb60 100644 --- a/graphics/tinygl/misc.cpp +++ b/graphics/tinygl/misc.cpp @@ -78,6 +78,9 @@ void GLContext::glopEnableDisable(GLParam *p) { case TGL_COLOR_MATERIAL: color_material_enabled = v; break; + case TGL_FOG: + fog_enabled = v; + break; case TGL_TEXTURE_2D: texture_2d_enabled = v; break; diff --git a/graphics/tinygl/opinfo.h b/graphics/tinygl/opinfo.h index 6953fd1746e..c4c6027ebd1 100644 --- a/graphics/tinygl/opinfo.h +++ b/graphics/tinygl/opinfo.h @@ -85,6 +85,8 @@ ADD_OP(DepthFunc, 1, "%d") ADD_OP(StencilFunc, 3, "%C %d %d") ADD_OP(StencilOp, 3, "%C %C %C") +ADD_OP(Fog, 5, "%d %f %f %f %f") + ADD_OP(CallList, 1, "%d") ADD_OP(Hint, 2, "%C %C") diff --git a/graphics/tinygl/vertex.cpp b/graphics/tinygl/vertex.cpp index 96220c92df8..db70b1bbd85 100644 --- a/graphics/tinygl/vertex.cpp +++ b/graphics/tinygl/vertex.cpp @@ -157,11 +157,17 @@ void GLContext::glopBegin(GLParam *p) { void GLContext::gl_vertex_transform(GLVertex *v) { Matrix4 *m; - if (lighting_enabled) { - // eye coordinates needed for lighting + if (lighting_enabled || fog_enabled) { + // eye coordinates needed for lighting and fog m = matrix_stack_ptr[0]; m->transform3x4(v->coord, v->ec); + } + if (fog_enabled) { + gl_calc_fog_factor(v); + } + + if (lighting_enabled) { // projection coordinates m = matrix_stack_ptr[1]; m->transform(v->ec, v->pc); diff --git a/graphics/tinygl/zbuffer.h b/graphics/tinygl/zbuffer.h index b0e5647d4ae..cc57efcc6de 100644 --- a/graphics/tinygl/zbuffer.h +++ b/graphics/tinygl/zbuffer.h @@ -41,6 +41,9 @@ namespace TinyGL { #define ZB_Z_BITS 16 +#define ZB_FOG_BITS 16 +#define ZB_FOG_MAX ( (1 << ZB_FOG_BITS) - 1 ) + #define ZB_POINT_Z_FRAC_BITS 14 #define ZB_POINT_ST_FRAC_BITS 14 @@ -80,11 +83,11 @@ struct Buffer { }; struct ZBufferPoint { - int x, y, z; // integer coordinates in the zbuffer - int s, t; // coordinates for the mapping + int x, y, z; // integer coordinates in the zbuffer + int s, t; // coordinates for the mapping int r, g, b, a; // color indexes - - float sz, tz; // temporary coordinates for mapping + float sz, tz; // temporary coordinates for mapping + int f; // fog factor bool operator==(const ZBufferPoint &other) const { return @@ -304,17 +307,19 @@ private: } } - template + template FORCEINLINE void putPixelNoTexture(int fbOffset, uint *pz, byte *ps, int _a, int x, int y, uint &z, uint &r, uint &g, uint &b, uint &a, - int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx); + int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx, + uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx); - template + template FORCEINLINE void putPixelTexture(int fbOffset, const TexelBuffer *texture, uint wrap_s, uint wrap_t, uint *pz, byte *ps, int _a, int x, int y, uint &z, int &t, int &s, uint &r, uint &g, uint &b, uint &a, - int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx); + int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx, + uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx); template FORCEINLINE void putPixelDepth(uint *pz, byte *ps, int _a, int x, int y, uint &z, int &dzdx); @@ -365,15 +370,43 @@ private: template FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc, uint z) { + writePixel(pixel, aSrc, rSrc, gSrc, bSrc, z, 0.0f, 0, 0, 0); + } + + template + FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc, float z, uint fog, byte fog_r, byte fog_g, byte fog_b) { if (kEnableAlphaTest) { if (!checkAlphaTest(aSrc)) return; } + if (kDepthWrite) { _zbuf[pixel] = z; } - if (kBlendingEnabled == false) { + if (kFogMode) { + int oneMinusFog = (1 << ZB_FOG_BITS) - fog; + int finalR = (rSrc * fog + fog_r * oneMinusFog) >> ZB_FOG_BITS; + int finalG = (gSrc * fog + fog_g * oneMinusFog) >> ZB_FOG_BITS; + int finalB = (bSrc * fog + fog_b * oneMinusFog) >> ZB_FOG_BITS; + if (finalR > 255) { + rSrc = 255; + } else { + rSrc = finalR; + } + if (finalG > 255) { + gSrc = 255; + } else { + gSrc = finalG; + } + if (finalB > 255) { + bSrc = 255; + } else { + bSrc = finalB; + } + } + + if (!kBlendingEnabled) { _pbuf.setPixelAt(pixel, aSrc, rSrc, gSrc, bSrc); } else { byte rDst, gDst, bDst, aDst; @@ -485,7 +518,7 @@ public: void clear(int clear_z, int z, int clear_color, int r, int g, int b, bool clearStencil, int stencilValue); void clearRegion(int x, int y, int w, int h, bool clearZ, int z, - bool clearColor, int r, int g, int b, bool clearStencil, int stencilValue); + bool clearColor, int r, int g, int b, bool clearStencil, int stencilValue); FORCEINLINE void setScissorRectangle(const Common::Rect &rect) { _clipRectangle = rect; @@ -545,7 +578,7 @@ public: _stencilDpfail = stencilDpfail; _stencilDppass = stencilDppass; } - + FORCEINLINE void setOffsetStates(int offsetStates) { _offsetStates = offsetStates; } @@ -569,6 +602,16 @@ public: _textureSizeMask = textureSizeMask; } + FORCEINLINE void setFogEnabled(bool enable) { + _fogEnabled = enable; + } + + FORCEINLINE void setFogColor(float colorR, float colorG, float colorB) { + _fogColorR = colorR; + _fogColorG = colorG; + _fogColorB = colorB; + } + private: /** @@ -582,29 +625,37 @@ private: void selectOffscreenBuffer(Buffer *buffer); void clearOffscreenBuffer(Buffer *buffer); - template + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); - template + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); - template + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); - template + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); - template + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); - template + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); - template + template + void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); + + template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); public: @@ -681,6 +732,10 @@ private: int _offsetStates; float _offsetFactor; float _offsetUnits; + bool _fogEnabled; + float _fogColorR; + float _fogColorG; + float _fogColorB; }; // memory.c diff --git a/graphics/tinygl/zdirtyrect.cpp b/graphics/tinygl/zdirtyrect.cpp index cb753f4d5ef..e1f66a82f33 100644 --- a/graphics/tinygl/zdirtyrect.cpp +++ b/graphics/tinygl/zdirtyrect.cpp @@ -473,6 +473,10 @@ RasterizationDrawCall::RasterizationState RasterizationDrawCall::captureState() state.wrapT = c->texture_wrap_t; state.lightingEnabled = c->lighting_enabled; state.textureVersion = c->current_texture->versionNumber; + state.fogEnabled = c->fog_enabled; + state.fogColorR = c->fog_color.X; + state.fogColorG = c->fog_color.Y; + state.fogColorB = c->fog_color.Z; memcpy(state.viewportScaling, c->viewport.scale._v, sizeof(c->viewport.scale._v)); memcpy(state.viewportTranslation, c->viewport.trans._v, sizeof(c->viewport.trans._v)); @@ -496,6 +500,8 @@ void RasterizationDrawCall::applyState(const RasterizationDrawCall::Rasterizatio c->fb->setOffsetStates(state.offsetStates); c->fb->setOffsetFactor(state.offsetFactor); c->fb->setOffsetUnits(state.offsetUnits); + c->fb->setFogEnabled(state.fogEnabled); + c->fb->setFogColor(state.fogColorR, state.fogColorG, state.fogColorB); c->blending_enabled = state.enableBlending; c->source_blending_factor = state.sfactor; @@ -533,6 +539,8 @@ void RasterizationDrawCall::applyState(const RasterizationDrawCall::Rasterizatio c->current_texture = state.texture; c->texture_wrap_s = state.wrapS; c->texture_wrap_t = state.wrapT; + c->fog_enabled = state.fogEnabled; + c->fog_color = Vector4(state.fogColorR, state.fogColorG, state.fogColorB, 1.0f); memcpy(c->viewport.scale._v, state.viewportScaling, sizeof(c->viewport.scale._v)); memcpy(c->viewport.trans._v, state.viewportTranslation, sizeof(c->viewport.trans._v)); @@ -752,6 +760,10 @@ bool RasterizationDrawCall::RasterizationState::operator==(const RasterizationSt texture2DEnabled == other.texture2DEnabled && texture == other.texture && textureVersion == texture->versionNumber && + fogEnabled == other.fogEnabled && + fogColorR == other.fogColorR && + fogColorG == other.fogColorG && + fogColorB == other.fogColorB && viewportTranslation[0] == other.viewportTranslation[0] && viewportTranslation[1] == other.viewportTranslation[1] && viewportTranslation[2] == other.viewportTranslation[2] && diff --git a/graphics/tinygl/zdirtyrect.h b/graphics/tinygl/zdirtyrect.h index 5f09466f4bc..867adb2e5f5 100644 --- a/graphics/tinygl/zdirtyrect.h +++ b/graphics/tinygl/zdirtyrect.h @@ -140,6 +140,10 @@ private: int stencilDppass; GLTexture *texture; uint wrapS, wrapT; + bool fogEnabled; + float fogColorR; + float fogColorG; + float fogColorB; bool operator==(const RasterizationState &other) const; }; diff --git a/graphics/tinygl/zgl.h b/graphics/tinygl/zgl.h index 821f52f0a3f..f146b1a9b01 100644 --- a/graphics/tinygl/zgl.h +++ b/graphics/tinygl/zgl.h @@ -149,6 +149,7 @@ struct GLVertex { Vector4 coord; Vector4 tex_coord; Vector4 color; + float fog_factor; // computed values Vector4 ec; // eye coordinates @@ -420,6 +421,13 @@ struct GLContext { bool color_mask_blue; bool color_mask_alpha; + bool fog_enabled; + int fog_mode; + Vector4 fog_color; + float fog_density; + float fog_start; + float fog_end; + Common::Rect _scissorRect; bool _enableDirtyRectangles; @@ -435,6 +443,7 @@ struct GLContext { bool _debugRectsEnabled; void gl_vertex_transform(GLVertex *v); + void gl_calc_fog_factor(GLVertex *v); public: // The glob* functions exposed to public, however they are only for internal use. diff --git a/graphics/tinygl/ztriangle.cpp b/graphics/tinygl/ztriangle.cpp index aab4c2adb09..b1b52ab1dbf 100644 --- a/graphics/tinygl/ztriangle.cpp +++ b/graphics/tinygl/ztriangle.cpp @@ -34,10 +34,11 @@ namespace TinyGL { static const int NB_INTERP = 8; -template +template FORCEINLINE void FrameBuffer::putPixelNoTexture(int fbOffset, uint *pz, byte *ps, int _a, - int x, int y, uint &z, uint &r, uint &g, uint &b, uint &a, - int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx) { + int x, int y, uint &z, uint &r, uint &g, uint &b, uint &a, + int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx, + uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx) { if (kEnableScissor && scissorPixel(x + _a, y)) { return; } @@ -58,9 +59,14 @@ FORCEINLINE void FrameBuffer::putPixelNoTexture(int fbOffset, uint *pz, byte *ps stencilOp(true, depthTestResult, ps + _a); } if (depthTestResult) { - writePixel(fbOffset + _a, a >> (ZB_POINT_ALPHA_BITS - 8), r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8), z); + writePixel + (fbOffset + _a, a >> (ZB_POINT_ALPHA_BITS - 8), r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8), + z, fog, fog_r, fog_g, fog_b); } z += dzdx; + if (kFogMode) { + fog += dfdx; + } if (kSmoothMode) { r += drdx; g += dgdx; @@ -69,12 +75,13 @@ FORCEINLINE void FrameBuffer::putPixelNoTexture(int fbOffset, uint *pz, byte *ps } } -template +template FORCEINLINE void FrameBuffer::putPixelTexture(int fbOffset, const TexelBuffer *texture, - uint wrap_s, uint wrap_t, uint *pz, byte *ps, int _a, - int x, int y, uint &z, int &t, int &s, - uint &r, uint &g, uint &b, uint &a, - int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx) { + uint wrap_s, uint wrap_t, uint *pz, byte *ps, int _a, + int x, int y, uint &z, int &t, int &s, + uint &r, uint &g, uint &b, uint &a, + int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx, + uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx) { if (kEnableScissor && scissorPixel(x + _a, y)) { return; } @@ -107,11 +114,14 @@ FORCEINLINE void FrameBuffer::putPixelTexture(int fbOffset, const TexelBuffer *t c_g = (c_g * l_g) >> (ZB_POINT_GREEN_BITS - 8); c_b = (c_b * l_b) >> (ZB_POINT_BLUE_BITS - 8); } - writePixel(fbOffset + _a, c_a, c_r, c_g, c_b, z); + writePixel(fbOffset + _a, c_a, c_r, c_g, c_b, z, fog >> ZB_FOG_BITS, fog_r, fog_g, fog_b); } z += dzdx; s += dsdx; t += dtdx; + if (kFogMode) { + fog += dfdx; + } if (kSmoothMode) { a += dadx; r += drdx; @@ -147,9 +157,9 @@ FORCEINLINE void FrameBuffer::putPixelDepth(uint *pz, byte *ps, int _a, int x, i z += dzdx; } -template +template void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { const TexelBuffer *texture; float fdzdx = 0, fndzdx = 0, ndszdx = 0, ndtzdx = 0; @@ -168,6 +178,7 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint int x2 = 0, dx2dy2 = 0; int z1 = 0, dzdx = 0, dzdy = 0, dzdl_min = 0, dzdl_max = 0; + int f1 = 0, dfdx = 0, dfdy = 0, dfdl_min = 0, dfdl_max = 0; int r1 = 0, drdx = 0, drdy = 0, drdl_min = 0, drdl_max = 0; int g1 = 0, dgdx = 0, dgdy = 0, dgdl_min = 0, dgdl_max = 0; @@ -177,6 +188,8 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint float sz1 = 0.0, dszdx = 0, dszdy = 0, dszdl_min = 0.0, dszdl_max = 0.0; float tz1 = 0.0, dtzdx = 0, dtzdy = 0, dtzdl_min = 0.0, dtzdl_max = 0.0; + byte fog_r = 0, fog_g = 0, fog_b = 0; + // we sort the vertex with increasing y if (p1->y < p0->y) { tp = p0; @@ -212,6 +225,16 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint fdx2 *= fz0; fdy2 *= fz0; + if (kInterpRGB && kFogMode) { + fog_r = _fogColorR * 255; + fog_g = _fogColorG * 255; + fog_b = _fogColorB * 255; + d1 = (float)(p1->f - p0->f); + d2 = (float)(p2->f - p0->f); + dfdx = (int)(fdy2 * d1 - fdy1 * d2); + dfdy = (int)(fdx1 * d2 - fdx2 * d1); + } + if (kInterpZ) { d1 = (float)(p1->z - p0->z); d2 = (float)(p2->z - p0->z); @@ -345,6 +368,12 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint dxdy_min = tmp >> 16; dxdy_max = dxdy_min + 1; + if (kInterpRGB && kFogMode) { + f1 = l1->f; + dfdl_min = (dfdy + dfdx * dxdy_min); + dfdl_max = dfdl_min + dfdx; + } + if (kInterpZ) { z1 = l1->z + polyOffset; dzdl_min = (dzdy + dzdx * dxdy_min); @@ -437,13 +466,16 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint uint *pz; byte *ps = nullptr; int pp; - uint z, r, g, b, a; + uint z, r, g, b, a, fog; int n = (x2 >> 16) - x1; pp = pp1 + x1; r = r1; g = g1; b = b1; a = a1; + if (kFogMode) { + fog = f1; + } if (kInterpZ) { pz = pz1 + x1; z = z1; @@ -452,10 +484,14 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint ps = ps1 + x1; } while (n >= 3) { - putPixelNoTexture(pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx); - putPixelNoTexture(pp, pz, ps, 1, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx); - putPixelNoTexture(pp, pz, ps, 2, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx); - putPixelNoTexture(pp, pz, ps, 3, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx); + putPixelNoTexture + (pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); + putPixelNoTexture + (pp, pz, ps, 1, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); + putPixelNoTexture + (pp, pz, ps, 2, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); + putPixelNoTexture + (pp, pz, ps, 3, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); pp += 4; if (kInterpZ) { pz += 4; @@ -467,7 +503,8 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint x += 4; } while (n >= 0) { - putPixelNoTexture(pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx); + putPixelNoTexture + (pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); pp += 1; if (kInterpZ) { pz += 1; @@ -482,7 +519,7 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint uint *pz; byte *ps = nullptr; int s, t; - uint z, r, g, b, a; + uint z, r, g, b, a, fog; int n, pp; float sz, tz, fz, zinv; int dsdx, dtdx; @@ -492,6 +529,9 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint zinv = (float)(1.0 / fz); pp = pp1 + x1; + if (kFogMode) { + fog = f1; + } if (kInterpZ) { pz = pz1 + x1; z = z1; @@ -518,8 +558,8 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint zinv = (float)(1.0 / fz); } for (int _a = 0; _a < NB_INTERP; _a++) { - putPixelTexture - (pp, texture, _wrapS, _wrapT, pz, ps, _a, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx); + putPixelTexture + (pp, texture, _wrapS, _wrapT, pz, ps, _a, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); } pp += NB_INTERP; if (kInterpZ) { @@ -545,8 +585,8 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint } while (n >= 0) { - putPixelTexture - (pp, texture, _wrapS, _wrapT, pz, ps, 0, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx); + putPixelTexture + (pp, texture, _wrapS, _wrapT, pz, ps, 0, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx); pp += 1; if (kInterpZ) { pz += 1; @@ -564,6 +604,9 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint if (error > 0) { error -= 0x10000; x1 += dxdy_max; + if (kInterpRGB && kFogMode) { + f1 += dfdl_max; + } if (kInterpZ) { z1 += dzdl_max; } @@ -579,6 +622,9 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint } } else { x1 += dxdy_min; + if (kInterpRGB && kFogMode) { + f1 += dfdl_min; + } if (kInterpZ) { z1 += dzdl_min; } @@ -614,60 +660,60 @@ void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint } } -template +template void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { if (_depthTestEnabled) { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } else { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } } -template +template void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { if (_sbuf && _stencilTestEnabled) { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } else { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } } -template +template void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { if (_blendingEnabled) { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } else { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } } -template +template void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { if (_enableScissor) { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } else { - fillTriangle(p0, p1, p2); + fillTriangle(p0, p1, p2); } } -template +template void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { if (_alphaTestEnabled) { + fillTriangle(p0, p1, p2); + } else { + fillTriangle(p0, p1, p2); + } +} + +template +void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { + if (_fogEnabled) { fillTriangle(p0, p1, p2); } else { fillTriangle(p0, p1, p2); } } -template -void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { - if (_depthWrite) { - fillTriangle(p0, p1, p2); - } else { - fillTriangle(p0, p1, p2); - } -} - void FrameBuffer::fillTriangleDepthOnly(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) { const bool interpZ = true; const bool interpRGB = false;