#include "gx/glsdl/GLSDLDevice.hpp" #include "gx/glsdl/GLPool.hpp" #include "gx/glsdl/GLUtil.hpp" #include "gx/glsdl/GL.hpp" #include #include #include #include #include #define GL_MAX_STREAM 4 class GLPixelShader; class GLVertexShader; Blizzard::Thread::TLSSlot GLSDLDevice::m_CurrentDevice; std::vector> GLSDLDevice::m_Devices; bool GLSDLDevice::m_ExtColorMaskIndexed = false; int32_t GLSDLDevice::m_StaticResourcesRefCount = 0; GLSDLDevice::RendererInfo GLSDLDevice::m_RendererInfo; bool GLSDLDevice::m_UseHybridShader = 0; bool GLSDLDevice::m_ExtARBShadow = 0; bool GLSDLDevice::m_ShaderConstantBindings = 1; GLBuffer* GLSDLDevice::m_BlitQuadVBO = nullptr; GLShader* GLSDLDevice::m_DeviceShaders[11] = {}; GLTexture* GLSDLDevice::m_DeviceTextures[4] = {}; GLVertexFormat GLSDLDevice::m_NormalBlitVF; GLVertexFormat GLSDLDevice::m_InvertedBlitVF; GLFramebuffer* GLSDLDevice::m_F8330C = nullptr; const char* GLSDLBlitVsCode = R"(!!ARBvp1.0 PARAM c0 = { 1.0 }; MOV result.position.xyz, vertex.attrib[0]; MOV result.position.w, c0.x; MOV result.texcoord[0].xyz, vertex.attrib[1]; END)"; const char* GLSDLDummyVsCode = R"(!!ARBvp1.0 PARAM c = {0.0, 0.0, 0.0, 1.0}; MOV result.position, c; END)"; const char* GLSDLBlitPsCode = R"(!!ARBfp1.0 PARAM c0 = { 1.0 }; TEX result.color.rgba, fragment.texcoord[0], texture[0], 2D; END)"; inline void COPY_TRANSFORM(GLTransform& dst, const GLTransform& src) { if (src.isIdentity) { dst.isIdentity = true; dst.isDirty = true; } else { dst.isIdentity = false; dst.isDirty = true; memcpy(dst.m, src.m, sizeof(float) * 16); } } void* Sub1D210(void* ptr) { GLSDLDevice** ptrptr = new GLSDLDevice*; *ptrptr = nullptr; return ptrptr; } void Sub1D230(void* ptr) { delete static_cast(ptr); } GLSDLDevice* GLSDLDevice::Get() { return *static_cast( Blizzard::Thread::RegisterLocalStorage(&GLSDLDevice::m_CurrentDevice, Sub1D210, 0, Sub1D230) ); } void GLSDLDevice::Set(GLSDLDevice* device) { *static_cast( Blizzard::Thread::RegisterLocalStorage(&GLSDLDevice::m_CurrentDevice, Sub1D210, 0, Sub1D230) ) = device; } GLSDLDevice::RendererInfo GLSDLDevice::GetRendererInfo() { if (!GLSDLDevice::m_RendererInfo.init) { GLSDLDevice::InitRendererInfo(); } return GLSDLDevice::m_RendererInfo; } void GLSDLDevice::InitRendererInfo() { // TODO GLSDLDevice::m_RendererInfo.init = 1; } void GLSDLDevice::InitPools() { // TODO // - init all pools GLPool::Init(); GLPool::Get()->SetNextName(1); GLPool::Init(); GLPool::Get()->SetNextName(0x21); GLPool::Init(); GLPool::Get()->SetNextName(0x1); GLPool::Init(); GLPool::Get()->SetNextName(0x2001); GLPool::Init(); GLPool::Get()->SetNextName(0x1); } void GLSDLDevice::SetOption(GLSDLDeviceOption option, bool enable) { switch (option) { case eUseMTGL: { break; } case eUseVertexArray: { break; } case eUseGLSL: { break; } case eCheckGLStates: { break; } case eFlushBeforeDraw: { break; } case eDeviceOption5: { break; } case eUseHybridShader: { break; } case eDeviceOption7: { break; } case eDeviceOption8: { break; } case eShaderConstantBindings: { GLSDLDevice::m_ShaderConstantBindings = enable; break; } default: { BLIZZARD_ASSERT(false); } } } void GLSDLDevice::StaticInit() { static float blitQuad[] = { -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f }; GLSDLDevice::m_BlitQuadVBO = GLBuffer::Create( GL_ARRAY_BUFFER, sizeof(blitQuad), blitQuad, GL_STATIC_DRAW, 0 ); GLSDLDevice::m_InvertedBlitVF.m_Attribs[0] = { 0, 0, GLVT_FLOAT3, 0 }; GLSDLDevice::m_InvertedBlitVF.m_Attribs[1] = { 0, 1, GLVT_FLOAT2, 12 }; GLSDLDevice::m_InvertedBlitVF.m_Size = 2; GLSDLDevice::m_NormalBlitVF.m_Attribs[0] = { 0, 0, GLVT_FLOAT3, 0 }; GLSDLDevice::m_NormalBlitVF.m_Attribs[1] = { 0, 1, GLVT_FLOAT2, 20 }; GLSDLDevice::m_NormalBlitVF.m_Size = 2; GLSDLDevice::m_F8330C = GLFramebuffer::Create(0); GLSDLDevice::m_DeviceShaders[0] = GLShader::Create( GLShader::eVertexShader, GLSDLDevice::m_UseHybridShader, false, "", GLSDLBlitVsCode, strlen(GLSDLBlitVsCode), "", "GL SDL Blit VS", nullptr ); GLSDLDevice::m_DeviceShaders[0]->Compile(nullptr); GLSDLDevice::m_DeviceShaders[1] = GLShader::Create( GLShader::eVertexShader, GLSDLDevice::m_UseHybridShader, false, "", GLSDLDummyVsCode, strlen(GLSDLDummyVsCode), "", "GL SDL Dummy VS", nullptr ); GLSDLDevice::m_DeviceShaders[1]->Compile(nullptr); GLSDLDevice::m_DeviceShaders[2] = GLShader::Create( GLShader::ePixelShader, GLSDLDevice::m_UseHybridShader, false, "", GLSDLBlitPsCode, strlen(GLSDLBlitPsCode), "", "GL SDL Blit PS", nullptr ); GLSDLDevice::m_DeviceShaders[2]->Compile(nullptr); // TODO // - remaining device shaders // Device textures uint32_t v30 = 0; uint32_t v31 = 0; auto texture0 = GLTexture2D::Create(1, 1, 1, GLTF_RGBA8888, 0x0); *static_cast(texture0->Map(0, nullptr, v30, GL_WRITE_ONLY)) = 0xFF; texture0->Unmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); GLSDLDevice::m_DeviceTextures[0] = texture0; // TODO // auto texture1 = GLTexture3D::Create(1, 1, 1, 1, GLTF_RGBA8888, 0x0); // *texture1->Map(0, nullptr, v30, v31, GL_WRITE_ONLY) = 0xFF; // texture1->Unmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); // GLSDLDevice::m_DeviceTextures[1] = texture1; // TODO texture2 auto texture3 = GLTexture2D::Create(1, 1, 1, GLTF_D32, 0x0); *static_cast(texture3->Map(0, nullptr, v30, GL_WRITE_ONLY)) = 0xFF; texture3->Unmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); GLSDLDevice::m_DeviceTextures[3] = texture3; } GLSDLDevice::GLSDLDevice() : m_Context(), m_DefaultVertexArrayObject(true) { // TODO // - fill in remaining initializers } void GLSDLDevice::ApplyGLBindings(const GLStates& states, bool a3) { static GLenum texTarget[4] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_RECTANGLE }; for (int32_t i = 0; i < 16; ++i) { for (int32_t t = 0; t < 4; ++t) { if (this->m_States.binding.texture[t][i] != states.binding.texture[t][i] || a3) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(texTarget[t], states.binding.texture[t][i]); } } } glActiveTexture(GL_TEXTURE0 + states.binding.currentActiveTexture); if (this->m_States.binding.framebuffer != states.binding.framebuffer || a3) { glBindFramebufferEXT(GL_FRAMEBUFFER, states.binding.framebuffer); } if (this->m_States.binding.renderbuffer != states.binding.renderbuffer || a3) { glBindRenderbufferEXT(GL_RENDERBUFFER, states.binding.renderbuffer); } if (this->m_States.binding.vertexArrayObject != states.binding.vertexArrayObject || a3) { glBindVertexArray(states.binding.vertexArrayObject); } if (this->m_States.binding.vertexProgram != states.binding.vertexProgram || a3) { glBindProgramARB(GL_VERTEX_PROGRAM_ARB, states.binding.vertexProgram); } if (this->m_States.binding.pixelProgram != states.binding.pixelProgram || a3) { glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, states.binding.pixelProgram); } if (this->m_States.binding.glslProgram != states.binding.glslProgram || a3) { glUseProgram(states.binding.glslProgram); } memcpy(&this->m_States.binding, &states.binding, sizeof(this->m_States.binding)); } void GLSDLDevice::ApplyGLStates(const GLStates& states, bool force) { if (force) { for (int32_t i = 0; i < 8; ++i) { glActiveTexture(GL_TEXTURE0 + i); float sPlane[] = { 1.0, 0.0, 0.0, 0.0 }; float tPlane[] = { 0.0, 1.0, 0.0, 0.0 }; float rPlane[] = { 0.0, 0.0, 1.0, 0.0 }; float qPlane[] = { 0.0, 0.0, 0.0, 1.0 }; glTexGenfv(GL_S, GL_EYE_PLANE, sPlane); glTexGenfv(GL_T, GL_EYE_PLANE, tPlane); glTexGenfv(GL_R, GL_EYE_PLANE, rPlane); glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane); glTexGenfv(GL_S, GL_OBJECT_PLANE, sPlane); glTexGenfv(GL_T, GL_OBJECT_PLANE, tPlane); glTexGenfv(GL_R, GL_OBJECT_PLANE, rPlane); glTexGenfv(GL_Q, GL_OBJECT_PLANE, qPlane); glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, 1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&GLColor4f::WHITE); } glActiveTexture(GL_TEXTURE0 + states.binding.currentActiveTexture); glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR_EXT); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1); } if (this->m_States.depth.testEnable != states.depth.testEnable || force) { if (states.depth.testEnable) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } if (this->m_States.depth.compareFunc != states.depth.compareFunc || force) { glDepthFunc(states.depth.compareFunc); } if (this->m_States.depth.writeMask != states.depth.writeMask || force) { glDepthMask(states.depth.writeMask); } if (this->m_States.stencil.testEnable != states.stencil.testEnable || force) { if (states.stencil.testEnable) { glEnable(GL_STENCIL_TEST); } else { glDisable(GL_STENCIL_TEST); } } if (this->m_States.stencil.front.compareFunc != states.stencil.front.compareFunc || this->m_States.stencil.back.compareFunc != states.stencil.back.compareFunc || this->m_States.stencil.ref != states.stencil.ref || this->m_States.stencil.mask != states.stencil.mask || force) { glStencilFuncSeparate( states.stencil.front.compareFunc, states.stencil.back.compareFunc, states.stencil.ref, states.stencil.mask ); } if (this->m_States.stencil.front.opFail != states.stencil.front.opFail || this->m_States.stencil.front.opZFail != states.stencil.front.opZFail || this->m_States.stencil.front.opZPass != states.stencil.front.opZPass || force) { glStencilOpSeparate( states.stencil.useTwoSidedStencil ? GL_FRONT : GL_FRONT_AND_BACK, states.stencil.front.opFail, states.stencil.front.opZFail, states.stencil.front.opZPass ); } if (states.stencil.useTwoSidedStencil) { if (this->m_States.stencil.back.opFail != states.stencil.back.opFail || this->m_States.stencil.back.opZFail != states.stencil.back.opZFail || this->m_States.stencil.back.opZPass != states.stencil.back.opZPass || force) { glStencilOpSeparate( GL_BACK, states.stencil.back.opFail, states.stencil.back.opZFail, states.stencil.back.opZPass ); } } if (this->m_States.stencil.writeMask != states.stencil.writeMask || force) { glStencilMask(states.stencil.writeMask); } if (this->m_States.rasterizer.cullFaceMode != states.rasterizer.cullFaceMode || force) { glCullFace(states.rasterizer.cullFaceMode); } if (this->m_States.rasterizer.cullMode != states.rasterizer.cullMode || force) { if (states.rasterizer.cullMode != 0) { glEnable(GL_CULL_FACE); glFrontFace(states.rasterizer.cullMode); } else { glDisable(GL_CULL_FACE); } } if (this->m_States.rasterizer.fillMode != states.rasterizer.fillMode || force) { glPolygonMode(GL_FRONT_AND_BACK, states.rasterizer.fillMode); } if (this->m_CurrentTargetDepth && (this->m_States.rasterizer.constantDepthBias != states.rasterizer.constantDepthBias || this->m_States.rasterizer.slopeScaledDepthBias != states.rasterizer.slopeScaledDepthBias || force)) { if (states.rasterizer.slopeScaledDepthBias == 0.0 && states.rasterizer.constantDepthBias == 0.0) { glDisable(GL_POLYGON_OFFSET_FILL); } else { glEnable(GL_POLYGON_OFFSET_FILL); } float units; if (states.rasterizer.constantDepthBias == 0.0 ) { units = 0.0; } else { units = (states.rasterizer.constantDepthBias * 2.0) * (1 << this->m_CurrentTargetDepth->GetDepthBits()); } glPolygonOffset(states.rasterizer.slopeScaledDepthBias * 2.0, units); } if (this->m_States.rasterizer.viewport.left != states.rasterizer.viewport.left || this->m_States.rasterizer.viewport.top != states.rasterizer.viewport.top || this->m_States.rasterizer.viewport.width != states.rasterizer.viewport.width || this->m_States.rasterizer.viewport.height != states.rasterizer.viewport.height || force) { glViewport( states.rasterizer.viewport.left, states.rasterizer.viewport.top, states.rasterizer.viewport.width, states.rasterizer.viewport.height ); } if (this->m_States.rasterizer.zNear != states.rasterizer.zNear || this->m_States.rasterizer.zFar != states.rasterizer.zFar || force) { glDepthRange(states.rasterizer.zNear, states.rasterizer.zFar); } if (this->m_States.rasterizer.scissorEnable != states.rasterizer.scissorEnable || force) { if (states.rasterizer.scissorEnable) { glEnable(GL_SCISSOR_TEST); } else { glDisable(GL_SCISSOR_TEST); } } if (this->m_States.rasterizer.scissor.left != states.rasterizer.scissor.left || this->m_States.rasterizer.scissor.top != states.rasterizer.scissor.top || this->m_States.rasterizer.scissor.width != states.rasterizer.scissor.width || this->m_States.rasterizer.scissor.height != states.rasterizer.scissor.height || force) { glScissor( states.rasterizer.scissor.left, states.rasterizer.scissor.top, states.rasterizer.scissor.width, states.rasterizer.scissor.height ); } int32_t maxClipPlaneIndex = GLSDLDevice::GetRendererInfo().unk36; if (this->m_States.rasterizer.clipPlaneMask != states.rasterizer.clipPlaneMask) { for (int32_t i = 0; i < maxClipPlaneIndex; ++i) { if (!(states.rasterizer.clipPlaneMask & this->m_States.rasterizer.clipPlaneMask & (1 << i))) { if ((1 << i) & states.rasterizer.clipPlaneMask) { glEnable(GL_CLIP_PLANE0 + i); } else { glDisable(GL_CLIP_PLANE0 + i); } } } } for (int32_t i = 0; i < maxClipPlaneIndex; ++i) { if (memcmp(&this->m_States.rasterizer.clipPlanes[i].plane, &states.rasterizer.clipPlanes[i].plane, sizeof(this->m_States.rasterizer.clipPlanes[i].plane))) { glClipPlane(GL_CLIP_PLANE0 + i, states.rasterizer.clipPlanes[i].plane); } } int32_t maxColorMaskIndex = GLSDLDevice::m_ExtColorMaskIndexed ? GLSDLDevice::GetRendererInfo().max_color_attachments : 1; for (int32_t i = 0; i < maxColorMaskIndex; ++i) { if (memcmp(&this->m_States.blend.colorMask[i], &states.blend.colorMask[i], sizeof(GLColor4f)) || force) { if (GLSDLDevice::m_ExtColorMaskIndexed) { glColorMaskIndexedEXT( i, states.blend.colorMask[i].red, states.blend.colorMask[i].green, states.blend.colorMask[i].blue, states.blend.colorMask[i].alpha ); } else { glColorMask( states.blend.colorMask[i].red, states.blend.colorMask[i].green, states.blend.colorMask[i].blue, states.blend.colorMask[i].alpha ); } } } if (this->m_States.blend.alphaBlend != states.blend.alphaBlend || force) { if (states.blend.alphaBlend) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } } if (this->m_States.blend.srcBlendFactor != states.blend.srcBlendFactor || this->m_States.blend.destBlendFactor != states.blend.destBlendFactor || force) { glBlendFunc(states.blend.srcBlendFactor, states.blend.destBlendFactor); } if (this->m_States.blend.blendOp != states.blend.blendOp || force) { glBlendEquation(states.blend.blendOp); } if (memcmp(&this->m_States.blend.blendColor, &states.blend.blendColor, sizeof(GLColor4f)) || force) { glBlendColor( states.blend.blendColor.r, states.blend.blendColor.g, states.blend.blendColor.b, states.blend.blendColor.a ); } if (this->m_States.fixedFunc.fogEnable != states.fixedFunc.fogEnable) { if (states.fixedFunc.fogEnable) { glEnable(GL_FOG); } else { glDisable(GL_FOG); } } if (memcmp(&this->m_States.fixedFunc.fogColor, &states.fixedFunc.fogColor, sizeof(GLColor4f)) || force) { glFogfv(GL_FOG_COLOR, (GLfloat*)&states.fixedFunc.fogColor); } if (this->m_States.fixedFunc.fogMode != states.fixedFunc.fogMode || force) { glFogi(GL_FOG_MODE, states.fixedFunc.fogMode); } if (this->m_States.fixedFunc.fogStart != states.fixedFunc.fogStart || force) { glFogf(GL_FOG_START, states.fixedFunc.fogStart); } if (this->m_States.fixedFunc.fogEnd != states.fixedFunc.fogEnd || force) { glFogf(GL_FOG_END, states.fixedFunc.fogEnd); } if (this->m_States.fixedFunc.fogDensity != states.fixedFunc.fogDensity || force) { glFogf(GL_FOG_DENSITY, states.fixedFunc.fogDensity); } if (this->m_States.fixedFunc.alphaTestEnable != states.fixedFunc.alphaTestEnable || force) { if (states.fixedFunc.alphaTestEnable) { glEnable(GL_ALPHA_TEST); } else { glDisable(GL_ALPHA_TEST); } } if (this->m_States.fixedFunc.alphaTestFunc != states.fixedFunc.alphaTestFunc || this->m_States.fixedFunc.alphaTestRef != states.fixedFunc.alphaTestRef || force) { glAlphaFunc(states.fixedFunc.alphaTestFunc, states.fixedFunc.alphaTestRef); } if (this->m_States.fixedFunc.transforms.modelView.isIdentity != states.fixedFunc.transforms.modelView.isIdentity || memcmp(this->m_States.fixedFunc.transforms.modelView.m, states.fixedFunc.transforms.modelView.m, sizeof(float) * 16) || force) { glMatrixMode(GL_MODELVIEW); if (states.fixedFunc.transforms.modelView.isIdentity) { glLoadIdentity(); } else { glLoadMatrixf(states.fixedFunc.transforms.modelView.m); } const_cast(states).fixedFunc.transforms.modelView.isDirty = false; } if (this->m_States.fixedFunc.transforms.projection.isIdentity != states.fixedFunc.transforms.projection.isIdentity || memcmp(this->m_States.fixedFunc.transforms.projection.m, states.fixedFunc.transforms.projection.m, sizeof(float) * 16) || force) { glMatrixMode(GL_PROJECTION); GLTransform projection = { true, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }, true }; if (!states.fixedFunc.transforms.projection.isIdentity) { projection.isIdentity = false; memcpy(projection.m, states.fixedFunc.transforms.projection.m, sizeof(projection.m)); projection.isDirty = true; } if (projection.isIdentity) { projection.SetIdentity(); } projection.a1 *= -1.0f; projection.b1 *= -1.0f; projection.c1 *= -1.0f; projection.d1 *= -1.0f; auto isIdentity = projection.a0 == 1.0f && projection.a1 == 0.0f && projection.a2 == 0.0f && projection.a3 == 0.0f && projection.b0 == 0.0f && projection.b1 == 1.0f && projection.b2 == 0.0f && projection.b3 == 0.0f && projection.c0 == 0.0f && projection.c1 == 0.0f && projection.c2 == 1.0f && projection.c3 == 0.0f && projection.d0 == 0.0f && projection.d1 == 0.0f && projection.d2 == 0.0f && projection.d3 == 1.0f; projection.isDirty = true; if (isIdentity) { glLoadIdentity(); } else { glLoadMatrixf(projection.m); } projection.isDirty = false; } glMatrixMode(states.fixedFunc.transforms.matrixMode); glMatrixMode(GL_MODELVIEW); if (states.fixedFunc.transforms.view.isIdentity) { glLoadIdentity(); } else { glLoadMatrixf(states.fixedFunc.transforms.view.m); } const_cast(states).fixedFunc.transforms.view.isDirty = false; if (this->m_States.fixedFunc.lighting.enable != states.fixedFunc.lighting.enable || force) { if (states.fixedFunc.lighting.enable) { glEnable(GL_LIGHTING); } else { glDisable(GL_LIGHTING); } } for (int32_t i = 0; i < 8; ++i) { // TODO // Set up each light } if (memcmp(&this->m_States.fixedFunc.lighting.sceneAmbient, &states.fixedFunc.lighting.sceneAmbient, sizeof(GLColor4f)) || force) { glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (GLfloat*)&states.fixedFunc.lighting.sceneAmbient); } if (this->m_States.fixedFunc.lighting.material.materialSource != states.fixedFunc.lighting.material.materialSource || force) { glColorMaterial(GL_FRONT_AND_BACK, states.fixedFunc.lighting.material.materialSource); // TODO // this->Sub38A20(); } if (this->m_States.fixedFunc.lighting.material.colorTracking != states.fixedFunc.lighting.material.colorTracking || force) { if (states.fixedFunc.lighting.material.colorTracking) { glEnable(GL_COLOR_MATERIAL); } else { glDisable(GL_COLOR_MATERIAL); } // TODO // this->Sub38A20(); } if (memcmp(&this->m_States.fixedFunc.lighting.material.ambient, &states.fixedFunc.lighting.material.ambient, sizeof(GLColor4f)) || force) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (GLfloat*)&states.fixedFunc.lighting.material.ambient); } if (memcmp(&this->m_States.fixedFunc.lighting.material.diffuse, &states.fixedFunc.lighting.material.diffuse, sizeof(GLColor4f)) || force) { glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (GLfloat*)&states.fixedFunc.lighting.material.diffuse); } if (memcmp(&this->m_States.fixedFunc.lighting.material.specular, &states.fixedFunc.lighting.material.specular, sizeof(GLColor4f)) || force) { glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*)&states.fixedFunc.lighting.material.specular); } if (memcmp(&this->m_States.fixedFunc.lighting.material.emission, &states.fixedFunc.lighting.material.emission, sizeof(GLColor4f)) || force) { glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (GLfloat*)&states.fixedFunc.lighting.material.emission); } if (this->m_States.fixedFunc.lighting.material.shininess != states.fixedFunc.lighting.material.shininess || force) { glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, states.fixedFunc.lighting.material.shininess); } for (int32_t i = 0; i < 8; ++i) { // TODO fixedFunc.transforms.texture[i] // TODO fixedFunc.texOp[i] // TODO fixedFunc.texGen[i] } glMatrixMode(states.fixedFunc.transforms.matrixMode); if (this->m_States.fixedFunc.normalizeNormal != states.fixedFunc.normalizeNormal) { if (states.fixedFunc.normalizeNormal) { glEnable(GL_NORMALIZE); } else { glDisable(GL_NORMALIZE); } } if (this->m_States.fixedFunc.pointSprite.enable != states.fixedFunc.pointSprite.enable || force) { if (states.fixedFunc.pointSprite.enable) { glEnable(GL_POINT_SPRITE); glEnable(GL_PROGRAM_POINT_SIZE_EXT); } else { glDisable(GL_POINT_SPRITE); glDisable(GL_PROGRAM_POINT_SIZE_EXT); } } if (this->m_States.fixedFunc.pointSprite.size != states.fixedFunc.pointSprite.size || force) { glPointSize(states.fixedFunc.pointSprite.size); } if (memcmp(&this->m_States.fixedFunc.pointSprite.attenuation, &states.fixedFunc.pointSprite.attenuation, sizeof(this->m_States.fixedFunc.pointSprite.attenuation)) || force) { glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION, states.fixedFunc.pointSprite.attenuation); } if (this->m_States.fixedFunc.pointSprite.min != states.fixedFunc.pointSprite.min || force ) { glPointParameterfARB(GL_POINT_SIZE_MIN, states.fixedFunc.pointSprite.min); } if (this->m_States.fixedFunc.pointSprite.max != states.fixedFunc.pointSprite.max || force) { glPointParameterfARB(GL_POINT_SIZE_MAX, states.fixedFunc.pointSprite.max); } if (this->m_States.shader.vertexShaderEnable != states.shader.vertexShaderEnable || force) { if (states.shader.vertexShaderEnable) { glEnable(GL_VERTEX_PROGRAM_ARB); } else { glDisable(GL_VERTEX_PROGRAM_ARB); } } glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, 0, 256, (GLfloat*)states.shader.vertexShaderConst); if (this->m_States.shader.pixelShaderEnable != states.shader.pixelShaderEnable || force) { if (states.shader.pixelShaderEnable) { glEnable(GL_FRAGMENT_PROGRAM_ARB); } else { glDisable(GL_FRAGMENT_PROGRAM_ARB); } } glProgramEnvParameters4fvEXT(GL_FRAGMENT_PROGRAM_ARB, 0, 64, (GLfloat*)states.shader.pixelShaderConst); if (memcmp(&this->m_States.clear.clearColor, &states.clear.clearColor, sizeof(GLColor4f)) || force) { glClearColor( states.clear.clearColor.r, states.clear.clearColor.g, states.clear.clearColor.b, states.clear.clearColor.a ); } if (this->m_States.clear.clearDepth != states.clear.clearDepth || force) { glClearDepth(states.clear.clearDepth); } if (this->m_States.clear.clearStencil != states.clear.clearStencil || force) { glClearStencil(states.clear.clearStencil); } // Copy provided states into current states memcpy(&this->m_States.depth, &states.depth, sizeof(this->m_States.depth)); memcpy(&this->m_States.stencil, &states.stencil, sizeof(this->m_States.stencil)); if (!states.stencil.useTwoSidedStencil) { memcpy(&this->m_States.stencil.back, &states.stencil.front, sizeof(this->m_States.stencil.back)); } if (this->m_CurrentTargetDepth) { memcpy(&this->m_States.rasterizer, &states.rasterizer, sizeof(this->m_States.rasterizer)); } else { float v117 = this->m_States.rasterizer.constantDepthBias; float v118 = this->m_States.rasterizer.slopeScaledDepthBias; memcpy(&this->m_States.rasterizer, &states.rasterizer, sizeof(this->m_States.rasterizer)); this->m_States.rasterizer.constantDepthBias = v117; this->m_States.rasterizer.slopeScaledDepthBias = v118; } memcpy(&this->m_States.blend, &states.blend, sizeof(this->m_States.blend)); memcpy(&this->m_States.clear, &states.clear, sizeof(this->m_States.clear)); this->m_States.fixedFunc.fogEnable = states.fixedFunc.fogEnable; memcpy(&this->m_States.fixedFunc.fogColor, &states.fixedFunc.fogColor, sizeof(GLColor4f)); this->m_States.fixedFunc.fogMode = states.fixedFunc.fogMode; this->m_States.fixedFunc.fogStart = states.fixedFunc.fogStart; this->m_States.fixedFunc.fogEnd = states.fixedFunc.fogEnd; this->m_States.fixedFunc.alphaTestEnable = states.fixedFunc.alphaTestEnable; this->m_States.fixedFunc.alphaTestRef = states.fixedFunc.alphaTestRef; memcpy(this->m_States.fixedFunc.texOp, states.fixedFunc.texOp, sizeof(this->m_States.fixedFunc.texOp)); this->m_States.fixedFunc.lighting.enable = states.fixedFunc.lighting.enable; memcpy(&this->m_States.fixedFunc.lighting.sceneAmbient, &states.fixedFunc.lighting.sceneAmbient, sizeof(GLColor4f)); for (int32_t i = 0; i < 8; ++i) { this->m_States.fixedFunc.lighting.lights[i].enable = states.fixedFunc.lighting.lights[i].enable; memcpy(&this->m_States.fixedFunc.lighting.lights[i].position, &states.fixedFunc.lighting.lights[i].position, sizeof(GLfloat4)); COPY_TRANSFORM(this->m_States.fixedFunc.lighting.lights[i].view, states.fixedFunc.lighting.lights[i].view); this->m_States.fixedFunc.lighting.lights[i].constantAttenuation = states.fixedFunc.lighting.lights[i].constantAttenuation; this->m_States.fixedFunc.lighting.lights[i].linearAttenuation = states.fixedFunc.lighting.lights[i].linearAttenuation; this->m_States.fixedFunc.lighting.lights[i].quadraticAttenuation = states.fixedFunc.lighting.lights[i].quadraticAttenuation; memcpy(&this->m_States.fixedFunc.lighting.lights[i].ambient, &states.fixedFunc.lighting.lights[i].ambient, sizeof(GLColor4f)); memcpy(&this->m_States.fixedFunc.lighting.lights[i].diffuse, &states.fixedFunc.lighting.lights[i].diffuse, sizeof(GLColor4f)); memcpy(&this->m_States.fixedFunc.lighting.lights[i].specular, &states.fixedFunc.lighting.lights[i].specular, sizeof(GLColor4f)); } memcpy(&this->m_States.fixedFunc.lighting.material, &states.fixedFunc.lighting.material, sizeof(this->m_States.fixedFunc.lighting.material)); COPY_TRANSFORM(this->m_States.fixedFunc.transforms.modelView, states.fixedFunc.transforms.modelView); COPY_TRANSFORM(this->m_States.fixedFunc.transforms.world, states.fixedFunc.transforms.world); COPY_TRANSFORM(this->m_States.fixedFunc.transforms.view, states.fixedFunc.transforms.view); COPY_TRANSFORM(this->m_States.fixedFunc.transforms.projection, states.fixedFunc.transforms.projection); for (int32_t i = 0; i < 8; ++i) { COPY_TRANSFORM(this->m_States.fixedFunc.transforms.texture[i], states.fixedFunc.transforms.texture[i]); } memcpy(this->m_States.fixedFunc.texCoordIndex, states.fixedFunc.texCoordIndex, sizeof(this->m_States.fixedFunc.texCoordIndex)); memcpy(this->m_States.fixedFunc.texGen, states.fixedFunc.texGen, sizeof(this->m_States.fixedFunc.texGen)); memcpy(this->m_States.samplers, states.samplers, sizeof(this->m_States.samplers)); memcpy(&this->m_States.shader, &states.shader, sizeof(this->m_States.shader)); } void GLSDLDevice::ApplyShaderConstants() { GLShader* vs = this->m_VertexShader; if (vs) { if (vs->m_UsingGLSL) { vs->FlushUniforms(this->m_GLSLProgram); } else { auto start = this->m_DirtyVertexShaderConsts.start; auto end = this->m_DirtyVertexShaderConsts.end; if (start != end) { glProgramEnvParameters4fvEXT( GL_VERTEX_PROGRAM_ARB, start, end - start, reinterpret_cast(&this->m_States.shader.vertexShaderConst[start]) ); this->m_DirtyVertexShaderConsts.start = 0; this->m_DirtyVertexShaderConsts.end = 0; } } } GLShader* ps = this->m_PixelShader; if (ps) { if (ps->m_UsingGLSL) { ps->FlushUniforms(this->m_GLSLProgram); } else { auto start = this->m_DirtyPixelShaderConsts.start; auto end = this->m_DirtyPixelShaderConsts.end; if (start != end) { glProgramEnvParameters4fvEXT( GL_FRAGMENT_PROGRAM_ARB, start, end - start, reinterpret_cast(&this->m_States.shader.pixelShaderConst[start]) ); this->m_DirtyPixelShaderConsts.start = 0; this->m_DirtyPixelShaderConsts.end = 0; } } } } void GLSDLDevice::ApplyTransforms() { this->SetModelView(GL_MODELVIEW); auto& projection = this->m_States.fixedFunc.transforms.projection; if (projection.isDirty) { if (projection.isIdentity) { projection.SetIdentity(); } projection.a1 *= -1.0f; projection.b1 *= -1.0f; projection.c1 *= -1.0f; projection.d1 *= -1.0f; projection.isIdentity = projection.a0 == 1.0f && projection.a1 == 0.0f && projection.a2 == 0.0f && projection.a3 == 0.0f && projection.b0 == 0.0f && projection.b1 == 1.0f && projection.b2 == 0.0f && projection.b3 == 0.0f && projection.c0 == 0.0f && projection.c1 == 0.0f && projection.c2 == 1.0f && projection.c3 == 0.0f && projection.d0 == 0.0f && projection.d1 == 0.0f && projection.d2 == 0.0f && projection.d3 == 1.0f; projection.isDirty = true; if (this->m_States.fixedFunc.transforms.matrixMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); this->m_States.fixedFunc.transforms.matrixMode = GL_PROJECTION; } if (projection.isIdentity) { glLoadIdentity(); } else { glLoadMatrixf(projection.m); } projection.isDirty = false; } // TODO texture transforms } void GLSDLDevice::BindBuffer(GLBuffer* buffer, GLEnum target) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); BLIZZARD_ASSERT(buffer != nullptr || target != GL_ZERO); GLEnum bindTarget = target == GL_ZERO ? buffer->m_Type : target; GLuint bindName = buffer == nullptr ? 0 : buffer->m_BufferID; int32_t bindIndex; if (bindTarget == GL_ARRAY_BUFFER) { bindIndex = 0; } else if (bindTarget == GL_ELEMENT_ARRAY_BUFFER) { bindIndex = 1; } else if (bindTarget == GL_PIXEL_PACK_BUFFER) { bindIndex = 2; } else if (bindTarget == GL_PIXEL_UNPACK_BUFFER) { bindIndex = 3; } else { BLIZZARD_ASSERT(false); } if (bindTarget == GL_ARRAY_BUFFER) { if (this->m_States.binding.vertexArrayObject && this->m_VertexArrayObject != &this->m_DefaultVertexArrayObject) { glBindVertexArray(0); this->m_States.binding.vertexArrayObject = 0; this->m_VertexArrayObject = &this->m_DefaultVertexArrayObject; } } else if (bindTarget == GL_PIXEL_PACK_BUFFER) { this->m_VertexArrayObject->m_Properties.m_PixelPackBuffer = buffer; } else if (bindTarget == GL_PIXEL_UNPACK_BUFFER) { this->m_VertexArrayObject->m_Properties.m_PixelUnpackBuffer = buffer; } if (this->m_VertexArrayObject->m_GLStates.buffers[bindIndex] != bindName) { glBindBuffer(bindTarget, bindName); this->m_VertexArrayObject->m_GLStates.buffers[bindIndex] = bindName; } } void GLSDLDevice::BindFramebuffer(GLFramebuffer* framebuffer) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); GLuint v3; if (framebuffer) { v3 = framebuffer->m_FramebufferID; } else { v3 = 0; } this->m_CurrentTarget = framebuffer; if (this->m_States.binding.framebuffer != v3) { glBindFramebufferEXT(GL_FRAMEBUFFER, v3); this->m_States.binding.framebuffer = v3; } } void GLSDLDevice::BindGLSLProgram(GLGLSLProgram* a2) { // TODO } void GLSDLDevice::BindShader(GLShader* shader) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); BLIZZARD_ASSERT(shader); if (shader->var5 == GL_FRAGMENT_PROGRAM_ARB) { if (this->m_States.binding.pixelProgram != shader->m_ShaderID) { glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader->m_ShaderID); this->m_States.binding.pixelProgram = shader->m_ShaderID; } } else if (shader->var5 == GL_VERTEX_PROGRAM_ARB) { if (this->m_States.binding.vertexProgram != shader->m_ShaderID) { glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shader->m_ShaderID); this->m_States.binding.vertexProgram = shader->m_ShaderID; } } else { BLIZZARD_ASSERT(false); } } void GLSDLDevice::BindTexture(GLEnum textureType, GLTexture* texture) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); BLIZZARD_ASSERT(texture == nullptr || textureType == texture->m_TextureType); uint32_t textureID = texture ? texture->m_TextureID : 0; uint32_t index = GLSDLTextureTypeToIndex(textureType); BLIZZARD_ASSERT(this->m_States.binding.texture[index][this->m_States.binding.currentActiveTexture] != textureID); BLIZZARD_ASSERT(this->m_BoundTextures[index][this->m_States.binding.currentActiveTexture] != texture); GLTexture* boundTexture = this->m_BoundTextures[index][this->m_States.binding.currentActiveTexture]; if (boundTexture) { boundTexture->Unbind(this, this->m_States.binding.currentActiveTexture); } glBindTexture(textureType, textureID); this->m_BoundTextures[index][this->m_States.binding.currentActiveTexture] = texture; this->m_States.binding.texture[index][this->m_States.binding.currentActiveTexture] = textureID; if (!texture || this->m_WorkerDevice || textureType == GL_TEXTURE_RECTANGLE) { return; } GLSDLDevice* mainDevice = GLSDLDevice::m_Devices[0]; if (texture->var7 == mainDevice->m_TextureList.begin()) { texture->var7 = mainDevice->m_TextureList.insert(mainDevice->m_TextureList.begin(), texture); mainDevice->m_TextureTotalSize += texture->m_Size; texture->m_LastFrameUsed = mainDevice->m_FrameNumber; } else if (texture->m_LastFrameUsed == 0 || texture->m_LastFrameUsed + 60 < mainDevice->m_FrameNumber) { if (texture->m_LastFrameUsed == 0) { texture->RecreateGLTexture(); mainDevice->m_TextureTotalSize += texture->m_Size; } // TODO // - oldest texture logic // TODO // - list transfer logic texture->m_LastFrameUsed = mainDevice->m_FrameNumber; } if (mainDevice->m_TextureTotalSize > 384 * 1024 * 1024) { // TODO // - track / clean up oldest textures } } void GLSDLDevice::BindVertexArray(GLVertexArray* a2) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); int32_t v4 = a2 ? a2->m_VertexArrayID : 0; if (this->m_States.binding.vertexArrayObject != v4) { glBindVertexArray(v4); this->m_States.binding.vertexArrayObject = v4; this->m_VertexArrayObject = a2 ? a2 : &this->m_DefaultVertexArrayObject; } } void GLSDLDevice::BlitFramebuffer(GLMipmap* src, const GLRect* srcRect, GLMipmap* dst, const GLRect* dstRect, GLEnum mask, GLEnum filter) { BLIZZARD_ASSERT(mask == GL_COLOR_BUFFER_BIT); BLIZZARD_ASSERT(src != nullptr); GLRect fullSrcRect = { 0, 0, src->GetWidth(), src->GetHeight() }; GLRect fullDstRect = { 0, 0, dst ? dst->GetWidth() : this->m_Window->GetWidth(), dst ? dst->GetHeight() : this->m_Window->GetHeight() }; BLIZZARD_ASSERT(filter == GL_NEAREST); // TODO // BLIZZARD_ASSERT(srcRect == nullptr || *srcRect == fullSrcRect); // TODO // - non-shader code path glEnable(GL_VERTEX_PROGRAM_ARB); glEnable(GL_FRAGMENT_PROGRAM_ARB); auto alphaTestEnable = this->m_States.fixedFunc.alphaTestEnable; auto depthTestEnable = this->m_States.depth.testEnable; auto alphaBlend = this->m_States.blend.alphaBlend; auto cullEnable = this->m_States.rasterizer.cullMode != 0; auto scissorEnable = this->m_States.rasterizer.scissorEnable; auto stencilTestEnable = this->m_States.stencil.testEnable; uint32_t width; uint32_t height; if (alphaTestEnable) { glDisable(GL_ALPHA_TEST); } if (depthTestEnable) { glDisable(GL_DEPTH_TEST); } if (alphaBlend) { glDisable(GL_BLEND); } if (cullEnable) { glDisable(GL_CULL_FACE); } if (scissorEnable) { glDisable(GL_SCISSOR_TEST); } if (stencilTestEnable) { glDisable(GL_STENCIL_TEST); } if (GLSDLDevice::m_ExtColorMaskIndexed) { glColorMaskIndexedEXT(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } else { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } if (dst) { glFramebufferTexture2DEXT( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst->m_Target, dst->GetTextureID(), dst->m_Level ); auto currentTargetDepth = this->m_CurrentTargetDepth; if (currentTargetDepth) { glFramebufferTexture2DEXT( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, currentTargetDepth->m_Target, 0, 0 ); } auto currentTargetStencil = this->m_CurrentTargetStencil; if (currentTargetStencil) { glFramebufferTexture2DEXT( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, currentTargetStencil->m_Target, 0, 0 ); } dst->m_Texture->SetAddressModeS(GL_CLAMP_TO_EDGE); dst->m_Texture->SetAddressModeT(GL_CLAMP_TO_EDGE); dst->m_Texture->SetMinFilterMode(GL_LINEAR); dst->m_Texture->SetMagFilterMode(GL_LINEAR); width = dst->m_Width; height = dst->m_Height; } else { glBindFramebufferEXT(GL_FRAMEBUFFER, 0); width = this->m_Window->GetWidth(); height = this->m_Window->GetHeight(); } if ( this->m_States.rasterizer.viewport.left != 0 || this->m_States.rasterizer.viewport.top != 0 || this->m_States.rasterizer.viewport.width != width || this->m_States.rasterizer.viewport.height != height ) { glViewport(0, 0, width, height); } this->SetActiveTexture(0); src->m_Texture->Bind(nullptr, true); src->m_Texture->SetAddressModeS(GL_CLAMP_TO_EDGE); src->m_Texture->SetAddressModeT(GL_CLAMP_TO_EDGE); src->m_Texture->SetMinFilterMode(filter); src->m_Texture->SetMagFilterMode(filter); this->SetVertexBuffer(0, GLSDLDevice::m_BlitQuadVBO, 0, 28); GLVertexFormat* format = dst ? &GLSDLDevice::m_NormalBlitVF : &GLSDLDevice::m_InvertedBlitVF; this->SetVertexFormat(format); auto vertexShader = this->m_VertexShader; auto pixelShader = this->m_PixelShader; this->BindGLSLProgram(nullptr); this->SetShader(GLShader::eVertexShader, GLSDLDevice::m_DeviceShaders[0]); this->SetShader(GLShader::ePixelShader, GLSDLDevice::m_DeviceShaders[2]); this->m_DefaultVertexArrayObject.m_Properties.m_VertexBase = 0; GLVertexArray::FindVertexArray(this, this->m_DefaultVertexArrayObject); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); this->SetShader(GLShader::eVertexShader, vertexShader); this->SetShader(GLShader::ePixelShader, pixelShader); if (alphaTestEnable) { glEnable(GL_ALPHA_TEST); } if (depthTestEnable) { glEnable(GL_DEPTH_TEST); } if (alphaBlend) { glEnable(GL_BLEND); } if (cullEnable) { glEnable(GL_CULL_FACE); } if (scissorEnable) { glEnable(GL_SCISSOR_TEST); } if (stencilTestEnable) { glEnable(GL_STENCIL_TEST); } if (GLSDLDevice::m_ExtColorMaskIndexed) { glColorMaskIndexedEXT( 0, this->m_States.blend.colorMask[0].red, this->m_States.blend.colorMask[0].green, this->m_States.blend.colorMask[0].blue, this->m_States.blend.colorMask[0].alpha ); } else { glColorMask( this->m_States.blend.colorMask[0].red, this->m_States.blend.colorMask[0].green, this->m_States.blend.colorMask[0].blue, this->m_States.blend.colorMask[0].alpha ); } if (dst) { auto currentTargetColor = this->m_CurrentTargetColor[0]; glFramebufferTexture2DEXT( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst->m_Target, currentTargetColor->GetTextureID(), 0 ); auto currentTargetDepth = this->m_CurrentTargetDepth; if (currentTargetDepth) { glFramebufferTexture2DEXT( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, currentTargetDepth->m_Target, currentTargetDepth->GetTextureID(), currentTargetDepth->m_Level ); } auto currentTargetStencil = this->m_CurrentTargetStencil; if (currentTargetStencil) { glFramebufferTexture2DEXT( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, currentTargetStencil->m_Target, currentTargetStencil->GetTextureID(), currentTargetStencil->m_Level ); } } if ( this->m_States.rasterizer.viewport.left != 0 || this->m_States.rasterizer.viewport.top != 0 || this->m_States.rasterizer.viewport.width != width || this->m_States.rasterizer.viewport.height != height ) { glViewport( this->m_States.rasterizer.viewport.left, this->m_States.rasterizer.viewport.top, this->m_States.rasterizer.viewport.width, this->m_States.rasterizer.viewport.height ); } } void GLSDLDevice::CheckDepthTarget() { BLIZZARD_ASSERT(this->m_CurrentTargetColor[0] == nullptr || this->m_CurrentTargetColor[0]->GetTexture()->IsValid()); BLIZZARD_ASSERT(this->m_CurrentTargetColor[1] == nullptr || this->m_CurrentTargetColor[1]->GetTexture()->IsValid()); BLIZZARD_ASSERT(this->m_CurrentTargetColor[2] == nullptr || this->m_CurrentTargetColor[2]->GetTexture()->IsValid()); BLIZZARD_ASSERT(this->m_CurrentTargetColor[3] == nullptr || this->m_CurrentTargetColor[3]->GetTexture()->IsValid()); BLIZZARD_ASSERT(this->m_CurrentTargetDepth == nullptr || this->m_CurrentDepthBuffer != nullptr); if (!this->m_CurrentDepthBuffer) { return; } BLIZZARD_ASSERT(this->m_CurrentDepthBuffer->GetTexture()->IsValid()); auto currentTargetColor = this->m_CurrentTargetColor[0]; auto currentDepthBuffer = this->m_CurrentDepthBuffer; if ( !currentTargetColor || (currentTargetColor->m_Width == currentDepthBuffer->m_Width && currentTargetColor->m_Height == currentDepthBuffer->m_Height) ) { if (this->m_CurrentTargetDepth != currentDepthBuffer) { this->Sub34BB0(GL_DEPTH_ATTACHMENT, currentDepthBuffer, 0); this->m_CurrentTarget->Attach(currentDepthBuffer, GL_DEPTH_ATTACHMENT, 0); auto currentTargetDepth = this->m_CurrentTargetDepth; this->m_CurrentTargetDepth = currentDepthBuffer; this->m_CurrentDepthBuffer = currentDepthBuffer; if ( (currentTargetDepth == nullptr && currentDepthBuffer != nullptr) || (currentDepthBuffer != nullptr && currentTargetDepth != nullptr && currentTargetDepth->m_DepthBits != currentDepthBuffer->m_DepthBits) ) { this->SetDepthBias(this->m_ConstantDepthBias, this->m_SlopeScaledDepthBias); } if (this->m_CurrentDepthBuffer->GetFormat() == GLTF_D24S8) { this->Sub34BB0(GL_STENCIL_ATTACHMENT, this->m_CurrentDepthBuffer, 0); this->m_CurrentTarget->Attach(this->m_CurrentDepthBuffer, GL_STENCIL_ATTACHMENT, 0); this->m_CurrentTargetStencil = this->m_CurrentDepthBuffer; } } return; } auto currentTargetDepth = this->m_CurrentTargetDepth; if (currentTargetDepth == currentDepthBuffer) { this->Sub34BB0(GL_DEPTH_ATTACHMENT, nullptr, 0); this->m_CurrentTarget->Attach(nullptr, GL_DEPTH_ATTACHMENT, 0); this->m_CurrentTargetDepth = nullptr; this->m_CurrentDepthBuffer = currentTargetDepth; if (currentTargetDepth->GetFormat() == GLTF_D24S8) { this->Sub34BB0(GL_STENCIL_ATTACHMENT, nullptr, 0); this->m_CurrentTarget->Attach(nullptr, GL_STENCIL_ATTACHMENT, 0); this->m_CurrentTargetStencil = nullptr; } } } void GLSDLDevice::Clear(uint32_t clearMask, const GLColor4f& clearColor, double clearDepth, int32_t clearStencil) { this->CheckDepthTarget(); this->RestoreTextures(); auto colorMask = this->m_States.blend.colorMask[0]; if (clearMask & 0x4000) { for (int32_t i = 0; i < 4; i++) { if (this->m_CurrentTargetColor[i] && this->m_CurrentTargetColor[i]->GetTextureID() == this->m_States.binding.texture[0][this->m_States.binding.currentActiveTexture]) { this->BindTexture(this->m_CurrentTargetColor[i]->m_Target, nullptr); } } this->SetColorWriteMask(1, 1, 1, 1, 0); this->SetClearColor(clearColor); } if (clearMask & 0x100) { if (this->m_CurrentTargetDepth) { if (this->m_CurrentTargetDepth->GetTextureID() == this->m_States.binding.texture[0][this->m_States.binding.currentActiveTexture]) { this->BindTexture(this->m_CurrentTargetDepth->m_Target, nullptr); } if (!this->m_States.depth.writeMask) { glDepthMask(1); } this->SetClearDepth(clearDepth); } else { clearMask &= ~0x100; } } else { if (this->m_CurrentTargetDepth) { this->m_CurrentTarget->Detach(GL_DEPTH_ATTACHMENT); } } if (clearMask & 0x400) { if (this->m_CurrentTargetStencil) { if (this->m_CurrentTargetStencil->GetTextureID() == this->m_States.binding.texture[0][this->m_States.binding.currentActiveTexture]) { this->BindTexture(this->m_CurrentTargetStencil->m_Target, nullptr); } if (this->m_States.stencil.writeMask != -1) { glStencilMask(-1); } this->SetClearStencil(clearStencil); } else { clearMask &= ~0x400; } } else { if (this->m_CurrentTargetStencil) { this->m_CurrentTarget->Detach(GL_STENCIL_ATTACHMENT); } } auto scissorEnable = this->m_States.rasterizer.scissorEnable; auto scissorRect = this->m_States.rasterizer.scissor; auto currentTargetColor = this->m_CurrentTargetColor[0]; if ( currentTargetColor && ( this->m_States.rasterizer.viewport.left || this->m_States.rasterizer.viewport.top || this->m_States.rasterizer.viewport.width != currentTargetColor->m_Width || this->m_States.rasterizer.viewport.height != currentTargetColor->m_Height ) ) { this->SetScissor(1, this->m_States.rasterizer.viewport); glClear(clearMask); this->SetScissor(scissorEnable, scissorRect); } else { glClear(clearMask); } if (clearMask & 0x4000) { this->SetColorWriteMask(colorMask.red, colorMask.blue, colorMask.green, colorMask.alpha, 0); } if (clearMask & 0x100) { if (!this->m_States.depth.writeMask) { glDepthMask(0); } } else { if (this->m_CurrentTargetDepth) { this->m_CurrentTarget->Attach(this->m_CurrentTargetDepth, GL_DEPTH_ATTACHMENT, 0); } } if (clearMask & 0x400) { if (this->m_States.stencil.writeMask != -1) { glStencilMask(this->m_States.stencil.writeMask); } } else { if (this->m_CurrentTargetStencil) { this->m_CurrentTarget->Attach(this->m_CurrentTargetStencil, GL_STENCIL_ATTACHMENT, 0); } } } void GLSDLDevice::CopyTex(uint32_t a2, uint32_t a3, GLMipmap* dst, const GLRect* framebufferRect) { BLIZZARD_ASSERT(framebufferRect->width == dst->GetWidth()); BLIZZARD_ASSERT(framebufferRect->height == dst->GetHeight()); dst->m_Texture->Bind(nullptr, false); glCopyTexSubImage2D( dst->m_Target, dst->m_Level, a2, a3, framebufferRect->left, framebufferRect->top, framebufferRect->width, framebufferRect->height ); } GLBuffer* GLSDLDevice::CreateBuffer(GLEnum type, uint32_t a3, const void* a4, GLEnum usage, GLEnum format) { return GLBuffer::Create(type, a3, a4, usage, format); } GLShader* GLSDLDevice::CreateShader(GLShader::ShaderType type, const void* buf, int32_t codeLen, const char* name) { // TODO // Blizzard::Debug::Assert(this); return GLShader::Create(type, GLSDLDevice::m_UseHybridShader, false, "", buf, codeLen, "", name, nullptr); } GLTexture* GLSDLDevice::CreateTexture2D(uint32_t width, uint32_t height, uint32_t numMipMap, GLTextureFormat format, uint32_t flags) { return GLTexture2D::Create(width, height, numMipMap, format, flags); } GLTexture* GLSDLDevice::CreateTextureCubeMap(uint32_t size, uint32_t numMipMap, GLTextureFormat format, uint32_t flags) { // TODO return nullptr; } void GLSDLDevice::Draw(GLEnum primitive, uint32_t a3, uint32_t a4) { // TODO } void GLSDLDevice::DrawIndexed(GLEnum primitive, uint32_t a3, uint32_t a4, uint32_t a5, uint32_t a6, uint32_t count) { this->GLSDLDraw(primitive, a3, a4, a5, a6, count); } void GLSDLDevice::DrawRect() { if (!this->m_Window) { return; } if (!this->m_UseWindowSystemBuffer || this->m_FlippedSystemBuffer) { GLTexture2D* backBuffer = this->m_BackBufferColor; if (!backBuffer) { return; } GLMipmap* backBufferImage = backBuffer->GetMipmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); this->BlitFramebuffer(backBufferImage, nullptr, nullptr, nullptr, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER, 0); this->m_States.binding.framebuffer = 0; } glFlush(); this->m_Window->Swap(); if (!this->m_UseWindowSystemBuffer || this->m_FlippedSystemBuffer) { glBindFramebufferEXT(GL_FRAMEBUFFER, this->m_CurrentTarget->m_FramebufferID); this->m_States.binding.framebuffer = this->m_CurrentTarget->m_FramebufferID; } } uint32_t GLSDLDevice::GetID() { return this->m_ID; } GLFramebuffer* GLSDLDevice::GetCurrentTarget() { return this->m_CurrentTarget; } GLShader* GLSDLDevice::GetShader(GLShader::ShaderType shaderType) { if (shaderType == GLShader::eVertexShader) { return this->m_VertexShader; } else if (shaderType == GLShader::ePixelShader) { return this->m_PixelShader; } else { return nullptr; } } const GLStates::VertexArrayObject& GLSDLDevice::GetVertexArrayStates() { return this->m_VertexArrayObject->m_GLStates; } void GLSDLDevice::GLSDLDraw(GLEnum mode, uint32_t start, uint32_t end, uint32_t a5, uint32_t a6, uint32_t count) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); this->CheckDepthTarget(); // if (!this->m_DrawCount) { // if (this->m_Context.m_MTGLEnabled) { // glFlush(); // } // // GLFence::TestFences(); // } this->m_DrawCount++; this->RestoreTextures(); this->m_DefaultVertexArrayObject.m_Properties.m_VertexBase = a5; GLVertexArray::FindVertexArray(this, this->m_DefaultVertexArrayObject); auto vs = this->m_VertexShader; auto ps = this->m_PixelShader; if (ps) { // TODO // this->Sub30440(); } // if (this->m_TexWorker && !this->m_TexWorker->m_UnkA1) { // this->m_TexWorker->WaitOnGLObjects(); // } if (vs) { this->SetShader(GLShader::eVertexShader, vs); } else { this->ApplyTransforms(); } if (ps) { this->SetShader(GLShader::ePixelShader, ps); } else { this->UpdateFFPTexturing(); } if (vs && vs->m_UsingGLSL && ps && ps->m_UsingGLSL) { this->m_GLSLProgram = GLGLSLProgram::Find(vs, ps); } else { this->BindGLSLProgram(nullptr); } this->ApplyShaderConstants(); if (count) { GLBuffer* buffer = this->m_VertexArrayObject->m_Properties.m_IndexBuffer; GLEnum format = buffer->m_IndexFormat; uint32_t v18; if (format == GL_UNSIGNED_SHORT) { v18 = 1; } else if (format == GL_UNSIGNED_INT) { v18 = 2; } else { BLIZZARD_ASSERT(!"buffer uses unknown format"); } void* indices = GLBuffer::m_UsingVBO ? reinterpret_cast(a6 << v18) : buffer->m_Data + (a6 << v18); glDrawRangeElements(mode, start, end, count, buffer->m_IndexFormat, indices); } else { glDrawArrays(mode, start, end - start); } } void GLSDLDevice::Init(GLSDLWindow* window, const char* debugName, uint32_t flags) { if (this->m_Init) { return; } this->m_BatchViewerEnabled = flags & 0x1; this->m_UseWindowSystemBuffer = flags & (0x2 | 0x4); this->m_FlippedSystemBuffer = flags & 0x4; this->m_ShaderCompiler = flags & 0x8; this->m_WorkerDevice = flags & 0x10; this->m_DebugName.assign(debugName, strlen(debugName)); this->m_Window = window; // *** sets // this->m_UseWindowSystemBuffer = false; // *** GLSDLDevice::Set(this); this->m_Context.Create(window); this->m_Context.MakeCurrent(window); // TODO // if (dword_10329E4 == dword_10329E0) // GLRendererInfo::InitExtensions(); this->LoadDefaultStates(); this->m_Init = true; if (this->m_ID == -1) { this->m_ID = GLSDLDevice::m_Devices.size(); GLSDLDevice::m_Devices.insert(GLSDLDevice::m_Devices.end(), this); } else { GLSDLDevice::m_Devices[this->m_ID] = this; } if (!GLSDLDevice::m_StaticResourcesRefCount) { // GLContext::s_MainContext = this->m_Context.m_Context->context; GLSDLDevice::InitPools(); GLSDLDevice::StaticInit(); } ++GLSDLDevice::m_StaticResourcesRefCount; // if (!this->m_WorkerDevice) { // GLWorker* v11 = new GLWorker(this); // this->m_TexWorker = v11; // } glBindFramebufferEXT(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); GLFramebuffer* v12 = GLFramebuffer::Create(0); this->m_FBOTarget = v12; GLFramebuffer* currentTarget = v12; // TODO verify this check if (this->m_UseWindowSystemBuffer) { GLFramebuffer* v14 = GLFramebuffer::Create(1); this->m_SystemTarget = v14; currentTarget = v14; } this->m_CurrentTarget = currentTarget; GLuint v15 = 0; if (currentTarget) { v15 = currentTarget->m_FramebufferID; } if (this->m_States.binding.framebuffer != v15) { glBindFramebufferEXT(GL_FRAMEBUFFER, v15); this->m_States.binding.framebuffer = v15; } } void GLSDLDevice::LoadDefaultStates() { // Depth this->m_States.depth.testEnable = false; this->m_States.depth.compareFunc = GL_GEQUAL; this->m_States.depth.writeMask = true; // Stencil this->m_States.stencil.testEnable = false; this->m_States.stencil.ref = 0; this->m_States.stencil.mask = 0xFFFFFFFF; this->m_States.stencil.writeMask = 0xFFFFFFFF; this->m_States.stencil.useTwoSidedStencil = false; this->m_States.stencil.front.compareFunc = GL_ALWAYS; this->m_States.stencil.front.opFail = GL_KEEP; this->m_States.stencil.front.opZFail = GL_KEEP; this->m_States.stencil.front.opZPass = GL_KEEP; this->m_States.stencil.back.compareFunc = GL_ALWAYS; this->m_States.stencil.back.opFail = GL_KEEP; this->m_States.stencil.back.opZFail = GL_KEEP; this->m_States.stencil.back.opZPass = GL_KEEP; // Rasterizer this->m_States.rasterizer.cullMode = GL_CCW; this->m_States.rasterizer.cullFaceMode = GL_BACK; this->m_States.rasterizer.fillMode = GL_FILL; this->m_States.rasterizer.constantDepthBias = 0.0; this->m_States.rasterizer.slopeScaledDepthBias = 0.0; this->m_States.rasterizer.viewport = { 0, 0, this->m_Window->GetWidth(), this->m_Window->GetHeight() }; this->m_States.rasterizer.zNear = 0.0; this->m_States.rasterizer.zFar = 1.0; this->m_States.rasterizer.scissorEnable = false; this->m_States.rasterizer.scissor = { 0, 0, this->m_Window->GetWidth(), this->m_Window->GetHeight() }; this->m_States.rasterizer.clipPlaneMask = 0; memset(this->m_States.rasterizer.clipPlanes, 0, sizeof(this->m_States.rasterizer.clipPlanes)); // Blend for (int32_t i = 0; i < 4; ++i) { this->m_States.blend.colorMask[i] = { true, true, true, true }; } this->m_States.blend.alphaBlend = 0; this->m_States.blend.srcBlendFactor = 1; this->m_States.blend.destBlendFactor = 0; this->m_States.blend.blendOp = GL_FUNC_ADD; this->m_States.blend.blendColor = GLColor4f::ZERO; // FixedFunc this->m_States.fixedFunc.fogColor = { 0.0, 0.0, 0.0, 0.0 }; this->m_States.fixedFunc.fogStart = 0.0; this->m_States.fixedFunc.alphaTestRef = 0.0; this->m_States.fixedFunc.fogEnable = 0; this->m_States.fixedFunc.fogMode = GL_LINEAR; this->m_States.fixedFunc.fogEnd = 1.0; this->m_States.fixedFunc.fogDensity = 1.0; this->m_States.fixedFunc.alphaTestEnable = 0; this->m_States.fixedFunc.alphaTestFunc = GL_ALWAYS; for (int32_t i = 0; i < 8; ++i) { this->m_States.fixedFunc.texOp[i].texturing = 0; this->m_States.fixedFunc.texOp[i].constant = GLColor4f::ZERO; this->m_States.fixedFunc.texOp[i].colorOp = GL_MODULATE; this->m_States.fixedFunc.texOp[i].colorScale = 1.0; this->m_States.fixedFunc.texOp[i].colorArg0 = GL_TEXTURE; this->m_States.fixedFunc.texOp[i].colorArg1 = GL_PREVIOUS; this->m_States.fixedFunc.texOp[i].colorArg2 = GL_CONSTANT; this->m_States.fixedFunc.texOp[i].alphaOp = GL_MODULATE; this->m_States.fixedFunc.texOp[i].alphaScale = 1.0; this->m_States.fixedFunc.texOp[i].alphaArg0 = GL_TEXTURE; this->m_States.fixedFunc.texOp[i].alphaArg1 = GL_PREVIOUS; this->m_States.fixedFunc.texOp[i].alphaArg2 = GL_CONSTANT; } this->m_States.fixedFunc.lighting.enable = true; this->m_States.fixedFunc.lighting.sceneAmbient = { 0.0, 0.0, 0.0, 0.0 }; for (int32_t i = 0; i < 8; ++i) { this->m_States.fixedFunc.lighting.lights[i].enable = false; this->m_States.fixedFunc.lighting.lights[i].position = { 0.0, 0.0, 1.0, 0.0 }; this->m_States.fixedFunc.lighting.lights[i].view.isDirty = true; this->m_States.fixedFunc.lighting.lights[i].view.isIdentity = true; this->m_States.fixedFunc.lighting.lights[i].constantAttenuation = 0.0; this->m_States.fixedFunc.lighting.lights[i].linearAttenuation = 0.0; this->m_States.fixedFunc.lighting.lights[i].quadraticAttenuation = 0.0; this->m_States.fixedFunc.lighting.lights[i].ambient = GLColor4f::ZERO; this->m_States.fixedFunc.lighting.lights[i].diffuse = GLColor4f::WHITE; this->m_States.fixedFunc.lighting.lights[i].specular = GLColor4f::ZERO; } this->m_States.fixedFunc.lighting.lights[0].enable = true; this->m_States.fixedFunc.lighting.material.materialSource = 4609; this->m_States.fixedFunc.lighting.material.ambient = GLColor4f::ZERO; this->m_States.fixedFunc.lighting.material.diffuse = GLColor4f::WHITE; this->m_States.fixedFunc.lighting.material.specular = GLColor4f::ZERO; this->m_States.fixedFunc.lighting.material.shininess = 0.0; this->m_States.fixedFunc.lighting.material.emission = GLColor4f::ZERO; this->m_States.fixedFunc.transforms.matrixMode = 5888; this->m_States.fixedFunc.transforms.modelviewStatus = 5888; this->m_States.fixedFunc.transforms.modelView.isIdentity = true; this->m_States.fixedFunc.transforms.modelView.isDirty = true; this->m_States.fixedFunc.transforms.world.isIdentity = true; this->m_States.fixedFunc.transforms.world.isDirty = true; this->m_States.fixedFunc.transforms.view.isIdentity = true; this->m_States.fixedFunc.transforms.view.isDirty = true; this->m_States.fixedFunc.transforms.projection.isIdentity = true; this->m_States.fixedFunc.transforms.projection.isDirty = true; for (int32_t i = 0; i < 8; ++i) { this->m_States.fixedFunc.transforms.texture[i].isIdentity = true; this->m_States.fixedFunc.transforms.texture[i].isDirty = true; } for (int32_t i = 0; i < 8; ++i) { this->m_States.fixedFunc.texCoordIndex[i] = i; } for (int32_t i = 0; i < 8; ++i) { this->m_States.fixedFunc.texGen[i].S = 0; this->m_States.fixedFunc.texGen[i].T = 0; this->m_States.fixedFunc.texGen[i].R = 0; this->m_States.fixedFunc.texGen[i].Q = 0; } this->m_States.fixedFunc.pointSprite.enable = false; this->m_States.fixedFunc.pointSprite.size = 1.0; this->m_States.fixedFunc.pointSprite.attenuation[0] = 1.0; this->m_States.fixedFunc.pointSprite.attenuation[1] = 0.0; this->m_States.fixedFunc.pointSprite.attenuation[2] = 0.0; this->m_States.fixedFunc.pointSprite.min = 0.0; this->m_States.fixedFunc.pointSprite.max = 1.0; this->m_States.fixedFunc.normalizeNormal = false; // Samplers for (int32_t i = 0; i < 16; ++i) { this->m_States.samplers[i].mipmapBias = 0.0; this->m_States.samplers[i].addressModeS = 10497; this->m_States.samplers[i].addressModeT = 10497; this->m_States.samplers[i].addressModeR = 10497; this->m_States.samplers[i].magFilterMode = 9729; this->m_States.samplers[i].minFilterMode = 9729; this->m_States.samplers[i].maxAnisotropy = 1.0; this->m_States.samplers[i].borderColor = { 0.0, 0.0, 0.0, 0.0 }; } // Shader this->m_States.shader.vertexShaderEnable = false; for (int32_t i = 0; i < 256; ++i) { this->m_States.shader.vertexShaderConst[i] = { 0.0, 0.0, 0.0, 1.0 }; } this->m_States.shader.pixelShaderEnable = false; for (int32_t i = 0; i < 64; ++i) { this->m_States.shader.pixelShaderConst[i] = { 0.0, 0.0, 0.0, 1.0 }; } // Binding memset(&this->m_States.binding, 0, sizeof(this->m_States.binding)); // Clear this->m_States.clear.clearColor = GLColor4f::ZERO; this->m_States.clear.clearDepth = 1.0; this->m_States.clear.clearStencil = 0; // Misc this->m_States.misc.drawBuffers[0] = 0; this->m_States.misc.drawBuffers[1] = 0; this->m_States.misc.drawBuffers[2] = 0; this->m_States.misc.drawBuffers[3] = 0; this->m_States.misc.readBuffer = 0; // Assign default states memcpy(&this->m_DefaultStates.depth, &this->m_States.depth, sizeof(this->m_DefaultStates.depth)); memcpy(&this->m_DefaultStates.stencil, &this->m_States.stencil, sizeof(this->m_DefaultStates.stencil)); memcpy(&this->m_DefaultStates.rasterizer, &this->m_States.rasterizer, sizeof(this->m_DefaultStates.rasterizer)); memcpy(&this->m_DefaultStates.blend, &this->m_States.blend, sizeof(this->m_DefaultStates.blend)); memcpy(&this->m_DefaultStates.clear, &this->m_States.clear, sizeof(this->m_DefaultStates.clear)); memcpy(&this->m_DefaultStates.fixedFunc, &this->m_States.fixedFunc, sizeof(this->m_DefaultStates.fixedFunc)); memcpy(this->m_DefaultStates.samplers, this->m_States.samplers, sizeof(this->m_DefaultStates.samplers)); memcpy(&this->m_DefaultStates.shader, &this->m_States.shader, sizeof(this->m_DefaultStates.shader)); memcpy(&this->m_DefaultStates.binding, &this->m_States.binding, sizeof(this->m_DefaultStates.binding)); memcpy(&this->m_DefaultStates.misc, &this->m_States.misc, sizeof(this->m_DefaultStates.misc)); // TODO // if (v54 != this->m_States.misc.unpackClientStorage) { // glPixelStorei(34226, v54); // this->m_States.misc.unpackClientStorage = v54; // } this->ApplyGLBindings(this->m_States, 1); this->ApplyGLStates(this->m_States, 1); } void GLSDLDevice::ResetBackbuffer(uint32_t width, uint32_t height, GLTextureFormat colorFormat, GLTextureFormat depthFormat, uint32_t sampleCount) { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); if ( this->m_BackBufferColor && this->m_BackBufferColor->m_Width == width && this->m_BackBufferColor->m_Height == height && this->m_BackBufferColor->m_Format == colorFormat && this->m_BackBufferDepth && this->m_BackBufferDepth->m_Format == depthFormat ) { if (this->m_UseWindowSystemBuffer && this->m_CurrentTarget->GetSampleCount() != sampleCount) { // this->m_Context.SetContextFormat(depthFormat, sampleCount); } return; } auto v24 = this->m_BackBufferColor != 0; if (this->m_BackBufferColor) { this->m_BackBufferColor->Release(); this->m_BackBufferColor = nullptr; } if (this->m_BackBufferStencil) { this->m_BackBufferStencil->Release(); this->m_BackBufferStencil = nullptr; } if (this->m_BackBufferDepth) { this->m_BackBufferDepth->Release(); this->m_BackBufferDepth = nullptr; } GLTextureFormat v10 = this->m_UseWindowSystemBuffer ? depthFormat : GLTF_INVALID; // this->m_Context.SetContextFormat(v10, sampleCount); this->BindFramebuffer( this->m_UseWindowSystemBuffer ? this->m_SystemTarget : this->m_FBOTarget ); if (this->m_UseWindowSystemBuffer && !v24) { this->Clear(0x4500, GLColor4f::BLACK, 1.0, 0); this->m_Window->Swap(); } uint32_t v13 = GLTFLAG_SYSTEM_BUFFER; if (!this->m_UseWindowSystemBuffer) { v13 = 0; } uint32_t v14 = GLTFLAG_RENDERTARGET; if (!this->m_FlippedSystemBuffer) { v14 = v13 | GLTFLAG_RENDERTARGET; } auto v15 = GLTexture2D::Create(width, height, 1, colorFormat, v14); this->m_BackBufferColor = v15; auto v16 = v15->GetMipmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); this->m_CurrentTargetColor[0] = v16; this->m_CurrentTarget->Attach(v16, GL_COLOR_ATTACHMENT0, 0); GLRect v29 = { 0, 0, static_cast(width), static_cast(height) }; this->SetViewport(v29, 0.0, 1.0); if (this->m_FlippedSystemBuffer) { auto v19 = this->m_BackBufferColor->GetMipmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); GLRect v25 = { 0, 0, v19->m_Width, v19->m_Height }; this->CopyTex(0, 0, v19, &v25); } if (depthFormat) { if (depthFormat == GLTF_D24S8) { auto v20 = GLTexture2D::Create(width, height, 1, GLTF_D24S8, v13 | GLTFLAG_RENDERTARGET | GLTFLAG_DEPTH | GLTFLAG_STENCIL); this->m_BackBufferDepth = v20; this->m_BackBufferStencil = v20; // TODO how to properly increment GLObject ref counts? v20->AddRefTwin(); v20->m_RefCount++; auto v22 = this->m_BackBufferStencil->GetMipmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); this->m_CurrentTargetStencil = v22; this->m_CurrentTarget->Attach(v22, GL_STENCIL_ATTACHMENT, 0); } else { this->m_BackBufferDepth = GLTexture2D::Create(width, height, 1, depthFormat, v13 | GLTFLAG_RENDERTARGET | GLTFLAG_DEPTH); } auto v17 = this->m_BackBufferDepth->GetMipmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); this->m_CurrentTargetDepth = v17; this->m_CurrentTarget->Attach(v17, GL_DEPTH_ATTACHMENT, 0); this->m_CurrentDepthBuffer = this->m_CurrentTargetDepth; this->SetDepthTestEnable(1); } BLIZZARD_ASSERT(this->m_CurrentTarget->IsValid()); this->Clear(0x4500, GLColor4f::BLACK, 1.0, 0); } void GLSDLDevice::Resize(uint32_t width, uint32_t height) { auto colorFormat = this->m_BackBufferColor ? this->m_BackBufferColor->m_Format : GLTF_INVALID; auto depthFormat = this->m_BackBufferDepth ? this->m_BackBufferDepth->m_Format : GLTF_INVALID; this->SetDisplay( width, height, colorFormat, depthFormat, 0, false, false, this->m_Context.GetSampleCount() ); } void GLSDLDevice::RestoreTextures() { BLIZZARD_ASSERT(this->m_Context.IsCurrentContext()); for (int32_t i = 0; i < 16; i++) { GLTexture* texture = this->m_Textures[i]; if (texture && !texture->IsValid()) { this->m_Textures[i] = nullptr; } this->SetTexture(i, this->m_Textures[i]); } } void GLSDLDevice::SetActiveTexture(uint32_t a2) { if (this->m_States.binding.currentActiveTexture != a2) { glActiveTexture(GL_TEXTURE0 + a2); this->m_States.binding.currentActiveTexture = a2; } } void GLSDLDevice::SetAlphaBlend(GLEnum srcBlend, GLEnum dstBlend, GLEnum blendOp) { if (this->m_States.blend.srcBlendFactor != srcBlend || this->m_States.blend.destBlendFactor != dstBlend) { glBlendFunc(srcBlend, dstBlend); this->m_States.blend.srcBlendFactor = srcBlend; this->m_States.blend.destBlendFactor = dstBlend; } if (this->m_States.blend.blendOp != blendOp) { glBlendEquation(blendOp); this->m_States.blend.blendOp = blendOp; } } void GLSDLDevice::SetAlphaBlendEnable(bool enable) { if (this->m_States.blend.alphaBlend != enable) { if (enable) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } this->m_States.blend.alphaBlend = enable; } } void GLSDLDevice::SetAlphaTest(GLEnum func, float ref) { if (this->m_States.fixedFunc.alphaTestFunc != func || this->m_States.fixedFunc.alphaTestRef != ref) { BLIZZARD_ASSERT(ref <= 1.0f); glAlphaFunc(func, ref); this->m_States.fixedFunc.alphaTestFunc = func; this->m_States.fixedFunc.alphaTestRef = ref; } } void GLSDLDevice::SetAlphaTestEnable(bool enable) { if (this->m_States.fixedFunc.alphaTestEnable != enable) { if (enable) { glEnable(GL_ALPHA_TEST); } else { glDisable(GL_ALPHA_TEST); } } } void GLSDLDevice::SetClearColor(const GLColor4f& clearColor) { if ( this->m_States.clear.clearColor.r != clearColor.r || this->m_States.clear.clearColor.g != clearColor.g || this->m_States.clear.clearColor.b != clearColor.b || this->m_States.clear.clearColor.a != clearColor.a ) { glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); this->m_States.clear.clearColor = { clearColor.r, clearColor.g, clearColor.b, clearColor.a }; } } void GLSDLDevice::SetClearDepth(double clearDepth) { if (this->m_States.clear.clearDepth != clearDepth) { glClearDepth(clearDepth); this->m_States.clear.clearDepth = clearDepth; } } void GLSDLDevice::SetClearStencil(int32_t clearStencil) { if (this->m_States.clear.clearStencil != clearStencil) { glClearStencil(clearStencil); this->m_States.clear.clearStencil = clearStencil; } } void GLSDLDevice::SetColorWriteMask(bool red, bool green, bool blue, bool alpha, uint32_t index) { if ( this->m_States.blend.colorMask[index].red != red || this->m_States.blend.colorMask[index].green != green || this->m_States.blend.colorMask[index].blue != blue || this->m_States.blend.colorMask[index].alpha != alpha ) { if (GLSDLDevice::m_ExtColorMaskIndexed) { glColorMaskIndexedEXT(index, red, green, blue, alpha); } else if (index == 0) { glColorMask(red, green, blue, alpha); } this->m_States.blend.colorMask[index].red = red; this->m_States.blend.colorMask[index].green = green; this->m_States.blend.colorMask[index].blue = blue; this->m_States.blend.colorMask[index].alpha = alpha; } } void GLSDLDevice::SetCullMode(GLEnum cullMode) { if (this->m_States.rasterizer.cullMode != cullMode) { if (cullMode) { if (cullMode - GL_CW <= 1) { glEnable(GL_CULL_FACE); glFrontFace(cullMode); } this->m_States.rasterizer.cullMode = cullMode; } else { glDisable(GL_CULL_FACE); this->m_States.rasterizer.cullMode = 0; } } } void GLSDLDevice::SetDepthBias(float constantBias, float slopeScaledBias) { // TODO } void GLSDLDevice::SetDepthTestEnable(bool enable) { if (this->m_States.depth.testEnable != enable) { if (enable) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } this->m_States.depth.testEnable = enable; } } void GLSDLDevice::SetDepthTestFunc(GLEnum func) { if (this->m_States.depth.compareFunc != func) { glDepthFunc(func); this->m_States.depth.compareFunc = func; } } void GLSDLDevice::SetDepthWriteMask(bool enable) { if (this->m_States.depth.writeMask != enable) { glDepthMask(enable); this->m_States.depth.writeMask = enable; } } void GLSDLDevice::SetDisplay(uint32_t width, uint32_t height, GLTextureFormat colorFormat, GLTextureFormat depthFormat, uint32_t refreshRate, bool windowed, bool captureDisplay, uint32_t sampleCount) { // uint32_t v9 = a9; // if (this->m_PBOPool) { // // TODO // // this->m_PBOPool->Flush(1); // } // if (a9 > 7) { // uint32_t v10; // if (a7) { // // CGDirectDisplayID mainDisplay = CGMainDisplayID(); // // CGRect bounds = CGDisplayBounds(mainDisplay); // // CGFloat boundsWidth = CGRectGetWidth(bounds); // // CGFloat boundsHeight = CGRectGetHeight(bounds); // // v10 = std::floor(boundsWidth) * std::floor(boundsHeight); // } else { // v10 = width * height; // } // if (v10 >= 2304001) { // v9 = 6; // } // } // if (this->m_Context.m_Window) { // // TODO // // - callback related... set to default callbacks? // // (this->m_Context.m_Window + 84)(); // } // if (a7) { // if (this->m_Context.m_Window) { // this->m_Context.m_Window->Resize(width, height); // } // this->m_Context.SetWindow(this->m_Context.m_Window, 0); // } else { // this->m_Context.SetFullscreenMode(width, height, a6, a8); // } GLSDLWindowRect newRect; newRect.size.width = width; newRect.size.height = height; this->m_Window->Resize(newRect); this->ResetBackbuffer(width, height, colorFormat, depthFormat, sampleCount); // if (this->m_Context.m_Window) { // // TODO // // - set active callbacks to callbacks // // (this->m_Context.m_Window + 88)(); // } } void GLSDLDevice::SetFogColor(float r, float g, float b, float a) { if ( this->m_States.fixedFunc.fogColor.r != r || this->m_States.fixedFunc.fogColor.g != g || this->m_States.fixedFunc.fogColor.b != b || this->m_States.fixedFunc.fogColor.a != a ) { this->m_States.fixedFunc.fogColor.r = r; this->m_States.fixedFunc.fogColor.g = g; this->m_States.fixedFunc.fogColor.b = b; this->m_States.fixedFunc.fogColor.a = a; glFogfv(GL_FOG_COLOR, reinterpret_cast(&this->m_States.fixedFunc.fogColor)); // TODO logic related to a renderer info value } } void GLSDLDevice::SetFogEnable(bool enable) { if (this->m_States.fixedFunc.fogEnable != enable) { if (enable) { glEnable(GL_FOG); } else { glDisable(GL_FOG); } this->m_States.fixedFunc.fogEnable = enable; } } void GLSDLDevice::SetFogParam(GLEnum param, float value) { if (param == GL_FOG_START) { if (this->m_States.fixedFunc.fogStart != value) { glFogf(GL_FOG_START, value); this->m_States.fixedFunc.fogStart = value; } } else if (param == GL_FOG_END) { if (this->m_States.fixedFunc.fogEnd != value) { glFogf(GL_FOG_END, value); this->m_States.fixedFunc.fogEnd = value; } } else if (param == GL_FOG_DENSITY) { if (this->m_States.fixedFunc.fogDensity != value) { glFogf(GL_FOG_DENSITY, value); this->m_States.fixedFunc.fogDensity = value; } } else { BLIZZARD_ASSERT(false); } } void GLSDLDevice::SetIndexBuffer(GLBuffer* buffer) { BLIZZARD_ASSERT(buffer == nullptr || buffer->m_IndexFormat != GL_ZERO); this->m_DefaultVertexArrayObject.m_Properties.m_IndexBuffer = buffer; } void GLSDLDevice::SetLightingEnable(bool enable) { if (this->m_States.fixedFunc.lighting.enable != enable) { if (enable) { glEnable(GL_LIGHTING); } else { glDisable(GL_LIGHTING); } this->m_States.fixedFunc.lighting.enable = enable; } } void GLSDLDevice::SetModelView(GLEnum transform) { if (transform == 'VIEW') { // TODO return; } if (transform == 'WRLD') { // TODO return; } if (transform != GL_MODELVIEW) { BLIZZARD_ASSERT(false); } auto& world = this->m_States.fixedFunc.transforms.world; auto& view = this->m_States.fixedFunc.transforms.view; auto& modelView = this->m_States.fixedFunc.transforms.modelView; if (this->m_States.fixedFunc.transforms.modelviewStatus != transform || modelView.isDirty) { if (world.isIdentity && view.isIdentity) { modelView.isIdentity = true; modelView.isDirty = true; } else if (world.isIdentity) { modelView = view; modelView.isIdentity = false; modelView.isDirty = true; } else if (view.isIdentity) { modelView = world; modelView.isIdentity = false; modelView.isDirty = true; } else { // TODO assign model * view to modelView BLIZZARD_ASSERT(!"Unimplemented"); } if (this->m_States.fixedFunc.transforms.matrixMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); this->m_States.fixedFunc.transforms.matrixMode = GL_MODELVIEW; } if (modelView.isIdentity) { glLoadIdentity(); } else { glLoadMatrixf(modelView.m); } this->m_States.fixedFunc.transforms.modelviewStatus = transform; } } void GLSDLDevice::SetScissor(bool a2, const GLRect& a3) { // TODO } void GLSDLDevice::SetShader(GLShader::ShaderType shaderType, GLShader* shader) { if (shader) { if (shader->var18) { // TODO } BLIZZARD_ASSERT(shader->IsEnabled()); BLIZZARD_ASSERT(shader->GetShaderType() == shaderType); this->BindShader(shader); } int32_t enable = shader != nullptr; if (shaderType == GLShader::eVertexShader) { if (this->m_States.shader.vertexShaderEnable != enable) { if (enable) { glEnable(GL_VERTEX_PROGRAM_ARB); } else { glDisable(GL_VERTEX_PROGRAM_ARB); } this->m_States.shader.vertexShaderEnable = enable; } this->m_VertexShader = shader; } else if (shaderType == GLShader::ePixelShader) { if (this->m_States.shader.pixelShaderEnable != enable) { if (enable) { glEnable(GL_FRAGMENT_PROGRAM_ARB); } else { glDisable(GL_FRAGMENT_PROGRAM_ARB); } this->m_States.shader.pixelShaderEnable = enable; } this->m_PixelShader = shader; } else { BLIZZARD_ASSERT(!"Unknown shader type!"); } } void GLSDLDevice::SetShaderConstants(GLShader::ShaderType shaderType, uint32_t index, const float* constants, uint32_t count) { BLIZZARD_ASSERT(count != 0); GLShader* shader = nullptr; if (shaderType == GLShader::eVertexShader) { shader = this->m_VertexShader; } else if (shaderType == GLShader::ePixelShader) { shader = this->m_PixelShader; } if (GLSDLDevice::m_ShaderConstantBindings) { if (!shader) { return; } if (shader && shader->var10) { shader->SetShaderConstants(shaderType, index, constants, count); return; } } this->SetShaderConstantsInternal(shaderType, index, constants, count); } void GLSDLDevice::SetShaderConstantsInternal(GLShader::ShaderType shaderType, uint32_t index, const float* constants, uint32_t count) { if (shaderType == GLShader::eVertexShader) { BLIZZARD_ASSERT((index + count) <= std::extentm_States.shader.vertexShaderConst)>::value); memcpy(&this->m_States.shader.vertexShaderConst[index], constants, (sizeof(float) * 4) * count); BLIZZARD_ASSERT(index <= 0xFFFF); BLIZZARD_ASSERT(count <= 0xFFFF); uint16_t start = std::min(static_cast(index), this->m_DirtyVertexShaderConsts.start); uint16_t end = std::max(static_cast(index + count), this->m_DirtyVertexShaderConsts.end); this->m_DirtyVertexShaderConsts.start = start; this->m_DirtyVertexShaderConsts.end = end; } else if (shaderType == GLShader::ePixelShader) { BLIZZARD_ASSERT((index + count) <= std::extentm_States.shader.pixelShaderConst)>::value); memcpy(&this->m_States.shader.pixelShaderConst[index], constants, (sizeof(float) * 4) * count); BLIZZARD_ASSERT(index <= 0xFFFF); BLIZZARD_ASSERT(count <= 0xFFFF); uint16_t start = std::min(static_cast(index), this->m_DirtyPixelShaderConsts.start); uint16_t end = std::max(static_cast(index + count), this->m_DirtyPixelShaderConsts.end); this->m_DirtyPixelShaderConsts.start = start; this->m_DirtyPixelShaderConsts.end = end; } else { // TODO // BLIZZARD_ASSERT(false, "Unknown shader type %d!", shaderType); } } void GLSDLDevice::SetTexture(uint32_t stage, GLTexture* texture) { if (stage > 15) { BLIZZARD_ASSERT(!"setting an unsupported texture stage to a non-NULL texture"); } BLIZZARD_ASSERT(texture == nullptr || texture->IsValid()); uint32_t textureID = 0; GLEnum textureType = GL_TEXTURE_2D; if (this->m_Textures[stage]) { textureType = this->m_Textures[stage]->m_TextureType; } if (texture) { textureID = texture->m_TextureID; textureType = texture->m_TextureType; } uint32_t index = GLSDLTextureTypeToIndex(textureType); if (this->m_States.binding.texture[index][stage] != textureID) { this->SetActiveTexture(stage); if (texture) { texture->Bind(this, 1); } else { this->BindTexture(textureType, nullptr); } } this->m_Textures[stage] = texture; } void GLSDLDevice::SetTransform(GLEnum transform, const float* a3) { GLTransform* t; if (transform == 'VIEW') { t = &this->m_States.fixedFunc.transforms.view; } else if (transform == 'WRLD') { t = &this->m_States.fixedFunc.transforms.world; } else if (transform == GL_PROJECTION) { t = &this->m_States.fixedFunc.transforms.projection; } else if (transform >= GL_TEXTURE0 && transform <= GL_TEXTURE7) { t = &this->m_States.fixedFunc.transforms.texture[transform - GL_TEXTURE0]; } else { BLIZZARD_ASSERT(false); } if (*t != a3) { t->Set(a3); } if (t->isDirty) { if (transform == 'VIEW' || transform == 'WRLD') { this->m_States.fixedFunc.transforms.modelView.isDirty = true; } } } void GLSDLDevice::SetUnpackClientStorage(bool enable) { // TODO // Blizzard::Debug::Assert(!this->IsUsingPBO() || enable == GL_FALSE); if (this->m_States.misc.unpackClientStorage != enable) { // glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, enable); this->m_States.misc.unpackClientStorage = enable; } } void GLSDLDevice::SetVertexBuffer(uint32_t index, GLBuffer* buffer, uint32_t offset, uint32_t stride) { BLIZZARD_ASSERT(index < GL_MAX_STREAM); BLIZZARD_ASSERT(buffer == nullptr || buffer->m_IndexFormat == GL_ZERO); auto properties = &this->m_DefaultVertexArrayObject.m_Properties; properties->m_VertexBuffer[index] = buffer; properties->m_VertexBufferOffset[index] = offset; properties->m_VertexBufferStride[index] = stride; } void GLSDLDevice::SetVertexFormat(GLVertexFormat* format) { BLIZZARD_ASSERT(format->m_Size <= kMAX_VERTEX_ATTRIBS); this->m_DefaultVertexArrayObject.m_Properties.m_VertexBufferFormat = format; } void GLSDLDevice::SetViewport(const GLRect& viewport, double zNear, double zFar) { if ( this->m_States.rasterizer.viewport.left != viewport.left || this->m_States.rasterizer.viewport.top != viewport.top || this->m_States.rasterizer.viewport.width != viewport.width || this->m_States.rasterizer.viewport.height != viewport.height ) { glViewport(viewport.left, viewport.top, viewport.width, viewport.height); this->m_States.rasterizer.viewport = viewport; } if ( this->m_States.rasterizer.zNear != zNear || this->m_States.rasterizer.zFar != zFar ) { glDepthRange(zNear, zFar); this->m_States.rasterizer.zNear = zNear; this->m_States.rasterizer.zFar = zFar; } } void GLSDLDevice::Sub34BB0(GLEnum a2, GLMipmap* a3, uint32_t index) { if (!a3 || !this->m_UseWindowSystemBuffer) { return; } GLFramebuffer* target; if (a3->GetTexture() == this->m_BackBufferColor || a3->GetTexture() == this->m_BackBufferDepth || a3->GetTexture() == this->m_BackBufferStencil) { if (this->m_CurrentTarget == this->m_SystemTarget) { return; } switch (a2) { case GL_DEPTH_ATTACHMENT: this->Sub34BB0(GL_DEPTH_ATTACHMENT, nullptr, 0); this->m_CurrentTarget->Attach(nullptr, GL_DEPTH_ATTACHMENT, 0); this->m_CurrentTargetDepth = nullptr; this->m_CurrentDepthBuffer = nullptr; break; case GL_STENCIL_ATTACHMENT: this->Sub34BB0(GL_STENCIL_ATTACHMENT, nullptr, 0); this->m_CurrentTarget->Attach(nullptr, GL_STENCIL_ATTACHMENT, 0); this->m_CurrentTargetStencil = nullptr; break; case GL_COLOR_ATTACHMENT0: // TODO this->SetColorTarget(0, index); break; } target = this->m_SystemTarget; } else { target = this->m_FBOTarget; } this->BindFramebuffer(target); } void GLSDLDevice::Sub38460(bool a2) { if (this->m_States.binding.framebuffer == 0) { glDrawBuffer(GL_BACK); this->m_States.misc.drawBuffers[0] = GL_BACK; glReadBuffer(GL_BACK); this->m_States.misc.readBuffer = GL_BACK; return; } if (a2) { // TODO return; } // TODO } void GLSDLDevice::Swap() { // if (this->m_Context.m_Window) { // if (this->m_FlippedSystemBuffer) { // GLRect rect = { // 0, // 0, // static_cast(this->m_BackBufferColor->m_Width), // static_cast(this->m_BackBufferColor->m_Height) // }; // GLMipmap* image = this->m_BackBufferColor->GetMipmap(0, GL_TEXTURE_CUBE_MAP_POSITIVE_X); // this->CopyTex(0, 0, image, &rect); // } // this->DrawRect(); // this->m_FrameNumber++; // this->m_DrawCount = 0; // } else { // // glFlushRender(); // this->m_DrawCount = 0; // } this->DrawRect(); this->m_FrameNumber++; this->m_DrawCount = 0; } void GLSDLDevice::UpdateFFPTexturing() { // TODO }