Implement OpenGL versions of GPU objects

This commit is contained in:
Magnus Norddahl 2016-10-10 07:39:02 +02:00
parent 5f0088ab8b
commit 40df46f94e
2 changed files with 327 additions and 61 deletions

View file

@ -92,30 +92,30 @@ IMPLEMENT_CLASS(OpenGLSWFrameBuffer)
const char *const OpenGLSWFrameBuffer::ShaderNames[OpenGLSWFrameBuffer::NUM_SHADERS] = const char *const OpenGLSWFrameBuffer::ShaderNames[OpenGLSWFrameBuffer::NUM_SHADERS] =
{ {
"NormalColor.fp", "NormalColor",
"NormalColorPal.fp", "NormalColorPal",
"NormalColorInv.fp", "NormalColorInv",
"NormalColorPalInv.fp", "NormalColorPalInv",
"RedToAlpha.fp", "RedToAlpha",
"RedToAlphaInv.fp", "RedToAlphaInv",
"VertexColor.fp", "VertexColor",
"SpecialColormap.fp", "SpecialColormap",
"SpecialColorMapPal.fp", "SpecialColorMapPal",
"InGameColormap.fp", "InGameColormap",
"InGameColormapDesat.fp", "InGameColormapDesat",
"InGameColormapInv.fp", "InGameColormapInv",
"InGameColormapInvDesat.fp", "InGameColormapInvDesat",
"InGameColormapPal.fp", "InGameColormapPal",
"InGameColormapPalDesat.fp", "InGameColormapPalDesat",
"InGameColormapPalInv.fp", "InGameColormapPalInv",
"InGameColormapPalInvDesat.fp", "InGameColormapPalInvDesat",
"BurnWipe.fp", "BurnWipe",
"GammaCorrection.fp", "GammaCorrection",
}; };
OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) : OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) :
@ -209,6 +209,256 @@ OpenGLSWFrameBuffer::~OpenGLSWFrameBuffer()
delete[] QuadExtra; delete[] QuadExtra;
} }
bool OpenGLSWFrameBuffer::CreatePixelShader(const void *vertexsrc, const void *fragmentsrc, HWPixelShader **outShader)
{
auto shader = std::make_unique<HWPixelShader>();
shader->Program = glCreateProgram();
shader->VertexShader = glCreateShader(GL_VERTEX_SHADER);
shader->FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
{
int lengths[1] = { (int)strlen((const char*)vertexsrc) };
const char *sources[1] = { (const char*)vertexsrc };
glShaderSource(shader->VertexShader, 1, sources, lengths);
glCompileShader(shader->VertexShader);
}
{
int lengths[1] = { (int)strlen((const char*)fragmentsrc) };
const char *sources[1] = { (const char*)fragmentsrc };
glShaderSource(shader->FragmentShader, 1, sources, lengths);
glCompileShader(shader->FragmentShader);
}
GLint status = 0;
glGetShaderiv(shader->VertexShader, GL_COMPILE_STATUS, &status);
if (status != GL_FALSE) glGetShaderiv(shader->FragmentShader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
*outShader = nullptr;
return false;
}
glAttachShader(shader->Program, shader->VertexShader);
glAttachShader(shader->Program, shader->FragmentShader);
glBindFragDataLocation(shader->Program, 0, "FragColor");
glLinkProgram(shader->Program);
glGetProgramiv(shader->Program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
*outShader = nullptr;
return false;
}
glBindAttribLocation(shader->Program, 0, "Position");
glBindAttribLocation(shader->Program, 1, "Color0");
glBindAttribLocation(shader->Program, 2, "Color1");
glBindAttribLocation(shader->Program, 3, "TexCoord");
*outShader = shader.release();
return true;
}
bool OpenGLSWFrameBuffer::CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer)
{
auto obj = std::make_unique<HWVertexBuffer>();
GLint oldBinding = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding);
glGenVertexArrays(1, (GLuint*)&obj->VertexArray);
glGenBuffers(1, (GLuint*)&obj->Buffer);
glBindVertexArray(obj->VertexArray);
glBindBuffer(GL_ARRAY_BUFFER, obj->Buffer);
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, x));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color0));
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color1));
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, tu));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(oldBinding);
*outVertexBuffer = obj.release();
return true;
}
bool OpenGLSWFrameBuffer::CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer)
{
auto obj = std::make_unique<HWIndexBuffer>();
GLint oldBinding = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &oldBinding);
glGenBuffers(1, (GLuint*)&obj->Buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj->Buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, GL_STREAM_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oldBinding);
*outIndexBuffer = obj.release();
return true;
}
bool OpenGLSWFrameBuffer::CreateTexture(int width, int height, int levels, int format, HWTexture **outTexture)
{
auto obj = std::make_unique<HWTexture>();
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
glGenTextures(1, (GLuint*)&obj->Texture);
glBindTexture(GL_TEXTURE_2D, obj->Texture);
GLenum srcformat;
switch (format)
{
case GL_R8: srcformat = GL_RED; break;
case GL_RGBA8: srcformat = GL_RGBA; break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: srcformat = GL_RGB; break;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: srcformat = GL_RGBA; break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: srcformat = GL_RGBA; break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: srcformat = GL_RGBA; break;
default:
I_FatalError("Unknown format passed to CreateTexture");
return false;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, srcformat, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, oldBinding);
*outTexture = obj.release();
return true;
}
bool OpenGLSWFrameBuffer::CreateOffscreenPlainSurface(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; }
bool OpenGLSWFrameBuffer::CreateRenderTarget(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; }
bool OpenGLSWFrameBuffer::GetBackBuffer(HWSurface **outSurface) { *outSurface = nullptr; return false; }
bool OpenGLSWFrameBuffer::GetRenderTarget(int index, HWSurface **outSurface) { *outSurface = nullptr; return false; }
void OpenGLSWFrameBuffer::GetRenderTargetData(HWSurface *a, HWSurface *b) { }
void OpenGLSWFrameBuffer::ColorFill(HWSurface *surface, float red, float green, float blue) { }
void OpenGLSWFrameBuffer::StretchRect(HWSurface *src, const LTRBRect *srcrect, HWSurface *dest) { }
bool OpenGLSWFrameBuffer::SetRenderTarget(int index, HWSurface *surface) { return true; }
void OpenGLSWFrameBuffer::SetGammaRamp(const GammaRamp *ramp) { }
void OpenGLSWFrameBuffer::SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount)
{
glUniform4fv(uniformIndex, vec4fcount, data);
}
void OpenGLSWFrameBuffer::SetHWPixelShader(HWPixelShader *shader)
{
if (shader)
glUseProgram(shader->Program);
else
glUseProgram(0);
}
void OpenGLSWFrameBuffer::SetStreamSource(HWVertexBuffer *vertexBuffer)
{
if (vertexBuffer)
glBindVertexArray(vertexBuffer->VertexArray);
else
glBindVertexArray(0);
}
void OpenGLSWFrameBuffer::SetIndices(HWIndexBuffer *indexBuffer)
{
if (indexBuffer)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->Buffer);
else
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void OpenGLSWFrameBuffer::DrawTriangleFans(int count, const FBVERTEX *vertices)
{
GLint oldBinding = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding);
if (!StreamVertexBuffer)
{
StreamVertexBuffer = std::make_unique<HWVertexBuffer>();
glGenVertexArrays(1, (GLuint*)&StreamVertexBuffer->VertexArray);
glGenBuffers(1, (GLuint*)&StreamVertexBuffer->Buffer);
glBindVertexArray(StreamVertexBuffer->VertexArray);
glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, x));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color0));
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color1));
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, tu));
}
else
{
glBindVertexArray(StreamVertexBuffer->VertexArray);
glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW);
}
glDrawArrays(GL_TRIANGLE_FAN, 0, count);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(oldBinding);
}
void OpenGLSWFrameBuffer::DrawPoints(int count, const FBVERTEX *vertices)
{
GLint oldBinding = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding);
if (!StreamVertexBuffer)
{
StreamVertexBuffer = std::make_unique<HWVertexBuffer>();
glGenVertexArrays(1, (GLuint*)&StreamVertexBuffer->VertexArray);
glGenBuffers(1, (GLuint*)&StreamVertexBuffer->Buffer);
glBindVertexArray(StreamVertexBuffer->VertexArray);
glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, x));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color0));
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color1));
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, tu));
}
else
{
glBindVertexArray(StreamVertexBuffer->VertexArray);
glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW);
}
glDrawArrays(GL_POINTS, 0, count);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(oldBinding);
}
void OpenGLSWFrameBuffer::DrawLineList(int count)
{
glDrawArrays(GL_LINES, 0, count);
}
void OpenGLSWFrameBuffer::DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount)
{
glDrawRangeElements(GL_TRIANGLES, minIndex, minIndex + numVertices - 1, primitiveCount * 3, GL_UNSIGNED_SHORT, (const void*)(startIndex * sizeof(uint16_t)));
}
void OpenGLSWFrameBuffer::Present()
{
SwapBuffers();
}
//========================================================================== //==========================================================================
// //
// OpenGLSWFrameBuffer :: SetInitialState // OpenGLSWFrameBuffer :: SetInitialState
@ -274,7 +524,6 @@ bool OpenGLSWFrameBuffer::CreateResources()
{ {
return false; return false;
} }
CreateGammaTexture();
CreateBlockSurfaces(); CreateBlockSurfaces();
return true; return true;
} }
@ -293,7 +542,7 @@ bool OpenGLSWFrameBuffer::LoadShaders()
static const char models[][4] = { "30/", "20/", "14/" }; static const char models[][4] = { "30/", "20/", "14/" };
FString shaderdir, shaderpath; FString shaderdir, shaderpath;
unsigned model, i; unsigned model, i;
int lump; int lump, lumpvert;
// We determine the best available model simply by trying them all in // We determine the best available model simply by trying them all in
// order of decreasing preference. // order of decreasing preference.
@ -304,12 +553,13 @@ bool OpenGLSWFrameBuffer::LoadShaders()
for (i = 0; i < NUM_SHADERS; ++i) for (i = 0; i < NUM_SHADERS; ++i)
{ {
shaderpath = shaderdir; shaderpath = shaderdir;
shaderpath += ShaderNames[i]; lump = Wads.CheckNumForFullName(shaderpath + ShaderNames[i] + ".fp");
lump = Wads.CheckNumForFullName(shaderpath); lumpvert = Wads.CheckNumForFullName(shaderpath + ShaderNames[i] + ".vp");
if (lump >= 0) if (lump >= 0 && lumpvert >= 0)
{ {
FMemLump data = Wads.ReadLump(lump); FMemLump data = Wads.ReadLump(lump);
if (!CreatePixelShader((uint32_t *)data.GetMem(), &Shaders[i]) && i < SHADER_BurnWipe) FMemLump datavert = Wads.ReadLump(lumpvert);
if (!CreatePixelShader(datavert.GetMem(), data.GetMem(), &Shaders[i]) && i < SHADER_BurnWipe)
{ {
break; break;
} }
@ -533,17 +783,6 @@ bool OpenGLSWFrameBuffer::CreatePaletteTexture()
return true; return true;
} }
//==========================================================================
//
// OpenGLSWFrameBuffer :: CreateGammaTexture
//
//==========================================================================
bool OpenGLSWFrameBuffer::CreateGammaTexture()
{
return false;
}
//========================================================================== //==========================================================================
// //
// OpenGLSWFrameBuffer :: CreateVertexes // OpenGLSWFrameBuffer :: CreateVertexes
@ -3293,7 +3532,7 @@ void OpenGLSWFrameBuffer::SetTexture(int tnum, HWTexture *texture)
{ {
Texture[tnum] = texture; Texture[tnum] = texture;
glActiveTexture(GL_TEXTURE0 + tnum); glActiveTexture(GL_TEXTURE0 + tnum);
glBindTexture(GL_TEXTURE_2D, texture->Handle); glBindTexture(GL_TEXTURE_2D, texture->Texture);
if (Texture[tnum]->WrapS != SamplerWrapS[tnum]) if (Texture[tnum]->WrapS != SamplerWrapS[tnum])
{ {
Texture[tnum]->WrapS = SamplerWrapS[tnum]; Texture[tnum]->WrapS = SamplerWrapS[tnum];

View file

@ -110,7 +110,7 @@ private:
void UnlockRect() { } void UnlockRect() { }
bool GetSurfaceLevel(int level, HWSurface **outSurface) { *outSurface = nullptr; return false; } bool GetSurfaceLevel(int level, HWSurface **outSurface) { *outSurface = nullptr; return false; }
int Handle = 0; int Texture = 0;
int WrapS = 0; int WrapS = 0;
int WrapT = 0; int WrapT = 0;
int Format = 0; int Format = 0;
@ -119,44 +119,70 @@ private:
class HWVertexBuffer class HWVertexBuffer
{ {
public: public:
~HWVertexBuffer()
{
if (Buffer != 0) glDeleteVertexArrays(1, (GLuint*)&VertexArray);
if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer);
}
FBVERTEX *Lock() { return nullptr; } FBVERTEX *Lock() { return nullptr; }
void Unlock() { } void Unlock() { }
int Buffer = 0;
int VertexArray = 0;
}; };
class HWIndexBuffer class HWIndexBuffer
{ {
public: public:
~HWIndexBuffer()
{
if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer);
}
uint16_t *Lock() { return nullptr; } uint16_t *Lock() { return nullptr; }
void Unlock() { } void Unlock() { }
int Buffer = 0;
}; };
class HWPixelShader class HWPixelShader
{ {
public: public:
~HWPixelShader()
{
if (Program != 0) glDeleteProgram(Program);
if (VertexShader != 0) glDeleteShader(VertexShader);
if (FragmentShader != 0) glDeleteShader(FragmentShader);
}
int Program = 0;
int VertexShader = 0;
int FragmentShader = 0;
}; };
bool CreatePixelShader(const void *src, HWPixelShader **outShader) { *outShader = nullptr; return false; } bool CreatePixelShader(const void *vertexsrc, const void *fragmentsrc, HWPixelShader **outShader);
bool CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer) { *outVertexBuffer = nullptr; return false; } bool CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer);
bool CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer) { *outIndexBuffer = nullptr; return false; } bool CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer);
bool CreateOffscreenPlainSurface(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; } bool CreateOffscreenPlainSurface(int width, int height, int format, HWSurface **outSurface);
bool CreateTexture(int width, int height, int levels, int format, HWTexture **outTexture) { *outTexture = nullptr; return false; } bool CreateTexture(int width, int height, int levels, int format, HWTexture **outTexture);
bool CreateRenderTarget(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; } bool CreateRenderTarget(int width, int height, int format, HWSurface **outSurface);
bool GetBackBuffer(HWSurface **outSurface) { *outSurface = nullptr; return false; } bool GetBackBuffer(HWSurface **outSurface);
bool GetRenderTarget(int index, HWSurface **outSurface) { *outSurface = nullptr; return false; } bool GetRenderTarget(int index, HWSurface **outSurface);
void GetRenderTargetData(HWSurface *a, HWSurface *b) { } void GetRenderTargetData(HWSurface *a, HWSurface *b);
void ColorFill(HWSurface *surface, float red, float green, float blue) { } void ColorFill(HWSurface *surface, float red, float green, float blue);
void StretchRect(HWSurface *src, const LTRBRect *srcrect, HWSurface *dest) { } void StretchRect(HWSurface *src, const LTRBRect *srcrect, HWSurface *dest);
bool SetRenderTarget(int index, HWSurface *surface) { return true; } bool SetRenderTarget(int index, HWSurface *surface);
void SetGammaRamp(const GammaRamp *ramp) { } void SetGammaRamp(const GammaRamp *ramp);
void SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount) { } void SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount);
void SetHWPixelShader(HWPixelShader *shader) { } void SetHWPixelShader(HWPixelShader *shader);
void SetStreamSource(HWVertexBuffer *vertexBuffer) { } void SetStreamSource(HWVertexBuffer *vertexBuffer);
void SetIndices(HWIndexBuffer *indexBuffer) { } void SetIndices(HWIndexBuffer *indexBuffer);
void DrawTriangleFans(int count, const FBVERTEX *vertices) { } void DrawTriangleFans(int count, const FBVERTEX *vertices);
void DrawPoints(int count, const FBVERTEX *vertices) { } void DrawPoints(int count, const FBVERTEX *vertices);
void DrawLineList(int count) { } void DrawLineList(int count);
void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount) { } void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount);
void Present() { } void Present();
static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); } static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); }
static uint32_t ColorRGBA(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(a, r, g, b); } static uint32_t ColorRGBA(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(a, r, g, b); }
@ -346,7 +372,6 @@ private:
void CreateBlockSurfaces(); void CreateBlockSurfaces();
bool CreateFBTexture(); bool CreateFBTexture();
bool CreatePaletteTexture(); bool CreatePaletteTexture();
bool CreateGammaTexture();
bool CreateVertexes(); bool CreateVertexes();
void UploadPalette(); void UploadPalette();
void UpdateGammaTexture(float igamma); void UpdateGammaTexture(float igamma);
@ -386,6 +411,8 @@ private:
template<typename T> static void SafeRelease(T &x) { if (x != nullptr) { delete x; x = nullptr; } } template<typename T> static void SafeRelease(T &x) { if (x != nullptr) { delete x; x = nullptr; } }
std::unique_ptr<HWVertexBuffer> StreamVertexBuffer;
BOOL AlphaTestEnabled; BOOL AlphaTestEnabled;
BOOL AlphaBlendEnabled; BOOL AlphaBlendEnabled;
int AlphaBlendOp; int AlphaBlendOp;