Mercurial > touhou
diff pytouhou/opengl/gamerenderer.py @ 108:2a03940deea3
Move everything graphical to pytouhou.opengl!
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Tue, 06 Sep 2011 00:26:13 +0200 |
parents | |
children | 340fcda8e64a |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/pytouhou/opengl/gamerenderer.py @@ -0,0 +1,143 @@ +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + +import struct +from itertools import chain + +import pygame + +import OpenGL +OpenGL.FORWARD_COMPATIBLE_ONLY = True +from OpenGL.GL import * +from OpenGL.GLU import * + + +from pytouhou.opengl.texture import TextureManager +from pytouhou.opengl.sprite import get_sprite_rendering_data +from pytouhou.opengl.background import get_background_rendering_data + + +class GameRenderer(object): + def __init__(self, resource_loader, game=None, background=None): + self.texture_manager = TextureManager(resource_loader) + + self.game = game + self.background = background + + self.window = None + + + def start(self, width=384, height=448): + # Initialize pygame + pygame.init() + self.window = pygame.display.set_mode((width, height), + pygame.OPENGL | pygame.DOUBLEBUF) + + # Initialize OpenGL + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(30, float(width)/float(height), + 101010101./2010101., 101010101./10101.) + + glEnable(GL_BLEND) + glEnable(GL_TEXTURE_2D) + glEnable(GL_FOG) + glHint(GL_FOG_HINT, GL_NICEST) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) + glEnableClientState(GL_COLOR_ARRAY) + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_TEXTURE_COORD_ARRAY) + + + def render_elements(self, elements): + texture_manager = self.texture_manager + objects_by_texture = {} + for element in elements: + sprite = element._sprite + if sprite: + ox, oy = element.x, element.y + key, (vertices, uvs, colors) = get_sprite_rendering_data(sprite) + rec = objects_by_texture.setdefault(key, ([], [], [])) + vertices = ((x + ox, y + oy, z) for x, y, z in vertices) + rec[0].extend(vertices) + rec[1].extend(uvs) + rec[2].extend(colors) + + for (texture_key, blendfunc), (vertices, uvs, colors) in objects_by_texture.items(): + nb_vertices = len(vertices) + glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) + glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) + glVertexPointer(3, GL_FLOAT, 0, struct.pack(str(3 * nb_vertices) + 'f', *chain(*vertices))) + glTexCoordPointer(2, GL_FLOAT, 0, struct.pack(str(2 * nb_vertices) + 'f', *chain(*uvs))) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, struct.pack(str(4 * nb_vertices) + 'B', *chain(*colors))) + glDrawArrays(GL_QUADS, 0, nb_vertices) + + + def render(self): + glClear(GL_DEPTH_BUFFER_BIT) + + back = self.background + game = self.game + texture_manager = self.texture_manager + + if back is not None: + fog_b, fog_g, fog_r, _, fog_start, fog_end = back.fog_interpolator.values + x, y, z = back.position_interpolator.values + dx, dy, dz = back.position2_interpolator.values + + glFogi(GL_FOG_MODE, GL_LINEAR) + glFogf(GL_FOG_START, fog_start) + glFogf(GL_FOG_END, fog_end) + glFogfv(GL_FOG_COLOR, (fog_r / 255., fog_g / 255., fog_b / 255., 1.)) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + # Some explanations on the magic constants: + # 192. = 384. / 2. = width / 2. + # 224. = 448. / 2. = height / 2. + # 835.979370 = 224./math.tan(math.radians(15)) = (height/2.)/math.tan(math.radians(fov/2)) + # This is so that objects on the (O, x, y) plane use pixel coordinates + gluLookAt(192., 224., - 835.979370 * dz, + 192. + dx, 224. - dy, 0., 0., -1., 0.) + glTranslatef(-x, -y, -z) + + glEnable(GL_DEPTH_TEST) + for (texture_key, blendfunc), (nb_vertices, vertices, uvs, colors) in get_background_rendering_data(back): + glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) + glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) + glVertexPointer(3, GL_FLOAT, 0, vertices) + glTexCoordPointer(2, GL_FLOAT, 0, uvs) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors) + glDrawArrays(GL_QUADS, 0, nb_vertices) + glDisable(GL_DEPTH_TEST) + else: + glClear(GL_COLOR_BUFFER_BIT) + + + if game is not None: + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + # Some explanations on the magic constants: + # 192. = 384. / 2. = width / 2. + # 224. = 448. / 2. = height / 2. + # 835.979370 = 224./math.tan(math.radians(15)) = (height/2.)/math.tan(math.radians(fov/2)) + # This is so that objects on the (O, x, y) plane use pixel coordinates + gluLookAt(192., 224., - 835.979370, + 192., 224., 0., 0., -1., 0.) + + glDisable(GL_FOG) + self.render_elements(game.enemies) + self.render_elements(game.game_state.bullets) + glEnable(GL_FOG) +