I've been working on my game engine, which is for mac on Xcode.
However, I'm a little bit tired of the complex configuration in Xcode. Terminal based projects do not have this problem. I can simply type make to compile my game.
I wonder how to do this. My project is a Swift + Metal project, which is like this:
.
├── ***
│ ├── aabb.swift
│ ├── bvh.swift
│ ├── camera.swift
│ ├── imageProcess.swift
│ ├── interval.swift
│ ├── loadScene.swift
│ ├── quad.swift
│ ├── ray.swift
│ ├── sphere.swift
│ ├── texture.swift
│ ├── triangle.swift
│ └── vec3.swift
├── ***
│ ├── aabb.metal
│ ├── camera.metal
│ ├── color.metal
│ ├── headers
│ │ ├── aabb.metal
│ │ ├── color.metal
│ │ ├── hittable.metal
│ │ ├── interval.metal
│ │ ├── material.metal
│ │ ├── quad.metal
│ │ ├── ray.metal
│ │ ├── sphere.metal
│ │ ├── texture.metal
│ │ ├── triangle.metal
│ │ └── vec3.metal
│ ├── hittable.metal
│ ├── interval.metal
│ ├── material.metal
│ ├── quad.metal
│ ├── ray.metal
│ ├── sphere.metal
│ ├── texture.metal
│ ├── triangle.metal
│ └── vec3.metal
├── main.swift
├── output.ppm
├── resources
...
└── types.h (Swift bridging header, also included in Metal)
13 directories, 69 files
I know how to compile swift (swiftc -c ~.swift -o ~.o) and how to compile Metal (`metal -c ~.metal -o ~.air) but I just don't know how to link them together to a single binary file.
It is a Metal program so I may have to build a metallib file.
This is my main.swift file I wish it could help:
import Foundation
import Metal
var renderSetting = renderSettings()
renderSetting.imageWidth = 1000
renderSetting.imageRatio = 1.0;
renderSetting.VFOV = 90;
renderSetting.defocusAngle = 0;
renderSetting.focusDistance = 10.0;
renderSetting.samplePerPixel = 5;
renderSetting.maxTracingDepth = 2;
renderSetting.lookFrom = createNewVector(3, -5, 3);
renderSetting.lookAt = createNewVector(0, -4.5, 4);
renderSetting.vup = createNewVector(0, 1, 0);
renderSetting.backGroundColor = createNewVector(1, 1, 1);
var objectSet: [object] = []
var objectSetIndex = 0
var imageTextureSet: [UInt8] = []
var imageTextureIndex = 0
loadScene(mapName: "gammaTestingScene", renderSetting: &renderSetting,
objectSet: &objectSet, objectSetIndex: &objectSetIndex,
imageTextureSet: &imageTextureSet, imageTextureIndex: &imageTextureIndex)
initialize(renderSetting: &renderSetting)
var sceneSet: [scene] = []
var sceneIndex: Int32 = 0
_ = buildBVH(objects: objectSet, start: 0, end: Int(renderSetting.objectAmount), sceneSet: &sceneSet, index: &sceneIndex)
let device = MTLCreateSystemDefaultDevice()!
var randomNumbers = (0..<1_000_000).map { _ in Float.random(in: 0..<1) }
var hitRecord: [hitRC] = Array(repeating: hitRC(), count: Int(renderSetting.imageWidth * renderSetting.imageHeight))
var atten: [color] = Array(repeating: color(), count: Int(renderSetting.imageWidth * renderSetting.imageHeight))
var scattered: [ray] = Array(repeating: ray(), count: Int(renderSetting.imageWidth * renderSetting.imageHeight))
var Image: [UInt8] = Array(repeating: UInt8(), count: Int(renderSetting.imageWidth * renderSetting.imageHeight) * 3)
var randomVector: [vec] = Array(repeating: vec(), count: 256)
var permuteX: [Int32] = Array (repeating: Int32(), count: 256)
var permuteY: [Int32] = Array (repeating: Int32(), count: 256)
var permuteZ: [Int32] = Array (repeating: Int32(), count: 256)
var size : Int32 = Int32(sceneSet.count)
var debug: [Float] = Array(repeating: Float(), count: 100)
let library = device.makeDefaultLibrary()!
let function = library.makeFunction(name: "render")!
var computePipelineState: MTLComputePipelineState
do {
computePipelineState = try device.makeComputePipelineState(function: function)
} catch {
fatalError("无法创建 computePipelineState: \(error)")
}
let commandQueue = device.makeCommandQueue()!
let commandBuffer = commandQueue.makeCommandBuffer()!
let computeEncoder = commandBuffer.makeComputeCommandEncoder()!
computeEncoder.setComputePipelineState(computePipelineState)
var randomNumbersBuffer = device.makeBuffer(bytes: randomNumbers,
length: randomNumbers.count * MemoryLayout<Float>.stride,
options: .storageModeShared)!
var randomIndexBuffer = device.makeBuffer(length: MemoryLayout<UInt32>.stride,
options: .storageModeShared)!
var randomIndex = randomIndexBuffer.contents().bindMemory(to: UInt32.self, capacity: 1)
randomIndex.pointee = 0
var hitRecordBuffer = device.makeBuffer(bytes: hitRecord,
length: hitRecord.count * MemoryLayout<hitRC>.stride,
options: .storageModeShared)!
var sceneSetBuffer = device.makeBuffer(bytes: sceneSet,
length: sceneSet.count * MemoryLayout<scene>.stride,
options: .storageModeShared)!
var attenBuffer = device.makeBuffer(bytes: atten,
length: atten.count * MemoryLayout<color>.stride,
options: .storageModeShared)!
var scatteredBuffer = device.makeBuffer(bytes: scattered,
length: scattered.count * MemoryLayout<ray>.stride,
options: .storageModeShared)!
var renderSettingBuffer = device.makeBuffer(bytes: &renderSetting, length: MemoryLayout<renderSettings>.stride, options: .storageModeShared)!
var ImageBuffer = device.makeBuffer(bytes: Image,
length: Int(renderSetting.imageWidth * renderSetting.imageHeight) * 3 * MemoryLayout<UInt8>.stride,
options: .storageModeShared)!
var imageTextureSetBuffer = device.makeBuffer(bytes: imageTextureSet,
length: imageTextureSet.count * MemoryLayout<UInt8>.stride,
options: .storageModeShared)!
var randomVectorBuffer = device.makeBuffer(bytes: randomVector,
length: 256 * MemoryLayout<vec>.stride,
options: .storageModeShared)!
var permuteXBuffer = device.makeBuffer(bytes: permuteX,
length: 256 * MemoryLayout<Int32>.stride,
options: .storageModeShared)!
var permuteYBuffer = device.makeBuffer(bytes: permuteY,
length: 256 * MemoryLayout<Int32>.stride,
options: .storageModeShared)!
var permuteZBuffer = device.makeBuffer(bytes: permuteZ,
length: 256 * MemoryLayout<Int32>.stride,
options: .storageModeShared)!
var sizeBuffer = device.makeBuffer(bytes: &size, length: MemoryLayout<Int32>.stride, options: .storageModeShared)!
var debugBuffer = device.makeBuffer(bytes: debug,
length: 100 * MemoryLayout<Float>.stride,
options: .storageModeShared)!
computeEncoder.setBuffer(randomIndexBuffer, offset: 0, index: 0)
computeEncoder.setBuffer(randomNumbersBuffer, offset: 0, index: 1)
computeEncoder.setBuffer(hitRecordBuffer, offset: 0, index: 2)
computeEncoder.setBuffer(sceneSetBuffer, offset: 0, index: 3)
computeEncoder.setBuffer(renderSettingBuffer, offset: 0, index: 4)
computeEncoder.setBuffer(attenBuffer, offset: 0, index: 5)
computeEncoder.setBuffer(scatteredBuffer, offset: 0, index: 6)
computeEncoder.setBuffer(randomVectorBuffer, offset: 0, index: 7)
computeEncoder.setBuffer(permuteXBuffer, offset: 0, index: 8)
computeEncoder.setBuffer(permuteYBuffer, offset: 0, index: 9)
computeEncoder.setBuffer(permuteZBuffer, offset: 0, index: 10)
computeEncoder.setBuffer(ImageBuffer, offset: 0, index: 11)
computeEncoder.setBuffer(imageTextureSetBuffer, offset: 0, index: 12)
computeEncoder.setBuffer(sizeBuffer, offset: 0, index: 13)
computeEncoder.setBuffer(debugBuffer, offset: 0, index: 14)
var threadGroupSize = MTLSize(width: 16, height: 16, depth: 1)
var gridSize = MTLSize(width: Int(renderSetting.imageWidth), height: Int(renderSetting.imageHeight), depth: 1)
let startTime = CFAbsoluteTimeGetCurrent()
computeEncoder.dispatchThreads(gridSize, threadsPerThreadgroup: threadGroupSize)
computeEncoder.endEncoding()
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
let endTime = CFAbsoluteTimeGetCurrent()
let gpuTime = endTime - startTime
print ("渲染时间:\(gpuTime)s")
var finalImageData = ImageBuffer.contents()
var resultPointer = finalImageData.assumingMemoryBound(to: UInt8.self)
var debugData = debugBuffer.contents()
var debugPointer = debugData.assumingMemoryBound(to: Float.self)
for i in 0..<5 {
print ("debug槽\(i): \((debugPointer+i).pointee)")
}
var imageWidth = renderSetting.imageWidth
var imageHeight = renderSetting.imageHeight
var totalPixels = imageWidth * imageHeight
var fileURL = URL(fileURLWithPath: "/Users/LimeEcho/Documents/DieInTheLight/DieInTheLight/output.ppm")
do {
var outputString = "P3\n\(imageWidth) \(imageHeight)\n255\n"
for i in 0..<totalPixels {
let r = (resultPointer + Int(i) * 3).pointee
let g = (resultPointer + Int(i * 3 + 1)).pointee
let b = (resultPointer + Int(i * 3 + 2)).pointee
outputString += "\(r) \(g) \(b)\n"
}
try outputString.write(to: fileURL, atomically: true, encoding: .utf8)
print ("数据已成功写入: \(fileURL.path)")
} catch {
print ("写入文件失败: \(error)")
}
Can you tell me how to write the makefile or just how to compile them and link to a single file?