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) } } } }