//----------------------------------------------------------------------- void GraphicsContextGL4::Clear(ClearOptions options, Color const& color, float depth, std::uint8_t stencil) { GLbitfield mask = 0; if ((options | ClearOptions::DepthBuffer) == options) { mask |= GL_DEPTH_BUFFER_BIT; auto clamped = std::min(std::max(depth, 0.0f), 1.0f); glClearDepthf(clamped); POMDOG_CHECK_ERROR_GL4("glClearDepthf"); } if ((options | ClearOptions::Stencil) == options) { mask |= GL_STENCIL_BUFFER_BIT; glClearStencil(stencil); POMDOG_CHECK_ERROR_GL4("glClearStencil"); } if ((options | ClearOptions::RenderTarget) == options) { mask |= GL_COLOR_BUFFER_BIT; auto colorVector = color.ToVector4(); glClearColor(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W); POMDOG_CHECK_ERROR_GL4("glClearColor"); } glClear(mask); POMDOG_CHECK_ERROR_GL4("glClear"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::SetViewport(Viewport const& viewport) { POMDOG_ASSERT(viewport.Width > 0); POMDOG_ASSERT(viewport.Height > 0); GLint viewportY = viewport.TopLeftY; if (renderTargets.empty()) { if (auto window = gameWindow.lock()) { viewportY = window->GetClientBounds().Height - (viewport.TopLeftY + viewport.Height); } } glViewport(viewport.TopLeftX, viewportY, viewport.Width, viewport.Height); POMDOG_CHECK_ERROR_GL4("glViewport"); static_assert(std::is_same<GLfloat, decltype(viewport.MinDepth)>::value && std::is_same<GLfloat, decltype(viewport.MaxDepth)>::value, "NOTE: You can use glDepthRange instead of glDepthRangef"); POMDOG_ASSERT(!std::isinf(viewport.MinDepth)); POMDOG_ASSERT(!std::isinf(viewport.MaxDepth)); POMDOG_ASSERT(!std::isnan(viewport.MinDepth)); POMDOG_ASSERT(!std::isnan(viewport.MaxDepth)); glDepthRangef(viewport.MinDepth, viewport.MaxDepth); POMDOG_CHECK_ERROR_GL4("glDepthRangef"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::SetRenderTarget() { POMDOG_ASSERT(frameBuffer); // Bind framebuffer glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->value); POMDOG_CHECK_ERROR_GL4("glBindFramebuffer"); // Unbind render targets { std::size_t index = 0; for (auto const& renderTarget: renderTargets) { POMDOG_ASSERT(renderTarget); renderTarget->UnbindFromFramebuffer(ToColorAttachment(index)); ++index; } } renderTargets.clear(); // Unbind depth stencil buffer glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); POMDOG_CHECK_ERROR_GL4("glFramebufferRenderbuffer"); // Bind default framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); POMDOG_CHECK_ERROR_GL4("glBindFramebuffer"); }
BufferGL4<Tag>::BufferGL4(void const* sourceData, std::size_t sizeInBytes, BufferUsage bufferUsage) { POMDOG_ASSERT(bufferUsage == BufferUsage::Immutable ? sourceData != nullptr : true); // Generate new buffer bufferObject = ([] { BufferObject buffer; glGenBuffers(1, buffer.Data()); return std::move(buffer); })(); POMDOG_CHECK_ERROR_GL4("glGenBuffers"); auto const oldBuffer = TypesafeHelperGL4::Get<BufferObject>(); ScopeGuard scope([&] { TypesafeHelperGL4::BindBuffer(oldBuffer); }); POMDOG_ASSERT(bufferObject); TypesafeHelperGL4::BindBuffer(*bufferObject); POMDOG_CHECK_ERROR_GL4("glBindBuffer"); POMDOG_ASSERT(sizeInBytes > 0); glBufferData(BufferTraits<Tag>::Buffer, sizeInBytes, sourceData, ToBufferUsage(bufferUsage)); POMDOG_CHECK_ERROR_GL4("glBufferData"); }
void BufferGL4<Tag>::SetData(std::size_t offsetInBytes, void const* source, std::size_t sizeInBytes) { POMDOG_ASSERT(source != nullptr); auto const oldBuffer = TypesafeHelperGL4::Get<BufferObject>(); ScopeGuard scope([&] { TypesafeHelperGL4::BindBuffer(oldBuffer); }); POMDOG_ASSERT(bufferObject); TypesafeHelperGL4::BindBuffer(*bufferObject); POMDOG_CHECK_ERROR_GL4("glBindBuffer"); #if defined(DEBUG) && !defined(NDEBUG) { GLint bufferSize = 0; glGetBufferParameteriv(BufferTraits<Tag>::Buffer, GL_BUFFER_SIZE, &bufferSize); POMDOG_ASSERT(sizeInBytes <= static_cast<std::size_t>(bufferSize)); } #endif POMDOG_ASSERT(sizeInBytes > 0); glBufferSubData(BufferTraits<Tag>::Buffer, offsetInBytes, sizeInBytes, source); POMDOG_CHECK_ERROR_GL4("glBufferSubData"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::DrawIndexedInstanced( std::size_t indexCount, std::size_t instanceCount) { ApplyPipelineState(); // Bind index buffer POMDOG_ASSERT(indexBuffer); auto indexBufferGL = dynamic_cast<IndexBufferGL4*>(indexBuffer->NativeIndexBuffer()); POMDOG_ASSERT(indexBufferGL != nullptr); indexBufferGL->BindBuffer(); // Draw POMDOG_ASSERT(indexCount > 0); POMDOG_ASSERT(indexCount <= indexBuffer->IndexCount()); POMDOG_ASSERT(instanceCount > 0); POMDOG_ASSERT(instanceCount < static_cast<decltype(instanceCount)>(std::numeric_limits<GLsizei>::max())); glDrawElementsInstanced( primitiveTopology.value, static_cast<GLsizei>(indexCount), ToIndexElementType(indexBuffer->ElementSize()), nullptr, static_cast<GLsizei>(instanceCount)); POMDOG_CHECK_ERROR_GL4("glDrawElementsInstanced"); }
SamplerStateGL4::~SamplerStateGL4() { if (samplerObject) { glDeleteSamplers(1, samplerObject->Data()); POMDOG_CHECK_ERROR_GL4("glDeleteSamplers"); } }
BufferGL4<Tag>::~BufferGL4() { if (bufferObject) { glDeleteBuffers(1, bufferObject->Data()); POMDOG_CHECK_ERROR_GL4("glDeleteBuffers"); } }
void OpenGLContextWin32::SwapBuffers() { glFlush(); POMDOG_CHECK_ERROR_GL4("glFlush"); POMDOG_ASSERT(hdc); ::SwapBuffers(hdc.get()); }
//----------------------------------------------------------------------- void GraphicsContextGL4::SetTexture(int textureUnit) { POMDOG_ASSERT(!textures.empty()); POMDOG_ASSERT(textureUnit >= 0); POMDOG_ASSERT(textureUnit < static_cast<int>(textures.size())); if (textures[textureUnit]) { glActiveTexture(ToTextureUnitIndexGL4(textureUnit)); POMDOG_CHECK_ERROR_GL4("glActiveTexture"); glBindTexture(*textures[textureUnit], 0); POMDOG_CHECK_ERROR_GL4("glBindTexture"); } textures[textureUnit] = Pomdog::NullOpt; }
void SamplerStateGL4::Apply(int index) { static_assert(GL_TEXTURE19 == (GL_TEXTURE0 + 19), ""); POMDOG_ASSERT(index >= 0); POMDOG_ASSERT(index <= 19); POMDOG_ASSERT(samplerObject); glBindSampler(index, samplerObject->value); POMDOG_CHECK_ERROR_GL4("glBindSampler"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::SetScissorRectangle(Rectangle const& rectangle) { POMDOG_ASSERT(rectangle.Width > 0); POMDOG_ASSERT(rectangle.Height > 0); GLint lowerLeftCornerY = rectangle.Y; if (renderTargets.empty()) { if (auto window = gameWindow.lock()) { lowerLeftCornerY = window->GetClientBounds().Height - (rectangle.Y + rectangle.Height); } } glScissor(rectangle.X, lowerLeftCornerY, rectangle.Width, rectangle.Height); POMDOG_CHECK_ERROR_GL4("glScissor"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::Draw(std::size_t vertexCount) { ApplyPipelineState(); // Draw POMDOG_ASSERT(!vertexBuffers.empty()); POMDOG_ASSERT(vertexBuffers.front().VertexBuffer); POMDOG_ASSERT(vertexCount > 0); POMDOG_ASSERT(vertexCount <= vertexBuffers.front().VertexBuffer->VertexCount()); glDrawArrays( primitiveTopology.value, 0, static_cast<GLsizei>(vertexCount)); POMDOG_CHECK_ERROR_GL4("glDrawArrays"); }
//----------------------------------------------------------------------- GraphicsContextGL4::~GraphicsContextGL4() { pipelineState.reset(); vertexBuffers.clear(); indexBuffer.reset(); textures.clear(); renderTargets.clear(); if (frameBuffer) { glDeleteFramebuffers(1, frameBuffer->Data()); POMDOG_CHECK_ERROR_GL4("glDeleteFramebuffers"); frameBuffer = Pomdog::NullOpt; } nativeContext.reset(); gameWindow.reset(); }
//----------------------------------------------------------------------- void GraphicsContextGL4::DrawInstanced( std::size_t vertexCount, std::size_t instanceCount) { ApplyPipelineState(); // Draw POMDOG_ASSERT(!vertexBuffers.empty()); POMDOG_ASSERT(vertexBuffers.front().VertexBuffer); POMDOG_ASSERT(vertexCount > 0); POMDOG_ASSERT(vertexCount <= vertexBuffers.front().VertexBuffer->VertexCount()); POMDOG_ASSERT(instanceCount > 0); POMDOG_ASSERT(instanceCount <= static_cast<decltype(instanceCount)>(std::numeric_limits<GLsizei>::max())); glDrawArraysInstanced( primitiveTopology.value, 0, static_cast<GLsizei>(vertexCount), static_cast<GLsizei>(instanceCount)); POMDOG_CHECK_ERROR_GL4("glDrawArraysInstanced"); }
//----------------------------------------------------------------------- GraphicsContextGL4::GraphicsContextGL4( std::shared_ptr<OpenGLContext> const& openGLContextIn, std::weak_ptr<GameWindow> windowIn) : nativeContext(openGLContextIn) , gameWindow(std::move(windowIn)) , needToApplyInputLayout(true) , needToApplyPipelineState(true) { auto version = reinterpret_cast<char const*>(glGetString(GL_VERSION)); Log::Stream(LogLevel::Internal) << "OpenGL Version: " << version; auto capabilities = GetCapabilities(); if (capabilities.SamplerSlotCount > 0) { textures.resize(capabilities.SamplerSlotCount); } glFrontFace(GL_CW); POMDOG_CHECK_ERROR_GL4("glFrontFace"); frameBuffer = CreateFrameBuffer(); primitiveTopology = ToPrimitiveTopology(PrimitiveTopology::TriangleList); }
SamplerStateGL4::SamplerStateGL4(const SamplerDescription& description) { samplerObject = ([] { SamplerObjectGL4 sampler; glGenSamplers(1, sampler.Data()); POMDOG_CHECK_ERROR_GL4("glGenSamplers"); return sampler; })(); glSamplerParameteri(samplerObject->value, GL_TEXTURE_WRAP_S, ToTextureAddressMode(description.AddressU)); glSamplerParameteri(samplerObject->value, GL_TEXTURE_WRAP_T, ToTextureAddressMode(description.AddressV)); glSamplerParameteri(samplerObject->value, GL_TEXTURE_WRAP_R, ToTextureAddressMode(description.AddressW)); POMDOG_CHECK_ERROR_GL4("glSamplerParameteri"); switch (description.Filter) { case TextureFilter::Linear: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case TextureFilter::Point: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case TextureFilter::LinearMipPoint: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case TextureFilter::PointMipLinear: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case TextureFilter::MinLinearMagPointMipLinear: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case TextureFilter::MinLinearMagPointMipPoint: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case TextureFilter::MinPointMagLinearMipLinear: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case TextureFilter::MinPointMagLinearMipPoint: glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case TextureFilter::Anisotropic: { // FIXME: Not implemented glSamplerParameteri(samplerObject->value, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameteri(samplerObject->value, GL_TEXTURE_MAG_FILTER, GL_LINEAR); POMDOG_CHECK_ERROR_GL4("glSamplerParameteri"); POMDOG_ASSERT(1 <= description.MaxAnisotropy && description.MaxAnisotropy <= 16); GLfloat deviceMaxAnisotropy = 1.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &deviceMaxAnisotropy); POMDOG_CHECK_ERROR_GL4("glGetFloatv"); deviceMaxAnisotropy = std::min(deviceMaxAnisotropy, static_cast<decltype(deviceMaxAnisotropy)>(description.MaxAnisotropy)); glSamplerParameterf(samplerObject->value, GL_TEXTURE_MAX_ANISOTROPY_EXT, deviceMaxAnisotropy); POMDOG_CHECK_ERROR_GL4("glSamplerParameterf"); break; } } { POMDOG_ASSERT(description.MinMipLevel <= description.MaxMipLevel); POMDOG_ASSERT(description.MaxMipLevel <= std::numeric_limits<GLfloat>::max()); glSamplerParameterf(samplerObject->value, GL_TEXTURE_MIN_LOD, description.MaxMipLevel); glSamplerParameterf(samplerObject->value, GL_TEXTURE_MAX_LOD, description.MaxMipLevel); glSamplerParameterf(samplerObject->value, GL_TEXTURE_LOD_BIAS, description.MipMapLevelOfDetailBias); POMDOG_CHECK_ERROR_GL4("glSamplerParameterf"); } }
//----------------------------------------------------------------------- void GraphicsContextGL4::Present() { nativeContext->SwapBuffers(); POMDOG_CHECK_ERROR_GL4("SwapBuffers"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::SetRenderTargets(std::vector<std::shared_ptr<RenderTarget2D>> const& renderTargetsIn) { POMDOG_ASSERT(!renderTargetsIn.empty()); POMDOG_ASSERT(frameBuffer); // Bind framebuffer glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->value); POMDOG_CHECK_ERROR_GL4("glBindFramebuffer"); // Unbind render targets { std::size_t index = 0; for (auto const& renderTarget: renderTargets) { POMDOG_ASSERT(renderTarget); renderTarget->UnbindFromFramebuffer(ToColorAttachment(index)); ++index; } } renderTargets.clear(); // Unbind depth stencil buffer glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); POMDOG_CHECK_ERROR_GL4("glFramebufferRenderbuffer"); std::vector<GLenum> attachments; attachments.reserve(renderTargetsIn.size()); renderTargets.reserve(renderTargetsIn.size()); // Attach textures std::uint32_t index = 0; for (auto const& renderTarget: renderTargetsIn) { POMDOG_ASSERT(renderTarget); auto const nativeRenderTarget = static_cast<RenderTarget2DGL4*>(renderTarget->NativeRenderTarget2D()); POMDOG_ASSERT(nativeRenderTarget != nullptr); POMDOG_ASSERT(nativeRenderTarget == dynamic_cast<RenderTarget2DGL4*>(renderTarget->NativeRenderTarget2D())); POMDOG_ASSERT(nativeRenderTarget); nativeRenderTarget->BindToFramebuffer(ToColorAttachment(index)); renderTargets.emplace_back(renderTarget, nativeRenderTarget); attachments.push_back(ToColorAttachment(index)); ++index; } // Attach depth stencil buffer { POMDOG_ASSERT(renderTargets.front()); auto const& renderTarget = renderTargets.front(); POMDOG_ASSERT(renderTarget); renderTarget->BindDepthStencilBuffer(); } // Check framebuffer status if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { // FUS RO DAH! POMDOG_THROW_EXCEPTION(std::runtime_error, "Failed to make complete framebuffer."); } POMDOG_ASSERT(!attachments.empty()); POMDOG_ASSERT(attachments.size() <= static_cast<std::size_t>(std::numeric_limits<GLsizei>::max())); glDrawBuffers(static_cast<GLsizei>(attachments.size()), attachments.data()); POMDOG_CHECK_ERROR_GL4("glDrawBuffers"); }
void BufferGL4<Tag>::BindBuffer() { POMDOG_ASSERT(bufferObject); TypesafeHelperGL4::BindBuffer(*bufferObject); POMDOG_CHECK_ERROR_GL4("glBindBuffer"); }
//----------------------------------------------------------------------- void GraphicsContextGL4::SetBlendFactor(Color const& blendFactor) { auto colorVector = blendFactor.ToVector4(); glBlendColor(colorVector.X, colorVector.Y, colorVector.Z, colorVector.W); POMDOG_CHECK_ERROR_GL4("glBlendColor"); }