Skip to content

Commit

Permalink
Added multithreaded rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Mar 9, 2020
1 parent 04ab7ac commit 0502a4c
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 17 deletions.
4 changes: 4 additions & 0 deletions Source/Rampage.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
01D0F5D922F80E1600682CA1 /* RampageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D0F5D822F80E1600682CA1 /* RampageTests.swift */; };
01D0F5F122FF095E00682CA1 /* Door.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D0F5F022FF095E00682CA1 /* Door.swift */; };
01E3963A2342758D00D02236 /* Pushwall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E396392342758D00D02236 /* Pushwall.swift */; };
01D0F5EF22FDF19A00682CA1 /* Bitmap+Rendering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D0F5EE22FDF19900682CA1 /* Bitmap+Rendering.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -174,6 +175,7 @@
01D0F5DA22F80E1600682CA1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
01D0F5F022FF095E00682CA1 /* Door.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Door.swift; sourceTree = "<group>"; };
01E396392342758D00D02236 /* Pushwall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pushwall.swift; sourceTree = "<group>"; };
01D0F5EE22FDF19900682CA1 /* Bitmap+Rendering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bitmap+Rendering.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -256,6 +258,7 @@
children = (
016E41B2228E9A5B00ACF137 /* AppDelegate.swift */,
016E41B4228E9A5B00ACF137 /* ViewController.swift */,
01D0F5EE22FDF19900682CA1 /* Bitmap+Rendering.swift */,
01D09AF422A482450052745A /* UIImage+Bitmap.swift */,
0199F57323E242D4003E3F08 /* SoundManager.swift */,
016E41B6228E9A5B00ACF137 /* Main.storyboard */,
Expand Down Expand Up @@ -544,6 +547,7 @@
files = (
01D09AF522A482450052745A /* UIImage+Bitmap.swift in Sources */,
0199F57423E242D4003E3F08 /* SoundManager.swift in Sources */,
01D0F5EF22FDF19A00682CA1 /* Bitmap+Rendering.swift in Sources */,
016E41B5228E9A5B00ACF137 /* ViewController.swift in Sources */,
016E41B3228E9A5B00ACF137 /* AppDelegate.swift in Sources */,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
Expand Down
33 changes: 33 additions & 0 deletions Source/Rampage/Bitmap+Rendering.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// ConcurrentRenderer.swift
// Rampage
//
// Created by Nick Lockwood on 09/08/2019.
// Copyright © 2019 Nick Lockwood. All rights reserved.
//

import UIKit
import Engine
import Renderer

public extension Bitmap {
init(width: Int, height: Int, world: World, textures: Textures) {
let cpuCores = ProcessInfo.processInfo.activeProcessorCount
var buffers = Array(repeating: [Color](), count: cpuCores)
let step = 1.0 / Double(cpuCores)
DispatchQueue.concurrentPerform(iterations: cpuCores) { i in
let offset = Double(i) * step
let range = offset ..< offset + step
var renderer = Renderer(
width: width,
height: height,
range: range,
textures: textures
)
renderer.draw(world)
buffers[i] = renderer.bitmap.pixels
}
let pixels = Array(buffers.joined())
self.init(height: height, pixels: pixels)
}
}
6 changes: 2 additions & 4 deletions Source/Rampage/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ class ViewController: UIViewController {
lastFrameTime = displayLink.timestamp

let width = Int(imageView.bounds.width), height = Int(imageView.bounds.height)
var renderer = Renderer(width: width, height: height, textures: textures)
renderer.draw(world)

imageView.image = UIImage(bitmap: renderer.bitmap)
let bitmap = Bitmap(width: width, height: height, world: world, textures: textures)
imageView.image = UIImage(bitmap: bitmap)
}

@objc func fire(_ gestureRecognizer: UITapGestureRecognizer) {
Expand Down
3 changes: 1 addition & 2 deletions Source/RampageTests/RampageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ class RampageTests: XCTestCase {

func testRenderFrame() {
self.measure {
var renderer = Renderer(width: 1000, height: 1000, textures: textures)
renderer.draw(world)
_ = Bitmap(width: 1000, height: 1000, world: world, textures: textures)
}
}
}
4 changes: 2 additions & 2 deletions Source/Renderer/Bitmap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ public extension Bitmap {
}

mutating func drawImage(_ source: Bitmap, at point: Vector, size: Vector) {
let start = Int(point.x), end = Int(point.x + size.x)
let start = max(0, Int(point.x)), end = Int(point.x + size.x)
let stepX = Double(source.width) / size.x
for x in max(0, start) ..< min(width, end) {
for x in start ..< max(start, min(width, end)) {
let sourceX = (Double(x) - point.x) * stepX
let outputPosition = Vector(x: Double(x), y: point.y)
drawColumn(Int(sourceX), of: source, at: outputPosition, height: size.y)
Expand Down
20 changes: 12 additions & 8 deletions Source/Renderer/Renderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,31 @@ private let fizzle = (0 ..< 10000).shuffled()

public struct Renderer {
public private(set) var bitmap: Bitmap
private let width: Int
private let range: Range<Double>
private let textures: Textures

public init(width: Int, height: Int, textures: Textures) {
self.bitmap = Bitmap(width: width, height: height, color: .black)
public init(width: Int, height: Int, range: Range<Double>, textures: Textures) {
self.width = width
self.range = range
let columns = Int(Double(width) * (range.upperBound - range.lowerBound))
self.bitmap = Bitmap(width: columns, height: height, color: .clear)
self.textures = textures
}
}

public extension Renderer {
mutating func draw(_ world: World) {
let focalLength = 1.0
let viewWidth = Double(bitmap.width) / Double(bitmap.height)
let viewWidth = Double(width) / Double(bitmap.height)
let viewPlane = world.player.direction.orthogonal * viewWidth
let viewCenter = world.player.position + world.player.direction * focalLength
let viewStart = viewCenter - viewPlane / 2
let viewStart = viewCenter - viewPlane * (0.5 - range.lowerBound)

// Cast rays
let columns = bitmap.width
let step = viewPlane / Double(columns)
let step = viewPlane / Double(width)
var columnPosition = viewStart
for x in 0 ..< columns {
for x in 0 ..< bitmap.width {
let rayDirection = columnPosition - world.player.position
let viewPlaneDistance = rayDirection.length
let ray = Ray(
Expand Down Expand Up @@ -130,7 +134,7 @@ public extension Renderer {
let weaponWidth = screenHeight * aspectRatio
bitmap.drawImage(
weaponTexture,
at: Vector(x: Double(bitmap.width) / 2 - weaponWidth / 2, y: 0),
at: Vector(x: Double(width) * (0.5 - range.lowerBound) - weaponWidth / 2, y: 0),
size: Vector(x: weaponWidth, y: screenHeight)
)

Expand Down

0 comments on commit 0502a4c

Please sign in to comment.