[update] graphics/py-soya3d
green dog
fiziologus at gmail.com
Fri Dec 9 13:43:32 UTC 2011
update to 0.15rc1
-------------- next part --------------
diff -ruN py-soya3d/Makefile py-soya3d.new/Makefile
--- py-soya3d/Makefile 2010-04-28 01:58:27.000000000 +0400
+++ py-soya3d.new/Makefile 2011-11-25 14:26:36.000000000 +0400
@@ -6,12 +6,12 @@
#
PORTNAME= soya3d
-PORTVERSION= 0.14
-PORTREVISION= 5
+DISTVERSION= 0.15rc1
+PORTREVISION= 1
CATEGORIES= graphics python
MASTER_SITES= http://download.gna.org/soya/
PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
-DISTNAME= Soya-${PORTVERSION}
+DISTNAME= Soya-${DISTVERSION}
DISTFILES= ${DISTNAME}${EXTRACT_SUFX}
DIST_SUBDIR= python
@@ -55,6 +55,9 @@
@${REINPLACE_CMD} -e \
's|%%LOCALBASE%%|${LOCALBASE}|g' -e \
's|/usr/include|${LOCALBASE}/include|g' ${WRKSRC}/setup.py
+#Replace bad file (content binary simbols)
+ @${RM} ${WRKSRC}/editor/world.py && \
+ ${CP} ${FILESDIR}/world.py ${WRKSRC}/editor
post-install:
.if !defined(NOPORTEXAMPLES)
diff -ruN py-soya3d/distinfo py-soya3d.new/distinfo
--- py-soya3d/distinfo 2011-07-03 18:12:02.000000000 +0400
+++ py-soya3d.new/distinfo 2011-11-25 14:24:56.000000000 +0400
@@ -1,4 +1,4 @@
-SHA256 (python/Soya-0.14.tar.bz2) = dcb93206d7154dc575ec6eeb7fa3ecfd6bfb78fa233db639e423857cd2a99590
-SIZE (python/Soya-0.14.tar.bz2) = 905659
+SHA256 (python/Soya-0.15rc1.tar.bz2) = 2567714bc312a171bb5b31cb854804a78cff878e8d5cd2352cf37f48c8eb6dd6
+SIZE (python/Soya-0.15rc1.tar.bz2) = 910576
SHA256 (python/SoyaTutorial-0.14.tar.bz2) = 86d5b8189e7f7b4269976a65f23a51291bb99c6272f2884cbd129a6e9cc6cbec
SIZE (python/SoyaTutorial-0.14.tar.bz2) = 5223674
diff -ruN py-soya3d/files/patch-setup.py py-soya3d.new/files/patch-setup.py
--- py-soya3d/files/patch-setup.py 2009-04-27 05:16:35.000000000 +0400
+++ py-soya3d.new/files/patch-setup.py 2011-11-25 14:24:56.000000000 +0400
@@ -1,14 +1,6 @@
---- setup.py 2009-04-22 10:00:23.000000000 -0500
-+++ setup.py 2009-04-22 10:03:23.000000000 -0500
-@@ -21,6 +21,7 @@
-
- # Modify the following if needed :
- USE_OPENAL = 1 # use OpenAL
-+HAVE_PYREX = 0
- #USE_OPENAL = 0
-
- # Modify the following if needed :
-@@ -32,7 +33,7 @@
+--- setup.py.bak 2010-01-19 00:39:57.000000000 +0300
++++ setup.py 2011-11-25 05:43:09.000000000 +0400
+@@ -32,7 +32,7 @@
INCDIR = [
#"ode-0.5/include",
"/usr/include",
@@ -17,7 +9,7 @@
"/usr/X11R6/include",
"/usr/X11/include",
"/usr/include/freetype2",
-@@ -48,7 +49,7 @@
+@@ -48,7 +48,7 @@
LIBDIR = [
#"ode-0.5/lib",
"/usr/lib",
@@ -26,19 +18,26 @@
"/opt/local/lib", # For Mac OS X "darwin port"
"/usr/X11R6/lib",
"/usr/X11/lib",
-@@ -79,11 +80,6 @@
+@@ -81,12 +81,12 @@
SDISTING = ("sdist" in sys.argv[1:]) and not ("--help" in sys.argv[1:])
MACOSX_DEPLOYMENT_TARGET = os.getenv('MACOSX_DEPLOYMENT_TARGET')
-try:
- from Pyrex.Distutils import build_ext
-- HAVE_PYREX = 1
--except:
-- HAVE_PYREX = 0
-
- # Only enable Pyrex compilation for SVN sources
- if not os.path.exists(os.path.join(os.path.dirname(__file__), ".svn")):
-@@ -159,6 +155,7 @@
+- USE_PYREX = 1
+-except ImportError:
+- USE_PYREX = 0
+- print "No Pyrex found"
++#try:
++# from Pyrex.Distutils import build_ext
++# USE_PYREX = 1
++#except ImportError:
++USE_PYREX = 0
++# print "No Pyrex found"
+
+ if USE_PYREX: print "Pyrex compilation enabled!"
+ else: print "Pyrex compilation disabled."
+@@ -172,6 +172,7 @@
DEFINES.append(('SOYA_MACOSX',1))
else:
LIBS.append("openal")
diff -ruN py-soya3d/files/world.py py-soya3d.new/files/world.py
--- py-soya3d/files/world.py 1970-01-01 03:00:00.000000000 +0300
+++ py-soya3d.new/files/world.py 2011-11-25 14:24:56.000000000 +0400
@@ -0,0 +1,723 @@
+# -*- indent-tabs-mode: t -*-
+
+# Soya 3D
+# Copyright (C) 2001-2002 Jean-Baptiste LAMY
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+from editobj.observe import *
+import editobj.custom as custom
+import Tkinter, time, weakref
+import soya, soya.opengl, soya.sdlconst, soya.cube as cube, soya.cursor as cursor
+
+STEP = 0.125
+EPSILON = 0.001
+
+# Additionnal key binding. (A dict mapping key ID to a lambda taking 2 args, the root world and the edited object).
+KEY_BINDINGS = {}
+
+class WorldEditor:
+ def __init__(self, world, dialog):
+ self.active = 0
+ self.dialog = dialog
+ self.handles = []
+ self.vertex_handles = []
+ self.children_visibility = { world : 1 }
+
+ self.world = self.current = world
+
+ self.scene = soya.World()
+ self.scene.name = "__scene__"
+ self.scene.atmosphere = soya.Atmosphere()
+ self.scene.atmosphere.ambient = (0.5, 0.5, 0.5, 1.0)
+
+ self.camera = soya.Camera(self.scene)
+ self.camera.set_xyz(0.0, 0.0, 5.0)
+ self.camera.rotate_y(45)
+ soya.set_root_widget(self.camera)
+
+ self.light = soya.Light(self.scene)
+ self.light.set_xyz(0.2, 2.0, 2.2)
+ self.light.top_level = 1
+ self.light.cast_shadow = 0
+
+ self.cursor = Cursor(self.scene, self.camera, self.handles, self.light)
+ self.cursor.name = "cursor"
+
+ self.content = soya.World(self.scene)
+ self.content.name = "__content__"
+ self.content.append(world)
+
+ self.add_handles_for(world)
+
+ observe_tree(world, self.on_changed)
+
+ self.last_click = 0
+ self.camera_mode = 0
+
+ def add_handles_for(self, item):
+ if isinstance(item, soya.Sprite):
+ self.handles.append(PositionHandle(self.content, self, item))
+
+ elif isinstance(item, soya.Face):
+ for vertex in item.vertices: self.add_handles_for_vertex(vertex)
+
+ elif isinstance(item, soya.CoordSyst):
+ self.handles.append(PositionHandle (self.content, self, item))
+ self.handles.append(OrientationHandle(self.content, self, item))
+
+ if isinstance(item, soya.World) and self.children_visibility.get(item, 0):
+ for subitem in item.children: self.add_handles_for(subitem)
+
+ def add_handles_for_vertex(self, vertex):
+ if getattr(vertex, "immature", 0): return
+
+ for handle in self.vertex_handles:
+ if handle.is_for(vertex): return
+
+ for handle in self.vertex_handles:
+ v = handle.vertices[0]
+ if (v.parent is vertex.parent) and (abs(v.x - vertex.x) < EPSILON) and (abs(v.y - vertex.y) < EPSILON) and (abs(v.z - vertex.z) < EPSILON):
+ handle.add_vertex(vertex)
+ return handle
+ else:
+ handle = VertexHandle(self.content, self, vertex)
+ self.handles.append(handle)
+ self.vertex_handles.append(handle)
+
+ def remove_handles_of(self, item):
+ for handle in self.handles[:]: handle.del_for(item)
+
+ if isinstance(item, soya.Face):
+ for handle in self.vertex_handles[:]:
+ for vertex in item.vertices: handle.del_for(vertex)
+
+ elif isinstance(item, soya.World):
+ for subitem in item: self.remove_handles_of(subitem)
+
+ def select_handles_for(self, item):
+ self.current = item
+ for handle in self.handles:
+ if handle.is_for(item): handle.select()
+
+ def children_edited(self, world, visible):
+ self.children_visibility[world] = visible
+ if visible:
+ for item in world.children:
+ for handle in self.handles:
+ if handle.is_for(item): continue
+ self.add_handles_for(item)
+ else:
+ for item in world.children: self.remove_handles_of(item)
+
+ def on_event(self, event):
+ #print event
+ if event[0] == soya.sdlconst.MOUSEMOTION:
+ if soya.get_mod() & soya.sdlconst.MOD_CTRL:
+ self.cursor.grid_step = STEP
+ else: self.cursor.grid_step = 0.0
+
+ if self.camera_mode:
+ self.camera.turn_y(float(event[3]))
+ self.camera.turn_x(float(event[4]))
+
+ x, y = event[1], event[2]
+ if x == 0: self.camera += soya.Vector(self.camera, -0.1, 0.0, 0.0)
+ elif x == self.camera.get_screen_width() - 1: self.camera += soya.Vector(self.camera, 0.1, 0.0, 0.0)
+ if y == 0: self.camera += soya.Vector(self.camera, 0.0, 0.1, 0.0)
+ elif y == self.camera.get_screen_height() - 1: self.camera += soya.Vector(self.camera, 0.0, -0.1, 0.0)
+
+ self.cursor.mouse_moved(x, y)
+
+ elif event[0] == soya.sdlconst.MOUSEBUTTONDOWN:
+ if event[1] < 3: # Left or middle button
+ current = time.time()
+ if current - self.last_click < 0.2:
+ self.cursor.button_pressed(2, soya.get_mod() & soya.sdlconst.MOD_SHIFT) # Double-click is the same that middle click
+ else:
+ self.cursor.button_pressed(event[1], soya.get_mod() & soya.sdlconst.MOD_SHIFT)
+ self.last_click = current
+ elif event[1] == 3: self.camera_mode = 1
+
+ elif event[0] == soya.sdlconst.MOUSEBUTTONUP:
+ if self.camera_mode:
+ if event[1] == 3: self.camera_mode = 0
+ elif event[1] == 4: self._zoom(-1.0)
+ elif event[1] == 5: self._zoom( 1.0)
+ else:
+ if event[1] < 3: self.cursor.button_released(event[1])
+ elif event[1] == 4: self.cursor.mouse_rolled(-0.25)
+ elif event[1] == 5: self.cursor.mouse_rolled( 0.25)
+
+ elif event[0] == soya.sdlconst.KEYDOWN:
+ # Page up, page down
+ if event[1] == 280: self.cursor.mouse_rolled(-1 - 9 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT))
+ elif event[1] == 281: self.cursor.mouse_rolled( 1 + 9 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT))
+
+ # Left, right, up, down
+ elif event[1] == 276: self.camera += soya.Vector(self.camera, -1.0 - 9.0 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT), 0.0, 0.0)
+ elif event[1] == 275: self.camera += soya.Vector(self.camera, 1.0 + 9.0 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT), 0.0, 0.0)
+ elif event[1] == 273: self.camera += soya.Vector(self.camera, 0.0, 1.0 + 9.0 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT), 0.0)
+ elif event[1] == 274: self.camera += soya.Vector(self.camera, 0.0, -1.0 - 9.0 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT), 0.0)
+
+ # o : toggle ortho camera
+ elif event[1] == 111:
+ self.camera.ortho = not self.camera.ortho
+ self.camera.fov = 60.0
+
+ # +, - : zoom
+ elif event[1] == 270: self._zoom(-1.0 - 9 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT))
+ elif event[1] == 269: self._zoom( 1.0 + 9 * (soya.get_mod() & soya.sdlconst.MOD_SHIFT))
+
+ # 4, 6, 8, 2, 5, 0 : predefined views
+ elif event[1] == 260:
+ a, b = self.world.get_box()
+ cameray, cameraz = self.camera.y, self.camera.z
+ self.camera.set_identity()
+ self.camera.set_xyz(min((a % self.scene).x, (b % self.scene).x) - 3.0, cameray, cameraz)
+ self.camera.look_at(soya.Vector(None, 1.0, 0.0, 0.0))
+ elif event[1] == 262:
+ a, b = self.world.get_box()
+ cameray, cameraz = self.camera.y, self.camera.z
+ self.camera.set_identity()
+ self.camera.set_xyz(max((a % self.scene).x, (b % self.scene).x) + 3.0, cameray, cameraz)
+ self.camera.look_at(soya.Vector(None, -1.0, 0.0, 0.0))
+ elif event[1] == 264:
+ a, b = self.world.get_box()
+ camerax, cameraz = self.camera.x, self.camera.z
+ self.camera.set_identity()
+ self.camera.set_xyz(camerax, max((a % self.scene).y, (b % self.scene).y) + 3.0, cameraz)
+ self.camera.look_at(soya.Vector(None, 0.0, -1.0, 0.0))
+ elif event[1] == 258:
+ a, b = self.world.get_box()
+ camerax, cameraz = self.camera.x, self.camera.z
+ self.camera.set_identity()
+ self.camera.set_xyz(camerax, min((a % self.scene).y, (b % self.scene).y) - 3.0, cameraz)
+ self.camera.look_at(soya.Vector(None, 0.0, 1.0, 0.0))
+ elif event[1] == 261:
+ a, b = self.world.get_box()
+ camerax, cameray = self.camera.x, self.camera.y
+ self.camera.set_identity()
+ self.camera.set_xyz(camerax, cameray, min((a % self.scene).z, (b % self.scene).z) - 3.0)
+ self.camera.look_at(soya.Vector(None, 0.0, 0.0, 1.0))
+ elif event[1] == 256:
+ a, b = self.world.get_box()
+ camerax, cameray = self.camera.x, self.camera.y
+ self.camera.set_identity()
+ self.camera.set_xyz(camerax, cameray, max((a % self.scene).z, (b % self.scene).z) + 3.0)
+ self.camera.look_at(soya.Vector(None, 0.0, 0.0, -1.0))
+
+ # q, t : new quad, new triangle
+ elif event[1] == 113:
+ if hasattr(self.current, "children"): into = self.current
+ else: into = self.current.parent
+ into.append(soya.Quad())
+ elif event[1] == 116:
+ if hasattr(self.current, "children"): into = self.current
+ else: into = self.current.parent
+ into.append(soya.Triangle())
+ else:
+ if KEY_BINDINGS.has_key(event[1]):
+ KEY_BINDINGS[event[1]](self.world, self.current)
+
+ def _zoom(self, z):
+ if self.camera.ortho: self.camera.fov = self.camera.fov * (1.0 + z / 10.0)
+ else: self.camera += soya.Vector(self.camera, 0.0, 0.0, z)
+
+ def render(self):
+ if self.active:
+ self.scene.begin_round()
+ self.scene.advance_time(1.0)
+ self.scene.begin_round()
+ self.scene.advance_time(1.0)
+ self.scene.begin_round()
+ self.scene.advance_time(1.0)
+ self.scene.begin_round()
+ self.scene.advance_time(1.0)
+ self.scene.begin_round()
+ self.scene.advance_time(1.0)
+ soya.render()
+
+ def activate(self, event = None):
+ if not self.active:
+ self.active = 1
+ soya.set_root_widget(self.camera)
+ soya.cursor_set_visible(0)
+ self.auto_render()
+
+ def auto_render(self):
+ for event in soya.coalesce_motion_event(soya.process_event()): self.on_event(event)
+ self.render()
+ self.cancel = self.dialog.after(150, self.auto_render)
+
+ def deactivate(self, event = None):
+ if self.active:
+ self.active = 0
+ soya.cursor_set_visible(1)
+ self.dialog.after_cancel(self.cancel)
+
+ def on_changed(self, obj, type, new, old):
+ if type is list:
+ for item in new:
+ if not item in old:
+ self.add_handles_for(item)
+ if isinstance(item, soya.Face):
+ for vertex in item.vertices:
+ if getattr(vertex, "immature", 0):
+ self.cursor.manage_click(FaceClickManager(self, item))
+ break
+ elif hasattr(item.__class__, "__clickmanager__"):
+ self.cursor.manage_click(item.__class__.__clickmanager__(self, item))
+
+ for item in old:
+ if not item in new: self.remove_handles_of(item)
+
+ else:
+ if (not hasattr(obj, "children")) and (not hasattr(obj, "items")):
+ unobserve_tree(obj, self.on_changed)
+
+RED = soya.Material(); RED .diffuse = (1.0, 0.0, 0.0, 1.0)
+GREEN = soya.Material(); GREEN .diffuse = (0.0, 1.0, 0.0, 1.0)
+BLUE = soya.Material(); BLUE .diffuse = (0.0, 0.0, 1.0, 1.0)
+YELLOW = soya.Material(); YELLOW.diffuse = (1.0, 1.0, 0.0, 1.0)
+
+RED_HANDLE = GREEN_HANDLE = BLUE_HANDLE = YELLOW_HANDLE = None
+
+def build_handles():
+ global RED_HANDLE, GREEN_HANDLE, BLUE_HANDLE, YELLOW_HANDLE
+
+ red_cube = cube.Cube(None, RED); red_cube .scale(STEP, STEP, STEP)
+ green_cube = cube.Cube(None, GREEN); green_cube .scale(STEP, STEP, STEP)
+ blue_cube = cube.Cube(None, BLUE); blue_cube .scale(STEP, STEP, STEP)
+ yellow_cube = cube.Cube(None, YELLOW); yellow_cube.scale(STEP, STEP, STEP)
+
+ RED_HANDLE = red_cube .to_model()
+ GREEN_HANDLE = green_cube .to_model()
+ BLUE_HANDLE = blue_cube .to_model()
+ YELLOW_HANDLE = yellow_cube.to_model()
+
+build_handles()
+
+class Cursor(cursor.Cursor):
+ def __init__(self, parent = None, camera = None, handles = None, light = None):
+ cursor.Cursor.__init__(self, parent, camera, GREEN_HANDLE)
+
+ self.handles = handles
+ self.draging = 0
+ self.light = light
+ self.click_managers = []
+
+ def manage_click(self, click_manager):
+ self.click_managers.append(click_manager)
+
+ def move(self, pos): self.add_vector(self >> pos)
+
+ def add_vector(self, dep):
+ cursor.Cursor.add_vector(self, dep)
+ for handle in self.handles: handle.cursor_moved(self, self.is_near, dep)
+ self.light.move(self)
+
+ if self.click_managers:
+ if not self.click_managers[-1].on_motion(self): del self.click_managers[-1]
+
+ __iadd__ = add_vector
+
+ def is_near(self, position): return position.distance_to(self) < STEP
+ def near(self, a, b): return ((self.distance_to(a) < self.distance_to(b)) and a) or b
+
+ def button_pressed(self, button, multiselect = 0):
+ if button == 1:
+ pred = self.is_near
+ print "%s, %s, %s" % (self.x, self.y, self.z)
+ else: pred = self.is_under_tester(STEP)
+
+ if self.click_managers:
+ if not self.click_managers[-1].on_click(self): del self.click_managers[-1]
+ else:
+ handles = filter(pred, self.handles)
+ if handles:
+ handle = min(map(lambda handle: (self.distance_to(handle), handle), handles))[1]
+ # move the cursor at the handle's Z (in the camera coordinate system)
+ mouse = self % self.camera
+ self.mouse_rolled((handle % self.camera).z - mouse.z)
+ handle.select()
+
+ if not multiselect:
+ for h in self.handles:
+ if not h is handle: h.highlight(0)
+ else:
+ for h in self.handles: h.highlight(0)
+
+ self.draging = 1
+
+ def button_released(self, button):
+ for handle in self.selected_handles():
+ handle.cursor_endmove(self)
+
+ if self.click_managers:
+ if not self.click_managers[-1].on_release(self): del self.click_managers[-1]
+ else: self.draging = 0
+
+ def selected_handles (self): return filter(lambda handle: handle.selected , self.handles)
+ def highlighted_handles (self): return filter(lambda handle: handle.highlighted, self.handles)
+ def highlighted_only_handles(self): return filter(lambda handle: handle.highlighted and not handle.selected, self.handles)
+ def nearest_selected_handle(self):
+ selected_handles = self.selected_handles()
+ return selected_handles and min(map(lambda handle: (self.distance_to(handle), handle), selected_handles))[1]
+ def over_handle(self):
+ handles = self.highlighted_only_handles()
+ return handles and min(map(lambda handle: (self.distance_to(handle), handle), handles))[1]
+
+class ClickManager:
+ def on_motion(self, cursor):
+ """Called when the cursor is moved. Must returns true if this manager is still usefull, or false if this manager's task is achieved."""
+ return 1
+ def on_click(self, cursor):
+ """Called when the cursor is clicked. Must returns true if this manager is still usefull, or false if this manager's task is achieved."""
+ return 1
+ def on_release(self, cursor):
+ """Called when the cursor is released. Must returns true if this manager is still usefull, or false if this manager's task is achieved."""
+ return 1
+
+class FaceClickManager(ClickManager):
+ def __init__(self, editor, face):
+ self.editor = editor
+ self.face = face
+
+ def on_motion(self, cursor):
+ i = 0
+ while not getattr(self.face.vertices[i], "immature", 0): i = i + 1
+
+ while i < len(self.face.vertices):
+ self.face.vertices[i].parent = self.face.parent
+ self.face.vertices[i].move(cursor)
+ i = i + 1
+
+ return 1
+
+ def on_click(self, cursor):
+ i = 0
+ while not getattr(self.face.vertices[i], "immature", 0): i = i + 1
+
+ vertex = self.face.vertices[i]
+ del vertex.immature
+
+ handle = cursor.over_handle()
+ if handle:
+ if isinstance(handle, VertexHandle):
+ handle.add_vertex(self.face.vertices[i])
+ else:
+ self.face.vertices[i].parent = self.face.parent
+ self.face.vertices[i].move(handle)
+
+ self.editor.add_handles_for_vertex(vertex)
+ else:
+ self.face.vertices[i].parent = self.face.parent
+ self.face.vertices[i].move(cursor)
+
+ self.editor.add_handles_for_vertex(vertex)
+
+ return i < len(self.face.vertices) - 1
+
+class MoveClickManager(ClickManager):
+ def __init__(self, editor, item):
+ self.editor = editor
+ self.item = item
+
+ def on_motion(self, cursor):
+ self.item.move(cursor)
+ return 1
+
+ def on_click(self, cursor):
+ handle = cursor.over_handle()
+ if handle:
+ self.item.move(handle)
+ else:
+ self.item.move(cursor)
+
+ return 0
+
+# List of 3D items' classes that are positionned at the next mouse click's position.
+
+class Handle(soya.Body):
+ def __init__(self, parent, editor = None):
+ soya.Body.__init__(self, parent, self.NATURAL)
+ self.editor = editor
+ self.selected = 0
+ self.highlighted = 0
+ self.ideal = soya.Point(parent)
+
+ def del_for(self, item):
+ if self.is_for(item):
+ self.parent.remove(self)
+ self.editor.handles.remove(self)
+ return 1
+
+ def highlight(self, value = 1):
+ self.highlighted = value
+ if value:
+ self.set_model(GREEN_HANDLE)
+ else:
+ if self.selected: self.select(0)
+ self.set_model(self.NATURAL)
+
+ def select(self, value = 1):
+ self.selected = value
+ if value:
+ if not self.highlighted: self.highlight(1)
+
+ def cursor_moved(self, cursor, pred, dep):
+ if self.selected:
+ if cursor.draging:
+ self.ideal += dep
+ if cursor.grid_step:
+ pos = self.ideal.copy()
+ step = cursor.grid_step
+ d = step / 2.0
+ pos.x = ((pos.x + d) // step) * step
+ pos.y = ((pos.y + d) // step) * step
+ pos.z = ((pos.z + d) // step) * step
+ self.move(pos)
+ else: self.move(self.ideal)
+ else:
+ if self.highlighted:
+ if not pred(self): self.highlight(0)
+ elif pred(self): self.highlight()
+
+ def cursor_endmove(self, cursor): pass
+
+
+class PositionHandle(Handle):
+ NATURAL = BLUE_HANDLE
+ def __init__(self, parent, editor, position):
+ Handle.__init__(self, parent, editor)
+
+ self.position = position
+ self.ideal.move(position)
+ Handle.move(self, position)
+
+ observe(position, self.on_changed)
+ world = position.parent
+ while world:
+ observe(world, self.on_parent_changed)
+ world = world.parent
+
+ def is_for (self, item): return item is self.position
+
+ def move(self, position):
+ Handle.move(self, position)
+ self.position.move(position)
+
+ def add_vector(self, vector):
+ Handle.add_vector(self, vector)
+ self.position.add_vector(vector)
+ __iadd__ = add_vector
+
+ def on_changed(self, obj, type, new, old):
+ if type is object:
+ if (new["x"] != old["x"]) or (new["y"] != old["y"]) or (new["z"] != old["z"]):
+ Handle.move(self, obj)
+ self.ideal.move(obj)
+ if new["parent"] != old["parent"]:
+ self.update_hierarchy(new["parent"], old["parent"])
+ Handle.move(self, self.position)
+ self.ideal.move(obj)
+
+ def on_parent_changed(self, obj, type, new, old):
+ if type is object:
+ if (new["x"] != old["x"]) or (new["y"] != old["y"]) or (new["z"] != old["z"]):
+ Handle.move(self, self.position)
+ self.ideal.move(self.position)
+ if new["parent"] != old["parent"]:
+ self.update_hierarchy(new["parent"], old["parent"])
+ Handle.move(self, self.position)
+ self.ideal.move(self.position)
+
+ def update_hierarchy(self, newparent, oldparent):
+ world = oldparent
+ while world:
+ unobserve(world, self.on_parent_changed)
+ world = world.parent
+
+ world = newparent
+ while world:
+ observe(world, self.on_parent_changed)
+ world = world.parent
+
+ def __repr__(self): return "<PositionHandle for %s>" % (self.position,)
+
+class VertexHandle(Handle):
+ NATURAL = RED_HANDLE
+ def __init__(self, parent, editor, vertex):
+ Handle.__init__(self, parent, editor)
+ self.vertices = [vertex]
+ Handle.move(self, vertex)
+ self.ideal.move(vertex)
+
+ observe(vertex, self.on_changed)
+ world = vertex.parent
+ while world:
+ observe(world, self.on_parent_changed)
+ world = world.parent
+
+ def is_for(self, item):
+ for vertex in self.vertices:
+ if vertex is item: return 1
+ return 0
+
+ def del_for(self, item):
+ for vertex in self.vertices:
+ if vertex is item:
+ self.vertices.remove(vertex)
+ unobserve(vertex, self.on_changed)
+ if not self.vertices:
+ self.parent.remove(self)
+ self.editor.handles.remove(self)
+ self.editor.vertex_handles.remove(self)
+
+ def del_for_all(self):
+ for vertex in self.vertices:
+ unobserve(vertex, self.on_changed)
+
+ self.parent.remove(self)
+ self.editor.handles.remove(self)
+
+ def move(self, position):
+ Handle.move(self, position)
+ for vertex in self.vertices: vertex.move(position)
+
+ def add_vector(self, vector):
+ Handle.add_vector(self, vector)
+ for vertex in self.vertices:
+ vertex.add_vector(vector)
+ __iadd__ = add_vector
+
+ def on_changed(self, obj, type, new, old):
+ if type is object:
+ if (new["x"] != old["x"]) or (new["y"] != old["y"]) or (new["z"] != old["z"]):
+ if len(self.vertices) == 1:
+ Handle.move(self, obj)
+ self.ideal.move(obj)
+ else:
+ self.give_up_vertex(obj)
+
+ if new["parent"] != old["parent"]: self.give_up_vertex(obj)
+
+ def on_parent_changed(self, obj, type, old, new):
+ if type is object:
+ if (new["x"] != old["x"]) or (new["y"] != old["y"]) or (new["z"] != old["z"]):
+ Handle.move(self, self.vertices[0])
+ self.ideal.move(self.vertices[0])
+ elif new["parent"] != old["parent"]:
+ self.update_hierarchy(new["parent"], old["parent"])
+ Handle.move(self, self.vertices[0])
+ self.ideal.move(self.vertices[0])
+
+ def update_hierarchy(self, newparent, oldparent):
+ world = oldparent
+ while world:
+ unobserve(world, self.on_parent_changed)
+ world = world.parent
+
+ world = newparent
+ while world:
+ observe(world, self.on_parent_changed)
+ world = world.parent
+
+ def add_vertex(self, vertex):
+ vertex.parent = self.vertices[0].parent
+ vertex.move(self)
+ self.vertices.append(vertex)
+ observe(vertex, self.on_changed)
+
+ def give_up_vertex(self, vertex):
+ self.del_for(vertex)
+ self.editor.add_handles_for_vertex(vertex)
+
+ def cursor_endmove(self, cursor):
+ handle = cursor.over_handle()
+ if handle:
+ if isinstance(handle, VertexHandle):
+ self.del_for_all()
+ for vertex in self.vertices: handle.add_vertex(vertex)
+ else:
+ self.move(handle)
+
+ def __repr__(self): return "<VertexHandle for %s>" % (self.vertices,)
+
+class OrientationHandle(Handle):
+ NATURAL = YELLOW_HANDLE
+ def __init__(self, parent, editor, orientation):
+ Handle.__init__(self, parent, editor)
+
+ self.orientation = orientation
+ self.place()
+ self.ideal.move(soya.Point(orientation, 0.0, 0.0, -1.0))
+
+ observe(orientation, self.on_changed)
+ world = orientation.parent
+ while world:
+ observe(world, self.on_parent_changed)
+ world = world.parent
+
+ def is_for (self, item): return item is self.orientation
+
+ def place(self): Handle.move(self, soya.Point(self.orientation, 0.0, 0.0, -1.0))
+
+ def move(self, position):
+ if soya.get_mod() & soya.sdlconst.MOD_SHIFT:
+ position = soya.Point(position.parent, position.x, position.y, position.z)
+ position.convert_to(self.orientation.parent)
+ position.y = self.orientation.y
+ self.orientation.look_at(position)
+ self.place()
+
+ def add_vector(self, vector):
+ self.move(self.position() + vector)
+ __iadd__ = add_vector
+
+ def on_changed(self, obj, type, new, old):
+ if type is object:
+ if (new["x"] != old["x"]) or (new["y"] != old["y"]) or (new["z"] != old["z"]):
+ self.place()
+ self.ideal.move(self)
+ if new["parent"] != old["parent"]:
+ self.update_hierarchy(new["parent"], old["parent"])
+ self.ideal.move(self)
+ self.place()
+
+ def on_parent_changed(self, obj, type, new, old):
+ if type is object:
+ if (new["x"] != old["x"]) or (new["y"] != old["y"]) or (new["z"] != old["z"]):
+ self.place()
+ self.ideal.move(self)
+ if new["parent"] != old["parent"]:
+ self.update_hierarchy(new["parent"], old["parent"])
+ self.place()
+ self.ideal.move(self)
+
+ def update_hierarchy(self, newparent, oldparent):
+ world = oldparent
+ while world:
+ unobserve(world, self.on_parent_changed)
+ world = world.parent
+
+ world = newparent
+ while world:
+ observe(world, self.on_parent_changed)
+ world = world.parent
+
+ def __repr__(self): return "<OrientationHandle for %s>" % (self.orientation,)
More information about the freebsd-ports
mailing list