void HdSt_TestDriver::Draw(HdRenderPassSharedPtr const &renderPass) { HdTaskSharedPtrVector tasks = { boost::make_shared<HdSt_DrawTask>(renderPass, _renderPassState) }; _engine.Execute(_sceneDelegate->GetRenderIndex(), tasks); GLF_POST_PENDING_GL_ERRORS(); }
bool HdxColorCorrectionTask::_CreateShaderResources() { if (_shaderProgram) { return true; } // Client can choose to use Hydra's build-in sRGB color correction or use // OpenColorIO for color correction in which case we insert extra OCIO code. #ifdef PXR_OCIO_PLUGIN_ENABLED bool useOCIO = _colorCorrectionMode == HdxColorCorrectionTokens->openColorIO; #else bool useOCIO = false; #endif _shaderProgram.reset(new HdStGLSLProgram(_tokens->colorCorrectionShader)); HioGlslfx glslfx(HdxPackageColorCorrectionShader()); std::string fragCode = "#version 120\n"; if (useOCIO) { fragCode += "#define GLSLFX_USE_OCIO\n"; } fragCode += glslfx.GetSource(_tokens->colorCorrectionFragment); if (useOCIO) { std::string ocioGpuShaderText = _CreateOpenColorIOResources(); fragCode += ocioGpuShaderText; } if (!_shaderProgram->CompileShader(GL_VERTEX_SHADER, glslfx.GetSource(_tokens->colorCorrectionVertex)) || !_shaderProgram->CompileShader(GL_FRAGMENT_SHADER, fragCode) || !_shaderProgram->Link()) { TF_CODING_ERROR("Failed to load color correction shader"); _shaderProgram.reset(); return false; } GLuint programId = _shaderProgram->GetProgram().GetId(); _locations[COLOR_IN] = glGetUniformLocation(programId, "colorIn"); _locations[POSITION] = glGetAttribLocation(programId, "position"); _locations[UV_IN] = glGetAttribLocation(programId, "uvIn"); if (useOCIO) { _locations[LUT3D_IN] = glGetUniformLocation(programId, "LUT3dIn"); } GLF_POST_PENDING_GL_ERRORS(); return true; }
HdxCompositor::~HdxCompositor() { if (_colorTexture != 0) { glDeleteTextures(1, &_colorTexture); } if (_depthTexture != 0) { glDeleteTextures(1, &_depthTexture); } if (_vertexBuffer != 0) { glDeleteBuffers(1, &_vertexBuffer); } if (_compositorProgram) { _compositorProgram.reset(); } GLF_POST_PENDING_GL_ERRORS(); }
bool HdxColorCorrectionTask::_CreateBufferResources() { if (_vertexBuffer) { return true; } // A larger-than screen triangle with UVs made to fit the screen. // positions | uvs static const float vertices[] = { -1, 3, -1, 1, 0, 2, -1, -1, -1, 1, 0, 0, 3, -1, -1, 1, 2, 0 }; glGenBuffers(1, &_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); GLF_POST_PENDING_GL_ERRORS(); return true; }
HdxColorCorrectionTask::~HdxColorCorrectionTask() { if (_texture != 0) { glDeleteTextures(1, &_texture); } if (_texture3dLUT != 0) { glDeleteTextures(1, &_texture3dLUT); } if (_vertexBuffer != 0) { glDeleteBuffers(1, &_vertexBuffer); } if (_shaderProgram) { _shaderProgram.reset(); } if (_framebuffer != 0) { glDeleteFramebuffers(1, &_framebuffer); } GLF_POST_PENDING_GL_ERRORS(); }
void HdxColorCorrectionTask::_CopyTexture() { GLint restoreReadFB, restoreDrawFB; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &restoreReadFB); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &restoreDrawFB); // The read framebuffer will be the client's FBO (viewer backbuffer). // The write framebuffer will be ours. glBindFramebuffer(GL_READ_FRAMEBUFFER, restoreDrawFB); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _framebuffer); int width = _textureSize[0]; int height = _textureSize[1]; glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, restoreReadFB); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, restoreDrawFB); GLF_POST_PENDING_GL_ERRORS(); }
void HdxCompositor::UpdateDepth(int width, int height, uint8_t *data) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); if (width == 0 || height == 0) { if (_depthTexture != 0) { glDeleteTextures(1, &_depthTexture); _depthTexture = 0; } return; } if (_depthTexture == 0) { _CreateTextureResources(&_depthTexture); } glBindTexture(GL_TEXTURE_2D, _depthTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, data); glBindTexture(GL_TEXTURE_2D, 0); GLF_POST_PENDING_GL_ERRORS(); }
void HdxCompositor::UpdateColor(int width, int height, uint8_t *data) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); if (width == 0 || height == 0) { if (_colorTexture != 0) { glDeleteTextures(1, &_colorTexture); _colorTexture = 0; } return; } if (_colorTexture == 0) { _CreateTextureResources(&_colorTexture); } glBindTexture(GL_TEXTURE_2D, _colorTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glBindTexture(GL_TEXTURE_2D, 0); GLF_POST_PENDING_GL_ERRORS(); }
void HdxColorCorrectionTask::_ApplyColorCorrection() { // Client can choose to use Hydra's build-in sRGB color correction or use // OpenColorIO for color correction in which case we insert extra OCIO code. #ifdef PXR_OCIO_PLUGIN_ENABLED bool useOCIO = _colorCorrectionMode == HdxColorCorrectionTokens->openColorIO; #else bool useOCIO = false; #endif // A note here: colorCorrection is used for all of our plugins and has to be // robust to poor GL support. OSX compatibility profile provides a // GL 2.1 API, slightly restricting our choice of API and heavily // restricting our shader syntax. See also HdxCompositor. // Read from the texture-copy we made of the clients FBO and output the // color-corrected pixels into the clients FBO. GLuint programId = _shaderProgram->GetProgram().GetId(); glUseProgram(programId); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _texture); glUniform1i(_locations[COLOR_IN], 0); if (useOCIO) { glEnable(GL_TEXTURE_3D); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_3D, _texture3dLUT); glUniform1i(_locations[LUT3D_IN], 1); } glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer(_locations[POSITION], 4, GL_FLOAT, GL_FALSE, sizeof(float)*6, 0); glEnableVertexAttribArray(_locations[POSITION]); glVertexAttribPointer(_locations[UV_IN], 2, GL_FLOAT, GL_FALSE, sizeof(float)*6, reinterpret_cast<void*>(sizeof(float)*4)); glEnableVertexAttribArray(_locations[UV_IN]); // Since we are rendering a full-screen triangle, we want to disable the // depth and stencil writes. We need to preserve the depth and stencil, // because they are copied back to the clients framebuffer so they can do // additional compositing of e.g. bounding boxes. GLboolean restoreDepthWriteMask; GLboolean restoreStencilWriteMask; glGetBooleanv(GL_DEPTH_WRITEMASK, &restoreDepthWriteMask); glGetBooleanv(GL_STENCIL_WRITEMASK, &restoreStencilWriteMask); glDepthMask(GL_FALSE); glStencilMask(GL_FALSE); // Depth test must be ALWAYS instead of disabling the depth_test because // we still want to write to the depth buffer. Disabling depth_test disables // depth_buffer writes. GLint restoreDepthFunc; glGetIntegerv(GL_DEPTH_FUNC, &restoreDepthFunc); glDepthFunc(GL_ALWAYS); GLint restoreViewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, restoreViewport); glViewport(0, 0, _framebufferSize[0], _framebufferSize[1]); // The app may have alpha blending enabled. // We want to pass-through the alpha values, not alpha-blend on top of dest. GLboolean restoreblendEnabled; glGetBooleanv(GL_BLEND, &restoreblendEnabled); glDisable(GL_BLEND); // Alpha to coverage would prevent any pixels that have an alpha of 0.0 from // being written. We want to color correct all pixels. Even background // pixels that were set with a clearColor alpha of 0.0 GLboolean restoreAlphaToCoverage; glGetBooleanv(GL_SAMPLE_ALPHA_TO_COVERAGE, &restoreAlphaToCoverage); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); glDrawArrays(GL_TRIANGLES, 0, 3); if (restoreAlphaToCoverage) { glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); } if (restoreblendEnabled) { glEnable(GL_BLEND); } glViewport(restoreViewport[0], restoreViewport[1], restoreViewport[2], restoreViewport[3]); glDepthFunc(restoreDepthFunc); glDepthMask(restoreDepthWriteMask); glStencilMask(restoreStencilWriteMask); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(_locations[POSITION]); glDisableVertexAttribArray(_locations[UV_IN]); glUseProgram(0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); if (useOCIO) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_3D, 0); glDisable(GL_TEXTURE_3D); } GLF_POST_PENDING_GL_ERRORS(); }
bool HdxColorCorrectionTask::_CreateFramebufferResources(GLuint *texture) { // If framebufferSize is not provided we use the viewport size. // This can be incorrect if the client/app has changed the viewport to // be different then the render window size. (E.g. UsdView CameraMask mode) GfVec2i fboSize = _framebufferSize; if (fboSize[0] <= 0 || fboSize[1] <= 0) { GLint res[4] = {0}; glGetIntegerv(GL_VIEWPORT, res); fboSize = GfVec2i(res[2], res[3]); } bool createTexture = (_texture == 0 || fboSize != _textureSize); if (createTexture) { if (_texture != 0) { glDeleteTextures(1, &_texture); _texture = 0; } _textureSize = fboSize; GLint restoreTexture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &restoreTexture); glGenTextures(1, texture); glBindTexture(GL_TEXTURE_2D, *texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // XXX For step 1 we copy the client FBO texture, apply gamma to the // copy and write it back to the client texture. // A future step will likely create a 16F texture at the start of // hydra rendering and use color-correction to render the results back // into the client FBO texture. // XXX For now we assume we always want R16F. We could perhaps expose // this as client-API in HdxColorCorrectionTaskParams. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, _textureSize[0], _textureSize[1], 0, GL_RGBA, GL_FLOAT, 0); glBindTexture(GL_TEXTURE_2D, restoreTexture); } bool switchedGLContext = !_owningContext || !_owningContext->IsCurrent(); if (switchedGLContext) { // If we're rendering with a different context than the render pass // was created with, recreate the FBO because FB is not shared. // XXX we need this since we use a FBO in _CopyTexture(). Ideally we // use HdxCompositor to do the copy, but for that we need to know the // textureId currently bound to the default framebuffer. However // glGetFramebufferAttachmentParameteriv will return and error when // trying to query the texture name bound to GL_BACK_LEFT. if (_owningContext && _owningContext->IsValid()) { GlfGLContextScopeHolder contextHolder(_owningContext); glDeleteFramebuffers(1, &_framebuffer); } _owningContext = GlfGLContext::GetCurrentGLContext(); if (!TF_VERIFY(_owningContext, "No valid GL context")) { return false; } if (_framebuffer == 0) { glGenFramebuffers(1, &_framebuffer); } } if (createTexture || switchedGLContext) { GLint restoreReadFB, restoreDrawFB; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &restoreReadFB); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &restoreDrawFB); glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, restoreReadFB); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, restoreDrawFB); } GLF_POST_PENDING_GL_ERRORS(); return true; }
std::string HdxColorCorrectionTask::_CreateOpenColorIOResources() { #ifdef PXR_OCIO_PLUGIN_ENABLED // Use client provided OCIO values, or use default fallback values OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); const char* display = _displayOCIO.empty() ? config->getDefaultDisplay() : _displayOCIO.c_str(); const char* view = _viewOCIO.empty() ? config->getDefaultView(display) : _viewOCIO.c_str(); std::string inputColorSpace = _colorspaceOCIO; if (inputColorSpace.empty()) { OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace("default"); if (cs) { inputColorSpace = cs->getName(); } else { inputColorSpace = OCIO::ROLE_SCENE_LINEAR; } } // Setup the transformation we need to apply OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); transform->setDisplay(display); transform->setView(view); transform->setInputColorSpaceName(inputColorSpace.c_str()); if (!_looksOCIO.empty()) { transform->setLooksOverride(_looksOCIO.c_str()); transform->setLooksOverrideEnabled(true); } else { transform->setLooksOverrideEnabled(false); } OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform); // Create a GPU Shader Description OCIO::GpuShaderDesc shaderDesc; shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); shaderDesc.setFunctionName("OCIODisplay"); shaderDesc.setLut3DEdgeLen(_lut3dSizeOCIO); // Compute and the 3D LUT int num3Dentries = 3 * _lut3dSizeOCIO*_lut3dSizeOCIO*_lut3dSizeOCIO; std::vector<float> lut3d; lut3d.resize(num3Dentries); processor->getGpuLut3D(&lut3d[0], shaderDesc); // Load the data into an OpenGL 3D Texture if (_texture3dLUT != 0) { glDeleteTextures(1, &_texture3dLUT); } GLint restoreTexture; glGetIntegerv(GL_TEXTURE_BINDING_3D, &restoreTexture); glGenTextures(1, &_texture3dLUT); glBindTexture(GL_TEXTURE_3D, _texture3dLUT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, _lut3dSizeOCIO, _lut3dSizeOCIO, _lut3dSizeOCIO, 0, GL_RGB, GL_FLOAT, &lut3d[0]); glBindTexture(GL_TEXTURE_3D, restoreTexture); const char* gpuShaderText = processor->getGpuShaderText(shaderDesc); GLF_POST_PENDING_GL_ERRORS(); return std::string(gpuShaderText); #else return std::string(); #endif }
bool HdxIntersector::Query(HdxIntersector::Params const& params, HdRprimCollection const& col, HdEngine* engine, HdxIntersector::Result* result) { TRACE_FUNCTION(); // Make sure we're in a sane GL state before attempting anything. if (GlfHasLegacyGraphics()) { TF_RUNTIME_ERROR("framebuffer object not supported"); return false; } GlfGLContextSharedPtr context = GlfGLContext::GetCurrentGLContext(); if (!TF_VERIFY(context)) { TF_RUNTIME_ERROR("Invalid GL context"); return false; } if (!_drawTarget) { // Initialize the shared draw target late to ensure there is a valid GL // context, which may not be the case at constructon time. _Init(GfVec2i(128,128)); } GfVec2i size(_drawTarget->GetSize()); GfVec4i viewport(0, 0, size[0], size[1]); if (!TF_VERIFY(_renderPass)) { return false; } _renderPass->SetRprimCollection(col); // Setup state based on incoming params. _renderPassState->SetAlphaThreshold(params.alphaThreshold); _renderPassState->SetClipPlanes(params.clipPlanes); _renderPassState->SetCullStyle(params.cullStyle); _renderPassState->SetCamera(params.viewMatrix, params.projectionMatrix, viewport); _renderPassState->SetLightingEnabled(false); // Use a separate drawTarget (framebuffer object) for each GL context // that uses this renderer, but the drawTargets share attachments/textures. GlfDrawTargetRefPtr drawTarget = GlfDrawTarget::New(size); // Clone attachments into this context. Note that this will do a // light-weight copy of the textures, it does not produce a full copy of the // underlying images. drawTarget->Bind(); drawTarget->CloneAttachments(_drawTarget); // // Setup GL raster state // GLenum drawBuffers[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(3, drawBuffers); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); glClearColor(0,0,0,0); glClearStencil(0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); GLF_POST_PENDING_GL_ERRORS(); // // Execute the picking pass // { GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // Setup stencil state and prevent writes to color buffer. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, // stencil failed GL_KEEP, // stencil passed, depth failed GL_REPLACE); // stencil passed, depth passed // // Condition the stencil buffer. // params.depthMaskCallback(); // we expect any GL state changes are restored. // Disable stencil updates and setup the stencil test. glStencilFunc(GL_LESS, 0, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Clear depth incase the depthMaskCallback pollutes the depth buffer. glClear(GL_DEPTH_BUFFER_BIT); // Restore color outputs & setup state for rendering glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDisable(GL_CULL_FACE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glFrontFace(GL_CCW); // // Enable conservative rasterization, if available. // // XXX: This wont work until it's in the Glew build. bool convRstr = glewIsSupported("GL_NV_conservative_raster"); if (convRstr) { // XXX: this should come from Glew #define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 glEnable(GL_CONSERVATIVE_RASTERIZATION_NV); } // // Execute // // XXX: make intersector a Task HdTaskSharedPtrVector tasks; tasks.push_back(boost::make_shared<HdxIntersector_DrawTask>(_renderPass, _renderPassState, params.renderTags)); engine->Execute(*_index, tasks); glDisable(GL_STENCIL_TEST); if (convRstr) { // XXX: this should come from Glew #define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 glDisable(GL_CONSERVATIVE_RASTERIZATION_NV); } // Restore glBindVertexArray(0); glDeleteVertexArrays(1, &vao); } GLF_POST_PENDING_GL_ERRORS(); // // Capture the result buffers to be resolved later. // size_t len = size[0] * size[1]; std::unique_ptr<unsigned char[]> primId(new unsigned char[len*4]); std::unique_ptr<unsigned char[]> instanceId(new unsigned char[len*4]); std::unique_ptr<unsigned char[]> elementId(new unsigned char[len*4]); std::unique_ptr<float[]> depths(new float[len]); glBindTexture(GL_TEXTURE_2D, drawTarget->GetAttachments().at("primId")->GetGlTextureName()); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &primId[0]); glBindTexture(GL_TEXTURE_2D, drawTarget->GetAttachments().at("instanceId")->GetGlTextureName()); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &instanceId[0]); glBindTexture(GL_TEXTURE_2D, drawTarget->GetAttachments().at("elementId")->GetGlTextureName()); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &elementId[0]); glBindTexture(GL_TEXTURE_2D, drawTarget->GetAttachments().at("depth")->GetGlTextureName()); glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, &depths[0]); glBindTexture(GL_TEXTURE_2D, 0); GLF_POST_PENDING_GL_ERRORS(); if (result) { *result = HdxIntersector::Result( std::move(primId), std::move(instanceId), std::move(elementId), std::move(depths), _index, params, viewport); } drawTarget->Unbind(); GLF_POST_PENDING_GL_ERRORS(); return true; }
void HdxCompositor::Draw(GLuint colorId, GLuint depthId, bool remapDepth) { // No-op if no color data was specified. if (colorId == 0) { return; } // Create draw buffers if they haven't been created yet. if (_vertexBuffer == 0) { _CreateBufferResources(); } bool useDepthProgram = (depthId != 0); // Load the shader if it hasn't been loaded, or we're changing modes. if (!_compositorProgram || _useDepthProgram != useDepthProgram) { _CreateShaderResources(useDepthProgram); _useDepthProgram = useDepthProgram; } // No-op if the shader failed to compile. if (!_compositorProgram) { return; } // A note here: HdxCompositor is used for all of our plugins and has to be // robust to poor GL support. OSX compatibility profile provides a // GL 2.1 API, slightly restricting our choice of API and heavily // restricting our shader syntax. GLuint programId = _compositorProgram->GetProgram().GetId(); glUseProgram(programId); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, colorId); glUniform1i(_locations[colorIn], 0); if (depthId != 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, depthId); glUniform1i(_locations[depthIn], 1); } glUniform1i(_locations[remapDepthIn], (GLint)remapDepth); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer(_locations[position], 4, GL_FLOAT, GL_FALSE, sizeof(float)*6, 0); glEnableVertexAttribArray(_locations[position]); glVertexAttribPointer(_locations[uvIn], 2, GL_FLOAT, GL_FALSE, sizeof(float)*6, reinterpret_cast<void*>(sizeof(float)*4)); glEnableVertexAttribArray(_locations[uvIn]); GLboolean restoreAlphaToCoverage; glGetBooleanv(GL_SAMPLE_ALPHA_TO_COVERAGE, &restoreAlphaToCoverage); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); glDrawArrays(GL_TRIANGLES, 0, 3); if (restoreAlphaToCoverage) { glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); } glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(_locations[position]); glDisableVertexAttribArray(_locations[uvIn]); glUseProgram(0); if (depthId != 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); GLF_POST_PENDING_GL_ERRORS(); }