819 lines
20 KiB
Swift
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
|
|
}
|
|
}
|
|
}
|
|
}
|