Skip to content

Commit 5f34e12

Browse files
authored
Merge pull request #15 from PureSwift/feature/sdl1
Add SDL 1.2 wrappers
2 parents 00c3f23 + 5c935bb commit 5f34e12

21 files changed

Lines changed: 1598 additions & 2 deletions

.github/workflows/swift.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Swift Version
1515
run: swift --version
1616
- name: Install dependencies
17-
run: brew install sdl2 sdl3 sdl2_image sdl2_mixer sdl3_image sdl3_mixer
17+
run: brew install sdl12-compat sdl2 sdl3 sdl2_image sdl2_mixer sdl3_image sdl3_mixer
1818
- name: Build
1919
run: swift build -c ${{ matrix.config }}
2020

@@ -34,7 +34,7 @@ jobs:
3434
run: swift --version
3535
- name: Install dependencies
3636
run: |
37-
apt-get update && apt-get install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev \
37+
apt-get update && apt-get install -y libsdl1.2-dev libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev \
3838
cmake ninja-build pkg-config \
3939
libasound2-dev libpulse-dev libaudio-dev libfribidi-dev libjack-dev libsndio-dev \
4040
libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \

Package.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import PackageDescription
44
let package = Package(
55
name: "SDL",
66
products: [
7+
.library(
8+
name: "SDL1Swift",
9+
targets: ["SDL1Swift"]
10+
),
711
.library(
812
name: "SDL2Swift",
913
targets: ["SDL2Swift"]
@@ -54,6 +58,21 @@ let package = Package(
5458
name: "SDLDemo",
5559
dependencies: ["SDL2Swift"]
5660
),
61+
// Named `SDL1Swift` (not `SDL1`) so the built module doesn't share a name
62+
// with the `SDL` system library, which would shadow `-lSDL` when linking.
63+
.target(
64+
name: "SDL1Swift",
65+
dependencies: ["CSDL"],
66+
path: "Sources/SDL1"
67+
),
68+
.systemLibrary(
69+
name: "CSDL",
70+
pkgConfig: "sdl",
71+
providers: [
72+
.brew(["sdl12-compat"]),
73+
.apt(["libsdl1.2-dev"])
74+
]
75+
),
5776
// Named `SDL2Swift` (not `SDL2`) so the built module doesn't share a name
5877
// with the `SDL2` system library, which would shadow `-lSDL2` when linking.
5978
.target(
@@ -137,6 +156,9 @@ let package = Package(
137156
.apt(["libsdl3-mixer-dev"])
138157
]
139158
),
159+
.testTarget(
160+
name: "SDL1Tests",
161+
dependencies: ["SDL1Swift"]),
140162
.testTarget(
141163
name: "SDL2Tests",
142164
dependencies: ["SDL2Swift"]),

Sources/CSDL/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CSDL [system] {
2+
header "shim.h"
3+
link "SDL"
4+
export *
5+
}

Sources/CSDL/shim.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#ifdef __APPLE__
2+
#include "/opt/homebrew/include/SDL/SDL.h"
3+
#else
4+
#include <SDL/SDL.h>
5+
#endif

Sources/SDL1/BitMaskOption.swift

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
//
2+
// BitMaskOption.swift
3+
// SDL1
4+
//
5+
// Created by Alsey Coleman Miller on 6/6/17.
6+
//
7+
8+
/// Enum that represents a bit mask flag / option.
9+
///
10+
/// Basically `Swift.OptionSet` for enums.
11+
public protocol BitMaskOption: RawRepresentable, Hashable, CaseIterable where RawValue: FixedWidthInteger { }
12+
13+
public extension Sequence where Element: BitMaskOption {
14+
15+
/// Convert Swift enums for bit mask options into their raw values OR'd.
16+
var rawValue: Element.RawValue {
17+
18+
@inline(__always)
19+
get { return reduce(0, { $0 | $1.rawValue }) }
20+
}
21+
}
22+
23+
public extension BitMaskOption {
24+
25+
/// Whether the enum case is present in the raw value.
26+
@inline(__always)
27+
func isContained(in rawValue: RawValue) -> Bool {
28+
29+
return (self.rawValue & rawValue) != 0
30+
}
31+
32+
@inline(__always)
33+
static func from(rawValue: RawValue) -> [Self] {
34+
35+
return Self.allCases.filter { $0.isContained(in: rawValue) }
36+
}
37+
}
38+
39+
// MARK: - BitMaskOptionSet
40+
41+
/// Integer-backed array type for `BitMaskOption`.
42+
///
43+
/// The elements are packed in the integer with bitwise math and stored on the stack.
44+
public struct BitMaskOptionSet <Element: BitMaskOption>: RawRepresentable {
45+
46+
public typealias RawValue = Element.RawValue
47+
48+
public private(set) var rawValue: RawValue
49+
50+
@inline(__always)
51+
public init(rawValue: RawValue) {
52+
53+
self.rawValue = rawValue
54+
}
55+
56+
@inline(__always)
57+
public init() {
58+
59+
self.rawValue = 0
60+
}
61+
62+
public static var all: BitMaskOptionSet<Element> {
63+
64+
return BitMaskOptionSet<Element>(rawValue: Element.allCases.rawValue)
65+
}
66+
67+
@inline(__always)
68+
public mutating func insert(_ element: Element) {
69+
70+
rawValue = rawValue | element.rawValue
71+
}
72+
73+
@discardableResult
74+
public mutating func remove(_ element: Element) -> Bool {
75+
76+
guard contains(element) else { return false }
77+
78+
rawValue = rawValue & ~element.rawValue
79+
80+
return true
81+
}
82+
83+
@inline(__always)
84+
public mutating func removeAll() {
85+
86+
self.rawValue = 0
87+
}
88+
89+
@inline(__always)
90+
public func contains(_ element: Element) -> Bool {
91+
92+
return element.isContained(in: rawValue)
93+
}
94+
95+
public func contains <S: Sequence> (_ other: S) -> Bool where S.Iterator.Element == Element {
96+
97+
for element in other {
98+
99+
guard element.isContained(in: rawValue)
100+
else { return false }
101+
}
102+
103+
return true
104+
}
105+
106+
public var count: Int {
107+
108+
return Element.allCases.reduce(0, { $0 + ($1.isContained(in: rawValue) ? 1 : 0) })
109+
}
110+
111+
public var isEmpty: Bool {
112+
113+
return rawValue == 0
114+
}
115+
}
116+
117+
// MARK: - Sequence Conversion
118+
119+
public extension BitMaskOptionSet {
120+
121+
init<S: Sequence>(_ sequence: S) where S.Iterator.Element == Element {
122+
123+
self.rawValue = sequence.rawValue
124+
}
125+
}
126+
127+
// MARK: - Equatable
128+
129+
extension BitMaskOptionSet: Equatable {
130+
131+
public static func == (lhs: BitMaskOptionSet, rhs: BitMaskOptionSet) -> Bool {
132+
133+
return lhs.rawValue == rhs.rawValue
134+
}
135+
}
136+
137+
// MARK: - CustomStringConvertible
138+
139+
extension BitMaskOptionSet: CustomStringConvertible {
140+
141+
public var description: String {
142+
143+
return Element.from(rawValue: rawValue)
144+
.sorted(by: { $0.rawValue < $1.rawValue })
145+
.description
146+
}
147+
}
148+
149+
// MARK: - Hashable
150+
151+
extension BitMaskOptionSet: Hashable {
152+
153+
#if swift(>=4.2)
154+
public func hash(into hasher: inout Hasher) {
155+
156+
rawValue.hash(into: &hasher)
157+
}
158+
#else
159+
public var hashValue: Int {
160+
161+
return rawValue.hashValue
162+
}
163+
#endif
164+
}
165+
166+
// MARK: - ExpressibleByArrayLiteral
167+
168+
extension BitMaskOptionSet: ExpressibleByArrayLiteral {
169+
170+
public init(arrayLiteral elements: Element...) {
171+
172+
self.init(elements)
173+
}
174+
}
175+
176+
// MARK: - ExpressibleByIntegerLiteral
177+
178+
extension BitMaskOptionSet: ExpressibleByIntegerLiteral {
179+
180+
public init(integerLiteral value: UInt64) {
181+
182+
self.init(rawValue: numericCast(value))
183+
}
184+
}
185+
186+
// MARK: - Sequence
187+
188+
extension BitMaskOptionSet: Sequence {
189+
190+
public func makeIterator() -> IndexingIterator<[Element]> {
191+
192+
return Element.from(rawValue: rawValue).makeIterator()
193+
}
194+
}

Sources/SDL1/Color.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// Color.swift
3+
// SDL1
4+
//
5+
// Created by Alsey Coleman Miller on 7/10/26.
6+
//
7+
8+
import CSDL
9+
10+
/// SDL Color
11+
///
12+
/// A single color entry, as used by palettes. SDL 1.2 colors carry no alpha channel.
13+
public struct SDLColor: Equatable, Hashable, Sendable {
14+
15+
public var red: UInt8
16+
17+
public var green: UInt8
18+
19+
public var blue: UInt8
20+
21+
public init(red: UInt8, green: UInt8, blue: UInt8) {
22+
self.red = red
23+
self.green = green
24+
self.blue = blue
25+
}
26+
27+
internal init(_ color: SDL_Color) {
28+
self.red = color.r
29+
self.green = color.g
30+
self.blue = color.b
31+
}
32+
33+
internal var internalValue: SDL_Color {
34+
SDL_Color(r: red, g: green, b: blue, unused: 0)
35+
}
36+
}

Sources/SDL1/CountableSet.swift

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//
2+
// CountableSet.swift
3+
// SDL1
4+
//
5+
// Created by Alsey Coleman Miller on 10/19/18.
6+
//
7+
8+
/// Static Integer-based array for use on the stack.
9+
///
10+
/// Allows a count value to be used a collection.
11+
/// Each element is basically a valid index in the collection (e.g. `0 ..< count`).
12+
public struct CountableSet <Element: IndexRepresentable>: Collection {
13+
14+
public typealias Index = Int
15+
16+
public init(count: Int) {
17+
18+
precondition(count >= 0, "Invalid negative value \(count)")
19+
20+
self.count = count
21+
}
22+
23+
public var count: Int
24+
25+
public subscript (index: Index) -> Element {
26+
27+
assert(index < count, "Invalid index")
28+
29+
return Element(rawValue: index)
30+
}
31+
32+
/// The start `Index`.
33+
public var startIndex: Index {
34+
return 0
35+
}
36+
37+
/// The end `Index`.
38+
///
39+
/// This is the "one-past-the-end" position, and will always be equal to the `count`.
40+
public var endIndex: Index {
41+
return count
42+
}
43+
44+
public func index(before i: Index) -> Index {
45+
return i - 1
46+
}
47+
48+
public func index(after i: Index) -> Index {
49+
return i + 1
50+
}
51+
52+
public func makeIterator() -> IndexingIterator<CountableSet<Element>> {
53+
return IndexingIterator(_elements: self)
54+
}
55+
}
56+
57+
/// A struct wrapper that represents an index value.
58+
public protocol IndexRepresentable: RawRepresentable, Hashable {
59+
60+
init(rawValue: Int)
61+
62+
var rawValue: Int { get }
63+
}

0 commit comments

Comments
 (0)