/* 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 . * */ /* * This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard, * which is licensed under the MIT license (see LICENSE). * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later). */ #ifndef GRAPHICS_TINYGL_ZBUFFER_H_ #define GRAPHICS_TINYGL_ZBUFFER_H_ #include "graphics/surface.h" #include "graphics/tinygl/texelbuffer.h" #include "graphics/tinygl/gl.h" #include "common/rect.h" #include "common/textconsole.h" namespace TinyGL { // Z buffer #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 #define ZB_POINT_ST_FRAC_SHIFT (ZB_POINT_ST_FRAC_BITS - 1) #define ZB_POINT_ST_MAX ( (_textureSize << ZB_POINT_ST_FRAC_BITS) - 1 ) #define ZB_POINT_RED_BITS 16 #define ZB_POINT_RED_FRAC_BITS 8 #define ZB_POINT_RED_FRAC_SHIFT (ZB_POINT_RED_FRAC_BITS - 1) #define ZB_POINT_RED_MAX ( (1 << ZB_POINT_RED_BITS) - 1 ) #define ZB_POINT_GREEN_BITS 16 #define ZB_POINT_GREEN_FRAC_BITS 8 #define ZB_POINT_GREEN_FRAC_SHIFT (ZB_POINT_GREEN_FRAC_BITS - 1) #define ZB_POINT_GREEN_MAX ( (1 << ZB_POINT_GREEN_BITS) - 1 ) #define ZB_POINT_BLUE_BITS 16 #define ZB_POINT_BLUE_FRAC_BITS 8 #define ZB_POINT_BLUE_FRAC_SHIFT (ZB_POINT_BLUE_FRAC_BITS - 1) #define ZB_POINT_BLUE_MAX ( (1 << ZB_POINT_BLUE_BITS) - 1 ) #define ZB_POINT_ALPHA_BITS 16 #define ZB_POINT_ALPHA_FRAC_BITS 8 #define ZB_POINT_ALPHA_FRAC_SHIFT (ZB_POINT_ALPHA_FRAC_BITS - 1) #define ZB_POINT_ALPHA_MAX ( (1 << ZB_POINT_ALPHA_BITS) - 1 ) #define RGB_TO_PIXEL(r, g, b) _pbufFormat.ARGBToColor(255, r, g, b) // Default to 255 alpha aka solid colour. static const int DRAW_DEPTH_ONLY = 0; static const int DRAW_FLAT = 1; static const int DRAW_SMOOTH = 2; struct GLTextureEnv; // defined in zdirtyrect.h struct Buffer { byte *pbuf; uint *zbuf; bool used; }; struct ZBufferPoint { 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 int f; // fog factor bool operator==(const ZBufferPoint &other) const { return x == other.x && y == other.y && z == other.z && s == other.s && t == other.t && r == other.r && g == other.g && b == other.b && a == other.a; } }; struct FrameBuffer { FrameBuffer(int width, int height, const Graphics::PixelFormat &format, bool enableStencilBuffer); ~FrameBuffer(); Graphics::PixelFormat getPixelFormat() { return _pbufFormat; } byte *getPixelBuffer() { return _pbuf; } int getPixelBufferWidth() { return _pbufWidth; } int getPixelBufferHeight() { return _pbufHeight; } int getPixelBufferPitch() { return _pbufPitch; } int getPixelBufferBpp() { return _pbufBpp; } const uint *getZBuffer() { return _zbuf; } Graphics::Surface *copyFromFrameBuffer(const Graphics::PixelFormat &dstFormat) { Graphics::Surface tmp; tmp.init(_pbufWidth, _pbufHeight, _pbufPitch, _pbuf, _pbufFormat); return tmp.convertTo(dstFormat); } void getSurfaceRef(Graphics::Surface &surface) { surface.init(_pbufWidth, _pbufHeight, _pbufPitch, _pbuf, _pbufFormat); } private: FORCEINLINE void setPixelAt(int pixel, uint32 value) { switch (_pbufBpp) { case 2: ((uint16 *) _pbuf)[pixel] = value; return; case 3: pixel *= 3; #if defined(SCUMM_BIG_ENDIAN) _pbuf[pixel + 0] = (value >> 16) & 0xFF; _pbuf[pixel + 1] = (value >> 8) & 0xFF; _pbuf[pixel + 2] = value & 0xFF; #elif defined(SCUMM_LITTLE_ENDIAN) _pbuf[pixel + 0] = value & 0xFF; _pbuf[pixel + 1] = (value >> 8) & 0xFF; _pbuf[pixel + 2] = (value >> 16) & 0xFF; #endif return; case 4: ((uint32 *) _pbuf)[pixel] = value; return; } error("setPixelAt: Unhandled bytesPerPixel %d", int(_pbufBpp)); } FORCEINLINE uint32 getPixelAt(int i) const { switch (_pbufBpp) { case 2: return ((uint16 *) _pbuf)[i]; case 3: i *= 3; #if defined(SCUMM_BIG_ENDIAN) return (_pbuf[i + 0] << 16) | (_pbuf[i + 1] << 8) | _pbuf[i + 2]; #elif defined(SCUMM_LITTLE_ENDIAN) return _pbuf[i + 0] | (_pbuf[i + 1] << 8) | (_pbuf[i + 2] << 16); #endif case 4: return ((uint32 *) _pbuf)[i]; } error("getPixelAt: Unhandled bytesPerPixel %d", int(_pbufBpp)); } FORCEINLINE bool compareDepth(uint &zSrc, uint &zDst) { if (!_depthTestEnabled) return true; switch (_depthFunc) { case TGL_NEVER: break; case TGL_LESS: if (zDst < zSrc) return true; break; case TGL_EQUAL: if (zDst == zSrc) return true; break; case TGL_LEQUAL: if (zDst <= zSrc) return true; break; case TGL_GREATER: if (zDst > zSrc) return true; break; case TGL_NOTEQUAL: if (zDst != zSrc) return true; break; case TGL_GEQUAL: if (zDst >= zSrc) return true; break; case TGL_ALWAYS: return true; } return false; } FORCEINLINE bool checkAlphaTest(byte aSrc) { if (!_alphaTestEnabled) return true; switch (_alphaTestFunc) { case TGL_NEVER: break; case TGL_LESS: if (aSrc < _alphaTestRefVal) return true; break; case TGL_EQUAL: if (aSrc == _alphaTestRefVal) return true; break; case TGL_LEQUAL: if (aSrc <= _alphaTestRefVal) return true; break; case TGL_GREATER: if (aSrc > _alphaTestRefVal) return true; break; case TGL_NOTEQUAL: if (aSrc != _alphaTestRefVal) return true; break; case TGL_GEQUAL: if (aSrc >= _alphaTestRefVal) return true; break; case TGL_ALWAYS: return true; } return false; } FORCEINLINE bool stencilTest(byte sSrc) { switch (_stencilTestFunc) { case TGL_NEVER: break; case TGL_LESS: if ((_stencilRefVal & _stencilMask) < (sSrc & _stencilMask)) return true; break; case TGL_LEQUAL: if ((_stencilRefVal & _stencilMask) <= (sSrc & _stencilMask)) return true; break; case TGL_GREATER: if ((_stencilRefVal & _stencilMask) > (sSrc & _stencilMask)) return true; break; case TGL_GEQUAL: if ((_stencilRefVal & _stencilMask) >= (sSrc & _stencilMask)) return true; break; case TGL_EQUAL: if ((_stencilRefVal & _stencilMask) == (sSrc & _stencilMask)) return true; break; case TGL_NOTEQUAL: if ((_stencilRefVal & _stencilMask) != (sSrc & _stencilMask)) return true; break; case TGL_ALWAYS: return true; } return false; } FORCEINLINE void stencilOp(bool stencilTestResult, bool depthTestResult, byte *sDst) { int op = !stencilTestResult ? _stencilSfail : !depthTestResult ? _stencilDpfail : _stencilDppass; byte oldValue = *sDst; byte newValue = oldValue; switch (op) { case TGL_KEEP: return; case TGL_ZERO: newValue = 0; break; case TGL_REPLACE: newValue = _stencilRefVal; break; case TGL_INCR: if (newValue < 255) newValue++; break; case TGL_INCR_WRAP: newValue++; break; case TGL_DECR: if (newValue > 0) newValue--; break; case TGL_DECR_WRAP: newValue--; break; case TGL_INVERT: newValue = ~newValue; } *sDst = (newValue & _stencilWriteMask) | (oldValue & ~_stencilWriteMask); } template FORCEINLINE void writePixel(int pixel, int value) { writePixel(pixel, value, 0); } template FORCEINLINE void writePixel(int pixel, int value, uint z) { if (kBlendingEnabled == false) { setPixelAt(pixel, value); if (kDepthWrite) { _zbuf[pixel] = z; } } else { byte rSrc, gSrc, bSrc, aSrc; _pbufFormat.colorToARGB(value, aSrc, rSrc, gSrc, bSrc); writePixel(pixel, aSrc, rSrc, gSrc, bSrc, z); } } FORCEINLINE void writePixel(int pixel, int value) { if (_alphaTestEnabled) { writePixel(pixel, value); } else { writePixel(pixel, value); } } template 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, uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx); enum class ColorMode { NoInterpolation, Default, // GL_TEXTURE_ENV_MODE == GL_MODULATE CustomTexEnv }; template 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, uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx); template void putPixelDepth(uint *pz, byte *ps, int _a, int x, int y, uint &z, int &dzdx); template FORCEINLINE void writePixel(int pixel, int value) { if (_blendingEnabled) { writePixel(pixel, value); } else { writePixel(pixel, value); } } FORCEINLINE void writePixel(int pixel, byte rSrc, byte gSrc, byte bSrc) { writePixel(pixel, 255, rSrc, gSrc, bSrc); } FORCEINLINE bool scissorPixel(int x, int y) { return !_clipRectangle.contains(x, y); } public: FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc) { if (_alphaTestEnabled) { writePixel(pixel, aSrc, rSrc, gSrc, bSrc); } else { writePixel(pixel, aSrc, rSrc, gSrc, bSrc); } } private: template FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc) { if (_blendingEnabled) { writePixel(pixel, aSrc, rSrc, gSrc, bSrc); } else { writePixel(pixel, aSrc, rSrc, gSrc, bSrc); } } template FORCEINLINE void writePixel(int pixel, byte aSrc, byte rSrc, byte gSrc, byte bSrc) { writePixel(pixel, aSrc, rSrc, gSrc, bSrc, 0); } 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 (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) { setPixelAt(pixel, _pbufFormat.ARGBToColor(aSrc, rSrc, gSrc, bSrc)); } else { byte rDst, gDst, bDst, aDst; _pbufFormat.colorToARGB(getPixelAt(pixel), aDst, rDst, gDst, bDst); switch (_sourceBlendingFactor) { case TGL_ZERO: rSrc = gSrc = bSrc = 0; break; case TGL_ONE: break; case TGL_DST_COLOR: rSrc = (rDst * rSrc) >> 8; gSrc = (gDst * gSrc) >> 8; bSrc = (bDst * bSrc) >> 8; break; case TGL_ONE_MINUS_DST_COLOR: rSrc = (rSrc * (255 - rDst)) >> 8; gSrc = (gSrc * (255 - gDst)) >> 8; bSrc = (bSrc * (255 - bDst)) >> 8; break; case TGL_SRC_ALPHA: rSrc = (rSrc * aSrc) >> 8; gSrc = (gSrc * aSrc) >> 8; bSrc = (bSrc * aSrc) >> 8; break; case TGL_ONE_MINUS_SRC_ALPHA: rSrc = (rSrc * (255 - aSrc)) >> 8; gSrc = (gSrc * (255 - aSrc)) >> 8; bSrc = (bSrc * (255 - aSrc)) >> 8; break; case TGL_DST_ALPHA: rSrc = (rSrc * aDst) >> 8; gSrc = (gSrc * aDst) >> 8; bSrc = (bSrc * aDst) >> 8; break; case TGL_ONE_MINUS_DST_ALPHA: rSrc = (rSrc * (255 - aDst)) >> 8; gSrc = (gSrc * (255 - aDst)) >> 8; bSrc = (bSrc * (255 - aDst)) >> 8; break; default: break; } switch (_destinationBlendingFactor) { case TGL_ZERO: rDst = gDst = bDst = 0; break; case TGL_ONE: break; case TGL_DST_COLOR: rDst = (rDst * rSrc) >> 8; gDst = (gDst * gSrc) >> 8; bDst = (bDst * bSrc) >> 8; break; case TGL_ONE_MINUS_DST_COLOR: rDst = (rDst * (255 - rSrc)) >> 8; gDst = (gDst * (255 - gSrc)) >> 8; bDst = (bDst * (255 - bSrc)) >> 8; break; case TGL_SRC_ALPHA: rDst = (rDst * aSrc) >> 8; gDst = (gDst * aSrc) >> 8; bDst = (bDst * aSrc) >> 8; break; case TGL_ONE_MINUS_SRC_ALPHA: rDst = (rDst * (255 - aSrc)) >> 8; gDst = (gDst * (255 - aSrc)) >> 8; bDst = (bDst * (255 - aSrc)) >> 8; break; case TGL_DST_ALPHA: rDst = (rDst * aDst) >> 8; gDst = (gDst * aDst) >> 8; bDst = (bDst * aDst) >> 8; break; case TGL_ONE_MINUS_DST_ALPHA: rDst = (rDst * (255 - aDst)) >> 8; gDst = (gDst * (255 - aDst)) >> 8; bDst = (bDst * (255 - aDst)) >> 8; break; case TGL_SRC_ALPHA_SATURATE: { int factor = aSrc < 1 - aDst ? aSrc : 1 - aDst; rDst = (rDst * factor) >> 8; gDst = (gDst * factor) >> 8; bDst = (bDst * factor) >> 8; } break; default: break; } int finalR = rDst + rSrc; int finalG = gDst + gSrc; int finalB = bDst + bSrc; if (finalR > 255) { finalR = 255; } if (finalG > 255) { finalG = 255; } if (finalB > 255) { finalB = 255; } setPixelAt(pixel, _pbufFormat.RGBToColor(finalR, finalG, finalB)); } } 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); const Common::Rect &getClippingRectangle() const { return _clipRectangle; } void setupScissor(bool enable, const int (&scissor)[4], const Common::Rect *clippingRectangle) { _clippingEnabled = enable || clippingRectangle; if (enable && clippingRectangle) { _clipRectangle = clippingRectangle->findIntersectingRect(Common::Rect( scissor[0], // all viewport calculations are already flipped upside down _pbufHeight - scissor[1] - scissor[3], scissor[0] + scissor[2], _pbufHeight - scissor[1])); } else if (enable) { _clipRectangle = Common::Rect( scissor[0], // all viewport calculations are already flipped upside down _pbufHeight - scissor[1] - scissor[3], scissor[0] + scissor[2], _pbufHeight - scissor[1]); } else if (clippingRectangle) { _clipRectangle = *clippingRectangle; } else { _clipRectangle = Common::Rect(0, 0, _pbufWidth, _pbufHeight); } } void enableBlending(bool enable) { _blendingEnabled = enable; } void setBlendingFactors(int sFactor, int dFactor) { _sourceBlendingFactor = sFactor; _destinationBlendingFactor = dFactor; } void enableAlphaTest(bool enable) { _alphaTestEnabled = enable; } void setAlphaTestFunc(int func, int ref) { _alphaTestFunc = func; _alphaTestRefVal = ref; } void enableDepthTest(bool enable) { _depthTestEnabled = enable; } void setDepthFunc(int func) { _depthFunc = func; } void enableDepthWrite(bool enable) { _depthWrite = enable; } void enableStencilTest(bool enable) { _stencilTestEnabled = enable; } void setStencilWriteMask(uint stencilWriteMask) { _stencilWriteMask = stencilWriteMask; } void enablePolygonStipple(bool enable) { _polygonStippleEnabled = enable; } void setPolygonStipplePattern(const byte *stipple) { _polygonStipplePattern = stipple; } void enableTwoColorStipple(bool enable) { _twoColorStippleEnabled = enable; } void setStippleColor(int r, int g, int b) { _stippleColor = RGB_TO_PIXEL(r, g, b); } void setStencilTestFunc(int stencilFunc, byte stencilValue, byte stencilMask) { _stencilTestFunc = stencilFunc; _stencilRefVal = stencilValue; _stencilMask = stencilMask; } void setStencilOp(int stencilSfail, int stencilDpfail, int stencilDppass) { _stencilSfail = stencilSfail; _stencilDpfail = stencilDpfail; _stencilDppass = stencilDppass; } void setOffsetStates(int offsetStates) { _offsetStates = offsetStates; } void setOffsetFactor(float offsetFactor) { _offsetFactor = offsetFactor; } void setOffsetUnits(float offsetUnits) { _offsetUnits = offsetUnits; } void setTexture(const TexelBuffer *texture, uint wraps, uint wrapt) { _currentTexture = texture; _wrapS = wraps; _wrapT = wrapt; } void setTextureEnvironment(const GLTextureEnv *texEnv) { _textureEnv = texEnv; } void setTextureSizeAndMask(int textureSize, int textureSizeMask) { _textureSize = textureSize; _textureSizeMask = textureSizeMask; } void setFogEnabled(bool enable) { _fogEnabled = enable; } void setFogColor(float colorR, float colorG, float colorB) { _fogColorR = colorR; _fogColorG = colorG; _fogColorB = colorB; } private: /** * Blit the buffer to the screen buffer, checking the depth of the pixels. * Eack pixel is copied if and only if its depth value is bigger than the * depth value of the screen pixel, so if it is 'above'. */ Buffer *genOffscreenBuffer(); void delOffscreenBuffer(Buffer *buffer); void blitOffscreenBuffer(Buffer *buffer); void selectOffscreenBuffer(Buffer *buffer); void clearOffscreenBuffer(Buffer *buffer); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); template void fillTriangleTextureMapping(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); public: void fillTriangleTextureMappingPerspectiveSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); void fillTriangleTextureMappingPerspectiveFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); void fillTriangleDepthOnly(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); void fillTriangleFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); void fillTriangleSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2); void plot(ZBufferPoint *p); void fillLine(ZBufferPoint *p1, ZBufferPoint *p2); void fillLineZ(ZBufferPoint *p1, ZBufferPoint *p2); private: void fillLineFlatZ(ZBufferPoint *p1, ZBufferPoint *p2); void fillLineInterpZ(ZBufferPoint *p1, ZBufferPoint *p2); void fillLineFlat(ZBufferPoint *p1, ZBufferPoint *p2); void fillLineInterp(ZBufferPoint *p1, ZBufferPoint *p2); template FORCEINLINE void putPixel(uint pixelOffset, int color, int x, int y, uint z); template FORCEINLINE void putPixel(uint pixelOffset, int color, int x, int y, uint z); template FORCEINLINE void putPixel(uint pixelOffset, int color, int x, int y); template void drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2); template void drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2); void applyTextureEnvironment( int internalformat, uint previousA, uint previousR, uint previousG, uint previousB, byte &texA, byte &texR, byte &texG, byte &texB); // the same as GL_TEXTURE_ENV_MODE == GL_MODULATE as fast-path for the default mode void applyModulation( uint previousA, uint previousR, uint previousG, uint previousB, byte &texA, byte &texR, byte &texG, byte &texB); Buffer _offscreenBuffer; byte *_pbuf; int _pbufWidth; int _pbufHeight; int _pbufPitch; Graphics::PixelFormat _pbufFormat; int _pbufBpp; uint *_zbuf; byte *_sbuf; bool _enableStencil; int _textureSize; int _textureSizeMask; Common::Rect _clipRectangle; bool _clippingEnabled; const TexelBuffer *_currentTexture; const GLTextureEnv *_textureEnv; uint _wrapS, _wrapT; bool _blendingEnabled; int _sourceBlendingFactor; int _destinationBlendingFactor; bool _alphaTestEnabled; int _alphaTestFunc; int _alphaTestRefVal; bool _depthTestEnabled; bool _depthWrite; bool _stencilTestEnabled; int _stencilTestFunc; byte _stencilRefVal; byte _stencilMask; byte _stencilWriteMask; int _stencilSfail; int _stencilDpfail; int _stencilDppass; bool _polygonStippleEnabled; bool _twoColorStippleEnabled; uint32 _stippleColor; const byte *_polygonStipplePattern; int _depthFunc; int _offsetStates; float _offsetFactor; float _offsetUnits; bool _fogEnabled; float _fogColorR; float _fogColorG; float _fogColorB; }; // memory.c void gl_free(void *p); void *gl_malloc(int size); void *gl_zalloc(int size); void *gl_realloc(void *p, int size); } // end of namespace TinyGL #endif