Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/add madgraphics demo #33

Merged
merged 5 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
28 changes: 28 additions & 0 deletions Examples/SwiftIOPlayground/13MoreProjects/Fireworks/Package.mmp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This is a MadMachine project file in TOML format
# This file contains parameters that cannot be managed by SwiftPM
# Editing this file will alter the behavior of the build/download process
# Project files within dependent libraries will be IGNORED

# Specify the board name below
# Supported boards are listed as follows
# "SwiftIOBoard"
# "SwiftIOMicro"
board = "SwiftIOMicro"

# Specify the target triple below
# Supported architectures are listed as follows
# "thumbv7em-unknown-none-eabi"
# "thumbv7em-unknown-none-eabihf"
# "armv7em-none-none-eabi"
triple = "armv7em-none-none-eabi"

# Enable or disable hardware floating-point support below
# If your code involves significant floating-point calculations, please set it to 'true'
hard-float = true

# Enable or disable float register below
# If your code involves significant floating-point calculations, please set it to 'true'
float-abi = false

# Reserved for future use
version = 1
28 changes: 28 additions & 0 deletions Examples/SwiftIOPlayground/13MoreProjects/Fireworks/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "Fireworks",
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/madmachineio/SwiftIO.git", branch: "develop"),
.package(url: "https://github.com/madmachineio/MadBoards.git", branch: "develop"),
.package(url: "https://github.com/madmachineio/MadDrivers.git", branch: "develop"),
.package(url: "https://github.com/madmachineio/CFreeType", from: "2.13.0"),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.executableTarget(
name: "Fireworks",
dependencies: [
"SwiftIO",
"MadBoards",
// Use specific library name rather than "MadDrivers" would speed up the build procedure.
.product(name: "ST7789", package: "MadDrivers"),
"CFreeType"
]),
]
)
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import MadGraphics
import ST7789
import SwiftIO

struct Firework {
var particle: Particle
var sparks: [Spark] = []

var exploded = false

let color: Color
let size = 2

// Create a firework at the bottom of the screen.
init(color: Color, maxWidth: Int) {
self.color = color

let x = Array(0..<(maxWidth - 1)).shuffled().randomElement()!
particle = Particle(pos: Point(x: x, y: maxWidth - 1))
}

// Update firework's position.
// If it explodes, it will return true to indicate it's time to play sound.
mutating func update(_ layer: Layer) -> Bool {
if exploded {
for spark in sparks {
layer.draw() { canvas in
canvas.fillCircle(at: spark.pos, radius: size, data: Color.black.rawValue)
}
}

updateSparks()

for spark in sparks {
let color = Color.blend(foreground: color.rawValue, background: Color.black.rawValue, mask: spark.lifespan)
layer.draw() { canvas in
canvas.fillCircle(at: spark.pos, radius: size, data: color.rawValue)
}
}
} else {
layer.draw() { canvas in
canvas.fillCircle(at: particle.pos, radius: size, data: Color.black.rawValue)
}

let playSound = updateParticle()

layer.draw() { canvas in
canvas.fillCircle(at: particle.pos, radius: size, data: color.rawValue)
}
return playSound
}

return false
}

// Update sparks' position and speed over time.
mutating func updateSparks() {
for i in sparks.indices.reversed() {
sparks[i].update()
// If
if sparks[i].done() {
sparks.remove(at: i)
}
}
}

// Update particle's position and speed over time.
mutating func updateParticle() -> Bool {
particle.update()
if particle.willExplode() {
exploded = true
explode()
return true
}

return false
}

// Generate firework sparks after explosion.
mutating func explode() {
for _ in 0..<100 {
sparks.append(Spark(pos: particle.pos))
}
}

func done() -> Bool {
return exploded && sparks.count == 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import SwiftIO
import MadBoard
import ST7789
import MadGraphics

// Use lock to protect data from simultaneous access by multiple threads.
let i2sLock = Mutex()
// Whether the speaker will play sound.
var playSound = false

@main
public struct Fireworks {
public static func main() {
// Initialize the SPI pin and the digital pins for the LCD.
let bl = DigitalOut(Id.D2)
let rst = DigitalOut(Id.D12)
let dc = DigitalOut(Id.D13)
let cs = DigitalOut(Id.D5)
let spi = SPI(Id.SPI0, speed: 30_000_000)

// Initialize the LCD using the pins above. Rotate the screen to keep the original at the upper left.
let screen = ST7789(spi: spi, cs: cs, dc: dc, rst: rst, bl: bl, rotation: .angle90)
var screenBuffer = [UInt16](repeating: 0, count: screen.width * screen.width)
var frameBuffer = [UInt32](repeating: 0, count: screen.width * screen.width)

var colorIndex = 0
let colors: [Color] = [
.pink, .red, .lime, .blue, .cyan,
.purple, .magenta, .orange, .yellow
]

let layer = Layer(at: Point.zero, anchorPoint: UnitPoint.zero, width: screen.width, height: screen.height)


let font = Font(path: "/lfs/Resources/Fonts/Roboto-Regular.ttf", pointSize: 10, dpi: 220)
let text1 = TextLayer(at: Point(x: layer.bounds.size.halfWidth, y: 40), anchorPoint: UnitPoint.center, string: "Happy", font: font, foregroundColor: Color.red)
let text2 = TextLayer(at: Point(x: layer.bounds.size.halfWidth, y: 80), anchorPoint: UnitPoint.center, string: "Christmas", font: font, foregroundColor: Color.red)

layer.append(text1)
layer.append(text2)

var fireworks: [Firework] = []
var exploded = false

createThread(
name: "play_sound",
priority: 3,
stackSize: 1024 * 64,
soundThread
)

sleep(ms: 10)

while true {
if Int.random(in: 0..<100) < 10 {
fireworks.append(Firework(color: colors[colorIndex], maxWidth: layer.bounds.width))
// Update firwork's color.
colorIndex += 1
if colorIndex == colors.count {
colorIndex = 0
}
}

var i = 0
while i < fireworks.count {
if fireworks[i].update(layer) {
exploded = true
}

// If a all sparks of a firework disppear, remove the firework.
if fireworks[i].done() {
fireworks.remove(at: i)
} else {
i += 1
}
}

// If any firework has exploded, update the global variable.
if exploded {
i2sLock.lock()
playSound = true
i2sLock.unlock()

exploded = false
}

layer.render(into: &frameBuffer, output: &screenBuffer, transform: Color.getRGB565LE) { dirty, data in
screen.writeBitmap(x: dirty.x, y: dirty.y, width: dirty.width, height: dirty.height, data: data)
}

sleep(ms: 10)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import MadGraphics

// The firework before explosion.
struct Particle {
var pos: Point
var velocity: (x: Float, y: Float)
var acceleration: (x: Float, y: Float)

// Create a particle with a random velocity and acceleration.
init(pos: Point) {
self.pos = pos
velocity = (0, Float.random(in: (-14.0)...(-10.0)))
acceleration = (0, Float.random(in: 0.3..<0.4))
}

// Update the particle's position and velocity over time.
mutating func update() {
pos.x += Int(velocity.x)
pos.y += Int(velocity.y)

velocity.x += acceleration.x
velocity.y += acceleration.y
}

// Whether the particle reaches its maximum height.
func willExplode() -> Bool {
return velocity.y > 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import SwiftIO
import MadBoard

func soundThread(_ a: UnsafeMutableRawPointer?, _ b: UnsafeMutableRawPointer?, _ c: UnsafeMutableRawPointer?) -> () {
let speaker = I2S(Id.I2S0, rate: 44_100)

// Read sound data from file.
let sound = readSoundData(from: "/lfs/Resources/Sounds/boom.wav")
var startPlay = false

while true {
sleep(ms: 100)

// Check the global variable to see if the speaker need to play sound.
i2sLock.lock()
if playSound {
startPlay = true
}
i2sLock.unlock()

if startPlay {
speaker.write(sound)
startPlay = false

// Update the global variable.
i2sLock.lock()
playSound = false
i2sLock.unlock()
}
}

func readSoundData(from path: String) -> [UInt8] {
let headerSize = 0x2C
var buffer = [UInt8]()

do {
let file = try FileDescriptor.open(path)
try file.seek(offset: 0, from: FileDescriptor.SeekOrigin.end)
let size = try file.tell() - headerSize

buffer = [UInt8](repeating: 0, count: size)
try file.read(fromAbsoluteOffest: headerSize, into: &buffer, count: size)
try file.close()
} catch {
print("File \(path) handle error: \(error)")
return []
}

return buffer
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import MadGraphics

// The firework after explosion.
struct Spark {
var pos: Point
var velocity: (x: Float, y: Float)
var acceleration: (x: Float, y: Float)
// How long the spark shows on the screen.
var lifespan: UInt8 = 255

// Create a particle with a random velocity and acceleration.
// Its initial position is the maximum height of the firework particle.
init(pos: Point) {
self.pos = pos

// The speed of the spark at a random direction.
velocity.x = Float(Array(-100..<100).shuffled().randomElement()!) / 50
velocity.y = Float(Array(-100..<100).shuffled().randomElement()!) / 50
velocity.x *= Float.random(in: 1...4)
velocity.y *= Float.random(in: 1...4)

acceleration = (0, Float.random(in: 0.3..<0.4))
}

// Update the particle's position and velocity over time.
mutating func update() {
velocity.x *= 0.8
velocity.y *= 0.8
lifespan -= 5

pos.x += Int(velocity.x)
pos.y += Int(velocity.y)

velocity.x += acceleration.x
velocity.y += acceleration.y
}

// Whether the spark will disappear.
func done() -> Bool {
return lifespan <= 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
Loading