我可以在没有Xcode的情况下编写Apple Metal图形吗?

时间:2018-10-25 20:15:39

标签: swift metal

是否可以仅使用编辑器和终端来编写Metal图形程序?如果是这样,那么最小应用程序的例子将是什么?

我想尝试一些生成式编码,但是没有Xcode。我能够使用OpenGL制作小型C或Python程序,但Apple弃用了它,使我考虑使用Metal。

我可以使用Swift和一些标头包含的内容吗?还是我需要更多吗?

2 个答案:

答案 0 :(得分:2)

您可以从命令行编译和运行使用Metal的应用程序,而根本没有Xcode项目,但是您仍然需要Xcode提供的基础结构(SDK和工具链),因此需要安装它。 / p>

在Swift中编写一个简单的应用程序非常简单,该应用程序创建必要的Metal对象,对一些工作进行编码,然后将结果写入文件。出于这个问题的目的,我将提供一个简单的Cocoa应用程序的源代码,该应用程序将通过创建一个承载MetalKit视图并绘制到该窗口的窗口来进一步介绍。有了这个脚手架,您就可以编写一个非常复杂的应用程序,而无需启动Xcode。

import Foundation
import Cocoa
import Metal
import MetalKit

class AppDelegate : NSObject, NSApplicationDelegate {
    let window = NSWindow()
    let windowDelegate = WindowDelegate()
    var rootViewController: NSViewController?

    func applicationDidFinishLaunching(_ notification: Notification) {
        window.setContentSize(NSSize(width: 800, height: 600))
        window.styleMask = [ .titled, .closable, .miniaturizable, .resizable ]
        window.title = "Window"
        window.level = .normal
        window.delegate = windowDelegate
        window.center()

        let view = window.contentView!
        rootViewController = ViewController(nibName: nil, bundle: nil)
        rootViewController!.view.frame = view.bounds
        view.addSubview(rootViewController!.view)

        window.makeKeyAndOrderFront(window)

        NSApp.activate(ignoringOtherApps: true)
    }
}

class WindowDelegate : NSObject, NSWindowDelegate {
    func windowWillClose(_ notification: Notification) {
        NSApp.terminate(self)
    }
}

class ViewController : NSViewController, MTKViewDelegate {
    var device: MTLDevice!
    var commandQueue: MTLCommandQueue!

    override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override func loadView() {
        device = MTLCreateSystemDefaultDevice()!
        commandQueue = device.makeCommandQueue()!

        let metalView = MTKView(frame: .zero, device: device)
        metalView.clearColor = MTLClearColorMake(0, 0, 1, 1)
        metalView.delegate = self

        self.view = metalView
    }

    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    }

    func draw(in view: MTKView) {
        guard let commandBuffer = commandQueue.makeCommandBuffer(),
              let passDescriptor = view.currentRenderPassDescriptor else { return }
        if let commandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: passDescriptor) {
            // set state, issue draw calls, etc.
            commandEncoder.endEncoding()
        }
        commandBuffer.present(view.currentDrawable!)
        commandBuffer.commit()
    }
}

func makeMainMenu() -> NSMenu {
    let mainMenu = NSMenu()
    let mainAppMenuItem = NSMenuItem(title: "Application", action: nil, keyEquivalent: "")
    let mainFileMenuItem = NSMenuItem(title: "File", action: nil, keyEquivalent: "")
    mainMenu.addItem(mainAppMenuItem)
    mainMenu.addItem(mainFileMenuItem)

    let appMenu = NSMenu()
    mainAppMenuItem.submenu = appMenu

    let appServicesMenu = NSMenu()
    NSApp.servicesMenu = appServicesMenu

    appMenu.addItem(withTitle: "Hide", action: #selector(NSApplication.hide(_:)), keyEquivalent: "h")
    appMenu.addItem({ () -> NSMenuItem in
        let m = NSMenuItem(title: "Hide Others", action: #selector(NSApplication.hideOtherApplications(_:)), keyEquivalent: "h")
        m.keyEquivalentModifierMask = [.command, .option]
        return m
    }())
    appMenu.addItem(withTitle: "Show All", action: #selector(NSApplication.unhideAllApplications(_:)), keyEquivalent: "")

    appMenu.addItem(NSMenuItem.separator())
    appMenu.addItem(withTitle: "Services", action: nil, keyEquivalent: "").submenu = appServicesMenu
    appMenu.addItem(NSMenuItem.separator())
    appMenu.addItem(withTitle: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")

    let fileMenu = NSMenu(title: "Window")
    mainFileMenuItem.submenu = fileMenu
    fileMenu.addItem(withTitle: "Close", action: #selector(NSWindowController.close), keyEquivalent: "w")

    return mainMenu
}

let app = NSApplication.shared
NSApp.setActivationPolicy(.regular)

NSApp.mainMenu = makeMainMenu()

let appDelegate = AppDelegate()
NSApp.delegate = appDelegate

NSApp.run()

尽管这看起来像很多代码,但其中大部分是可可模板,用于创建窗口及其主菜单并与之交互。金属代码仅在中间隐藏了几行(请参见func draw)。

要构建和运行此应用,请将代码保存到Swift文件(我称为MinalMetal.swift),然后使用xcrun找到构建所需的工具和SDK:

xcrun -sdk macosx swiftc MinimalMetal.swift -o MinimalMetal

这将在同一目录中创建一个名为“ MinimalMetal”的可执行文件,您可以使用该可执行文件运行

./MinimalMetal 

这是一款功能完善的应用程序,具有窗口,菜单,运行循环和60 FPS绘图。从这里,您可以使用您可能想要的Metal的所有功能。

答案 1 :(得分:0)

您可以使用python,请尝试以下操作: https://github.com/wtnb75/runmetal您可以将金属内核编译为字符串并将其与numpy数组链接