void TextureOgl::setTexels( const Separate3dRegion ®ion, const void *data ) { storm_assert( _description.layout == Layout::Separate3d ); const MipLevelDimensions mipLevelDimensions = getMipLevelDimensions( region.mipLevel ); storm_assert( region.mipLevel < _description.mipLevels ); storm_assert( region.x + region.width <= mipLevelDimensions.width ); storm_assert( region.y + region.height <= mipLevelDimensions.height ); storm_assert( region.z + region.depth <= mipLevelDimensions.depth ); ScopeTextureBinding scopeTextureBinding( _target, _texture ); setTexelTransferAlignment( region.width ); ::glTexSubImage3D( _target, region.mipLevel, region.x, region.y, region.z, region.width, region.height, region.depth, _texelDescription.format, _texelDescription.type, data ); checkResult( "::glTexSubImage3D" ); resetTexelTransferAlignment(); }
void TextureOgl::getTexels( unsigned int mipLevel, unsigned int /*size*/, void *texels ) const { storm_assert( _description.layout != Layout::Separate2dMsaa ); storm_assert( _description.layout != Layout::Layered2dMsaa ); storm_assert( mipLevel < _description.mipLevels ); // TODO: check size ScopeTextureBinding scopeTextureBinding( _target, _texture ); if( _description.layout == Layout::CubeMap ) { if( _texelDescription.compressed ) throwNotImplemented(); const MipLevelDimensions mipLevelDimensions = getMipLevelDimensions( mipLevel ); setTexelTransferAlignment( mipLevelDimensions.width ); const GLenum targets[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; for( GLenum target : targets ) { ::glGetTexImage( target, mipLevel, _texelDescription.format, _texelDescription.type, texels ); checkResult( "::glGetTexImage" ); texels = static_cast<unsigned char*>( texels ) + _texelDescription.size * mipLevelDimensions.width * mipLevelDimensions.height; } resetTexelTransferAlignment(); return; } if( !_texelDescription.compressed ) { setTexelTransferAlignment( getMipLevelDimensions(mipLevel).width ); ::glGetTexImage( _target, mipLevel, _texelDescription.format, _texelDescription.type, texels ); checkResult( "::glGetTexImage" ); resetTexelTransferAlignment(); } else { ::glGetCompressedTexImage( _target, mipLevel, texels ); checkResult( "::glGetCompressedTexImage" ); } }
void TextureOgl::generateMipMap() { storm_assert( _description.layout != Layout::Separate2dMsaa ); storm_assert( _description.layout != Layout::Layered2dMsaa ); ScopeTextureBinding scopeTextureBinding( _target, _texture ); ::glGenerateMipmap( _target ); checkResult( "::glGenerateMipmap" ); }
GLenum TextureOgl::convertCubeMapFace( unsigned int face ) { storm_assert( face >= CubeMapFace::PositiveX ); storm_assert( face <= CubeMapFace::NegativeZ ); static const GLenum faces[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; return faces[face]; }
void TextureOgl::setTexels( const Layered2dRegion ®ion, const void *data ) { storm_assert( _description.layout == Layout::Layered2d ); const MipLevelDimensions mipLevelDimensions = getMipLevelDimensions( region.mipLevel ); storm_assert( region.mipLevel < _description.mipLevels ); storm_assert( region.layer < _description.layers ); storm_assert( region.x + region.width <= mipLevelDimensions.width ); storm_assert( region.y + region.height <= mipLevelDimensions.height ); ScopeTextureBinding scopeTextureBinding( _target, _texture ); if( _texelDescription.compressed ) { CompressedRegion compressedRegion; compressedRegion.target = _target; compressedRegion.mipLevel = region.mipLevel; compressedRegion.x = region.x; compressedRegion.y = region.y; compressedRegion.z = region.layer; compressedRegion.width = region.width; compressedRegion.height = region.height; compressedRegion.depth = 1; setTexelsCompressed( compressedRegion, data ); return; } setTexelTransferAlignment( region.width ); ::glTexSubImage3D( _target, region.mipLevel, region.x, region.y, region.layer, region.width, region.height, /* depth = */ 1, _texelDescription.format, _texelDescription.type, data ); checkResult( "::glTexSubImage3D" ); resetTexelTransferAlignment(); }
void RenderingSystemOgl::setOutputTechnique( OutputTechnique::Pointer technique ) { storm_assert( technique ); if( _outputTechnique == technique ) return; auto nativeTechnique = std::static_pointer_cast< OutputTechniqueOgl >( technique ); const auto &description = nativeTechnique->getNativeDescription(); const auto &depthTest = description.depthTest; const auto &stencilTest = description.stencilTest; setBooleanGlState( GL_DEPTH_TEST, depthTest.has_value() ); setBooleanGlState( GL_STENCIL_TEST, stencilTest.has_value() ); if( depthTest ) { ::glDepthFunc( depthTest->passCondition ); checkResult( "::glDepthFunc" ); } if( stencilTest ) { ::glStencilOpSeparate( GL_FRONT, stencilTest->algorithmForFrontFaces.operationOnStencilTestFail, stencilTest->algorithmForFrontFaces.operationOnDepthTestFail, stencilTest->algorithmForFrontFaces.operationOnDepthTestPass ); checkResult( "::glStencilOpSeparate" ); ::glStencilOpSeparate( GL_BACK, stencilTest->algorithmForBackFaces.operationOnStencilTestFail, stencilTest->algorithmForBackFaces.operationOnDepthTestFail, stencilTest->algorithmForBackFaces.operationOnDepthTestPass ); checkResult( "::glStencilOpSeparate" ); ::glStencilFuncSeparate( GL_FRONT, stencilTest->algorithmForFrontFaces.passCondition, stencilTest->referenceValue, stencilTest->mask ); checkResult( "::glStencilFuncSeparate" ); ::glStencilFuncSeparate( GL_BACK, stencilTest->algorithmForBackFaces.passCondition, stencilTest->referenceValue, stencilTest->mask ); checkResult( "::glStencilFuncSeparate" ); } ::glDepthMask( description.writeDepthValues ); checkResult( "::glDepthMask" ); _outputTechnique = technique; return; }
void RenderingSystemOgl::setBlendingTechnique( BlendingTechnique::Pointer technique ) { storm_assert( technique ); if( _blendingTechnique == technique ) return; auto nativeTechnique = std::static_pointer_cast< BlendingTechniqueOgl >( technique ); const BlendingTechniqueOgl::EquationOgl colorEquation = nativeTechnique->getColorEquation(); const BlendingTechniqueOgl::EquationOgl alphaEquation = nativeTechnique->getAlphaEquation(); const bool blendingDisabled = colorEquation.operation == GL_FUNC_ADD && alphaEquation.operation == GL_FUNC_ADD && colorEquation.sourceFactor == GL_ONE && alphaEquation.sourceFactor == GL_ONE && colorEquation.destinationFactor == GL_ZERO && alphaEquation.destinationFactor == GL_ZERO; const bool blendingEnabled = !blendingDisabled; setBooleanGlState( GL_BLEND, blendingEnabled ); if( blendingEnabled ) { if( colorEquation.operation == alphaEquation.operation ) { ::glBlendEquation( colorEquation.operation ); checkResult( "::glBlendEquation" ); } else { ::glBlendEquationSeparate( colorEquation.operation, alphaEquation.operation ); checkResult( "::glBlendEquationSeparate" ); } if( colorEquation.sourceFactor == alphaEquation.sourceFactor && colorEquation.destinationFactor == alphaEquation.destinationFactor ) { ::glBlendFunc( colorEquation.sourceFactor, colorEquation.destinationFactor ); checkResult( "::glBlendFunc" ); } else { ::glBlendFuncSeparate( colorEquation.sourceFactor, colorEquation.destinationFactor, alphaEquation.sourceFactor, alphaEquation.destinationFactor ); checkResult( "::glBlendFuncSeparate" ); } } _blendingTechnique = technique; }
void TextureOgl::setTexels( const Separate1dRegion ®ion, const void *data ) { storm_assert( _description.layout == Layout::Separate1d ); const MipLevelDimensions mipLevelDimensions = getMipLevelDimensions( region.mipLevel ); storm_assert( region.mipLevel < _description.mipLevels ); storm_assert( region.x + region.width <= mipLevelDimensions.width ); ScopeTextureBinding scopeTextureBinding( _target, _texture ); ::glTexSubImage1D( _target, region.mipLevel, region.x, region.width, _texelDescription.format, _texelDescription.type, data ); checkResult( "::glTexSubImage1D" ); }
void RenderingSystemOgl::renderMesh( Mesh::Pointer mesh, unsigned count ) { storm_assert( mesh ); auto nativeMesh = std::static_pointer_cast< MeshOgl >( mesh ); bindVertexArray( nativeMesh->getHandle() ); const auto &indexBufferDescription = mesh->getDescription().indexBuffer->getDescription(); storm_assert( indexBufferDescription.elementSize == 2 || indexBufferDescription.elementSize == 4 ); const GLuint primitiveRestartIndex = (indexBufferDescription.elementSize == 2) ? 0xffff : 0xffffffff; if( _primitiveRestartIndex != primitiveRestartIndex ) { _primitiveRestartIndex = primitiveRestartIndex; ::glPrimitiveRestartIndex( _primitiveRestartIndex ); } const GLenum primitiveTopology = nativeMesh->getPrimitiveTopology(); const GLsizei indexCount = static_cast<GLsizei>( indexBufferDescription.size / indexBufferDescription.elementSize ); const GLenum indexFormat = (indexBufferDescription.elementSize == 2) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; const GLvoid *indexOffset = nullptr; if( count == 1 ) { ::glDrawElements( primitiveTopology, indexCount, indexFormat, indexOffset ); checkResult( "::glDrawElements" ); } else { ::glDrawElementsInstanced( primitiveTopology, indexCount, indexFormat, indexOffset, count ); checkResult( "::glDrawElementsInstanced" ); } }
void TextureOgl::validateDescription() const { storm_assert( _description.width ); storm_assert( _description.height ); storm_assert( _description.depth ); storm_assert( _description.mipLevels ); storm_assert( _description.layers ); storm_assert( _description.texelSamples ); if( _texelDescription.compressed ) { storm_assert( _description.layout == Layout::Separate2d || _description.layout == Layout::Layered2d || _description.layout == Layout::CubeMap ); } }
void RenderingSystemOgl::setShader( Shader::Pointer shader ) { storm_assert( shader ); const Shader::Type shaderType = shader->getType(); if( getShader(shaderType) == shader ) return; RenderingSystemCommon::setShader( shader ); const auto nativeShader = std::static_pointer_cast< ShaderOgl >( shader ); const GLbitfield stage = selectShaderStage( shaderType ); ::glUseProgramStages( *_programPipeline, stage, nativeShader->getHandle() ); checkResult( "::glUseProgramStages" ); nativeShader->install(); nativeShader->handleRootBufferUpdate( _rootBufferData, /* offset */ 0, _rootBufferData.size() ); }
void RenderingSystemOgl::setRootBufferData( size_t offset, size_t size, const void *data ) { storm_assert( _rootBufferData.size() >= offset + size ); std::copy( static_cast<const uint8_t*>(data), static_cast<const uint8_t*>(data) + size, _rootBufferData.begin() + offset ); Shader *shaders[] = { _geometryShader.get(), _vertexShader.get(), _pixelShader.get() }; for( Shader *shader : shaders ) { if( shader ) { static_cast<ShaderOgl*>( shader )->handleRootBufferUpdate( _rootBufferData, offset, size ); } } }
void RenderingSystemOgl::setRasterizationTechnique( RasterizationTechnique::Pointer technique ) { storm_assert( technique ); if( _rasterizationTechnique == technique ) return; auto nativeTechnique = std::static_pointer_cast< RasterizationTechniqueOgl >( technique ); GLenum cullMode = nativeTechnique->getCullMode(); GLenum fillMode = nativeTechnique->getFillMode(); const bool cullingEnabled = (cullMode != GL_NONE); setBooleanGlState( GL_CULL_FACE, cullingEnabled ); if( cullingEnabled ) { ::glFrontFace( GL_CW ); checkResult( "::glFrontFace" ); ::glCullFace( cullMode ); checkResult( "::glCullFace" ); } ::glPolygonMode( GL_FRONT_AND_BACK, fillMode ); checkResult( "::glPolygonMode" ); const auto &description = nativeTechnique->getDescription(); setBooleanGlState( GL_SCISSOR_TEST, description.rectangleClippingEnabled ); setBooleanGlState( GL_DEPTH_CLAMP, !description.depthClippingEnabled ); ::glPolygonOffset( static_cast<GLfloat>(description.slopeScaleDepthBias), static_cast<GLfloat>(description.depthBias) ); checkResult( "::glPolygonOffset" ); _rasterizationTechnique = technique; return; }
void OrthographicCamera::setFrameDimensions( Vector2d frameDimensions ) { storm_assert( frameDimensions.x > 0 && frameDimensions.y > 0 ); _frameDimensions = frameDimensions; }
void PerspectiveCamera::setFrameAspectRatio( float frameAspectRatio ) { storm_assert( frameAspectRatio > 0 ); _frameAspectRatio = frameAspectRatio; }
void PerspectiveCamera::setFieldOfView( float fieldOfView ) { storm_assert( fieldOfView > 0 ); _fieldOfView = fieldOfView; }
void TextureOgl::setTexelsCompressed( const CompressedRegion ®ion, const void *texels ) { struct BlockDescription { GLsizei width; GLsizei height; GLsizei size; }; static const std::map<Format, BlockDescription> formatBlockDescriptions = { {Format::RgbDxt1, {4, 4, 8}}, {Format::RgbaDxt1, {4, 4, 8}}, {Format::RgbaDxt3, {4, 4, 16}}, {Format::RgbaDxt5, {4, 4, 16}}, {Format::SrgbDxt1, {4, 4, 8}}, {Format::SrgbaDxt1, {4, 4, 8}}, {Format::SrgbaDxt3, {4, 4, 16}}, {Format::SrgbaDxt5, {4, 4, 16}} }; const BlockDescription &block = formatBlockDescriptions.at( _description.format ); const MipLevelDimensions mipLevelDimensions = getMipLevelDimensions( region.mipLevel ); storm_assert( (region.x % block.width) == 0 ); storm_assert( (region.y % block.height) == 0 ); storm_assert( (region.width % block.width) == 0 || region.x + region.width == mipLevelDimensions.width ); storm_assert( (region.height % block.height) == 0 || region.y + region.height == mipLevelDimensions.height ); const GLsizei dataSize = static_cast<GLsizei>( ceil(1.0f * region.width / block.width) ) * static_cast<GLsizei>( ceil(1.0f * region.height / block.height) ) * static_cast<GLsizei>( region.depth ) * block.size; if( region.target != GL_TEXTURE_2D_ARRAY ) { ::glCompressedTexSubImage2D( region.target, region.mipLevel, region.x, region.y, region.width, region.height, _texelDescription.internalFormat, dataSize, texels ); checkResult( "::glCompressedTexSubImage2D" ); } else { ::glCompressedTexSubImage3D( region.target, region.mipLevel, region.x, region.y, region.z, region.width, region.height, region.depth, _texelDescription.internalFormat, dataSize, texels ); checkResult( "::glCompressedTexSubImage3D" ); } }
TextureOgl::TextureOgl( const Description &description ) : _description( description ), _texelDescription( selectTexelDescription(description.format) ), _target( selectTarget(description.layout) ) { validateDescription(); ScopeTextureBinding scopeTextureBinding( _target, _texture ); const unsigned int levelsMaximum = getMipLevelsMaximum( _description ); const unsigned int levels = _description.mipLevels == CompleteMipMap ? levelsMaximum : _description.mipLevels; storm_assert( levels <= levelsMaximum ); if( _description.mipLevels == CompleteMipMap ) _description.mipLevels = levels; switch( _description.layout ) { case Layout::Separate1d: ::glTexStorage1D( _target, levels, _texelDescription.internalFormat, description.width ); checkResult( "::glTexStorage1D" ); break; case Layout::Separate2d: case Layout::CubeMap: ::glTexStorage2D( _target, levels, _texelDescription.internalFormat, description.width, description.height ); checkResult( "::glTexStorage2D" ); break; case Layout::Separate3d: ::glTexStorage3D( _target, levels, _texelDescription.internalFormat, description.width, description.height, description.depth ); checkResult( "::glTexStorage3D" ); break; case Layout::Layered1d: ::glTexStorage2D( _target, levels, _texelDescription.internalFormat, description.width, description.layers ); checkResult( "::glTexStorage2D" ); break; case Layout::Layered2d: ::glTexStorage3D( _target, levels, _texelDescription.internalFormat, description.width, description.height, description.layers ); checkResult( "::glTexStorage3D" ); break; case Layout::Separate2dMsaa: ::glTexStorage2DMultisample( _target, description.texelSamples, _texelDescription.internalFormat, description.width, description.height, GL_TRUE ); checkResult( "::glTexStorage2DMultisample" ); break; case Layout::Layered2dMsaa: ::glTexStorage3DMultisample( _target, description.texelSamples, _texelDescription.internalFormat, description.width, description.height, description.layers, GL_TRUE ); checkResult( "::glTexStorage3DMultisample" ); break; default: throwNotImplemented(); } }
void Camera::setDepthRange( DepthRange depthRange ) { storm_assert( depthRange.maximum - depthRange.minimum > 0 && depthRange.minimum >= 0 ); _depthRange = depthRange; }