Skip to content
Browse files

Initial clean commit after svn conversion

  • Loading branch information...
1 parent ae92154 commit c5c5de8ef63ce423433e4a0ac223df55c7f37447 @weltenwort committed Oct 1, 2012
Showing with 2,057,675 additions and 1 deletion.
  1. +3 −1 README.md
  2. +9 −0 cg2_ex1/cg2_defaults.conf
  3. +106 −0 cg2_ex1/cg2_ex1.py
  4. +163 −0 cg2_ex1/cg2kit.py
  5. +8,709 −0 cg2_ex1/data/cow.off
  6. +437,648 −0 cg2_ex1/data/dragon.off
  7. +3,002 −0 cg2_ex1/data/torus.off
  8. +160 −0 cg2_ex1/kd_tree.py
  9. +49 −0 cg2_ex1/point_cloud.py
  10. +24 −0 cg2_ex1/reader.py
  11. +11 −0 cg2_ex1/run_tests.py
  12. +13 −0 cg2_ex1/test1.py
  13. 0 cg2_ex1/tests/__init__.py
  14. +18 −0 cg2_ex1/tests/test_kd_tree.py
  15. BIN cg2_ex1/theory/ex1.pdf
  16. +112 −0 cg2_ex1/theory/ex1.tex
  17. BIN cg2_ex1/theory/spline.png
  18. BIN cg2_ex1/theory/triangle.png
  19. +16 −0 cg2_ex1/tk_global_frame.py
  20. +527 −0 cg2_ex1/tk_viewer.py
  21. +683 −0 cg2_ex1/tk_viewer_prototype.py
  22. +88 −0 cg2_ex1/trimesh.py
  23. +87 −0 cg2_ex2/camera.py
  24. +68 −0 cg2_ex2/casteljau.py
  25. +234 −0 cg2_ex2/cg2_ex2.py
  26. +104 −0 cg2_ex2/min_squares.py
  27. +1 −0 cg2_ex2/panda.prc
  28. +1,002 −0 cg2_ex2/pointdata/franke4.off
  29. +10,002 −0 cg2_ex2/pointdata/franke5.off
  30. +100,002 −0 cg2_ex2/pointdata/franke6.off
  31. +1,000,002 −0 cg2_ex2/pointdata/franke7.off
  32. +42 −0 cg2_ex2/reader.py
  33. +17 −0 cg2_ex2/run_tests.py
  34. +191 −0 cg2_ex2/surface.py
  35. +1 −0 cg2_ex2/tests/__init__.py
  36. +13 −0 cg2_ex2/tests/test_bezier_surface.py
  37. +25 −0 cg2_ex2/tests/test_casteljau.py
  38. +33 −0 cg2_ex2/tests/test_min_squares.py
  39. +13 −0 cg2_ex2/tests/test_mls_surface.py
  40. +13 −0 cg2_ex2/tests/test_parameter_plane.py
  41. +11 −0 cg2_ex2/tests/test_point_cloud.py
  42. +28 −0 cg2_ex2/tests/test_reader.py
  43. +6 −0 cg2_ex2/theory/ex2.aux
  44. +618 −0 cg2_ex2/theory/ex2.log
  45. BIN cg2_ex2/theory/ex2.pdf
  46. +61 −0 cg2_ex2/theory/ex2.tex
  47. +87 −0 cg2_ex3/camera.py
  48. +264 −0 cg2_ex3/cg2_ex3.py
  49. +24 −0 cg2_ex3/debughelpers.py
  50. +468 −0 cg2_ex3/marching_cube.py
  51. +133 −0 cg2_ex3/min_squares.py
  52. +1,066 −0 cg2_ex3/pointdata/cat.off
  53. +145,453 −0 cg2_ex3/pointdata/horse.off
  54. +37,547 −0 cg2_ex3/pointdata/hound.off
  55. +24,104 −0 cg2_ex3/pointdata/rhino.off
  56. +35,992 −0 cg2_ex3/pointdata/snail.off
  57. +726 −0 cg2_ex3/profilehooks.py
  58. +60 −0 cg2_ex3/reader.py
  59. +18 −0 cg2_ex3/run_tests.py
  60. +240 −0 cg2_ex3/surface.py
  61. +1 −0 cg2_ex3/tests/__init__.py
  62. +13 −0 cg2_ex3/tests/test_bezier_surface.py
  63. +25 −0 cg2_ex3/tests/test_casteljau.py
  64. +25 −0 cg2_ex3/tests/test_implicit_surface.py
  65. +15 −0 cg2_ex3/tests/test_marching_cube.py
  66. +95 −0 cg2_ex3/tests/test_min_squares.py
  67. 0 cg2_ex3/tests/test_mls_surface.py
  68. +13 −0 cg2_ex3/tests/test_parameter_plane.py
  69. +11 −0 cg2_ex3/tests/test_point_cloud.py
  70. +22 −0 cg2_ex3/tests/test_reader.py
  71. BIN cg2_ex3/theory/ex3.pdf
  72. +73 −0 cg2_ex3/theory/ex3.tex
  73. +87 −0 cg2_ex4/camera.py
  74. +407 −0 cg2_ex4/cg2_ex4.py
  75. +15 −0 cg2_ex4/debug_tests.py
  76. +24 −0 cg2_ex4/debughelpers.py
  77. +227 −0 cg2_ex4/halfedge.py
  78. +451 −0 cg2_ex4/marching_cube.py
  79. +169 −0 cg2_ex4/min_squares.py
  80. +258 −0 cg2_ex4/operations.py
  81. +75 −0 cg2_ex4/optimizer.py
  82. +1,066 −0 cg2_ex4/pointdata/cat.off
  83. +145,453 −0 cg2_ex4/pointdata/horse.off
  84. +37,547 −0 cg2_ex4/pointdata/hound.off
  85. +24,104 −0 cg2_ex4/pointdata/rhino.off
  86. +35,992 −0 cg2_ex4/pointdata/snail.off
  87. +726 −0 cg2_ex4/profilehooks.py
  88. +60 −0 cg2_ex4/reader.py
  89. +20 −0 cg2_ex4/run_tests.py
  90. +270 −0 cg2_ex4/surface.py
  91. +1 −0 cg2_ex4/tests/__init__.py
  92. +13 −0 cg2_ex4/tests/test_bezier_surface.py
  93. +25 −0 cg2_ex4/tests/test_casteljau.py
  94. +36 −0 cg2_ex4/tests/test_halfedges.py
  95. +25 −0 cg2_ex4/tests/test_implicit_surface.py
  96. +15 −0 cg2_ex4/tests/test_marching_cube.py
  97. +82 −0 cg2_ex4/tests/test_min_squares.py
  98. 0 cg2_ex4/tests/test_mls_surface.py
  99. +13 −0 cg2_ex4/tests/test_parameter_plane.py
  100. +11 −0 cg2_ex4/tests/test_point_cloud.py
  101. +22 −0 cg2_ex4/tests/test_reader.py
  102. BIN cg2_ex4/theory/cg2_ex4_3a.png
  103. BIN cg2_ex4/theory/cg2_ex4_3b.png
  104. BIN cg2_ex4/theory/cg2_ex4_4-1.png
  105. BIN cg2_ex4/theory/cg2_ex4_4-2.png
  106. BIN cg2_ex4/theory/cg2_ex4_4-3.png
  107. BIN cg2_ex4/theory/cg2_ex4_4-4.png
  108. BIN cg2_ex4/theory/ex4.pdf
  109. +91 −0 cg2_ex4/theory/ex4.tex
  110. BIN cg2_ex4/theory/ex4_aufgabe1.pdf
View
4 README.md
@@ -1,2 +1,4 @@
uni_cg2
-=======
+=======
+
+Exercise code for Computer Graphics 2
View
9 cg2_ex1/cg2_defaults.conf
@@ -0,0 +1,9 @@
+[general]
+framerate=15
+
+[window]
+width=800
+height=600
+x=400
+y=0
+title=CG_2
View
106 cg2_ex1/cg2_ex1.py
@@ -0,0 +1,106 @@
+import logging
+from Tkinter import *
+from OpenGL.GL import *
+from cg2kit import *
+
+from reader import openOff
+from kd_tree import KdTree
+
+class KdTreeOptionFrame(Frame):
+ def __init__(self, master=None):
+ Frame.__init__(self, master,
+ borderwidth=1,
+ relief=GROOVE)
+ self._log = logging.getLogger('KdTreeOptions')
+ self._model_var = StringVar()
+ self._model_var.set("data/cow.off")
+ self._tree_min_depth_var = IntVar()
+ self._tree_min_depth_var.set(0)
+ self._tree_max_depth_var = IntVar()
+ self._tree_max_depth_var.set(5)
+ self._label = Label(self, text="KD-Tree Options", width=30)
+ self._label.grid(row=0, sticky=E+W)
+ self._entry_model = Entry(self, textvariable=self._model_var)
+ self._entry_model.grid(row=1, sticky=E+W)
+ self._button_build = Button(self, text="Build KD-Tree", command=self._build_tree)
+ self._button_build.grid(row=2, sticky=E+W)
+ self._scale_tree_min_depth = Scale(self, label="Minimum tree depth", variable=self._tree_min_depth_var, from_=0, to=10, orient=HORIZONTAL)
+ self._scale_tree_min_depth.grid(row=3, sticky=E+W)
+ self._scale_tree_max_depth = Scale(self, label="Maximum tree depth", variable=self._tree_max_depth_var, from_=0, to=10, orient=HORIZONTAL)
+ self._scale_tree_max_depth.grid(row=4, sticky=E+W)
+ self._button_show = Button(self, text="Show KD-Tree boxes", command=self._build_tree_visualization)
+ self._button_show.grid(row=5, sticky=E+W)
+
+ self._tree_boxes = []
+
+ def _build_tree(self):
+ # build tree
+ self._log.info(u"Building kd-tree...")
+ self.tree = KdTree(point_list=openOff(self._model_var.get()).get_vertices())
+ self._log.info(u"Building kd-tree done.")
+
+ # create vertex visualization
+ self._log.info(u"Building kd-tree vizualization...")
+ GLTargetDistantLight(
+ pos = (0.3, -0.5, 1)
+ )
+ mat = GLMaterial(
+ diffuse = (1, 0, 0)
+ )
+
+ vertices = list(self.tree.iter_vertices())
+ t_vertices, t_faces = self._generate_trimesh_params(vertices)
+ TriMesh(verts=t_vertices, faces=t_faces, material=mat) #, dynamics=False, static=True)
+
+ #for vertex in list(tree.iter_vertices()):
+ #Box(pos=vertex, lx=0.05, ly=0.05, lz=0.05, dynamics=False, static=True, material=mat)
+ #Sphere()
+
+ # create bbox visualization
+ pass
+ self._log.info(u"Building kd-tree vizualization done.")
+
+ def _build_tree_visualization(self):
+ min_depth = self._tree_min_depth_var.get()
+ max_depth = self._tree_max_depth_var.get()
+ mat = GLMaterial(
+ diffuse = (0, 1, 0, 0.1),
+ blend_factors = (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+ )
+
+ if hasattr(self, 'tree'):
+ self._log.info(u"Building kd-tree bounding box visualization...")
+ stack = [(self.tree.root, 0), ]
+ while stack:
+ node, level = stack.pop()
+ if level >= min_depth and level <= max_depth:
+ bbox = node.get_bbox()
+ bounds = bbox.getBounds()
+ self._tree_boxes.append(Box(pos=bbox.center(), lx=bounds[0][0] - bounds[1][0], ly=bounds[0][1] - bounds[1][1], lz=bounds[0][2] - bounds[1][2], material=mat))
+ if level < max_depth:
+ if node.left_child:
+ stack.append((node.left_child, level+1))
+ if node.right_child:
+ stack.append((node.right_child, level+1))
+ self._log.info(u"Building kd-tree bounding box visualization done.")
+ else:
+ self._log.error(u"No kd-tree found. Please build the tree first.")
+
+ def _generate_trimesh_params(self, vertices):
+ result_vertices = []
+ result_faces = []
+ for n, vertex in enumerate(vertices):
+ n = n * 4
+ result_vertices.append(vertex)
+ result_vertices.append(vertex+(0.1, 0 , 0 ))
+ result_vertices.append(vertex+(0 , 0.1, 0 ))
+ result_vertices.append(vertex+(0 , 0 , 0.1))
+ result_faces.append((n , n+1, n+2))
+ result_faces.append((n , n+1, n+3))
+ result_faces.append((n , n+2, n+3))
+ result_faces.append((n+1, n+2, n+3))
+
+ return (result_vertices, result_faces)
+
+
+option_frames = [KdTreeOptionFrame, ]
View
163 cg2_ex1/cg2kit.py
@@ -0,0 +1,163 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Python Computer Graphics Kit.
+#
+# The Initial Developer of the Original Code is Matthias Baas.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+# $Id: __init__.py,v 1.8 2006/05/26 21:32:01 mbaas Exp $
+
+"""The 'all' sub package imports all names from cgkit.
+
+You can import from this package if you simply want to make available
+(almost) all the objects, functions, etc. defined in cgkit (e.g. for
+interactive sessions or simple scripts):
+
+from cgkit.all import *
+"""
+
+from cgkit import _core
+
+from cgkit.eventmanager import eventManager
+from cgkit.events import *
+from cgkit.keydefs import *
+from cgkit.application import getApp
+
+from cgkit.cgtypes import vec3, vec4, mat3, mat4, quat, getEpsilon, setEpsilon, slerp, squad
+from cgkit.scene import Scene, getScene
+from cgkit.sceneglobals import Globals
+from cgkit.worldobject import WorldObject
+from cgkit.material import Material
+from cgkit.glmaterial import GLMaterial, GLTexture, GLShader, GLSLANG_VERTEX, GLSLANG_FRAGMENT, GL_DECAL, GL_REPLACE, GL_BLEND, GL_MODULATE, GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_CLAMP, GL_REPEAT, GL_RGB, GL_RGBA
+from cgkit.lightsource import LightSource
+from cgkit.component import Component, createFunctionComponent
+from cgkit.slots import DoubleSlot, BoolSlot, IntSlot, Vec3Slot, Vec4Slot, Mat3Slot, Mat4Slot, QuatSlot, PySlot, slotPropertyCode, ProceduralIntSlot, ProceduralDoubleSlot, ProceduralVec3Slot, ProceduralVec4Slot, ProceduralMat3Slot, ProceduralMat4Slot, ProceduralQuatSlot, NotificationForwarder, UserSizeConstraint, LinearSizeConstraint
+from cgkit.slots import Dependent
+from cgkit.boundingbox import BoundingBox
+
+### Geom objects:
+from cgkit.spheregeom import SphereGeom
+from cgkit.ccylindergeom import CCylinderGeom
+from cgkit.torusgeom import TorusGeom
+from cgkit.boxgeom import BoxGeom
+from cgkit.planegeom import PlaneGeom
+from cgkit.trimeshgeom import TriMeshGeom
+from cgkit.polyhedrongeom import PolyhedronGeom
+from cgkit.drawgeom import DrawGeom
+from cgkit.beziercurvegeom import BezierCurveGeom, BezierPoint
+
+### Geometry world objects:
+from cgkit.quadrics import Sphere
+from cgkit.ccylinder import CCylinder
+from cgkit.torus import Torus
+from cgkit.box import Box
+from cgkit.plane import Plane
+from cgkit.trimesh import TriMesh
+from cgkit.polyhedron import Polyhedron
+from cgkit.draw import Draw
+from cgkit.ribarchive import RIBArchive
+from cgkit.beziercurve import BezierCurve
+
+from cgkit.joint import Joint
+
+### Dynamics world objects
+from cgkit.odedynamics import ODEDynamics, ODEContactProperties, ODEBallJoint, ODEHingeJoint, ODESliderJoint, ODEHinge2Joint, ODE_COLLISION
+from cgkit.joints import HingeJoint
+
+### Camera/light
+from cgkit.targetcamera import TargetCamera
+from cgkit.freecamera import FreeCamera
+from cgkit.lookat import LookAt
+from cgkit.glpointlight import GLPointLight
+from cgkit.glfreespotlight import GLFreeSpotLight
+from cgkit.gltargetspotlight import GLTargetSpotLight
+from cgkit.glfreedistantlight import GLFreeDistantLight
+from cgkit.gltargetdistantlight import GLTargetDistantLight
+
+from cgkit.spotlight3ds import SpotLight3DS
+from cgkit.material3ds import Material3DS, TextureMap3DS
+from cgkit.objmaterial import OBJMaterial, OBJTextureMap
+from cgkit.mayaspotlight import MayaSpotLight
+
+from cgkit.camcontrol import CameraControl
+
+from cgkit.group import Group
+from cgkit.tunnel import Tunnel
+from cgkit.valuetable import ValueTable
+from cgkit.expression import Expression
+from cgkit.euleradapter import EulerAdapter
+from cgkit.pidcontroller import PIDController
+from cgkit.gnuplotter import GnuPlotter
+from cgkit.slideshow import SlideShow, Slide, XFade, XCube
+from cgkit.motionpath import MotionPath
+
+from cgkit.glrenderer import GLRenderInstance
+
+from cgkit.joystick import Joystick
+
+CONSTANT = _core.VarStorage.CONSTANT
+UNIFORM = _core.VarStorage.UNIFORM
+VARYING = _core.VarStorage.VARYING
+VERTEX = _core.VarStorage.VERTEX
+FACEVARYING = _core.VarStorage.FACEVARYING
+FACEVERTEX = _core.VarStorage.FACEVERTEX
+USER = _core.VarStorage.USER
+
+INT = _core.VarType.INT
+FLOAT = _core.VarType.FLOAT
+STRING = _core.VarType.STRING
+COLOR = _core.VarType.COLOR
+POINT = _core.VarType.POINT
+VECTOR = _core.VarType.VECTOR
+NORMAL = _core.VarType.NORMAL
+MATRIX = _core.VarType.MATRIX
+HPOINT = _core.VarType.HPOINT
+
+### Importer
+import cgkit.offimport
+import cgkit.pyimport
+import cgkit.dddsimport
+import cgkit.x3dimport
+import cgkit.ifsimport
+import cgkit.stlimport
+import cgkit.asfamcimport
+import cgkit.bvhimport
+import cgkit.maimport
+import cgkit.plyimport
+### Exporter
+import cgkit.ribexport
+import cgkit.offexport
+import cgkit.objexport
+import cgkit.plyexport
+
+from cgkit.rmshader import RMMaterial, RMLightSource, RMShader
+from cgkit.ribexport import ShadowPass, FlatReflectionPass
+
+from cgkit.cmds import *
View
8,709 cg2_ex1/data/cow.off
8,709 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
437,648 cg2_ex1/data/dragon.off
437,648 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
3,002 cg2_ex1/data/torus.off
3,002 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
160 cg2_ex1/kd_tree.py
@@ -0,0 +1,160 @@
+from math import abs
+
+from cg2kit import BoundingBox
+from numpy import *
+
+class Node(object):
+ def __init__(self, location, splitaxis, left_child, right_child):
+ self.location = location
+ self.splitaxis = splitaxis
+ self.left_child = left_child
+ self.right_child = right_child
+
+ def is_leaf(self):
+ return (not self.right_child) and (not self.left_child)
+
+ def get_bbox(self):
+ bbox = BoundingBox()
+ bbox.addPoint(self.location)
+ if self.left_child:
+ bbox.addBoundingBox(self.left_child.get_bbox())
+ if self.right_child:
+ bbox.addBoundingBox(self.right_child.get_bbox())
+ return bbox
+
+ def approx_distance(self, point):
+ bbox = self.get_bbox()
+ center = bbox.center()
+ dir = array(center) - point
+ bounds = bbox.getBounds(dir)
+ max_distance = 0
+ for axis in range(len(self.location)):
+ t = self.location[axis] - bounds[1][axis]
+ if t > max_distance:
+ max_distance = t
+ t = bounds[1][axis] - self.location[axis]
+ if t > max_distance:
+ max_distance = t
+ return max_distance
+
+ def exact_sq_distance(self, point):
+ return sum((self.location - point)**2)
+
+ def iter_vertices(self):
+ stack = [self, ]
+ while stack:
+ node = stack.pop()
+ yield node.location
+ if node.left_child:
+ stack.append(node.left_child)
+ if node.right_child:
+ stack.append(node.right_child)
+
+class KdTree(object):
+
+ def __init__(self, point_list):
+ self.root = self.buildTree(point_list)
+ self.nodecount = 0
+ self._count_nodes(self.root)
+ #self.knearest = () saving the results within the tree makes no sense since they depend on various parameters
+ #self.inradius = ()
+
+ def buildTree(self, point_list, depth = 0):
+ if not point_list:
+ return None
+ else:
+ # Select axis based on depth so that axis cycles through all valid values
+ point_dimension = len(point_list[0]) # assumes all points have the same dimension
+ axis = depth % point_dimension
+
+ # Sort point list and choose median as pivot element
+ point_list.sort(key=lambda point: point[axis])
+ median = len(point_list)/2 # choose median
+
+ # Create node and construct subtrees
+ return Node(
+ location = point_list[median],
+ splitaxis = axis,
+ left_child = self.buildTree(point_list[0:median], depth+1),
+ right_child = self.buildTree(point_list[median+1:], depth+1))
+
+ def _count_nodes(self, rootnode):
+ self.nodecount += 1
+ if rootnode.left_child:
+ self._count_nodes(rootnode.left_child)
+ if rootnode.right_child:
+ self._count_nodes(rootnode.right_child)
+
+ def iter_vertices(self):
+ stack = [self.root, ]
+ while stack:
+ node = stack.pop()
+ yield node.location
+ if node.left_child:
+ stack.append(node.left_child)
+ if node.right_child:
+ stack.append(node.right_child)
+
+ def collectKNearest(self, k, point):
+ knearest = []
+ self._collectKNearest_recursive(k, self.root, point, knearest)
+ return knearest
+
+ #TODO: fix type errors, test functionality
+ def _collectKNearest_recursive(self, k, rootnode, point, knearest):
+ point_dimension = len(point)
+ axis = rootnode.splitaxis
+ walked_right = False
+ walked_left = False
+
+ if (point[axis] >= rootnode.location[axis]) and (not rootnode.is_leaf()) and rootnode.right_child:
+ self._collectKNearest_recursive(k, rootnode.right_child, point, knearest)
+ walked_right = True
+ elif (point[axis] < rootnode.location[axis]) and (not rootnode.is_leaf()) and rootnode.left_child:
+ self._collectKNearest_recursive(k, rootnode.left_child, point, knearest)
+ walked_left = True
+
+ distance = sum(square(rootnode.location - array(point)))
+ if len(knearest) < k:
+ knearest.append([rootnode,distance])
+ else:
+ max_distance = max(point[1] for point in knearest)
+ if distance < max_distance:
+ for index,point in enumerate(knearest):
+ if point[1] == max_distance:
+ elementindex = index
+ del knearest[elementindex]
+ knearest.append([rootnode,distance])
+
+ max_distance = max(point[1] for point in knearest)
+ if square(float(rootnode.location[axis]) - float(point[axis])) < max_distance:
+ if walked_right and not walked_left and rootnode.left_child:
+ self._collectKNearest_recursive(k, rootnode.left_child, point, knearest)
+ elif walked_left and not walked_right and rootnode.right_child:
+ self._collectKNearest_recursive(k, rootnode.right_child, point, knearest)
+
+
+ def collectInRadius(self, point, radius):
+ inradius = []
+ self._collectInRadius_recursive(r, self.root, point, inradius)
+ return inradius
+
+ def _collectInRadius_recursive(self, point, radius, node, inradius):
+ sq_radius = radius**2
+ if node.left_child or node.right_child:
+ if node.left_child:
+ if node.left_child.approx_distance(point)**2 <= sq_radius:
+ self._collectInRadius_recursive(point, radius, node.left_child, inradius)
+ elif node.left_child
+ inradius.extend(node.left_child.iter_vertices())
+ else:
+ if node.exact_sq_distance(point) <= sq_radius:
+ inradius.append(node)
+
+ #if rootnode is a leaf: report it if it lies in r
+ #elif region(left_child) is fully contained in r: report left subtree
+ #elif region(left_child) intersects r: collectInRadius(r, left_child, point, depth+1)
+
+ #if region(right_child) is fully contained in r: report right subtree
+ #elif region(right_child) intersects r: collectInRadius(r, right_child, point, depth+1)
+ pass
View
49 cg2_ex1/point_cloud.py
@@ -0,0 +1,49 @@
+from OpenGL.GL import *
+from OpenGL.GLUT import *
+
+from cg2kit import *
+
+class PointCloudGeom(TriMeshGeom):
+ def drawGL(self):
+ print("foo")
+ glBegin(GL_POINTS)
+ for vertex in self.verts:
+ glVertex3fv(tuple(vertex))
+ glEnd()
+
+
+class PointCloud(WorldObject):
+ def __init__(self,
+ name = "PointCloud",
+ dynamics = True,
+ static = False,
+ verts = [],
+ faces = [],
+ **params):
+ WorldObject.__init__(self, name=name, **params)
+
+ self.geom = PointCloudGeom()
+
+ self.dynamics_slot = BoolSlot(dynamics)
+ self.static_slot = BoolSlot(static)
+ self.addSlot("dynamics", self.dynamics_slot)
+ self.addSlot("static", self.static_slot)
+
+ tm = self.geom
+
+ if len(verts)>0:
+ tm.verts.resize(len(verts))
+ i = 0
+ for v in verts:
+ tm.verts.setValue(i, v)
+ i+=1
+
+ if len(faces)>0:
+ tm.faces.resize(len(faces))
+ i = 0
+ for f in faces:
+ tm.faces.setValue(i, f)
+ i+=1
+
+ exec slotPropertyCode("static")
+ exec slotPropertyCode("dynamics")
View
24 cg2_ex1/reader.py
@@ -0,0 +1,24 @@
+import logging
+
+from numpy import array
+
+class FileFormatException(Exception):
+ pass
+
+class openOff(object):
+ def __init__(self, filename):
+ self._filename = filename
+ self._log = logging.getLogger('openOff')
+
+ def get_vertices(self):
+ with open(self._filename) as f:
+ self._log.debug(u"Opened file '%s' as OFF file." % self._filename)
+ vertices = []
+ first_line = f.readline()
+ if first_line.startswith("OFF"):
+ vertice_count, polygon_count, edge_count = [ int(value.strip()) for value in f.readline().split(" ") ]
+ for vertex_index in range(vertice_count):
+ vertices.append(array([ float(coord.strip()) for coord in f.readline().split(" ") if coord.strip() != "" ]))
+ else:
+ raise FileFormatException("The file '%s' is not of the expected format: %s" % (self._filename, first_line))
+ return vertices
View
11 cg2_ex1/run_tests.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+import unittest
+
+names = [
+ "tests.test_kd_tree.CowTestCase",
+ ]
+
+if __name__ == '__main__':
+ suite = unittest.TestLoader().loadTestsFromNames(names)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
View
13 cg2_ex1/test1.py
@@ -0,0 +1,13 @@
+from Tkinter import *
+from cg2kit import *
+
+class TestOptionFrame(Frame):
+ def __init__(self, master=None):
+ Frame.__init__(self, master,
+ borderwidth=1,
+ relief=GROOVE)
+ self._label = Label(self, text="Test 1")
+ self._label.grid(row=0)
+
+option_frames = [TestOptionFrame, ]
+Sphere()
View
0 cg2_ex1/tests/__init__.py
No changes.
View
18 cg2_ex1/tests/test_kd_tree.py
@@ -0,0 +1,18 @@
+import unittest
+
+from reader import *
+from kd_tree import *
+
+class CowTestCase(unittest.TestCase):
+ def setUp(self):
+ self.model_filename = "data/cow.off"
+ self.reader = openOff(self.model_filename)
+ self.vertices = self.reader.get_vertices()
+ self.tree = KdTree(self.vertices)
+
+ def test_vertex_count(self):
+ self.failUnless(self.tree.nodecount == len(self.vertices))
+
+ def test_vertex_iterator(self):
+ iter_vertices = list(self.tree.iter_vertices())
+ self.failUnlessEqual(len(iter_vertices), len(self.vertices))
View
BIN cg2_ex1/theory/ex1.pdf
Binary file not shown.
View
112 cg2_ex1/theory/ex1.tex
@@ -0,0 +1,112 @@
+\documentclass[a4paper,10pt]{scrartcl}
+\usepackage{fancyhdr}
+\usepackage[utf8]{inputenc}
+\usepackage[ngerman]{babel}
+\usepackage{enumerate}
+\usepackage[top=2cm, left=2cm, bottom=2cm, right=2cm]{geometry}
+\usepackage{graphicx}
+\usepackage{listings}
+\usepackage{amsmath}
+\usepackage{amsfonts}
+\usepackage{amssymb}
+\usepackage{float}
+
+\pagestyle{fancy}
+\fancyhf{}
+\fancyhead[L]{\begin{small}Computer Graphics 2\\Übungsblatt 1\\Gruppe 5\end{small}}
+\fancyhead[R]{\begin{small}Stürmer, Felix - 230127 - Informatik(Diplom) - stuermer@cs.tu-berlin.de\\
+ Oskamp, Robert - 306952 - Mathematik(Diplom) - robert.oskamp@gmx.de\\
+ Olthoff, Inken - 305844 - Mathematik(Diplom) - some-body@gmx.de\\
+ Neumann, Cedrik - 301635 - Mathematik(Diplom) - c.neumann@live.de\end{small}}
+\renewcommand{\headrulewidth}{0.4pt}
+\fancyfoot[R]{\thepage}
+\renewcommand{\footrulewidth}{0.4pt}
+
+
+\begin{document}
+\vspace*{1cm}
+\begin{enumerate}[1.]
+
+\item Der Algorithmus zum Auffinden des Medians in linearer Zeit sieht folgenderma"sen aus:\\
+Sei $A$ eine Liste von Zahlen mit $|A| = n$, von denen wir den Median suchen und $k = \lfloor \frac{n}{2} \rfloor$ die Stelle an der wir den Median in einer sortierten Liste finden w"urden.\\
+ Wenn $A$ weniger als z.B. $10$ Elemente besitzt, dann sortieren wir $A$ und geben das $k$-te Element aus.\\
+ Ansonsten teilen wir $A$ in $\lceil \frac{n}{5} \rceil$ viele Teilmengen $S_i$, die aus (maximal) $5$ Elementen bestehen und suchen f"ur alle Teilmengen einzeln den Median $M_i$.\\
+ Als n"achstes berechnen wir den Median $M$ der Mediane $M_i$ und teilen die Menge $A$ in drei disjunkte Teilmengen $A_1$, $A_2$ und $A_3$. Hierbei gilt f"ur die Mengen $a_1 < M ~\forall{a_1 \in A_1}$, $a_2 = M ~\forall{a_2 \in A_2}$ und $a_3 > M ~\forall{a_3 \in A_3}$.\\
+Wenn jetzt f"ur $k$ gilt $k \leq |A_1|$, dann suche den Median in $A_1$ mit $k = k$.\\
+Wenn f"ur $k$ gilt $k > |A_1| + |A_2|$, dann suche Median in $A_3$ mit $k = k - |A_1| - |A_2|$.\\
+Wenn keine der beiden Bedingungen gilt, dann gib $M$ als Median aus.\\
+\newline
+Formal kann man auch schreiben:\\
+\newline
+median$(A,k)$ \{\\
+ \hspace*{5 mm} if $(n \leq 10)$ \{\\
+ \hspace*{10 mm} sort $A$\\
+ \hspace*{10 mm} return the element at the $k$-th position of $A$\\
+ \hspace*{5 mm} \}\\
+ \hspace*{5 mm} partition $A$ into subsets $S_i$ of five elements\\
+ \hspace*{5 mm} for $(i = 1, ~\dots ,~ n/5)$ \{\\
+ \hspace*{10 mm} $M_i = $median$(S_i,3)$\\
+ \hspace*{5 mm}\}\\
+ \hspace*{5 mm} $M = $median$(\{M_i\}_{i=1,\dots,~ n/5},~ n/10)$\\
+ \hspace*{5 mm} partition $A$ into $A_1$ with $a_1 < M ~\forall{a_1 \in A_1}$, $A_2$ with $a_2 = M ~\forall{a_2 \in A_2}$ and $A_3$ with $A_3 = A \setminus (A_1 \cup A_2)$\\
+ \hspace*{5 mm} if $(k \leq |A_1|)$ \{\\
+ \hspace*{10 mm} return median$(A_1,k)$\\
+ \hspace*{5 mm} \}\\
+ \hspace*{5 mm} else if $(k > |A_1| + |A_2|)$ \{\\
+ \hspace*{10 mm} return median$(A_3, k - |A_1| - |A_2|)$\\
+ \hspace*{5 mm} \}\\
+ \hspace*{5 mm} else return $M$\\
+ \}\\
+\newline
+F"ur die Laufzeit gilt:\\
+$\begin{array}{r c l}\\
+T(n)& \leq & \frac{12\cdot n}{5} + T(\frac{n}{5}) + T(\frac{7\cdot n}{10})\\
+& = & \frac{12\cdot n}{5} + \frac{c\cdot n}{5} + \frac{7\cdot c\cdot n}{10}\\
+& = & n\cdot (\frac{12}{5} + \frac{9\cdot c}{10})\\
+\end{array}$\\
+und damit ist die Laufzeit (asymptotisch) linear in $n$.
+
+\item Sei $s$ die Kantenl"ange der kubischen Zelle und der Abstand der $n$ Punkte $\geq \varepsilon$.\\
+In jedem Schritt halbieren wir die Kantenl"angen. Also haben im $k$-ten Schritt die kubischen Zellen die Kantenl"ange $s \cdot 2^{-k}$\\
+Damit die $n$ Punkte sicher in verschiedenen kubischen Zellen liegen, muss die Diagonale der Zellen $< \varepsilon$ sein.\\
+Somit erhalten wir eine maximale Tiefe $k$ f"ur die gilt:
+$$s \cdot 2^{-k} < \frac{\varepsilon}{\sqrt{3}}$$
+$$\Leftrightarrow k > -\log_2{\left( \frac{\varepsilon}{\sqrt{3}\cdot s}\right)} $$
+
+\item
+Betrachte ein Prisma, welches als Grundfläche ein gleichseitiges Dreick hat. Die Grundfläche ist so durch vier teilbar, dass wieder gleichseitige Dreiecke entstehen (siehe nachfolgende Skizze). Teilt man dann noch die Höhe des Prismas durch zwei, so erhält man aus einer solchen Prisma Zelle 8 translierte und um den Faktor 0.5 skalierte Prisma Zellen. Mit diesen Zellen kann jeweils wieder in gleicher Weise verfahren werden, so dass bei dieser Unterteilungsstrategie beliebig viele affin transformierte Versionen des Ausgangsprismas entstehen können.\\
+\includegraphics[scale=0.3]{triangle.png}
+
+\item
+Die Basisfunktionen f"ur einen B-Spline erster Ordnung sehen folgenderma"sen aus:\\
+$N_i^1 (t) = \frac{t - t_i}{t_{i+1} - t_i} \cdot N_i^{0} (t) + \frac{t_{i+2} - t}{t_{i+2} - t_{i+1}} \cdot N_{i+1}^{0} (t)$\\
+\newline
+$N_i^1 (t) = \left\{
+\begin{array}{ c l }
+\frac{t - t_i}{t_{i+1} - t_i} \cdot N_i^{0} (t) &$ , falls $t_i \leq t < t_{i+1} \\
+\frac{t_{i+2} - t}{t_{i+2} - t_{i+1}} \cdot N_{i+1}^{0} (t) &$ , falls $t_{i+1} \leq t < t_{i+2} \\
+0 &$ , sonst$ \\
+\end{array}
+\right.$ \\
+Ein B-Spline erster Ordnung für die Kontrollpunkte $d_0 = (0,0)$, $d_1 = (1,3)$, $d_2 = (2,1)$, $d_3 = (3,2)$ und $d_4 = (4,1)$ sieht wie folgt aus:\\
+\includegraphics[scale=0.5]{spline.png}\\
+Erklären Sie den Zusammenhang zwischen Grad, Stetigkeit und Träger bei B-Splines an diesem Beispiel.
+Ein B-Spline vom Grad $g$ ist $g-1$ mal stetig differenzierbar, also in $C^{g-1}$, zusätzlich vergrößert sich mit höherem Grad der Träger. Im Beispiel haben Grad $g=1$ und sehen an den Kontrollpunkten Ecken, was darauf hindeutet, dass zwar Stetigkeit vorliegt, aber dass die Ableitung nicht mehr stetig ist, es liegt also $C^0$ Stetigkeit vor.
+
+\item
+Wir haben eine Kurve durch Kontrollpunkte $p_i$ im Raum gegeben, sowie Basisfunktionen $\beta_i(x)$.\\
+Die Kontrollpunkte $p_i$ werden nun durch die Basisfunktionen $\beta_i$ gewichtet und addiert, so dass wir folgendes erhalten:
+$$\sum_i{p_i \beta_i(x)}$$
+F"ur diese so konstruierte Kurve soll nun affine Invarianz gilt, also
+$$T \left( \sum_i{p_i \beta_i(x)}\right) = \sum_i{T p_i \beta_i(x)}$$
+Dies gilt trivialerweise f"ur lineare Abbildungen.\\
+Wir k"onnen unsere Transformation $T$ als linearen Abbildung mit einer Translation $T = A + a$ darstellen, wobei $A$ die lineare Abbildung und $a$ die Translation darstellt. (Wissen aus CG1)\\
+Nun gilt f"ur unser T:
+$$T \left( \sum_i{p_i \beta_i(x)}\right) = \sum_i{T p_i \beta_i(x)}$$
+$$\Leftrightarrow \left( A + a \right) \left( \sum_i{p_i \beta_i(x)}\right) = \sum_i{\left( A + a \right) p_i \beta_i(x)}$$
+$$\Leftrightarrow A\left( \sum_i{p_i \beta_i(x)}\right) + a = \sum_i{\left( A p_i \beta_i(x) + a \beta_i(x) \right)} $$
+$$\Leftrightarrow A\left( \sum_i{p_i \beta_i(x)}\right) + a = \sum_i{A p_i \beta_i(x)} + \sum_i{a \beta_i(x)}$$
+und dies gilt genau dann, wenn die $\beta_i$ an jeder Stelle eine Partition der Eins sind, also $\sum_i{\beta_i(x)} = 1 ~ \forall x$.\\
+
+\end{enumerate}
+\end{document}
View
BIN cg2_ex1/theory/spline.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN cg2_ex1/theory/triangle.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
16 cg2_ex1/tk_global_frame.py
@@ -0,0 +1,16 @@
+from Tkinter import *
+
+from cg2kit import *
+
+class GlobalOptionsFrame(Frame):
+ def __init__(self, master=None):
+ Frame.__init__(self, master,
+ borderwidth=1,
+ relief=GROOVE)
+ self._tk_title = Label(self, text="Global Options", width=30)
+ self._tk_title.grid(row=0, sticky=W)
+ self._button_clear = Button(self, text="Clear Scene", command=self._clear_scene)
+ self._button_clear.grid(row=1, sticky=E+W)
+
+ def _clear_scene(self):
+ getScene().clear()
View
527 cg2_ex1/tk_viewer.py
@@ -0,0 +1,527 @@
+#!/usr/bin/python
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Python Computer Graphics Kit.
+#
+# The Initial Developer of the Original Code is Matthias Baas.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+# $Id: viewer.py,v 1.13 2006/03/03 09:13:59 mbaas Exp $
+
+"""Viewer tool.
+
+Global options:
+
+background Background color (must be anything that can be passed to the
+ vec4 constructor).
+fullscreen Boolean indicating if a full screen view should be used
+stereo Stereo setting (None, "vsplit", "glstereo")
+eyedistance Eye distance for stereo display
+polygonmode Drawing mode ("fill", "line", "point")
+navigationmode Selects the navigation mode ("maya", "max", "softimage")
+resolution (width, height) (aspect is ignored)
+fps Framerate
+camera Specify camera to be used
+"""
+
+import sys
+import os
+import os.path
+import logging
+from optparse import OptionParser
+from ConfigParser import SafeConfigParser
+
+#sys.path = [r"D:\tmp\pygame_src\pygame-1.6.2\build\lib.win32-2.3"]+sys.path
+import pygame
+from pygame.locals import *
+from cgkit._OpenGL.GL import *
+#from cgkit._OpenGL.GLU import *
+import cgkit._Image as Image
+
+from math import *
+from cg2kit import *
+from cgkit.scene import getScene
+import cgkit
+from cgkit.cmds import *
+from cgkit.tool import Tool
+from cgkit.Interfaces import *
+
+import cgkit.wintab
+from cgkit.wintab.constants import *
+import cgkit.spacedevice
+
+from Tkinter import *
+from tk_global_frame import GlobalOptionsFrame
+
+
+# Viewer
+class Viewer(object):
+ """Viewer tool."""
+
+ def __init__(self):
+ self._init_log()
+ self._init_config(['cg2_defaults.conf'])
+ self._init_modules()
+ self._init_input()
+ self._init_tk()
+ self._init_gl()
+ #self._init_camera()
+
+ def _init_log(self):
+ logging.basicConfig(level=logging.DEBUG)
+ self._log = logging.getLogger("Application")
+ self._log.info(u"Starting up...")
+
+ def _init_config(self, default_config_files):
+ self._log.info(u"Initializing configuration...")
+ config_files = list(default_config_files)
+
+ parser = OptionParser()
+ parser.add_option('-c', '--conf', dest='config_file', default=None, help=u"config file to use (besides cg1_defaults.conf)")
+ (options, args) = parser.parse_args()
+
+ if options.config_file:
+ config_files.append(options.config_file)
+
+ self._log.info(u"Reading config files %s...", config_files)
+ self._config = SafeConfigParser()
+ self._config.read(config_files)
+
+ #scene = getScene()
+ #scene.setGlobal("stereo", self.options.stereo)
+ #scene.setGlobal("polygonmode", self.options.polygon_mode)
+ #scene.setGlobal("navigationmode", self.options.navigation_mode)
+ #self.separate_specular_color = False
+ #self.draw_orientation = True
+
+ self._modules = args
+
+ sys.setrecursionlimit(4000)
+ self._log.info(u"Recursion limit is now %d." % sys.getrecursionlimit())
+
+ def _init_modules(self):
+ self._log.info(u"Initializing modules...")
+ self._scene_globals = {'scene' : cgkit.scene.getScene()}
+ for filename in self._modules:
+ execfile(filename, self._scene_globals)
+ self.tk_option_frame_classes = list(self._scene_globals['option_frames'])
+
+ def _init_input(self):
+ self._log.info(u"Initializing input...")
+ self.keydict = {
+ 8 : KEY_BACK,
+ 9 : KEY_TAB,
+ 13 : KEY_RETURN,
+ 27 : KEY_ESCAPE,
+ 32 : KEY_SPACE,
+ 276 : KEY_LEFT,
+ 273 : KEY_UP,
+ 275 : KEY_RIGHT,
+ 274 : KEY_DOWN,
+ 301 : KEY_CAPSLOCK,
+ 304 : KEY_SHIFT_LEFT,
+ 303 : KEY_SHIFT_RIGHT,
+ 306 : KEY_CONTROL_LEFT,
+ 305 : KEY_CONTROL_RIGHT,
+ 308 : KEY_ALT_LEFT,
+ 307 : KEY_ALT_RIGHT,
+ 310 : KEY_WINDOWS_LEFT,
+ 309 : KEY_WINDOWS_RIGHT,
+ 319 : KEY_WINDOWS_MENU,
+ 317 : KEY_PRINT,
+ 302 : KEY_SCROLL,
+ 19 : KEY_PAUSE,
+ 277 : KEY_INSERT,
+ 127 : KEY_DELETE,
+ 278 : KEY_HOME,
+ 279 : KEY_END,
+ 280 : KEY_PRIOR,
+ 281 : KEY_NEXT,
+ 282 : KEY_F1,
+ 283 : KEY_F2,
+ 284 : KEY_F3,
+ 285 : KEY_F4,
+ 286 : KEY_F5,
+ 287 : KEY_F6,
+ 288 : KEY_F7,
+ 289 : KEY_F8,
+ 290 : KEY_F9,
+ 291 : KEY_F10,
+ 292 : KEY_F11,
+ 293 : KEY_F12,
+ 300 : KEY_NUMLOCK,
+ 256 : KEY_NUMPAD0,
+ 257 : KEY_NUMPAD1,
+ 258 : KEY_NUMPAD2,
+ 259 : KEY_NUMPAD3,
+ 260 : KEY_NUMPAD4,
+ 261 : KEY_NUMPAD5,
+ 262 : KEY_NUMPAD6,
+ 263 : KEY_NUMPAD7,
+ 264 : KEY_NUMPAD8,
+ 265 : KEY_NUMPAD9,
+ 266 : KEY_NUMPAD_DECIMAL,
+ 267 : KEY_NUMPAD_DIVIDE,
+ 268 : KEY_NUMPAD_MULTIPLY,
+ 269 : KEY_NUMPAD_SUBTRACT,
+ 270 : KEY_NUMPAD_ADD,
+ 271 : KEY_NUMPAD_ENTER
+ }
+
+ def _init_tk(self):
+ self._log.info(u"Initializing tk widgets...")
+ self.tk_root = Tk()
+ self.tk_option_frames = []
+ self.tk_run_button = Button(self.tk_root, text="Run", command=self.run_gl)
+ self.tk_run_button.grid(row=0, column=0, sticky=W+E)
+ self.tk_option_frame_classes = [GlobalOptionsFrame, ] + getattr(self, 'tk_option_frame_classes', [])
+ for index, option_frame_class in enumerate(self.tk_option_frame_classes):
+ option_frame = option_frame_class(self.tk_root)
+ option_frame.grid(row=index+1, column=0, sticky=W+E)
+ self.tk_option_frames.append(option_frame)
+
+ def _init_gl(self):
+ self._log.info(u"Initializing opengl renderer...")
+ passed, failed = pygame.init()
+ if failed>0:
+ self._log.error(u"Warning: %d pygame modules couldn't be initialized" % failed)
+ self.gl_renderer = GLRenderInstance()
+
+ def _init_camera(self):
+ scene = getScene()
+
+ if self._config.has_option('scene', 'camera'):
+ cname = self._config.get('scene', 'camera')
+ else:
+ cname = None
+
+ # Search for a camera...
+ cam = None
+ for obj in scene.walkWorld():
+ prots = obj.protocols()
+ if ICamera in prots:
+ if obj.name==cname or cname==None :
+ cam = obj
+ break
+
+ if cname!=None and cam==None:
+ raise ValueError, 'Camera "%s" not found.' % cname
+
+ # No camera? Then create a default camera...
+ if cam==None:
+ self._log.info(u"No camera set, using a default camera.")
+ bbmin, bbmax = scene.boundingBox().getBounds()
+ dif = bbmax-bbmin
+ b1 = scene.up.ortho()
+ b2 = scene.up.cross(b1)
+ pos = dif.length()*(0.5*b1+b2) + (bbmax.z+0.5*dif.z)*scene.up
+ if abs(dif.z)<0.0001:
+ pos += 0.8*dif.length()*scene.up
+ cam = TargetCamera(pos = pos,
+ target = 0.5*(bbmin+bbmax)-0.2*(dif.z*scene.up),
+ fov = 50)
+ else:
+ self._log.info(u"Camera: %s" % cam.name)
+
+ self._camera = cam
+
+ def run(self):
+ self.tk_root.mainloop()
+
+ def run_gl(self):
+ # Create a camera control component
+ self._init_camera()
+ CameraControl(cam=self._camera, mode=1)
+
+ # Get options...
+ width = self._config.getint('window', 'width')
+ height = self._config.getint('window', 'height')
+
+ # Open a window...
+ pygame.display.set_caption("OpenGL viewer")
+ flags = OPENGL | DOUBLEBUF
+ self.gl_surface = pygame.display.set_mode((width,height), flags)
+
+ # Try to get the native window handle
+ # (this only works with pygame 1.6.2 and later)
+ try:
+ info = pygame.display.get_wm_info()
+ hwnd = info["window"]
+ except:
+ hwnd = None
+
+ # Event loop...
+ self._running = True
+ self._timer = getScene().timer()
+ self._clock = pygame.time.Clock()
+ self._cnt = 0
+ self._timer.startClock()
+ self._fps = self._config.getint('general', 'framerate')
+
+ self.tk_root.after(50, self._loop_once, width, height)
+ self._log.info(u"3d visualization running...")
+
+ def stop_gl(self):
+ self._running = False
+
+ def _loop_once(self, width, height):
+ if self._running:
+ self.tk_root.after(1000/self._fps, self._loop_once, width, height)
+
+ # Display the scene
+ self.draw(self._camera, width, height)
+ pygame.display.flip()
+
+ # Handle events
+ events = pygame.event.get()
+ self.handleEvents(events)
+
+ self._timer.step()
+
+ # Sync
+ self._clock.tick(1000/self._fps)
+
+ # handleEvents
+ def handleEvents(self, events):
+ eventmanager = eventManager()
+ width = self._config.getint('window', 'width')
+ height = self._config.getint('window', 'height')
+ for e in events:
+ if e.type==QUIT:
+ self._running=False
+ # KEYDOWN?
+ elif e.type==KEYDOWN:
+ if e.key==27:
+ self._running=False
+ key = e.unicode
+ code = self.keydict.get(e.key, e.key)
+ mods = self.convertMods(e.mod)
+ eventmanager.event(KEY_PRESS, KeyEvent(key, code, mods))
+# keyboard.setKeyValue(e.key, True)
+ # KEYUP
+ elif e.type==KEYUP:
+ code = self.keydict.get(e.key, e.key)
+ try:
+ key = unicode(chr(e.key))
+ except:
+ key = u""
+ mods = self.convertMods(e.mod)
+ eventmanager.event(KEY_RELEASE, KeyEvent(key, code, mods))
+# keyboard.setKeyValue(e.key, False)
+ # MOUSEBUTTONDOWN
+ elif e.type==MOUSEBUTTONDOWN:
+ x,y = e.pos
+ x0 = float(x)/width
+ y0 = float(y)/height
+ if e.button==1:
+ eventname = LEFT_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==2:
+ eventname = MIDDLE_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==3:
+ eventname = RIGHT_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==4:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(120, x, y, x0, y0)
+ elif e.button==5:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(-120, x, y, x0, y0)
+ else:
+ eventname = MOUSE_BUTTON_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ eventmanager.event(eventname, evt)
+ # MOUSEBUTTONUP
+ elif e.type==MOUSEBUTTONUP:
+ x,y = e.pos
+ x0 = float(x)/width
+ y0 = float(y)/height
+ if e.button==1:
+ eventname = LEFT_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==2:
+ eventname = MIDDLE_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==3:
+ eventname = RIGHT_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==4:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(120, x, y, x0, y0)
+ elif e.button==5:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(-120, x, y, x0, y0)
+ else:
+ eventname = MOUSE_BUTTON_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ eventmanager.event(eventname, evt)
+ # MOUSEMOTION
+ elif e.type==MOUSEMOTION:
+ btns = 0
+ b1,b2,b3 = e.buttons
+ if b1:
+ btns |= 0x1
+ if b2:
+ btns |= 0x2
+ if b3:
+ btns |= 0x4
+ x,y = e.pos
+ dx, dy = e.rel
+ x0 = float(x)/width
+ y0 = float(y)/height
+ dx0 = float(dx)/width
+ dy0 = float(dy)/height
+ evt = MouseMoveEvent(x, y, dx, dy, x0, y0, dx0, dy0, btns)
+ eventmanager.event(MOUSE_MOVE, evt)
+ # SYSWMEVENT
+ elif e.type==SYSWMEVENT:
+ if sys.platform=="win32" and not hasattr(e, "msg") and not pygame.event.get_blocked(SYSWMEVENT):
+ pygame.event.set_blocked(SYSWMEVENT)
+ print "Warning: This version of pygame does not allow processing system events."
+
+ def setOptions(self, optparser):
+ """Add options specific to this tool."""
+
+ Tool.setOptions(self, optparser)
+ optparser.add_option("-F", "--full-screen", action="store_true", default=False,
+ help="Full screen display")
+ optparser.add_option("-S", "--stereo", metavar="MODE",
+ help="Activate stereo display (vsplit, glstereo)")
+ optparser.add_option("-D", "--eye-distance", type="float", default=0.07,
+ help="Default eye distance for stereo display. Default: 0.07")
+ optparser.add_option("-B", "--bounding-box", action="store_true", default=False,
+ help="Show bounding boxes")
+ optparser.add_option("-P", "--polygon-mode", metavar="MODE",
+ help="Polygon mode (fill, line, point). Default: fill")
+ optparser.add_option("-s", "--save", metavar="NAME",
+ help="Save screenshots as images.")
+ optparser.add_option("-N", "--navigation-mode", metavar="MODE",
+ help="Navigation mode (MAX, Maya, Softimage). Default: Maya")
+ optparser.add_option("-X", "--disable-spacedevice", action="store_true", default=False,
+ help="Disable SpaceMouse/SpaceBall.")
+ optparser.add_option("-T", "--disable-wintab", action="store_true", default=False,
+ help="Disable tablet support.")
+
+ def convertMods(self, mods):
+ """Convert pygame key modifier flags to cgkit modifier flags.
+ """
+ res = 0
+ if mods & 0x0001 or mods & 0x0002:
+ res |= KEYMOD_SHIFT
+ if mods & 0x0040 or mods & 0x0080:
+ res |= KEYMOD_CONTROL
+ if mods & 0x0100 or mods & 0x0200:
+ res |= KEYMOD_ALT
+ return res
+
+ def draw(self, cam, width, height):
+ scene = getScene()
+ renderer = self.gl_renderer
+
+ # Set handedness
+ renderer.left_handed = scene.handedness=="l"
+ renderer.setViewport(0,0,width,height)
+
+ renderer.draw_solid = True
+ #renderer.draw_bboxes = self.options.bounding_box
+ renderer.draw_coordsys = False
+ #renderer.draw_orientation = self.draw_orientation
+ renderer.smooth_model = True
+ renderer.backface_culling = False
+ #renderer.separate_specular_color = self.separate_specular_color
+ #renderer.polygon_mode = self.polygon_mode # 0=Point 1=Line 2=Fill
+ #renderer.stereo_mode = self.stereo_mode
+ renderer.clearcol = vec4(scene.getGlobal("background", vec4(0.5,0.5,0.6,0)))
+
+ # Set projection matrix
+ near, far = cam.getNearFar()
+ P = cam.projection(width,height,near,far)
+ renderer.setProjection(P)
+
+ # Set view matrix
+ renderer.setViewTransformation(cam.viewTransformation(), 0)
+
+ # Draw scene
+ root = scene.worldRoot()
+ renderer.paint(root)
+
+ # saveScreenshot
+ def saveScreenshot(self, srf):
+ """Save the current window content.
+
+ srf is the pygame Surface object.
+ """
+ name,ext = os.path.splitext(self.options.save)
+ f = int(round(getScene().timer().frame))
+ fname = "%s%04d%s"%(name, f, ext)
+ print 'Saving "%s"...'%fname
+ data = pygame.image.tostring(srf, "RGB")
+ img = Image.fromstring("RGB", (srf.get_width(), srf.get_height()), data)
+ img.save(fname)
+
+ # setOptionsFromGlobals
+ def setOptionsFromGlobals(self):
+ Tool.setOptionsFromGlobals(self)
+
+ scene = getScene()
+ self.options.full_screen = scene.getGlobal("fullscreen", self.options.full_screen)
+
+ self.options.eye_distance = float(scene.getGlobal("eyedistance", self.options.eye_distance))
+
+ # Check the stereo option and initialize the variable "stereo_mode"
+ Sopt = scene.getGlobal("stereo", None)
+ self.stereo_mode = self.translateKeyWordOpt(Sopt,
+ { None:0, "vsplit":1, "glstereo":2 },
+ "Unknown stereo mode: '%s'")
+
+ # Check the polygon mode option
+ Popt = scene.getGlobal("polygonmode", "fill")
+ self.polygon_mode = self.translateKeyWordOpt(Popt,
+ { None:2, "point":0, "line":1, "fill":2 },
+ "Unknown polygon mode: '%s'")
+
+ # Check the navigationmode option
+ Nopt = scene.getGlobal("navigationmode", "maya")
+ self.navigation_mode = self.translateKeyWordOpt(Nopt,
+ { None:1, "max":0, "maya":1, "softimage":2 },
+ "Unknown navigation mode: '%s'")
+
+
+
+
+
+######################################################################
+
+if __name__=="__main__":
+ viewer = Viewer()
+ viewer.run()
+
+
View
683 cg2_ex1/tk_viewer_prototype.py
@@ -0,0 +1,683 @@
+#!/usr/bin/python
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Python Computer Graphics Kit.
+#
+# The Initial Developer of the Original Code is Matthias Baas.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+# $Id: viewer.py,v 1.13 2006/03/03 09:13:59 mbaas Exp $
+
+"""Viewer tool.
+
+Global options:
+
+background Background color (must be anything that can be passed to the
+ vec4 constructor).
+fullscreen Boolean indicating if a full screen view should be used
+stereo Stereo setting (None, "vsplit", "glstereo")
+eyedistance Eye distance for stereo display
+polygonmode Drawing mode ("fill", "line", "point")
+navigationmode Selects the navigation mode ("maya", "max", "softimage")
+resolution (width, height) (aspect is ignored)
+fps Framerate
+camera Specify camera to be used
+"""
+
+import sys, os, os.path
+#sys.path = [r"D:\tmp\pygame_src\pygame-1.6.2\build\lib.win32-2.3"]+sys.path
+import pygame
+from pygame.locals import *
+from cgkit._OpenGL.GL import *
+#from cgkit._OpenGL.GLU import *
+import cgkit._Image as Image
+
+from math import *
+from cgkit.all import *
+from cgkit.scene import getScene
+import cgkit
+from cgkit.cmds import *
+from cgkit.tool import Tool
+
+import cgkit.wintab
+from cgkit.wintab.constants import *
+import cgkit.spacedevice
+
+from Tkinter import *
+
+
+# Viewer
+class Viewer(Tool):
+ """Viewer tool."""
+
+ def __init__(self):
+ Tool.__init__(self, defaultoptionvar="VIEWER_DEFAULT_OPTIONS")
+
+ self.pygame_joysticks = []
+ self.cgkit_joysticks = []
+
+ self.spacedevice = None
+ self.enable_spacedevice = False # Disable SpaceMouse for now
+
+ self.wintabcontext = None
+ self.enable_wintab = True
+
+ if sys.platform!="win32":
+ self.enable_spacedevice = False
+ self.enable_wintab = False
+
+ scene = getScene()
+ scene.setGlobal("stereo", self.options.stereo)
+ scene.setGlobal("polygonmode", self.options.polygon_mode)
+ scene.setGlobal("navigationmode", self.options.navigation_mode)
+
+ self.separate_specular_color = False
+ self.draw_orientation = True
+
+ self.keydict = {
+ 8 : KEY_BACK,
+ 9 : KEY_TAB,
+ 13 : KEY_RETURN,
+ 27 : KEY_ESCAPE,
+ 32 : KEY_SPACE,
+ 276 : KEY_LEFT,
+ 273 : KEY_UP,
+ 275 : KEY_RIGHT,
+ 274 : KEY_DOWN,
+ 301 : KEY_CAPSLOCK,
+ 304 : KEY_SHIFT_LEFT,
+ 303 : KEY_SHIFT_RIGHT,
+ 306 : KEY_CONTROL_LEFT,
+ 305 : KEY_CONTROL_RIGHT,
+ 308 : KEY_ALT_LEFT,
+ 307 : KEY_ALT_RIGHT,
+ 310 : KEY_WINDOWS_LEFT,
+ 309 : KEY_WINDOWS_RIGHT,
+ 319 : KEY_WINDOWS_MENU,
+ 317 : KEY_PRINT,
+ 302 : KEY_SCROLL,
+ 19 : KEY_PAUSE,
+ 277 : KEY_INSERT,
+ 127 : KEY_DELETE,
+ 278 : KEY_HOME,
+ 279 : KEY_END,
+ 280 : KEY_PRIOR,
+ 281 : KEY_NEXT,
+ 282 : KEY_F1,
+ 283 : KEY_F2,
+ 284 : KEY_F3,
+ 285 : KEY_F4,
+ 286 : KEY_F5,
+ 287 : KEY_F6,
+ 288 : KEY_F7,
+ 289 : KEY_F8,
+ 290 : KEY_F9,
+ 291 : KEY_F10,
+ 292 : KEY_F11,
+ 293 : KEY_F12,
+ 300 : KEY_NUMLOCK,
+ 256 : KEY_NUMPAD0,
+ 257 : KEY_NUMPAD1,
+ 258 : KEY_NUMPAD2,
+ 259 : KEY_NUMPAD3,
+ 260 : KEY_NUMPAD4,
+ 261 : KEY_NUMPAD5,
+ 262 : KEY_NUMPAD6,
+ 263 : KEY_NUMPAD7,
+ 264 : KEY_NUMPAD8,
+ 265 : KEY_NUMPAD9,
+ 266 : KEY_NUMPAD_DECIMAL,
+ 267 : KEY_NUMPAD_DIVIDE,
+ 268 : KEY_NUMPAD_MULTIPLY,
+ 269 : KEY_NUMPAD_SUBTRACT,
+ 270 : KEY_NUMPAD_ADD,
+ 271 : KEY_NUMPAD_ENTER
+ }
+
+ def setOptions(self, optparser):
+ """Add options specific to this tool."""
+
+ Tool.setOptions(self, optparser)
+ optparser.add_option("-F", "--full-screen", action="store_true", default=False,
+ help="Full screen display")
+ optparser.add_option("-S", "--stereo", metavar="MODE",
+ help="Activate stereo display (vsplit, glstereo)")
+ optparser.add_option("-D", "--eye-distance", type="float", default=0.07,
+ help="Default eye distance for stereo display. Default: 0.07")
+ optparser.add_option("-B", "--bounding-box", action="store_true", default=False,
+ help="Show bounding boxes")
+ optparser.add_option("-P", "--polygon-mode", metavar="MODE",
+ help="Polygon mode (fill, line, point). Default: fill")
+ optparser.add_option("-s", "--save", metavar="NAME",
+ help="Save screenshots as images.")
+ optparser.add_option("-N", "--navigation-mode", metavar="MODE",
+ help="Navigation mode (MAX, Maya, Softimage). Default: Maya")
+ optparser.add_option("-X", "--disable-spacedevice", action="store_true", default=False,
+ help="Disable SpaceMouse/SpaceBall.")
+ optparser.add_option("-T", "--disable-wintab", action="store_true", default=False,
+ help="Disable tablet support.")
+
+
+ # init
+ def init(self):
+ self.root = Tk()
+ self.w = Label(self.root, text="Hallo")
+ self.w.pack()
+
+ # Initialize pygame
+ passed, failed = pygame.init()
+ if failed>0:
+ print "Warning: %d pygame modules couldn't be initialized"%failed
+
+ # Initialize joysticks...
+ numjoy = pygame.joystick.get_count()
+ if self.options.verbose:
+ print numjoy, "joysticks available"
+
+ self.pygame_joysticks = []
+ self.cgkit_joysticks = []
+ for id in range(numjoy):
+ j = pygame.joystick.Joystick(id)
+ j.init()
+ self.pygame_joysticks.append(j)
+ # Create a cgkit joystick object...
+ id = j.get_id()
+ name = j.get_name()
+ numaxes = j.get_numaxes()
+ numballs = j.get_numballs()
+ numhats = j.get_numhats()
+ numbuttons = j.get_numbuttons()
+ cgj = Joystick(id=id, name=name, numaxes=numaxes, numhats=numhats,
+ numballs=numballs, numbuttons=numbuttons)
+ getScene().setJoystick(cgj)
+ # Initialize the values
+ # for i in range(numaxes):
+ # cgj.setAxis(i, j.get_axis(i))
+ self.cgkit_joysticks.append(cgj)
+ if self.options.verbose:
+ print "Joystick #%d (%s):"%(id, name)
+ print " %d axes, %d balls, %d buttons, %d hats"%(numaxes, numballs, numbuttons, numhats)
+
+ if self.options.disable_spacedevice:
+ self.enable_spacedevice = True # temporarily invert the meaning of -X
+# self.enable_spacedevice = False
+ if self.options.disable_wintab:
+ self.enable_wintab = False
+
+ # Initialize SpaceMouse/SpaceBall
+ if self.enable_spacedevice and cgkit.spacedevice.available():
+ try:
+ self.spacedevice = cgkit.spacedevice.SpaceDevice()
+ except RuntimeError, e:
+ print "3DxWare exception:",e
+ else:
+ if self.options.verbose and self.enable_spacedevice:
+ print "SpaceMouse/SpaceBall module (spacedevice) not available"
+
+ # Initialize Wintab context
+ if self.enable_wintab and cgkit.wintab.available():
+ if self.options.verbose:
+ info = cgkit.wintab.info(WTI_INTERFACE)
+ print 'Wintab identification: "%s"'%info["WINTABID"]
+ info = cgkit.wintab.info(WTI_DEVICES)
+ print "Initializing %s..."%info["NAME"]
+
+ self.wintabcontext = cgkit.wintab.Context()
+ ctx = self.wintabcontext
+ ctx.name = os.path.basename(sys.argv[0])
+ ctx.options = 0
+
+ # Compute the pktdata attribute...
+ ncursors = cgkit.wintab.info(WTI_INTERFACE)["NCURSORS"]
+ pktdata = 0
+ for i in range(ncursors):
+ info = cgkit.wintab.info(WTI_CURSORS+i)
+ pd = info["PKTDATA"]
+ if pd!=None:
+ pktdata |= pd
+ ctx.pktdata = pktdata
+ else:
+ if self.options.verbose and self.enable_wintab:
+ print "No Wintab driver available"
+
+ # Create renderer
+ self.renderer = GLRenderInstance()
+
+ # setOptionsFromGlobals
+ def setOptionsFromGlobals(self):
+ Tool.setOptionsFromGlobals(self)
+
+ scene = getScene()
+ self.options.full_screen = scene.getGlobal("fullscreen", self.options.full_screen)
+
+ self.options.eye_distance = float(scene.getGlobal("eyedistance", self.options.eye_distance))
+
+ # Check the stereo option and initialize the variable "stereo_mode"
+ Sopt = scene.getGlobal("stereo", None)
+ self.stereo_mode = self.translateKeyWordOpt(Sopt,
+ { None:0, "vsplit":1, "glstereo":2 },
+ "Unknown stereo mode: '%s'")
+
+ # Check the polygon mode option
+ Popt = scene.getGlobal("polygonmode", "fill")
+ self.polygon_mode = self.translateKeyWordOpt(Popt,
+ { None:2, "point":0, "line":1, "fill":2 },
+ "Unknown polygon mode: '%s'")
+
+ # Check the navigationmode option
+ Nopt = scene.getGlobal("navigationmode", "maya")
+ self.navigation_mode = self.translateKeyWordOpt(Nopt,
+ { None:1, "max":0, "maya":1, "softimage":2 },
+ "Unknown navigation mode: '%s'")
+
+ # action
+ def action(self):
+ # Display the scene using pygame...
+ scene = getScene()
+ timer = scene.timer()
+
+ # Create a camera control component
+ CameraControl(cam=self.cam, mode=self.navigation_mode)
+
+ # Get options...
+ fps = timer.fps
+ width = self.options.width
+ height = self.options.height
+
+ # Open a window...
+ pygame.display.set_caption("OpenGL viewer")
+ if self.stereo_mode==2:
+ pygame.display.gl_set_attribute(pygame.GL_STEREO, 1)
+ flags = OPENGL | DOUBLEBUF
+ if self.options.full_screen:
+ flags |= FULLSCREEN
+ srf = pygame.display.set_mode((width,height), flags)
+
+ # Output OpenGL infos...
+ if self.options.verbose:
+ print "OpenGL information:"
+ print " Vendor :",glGetString(GL_VENDOR)
+ print " Renderer:", glGetString(GL_RENDERER)
+ print " Version :",glGetString(GL_VERSION)
+
+ # Check if stereo output is active...
+ if self.stereo_mode==2:
+ if pygame.display.gl_get_attribute(pygame.GL_STEREO)==0:
+ raise RuntimeError, "Stereo buffers not supported by this hardware."
+
+ # Try to get the native window handle
+ # (this only works with pygame 1.6.2 and later)
+ try:
+ info = pygame.display.get_wm_info()
+ hwnd = info["window"]
+ except:
+ hwnd = None
+
+ # Open SpaceMouse/SpaceBall device...
+ if self.spacedevice!=None:
+ if hwnd==None:
+ if sys.platform=="win32" and self.options.verbose:
+ print "SpaceMouse/SpaceBall support is not available with the installed version"
+ print "of pygame. Please upgrade to v1.6.2 or later."
+ else:
+ try:
+ self.spacedevice.open("viewer.py", hwnd)
+ self.spacedevice.setUIMode(True)
+ if self.options.verbose:
+ typ,btns,degs,beep,firmware = self.spacedevice.getDeviceInfo()
+ print "3D input device:",firmware
+ print "%s: %d buttons, %d degrees of freedom"%(typ,btns,degs)
+ pygame.event.set_allowed(SYSWMEVENT)
+ except RuntimeError, e:
+ print "SpaceDevice:",e
+ print "SpaceMouse/SpaceBall support is disabled."
+ self.spacedevice = None
+
+ # Open Wintab context
+ if self.wintabcontext!=None:
+ if hwnd==None:
+ self.wintabcontext = None
+ if sys.platform=="win32" and self.options.verbose:
+ print "Tablet support is not available with the installed version of pygame."
+ print "Please upgrade to v1.6.2 or later."
+ else:
+ self.wintabcontext.open(hwnd, True)
+ pygame.event.set_allowed(SYSWMEVENT)
+
+ # Event loop...
+ self.running = True
+ active = True
+ clk = pygame.time.Clock()
+ cnt = 0
+ timer.startClock()
+
+ self.root.after(50, self.loop_once, clk, timer, width, height)
+ self.root.mainloop()
+ #while self.running:
+ # self.loop_once(clk, timer)
+
+ def loop_once(self, clk, timer, width, height):
+ self.root.after(50, self.loop_once, clk, timer, width, height)
+ # Display the scene
+ self.draw(self.cam, width, height)
+ pygame.display.flip()
+
+ # Handle events
+ events = pygame.event.get()
+ self.handleEvents(events)
+
+ if self.wintabcontext!=None:
+ self.handleWintabEvents()
+
+ if self.time_end!=None and timer.time>self.time_end+1E-10:
+ active = False
+ else:
+ active = True
+
+ if active:
+ if self.options.save!=None:
+ self.saveScreenshot(srf)
+
+ # Step time
+ timer.step()
+
+ # Sync
+ clk.tick(timer.fps)
+ #cnt+=1
+# if cnt==25:
+# print "fps: %d"%clk.get_fps()
+# print "Virtual time:",timer.time, "Real time:",timer.clock
+# cnt=0
+
+
+
+ # handleEvents
+ def handleEvents(self, events):
+ eventmanager = eventManager()
+ for e in events:
+ if e.type==QUIT:
+ self.running=False
+ # KEYDOWN?
+ elif e.type==KEYDOWN:
+ if e.key==27:
+ self.running=False
+ key = e.unicode
+ code = self.keydict.get(e.key, e.key)
+ mods = self.convertMods(e.mod)
+ eventmanager.event(KEY_PRESS, KeyEvent(key, code, mods))
+# keyboard.setKeyValue(e.key, True)
+ # KEYUP
+ elif e.type==KEYUP:
+ code = self.keydict.get(e.key, e.key)
+ try:
+ key = unicode(chr(e.key))
+ except:
+ key = u""
+ mods = self.convertMods(e.mod)
+ eventmanager.event(KEY_RELEASE, KeyEvent(key, code, mods))
+# keyboard.setKeyValue(e.key, False)
+ # MOUSEBUTTONDOWN
+ elif e.type==MOUSEBUTTONDOWN:
+ x,y = e.pos
+ x0 = float(x)/self.options.width
+ y0 = float(y)/self.options.height
+ if e.button==1:
+ eventname = LEFT_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==2:
+ eventname = MIDDLE_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==3:
+ eventname = RIGHT_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==4:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(120, x, y, x0, y0)
+ elif e.button==5:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(-120, x, y, x0, y0)
+ else:
+ eventname = MOUSE_BUTTON_DOWN
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ eventmanager.event(eventname, evt)
+ # MOUSEBUTTONUP
+ elif e.type==MOUSEBUTTONUP:
+ x,y = e.pos
+ x0 = float(x)/self.options.width
+ y0 = float(y)/self.options.height
+ if e.button==1:
+ eventname = LEFT_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==2:
+ eventname = MIDDLE_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==3:
+ eventname = RIGHT_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ elif e.button==4:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(120, x, y, x0, y0)
+ elif e.button==5:
+ eventname = MOUSE_WHEEL
+ evt = MouseWheelEvent(-120, x, y, x0, y0)
+ else:
+ eventname = MOUSE_BUTTON_UP
+ evt = MouseButtonEvent(e.button, x, y, x0, y0)
+ eventmanager.event(eventname, evt)
+ # MOUSEMOTION
+ elif e.type==MOUSEMOTION:
+ btns = 0
+ b1,b2,b3 = e.buttons
+ if b1:
+ btns |= 0x1
+ if b2:
+ btns |= 0x2
+ if b3:
+ btns |= 0x4
+ x,y = e.pos
+ dx, dy = e.rel
+ width = self.options.width
+ height = self.options.height
+ x0 = float(x)/width
+ y0 = float(y)/height
+ dx0 = float(dx)/width
+ dy0 = float(dy)/height
+ evt = MouseMoveEvent(x, y, dx, dy, x0, y0, dx0, dy0, btns)
+ eventmanager.event(MOUSE_MOVE, evt)
+ # JOYAXISMOTION
+ elif e.type==JOYAXISMOTION:
+ self.cgkit_joysticks[e.joy].setAxis(e.axis, e.value)
+# e = JoystickAxisEvent(e.joy, e.axis, e.value)
+# print e
+# eventmanager.event(JOYSTICK_AXIS, e)
+ # JOYBALLMOTION
+ elif e.type==JOYBALLMOTION:
+ self.cgkit_joysticks[e.joy].setBall(e.ball, e.value)
+# e = JoystickBallEvent(e.joy, e.ball, e.value)
+# print e
+# eventmanager.event(JOYSTICK_BALL, e)
+ # JOYHATMOTION
+ elif e.type==JOYHATMOTION:
+ x,y = e.value
+ self.cgkit_joysticks[e.joy].setBall(e.hat, x, y)
+# e = JoystickHatEvent(e.joy, e.hat, x, y)
+# print e
+# eventmanager.event(JOYSTICK_HAT, e)
+ # JOYBUTTONUP
+ elif e.type==JOYBUTTONUP:
+ self.cgkit_joysticks[e.joy].setButton(e.button, False)
+# e = JoystickButtonEvent(e.joy, e.button)
+# print "up",e
+# eventmanager.event(JOYSTICK_BUTTON_UP, e)
+ # JOYBUTTONDOWN
+ elif e.type==JOYBUTTONDOWN:
+ self.cgkit_joysticks[e.joy].setButton(e.button, True)
+# e = JoystickButtonEvent(e.joy, e.button)
+# print "down",e
+# eventmanager.event(JOYSTICK_BUTTON_DOWN, e)
+ # SYSWMEVENT
+ elif e.type==SYSWMEVENT:
+ if sys.platform=="win32" and not hasattr(e, "msg") and not pygame.event.get_blocked(SYSWMEVENT):
+ pygame.event.set_blocked(SYSWMEVENT)
+ print "Warning: This version of pygame does not allow processing system events."
+ if self.spacedevice!=None:
+ self.spacedevice=None
+ print " -> SpaceMouse/SpaceBall support is disabled."
+ if self.wintabcontext!=None:
+ print " -> Tablet support is only partially available."
+
+ if self.spacedevice!=None:
+ self.handleSpaceEvents(e)
+
+ # handleSpaceEvents
+ def handleSpaceEvents(self, e):
+ """Handle SpaceMouse/SpaceBall events.
+
+ Check if the event e is a SpaceMouse/SpaceBall event and process it.
+ The return value is True if the event was a SpaceMouse/SpaceBall event.
+
+ This method may currently only be calld on Windows.
+ """
+ # Check if the event was a SpaceMouse event
+ res, evttype, data = self.spacedevice.translateWin32Event(e.msg, e.wparam, e.lparam)
+ if res!=cgkit.spacedevice.RetVal.IS_EVENT:
+ return False
+
+ eventmanager = eventManager()
+ # Motion?
+ if evttype==cgkit.spacedevice.EventType.MOTION_EVENT:
+ t,r,period = data
+ eventmanager.event(SPACE_MOTION, SpaceMotionEvent(vec3(t), vec3(r) ,period))
+ # Button?
+ elif evttype==cgkit.spacedevice.EventType.BUTTON_EVENT:
+ pressed, released = data
+ for b in pressed:
+ eventmanager.event(SPACE_BUTTON_DOWN, SpaceButtonEvent(b))
+ for b in released:
+ eventmanager.event(SPACE_BUTTON_UP, SpaceButtonEvent(b))
+ # Zero?
+ elif evttype==cgkit.spacedevice.EventType.ZERO_EVENT:
+ eventmanager.event(SPACE_ZERO)
+
+ return True
+
+
+ # handleWintabEvents
+ def handleWintabEvents(self):
+ """Poll and process Wintab events.
+
+ This method may only be called if self.wintabcontext is not None!
+ """
+ eventmanager = eventManager()
+ pkts = self.wintabcontext.packetsGet(20)
+ for p in pkts:
+ eventmanager.event(TABLET, p)
+
+
+ def convertMods(self, mods):
+ """Convert pygame key modifier flags to cgkit modifier flags.
+ """
+ res = 0
+ if mods & 0x0001 or mods & 0x0002:
+ res |= KEYMOD_SHIFT
+ if mods & 0x0040 or mods & 0x0080:
+ res |= KEYMOD_CONTROL
+ if mods & 0x0100 or mods & 0x0200:
+ res |= KEYMOD_ALT
+ return res
+
+ def draw(self, cam, width, height):
+ scene = getScene()
+ renderer = self.renderer
+
+ # Set handedness
+ renderer.left_handed = scene.handedness=="l"
+ renderer.setViewport(0,0,width,height)
+
+ renderer.draw_solid = True
+ renderer.draw_bboxes = self.options.bounding_box
+ renderer.draw_coordsys = False
+ renderer.draw_orientation = self.draw_orientation
+ renderer.smooth_model = True
+ renderer.backface_culling = False
+ renderer.separate_specular_color = self.separate_specular_color
+ renderer.polygon_mode = self.polygon_mode # 0=Point 1=Line 2=Fill
+ renderer.stereo_mode = self.stereo_mode
+ renderer.clearcol = vec4(scene.getGlobal("background", vec4(0.5,0.5,0.6,0)))
+
+ V = cam.viewTransformation()
+ V2 = None
+ if renderer.stereo_mode!=0:
+ d = getattr(cam, "eye_distance", self.options.eye_distance)
+ T1 = mat4().translation(vec3(-d,0,0))
+ T2 = mat4().translation(vec3(d,0,0))
+ V2 = T2*V
+ V = T1*V
+ if renderer.stereo_mode==1:
+ width /= 2
+
+ # Set projection matrix
+ near, far = cam.getNearFar()
+ P = cam.projection(width,height,near,far)
+ renderer.setProjection(P)
+
+ # Set view matrix
+ renderer.setViewTransformation(V, 0)
+ if V2!=None:
+ renderer.setViewTransformation(V2, 1)
+
+ # Draw scene
+ root = scene.worldRoot()
+ renderer.paint(root)
+
+ # saveScreenshot
+ def saveScreenshot(self, srf):
+ """Save the current window content.
+
+ srf is the pygame Surface object.
+ """
+ name,ext = os.path.splitext(self.options.save)
+ f = int(round(getScene().timer().frame))
+ fname = "%s%04d%s"%(name, f, ext)
+ print 'Saving "%s"...'%fname
+ data = pygame.image.tostring(srf, "RGB")
+ img = Image.fromstring("RGB", (srf.get_width(), srf.get_height()), data)
+ img.save(fname)
+
+
+
+
+######################################################################
+
+if __name__=="__main__":
+ viewer = Viewer()
+ viewer.run()
+
+
View
88 cg2_ex1/trimesh.py
@@ -0,0 +1,88 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Python Computer Graphics Kit.
+#
+# The Initial Developer of the Original Code is Matthias Baas.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+# $Id: trimesh.py,v 1.3 2005/04/19 08:45:56 mbaas Exp $
+
+## \file trimesh.py
+## Contains the TriMesh class.
+
+from cgtypes import vec3
+from Interfaces import *
+from worldobject import WorldObject
+from trimeshgeom import TriMeshGeom
+from slots import *
+import protocols
+import _core
+
+
+# TriMesh
+class TriMesh(WorldObject):
+
+ protocols.advise(instancesProvide=[ISceneItem, IRigidBody])
+
+ def __init__(self,
+ name="TriMesh",
+ dynamics=True,
+ static=False,
+ verts=[],
+ faces=[],
+ **params):
+ WorldObject.__init__(self, name=name, **params)
+
+ self.geom = TriMeshGeom()
+
+ self.dynamics_slot = BoolSlot(dynamics)
+ self.static_slot = BoolSlot(static)
+ self.addSlot("dynamics", self.dynamics_slot)
+ self.addSlot("static", self.static_slot)
+
+ tm = self.geom
+
+ if len(verts)>0:
+ tm.verts.resize(len(verts))
+ i = 0
+ for v in verts:
+ tm.verts.setValue(i, v)
+ i+=1
+
+ if len(faces)>0:
+ tm.faces.resize(len(faces))
+ i = 0
+ for f in faces:
+ tm.faces.setValue(i, f)
+ i+=1
+
+ exec slotPropertyCode("static")
+ exec slotPropertyCode("dynamics")
+
View
87 cg2_ex2/camera.py
@@ -0,0 +1,87 @@
+from direct.directbase import DirectStart
+from direct.showbase import DirectObject
+from pandac.PandaModules import Vec3
+import math
+
+class CameraHandler(DirectObject.DirectObject):
+ def __init__(self):
+ base.disableMouse()
+ base.camera.setPos(0,10,10)
+ base.camera.lookAt(0,0,0)
+ self.mx,self.my=0,0
+ self.dragging=False
+ self.moving = False
+ self.target=Vec3()
+ self.camDist=40
+ self.setTarget(0,0,0)
+ self.turnCameraAroundPoint(0,0,self.target,self.camDist)
+ self.accept("mouse3",self.startDrag)
+ self.accept("mouse3-up",self.stopDrag)
+ self.accept("ctrl", self.startMoving)
+ self.accept("ctrl-up", self.stopMoving)
+ self.accept("wheel_up",lambda : self.adjustCamDist(0.9))
+ self.accept("wheel_down",lambda : self.adjustCamDist(1.1))
+ taskMgr.add(self.dragTask,'dragTask')
+ def turnCameraAroundPoint(self,tx,ty,p,dist):
+ newCamHpr=Vec3()
+ camHpr=base.camera.getHpr()
+ newCamHpr.setX(camHpr.getX()+tx)
+ newCamHpr.setY(camHpr.getY()-ty)
+ newCamHpr.setZ(camHpr.getZ())
+ base.camera.setHpr(newCamHpr)
+ angleradiansX = newCamHpr.getX() * (math.pi / 180.0)
+ angleradiansY = newCamHpr.getY() * (math.pi / 180.0)
+ base.camera.setPos( dist*math.sin(angleradiansX)*math.cos(angleradiansY)+p.getX(),
+ -dist*math.cos(angleradiansX)*math.cos(angleradiansY)+p.getY(),
+ -dist*math.sin(angleradiansY)+p.getZ() )
+ base.camera.lookAt(p.getX(),p.getY(),p.getZ() )
+ def setTarget(self,x,y,z):
+ self.target.setX(x)
+ self.target.setY(y)
+ self.target.setZ(z)
+ def startDrag(self):
+ self.dragging=True
+ def stopDrag(self):
+ self.dragging=False
+ def startMoving(self):
+ self.moving = True
+ def stopMoving(self):
+ self.moving = False
+ def adjustCamDist(self,aspect):