Skip to content

Commit 4213139

Browse files
author
Kurt Yoder
authored
Merge pull request #38 from einarf/parser-revamp
Parser revamp preparing to support different vertex formats
2 parents 6c6db76 + 014f7d9 commit 4213139

18 files changed

+672
-386
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ build
55
MANIFEST
66
dist
77
*.swp
8+
.idea
9+
*.egg-info
10+
.venv
11+

example/pyglet_demo.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
#!/usr/bin/env python
22
"""This script shows an example of using the PyWavefront module."""
3+
import ctypes
34
import sys
5+
46
sys.path.append('..')
5-
import ctypes
67

78
import pyglet
89
from pyglet.gl import *
910

10-
import pywavefront.visualization
11+
from pywavefront import visualization
12+
import pywavefront
1113

1214
rotation = 0
13-
1415
meshes = pywavefront.Wavefront('uv_sphere.obj')
15-
1616
window = pyglet.window.Window()
17-
1817
lightfv = ctypes.c_float * 4
1918

19+
2020
@window.event
2121
def on_resize(width, height):
2222
glMatrixMode(GL_PROJECTION)
@@ -25,6 +25,7 @@ def on_resize(width, height):
2525
glMatrixMode(GL_MODELVIEW)
2626
return True
2727

28+
2829
@window.event
2930
def on_draw():
3031
window.clear()
@@ -33,19 +34,23 @@ def on_draw():
3334
glLightfv(GL_LIGHT0, GL_POSITION, lightfv(-1.0, 1.0, 1.0, 0.0))
3435
glEnable(GL_LIGHT0)
3536

36-
glTranslated(0, 0, -3)
37-
glRotatef(rotation, 0, 1, 0)
38-
glRotatef(-25, 1, 0, 0)
39-
glRotatef(45, 0, 0, 1)
37+
glTranslated(0.0, 0.0, -3.0)
38+
glRotatef(rotation, 0.0, 1.0, 0.0)
39+
glRotatef(-25.0, 1.0, 0.0, 0.0)
40+
glRotatef(45.0, 0.0, 0.0, 1.0)
41+
4042
glEnable(GL_LIGHTING)
4143

42-
meshes.draw()
44+
visualization.draw(meshes)
45+
4346

4447
def update(dt):
4548
global rotation
46-
rotation += 90*dt
47-
if rotation > 720: rotation = 0
49+
rotation += 90.0 * dt
50+
51+
if rotation > 720.0:
52+
rotation = 0.0
4853

49-
pyglet.clock.schedule(update)
5054

55+
pyglet.clock.schedule(update)
5156
pyglet.app.run()

example/pyglet_demo2.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,78 @@
11
#!/usr/bin/env python
22
"""This script shows another example of using the PyWavefront module."""
33
# This example was created by intrepid94
4+
import ctypes
45
import sys
56
sys.path.append('..')
6-
import ctypes
77

88
import pyglet
99
from pyglet.gl import *
1010

11+
from pywavefront import visualization
1112
from pywavefront import Wavefront
12-
import pywavefront.visualization
13-
14-
rotation = 0
1513

14+
rotation = 0.0
1615
meshes = Wavefront('earth.obj')
16+
window = pyglet.window.Window(1024, 720, caption='Demo', resizable=True)
17+
lightfv = ctypes.c_float * 4
18+
label = pyglet.text.Label(
19+
'Hello, world',
20+
font_name='Times New Roman',
21+
font_size=12,
22+
x=800, y=700,
23+
anchor_x='center', anchor_y='center')
1724

18-
window = pyglet.window.Window(1024, 720, caption = 'Demo', resizable = True)
1925

20-
lightfv = ctypes.c_float * 4
21-
label = pyglet.text.Label('Hello, world', font_name = 'Times New Roman', font_size = 12, x = 800, y = 700, anchor_x = 'center', anchor_y = 'center')
2226
@window.event
2327
def on_resize(width, height):
2428
glMatrixMode(GL_PROJECTION)
2529
glLoadIdentity()
26-
gluPerspective(40.0, float(width)/height, 1, 100.0)
30+
gluPerspective(40.0, float(width) / height, 1.0, 100.0)
2731
glEnable(GL_DEPTH_TEST)
2832
glMatrixMode(GL_MODELVIEW)
2933
return True
3034

35+
3136
@window.event
3237
def on_draw():
3338
window.clear()
39+
3440
glLoadIdentity()
35-
glLightfv(GL_LIGHT0, GL_POSITION, lightfv(-40, 200, 100, 0.0))
41+
42+
glLightfv(GL_LIGHT0, GL_POSITION, lightfv(-40.0, 200.0, 100.0, 0.0))
3643
glLightfv(GL_LIGHT0, GL_AMBIENT, lightfv(0.2, 0.2, 0.2, 1.0))
3744
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightfv(0.5, 0.5, 0.5, 1.0))
3845
glEnable(GL_LIGHT0)
3946
glEnable(GL_LIGHTING)
47+
4048
glEnable(GL_COLOR_MATERIAL)
4149
glEnable(GL_DEPTH_TEST)
4250
glShadeModel(GL_SMOOTH)
51+
4352
glMatrixMode(GL_MODELVIEW)
53+
4454
# glTranslated(0, 4, -8)
45-
# glRotatef(90, 0, 1, 0)
46-
# glRotatef(-60, 0, 0, 1)
47-
# Rotations for sphere on axis - useful
55+
# glRotatef(90, 0, 1, 0)
56+
# glRotatef(-60, 0, 0, 1)
57+
58+
# Rotations for sphere on axis - useful
4859
glTranslated(0, .8, -20)
4960
glRotatef(-66.5, 0, 0, 1)
5061
glRotatef(rotation, 1, 0, 0)
5162
glRotatef(90, 0, 0, 1)
5263
glRotatef(0, 0, 1, 0)
53-
meshes.draw()
64+
65+
visualization.draw(meshes)
66+
67+
5468
def update(dt):
5569
global rotation
70+
5671
rotation += 45 * dt
57-
if rotation > 720:
58-
rotation = 0
5972

60-
pyglet.clock.schedule(update)
73+
if rotation > 720.0:
74+
rotation = 0.0
6175

76+
77+
pyglet.clock.schedule(update)
6278
pyglet.app.run()

profiler.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import cProfile
2+
import pstats
3+
import sys
4+
5+
try:
6+
from StringIO import StringIO
7+
except:
8+
from io import StringIO
9+
10+
11+
if len(sys.argv) < 2:
12+
print("Usage: profiler.py <obj file>")
13+
exit(1)
14+
15+
# Run the profiler
16+
pr = cProfile.Profile()
17+
pr.enable()
18+
import pywavefront
19+
pywavefront.Wavefront(sys.argv[1])
20+
pr.disable()
21+
22+
# Print the stats
23+
s = StringIO()
24+
sortby = 'tottime'
25+
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
26+
ps.print_stats()
27+
print(s.getvalue())

pywavefront/__init__.py

Lines changed: 3 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -31,121 +31,6 @@
3131
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3232
# POSSIBILITY OF SUCH DAMAGE.
3333
# ----------------------------------------------------------------------------
34-
import os
35-
36-
import pywavefront.material
37-
import pywavefront.mesh
38-
import pywavefront.parser
39-
40-
41-
class PywavefrontException(Exception):
42-
pass
43-
44-
45-
class Wavefront(object):
46-
"""Import a wavefront .obj file."""
47-
def __init__(self, file_name):
48-
self.file_name = file_name
49-
50-
self.materials = {}
51-
self.meshes = {} # Name mapping
52-
self.mesh_list = [] # Also includes anonymous meshes
53-
54-
ObjParser(self, self.file_name)
55-
56-
def draw(self):
57-
for this_mesh in self.mesh_list:
58-
this_mesh.draw()
59-
60-
def add_mesh(self, the_mesh):
61-
self.mesh_list.append(the_mesh)
62-
self.meshes[the_mesh.name] = the_mesh
63-
64-
65-
class ObjParser(parser.Parser):
66-
"""This parser parses lines from .obj files."""
67-
68-
def __init__(self, wavefront, file_name):
69-
super(ObjParser, self).__init__(file_name)
70-
self.wavefront = wavefront
71-
72-
self.mesh = None
73-
self.material = None
74-
self.vertices = [[0., 0., 0.]]
75-
self.normals = [[0., 0., 0.]]
76-
self.tex_coords = [[0., 0.]]
77-
self.read_file()
78-
79-
# methods for parsing types of wavefront lines
80-
def parse_v(self, args):
81-
self.vertices.append(list(map(float, args[0:3])))
82-
83-
def parse_vn(self, args):
84-
self.normals.append(list(map(float, args[0:3])))
85-
86-
def parse_vt(self, args):
87-
self.tex_coords.append(list(map(float, args[0:2])))
88-
89-
def parse_mtllib(self, args):
90-
mtllib = os.path.join(self.dir, " ".join(args))
91-
materials = material.MaterialParser(mtllib).materials
92-
for material_name, material_object in materials.items():
93-
self.wavefront.materials[material_name] = material_object
94-
95-
def parse_usemtl(self, args):
96-
[usemtl] = args
97-
self.material = self.wavefront.materials.get(usemtl, None)
98-
if self.material is None:
99-
raise PywavefrontException('Unknown material: %s' % args[0])
100-
if self.mesh is not None:
101-
self.mesh.add_material(self.material)
102-
103-
def parse_usemat(self, args):
104-
self.parse_usemtl(args)
105-
106-
def parse_o(self, args):
107-
[o] = args
108-
self.mesh = mesh.Mesh(o)
109-
self.wavefront.add_mesh(self.mesh)
110-
111-
def parse_f(self, args):
112-
if (len(self.tex_coords) > 1) and (len(self.normals) == 1):
113-
# does the spec allow for texture coordinates without normals?
114-
# if we allow this condition, the user will get a black screen
115-
# which is really confusing
116-
raise PywavefrontException('Found texture coordinates, but no normals')
117-
118-
if self.mesh is None:
119-
self.mesh = mesh.Mesh()
120-
self.wavefront.add_mesh(self.mesh)
121-
if self.material is None:
122-
self.material = material.Material()
123-
self.wavefront.materials[self.material.name] = self.material
124-
self.mesh.add_material(self.material)
125-
126-
# For fan triangulation, remember first and latest vertices
127-
v1 = None
128-
vlast = None
129-
for i, v in enumerate(args[0:]):
130-
if type(v) is bytes:
131-
v = v.decode()
132-
v_index, t_index, n_index = \
133-
(list(map(int, [j or 0 for j in v.split('/')])) + [0, 0])[:3]
134-
if v_index < 0:
135-
v_index += len(self.vertices) - 1
136-
if t_index < 0:
137-
t_index += len(self.tex_coords) - 1
138-
if n_index < 0:
139-
n_index += len(self.normals) - 1
140-
vertex = list(self.tex_coords[t_index]) + \
141-
list(self.normals[n_index]) + \
142-
list(self.vertices[v_index])
143-
144-
if i >= 3:
145-
# Triangulate
146-
self.material.vertices += v1 + vlast
147-
self.material.vertices += vertex
148-
149-
if i == 0:
150-
v1 = vertex
151-
vlast = vertex
34+
from pywavefront.exceptions import PywavefrontException
35+
from pywavefront.obj import ObjParser
36+
from pywavefront.wavefront import Wavefront

pywavefront/exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
class PywavefrontException(Exception):
4+
"""Generic exception for this package to separate from common ones"""
5+
pass

0 commit comments

Comments
 (0)