2016-09-14 18:01:13 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright(C) 2009-2016 Christoph Oelckers
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
2013-06-23 07:49:34 +00:00
|
|
|
/*
|
|
|
|
** gl_renderstate.cpp
|
|
|
|
** Render state maintenance
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2014-05-12 12:45:41 +00:00
|
|
|
#include "templates.h"
|
2018-04-02 13:58:28 +00:00
|
|
|
#include "doomstat.h"
|
2018-04-26 22:22:00 +00:00
|
|
|
#include "r_data/colormaps.h"
|
2018-05-16 21:34:52 +00:00
|
|
|
#include "gl_load/gl_system.h"
|
2018-05-16 21:21:21 +00:00
|
|
|
#include "gl_load/gl_interface.h"
|
2014-05-10 19:47:07 +00:00
|
|
|
#include "gl/data/gl_vertexbuffer.h"
|
2018-04-25 18:33:55 +00:00
|
|
|
#include "hwrenderer/utility/hw_cvars.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/shaders/gl_shader.h"
|
|
|
|
#include "gl/renderer/gl_renderer.h"
|
2014-08-01 18:59:39 +00:00
|
|
|
#include "gl/dynlights//gl_lightbuffer.h"
|
2016-09-01 15:14:51 +00:00
|
|
|
#include "gl/renderer/gl_renderbuffers.h"
|
2018-07-14 11:05:49 +00:00
|
|
|
#include "gl/textures/gl_hwtexture.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2018-10-20 19:08:24 +00:00
|
|
|
static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR };
|
|
|
|
|
2018-10-20 11:05:36 +00:00
|
|
|
FGLRenderState gl_RenderState;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-07-13 18:41:20 +00:00
|
|
|
static VSMatrix identityMatrix(1);
|
2014-07-13 20:37:34 +00:00
|
|
|
TArray<VSMatrix> gl_MatrixStack;
|
2014-07-13 18:41:20 +00:00
|
|
|
|
2017-11-25 12:51:09 +00:00
|
|
|
static void matrixToGL(const VSMatrix &mat, int loc)
|
|
|
|
{
|
|
|
|
glUniformMatrix4fv(loc, 1, false, (float*)&mat);
|
|
|
|
}
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2018-10-20 11:05:36 +00:00
|
|
|
void FGLRenderState::Reset()
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2018-10-20 11:34:29 +00:00
|
|
|
FRenderState::Reset();
|
|
|
|
mSplitEnabled = false;
|
2013-06-23 07:49:34 +00:00
|
|
|
mSrcBlend = GL_SRC_ALPHA;
|
|
|
|
mDstBlend = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
mBlendEquation = GL_FUNC_ADD;
|
2014-05-10 19:47:07 +00:00
|
|
|
mVertexBuffer = mCurrentVertexBuffer = NULL;
|
2018-01-25 18:53:55 +00:00
|
|
|
mGlossiness = 0.0f;
|
|
|
|
mSpecularLevel = 0.0f;
|
2016-08-25 23:36:21 +00:00
|
|
|
mShaderTimer = 0.0f;
|
2015-04-05 16:55:21 +00:00
|
|
|
ClearClipSplit();
|
2014-07-27 10:33:54 +00:00
|
|
|
|
|
|
|
stSrcBlend = stDstBlend = -1;
|
|
|
|
stBlendEquation = -1;
|
2016-08-25 23:36:21 +00:00
|
|
|
stAlphaTest = 0;
|
2014-11-27 11:26:52 +00:00
|
|
|
mLastDepthClamp = true;
|
2016-08-25 23:36:21 +00:00
|
|
|
mInterpolationFactor = 0.0f;
|
|
|
|
|
|
|
|
mEffectState = 0;
|
|
|
|
activeShader = nullptr;
|
2016-09-20 00:57:57 +00:00
|
|
|
mPassType = NORMAL_PASS;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Apply shader settings
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2018-10-20 11:05:36 +00:00
|
|
|
bool FGLRenderState::ApplyShader()
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2017-11-15 03:46:28 +00:00
|
|
|
static uint64_t firstFrame = 0;
|
|
|
|
// if firstFrame is not yet initialized, initialize it to current time
|
|
|
|
// if we're going to overflow a float (after ~4.6 hours, or 24 bits), re-init to regain precision
|
2018-09-16 20:38:20 +00:00
|
|
|
if ((firstFrame == 0) || (screen->FrameTime - firstFrame >= 1<<24) || level.ShaderStartTime >= firstFrame)
|
2017-11-14 20:52:54 +00:00
|
|
|
firstFrame = screen->FrameTime;
|
|
|
|
|
2016-01-30 22:01:11 +00:00
|
|
|
static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f };
|
2014-06-21 13:50:32 +00:00
|
|
|
if (mSpecialEffect > EFF_NONE)
|
|
|
|
{
|
2016-09-20 00:57:57 +00:00
|
|
|
activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect, mPassType);
|
2014-06-21 13:50:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-25 19:22:51 +00:00
|
|
|
activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, mPassType);
|
2014-06-21 13:50:32 +00:00
|
|
|
activeShader->Bind();
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2018-09-16 20:38:20 +00:00
|
|
|
int fogset = 0;
|
|
|
|
|
|
|
|
if (mFogEnabled)
|
|
|
|
{
|
|
|
|
if (mFogEnabled == 2)
|
|
|
|
{
|
|
|
|
fogset = -3; // 2D rendering with 'foggy' overlay.
|
|
|
|
}
|
|
|
|
else if ((mFogColor & 0xffffff) == 0)
|
|
|
|
{
|
|
|
|
fogset = gl_fogmode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fogset = -gl_fogmode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-14 22:37:13 +00:00
|
|
|
glVertexAttrib4fv(VATTR_COLOR, mColor.vec);
|
2017-01-28 17:26:52 +00:00
|
|
|
glVertexAttrib4fv(VATTR_NORMAL, mNormal.vec);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
activeShader->muDesaturation.Set(mDesaturation / 255.f);
|
2018-09-16 20:38:20 +00:00
|
|
|
activeShader->muFogEnabled.Set(fogset);
|
2018-10-21 06:14:48 +00:00
|
|
|
activeShader->muTextureMode.Set(mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
|
2014-06-21 13:50:32 +00:00
|
|
|
activeShader->muLightParms.Set(mLightParms);
|
|
|
|
activeShader->muFogColor.Set(mFogColor);
|
2017-01-28 17:26:52 +00:00
|
|
|
activeShader->muObjectColor.Set(mObjectColor);
|
2018-03-29 14:21:21 +00:00
|
|
|
activeShader->muObjectColor2.Set(mObjectColor2);
|
2014-07-01 07:52:41 +00:00
|
|
|
activeShader->muDynLightColor.Set(mDynColor.vec);
|
2014-06-29 09:00:21 +00:00
|
|
|
activeShader->muInterpolationFactor.Set(mInterpolationFactor);
|
2017-12-04 22:39:44 +00:00
|
|
|
activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.);
|
2014-07-30 21:13:16 +00:00
|
|
|
activeShader->muAlphaThreshold.Set(mAlphaThreshold);
|
2018-04-15 10:21:40 +00:00
|
|
|
activeShader->muLightIndex.Set(-1);
|
2015-04-05 16:55:21 +00:00
|
|
|
activeShader->muClipSplit.Set(mClipSplit);
|
2018-01-25 18:53:55 +00:00
|
|
|
activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel);
|
2014-05-12 12:45:41 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
if (mGlowEnabled)
|
|
|
|
{
|
|
|
|
activeShader->muGlowTopColor.Set(mGlowTop.vec);
|
|
|
|
activeShader->muGlowBottomColor.Set(mGlowBottom.vec);
|
|
|
|
activeShader->currentglowstate = 1;
|
|
|
|
}
|
|
|
|
else if (activeShader->currentglowstate)
|
|
|
|
{
|
|
|
|
// if glowing is on, disable it.
|
|
|
|
activeShader->muGlowTopColor.Set(nulvec);
|
|
|
|
activeShader->muGlowBottomColor.Set(nulvec);
|
|
|
|
activeShader->currentglowstate = 0;
|
|
|
|
}
|
2017-01-28 19:44:46 +00:00
|
|
|
if (mGlowEnabled || mObjectColor2.a != 0)
|
|
|
|
{
|
|
|
|
activeShader->muGlowTopPlane.Set(mGlowTopPlane.vec);
|
|
|
|
activeShader->muGlowBottomPlane.Set(mGlowBottomPlane.vec);
|
|
|
|
}
|
2014-06-21 13:50:32 +00:00
|
|
|
|
2016-01-30 22:01:11 +00:00
|
|
|
if (mSplitEnabled)
|
|
|
|
{
|
|
|
|
activeShader->muSplitTopPlane.Set(mSplitTopPlane.vec);
|
|
|
|
activeShader->muSplitBottomPlane.Set(mSplitBottomPlane.vec);
|
|
|
|
activeShader->currentsplitstate = 1;
|
|
|
|
}
|
2016-04-28 23:48:06 +00:00
|
|
|
else if (activeShader->currentsplitstate)
|
2016-01-30 22:01:11 +00:00
|
|
|
{
|
|
|
|
activeShader->muSplitTopPlane.Set(nulvec);
|
|
|
|
activeShader->muSplitBottomPlane.Set(nulvec);
|
2016-04-28 23:48:06 +00:00
|
|
|
activeShader->currentsplitstate = 0;
|
|
|
|
}
|
|
|
|
|
2014-07-13 18:41:20 +00:00
|
|
|
if (mTextureMatrixEnabled)
|
|
|
|
{
|
2017-11-25 12:51:09 +00:00
|
|
|
matrixToGL(mTextureMatrix, activeShader->texturematrix_index);
|
2014-07-13 18:41:20 +00:00
|
|
|
activeShader->currentTextureMatrixState = true;
|
|
|
|
}
|
|
|
|
else if (activeShader->currentTextureMatrixState)
|
|
|
|
{
|
|
|
|
activeShader->currentTextureMatrixState = false;
|
2017-11-25 12:51:09 +00:00
|
|
|
matrixToGL(identityMatrix, activeShader->texturematrix_index);
|
2014-07-13 18:41:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mModelMatrixEnabled)
|
|
|
|
{
|
2017-11-25 12:51:09 +00:00
|
|
|
matrixToGL(mModelMatrix, activeShader->modelmatrix_index);
|
2016-10-03 14:09:32 +00:00
|
|
|
VSMatrix norm;
|
|
|
|
norm.computeNormalMatrix(mModelMatrix);
|
2017-11-25 12:51:09 +00:00
|
|
|
matrixToGL(norm, activeShader->normalmodelmatrix_index);
|
2014-07-13 18:41:20 +00:00
|
|
|
activeShader->currentModelMatrixState = true;
|
|
|
|
}
|
|
|
|
else if (activeShader->currentModelMatrixState)
|
|
|
|
{
|
|
|
|
activeShader->currentModelMatrixState = false;
|
2017-11-25 12:51:09 +00:00
|
|
|
matrixToGL(identityMatrix, activeShader->modelmatrix_index);
|
|
|
|
matrixToGL(identityMatrix, activeShader->normalmodelmatrix_index);
|
2014-07-13 18:41:20 +00:00
|
|
|
}
|
2014-06-21 13:50:32 +00:00
|
|
|
return true;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Apply State
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2018-10-20 11:05:36 +00:00
|
|
|
void FGLRenderState::Apply()
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2018-10-20 21:14:57 +00:00
|
|
|
if (mRenderStyle != stRenderStyle)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2018-10-20 21:14:57 +00:00
|
|
|
ApplyBlendMode();
|
|
|
|
stRenderStyle = mRenderStyle;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
2018-10-20 19:36:50 +00:00
|
|
|
if (mMaterial.mChanged)
|
|
|
|
{
|
|
|
|
ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader);
|
|
|
|
mMaterial.mChanged = false;
|
|
|
|
}
|
|
|
|
|
2018-10-20 19:08:24 +00:00
|
|
|
if (mStencil.mChanged)
|
|
|
|
{
|
|
|
|
int recursion = GLRenderer->mPortalState.GetRecursion();
|
|
|
|
glStencilFunc(GL_EQUAL, recursion + mStencil.mOffsVal, ~0); // draw sky into stencil
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, op2gl[mStencil.mOperation]); // this stage doesn't modify the stencil
|
|
|
|
|
|
|
|
bool cmon = !(mStencil.mFlags & SF_ColorMaskOff);
|
|
|
|
glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer
|
|
|
|
glDepthMask(!(mStencil.mFlags & SF_DepthMaskOff));
|
|
|
|
if (mStencil.mFlags & SF_DepthTestOff)
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
else
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
2018-10-20 19:36:50 +00:00
|
|
|
mStencil.mChanged = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mBias.mChanged)
|
|
|
|
{
|
|
|
|
if (mBias.mFactor == 0 && mBias.mUnits == 0)
|
|
|
|
{
|
|
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
}
|
|
|
|
glPolygonOffset(mBias.mFactor, mBias.mUnits);
|
|
|
|
mBias.mChanged = false;
|
2018-10-20 19:08:24 +00:00
|
|
|
}
|
|
|
|
|
2014-05-10 19:47:07 +00:00
|
|
|
if (mVertexBuffer != mCurrentVertexBuffer)
|
|
|
|
{
|
|
|
|
if (mVertexBuffer == NULL) glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
else mVertexBuffer->BindVBO();
|
|
|
|
mCurrentVertexBuffer = mVertexBuffer;
|
|
|
|
}
|
2018-06-08 17:12:06 +00:00
|
|
|
ApplyShader();
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
2014-07-13 20:37:34 +00:00
|
|
|
|
|
|
|
|
2018-10-20 11:05:36 +00:00
|
|
|
void FGLRenderState::ApplyLightIndex(int index)
|
2014-08-01 18:59:39 +00:00
|
|
|
{
|
2018-10-20 19:36:50 +00:00
|
|
|
if (index == -2) index = mLightIndex; // temporary workaround so that both old and new code can be handled.
|
2018-06-08 17:12:06 +00:00
|
|
|
if (index > -1 && GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER)
|
2014-08-01 18:59:39 +00:00
|
|
|
{
|
2018-06-08 17:12:06 +00:00
|
|
|
index = GLRenderer->mLights->BindUBO(index);
|
2014-08-01 18:59:39 +00:00
|
|
|
}
|
2018-06-08 17:12:06 +00:00
|
|
|
activeShader->muLightIndex.Set(index);
|
2016-04-26 22:41:00 +00:00
|
|
|
}
|
2018-07-14 11:05:49 +00:00
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// Binds a texture to the renderer
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2018-10-20 19:36:50 +00:00
|
|
|
void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader)
|
2018-07-14 11:05:49 +00:00
|
|
|
{
|
|
|
|
if (mat->tex->bHasCanvas)
|
|
|
|
{
|
|
|
|
mTempTM = TM_OPAQUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-21 06:14:48 +00:00
|
|
|
mTempTM = TM_NORMAL;
|
2018-07-14 11:05:49 +00:00
|
|
|
}
|
2018-10-20 11:05:36 +00:00
|
|
|
mEffectState = overrideshader >= 0 ? overrideshader : mat->GetShaderIndex();
|
2018-07-14 11:05:49 +00:00
|
|
|
mShaderTimer = mat->tex->shaderspeed;
|
|
|
|
SetSpecular(mat->tex->Glossiness, mat->tex->SpecularLevel);
|
|
|
|
|
2018-07-23 19:17:57 +00:00
|
|
|
auto tex = mat->tex;
|
2018-07-23 15:53:35 +00:00
|
|
|
if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER;
|
|
|
|
if (tex->bHasCanvas) clampmode = CLAMP_CAMTEX;
|
|
|
|
else if ((tex->bWarped || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE;
|
|
|
|
|
2018-07-14 11:05:49 +00:00
|
|
|
// avoid rebinding the same texture multiple times.
|
|
|
|
if (mat == lastMaterial && lastClamp == clampmode && translation == lastTranslation) return;
|
|
|
|
lastMaterial = mat;
|
|
|
|
lastClamp = clampmode;
|
|
|
|
lastTranslation = translation;
|
|
|
|
|
|
|
|
int usebright = false;
|
|
|
|
int maxbound = 0;
|
|
|
|
|
|
|
|
// Textures that are already scaled in the texture lump will not get replaced by hires textures.
|
|
|
|
int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && tex->Scale.X == 1 && tex->Scale.Y == 1 && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0;
|
|
|
|
int numLayers = mat->GetLayers();
|
|
|
|
auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0));
|
|
|
|
|
|
|
|
if (base->BindOrCreate(tex, 0, clampmode, translation, flags))
|
|
|
|
{
|
|
|
|
for (int i = 1; i<numLayers; i++)
|
|
|
|
{
|
|
|
|
FTexture *layer;
|
|
|
|
auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, &layer));
|
|
|
|
systex->BindOrCreate(layer, i, clampmode, 0, mat->isExpanded() ? CTF_Expand : 0);
|
|
|
|
maxbound = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// unbind everything from the last texture that's still active
|
|
|
|
for (int i = maxbound + 1; i <= maxBoundMaterial; i++)
|
|
|
|
{
|
|
|
|
FHardwareTexture::Unbind(i);
|
|
|
|
maxBoundMaterial = maxbound;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-20 21:14:57 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Apply blend mode from RenderStyle
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FGLRenderState::ApplyBlendMode()
|
|
|
|
{
|
|
|
|
static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, };
|
|
|
|
static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1,
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1 };
|
|
|
|
|
|
|
|
int srcblend = blendstyles[mRenderStyle.SrcAlpha%STYLEALPHA_MAX];
|
|
|
|
int dstblend = blendstyles[mRenderStyle.DestAlpha%STYLEALPHA_MAX];
|
|
|
|
int blendequation = renderops[mRenderStyle.BlendOp & 15];
|
|
|
|
|
|
|
|
if (blendequation == -1) // This was a fuzz style.
|
|
|
|
{
|
|
|
|
srcblend = GL_DST_COLOR;
|
|
|
|
dstblend = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
blendequation = GL_FUNC_ADD;
|
|
|
|
}
|
2018-07-14 11:05:49 +00:00
|
|
|
|
2018-10-20 21:14:57 +00:00
|
|
|
// Checks must be disabled until all draw code has been converted.
|
|
|
|
//if (srcblend != stSrcBlend || dstblend != stDstBlend)
|
|
|
|
{
|
|
|
|
stSrcBlend = srcblend;
|
|
|
|
stDstBlend = dstblend;
|
|
|
|
glBlendFunc(srcblend, dstblend);
|
|
|
|
}
|
|
|
|
//if (blendequation != stBlendEquation)
|
|
|
|
{
|
|
|
|
stBlendEquation = blendequation;
|
|
|
|
glBlendEquation(blendequation);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|