diff --git a/glcube.py b/glcube.py index 2be5c0a..7cc4f5c 100644 --- a/glcube.py +++ b/glcube.py @@ -10,14 +10,16 @@ import pygame.locals as pgl import numpy import cubehelper +import math vertex_code = """ attribute vec3 position; uniform mat4 proj; +uniform mat4 rot; uniform vec3 offset; void main() { - gl_Position = proj * vec4(position + offset, 1.0); + gl_Position = proj * rot * vec4(position + offset, 1.0); } """ @@ -72,18 +74,31 @@ def m0_projection(aspect, n, f): class Cube(object): def __init__(self, args): self.color = True - width = 640 - height = 480 + self.width = 640 + self.height = 480 size = args.size self.size = size self.pixels = numpy.zeros((size, size, size, 3), 'f') pygame.init() - video_flags = pgl.OPENGL | pgl.DOUBLEBUF - pygame.display.set_mode((width, height), video_flags) + pygame.key.set_repeat(20, 20) + self.video_init() self.shader_init() self.geometry_init() - self.projection = m0_projection(width/float(height), 1.0, 100.0) glEnable(GL_DEPTH_TEST) + self.keyboard_speed = math.pi / 32 + self.mouse_speed = math.pi / 400 + self.alpha = 0 + self.beta = 0 + self.dragging = False + self.update_rotation() + + def video_init(self): + (w, h) = (self.width, self.height) + video_flags = pgl.OPENGL | pgl.DOUBLEBUF | pgl.RESIZABLE + pygame.display.set_mode((w, h), video_flags) + glViewport (0, 0, w, h) + self.projection = m0_projection(w/float(h), 1.0, 100.0) + pygame.display.set_caption(u"Cubulator\u2122".encode('utf8')) def shader_init(self): vertex = shaders.compileShader(vertex_code, GL_VERTEX_SHADER) @@ -93,11 +108,30 @@ def shader_init(self): self.attr_position = glGetAttribLocation(program, "position") self.param_color = glGetUniformLocation(program, "color") self.param_proj = glGetUniformLocation(program, "proj") + self.param_rot = glGetUniformLocation(program, "rot") self.param_offset = glGetUniformLocation(program, "offset") def geometry_init(self): self.pixel_model = Model("pixel.off") + def update_rotation(self): + self.alpha = max(-math.pi/2, min(self.alpha, math.pi/2)) + ca = math.cos(self.alpha) + sa = math.sin(self.alpha) + cb = math.cos(self.beta) + sb = math.sin(self.beta) + rot1 = numpy.array([[1.0, 0.0, 0.0, 0.0], + [0.0, ca, sa, 0.0], + [0.0, -sa, ca, 0.0], + [0.0, 0.0, 0.0, 1.0] + ], 'f') + rot2 = numpy.array([[cb, sb, 0.0, 0.0], + [-sb, cb, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 1.0] + ], 'f') + self.rot = numpy.dot(rot1, rot2) + def set_pixel(self, xyz, rgb): rgb = cubehelper.color_to_float(rgb) self.pixels[tuple(xyz)] = rgb @@ -121,27 +155,65 @@ def render(self): spacing = 5.0 xoff = (self.size / 2 - 0.5) * -spacing yoff = (self.size / 2 - 0.5) * -spacing - zoff = (self.size / 2 + 1) * spacing - eye = numpy.array([[1.0, 0.0, 0.0, xoff], - [0.0, 0.0, 1.0, yoff], + zoff = (self.size + 2) * spacing + eye = numpy.array([[1.0, 0.0, 0.0, 0], + [0.0, 0.0, 1.0, 0], [0.0, 1.0, 0.0, zoff], [0.0, 0.0, 0.0, 1.0] ], 'f') eye = numpy.dot(self.projection, eye) glUniformMatrix4fv(self.param_proj, 1, GL_TRUE, eye) + glUniformMatrix4fv(self.param_rot, 1, GL_TRUE, self.rot) for x in range(0, self.size): for y in range(0, self.size): for z in range(0, self.size): (r, g, b) = self.pixels[x, y, z] glUniform3f(self.param_color, r, g, b) - glUniform3f(self.param_offset, x * spacing, y * spacing, z * spacing) + glUniform3f(self.param_offset, + (x - self.size/2 + 0.5) * spacing, + (y - self.size/2 + 0.5) * spacing, + (z - self.size/2 + 0.5) * spacing) self.pixel_model.render() pygame.display.flip() for event in pygame.event.get(): if event.type == pgl.QUIT: raise KeyboardInterrupt + if event.type == pgl.VIDEORESIZE: + (self.width, self.height) = event.dict['size'] + self.video_init() if event.type == pgl.KEYUP: if event.key == pgl.K_ESCAPE or event.key == ord('q'): raise KeyboardInterrupt if event.key == pgl.K_SPACE: raise StopIteration + if event.key == ord('r'): + self.alpha = self.beta = 0 + self.update_rotation() + if event.type == pgl.MOUSEBUTTONDOWN: + self.dragging = True + pygame.mouse.set_visible(False) + pygame.event.set_grab(True) + pygame.mouse.get_rel() + if event.type == pgl.MOUSEBUTTONUP: + self.dragging = False + pygame.mouse.set_visible(True) + pygame.event.set_grab(False) + if event.type == pgl.MOUSEMOTION and self.dragging: + ms = self.mouse_speed + (dx, dy) = pygame.mouse.get_rel() + self.beta -= dx * ms + self.alpha -= dy * ms + self.update_rotation() + if event.type == pgl.KEYDOWN: + ks = self.keyboard_speed + if event.key == ord('w') or event.key == pgl.K_UP: + self.alpha += ks + elif event.key == ord('s') or event.key == pgl.K_DOWN: + self.alpha -= ks + elif event.key == ord('a') or event.key == pgl.K_LEFT: + self.beta += ks + elif event.key == ord('d') or event.key == pgl.K_RIGHT: + self.beta -= ks + else: + continue + self.update_rotation()