From 6fd8405944aa66a7ad03122c4ff7c319b3a5e336 Mon Sep 17 00:00:00 2001 From: sunlubo Date: Wed, 15 Aug 2018 23:29:06 +0800 Subject: [PATCH] refactor some code --- Sources/Demo/main.swift | 4 +- Sources/SwiftSDL2/Audio.swift | 21 ++++----- Sources/SwiftSDL2/Event.swift | 62 ++++++++++++++++---------- Sources/SwiftSDL2/Mutex.swift | 76 +++++++++++++++++++++----------- Sources/SwiftSDL2/SDLError.swift | 4 +- Sources/SwiftSDL2/Texture.swift | 19 ++++++++ 6 files changed, 122 insertions(+), 64 deletions(-) diff --git a/Sources/Demo/main.swift b/Sources/Demo/main.swift index 6d3b6b2..a27c928 100644 --- a/Sources/Demo/main.swift +++ b/Sources/Demo/main.swift @@ -8,9 +8,7 @@ let renderer = Renderer(window: window) let texture = Texture(renderer: renderer, format: .rgba8888, access: .target, width: 640, height: 480) while true { - var event = Event() - Events.pollEvent(&event) - if event.type == .quit { + if let event = Events.poll(), event.type == .quit { break } diff --git a/Sources/SwiftSDL2/Audio.swift b/Sources/SwiftSDL2/Audio.swift index a95d31b..bdb4284 100644 --- a/Sources/SwiftSDL2/Audio.swift +++ b/Sources/SwiftSDL2/Audio.swift @@ -61,7 +61,7 @@ extension AudioFormat { // 32-bit integer samples in big-endian byte order public static let s32msb = UInt16(AUDIO_S32MSB) // 32-bit integer samples in native byte order - public static let s32sys = UInt16(AUDIO_F32SYS) + public static let s32sys = UInt16(AUDIO_S32SYS) // AUDIO_S32LSB public static let s32 = UInt16(AUDIO_S32) @@ -104,7 +104,6 @@ extension AudioStatus { /// - 7: FL FR FC LFE BC SL SR (6.1 surround) /// - 8: FL FR FC LFE BL BR SL SR (7.1 surround) public typealias AudioSpec = SDL_AudioSpec - public typealias AudioCallback = SDL_AudioCallback /// Allow change flags @@ -127,9 +126,9 @@ public final class AudioDevice { let deviceId: SDL_AudioDeviceID /// the desired output format - let desiredSpec: AudioSpec + public let desiredSpec: AudioSpec /// the obtained output format - let obtainedSpec: AudioSpec + public let obtainedSpec: AudioSpec /// Create and open a specific audio device. Passing in a device name of nil requests /// the most reasonable default (and is equivalent to calling SDL_OpenAudio()). @@ -201,7 +200,7 @@ public final class AudioDevice { /// /// - Parameters: /// - index: the index of the audio device; the value ranges from 0 to deviceCount - 1 - /// - isCapture: non-zero to specify a device that has recording capability + /// - isCapture: true to specify a device that has recording capability /// - Returns: Returns the name of the audio device at the requested index, or nil on error. public static func deviceName(index: Int, isCapture: Bool) -> String? { assert(index < deviceCount(isCapture: isCapture), "Must be a value between 0 and (number of audio devices-1).") @@ -235,20 +234,22 @@ public final class AudioDevice { } } +public let MIX_MAXVOLUME = Int(SDL_MIX_MAXVOLUME) + /// Mix audio data in a specified format. /// /// - Parameters: -/// - src: the source audio buffer to be mixed /// - dst: the destination for the mixed audio +/// - src: the source audio buffer to be mixed /// - format: the desired audio format /// - len: the length of the audio buffer in bytes -/// - volume: ranges from 0 - 128, and should be set to SDL_MIX_MAXVOLUME for full audio volume -public func mixAudioFormat( - src: UnsafePointer, +/// - volume: ranges from 0 - 128, and should be set to `MIX_MAXVOLUME` for full audio volume +public func mixAudio( dst: UnsafeMutablePointer, + src: UnsafePointer, format: AudioFormat, len: Int, - volume: Int + volume: Int = MIX_MAXVOLUME ) { SDL_MixAudioFormat(dst, src, format, UInt32(len), Int32(volume)) } diff --git a/Sources/SwiftSDL2/Event.swift b/Sources/SwiftSDL2/Event.swift index 69f85be..5a45276 100644 --- a/Sources/SwiftSDL2/Event.swift +++ b/Sources/SwiftSDL2/Event.swift @@ -10,9 +10,8 @@ import CSDL2 public typealias EventType = SDL_EventType extension EventType { - /// Unused (do not remove) - public static let firstEvent = SDL_FIRSTEVENT + public static let first = SDL_FIRSTEVENT /* Application events */ @@ -20,7 +19,7 @@ extension EventType { public static let quit = SDL_QUIT /// This last event is only for bounding internal arrays - public static let lastEvent = SDL_LASTEVENT + public static let last = SDL_LASTEVENT } extension UInt32 { @@ -49,11 +48,11 @@ extension Event: CustomStringConvertible { public var description: String { switch EventType(rawValue: type) { - case .firstEvent: + case .first: return "first" case .quit: return "quit" - case .lastEvent: + case .last: return "last" default: return "unknown" @@ -81,7 +80,7 @@ public final class Events { /// This function updates the event queue and internal input device state. /// /// This should only be run in the thread that sets the video mode. - public static func pumpEvents() { + public static func pump() { SDL_PumpEvents() } @@ -97,47 +96,64 @@ public final class Events { /// - minType: minimum value of the event type to be considered; SDL_FIRSTEVENT is a safe choice /// - maxType: maximum value of the event type to be considered; SDL_LASTEVENT is a safe choice /// - Returns: The number of events actually stored, or -1 if there was an error. + /// - Throws: SDLError @discardableResult - public static func peepEvents( + public static func peep( _ events: inout [Event], count: Int, action: EventAction, - minType: UInt32 = EventType.firstEvent.rawValue, - maxType: Uint32 = EventType.lastEvent.rawValue - ) -> Int { + minType: UInt32 = EventType.first.rawValue, + maxType: Uint32 = EventType.last.rawValue + ) throws -> Int { precondition(events.capacity >= count, "Please allocate enough memory.") - return Int(SDL_PeepEvents(&events, Int32(count), action, minType, maxType)) + let ret = SDL_PeepEvents(&events, Int32(count), action, minType, maxType) + try throwIfFail(ret) + return Int(ret) } /// Polls for currently pending events. /// /// - Parameter event: the next event is removed from the queue and stored in that area. /// - Returns: true if there are any pending events, or false if there are none available. - @discardableResult - public static func pollEvent(_ event: inout Event) -> Bool { - return SDL_PollEvent(&event) == 1 + public static func poll() -> Event? { + var event = Event() + if SDL_PollEvent(&event) == 1 { + return event + } + return nil } /// Add an event to the event queue. /// /// - Returns: true on success, otherwise false. @discardableResult - public static func pushEvent(_ event: inout Event) -> Bool { + public static func push(_ event: inout Event) -> Bool { return SDL_PushEvent(&event) == 1 } /// Waits indefinitely for the next available event. /// - /// - Parameters: - /// - event: the SDL_Event structure to be filled in with the next event from the queue - /// - timeout: the maximum number of milliseconds to wait for the next available event - /// - Returns: true, or false if there was an error while waiting for events. + /// - Returns: the next event from the queue, or nil if there was an error while waiting for events. + @discardableResult + public static func wait() -> Event? { + var event = Event() + if SDL_WaitEvent(&event) == 1 { + return event + } + return nil + } + + /// Waits until the specified timeout (in milliseconds) for the next available event. + /// + /// - Parameter timeout: the maximum number of milliseconds to wait for the next available event + /// - Returns: the next event from the queue, or nil if there was an error while waiting for events. @discardableResult - public static func waitEvent(_ event: inout Event, timeout: Int = -1) -> Bool { - if timeout != -1 { - return SDL_WaitEventTimeout(&event, Int32(timeout)) == 1 + public static func wait(timeout: Int) -> Event? { + var event = Event() + if SDL_WaitEventTimeout(&event, Int32(timeout)) == 1 { + return event } - return SDL_WaitEvent(&event) == 1 + return nil } /// Set the state of processing events by type. diff --git a/Sources/SwiftSDL2/Mutex.swift b/Sources/SwiftSDL2/Mutex.swift index ed19941..611435f 100644 --- a/Sources/SwiftSDL2/Mutex.swift +++ b/Sources/SwiftSDL2/Mutex.swift @@ -18,18 +18,26 @@ public final class Mutex { } /// Lock the mutex. - public func lock() { - SDL_LockMutex(mutexPtr) + /// + /// - Throws: SDLError + public func lock() throws { + try throwIfFail(SDL_LockMutex(mutexPtr)) } /// Try to lock the mutex. - public func tryLock() -> Bool { - return SDL_TryLockMutex(mutexPtr) == 0 + /// + /// - Throws: SDLError + public func tryLock() throws -> Bool { + let ret = SDL_TryLockMutex(mutexPtr) + try throwIfFail(ret) + return ret != SDL_MUTEX_TIMEDOUT } /// Unlock the mutex. - public func unlock() { - SDL_UnlockMutex(mutexPtr) + /// + /// - Throws: SDLError + public func unlock() throws { + try throwIfFail(SDL_UnlockMutex(mutexPtr)) } deinit { @@ -54,31 +62,39 @@ public final class Semaphore { /// This function suspends the calling thread until the semaphore has a positive count. /// It then atomically decreases the semaphore count. - public func wait() { - SDL_SemWait(semaphorePtr) - } - - /// Non-blocking variant of SDL_SemWait(). /// - /// - Returns: true if the wait succeeds - public func tryWait() -> Bool { - return SDL_SemTryWait(semaphorePtr) == 0 + /// - Throws: SDLError + public func wait() throws { + try throwIfFail(SDL_SemWait(semaphorePtr)) } /// Variant of SDL_SemWait() with a timeout in milliseconds. /// /// - Parameter timeout: the length of the timeout in milliseconds /// - Returns: true if the wait succeeds + /// - Throws: SDLError /// /// - Warning: On some platforms this function is implemented by looping with a delay of 1 ms, /// and so should be avoided if possible. - public func wait(timeout: Int) -> Bool { - return SDL_SemWaitTimeout(semaphorePtr, Uint32(timeout)) == 0 + public func wait(timeout: Int) throws -> Bool { + let ret = SDL_SemWaitTimeout(semaphorePtr, Uint32(timeout)) + try throwIfFail(ret) + return ret != SDL_MUTEX_TIMEDOUT + } + + /// Non-blocking variant of SDL_SemWait(). + /// + /// - Returns: true if the wait succeeds + /// - Throws: SDLError + public func tryWait() throws -> Bool { + let ret = SDL_SemTryWait(semaphorePtr) + try throwIfFail(ret) + return ret != SDL_MUTEX_TIMEDOUT } /// Atomically increases the semaphore's count (not blocking). - public func post() { - SDL_SemPost(semaphorePtr) + public func post() throws { + try throwIfFail(SDL_SemPost(semaphorePtr)) } deinit { @@ -104,13 +120,17 @@ public final class Condition { } /// Restart one of the threads that are waiting on the condition variable. - public func signal() { - SDL_CondSignal(condPtr) + /// + /// - Throws: SDLError + public func signal() throws { + try throwIfFail(SDL_CondSignal(condPtr)) } /// Restart all threads that are waiting on the condition variable. - public func broadcast() { - SDL_CondBroadcast(condPtr) + /// + /// - Throws: SDLError + public func broadcast() throws { + try throwIfFail(SDL_CondBroadcast(condPtr)) } /// Wait on the condition variable, unlocking the provided mutex. @@ -118,10 +138,11 @@ public final class Condition { /// The mutex is re-locked once the condition variable is signaled. /// /// - Parameter mutex: the mutex used to coordinate thread access + /// - Throws: SDLError /// /// - Warning: The mutex must be locked before entering this function. - public func wait(mutex: Mutex) { - SDL_CondWait(condPtr, mutex.mutexPtr) + public func wait(mutex: Mutex) throws { + try throwIfFail(SDL_CondWait(condPtr, mutex.mutexPtr)) } /// Wait until a condition variable is signaled or a specified amount of time has passed. @@ -130,11 +151,14 @@ public final class Condition { /// - mutex: the mutex used to coordinate thread access /// - timeout: the maximum time to wait in milliseconds, or SDL_MUTEX_MAXWAIT to wait indefinitely /// - Returns: true if the wait succeeds + /// - Throws: SDLError /// /// - Warning: On some platforms this function is implemented by looping with a /// delay of 1 ms, and so should be avoided if possible. - public func wait(mutex: Mutex, timeout: Int) -> Bool { - return SDL_CondWaitTimeout(condPtr, mutex.mutexPtr, Uint32(timeout)) == 0 + public func wait(mutex: Mutex, timeout: Int) throws -> Bool { + let ret = SDL_CondWaitTimeout(condPtr, mutex.mutexPtr, Uint32(timeout)) + try throwIfFail(ret) + return ret != SDL_MUTEX_TIMEDOUT } deinit { diff --git a/Sources/SwiftSDL2/SDLError.swift b/Sources/SwiftSDL2/SDLError.swift index 55c1ed2..87ffdd8 100644 --- a/Sources/SwiftSDL2/SDLError.swift +++ b/Sources/SwiftSDL2/SDLError.swift @@ -19,8 +19,8 @@ public struct SDLError: Error, Equatable, CustomStringConvertible { } } -func throwIfFail(_ code: Int32) throws { - if code < 0 { +func throwIfFail(_ code: Int32, predicate: (Int32) -> Bool = { $0 < 0 }) throws { + if predicate(code) { throw SDLError(code: code) } } diff --git a/Sources/SwiftSDL2/Texture.swift b/Sources/SwiftSDL2/Texture.swift index c8a32ae..3ee5b5b 100644 --- a/Sources/SwiftSDL2/Texture.swift +++ b/Sources/SwiftSDL2/Texture.swift @@ -149,6 +149,25 @@ public final class Texture { return SDL_SetTextureBlendMode(texturePtr, mode) == 0 } + /// Update the given texture rectangle with new pixel data. + /// + /// - Parameters: + /// - rect: an SDL_Rect structure representing the area to update, or NULL to update the entire texture + /// - pixels: the raw pixel data in the format of the texture + /// - pitch: the number of bytes in a row of pixel data, including padding between lines + /// - Throws: SDLError + public func update(rect: Rect?, pixels: UnsafeRawPointer, pitch: Int) throws { + var rectPtr: UnsafeMutablePointer? + defer { + rectPtr?.deallocate() + } + if let rect = rect { + rectPtr = UnsafeMutablePointer.allocate(capacity: 1) + rectPtr?.initialize(to: rect) + } + try throwIfFail(SDL_UpdateTexture(texturePtr, rectPtr, pixels, Int32(pitch))) + } + /// Update a rectangle within a planar YV12 or IYUV texture with new pixel data. /// /// - Parameters: