Files
CavesOfSwift/Sources/JolkEngine/Renderer/OpenGLState.swift
2024-05-09 20:52:01 +10:00

819 lines
20 KiB
Swift

import OpenGL
struct OpenGLState
{
struct Capability: OptionSet
{
let rawValue: UInt32
static let alphaTest = Self(rawValue: 1 << 0)
static let blend = Self(rawValue: 1 << 1)
static let colourMaterial = Self(rawValue: 1 << 2)
static let colourSum = Self(rawValue: 1 << 3)
static let cullFace = Self(rawValue: 1 << 4)
static let depthTest = Self(rawValue: 1 << 5)
static let dither = Self(rawValue: 1 << 6)
static let fog = Self(rawValue: 1 << 7)
static let light0 = Self(rawValue: 1 << 8)
static let light1 = Self(rawValue: 1 << 9)
static let light2 = Self(rawValue: 1 << 10)
static let light3 = Self(rawValue: 1 << 11)
static let light4 = Self(rawValue: 1 << 12)
static let light5 = Self(rawValue: 1 << 13)
static let light6 = Self(rawValue: 1 << 14)
static let light7 = Self(rawValue: 1 << 15)
static let lighting = Self(rawValue: 1 << 16)
//static let lineSmooth = Self(rawValue: 1 << 17)
static let lineStipple = Self(rawValue: 1 << 18)
static let multiSample = Self(rawValue: 1 << 19)
//static let pointSmooth = Self(rawValue: 1 << 20)
static let scissorTest = Self(rawValue: 1 << 21)
static let stencilTest = Self(rawValue: 1 << 22)
//static let texture1D = Self(rawValue: 1 << 23)
static let texture2D = Self(rawValue: 1 << 24)
static let clipPlane0 = Self(rawValue: 1 << 25)
static let clipPlane1 = Self(rawValue: 1 << 26)
static let clipPlane2 = Self(rawValue: 1 << 27)
static let clipPlane3 = Self(rawValue: 1 << 28)
static let clipPlane4 = Self(rawValue: 1 << 29)
static let clipPlane5 = Self(rawValue: 1 << 30)
//static let colourLogicOp = Self(rawValue: 1 << 31)
static let sampleCoverage = Self(rawValue: 1 << 17)
static let alphaToOne = Self(rawValue: 1 << 20)
static let rescaleNormal = Self(rawValue: 1 << 23)
static let frameBufferSrgb = Self(rawValue: 1 << 31)
static let all: [Self] = [ .alphaTest, .blend, .colourMaterial, .colourSum, .cullFace, .depthTest, .dither,
.fog, .light0, .light1, .light2, .light3, .light4, .light5, .light6, .light7, .lighting, /*.lineSmooth,*/
.lineStipple, /*.pointSmooth,*/ .multiSample, .scissorTest, .stencilTest, /*.texture1D,*/ .texture2D,
.clipPlane0, .clipPlane1, .clipPlane2, .clipPlane3, .clipPlane4, .clipPlane5, /*.colourLogicOp,*/
.sampleCoverage, .alphaToOne, .rescaleNormal, .frameBufferSrgb ]
static let initial: Self = [ .dither, .multiSample ]
var glCap: GLenum
{
let capEnum = switch self
{
case .alphaTest: GL_ALPHA_TEST
case .blend: GL_BLEND
case .colourMaterial: GL_COLOR_MATERIAL
case .colourSum: GL_COLOR_SUM
case .cullFace: GL_CULL_FACE
case .depthTest: GL_DEPTH_TEST
case .dither: GL_DITHER
case .fog: GL_FOG
case .light0: GL_LIGHT0
case .light1: GL_LIGHT1
case .light2: GL_LIGHT2
case .light3: GL_LIGHT3
case .light4: GL_LIGHT4
case .light5: GL_LIGHT5
case .light6: GL_LIGHT6
case .light7: GL_LIGHT7
case .lighting: GL_LIGHTING
//case .lineSmooth: GL_LINE_SMOOTH
case .lineStipple: GL_LINE_STIPPLE
case .multiSample: GL_MULTISAMPLE
//case .pointSmooth: GL_POINT_SMOOTH
case .scissorTest: GL_SCISSOR_TEST
case .stencilTest: GL_STENCIL_TEST
//case .texture1D: GL_TEXTURE_1D
case .texture2D: GL_TEXTURE_2D
case .clipPlane0: GL_CLIP_PLANE0
case .clipPlane1: GL_CLIP_PLANE1
case .clipPlane2: GL_CLIP_PLANE2
case .clipPlane3: GL_CLIP_PLANE3
case .clipPlane4: GL_CLIP_PLANE4
case .clipPlane5: GL_CLIP_PLANE5
//case .colourLogicOp: GL_COLOR_LOGIC_OP
case .sampleCoverage: GL_SAMPLE_COVERAGE
case .alphaToOne: GL_SAMPLE_ALPHA_TO_ONE
case .rescaleNormal: GL_RESCALE_NORMAL
case .frameBufferSrgb: GL_FRAMEBUFFER_SRGB
default: fatalError()
}
return GLenum(capEnum)
}
}
private var _capabilities: Capability = .initial
private mutating func toggle(_ cap: Capability, _ en: Bool)
{
if en
{
if !_capabilities.contains(cap)
{
glEnable(cap.glCap)
_capabilities.insert(cap)
}
}
else
{
if _capabilities.contains(cap)
{
glDisable(cap.glCap)
_capabilities.remove(cap)
}
}
}
mutating func enable(_ caps: Capability)
{
if Capability.all.contains(caps)
{
toggle(caps, true)
}
else
{
for i in Capability.all
{
if i.intersection(caps) == i { toggle(i, true) }
}
}
}
mutating func disable(_ caps: Capability)
{
if Capability.all.contains(caps)
{
toggle(caps, false)
}
else
{
for i in Capability.all
{
if i.intersection(caps) == i { toggle(i, false) }
}
}
}
struct ClientState: OptionSet
{
let rawValue: UInt32
static let colour = Self(rawValue: 1 << 0)
static let edgeFlag = Self(rawValue: 1 << 1)
static let fogCoord = Self(rawValue: 1 << 2)
static let index = Self(rawValue: 1 << 3)
static let normal = Self(rawValue: 1 << 4)
static let secondaryColour = Self(rawValue: 1 << 5)
static let textureCoord = Self(rawValue: 1 << 6)
static let vertex = Self(rawValue: 1 << 7)
static let all: [Self] = [ .colour, .edgeFlag, .fogCoord, .index, .normal, .secondaryColour, .textureCoord, .vertex ]
static let initial: Self = []
var glCap: GLenum
{
let capEnum = switch self
{
case .colour: GL_COLOR_ARRAY
case .edgeFlag: GL_EDGE_FLAG_ARRAY
case .fogCoord: GL_FOG_COORD_ARRAY
case .index: GL_INDEX_ARRAY
case .normal: GL_NORMAL_ARRAY
case .secondaryColour: GL_SECONDARY_COLOR_ARRAY
case .textureCoord: GL_TEXTURE_COORD_ARRAY
case .vertex: GL_VERTEX_ARRAY
default: fatalError()
}
return GLenum(capEnum)
}
}
private var _clientState: ClientState = .initial
private mutating func toggleClientState(_ cap: ClientState, _ en: Bool)
{
if en
{
if !_clientState.contains(cap)
{
glEnableClientState(cap.glCap)
_clientState.insert(cap)
}
}
else
{
if _clientState.contains(cap)
{
glDisableClientState(cap.glCap)
_clientState.remove(cap)
}
}
}
mutating func enableClient(_ caps: ClientState)
{
if ClientState.all.contains(caps)
{
toggleClientState(caps, true)
}
else
{
for i in ClientState.all
{
if i.intersection(caps) == i { toggleClientState(i, true) }
}
}
}
mutating func disableClient(_ caps: ClientState)
{
if ClientState.all.contains(caps)
{
toggleClientState(caps, false)
}
else
{
for i in ClientState.all
{
if i.intersection(caps) == i { toggleClientState(i, false) }
}
}
}
private var _activeTexture2D = 0
private mutating func setActiveTexture2D(_ active: Int)
{
if active != _activeTexture2D
{
let slots = [ GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3, GL_TEXTURE4, GL_TEXTURE5, GL_TEXTURE6,
GL_TEXTURE7, GL_TEXTURE8, GL_TEXTURE9, GL_TEXTURE10, GL_TEXTURE11, GL_TEXTURE12, GL_TEXTURE13,
GL_TEXTURE14, GL_TEXTURE15, GL_TEXTURE16, GL_TEXTURE17, GL_TEXTURE18, GL_TEXTURE19, GL_TEXTURE20,
GL_TEXTURE21, GL_TEXTURE22, GL_TEXTURE23, GL_TEXTURE24, GL_TEXTURE25, GL_TEXTURE26, GL_TEXTURE27,
GL_TEXTURE28, GL_TEXTURE29, GL_TEXTURE30, GL_TEXTURE31 ]
glActiveTexture(GLenum(slots[active]))
_activeTexture2D = active
}
}
static let defaultTexture: UInt32 = 0
private var _texture2D: GLuint = GLuint(defaultTexture)
mutating func bindTexture2D(active: Int, texture: UInt32)
{
if GLuint(texture) != _texture2D
{
setActiveTexture2D(active)
glBindTexture(GLenum(GL_TEXTURE_2D), GLuint(texture))
_texture2D = GLuint(texture)
}
}
enum TexureParameter { case magFilter, minFilter, wrapS, wrapT }
mutating func texture2DParameter(active: Int, param: TexureParameter, int value: Int32)
{
setActiveTexture2D(active)
let pname = switch param
{
case .magFilter: GL_TEXTURE_MAG_FILTER
case .minFilter: GL_TEXTURE_MIN_FILTER
case .wrapS: GL_TEXTURE_WRAP_S
case .wrapT: GL_TEXTURE_WRAP_T
}
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(pname), GLint(value))
}
private var _clearDepth: GLclampd = 1
var clearDepth: Double
{
get { Double(_clearDepth) }
set(newDepth)
{
if GLclampd(newDepth) != _clearDepth
{
glClearDepth(newDepth)
_clearDepth = GLclampd(newDepth)
}
}
}
private var _clearColour: Colour = .zero
mutating func clearColour(_ newColour: Colour)
{
if newColour != _clearColour
{
glClearColor(newColour.r, newColour.g, newColour.b, newColour.a)
_clearColour = newColour
}
}
enum CullFace { case front, back, frontAndBack }
private var _cullFace: CullFace = .back
var cullFace: CullFace
{
get { _cullFace }
set(newMode)
{
if newMode != _cullFace
{
let modeEnum = switch newMode
{
case .front: GL_FRONT
case .back: GL_BACK
case .frontAndBack: GL_FRONT_AND_BACK
}
glCullFace(GLenum(modeEnum))
_cullFace = newMode
}
}
}
enum DepthFunc { case never, less, equal, lessOrEqual, greater, notEqual, greaterOrEqual, always }
private var _depthFunc: DepthFunc = .less
var depthFunc: DepthFunc
{
get { _depthFunc }
set(newFunc)
{
if newFunc != _depthFunc
{
let funcEnum = switch newFunc
{
case .never: GL_NEVER
case .less: GL_LESS
case .equal: GL_EQUAL
case .lessOrEqual: GL_LEQUAL
case .greater: GL_GREATER
case .notEqual: GL_NOTEQUAL
case .greaterOrEqual: GL_GEQUAL
case .always: GL_ALWAYS
}
glDepthFunc(GLenum(funcEnum))
_depthFunc = newFunc
}
}
}
enum FogMode { case linear, exp, exp2 }
private var _fogMode: FogMode = .exp
var fogMode: FogMode
{
get { _fogMode }
set(newMode)
{
if newMode != _fogMode
{
let modeEnum = switch newMode
{
case .linear: GL_LINEAR
case .exp: GL_EXP
case .exp2: GL_EXP2
}
glFogi(GLenum(GL_FOG_MODE), modeEnum)
_fogMode = newMode
}
}
}
private var _fogDensity: Float = 1
var fogDensity: Float
{
get { _fogDensity }
set(newDensity)
{
if newDensity != _fogDensity
{
glFogf(GLenum(GL_FOG_DENSITY), newDensity)
_fogDensity = newDensity
}
}
}
private var _fogStart: Float = 0
var fogStart: Float
{
get { _fogStart }
set(newStart)
{
if newStart != _fogStart
{
glFogf(GLenum(GL_FOG_START), newStart)
_fogStart = newStart
}
}
}
private var _fogEnd: Float = 1
var fogEnd: Float
{
get { _fogEnd }
set(newEnd)
{
if newEnd != _fogEnd
{
glFogf(GLenum(GL_FOG_END), newEnd)
_fogEnd = newEnd
}
}
}
private var _fogColour: Colour = .zero
var fogColour: Colour
{
get { _fogColour }
set(newColour)
{
if newColour != _fogColour
{
withUnsafePointer(to: newColour)
{
$0.withMemoryRebound(to: GLfloat.self, capacity: 4)
{
glFogfv(GLenum(GL_FOG_COLOR), $0)
}
}
}
}
}
enum FogCoordinateSource { case coordinate, fragmentDepth }
private var _fogCoordinateSource: FogCoordinateSource = .fragmentDepth
var fogCoodinateSource: FogCoordinateSource
{
get { _fogCoordinateSource }
set(newCoordinateSource)
{
if newCoordinateSource != _fogCoordinateSource
{
let coordinateSourceEnum = switch newCoordinateSource
{
case .coordinate: GL_FOG_COORD
case .fragmentDepth: GL_FRAGMENT_DEPTH
}
glFogi(GLenum(GL_FOG_COORD_SRC), coordinateSourceEnum)
_fogCoordinateSource = newCoordinateSource
}
}
}
enum Hint
{
case fog
case generateMipmap
case lineSmooth
case perspectiveCorrection
case pointSmooth
case polygonSmooth
case textureCompression
}
enum HintBehaviour { case fastest, nicest, dontCare }
func setHint(target: Hint, hint: HintBehaviour)
{
let target = switch target
{
case .fog: GL_FOG_HINT
case .generateMipmap: GL_GENERATE_MIPMAP_HINT
case .lineSmooth: GL_LINE_SMOOTH_HINT
case .perspectiveCorrection: GL_PERSPECTIVE_CORRECTION_HINT
case .pointSmooth: GL_POINT_SMOOTH_HINT
case .polygonSmooth: GL_POLYGON_SMOOTH_HINT
case .textureCompression: GL_TEXTURE_COMPRESSION_HINT
}
let mode = switch hint
{
case .fastest: GL_FASTEST
case .nicest: GL_NICEST
case .dontCare: GL_DONT_CARE
}
glHint(GLenum(target), GLenum(mode))
}
struct LightAmbientProperty
{
private var _lightAmbient = [Colour](repeating: .black, count: 8)
subscript(index: Int) -> Colour
{
get { _lightAmbient[index] }
set(newAmbient)
{
if newAmbient != _lightAmbient[index]
{
withUnsafePointer(to: newAmbient)
{
$0.withMemoryRebound(to: GLfloat.self, capacity: 4)
{
// glLightModelfv(GLenum(GL_LIGHT_MODEL_AMBIENT), ambientColour)
glLightfv(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_AMBIENT), $0)
}
}
_lightAmbient[index] = newAmbient
}
}
}
}
var lightAmbient = LightAmbientProperty()
struct LightDiffuseProperty
{
private var _lightDiffuse: [Colour] = [ .white, .black, .black, .black, .black, .black, .black, .black ]
subscript(index: Int) -> Colour
{
get { _lightDiffuse[index] }
set(newDiffuse)
{
if newDiffuse != _lightDiffuse[index]
{
withUnsafePointer(to: newDiffuse)
{
$0.withMemoryRebound(to: GLfloat.self, capacity: 4)
{
glLightfv(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_DIFFUSE), $0)
}
}
_lightDiffuse[index] = newDiffuse
}
}
}
}
var lightDiffuse = LightDiffuseProperty()
struct LightSpecularProperty
{
private var _lightSpecular: [Colour] = [ .white, .black, .black, .black, .black, .black, .black, .black ]
subscript(index: Int) -> Colour
{
get { _lightSpecular[index] }
set(newSpecular)
{
if newSpecular != _lightSpecular[index]
{
withUnsafePointer(to: newSpecular)
{
$0.withMemoryRebound(to: GLfloat.self, capacity: 4)
{
glLightfv(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_SPECULAR), $0)
}
}
_lightSpecular[index] = newSpecular
}
}
}
}
var lightSpecular = LightSpecularProperty()
struct LightPositionProperty
{
private var _lightPosition = [Vec4f](repeating: .Z, count: 8)
subscript(index: Int) -> Vec4f
{
get { _lightPosition[index] }
set(newPosition)
{
withUnsafePointer(to: newPosition)
{
$0.withMemoryRebound(to: GLfloat.self, capacity: 4)
{
glLightfv(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_POSITION), $0)
}
}
_lightPosition[index] = newPosition
}
}
}
var lightPosition = LightPositionProperty()
//private var _lightSpotDirection = [Vec4f](repeating: .zero, count: 8)
//private var _lightSpotExponent = [Vec4f](repeating: .zero, count: 8)
//private var _lightSpotCutoff = [Vec4f](repeating: .zero, count: 8)
struct LightConstantAttenuationProperty
{
private var _lightConstantAttenuation = [Float](repeating: 1, count: 8)
subscript(index: Int) -> Float
{
get { _lightConstantAttenuation[index] }
set(newConstantAttenuation)
{
if newConstantAttenuation != _lightConstantAttenuation[index]
{
glLightf(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_CONSTANT_ATTENUATION), newConstantAttenuation)
_lightConstantAttenuation[index] = newConstantAttenuation
}
}
}
}
var lightConstantAttenuation = LightConstantAttenuationProperty()
struct LightLinearAttenuationProperty
{
private var _lightLinearAttenuation = [Float](repeating: 0, count: 8)
subscript(index: Int) -> Float
{
get { _lightLinearAttenuation[index] }
set(newLinearAttenuation)
{
if newLinearAttenuation != _lightLinearAttenuation[index]
{
glLightf(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_LINEAR_ATTENUATION), newLinearAttenuation)
_lightLinearAttenuation[index] = newLinearAttenuation
}
}
}
}
var lightLinearAttenuation = LightLinearAttenuationProperty()
struct LightQuadraticAttenuation
{
private var _lightQuadraticAttenuation = [Float](repeating: 0, count: 8)
subscript(index: Int) -> Float
{
get { _lightQuadraticAttenuation[index] }
set(newQuadraticAttenuation)
{
if newQuadraticAttenuation != _lightQuadraticAttenuation[index]
{
glLightf(GLenum(GL_LIGHT0 + Int32(index)), GLenum(GL_QUADRATIC_ATTENUATION), newQuadraticAttenuation)
_lightQuadraticAttenuation[index] = newQuadraticAttenuation
}
}
}
}
var lightQuadraticAttenuation = LightQuadraticAttenuation()
var _lightModelAmbient = Colour(r: 0.2, g: 0.2, b: 0.2, a: 1)
var lightModelAmbient: Colour
{
get { _lightModelAmbient }
set(newAmbient)
{
if newAmbient != _lightModelAmbient
{
withUnsafePointer(to: newAmbient)
{
$0.withMemoryRebound(to: GLfloat.self, capacity: 4)
{
glLightModelfv(GLenum(GL_LIGHT_MODEL_AMBIENT), $0)
}
}
_lightModelAmbient = newAmbient
}
}
}
enum LightModelColourControl { case single, separateSpecular }
var _lightModelColourControl: LightModelColourControl = .single
var lightModelColourControl: LightModelColourControl
{
get { _lightModelColourControl }
set(newControl)
{
if newControl != _lightModelColourControl
{
let param = switch newControl
{
case .single: GL_SINGLE_COLOR
case .separateSpecular: GL_SEPARATE_SPECULAR_COLOR
}
glLightModelf(GLenum(GL_LIGHT_MODEL_COLOR_CONTROL), GLfloat(param))
_lightModelColourControl = newControl
}
}
}
var _lightModelLocalViewer = false
var lightModelLocalViewer: Bool
{
get { _lightModelLocalViewer }
set(newMode)
{
if newMode != _lightModelLocalViewer
{
glLightModeli(GLenum(GL_LIGHT_MODEL_LOCAL_VIEWER), newMode ? 1 : 0)
_lightModelLocalViewer = newMode
}
}
}
var _lightModeTwoSide = false
var lightModeTwoSide: Bool
{
get { _lightModeTwoSide }
set(newMode)
{
if newMode != _lightModeTwoSide
{
glLightModeli(GLenum(GL_LIGHT_MODEL_TWO_SIDE), newMode ? 1 : 0)
_lightModeTwoSide = newMode
}
}
}
enum MatrixMode { case modelView, projection, texture, colour }
private var _matrixMode: MatrixMode = .modelView
var matrixMode: MatrixMode
{
get { _matrixMode }
set(newMode)
{
if newMode != _matrixMode
{
let modeEnum = switch newMode
{
case .modelView: GL_MODELVIEW
case .projection: GL_PROJECTION
case .texture: GL_TEXTURE
case .colour: GL_COLOR
}
glMatrixMode(GLenum(modeEnum))
_matrixMode = newMode
}
}
}
static let defaultBuffer: UInt32 = 0
private var _arrayBuffer = GLuint(defaultBuffer)
var arrayBuffer: UInt32
{
get { UInt32(_arrayBuffer) }
set(newBuf)
{
if newBuf != _arrayBuffer
{
_arrayBuffer = GLuint(newBuf)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), _arrayBuffer)
}
}
}
private var _elementArrayBuffer = GLuint(defaultBuffer)
var elementArrayBuffer: UInt32
{
get { UInt32(_elementArrayBuffer) }
set(newBuf)
{
if newBuf != _elementArrayBuffer
{
_elementArrayBuffer = GLuint(newBuf)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), _elementArrayBuffer)
}
}
}
enum PolygonMode { case point, line, fill }
private var _polygonMode = PolygonMode.fill
var polygonMode: PolygonMode
{
get { _polygonMode }
set(newMode)
{
if newMode != _polygonMode
{
let modeEnum = switch newMode
{
case .point: GL_POINT
case .line: GL_LINE
case .fill: GL_FILL
}
glPolygonMode(GLenum(GL_FRONT_AND_BACK), GLenum(modeEnum));
_polygonMode = newMode
}
}
}
}