From f5a2839fcfedd31aba7c0b224112007f3e386787 Mon Sep 17 00:00:00 2001
From: Quantum <quantum2048@gmail.com>
Date: Tue, 28 Aug 2018 19:41:03 -0400
Subject: [PATCH] Turn the circle thing to use shaders.

It's for tiny things like that that immediate mode is useful.
---
 punyverse/glgeom.py                  | 112 ++++-----------------------
 punyverse/loader.py                  |  61 ++++++++++++++-
 punyverse/shader.py                  |   3 +
 punyverse/shaders/line.fragment.glsl |   8 ++
 punyverse/shaders/line.vertex.glsl   |   8 ++
 punyverse/ui.py                      |  23 ++++--
 punyverse/world.py                   |   1 +
 7 files changed, 110 insertions(+), 106 deletions(-)
 create mode 100644 punyverse/shaders/line.fragment.glsl
 create mode 100644 punyverse/shaders/line.vertex.glsl

diff --git a/punyverse/glgeom.py b/punyverse/glgeom.py
index c6c968a..2193f15 100644
--- a/punyverse/glgeom.py
+++ b/punyverse/glgeom.py
@@ -11,32 +11,8 @@ from six.moves import range
 
 TWOPI = pi * 2
 
-__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'belt',
-           'glSection', 'glRestore', 'glContext', 'progress_bar',
-           'FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO', 'SimpleSphere', 'TangentSphere', 'Cube']
-
-
-class glContext(object):
-    def __init__(self, context):
-        self.new_context = context
-
-    def __enter__(self):
-        self.old_context = get_current_context()
-        self.new_context.set_current()
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.old_context.set_current()
-
-
-class glSection(object):
-    def __init__(self, type):
-        self.type = type
-
-    def __enter__(self):
-        glBegin(self.type)
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        glEnd()
+__all__ = ['compile', 'belt', 'glRestore', 'FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO',
+           'SimpleSphere', 'TangentSphere', 'Cube', 'Circle']
 
 
 class glRestore(object):
@@ -143,42 +119,20 @@ def compile(pointer, *args, **kwargs):
     return display
 
 
-def ortho(width, height):
-    glDisable(GL_LIGHTING)
-    glDisable(GL_DEPTH_TEST)
-    glMatrixMode(GL_PROJECTION)
-    glPushMatrix()
-    glLoadIdentity()
-    glOrtho(0, width, 0, height, -1, 1)
-    glMatrixMode(GL_MODELVIEW)
-    glPushMatrix()
-    glLoadIdentity()
+class Circle(object):
+    type = GL_FLOAT
+    stride = 2 * 4
+    position_offset = 0
+    position_size = 2
 
-
-def frustrum():
-    glMatrixMode(GL_PROJECTION)
-    glPopMatrix()
-    glMatrixMode(GL_MODELVIEW)
-    glPopMatrix()
-    glEnable(GL_LIGHTING)
-    glEnable(GL_DEPTH_TEST)
-
-
-def crosshair(size, coords):
-    cx, cy = coords
-    with glSection(GL_LINES):
-        glVertex2f(cx - size, cy)
-        glVertex2f(cx + size, cy)
-        glVertex2f(cx, cy - size)
-        glVertex2f(cx, cy + size)
-
-
-def circle(r, seg, coords):
-    cx, cy = coords
-    with glSection(GL_LINE_LOOP):
-        for i in range(seg):
-            theta = TWOPI * i / seg
-            glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r)
+    def __init__(self, r, segs):
+        self.vertex_count = segs
+        buffer = segs * 2 * [0]
+        delta = 2 * pi / segs
+        for i in range(segs):
+            theta = delta * i
+            buffer[2*i:2*i+2] = [cos(theta) * r, sin(theta) * r]
+        self.vbo = array_to_gl_buffer(buffer)
 
 
 class Disk(object):
@@ -384,39 +338,3 @@ def belt(radius, cross, object, count):
         glScalef(scale, scale, scale)
         choice(object).draw()
         glPopMatrix()
-
-
-def progress_bar(x, y, width, height, filled):
-    with glRestore(GL_ENABLE_BIT):
-        glDisable(GL_TEXTURE_2D)
-        glDisable(GL_BLEND)
-        x1 = x
-        x2 = x + width
-        y1 = y
-        y2 = y - height
-        y3 = 0.65 * y1 + 0.35 * y2
-        y4 = 0.25 * y1 + 0.75 * y2
-
-        glColor3f(0.6, 0.6, 0.6)
-        with glSection(GL_LINE_LOOP):
-            glVertex2f(x1, y1)
-            glVertex2f(x1, y2)
-            glVertex2f(x2, y2)
-            glVertex2f(x2, y1)
-
-        x1 += 1
-        y1 -= 1
-        x2 = x + width * filled - 1
-
-        with glSection(GL_TRIANGLE_STRIP):
-            glColor3f(0.81, 1, 0.82)
-            glVertex2f(x1, y1)
-            glVertex2f(x2, y1)
-            glColor3f(0, 0.83, 0.16)
-            glVertex2f(x1, y3)
-            glVertex2f(x2, y3)
-            glVertex2f(x1, y4)
-            glVertex2f(x2, y4)
-            glColor3f(0.37, 0.92, 0.43)
-            glVertex2f(x1, y2)
-            glVertex2f(x2, y2)
diff --git a/punyverse/loader.py b/punyverse/loader.py
index fd31b55..4c6d7fd 100644
--- a/punyverse/loader.py
+++ b/punyverse/loader.py
@@ -8,10 +8,69 @@ import pyglet
 from pyglet.gl import *
 from six.moves import zip_longest
 
-from punyverse.glgeom import glContext, progress_bar
+from punyverse.glgeom import glRestore
 from punyverse.world import World
 
 
+class glContext(object):
+    def __init__(self, context):
+        self.new_context = context
+
+    def __enter__(self):
+        self.old_context = get_current_context()
+        self.new_context.set_current()
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.old_context.set_current()
+
+
+class glSection(object):
+    def __init__(self, type):
+        self.type = type
+
+    def __enter__(self):
+        glBegin(self.type)
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        glEnd()
+
+
+def progress_bar(x, y, width, height, filled):
+    with glRestore(GL_ENABLE_BIT):
+        glDisable(GL_TEXTURE_2D)
+        glDisable(GL_BLEND)
+        x1 = x
+        x2 = x + width
+        y1 = y
+        y2 = y - height
+        y3 = 0.65 * y1 + 0.35 * y2
+        y4 = 0.25 * y1 + 0.75 * y2
+
+        glColor3f(0.6, 0.6, 0.6)
+        with glSection(GL_LINE_LOOP):
+            glVertex2f(x1, y1)
+            glVertex2f(x1, y2)
+            glVertex2f(x2, y2)
+            glVertex2f(x2, y1)
+
+        x1 += 1
+        y1 -= 1
+        x2 = x + width * filled - 1
+
+        with glSection(GL_TRIANGLE_STRIP):
+            glColor3f(0.81, 1, 0.82)
+            glVertex2f(x1, y1)
+            glVertex2f(x2, y1)
+            glColor3f(0, 0.83, 0.16)
+            glVertex2f(x1, y3)
+            glVertex2f(x2, y3)
+            glVertex2f(x1, y4)
+            glVertex2f(x2, y4)
+            glColor3f(0.37, 0.92, 0.43)
+            glVertex2f(x1, y2)
+            glVertex2f(x2, y2)
+
+
 def get_context_info(context):
     info = ['  %-22s %s' % (key + ':', value)
             for key, value in context.config.get_gl_attributes()]
diff --git a/punyverse/shader.py b/punyverse/shader.py
index 835571f..5f10d41 100644
--- a/punyverse/shader.py
+++ b/punyverse/shader.py
@@ -109,6 +109,9 @@ class Program(object):
     def uniform_vec3(self, name, a, b, c):
         glUniform3f(self.uniforms[name], a, b, c)
 
+    def uniform_vec4(self, name, a, b, c, d):
+        glUniform4f(self.uniforms[name], a, b, c, d)
+
     def _variable_locations(self, count_type, get_func, loc_func):
         variables = {}
         count = GLint()
diff --git a/punyverse/shaders/line.fragment.glsl b/punyverse/shaders/line.fragment.glsl
new file mode 100644
index 0000000..4a54b1c
--- /dev/null
+++ b/punyverse/shaders/line.fragment.glsl
@@ -0,0 +1,8 @@
+#version 130
+
+out vec4 o_fragColor;
+uniform vec4 u_color;
+
+void main() {
+    o_fragColor = u_color;
+}
diff --git a/punyverse/shaders/line.vertex.glsl b/punyverse/shaders/line.vertex.glsl
new file mode 100644
index 0000000..2a01d02
--- /dev/null
+++ b/punyverse/shaders/line.vertex.glsl
@@ -0,0 +1,8 @@
+#version 130
+
+in vec2 a_position;
+uniform mat4 u_mvpMatrix;
+
+void main() {
+    gl_Position = u_mvpMatrix * vec4(a_position, 0, 1);
+}
diff --git a/punyverse/ui.py b/punyverse/ui.py
index 4247ae8..6368e0b 100644
--- a/punyverse/ui.py
+++ b/punyverse/ui.py
@@ -143,6 +143,7 @@ class Punyverse(pyglet.window.Window):
         glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1))
 
         self.info_engine = FontEngine()
+        self.circle = Circle(10, 20)
 
         pyglet.clock.schedule(self.update)
         self.on_resize(self.width, self.height)  # On resize handler does nothing unless it's loaded
@@ -296,13 +297,19 @@ class Punyverse(pyglet.window.Window):
             glDrawArrays(GL_TRIANGLES, 0, self.info_engine.vertex_count)
 
             self.info_engine.end()
-            self.world.activate_shader(None)
             glDisable(GL_BLEND)
 
-            ortho(width, height)
-            with glRestore(GL_CURRENT_BIT | GL_LINE_BIT):
-                glLineWidth(2)
-                cx, cy = width / 2, height / 2
-                glColor4f(0, 1, 0, 1)
-                circle(10, 20, (cx, cy))
-            frustrum()
+            glLineWidth(2)
+            mvp = projection * Matrix4f.from_angles((width / 2, height /2, 0))
+            shader = self.world.activate_shader('line')
+            shader.uniform_vec4('u_color', 0, 1, 0, 1)
+            shader.uniform_mat4('u_mvpMatrix', mvp)
+            glBindBuffer(GL_ARRAY_BUFFER, self.circle.vbo)
+
+            shader.vertex_attribute('a_position', self.circle.position_size, self.circle.type, GL_FALSE,
+                                    self.circle.stride, self.circle.position_offset)
+            glDrawArrays(GL_LINE_LOOP, 0, self.circle.vertex_count)
+
+            glBindBuffer(GL_ARRAY_BUFFER, 0)
+            glLineWidth(1)
+            self.world.activate_shader(None)
diff --git a/punyverse/world.py b/punyverse/world.py
index f48549e..fc600eb 100644
--- a/punyverse/world.py
+++ b/punyverse/world.py
@@ -25,6 +25,7 @@ class World(object):
         'ring': ('ring.vertex.glsl', 'ring.fragment.glsl'),
         'atmosphere': ('atmosphere.vertex.glsl', 'atmosphere.fragment.glsl'),
         'text': ('text.vertex.glsl', 'text.fragment.glsl'),
+        'line': ('line.vertex.glsl', 'line.fragment.glsl'),
     }
 
     def __init__(self, file, callback):