From a165c0da2484776124bf895a810076c8acf94368 Mon Sep 17 00:00:00 2001 From: rom Date: Wed, 21 Apr 2021 20:00:04 +0200 Subject: swap to open gl xd --- main.py | 35 ------------- requirements.txt | 4 +- txtgameengine/__init__.py | 2 + txtgameengine/__main__.py | 34 ++++++++++++ txtgameengine/app.py | 131 ++++------------------------------------------ txtgameengine/platform.py | 67 ++++++++++++++++++++++++ 6 files changed, 115 insertions(+), 158 deletions(-) delete mode 100644 main.py create mode 100644 txtgameengine/__init__.py create mode 100644 txtgameengine/__main__.py create mode 100644 txtgameengine/platform.py diff --git a/main.py b/main.py deleted file mode 100644 index c33a120..0000000 --- a/main.py +++ /dev/null @@ -1,35 +0,0 @@ -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 index 44c7d1d..beb7232 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -vulkan -glfw +glfw~=2.1.0 +pyopengl~=3.1.5 diff --git a/txtgameengine/__init__.py b/txtgameengine/__init__.py new file mode 100644 index 0000000..ac608af --- /dev/null +++ b/txtgameengine/__init__.py @@ -0,0 +1,2 @@ +from .app import TxtGameApp +from .platform import PlatformComponent, PlatformError diff --git a/txtgameengine/__main__.py b/txtgameengine/__main__.py new file mode 100644 index 0000000..bed2972 --- /dev/null +++ b/txtgameengine/__main__.py @@ -0,0 +1,34 @@ +import glfw +from glfw.GLFW import * + +from .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 + glfw.swap_interval(1) + while not glfw.window_should_close(window): + glfw.swap_buffers(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): + super().update(delta) + + +if __name__ == '__main__': + # main() + a = TestApp() + a.start() diff --git a/txtgameengine/app.py b/txtgameengine/app.py index a8c9913..e651078 100644 --- a/txtgameengine/app.py +++ b/txtgameengine/app.py @@ -1,123 +1,8 @@ -import glfw -from vulkan import * import time +from .platform import PlatformComponent -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() +EPSILON = 1.e-10 class TxtGameApp: @@ -126,17 +11,21 @@ class TxtGameApp: def __init__(self, size: (int, int), name: str): self.size = size self.name = name - self.platform: self.PLATFORM_CLASS = self.PLATFORM_CLASS(self) + self.platform = self.PLATFORM_CLASS(self) self.requested_validation_layers = [] def start(self): self.platform.init() - last_update_time = time.monotonic() + self.platform.set_clear_color(1, 0, 0.75, 1) + last_update_time = self.platform.monotonic_time() while not self.platform.should_close: - update_time = time.monotonic() + update_time = self.platform.monotonic_time() self.platform.poll_events() self.update(update_time - last_update_time) + self.platform.swap_buffers() last_update_time = update_time + self.platform.cleanup() def update(self, delta: float): - raise NotImplementedError + print("Running: delta = %.4fs, approx. fps = %ds" % (delta, 1. / (delta or EPSILON))) + self.platform.clear_background() diff --git a/txtgameengine/platform.py b/txtgameengine/platform.py new file mode 100644 index 0000000..0d89213 --- /dev/null +++ b/txtgameengine/platform.py @@ -0,0 +1,67 @@ +import glfw +import typing + +from OpenGL import GL + +if typing.TYPE_CHECKING: + from .app import TxtGameApp + + +class PlatformError(Exception): + pass + + +class PlatformComponent: + def __init__(self, app: 'TxtGameApp'): + self.app = app + self.window = None + + def init(self): + glfw.init() + self.init_window() + glfw.make_context_current(self.window) + + @staticmethod + def monotonic_time(): + return glfw.get_time() + + @staticmethod + def enable_vsync(): + glfw.swap_interval(1) + + def init_window(self): + glfw.window_hint(glfw.CLIENT_API, glfw.OPENGL_API) + glfw.window_hint(glfw.RESIZABLE, glfw.FALSE) + glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) + glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) + 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) + + @staticmethod + def poll_events(): + glfw.poll_events() + + def cleanup(self): + glfw.destroy_window(self.window) + glfw.terminate() + + def swap_buffers(self): + glfw.swap_buffers(self.window) + + @staticmethod + def set_clear_color(r, g, b, a): + GL.glClearColor(r, g, b, a) + + @staticmethod + def clear_background(depth_buffer=False): + GL.glClear(GL.GL_COLOR_BUFFER_BIT | (depth_buffer and GL.GL_DEPTH_BUFFER_BIT or 0)) -- cgit