-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
Examples/SwiftIOPlayground/12MoreProjects/SpinningCube/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
17 changes: 17 additions & 0 deletions
17
Examples/SwiftIOPlayground/12MoreProjects/SpinningCube/Package.mmp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# This is a MadMachine project file in TOML format | ||
# This file holds those parameters that could not be managed by SwiftPM | ||
# Edit this file would change the behavior of the building/downloading procedure | ||
# Those project files in the dependent libraries would be IGNORED | ||
|
||
# Specify the board name below | ||
# There are "SwiftIOBoard" and "SwiftIOMicro" now | ||
board = "SwiftIOMicro" | ||
|
||
# Specifiy the target triple below | ||
# There are "thumbv7em-unknown-none-eabi" and "thumbv7em-unknown-none-eabihf" now | ||
# If your code use significant floating-point calculation, | ||
# plz set it to "thumbv7em-unknown-none-eabihf" | ||
triple = "thumbv7em-unknown-none-eabi" | ||
|
||
# Reserved for future use | ||
version = 1 |
30 changes: 30 additions & 0 deletions
30
Examples/SwiftIOPlayground/12MoreProjects/SpinningCube/Package.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// 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: "SpinningCube", | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
.package(url: "https://github.com/madmachineio/SwiftIO.git", branch: "main"), | ||
.package(url: "https://github.com/madmachineio/MadBoards.git", branch: "main"), | ||
.package(url: "https://github.com/madmachineio/MadDrivers.git", branch: "main"), | ||
.package(path: "https://github.com/madmachineio/MadGraphics.git"), | ||
.package(url: "https://github.com/apple/swift-numerics", from: "1.0.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: "SpinningCube", | ||
dependencies: [ | ||
"SwiftIO", | ||
"MadBoards", | ||
// Use specific library name rather than "MadDrivers" would speed up the build procedure. | ||
.product(name: "ST7789", package: "MadDrivers"), | ||
"MadGraphics", | ||
.product(name: "Numerics", package: "swift-numerics"), | ||
]), | ||
] | ||
) |
187 changes: 187 additions & 0 deletions
187
Examples/SwiftIOPlayground/12MoreProjects/SpinningCube/Sources/main.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
import SwiftIO | ||
import MadBoard | ||
import ST7789 | ||
import MadGraphics | ||
import RealModule | ||
|
||
// 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) | ||
|
||
let colors: [Color] = [.red, .orange, .yellow, .lime, .blue, Color(0x4B0082), .purple] | ||
|
||
let canvas = Canvas(width: screen.width, height: screen.height) | ||
var frameBuffer = [UInt16](repeating: 0, count: 240 * 240) | ||
|
||
// The vertices of the cube in 3D space. | ||
let points: [[Float]] = [ | ||
[-0.5, -0.5, -0.5], | ||
[0.5, -0.5, -0.5], | ||
[0.5, 0.5, -0.5], | ||
[-0.5, 0.5, -0.5], | ||
|
||
[-0.5, -0.5, 0.5], | ||
[0.5, -0.5, 0.5], | ||
[0.5, 0.5, 0.5], | ||
[-0.5, 0.5, 0.5] | ||
] | ||
|
||
// The coordinates on 2D plan of cube vertices. | ||
var projectedPoints: [Point] = Array(repeating: Point(x: 0, y: 0), count: points.count) | ||
var lastProjectedPoints = projectedPoints | ||
|
||
var angle: Float = 0 | ||
let width: Float = 200 | ||
let offset = Point(x: 120, y: 120) | ||
|
||
while true { | ||
// Rotate vertices of the cube and project them onto a 2D plane using perspective projection. | ||
for i in points.indices { | ||
let rotated = rotate([[points[i][0]], [points[i][1]], [points[i][2]]], angle: angle) | ||
let projected = project(distance: 2, point: rotated) | ||
projectedPoints[i] = Point(x: Int(projected[0][0] * width), y: Int(projected[1][0] * width)) | ||
} | ||
|
||
// Clear the cube from its last position | ||
for i in 0..<4 { | ||
drawLine( | ||
from: lastProjectedPoints[i], | ||
to: lastProjectedPoints[(i + 1) % 4], | ||
offset: offset, color: Color.black | ||
) | ||
drawLine( | ||
from: lastProjectedPoints[i + 4], | ||
to: lastProjectedPoints[(i + 1) % 4 + 4], | ||
offset: offset, color: Color.black | ||
) | ||
drawLine( | ||
from: lastProjectedPoints[i], | ||
to: lastProjectedPoints[i + 4], | ||
offset: offset, color: Color.black | ||
) | ||
} | ||
|
||
// Draw the cube in its current position. | ||
for i in 0..<4 { | ||
drawLine( | ||
from: projectedPoints[i], | ||
to: projectedPoints[(i + 1) % 4], | ||
offset: offset, color: colors[(3 * i) % colors.count] | ||
) | ||
drawLine( | ||
from: projectedPoints[i + 4], | ||
to: projectedPoints[(i + 1) % 4 + 4], | ||
offset: offset, color: colors[(3 * i + 1) % colors.count] | ||
) | ||
drawLine( | ||
from: projectedPoints[i], | ||
to: projectedPoints[i + 4], | ||
offset: offset, color: colors[(3 * i + 2) % colors.count] | ||
) | ||
} | ||
|
||
updateDisplay(canvas: canvas, frameBuffer: &frameBuffer, screen: screen) | ||
|
||
lastProjectedPoints = projectedPoints | ||
angle += 0.02 | ||
|
||
sleep(ms: 10) | ||
} | ||
|
||
func drawLine(from p0: Point, to p1: Point, offset: Point, color: Color) { | ||
canvas.drawLine( | ||
from: Point(x: p0.x + offset.x, y: p0.y + offset.y), | ||
to: Point(x: p1.x + offset.x, y: p1.y + offset.y), | ||
color: color | ||
) | ||
} | ||
|
||
// Calculate the projection of a point onto a 2D plane using perspective projection. | ||
// `distance` refers to the distance from the viewer. | ||
func project(distance: Float, point: [[Float]]) -> [[Float]] { | ||
let z = 1 / (distance - point[2][0]) | ||
let projectionMatrix: [[Float]] = [ | ||
[z, 0, 0], | ||
[0, z, 0] | ||
] | ||
|
||
return matrixMultiply(projectionMatrix, point) | ||
} | ||
|
||
// Rotate a point around the x, y, and z axes by a given angle. | ||
func rotate(_ point: [[Float]], angle: Float) -> [[Float]] { | ||
var rotated = matrixMultiply(rotateX(angle), point) | ||
rotated = matrixMultiply(rotateY(angle), rotated) | ||
rotated = matrixMultiply(rotateZ(angle), rotated) | ||
return rotated | ||
} | ||
|
||
// Rotate around x-axis. | ||
func rotateX(_ angle: Float) -> [[Float]] { | ||
return [[1, 0, 0], | ||
[0, Float.cos(angle), -Float.sin(angle)], | ||
[0, Float.sin(angle), Float.cos(angle)]] | ||
} | ||
|
||
// Rotate around y-axis. | ||
func rotateY(_ angle: Float) -> [[Float]] { | ||
return [[Float.cos(angle), 0, Float.sin(angle)], | ||
[0, 1, 0], | ||
[-Float.sin(angle), 0, Float.cos(angle)]] | ||
} | ||
|
||
// Rotate around z-axis. | ||
func rotateZ(_ angle: Float) -> [[Float]] { | ||
return [[Float.cos(angle), -Float.sin(angle), 0], | ||
[Float.sin(angle), Float.cos(angle), 0], | ||
[0, 0, 1]] | ||
} | ||
|
||
func matrixMultiply(_ matrix1: [[Float]], _ matrix2: [[Float]]) -> [[Float]] { | ||
// Check if matrices are compatible for multiplication | ||
guard matrix1[0].count == matrix2.count else { | ||
return [[]] | ||
} | ||
|
||
// Initialize result matrix with zeros | ||
var result = Array(repeating: Array(repeating: Float(0), count: matrix2[0].count), count: matrix1.count) | ||
|
||
// Perform matrix multiplication | ||
for i in 0..<matrix1.count { | ||
for j in 0..<matrix2[0].count { | ||
for k in 0..<matrix2.count { | ||
result[i][j] += matrix1[i][k] * matrix2[k][j] | ||
} | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
// Get the region that needs to be updated and send data to the screen. | ||
func updateDisplay(canvas: Canvas, frameBuffer: inout [UInt16], screen: ST7789) { | ||
guard let dirty = canvas.getDirtyRect() else { | ||
return | ||
} | ||
|
||
var index = 0 | ||
let stride = canvas.width | ||
let canvasBuffer = canvas.buffer | ||
for y in dirty.y0..<dirty.y1 { | ||
for x in dirty.x0..<dirty.x1 { | ||
frameBuffer[index] = Color.getRGB565LE(canvasBuffer[y * stride + x]) | ||
index += 1 | ||
} | ||
} | ||
frameBuffer.withUnsafeBytes { ptr in | ||
screen.writeBitmap(x: dirty.x, y: dirty.y, width: dirty.width, height: dirty.height, data: ptr) | ||
} | ||
|
||
canvas.finishRefresh() | ||
} |