lambdacube-engine-0.1.1: Graphics/LambdaCube/RenderSystem/GL/GLUtils.hs
module Graphics.LambdaCube.RenderSystem.GL.GLUtils where
import qualified Data.Set as Set
import Data.Bits
import Unsafe.Coerce
import Graphics.Rendering.OpenGL (($=))
import qualified Graphics.Rendering.OpenGL as GL
import Graphics.LambdaCube.Types
import Graphics.LambdaCube.Math
import Graphics.LambdaCube.Common
import Graphics.LambdaCube.PixelFormat
import Graphics.LambdaCube.Texture
import Graphics.LambdaCube.BlendMode
import Graphics.LambdaCube.HardwareBuffer
import Graphics.LambdaCube.HardwareVertexBuffer
import Graphics.LambdaCube.RenderSystemCapabilities
import Graphics.LambdaCube.TextureUnitState
toGLMatrix :: Matrix4 -> IO (GL.GLmatrix GL.GLfloat)
toGLMatrix m = GL.newMatrix GL.ColumnMajor $ unsafeCoerce $ toListsMatrix4 m
getGLUsage :: Usage -> GL.BufferUsage
getGLUsage usage = case usage of
{ HBU_STATIC -> GL.StaticDraw
; HBU_STATIC_WRITE_ONLY -> GL.StaticDraw
; HBU_DYNAMIC -> GL.DynamicDraw
; HBU_DYNAMIC_WRITE_ONLY -> GL.DynamicDraw
; HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE -> GL.StreamDraw
; _ -> GL.DynamicDraw
}
getGLType :: VertexElementType -> GL.DataType
getGLType t = case t of
{ VET_FLOAT1 -> GL.Float
; VET_FLOAT2 -> GL.Float
; VET_FLOAT3 -> GL.Float
; VET_FLOAT4 -> GL.Float
; VET_SHORT1 -> GL.Short
; VET_SHORT2 -> GL.Short
; VET_SHORT3 -> GL.Short
; VET_SHORT4 -> GL.Short
; VET_COLOUR_ABGR -> GL.UnsignedByte
; VET_COLOUR_ARGB -> GL.UnsignedByte
; VET_UBYTE4 -> GL.UnsignedByte
}
getGLTextureTarget :: TextureType -> GL.TextureTarget
getGLTextureTarget textureType = case textureType of
{ TEX_TYPE_1D -> GL.Texture1D
; TEX_TYPE_2D -> GL.Texture2D
; TEX_TYPE_3D -> GL.Texture3D
; TEX_TYPE_CUBE_MAP -> GL.TextureCubeMap
}
optionalPO2 :: RenderSystemCapabilities -> Int -> Int
optionalPO2 rcaps value = case Set.member RSC_NON_POWER_OF_2_TEXTURES (rscCapabilities rcaps) of
{ True -> value
; False -> 2 ^ ( 1 + log2 (value-1) )
}
where
log2 n = case n of
0 -> -1
_ -> 1 + log2 (shiftR n 1)
getMaxMipmaps :: Int -> Int -> Int -> PixelFormat -> Int
getMaxMipmaps width height depth format = maximum [f width, f height, f depth]
where
f x = floor $ logBase 2 $ fromIntegral x
{-
size_t GLPixelUtil::getMaxMipmaps(size_t width, size_t height, size_t depth, PixelFormat format)
{
size_t count = 0;
do {
if(width>1) width = width/2;
if(height>1) height = height/2;
if(depth>1) depth = depth/2;
count ++;
} while(!(width == 1 && height == 1 && depth == 1));
return count;
}
-}
-- TODO
getNativeFormat :: TextureType -> PixelFormat -> Bool -> PixelFormat
getNativeFormat ttype format isTarget = PF_R8G8B8
{-
PixelFormat GLTextureManager::getNativeFormat(TextureType ttype, PixelFormat format, int usage)
{
// Adjust requested parameters to capabilities
const RenderSystemCapabilities *caps = Root::getSingleton().getRenderSystem()->getCapabilities();
// Check compressed texture support
// if a compressed format not supported, revert to PF_A8R8G8B8
if(PixelUtil::isCompressed(format) &&
!caps->hasCapability( RSC_TEXTURE_COMPRESSION_DXT ))
{
return PF_A8R8G8B8;
}
// if floating point textures not supported, revert to PF_A8R8G8B8
if(PixelUtil::isFloatingPoint(format) &&
!caps->hasCapability( RSC_TEXTURE_FLOAT ))
{
return PF_A8R8G8B8;
}
// Check if this is a valid rendertarget format
if( usage & TU_RENDERTARGET )
{
/// Get closest supported alternative
/// If mFormat is supported it's returned
return GLRTTManager::getSingleton().getSupportedAlternative(format);
}
// Supported
return format;
}
PixelFormat GLRTTManager::getSupportedAlternative(PixelFormat format)
{
if(checkFormat(format))
return format;
/// Find first alternative
PixelComponentType pct = PixelUtil::getComponentType(format);
switch(pct)
{
case PCT_BYTE: format = PF_A8R8G8B8; break;
case PCT_SHORT: format = PF_SHORT_RGBA; break;
case PCT_FLOAT16: format = PF_FLOAT16_RGBA; break;
case PCT_FLOAT32: format = PF_FLOAT32_RGBA; break;
case PCT_COUNT: break;
}
if(checkFormat(format))
return format;
/// If none at all, return to default
return PF_A8R8G8B8;
}
-}
getGLInternalFormat :: PixelFormat -> Bool -> GL.PixelInternalFormat
getGLInternalFormat mFormat hwGamma = case mFormat of
{ PF_L8 -> GL.Luminance8
; PF_L16 -> GL.Luminance16
; PF_A8 -> GL.Alpha8
; PF_A4L4 -> GL.Luminance4Alpha4
; PF_BYTE_LA -> GL.Luminance8Alpha8
; PF_R3G3B2 -> GL.R3G3B2
; PF_A1R5G5B5 -> GL.RGB5A1
; PF_R5G6B5 -> GL.RGB5
; PF_B5G6R5 -> GL.RGB5
; PF_A4R4G4B4 -> GL.RGBA4
; PF_R8G8B8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_B8G8R8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_X8B8G8R8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_X8R8G8B8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_A8R8G8B8 -> if hwGamma then GL.SRGB8Alpha8 else GL.RGBA8
; PF_B8G8R8A8 -> if hwGamma then GL.SRGB8Alpha8 else GL.RGBA8
; PF_A2R10G10B10 -> GL.RGB10A2
; PF_A2B10G10R10 -> GL.RGB10A2
--FIXME ; PF_FLOAT16_R -> GL_LUMINANCE16F_ARB
--FIXME ; PF_FLOAT16_RGB -> GL_RGB16F_ARB
--FIXME ; PF_FLOAT16_GR -> GL_LUMINANCE_ALPHA16F_ARB
--FIXME ; PF_FLOAT16_RGBA -> GL_RGBA16F_ARB
--FIXME ; PF_FLOAT32_R -> GL_LUMINANCE32F_ARB
--FIXME ; PF_FLOAT32_GR -> GL_LUMINANCE_ALPHA32F_ARB
--FIXME ; PF_FLOAT32_RGB -> GL_RGB32F_ARB
--FIXME ; PF_FLOAT32_RGBA -> GL_RGBA32F_ARB
; PF_SHORT_RGBA -> GL.RGBA16
; PF_SHORT_RGB -> GL.RGB16
; PF_SHORT_GR -> GL.Luminance16Alpha16
-- case PF_DXT1:
-- if (hwGamma)
-- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
-- else
-- return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-- case PF_DXT3:
-- if (hwGamma)
-- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
-- else
-- return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-- case PF_DXT5:
-- if (hwGamma)
-- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
-- else
-- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
; _ -> error "Unsupported pixel format"
}
{-
GLenum GLPixelUtil::getGLInternalFormat(PixelFormat mFormat, bool hwGamma)
{
switch(mFormat) {
default:
return GL_NONE;
}
}
GLenum GLPixelUtil::getClosestGLInternalFormat(PixelFormat mFormat, bool hwGamma)
{
GLenum format = getGLInternalFormat(mFormat, hwGamma);
if(format==GL_NONE)
{
if (hwGamma)
return GL_SRGB8;
else
return GL_RGBA8;
}
else
return format;
}
-}
getClosestGLInternalFormat :: PixelFormat -> Bool -> GL.PixelInternalFormat
getClosestGLInternalFormat mFormat hwGamma = case mFormat of
{ PF_L8 -> GL.Luminance8
; PF_L16 -> GL.Luminance16
; PF_A8 -> GL.Alpha8
; PF_A4L4 -> GL.Luminance4Alpha4
; PF_BYTE_LA -> GL.Luminance8Alpha8
; PF_R3G3B2 -> GL.R3G3B2
; PF_A1R5G5B5 -> GL.RGB5A1
; PF_R5G6B5 -> GL.RGB5
; PF_B5G6R5 -> GL.RGB5
; PF_A4R4G4B4 -> GL.RGBA4
; PF_R8G8B8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_B8G8R8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_X8B8G8R8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_X8R8G8B8 -> if hwGamma then GL.SRGB8 else GL.RGB8
; PF_A8R8G8B8 -> if hwGamma then GL.SRGB8Alpha8 else GL.RGBA8
; PF_B8G8R8A8 -> if hwGamma then GL.SRGB8Alpha8 else GL.RGBA8
; PF_A2R10G10B10 -> GL.RGB10A2
; PF_A2B10G10R10 -> GL.RGB10A2
--FIXME ; PF_FLOAT16_R -> GL_LUMINANCE16F_ARB
--FIXME ; PF_FLOAT16_RGB -> GL_RGB16F_ARB
--FIXME ; PF_FLOAT16_GR -> GL_LUMINANCE_ALPHA16F_ARB
--FIXME ; PF_FLOAT16_RGBA -> GL_RGBA16F_ARB
--FIXME ; PF_FLOAT32_R -> GL_LUMINANCE32F_ARB
--FIXME ; PF_FLOAT32_GR -> GL_LUMINANCE_ALPHA32F_ARB
--FIXME ; PF_FLOAT32_RGB -> GL_RGB32F_ARB
--FIXME ; PF_FLOAT32_RGBA -> GL_RGBA32F_ARB
; PF_SHORT_RGBA -> GL.RGBA16
; PF_SHORT_RGB -> GL.RGB16
; PF_SHORT_GR -> GL.Luminance16Alpha16
-- FIXME
-- case PF_DXT1:
-- if (hwGamma)
-- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
-- else
-- return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-- case PF_DXT3:
-- if (hwGamma)
-- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
-- else
-- return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-- case PF_DXT5:
-- if (hwGamma)
-- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
-- else
-- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
; _ -> if hwGamma then GL.SRGB8 else GL.RGBA8
}
getBlendMode :: SceneBlendFactor -> GL.BlendingFactor
getBlendMode blend = case blend of
{ SBF_ONE -> GL.One
; SBF_ZERO -> GL.Zero
; SBF_DEST_COLOUR -> GL.DstColor
; SBF_SOURCE_COLOUR -> GL.SrcColor
; SBF_ONE_MINUS_DEST_COLOUR -> GL.OneMinusDstColor
; SBF_ONE_MINUS_SOURCE_COLOUR -> GL.OneMinusSrcColor
; SBF_DEST_ALPHA -> GL.DstAlpha
; SBF_SOURCE_ALPHA -> GL.SrcAlpha
; SBF_ONE_MINUS_DEST_ALPHA -> GL.OneMinusDstAlpha
; SBF_ONE_MINUS_SOURCE_ALPHA -> GL.OneMinusSrcAlpha
}
getBlendEquation op = case op of
{ SBO_ADD -> GL.FuncAdd
; SBO_SUBTRACT -> GL.FuncSubtract
; SBO_REVERSE_SUBTRACT -> GL.FuncReverseSubtract
; SBO_MIN -> GL.Min
; SBO_MAX -> GL.Max
}
getTextureAddressingMode tam = case tam of
{ TAM_WRAP -> (GL.Repeated, GL.Repeat)
; TAM_MIRROR -> (GL.Mirrored, GL.Repeat)
; TAM_CLAMP -> (GL.Repeated, GL.ClampToEdge)
; TAM_BORDER -> (GL.Repeated, GL.ClampToBorder)
}
getLayerBlendSource src = case src of
{ LBS_CURRENT -> GL.Previous
; LBS_TEXTURE -> GL.CurrentUnit
; LBS_MANUAL -> GL.Constant
; LBS_DIFFUSE -> GL.PrimaryColor
; LBS_SPECULAR -> GL.PrimaryColor
}
getTextureCombineFunction hasDot3 op = case op of
{ LBX_SOURCE1 -> GL.Replace'
; LBX_SOURCE2 -> GL.Replace'
; LBX_MODULATE -> GL.Modulate'
; LBX_MODULATE_X2 -> GL.Modulate'
; LBX_MODULATE_X4 -> GL.Modulate'
; LBX_ADD -> GL.AddUnsigned'
; LBX_ADD_SIGNED -> GL.AddSigned
; LBX_ADD_SMOOTH -> GL.Interpolate
; LBX_SUBTRACT -> GL.Subtract
; LBX_BLEND_DIFFUSE_COLOUR -> GL.Interpolate
; LBX_BLEND_DIFFUSE_ALPHA -> GL.Interpolate
; LBX_BLEND_TEXTURE_ALPHA -> GL.Interpolate
; LBX_BLEND_CURRENT_ALPHA -> GL.Interpolate
; LBX_BLEND_MANUAL -> GL.Interpolate
; LBX_DOTPRODUCT -> if hasDot3 then GL.Dot3RGB else GL.Modulate'
}
convertCompareFunction f = case f of
{ CMPF_ALWAYS_FAIL -> GL.Never
; CMPF_ALWAYS_PASS -> GL.Always
; CMPF_LESS -> GL.Less
; CMPF_LESS_EQUAL -> GL.Lequal
; CMPF_EQUAL -> GL.Equal
; CMPF_NOT_EQUAL -> GL.Notequal
; CMPF_GREATER_EQUAL -> GL.Gequal
; CMPF_GREATER -> GL.Greater
}