summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--requirements.txt4
-rw-r--r--txtgameengine/__init__.py2
-rw-r--r--txtgameengine/__main__.py (renamed from main.py)9
-rw-r--r--txtgameengine/app.py131
-rw-r--r--txtgameengine/platform.py67
5 files changed, 85 insertions, 128 deletions
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/main.py b/txtgameengine/__main__.py
index c33a120..bed2972 100644
--- a/main.py
+++ b/txtgameengine/__main__.py
@@ -1,8 +1,7 @@
import glfw
-from vulkan import *
from glfw.GLFW import *
-from txtgameengine.app import TxtGameApp
+from .app import TxtGameApp
def main():
@@ -12,9 +11,9 @@ def main():
if not window:
glfw.terminate()
return
- extensions = vkEnumerateInstanceExtensionProperties(None)
- print([e.name for e in extensions])
+ glfw.swap_interval(1)
while not glfw.window_should_close(window):
+ glfw.swap_buffers(window)
glfw.poll_events()
glfw.destroy_window(window)
glfw.terminate()
@@ -26,7 +25,7 @@ class TestApp(TxtGameApp):
self.requested_validation_layers += ["VK_LAYER_KHRONOS_validation"]
def update(self, delta: float):
- pass
+ super().update(delta)
if __name__ == '__main__':
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))