summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--txtgameengine/__main__.py9
-rw-r--r--txtgameengine/app.py2
-rw-r--r--txtgameengine/platform.py10
-rw-r--r--txtgameengine/shaders/__init__.py2
-rw-r--r--txtgameengine/shaders/integrated.py16
-rw-r--r--txtgameengine/shaders/shader.py50
6 files changed, 81 insertions, 8 deletions
diff --git a/txtgameengine/__main__.py b/txtgameengine/__main__.py
index 1ebc309..9aeeec3 100644
--- a/txtgameengine/__main__.py
+++ b/txtgameengine/__main__.py
@@ -2,8 +2,8 @@ import numpy as np
from PIL import Image
from .scenes import SceneTxtGameApp, Scene
-from OpenGL.GL import *
from pathlib import Path
+from .shaders import TextureShader
shader_path = Path(__file__).parent / 'builtin_shaders'
@@ -46,9 +46,7 @@ class EvilTriangleScene(TriangleScene):
class TextureScene(Scene):
def on_enter(self):
- self.texture_shaders = self.app.shaders.load_shaders(str(shader_path / 'texture/vertex.glsl'),
- str(shader_path / 'texture/fragment.glsl'))
- self.sampler_location = self.app.shaders.get_uniform_location(self.texture_shaders, 'textureSampler')
+ self.texture_shaders = TextureShader(self.app)
self.texture = self.app.render.setup_texture_from_pil(Image.open('test_image.png'))
self.triangle = self.app.render.setup_buffer(
np.array([
@@ -65,7 +63,8 @@ class TextureScene(Scene):
def update(self, delta: float):
with self.texture_shaders:
- self.app.render.textured_triangle(self.sampler_location, self.texture, self.triangle, self.uvs)
+ self.app.render.textured_triangle(self.texture_shaders.textureSampler, self.texture, self.triangle,
+ self.uvs)
class TestApp(SceneTxtGameApp):
diff --git a/txtgameengine/app.py b/txtgameengine/app.py
index f3cb711..e7121da 100644
--- a/txtgameengine/app.py
+++ b/txtgameengine/app.py
@@ -1,8 +1,10 @@
import time
+from pathlib import Path
from .platform import PlatformComponent, RenderComponent, ShaderComponent
EPSILON = 1.e-10
+base_path = Path(__file__).parent
class TxtGameApp:
diff --git a/txtgameengine/platform.py b/txtgameengine/platform.py
index 17d85ab..f4b3b5b 100644
--- a/txtgameengine/platform.py
+++ b/txtgameengine/platform.py
@@ -90,7 +90,7 @@ class ShaderComponent:
self.app = app
@staticmethod
- def load_shaders(vertex_file, fragment_file):
+ def load_shaders(vertex_file: str, fragment_file: str):
with open(vertex_file) as fp:
vertex_source = fp.read()
with open(fragment_file) as fp:
@@ -101,8 +101,12 @@ class ShaderComponent:
return shaders.compileProgram(vertex_shader, fragment_shader)
@staticmethod
- def get_uniform_location(shader, name):
- return glGetUniformLocation(shader, name)
+ def bind_shader(prog_id: int):
+ glUseProgram(prog_id)
+
+ @staticmethod
+ def get_uniform_location(prog_id: int, name: str):
+ return glGetUniformLocation(prog_id, name)
class RenderComponent:
diff --git a/txtgameengine/shaders/__init__.py b/txtgameengine/shaders/__init__.py
new file mode 100644
index 0000000..64b0cc8
--- /dev/null
+++ b/txtgameengine/shaders/__init__.py
@@ -0,0 +1,2 @@
+from .shader import Shader
+from .integrated import TextureShader, BasicShader
diff --git a/txtgameengine/shaders/integrated.py b/txtgameengine/shaders/integrated.py
new file mode 100644
index 0000000..dfa1033
--- /dev/null
+++ b/txtgameengine/shaders/integrated.py
@@ -0,0 +1,16 @@
+from .shader import Shader
+from ..app import base_path
+
+shader_base_path = base_path / 'builtin_shaders'
+
+
+class BasicShader(Shader):
+ UNIFORMS = dict()
+ VERTEX_PATH = shader_base_path / 'basic/vertex.glsl'
+ FRAGMENT_PATH = shader_base_path / 'basic/fragment.glsl'
+
+
+class TextureShader(Shader):
+ UNIFORMS = dict(textureSampler="textureSampler")
+ VERTEX_PATH = shader_base_path / 'texture/vertex.glsl'
+ FRAGMENT_PATH = shader_base_path / 'texture/fragment.glsl'
diff --git a/txtgameengine/shaders/shader.py b/txtgameengine/shaders/shader.py
new file mode 100644
index 0000000..61b6aaf
--- /dev/null
+++ b/txtgameengine/shaders/shader.py
@@ -0,0 +1,50 @@
+import typing
+
+if typing.TYPE_CHECKING:
+ from ..app import TxtGameApp
+
+
+class Shader:
+ """Wrapper class for a GL program"""
+
+ UNIFORMS: typing.Dict[str, str] = dict()
+ VERTEX_PATH: str
+ FRAGMENT_PATH: str
+
+ def __init__(self, app: 'TxtGameApp'):
+ self.app = app
+ self._prog_id = self.app.shaders.load_shaders(self.VERTEX_PATH, self.FRAGMENT_PATH)
+ self._is_bound = 0
+ self.uniform_locations = {}
+ self._fill_uniforms()
+
+ def _fill_uniforms(self):
+ with self:
+ for prop_name, shader_name in self.UNIFORMS.items():
+ self.uniform_locations[prop_name] = \
+ self.app.shaders.get_uniform_location(self._prog_id, shader_name)
+
+ def __getattr__(self, item):
+ if item in self.uniform_locations:
+ return self.uniform_locations[item]
+ raise AttributeError("Shader '%s' has no attribute or uniform named %s" % (type(self).__name__, item))
+
+ def _require_bound(self, required=False):
+ assert self._is_bound > 0 or not required
+ return self
+
+ def get_uniform_location(self, name: str):
+ return self.uniform_locations[name]
+
+ def __enter__(self):
+ self._is_bound += 1
+ if self._is_bound == 1:
+ self.app.shaders.bind_shader(self._prog_id)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self._is_bound -= 1
+ if self._is_bound == 0:
+ self.app.shaders.bind_shader(0)
+
+ def __repr__(self):
+ return '<Shader prog_id=%d uniforms=%r>' % (self._prog_id, self.uniform_locations)