summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--main.py35
-rw-r--r--requirements.txt2
-rw-r--r--txtgameengine/app.py142
4 files changed, 183 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e5fe787
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+venv/
+__pycache__/
+.vscode/
+.idea/
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..c33a120
--- /dev/null
+++ b/main.py
@@ -0,0 +1,35 @@
+import glfw
+from vulkan import *
+from glfw.GLFW import *
+
+from txtgameengine.app import TxtGameApp
+
+
+def main():
+ glfw.init()
+ glfw.window_hint(GLFW_CLIENT_API, GLFW_NO_API)
+ window = glfw.create_window(640, 480, "Vulkan window", None, None)
+ if not window:
+ glfw.terminate()
+ return
+ extensions = vkEnumerateInstanceExtensionProperties(None)
+ print([e.name for e in extensions])
+ while not glfw.window_should_close(window):
+ glfw.poll_events()
+ glfw.destroy_window(window)
+ glfw.terminate()
+
+
+class TestApp(TxtGameApp):
+ def __init__(self):
+ super().__init__((640, 480), "Vulkan window")
+ self.requested_validation_layers += ["VK_LAYER_KHRONOS_validation"]
+
+ def update(self, delta: float):
+ pass
+
+
+if __name__ == '__main__':
+ # main()
+ a = TestApp()
+ a.start()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..44c7d1d
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+vulkan
+glfw
diff --git a/txtgameengine/app.py b/txtgameengine/app.py
new file mode 100644
index 0000000..a8c9913
--- /dev/null
+++ b/txtgameengine/app.py
@@ -0,0 +1,142 @@
+import glfw
+from vulkan import *
+import time
+
+
+class PlatformError(Exception):
+ pass
+
+
+class QueueFamilies:
+ graphics_i: int
+ graphics: object
+
+
+class PlatformComponent:
+ def __init__(self, app: 'TxtGameApp'):
+ self.app = app
+
+ def init(self):
+ glfw.init()
+ self.init_vulkan()
+ self.init_window()
+
+ def init_vulkan(self):
+ self.create_instance()
+ self.pick_physical_device()
+ self.create_logical_device()
+
+ def is_device_suitable(self, device):
+ return 1
+
+ def pick_physical_device(self):
+ devices = [(d, self.is_device_suitable(d))
+ for d in vkEnumeratePhysicalDevices(self.instance)]
+ if len(devices) == 0:
+ raise PlatformError("No vulkan devices available.")
+ device, rating = sorted(devices, key=lambda x: x[1])[-1]
+ if rating < 0:
+ raise PlatformError("No suitable devices available.")
+ self.physical_device = device
+ self.find_queue_families()
+
+ def find_queue_families(self):
+ self.queues = QueueFamilies()
+ for i, queue_family in enumerate(vkGetPhysicalDeviceQueueFamilyProperties(self.physical_device)):
+ if queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT:
+ self.queues.graphics_i = i
+
+ def create_logical_device(self):
+ queue_create_info = [VkDeviceQueueCreateInfo(
+ queueFamilyIndex=self.queues.graphics_i,
+ queueCount=1,
+ pQueuePriorities=[1],
+ flags=0,
+ )]
+ device_create = VkDeviceCreateInfo(
+ pQueueCreateInfos=queue_create_info,
+ pEnabledFeatures=vkGetPhysicalDeviceFeatures(self.physical_device),
+ flags=0,
+ ppEnabledLayerNames=self.layers,
+ ppEnabledExtensionNames=[],
+ )
+ self.logical_device = vkCreateDevice(
+ self.physical_device, device_create, None)
+ self.queues.graphic = vkGetDeviceQueue(
+ device=self.logical_device,
+ queueFamilyIndex=self.queues.graphics_i,
+ queueIndex=0,
+ )
+
+ def create_instance(self):
+ app_info = VkApplicationInfo(
+ pApplicationName=self.app.name,
+ applicationVersion=VK_MAKE_VERSION(1, 0, 0),
+ pEngineName="TxtGameEngine",
+ engineVersion=VK_MAKE_VERSION(1, 0, 0),
+ apiVersion=VK_API_VERSION_1_0,
+ )
+ extensions = glfw.get_required_instance_extensions()
+ present_layers = vkEnumerateInstanceLayerProperties()
+ missing_layers = set(self.app.requested_validation_layers) - \
+ set(l.layerName for l in present_layers)
+ if missing_layers:
+ raise PlatformError(
+ "Missing validation layers: "+str(missing_layers))
+ self.layers = self.app.requested_validation_layers
+ createInfo = VkInstanceCreateInfo(
+ pApplicationInfo=app_info,
+ flags=0,
+ enabledExtensionCount=len(extensions),
+ ppEnabledExtensionNames=extensions,
+ enabledLayerCount=len(self.layers),
+ ppEnabledLayerNames=self.layers,
+ )
+ self.instance = vkCreateInstance(createInfo, None)
+
+ def init_window(self):
+ glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
+ glfw.window_hint(glfw.RESIZABLE, glfw.FALSE)
+ self.window = glfw.create_window(
+ *self.app.size, self.app.name, None, None)
+ if not self.window:
+ raise PlatformError("Failed to initialize glfw window")
+
+ @property
+ def should_close(self) -> bool:
+ return glfw.window_should_close(self.window)
+
+ @should_close.setter
+ def should_close(self, val: bool):
+ glfw.set_window_should_close(val)
+
+ def poll_events(self):
+ glfw.poll_events()
+
+ def cleanup(self):
+ vkDestroyDevice(self.logical_device)
+ vkDestroyInstance(self.instance)
+ glfw.destroy_window(window)
+ glfw.terminate()
+
+
+class TxtGameApp:
+ PLATFORM_CLASS = PlatformComponent
+
+ def __init__(self, size: (int, int), name: str):
+ self.size = size
+ self.name = name
+ self.platform: self.PLATFORM_CLASS = self.PLATFORM_CLASS(self)
+ self.requested_validation_layers = []
+
+ def start(self):
+ self.platform.init()
+ last_update_time = time.monotonic()
+ while not self.platform.should_close:
+ update_time = time.monotonic()
+ self.platform.poll_events()
+ self.update(update_time - last_update_time)
+ last_update_time = update_time
+
+ def update(self, delta: float):
+ raise NotImplementedError