Merge pull request #10 from severin-lemaignan/for-upstream

[pyassimp] New sample application based on SDL/pygame + various fixes
pull/15/merge
Alexander Gessler 2013-01-19 17:48:22 -08:00
commit c50926b43b
5 changed files with 481 additions and 141 deletions

View File

@ -1,8 +1,8 @@
PyAssimp Readme
===============
-- a simple Python wrapper for Assimp using ctypes to access
the library. Requires Python >= 2.6.
A simple Python wrapper for Assimp using `ctypes` to access the library.
Requires Python >= 2.6.
Python 3 support is mostly here, but not well tested.
@ -12,10 +12,10 @@ particular, only loading of models is currently supported (no export).
USAGE
-----
To get started with pyAssimp, examine the sample.py script in scripts/, which
illustrates the basic usage. All Assimp data structures are wrapped using
To get started with pyAssimp, examine the `sample.py` script in `scripts/`,
which illustrates the basic usage. All Assimp data structures are wrapped using
ctypes. All the data+length fields in Assimp's data structures (such as
'aiMesh::mNumVertices','aiMesh::mVertices') are replaced by simple python
`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python
lists, so you can call len() on them to get their respective size and access
members using [].
@ -57,18 +57,18 @@ release(scene)
INSTALL
-------
Install pyassimp by running:
Install `pyassimp` by running:
> python setup.py install
PyAssimp requires a assimp dynamic library (DLL on windows,
so on linux :-) in order to work. The default search directories
PyAssimp requires a assimp dynamic library (`DLL` on windows,
`.so` on linux :-) in order to work. The default search directories
are:
- the current directory
- on linux additionally: /usr/lib and /usr/local/lib
- on linux additionally: `/usr/lib` and `/usr/local/lib`
To build that library, refer to the Assimp master INSTALL
instructions. To look in more places, edit ./pyassimp/helper.py.
There's an 'additional_dirs' list waiting for your entries.
instructions. To look in more places, edit `./pyassimp/helper.py`.
There's an `additional_dirs` list waiting for your entries.

View File

@ -346,60 +346,28 @@ def _get_properties(properties, length):
for p in [properties[i] for i in range(length)]:
#the name
p = p.contents
key = str(p.mKey.data)
key = str(p.mKey.data).split('.')[1]
#the data
from ctypes import POINTER, cast, c_int, c_float, sizeof
if p.mType == 1:
arr = cast(p.mData, POINTER(c_float * int(p.mDataLength/sizeof(c_float)) )).contents
value = numpy.array([x for x in arr])
value = [x for x in arr]
elif p.mType == 3: #string can't be an array
value = cast(p.mData, POINTER(structs.String)).contents.data
elif p.mType == 4:
arr = cast(p.mData, POINTER(c_int * int(p.mDataLength/sizeof(c_int)) )).contents
value = numpy.array([x for x in arr])
value = [x for x in arr]
else:
value = p.mData[:p.mDataLength]
if len(value) == 1:
[value] = value
result[key] = value
return result
def aiGetMaterialFloatArray(material, key):
AI_SUCCESS = 0
from ctypes import byref, pointer, cast, c_float, POINTER, sizeof, c_uint
out = structs.Color4D()
max = c_uint(sizeof(structs.Color4D))
r=_assimp_lib.dll.aiGetMaterialFloatArray(pointer(material),
key[0],
key[1],
key[2],
byref(out),
byref(max))
if (r != AI_SUCCESS):
raise AssimpError("aiGetMaterialFloatArray failed!")
out._init()
return [out[i] for i in range(max.value)]
def aiGetMaterialString(material, key):
AI_SUCCESS = 0
from ctypes import byref, pointer, cast, c_float, POINTER, sizeof, c_uint
out = structs.String()
r=_assimp_lib.dll.aiGetMaterialString(pointer(material),
key[0],
key[1],
key[2],
byref(out))
if (r != AI_SUCCESS):
raise AssimpError("aiGetMaterialString failed!")
return str(out.data)
def decompose_matrix(matrix):
if not isinstance(matrix, structs.Matrix4x4):
raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!")

View File

@ -9,6 +9,7 @@ import ctypes
from ctypes import POINTER
import operator
import numpy
from numpy import linalg
import logging;logger = logging.getLogger("pyassimp")
@ -47,12 +48,14 @@ def transform(vector3, matrix4x4):
def get_bounding_box(scene):
bb_min = [1e10, 1e10, 1e10] # x,y,z
bb_max = [-1e10, -1e10, -1e10] # x,y,z
return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max)
return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, linalg.inv(scene.rootnode.transformation))
def get_bounding_box_for_node(node, bb_min, bb_max):
def get_bounding_box_for_node(node, bb_min, bb_max, transformation):
transformation = numpy.dot(transformation, node.transformation)
for mesh in node.meshes:
for v in mesh.vertices:
v = transform(v, node.transformation)
v = transform(v, transformation)
bb_min[0] = min(bb_min[0], v[0])
bb_min[1] = min(bb_min[1], v[1])
bb_min[2] = min(bb_min[2], v[2])
@ -62,7 +65,7 @@ def get_bounding_box_for_node(node, bb_min, bb_max):
for child in node.children:
bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max)
bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation)
return bb_min, bb_max

View File

@ -0,0 +1,410 @@
#!/usr/bin/env python
#-*- coding: UTF-8 -*-
""" This program loads a model with PyASSIMP, and display it.
It make a large use of shaders to illustrate a 'modern' OpenGL pipeline.
Based on:
- pygame + mouselook code from http://3dengine.org/Spectator_%28PyOpenGL%29
- http://www.lighthouse3d.com/tutorials
- http://www.songho.ca/opengl/gl_transform.html
- http://code.activestate.com/recipes/325391/
- ASSIMP's C++ SimpleOpenGL viewer
"""
import sys
import logging
logger = logging.getLogger("underworlds.3d_viewer")
gllogger = logging.getLogger("OpenGL")
gllogger.setLevel(logging.WARNING)
logging.basicConfig(level=logging.INFO)
import OpenGL
#OpenGL.ERROR_CHECKING=False
#OpenGL.ERROR_LOGGING = False
#OpenGL.ERROR_ON_COPY = True
#OpenGL.FULL_LOGGING = True
from OpenGL.GL import *
from OpenGL.error import GLError
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL.arrays import vbo
from OpenGL.GL import shaders
import pygame
import math, random
import numpy
from numpy import linalg
from pyassimp import core as pyassimp
from pyassimp.postprocess import *
from pyassimp.helper import *
class DefaultCamera:
def __init__(self, w, h, fov):
self.clipplanenear = 0.001
self.clipplanefar = 100000.0
self.aspect = w/h
self.horizontalfov = fov * math.pi/180
self.transformation = [[ 0.68, -0.32, 0.65, 7.48],
[ 0.73, 0.31, -0.61, -6.51],
[-0.01, 0.89, 0.44, 5.34],
[ 0., 0., 0., 1. ]]
self.lookat = [0.0,0.0,-1.0]
def __str__(self):
return "Default camera"
class PyAssimp3DViewer:
base_name = "PyASSIMP 3D viewer"
def __init__(self, model, w=1024, h=768, fov=75):
pygame.init()
pygame.display.set_caption(self.base_name)
pygame.display.set_mode((w,h), pygame.OPENGL | pygame.DOUBLEBUF)
self.prepare_shaders()
self.cameras = [DefaultCamera(w,h,fov)]
self.current_cam_index = 0
self.load_model(model)
# for FPS computation
self.frames = 0
self.last_fps_time = glutGet(GLUT_ELAPSED_TIME)
self.cycle_cameras()
def prepare_shaders(self):
phong_weightCalc = """
float phong_weightCalc(
in vec3 light_pos, // light position
in vec3 frag_normal // geometry normal
) {
// returns vec2( ambientMult, diffuseMult )
float n_dot_pos = max( 0.0, dot(
frag_normal, light_pos
));
return n_dot_pos;
}
"""
vertex = shaders.compileShader( phong_weightCalc +
"""
uniform vec4 Global_ambient;
uniform vec4 Light_ambient;
uniform vec4 Light_diffuse;
uniform vec3 Light_location;
uniform vec4 Material_ambient;
uniform vec4 Material_diffuse;
attribute vec3 Vertex_position;
attribute vec3 Vertex_normal;
varying vec4 baseColor;
void main() {
gl_Position = gl_ModelViewProjectionMatrix * vec4(
Vertex_position, 1.0
);
vec3 EC_Light_location = gl_NormalMatrix * Light_location;
float diffuse_weight = phong_weightCalc(
normalize(EC_Light_location),
normalize(gl_NormalMatrix * Vertex_normal)
);
baseColor = clamp(
(
// global component
(Global_ambient * Material_ambient)
// material's interaction with light's contribution
// to the ambient lighting...
+ (Light_ambient * Material_ambient)
// material's interaction with the direct light from
// the light.
+ (Light_diffuse * Material_diffuse * diffuse_weight)
), 0.0, 1.0);
}""", GL_VERTEX_SHADER)
fragment = shaders.compileShader("""
varying vec4 baseColor;
void main() {
gl_FragColor = baseColor;
}
""", GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(vertex,fragment)
self.set_shader_accessors( (
'Global_ambient',
'Light_ambient','Light_diffuse','Light_location',
'Material_ambient','Material_diffuse',
), (
'Vertex_position','Vertex_normal',
), self.shader)
def set_shader_accessors(self, uniforms, attributes, shader):
# add accessors to the shaders uniforms and attributes
for uniform in uniforms:
location = glGetUniformLocation( shader, uniform )
if location in (None,-1):
logger.warning('No uniform: %s'%( uniform ))
setattr( shader, uniform, location )
for attribute in attributes:
location = glGetAttribLocation( shader, attribute )
if location in (None,-1):
logger.warning('No attribute: %s'%( attribute ))
setattr( shader, attribute, location )
def prepare_gl_buffers(self, mesh):
mesh.gl = {}
# Fill the buffer for vertex and normals positions
v = numpy.array(mesh.vertices, 'f')
n = numpy.array(mesh.normals, 'f')
mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v,n)))
# Fill the buffer for vertex positions
mesh.gl["faces"] = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"])
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
mesh.faces,
GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0)
def load_model(self, path, postprocess = aiProcessPreset_TargetRealtime_MaxQuality):
logger.info("Loading model:" + path + "...")
if postprocess:
self.scene = pyassimp.load(path, postprocess)
else:
self.scene = pyassimp.load(path)
logger.info("Done.")
scene = self.scene
#log some statistics
logger.info(" meshes: %d" % len(scene.meshes))
logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes]))
logger.info(" materials: %d" % len(scene.materials))
self.bb_min, self.bb_max = get_bounding_box(self.scene)
logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max))
self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)]
for index, mesh in enumerate(scene.meshes):
self.prepare_gl_buffers(mesh)
# Finally release the model
pyassimp.release(scene)
logger.info("Ready for 3D rendering!")
def cycle_cameras(self):
if not self.cameras:
logger.info("No camera in the scene")
return None
self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras)
self.current_cam = self.cameras[self.current_cam_index]
self.set_camera(self.current_cam)
logger.info("Switched to camera <%s>" % self.current_cam)
def set_camera_projection(self, camera = None):
if not camera:
camera = self.cameras[self.current_cam_index]
znear = camera.clipplanenear
zfar = camera.clipplanefar
aspect = camera.aspect
fov = camera.horizontalfov
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# Compute gl frustrum
tangent = math.tan(fov/2.)
h = znear * tangent
w = h * aspect
# params: left, right, bottom, top, near, far
glFrustum(-w, w, -h, h, znear, zfar)
# equivalent to:
#gluPerspective(fov * 180/math.pi, aspect, znear, zfar)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def set_camera(self, camera):
self.set_camera_projection(camera)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
cam = transform([0.0, 0.0, 0.0], camera.transformation)
at = transform(camera.lookat, camera.transformation)
gluLookAt(cam[0], cam[2], -cam[1],
at[0], at[2], -at[1],
0, 1, 0)
def render(self, wireframe = False, twosided = False):
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL)
glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE)
shader = self.shader
glUseProgram(shader)
glUniform4f( shader.Global_ambient, .4,.2,.2,.1 )
glUniform4f( shader.Light_ambient, .4,.4,.4, 1.0 )
glUniform4f( shader.Light_diffuse, 1,1,1,1 )
glUniform3f( shader.Light_location, 2,2,10 )
self.recursive_render(self.scene.rootnode, shader)
glUseProgram( 0 )
def recursive_render(self, node, shader):
""" Main recursive rendering method.
"""
# save model matrix and apply node transformation
glPushMatrix()
m = node.transformation.transpose() # OpenGL row major
glMultMatrixf(m)
for mesh in node.meshes:
stride = 24 # 6 * 4 bytes
glUniform4f( shader.Material_diffuse, *mesh.material.properties["diffuse"] )
glUniform4f( shader.Material_ambient, *mesh.material.properties["ambient"] )
vbo = mesh.gl["vbo"]
vbo.bind()
glEnableVertexAttribArray( shader.Vertex_position )
glEnableVertexAttribArray( shader.Vertex_normal )
glVertexAttribPointer(
shader.Vertex_position,
3, GL_FLOAT,False, stride, vbo
)
glVertexAttribPointer(
shader.Vertex_normal,
3, GL_FLOAT,False, stride, vbo+12
)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"])
glDrawElements(GL_TRIANGLES, len(mesh.faces) * 3, GL_UNSIGNED_INT, None)
vbo.unbind()
glDisableVertexAttribArray( shader.Vertex_position )
glDisableVertexAttribArray( shader.Vertex_normal )
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
for child in node.children:
self.recursive_render(child, shader)
glPopMatrix()
def loop(self):
pygame.display.flip()
pygame.event.pump()
self.keys = [k for k, pressed in enumerate(pygame.key.get_pressed()) if pressed]
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# Compute FPS
gl_time = glutGet(GLUT_ELAPSED_TIME)
self.frames += 1
if gl_time - self.last_fps_time >= 1000:
current_fps = self.frames * 1000 / (gl_time - self.last_fps_time)
pygame.display.set_caption(self.base_name + " - %.0f fps" % current_fps)
self.frames = 0
self.last_fps_time = gl_time
return True
def controls_3d(self,
mouse_button=1, \
up_key=pygame.K_UP, \
down_key=pygame.K_DOWN, \
left_key=pygame.K_LEFT, \
right_key=pygame.K_RIGHT):
""" The actual camera setting cycle """
mouse_dx,mouse_dy = pygame.mouse.get_rel()
if pygame.mouse.get_pressed()[mouse_button]:
look_speed = .2
buffer = glGetDoublev(GL_MODELVIEW_MATRIX)
c = (-1 * numpy.mat(buffer[:3,:3]) * \
numpy.mat(buffer[3,:3]).T).reshape(3,1)
# c is camera center in absolute coordinates,
# we need to move it back to (0,0,0)
# before rotating the camera
glTranslate(c[0],c[1],c[2])
m = buffer.flatten()
glRotate(mouse_dx * look_speed, m[1],m[5],m[9])
glRotate(mouse_dy * look_speed, m[0],m[4],m[8])
# compensate roll
glRotated(-math.atan2(-m[4],m[5]) * \
57.295779513082320876798154814105 ,m[2],m[6],m[10])
glTranslate(-c[0],-c[1],-c[2])
# move forward-back or right-left
if up_key in self.keys:
fwd = .1
elif down_key in self.keys:
fwd = -.1
else:
fwd = 0
if left_key in self.keys:
strafe = .1
elif right_key in self.keys:
strafe = -.1
else:
strafe = 0
if abs(fwd) or abs(strafe):
m = glGetDoublev(GL_MODELVIEW_MATRIX).flatten()
glTranslate(fwd*m[2],fwd*m[6],fwd*m[10])
glTranslate(strafe*m[0],strafe*m[4],strafe*m[8])
if __name__ == '__main__':
if not len(sys.argv) > 1:
print("Usage: " + __file__ + " <model>")
sys.exit(2)
app = PyAssimp3DViewer(model = sys.argv[1], w = 1024, h = 768, fov = 75)
while app.loop():
app.render()
app.controls_3d(0)
if pygame.K_f in app.keys: pygame.display.toggle_fullscreen()
if pygame.K_s in app.keys: app.screenshot()
if pygame.K_v in app.keys: app.check_visibility()
if pygame.K_TAB in app.keys: app.cycle_cameras()
if pygame.K_ESCAPE in app.keys:
break

View File

@ -1,14 +1,21 @@
#!/usr/bin/env python
#-*- coding: UTF-8 -*-
""" This program demonstrate the use of pyassimp to render
objects in OpenGL.
""" This program demonstrates the use of pyassimp to load and
render objects with OpenGL.
It loads a 3D model with ASSIMP and display it.
'c' cycles between cameras (if any available)
'q' to quit
This example mixes 'old' OpenGL fixed-function pipeline with
Vertex Buffer Objects.
Materials are supported but textures are currently ignored.
Half-working keyboard + mouse navigation is supported.
For a more advanced example (with shaders + keyboard/mouse
controls), check scripts/sdl_viewer.py
Author: SĂ©verin Lemaignan, 2012
This sample is based on several sources, including:
- http://www.lighthouse3d.com/tutorials
@ -21,9 +28,8 @@ import os, sys
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from OpenGL.arrays import ArrayDatatype
import logging;logger = logging.getLogger("assimp_opengl")
import logging;logger = logging.getLogger("pyassimp_opengl")
logging.basicConfig(level=logging.INFO)
import math
@ -40,20 +46,14 @@ width = 900
class GLRenderer():
def __init__(self):
self.scene = None
self.drot = 0.0
self.dp = 0.0
self.angle = 0.0
self.x = 1.0
self.z = 3.0
self.lx = 0.0
self.lz = 0.0
self.using_fixed_cam = False
self.current_cam_index = 0
self.x_origin = -1 # x position of the mouse when pressing left btn
# store the global scene rotation
self.angle = 0.
# for FPS calculation
self.prev_time = 0
@ -61,6 +61,10 @@ class GLRenderer():
self.frames = 0
def prepare_gl_buffers(self, mesh):
""" Creates 3 buffer objets for each mesh,
to store the vertices, the normals, and the faces
indices.
"""
mesh.gl = {}
@ -90,8 +94,7 @@ class GLRenderer():
glBindBuffer(GL_ARRAY_BUFFER,0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0)
def load_dae(self, path, postprocess = None):
def load_model(self, path, postprocess = None):
logger.info("Loading model:" + path + "...")
if postprocess:
@ -129,9 +132,11 @@ class GLRenderer():
if not self.using_fixed_cam:
glLoadIdentity()
gluLookAt(self.x ,1., self.z, # pos
self.x + self.lx - 1.0, 1., self.z + self.lz - 3.0, # look at
0.,1.,0.) # up vector
gluLookAt(0.,0.,3.,
0.,0.,-5.,
0.,1.,0.)
def set_camera(self, camera):
@ -194,23 +199,21 @@ class GLRenderer():
return x_max, y_max, z_max
def apply_material(self, mat):
""" Apply an OpenGL, using one OpenGL list per material to cache
""" Apply an OpenGL, using one OpenGL display list per material to cache
the operation.
"""
if not hasattr(mat, "gl_mat"): # evaluate once the mat properties, and cache the values in a glDisplayList.
diffuse = mat.properties.get("$clr.diffuse", numpy.array([0.8, 0.8, 0.8, 1.0]))
specular = mat.properties.get("$clr.specular", numpy.array([0., 0., 0., 1.0]))
ambient = mat.properties.get("$clr.ambient", numpy.array([0.2, 0.2, 0.2, 1.0]))
emissive = mat.properties.get("$clr.emissive", numpy.array([0., 0., 0., 1.0]))
shininess = min(mat.properties.get("$mat.shininess", 1.0), 128)
wireframe = mat.properties.get("$mat.wireframe", 0)
twosided = mat.properties.get("$mat.twosided", 1)
diffuse = numpy.array(mat.properties.get("diffuse", [0.8, 0.8, 0.8, 1.0]))
specular = numpy.array(mat.properties.get("specular", [0., 0., 0., 1.0]))
ambient = numpy.array(mat.properties.get("ambient", [0.2, 0.2, 0.2, 1.0]))
emissive = numpy.array(mat.properties.get("emissive", [0., 0., 0., 1.0]))
shininess = min(mat.properties.get("shininess", 1.0), 128)
wireframe = mat.properties.get("wireframe", 0)
twosided = mat.properties.get("twosided", 1)
from OpenGL.raw import GL
setattr(mat, "gl_mat", GL.GLuint(0))
mat.gl_mat = glGenLists(1)
setattr(mat, "gl_mat", glGenLists(1))
glNewList(mat.gl_mat, GL_COMPILE)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse)
@ -239,6 +242,8 @@ class GLRenderer():
self.lz = -math.cos(self.angle)
self.set_default_camera()
self.angle = (gl_time - self.prev_time) * 0.1
self.prev_time = gl_time
# Compute FPS
@ -291,6 +296,7 @@ class GLRenderer():
"""
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glRotatef(self.angle,0.,1.,0.)
self.recursive_render(self.scene.rootnode)
glutSwapBuffers()
@ -307,42 +313,6 @@ class GLRenderer():
if key == 'q':
sys.exit(0)
def onspecialkeypress(self, key, x, y):
fraction = 0.05
if key == GLUT_KEY_UP:
self.dp = 0.5
if key == GLUT_KEY_DOWN:
self.dp = -0.5
if key == GLUT_KEY_LEFT:
self.drot = -0.01
if key == GLUT_KEY_RIGHT:
self.drot = 0.01
def onspecialkeyrelease(self, key, x, y):
if key == GLUT_KEY_UP:
self.dp = 0.
if key == GLUT_KEY_DOWN:
self.dp = 0.
if key == GLUT_KEY_LEFT:
self.drot = 0.0
if key == GLUT_KEY_RIGHT:
self.drot = 0.0
def onclick(self, button, state, x, y):
if button == GLUT_LEFT_BUTTON:
if state == GLUT_UP:
self.drot = 0
self.x_origin = -1
else: # GLUT_DOWN
self.x_origin = x
def onmousemove(self, x, y):
if self.x_origin >= 0:
self.drot = (x - self.x_origin) * 0.001
def render(self, filename=None, fullscreen = False, autofit = True, postprocess = None):
"""
@ -364,7 +334,8 @@ class GLRenderer():
print("Fullscreen mode not available!")
sys.exit(1)
self.load_dae(filename, postprocess = postprocess)
self.load_model(filename, postprocess = postprocess)
glClearColor(0.1,0.1,0.1,1.)
#glShadeModel(GL_SMOOTH)
@ -374,12 +345,6 @@ class GLRenderer():
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
#lightZeroPosition = [10.,4.,10.,1.]
#lightZeroColor = [0.8,1.0,0.8,1.0] #green tinged
#glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition)
#glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor)
#glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1)
#glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05)
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
glEnable(GL_NORMALIZE)
glEnable(GL_LIGHT0)
@ -399,14 +364,8 @@ class GLRenderer():
glPushMatrix()
# Register GLUT callbacks for keyboard and mouse
glutKeyboardFunc(self.onkeypress)
glutSpecialFunc(self.onspecialkeypress)
glutIgnoreKeyRepeat(1)
glutSpecialUpFunc(self.onspecialkeyrelease)
glutMouseFunc(self.onclick)
glutMotionFunc(self.onmousemove)
glutMainLoop()