diff options
author | Russell D. Fish <fish@cs.utah.edu> | 2008-05-21 16:22:55 +0000 |
---|---|---|
committer | Russell D. Fish <fish@cs.utah.edu> | 2008-05-21 16:22:55 +0000 |
commit | 7ecf4fb89f6a169544f0126d3b8a49f7862f8477 (patch) | |
tree | ee3c3c550ea8cb054f4e9c37d476fb04aaf725b4 | |
parent | d2068d6297662cdea172df08d99830bfa9030c29 (diff) | |
download | nanoengineer-theirix-7ecf4fb89f6a169544f0126d3b8a49f7862f8477.tar.gz nanoengineer-theirix-7ecf4fb89f6a169544f0126d3b8a49f7862f8477.zip |
Break up drawer.py
The globals tying together drawer.py have already been factored into a separate drawing_globals.py module.
The remainder of drawer.py is now in 10 smaller modules:
glprefs.py setup_draw.py shape_vertices.py
ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py
drawers.py gl_lighting.py gl_buffers.py
(Continuity of SVN history with drawer.py has been retained.)
There is a large imports section cloned from drawer.py at the front of each of them.
(I will remove the unused imports as a separate phase.)
All imports from graphics.drawing.drawer have been pointed to the new modules.
62 files changed, 5744 insertions, 4128 deletions
diff --git a/cad/src/analysis/ESP/ESPImage.py b/cad/src/analysis/ESP/ESPImage.py index a392810be..ec19c168f 100755 --- a/cad/src/analysis/ESP/ESPImage.py +++ b/cad/src/analysis/ESP/ESPImage.py @@ -66,9 +66,9 @@ from foundation.state_utils import DataMixin from model.chunk import Chunk from model.chem import Atom -from graphics.drawing.drawer import drawPlane -from graphics.drawing.drawer import drawwirecube -from graphics.drawing.drawer import drawLineLoop +from graphics.drawing.drawers import drawPlane +from graphics.drawing.drawers import drawwirecube +from graphics.drawing.drawers import drawLineLoop from geometry.VQT import V, Q, A from graphics.rendering.povray.povheader import povpoint @@ -391,7 +391,7 @@ class ESPImage(RectGadget): # This is for debugging purposes. This draws a green normal vector using # local space coords. Mark 050930 if 0: - from graphics.drawing.drawer import drawline + from graphics.drawing.CS_draw_primitives import drawline drawline(green, V(0.0, 0.0, 0.0), V(0.0, 0.0, 1.0), 0, 3) glPopMatrix() @@ -399,7 +399,7 @@ class ESPImage(RectGadget): # This is for debugging purposes. This draws a yellow normal vector using # model space coords. Mark 050930 if 0: - from graphics.drawing.drawer import drawline + from graphics.drawing.CS_draw_primitives import drawline from utilities.constants import yellow drawline(yellow, self.center, self.center + self.planeNorm, 0, 3) diff --git a/cad/src/analysis/GAMESS/jig_Gamess.py b/cad/src/analysis/GAMESS/jig_Gamess.py index f3b973b9a..ed64bcc70 100755 --- a/cad/src/analysis/GAMESS/jig_Gamess.py +++ b/cad/src/analysis/GAMESS/jig_Gamess.py @@ -10,7 +10,7 @@ jig_Gamess.py import sys from model.jigs import Jig -from graphics.drawing.drawer import drawwirecube +from graphics.drawing.drawers import drawwirecube from graphics.rendering.povray.povheader import povpoint # Fix for bug 692 Mark 050628 from analysis.GAMESS.files_gms import get_energy_from_gms_outfile, get_atompos_from_gms_outfile from utilities.Log import redmsg, greenmsg diff --git a/cad/src/command_support/GraphicsMode.py b/cad/src/command_support/GraphicsMode.py index aa39e3ec6..1dbf290a4 100755 --- a/cad/src/command_support/GraphicsMode.py +++ b/cad/src/command_support/GraphicsMode.py @@ -29,11 +29,11 @@ from PyQt4.Qt import Qt from PyQt4.Qt import QMenu from geometry.VQT import V, Q, vlen, norm, planeXline, ptonline, cross -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import drawOriginAsSmallAxis -from graphics.drawing.drawer import drawTag -from graphics.drawing.drawer import drawaxes -from graphics.drawing.drawer import drawrectangle +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.CS_draw_primitives import drawTag +from graphics.drawing.drawers import drawOriginAsSmallAxis +from graphics.drawing.drawers import drawaxes +from graphics.drawing.drawers import drawrectangle from utilities.debug import print_compact_traceback diff --git a/cad/src/commands/BuildAtoms/BuildAtoms_GraphicsMode.py b/cad/src/commands/BuildAtoms/BuildAtoms_GraphicsMode.py index 69f7e4d49..a279c6ab2 100755 --- a/cad/src/commands/BuildAtoms/BuildAtoms_GraphicsMode.py +++ b/cad/src/commands/BuildAtoms/BuildAtoms_GraphicsMode.py @@ -67,7 +67,7 @@ from model.chem import oneUnbonded from model.elements import Singlet from geometry.VQT import Q, A, norm, twistor -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from foundation.Group import Group from foundation.Utility import Node diff --git a/cad/src/commands/BuildCrystal/CookieShape.py b/cad/src/commands/BuildCrystal/CookieShape.py index 3f32bf6c3..fd55b086e 100755 --- a/cad/src/commands/BuildCrystal/CookieShape.py +++ b/cad/src/commands/BuildCrystal/CookieShape.py @@ -26,13 +26,13 @@ from geometry.VQT import vlen, V from OpenGL.GL import glNewList, glEndList, glCallList from OpenGL.GL import GL_COMPILE_AND_EXECUTE -from graphics.drawing.drawer import drawCircle -from graphics.drawing.drawer import genDiam -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawsphere -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import ColorSorter -from graphics.drawing.drawer import ColorSortedDisplayList +from graphics.drawing.drawers import drawCircle +from graphics.drawing.drawers import genDiam +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.ColorSorter import ColorSorter +from graphics.drawing.ColorSorter import ColorSortedDisplayList from utilities.constants import SUBTRACT_FROM_SELECTION from utilities.constants import OUTSIDE_SUBTRACT_FROM_SELECTION diff --git a/cad/src/commands/BuildCrystal/cookieMode.py b/cad/src/commands/BuildCrystal/cookieMode.py index ba5ea181c..66fa335fd 100755 --- a/cad/src/commands/BuildCrystal/cookieMode.py +++ b/cad/src/commands/BuildCrystal/cookieMode.py @@ -43,12 +43,12 @@ from geometry.Slab import Slab from commands.BuildCrystal.CookieShape import CookieShape import graphics.drawing.drawing_globals as drawing_globals -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import drawCircle -from graphics.drawing.drawer import drawGrid -from graphics.drawing.drawer import drawLineLoop -from graphics.drawing.drawer import drawrectangle -from graphics.drawing.drawer import findCell +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.drawers import drawCircle +from graphics.drawing.drawers import drawGrid +from graphics.drawing.drawers import drawLineLoop +from graphics.drawing.drawers import drawrectangle +from graphics.drawing.drawers import findCell from model.chunk import Chunk from model.chem import Atom diff --git a/cad/src/commands/Extrude/extrudeMode.py b/cad/src/commands/Extrude/extrudeMode.py index e761a4e15..c0731e85a 100755 --- a/cad/src/commands/Extrude/extrudeMode.py +++ b/cad/src/commands/Extrude/extrudeMode.py @@ -62,7 +62,7 @@ from geometry.VQT import V, Q, norm, vlen, cross from commands.Extrude.ExtrudePropertyManager import ExtrudePropertyManager -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from model.chunk import Chunk from graphics.behaviors.shape import get_selCurve_color diff --git a/cad/src/commands/Fuse/FuseChunks_GraphicsMode.py b/cad/src/commands/Fuse/FuseChunks_GraphicsMode.py index 2a9a51c33..70ebc31f1 100755 --- a/cad/src/commands/Fuse/FuseChunks_GraphicsMode.py +++ b/cad/src/commands/Fuse/FuseChunks_GraphicsMode.py @@ -12,7 +12,7 @@ Ninad 2008-01-25: Split Command and GraphicsMode classes out of class fuseChunksMode. The command class can be found in FuseChunks_Command.py """ -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from graphics.behaviors.shape import get_selCurve_color from utilities.constants import green diff --git a/cad/src/dna/commands/MultipleDnaSegmentResize/MultipleDnaSegmentResize_GraphicsMode.py b/cad/src/dna/commands/MultipleDnaSegmentResize/MultipleDnaSegmentResize_GraphicsMode.py index 80b80ec25..5e170311e 100644 --- a/cad/src/dna/commands/MultipleDnaSegmentResize/MultipleDnaSegmentResize_GraphicsMode.py +++ b/cad/src/dna/commands/MultipleDnaSegmentResize/MultipleDnaSegmentResize_GraphicsMode.py @@ -17,7 +17,8 @@ from dna.commands.DnaSegment.DnaSegment_GraphicsMode import DnaSegment_GraphicsM from PyQt4.Qt import Qt from graphics.drawing.drawDnaRibbons import drawDnaRibbons from utilities.constants import black, banana, silver, lighterblue, darkred, darkgreen -from graphics.drawing import drawer +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawsphere SPHERE_RADIUS = 6.0 SPHERE_DRAWLEVEL = 2 @@ -129,12 +130,13 @@ class MultipleDnaSegmentResize_GraphicsMode(DnaSegment_GraphicsMode): for segment in segmentList: end1, end2 = segment.getAxisEndPoints() if end1 is not None and end2 is not None: - drawer.drawcylinder(banana, - end1, - end2, - CYL_RADIUS, - capped = True, - opacity = CYL_OPACITY ) + drawcylinder(banana, + end1, + end2, + CYL_RADIUS, + capped = True, + opacity = CYL_OPACITY ) + def _drawTags(self): """ Overrides _superClass._drawTags() @@ -149,12 +151,11 @@ class MultipleDnaSegmentResize_GraphicsMode(DnaSegment_GraphicsMode): if self._tagPositions: for point in self._tagPositions: - drawer.drawsphere(silver, - point, - SPHERE_RADIUS, - SPHERE_DRAWLEVEL, - opacity = SPHERE_OPACITY) - + drawsphere(silver, + point, + SPHERE_RADIUS, + SPHERE_DRAWLEVEL, + opacity = SPHERE_OPACITY) def _DEBUG_Flag_EndPoint1_ofDnaSegments(self): """ @@ -172,11 +173,11 @@ class MultipleDnaSegmentResize_GraphicsMode(DnaSegment_GraphicsMode): if e1 is not None: endPoints_1.append(e1) for end1 in endPoints_1: - drawer.drawsphere(lighterblue, - end1, - SPHERE_RADIUS, - SPHERE_DRAWLEVEL, - opacity = 1.0) + drawsphere(lighterblue, + end1, + SPHERE_RADIUS, + SPHERE_DRAWLEVEL, + opacity = 1.0) def _drawDnaRubberbandLine(self): """ @@ -242,11 +243,11 @@ class MultipleDnaSegmentResize_GraphicsMode(DnaSegment_GraphicsMode): #Draw a sphere that indicates the current position of #the resize end of each segment . - drawer.drawsphere(darkgreen, - end2, - SPHERE_RADIUS_2, - SPHERE_DRAWLEVEL, - opacity = SPHERE_OPACITY) + drawsphere(darkgreen, + end2, + SPHERE_RADIUS_2, + SPHERE_DRAWLEVEL, + opacity = SPHERE_OPACITY) numberOfBasePairsString = "+" + str(numberOfBasePairs) self.glpane.renderTextAtPosition( end2, @@ -256,23 +257,17 @@ class MultipleDnaSegmentResize_GraphicsMode(DnaSegment_GraphicsMode): numberOfBasePairs , end2 = params_when_removing_bases #Draw a sphere that indicates the current position of #the resize end of each segment. - drawer.drawsphere(darkred, - end2, - SPHERE_RADIUS_2, - SPHERE_DRAWLEVEL, - opacity = SPHERE_OPACITY) + drawsphere(darkred, + end2, + SPHERE_RADIUS_2, + SPHERE_DRAWLEVEL, + opacity = SPHERE_OPACITY) numberOfBasePairsString = str(numberOfBasePairs) self.glpane.renderTextAtPosition( end2, textString = numberOfBasePairsString, ) - - - #Draw the text next to the cursor that gives info about #number of base pairs etc self._drawCursorText() - - - diff --git a/cad/src/dna/model/DnaMarker.py b/cad/src/dna/model/DnaMarker.py index 3d17f9727..e3a5ae924 100644 --- a/cad/src/dna/model/DnaMarker.py +++ b/cad/src/dna/model/DnaMarker.py @@ -27,7 +27,7 @@ from dna.updater.dna_updater_prefs import pref_draw_internal_markers from utilities import debug_flags -from graphics.drawing.drawer import drawwirecube +from graphics.drawing.drawers import drawwirecube from utilities.constants import orange diff --git a/cad/src/dna/updater/dna_updater_debug.py b/cad/src/dna/updater/dna_updater_debug.py index f86f79a13..5e5be1ceb 100644 --- a/cad/src/dna/updater/dna_updater_debug.py +++ b/cad/src/dna/updater/dna_updater_debug.py @@ -9,7 +9,7 @@ dna_updater_debug.py -- debug code for dna_updater from utilities import debug_flags -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from model.jigs import Jig diff --git a/cad/src/exprs/Arrow.py b/cad/src/exprs/Arrow.py index eb298ad1e..c57dfe777 100644 --- a/cad/src/exprs/Arrow.py +++ b/cad/src/exprs/Arrow.py @@ -14,8 +14,7 @@ from exprs.ExprsConstants import Color, Position, ORIGIN, DX from utilities.constants import gray -from graphics.drawing.drawer import drawDirectionArrow - +from graphics.drawing.CS_draw_primitives import drawDirectionArrow class Arrow(Widget2D): """ @@ -40,4 +39,4 @@ class Arrow(Widget2D): numberOfSides = 6 ) -
\ No newline at end of file + diff --git a/cad/src/exprs/Rect.py b/cad/src/exprs/Rect.py index 26cfca1d4..e4c9206f3 100755 --- a/cad/src/exprs/Rect.py +++ b/cad/src/exprs/Rect.py @@ -34,8 +34,8 @@ from exprs.__Symbols__ import _self from exprs.py_utils import printnim, printfyi -from graphics.drawing.drawer import drawsphere # drawsphere(color, pos, radius, detailLevel) -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.CS_draw_primitives import drawline # == diff --git a/cad/src/exprs/dna_ribbon_view.py b/cad/src/exprs/dna_ribbon_view.py index 7f69d9ff1..1858ec5c9 100755 --- a/cad/src/exprs/dna_ribbon_view.py +++ b/cad/src/exprs/dna_ribbon_view.py @@ -101,9 +101,9 @@ from OpenGL.GL import GL_FALSE from exprs.Overlay import Overlay -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawsphere # drawsphere(color, pos, radius, detailLevel) -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.CS_draw_primitives import drawline from exprs.world import World diff --git a/cad/src/exprs/scratch/dna_ribbon_view_scraps.py b/cad/src/exprs/scratch/dna_ribbon_view_scraps.py index 929fabe16..b62d2e2f0 100755 --- a/cad/src/exprs/scratch/dna_ribbon_view_scraps.py +++ b/cad/src/exprs/scratch/dna_ribbon_view_scraps.py @@ -21,7 +21,6 @@ from Overlay import Overlay from TextRect import TextRect from OpenGL.GL import * #e move what needs this into draw_utils -import graphics.drawing.drawer as drawer from dna_ribbon_view import * ###e reloadable -- needed at least for IorE, probably more from utilities import debug_flags diff --git a/cad/src/exprs/scratch/test_animation_mode.py b/cad/src/exprs/scratch/test_animation_mode.py index c2eceb71a..bb031e31b 100644 --- a/cad/src/exprs/scratch/test_animation_mode.py +++ b/cad/src/exprs/scratch/test_animation_mode.py @@ -68,7 +68,10 @@ from foundation.state_utils import copy_val from utilities.constants import green, red, white, pink, black, brown, gray # other colors below from math import pi -from graphics.drawing.drawer import drawline, drawbrick, drawsphere, drawcylinder +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.drawers import drawbrick +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.CS_draw_primitives import drawcylinder from OpenGL.GL import GL_LIGHTING, glDisable, glEnable from geometry.VQT import cross, proj2sphere, V, norm, Q, vlen @@ -967,7 +970,7 @@ annoyers = [##'editToolbar', 'fileToolbar', 'helpToolbar', 'modifyToolbar', # code copied from test_commands.py: # these imports are not needed in a minimal example like ExampleCommand2; # to make that clear, we put them down here instead of at the top of the file -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from utilities.constants import red, green ##from exprs.ExprsConstants import PIXELS from exprs.images import Image diff --git a/cad/src/exprs/test.py b/cad/src/exprs/test.py index 55e213265..5bd08c0b0 100755 --- a/cad/src/exprs/test.py +++ b/cad/src/exprs/test.py @@ -144,7 +144,7 @@ from utilities.constants import ave_colors, noop from utilities.prefs_constants import displayOriginAxis_prefs_key from graphics.drawing.texture_fonts import courierfile -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from exprs.reload import exprs_globals diff --git a/cad/src/geometry/BoundingBox.py b/cad/src/geometry/BoundingBox.py index 593fcb6bc..935f5432b 100644 --- a/cad/src/geometry/BoundingBox.py +++ b/cad/src/geometry/BoundingBox.py @@ -19,7 +19,7 @@ even though it also includes graphics code, and hardcoded constants about its use for our model objects (atoms). """ -from graphics.drawing.drawer import drawwirebox +from graphics.drawing.drawers import drawwirebox from Numeric import add, subtract, sqrt from Numeric import maximum, minimum, dot diff --git a/cad/src/graphics/behaviors/shape.py b/cad/src/graphics/behaviors/shape.py index 4b80a6d68..b84993ddc 100755 --- a/cad/src/graphics/behaviors/shape.py +++ b/cad/src/graphics/behaviors/shape.py @@ -32,8 +32,8 @@ from Numeric import array, zeros, maximum, minimum, ceil, dot, floor from geometry.VQT import A, vlen, V -from graphics.drawing.drawer import drawrectangle -from graphics.drawing.drawer import drawline +from graphics.drawing.drawers import drawrectangle +from graphics.drawing.CS_draw_primitives import drawline from utilities.constants import black from utilities.constants import DELETE_SELECTION diff --git a/cad/src/graphics/display_styles/CylinderChunks.py b/cad/src/graphics/display_styles/CylinderChunks.py index 0d1fe2821..c1cf94f6d 100755 --- a/cad/src/graphics/display_styles/CylinderChunks.py +++ b/cad/src/graphics/display_styles/CylinderChunks.py @@ -14,8 +14,8 @@ though it might be useful as a fast-rendering display mode too. from Numeric import dot, argmax, argmin, sqrt import foundation.env as env -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawcylinder_wireframe +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawcylinder_wireframe from geometry.geometryUtilities import matrix_putting_axis_at_z from geometry.VQT import V, norm from utilities.debug import print_compact_traceback diff --git a/cad/src/graphics/display_styles/DnaCylinderChunks.py b/cad/src/graphics/display_styles/DnaCylinderChunks.py index d9c22e439..1cc371b2f 100644 --- a/cad/src/graphics/display_styles/DnaCylinderChunks.py +++ b/cad/src/graphics/display_styles/DnaCylinderChunks.py @@ -42,12 +42,12 @@ piotr 080520: Further code cleanup.. import sys import foundation.env as env -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawpolycone -from graphics.drawing.drawer import drawpolycone_multicolor -from graphics.drawing.drawer import drawsphere -from graphics.drawing.drawer import drawCircle -from graphics.drawing.drawer import drawFilledCircle +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawpolycone +from graphics.drawing.CS_draw_primitives import drawpolycone_multicolor +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.drawers import drawCircle +from graphics.drawing.drawers import drawFilledCircle from math import sin, cos, pi from Numeric import dot, argmax, argmin, sqrt diff --git a/cad/src/graphics/display_styles/SurfaceChunks.py b/cad/src/graphics/display_styles/SurfaceChunks.py index 9e4410e85..54a85461e 100755 --- a/cad/src/graphics/display_styles/SurfaceChunks.py +++ b/cad/src/graphics/display_styles/SurfaceChunks.py @@ -22,9 +22,9 @@ import types from PyQt4.Qt import QApplication, Qt, QCursor import foundation.env as env -from graphics.drawing.drawer import drawsurface -from graphics.drawing.drawer import drawsurface_wireframe -from graphics.drawing.drawer import getSphereTriangles +from graphics.drawing.CS_draw_primitives import drawsurface +from graphics.drawing.CS_draw_primitives import drawsurface_wireframe +from graphics.drawing.shape_vertices import getSphereTriangles from geometry.VQT import V, cross from utilities.Log import greenmsg from graphics.display_styles.displaymodes import ChunkDisplayMode diff --git a/cad/src/graphics/drawables/DirectionArrow.py b/cad/src/graphics/drawables/DirectionArrow.py index 787a59367..fa15026f6 100644 --- a/cad/src/graphics/drawables/DirectionArrow.py +++ b/cad/src/graphics/drawables/DirectionArrow.py @@ -23,7 +23,7 @@ from OpenGL.GL import glTranslatef from OpenGL.GL import glRotatef from OpenGL.GL import glPopMatrix -from graphics.drawing.drawer import drawDirectionArrow +from graphics.drawing.CS_draw_primitives import drawDirectionArrow from geometry.VQT import V, norm, vlen from math import pi diff --git a/cad/src/graphics/drawables/ResizeHandle.py b/cad/src/graphics/drawables/ResizeHandle.py index d42046e89..afc759df3 100644 --- a/cad/src/graphics/drawables/ResizeHandle.py +++ b/cad/src/graphics/drawables/ResizeHandle.py @@ -21,7 +21,8 @@ from OpenGL.GL import glPopMatrix from OpenGL.GL import glTranslatef from OpenGL.GL import glRotatef -from graphics.drawing.drawer import drawLineLoop, drawPlane +from graphics.drawing.drawers import drawLineLoop +from graphics.drawing.drawers import drawPlane from utilities.constants import black, orange, darkgreen from math import pi diff --git a/cad/src/graphics/drawables/handles.py b/cad/src/graphics/drawables/handles.py index d2afc26ee..bbf79a1fb 100755 --- a/cad/src/graphics/drawables/handles.py +++ b/cad/src/graphics/drawables/handles.py @@ -20,7 +20,7 @@ from geometry.VQT import V from geometry.VQT import vlen from geometry.VQT import norm from geometry.VQT import orthodist -from graphics.drawing.drawer import drawsphere +from graphics.drawing.CS_draw_primitives import drawsphere from utilities.constants import ave_colors from utilities.constants import magenta from utilities.constants import blue diff --git a/cad/src/graphics/drawing/CS_ShapeList.py b/cad/src/graphics/drawing/CS_ShapeList.py new file mode 100755 index 000000000..a061833cf --- /dev/null +++ b/cad/src/graphics/drawing/CS_ShapeList.py @@ -0,0 +1,472 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +CS_ShapeList.py - The C++ ColorSorter's arrays of primitives to draw. + +Does some memoization as a speedup. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +import graphics.drawing.drawing_globals as drawing_globals +if drawing_globals.quux_module_import_succeeded: + import quux + +class ShapeList_inplace: + + """ + Records sphere and cylinder data and invokes it through the native C++ + rendering system. + + This has the benefit over ShapeList that shapes aren't first stored in + lots of Python lists, and then turned into lots of Numeric arrays. + Instead, it stores directly in a list of fixed-size Numeric arrays. + It shows some speedup, but not a lot. And tons of memory is being + used. I'm not sure where. -grantham + + """ + + __author__ = "grantham@plunk.org" + + _blocking = 512 # balance between memory zeroing and drawing efficiency + + def __init__(self): + + # + # Lists of lists, each list containing a Numeric array and the + # number of objects in that array. E.g. Each element in + # sphere is [l, n], where l is array((m, 9), 'f'), n is the + # number of valid 9 element slices in l that represent + # spheres, and m is equal to or more than n+1. + # + self.spheres = [] + self.cylinders = [] + + # If this is true, disallow future adds. + self.petrified = False + + + def draw(self): + + """ + Draw all the objects represented in this shape list. + """ + + for (spheres, count) in self.spheres: + quux.shapeRendererDrawSpheresIlvd(count, spheres) + for (cylinders, count) in self.cylinders: + quux.shapeRendererDrawCylindersIlvd(count, cylinders) + + + def add_sphere(self, color4, pos, radius, name = 0): + """ + Add a sphere to this shape list. + + "color4" must have 4 elements. "name" is the GL selection name. + """ + + if self.petrified: + raise ValueError, "Tried to add a sphere to a petrified ShapeList_inplace" + + # struct Sphere { + # float m_color[4]; + # float m_nameUInt; + # float m_center[3]; + # float m_radius; + # }; + + if len(self.spheres) == 0 or self.spheres[-1][1] == ShapeList_inplace._blocking: + # size of struct Sphere in floats is 9 + block = Numeric.zeros((ShapeList_inplace._blocking, 9), 'f') + self.spheres.append([block, 0]) + + (block, count) = self.spheres[-1] + + block[count] = (\ + color4[0], color4[1], color4[2], color4[3], + float(name), + pos[0], pos[1], pos[2], + radius) + + self.spheres[-1][1] += 1 + + + def add_cylinder(self, color4, pos1, pos2, radius, name = 0, capped=0): + """ + Add a cylinder to this shape list. + + "color4" must have 4 elements. "name" is the GL selection name. + """ + + if self.petrified: + raise ValueError, "Tried to add a cylinder to a petrified ShapeList_inplace" + + # struct Cylinder { + # float m_color[4]; + # float m_nameUInt; + # float m_cappedBool; + # float m_pos1[3]; + # float m_pos2[3]; + # float m_radius; + # }; + + if len(self.cylinders) == 0 or self.cylinders[-1][1] == ShapeList_inplace._blocking: + # size of struct Cylinder in floats is 13 + block = Numeric.zeros((ShapeList_inplace._blocking, 13), 'f') + self.cylinders.append([block, 0]) + + (block, count) = self.cylinders[-1] + + block[count] = (\ + color4[0], color4[1], color4[2], color4[3], + float(name), + float(capped), + pos1[0], pos1[1], pos1[2], + pos2[0], pos2[1], pos2[2], + radius) + + self.cylinders[-1][1] += 1 + + + def petrify(self): + """ + Make this object + + Since the last block of shapes might not be full, this + function copies them to a new block exactly big enough to hold + the shapes in that block. The gc has a chance to release the + old block and reduce memory use. After this point, shapes + must not be added to this ShapeList. + """ + + self.petrified = True + + if len(self.spheres) > 0: + count = self.spheres[-1][1] + if count < ShapeList_inplace._blocking: + block = self.spheres[-1][0] + newblock = Numeric.array(block[0:count], 'f') + self.spheres[-1][0] = newblock + + if len(self.cylinders) > 0: + count = self.cylinders[-1][1] + if count < ShapeList_inplace._blocking: + block = self.cylinders[-1][0] + newblock = Numeric.array(block[0:count], 'f') + self.cylinders[-1][0] = newblock + + +class ShapeList: + + """ + Records sphere and cylinder data and invokes it through the native C++ + rendering system. + + Probably better to use "ShapeList_inplace". + """ + + __author__ = "grantham@plunk.org" + + def __init__(self): + + self.memoized = False + + self.sphere_colors = [] + self.sphere_radii = [] + self.sphere_centers = [] + self.sphere_names = [] + + self.cylinder_colors = [] + self.cylinder_radii = [] + self.cylinder_pos1 = [] + self.cylinder_pos2 = [] + self.cylinder_cappings = [] + self.cylinder_names = [] + + + def _memoize(self): + + """ + Internal function that creates Numeric arrays from the data stored + in add_sphere and add-cylinder. + """ + + self.memoized = True + + # GL Names are uint32. Numeric.array appears to have only + # int32. Winging it... + + self.sphere_colors_array = Numeric.array(self.sphere_colors, 'f') + self.sphere_radii_array = Numeric.array(self.sphere_radii, 'f') + self.sphere_centers_array = Numeric.array(self.sphere_centers, 'f') + self.sphere_names_array = Numeric.array(self.sphere_names, 'i') + + self.cylinder_colors_array = Numeric.array(self.cylinder_colors, 'f') + self.cylinder_radii_array = Numeric.array(self.cylinder_radii, 'f') + self.cylinder_pos1_array = Numeric.array(self.cylinder_pos1, 'f') + self.cylinder_pos2_array = Numeric.array(self.cylinder_pos2, 'f') + self.cylinder_cappings_array = Numeric.array(self.cylinder_cappings, 'f') + self.cylinder_names_array = Numeric.array(self.cylinder_names, 'i') + + + def draw(self): + + """ + Draw all the objects represented in this shape list. + """ + + # ICK - SLOW - Probably no big deal in a display list. + + if len(self.sphere_radii) > 0: + if not self.memoized: + self._memoize() + quux.shapeRendererDrawSpheres(len(self.sphere_radii), + self.sphere_centers_array, + self.sphere_radii_array, + self.sphere_colors_array, + self.sphere_names_array) + + if len(self.cylinder_radii) > 0: + if not self.memoized: + self._memoize() + quux.shapeRendererDrawCylinders(len(self.cylinder_radii), + self.cylinder_pos1_array, + self.cylinder_pos2_array, + self.cylinder_radii_array, + self.cylinder_cappings_array, + self.cylinder_colors_array, + self.cylinder_names_array) + + + def add_sphere(self, color4, pos, radius, name = 0): + """ + Add a sphere to this shape list. + + "color4" must have 4 elements. "name" is the GL selection name. + """ + + self.sphere_colors.append(color4) + self.sphere_centers.append(list(pos)) + self.sphere_radii.append(radius) + self.sphere_names.append(name) + self.memoized = False + + + def add_cylinder(self, color4, pos1, pos2, radius, name = 0, capped=0): + """ + Add a cylinder to this shape list. + + "color4" must have 4 elements. "name" is the GL selection name. + """ + + self.cylinder_colors.append(color4) + self.cylinder_radii.append(radius) + self.cylinder_pos1.append(list(pos1)) + self.cylinder_pos2.append(list(pos2)) + self.cylinder_cappings.append(capped) + self.cylinder_names.append(name) + self.memoized = False + + + def petrify(self): + """ + Delete all but the cached Numeric arrays. + + Call this when you're sure you don't have any more shapes to store + in the shape list and you want to release the python lists of data + back to the heap. Additional shapes must not be added to this shape + list. + """ + if not self.memoized: + self._memoize() + + del self.sphere_colors + del self.sphere_radii + del self.sphere_centers + del self.sphere_names + + del self.cylinder_colors + del self.cylinder_radii + del self.cylinder_pos1 + del self.cylinder_pos2 + del self.cylinder_cappings + del self.cylinder_names diff --git a/cad/src/graphics/drawing/CS_draw_primitives.py b/cad/src/graphics/drawing/CS_draw_primitives.py new file mode 100755 index 000000000..eefba073e --- /dev/null +++ b/cad/src/graphics/drawing/CS_draw_primitives.py @@ -0,0 +1,417 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +CS_draw_primitives.py - Public entry points for ColorSorter drawing primitives. + +These functions all call ColorSorter.schedule_* methods, which record object +data for sorting, including the object color and an eventual call on the +appropriate drawing worker function. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= +from graphics.drawing.ColorSorter import ColorSorter +from graphics.drawing.drawers import drawPoint + +try: + from OpenGL.GLE import gleGetNumSides, gleSetNumSides +except: + print "GLE module can't be imported. Now trying _GLE" + from OpenGL._GLE import gleGetNumSides, gleSetNumSides + +import foundation.env as env #bruce 051126 + +def drawsphere(color, pos, radius, detailLevel, opacity = 1.0): + """ + Schedule a sphere for rendering whenever ColorSorter thinks is appropriate. + """ + ColorSorter.schedule_sphere(color, + pos, + radius, + detailLevel, + opacity = opacity) + +def drawwiresphere(color, pos, radius, detailLevel = 1): + """ + Schedule a wireframe sphere for rendering whenever ColorSorter thinks is appropriate. + """ + ColorSorter.schedule_wiresphere(color, pos, radius, detailLevel = detailLevel) + +def drawcylinder(color, pos1, pos2, radius, capped = 0, opacity = 1.0): + """Schedule a cylinder for rendering whenever ColorSorter thinks is + appropriate.""" + if 1: + #bruce 060304 optimization: don't draw zero-length or almost-zero-length cylinders. + # (This happens a lot, apparently for both long-bond indicators and for open bonds. + # The callers hitting this should be fixed directly! That might provide a further + # optim by making a lot more single bonds draw as single cylinders.) + # The reason the threshhold depends on capped is in case someone draws a very thin + # cylinder as a way of drawing a disk. But they have to use some positive length + # (or the direction would be undefined), so we still won't permit zero-length then. + cyllen = vlen(pos1 - pos2) + if cyllen < (capped and 0.000000000001 or 0.0001): + # uncomment this to find the callers that ought to be optimized +## if env.debug(): #e optim or remove this test; until then it's commented out +## print "skipping drawcylinder since length is only %5g" % (cyllen,), \ +## " (color is (%0.2f, %0.2f, %0.2f))" % (color[0], color[1], color[2]) + return + ColorSorter.schedule_cylinder(color, pos1, pos2, radius, + capped = capped, opacity = opacity) + +def drawcylinder_wireframe(color, end1, end2, radius): #bruce 060608 + "draw a wireframe cylinder (not too pretty, definitely could look nicer, but it works)" + # display polys as their edges (see drawer.py's drawwirecube or Jig.draw for related code) + # (probably we should instead create a suitable lines display list, + # or even use a wire-frame-like texture so various lengths work well) + glPolygonMode(GL_FRONT, GL_LINE) + glPolygonMode(GL_BACK, GL_LINE) + glDisable(GL_LIGHTING) + glDisable(GL_CULL_FACE) # this makes motors look too busy, but without it, they look too weird (which seems worse) + try: + drawcylinder(color, end1, end2, radius) ##k not sure if this color will end up controlling the edge color; we hope it will + except: + debug.print_compact_traceback("bug, ignored: ") + # the following assumes that we are never called as part of a jig's drawing method, + # or it will mess up drawing of the rest of the jig if it's disabled + glEnable(GL_CULL_FACE) + glEnable(GL_LIGHTING) + glPolygonMode(GL_FRONT, GL_FILL) + glPolygonMode(GL_BACK, GL_FILL) # could probably use GL_FRONT_AND_BACK + return + +def drawDirectionArrow(color, + tailPoint, + arrowBasePoint, + tailRadius, + scale, + flipDirection = False, + opacity = 1.0, + numberOfSides = 20 + ): + """ + Draw a directional arrow staring at <tailPoint> with an endpoint decided + by the vector between <arrowBasePoint> and <tailPoint> + and the glpane scale <scale> + @param color : The arrow color + @type color: Array + @param tailPoint: The point on the arrow tail where the arrow begins. + @type tailPoint: V + @param arrowBasePoint: A point on the arrow where the arrow head begins(?? + @type arrowBasePoint: V + @param tailRadius: The radius of the arrow tail (cylinder radius + representing the arrow tail) + @type tailRaius: float + @param opacity: The opacity decides the opacity (or transparent display) + of the rendered arrow. By default it is rendered as a solid + arrow. It varies between 0.0 to 1.0 ... 1.0 represents the + solid arrow renderring style + @type opacity: float + @param numberOfSides: The total number of sides for the arrow head + (a glePolycone) The default value if 20 (20 sided + polycone) + @type numberOfSides: int + """ + + vec = arrowBasePoint - tailPoint + vec = scale*0.07*vec + arrowBase = tailRadius*3.0 + arrowHeight = arrowBase*1.5 + axis = norm(vec) + + #as of 2008-03-03 scaledBasePoint is not used so commenting out. + #(will be removed after more testing) + ##scaledBasePoint = tailPoint + vlen(vec)*axis + drawcylinder(color, tailPoint, arrowBasePoint, tailRadius, capped = True, + opacity = opacity) + + ##pos = scaledBasePoint + pos = arrowBasePoint + arrowRadius = arrowBase + gleSetNumSides(numberOfSides) + drawpolycone(color, [[pos[0] - 1 * axis[0], + pos[1] - 1 * axis[1], + pos[2] - 1 * axis[2]], + [pos[0],# - axis[0], + pos[1], #- axis[1], + pos[2]], #- axis[2]], + [pos[0] + arrowHeight * axis[0], + pos[1] + arrowHeight * axis[1], + pos[2] + arrowHeight * axis[2]], + [pos[0] + (arrowHeight + 1) * axis[0], + pos[1] + (arrowHeight + 1) * axis[1], + pos[2] + (arrowHeight + 1) * axis[2]]], # Point array (the two end + # points not drawn) + [arrowRadius, arrowRadius, 0, 0], # Radius array + opacity = opacity + ) + #reset the gle number of sides to the gle default of '20' + gleSetNumSides(20) + +def drawpolycone(color, pos_array, rad_array, opacity = 1.0): + """Schedule a polycone for rendering whenever ColorSorter thinks is + appropriate.""" + ColorSorter.schedule_polycone(color, pos_array, rad_array, opacity = opacity) + +def drawpolycone_multicolor(color, pos_array, color_array, rad_array, opacity = 1.0): + """Schedule a polycone for rendering whenever ColorSorter thinks is + appropriate. Accepts color_array for per-vertex coloring. """ + ColorSorter.schedule_polycone_multicolor(color, pos_array, color_array, rad_array, opacity = opacity) + +def drawsurface(color, pos, radius, tm, nm): + """ + Schedule a surface for rendering whenever ColorSorter thinks is + appropriate. + """ + ColorSorter.schedule_surface(color, pos, radius, tm, nm) + +def drawsurface_wireframe(color, pos, radius, tm, nm): + glPolygonMode(GL_FRONT, GL_LINE) + glPolygonMode(GL_BACK, GL_LINE) + glDisable(GL_LIGHTING) + glDisable(GL_CULL_FACE) + try: + drawsurface(color, pos, radius, tm, nm) + except: + debug.print_compact_traceback("bug, ignored: ") + glEnable(GL_CULL_FACE) + glEnable(GL_LIGHTING) + glPolygonMode(GL_FRONT, GL_FILL) + glPolygonMode(GL_BACK, GL_FILL) + return + +def drawline(color, + endpt1, + endpt2, + dashEnabled = False, + stipleFactor = 1, + width = 1, + isSmooth = False): + """ + Draw a line from endpt1 to endpt2 in the given color. Actually, schedule + it for rendering whenever ColorSorter thinks is appropriate. + + @param endpt1: First endpoint. + @type endpt1: point + + @param endpt2: Second endpoint. + @type endpt2: point + + @param dashEnabled: If dashEnabled is True, it will be dashed. + @type dashEnabled: boolean + + @param stipleFactor: The stiple factor. + @param stipleFactor: int + + @param width: The line width in pixels. The default is 1. + @type width: int or float + + @param isSmooth: Enables GL_LINE_SMOOTH. The default is False. + @type isSmooth: boolean + + @note: Whether the line is antialiased is determined by GL state variables + which are not set in this function. + + @warning: Some callers pass dashEnabled as a positional argument rather + than a named argument. + """ + ColorSorter.schedule_line(color, endpt1, endpt2, dashEnabled, + stipleFactor, width, isSmooth) + +def drawTag(color, basePoint, endPoint, pointSize = 20.0): + """ + Draw a tag (or a 'flag') as a line ending with a circle (like a balloon + with a string). Note: The word 'Flag' is intentionally not used in the + method nameto avoid potential confusion with a boolean flag. + + @param color: color of the tag + @type color: A + @param basePoint: The base point of the tag + @type basePoint: V + @param endPoint: The end point of the tag + @type endPoint: V + @param pointSize: The pointSize of the point to be drawin at the <endPoint> + @type pointSize: float + + @see: GraphicsMode._drawTags where it is called (an example) + + """ + drawline(color, basePoint, endPoint) + drawPoint(color, endPoint, pointSize = 20.0) diff --git a/cad/src/graphics/drawing/CS_workers.py b/cad/src/graphics/drawing/CS_workers.py new file mode 100755 index 000000000..feabb607d --- /dev/null +++ b/cad/src/graphics/drawing/CS_workers.py @@ -0,0 +1,431 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +CS_workers.py - Drawing functions for primitives drawn by the ColorSorter. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +import graphics.drawing.drawing_globals as drawing_globals +from graphics.drawing.drawers import renderSurface + +try: + from OpenGL.GLE import glePolyCone +except: + print "GLE module can't be imported. Now trying _GLE" + from OpenGL._GLE import glePolyCone + +try: + from OpenGL.GL import glScale +except: + # The installed version of OpenGL requires argument-typed glScale calls. + from OpenGL.GL import glScalef as glScale + +from OpenGL.GL import glScalef + # Note: this is NOT redundant with the above import of glScale -- + # without it, displaying an ESP Image gives a NameError traceback + # and doesn't work. [Fixed by bruce 070703; bug caught by Eric M using + # PyChecker; bug introduced sometime after A9.1 went out.] + +### Substitute this for drawsphere_worker to test drawing a lot of spheres. +def drawsphere_worker_loop(params): + (pos, radius, detailLevel) = params + for x in range(100): ## 500 + for y in range(100): + newpos = pos + (x+x/10+x/100) * V(1, 0, 0) + (y+y/10+y/100) * V(0, 1, 0) + drawsphere_worker((newpos, radius, detailLevel)) + continue + continue + return + +def drawsphere_worker(params): + """Draw a sphere. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below)""" + + (pos, radius, detailLevel) = params + + vboLevel = drawing_globals.use_drawing_variant + + glPushMatrix() + glTranslatef(pos[0], pos[1], pos[2]) + glScale(radius,radius,radius) + + if vboLevel is 0: + glCallList(drawing_globals.sphereList[detailLevel]) + else: # Array variants. + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_NORMAL_ARRAY) + + size = len(drawing_globals.sphereArrays[detailLevel]) + GLIndexType = drawing_globals.sphereGLIndexTypes[detailLevel] + + if vboLevel is 1: # DrawArrays from CPU RAM. + verts = drawing_globals.sphereCArrays[detailLevel] + glVertexPointer(3, GL_FLOAT, 0, verts) + glNormalPointer(GL_FLOAT, 0, verts) + glDrawArrays(GL_TRIANGLE_STRIP, 0, size) + + elif vboLevel is 2: # DrawElements from CPU RAM. + verts = drawing_globals.sphereCElements[detailLevel][1] + glVertexPointer(3, GL_FLOAT, 0, verts) + glNormalPointer(GL_FLOAT, 0, verts) + # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. + index = drawing_globals.sphereElements[detailLevel][0] + glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) + + elif vboLevel is 3: # DrawArrays from graphics RAM VBO. + vbo = drawing_globals.sphereArrayVBOs[detailLevel] + vbo.bind() + glVertexPointer(3, GL_FLOAT, 0, None) + glNormalPointer(GL_FLOAT, 0, None) + glDrawArrays(GL_TRIANGLE_STRIP, 0, vbo.size) + vbo.unbind() + + elif vboLevel is 4: # DrawElements from index in CPU RAM, verts in VBO. + vbo = drawing_globals.sphereElementVBOs[detailLevel][1] + vbo.bind() # Vertex and normal data comes from the vbo. + glVertexPointer(3, GL_FLOAT, 0, None) + glNormalPointer(GL_FLOAT, 0, None) + # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. + index = drawing_globals.sphereElements[detailLevel][0] + glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) + vbo.unbind() + + elif vboLevel is 5: # VBO/IBO buffered DrawElements from graphics RAM. + (ibo, vbo) = drawing_globals.sphereElementVBOs[detailLevel] + vbo.bind() # Vertex and normal data comes from the vbo. + glVertexPointer(3, GL_FLOAT, 0, None) + glNormalPointer(GL_FLOAT, 0, None) + ibo.bind() # Index data comes from the ibo. + glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, None) + vbo.unbind() + ibo.unbind() + pass + + glDisableClientState(GL_VERTEX_ARRAY) + glDisableClientState(GL_NORMAL_ARRAY) + pass + + glPopMatrix() + return + +def drawwiresphere_worker(params): + """ + Draw a wireframe sphere. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below) + """ + + (color, pos, radius, detailLevel) = params + ## assert detailLevel == 1 # true, but leave out for speed + from utilities.debug_prefs import debug_pref, Choice_boolean_True + newway = debug_pref("new wirespheres?", Choice_boolean_True) #bruce 060415 experiment, re iMac G4 wiresphere bug; fixes it! + oldway = not newway + # These objects want a constant line color even if they are selected or highlighted. + glColor3fv(color) + glDisable(GL_LIGHTING) + if oldway: + glPolygonMode(GL_FRONT, GL_LINE) + glPushMatrix() + glTranslatef(pos[0], pos[1], pos[2]) + glScale(radius,radius,radius) + if oldway: + glCallList(drawing_globals.sphereList[detailLevel]) + else: + glCallList(drawing_globals.wiresphere1list) + glEnable(GL_LIGHTING) + glPopMatrix() + if oldway: + glPolygonMode(GL_FRONT, GL_FILL) + return + +def drawcylinder_worker(params): + """ + Draw a cylinder. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below) + + WARNING: our circular cross-section is approximated by a 13-gon + whose alignment around the axis is chosen arbitrary, in a way + which depends on the direction of the axis; negating the axis usually + causes a different alignment of that 13-gon. This effect can cause + visual bugs when drawing one cylinder over an identical or slightly + smaller one (e.g. when highlighting a bond), unless the axes are kept + parallel as opposed to antiparallel. + """ + + (pos1, pos2, radius, capped) = params + + glPushMatrix() + vec = pos2-pos1 + axis = norm(vec) + glTranslatef(pos1[0], pos1[1], pos1[2]) + + ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes + ## display problem on some platforms + angle = -acos(axis[2])*180.0/pi + if (axis[2]*axis[2] >= 1.0): + glRotate(angle, 0.0, 1.0, 0.0) + else: + glRotate(angle, axis[1], -axis[0], 0.0) + + glScale(radius,radius,Numeric.dot(vec,vec)**.5) + glCallList(drawing_globals.CylList) + if capped: glCallList(drawing_globals.CapList) + + glPopMatrix() + + return + +def drawpolycone_worker(params): + """ + Draw a polycone. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below) + """ + (pos_array, rad_array) = params + glePolyCone(pos_array, None, rad_array) + return + +def drawpolycone_multicolor_worker(params): + """ + Draw a polycone. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below) + piotr 080311: this variant accepts a color array as an additional parameter + """ + (pos_array, color_array, rad_array) = params + glEnable(GL_COLOR_MATERIAL) # have to enable GL_COLOR_MATERIAL for + # the GLE function + glPushAttrib(GL_CURRENT_BIT) # store current attributes in case glePolyCone + # modifies the (e.g. current color) + # piotr 080411 + glePolyCone(pos_array, color_array, rad_array) + glPopAttrib() # This fixes the 'disappearing cylinder' bug + # glPopAttrib doesn't take any arguments + # piotr 080415 + glDisable(GL_COLOR_MATERIAL) + return + +def drawsurface_worker(params): + """Draw a surface. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below)""" + + (pos, radius, tm, nm) = params + glPushMatrix() + glTranslatef(pos[0], pos[1], pos[2]) + glScale(radius,radius,radius) + renderSurface(tm, nm) + glPopMatrix() + return + +def drawline_worker(params): + """ + Draw a line. Receive parameters through a sequence so that this + function and its parameters can be passed to another function for + deferment. Right now this is only ColorSorter.schedule (see below) + """ + (endpt1, endpt2, dashEnabled, stipleFactor, width, isSmooth) = params + + ###glDisable(GL_LIGHTING) + ###glColor3fv(color) + if dashEnabled: + glLineStipple(stipleFactor, 0xAAAA) + glEnable(GL_LINE_STIPPLE) + if width != 1: + glLineWidth(width) + if isSmooth: + glEnable(GL_LINE_SMOOTH) + glBegin(GL_LINES) + glVertex(endpt1[0], endpt1[1], endpt1[2]) + glVertex(endpt2[0], endpt2[1], endpt2[2]) + glEnd() + if isSmooth: + glDisable(GL_LINE_SMOOTH) + if width != 1: + glLineWidth(1.0) # restore default state + if dashEnabled: + glDisable(GL_LINE_STIPPLE) + ###glEnable(GL_LIGHTING) + return diff --git a/cad/src/graphics/drawing/ColorSorter.py b/cad/src/graphics/drawing/ColorSorter.py new file mode 100755 index 000000000..aafd00db8 --- /dev/null +++ b/cad/src/graphics/drawing/ColorSorter.py @@ -0,0 +1,879 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +ColorSorter.py - A class to group primitive drawing by colors. + +This was originally done as a GL optimization to minimize calls on +apply_material. + +Later, it was extended to handle multiple display lists per Chunk object as an +optimization to avoid rebuilding a single display list when the appearance of +the object changes for hover-highlighting and selection. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +import graphics.drawing.drawing_globals as drawing_globals +if drawing_globals.quux_module_import_succeeded: + import quux + +from graphics.drawing.CS_ShapeList import ShapeList_inplace +from graphics.drawing.CS_workers import drawcylinder_worker +from graphics.drawing.CS_workers import drawline_worker +from graphics.drawing.CS_workers import drawpolycone_multicolor_worker +from graphics.drawing.CS_workers import drawpolycone_worker +from graphics.drawing.CS_workers import drawsphere_worker +from graphics.drawing.CS_workers import drawsurface_worker +from graphics.drawing.CS_workers import drawwiresphere_worker +from graphics.drawing.gl_lighting import apply_material + +class ColorSortedDisplayList: #Russ 080225: Added. + """ + The ColorSorter's parent uses one of these to store color-sorted display list + state. It's passed in to ColorSorter.start() . + """ + def __init__(self): + self.clear() + self.selected = False # Whether to draw in the selection over-ride color. + return + + #russ 080320 Experiment with VBO drawing from cached ColorSorter lists. + cache_ColorSorter = False ## True + + def clear(self): + """ + Empty state. + """ + self.dl = 0 # Current display list (color or selected.) + self.color_dl = 0 # DL to set colors, call each lower level list. + self.selected_dl = 0 # DL with a single (selected) over-ride color. + self.nocolor_dl = 0 # DL of lower-level calls for color over-rides. + self.per_color_dls = [] # Lower level, per-color primitive sublists. + return + + def not_clear(self): + """ + Check for empty state. + """ + return self.dl or self.color_dl or self.nocolor_dl or self.selected_dl or \ + self.per_color_dls and len(self.per_color_dls) + + def activate(self): + """ + Make a top-level display list id ready, but don't fill it in. + """ + # Display list id for the current appearance. + if not self.selected: + self.color_dl = glGenLists(1) + else: + self.selected_dl = glGenLists(1) + pass + self.selectDl() + assert type(self.dl) in (type(1), type(1L)) #bruce 070521 added these two asserts + assert self.dl != 0 # This failed on Linux, keep checking. (bug 2042) + return + + def draw_dl(self): #russ 080320 Added. + """ + Draw the displist (cached display procedure.) + """ + #russ 080320: Experiment with VBO drawing from cached ColorSorter lists. + if (ColorSortedDisplayList.cache_ColorSorter and + drawing_globals.allow_color_sorting and + drawing_globals.use_color_sorted_vbos): + ColorSorter.draw_sorted(self.sorted_by_color) + else: + # Call a normal OpenGL display list. + glCallList(self.dl) + return + + def selectPick(self, boolVal): + """ + Remember whether we're selected or not. + """ + self.selected = boolVal + self.selectDl() + return + + def selectDl(self): + """ + Change to either the normal-color display list or the selected one. + """ + self.dl = self.selected and self.selected_dl or self.color_dl + return + + def reset(self): + """ + Return to initialized state. + """ + if self.not_clear(): + # deallocate leaves it clear. + self.deallocate_displists() + pass + return + + def deallocate_displists(self): + """ + Free any allocated display lists. + """ + # With CSDL active, self.dl duplicates either selected_dl or color_dl. + if (self.dl is not self.color_dl and + self.dl is not self.selected_dl): + glDeleteLists(self.dl, 1) + for dl in [self.color_dl, self.nocolor_dl, self.selected_dl]: + if dl != 0: + glDeleteLists(dl, 1) + pass + continue + # piotr 080420: The second level dl's are 2-element lists of DL ids + # rather than just a list of ids. The secod DL is used in case + # of multi-color objects and is required for highlighting + # and selection (not in rc1) + for clr, dls in self.per_color_dls: # Second-level dl's. + for dl in dls: # iterate over DL pairs. + if dl != 0: + glDeleteLists(dl, 1) + pass + continue + self.clear() + return + + pass # End of ColorSortedDisplayList. + +class ColorSorter: + + """ + State Sorter specializing in color (Really any object that can be + passed to apply_material, which on 20051204 is only color 4-tuples) + + Invoke start() to begin sorting. + Call finish() to complete sorting and draw all sorted objects. + + Call schedule() with any function and parameters to be sorted by color. + If not sorting, schedule() will invoke the function immediately. If + sorting, then the function will not be called until "finish()". + + In any function which will take part in sorting which previously did + not, create a worker function from the old function except the call to + apply_material. Then create a wrapper which calls + ColorSorter.schedule with the worker function and its params. + + Also an app can call schedule_sphere and schedule_cylinder to + schedule a sphere or a cylinder. Right now this is the only way + to directly access the native C++ rendering engine. + """ + __author__ = "grantham@plunk.org" + + # For now, these are class globals. As long as OpenGL drawing is + # serialized and Sorting isn't nested, this is okay. When/if + # OpenGL drawing becomes multi-threaded, sorters will have to + # become instances. This is probably okay because objects and + # materials will probably become objects of their own about that + # time so the whole system will get a redesign and + # reimplementation. + + sorting = False # Guard against nested sorting + _sorted = 0 # Number of calls to _add_to_sorter since last + # _printstats + _immediate = 0 # Number of calls to _invoke_immediately since last + # _printstats + _gl_name_stack = [0] # internal record of GL name stack; 0 is a sentinel + + def pushName(glname): + """ + Record the current pushed GL name, which must not be 0. + """ + assert glname, "glname of 0 is illegal (used as sentinel)" #bruce 060217 added this assert + ColorSorter._gl_name_stack.append(glname) + + pushName = staticmethod(pushName) + + + def popName(): + """ + Record a pop of the GL name. + """ + del ColorSorter._gl_name_stack[-1] + + popName = staticmethod(popName) + + + def _printstats(): + """ + Internal function for developers to call to print stats on number of + sorted and immediately-called objects. + """ + print "Since previous 'stats', %d sorted, %d immediate: " % (ColorSorter._sorted, ColorSorter._immediate) + ColorSorter._sorted = 0 + ColorSorter._immediate = 0 + + _printstats = staticmethod(_printstats) + + + def _add_to_sorter(color, func, params): + """ + Internal function that stores 'scheduled' operations for a later + sort, between a start/finish + """ + ColorSorter._sorted += 1 + color = tuple(color) + if not ColorSorter.sorted_by_color.has_key(color): + ColorSorter.sorted_by_color[color] = [] + ColorSorter.sorted_by_color[color].append((func, params, + ColorSorter._gl_name_stack[-1])) + + _add_to_sorter = staticmethod(_add_to_sorter) + + + def schedule(color, func, params): + if ColorSorter.sorting and drawing_globals.allow_color_sorting: + + ColorSorter._add_to_sorter(color, func, params) + + else: + + ColorSorter._immediate += 1 # for benchmark/debug stats, mostly + + # 20060216 We know we can do this here because the stack is + # only ever one element deep + name = ColorSorter._gl_name_stack[-1] + if name: + glPushName(name) + + #Apply appropriate opacity for the object if it is specified + #in the 'color' param. (Also do necessary things such as + #call glBlendFunc it. -- Ninad 20071009 + + if len(color) == 4: + opacity = color[3] + else: + opacity = 1.0 + + if opacity >= 0.0 and opacity != 1.0: + glDepthMask(GL_FALSE) + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + elif opacity == -1: + # piotr 080429: I replaced the " < 0" condition with " == -1" + # The opacity flag is now used to signal either "unshaded colors" + # (opacity == -1) or "multicolor object" (opacity == -2) + glDisable(GL_LIGHTING) # Don't forget to re-enable it! + glColor3fv(color[:3]) + pass + + apply_material(color) + func(params) + + if opacity > 0.0 and opacity != 1.0: + glDisable(GL_BLEND) + glDepthMask(GL_TRUE) + elif opacity == -1: + # piotr 080429: See my comment above. + glEnable(GL_LIGHTING) + + if name: + glPopName() + return + + schedule = staticmethod(schedule) + + def schedule_sphere(color, pos, radius, detailLevel, opacity = 1.0): + """ + Schedule a sphere for rendering whenever ColorSorter thinks is + appropriate. + """ + if drawing_globals.use_c_renderer and ColorSorter.sorting: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], opacity) + else: + lcolor = color + ColorSorter._cur_shapelist.add_sphere(lcolor, pos, radius, + ColorSorter._gl_name_stack[-1]) + # 20060208 grantham - I happen to know that one detailLevel + # is chosen for all spheres, I just record it over and + # over here, and use the last one for the render + if ColorSorter.sphereLevel > -1 and ColorSorter.sphereLevel != detailLevel: + raise ValueError, "unexpected different sphere LOD levels within same frame" + ColorSorter.sphereLevel = detailLevel + else: # Older sorted material rendering + if len(color) == 3: + lcolor = (color[0], color[1], color[2], opacity) + else: + lcolor = color + ColorSorter.schedule(lcolor, drawsphere_worker, ### drawsphere_worker_loop ### Testing. + (pos, radius, detailLevel)) + + schedule_sphere = staticmethod(schedule_sphere) + + + def schedule_wiresphere(color, pos, radius, detailLevel = 1): + """ + Schedule a wiresphere for rendering whenever ColorSorter thinks is + appropriate. + """ + if drawing_globals.use_c_renderer and ColorSorter.sorting: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], 1.0) + else: + lcolor = color + assert 0, "Need to implement a C add_wiresphere function." + ColorSorter._cur_shapelist.add_wiresphere(lcolor, pos, radius, + ColorSorter._gl_name_stack[-1]) + else: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], 1.0) + else: + lcolor = color + + ColorSorter.schedule(lcolor, drawwiresphere_worker, + # Use constant-color line drawing. + (color, pos, radius, detailLevel)) + + schedule_wiresphere = staticmethod(schedule_wiresphere) + + def schedule_cylinder(color, pos1, pos2, radius, capped = 0, opacity = 1.0 ): + """ + Schedule a cylinder for rendering whenever ColorSorter thinks is + appropriate. + """ + if drawing_globals.use_c_renderer and ColorSorter.sorting: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], 1.0) + else: + lcolor = color + ColorSorter._cur_shapelist.add_cylinder(lcolor, pos1, pos2, radius, + ColorSorter._gl_name_stack[-1], capped) + else: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], opacity) + else: + lcolor = color + + ColorSorter.schedule(lcolor, drawcylinder_worker, (pos1, pos2, radius, capped)) + + schedule_cylinder = staticmethod(schedule_cylinder) + + def schedule_polycone(color, pos_array, rad_array, capped = 0, opacity = 1.0): + """ + Schedule a polycone for rendering whenever ColorSorter thinks is + appropriate. + """ + if drawing_globals.use_c_renderer and ColorSorter.sorting: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], 1.0) + else: + lcolor = color + assert 0, "Need to implement a C add_polycone_multicolor function." + ColorSorter._cur_shapelist.add_polycone(lcolor, pos_array, rad_array, + ColorSorter._gl_name_stack[-1], capped) + else: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], opacity) + else: + lcolor = color + + ColorSorter.schedule(lcolor, drawpolycone_worker, (pos_array, rad_array)) + + schedule_polycone = staticmethod(schedule_polycone) + + def schedule_polycone_multicolor(color, pos_array, color_array, rad_array, capped = 0, opacity = 1.0): + """ + Schedule a polycone for rendering whenever ColorSorter thinks is + appropriate. + piotr 080311: this variant accepts a color array as an additional parameter + """ + if drawing_globals.use_c_renderer and ColorSorter.sorting: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], 1.0) + else: + lcolor = color + assert 0, "Need to implement a C add_polycone function." + ColorSorter._cur_shapelist.add_polycone_multicolor(lcolor, pos_array, color_array, rad_array, + ColorSorter._gl_name_stack[-1], capped) + else: + if len(color) == 3: + lcolor = (color[0], color[1], color[2], opacity) + else: + lcolor = color + + ColorSorter.schedule(lcolor, drawpolycone_multicolor_worker, (pos_array, color_array, rad_array)) + + schedule_polycone_multicolor = staticmethod(schedule_polycone_multicolor) + + def schedule_surface(color, pos, radius, tm, nm): + """ + Schedule a surface for rendering whenever ColorSorter thinks is + appropriate. + """ + ColorSorter.schedule(color, drawsurface_worker, (pos, radius, tm, nm)) + + schedule_surface = staticmethod(schedule_surface) + + def schedule_line(color, endpt1, endpt2, dashEnabled, + stipleFactor, width, isSmooth): + """ + Schedule a line for rendering whenever ColorSorter thinks is + appropriate. + """ + #russ 080306: Signal "unshaded colors" for lines by a negative alpha. (Hack!) + color = tuple(color) + (-1,) + ColorSorter.schedule(color, drawline_worker, + (endpt1, endpt2, dashEnabled, + stipleFactor, width, isSmooth)) + + schedule_line = staticmethod(schedule_line) + + def start(csdl, pickstate=None): + """ + Start sorting - objects provided to "schedule", "schedule_sphere", and + "schedule_cylinder" will be stored for a sort at the time "finish" is called. + csdl is a ColorSortedDisplayList or None, in which case immediate drawing is done. + pickstate (optional) indicates whether the parent is currently selected. + """ + + #russ 080225: Moved glNewList here for displist re-org. + ColorSorter.parent_csdl = csdl # Remember, used by finish(). + if pickstate is not None: + csdl.selectPick(pickstate) + pass + + if csdl != None: + if not (drawing_globals.allow_color_sorting and + (drawing_globals.use_color_sorted_dls + or drawing_globals.use_color_sorted_vbos)): #russ 080320 + # This is the beginning of the single display list created when color + # sorting is turned off. It is ended in ColorSorter.finish . In + # between, the calls to draw{sphere,cylinder,polycone} methods pass + # through ColorSorter.schedule_* but are immediately sent to *_worker + # where they do OpenGL drawing that is captured into the display list. + try: + if csdl.dl is 0: + csdl.activate() # Allocate a display list for our use. + pass + glNewList(csdl.dl, GL_COMPILE_AND_EXECUTE) # Start a single-level list. + except: + print "data related to following exception: csdl.dl = %r" % (csdl.dl,) #bruce 070521 + raise + + assert not ColorSorter.sorting, "Called ColorSorter.start but already sorting?!" + ColorSorter.sorting = True + if drawing_globals.use_c_renderer and ColorSorter.sorting: + ColorSorter._cur_shapelist = ShapeList_inplace() + ColorSorter.sphereLevel = -1 + else: + ColorSorter.sorted_by_color = {} + + start = staticmethod(start) + + def finish(): + """ + Finish sorting - objects recorded since "start" will + be sorted and invoked now. + """ + from utilities.debug_prefs import debug_pref, Choice_boolean_False + debug_which_renderer = debug_pref("debug print which renderer", Choice_boolean_False) #bruce 060314, imperfect but tolerable + + parent_csdl = ColorSorter.parent_csdl + if drawing_globals.use_c_renderer: + quux.shapeRendererInit() + if debug_which_renderer: + #bruce 060314 uncommented/revised the next line; it might have to come after shapeRendererInit (not sure); + # it definitely has to come after a graphics context is created and initialized. + # 20060314 grantham - yes, has to come after quux.shapeRendererInit + print "using C renderer: VBO %s enabled" % (('is NOT', 'is')[quux.shapeRendererGetInteger(quux.IS_VBO_ENABLED)]) + quux.shapeRendererSetUseDynamicLOD(0) + if ColorSorter.sphereLevel != -1: + quux.shapeRendererSetStaticLODLevels(ColorSorter.sphereLevel, 1) + quux.shapeRendererStartDrawing() + ColorSorter._cur_shapelist.draw() + quux.shapeRendererFinishDrawing() + ColorSorter.sorting = False + + # So chunks can actually record their shapelist + # at some point if they want to + # ColorSorter._cur_shapelist.petrify() + # return ColorSorter._cur_shapelist + + else: + if debug_which_renderer: + print "using Python renderer: use_color_sorted_dls %s enabled" \ + % (drawing_globals.use_color_sorted_dls and 'IS' + or 'is NOT') + print "using Python renderer: use_color_sorted_vbos %s enabled" \ + % (drawing_globals.use_color_sorted_vbos and 'IS' + or 'is NOT') + color_groups = len(ColorSorter.sorted_by_color) + objects_drawn = 0 + + if (not (drawing_globals.allow_color_sorting and + drawing_globals.use_color_sorted_dls) + or (ColorSortedDisplayList.cache_ColorSorter and + drawing_globals.allow_color_sorting and + drawing_globals.use_color_sorted_vbos) + or parent_csdl is None): #russ 080225 Added, 080320 VBO experiment. + + # Either all in one display list, or immediate-mode drawing. + objects_drawn += ColorSorter.draw_sorted(ColorSorter.sorted_by_color) + + #russ 080225: Moved glEndList here for displist re-org. + if parent_csdl is not None: + #russ 080320: Experiment with VBO drawing from cached ColorSorter lists. + if (ColorSortedDisplayList.cache_ColorSorter and + drawing_globals.allow_color_sorting and + drawing_globals.use_color_sorted_vbos): + # Remember the ColorSorter lists for use as a pseudo-display-list. + parent_csdl.sorted_by_color = ColorSorter.sorted_by_color + else: + # Terminate a single display list, created when color sorting + # is turned off. It was started in ColorSorter.start . + glEndList() + pass + pass + + else: #russ 080225 + + parent_csdl.reset() + + # First build the lower level per-color sublists of primitives. + for color, funcs in ColorSorter.sorted_by_color.iteritems(): + sublists = [glGenLists(1), 0] + + # Remember the display list ID for this color. + parent_csdl.per_color_dls.append([color, sublists]) + + glNewList(sublists[0], GL_COMPILE) + opacity = color[3] + + if opacity == -1: + #russ 080306: "Unshaded colors" for lines are signaled + # by an opacity of -1 (4th component of the color.) + glDisable(GL_LIGHTING) # Don't forget to re-enable it! + pass + + for func, params, name in funcs: + objects_drawn += 1 + if name != 0: + glPushName(name) + func(params) + if name != 0: + glPopName() + pass + continue + + if opacity == -1: + # Enable lighting after drawing "unshaded" objects. + glEnable(GL_LIGHTING) + pass + glEndList() + + if opacity == -2: + # piotr 080419: Special case for drawpolycone_multicolor + # create another display list that ignores + # the contents of color_array. + # Remember the display list ID for this color. + + sublists[1] = glGenLists(1) + + glNewList(sublists[1], GL_COMPILE) + + for func, params, name in funcs: + objects_drawn += 1 + if name != 0: + glPushName(name) + pos_array, color_array, rad_array = params + if func == drawpolycone_multicolor_worker: + # Just to be sure, check if the func + # is drawpolycone_multicolor_worker + # and call drawpolycone_worker instead. + # I think in the future we can figure out + # a more general way of handling the + # GL_COLOR_MATERIAL objects. piotr 080420 + drawpolycone_worker((pos_array, rad_array)) + if name != 0: + glPopName() + pass + continue + glEndList() + + continue + + # Now the upper-level lists call all of the per-color sublists. + # One with colors. + color_dl = parent_csdl.color_dl = glGenLists(1) + glNewList(color_dl, GL_COMPILE) + + for color, dls in parent_csdl.per_color_dls: + + opacity = color[3] + if opacity < 0: + #russ 080306: "Unshaded colors" for lines are signaled + # by a negative alpha. + glColor3fv(color[:3]) + # piotr 080417: for opacity == -2, i.e. if + # GL_COLOR_MATERIAL is enabled, the color is going + # to be ignored, anyway, so it is not necessary + # to be tested here + else: + apply_material(color) + + glCallList(dls[0]) + + continue + glEndList() + + # A second one without any colors. + nocolor_dl = parent_csdl.nocolor_dl = glGenLists(1) + glNewList(nocolor_dl, GL_COMPILE) + for color, dls in parent_csdl.per_color_dls: + opacity = color[3] + + if opacity == -2 \ + and dls[1] > 0: + # piotr 080420: If GL_COLOR_MATERIAL is enabled, + # use a regular, single color dl rather than the + # multicolor one. Btw, dls[1] == 0 should never + # happen. + glCallList(dls[1]) + else: + glCallList(dls[0]) + + glEndList() + + # A third overlays the second with a single color for selection. + selected_dl = parent_csdl.selected_dl = glGenLists(1) + glNewList(selected_dl, GL_COMPILE) + apply_material(darkgreen) + glCallList(nocolor_dl) + glEndList() + + # Use either the normal-color display list or the selected one. + parent_csdl.selectDl() + + # Draw the newly-built display list. + parent_csdl.draw_dl() + pass + + ColorSorter.sorted_by_color = None + pass + ColorSorter.sorting = False + return + + finish = staticmethod(finish) + + def draw_sorted(sorted_by_color): #russ 080320: factored out of finish(). + """ + Traverse color-sorted lists, invoking worker procedures. + """ + objects_drawn = 0 # Keep track and return. + glEnable(GL_LIGHTING) + + for color, funcs in sorted_by_color.iteritems(): + + opacity = color[3] + if opacity == -1: + #piotr 080429: Opacity == -1 signals the "unshaded color". + # Also, see my comment in "schedule". + glDisable(GL_LIGHTING) # Don't forget to re-enable it! + glColor3fv(color[:3]) + else: + apply_material(color) + pass + + for func, params, name in funcs: + objects_drawn += 1 + if name != 0: + glPushName(name) + func(params) + if name != 0: + glPopName() + pass + continue + + if opacity == -1: + glEnable(GL_LIGHTING) + + continue + return objects_drawn + + draw_sorted = staticmethod(draw_sorted) + + pass # End of class ColorSorter. diff --git a/cad/src/graphics/drawing/Font3D.py b/cad/src/graphics/drawing/Font3D.py index 1311d8771..be150461f 100755 --- a/cad/src/graphics/drawing/Font3D.py +++ b/cad/src/graphics/drawing/Font3D.py @@ -23,7 +23,7 @@ from Numeric import dot from OpenGL.GL import glVertex from geometry.VQT import cross -from graphics.drawing.drawer import drawline # import cycle +from graphics.drawing.CS_draw_primitives import drawline # import cycle _font = { ' ': ( ), diff --git a/cad/src/graphics/drawing/bond_drawer.py b/cad/src/graphics/drawing/bond_drawer.py index 561b60d9b..54e046437 100755 --- a/cad/src/graphics/drawing/bond_drawer.py +++ b/cad/src/graphics/drawing/bond_drawer.py @@ -24,11 +24,11 @@ from PyQt4.Qt import QFont, QString, QColor from geometry.VQT import V from geometry.VQT import norm, vlen -from graphics.drawing.drawer import ColorSorter -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawsphere -from graphics.drawing.drawer import drawpolycone +from graphics.drawing.ColorSorter import ColorSorter +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.CS_draw_primitives import drawpolycone import foundation.env as env from utilities import debug_flags diff --git a/cad/src/graphics/drawing/dimensions.py b/cad/src/graphics/drawing/dimensions.py index 5335ddcb8..4d7f0cde7 100755 --- a/cad/src/graphics/drawing/dimensions.py +++ b/cad/src/graphics/drawing/dimensions.py @@ -21,7 +21,7 @@ from utilities import debug_flags from geometry.VQT import cross from geometry.VQT import vlen from geometry.VQT import norm -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from graphics.drawing.Font3D import Font3D, WIDTH, HEIGHT # TODO: WIDTH, HEIGHT should be Font3D attributes [bruce 071030 comment] diff --git a/cad/src/graphics/drawing/drawDnaLadder.py b/cad/src/graphics/drawing/drawDnaLadder.py index 0b931d35a..2d7c429e6 100755 --- a/cad/src/graphics/drawing/drawDnaLadder.py +++ b/cad/src/graphics/drawing/drawDnaLadder.py @@ -21,9 +21,9 @@ from OpenGL.GL import glPopMatrix from OpenGL.GL import glPushMatrix from OpenGL.GL import glTranslatef -from graphics.drawing.drawer import drawArrowHead -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import drawPoint +from graphics.drawing.drawers import drawArrowHead +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.drawers import drawPoint from geometry.VQT import norm, vlen, V, cross diff --git a/cad/src/graphics/drawing/drawDnaRibbons.py b/cad/src/graphics/drawing/drawDnaRibbons.py index e6ef153dc..093eb3a60 100755 --- a/cad/src/graphics/drawing/drawDnaRibbons.py +++ b/cad/src/graphics/drawing/drawDnaRibbons.py @@ -26,11 +26,11 @@ from OpenGL.GL import glPopMatrix from OpenGL.GL import glPushMatrix from OpenGL.GL import glTranslatef -from graphics.drawing.drawer import drawArrowHead -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import drawPoint -from graphics.drawing.drawer import drawsphere -from graphics.drawing.drawer import drawtext +from graphics.drawing.drawers import drawArrowHead +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.drawers import drawPoint +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.drawers import drawtext from geometry.VQT import norm, vlen, V, cross, Q from geometry.VQT import orthodist, angleBetween diff --git a/cad/src/graphics/drawing/drawNanotubeLadder.py b/cad/src/graphics/drawing/drawNanotubeLadder.py index 2a26b3b8b..33c7a6d86 100644 --- a/cad/src/graphics/drawing/drawNanotubeLadder.py +++ b/cad/src/graphics/drawing/drawNanotubeLadder.py @@ -15,9 +15,9 @@ from OpenGL.GL import glPopMatrix from OpenGL.GL import glPushMatrix from OpenGL.GL import glTranslatef -from graphics.drawing.drawer import drawline -from graphics.drawing.drawer import drawPoint -from graphics.drawing.drawer import drawCircle +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.drawers import drawPoint +from graphics.drawing.drawers import drawCircle from geometry.VQT import norm, vlen, V, cross diff --git a/cad/src/graphics/drawing/draw_bond_vanes.py b/cad/src/graphics/drawing/draw_bond_vanes.py index 21bedfa26..ee7227d8e 100755 --- a/cad/src/graphics/drawing/draw_bond_vanes.py +++ b/cad/src/graphics/drawing/draw_bond_vanes.py @@ -32,7 +32,7 @@ from OpenGL.GL import GL_FALSE from geometry.VQT import cross, vlen, norm import foundation.env as env -from graphics.drawing.drawer import apply_material +from graphics.drawing.gl_lighting import apply_material from utilities.constants import white from utilities.prefs_constants import pibondStyle_prefs_key diff --git a/cad/src/graphics/drawing/draw_grid_lines.py b/cad/src/graphics/drawing/draw_grid_lines.py index 60b7de0d9..2ad5047da 100644 --- a/cad/src/graphics/drawing/draw_grid_lines.py +++ b/cad/src/graphics/drawing/draw_grid_lines.py @@ -55,7 +55,7 @@ from OpenGL.GL import glVertex3fv from OpenGL.GL import glEndList from OpenGL.GL import glColor3fv -from graphics.drawing.drawer import drawtext +from graphics.drawing.drawers import drawtext from geometry.VQT import V from graphics.drawing.Font3D import Font3D diff --git a/cad/src/graphics/drawing/drawer.py b/cad/src/graphics/drawing/drawer.py deleted file mode 100755 index a2b777571..000000000 --- a/cad/src/graphics/drawing/drawer.py +++ /dev/null @@ -1,3975 +0,0 @@ -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -drawer.py - OpenGL drawing utilities. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. - -TODO: - -This module is too large. It needs to be split into -several smaller files. Don't add new functions to it -- -add them in new files whose names start with "draw". - -History: - -Originated by Josh. - -Various developers extended it since then. - -Brad G. added ColorSorter features. - -At some point Bruce partly cleaned up the use of display lists. - -071030 bruce split some functions and globals into draw_grid_lines.py -and removed some obsolete functions. - -080210 russ Split the single display-list into two second-level lists (with and without color) -and a set of per-color sublists so selection and hover-highlight can over-ride Chunk base colors. -ColorSortedDisplayList is now a class in the parent's displist attr to keep track of all that stuff. - -080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone -tubes with per-vertex colors (necessary for DNA display style) - -080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". - -080420 piotr Solved highlighting and selection problems for multi-colored -objects (e.g. rainbow colored DNA structures). - -""" - -import os -import sys - -# the imports from math vs. Numeric are as discovered in existing code -# as of 2007/06/25. It's not clear why acos is coming from math... -from math import floor, ceil, acos, atan2 -import Numeric -from Numeric import sin, cos, sqrt, pi -degreesPerRadian = 180.0 / pi - -from OpenGL.GL import GL_AMBIENT -from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE -from OpenGL.GL import glAreTexturesResident -from OpenGL.GL import GL_ARRAY_BUFFER_ARB -from OpenGL.GL import GL_BACK -from OpenGL.GL import glBegin -from OpenGL.GL import glBindTexture -from OpenGL.GL import GL_BLEND -from OpenGL.GL import glBlendFunc -from OpenGL.GL import glCallList -from OpenGL.GL import glColor3f -from OpenGL.GL import glColor3fv -from OpenGL.GL import glColor4fv -from OpenGL.GL import GL_COLOR_MATERIAL -from OpenGL.GL import GL_COMPILE -from OpenGL.GL import GL_COMPILE_AND_EXECUTE -from OpenGL.GL import GL_CONSTANT_ATTENUATION -from OpenGL.GL import GL_CULL_FACE -from OpenGL.GL import GL_CURRENT_BIT -from OpenGL.GL import glDeleteLists -from OpenGL.GL import glDeleteTextures -from OpenGL.GL import glDepthMask -from OpenGL.GL import GL_DEPTH_TEST -from OpenGL.GL import GL_DIFFUSE -from OpenGL.GL import glDisable -from OpenGL.GL import glDisableClientState -from OpenGL.GL import glDrawArrays -from OpenGL.GL import glDrawElements -from OpenGL.GL import glDrawElementsub -from OpenGL.GL import glDrawElementsui -from OpenGL.GL import glDrawElementsus -from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB -from OpenGL.GL import glEnable -from OpenGL.GL import glEnableClientState -from OpenGL.GL import glEnd -from OpenGL.GL import glEndList -from OpenGL.GL import GL_EXTENSIONS -from OpenGL.GL import GL_FALSE -from OpenGL.GL import GL_FILL -from OpenGL.GL import glFinish -from OpenGL.GL import GL_FLOAT -from OpenGL.GL import GL_FOG -from OpenGL.GL import GL_FOG_COLOR -from OpenGL.GL import GL_FOG_END -from OpenGL.GL import GL_FOG_MODE -from OpenGL.GL import GL_FOG_START -from OpenGL.GL import GL_FRONT -from OpenGL.GL import GL_FRONT_AND_BACK -from OpenGL.GL import glGenLists -from OpenGL.GL import glGenTextures -from OpenGL.GL import glGetString -from OpenGL.GL import GL_LIGHT0 -from OpenGL.GL import GL_LIGHT1 -from OpenGL.GL import GL_LIGHT2 -from OpenGL.GL import glLightf -from OpenGL.GL import glLightfv -from OpenGL.GL import GL_LIGHTING -from OpenGL.GL import GL_LINE -from OpenGL.GL import GL_LINEAR -from OpenGL.GL import GL_LINE_LOOP -from OpenGL.GL import GL_LINES -from OpenGL.GL import GL_LINE_SMOOTH -from OpenGL.GL import glLineStipple -from OpenGL.GL import GL_LINE_STIPPLE -from OpenGL.GL import GL_LINE_STRIP -from OpenGL.GL import glLineWidth -from OpenGL.GL import glLoadIdentity -from OpenGL.GL import glMaterialf -from OpenGL.GL import glMaterialfv -from OpenGL.GL import glMatrixMode -from OpenGL.GL import GL_MODELVIEW -from OpenGL.GL import glNewList -from OpenGL.GL import glNormal3fv -from OpenGL.GL import glNormalPointer -from OpenGL.GL import glNormalPointerf -from OpenGL.GL import GL_NORMAL_ARRAY -from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA -from OpenGL.GL import glPointSize -from OpenGL.GL import GL_POINTS -from OpenGL.GL import GL_POINT_SMOOTH -from OpenGL.GL import GL_POLYGON -from OpenGL.GL import glPolygonMode -from OpenGL.GL import glPopAttrib -from OpenGL.GL import glPopMatrix -from OpenGL.GL import glPopName -from OpenGL.GL import GL_POSITION -from OpenGL.GL import glPushAttrib -from OpenGL.GL import glPushMatrix -from OpenGL.GL import glPushName -from OpenGL.GL import GL_QUADS -from OpenGL.GL import GL_QUAD_STRIP -from OpenGL.GL import GL_RENDERER -from OpenGL.GL import GL_RGBA -from OpenGL.GL import glRotate -from OpenGL.GL import glRotatef -from OpenGL.GL import GL_SHININESS -from OpenGL.GL import GL_SPECULAR -from OpenGL.GL import GL_SRC_ALPHA -from OpenGL.GL import GL_STATIC_DRAW -from OpenGL.GL import glTexCoord2f -from OpenGL.GL import glTexCoord2fv -from OpenGL.GL import GL_TEXTURE_2D -from OpenGL.GL import glTranslate -from OpenGL.GL import glTranslatef -from OpenGL.GL import GL_TRIANGLES -from OpenGL.GL import GL_TRIANGLE_STRIP -from OpenGL.GL import GL_TRUE -from OpenGL.GL import GL_UNSIGNED_BYTE -from OpenGL.GL import GL_UNSIGNED_SHORT -from OpenGL.GL import GL_VENDOR -from OpenGL.GL import GL_VERSION -from OpenGL.GL import glVertex -from OpenGL.GL import glVertex2f -from OpenGL.GL import glVertex3f -from OpenGL.GL import glVertex3fv -from OpenGL.GL import GL_VERTEX_ARRAY -from OpenGL.GL import glVertexPointer -from OpenGL.GL import glVertexPointerf - -from OpenGL.GLU import gluBuild2DMipmaps - -try: - from OpenGL.GL import glScale -except: - # The installed version of OpenGL requires argument-typed glScale calls. - from OpenGL.GL import glScalef as glScale - -from OpenGL.GL import glScalef - # Note: this is NOT redundant with the above import of glScale -- - # without it, displaying an ESP Image gives a NameError traceback - # and doesn't work. [Fixed by bruce 070703; bug caught by Eric M using - # PyChecker; bug introduced sometime after A9.1 went out.] - -try: - from OpenGL.GL import glFog - from OpenGL.GL import glFogv # piotr 080515 -except: - # The installed version of OpenGL requires argument-typed glFog calls. - from OpenGL.GL import glFogf as glFog - from OpenGL.GL import glFogfv as glFogv - -from geometry.VQT import norm, vlen, V, Q, A - -from utilities.constants import white, blue, red -from utilities.constants import darkgreen, lightblue -from utilities.constants import DIAMOND_BOND_LENGTH -from utilities.prefs_constants import material_specular_highlights_prefs_key -from utilities.prefs_constants import material_specular_shininess_prefs_key -from utilities.prefs_constants import material_specular_finish_prefs_key -from utilities.prefs_constants import material_specular_brightness_prefs_key - -import graphics.drawing.drawing_globals as drawing_globals - -from utilities.debug_prefs import Choice -import utilities.debug as debug # for debug.print_compact_traceback - -# this can't be done at toplevel due to a recursive import issue. -# TODO: fix by splitting this module (drawer) into smaller files. -## from Font3D import Font3D - -import utilities.EndUser as EndUser - -import numpy - -#================================================================ shape_vertices.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -shape_vertices.py - Geometric constructions of vertex lists used by the drawing functions. - -This includes vertices for the shapes of primitives that will go into display -lists in the setup_drawer function in setup_draw.py . - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals - -def init_icos(): - global icosa, icosix - - # the golden ratio - global phi - phi = (1.0+sqrt(5.0))/2.0 - vert = norm(V(phi,0,1)) - a = vert[0] - b = vert[1] - c = vert[2] - - # vertices of an icosahedron - icosa = ((-a,b,c), (b,c,-a), (b,c,a), (a,b,-c), (-c,-a,b), (-c,a,b), - (b,-c,a), (c,a,b), (b,-c,-a), (a,b,c), (c,-a,b), (-a,b,-c)) - icosix = ((9, 2, 6), (1, 11, 5), (11, 1, 8), (0, 11, 4), (3, 1, 7), - (3, 8, 1), (9, 3, 7), (0, 6, 2), (4, 10, 6), (1, 5, 7), - (7, 5, 2), (8, 3, 10), (4, 11, 8), (9, 7, 2), (10, 9, 6), - (0, 5, 11), (0, 2, 5), (8, 10, 4), (3, 9, 10), (6, 0, 4)) - return -init_icos() - -# generate geodesic spheres by subdividing the faces of an icosahedron -# recursively: -# /\ /\ -# / \ / \ -# / \ /____\ -# / \ => /\ /\ -# / \ / \ / \ -# /__________\ /____\/____\ -# -# and normalizing the resulting vectors to the surface of a sphere - -def subdivide(tri,deep): - if deep: - a = tri[0] - b = tri[1] - c = tri[2] - a1 = norm(A(tri[0])) - b1 = norm(A(tri[1])) - c1 = norm(A(tri[2])) - d = tuple(norm(a1+b1)) - e = tuple(norm(b1+c1)) - f = tuple(norm(c1+a1)) - return subdivide((a,d,f), deep-1) + subdivide((d,e,f), deep-1) +\ - subdivide((d,b,e), deep-1) + subdivide((f,e,c), deep-1) - else: return [tri] - -## Get the specific detail level of triangles approximation of a sphere -def getSphereTriangles(level): - ocdec = [] - for i in icosix: - ocdec += subdivide((icosa[i[0]],icosa[i[1]],icosa[i[2]]),level) - return ocdec - -# == - -# Instead of the above recursive scheme that orients the icosahedron with the -# midpoints of six edges perpendicular to the major axes, use a ring approach -# to make subdivided icosa-spheres for Triangle Strips. The vertices are -# grouped in rings from the North Pole to the South Pole. Each strip zig-zags -# between two rings, and the poles are surrounded by pentagonal Triangle Fans. -# -# ---------------- -# -# The pattern of five-fold vertices in a "twisted orange-slice" segment -# covering one-fifth of the icosahedron is: -# -# ... [3,0] ... (North Pole) -# / | \ -# / | ... -# / | -# ... [2,1]---[2,0] ... -# / \ / \ -# ... \ / \ ... -# \ / \ / -# ... [1,1]---[1,0] ... -# | / -# ... | / -# \ | / -# ... [0,0] ... (South Pole) -# -# ---------------- -# -# Higher subdivision levels step the strip verts along the icos edges, -# interpolating intermediate points on the icos and projecting each onto the -# sphere. Note: sphere vertex normals are the same as their coords. -# -# The "*"s show approximate vertex locations at each subdivision level. -# Bands are numbered from South to North. (Reason explained below.) -# Sub-band numbers are in angle-brackets, "<>". -# -# Level 0 [3*0] Level 1 [6*0] Level 2 [12*0] _<3> -# / | (2 steps) / | <1> (4 steps) *-* _<2> -# Band 2 / | * - * *-*-* _<1> -# / | / | / | <0> *-*-*-* _<0> -# [2*1]- -[2*0] => [4*2]-*-[4*0] => [8*4]***[8*0] _<3> -# \ / \ \ / \ / \ <1> *-*-*-*-* _<2> -# Band 1 \ / \ * - * - * *-*-*-*-* _<1> -# \ / \ \ / \ / \ <0> *-*-*-*-* _<0> -# [1*1]---[1*0] [2*2]-*-[2*0] [4*4]***[4*0]_<3> -# | / | \ | / <1> *-*-*-* _<2> -# Band 0 | / * - * *-*-* _<1> -# | / | / <0> *-* _<0> -# [0*0] [0*0] [0*0] -# -# ---------------- -# -# The reason for rotating east, then going west along the latitude lines, is -# that the "grain" of triangle strip diagonals runs that way in the middle -# band of the icos: -# -# Triangle Strip triangles -# -# 6 ----- 4 ----- 2 -# \5,4,6/ \3,2,4/ \ -# ... \ / \ / \ -# \ /3,4,5\ /1,2,3\ -# 5 ----- 3 ----- 1 <- Vertex order -# -# This draws triangles 1-2-3, 3-2-4, 3-4-5, and 5-4-6, all counter-clockwise -# so the normal directions don't flip-flop. -# -# ---------------- -# -# This version optimizes by concatenating vertices for separate Triangle Fan -# and Triangle Strip calls into a single long Triangle Strip to minimize calls. -# -# In the "pentagon cap" band at the top of the icos, points 2, 4, and 6 in the -# above example are collapsed to the North Pole; at the bottom, points 1, 3, -# and 5 are collapsed to the South Pole. This makes "null triangles" with one -# zero-length edge, and the other two edges echoing one of the other triangle -# edges (5,4,6 and 3,2,4 at the top, and 3,4,5 and 1,2,3 at the bottom.) -# -# In the subdivided caps, the icosahedron bands are split into horizontal -# sub-bands. In the tapering-in sub-bands in the North cap, there is one less -# vertex on the top edges of sub-bands, so we collapse the *LAST* triangle -# there (e.g. 5,4,6 above) On the bottom edges of the South cap bands there -# is one less vertex, so we collapse the *FIRST* triangle (e.g. 1,2,3.) -# -# Similarly, moving from the end of each sub-band to the beginning of the next -# requires a *pair* of null triangles. We get that by simply concatenating the -# wrapped triangle strips. We orient point pairs in the triangle strip from -# south to north, so this works as long as we jog northward between (sub-)bands. -# This is the reason we start the Triangle Strip with the South Pole band. -# -def getSphereTriStrips(level): - steps = 2**level - points = [] # Triangle Strip vertices o be returned. - - # Construct an icosahedron with two vertices at the North and South Poles, - # +-1 on the Y axis, as you look toward the X-Y plane with the Z axis - # pointing out at you. The "middle ring" vertices are all at the same - # +-latitudes, on the intersection circles of the globe with a polar-axis - # cylinder of the proper radius. - # - # The third "master vertex" of the icosahedron is placed on the X-Y plane, - # which intersects the globe at the Greenwich Meridian (the semi-circle at - # longitude 0, through Greenwich Observatory, 5 miles south-east of London.) - # - # The X (distance from the polar axis) and Y (height above the equatorial - # plane) of the master vertex make a "golden rectangle", one unit high by - # "phi" (1.6180339887498949) wide. We normalize this to put it on the - # unit-radius sphere, and take the distance from the axis as the cylinder - # radius used to generate the rest of the vertices of the two middle rings. - # - # Plotted on the globe, the master vertex (first vertex of the North ring) - # is lat-long 31.72,0 due south of London in Africa, about 45 miles - # south-southwest of Benoud, Algeria. The first vertex of the south ring is - # rotated 1/10 of a circle east, at lat-long -31.72,36 in the south end of - # the Indian Ocean, about 350 miles east-southeast of Durban, South Africa. - # - vert0 = norm(V(phi,1,0)) # Project the "master vertex" onto a unit sphere. - cylRad = vert0[0] # Icos vertex distance from the Y axis. - ringLat = atan2(vert0[1], vert0[0]) * degreesPerRadian # Latitude +-31.72 . - - # Basic triangle-strip icosahedron vertices. Start and end with the Poles. - # Reflect the master vertex into the southern hemisphere and rotate 5 copies - # to make the middle rings of 5 vertices at North and South latitudes. - p2_5 = 2*pi / 5.0 - # Simplify indexing by replicating the Poles, so everything is in fives. - icosRings = [ 5 * [V(0.0, -1.0, 0.0)], # South Pole. - - # South ring, first edge *centered on* the Greenwich Meridian. - [V(cylRad*cos((i-.5)*p2_5), -vert0[1], cylRad*sin((i-.5)*p2_5)) - for i in range(5)], - - # North ring, first vertex *on* the Greenwich Meridian. - [V(cylRad*cos(i*p2_5 ), vert0[1], cylRad*sin(i*p2_5)) - for i in range(5)], - - 5 * [V(0.0, 1.0, 0.0)] ] # North Pole. - - - # Three bands, going from bottom to top (South to North.) - for band in range(3): - lowerRing = icosRings[band] - upperRing = icosRings[band+1] - - # Subdivide bands into sub-bands. When level == 0, steps == 1, - # subBand == 0, and we get just the icosahedron out. (Really!) - for subBand in range(steps): - - # Account for the tapering-in at the poles, making less points on - # one edge of a sub-band than there are on the other edge. - botOffset = 0 - if band is 0: # South. - botSteps = max(subBand, 1) # Don't divide by zero. - topSteps = subBand + 1 - # Collapse the *first* triangle of south sub-band bottom edges. - botOffset = -1 - elif band is 1: # Middle. - botSteps = topSteps = steps - else: # band is 2: North. - botSteps = steps - subBand - topSteps = max(steps - (subBand+1), 1) - pass - subBandSteps = max(botSteps, topSteps) - - # Do five segments, clockwise around the North Pole (East to West.) - for seg in range(5): - nextseg = (seg+1) % 5 # Wrap-around. - - # Interpolate ends of bottom & top edges of a sub-band segment. - fractBot = float(subBand)/float(steps) - fractTop = float(subBand+1)/float(steps) - sbBotRight = fractBot * upperRing[seg] + \ - (1.0-fractBot) * lowerRing[seg] - sbTopRight = fractTop * upperRing[seg] + \ - (1.0-fractTop) * lowerRing[seg] - sbBotLeft = fractBot * upperRing[nextseg] + \ - (1.0-fractBot) * lowerRing[nextseg] - sbTopLeft = fractTop * upperRing[nextseg] + \ - (1.0-fractTop) * lowerRing[nextseg] - - # Output the right end of the first segment of the sub-band. - # We'll end up wrapping around to this same pair of points at - # the left end of the last segment of the sub-band. - if seg is 0: - # Project verts from icosahedron faces onto the unit sphere. - points += [norm(sbBotRight), norm(sbTopRight)] - - # Step across the sub-band edges from right to left, - # stitching triangle pairs from their lower to upper edges. - for step in range(1, subBandSteps+1): - - # Interpolate step point pairs along the sub-band edges. - fractLower = float(step+botOffset)/float(botSteps) - lower = fractLower * sbBotLeft + \ - (1.0-fractLower) * sbBotRight - # Collapse the *last* triangle of north sub-band top edges. - fractUpper = float(min(step, topSteps))/float(topSteps) - upper = fractUpper * sbTopLeft + \ - (1.0-fractUpper) * sbTopRight - - # Output verts, projected from icos faces onto unit sphere. - points += [norm(lower), norm(upper)] - - continue # step - continue # seg - continue # subBand - continue # band - return points - -def indexVerts(verts, close): - """ - Compress a vertex array into an array of unique vertices, and an array of - index values into the unique vertices. This is good for converting input - for glDrawArrays into input for glDrawElements. - - The second arg is 'close', the distance between vertices which are close - enough to be considered a single vertex. - - The return value is a pair of arrays (index, verts). - """ - unique = [] - index = [] - for v in verts: - for i in range(len(unique)): - if vlen(unique[i] - v) < close: - index += [i] - break - pass - else: - index += [len(unique)] - unique += [v] - pass - continue - return (index, unique) - -# == - -def init_cyls(): - # generate two circles in space as 13-gons, - # one rotated half a segment with respect to the other - # these are used as cylinder ends [not quite true anymore, see comments just below] - slices = 13 - circ1 = map((lambda n: n*2.0*pi/slices), range(slices+1)) - circ2 = map((lambda a: a+pi/slices), circ1) - drawing_globals.drum0 = drum0 = map((lambda a: (cos(a), sin(a), 0.0)), circ1) - drum1 = map((lambda a: (cos(a), sin(a), 1.0)), circ2) - drum1n = map((lambda a: (cos(a), sin(a), 0.0)), circ2) - - # grantham 20051213 I finally decided the look of the oddly twisted - # cylinder bonds was not pretty enough, so I made a "drum2" which is just - # drum0 with a 1.0 Z coordinate, a la drum1. - #bruce 060609: this apparently introduced the bug of the drum1 end-cap of a cylinder being "ragged" - # (letting empty space show through), which I fixed by using drum2 for that cap rather than drum1. - # drum1 is no longer used except as an intermediate value in the next few lines. - drawing_globals.drum2 = drum2 = map((lambda a: (cos(a), sin(a), 1.0)), circ1) - - # This edge list zips up the "top" vertex and normal and then - # the "bottom" vertex and normal. - # Thus each tuple in the sequence would be (vtop, ntop, vbot, nbot) [grantham 20051213] - # (bruce 051215 simplified the python usage in a way which should create the same list.) - drawing_globals.cylinderEdges = zip(drum0, drum0, drum2, drum0) - - circle = zip(drum0[:-1],drum0[1:],drum1[:-1]) +\ - zip(drum1[:-1],drum0[1:],drum1[1:]) - circlen = zip(drum0[:-1],drum0[1:],drum1n[:-1]) +\ - zip(drum1n[:-1],drum0[1:],drum1n[1:]) - - drawing_globals.cap0n = (0.0, 0.0, -1.0) - drawing_globals.cap1n = (0.0, 0.0, 1.0) - drum0.reverse() - return -init_cyls() - -def init_motors(): - ###data structure to construct the rotation sign for rotary motor - numSeg = 20 - rotS = map((lambda n: pi/2+n*2.0*pi/numSeg), range(numSeg*3/4 + 1)) - zOffset = 0.005 - scaleS = 0.4 - drawing_globals.rotS0n = rotS0n = map( - (lambda a: (scaleS*cos(a), scaleS*sin(a), 0.0 - zOffset)), rotS) - drawing_globals.rotS1n = rotS1n = map( - (lambda a: (scaleS*cos(a), scaleS*sin(a), 1.0 + zOffset)), rotS) - - ###Linear motor arrow sign data structure - drawing_globals.halfHeight = 0.45 - drawing_globals.halfEdge = halfEdge = 3.0 * scaleS * sin(pi/numSeg) - - arrow0Vertices = [ - (rotS0n[-1][0]-halfEdge, rotS0n[-1][1], rotS0n[-1][2]), - (rotS0n[-1][0]+halfEdge, rotS0n[-1][1], rotS0n[-1][2]), - (rotS0n[-1][0], rotS0n[-1][1] + 2.0*halfEdge, rotS0n[-1][2])] - arrow0Vertices.reverse() - drawing_globals.arrow0Vertices = arrow0Vertices - - drawing_globals.arrow1Vertices = [ - (rotS1n[-1][0]-halfEdge, rotS1n[-1][1], rotS1n[-1][2]), - (rotS1n[-1][0]+halfEdge, rotS1n[-1][1], rotS1n[-1][2]), - (rotS1n[-1][0], rotS1n[-1][1] + 2.0*halfEdge, rotS1n[-1][2])] - - drawing_globals.halfEdge = halfEdge = 1.0/3.0 ##1.0/8.0 - drawing_globals.linearArrowVertices = [ - (0.0, -halfEdge, 0.0), (0.0, halfEdge, 0.0), (0.0, 0.0,2*halfEdge)] - - return -init_motors() - -def init_diamond(): - # a chunk of diamond grid, to be tiled out in 3d - sp0 = 0.0 - #bruce 051102 replaced 1.52 with this constant (1.544), re bug 900 (partial fix) - sp1 = DIAMOND_BOND_LENGTH / sqrt(3.0) - sp2 = 2.0*sp1 - sp3 = 3.0*sp1 - sp4 = 4.0*sp1 - - digrid=[[[sp0, sp0, sp0], [sp1, sp1, sp1]], [[sp1, sp1, sp1], [sp2, sp2, sp0]], - [[sp2, sp2, sp0], [sp3, sp3, sp1]], [[sp3, sp3, sp1], [sp4, sp4, sp0]], - [[sp2, sp0, sp2], [sp3, sp1, sp3]], [[sp3, sp1, sp3], [sp4, sp2, sp2]], - [[sp2, sp0, sp2], [sp1, sp1, sp1]], [[sp1, sp1, sp1], [sp0, sp2, sp2]], - [[sp0, sp2, sp2], [sp1, sp3, sp3]], [[sp1, sp3, sp3], [sp2, sp4, sp2]], - [[sp2, sp4, sp2], [sp3, sp3, sp1]], [[sp3, sp3, sp1], [sp4, sp2, sp2]], - [[sp4, sp0, sp4], [sp3, sp1, sp3]], [[sp3, sp1, sp3], [sp2, sp2, sp4]], - [[sp2, sp2, sp4], [sp1, sp3, sp3]], [[sp1, sp3, sp3], [sp0, sp4, sp4]]] - drawing_globals.digrid = A(digrid) - drawing_globals.DiGridSp = sp4 - return -init_diamond() - -def init_cube(): - drawing_globals.cubeVertices = cubeVertices = [ - [-1.0, 1.0, -1.0], [-1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, -1.0], - [-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, -1.0, -1.0]] - - #bruce 051117: compute this rather than letting a subroutine hardcode it as - # a redundant constant - flatCubeVertices = [] - for threemore in cubeVertices: - flatCubeVertices.extend(threemore) - flatCubeVertices = list(flatCubeVertices) #k probably not needed - drawing_globals.flatCubeVertices = flatCubeVertices - - if 1: # remove this when it works - flatCubeVertices_hardcoded = [-1.0, 1.0, -1.0, - -1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0, -1.0, - -1.0, -1.0, -1.0, - -1.0, -1.0, 1.0, - 1.0, -1.0, 1.0, - 1.0, -1.0, -1.0] - assert flatCubeVertices == flatCubeVertices_hardcoded - - sq3 = sqrt(3.0)/3.0 - drawing_globals.cubeNormals = [ - [-sq3, sq3, -sq3], [-sq3, sq3, sq3], - [sq3, sq3, sq3], [sq3, sq3, -sq3], - [-sq3, -sq3, -sq3], [-sq3, -sq3, sq3], - [sq3, -sq3, sq3], [sq3, -sq3, -sq3]] - drawing_globals.cubeIndices = [ - [0, 1, 2, 3], [0, 4, 5, 1], [1, 5, 6, 2], - [2, 6, 7, 3], [0, 3, 7, 4], [4, 7, 6, 5]] - - return -init_cube() - - -# Some variables used by the Lonsdaleite lattice construction. -ux = 1.262; uy = 0.729; dz = 0.5153; ul = 1.544 -drawing_globals.XLen = XLen = 2*ux -drawing_globals.YLen = YLen = 6*uy -drawing_globals.ZLen = ZLen = 2*(ul + dz) - -def _makeLonsCell(): - """Data structure to construct a Lonsdaleite lattice cell""" - lVp = [# 2 outward vertices - [-ux, -2*uy, 0.0], [0.0, uy, 0.0], - # Layer 1: 7 vertices - [ux, -2*uy, ul], [-ux, -2*uy, ul], [0.0, uy, ul], - [ux, 2*uy, ul+dz], [-ux, 2*uy, ul+dz], [0.0, -uy, ul+dz], - [-ux, 4*uy, ul], - # Layer 2: 7 vertices - [ux, -2*uy, 2*(ul+dz)], [-ux, -2*uy, 2*(ul+dz)], [0.0, uy, 2*(ul+dz)], - [ux, 2*uy, 2*ul+dz], [-ux, 2*uy, 2*ul+dz], [0.0, -uy, 2*ul+dz], - [-ux, 4*uy, 2*(ul+dz)] - ] - - res = [ # 2 outward vertical edges for layer 1 - [lVp[0], lVp[3]], [lVp[1], lVp[4]], - # 6 xy Edges for layer 1 - [lVp[2], lVp[7]], [lVp[3], lVp[7]], [lVp[7], lVp[4]], - [lVp[4], lVp[6]], [lVp[4], lVp[5]], - [lVp[6], lVp[8]], - # 2 outward vertical edges for layer 2 - [lVp[14], lVp[7]], [lVp[13], lVp[6]], - # 6 xy Edges for layer 2 - [lVp[14], lVp[9]], [lVp[14], lVp[10]], [lVp[14], lVp[11]], - [lVp[11], lVp[13]], [lVp[11], lVp[12]], - [lVp[13], lVp[15]] - ] - return res -drawing_globals.lonsEdges = _makeLonsCell() - -#================================================================ glprefs.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -glprefs.py - Attributes from drawing-related prefs stored in the prefs db cache. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals - -import foundation.env as env #bruce 051126 - -if EndUser.getAlternateSourcePath() != None: - sys.path.append(os.path.join( EndUser.getAlternateSourcePath(), "experimental/pyrex-opengl")) -else: - sys.path.append("./experimental/pyrex-opengl") - -binPath = os.path.normpath(os.path.dirname(os.path.abspath(sys.argv[0])) + '/../bin') -if binPath not in sys.path: - sys.path.append(binPath) - -try: - import quux - drawing_globals.quux_module_import_succeeded = True - if "experimental" in os.path.dirname(quux.__file__): - # should never happen for end users, but if it does we want to print the warning - if env.debug() or not EndUser.enableDeveloperFeatures(): - print "debug: fyi: Using experimental version of C rendering code:", quux.__file__ -except: - drawing_globals.use_c_renderer = False - drawing_globals.quux_module_import_succeeded = False - if env.debug(): #bruce 060323 added condition - print "WARNING: unable to import C rendering code (quux module). Only Python rendering will be available." - pass - -# grantham 20051118; revised by bruce 051126 -class glprefs: - - def __init__(self): -## self.override_material_specular = None -## # set to 4-element sequence to override material specular component -## self.override_shininess = None -## # if exists, overrides shininess -## self.override_light_specular = None -## # set to 4-element sequence to override light specular component - import foundation.preferences as preferences #bruce 051126 KLUGE: make sure env.prefs exists (could use cleanup, but that's not trivial) - self.update() - - def update(self): #bruce 051126 added this method - """Update attributes from current drawing-related prefs stored in prefs db cache. - This should be called at the start of each complete redraw, or whenever the user changes these global prefs values - (whichever is more convenient). - (Note: When this is called during redraw, its prefs db accesses (like any others) - record those prefs as potentially affecting what should be drawn, so that subsequent - changes to those prefs values cause an automatic gl_update.) - Using these attributes in drawing code (rather than directly accessing prefs db cache) - is desirable for efficiency, since direct access to prefs db cache is a bit slow. - (Our drawing code still does that in other places -- those might also benefit from this system, - though this will soon be moot when low-level drawing code gets rewritten in C.) - """ - self.enable_specular_highlights = not not env.prefs[ - material_specular_highlights_prefs_key] # boolean - if self.enable_specular_highlights: - self.override_light_specular = None # used in glpane - # self.specular_shininess: float; shininess exponent for all specular highlights - self.specular_shininess = float(env.prefs[material_specular_shininess_prefs_key]) - # self.specular_whiteness: float; whiteness for all material specular colors - self.specular_whiteness = float(env.prefs[material_specular_finish_prefs_key]) - # self.specular_brightness: float; for all material specular colors - self.specular_brightness = float(env.prefs[material_specular_brightness_prefs_key]) - else: - self.override_light_specular = (0.0, 0.0, 0.0, 0.0) # used in glpane - # Set these to reasonable values, though these attributes are presumably never used in this case. - # Don't access the prefs db in this case, since that would cause UI prefs changes to do unnecessary gl_updates. - # (If we ever add a scenegraph node which can enable specular highlights but use outside values for these parameters, - # then to make it work correctly we'll need to revise this code.) - self.specular_shininess = 20.0 - self.specular_whiteness = 1.0 - self.specular_brightness = 1.0 - - drawing_globals.allow_color_sorting = env.prefs.get( - drawing_globals.allow_color_sorting_prefs_key, - drawing_globals.allow_color_sorting_default) - drawing_globals.use_color_sorted_dls = env.prefs.get( - drawing_globals.use_color_sorted_dls_prefs_key, - drawing_globals.use_color_sorted_dls_default) - drawing_globals.use_color_sorted_vbos = env.prefs.get( - drawing_globals.use_color_sorted_vbos_prefs_key, - drawing_globals.use_color_sorted_vbos_default) - drawing_globals.use_drawing_variant = env.prefs.get( - drawing_globals.use_drawing_variant_prefs_key, - drawing_globals.use_drawing_variant_default) - drawing_globals.use_c_renderer = ( - drawing_globals.quux_module_import_succeeded and - env.prefs.get(drawing_globals.use_c_renderer_prefs_key, - drawing_globals.use_c_renderer_default)) - - if drawing_globals.use_c_renderer: - quux.shapeRendererSetMaterialParameters(self.specular_whiteness, - self.specular_brightness, - self.specular_shininess); - return - - def materialprefs_summary(self): #bruce 051126 - """ - Return a Python data object summarizing our prefs which affect chunk display lists, - so that memoized display lists should become invalid (due to changes in this object) - if and only if this value becomes different. - """ - res = (self.enable_specular_highlights,) - if self.enable_specular_highlights: - res = res + ( self.specular_shininess, - self.specular_whiteness, - self.specular_brightness ) - - # grantham 20060314 - res += (drawing_globals.quux_module_import_succeeded and - env.prefs.get(drawing_globals.use_c_renderer_prefs_key, - drawing_globals.use_c_renderer_default),) - - # grantham 20060314 - Not too sure this next addition is - # really necessary, but it seems to me that for testing - # purposes it is important to rebuild display lists if the - # color sorting pref is changed. - res += (env.prefs.get(drawing_globals.allow_color_sorting_prefs_key, - drawing_globals.allow_color_sorting_default),) - res += (env.prefs.get(drawing_globals.use_color_sorted_dls_prefs_key, - drawing_globals.use_color_sorted_dls_default),) - res += (env.prefs.get(drawing_globals.use_color_sorted_vbos_prefs_key, - drawing_globals.use_color_sorted_vbos_default),) - res += (env.prefs.get(drawing_globals.use_drawing_variant_prefs_key, - drawing_globals.use_drawing_variant_default),) - return res - - pass # end of class glprefs - -drawing_globals.glprefs = glprefs() - -#================================================================ gl_lighting.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -gl_lighting.py - Lights, materials, and special effects. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -import graphics.drawing.drawing_globals as drawing_globals - -# == -# Helper functions for use by GL widgets wanting to set up lighting. - -#bruce 051212 made these from the code in GLPane which now calls them, so they can also be used in ThumbView - -# Default lights tuples (format is as used by setup_standard_lights; perhaps also assumed by other code). -#grantham 20051121 comment - Light should probably be a class. Right now, -# changing the behavior of lights requires changing a bunch of -# ambiguous tuples and tuple packing/unpacking. -#bruce 051212 moved this here from GLPane; maybe it belongs in prefs_constants instead? -# Note: I'm not sure whether this is the only place where this data is coded. -_default_lights = ((white, 0.1, 0.5, 0.5, -50, 70, 30, True), - (white, 0.1, 0.5, 0.5, -20, 20, 20, True), - (white, 0.1, 0.1, 0.1, 0, 0, 100, False)) - # for each of 3 lights, this stores ((r,g,b),a,d,s,x,y,z,e) - # revised format to include s,x,y,z. Mark 051202. - # revised format to include c (r,g,b). Mark 051204. - # Be sure to keep the lightColor prefs keys and _lights colors synchronized. - # Mark 051204. [a comment from when this was located in GLPane] - -def glprefs_data_used_by_setup_standard_lights( glprefs = None): #bruce 051212 - """ - Return a summary of the glprefs data used by setup_standard_lights, - for use in later deciding whether it needs to be called again due to changes in glprefs. - """ - if glprefs is None: - glprefs = drawing_globals.glprefs - pass - # This must be kept in sync with what's used by setup_standard_lights() . - return (glprefs.override_light_specular,) - -def setup_standard_lights( lights, glprefs = None): - """ - Set up lighting in the current GL context using the supplied "lights" tuple (in the format used by GLPane's prefs) - and the optional glprefs object (which defaults to drawing_globals.glprefs ). - Note: the glprefs data used can be summarized by the related function glprefs_data_used_by_setup_standard_lights (which see). - Warning: has side effects on GL_MODELVIEW matrix. - Note: If GL_NORMALIZE needs to be enabled, callers should do that themselves, - since this depends on what they will draw and might slow down drawing. - """ - #e not sure whether projection matrix also needs to be reset here [bruce 051212] - glMatrixMode(GL_MODELVIEW) - glLoadIdentity() - - if glprefs is None: - glprefs = drawing_globals.glprefs - # note: whatever glprefs data is used below must also be present - # in the return value of glprefs_data_used_by_setup_standard_lights(). [bruce 051212] - - try: - # new code - (((r0,g0,b0),a0,d0,s0,x0,y0,z0,e0), \ - ( (r1,g1,b1),a1,d1,s1,x1,y1,z1,e1), \ - ( (r2,g2,b2),a2,d2,s2,x2,y2,z2,e2)) = lights - - # Great place for a print statement for debugging lights. Keep this. Mark 051204. [revised by bruce 051212] - #print "-------------------------------------------------------------" - #print "setup_standard_lights: lights[0]=", lights[0] - #print "setup_standard_lights: lights[1]=", lights[1] - #print "setup_standard_lights: lights[2]=", lights[2] - - glLightfv(GL_LIGHT0, GL_POSITION, (x0, y0, z0, 0)) - glLightfv(GL_LIGHT0, GL_AMBIENT, (r0*a0, g0*a0, b0*a0, 1.0)) - glLightfv(GL_LIGHT0, GL_DIFFUSE, (r0*d0, g0*d0, b0*d0, 1.0)) - if glprefs.override_light_specular is not None: - glLightfv(GL_LIGHT0, GL_SPECULAR, glprefs.override_light_specular) - else: - # grantham 20051121 - this should be a component on its own - # not replicating the diffuse color. - # Added specular (s0) as its own component. mark 051202. - glLightfv(GL_LIGHT0, GL_SPECULAR, (r0*s0, g0*s0, b0*s0, 1.0)) - glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0) - - glLightfv(GL_LIGHT1, GL_POSITION, (x1, y1, z1, 0)) - glLightfv(GL_LIGHT1, GL_AMBIENT, (r1*a1, g1*a1, b1*a1, 1.0)) - glLightfv(GL_LIGHT1, GL_DIFFUSE, (r1*d1, g1*d1, b1*d1, 1.0)) - if glprefs.override_light_specular is not None: - glLightfv(GL_LIGHT1, GL_SPECULAR, glprefs.override_light_specular) - else: - glLightfv(GL_LIGHT1, GL_SPECULAR, (r1*s1, g1*s1, b1*s1, 1.0)) - glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0) - - glLightfv(GL_LIGHT2, GL_POSITION, (x2, y2, z2, 0)) - glLightfv(GL_LIGHT2, GL_AMBIENT, (r2*a2, g2*a2, b2*a2, 1.0)) - glLightfv(GL_LIGHT2, GL_DIFFUSE, (r2*d2, g2*d2, b2*d2, 1.0)) - if glprefs.override_light_specular is not None: - glLightfv(GL_LIGHT2, GL_SPECULAR, glprefs.override_light_specular) - else: - glLightfv(GL_LIGHT2, GL_SPECULAR, (r2*s2, g2*s2, b2*s2, 1.0)) - glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 1.0) - - glEnable(GL_LIGHTING) - - if e0: - glEnable(GL_LIGHT0) - else: - glDisable(GL_LIGHT0) - - if e1: - glEnable(GL_LIGHT1) - else: - glDisable(GL_LIGHT1) - - if e2: - glEnable(GL_LIGHT2) - else: - glDisable(GL_LIGHT2) - except: - debug.print_compact_traceback("bug (worked around): setup_standard_lights reverting to old code, because: ") - # old code, used only to set up some sort of workable lighting in case of bugs - # (this is not necessarily using the same values as _default_lights; doesn't matter since never used unless there are bugs) - glLightfv(GL_LIGHT0, GL_POSITION, (-50, 70, 30, 0)) - glLightfv(GL_LIGHT0, GL_AMBIENT, (0.3, 0.3, 0.3, 1.0)) - glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.8, 0.8, 0.8, 1.0)) - glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0) - - glLightfv(GL_LIGHT1, GL_POSITION, (-20, 20, 20, 0)) - glLightfv(GL_LIGHT1, GL_AMBIENT, (0.4, 0.4, 0.4, 1.0)) - glLightfv(GL_LIGHT1, GL_DIFFUSE, (0.4, 0.4, 0.4, 1.0)) - glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0) - - glLightfv(GL_LIGHT2, GL_POSITION, (0, 0, 100, 0)) - glLightfv(GL_LIGHT2, GL_AMBIENT, (1.0, 1.0, 1.0, 1.0)) - glLightfv(GL_LIGHT2, GL_DIFFUSE, (1.0, 1.0, 1.0, 1.0)) - glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 1.0) - - glEnable(GL_LIGHTING) - - glEnable(GL_LIGHT0) - glEnable(GL_LIGHT1) - glDisable(GL_LIGHT2) - return # from setup_standard_lights - -# == - -def setup_fog(fog_start, fog_end, fog_color): - - glFog(GL_FOG_MODE, GL_LINEAR) - glFog(GL_FOG_START, fog_start) - glFog(GL_FOG_END, fog_end) - if len(fog_color) == 3: - fog_color = (fog_color[0], fog_color[1], fog_color[2], 1.0) - glFogv(GL_FOG_COLOR, fog_color) # piotr 080515 - -def enable_fog(): - glEnable(GL_FOG) - -def disable_fog(): - glDisable(GL_FOG) - -# == - -def apply_material(color): # grantham 20051121, renamed 20051201; revised by bruce 051126, 051203 (added specular_brightness), 051215 - """ - Set OpenGL material parameters based on the given color (length 3 or 4) and - the material-related prefs values in drawing_globals.glprefs. - """ - - #bruce 051215: make sure color is a tuple, and has length exactly 4, for all uses inside this function, - # assuming callers pass sequences of length 3 or 4. Needed because glMaterial requires four-component - # vector and PyOpenGL doesn't check. [If this is useful elsewhere, we can split it into a separate function.] - color = tuple(color) - if len(color) == 3: - color = color + (1.0,) # usual case - elif len(color) != 4: - # should never happen; if it does, this assert will always fail - assert len(color) in [3,4], "color tuples must have length 3 or 4, unlike %r" % (color,) - - glColor4fv(color) # For drawing lines with lighting disabled. - - if not drawing_globals.glprefs.enable_specular_highlights: - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color) - # glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (0,0,0,1)) - return - - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color) - - whiteness = drawing_globals.glprefs.specular_whiteness - brightness = drawing_globals.glprefs.specular_brightness - if whiteness == 1.0: - specular = (1.0, 1.0, 1.0, 1.0) # optimization - else: - if whiteness == 0.0: - specular = color # optimization - else: - # assume color[3] (alpha) is not passed or is always 1.0 - c1 = 1.0 - whiteness - specular = ( c1 * color[0] + whiteness, c1 * color[1] + whiteness, c1 * color[2] + whiteness, 1.0 ) - if brightness != 1.0: - specular = ( specular[0] * brightness, specular[1] * brightness, specular[2] * brightness, 1.0 ) - #e could optimize by merging this with above 3 cases (or, of course, by doing it in C, which we'll do eventually) - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular) - - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, - drawing_globals.glprefs.specular_shininess) - return - -# == - -#russ 080515: We should find a better place for this! -def get_gl_info_string(glpane): # grantham 20051129 - """Return a string containing some useful information about the OpenGL implementation. - Use the GL context from the given QGLWidget glpane (by calling glpane.makeCurrent()). - """ - - glpane.makeCurrent() #bruce 070308 added glpane arg and makeCurrent call - - gl_info_string = '' - - gl_info_string += 'GL_VENDOR : "%s"\n' % glGetString(GL_VENDOR) - gl_info_string += 'GL_VERSION : "%s"\n' % glGetString(GL_VERSION) - gl_info_string += 'GL_RENDERER : "%s"\n' % glGetString(GL_RENDERER) - gl_info_string += 'GL_EXTENSIONS : "%s"\n' % glGetString(GL_EXTENSIONS) - - from utilities.debug_prefs import debug_pref, Choice_boolean_False - if debug_pref("get_gl_info_string call glAreTexturesResident?", Choice_boolean_False): - # Give a practical indication of how much video memory is available. - # Should also do this with VBOs. - - # I'm pretty sure this code is right, but PyOpenGL seg faults in - # glAreTexturesResident, so it's disabled until I can figure that - # out. [grantham] [bruce 070308 added the debug_pref] - - all_tex_in = True - tex_bytes = '\0' * (512 * 512 * 4) - tex_names = [] - tex_count = 0 - tex_names = glGenTextures(1024) - glEnable(GL_TEXTURE_2D) - while all_tex_in: - glBindTexture(GL_TEXTURE_2D, tex_names[tex_count]) - gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 512, 512, GL_RGBA, - GL_UNSIGNED_BYTE, tex_bytes) - tex_count += 1 - - glTexCoord2f(0.0, 0.0) - glBegin(GL_QUADS) - glVertex2f(0.0, 0.0) - glVertex2f(1.0, 0.0) - glVertex2f(1.0, 1.0) - glVertex2f(0.0, 1.0) - glEnd() - glFinish() - - residences = glAreTexturesResident(tex_names[:tex_count]) - all_tex_in = reduce(lambda a,b: a and b, residences) - # bruce 070308 sees this exception from this line: - # TypeError: reduce() arg 2 must support iteration - - glDisable(GL_TEXTURE_2D) - glDeleteTextures(tex_names) - - gl_info_string += "Could create %d 512x512 RGBA resident textures\n", tex_count - return gl_info_string - -#================================================================ gl_buffers.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -gl_buffers.py - OpenGL data buffer objects. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -# Vertex Buffer Object (VBO) and Index Buffer Object (IBO) support. -# For docs see http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml . - -# Notice that the ARB-suffixed versions of the OpenGL calls are used here. -# They're the ones with PyConvert ctypes wrappers, see: (the incomprehensible) -# http://pyopengl.sourceforge.net/ctypes/pydoc/OpenGL.GL.ARB.vertex_buffer_object.html -# The sources will do you more good. Also see "Array Handling Routines" here: -# http://pyopengl.sourceforge.net/documentation/opengl_diffs.html -# -from OpenGL.GL.ARB.vertex_buffer_object import glGenBuffersARB -from OpenGL.GL.ARB.vertex_buffer_object import glDeleteBuffersARB -# Patched versions. -from graphics.drawing.vbo_patch import glBufferDataARB, glBufferSubDataARB - -from OpenGL.raw.GL.ARB.vertex_buffer_object import glBindBufferARB # Unwrappered. - -class GLBufferObject(object): - """ - Buffer data in the graphics card's RAM space. - - Useful man pages for glBind, glBufferData, etc. for OpenGL 2.1 are at: - http://www.opengl.org/sdk/docs/man - PyOpenGL versions are at: - http://pyopengl.sourceforge.net/ctypes/pydoc/OpenGL.html - - 'target' is GL_ARRAY_BUFFER_ARB for vertex/normal buffers (VBO's), and - GL_ELEMENT_ARRAY_BUFFER_ARB for index buffers (IBO's.) - - 'data' is a numpy.array, with dtype=numpy.<datatype> . - - 'usage' is one of the hint constants, like GL_STATIC_DRAW. - """ - - def __init__(self, target, data, usage): - self.buffer = glGenBuffersARB(1) # Returns a numpy.ndarray for > 1. - self.target = target - - self.bind() - self.size = len(data) - - # Push the data over to Graphics card RAM. - glBufferDataARB(target, data, usage) - - self.unbind() - return - - def __del__(self): - """ - Delete a GLBufferObject. We don't expect that there will be a lot of - deleting of GLBufferObjects, but don't want them to sit on a lot of graphics - card RAM if we did. - """ - - # Since may be too late to clean up buffer objects through the Graphics - # Context while exiting, we trust that OpenGL or the device driver will - # deallocate the graphics card RAM when the Python process exits. - try: - glDeleteBuffersARB(1, [self.buffer]) - except: - ##print "Exception in glDeleteBuffersARB." - pass - return - - def bind(self): - """ - Have to bind a particular buffer to its target to fill or draw from it. - Don't forget to unbind() it! - """ - glBindBufferARB(self.target, self.buffer) - return - - def unbind(self): - """ - Unbind a buffer object from its target after use. - Failure to do this can kill Python on some graphics platforms! - """ - glBindBufferARB(self.target, 0) - return - - pass # End of class GLBufferObject. - -#================================================================ CS_workers.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -CS_workers.py - Drawing functions for primitives drawn by the ColorSorter. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals - -try: - from OpenGL.GLE import glePolyCone -except: - print "GLE module can't be imported. Now trying _GLE" - from OpenGL._GLE import glePolyCone - -### Substitute this for drawsphere_worker to test drawing a lot of spheres. -def drawsphere_worker_loop(params): - (pos, radius, detailLevel) = params - for x in range(100): ## 500 - for y in range(100): - newpos = pos + (x+x/10+x/100) * V(1, 0, 0) + (y+y/10+y/100) * V(0, 1, 0) - drawsphere_worker((newpos, radius, detailLevel)) - continue - continue - return - -def drawsphere_worker(params): - """Draw a sphere. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below)""" - - (pos, radius, detailLevel) = params - - vboLevel = drawing_globals.use_drawing_variant - - glPushMatrix() - glTranslatef(pos[0], pos[1], pos[2]) - glScale(radius,radius,radius) - - if vboLevel is 0: - glCallList(drawing_globals.sphereList[detailLevel]) - else: # Array variants. - glEnableClientState(GL_VERTEX_ARRAY) - glEnableClientState(GL_NORMAL_ARRAY) - - size = len(drawing_globals.sphereArrays[detailLevel]) - GLIndexType = drawing_globals.sphereGLIndexTypes[detailLevel] - - if vboLevel is 1: # DrawArrays from CPU RAM. - verts = drawing_globals.sphereCArrays[detailLevel] - glVertexPointer(3, GL_FLOAT, 0, verts) - glNormalPointer(GL_FLOAT, 0, verts) - glDrawArrays(GL_TRIANGLE_STRIP, 0, size) - - elif vboLevel is 2: # DrawElements from CPU RAM. - verts = drawing_globals.sphereCElements[detailLevel][1] - glVertexPointer(3, GL_FLOAT, 0, verts) - glNormalPointer(GL_FLOAT, 0, verts) - # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. - index = drawing_globals.sphereElements[detailLevel][0] - glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) - - elif vboLevel is 3: # DrawArrays from graphics RAM VBO. - vbo = drawing_globals.sphereArrayVBOs[detailLevel] - vbo.bind() - glVertexPointer(3, GL_FLOAT, 0, None) - glNormalPointer(GL_FLOAT, 0, None) - glDrawArrays(GL_TRIANGLE_STRIP, 0, vbo.size) - vbo.unbind() - - elif vboLevel is 4: # DrawElements from index in CPU RAM, verts in VBO. - vbo = drawing_globals.sphereElementVBOs[detailLevel][1] - vbo.bind() # Vertex and normal data comes from the vbo. - glVertexPointer(3, GL_FLOAT, 0, None) - glNormalPointer(GL_FLOAT, 0, None) - # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. - index = drawing_globals.sphereElements[detailLevel][0] - glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) - vbo.unbind() - - elif vboLevel is 5: # VBO/IBO buffered DrawElements from graphics RAM. - (ibo, vbo) = drawing_globals.sphereElementVBOs[detailLevel] - vbo.bind() # Vertex and normal data comes from the vbo. - glVertexPointer(3, GL_FLOAT, 0, None) - glNormalPointer(GL_FLOAT, 0, None) - ibo.bind() # Index data comes from the ibo. - glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, None) - vbo.unbind() - ibo.unbind() - pass - - glDisableClientState(GL_VERTEX_ARRAY) - glDisableClientState(GL_NORMAL_ARRAY) - pass - - glPopMatrix() - return - -def drawwiresphere_worker(params): - """ - Draw a wireframe sphere. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below) - """ - - (color, pos, radius, detailLevel) = params - ## assert detailLevel == 1 # true, but leave out for speed - from utilities.debug_prefs import debug_pref, Choice_boolean_True - newway = debug_pref("new wirespheres?", Choice_boolean_True) #bruce 060415 experiment, re iMac G4 wiresphere bug; fixes it! - oldway = not newway - # These objects want a constant line color even if they are selected or highlighted. - glColor3fv(color) - glDisable(GL_LIGHTING) - if oldway: - glPolygonMode(GL_FRONT, GL_LINE) - glPushMatrix() - glTranslatef(pos[0], pos[1], pos[2]) - glScale(radius,radius,radius) - if oldway: - glCallList(drawing_globals.sphereList[detailLevel]) - else: - glCallList(drawing_globals.wiresphere1list) - glEnable(GL_LIGHTING) - glPopMatrix() - if oldway: - glPolygonMode(GL_FRONT, GL_FILL) - return - -def drawcylinder_worker(params): - """ - Draw a cylinder. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below) - - WARNING: our circular cross-section is approximated by a 13-gon - whose alignment around the axis is chosen arbitrary, in a way - which depends on the direction of the axis; negating the axis usually - causes a different alignment of that 13-gon. This effect can cause - visual bugs when drawing one cylinder over an identical or slightly - smaller one (e.g. when highlighting a bond), unless the axes are kept - parallel as opposed to antiparallel. - """ - - (pos1, pos2, radius, capped) = params - - glPushMatrix() - vec = pos2-pos1 - axis = norm(vec) - glTranslatef(pos1[0], pos1[1], pos1[2]) - - ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes - ## display problem on some platforms - angle = -acos(axis[2])*180.0/pi - if (axis[2]*axis[2] >= 1.0): - glRotate(angle, 0.0, 1.0, 0.0) - else: - glRotate(angle, axis[1], -axis[0], 0.0) - - glScale(radius,radius,Numeric.dot(vec,vec)**.5) - glCallList(drawing_globals.CylList) - if capped: glCallList(drawing_globals.CapList) - - glPopMatrix() - - return - -def drawpolycone_worker(params): - """ - Draw a polycone. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below) - """ - (pos_array, rad_array) = params - glePolyCone(pos_array, None, rad_array) - return - -def drawpolycone_multicolor_worker(params): - """ - Draw a polycone. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below) - piotr 080311: this variant accepts a color array as an additional parameter - """ - (pos_array, color_array, rad_array) = params - glEnable(GL_COLOR_MATERIAL) # have to enable GL_COLOR_MATERIAL for - # the GLE function - glPushAttrib(GL_CURRENT_BIT) # store current attributes in case glePolyCone - # modifies the (e.g. current color) - # piotr 080411 - glePolyCone(pos_array, color_array, rad_array) - glPopAttrib() # This fixes the 'disappearing cylinder' bug - # glPopAttrib doesn't take any arguments - # piotr 080415 - glDisable(GL_COLOR_MATERIAL) - return - -def drawsurface_worker(params): - """Draw a surface. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below)""" - - (pos, radius, tm, nm) = params - glPushMatrix() - glTranslatef(pos[0], pos[1], pos[2]) - glScale(radius,radius,radius) - renderSurface(tm, nm) - glPopMatrix() - return - -def drawline_worker(params): - """ - Draw a line. Receive parameters through a sequence so that this - function and its parameters can be passed to another function for - deferment. Right now this is only ColorSorter.schedule (see below) - """ - (endpt1, endpt2, dashEnabled, stipleFactor, width, isSmooth) = params - - ###glDisable(GL_LIGHTING) - ###glColor3fv(color) - if dashEnabled: - glLineStipple(stipleFactor, 0xAAAA) - glEnable(GL_LINE_STIPPLE) - if width != 1: - glLineWidth(width) - if isSmooth: - glEnable(GL_LINE_SMOOTH) - glBegin(GL_LINES) - glVertex(endpt1[0], endpt1[1], endpt1[2]) - glVertex(endpt2[0], endpt2[1], endpt2[2]) - glEnd() - if isSmooth: - glDisable(GL_LINE_SMOOTH) - if width != 1: - glLineWidth(1.0) # restore default state - if dashEnabled: - glDisable(GL_LINE_STIPPLE) - ###glEnable(GL_LIGHTING) - return - -#================================================================ CS_ShapeList.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -CS_ShapeList.py - The C++ ColorSorter's arrays of primitives to draw. - -Does some memoization as a speedup. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - - -class ShapeList_inplace: - - """ - Records sphere and cylinder data and invokes it through the native C++ - rendering system. - - This has the benefit over ShapeList that shapes aren't first stored in - lots of Python lists, and then turned into lots of Numeric arrays. - Instead, it stores directly in a list of fixed-size Numeric arrays. - It shows some speedup, but not a lot. And tons of memory is being - used. I'm not sure where. -grantham - - """ - - __author__ = "grantham@plunk.org" - - _blocking = 512 # balance between memory zeroing and drawing efficiency - - def __init__(self): - - # - # Lists of lists, each list containing a Numeric array and the - # number of objects in that array. E.g. Each element in - # sphere is [l, n], where l is array((m, 9), 'f'), n is the - # number of valid 9 element slices in l that represent - # spheres, and m is equal to or more than n+1. - # - self.spheres = [] - self.cylinders = [] - - # If this is true, disallow future adds. - self.petrified = False - - - def draw(self): - - """ - Draw all the objects represented in this shape list. - """ - - for (spheres, count) in self.spheres: - quux.shapeRendererDrawSpheresIlvd(count, spheres) - for (cylinders, count) in self.cylinders: - quux.shapeRendererDrawCylindersIlvd(count, cylinders) - - - def add_sphere(self, color4, pos, radius, name = 0): - """ - Add a sphere to this shape list. - - "color4" must have 4 elements. "name" is the GL selection name. - """ - - if self.petrified: - raise ValueError, "Tried to add a sphere to a petrified ShapeList_inplace" - - # struct Sphere { - # float m_color[4]; - # float m_nameUInt; - # float m_center[3]; - # float m_radius; - # }; - - if len(self.spheres) == 0 or self.spheres[-1][1] == ShapeList_inplace._blocking: - # size of struct Sphere in floats is 9 - block = Numeric.zeros((ShapeList_inplace._blocking, 9), 'f') - self.spheres.append([block, 0]) - - (block, count) = self.spheres[-1] - - block[count] = (\ - color4[0], color4[1], color4[2], color4[3], - float(name), - pos[0], pos[1], pos[2], - radius) - - self.spheres[-1][1] += 1 - - - def add_cylinder(self, color4, pos1, pos2, radius, name = 0, capped=0): - """ - Add a cylinder to this shape list. - - "color4" must have 4 elements. "name" is the GL selection name. - """ - - if self.petrified: - raise ValueError, "Tried to add a cylinder to a petrified ShapeList_inplace" - - # struct Cylinder { - # float m_color[4]; - # float m_nameUInt; - # float m_cappedBool; - # float m_pos1[3]; - # float m_pos2[3]; - # float m_radius; - # }; - - if len(self.cylinders) == 0 or self.cylinders[-1][1] == ShapeList_inplace._blocking: - # size of struct Cylinder in floats is 13 - block = Numeric.zeros((ShapeList_inplace._blocking, 13), 'f') - self.cylinders.append([block, 0]) - - (block, count) = self.cylinders[-1] - - block[count] = (\ - color4[0], color4[1], color4[2], color4[3], - float(name), - float(capped), - pos1[0], pos1[1], pos1[2], - pos2[0], pos2[1], pos2[2], - radius) - - self.cylinders[-1][1] += 1 - - - def petrify(self): - """ - Make this object - - Since the last block of shapes might not be full, this - function copies them to a new block exactly big enough to hold - the shapes in that block. The gc has a chance to release the - old block and reduce memory use. After this point, shapes - must not be added to this ShapeList. - """ - - self.petrified = True - - if len(self.spheres) > 0: - count = self.spheres[-1][1] - if count < ShapeList_inplace._blocking: - block = self.spheres[-1][0] - newblock = Numeric.array(block[0:count], 'f') - self.spheres[-1][0] = newblock - - if len(self.cylinders) > 0: - count = self.cylinders[-1][1] - if count < ShapeList_inplace._blocking: - block = self.cylinders[-1][0] - newblock = Numeric.array(block[0:count], 'f') - self.cylinders[-1][0] = newblock - - -class ShapeList: - - """ - Records sphere and cylinder data and invokes it through the native C++ - rendering system. - - Probably better to use "ShapeList_inplace". - """ - - __author__ = "grantham@plunk.org" - - def __init__(self): - - self.memoized = False - - self.sphere_colors = [] - self.sphere_radii = [] - self.sphere_centers = [] - self.sphere_names = [] - - self.cylinder_colors = [] - self.cylinder_radii = [] - self.cylinder_pos1 = [] - self.cylinder_pos2 = [] - self.cylinder_cappings = [] - self.cylinder_names = [] - - - def _memoize(self): - - """ - Internal function that creates Numeric arrays from the data stored - in add_sphere and add-cylinder. - """ - - self.memoized = True - - # GL Names are uint32. Numeric.array appears to have only - # int32. Winging it... - - self.sphere_colors_array = Numeric.array(self.sphere_colors, 'f') - self.sphere_radii_array = Numeric.array(self.sphere_radii, 'f') - self.sphere_centers_array = Numeric.array(self.sphere_centers, 'f') - self.sphere_names_array = Numeric.array(self.sphere_names, 'i') - - self.cylinder_colors_array = Numeric.array(self.cylinder_colors, 'f') - self.cylinder_radii_array = Numeric.array(self.cylinder_radii, 'f') - self.cylinder_pos1_array = Numeric.array(self.cylinder_pos1, 'f') - self.cylinder_pos2_array = Numeric.array(self.cylinder_pos2, 'f') - self.cylinder_cappings_array = Numeric.array(self.cylinder_cappings, 'f') - self.cylinder_names_array = Numeric.array(self.cylinder_names, 'i') - - - def draw(self): - - """ - Draw all the objects represented in this shape list. - """ - - # ICK - SLOW - Probably no big deal in a display list. - - if len(self.sphere_radii) > 0: - if not self.memoized: - self._memoize() - quux.shapeRendererDrawSpheres(len(self.sphere_radii), - self.sphere_centers_array, - self.sphere_radii_array, - self.sphere_colors_array, - self.sphere_names_array) - - if len(self.cylinder_radii) > 0: - if not self.memoized: - self._memoize() - quux.shapeRendererDrawCylinders(len(self.cylinder_radii), - self.cylinder_pos1_array, - self.cylinder_pos2_array, - self.cylinder_radii_array, - self.cylinder_cappings_array, - self.cylinder_colors_array, - self.cylinder_names_array) - - - def add_sphere(self, color4, pos, radius, name = 0): - """ - Add a sphere to this shape list. - - "color4" must have 4 elements. "name" is the GL selection name. - """ - - self.sphere_colors.append(color4) - self.sphere_centers.append(list(pos)) - self.sphere_radii.append(radius) - self.sphere_names.append(name) - self.memoized = False - - - def add_cylinder(self, color4, pos1, pos2, radius, name = 0, capped=0): - """ - Add a cylinder to this shape list. - - "color4" must have 4 elements. "name" is the GL selection name. - """ - - self.cylinder_colors.append(color4) - self.cylinder_radii.append(radius) - self.cylinder_pos1.append(list(pos1)) - self.cylinder_pos2.append(list(pos2)) - self.cylinder_cappings.append(capped) - self.cylinder_names.append(name) - self.memoized = False - - - def petrify(self): - """ - Delete all but the cached Numeric arrays. - - Call this when you're sure you don't have any more shapes to store - in the shape list and you want to release the python lists of data - back to the heap. Additional shapes must not be added to this shape - list. - """ - if not self.memoized: - self._memoize() - - del self.sphere_colors - del self.sphere_radii - del self.sphere_centers - del self.sphere_names - - del self.cylinder_colors - del self.cylinder_radii - del self.cylinder_pos1 - del self.cylinder_pos2 - del self.cylinder_cappings - del self.cylinder_names - -#================================================================ ColorSortedDisplayList.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -ColorSortedDisplayList.py - A class to remember display list id's for -objects that draw their instances through the ColorSorter. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals - -class ColorSortedDisplayList: #Russ 080225: Added. - """ - The ColorSorter's parent uses one of these to store color-sorted display list - state. It's passed in to ColorSorter.start() . - """ - def __init__(self): - self.clear() - self.selected = False # Whether to draw in the selection over-ride color. - return - - #russ 080320 Experiment with VBO drawing from cached ColorSorter lists. - cache_ColorSorter = False ## True - - def clear(self): - """ - Empty state. - """ - self.dl = 0 # Current display list (color or selected.) - self.color_dl = 0 # DL to set colors, call each lower level list. - self.selected_dl = 0 # DL with a single (selected) over-ride color. - self.nocolor_dl = 0 # DL of lower-level calls for color over-rides. - self.per_color_dls = [] # Lower level, per-color primitive sublists. - return - - def not_clear(self): - """ - Check for empty state. - """ - return self.dl or self.color_dl or self.nocolor_dl or self.selected_dl or \ - self.per_color_dls and len(self.per_color_dls) - - def activate(self): - """ - Make a top-level display list id ready, but don't fill it in. - """ - # Display list id for the current appearance. - if not self.selected: - self.color_dl = glGenLists(1) - else: - self.selected_dl = glGenLists(1) - pass - self.selectDl() - assert type(self.dl) in (type(1), type(1L)) #bruce 070521 added these two asserts - assert self.dl != 0 # This failed on Linux, keep checking. (bug 2042) - return - - def draw_dl(self): #russ 080320 Added. - """ - Draw the displist (cached display procedure.) - """ - #russ 080320: Experiment with VBO drawing from cached ColorSorter lists. - if (ColorSortedDisplayList.cache_ColorSorter and - drawing_globals.allow_color_sorting and - drawing_globals.use_color_sorted_vbos): - ColorSorter.draw_sorted(self.sorted_by_color) - else: - # Call a normal OpenGL display list. - glCallList(self.dl) - return - - def selectPick(self, boolVal): - """ - Remember whether we're selected or not. - """ - self.selected = boolVal - self.selectDl() - return - - def selectDl(self): - """ - Change to either the normal-color display list or the selected one. - """ - self.dl = self.selected and self.selected_dl or self.color_dl - return - - def reset(self): - """ - Return to initialized state. - """ - if self.not_clear(): - # deallocate leaves it clear. - self.deallocate_displists() - pass - return - - def deallocate_displists(self): - """ - Free any allocated display lists. - """ - # With CSDL active, self.dl duplicates either selected_dl or color_dl. - if (self.dl is not self.color_dl and - self.dl is not self.selected_dl): - glDeleteLists(self.dl, 1) - for dl in [self.color_dl, self.nocolor_dl, self.selected_dl]: - if dl != 0: - glDeleteLists(dl, 1) - pass - continue - # piotr 080420: The second level dl's are 2-element lists of DL ids - # rather than just a list of ids. The secod DL is used in case - # of multi-color objects and is required for highlighting - # and selection (not in rc1) - for clr, dls in self.per_color_dls: # Second-level dl's. - for dl in dls: # iterate over DL pairs. - if dl != 0: - glDeleteLists(dl, 1) - pass - continue - self.clear() - return - - pass # End of ColorSortedDisplayList. - -#================================================================ ColorSorter.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -ColorSorter.py - A class to group primitive drawing by colors. - -This was originally done as a GL optimization to minimize calls on -apply_material. - -Later, it was extended to handle multiple display lists per Chunk object as an -optimization to avoid rebuilding a single display list when the appearance of -the object changes for hover-highlighting and selection. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals - -class ColorSorter: - - """ - State Sorter specializing in color (Really any object that can be - passed to apply_material, which on 20051204 is only color 4-tuples) - - Invoke start() to begin sorting. - Call finish() to complete sorting and draw all sorted objects. - - Call schedule() with any function and parameters to be sorted by color. - If not sorting, schedule() will invoke the function immediately. If - sorting, then the function will not be called until "finish()". - - In any function which will take part in sorting which previously did - not, create a worker function from the old function except the call to - apply_material. Then create a wrapper which calls - ColorSorter.schedule with the worker function and its params. - - Also an app can call schedule_sphere and schedule_cylinder to - schedule a sphere or a cylinder. Right now this is the only way - to directly access the native C++ rendering engine. - """ - __author__ = "grantham@plunk.org" - - # For now, these are class globals. As long as OpenGL drawing is - # serialized and Sorting isn't nested, this is okay. When/if - # OpenGL drawing becomes multi-threaded, sorters will have to - # become instances. This is probably okay because objects and - # materials will probably become objects of their own about that - # time so the whole system will get a redesign and - # reimplementation. - - sorting = False # Guard against nested sorting - _sorted = 0 # Number of calls to _add_to_sorter since last - # _printstats - _immediate = 0 # Number of calls to _invoke_immediately since last - # _printstats - _gl_name_stack = [0] # internal record of GL name stack; 0 is a sentinel - - def pushName(glname): - """ - Record the current pushed GL name, which must not be 0. - """ - assert glname, "glname of 0 is illegal (used as sentinel)" #bruce 060217 added this assert - ColorSorter._gl_name_stack.append(glname) - - pushName = staticmethod(pushName) - - - def popName(): - """ - Record a pop of the GL name. - """ - del ColorSorter._gl_name_stack[-1] - - popName = staticmethod(popName) - - - def _printstats(): - """ - Internal function for developers to call to print stats on number of - sorted and immediately-called objects. - """ - print "Since previous 'stats', %d sorted, %d immediate: " % (ColorSorter._sorted, ColorSorter._immediate) - ColorSorter._sorted = 0 - ColorSorter._immediate = 0 - - _printstats = staticmethod(_printstats) - - - def _add_to_sorter(color, func, params): - """ - Internal function that stores 'scheduled' operations for a later - sort, between a start/finish - """ - ColorSorter._sorted += 1 - color = tuple(color) - if not ColorSorter.sorted_by_color.has_key(color): - ColorSorter.sorted_by_color[color] = [] - ColorSorter.sorted_by_color[color].append((func, params, - ColorSorter._gl_name_stack[-1])) - - _add_to_sorter = staticmethod(_add_to_sorter) - - - def schedule(color, func, params): - if ColorSorter.sorting and drawing_globals.allow_color_sorting: - - ColorSorter._add_to_sorter(color, func, params) - - else: - - ColorSorter._immediate += 1 # for benchmark/debug stats, mostly - - # 20060216 We know we can do this here because the stack is - # only ever one element deep - name = ColorSorter._gl_name_stack[-1] - if name: - glPushName(name) - - #Apply appropriate opacity for the object if it is specified - #in the 'color' param. (Also do necessary things such as - #call glBlendFunc it. -- Ninad 20071009 - - if len(color) == 4: - opacity = color[3] - else: - opacity = 1.0 - - if opacity >= 0.0 and opacity != 1.0: - glDepthMask(GL_FALSE) - glEnable(GL_BLEND) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - elif opacity == -1: - # piotr 080429: I replaced the " < 0" condition with " == -1" - # The opacity flag is now used to signal either "unshaded colors" - # (opacity == -1) or "multicolor object" (opacity == -2) - glDisable(GL_LIGHTING) # Don't forget to re-enable it! - glColor3fv(color[:3]) - pass - - apply_material(color) - func(params) - - if opacity > 0.0 and opacity != 1.0: - glDisable(GL_BLEND) - glDepthMask(GL_TRUE) - elif opacity == -1: - # piotr 080429: See my comment above. - glEnable(GL_LIGHTING) - - if name: - glPopName() - return - - schedule = staticmethod(schedule) - - def schedule_sphere(color, pos, radius, detailLevel, opacity = 1.0): - """ - Schedule a sphere for rendering whenever ColorSorter thinks is - appropriate. - """ - if drawing_globals.use_c_renderer and ColorSorter.sorting: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], opacity) - else: - lcolor = color - ColorSorter._cur_shapelist.add_sphere(lcolor, pos, radius, - ColorSorter._gl_name_stack[-1]) - # 20060208 grantham - I happen to know that one detailLevel - # is chosen for all spheres, I just record it over and - # over here, and use the last one for the render - if ColorSorter.sphereLevel > -1 and ColorSorter.sphereLevel != detailLevel: - raise ValueError, "unexpected different sphere LOD levels within same frame" - ColorSorter.sphereLevel = detailLevel - else: # Older sorted material rendering - if len(color) == 3: - lcolor = (color[0], color[1], color[2], opacity) - else: - lcolor = color - ColorSorter.schedule(lcolor, drawsphere_worker, ### drawsphere_worker_loop ### Testing. - (pos, radius, detailLevel)) - - schedule_sphere = staticmethod(schedule_sphere) - - - def schedule_wiresphere(color, pos, radius, detailLevel = 1): - """ - Schedule a wiresphere for rendering whenever ColorSorter thinks is - appropriate. - """ - if drawing_globals.use_c_renderer and ColorSorter.sorting: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], 1.0) - else: - lcolor = color - assert 0, "Need to implement a C add_wiresphere function." - ColorSorter._cur_shapelist.add_wiresphere(lcolor, pos, radius, - ColorSorter._gl_name_stack[-1]) - else: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], 1.0) - else: - lcolor = color - - ColorSorter.schedule(lcolor, drawwiresphere_worker, - # Use constant-color line drawing. - (color, pos, radius, detailLevel)) - - schedule_wiresphere = staticmethod(schedule_wiresphere) - - def schedule_cylinder(color, pos1, pos2, radius, capped = 0, opacity = 1.0 ): - """ - Schedule a cylinder for rendering whenever ColorSorter thinks is - appropriate. - """ - if drawing_globals.use_c_renderer and ColorSorter.sorting: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], 1.0) - else: - lcolor = color - ColorSorter._cur_shapelist.add_cylinder(lcolor, pos1, pos2, radius, - ColorSorter._gl_name_stack[-1], capped) - else: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], opacity) - else: - lcolor = color - - ColorSorter.schedule(lcolor, drawcylinder_worker, (pos1, pos2, radius, capped)) - - schedule_cylinder = staticmethod(schedule_cylinder) - - def schedule_polycone(color, pos_array, rad_array, capped = 0, opacity = 1.0): - """ - Schedule a polycone for rendering whenever ColorSorter thinks is - appropriate. - """ - if drawing_globals.use_c_renderer and ColorSorter.sorting: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], 1.0) - else: - lcolor = color - assert 0, "Need to implement a C add_polycone_multicolor function." - ColorSorter._cur_shapelist.add_polycone(lcolor, pos_array, rad_array, - ColorSorter._gl_name_stack[-1], capped) - else: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], opacity) - else: - lcolor = color - - ColorSorter.schedule(lcolor, drawpolycone_worker, (pos_array, rad_array)) - - schedule_polycone = staticmethod(schedule_polycone) - - def schedule_polycone_multicolor(color, pos_array, color_array, rad_array, capped = 0, opacity = 1.0): - """ - Schedule a polycone for rendering whenever ColorSorter thinks is - appropriate. - piotr 080311: this variant accepts a color array as an additional parameter - """ - if drawing_globals.use_c_renderer and ColorSorter.sorting: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], 1.0) - else: - lcolor = color - assert 0, "Need to implement a C add_polycone function." - ColorSorter._cur_shapelist.add_polycone_multicolor(lcolor, pos_array, color_array, rad_array, - ColorSorter._gl_name_stack[-1], capped) - else: - if len(color) == 3: - lcolor = (color[0], color[1], color[2], opacity) - else: - lcolor = color - - ColorSorter.schedule(lcolor, drawpolycone_multicolor_worker, (pos_array, color_array, rad_array)) - - schedule_polycone_multicolor = staticmethod(schedule_polycone_multicolor) - - def schedule_surface(color, pos, radius, tm, nm): - """ - Schedule a surface for rendering whenever ColorSorter thinks is - appropriate. - """ - ColorSorter.schedule(color, drawsurface_worker, (pos, radius, tm, nm)) - - schedule_surface = staticmethod(schedule_surface) - - def schedule_line(color, endpt1, endpt2, dashEnabled, - stipleFactor, width, isSmooth): - """ - Schedule a line for rendering whenever ColorSorter thinks is - appropriate. - """ - #russ 080306: Signal "unshaded colors" for lines by a negative alpha. (Hack!) - color = tuple(color) + (-1,) - ColorSorter.schedule(color, drawline_worker, - (endpt1, endpt2, dashEnabled, - stipleFactor, width, isSmooth)) - - schedule_line = staticmethod(schedule_line) - - def start(csdl, pickstate=None): - """ - Start sorting - objects provided to "schedule", "schedule_sphere", and - "schedule_cylinder" will be stored for a sort at the time "finish" is called. - csdl is a ColorSortedDisplayList or None, in which case immediate drawing is done. - pickstate (optional) indicates whether the parent is currently selected. - """ - - #russ 080225: Moved glNewList here for displist re-org. - ColorSorter.parent_csdl = csdl # Remember, used by finish(). - if pickstate is not None: - csdl.selectPick(pickstate) - pass - - if csdl != None: - if not (drawing_globals.allow_color_sorting and - (drawing_globals.use_color_sorted_dls - or drawing_globals.use_color_sorted_vbos)): #russ 080320 - # This is the beginning of the single display list created when color - # sorting is turned off. It is ended in ColorSorter.finish . In - # between, the calls to draw{sphere,cylinder,polycone} methods pass - # through ColorSorter.schedule_* but are immediately sent to *_worker - # where they do OpenGL drawing that is captured into the display list. - try: - if csdl.dl is 0: - csdl.activate() # Allocate a display list for our use. - pass - glNewList(csdl.dl, GL_COMPILE_AND_EXECUTE) # Start a single-level list. - except: - print "data related to following exception: csdl.dl = %r" % (csdl.dl,) #bruce 070521 - raise - - assert not ColorSorter.sorting, "Called ColorSorter.start but already sorting?!" - ColorSorter.sorting = True - if drawing_globals.use_c_renderer and ColorSorter.sorting: - ColorSorter._cur_shapelist = ShapeList_inplace() - ColorSorter.sphereLevel = -1 - else: - ColorSorter.sorted_by_color = {} - - start = staticmethod(start) - - def finish(): - """ - Finish sorting - objects recorded since "start" will - be sorted and invoked now. - """ - from utilities.debug_prefs import debug_pref, Choice_boolean_False - debug_which_renderer = debug_pref("debug print which renderer", Choice_boolean_False) #bruce 060314, imperfect but tolerable - - parent_csdl = ColorSorter.parent_csdl - if drawing_globals.use_c_renderer: - quux.shapeRendererInit() - if debug_which_renderer: - #bruce 060314 uncommented/revised the next line; it might have to come after shapeRendererInit (not sure); - # it definitely has to come after a graphics context is created and initialized. - # 20060314 grantham - yes, has to come after quux.shapeRendererInit - print "using C renderer: VBO %s enabled" % (('is NOT', 'is')[quux.shapeRendererGetInteger(quux.IS_VBO_ENABLED)]) - quux.shapeRendererSetUseDynamicLOD(0) - if ColorSorter.sphereLevel != -1: - quux.shapeRendererSetStaticLODLevels(ColorSorter.sphereLevel, 1) - quux.shapeRendererStartDrawing() - ColorSorter._cur_shapelist.draw() - quux.shapeRendererFinishDrawing() - ColorSorter.sorting = False - - # So chunks can actually record their shapelist - # at some point if they want to - # ColorSorter._cur_shapelist.petrify() - # return ColorSorter._cur_shapelist - - else: - if debug_which_renderer: - print "using Python renderer: use_color_sorted_dls %s enabled" \ - % (drawing_globals.use_color_sorted_dls and 'IS' - or 'is NOT') - print "using Python renderer: use_color_sorted_vbos %s enabled" \ - % (drawing_globals.use_color_sorted_vbos and 'IS' - or 'is NOT') - color_groups = len(ColorSorter.sorted_by_color) - objects_drawn = 0 - - if (not (drawing_globals.allow_color_sorting and - drawing_globals.use_color_sorted_dls) - or (ColorSortedDisplayList.cache_ColorSorter and - drawing_globals.allow_color_sorting and - drawing_globals.use_color_sorted_vbos) - or parent_csdl is None): #russ 080225 Added, 080320 VBO experiment. - - # Either all in one display list, or immediate-mode drawing. - objects_drawn += ColorSorter.draw_sorted(ColorSorter.sorted_by_color) - - #russ 080225: Moved glEndList here for displist re-org. - if parent_csdl is not None: - #russ 080320: Experiment with VBO drawing from cached ColorSorter lists. - if (ColorSortedDisplayList.cache_ColorSorter and - drawing_globals.allow_color_sorting and - drawing_globals.use_color_sorted_vbos): - # Remember the ColorSorter lists for use as a pseudo-display-list. - parent_csdl.sorted_by_color = ColorSorter.sorted_by_color - else: - # Terminate a single display list, created when color sorting - # is turned off. It was started in ColorSorter.start . - glEndList() - pass - pass - - else: #russ 080225 - - parent_csdl.reset() - - # First build the lower level per-color sublists of primitives. - for color, funcs in ColorSorter.sorted_by_color.iteritems(): - sublists = [glGenLists(1), 0] - - # Remember the display list ID for this color. - parent_csdl.per_color_dls.append([color, sublists]) - - glNewList(sublists[0], GL_COMPILE) - opacity = color[3] - - if opacity == -1: - #russ 080306: "Unshaded colors" for lines are signaled - # by an opacity of -1 (4th component of the color.) - glDisable(GL_LIGHTING) # Don't forget to re-enable it! - pass - - for func, params, name in funcs: - objects_drawn += 1 - if name != 0: - glPushName(name) - func(params) - if name != 0: - glPopName() - pass - continue - - if opacity == -1: - # Enable lighting after drawing "unshaded" objects. - glEnable(GL_LIGHTING) - pass - glEndList() - - if opacity == -2: - # piotr 080419: Special case for drawpolycone_multicolor - # create another display list that ignores - # the contents of color_array. - # Remember the display list ID for this color. - - sublists[1] = glGenLists(1) - - glNewList(sublists[1], GL_COMPILE) - - for func, params, name in funcs: - objects_drawn += 1 - if name != 0: - glPushName(name) - pos_array, color_array, rad_array = params - if func == drawpolycone_multicolor_worker: - # Just to be sure, check if the func - # is drawpolycone_multicolor_worker - # and call drawpolycone_worker instead. - # I think in the future we can figure out - # a more general way of handling the - # GL_COLOR_MATERIAL objects. piotr 080420 - drawpolycone_worker((pos_array, rad_array)) - if name != 0: - glPopName() - pass - continue - glEndList() - - continue - - # Now the upper-level lists call all of the per-color sublists. - # One with colors. - color_dl = parent_csdl.color_dl = glGenLists(1) - glNewList(color_dl, GL_COMPILE) - - for color, dls in parent_csdl.per_color_dls: - - opacity = color[3] - if opacity < 0: - #russ 080306: "Unshaded colors" for lines are signaled - # by a negative alpha. - glColor3fv(color[:3]) - # piotr 080417: for opacity == -2, i.e. if - # GL_COLOR_MATERIAL is enabled, the color is going - # to be ignored, anyway, so it is not necessary - # to be tested here - else: - apply_material(color) - - glCallList(dls[0]) - - continue - glEndList() - - # A second one without any colors. - nocolor_dl = parent_csdl.nocolor_dl = glGenLists(1) - glNewList(nocolor_dl, GL_COMPILE) - for color, dls in parent_csdl.per_color_dls: - opacity = color[3] - - if opacity == -2 \ - and dls[1] > 0: - # piotr 080420: If GL_COLOR_MATERIAL is enabled, - # use a regular, single color dl rather than the - # multicolor one. Btw, dls[1] == 0 should never - # happen. - glCallList(dls[1]) - else: - glCallList(dls[0]) - - glEndList() - - # A third overlays the second with a single color for selection. - selected_dl = parent_csdl.selected_dl = glGenLists(1) - glNewList(selected_dl, GL_COMPILE) - apply_material(darkgreen) - glCallList(nocolor_dl) - glEndList() - - # Use either the normal-color display list or the selected one. - parent_csdl.selectDl() - - # Draw the newly-built display list. - parent_csdl.draw_dl() - pass - - ColorSorter.sorted_by_color = None - pass - ColorSorter.sorting = False - return - - finish = staticmethod(finish) - - def draw_sorted(sorted_by_color): #russ 080320: factored out of finish(). - """ - Traverse color-sorted lists, invoking worker procedures. - """ - objects_drawn = 0 # Keep track and return. - glEnable(GL_LIGHTING) - - for color, funcs in sorted_by_color.iteritems(): - - opacity = color[3] - if opacity == -1: - #piotr 080429: Opacity == -1 signals the "unshaded color". - # Also, see my comment in "schedule". - glDisable(GL_LIGHTING) # Don't forget to re-enable it! - glColor3fv(color[:3]) - else: - apply_material(color) - pass - - for func, params, name in funcs: - objects_drawn += 1 - if name != 0: - glPushName(name) - func(params) - if name != 0: - glPopName() - pass - continue - - if opacity == -1: - glEnable(GL_LIGHTING) - - continue - return objects_drawn - - draw_sorted = staticmethod(draw_sorted) - - pass # End of class ColorSorter. - -#================================================================ CS_draw_primitives.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -CS_draw_primitives.py - Public entry points for ColorSorter drawing primitives. - -These functions all call ColorSorter.schedule_* methods, which record object -data for sorting, including the object color and an eventual call on the -appropriate drawing worker function. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import foundation.env as env #bruce 051126 - -def drawsphere(color, pos, radius, detailLevel, opacity = 1.0): - """ - Schedule a sphere for rendering whenever ColorSorter thinks is appropriate. - """ - ColorSorter.schedule_sphere(color, - pos, - radius, - detailLevel, - opacity = opacity) - -def drawwiresphere(color, pos, radius, detailLevel = 1): - """ - Schedule a wireframe sphere for rendering whenever ColorSorter thinks is appropriate. - """ - ColorSorter.schedule_wiresphere(color, pos, radius, detailLevel = detailLevel) - -def drawcylinder(color, pos1, pos2, radius, capped = 0, opacity = 1.0): - """Schedule a cylinder for rendering whenever ColorSorter thinks is - appropriate.""" - if 1: - #bruce 060304 optimization: don't draw zero-length or almost-zero-length cylinders. - # (This happens a lot, apparently for both long-bond indicators and for open bonds. - # The callers hitting this should be fixed directly! That might provide a further - # optim by making a lot more single bonds draw as single cylinders.) - # The reason the threshhold depends on capped is in case someone draws a very thin - # cylinder as a way of drawing a disk. But they have to use some positive length - # (or the direction would be undefined), so we still won't permit zero-length then. - cyllen = vlen(pos1 - pos2) - if cyllen < (capped and 0.000000000001 or 0.0001): - # uncomment this to find the callers that ought to be optimized -## if env.debug(): #e optim or remove this test; until then it's commented out -## print "skipping drawcylinder since length is only %5g" % (cyllen,), \ -## " (color is (%0.2f, %0.2f, %0.2f))" % (color[0], color[1], color[2]) - return - ColorSorter.schedule_cylinder(color, pos1, pos2, radius, - capped = capped, opacity = opacity) - -def drawpolycone(color, pos_array, rad_array, opacity = 1.0): - """Schedule a polycone for rendering whenever ColorSorter thinks is - appropriate.""" - ColorSorter.schedule_polycone(color, pos_array, rad_array, opacity = opacity) - -def drawpolycone_multicolor(color, pos_array, color_array, rad_array, opacity = 1.0): - """Schedule a polycone for rendering whenever ColorSorter thinks is - appropriate. Accepts color_array for per-vertex coloring. """ - ColorSorter.schedule_polycone_multicolor(color, pos_array, color_array, rad_array, opacity = opacity) - -def drawsurface(color, pos, radius, tm, nm): - """ - Schedule a surface for rendering whenever ColorSorter thinks is - appropriate. - """ - ColorSorter.schedule_surface(color, pos, radius, tm, nm) - -def drawline(color, - endpt1, - endpt2, - dashEnabled = False, - stipleFactor = 1, - width = 1, - isSmooth = False): - """ - Draw a line from endpt1 to endpt2 in the given color. Actually, schedule - it for rendering whenever ColorSorter thinks is appropriate. - - @param endpt1: First endpoint. - @type endpt1: point - - @param endpt2: Second endpoint. - @type endpt2: point - - @param dashEnabled: If dashEnabled is True, it will be dashed. - @type dashEnabled: boolean - - @param stipleFactor: The stiple factor. - @param stipleFactor: int - - @param width: The line width in pixels. The default is 1. - @type width: int or float - - @param isSmooth: Enables GL_LINE_SMOOTH. The default is False. - @type isSmooth: boolean - - @note: Whether the line is antialiased is determined by GL state variables - which are not set in this function. - - @warning: Some callers pass dashEnabled as a positional argument rather - than a named argument. - """ - ColorSorter.schedule_line(color, endpt1, endpt2, dashEnabled, - stipleFactor, width, isSmooth) - - -#================================================================ setup_draw.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -setup_draw.py - The function to allocate and compile our standard display lists -into the current GL context, and initialize the globals that hold their opengl -names. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals -####from graphics.drawing.shape_vertices import getSphereTriStrips - -numSphereSizes = 3 - -def setup_drawer(): - """ - Set up the usual constant display lists in the current OpenGL context. - - WARNING: THIS IS ONLY CORRECT IF ONLY ONE GL CONTEXT CONTAINS DISPLAY LISTS -- - or more precisely, only the GL context this has last been called in - (or one which shares its display lists) will work properly with the routines in drawer.py, - since the allocated display list names are stored in globals set by this function, - but in general those names might differ if this was called in different GL contexts. - """ - #bruce 060613 added docstring, cleaned up display list name allocation - # bruce 071030 renamed from setup to setup_drawer - - spherelistbase = glGenLists(numSphereSizes) - sphereList = [] - for i in range(numSphereSizes): - sphereList += [spherelistbase+i] - glNewList(sphereList[i], GL_COMPILE) - glBegin(GL_TRIANGLE_STRIP) # GL_LINE_LOOP to see edges. - stripVerts = getSphereTriStrips(i) - for vertNorm in stripVerts: - glNormal3fv(vertNorm) - glVertex3fv(vertNorm) - continue - glEnd() - glEndList() - continue - drawing_globals.sphereList = sphereList - - # Sphere triangle-strip vertices for each level of detail. - # (Cache and re-use the work of making them.) - # Can use in converter-wrappered calls like glVertexPointerfv, - # but the python arrays are re-copied to C each time. - sphereArrays = [] - for i in range(numSphereSizes): - sphereArrays += [getSphereTriStrips(i)] - continue - drawing_globals.sphereArrays = sphereArrays - - # Sphere glDrawArrays triangle-strip vertices for C calls. - # (Cache and re-use the work of converting a C version.) - # Used in thinly-wrappered calls like glVertexPointer. - sphereCArrays = [] - for i in range(numSphereSizes): - CArray = numpy.array(sphereArrays[i], dtype=numpy.float32) - sphereCArrays += [CArray] - continue - drawing_globals.sphereCArrays = sphereCArrays - - # Sphere indexed vertices. - # (Cache and re-use the work of making the indexes.) - # Can use in converter-wrappered calls like glDrawElementsui, - # but the python arrays are re-copied to C each time. - sphereElements = [] # Pairs of lists (index, verts) . - for i in range(numSphereSizes): - sphereElements += [indexVerts(sphereArrays[i], .0001)] - continue - drawing_globals.sphereElements = sphereElements - - # Sphere glDrawElements index and vertex arrays for C calls. - sphereCIndexTypes = [] # numpy index unsigned types. - sphereGLIndexTypes = [] # GL index types for drawElements. - sphereCElements = [] # Pairs of numpy arrays (Cindex, Cverts) . - for i in range(numSphereSizes): - (index, verts) = sphereElements[i] - if len(index) < 256: - Ctype = numpy.uint8 - GLtype = GL_UNSIGNED_BYTE - else: - Ctype = numpy.uint16 - GLtype = GL_UNSIGNED_SHORT - pass - sphereCIndexTypes += [Ctype] - sphereGLIndexTypes += [GLtype] - sphereCIndex = numpy.array(index, dtype=Ctype) - sphereCVerts = numpy.array(verts, dtype=numpy.float32) - sphereCElements += [(sphereCIndex, sphereCVerts)] - continue - drawing_globals.sphereCIndexTypes = sphereCIndexTypes - drawing_globals.sphereGLIndexTypes = sphereGLIndexTypes - drawing_globals.sphereCElements = sphereCElements - - if glGetString(GL_EXTENSIONS).find("GL_ARB_vertex_buffer_object") >= 0: - - # A GLBufferObject version for glDrawArrays. - sphereArrayVBOs = [] - for i in range(numSphereSizes): - vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, - sphereCArrays[i], GL_STATIC_DRAW) - sphereArrayVBOs += [vbo] - continue - drawing_globals.sphereArrayVBOs = sphereArrayVBOs - - # A GLBufferObject version for glDrawElements indexed verts. - sphereElementVBOs = [] # Pairs of (IBO, VBO) - for i in range(numSphereSizes): - ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, - sphereCElements[i][0], GL_STATIC_DRAW) - vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, - sphereCElements[i][1], GL_STATIC_DRAW) - sphereElementVBOs += [(ibo, vbo)] - continue - drawing_globals.sphereElementVBOs = sphereElementVBOs - - ibo.unbind() - vbo.unbind() - pass - - #bruce 060415 - drawing_globals.wiresphere1list = wiresphere1list = glGenLists(1) - glNewList(wiresphere1list, GL_COMPILE) - didlines = {} # don't draw each triangle edge more than once - def shoulddoline(v1,v2): - v1 = tuple(v1) # make sure not list (unhashable) or Numeric array (bug in __eq__) - v2 = tuple(v2) - if (v1,v2) not in didlines: - didlines[(v1,v2)] = didlines[(v2,v1)] = None - return True - return False - def doline(v1,v2): - if shoulddoline(v1,v2): - glVertex3fv(v1) - glVertex3fv(v2) - return - glBegin(GL_LINES) - ocdec = getSphereTriangles(1) - for tri in ocdec: - #e could probably optim this more, e.g. using a vertex array or VBO or maybe GL_LINE_STRIP - doline(tri[0], tri[1]) - doline(tri[1], tri[2]) - doline(tri[2], tri[0]) - glEnd() - glEndList() - - drawing_globals.CylList = CylList = glGenLists(1) - glNewList(CylList, GL_COMPILE) - glBegin(GL_TRIANGLE_STRIP) - for (vtop, ntop, vbot, nbot) in drawing_globals.cylinderEdges: - glNormal3fv(nbot) - glVertex3fv(vbot) - glNormal3fv(ntop) - glVertex3fv(vtop) - glEnd() - glEndList() - - drawing_globals.CapList = CapList = glGenLists(1) - glNewList(CapList, GL_COMPILE) - glNormal3fv(drawing_globals.cap0n) - glBegin(GL_POLYGON) - for p in drawing_globals.drum0: - glVertex3fv(p) - glEnd() - glNormal3fv(drawing_globals.cap1n) - glBegin(GL_POLYGON) - #bruce 060609 fix "ragged edge" bug in this endcap: drum1 -> drum2 - for p in drawing_globals.drum2: - glVertex3fv(p) - glEnd() - glEndList() - - drawing_globals.diamondGridList = diamondGridList = glGenLists(1) - glNewList(diamondGridList, GL_COMPILE) - glBegin(GL_LINES) - for p in drawing_globals.digrid: - glVertex(p[0]) - glVertex(p[1]) - glEnd() - glEndList() - - drawing_globals.lonsGridList = lonsGridList = glGenLists(1) - glNewList(lonsGridList, GL_COMPILE) - glBegin(GL_LINES) - for p in drawing_globals.lonsEdges: - glVertex(p[0]) - glVertex(p[1]) - glEnd() - glEndList() - - drawing_globals.CubeList = CubeList = glGenLists(1) - glNewList(CubeList, GL_COMPILE) - glBegin(GL_QUAD_STRIP) - # note: CubeList has only 4 faces of the cube; only suitable for use in wireframes; - # see also solidCubeList [bruce 051215 comment reporting grantham 20051213 observation] - glVertex((-1,-1,-1)) - glVertex(( 1,-1,-1)) - glVertex((-1, 1,-1)) - glVertex(( 1, 1,-1)) - glVertex((-1, 1, 1)) - glVertex(( 1, 1, 1)) - glVertex((-1,-1, 1)) - glVertex(( 1,-1, 1)) - glVertex((-1,-1,-1)) - glVertex(( 1,-1,-1)) - glEnd() - glEndList() - - drawing_globals.solidCubeList = solidCubeList = glGenLists(1) - glNewList(solidCubeList, GL_COMPILE) - glBegin(GL_QUADS) - for i in xrange(len(drawing_globals.cubeIndices)): - avenormals = V(0,0,0) #bruce 060302 fixed normals for flat shading - for j in xrange(4) : - nTuple = tuple( - drawing_globals.cubeNormals[drawing_globals.cubeIndices[i][j]]) - avenormals += A(nTuple) - avenormals = norm(avenormals) - for j in xrange(4) : - vTuple = tuple( - drawing_globals.cubeVertices[drawing_globals.cubeIndices[i][j]]) - #bruce 060302 made size compatible with glut.glutSolidCube(1.0) - vTuple = A(vTuple) * 0.5 - glNormal3fv(avenormals) - glVertex3fv(vTuple) - glEnd() - glEndList() - - drawing_globals.rotSignList = rotSignList = glGenLists(1) - glNewList(rotSignList, GL_COMPILE) - glBegin(GL_LINE_STRIP) - for ii in xrange(len(drawing_globals.rotS0n)): - glVertex3fv(tuple(drawing_globals.rotS0n[ii])) - glEnd() - glBegin(GL_LINE_STRIP) - for ii in xrange(len(drawing_globals.rotS1n)): - glVertex3fv(tuple(drawing_globals.rotS1n[ii])) - glEnd() - glBegin(GL_TRIANGLES) - for v in drawing_globals.arrow0Vertices + drawing_globals.arrow1Vertices: - glVertex3f(v[0], v[1], v[2]) - glEnd() - glEndList() - - drawing_globals.linearArrowList = linearArrowList = glGenLists(1) - glNewList(linearArrowList, GL_COMPILE) - glBegin(GL_TRIANGLES) - for v in drawing_globals.linearArrowVertices: - glVertex3f(v[0], v[1], v[2]) - glEnd() - glEndList() - - drawing_globals.linearLineList = linearLineList = glGenLists(1) - glNewList(linearLineList, GL_COMPILE) - glEnable(GL_LINE_SMOOTH) - glBegin(GL_LINES) - glVertex3f(0.0, 0.0, -drawing_globals.halfHeight) - glVertex3f(0.0, 0.0, drawing_globals.halfHeight) - glEnd() - glDisable(GL_LINE_SMOOTH) - glEndList() - - drawing_globals.circleList = circleList = glGenLists(1) - glNewList(circleList, GL_COMPILE) - glBegin(GL_LINE_LOOP) - for ii in range(60): - x = cos(ii*2.0*pi/60) - y = sin(ii*2.0*pi/60) - glVertex3f(x, y, 0.0) - glEnd() - glEndList() - - # piotr 080405 - drawing_globals.filledCircleList = filledCircleList = glGenLists(1) - glNewList(filledCircleList, GL_COMPILE) - glBegin(GL_POLYGON) - for ii in range(60): - x = cos(ii*2.0*pi/60) - y = sin(ii*2.0*pi/60) - glVertex3f(x, y, 0.0) - glEnd() - glEndList() - - drawing_globals.lineCubeList = lineCubeList = glGenLists(1) - glNewList(lineCubeList, GL_COMPILE) - glBegin(GL_LINES) - cvIndices = [0,1, 2,3, 4,5, 6,7, 0,3, 1,2, 5,6, 4,7, 0,4, 1,5, 2,6, 3,7] - for i in cvIndices: - glVertex3fv(tuple(drawing_globals.cubeVertices[i])) - glEnd() - glEndList() - - # Debug Preferences - from utilities.debug_prefs import debug_pref, Choice_boolean_True - from utilities.debug_prefs import Choice_boolean_False - choices = [Choice_boolean_False, Choice_boolean_True] - - # 20060314 grantham - initial_choice = choices[drawing_globals.allow_color_sorting_default] - drawing_globals.allow_color_sorting_pref = debug_pref( - "Use Color Sorting?", initial_choice, - prefs_key = drawing_globals.allow_color_sorting_prefs_key) - #bruce 060323 removed non_debug = True for A7 release, changed default - #value to False (far above), and changed its prefs_key so developers - #start with the new default value. - #russ 080225: Added. - initial_choice = choices[drawing_globals.use_color_sorted_dls_default] - drawing_globals.use_color_sorted_dls_pref = debug_pref( - "Use Color-sorted Display Lists?", initial_choice, - prefs_key = drawing_globals.use_color_sorted_dls_prefs_key) - #russ 080225: Added. - initial_choice = choices[drawing_globals.use_color_sorted_vbos_default] - drawing_globals.use_color_sorted_vbos_pref = debug_pref( - "Use Color-sorted Vertex Buffer Objects?", initial_choice, - prefs_key = drawing_globals.use_color_sorted_vbos_prefs_key) - - #russ 080403: Added drawing variant selection - variants = [ - "0. OpenGL 1.0 - glBegin/glEnd tri-strips vertex-by-vertex.", - "1. OpenGL 1.1 - glDrawArrays from CPU RAM.", - "2. OpenGL 1.1 - glDrawElements indexed arrays from CPU RAM.", - "3. OpenGL 1.5 - glDrawArrays from graphics RAM VBO.", - "4. OpenGL 1.5 - glDrawElements, verts in VBO, index in CPU.", - "5. OpenGL 1.5 - VBO/IBO buffered glDrawElements."] - drawing_globals.use_drawing_variant = debug_pref( - "GLPane: drawing method", - Choice(names = variants, values = range(len(variants)), - defaultValue = drawing_globals.use_drawing_variant_default), - prefs_key = drawing_globals.use_drawing_variant_prefs_key) - - # temporarily always print this, while default setting might be in flux, - # and to avoid confusion if the two necessary prefs are set differently - # [bruce 080305] - if (drawing_globals.allow_color_sorting_pref and - drawing_globals.use_color_sorted_dls_pref): - print "\nnote: this session WILL use color sorted display lists" - else: - print "\nnote: this session will NOT use color sorted display lists" - if (drawing_globals.allow_color_sorting_pref and - drawing_globals.use_color_sorted_vbos_pref): - print "note: this session WILL use color sorted Vertex Buffer Objects\n" - else: - print "note: this session will NOT use color sorted Vertex Buffer Objects\n" - - # 20060313 grantham Added use_c_renderer debug pref, can - # take out when C renderer used by default. - if drawing_globals.quux_module_import_succeeded: - initial_choice = choices[drawing_globals.use_c_renderer_default] - drawing_globals.use_c_renderer = ( - debug_pref("Use native C renderer?", - initial_choice, - prefs_key = drawing_globals.use_c_renderer_prefs_key)) - #bruce 060323 removed non_debug = True for A7 release, - # and changed its prefs_key so developers start over with the default value. - - #initTexture('C:\\Huaicai\\atom\\temp\\newSample.png', 128,128) - return # from setup_drawer - -#================================================================ drawers.py -# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" -drawers.py - Miscellaneous drawing functions that are not used as primitives. - -@version: $Id$ -@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. -""" - -import graphics.drawing.drawing_globals as drawing_globals - -try: - from OpenGL.GLE import glePolyCone, gleGetNumSides, gleSetNumSides -except: - print "GLE module can't be imported. Now trying _GLE" - from OpenGL._GLE import glePolyCone, gleGetNumSides, gleSetNumSides - -# Check if the gleGet/SetNumSides function is working on this install, and if -# not, alias it to an effective no-op. Checking method is as recommended in -# an OpenGL exception reported by Brian [070622]: -# OpenGL.error.NullFunctionError: Attempt to call an -# undefined function gleGetNumSides, check for -# bool(gleGetNumSides) before calling -# The underlying cause of this (described by Brian) is that the computer's OpenGL -# has the older gleGetNumSlices (so it supports the functionality), but PyOpenGL -# binds (only) to the newer gleGetNumSides. Given the PyOpenGL we're using, -# there's no way to access gleGetNumSlices, but in the future we might patch it -# to let us do that when this happens. I [bruce 070629] think Brian said this is -# only an issue on Macs. -if not bool(gleGetNumSides): - print "fyi: gleGetNumSides is not supported by the OpenGL pre-installed on this computer." - gleGetNumSides = int - gleSetNumSides = int - -# == - -def drawCircle(color, center, radius, normal): - """Scale, rotate/translate the unit circle properly """ - glMatrixMode(GL_MODELVIEW) - glPushMatrix() - glColor3fv(color) - glDisable(GL_LIGHTING) - - glTranslatef(center[0], center[1], center[2]) - rQ = Q(V(0, 0, 1), normal) - rotAngle = rQ.angle*180.0/pi - - #This may cause problems as proved before in Linear motor display. - #rotation around (0, 0, 0) - #if vlen(V(rQ.x, rQ.y, rQ.z)) < 0.00005: - # rQ.x = 1.0 - - glRotatef(rotAngle, rQ.x, rQ.y, rQ.z) - glScalef(radius, radius, 1.0) - glCallList(drawing_globals.circleList) - glEnable(GL_LIGHTING) - glPopMatrix() - return - -def drawFilledCircle(color, center, radius, normal): - """ - Scale, rotate/translate the unit circle properly. - Added a filled circle variant, piotr 080405 - """ - glMatrixMode(GL_MODELVIEW) - glPushMatrix() - glColor3fv(color) - glDisable(GL_LIGHTING) - - glTranslatef(center[0], center[1], center[2]) - rQ = Q(V(0, 0, 1), normal) - rotAngle = rQ.angle*180.0/pi - - #This may cause problems as proved before in Linear motor display. - #rotation around (0, 0, 0) - #if vlen(V(rQ.x, rQ.y, rQ.z)) < 0.00005: - # rQ.x = 1.0 - - glRotatef(rotAngle, rQ.x, rQ.y, rQ.z) - glScalef(radius, radius, 1.0) - glCallList(drawing_globals.filledCircleList) - glEnable(GL_LIGHTING) - glPopMatrix() - return - -def drawLinearArrows(longScale): - glCallList(drawing_globals.linearArrowList) - newPos = drawing_globals.halfHeight*longScale - glPushMatrix() - glTranslate(0.0, 0.0, -newPos) - glCallList(drawing_globals.linearArrowList) - glPopMatrix() - glPushMatrix() - glTranslate(0.0, 0.0, newPos -2.0*drawing_globals.halfEdge) - glCallList(drawing_globals.linearArrowList) - glPopMatrix() - return - -def drawLinearSign(color, center, axis, l, h, w): - """Linear motion sign on the side of squa-linder """ - depthOffset = 0.005 - glPushMatrix() - glColor3fv(color) - glDisable(GL_LIGHTING) - glTranslatef(center[0], center[1], center[2]) - - ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes - ## display problem on some platforms - angle = -acos(axis[2])*180.0/pi - if (axis[2]*axis[2] >= 1.0): - glRotate(angle, 0.0, 1.0, 0.0) - else: - glRotate(angle, axis[1], -axis[0], 0.0) - - glPushMatrix() - glTranslate(h/2.0 + depthOffset, 0.0, 0.0) - glPushMatrix() - glScale(1.0, 1.0, l) - glCallList(drawing_globals.linearLineList) - glPopMatrix() - if l < 2.6: - sl = l/2.7 - glScale(1.0, sl, sl) - if w < 1.0: - glScale(1.0, w, w) - drawLinearArrows(l) - glPopMatrix() - - glPushMatrix() - glTranslate(-h/2.0 - depthOffset, 0.0, 0.0) - glRotate(180.0, 0.0, 0.0, 1.0) - glPushMatrix() - glScale(1.0, 1.0, l) - glCallList(drawing_globals.linearLineList) - glPopMatrix() - if l < 2.6: - glScale(1.0, sl, sl) - if w < 1.0: - glScale(1.0, w, w) - drawLinearArrows(l) - glPopMatrix() - - glPushMatrix() - glTranslate(0.0, w/2.0 + depthOffset, 0.0) - glRotate(90.0, 0.0, 0.0, 1.0) - glPushMatrix() - glScale(1.0, 1.0, l) - glCallList(drawing_globals.linearLineList) - glPopMatrix() - if l < 2.6: - glScale(1.0, sl, sl) - if w < 1.0: - glScale(1.0, w, w) - drawLinearArrows(l) - glPopMatrix() - - glPushMatrix() - glTranslate(0.0, -w/2.0 - depthOffset, 0.0 ) - glRotate(-90.0, 0.0, 0.0, 1.0) - glPushMatrix() - glScale(1.0, 1.0, l) - glCallList(drawing_globals.linearLineList) - glPopMatrix() - if l < 2.6: - glScale(1.0, sl, sl) - if w < 1.0: - glScale(1.0, w, w) - drawLinearArrows(l) - glPopMatrix() - - glEnable(GL_LIGHTING) - glPopMatrix() - return - -def drawRotateSign(color, pos1, pos2, radius, rotation = 0.0): - """Rotate sign on top of the caps of the cylinder """ - glPushMatrix() - glColor3fv(color) - vec = pos2-pos1 - axis = norm(vec) - glTranslatef(pos1[0], pos1[1], pos1[2]) - - ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes - ## display problem on some platforms - angle = -acos(axis[2])*180.0/pi - if (axis[2]*axis[2] >= 1.0): - glRotate(angle, 0.0, 1.0, 0.0) - else: - glRotate(angle, axis[1], -axis[0], 0.0) - glRotate(rotation, 0.0, 0.0, 1.0) #bruce 050518 - glScale(radius,radius,Numeric.dot(vec,vec)**.5) - - glLineWidth(2.0) - glDisable(GL_LIGHTING) - glCallList(drawing_globals.rotSignList) - glEnable(GL_LIGHTING) - glLineWidth(1.0) - - glPopMatrix() - return - -def drawArrowHead(color, - basePoint, - drawingScale, - unitBaseVector, - unitHeightVector): - - - - arrowBase = drawingScale * 0.08 - arrowHeight = drawingScale * 0.12 - glDisable(GL_LIGHTING) - glPushMatrix() - glTranslatef(basePoint[0],basePoint[1],basePoint[2]) - point1 = V(0, 0, 0) - point1 = point1 + unitHeightVector * arrowHeight - point2 = unitBaseVector * arrowBase - point3 = - unitBaseVector * arrowBase - #Draw the arrowheads as filled triangles - glColor3fv(color) - glBegin(GL_POLYGON) - glVertex3fv(point1) - glVertex3fv(point2) - glVertex3fv(point3) - glEnd() - glPopMatrix() - glEnable(GL_LIGHTING) - -def drawSineWave(color, startPoint, endPoint, numberOfPoints, phaseAngle): - """ - """ - pass - -def drawPolyLine(color, points): - '''Draws a poly line passing through the given list of points''' - glDisable(GL_LIGHTING) - glColor3fv(color) - glBegin(GL_LINE_STRIP) - for v in points: - glVertex3fv(v) - glEnd() - - glEnable(GL_LIGHTING) - return - -def drawPoint(color, - point, - pointSize = 3.0, - isRound = True): - """ - Draw a point using GL_POINTS. - @param point: The x,y,z coordinate array/ vector of the point - @type point: A or V - @param pointSize: The point size to be used by glPointSize - @type pointSize: float - @param isRound: If True, the point will be drawn round otherwise square - @type isRound: boolean - """ - glDisable(GL_LIGHTING) - glColor3fv(color) - glPointSize(float(pointSize)) - if isRound: - glEnable(GL_POINT_SMOOTH) - glBegin(GL_POINTS) - glVertex3fv(point) - glEnd() - if isRound: - glDisable(GL_POINT_SMOOTH) - - glEnable(GL_LIGHTING) - if pointSize != 1.0: - glPointSize(1.0) - return - -def drawTag(color, basePoint, endPoint, pointSize = 20.0): - """ - Draw a tag (or a 'flag') as a line ending with a circle (like a balloon - with a string). Note: The word 'Flag' is intentionally not used in the - method nameto avoid potential confusion with a boolean flag. - - @param color: color of the tag - @type color: A - @param basePoint: The base point of the tag - @type basePoint: V - @param endPoint: The end point of the tag - @type endPoint: V - @param pointSize: The pointSize of the point to be drawin at the <endPoint> - @type pointSize: float - - @see: GraphicsMode._drawTags where it is called (an example) - - """ - drawline(color, basePoint, endPoint) - drawPoint(color, endPoint, pointSize = 20.0) - -def drawLineCube(color, pos, radius): - vtIndices = [0,1,2,3, 0,4,5,1, 5,4,7,6, 6,7,3,2] - glEnableClientState(GL_VERTEX_ARRAY) - #bruce 051117 revised this - glVertexPointer(3, GL_FLOAT, 0, drawing_globals.flatCubeVertices) - #grantham 20051213 observations, reported/paraphrased by bruce 051215: - # - should verify PyOpenGL turns Python float (i.e. C double) into C float - # for OpenGL's GL_FLOAT array element type. - # - note that GPUs are optimized for DrawElements types GL_UNSIGNED_INT and GL_UNSIGNED_SHORT. - glDisable(GL_LIGHTING) - glColor3fv(color) - glPushMatrix() - glTranslatef(pos[0], pos[1], pos[2]) - glScale(radius,radius,radius) - glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices) - #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[4]) - #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[8]) - #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[12]) - glPopMatrix() - glEnable(GL_LIGHTING) - glDisableClientState(GL_VERTEX_ARRAY) - return - -def drawwirecube(color, pos, radius, lineWidth=3.0): - glPolygonMode(GL_FRONT, GL_LINE) - glPolygonMode(GL_BACK, GL_LINE) - glDisable(GL_LIGHTING) - glDisable(GL_CULL_FACE) - glColor3fv(color) - glPushMatrix() - glTranslatef(pos[0], pos[1], pos[2]) - if type(radius) == type(1.0): - glScale(radius,radius,radius) - else: - glScale(radius[0], radius[1], radius[2]) - glLineWidth(lineWidth) - glCallList(drawing_globals.lineCubeList) - glLineWidth(1.0) ## restore its state - glPopMatrix() - glEnable(GL_CULL_FACE) - glEnable(GL_LIGHTING) - glPolygonMode(GL_FRONT, GL_FILL) - glPolygonMode(GL_BACK, GL_FILL) #bruce 050729 to help fix bug 835 or related bugs - return - -def drawwirebox(color, pos, len): - glPolygonMode(GL_FRONT, GL_LINE) - glPolygonMode(GL_BACK, GL_LINE) - glDisable(GL_LIGHTING) - glDisable(GL_CULL_FACE) - glColor3fv(color) - glPushMatrix() - glTranslatef(pos[0], pos[1], pos[2]) - glScale(len[0], len[1], len[2]) - glCallList(drawing_globals.CubeList) - glPopMatrix() - glEnable(GL_CULL_FACE) - glEnable(GL_LIGHTING) - glPolygonMode(GL_FRONT, GL_FILL) - glPolygonMode(GL_BACK, GL_FILL) #bruce 050729 to help fix bug 835 or related bugs - return - -def segstart(color): - glDisable(GL_LIGHTING) - glColor3fv(color) - glBegin(GL_LINES) - return - -def drawsegment(pos1,pos2): - glVertex3fv(pos1) - glVertex3fv(pos2) - return - -def segend(): - glEnd() - glEnable(GL_LIGHTING) - return - -def drawAxis(color, pos1, pos2, width = 2): #Ninad 060907 - '''Draw chunk or jig axis''' - #ninad060907 Note that this is different than draw - #I may need this function to draw axis line. see its current implementation in - #branch "ninad_060908_drawAxis_notAsAPropOfObject" - glDisable(GL_LIGHTING) - glColor3fv(color) - glLineStipple(3, 0x1C47) # dash-dot-dash line - glEnable(GL_LINE_STIPPLE) - if width != 1: - glLineWidth(width) - glBegin(GL_LINES) - glVertex(pos1[0], pos1[1], pos1[2]) - glVertex(pos2[0], pos2[1], pos2[2]) - glEnd() - if width != 1: - glLineWidth(1.0) # restore default state - glDisable(GL_LINE_STIPPLE) - glEnable(GL_LIGHTING) - return - -def drawaxes(n,point,coloraxes=False, dashEnabled = False): - - n *= 0.5 - glPushMatrix() - glTranslate(point[0], point[1], point[2]) - glDisable(GL_LIGHTING) - - if coloraxes: - glColor3f(red[0], red[1], red[2]) - if dashEnabled: - #ninad060921 Note that we will only support dotted origin axis - #(hidden lines)but not POV axis. (as it could be annoying) - glLineStipple(5, 0xAAAA) - glEnable(GL_LINE_STIPPLE) - glDisable(GL_DEPTH_TEST) - else: - glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) - - glBegin(GL_LINES) - glVertex(n,0,0) - glVertex(-n,0,0) - glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) - glVertex(0,n,0) - glVertex(0,-n,0) - if coloraxes: glColor3f(blue[0], blue[1], blue[2]) - else: glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) - glVertex(0,0,n) - glVertex(0,0,-n) - glEnd() - - if coloraxes: - if dashEnabled: - glDisable(GL_LINE_STIPPLE) - glEnable(GL_DEPTH_TEST) - - glEnable(GL_LIGHTING) - glPopMatrix() - return - -def drawOriginAsSmallAxis(scale, origin, dashEnabled = False): - """ - Draws a small wireframe version of the origin. It is rendered as a - 3D point at (0, 0, 0) with 3 small axes extending from it in the positive - X, Y, Z directions. - """ - #Perhaps we should split this method into smaller methods? ninad060920 - #Notes: - #1. drawing arrowheads implemented on 060918 - #2. ninad060921 Show the origin axes as dotted if behind the mode. - #3. ninad060922 The arrow heads are drawn as wireframe cones if behind the object - # the arrowhead size is slightly smaller (otherwise some portion of the - # the wireframe arrow shows up! - #3.Making origin non-zoomable is acheived by replacing - #hardcoded 'n' with glpane's scale - ninad060922 - - #ninad060922 in future , the following could be user preferences. - if (dashEnabled): - dashShrinkage = 0.9 - else: - dashShrinkage=1 - x1, y1, z1 = scale * 0.01, scale * 0.01, scale * 0.01 - xEnd, yEnd, zEnd = scale * 0.04, scale * 0.09, scale * 0.025 - arrowBase = scale * 0.0075 * dashShrinkage - arrowHeight = scale * 0.035 * dashShrinkage - lineWidth = 1.0 - - glPushMatrix() - - glTranslate(origin[0], origin[1], origin[2]) - glDisable(GL_LIGHTING) - glLineWidth(lineWidth) - - gleNumSides = gleGetNumSides() - #Code to show hidden lines of the origin if some model obscures it ninad060921 - if dashEnabled: - glLineStipple(2, 0xAAAA) - glEnable(GL_LINE_STIPPLE) - glDisable(GL_DEPTH_TEST) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) - gleSetNumSides(5) - else: - gleSetNumSides(10) - - glBegin(GL_LINES) - - #glColor3f(black) - glColor3fv(lightblue) - - #start draw a point at origin . - #ninad060922 is thinking about using GL_POINTS here - - glVertex(-x1, 0.0, 0.0) - glVertex( x1, 0.0, 0.0) - glVertex(0.0, -y1, 0.0) - glVertex(0.0, y1, 0.0) - glVertex(-x1, y1, z1) - glVertex( x1, -y1, -z1) - glVertex(x1, y1, z1) - glVertex(-x1, -y1, -z1) - glVertex(x1, y1, -z1) - glVertex(-x1, -y1, z1) - glVertex(-x1, y1, -z1) - glVertex(x1, -y1, z1) - #end draw a point at origin - - #start draw small origin axes - #glColor3fv(darkred) - glColor3fv(lightblue) - glVertex(xEnd, 0.0, 0.0) - glVertex( 0.0, 0.0, 0.0) - #glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) - glColor3fv(lightblue) - glVertex(0.0, yEnd, 0.0) - glVertex(0.0, 0.0, 0.0) - #glColor3f(blue[0], blue[1], blue[2]) - glColor3fv(lightblue) - glVertex(0.0, 0.0, zEnd) - glVertex(0.0, 0.0, 0.0) - glEnd() #end draw lines - glLineWidth(1.0) - - glPopMatrix() # end push matrix for drawing various lines in the origin and axes - - #start draw solid arrow heads for X , Y and Z axes - glPushMatrix() - glDisable(GL_CULL_FACE) - #glColor3fv(darkred) - glColor3fv(lightblue) - glTranslatef(xEnd, 0.0, 0.0) - glRotatef(90, 0.0, 1.0, 0.0) - - glePolyCone([[0, 0, -1], [0, 0, 0], [0, 0, arrowHeight], [0, 0, arrowHeight+1]], None, [arrowBase, arrowBase, 0, 0]) - - glPopMatrix() - - glPushMatrix() - #glColor3f(darkgreen) - glColor3fv(lightblue) - glTranslatef(0.0, yEnd, 0.0) - glRotatef(-90, 1.0, 0.0, 0.0) - - glePolyCone([[0, 0, -1], [0, 0, 0], [0, 0, arrowHeight], [0, 0, arrowHeight+1]], None, [arrowBase, arrowBase, 0, 0]) - - glPopMatrix() - - glPushMatrix() - glColor3fv(lightblue) - glTranslatef(0.0,0.0,zEnd) - - glePolyCone([[0, 0, -1], [0, 0, 0], [0, 0, arrowHeight], [0, 0, arrowHeight+1]], None, [arrowBase, arrowBase, 0, 0]) - - #Disable line stipple and Enable Depth test - if dashEnabled: - glLineStipple(1, 0xAAAA) - glDisable(GL_LINE_STIPPLE) - glEnable(GL_DEPTH_TEST) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - gleSetNumSides(gleNumSides) - glEnable(GL_CULL_FACE) - glEnable(GL_LIGHTING) - glPopMatrix() - #end draw solid arrow heads for X , Y and Z axes - return - -def drawDirectionArrow(color, - tailPoint, - arrowBasePoint, - tailRadius, - scale, - flipDirection = False, - opacity = 1.0, - numberOfSides = 20 - ): - """ - Draw a directional arrow staring at <tailPoint> with an endpoint decided - by the vector between <arrowBasePoint> and <tailPoint> - and the glpane scale <scale> - @param color : The arrow color - @type color: Array - @param tailPoint: The point on the arrow tail where the arrow begins. - @type tailPoint: V - @param arrowBasePoint: A point on the arrow where the arrow head begins(?? - @type arrowBasePoint: V - @param tailRadius: The radius of the arrow tail (cylinder radius - representing the arrow tail) - @type tailRaius: float - @param opacity: The opacity decides the opacity (or transparent display) - of the rendered arrow. By default it is rendered as a solid - arrow. It varies between 0.0 to 1.0 ... 1.0 represents the - solid arrow renderring style - @type opacity: float - @param numberOfSides: The total number of sides for the arrow head - (a glePolycone) The default value if 20 (20 sided - polycone) - @type numberOfSides: int - """ - - vec = arrowBasePoint - tailPoint - vec = scale*0.07*vec - arrowBase = tailRadius*3.0 - arrowHeight = arrowBase*1.5 - axis = norm(vec) - - #as of 2008-03-03 scaledBasePoint is not used so commenting out. - #(will be removed after more testing) - ##scaledBasePoint = tailPoint + vlen(vec)*axis - drawcylinder(color, tailPoint, arrowBasePoint, tailRadius, capped = True, - opacity = opacity) - - ##pos = scaledBasePoint - pos = arrowBasePoint - arrowRadius = arrowBase - gleSetNumSides(numberOfSides) - drawpolycone(color, [[pos[0] - 1 * axis[0], - pos[1] - 1 * axis[1], - pos[2] - 1 * axis[2]], - [pos[0],# - axis[0], - pos[1], #- axis[1], - pos[2]], #- axis[2]], - [pos[0] + arrowHeight * axis[0], - pos[1] + arrowHeight * axis[1], - pos[2] + arrowHeight * axis[2]], - [pos[0] + (arrowHeight + 1) * axis[0], - pos[1] + (arrowHeight + 1) * axis[1], - pos[2] + (arrowHeight + 1) * axis[2]]], # Point array (the two end - # points not drawn) - [arrowRadius, arrowRadius, 0, 0], # Radius array - opacity = opacity - ) - #reset the gle number of sides to the gle default of '20' - gleSetNumSides(20) - - -def findCell(pt, latticeType): - """Return the cell which contains the point <pt> """ - if latticeType == 'DIAMOND': - a = 0; cellX = cellY = cellZ = drawing_globals.DiGridSp - elif latticeType == 'LONSDALEITE': - a = 1 - cellX = drawing_globals.XLen - cellY = drawing_globals.YLen - cellZ = drawing_globals.ZLen - - i = int(floor(pt[0]/cellX)) - j = int(floor(pt[1]/cellY)) - k = int(floor(pt[2]/cellZ)) - - orig = V(i*cellX, j*cellY, k*cellZ) - - return orig, sp1 - -def genDiam(bblo, bbhi, latticeType): - """Generate a list of possible atom positions within the area enclosed by (bblo, bbhi). - <Return>: A list of unit cells""" - if latticeType == 'DIAMOND': - a = 0; cellX = cellY = cellZ = drawing_globals.DiGridSp - elif latticeType == 'LONSDALEITE': - a = 1 - cellX = drawing_globals.XLen - cellY = drawing_globals.YLen - cellZ = drawing_globals.ZLen - - allCells = [] - for i in range(int(floor(bblo[0]/cellX)), - int(ceil(bbhi[0]/cellX))): - for j in range(int(floor(bblo[1]/cellY)), - int(ceil(bbhi[1]/cellY))): - for k in range(int(floor(bblo[2]/cellZ)), - int(ceil(bbhi[2]/cellZ))): - off = V(i*cellX, j*cellY, k*cellZ) - if a == 0: allCells += [drawing_globals.digrid + off] - elif a ==1: allCells += [drawing_globals.lonsEdges + off] - return allCells - - -def drawGrid(scale, center, latticeType): - """ - Construct the grid model and show as position references for cookies. - The model is build around "pov" and has size of 2*"scale" on each of - the (x, y, z) directions. - - @note: This should be optimized later. - For "scale = 200", it takes about 1479623 loops. ---Huaicai - """ - glDisable(GL_LIGHTING) - - # bruce 041201: - # Quick fix to prevent "hang" from drawing too large a cookieMode grid - # with our current cubic algorithm (bug 8). The constant 120.0 is still on - # the large side in terms of responsiveness -- on a 1.8GHz iMac G5 it can - # take many seconds to redraw the largest grid, or to update a selection - # rectangle during a drag. I also tried 200.0 but that was way too large. - # Since some users have slower machines, I'll be gentle and put 90.0 here. - # Someday we need to fix the alg to be quadratic by teaching this code - # (and the cookie baker code too) about the eyespace clipping planes. - # Once we support user prefs, this should be one of them (if the alg is - # not fixed by then). - - MAX_GRID_SCALE = 90.0 - if scale > MAX_GRID_SCALE: - scale = MAX_GRID_SCALE - - if latticeType == 'DIAMOND': - cellX = cellY = cellZ = drawing_globals.DiGridSp - elif latticeType == 'LONSDALEITE': - cellX = drawing_globals.XLen - cellY = drawing_globals.YLen - cellZ = drawing_globals.ZLen - - bblo = center - scale - bbhi = center + scale - i1 = int(floor(bblo[0]/cellX)) - i2 = int(ceil(bbhi[0]/cellX)) - j1 = int(floor(bblo[1]/cellY)) - j2 = int(ceil(bbhi[1]/cellY)) - k1 = int(floor(bblo[2]/cellZ)) - k2 = int(ceil(bbhi[2]/cellZ)) - glPushMatrix() - glTranslate(i1*cellX, j1*cellY, k1*cellZ) - for i in range(i1, i2): - glPushMatrix() - for j in range(j1, j2): - glPushMatrix() - for k in range(k1, k2): - if latticeType == 'DIAMOND': - glCallList(drawing_globals.diamondGridList) - else: - glCallList(drawing_globals.lonsGridList) - glTranslate(0.0, 0.0, cellZ) - glPopMatrix() - glTranslate(0.0, cellY, 0.0) - glPopMatrix() - glTranslate(cellX, 0.0, 0.0) - glPopMatrix() - glEnable(GL_LIGHTING) - - #drawCubeCell(V(1, 0, 0)) - return - - -def drawrectangle(pt1, pt2, rt, up, color): - """ - Draws a (hollow) rectangle outline of the given I{color}. - - @param pt1: First corner of the rectangle. - @type pt1: Point - - @param pt1: Opposite corner of the rectangle. - @type pt1: Point - - @param rt: Right vector of the glpane. - @type rt: Unit vector - - @param up: Right vector of the glpane. - @type up: Unit vector - - @param color: Color - @type color: color - """ - glColor3f(color[0], color[1], color[2]) - glDisable(GL_LIGHTING) - c2 = pt1 + rt * Numeric.dot(rt, pt2 - pt1) - c3 = pt1 + up * Numeric.dot(up, pt2 - pt1) - glBegin(GL_LINE_LOOP) - glVertex(pt1[0], pt1[1], pt1[2]) - glVertex(c2[0], c2[1], c2[2]) - glVertex(pt2[0], pt2[1], pt2[2]) - glVertex(c3[0], c3[1], c3[2]) - glEnd() - glEnable(GL_LIGHTING) - -#bruce & wware 060404: drawRubberBand apparently caused bug 1814 (Zoom Tool hanging some Macs, requiring power toggle) -# so it should not be used until debugged. Use drawrectangle instead. (For an example of how to translate between them, -# see ZoomMode.py rev 1.32 vs 1.31 in ViewCVS.) That bug was only repeatable on Bruce's & Will's iMacs G5. -# -# Bruce's speculations (not very definite; no evidence for them at all) about possible causes of the bug in drawRubberBand: -# - use of glVertex instead of glVertex3f or so??? This seems unlikely, since we have other uses of it, -# but perhaps they work due to different arg types. -# - use of GL_LINE_LOOP within OpenGL xor mode, and bugs in some OpenGL drivers?? I didn't check whether cookieMode does this too. -##def drawRubberBand(pt1, pt2, c2, c3, color): -## """Huaicai: depth test should be disabled to make the xor work """ -## glBegin(GL_LINE_LOOP) -## glVertex(pt1[0],pt1[1],pt1[2]) -## glVertex(c2[0],c2[1],c2[2]) -## glVertex(pt2[0],pt2[1],pt2[2]) -## glVertex(c3[0],c3[1],c3[2]) -## glEnd() -## return - - -# Wrote drawbrick for the Linear Motor. Mark [2004-10-10] -def drawbrick(color, center, axis, l, h, w, opacity = 1.0): - - if len(color) == 3: - color = (color[0], color[1], color[2], opacity) - - if opacity != 1.0: - glDepthMask(GL_FALSE) - glEnable(GL_BLEND) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - - - apply_material(color) - glPushMatrix() - glTranslatef(center[0], center[1], center[2]) - - ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes - ## display problem on some platforms - angle = -acos(axis[2])*180.0/pi - if (axis[2]*axis[2] >= 1.0): - glRotate(angle, 0.0, 1.0, 0.0) - else: - glRotate(angle, axis[1], -axis[0], 0.0) - - - - glScale(h, w, l) - #bruce 060302 revised the contents of solidCubeList while fixing bug 1595 - glCallList(drawing_globals.solidCubeList) - - if opacity != 1.0: - glDisable(GL_BLEND) - glDepthMask(GL_TRUE) - - glPopMatrix() - return - -def drawLineLoop(color,lines, width = 1): - glDisable(GL_LIGHTING) - glColor3fv(color) - glLineWidth(width) - glBegin(GL_LINE_LOOP) - for v in lines: - glVertex3fv(v) - glEnd() - glEnable(GL_LIGHTING) - #reset the glLineWidth to 1 - if width!=1: - glLineWidth(1) - return - - -def drawlinelist(color,lines): - glDisable(GL_LIGHTING) - glColor3fv(color) - glBegin(GL_LINES) - for v in lines: - glVertex3fv(v) - glEnd() - glEnable(GL_LIGHTING) - return - -cubeLines = A([[-1,-1,-1], [-1,-1, 1], - [-1, 1,-1], [-1, 1, 1], - [ 1,-1,-1], [ 1,-1, 1], - [ 1, 1,-1], [ 1, 1, 1], - - [-1,-1,-1], [-1, 1,-1], - [-1,-1, 1], [-1, 1, 1], - [ 1,-1,-1], [ 1, 1,-1], - [ 1,-1, 1], [ 1, 1, 1], - - [-1,-1,-1], [ 1,-1,-1], - [-1,-1, 1], [ 1,-1, 1], - [-1, 1,-1], [ 1, 1,-1], - [-1, 1, 1], [ 1, 1, 1]]) - -def drawCubeCell(color): - vs = [[sp0, sp0, sp0], [sp4, sp0, sp0], [sp4, sp4, sp0], [sp0, sp4, sp0], - [sp0, sp0, sp4], [sp4, sp0, sp4], [sp4, sp4, sp4], [sp0, sp4, sp4]] - - glDisable(GL_LIGHTING) - glColor3fv(color) - glBegin(GL_LINE_LOOP) - for ii in range(4): - glVertex3fv(vs[ii]) - glEnd() - - glBegin(GL_LINE_LOOP) - for ii in range(4, 8): - glVertex3fv(vs[ii]) - glEnd() - - glBegin(GL_LINES) - for ii in range(4): - glVertex3fv(vs[ii]) - glVertex3fv(vs[ii+4]) - glEnd() - - glEnable(GL_LIGHTING) - return - -def drawPlane(color, w, h, textureReady, opacity, SOLID=False, pickCheckOnly=False): - '''Draw polygon with size of <w>*<h> and with color <color>. Optionally, it could be texuture mapped, translucent. - @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose.''' - vs = [[-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0]] - vt = [[0.0, 1.0], [0.0, 0.0], [1.0, 0.0], [1.0, 1.0]] - - glDisable(GL_LIGHTING) - glColor4fv(list(color) + [opacity]) - - glPushMatrix() - glScalef(w, h, 1.0) - - if SOLID: - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - else: - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) - glDisable(GL_CULL_FACE) - - if not pickCheckOnly: - glDepthMask(GL_FALSE) # This makes sure translucent object will not occlude another translucent object - glEnable(GL_BLEND) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - - if textureReady: - glEnable(GL_TEXTURE_2D) - - glBegin(GL_QUADS) - for ii in range(len(vs)): - t = vt[ii]; v = vs[ii] - if textureReady: - glTexCoord2fv(t) - glVertex3fv(v) - glEnd() - - if not pickCheckOnly: - if textureReady: - glDisable(GL_TEXTURE_2D) - - glDisable(GL_BLEND) - glDepthMask(GL_TRUE) - - glEnable(GL_CULL_FACE) - if not SOLID: - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - - glPopMatrix() - glEnable(GL_LIGHTING) - return - -def drawFullWindow(vtColors): - """Draw gradient background color. - <vtColors> is a 4 element list specifying colors for the - left-down, right-down, right-up, left-up window corners. - To draw the full window, the modelview and projection should be set in identity. - """ - from utilities.constants import GL_FAR_Z - glDisable(GL_LIGHTING) - - glBegin(GL_QUADS) - glColor3fv(vtColors[0]) - glVertex3f(-1, -1, GL_FAR_Z) - glColor3fv(vtColors[1]) - glVertex3f(1, -1, GL_FAR_Z) - glColor3fv(vtColors[2]) - glVertex3f(1, 1, GL_FAR_Z) - glColor3fv(vtColors[3]) - glVertex3f(-1, 1, GL_FAR_Z) - glEnd() - - glEnable(GL_LIGHTING) - return - -def drawtext(text, color, origin, point_size, glpane): - """ - """ - # see also: _old_code_for_drawing_text() - - if not text: - return - - glDisable(GL_LIGHTING) - glDisable(GL_DEPTH_TEST) - - from PyQt4.Qt import QFont, QString, QColor - font = QFont( QString("Helvetica"), point_size) - #glpane.qglColor(QColor(75, 75, 75)) - from widgets.widget_helpers import RGBf_to_QColor - glpane.qglColor(RGBf_to_QColor(color)) - glpane.renderText(origin[0], origin[1], origin[2], QString(text), font) - - glEnable(GL_DEPTH_TEST) - glEnable(GL_LIGHTING) - return - -##Junk code### -## The following code used to be for drawing text on a QGLWidget -- -# some of it might still be useful if integrated into drawtext() above -# [moved here from elementColors.py and slightly cleaned up by bruce 080223] -def _old_code_for_drawing_text(glpane): - self = glpane - glDisable(GL_LIGHTING) - glDisable(GL_DEPTH_TEST) - self.qglColor(QColor(0, 0, 0)) - font = QFont( QString("Times"), 10) - text = QString('Rvdw = ' + str(self.rad)) - fontMecs = QFontMetrics(font) - strWd = fontMecs.width(text) - strHt = fontMecs.height() - w = self.width/2 - strWd/2 - h = self.height - strHt/2 - self.renderText(w, h, text, font) - glEnable(GL_DEPTH_TEST) - glEnable(GL_LIGHTING) - -def drawcylinder_wireframe(color, end1, end2, radius): #bruce 060608 - "draw a wireframe cylinder (not too pretty, definitely could look nicer, but it works)" - # display polys as their edges (see drawer.py's drawwirecube or Jig.draw for related code) - # (probably we should instead create a suitable lines display list, - # or even use a wire-frame-like texture so various lengths work well) - glPolygonMode(GL_FRONT, GL_LINE) - glPolygonMode(GL_BACK, GL_LINE) - glDisable(GL_LIGHTING) - glDisable(GL_CULL_FACE) # this makes motors look too busy, but without it, they look too weird (which seems worse) - try: - drawcylinder(color, end1, end2, radius) ##k not sure if this color will end up controlling the edge color; we hope it will - except: - debug.print_compact_traceback("bug, ignored: ") - # the following assumes that we are never called as part of a jig's drawing method, - # or it will mess up drawing of the rest of the jig if it's disabled - glEnable(GL_CULL_FACE) - glEnable(GL_LIGHTING) - glPolygonMode(GL_FRONT, GL_FILL) - glPolygonMode(GL_BACK, GL_FILL) # could probably use GL_FRONT_AND_BACK - return - -def drawsurface_wireframe(color, pos, radius, tm, nm): - glPolygonMode(GL_FRONT, GL_LINE) - glPolygonMode(GL_BACK, GL_LINE) - glDisable(GL_LIGHTING) - glDisable(GL_CULL_FACE) - try: - drawsurface(color, pos, radius, tm, nm) - except: - debug.print_compact_traceback("bug, ignored: ") - glEnable(GL_CULL_FACE) - glEnable(GL_LIGHTING) - glPolygonMode(GL_FRONT, GL_FILL) - glPolygonMode(GL_BACK, GL_FILL) - return - -def renderSurface(surfaceEntities, surfaceNormals): - ####@@@@ bruce 060927 comments: - # - The color needs to come before the vertex. I fixed that, but left a debug_pref that can change it - # so you can see the effect of that bug before it was fixed. (Same for the normal, but it already did come before.) - # - I suspect normals are not used (when nc > 0) due to lighting being off. But if it's on, colors are not used. - # I saw that problem before, and we had to use apply_material instead, to set color; I'm not sure why, - # it might just be due to specific OpenGL settings we make for other purposes. So I'll use drawer.apply_material(color) - # (again with a debug pref to control that). - # The effect of the default debug_pref settings is that it now works properly with color -- but only for the 2nd chunk, - # if you create two, and not at all if you create only one. I don't know why it doesn't work for the first chunk. - (entityIndex, surfacePoints, surfaceColors) = surfaceEntities - e0 = entityIndex[0] - n = len(e0) - nc = len(surfaceColors) - if 1: - ### bruce 060927 debug code; when done debugging, we can change them to constants & simplify the code that uses them. - from utilities.debug_prefs import debug_pref, Choice_boolean_True, Choice_boolean_False - disable_lighting = debug_pref("surface: disable lighting?", Choice_boolean_False) - if nc: - color_first = debug_pref("surface: color before vertex?", Choice_boolean_True) - use_apply_material = debug_pref("surface: use apply_material?", Choice_boolean_True) - ## old code was equivalent to disable_lighting = (nc > 0) - def use_color(color): #bruce 060927 split this out, so we can change how we apply color in a single place in the code - if use_apply_material: - apply_material(color) # This makes the colors visible even when lighting is enabled. - else: - glColor3fv(color) # Old code did this. These colors are only visible when lighting is not enabled. - return - def onevert(vertex_index): #bruce 060927 split this out, for code clarity, and so debug prefs are used in only one place - glNormal3fv(surfaceNormals[vertex_index]) - if nc > 0 and color_first: use_color(surfaceColors[vertex_index]) # this needs to be done before glVertex3fv - glVertex3fv(surfacePoints[vertex_index]) - if nc > 0 and not color_first: use_color(surfaceColors[vertex_index]) # old code did it here -- used wrong colors sometimes - return - ## if nc > 0 : glDisable(GL_LIGHTING) - if disable_lighting: glDisable(GL_LIGHTING) - if n == 3: - glBegin(GL_TRIANGLES) - for entity in entityIndex: - onevert(entity[0]) - onevert(entity[1]) - onevert(entity[2]) - glEnd() - else: - glBegin(GL_QUADS) - for entity in entityIndex: - onevert(entity[0]) - onevert(entity[1]) - onevert(entity[2]) - onevert(entity[3]) - glEnd() - if disable_lighting: glEnable(GL_LIGHTING) - return - -# end diff --git a/cad/src/graphics/drawing/drawers.py b/cad/src/graphics/drawing/drawers.py new file mode 100755 index 000000000..e3cf5460f --- /dev/null +++ b/cad/src/graphics/drawing/drawers.py @@ -0,0 +1,1158 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +drawers.py - Miscellaneous drawing functions that are not used as primitives. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +import graphics.drawing.drawing_globals as drawing_globals +from graphics.drawing.gl_lighting import apply_material + +try: + from OpenGL.GLE import glePolyCone, gleGetNumSides, gleSetNumSides +except: + print "GLE module can't be imported. Now trying _GLE" + from OpenGL._GLE import glePolyCone, gleGetNumSides, gleSetNumSides + +# Check if the gleGet/SetNumSides function is working on this install, and if +# not, alias it to an effective no-op. Checking method is as recommended in +# an OpenGL exception reported by Brian [070622]: +# OpenGL.error.NullFunctionError: Attempt to call an +# undefined function gleGetNumSides, check for +# bool(gleGetNumSides) before calling +# The underlying cause of this (described by Brian) is that the computer's OpenGL +# has the older gleGetNumSlices (so it supports the functionality), but PyOpenGL +# binds (only) to the newer gleGetNumSides. Given the PyOpenGL we're using, +# there's no way to access gleGetNumSlices, but in the future we might patch it +# to let us do that when this happens. I [bruce 070629] think Brian said this is +# only an issue on Macs. +if not bool(gleGetNumSides): + print "fyi: gleGetNumSides is not supported by the OpenGL pre-installed on this computer." + gleGetNumSides = int + gleSetNumSides = int + +try: + from OpenGL.GL import glScale +except: + # The installed version of OpenGL requires argument-typed glScale calls. + from OpenGL.GL import glScalef as glScale + +from OpenGL.GL import glScalef + # Note: this is NOT redundant with the above import of glScale -- + # without it, displaying an ESP Image gives a NameError traceback + # and doesn't work. [Fixed by bruce 070703; bug caught by Eric M using + # PyChecker; bug introduced sometime after A9.1 went out.] + +# == + +def drawCircle(color, center, radius, normal): + """Scale, rotate/translate the unit circle properly """ + glMatrixMode(GL_MODELVIEW) + glPushMatrix() + glColor3fv(color) + glDisable(GL_LIGHTING) + + glTranslatef(center[0], center[1], center[2]) + rQ = Q(V(0, 0, 1), normal) + rotAngle = rQ.angle*180.0/pi + + #This may cause problems as proved before in Linear motor display. + #rotation around (0, 0, 0) + #if vlen(V(rQ.x, rQ.y, rQ.z)) < 0.00005: + # rQ.x = 1.0 + + glRotatef(rotAngle, rQ.x, rQ.y, rQ.z) + glScalef(radius, radius, 1.0) + glCallList(drawing_globals.circleList) + glEnable(GL_LIGHTING) + glPopMatrix() + return + +def drawFilledCircle(color, center, radius, normal): + """ + Scale, rotate/translate the unit circle properly. + Added a filled circle variant, piotr 080405 + """ + glMatrixMode(GL_MODELVIEW) + glPushMatrix() + glColor3fv(color) + glDisable(GL_LIGHTING) + + glTranslatef(center[0], center[1], center[2]) + rQ = Q(V(0, 0, 1), normal) + rotAngle = rQ.angle*180.0/pi + + #This may cause problems as proved before in Linear motor display. + #rotation around (0, 0, 0) + #if vlen(V(rQ.x, rQ.y, rQ.z)) < 0.00005: + # rQ.x = 1.0 + + glRotatef(rotAngle, rQ.x, rQ.y, rQ.z) + glScalef(radius, radius, 1.0) + glCallList(drawing_globals.filledCircleList) + glEnable(GL_LIGHTING) + glPopMatrix() + return + +def drawLinearArrows(longScale): + glCallList(drawing_globals.linearArrowList) + newPos = drawing_globals.halfHeight*longScale + glPushMatrix() + glTranslate(0.0, 0.0, -newPos) + glCallList(drawing_globals.linearArrowList) + glPopMatrix() + glPushMatrix() + glTranslate(0.0, 0.0, newPos -2.0*drawing_globals.halfEdge) + glCallList(drawing_globals.linearArrowList) + glPopMatrix() + return + +def drawLinearSign(color, center, axis, l, h, w): + """Linear motion sign on the side of squa-linder """ + depthOffset = 0.005 + glPushMatrix() + glColor3fv(color) + glDisable(GL_LIGHTING) + glTranslatef(center[0], center[1], center[2]) + + ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes + ## display problem on some platforms + angle = -acos(axis[2])*180.0/pi + if (axis[2]*axis[2] >= 1.0): + glRotate(angle, 0.0, 1.0, 0.0) + else: + glRotate(angle, axis[1], -axis[0], 0.0) + + glPushMatrix() + glTranslate(h/2.0 + depthOffset, 0.0, 0.0) + glPushMatrix() + glScale(1.0, 1.0, l) + glCallList(drawing_globals.linearLineList) + glPopMatrix() + if l < 2.6: + sl = l/2.7 + glScale(1.0, sl, sl) + if w < 1.0: + glScale(1.0, w, w) + drawLinearArrows(l) + glPopMatrix() + + glPushMatrix() + glTranslate(-h/2.0 - depthOffset, 0.0, 0.0) + glRotate(180.0, 0.0, 0.0, 1.0) + glPushMatrix() + glScale(1.0, 1.0, l) + glCallList(drawing_globals.linearLineList) + glPopMatrix() + if l < 2.6: + glScale(1.0, sl, sl) + if w < 1.0: + glScale(1.0, w, w) + drawLinearArrows(l) + glPopMatrix() + + glPushMatrix() + glTranslate(0.0, w/2.0 + depthOffset, 0.0) + glRotate(90.0, 0.0, 0.0, 1.0) + glPushMatrix() + glScale(1.0, 1.0, l) + glCallList(drawing_globals.linearLineList) + glPopMatrix() + if l < 2.6: + glScale(1.0, sl, sl) + if w < 1.0: + glScale(1.0, w, w) + drawLinearArrows(l) + glPopMatrix() + + glPushMatrix() + glTranslate(0.0, -w/2.0 - depthOffset, 0.0 ) + glRotate(-90.0, 0.0, 0.0, 1.0) + glPushMatrix() + glScale(1.0, 1.0, l) + glCallList(drawing_globals.linearLineList) + glPopMatrix() + if l < 2.6: + glScale(1.0, sl, sl) + if w < 1.0: + glScale(1.0, w, w) + drawLinearArrows(l) + glPopMatrix() + + glEnable(GL_LIGHTING) + glPopMatrix() + return + +def drawRotateSign(color, pos1, pos2, radius, rotation = 0.0): + """Rotate sign on top of the caps of the cylinder """ + glPushMatrix() + glColor3fv(color) + vec = pos2-pos1 + axis = norm(vec) + glTranslatef(pos1[0], pos1[1], pos1[2]) + + ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes + ## display problem on some platforms + angle = -acos(axis[2])*180.0/pi + if (axis[2]*axis[2] >= 1.0): + glRotate(angle, 0.0, 1.0, 0.0) + else: + glRotate(angle, axis[1], -axis[0], 0.0) + glRotate(rotation, 0.0, 0.0, 1.0) #bruce 050518 + glScale(radius,radius,Numeric.dot(vec,vec)**.5) + + glLineWidth(2.0) + glDisable(GL_LIGHTING) + glCallList(drawing_globals.rotSignList) + glEnable(GL_LIGHTING) + glLineWidth(1.0) + + glPopMatrix() + return + +def drawArrowHead(color, + basePoint, + drawingScale, + unitBaseVector, + unitHeightVector): + + + + arrowBase = drawingScale * 0.08 + arrowHeight = drawingScale * 0.12 + glDisable(GL_LIGHTING) + glPushMatrix() + glTranslatef(basePoint[0],basePoint[1],basePoint[2]) + point1 = V(0, 0, 0) + point1 = point1 + unitHeightVector * arrowHeight + point2 = unitBaseVector * arrowBase + point3 = - unitBaseVector * arrowBase + #Draw the arrowheads as filled triangles + glColor3fv(color) + glBegin(GL_POLYGON) + glVertex3fv(point1) + glVertex3fv(point2) + glVertex3fv(point3) + glEnd() + glPopMatrix() + glEnable(GL_LIGHTING) + +def drawSineWave(color, startPoint, endPoint, numberOfPoints, phaseAngle): + """ + """ + pass + +def drawPolyLine(color, points): + '''Draws a poly line passing through the given list of points''' + glDisable(GL_LIGHTING) + glColor3fv(color) + glBegin(GL_LINE_STRIP) + for v in points: + glVertex3fv(v) + glEnd() + + glEnable(GL_LIGHTING) + return + +def drawPoint(color, + point, + pointSize = 3.0, + isRound = True): + """ + Draw a point using GL_POINTS. + @param point: The x,y,z coordinate array/ vector of the point + @type point: A or V + @param pointSize: The point size to be used by glPointSize + @type pointSize: float + @param isRound: If True, the point will be drawn round otherwise square + @type isRound: boolean + """ + glDisable(GL_LIGHTING) + glColor3fv(color) + glPointSize(float(pointSize)) + if isRound: + glEnable(GL_POINT_SMOOTH) + glBegin(GL_POINTS) + glVertex3fv(point) + glEnd() + if isRound: + glDisable(GL_POINT_SMOOTH) + + glEnable(GL_LIGHTING) + if pointSize != 1.0: + glPointSize(1.0) + return + +def drawLineCube(color, pos, radius): + vtIndices = [0,1,2,3, 0,4,5,1, 5,4,7,6, 6,7,3,2] + glEnableClientState(GL_VERTEX_ARRAY) + #bruce 051117 revised this + glVertexPointer(3, GL_FLOAT, 0, drawing_globals.flatCubeVertices) + #grantham 20051213 observations, reported/paraphrased by bruce 051215: + # - should verify PyOpenGL turns Python float (i.e. C double) into C float + # for OpenGL's GL_FLOAT array element type. + # - note that GPUs are optimized for DrawElements types GL_UNSIGNED_INT and GL_UNSIGNED_SHORT. + glDisable(GL_LIGHTING) + glColor3fv(color) + glPushMatrix() + glTranslatef(pos[0], pos[1], pos[2]) + glScale(radius,radius,radius) + glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices) + #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[4]) + #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[8]) + #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[12]) + glPopMatrix() + glEnable(GL_LIGHTING) + glDisableClientState(GL_VERTEX_ARRAY) + return + +def drawwirecube(color, pos, radius, lineWidth=3.0): + glPolygonMode(GL_FRONT, GL_LINE) + glPolygonMode(GL_BACK, GL_LINE) + glDisable(GL_LIGHTING) + glDisable(GL_CULL_FACE) + glColor3fv(color) + glPushMatrix() + glTranslatef(pos[0], pos[1], pos[2]) + if type(radius) == type(1.0): + glScale(radius,radius,radius) + else: + glScale(radius[0], radius[1], radius[2]) + glLineWidth(lineWidth) + glCallList(drawing_globals.lineCubeList) + glLineWidth(1.0) ## restore its state + glPopMatrix() + glEnable(GL_CULL_FACE) + glEnable(GL_LIGHTING) + glPolygonMode(GL_FRONT, GL_FILL) + glPolygonMode(GL_BACK, GL_FILL) #bruce 050729 to help fix bug 835 or related bugs + return + +def drawwirebox(color, pos, len): + glPolygonMode(GL_FRONT, GL_LINE) + glPolygonMode(GL_BACK, GL_LINE) + glDisable(GL_LIGHTING) + glDisable(GL_CULL_FACE) + glColor3fv(color) + glPushMatrix() + glTranslatef(pos[0], pos[1], pos[2]) + glScale(len[0], len[1], len[2]) + glCallList(drawing_globals.CubeList) + glPopMatrix() + glEnable(GL_CULL_FACE) + glEnable(GL_LIGHTING) + glPolygonMode(GL_FRONT, GL_FILL) + glPolygonMode(GL_BACK, GL_FILL) #bruce 050729 to help fix bug 835 or related bugs + return + +def segstart(color): + glDisable(GL_LIGHTING) + glColor3fv(color) + glBegin(GL_LINES) + return + +def drawsegment(pos1,pos2): + glVertex3fv(pos1) + glVertex3fv(pos2) + return + +def segend(): + glEnd() + glEnable(GL_LIGHTING) + return + +def drawAxis(color, pos1, pos2, width = 2): #Ninad 060907 + '''Draw chunk or jig axis''' + #ninad060907 Note that this is different than draw + #I may need this function to draw axis line. see its current implementation in + #branch "ninad_060908_drawAxis_notAsAPropOfObject" + glDisable(GL_LIGHTING) + glColor3fv(color) + glLineStipple(3, 0x1C47) # dash-dot-dash line + glEnable(GL_LINE_STIPPLE) + if width != 1: + glLineWidth(width) + glBegin(GL_LINES) + glVertex(pos1[0], pos1[1], pos1[2]) + glVertex(pos2[0], pos2[1], pos2[2]) + glEnd() + if width != 1: + glLineWidth(1.0) # restore default state + glDisable(GL_LINE_STIPPLE) + glEnable(GL_LIGHTING) + return + +def drawaxes(n,point,coloraxes=False, dashEnabled = False): + + n *= 0.5 + glPushMatrix() + glTranslate(point[0], point[1], point[2]) + glDisable(GL_LIGHTING) + + if coloraxes: + glColor3f(red[0], red[1], red[2]) + if dashEnabled: + #ninad060921 Note that we will only support dotted origin axis + #(hidden lines)but not POV axis. (as it could be annoying) + glLineStipple(5, 0xAAAA) + glEnable(GL_LINE_STIPPLE) + glDisable(GL_DEPTH_TEST) + else: + glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) + + glBegin(GL_LINES) + glVertex(n,0,0) + glVertex(-n,0,0) + glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) + glVertex(0,n,0) + glVertex(0,-n,0) + if coloraxes: glColor3f(blue[0], blue[1], blue[2]) + else: glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) + glVertex(0,0,n) + glVertex(0,0,-n) + glEnd() + + if coloraxes: + if dashEnabled: + glDisable(GL_LINE_STIPPLE) + glEnable(GL_DEPTH_TEST) + + glEnable(GL_LIGHTING) + glPopMatrix() + return + +def drawOriginAsSmallAxis(scale, origin, dashEnabled = False): + """ + Draws a small wireframe version of the origin. It is rendered as a + 3D point at (0, 0, 0) with 3 small axes extending from it in the positive + X, Y, Z directions. + """ + #Perhaps we should split this method into smaller methods? ninad060920 + #Notes: + #1. drawing arrowheads implemented on 060918 + #2. ninad060921 Show the origin axes as dotted if behind the mode. + #3. ninad060922 The arrow heads are drawn as wireframe cones if behind the object + # the arrowhead size is slightly smaller (otherwise some portion of the + # the wireframe arrow shows up! + #3.Making origin non-zoomable is acheived by replacing + #hardcoded 'n' with glpane's scale - ninad060922 + + #ninad060922 in future , the following could be user preferences. + if (dashEnabled): + dashShrinkage = 0.9 + else: + dashShrinkage=1 + x1, y1, z1 = scale * 0.01, scale * 0.01, scale * 0.01 + xEnd, yEnd, zEnd = scale * 0.04, scale * 0.09, scale * 0.025 + arrowBase = scale * 0.0075 * dashShrinkage + arrowHeight = scale * 0.035 * dashShrinkage + lineWidth = 1.0 + + glPushMatrix() + + glTranslate(origin[0], origin[1], origin[2]) + glDisable(GL_LIGHTING) + glLineWidth(lineWidth) + + gleNumSides = gleGetNumSides() + #Code to show hidden lines of the origin if some model obscures it ninad060921 + if dashEnabled: + glLineStipple(2, 0xAAAA) + glEnable(GL_LINE_STIPPLE) + glDisable(GL_DEPTH_TEST) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + gleSetNumSides(5) + else: + gleSetNumSides(10) + + glBegin(GL_LINES) + + #glColor3f(black) + glColor3fv(lightblue) + + #start draw a point at origin . + #ninad060922 is thinking about using GL_POINTS here + + glVertex(-x1, 0.0, 0.0) + glVertex( x1, 0.0, 0.0) + glVertex(0.0, -y1, 0.0) + glVertex(0.0, y1, 0.0) + glVertex(-x1, y1, z1) + glVertex( x1, -y1, -z1) + glVertex(x1, y1, z1) + glVertex(-x1, -y1, -z1) + glVertex(x1, y1, -z1) + glVertex(-x1, -y1, z1) + glVertex(-x1, y1, -z1) + glVertex(x1, -y1, z1) + #end draw a point at origin + + #start draw small origin axes + #glColor3fv(darkred) + glColor3fv(lightblue) + glVertex(xEnd, 0.0, 0.0) + glVertex( 0.0, 0.0, 0.0) + #glColor3f(darkgreen[0], darkgreen[1], darkgreen[2]) + glColor3fv(lightblue) + glVertex(0.0, yEnd, 0.0) + glVertex(0.0, 0.0, 0.0) + #glColor3f(blue[0], blue[1], blue[2]) + glColor3fv(lightblue) + glVertex(0.0, 0.0, zEnd) + glVertex(0.0, 0.0, 0.0) + glEnd() #end draw lines + glLineWidth(1.0) + + glPopMatrix() # end push matrix for drawing various lines in the origin and axes + + #start draw solid arrow heads for X , Y and Z axes + glPushMatrix() + glDisable(GL_CULL_FACE) + #glColor3fv(darkred) + glColor3fv(lightblue) + glTranslatef(xEnd, 0.0, 0.0) + glRotatef(90, 0.0, 1.0, 0.0) + + glePolyCone([[0, 0, -1], [0, 0, 0], [0, 0, arrowHeight], [0, 0, arrowHeight+1]], None, [arrowBase, arrowBase, 0, 0]) + + glPopMatrix() + + glPushMatrix() + #glColor3f(darkgreen) + glColor3fv(lightblue) + glTranslatef(0.0, yEnd, 0.0) + glRotatef(-90, 1.0, 0.0, 0.0) + + glePolyCone([[0, 0, -1], [0, 0, 0], [0, 0, arrowHeight], [0, 0, arrowHeight+1]], None, [arrowBase, arrowBase, 0, 0]) + + glPopMatrix() + + glPushMatrix() + glColor3fv(lightblue) + glTranslatef(0.0,0.0,zEnd) + + glePolyCone([[0, 0, -1], [0, 0, 0], [0, 0, arrowHeight], [0, 0, arrowHeight+1]], None, [arrowBase, arrowBase, 0, 0]) + + #Disable line stipple and Enable Depth test + if dashEnabled: + glLineStipple(1, 0xAAAA) + glDisable(GL_LINE_STIPPLE) + glEnable(GL_DEPTH_TEST) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + gleSetNumSides(gleNumSides) + glEnable(GL_CULL_FACE) + glEnable(GL_LIGHTING) + glPopMatrix() + #end draw solid arrow heads for X , Y and Z axes + return + +def findCell(pt, latticeType): + """Return the cell which contains the point <pt> """ + if latticeType == 'DIAMOND': + a = 0; cellX = cellY = cellZ = drawing_globals.DiGridSp + elif latticeType == 'LONSDALEITE': + a = 1 + cellX = drawing_globals.XLen + cellY = drawing_globals.YLen + cellZ = drawing_globals.ZLen + + i = int(floor(pt[0]/cellX)) + j = int(floor(pt[1]/cellY)) + k = int(floor(pt[2]/cellZ)) + + orig = V(i*cellX, j*cellY, k*cellZ) + + return orig, drawing_globals.sp1 + +def genDiam(bblo, bbhi, latticeType): + """Generate a list of possible atom positions within the area enclosed by (bblo, bbhi). + <Return>: A list of unit cells""" + if latticeType == 'DIAMOND': + a = 0; cellX = cellY = cellZ = drawing_globals.DiGridSp + elif latticeType == 'LONSDALEITE': + a = 1 + cellX = drawing_globals.XLen + cellY = drawing_globals.YLen + cellZ = drawing_globals.ZLen + + allCells = [] + for i in range(int(floor(bblo[0]/cellX)), + int(ceil(bbhi[0]/cellX))): + for j in range(int(floor(bblo[1]/cellY)), + int(ceil(bbhi[1]/cellY))): + for k in range(int(floor(bblo[2]/cellZ)), + int(ceil(bbhi[2]/cellZ))): + off = V(i*cellX, j*cellY, k*cellZ) + if a == 0: allCells += [drawing_globals.digrid + off] + elif a ==1: allCells += [drawing_globals.lonsEdges + off] + return allCells + + +def drawGrid(scale, center, latticeType): + """ + Construct the grid model and show as position references for cookies. + The model is build around "pov" and has size of 2*"scale" on each of + the (x, y, z) directions. + + @note: This should be optimized later. + For "scale = 200", it takes about 1479623 loops. ---Huaicai + """ + glDisable(GL_LIGHTING) + + # bruce 041201: + # Quick fix to prevent "hang" from drawing too large a cookieMode grid + # with our current cubic algorithm (bug 8). The constant 120.0 is still on + # the large side in terms of responsiveness -- on a 1.8GHz iMac G5 it can + # take many seconds to redraw the largest grid, or to update a selection + # rectangle during a drag. I also tried 200.0 but that was way too large. + # Since some users have slower machines, I'll be gentle and put 90.0 here. + # Someday we need to fix the alg to be quadratic by teaching this code + # (and the cookie baker code too) about the eyespace clipping planes. + # Once we support user prefs, this should be one of them (if the alg is + # not fixed by then). + + MAX_GRID_SCALE = 90.0 + if scale > MAX_GRID_SCALE: + scale = MAX_GRID_SCALE + + if latticeType == 'DIAMOND': + cellX = cellY = cellZ = drawing_globals.DiGridSp + elif latticeType == 'LONSDALEITE': + cellX = drawing_globals.XLen + cellY = drawing_globals.YLen + cellZ = drawing_globals.ZLen + + bblo = center - scale + bbhi = center + scale + i1 = int(floor(bblo[0]/cellX)) + i2 = int(ceil(bbhi[0]/cellX)) + j1 = int(floor(bblo[1]/cellY)) + j2 = int(ceil(bbhi[1]/cellY)) + k1 = int(floor(bblo[2]/cellZ)) + k2 = int(ceil(bbhi[2]/cellZ)) + glPushMatrix() + glTranslate(i1*cellX, j1*cellY, k1*cellZ) + for i in range(i1, i2): + glPushMatrix() + for j in range(j1, j2): + glPushMatrix() + for k in range(k1, k2): + if latticeType == 'DIAMOND': + glCallList(drawing_globals.diamondGridList) + else: + glCallList(drawing_globals.lonsGridList) + glTranslate(0.0, 0.0, cellZ) + glPopMatrix() + glTranslate(0.0, cellY, 0.0) + glPopMatrix() + glTranslate(cellX, 0.0, 0.0) + glPopMatrix() + glEnable(GL_LIGHTING) + + #drawCubeCell(V(1, 0, 0)) + return + + +def drawrectangle(pt1, pt2, rt, up, color): + """ + Draws a (hollow) rectangle outline of the given I{color}. + + @param pt1: First corner of the rectangle. + @type pt1: Point + + @param pt1: Opposite corner of the rectangle. + @type pt1: Point + + @param rt: Right vector of the glpane. + @type rt: Unit vector + + @param up: Right vector of the glpane. + @type up: Unit vector + + @param color: Color + @type color: color + """ + glColor3f(color[0], color[1], color[2]) + glDisable(GL_LIGHTING) + c2 = pt1 + rt * Numeric.dot(rt, pt2 - pt1) + c3 = pt1 + up * Numeric.dot(up, pt2 - pt1) + glBegin(GL_LINE_LOOP) + glVertex(pt1[0], pt1[1], pt1[2]) + glVertex(c2[0], c2[1], c2[2]) + glVertex(pt2[0], pt2[1], pt2[2]) + glVertex(c3[0], c3[1], c3[2]) + glEnd() + glEnable(GL_LIGHTING) + +#bruce & wware 060404: drawRubberBand apparently caused bug 1814 (Zoom Tool hanging some Macs, requiring power toggle) +# so it should not be used until debugged. Use drawrectangle instead. (For an example of how to translate between them, +# see ZoomMode.py rev 1.32 vs 1.31 in ViewCVS.) That bug was only repeatable on Bruce's & Will's iMacs G5. +# +# Bruce's speculations (not very definite; no evidence for them at all) about possible causes of the bug in drawRubberBand: +# - use of glVertex instead of glVertex3f or so??? This seems unlikely, since we have other uses of it, +# but perhaps they work due to different arg types. +# - use of GL_LINE_LOOP within OpenGL xor mode, and bugs in some OpenGL drivers?? I didn't check whether cookieMode does this too. +##def drawRubberBand(pt1, pt2, c2, c3, color): +## """Huaicai: depth test should be disabled to make the xor work """ +## glBegin(GL_LINE_LOOP) +## glVertex(pt1[0],pt1[1],pt1[2]) +## glVertex(c2[0],c2[1],c2[2]) +## glVertex(pt2[0],pt2[1],pt2[2]) +## glVertex(c3[0],c3[1],c3[2]) +## glEnd() +## return + + +# Wrote drawbrick for the Linear Motor. Mark [2004-10-10] +def drawbrick(color, center, axis, l, h, w, opacity = 1.0): + + if len(color) == 3: + color = (color[0], color[1], color[2], opacity) + + if opacity != 1.0: + glDepthMask(GL_FALSE) + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + + apply_material(color) + glPushMatrix() + glTranslatef(center[0], center[1], center[2]) + + ##Huaicai 1/17/05: To avoid rotate around (0, 0, 0), which causes + ## display problem on some platforms + angle = -acos(axis[2])*180.0/pi + if (axis[2]*axis[2] >= 1.0): + glRotate(angle, 0.0, 1.0, 0.0) + else: + glRotate(angle, axis[1], -axis[0], 0.0) + + + + glScale(h, w, l) + #bruce 060302 revised the contents of solidCubeList while fixing bug 1595 + glCallList(drawing_globals.solidCubeList) + + if opacity != 1.0: + glDisable(GL_BLEND) + glDepthMask(GL_TRUE) + + glPopMatrix() + return + +def drawLineLoop(color,lines, width = 1): + glDisable(GL_LIGHTING) + glColor3fv(color) + glLineWidth(width) + glBegin(GL_LINE_LOOP) + for v in lines: + glVertex3fv(v) + glEnd() + glEnable(GL_LIGHTING) + #reset the glLineWidth to 1 + if width!=1: + glLineWidth(1) + return + + +def drawlinelist(color,lines): + glDisable(GL_LIGHTING) + glColor3fv(color) + glBegin(GL_LINES) + for v in lines: + glVertex3fv(v) + glEnd() + glEnable(GL_LIGHTING) + return + +cubeLines = A([[-1,-1,-1], [-1,-1, 1], + [-1, 1,-1], [-1, 1, 1], + [ 1,-1,-1], [ 1,-1, 1], + [ 1, 1,-1], [ 1, 1, 1], + + [-1,-1,-1], [-1, 1,-1], + [-1,-1, 1], [-1, 1, 1], + [ 1,-1,-1], [ 1, 1,-1], + [ 1,-1, 1], [ 1, 1, 1], + + [-1,-1,-1], [ 1,-1,-1], + [-1,-1, 1], [ 1,-1, 1], + [-1, 1,-1], [ 1, 1,-1], + [-1, 1, 1], [ 1, 1, 1]]) + +def drawCubeCell(color): + sp0 = drawing_globals.sp0 + sp4 = drawing_globals.sp4 + vs = [[sp0, sp0, sp0], [sp4, sp0, sp0], [sp4, sp4, sp0], [sp0, sp4, sp0], + [sp0, sp0, sp4], [sp4, sp0, sp4], [sp4, sp4, sp4], [sp0, sp4, sp4]] + + glDisable(GL_LIGHTING) + glColor3fv(color) + glBegin(GL_LINE_LOOP) + for ii in range(4): + glVertex3fv(vs[ii]) + glEnd() + + glBegin(GL_LINE_LOOP) + for ii in range(4, 8): + glVertex3fv(vs[ii]) + glEnd() + + glBegin(GL_LINES) + for ii in range(4): + glVertex3fv(vs[ii]) + glVertex3fv(vs[ii+4]) + glEnd() + + glEnable(GL_LIGHTING) + return + +def drawPlane(color, w, h, textureReady, opacity, SOLID=False, pickCheckOnly=False): + '''Draw polygon with size of <w>*<h> and with color <color>. Optionally, it could be texuture mapped, translucent. + @pickCheckOnly This is used to draw the geometry only, used for OpenGL pick selection purpose.''' + vs = [[-0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.5, 0.5, 0.0]] + vt = [[0.0, 1.0], [0.0, 0.0], [1.0, 0.0], [1.0, 1.0]] + + glDisable(GL_LIGHTING) + glColor4fv(list(color) + [opacity]) + + glPushMatrix() + glScalef(w, h, 1.0) + + if SOLID: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + else: + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + glDisable(GL_CULL_FACE) + + if not pickCheckOnly: + glDepthMask(GL_FALSE) # This makes sure translucent object will not occlude another translucent object + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + if textureReady: + glEnable(GL_TEXTURE_2D) + + glBegin(GL_QUADS) + for ii in range(len(vs)): + t = vt[ii]; v = vs[ii] + if textureReady: + glTexCoord2fv(t) + glVertex3fv(v) + glEnd() + + if not pickCheckOnly: + if textureReady: + glDisable(GL_TEXTURE_2D) + + glDisable(GL_BLEND) + glDepthMask(GL_TRUE) + + glEnable(GL_CULL_FACE) + if not SOLID: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + + glPopMatrix() + glEnable(GL_LIGHTING) + return + +def drawFullWindow(vtColors): + """Draw gradient background color. + <vtColors> is a 4 element list specifying colors for the + left-down, right-down, right-up, left-up window corners. + To draw the full window, the modelview and projection should be set in identity. + """ + from utilities.constants import GL_FAR_Z + glDisable(GL_LIGHTING) + + glBegin(GL_QUADS) + glColor3fv(vtColors[0]) + glVertex3f(-1, -1, GL_FAR_Z) + glColor3fv(vtColors[1]) + glVertex3f(1, -1, GL_FAR_Z) + glColor3fv(vtColors[2]) + glVertex3f(1, 1, GL_FAR_Z) + glColor3fv(vtColors[3]) + glVertex3f(-1, 1, GL_FAR_Z) + glEnd() + + glEnable(GL_LIGHTING) + return + +def drawtext(text, color, origin, point_size, glpane): + """ + """ + # see also: _old_code_for_drawing_text() + + if not text: + return + + glDisable(GL_LIGHTING) + glDisable(GL_DEPTH_TEST) + + from PyQt4.Qt import QFont, QString, QColor + font = QFont( QString("Helvetica"), point_size) + #glpane.qglColor(QColor(75, 75, 75)) + from widgets.widget_helpers import RGBf_to_QColor + glpane.qglColor(RGBf_to_QColor(color)) + glpane.renderText(origin[0], origin[1], origin[2], QString(text), font) + + glEnable(GL_DEPTH_TEST) + glEnable(GL_LIGHTING) + return + +##Junk code### +## The following code used to be for drawing text on a QGLWidget -- +# some of it might still be useful if integrated into drawtext() above +# [moved here from elementColors.py and slightly cleaned up by bruce 080223] +def _old_code_for_drawing_text(glpane): + self = glpane + glDisable(GL_LIGHTING) + glDisable(GL_DEPTH_TEST) + self.qglColor(QColor(0, 0, 0)) + font = QFont( QString("Times"), 10) + text = QString('Rvdw = ' + str(self.rad)) + fontMecs = QFontMetrics(font) + strWd = fontMecs.width(text) + strHt = fontMecs.height() + w = self.width/2 - strWd/2 + h = self.height - strHt/2 + self.renderText(w, h, text, font) + glEnable(GL_DEPTH_TEST) + glEnable(GL_LIGHTING) + +def renderSurface(surfaceEntities, surfaceNormals): + ####@@@@ bruce 060927 comments: + # - The color needs to come before the vertex. I fixed that, but left a debug_pref that can change it + # so you can see the effect of that bug before it was fixed. (Same for the normal, but it already did come before.) + # - I suspect normals are not used (when nc > 0) due to lighting being off. But if it's on, colors are not used. + # I saw that problem before, and we had to use apply_material instead, to set color; I'm not sure why, + # it might just be due to specific OpenGL settings we make for other purposes. So I'll use drawer.apply_material(color) + # (again with a debug pref to control that). + # The effect of the default debug_pref settings is that it now works properly with color -- but only for the 2nd chunk, + # if you create two, and not at all if you create only one. I don't know why it doesn't work for the first chunk. + (entityIndex, surfacePoints, surfaceColors) = surfaceEntities + e0 = entityIndex[0] + n = len(e0) + nc = len(surfaceColors) + if 1: + ### bruce 060927 debug code; when done debugging, we can change them to constants & simplify the code that uses them. + from utilities.debug_prefs import debug_pref, Choice_boolean_True, Choice_boolean_False + disable_lighting = debug_pref("surface: disable lighting?", Choice_boolean_False) + if nc: + color_first = debug_pref("surface: color before vertex?", Choice_boolean_True) + use_apply_material = debug_pref("surface: use apply_material?", Choice_boolean_True) + ## old code was equivalent to disable_lighting = (nc > 0) + def use_color(color): #bruce 060927 split this out, so we can change how we apply color in a single place in the code + if use_apply_material: + apply_material(color) # This makes the colors visible even when lighting is enabled. + else: + glColor3fv(color) # Old code did this. These colors are only visible when lighting is not enabled. + return + def onevert(vertex_index): #bruce 060927 split this out, for code clarity, and so debug prefs are used in only one place + glNormal3fv(surfaceNormals[vertex_index]) + if nc > 0 and color_first: use_color(surfaceColors[vertex_index]) # this needs to be done before glVertex3fv + glVertex3fv(surfacePoints[vertex_index]) + if nc > 0 and not color_first: use_color(surfaceColors[vertex_index]) # old code did it here -- used wrong colors sometimes + return + ## if nc > 0 : glDisable(GL_LIGHTING) + if disable_lighting: glDisable(GL_LIGHTING) + if n == 3: + glBegin(GL_TRIANGLES) + for entity in entityIndex: + onevert(entity[0]) + onevert(entity[1]) + onevert(entity[2]) + glEnd() + else: + glBegin(GL_QUADS) + for entity in entityIndex: + onevert(entity[0]) + onevert(entity[1]) + onevert(entity[2]) + onevert(entity[3]) + glEnd() + if disable_lighting: glEnable(GL_LIGHTING) + return + +# end diff --git a/cad/src/graphics/drawing/drawing_globals.py b/cad/src/graphics/drawing/drawing_globals.py index 1f858cb5d..cccdf983b 100644 --- a/cad/src/graphics/drawing/drawing_globals.py +++ b/cad/src/graphics/drawing/drawing_globals.py @@ -38,3 +38,33 @@ use_c_renderer = use_c_renderer_default = False #bruce 060323 changed this to disconnect it from old pref setting use_c_renderer_prefs_key = "use_c_renderer_rev2" +#= + +import foundation.env as env #bruce 051126 +import utilities.EndUser as EndUser +import sys +import os + +if EndUser.getAlternateSourcePath() != None: + sys.path.append(os.path.join( EndUser.getAlternateSourcePath(), "experimental/pyrex-opengl")) +else: + sys.path.append("./experimental/pyrex-opengl") + +binPath = os.path.normpath(os.path.dirname(os.path.abspath(sys.argv[0])) + '/../bin') +if binPath not in sys.path: + sys.path.append(binPath) + +global quux_module_import_succeeded +try: + import quux + quux_module_import_succeeded = True + if "experimental" in os.path.dirname(quux.__file__): + # should never happen for end users, but if it does we want to print the warning + if env.debug() or not EndUser.enableDeveloperFeatures(): + print "debug: fyi: Using experimental version of C rendering code:", quux.__file__ +except: + use_c_renderer = False + quux_module_import_succeeded = False + if env.debug(): #bruce 060323 added condition + print "WARNING: unable to import C rendering code (quux module). Only Python rendering will be available." + pass diff --git a/cad/src/graphics/drawing/gl_buffers.py b/cad/src/graphics/drawing/gl_buffers.py new file mode 100755 index 000000000..5f11700d7 --- /dev/null +++ b/cad/src/graphics/drawing/gl_buffers.py @@ -0,0 +1,267 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +gl_buffers.py - OpenGL data buffer objects. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +# Vertex Buffer Object (VBO) and Index Buffer Object (IBO) support. +# For docs see http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml . + +# Notice that the ARB-suffixed versions of the OpenGL calls are used here. +# They're the ones with PyConvert ctypes wrappers, see: (the incomprehensible) +# http://pyopengl.sourceforge.net/ctypes/pydoc/OpenGL.GL.ARB.vertex_buffer_object.html +# The sources will do you more good. Also see "Array Handling Routines" here: +# http://pyopengl.sourceforge.net/documentation/opengl_diffs.html +# +from OpenGL.GL.ARB.vertex_buffer_object import glGenBuffersARB +from OpenGL.GL.ARB.vertex_buffer_object import glDeleteBuffersARB +# Patched versions. +from graphics.drawing.vbo_patch import glBufferDataARB, glBufferSubDataARB + +from OpenGL.raw.GL.ARB.vertex_buffer_object import glBindBufferARB # Unwrappered. + +class GLBufferObject(object): + """ + Buffer data in the graphics card's RAM space. + + Useful man pages for glBind, glBufferData, etc. for OpenGL 2.1 are at: + http://www.opengl.org/sdk/docs/man + PyOpenGL versions are at: + http://pyopengl.sourceforge.net/ctypes/pydoc/OpenGL.html + + 'target' is GL_ARRAY_BUFFER_ARB for vertex/normal buffers (VBO's), and + GL_ELEMENT_ARRAY_BUFFER_ARB for index buffers (IBO's.) + + 'data' is a numpy.array, with dtype=numpy.<datatype> . + + 'usage' is one of the hint constants, like GL_STATIC_DRAW. + """ + + def __init__(self, target, data, usage): + self.buffer = glGenBuffersARB(1) # Returns a numpy.ndarray for > 1. + self.target = target + + self.bind() + self.size = len(data) + + # Push the data over to Graphics card RAM. + glBufferDataARB(target, data, usage) + + self.unbind() + return + + def __del__(self): + """ + Delete a GLBufferObject. We don't expect that there will be a lot of + deleting of GLBufferObjects, but don't want them to sit on a lot of graphics + card RAM if we did. + """ + + # Since may be too late to clean up buffer objects through the Graphics + # Context while exiting, we trust that OpenGL or the device driver will + # deallocate the graphics card RAM when the Python process exits. + try: + glDeleteBuffersARB(1, [self.buffer]) + except: + ##print "Exception in glDeleteBuffersARB." + pass + return + + def bind(self): + """ + Have to bind a particular buffer to its target to fill or draw from it. + Don't forget to unbind() it! + """ + glBindBufferARB(self.target, self.buffer) + return + + def unbind(self): + """ + Unbind a buffer object from its target after use. + Failure to do this can kill Python on some graphics platforms! + """ + glBindBufferARB(self.target, 0) + return + + pass # End of class GLBufferObject. diff --git a/cad/src/graphics/drawing/gl_lighting.py b/cad/src/graphics/drawing/gl_lighting.py new file mode 100755 index 000000000..10d7d4f94 --- /dev/null +++ b/cad/src/graphics/drawing/gl_lighting.py @@ -0,0 +1,451 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +gl_lighting.py - Lights, materials, and special effects. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= +import graphics.drawing.drawing_globals as drawing_globals + +try: + from OpenGL.GL import glFog + from OpenGL.GL import glFogv # piotr 080515 +except: + # The installed version of OpenGL requires argument-typed glFog calls. + from OpenGL.GL import glFogf as glFog + from OpenGL.GL import glFogfv as glFogv + +# == + +# Helper functions for use by GL widgets wanting to set up lighting. + +#bruce 051212 made these from the code in GLPane which now calls them, so they can also be used in ThumbView + +# Default lights tuples (format is as used by setup_standard_lights; perhaps also assumed by other code). +#grantham 20051121 comment - Light should probably be a class. Right now, +# changing the behavior of lights requires changing a bunch of +# ambiguous tuples and tuple packing/unpacking. +#bruce 051212 moved this here from GLPane; maybe it belongs in prefs_constants instead? +# Note: I'm not sure whether this is the only place where this data is coded. +_default_lights = ((white, 0.1, 0.5, 0.5, -50, 70, 30, True), + (white, 0.1, 0.5, 0.5, -20, 20, 20, True), + (white, 0.1, 0.1, 0.1, 0, 0, 100, False)) + # for each of 3 lights, this stores ((r,g,b),a,d,s,x,y,z,e) + # revised format to include s,x,y,z. Mark 051202. + # revised format to include c (r,g,b). Mark 051204. + # Be sure to keep the lightColor prefs keys and _lights colors synchronized. + # Mark 051204. [a comment from when this was located in GLPane] + +def glprefs_data_used_by_setup_standard_lights( glprefs = None): #bruce 051212 + """ + Return a summary of the glprefs data used by setup_standard_lights, + for use in later deciding whether it needs to be called again due to changes in glprefs. + """ + if glprefs is None: + glprefs = drawing_globals.glprefs + pass + # This must be kept in sync with what's used by setup_standard_lights() . + return (glprefs.override_light_specular,) + +def setup_standard_lights( lights, glprefs = None): + """ + Set up lighting in the current GL context using the supplied "lights" tuple (in the format used by GLPane's prefs) + and the optional glprefs object (which defaults to drawing_globals.glprefs ). + Note: the glprefs data used can be summarized by the related function glprefs_data_used_by_setup_standard_lights (which see). + Warning: has side effects on GL_MODELVIEW matrix. + Note: If GL_NORMALIZE needs to be enabled, callers should do that themselves, + since this depends on what they will draw and might slow down drawing. + """ + #e not sure whether projection matrix also needs to be reset here [bruce 051212] + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + if glprefs is None: + glprefs = drawing_globals.glprefs + # note: whatever glprefs data is used below must also be present + # in the return value of glprefs_data_used_by_setup_standard_lights(). [bruce 051212] + + try: + # new code + (((r0,g0,b0),a0,d0,s0,x0,y0,z0,e0), \ + ( (r1,g1,b1),a1,d1,s1,x1,y1,z1,e1), \ + ( (r2,g2,b2),a2,d2,s2,x2,y2,z2,e2)) = lights + + # Great place for a print statement for debugging lights. Keep this. Mark 051204. [revised by bruce 051212] + #print "-------------------------------------------------------------" + #print "setup_standard_lights: lights[0]=", lights[0] + #print "setup_standard_lights: lights[1]=", lights[1] + #print "setup_standard_lights: lights[2]=", lights[2] + + glLightfv(GL_LIGHT0, GL_POSITION, (x0, y0, z0, 0)) + glLightfv(GL_LIGHT0, GL_AMBIENT, (r0*a0, g0*a0, b0*a0, 1.0)) + glLightfv(GL_LIGHT0, GL_DIFFUSE, (r0*d0, g0*d0, b0*d0, 1.0)) + if glprefs.override_light_specular is not None: + glLightfv(GL_LIGHT0, GL_SPECULAR, glprefs.override_light_specular) + else: + # grantham 20051121 - this should be a component on its own + # not replicating the diffuse color. + # Added specular (s0) as its own component. mark 051202. + glLightfv(GL_LIGHT0, GL_SPECULAR, (r0*s0, g0*s0, b0*s0, 1.0)) + glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0) + + glLightfv(GL_LIGHT1, GL_POSITION, (x1, y1, z1, 0)) + glLightfv(GL_LIGHT1, GL_AMBIENT, (r1*a1, g1*a1, b1*a1, 1.0)) + glLightfv(GL_LIGHT1, GL_DIFFUSE, (r1*d1, g1*d1, b1*d1, 1.0)) + if glprefs.override_light_specular is not None: + glLightfv(GL_LIGHT1, GL_SPECULAR, glprefs.override_light_specular) + else: + glLightfv(GL_LIGHT1, GL_SPECULAR, (r1*s1, g1*s1, b1*s1, 1.0)) + glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0) + + glLightfv(GL_LIGHT2, GL_POSITION, (x2, y2, z2, 0)) + glLightfv(GL_LIGHT2, GL_AMBIENT, (r2*a2, g2*a2, b2*a2, 1.0)) + glLightfv(GL_LIGHT2, GL_DIFFUSE, (r2*d2, g2*d2, b2*d2, 1.0)) + if glprefs.override_light_specular is not None: + glLightfv(GL_LIGHT2, GL_SPECULAR, glprefs.override_light_specular) + else: + glLightfv(GL_LIGHT2, GL_SPECULAR, (r2*s2, g2*s2, b2*s2, 1.0)) + glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 1.0) + + glEnable(GL_LIGHTING) + + if e0: + glEnable(GL_LIGHT0) + else: + glDisable(GL_LIGHT0) + + if e1: + glEnable(GL_LIGHT1) + else: + glDisable(GL_LIGHT1) + + if e2: + glEnable(GL_LIGHT2) + else: + glDisable(GL_LIGHT2) + except: + debug.print_compact_traceback("bug (worked around): setup_standard_lights reverting to old code, because: ") + # old code, used only to set up some sort of workable lighting in case of bugs + # (this is not necessarily using the same values as _default_lights; doesn't matter since never used unless there are bugs) + glLightfv(GL_LIGHT0, GL_POSITION, (-50, 70, 30, 0)) + glLightfv(GL_LIGHT0, GL_AMBIENT, (0.3, 0.3, 0.3, 1.0)) + glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.8, 0.8, 0.8, 1.0)) + glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0) + + glLightfv(GL_LIGHT1, GL_POSITION, (-20, 20, 20, 0)) + glLightfv(GL_LIGHT1, GL_AMBIENT, (0.4, 0.4, 0.4, 1.0)) + glLightfv(GL_LIGHT1, GL_DIFFUSE, (0.4, 0.4, 0.4, 1.0)) + glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0) + + glLightfv(GL_LIGHT2, GL_POSITION, (0, 0, 100, 0)) + glLightfv(GL_LIGHT2, GL_AMBIENT, (1.0, 1.0, 1.0, 1.0)) + glLightfv(GL_LIGHT2, GL_DIFFUSE, (1.0, 1.0, 1.0, 1.0)) + glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 1.0) + + glEnable(GL_LIGHTING) + + glEnable(GL_LIGHT0) + glEnable(GL_LIGHT1) + glDisable(GL_LIGHT2) + return # from setup_standard_lights + +# == + +def setup_fog(fog_start, fog_end, fog_color): + + glFog(GL_FOG_MODE, GL_LINEAR) + glFog(GL_FOG_START, fog_start) + glFog(GL_FOG_END, fog_end) + if len(fog_color) == 3: + fog_color = (fog_color[0], fog_color[1], fog_color[2], 1.0) + glFogv(GL_FOG_COLOR, fog_color) # piotr 080515 + +def enable_fog(): + glEnable(GL_FOG) + +def disable_fog(): + glDisable(GL_FOG) + +# == + +def apply_material(color): # grantham 20051121, renamed 20051201; revised by bruce 051126, 051203 (added specular_brightness), 051215 + """ + Set OpenGL material parameters based on the given color (length 3 or 4) and + the material-related prefs values in drawing_globals.glprefs. + """ + + #bruce 051215: make sure color is a tuple, and has length exactly 4, for all uses inside this function, + # assuming callers pass sequences of length 3 or 4. Needed because glMaterial requires four-component + # vector and PyOpenGL doesn't check. [If this is useful elsewhere, we can split it into a separate function.] + color = tuple(color) + if len(color) == 3: + color = color + (1.0,) # usual case + elif len(color) != 4: + # should never happen; if it does, this assert will always fail + assert len(color) in [3,4], "color tuples must have length 3 or 4, unlike %r" % (color,) + + glColor4fv(color) # For drawing lines with lighting disabled. + + if not drawing_globals.glprefs.enable_specular_highlights: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color) + # glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (0,0,0,1)) + return + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color) + + whiteness = drawing_globals.glprefs.specular_whiteness + brightness = drawing_globals.glprefs.specular_brightness + if whiteness == 1.0: + specular = (1.0, 1.0, 1.0, 1.0) # optimization + else: + if whiteness == 0.0: + specular = color # optimization + else: + # assume color[3] (alpha) is not passed or is always 1.0 + c1 = 1.0 - whiteness + specular = ( c1 * color[0] + whiteness, c1 * color[1] + whiteness, c1 * color[2] + whiteness, 1.0 ) + if brightness != 1.0: + specular = ( specular[0] * brightness, specular[1] * brightness, specular[2] * brightness, 1.0 ) + #e could optimize by merging this with above 3 cases (or, of course, by doing it in C, which we'll do eventually) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular) + + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, + drawing_globals.glprefs.specular_shininess) + return + +# == + +#russ 080515: We should find a better place for this! +def get_gl_info_string(glpane): # grantham 20051129 + """Return a string containing some useful information about the OpenGL implementation. + Use the GL context from the given QGLWidget glpane (by calling glpane.makeCurrent()). + """ + + glpane.makeCurrent() #bruce 070308 added glpane arg and makeCurrent call + + gl_info_string = '' + + gl_info_string += 'GL_VENDOR : "%s"\n' % glGetString(GL_VENDOR) + gl_info_string += 'GL_VERSION : "%s"\n' % glGetString(GL_VERSION) + gl_info_string += 'GL_RENDERER : "%s"\n' % glGetString(GL_RENDERER) + gl_info_string += 'GL_EXTENSIONS : "%s"\n' % glGetString(GL_EXTENSIONS) + + from utilities.debug_prefs import debug_pref, Choice_boolean_False + if debug_pref("get_gl_info_string call glAreTexturesResident?", Choice_boolean_False): + # Give a practical indication of how much video memory is available. + # Should also do this with VBOs. + + # I'm pretty sure this code is right, but PyOpenGL seg faults in + # glAreTexturesResident, so it's disabled until I can figure that + # out. [grantham] [bruce 070308 added the debug_pref] + + all_tex_in = True + tex_bytes = '\0' * (512 * 512 * 4) + tex_names = [] + tex_count = 0 + tex_names = glGenTextures(1024) + glEnable(GL_TEXTURE_2D) + while all_tex_in: + glBindTexture(GL_TEXTURE_2D, tex_names[tex_count]) + gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 512, 512, GL_RGBA, + GL_UNSIGNED_BYTE, tex_bytes) + tex_count += 1 + + glTexCoord2f(0.0, 0.0) + glBegin(GL_QUADS) + glVertex2f(0.0, 0.0) + glVertex2f(1.0, 0.0) + glVertex2f(1.0, 1.0) + glVertex2f(0.0, 1.0) + glEnd() + glFinish() + + residences = glAreTexturesResident(tex_names[:tex_count]) + all_tex_in = reduce(lambda a,b: a and b, residences) + # bruce 070308 sees this exception from this line: + # TypeError: reduce() arg 2 must support iteration + + glDisable(GL_TEXTURE_2D) + glDeleteTextures(tex_names) + + gl_info_string += "Could create %d 512x512 RGBA resident textures\n", tex_count + return gl_info_string diff --git a/cad/src/graphics/drawing/glprefs.py b/cad/src/graphics/drawing/glprefs.py new file mode 100755 index 000000000..f8e3f0d11 --- /dev/null +++ b/cad/src/graphics/drawing/glprefs.py @@ -0,0 +1,294 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +glprefs.py - Attributes from drawing-related prefs stored in the prefs db cache. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +import graphics.drawing.drawing_globals as drawing_globals +if drawing_globals.quux_module_import_succeeded: + import quux + +#= +import foundation.env as env #bruce 051126 + +# grantham 20051118; revised by bruce 051126 +class glprefs: + + def __init__(self): +## self.override_material_specular = None +## # set to 4-element sequence to override material specular component +## self.override_shininess = None +## # if exists, overrides shininess +## self.override_light_specular = None +## # set to 4-element sequence to override light specular component + import foundation.preferences as preferences #bruce 051126 KLUGE: make sure env.prefs exists (could use cleanup, but that's not trivial) + self.update() + + def update(self): #bruce 051126 added this method + """Update attributes from current drawing-related prefs stored in prefs db cache. + This should be called at the start of each complete redraw, or whenever the user changes these global prefs values + (whichever is more convenient). + (Note: When this is called during redraw, its prefs db accesses (like any others) + record those prefs as potentially affecting what should be drawn, so that subsequent + changes to those prefs values cause an automatic gl_update.) + Using these attributes in drawing code (rather than directly accessing prefs db cache) + is desirable for efficiency, since direct access to prefs db cache is a bit slow. + (Our drawing code still does that in other places -- those might also benefit from this system, + though this will soon be moot when low-level drawing code gets rewritten in C.) + """ + self.enable_specular_highlights = not not env.prefs[ + material_specular_highlights_prefs_key] # boolean + if self.enable_specular_highlights: + self.override_light_specular = None # used in glpane + # self.specular_shininess: float; shininess exponent for all specular highlights + self.specular_shininess = float(env.prefs[material_specular_shininess_prefs_key]) + # self.specular_whiteness: float; whiteness for all material specular colors + self.specular_whiteness = float(env.prefs[material_specular_finish_prefs_key]) + # self.specular_brightness: float; for all material specular colors + self.specular_brightness = float(env.prefs[material_specular_brightness_prefs_key]) + else: + self.override_light_specular = (0.0, 0.0, 0.0, 0.0) # used in glpane + # Set these to reasonable values, though these attributes are presumably never used in this case. + # Don't access the prefs db in this case, since that would cause UI prefs changes to do unnecessary gl_updates. + # (If we ever add a scenegraph node which can enable specular highlights but use outside values for these parameters, + # then to make it work correctly we'll need to revise this code.) + self.specular_shininess = 20.0 + self.specular_whiteness = 1.0 + self.specular_brightness = 1.0 + + drawing_globals.allow_color_sorting = env.prefs.get( + drawing_globals.allow_color_sorting_prefs_key, + drawing_globals.allow_color_sorting_default) + drawing_globals.use_color_sorted_dls = env.prefs.get( + drawing_globals.use_color_sorted_dls_prefs_key, + drawing_globals.use_color_sorted_dls_default) + drawing_globals.use_color_sorted_vbos = env.prefs.get( + drawing_globals.use_color_sorted_vbos_prefs_key, + drawing_globals.use_color_sorted_vbos_default) + drawing_globals.use_drawing_variant = env.prefs.get( + drawing_globals.use_drawing_variant_prefs_key, + drawing_globals.use_drawing_variant_default) + drawing_globals.use_c_renderer = ( + drawing_globals.quux_module_import_succeeded and + env.prefs.get(drawing_globals.use_c_renderer_prefs_key, + drawing_globals.use_c_renderer_default)) + + if drawing_globals.use_c_renderer: + quux.shapeRendererSetMaterialParameters(self.specular_whiteness, + self.specular_brightness, + self.specular_shininess); + return + + def materialprefs_summary(self): #bruce 051126 + """ + Return a Python data object summarizing our prefs which affect chunk display lists, + so that memoized display lists should become invalid (due to changes in this object) + if and only if this value becomes different. + """ + res = (self.enable_specular_highlights,) + if self.enable_specular_highlights: + res = res + ( self.specular_shininess, + self.specular_whiteness, + self.specular_brightness ) + + # grantham 20060314 + res += (drawing_globals.quux_module_import_succeeded and + env.prefs.get(drawing_globals.use_c_renderer_prefs_key, + drawing_globals.use_c_renderer_default),) + + # grantham 20060314 - Not too sure this next addition is + # really necessary, but it seems to me that for testing + # purposes it is important to rebuild display lists if the + # color sorting pref is changed. + res += (env.prefs.get(drawing_globals.allow_color_sorting_prefs_key, + drawing_globals.allow_color_sorting_default),) + res += (env.prefs.get(drawing_globals.use_color_sorted_dls_prefs_key, + drawing_globals.use_color_sorted_dls_default),) + res += (env.prefs.get(drawing_globals.use_color_sorted_vbos_prefs_key, + drawing_globals.use_color_sorted_vbos_default),) + res += (env.prefs.get(drawing_globals.use_drawing_variant_prefs_key, + drawing_globals.use_drawing_variant_default),) + return res + + pass # end of class glprefs + +drawing_globals.glprefs = glprefs() diff --git a/cad/src/graphics/drawing/setup_draw.py b/cad/src/graphics/drawing/setup_draw.py new file mode 100755 index 000000000..00aa33527 --- /dev/null +++ b/cad/src/graphics/drawing/setup_draw.py @@ -0,0 +1,544 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +setup_draw.py - The function to allocate and compile our standard display lists +into the current GL context, and initialize the globals that hold their opengl +names. + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +import graphics.drawing.drawing_globals as drawing_globals +from graphics.drawing.gl_buffers import GLBufferObject +from graphics.drawing.shape_vertices import getSphereTriStrips +from graphics.drawing.shape_vertices import getSphereTriangles +from graphics.drawing.shape_vertices import indexVerts + +import numpy + +numSphereSizes = 3 + +def setup_drawer(): + """ + Set up the usual constant display lists in the current OpenGL context. + + WARNING: THIS IS ONLY CORRECT IF ONLY ONE GL CONTEXT CONTAINS DISPLAY LISTS -- + or more precisely, only the GL context this has last been called in + (or one which shares its display lists) will work properly with the routines in drawer.py, + since the allocated display list names are stored in globals set by this function, + but in general those names might differ if this was called in different GL contexts. + """ + #bruce 060613 added docstring, cleaned up display list name allocation + # bruce 071030 renamed from setup to setup_drawer + + spherelistbase = glGenLists(numSphereSizes) + sphereList = [] + for i in range(numSphereSizes): + sphereList += [spherelistbase+i] + glNewList(sphereList[i], GL_COMPILE) + glBegin(GL_TRIANGLE_STRIP) # GL_LINE_LOOP to see edges. + stripVerts = getSphereTriStrips(i) + for vertNorm in stripVerts: + glNormal3fv(vertNorm) + glVertex3fv(vertNorm) + continue + glEnd() + glEndList() + continue + drawing_globals.sphereList = sphereList + + # Sphere triangle-strip vertices for each level of detail. + # (Cache and re-use the work of making them.) + # Can use in converter-wrappered calls like glVertexPointerfv, + # but the python arrays are re-copied to C each time. + sphereArrays = [] + for i in range(numSphereSizes): + sphereArrays += [getSphereTriStrips(i)] + continue + drawing_globals.sphereArrays = sphereArrays + + # Sphere glDrawArrays triangle-strip vertices for C calls. + # (Cache and re-use the work of converting a C version.) + # Used in thinly-wrappered calls like glVertexPointer. + sphereCArrays = [] + for i in range(numSphereSizes): + CArray = numpy.array(sphereArrays[i], dtype=numpy.float32) + sphereCArrays += [CArray] + continue + drawing_globals.sphereCArrays = sphereCArrays + + # Sphere indexed vertices. + # (Cache and re-use the work of making the indexes.) + # Can use in converter-wrappered calls like glDrawElementsui, + # but the python arrays are re-copied to C each time. + sphereElements = [] # Pairs of lists (index, verts) . + for i in range(numSphereSizes): + sphereElements += [indexVerts(sphereArrays[i], .0001)] + continue + drawing_globals.sphereElements = sphereElements + + # Sphere glDrawElements index and vertex arrays for C calls. + sphereCIndexTypes = [] # numpy index unsigned types. + sphereGLIndexTypes = [] # GL index types for drawElements. + sphereCElements = [] # Pairs of numpy arrays (Cindex, Cverts) . + for i in range(numSphereSizes): + (index, verts) = sphereElements[i] + if len(index) < 256: + Ctype = numpy.uint8 + GLtype = GL_UNSIGNED_BYTE + else: + Ctype = numpy.uint16 + GLtype = GL_UNSIGNED_SHORT + pass + sphereCIndexTypes += [Ctype] + sphereGLIndexTypes += [GLtype] + sphereCIndex = numpy.array(index, dtype=Ctype) + sphereCVerts = numpy.array(verts, dtype=numpy.float32) + sphereCElements += [(sphereCIndex, sphereCVerts)] + continue + drawing_globals.sphereCIndexTypes = sphereCIndexTypes + drawing_globals.sphereGLIndexTypes = sphereGLIndexTypes + drawing_globals.sphereCElements = sphereCElements + + if glGetString(GL_EXTENSIONS).find("GL_ARB_vertex_buffer_object") >= 0: + + # A GLBufferObject version for glDrawArrays. + sphereArrayVBOs = [] + for i in range(numSphereSizes): + vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, + sphereCArrays[i], GL_STATIC_DRAW) + sphereArrayVBOs += [vbo] + continue + drawing_globals.sphereArrayVBOs = sphereArrayVBOs + + # A GLBufferObject version for glDrawElements indexed verts. + sphereElementVBOs = [] # Pairs of (IBO, VBO) + for i in range(numSphereSizes): + ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, + sphereCElements[i][0], GL_STATIC_DRAW) + vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, + sphereCElements[i][1], GL_STATIC_DRAW) + sphereElementVBOs += [(ibo, vbo)] + continue + drawing_globals.sphereElementVBOs = sphereElementVBOs + + ibo.unbind() + vbo.unbind() + pass + + #bruce 060415 + drawing_globals.wiresphere1list = wiresphere1list = glGenLists(1) + glNewList(wiresphere1list, GL_COMPILE) + didlines = {} # don't draw each triangle edge more than once + def shoulddoline(v1,v2): + v1 = tuple(v1) # make sure not list (unhashable) or Numeric array (bug in __eq__) + v2 = tuple(v2) + if (v1,v2) not in didlines: + didlines[(v1,v2)] = didlines[(v2,v1)] = None + return True + return False + def doline(v1,v2): + if shoulddoline(v1,v2): + glVertex3fv(v1) + glVertex3fv(v2) + return + glBegin(GL_LINES) + ocdec = getSphereTriangles(1) + for tri in ocdec: + #e could probably optim this more, e.g. using a vertex array or VBO or maybe GL_LINE_STRIP + doline(tri[0], tri[1]) + doline(tri[1], tri[2]) + doline(tri[2], tri[0]) + glEnd() + glEndList() + + drawing_globals.CylList = CylList = glGenLists(1) + glNewList(CylList, GL_COMPILE) + glBegin(GL_TRIANGLE_STRIP) + for (vtop, ntop, vbot, nbot) in drawing_globals.cylinderEdges: + glNormal3fv(nbot) + glVertex3fv(vbot) + glNormal3fv(ntop) + glVertex3fv(vtop) + glEnd() + glEndList() + + drawing_globals.CapList = CapList = glGenLists(1) + glNewList(CapList, GL_COMPILE) + glNormal3fv(drawing_globals.cap0n) + glBegin(GL_POLYGON) + for p in drawing_globals.drum0: + glVertex3fv(p) + glEnd() + glNormal3fv(drawing_globals.cap1n) + glBegin(GL_POLYGON) + #bruce 060609 fix "ragged edge" bug in this endcap: drum1 -> drum2 + for p in drawing_globals.drum2: + glVertex3fv(p) + glEnd() + glEndList() + + drawing_globals.diamondGridList = diamondGridList = glGenLists(1) + glNewList(diamondGridList, GL_COMPILE) + glBegin(GL_LINES) + for p in drawing_globals.digrid: + glVertex(p[0]) + glVertex(p[1]) + glEnd() + glEndList() + + drawing_globals.lonsGridList = lonsGridList = glGenLists(1) + glNewList(lonsGridList, GL_COMPILE) + glBegin(GL_LINES) + for p in drawing_globals.lonsEdges: + glVertex(p[0]) + glVertex(p[1]) + glEnd() + glEndList() + + drawing_globals.CubeList = CubeList = glGenLists(1) + glNewList(CubeList, GL_COMPILE) + glBegin(GL_QUAD_STRIP) + # note: CubeList has only 4 faces of the cube; only suitable for use in wireframes; + # see also solidCubeList [bruce 051215 comment reporting grantham 20051213 observation] + glVertex((-1,-1,-1)) + glVertex(( 1,-1,-1)) + glVertex((-1, 1,-1)) + glVertex(( 1, 1,-1)) + glVertex((-1, 1, 1)) + glVertex(( 1, 1, 1)) + glVertex((-1,-1, 1)) + glVertex(( 1,-1, 1)) + glVertex((-1,-1,-1)) + glVertex(( 1,-1,-1)) + glEnd() + glEndList() + + drawing_globals.solidCubeList = solidCubeList = glGenLists(1) + glNewList(solidCubeList, GL_COMPILE) + glBegin(GL_QUADS) + for i in xrange(len(drawing_globals.cubeIndices)): + avenormals = V(0,0,0) #bruce 060302 fixed normals for flat shading + for j in xrange(4) : + nTuple = tuple( + drawing_globals.cubeNormals[drawing_globals.cubeIndices[i][j]]) + avenormals += A(nTuple) + avenormals = norm(avenormals) + for j in xrange(4) : + vTuple = tuple( + drawing_globals.cubeVertices[drawing_globals.cubeIndices[i][j]]) + #bruce 060302 made size compatible with glut.glutSolidCube(1.0) + vTuple = A(vTuple) * 0.5 + glNormal3fv(avenormals) + glVertex3fv(vTuple) + glEnd() + glEndList() + + drawing_globals.rotSignList = rotSignList = glGenLists(1) + glNewList(rotSignList, GL_COMPILE) + glBegin(GL_LINE_STRIP) + for ii in xrange(len(drawing_globals.rotS0n)): + glVertex3fv(tuple(drawing_globals.rotS0n[ii])) + glEnd() + glBegin(GL_LINE_STRIP) + for ii in xrange(len(drawing_globals.rotS1n)): + glVertex3fv(tuple(drawing_globals.rotS1n[ii])) + glEnd() + glBegin(GL_TRIANGLES) + for v in drawing_globals.arrow0Vertices + drawing_globals.arrow1Vertices: + glVertex3f(v[0], v[1], v[2]) + glEnd() + glEndList() + + drawing_globals.linearArrowList = linearArrowList = glGenLists(1) + glNewList(linearArrowList, GL_COMPILE) + glBegin(GL_TRIANGLES) + for v in drawing_globals.linearArrowVertices: + glVertex3f(v[0], v[1], v[2]) + glEnd() + glEndList() + + drawing_globals.linearLineList = linearLineList = glGenLists(1) + glNewList(linearLineList, GL_COMPILE) + glEnable(GL_LINE_SMOOTH) + glBegin(GL_LINES) + glVertex3f(0.0, 0.0, -drawing_globals.halfHeight) + glVertex3f(0.0, 0.0, drawing_globals.halfHeight) + glEnd() + glDisable(GL_LINE_SMOOTH) + glEndList() + + drawing_globals.circleList = circleList = glGenLists(1) + glNewList(circleList, GL_COMPILE) + glBegin(GL_LINE_LOOP) + for ii in range(60): + x = cos(ii*2.0*pi/60) + y = sin(ii*2.0*pi/60) + glVertex3f(x, y, 0.0) + glEnd() + glEndList() + + # piotr 080405 + drawing_globals.filledCircleList = filledCircleList = glGenLists(1) + glNewList(filledCircleList, GL_COMPILE) + glBegin(GL_POLYGON) + for ii in range(60): + x = cos(ii*2.0*pi/60) + y = sin(ii*2.0*pi/60) + glVertex3f(x, y, 0.0) + glEnd() + glEndList() + + drawing_globals.lineCubeList = lineCubeList = glGenLists(1) + glNewList(lineCubeList, GL_COMPILE) + glBegin(GL_LINES) + cvIndices = [0,1, 2,3, 4,5, 6,7, 0,3, 1,2, 5,6, 4,7, 0,4, 1,5, 2,6, 3,7] + for i in cvIndices: + glVertex3fv(tuple(drawing_globals.cubeVertices[i])) + glEnd() + glEndList() + + # Debug Preferences + from utilities.debug_prefs import debug_pref, Choice_boolean_True + from utilities.debug_prefs import Choice_boolean_False + choices = [Choice_boolean_False, Choice_boolean_True] + + # 20060314 grantham + initial_choice = choices[drawing_globals.allow_color_sorting_default] + drawing_globals.allow_color_sorting_pref = debug_pref( + "Use Color Sorting?", initial_choice, + prefs_key = drawing_globals.allow_color_sorting_prefs_key) + #bruce 060323 removed non_debug = True for A7 release, changed default + #value to False (far above), and changed its prefs_key so developers + #start with the new default value. + #russ 080225: Added. + initial_choice = choices[drawing_globals.use_color_sorted_dls_default] + drawing_globals.use_color_sorted_dls_pref = debug_pref( + "Use Color-sorted Display Lists?", initial_choice, + prefs_key = drawing_globals.use_color_sorted_dls_prefs_key) + #russ 080225: Added. + initial_choice = choices[drawing_globals.use_color_sorted_vbos_default] + drawing_globals.use_color_sorted_vbos_pref = debug_pref( + "Use Color-sorted Vertex Buffer Objects?", initial_choice, + prefs_key = drawing_globals.use_color_sorted_vbos_prefs_key) + + #russ 080403: Added drawing variant selection + variants = [ + "0. OpenGL 1.0 - glBegin/glEnd tri-strips vertex-by-vertex.", + "1. OpenGL 1.1 - glDrawArrays from CPU RAM.", + "2. OpenGL 1.1 - glDrawElements indexed arrays from CPU RAM.", + "3. OpenGL 1.5 - glDrawArrays from graphics RAM VBO.", + "4. OpenGL 1.5 - glDrawElements, verts in VBO, index in CPU.", + "5. OpenGL 1.5 - VBO/IBO buffered glDrawElements."] + drawing_globals.use_drawing_variant = debug_pref( + "GLPane: drawing method", + Choice(names = variants, values = range(len(variants)), + defaultValue = drawing_globals.use_drawing_variant_default), + prefs_key = drawing_globals.use_drawing_variant_prefs_key) + + # temporarily always print this, while default setting might be in flux, + # and to avoid confusion if the two necessary prefs are set differently + # [bruce 080305] + if (drawing_globals.allow_color_sorting_pref and + drawing_globals.use_color_sorted_dls_pref): + print "\nnote: this session WILL use color sorted display lists" + else: + print "\nnote: this session will NOT use color sorted display lists" + if (drawing_globals.allow_color_sorting_pref and + drawing_globals.use_color_sorted_vbos_pref): + print "note: this session WILL use color sorted Vertex Buffer Objects\n" + else: + print "note: this session will NOT use color sorted Vertex Buffer Objects\n" + + # 20060313 grantham Added use_c_renderer debug pref, can + # take out when C renderer used by default. + if drawing_globals.quux_module_import_succeeded: + initial_choice = choices[drawing_globals.use_c_renderer_default] + drawing_globals.use_c_renderer = ( + debug_pref("Use native C renderer?", + initial_choice, + prefs_key = drawing_globals.use_c_renderer_prefs_key)) + #bruce 060323 removed non_debug = True for A7 release, + # and changed its prefs_key so developers start over with the default value. + + #initTexture('C:\\Huaicai\\atom\\temp\\newSample.png', 128,128) + return # from setup_drawer diff --git a/cad/src/graphics/drawing/shape_vertices.py b/cad/src/graphics/drawing/shape_vertices.py new file mode 100755 index 000000000..ca5a4fded --- /dev/null +++ b/cad/src/graphics/drawing/shape_vertices.py @@ -0,0 +1,648 @@ +# Copyright 2004-2008 Nanorex, Inc. See LICENSE file for details. +""" +shape_vertices.py - Geometric constructions of vertex lists used by the drawing functions. + +This includes vertices for the shapes of primitives that will go into display +lists in the setup_drawer function in setup_draw.py . + +@version: $Id$ +@copyright: 2004-2008 Nanorex, Inc. See LICENSE file for details. + +History: + +Originated by Josh as drawer.py . + +Various developers extended it since then. + +Brad G. added ColorSorter features. + +At some point Bruce partly cleaned up the use of display lists. + +071030 bruce split some functions and globals into draw_grid_lines.py +and removed some obsolete functions. + +080210 russ Split the single display-list into two second-level lists (with and +without color) and a set of per-color sublists so selection and hover-highlight +can over-ride Chunk base colors. ColorSortedDisplayList is now a class in the +parent's displist attr to keep track of all that stuff. + +080311 piotr Added a "drawpolycone_multicolor" function for drawing polycone +tubes with per-vertex colors (necessary for DNA display style) + +080313 russ Added triangle-strip icosa-sphere constructor, "getSphereTriStrips". + +080420 piotr Solved highlighting and selection problems for multi-colored +objects (e.g. rainbow colored DNA structures). + +080519 russ pulled the globals into a drawing_globals module and broke drawer.py +into 10 smaller chunks: glprefs.py setup_draw.py shape_vertices.py +ColorSorter.py CS_workers.py CS_ShapeList.py CS_draw_primitives.py drawers.py +gl_lighting.py gl_buffers.py +""" + +import os +import sys + +# the imports from math vs. Numeric are as discovered in existing code +# as of 2007/06/25. It's not clear why acos is coming from math... +from math import floor, ceil, acos, atan2 +import Numeric +from Numeric import sin, cos, sqrt, pi +degreesPerRadian = 180.0 / pi + +# russ 080519 No doubt many of the following imports are unused. +# When the dust settles, the unnecessary ones will be removed. +from OpenGL.GL import GL_AMBIENT +from OpenGL.GL import GL_AMBIENT_AND_DIFFUSE +from OpenGL.GL import glAreTexturesResident +from OpenGL.GL import GL_ARRAY_BUFFER_ARB +from OpenGL.GL import GL_BACK +from OpenGL.GL import glBegin +from OpenGL.GL import glBindTexture +from OpenGL.GL import GL_BLEND +from OpenGL.GL import glBlendFunc +from OpenGL.GL import glCallList +from OpenGL.GL import glColor3f +from OpenGL.GL import glColor3fv +from OpenGL.GL import glColor4fv +from OpenGL.GL import GL_COLOR_MATERIAL +from OpenGL.GL import GL_COMPILE +from OpenGL.GL import GL_COMPILE_AND_EXECUTE +from OpenGL.GL import GL_CONSTANT_ATTENUATION +from OpenGL.GL import GL_CULL_FACE +from OpenGL.GL import GL_CURRENT_BIT +from OpenGL.GL import glDeleteLists +from OpenGL.GL import glDeleteTextures +from OpenGL.GL import glDepthMask +from OpenGL.GL import GL_DEPTH_TEST +from OpenGL.GL import GL_DIFFUSE +from OpenGL.GL import glDisable +from OpenGL.GL import glDisableClientState +from OpenGL.GL import glDrawArrays +from OpenGL.GL import glDrawElements +from OpenGL.GL import glDrawElementsub +from OpenGL.GL import glDrawElementsui +from OpenGL.GL import glDrawElementsus +from OpenGL.GL import GL_ELEMENT_ARRAY_BUFFER_ARB +from OpenGL.GL import glEnable +from OpenGL.GL import glEnableClientState +from OpenGL.GL import glEnd +from OpenGL.GL import glEndList +from OpenGL.GL import GL_EXTENSIONS +from OpenGL.GL import GL_FALSE +from OpenGL.GL import GL_FILL +from OpenGL.GL import glFinish +from OpenGL.GL import GL_FLOAT +from OpenGL.GL import GL_FOG +from OpenGL.GL import GL_FOG_COLOR +from OpenGL.GL import GL_FOG_END +from OpenGL.GL import GL_FOG_MODE +from OpenGL.GL import GL_FOG_START +from OpenGL.GL import GL_FRONT +from OpenGL.GL import GL_FRONT_AND_BACK +from OpenGL.GL import glGenLists +from OpenGL.GL import glGenTextures +from OpenGL.GL import glGetString +from OpenGL.GL import GL_LIGHT0 +from OpenGL.GL import GL_LIGHT1 +from OpenGL.GL import GL_LIGHT2 +from OpenGL.GL import glLightf +from OpenGL.GL import glLightfv +from OpenGL.GL import GL_LIGHTING +from OpenGL.GL import GL_LINE +from OpenGL.GL import GL_LINEAR +from OpenGL.GL import GL_LINE_LOOP +from OpenGL.GL import GL_LINES +from OpenGL.GL import GL_LINE_SMOOTH +from OpenGL.GL import glLineStipple +from OpenGL.GL import GL_LINE_STIPPLE +from OpenGL.GL import GL_LINE_STRIP +from OpenGL.GL import glLineWidth +from OpenGL.GL import glLoadIdentity +from OpenGL.GL import glMaterialf +from OpenGL.GL import glMaterialfv +from OpenGL.GL import glMatrixMode +from OpenGL.GL import GL_MODELVIEW +from OpenGL.GL import glNewList +from OpenGL.GL import glNormal3fv +from OpenGL.GL import glNormalPointer +from OpenGL.GL import glNormalPointerf +from OpenGL.GL import GL_NORMAL_ARRAY +from OpenGL.GL import GL_ONE_MINUS_SRC_ALPHA +from OpenGL.GL import glPointSize +from OpenGL.GL import GL_POINTS +from OpenGL.GL import GL_POINT_SMOOTH +from OpenGL.GL import GL_POLYGON +from OpenGL.GL import glPolygonMode +from OpenGL.GL import glPopAttrib +from OpenGL.GL import glPopMatrix +from OpenGL.GL import glPopName +from OpenGL.GL import GL_POSITION +from OpenGL.GL import glPushAttrib +from OpenGL.GL import glPushMatrix +from OpenGL.GL import glPushName +from OpenGL.GL import GL_QUADS +from OpenGL.GL import GL_QUAD_STRIP +from OpenGL.GL import GL_RENDERER +from OpenGL.GL import GL_RGBA +from OpenGL.GL import glRotate +from OpenGL.GL import glRotatef +from OpenGL.GL import GL_SHININESS +from OpenGL.GL import GL_SPECULAR +from OpenGL.GL import GL_SRC_ALPHA +from OpenGL.GL import GL_STATIC_DRAW +from OpenGL.GL import glTexCoord2f +from OpenGL.GL import glTexCoord2fv +from OpenGL.GL import GL_TEXTURE_2D +from OpenGL.GL import glTranslate +from OpenGL.GL import glTranslatef +from OpenGL.GL import GL_TRIANGLES +from OpenGL.GL import GL_TRIANGLE_STRIP +from OpenGL.GL import GL_TRUE +from OpenGL.GL import GL_UNSIGNED_BYTE +from OpenGL.GL import GL_UNSIGNED_SHORT +from OpenGL.GL import GL_VENDOR +from OpenGL.GL import GL_VERSION +from OpenGL.GL import glVertex +from OpenGL.GL import glVertex2f +from OpenGL.GL import glVertex3f +from OpenGL.GL import glVertex3fv +from OpenGL.GL import GL_VERTEX_ARRAY +from OpenGL.GL import glVertexPointer +from OpenGL.GL import glVertexPointerf + +from OpenGL.GLU import gluBuild2DMipmaps + +from geometry.VQT import norm, vlen, V, Q, A + +from utilities.constants import white, blue, red +from utilities.constants import darkgreen, lightblue +from utilities.constants import DIAMOND_BOND_LENGTH +from utilities.prefs_constants import material_specular_highlights_prefs_key +from utilities.prefs_constants import material_specular_shininess_prefs_key +from utilities.prefs_constants import material_specular_finish_prefs_key +from utilities.prefs_constants import material_specular_brightness_prefs_key + +from utilities.debug_prefs import Choice +import utilities.debug as debug # for debug.print_compact_traceback + +#= + +import graphics.drawing.drawing_globals as drawing_globals + +def init_icos(): + global icosa, icosix + + # the golden ratio + global phi + phi = (1.0+sqrt(5.0))/2.0 + vert = norm(V(phi,0,1)) + a = vert[0] + b = vert[1] + c = vert[2] + + # vertices of an icosahedron + icosa = ((-a,b,c), (b,c,-a), (b,c,a), (a,b,-c), (-c,-a,b), (-c,a,b), + (b,-c,a), (c,a,b), (b,-c,-a), (a,b,c), (c,-a,b), (-a,b,-c)) + icosix = ((9, 2, 6), (1, 11, 5), (11, 1, 8), (0, 11, 4), (3, 1, 7), + (3, 8, 1), (9, 3, 7), (0, 6, 2), (4, 10, 6), (1, 5, 7), + (7, 5, 2), (8, 3, 10), (4, 11, 8), (9, 7, 2), (10, 9, 6), + (0, 5, 11), (0, 2, 5), (8, 10, 4), (3, 9, 10), (6, 0, 4)) + return +init_icos() + +# generate geodesic spheres by subdividing the faces of an icosahedron +# recursively: +# /\ /\ +# / \ / \ +# / \ /____\ +# / \ => /\ /\ +# / \ / \ / \ +# /__________\ /____\/____\ +# +# and normalizing the resulting vectors to the surface of a sphere + +def subdivide(tri,deep): + if deep: + a = tri[0] + b = tri[1] + c = tri[2] + a1 = norm(A(tri[0])) + b1 = norm(A(tri[1])) + c1 = norm(A(tri[2])) + d = tuple(norm(a1+b1)) + e = tuple(norm(b1+c1)) + f = tuple(norm(c1+a1)) + return subdivide((a,d,f), deep-1) + subdivide((d,e,f), deep-1) +\ + subdivide((d,b,e), deep-1) + subdivide((f,e,c), deep-1) + else: return [tri] + +## Get the specific detail level of triangles approximation of a sphere +def getSphereTriangles(level): + ocdec = [] + for i in icosix: + ocdec += subdivide((icosa[i[0]],icosa[i[1]],icosa[i[2]]),level) + return ocdec + +# == + +# Instead of the above recursive scheme that orients the icosahedron with the +# midpoints of six edges perpendicular to the major axes, use a ring approach +# to make subdivided icosa-spheres for Triangle Strips. The vertices are +# grouped in rings from the North Pole to the South Pole. Each strip zig-zags +# between two rings, and the poles are surrounded by pentagonal Triangle Fans. +# +# ---------------- +# +# The pattern of five-fold vertices in a "twisted orange-slice" segment +# covering one-fifth of the icosahedron is: +# +# ... [3,0] ... (North Pole) +# / | \ +# / | ... +# / | +# ... [2,1]---[2,0] ... +# / \ / \ +# ... \ / \ ... +# \ / \ / +# ... [1,1]---[1,0] ... +# | / +# ... | / +# \ | / +# ... [0,0] ... (South Pole) +# +# ---------------- +# +# Higher subdivision levels step the strip verts along the icos edges, +# interpolating intermediate points on the icos and projecting each onto the +# sphere. Note: sphere vertex normals are the same as their coords. +# +# The "*"s show approximate vertex locations at each subdivision level. +# Bands are numbered from South to North. (Reason explained below.) +# Sub-band numbers are in angle-brackets, "<>". +# +# Level 0 [3*0] Level 1 [6*0] Level 2 [12*0] _<3> +# / | (2 steps) / | <1> (4 steps) *-* _<2> +# Band 2 / | * - * *-*-* _<1> +# / | / | / | <0> *-*-*-* _<0> +# [2*1]- -[2*0] => [4*2]-*-[4*0] => [8*4]***[8*0] _<3> +# \ / \ \ / \ / \ <1> *-*-*-*-* _<2> +# Band 1 \ / \ * - * - * *-*-*-*-* _<1> +# \ / \ \ / \ / \ <0> *-*-*-*-* _<0> +# [1*1]---[1*0] [2*2]-*-[2*0] [4*4]***[4*0]_<3> +# | / | \ | / <1> *-*-*-* _<2> +# Band 0 | / * - * *-*-* _<1> +# | / | / <0> *-* _<0> +# [0*0] [0*0] [0*0] +# +# ---------------- +# +# The reason for rotating east, then going west along the latitude lines, is +# that the "grain" of triangle strip diagonals runs that way in the middle +# band of the icos: +# +# Triangle Strip triangles +# +# 6 ----- 4 ----- 2 +# \5,4,6/ \3,2,4/ \ +# ... \ / \ / \ +# \ /3,4,5\ /1,2,3\ +# 5 ----- 3 ----- 1 <- Vertex order +# +# This draws triangles 1-2-3, 3-2-4, 3-4-5, and 5-4-6, all counter-clockwise +# so the normal directions don't flip-flop. +# +# ---------------- +# +# This version optimizes by concatenating vertices for separate Triangle Fan +# and Triangle Strip calls into a single long Triangle Strip to minimize calls. +# +# In the "pentagon cap" band at the top of the icos, points 2, 4, and 6 in the +# above example are collapsed to the North Pole; at the bottom, points 1, 3, +# and 5 are collapsed to the South Pole. This makes "null triangles" with one +# zero-length edge, and the other two edges echoing one of the other triangle +# edges (5,4,6 and 3,2,4 at the top, and 3,4,5 and 1,2,3 at the bottom.) +# +# In the subdivided caps, the icosahedron bands are split into horizontal +# sub-bands. In the tapering-in sub-bands in the North cap, there is one less +# vertex on the top edges of sub-bands, so we collapse the *LAST* triangle +# there (e.g. 5,4,6 above) On the bottom edges of the South cap bands there +# is one less vertex, so we collapse the *FIRST* triangle (e.g. 1,2,3.) +# +# Similarly, moving from the end of each sub-band to the beginning of the next +# requires a *pair* of null triangles. We get that by simply concatenating the +# wrapped triangle strips. We orient point pairs in the triangle strip from +# south to north, so this works as long as we jog northward between (sub-)bands. +# This is the reason we start the Triangle Strip with the South Pole band. +# +def getSphereTriStrips(level): + steps = 2**level + points = [] # Triangle Strip vertices o be returned. + + # Construct an icosahedron with two vertices at the North and South Poles, + # +-1 on the Y axis, as you look toward the X-Y plane with the Z axis + # pointing out at you. The "middle ring" vertices are all at the same + # +-latitudes, on the intersection circles of the globe with a polar-axis + # cylinder of the proper radius. + # + # The third "master vertex" of the icosahedron is placed on the X-Y plane, + # which intersects the globe at the Greenwich Meridian (the semi-circle at + # longitude 0, through Greenwich Observatory, 5 miles south-east of London.) + # + # The X (distance from the polar axis) and Y (height above the equatorial + # plane) of the master vertex make a "golden rectangle", one unit high by + # "phi" (1.6180339887498949) wide. We normalize this to put it on the + # unit-radius sphere, and take the distance from the axis as the cylinder + # radius used to generate the rest of the vertices of the two middle rings. + # + # Plotted on the globe, the master vertex (first vertex of the North ring) + # is lat-long 31.72,0 due south of London in Africa, about 45 miles + # south-southwest of Benoud, Algeria. The first vertex of the south ring is + # rotated 1/10 of a circle east, at lat-long -31.72,36 in the south end of + # the Indian Ocean, about 350 miles east-southeast of Durban, South Africa. + # + vert0 = norm(V(phi,1,0)) # Project the "master vertex" onto a unit sphere. + cylRad = vert0[0] # Icos vertex distance from the Y axis. + ringLat = atan2(vert0[1], vert0[0]) * degreesPerRadian # Latitude +-31.72 . + + # Basic triangle-strip icosahedron vertices. Start and end with the Poles. + # Reflect the master vertex into the southern hemisphere and rotate 5 copies + # to make the middle rings of 5 vertices at North and South latitudes. + p2_5 = 2*pi / 5.0 + # Simplify indexing by replicating the Poles, so everything is in fives. + icosRings = [ 5 * [V(0.0, -1.0, 0.0)], # South Pole. + + # South ring, first edge *centered on* the Greenwich Meridian. + [V(cylRad*cos((i-.5)*p2_5), -vert0[1], cylRad*sin((i-.5)*p2_5)) + for i in range(5)], + + # North ring, first vertex *on* the Greenwich Meridian. + [V(cylRad*cos(i*p2_5 ), vert0[1], cylRad*sin(i*p2_5)) + for i in range(5)], + + 5 * [V(0.0, 1.0, 0.0)] ] # North Pole. + + + # Three bands, going from bottom to top (South to North.) + for band in range(3): + lowerRing = icosRings[band] + upperRing = icosRings[band+1] + + # Subdivide bands into sub-bands. When level == 0, steps == 1, + # subBand == 0, and we get just the icosahedron out. (Really!) + for subBand in range(steps): + + # Account for the tapering-in at the poles, making less points on + # one edge of a sub-band than there are on the other edge. + botOffset = 0 + if band is 0: # South. + botSteps = max(subBand, 1) # Don't divide by zero. + topSteps = subBand + 1 + # Collapse the *first* triangle of south sub-band bottom edges. + botOffset = -1 + elif band is 1: # Middle. + botSteps = topSteps = steps + else: # band is 2: North. + botSteps = steps - subBand + topSteps = max(steps - (subBand+1), 1) + pass + subBandSteps = max(botSteps, topSteps) + + # Do five segments, clockwise around the North Pole (East to West.) + for seg in range(5): + nextseg = (seg+1) % 5 # Wrap-around. + + # Interpolate ends of bottom & top edges of a sub-band segment. + fractBot = float(subBand)/float(steps) + fractTop = float(subBand+1)/float(steps) + sbBotRight = fractBot * upperRing[seg] + \ + (1.0-fractBot) * lowerRing[seg] + sbTopRight = fractTop * upperRing[seg] + \ + (1.0-fractTop) * lowerRing[seg] + sbBotLeft = fractBot * upperRing[nextseg] + \ + (1.0-fractBot) * lowerRing[nextseg] + sbTopLeft = fractTop * upperRing[nextseg] + \ + (1.0-fractTop) * lowerRing[nextseg] + + # Output the right end of the first segment of the sub-band. + # We'll end up wrapping around to this same pair of points at + # the left end of the last segment of the sub-band. + if seg is 0: + # Project verts from icosahedron faces onto the unit sphere. + points += [norm(sbBotRight), norm(sbTopRight)] + + # Step across the sub-band edges from right to left, + # stitching triangle pairs from their lower to upper edges. + for step in range(1, subBandSteps+1): + + # Interpolate step point pairs along the sub-band edges. + fractLower = float(step+botOffset)/float(botSteps) + lower = fractLower * sbBotLeft + \ + (1.0-fractLower) * sbBotRight + # Collapse the *last* triangle of north sub-band top edges. + fractUpper = float(min(step, topSteps))/float(topSteps) + upper = fractUpper * sbTopLeft + \ + (1.0-fractUpper) * sbTopRight + + # Output verts, projected from icos faces onto unit sphere. + points += [norm(lower), norm(upper)] + + continue # step + continue # seg + continue # subBand + continue # band + return points + +def indexVerts(verts, close): + """ + Compress a vertex array into an array of unique vertices, and an array of + index values into the unique vertices. This is good for converting input + for glDrawArrays into input for glDrawElements. + + The second arg is 'close', the distance between vertices which are close + enough to be considered a single vertex. + + The return value is a pair of arrays (index, verts). + """ + unique = [] + index = [] + for v in verts: + for i in range(len(unique)): + if vlen(unique[i] - v) < close: + index += [i] + break + pass + else: + index += [len(unique)] + unique += [v] + pass + continue + return (index, unique) + +# == + +def init_cyls(): + # generate two circles in space as 13-gons, + # one rotated half a segment with respect to the other + # these are used as cylinder ends [not quite true anymore, see comments just below] + slices = 13 + circ1 = map((lambda n: n*2.0*pi/slices), range(slices+1)) + circ2 = map((lambda a: a+pi/slices), circ1) + drawing_globals.drum0 = drum0 = map((lambda a: (cos(a), sin(a), 0.0)), circ1) + drum1 = map((lambda a: (cos(a), sin(a), 1.0)), circ2) + drum1n = map((lambda a: (cos(a), sin(a), 0.0)), circ2) + + # grantham 20051213 I finally decided the look of the oddly twisted + # cylinder bonds was not pretty enough, so I made a "drum2" which is just + # drum0 with a 1.0 Z coordinate, a la drum1. + #bruce 060609: this apparently introduced the bug of the drum1 end-cap of a cylinder being "ragged" + # (letting empty space show through), which I fixed by using drum2 for that cap rather than drum1. + # drum1 is no longer used except as an intermediate value in the next few lines. + drawing_globals.drum2 = drum2 = map((lambda a: (cos(a), sin(a), 1.0)), circ1) + + # This edge list zips up the "top" vertex and normal and then + # the "bottom" vertex and normal. + # Thus each tuple in the sequence would be (vtop, ntop, vbot, nbot) [grantham 20051213] + # (bruce 051215 simplified the python usage in a way which should create the same list.) + drawing_globals.cylinderEdges = zip(drum0, drum0, drum2, drum0) + + circle = zip(drum0[:-1],drum0[1:],drum1[:-1]) +\ + zip(drum1[:-1],drum0[1:],drum1[1:]) + circlen = zip(drum0[:-1],drum0[1:],drum1n[:-1]) +\ + zip(drum1n[:-1],drum0[1:],drum1n[1:]) + + drawing_globals.cap0n = (0.0, 0.0, -1.0) + drawing_globals.cap1n = (0.0, 0.0, 1.0) + drum0.reverse() + return +init_cyls() + +def init_motors(): + ###data structure to construct the rotation sign for rotary motor + numSeg = 20 + rotS = map((lambda n: pi/2+n*2.0*pi/numSeg), range(numSeg*3/4 + 1)) + zOffset = 0.005 + scaleS = 0.4 + drawing_globals.rotS0n = rotS0n = map( + (lambda a: (scaleS*cos(a), scaleS*sin(a), 0.0 - zOffset)), rotS) + drawing_globals.rotS1n = rotS1n = map( + (lambda a: (scaleS*cos(a), scaleS*sin(a), 1.0 + zOffset)), rotS) + + ###Linear motor arrow sign data structure + drawing_globals.halfHeight = 0.45 + drawing_globals.halfEdge = halfEdge = 3.0 * scaleS * sin(pi/numSeg) + + arrow0Vertices = [ + (rotS0n[-1][0]-halfEdge, rotS0n[-1][1], rotS0n[-1][2]), + (rotS0n[-1][0]+halfEdge, rotS0n[-1][1], rotS0n[-1][2]), + (rotS0n[-1][0], rotS0n[-1][1] + 2.0*halfEdge, rotS0n[-1][2])] + arrow0Vertices.reverse() + drawing_globals.arrow0Vertices = arrow0Vertices + + drawing_globals.arrow1Vertices = [ + (rotS1n[-1][0]-halfEdge, rotS1n[-1][1], rotS1n[-1][2]), + (rotS1n[-1][0]+halfEdge, rotS1n[-1][1], rotS1n[-1][2]), + (rotS1n[-1][0], rotS1n[-1][1] + 2.0*halfEdge, rotS1n[-1][2])] + + drawing_globals.halfEdge = halfEdge = 1.0/3.0 ##1.0/8.0 + drawing_globals.linearArrowVertices = [ + (0.0, -halfEdge, 0.0), (0.0, halfEdge, 0.0), (0.0, 0.0,2*halfEdge)] + + return +init_motors() + +def init_diamond(): + # a chunk of diamond grid, to be tiled out in 3d + drawing_globals.sp0 = sp0 = 0.0 + #bruce 051102 replaced 1.52 with this constant (1.544), re bug 900 (partial fix) + drawing_globals.sp1 = sp1 = DIAMOND_BOND_LENGTH / sqrt(3.0) + sp2 = 2.0*sp1 + sp3 = 3.0*sp1 + drawing_globals.sp4 = sp4 = 4.0*sp1 + + digrid=[[[sp0, sp0, sp0], [sp1, sp1, sp1]], [[sp1, sp1, sp1], [sp2, sp2, sp0]], + [[sp2, sp2, sp0], [sp3, sp3, sp1]], [[sp3, sp3, sp1], [sp4, sp4, sp0]], + [[sp2, sp0, sp2], [sp3, sp1, sp3]], [[sp3, sp1, sp3], [sp4, sp2, sp2]], + [[sp2, sp0, sp2], [sp1, sp1, sp1]], [[sp1, sp1, sp1], [sp0, sp2, sp2]], + [[sp0, sp2, sp2], [sp1, sp3, sp3]], [[sp1, sp3, sp3], [sp2, sp4, sp2]], + [[sp2, sp4, sp2], [sp3, sp3, sp1]], [[sp3, sp3, sp1], [sp4, sp2, sp2]], + [[sp4, sp0, sp4], [sp3, sp1, sp3]], [[sp3, sp1, sp3], [sp2, sp2, sp4]], + [[sp2, sp2, sp4], [sp1, sp3, sp3]], [[sp1, sp3, sp3], [sp0, sp4, sp4]]] + drawing_globals.digrid = A(digrid) + drawing_globals.DiGridSp = sp4 + return +init_diamond() + +def init_cube(): + drawing_globals.cubeVertices = cubeVertices = [ + [-1.0, 1.0, -1.0], [-1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, -1.0], + [-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, -1.0, -1.0]] + + #bruce 051117: compute this rather than letting a subroutine hardcode it as + # a redundant constant + flatCubeVertices = [] + for threemore in cubeVertices: + flatCubeVertices.extend(threemore) + flatCubeVertices = list(flatCubeVertices) #k probably not needed + drawing_globals.flatCubeVertices = flatCubeVertices + + if 1: # remove this when it works + flatCubeVertices_hardcoded = [-1.0, 1.0, -1.0, + -1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, + 1.0, 1.0, -1.0, + -1.0, -1.0, -1.0, + -1.0, -1.0, 1.0, + 1.0, -1.0, 1.0, + 1.0, -1.0, -1.0] + assert flatCubeVertices == flatCubeVertices_hardcoded + + sq3 = sqrt(3.0)/3.0 + drawing_globals.cubeNormals = [ + [-sq3, sq3, -sq3], [-sq3, sq3, sq3], + [sq3, sq3, sq3], [sq3, sq3, -sq3], + [-sq3, -sq3, -sq3], [-sq3, -sq3, sq3], + [sq3, -sq3, sq3], [sq3, -sq3, -sq3]] + drawing_globals.cubeIndices = [ + [0, 1, 2, 3], [0, 4, 5, 1], [1, 5, 6, 2], + [2, 6, 7, 3], [0, 3, 7, 4], [4, 7, 6, 5]] + + return +init_cube() + + +# Some variables used by the Lonsdaleite lattice construction. +ux = 1.262; uy = 0.729; dz = 0.5153; ul = 1.544 +drawing_globals.XLen = XLen = 2*ux +drawing_globals.YLen = YLen = 6*uy +drawing_globals.ZLen = ZLen = 2*(ul + dz) + +def _makeLonsCell(): + """Data structure to construct a Lonsdaleite lattice cell""" + lVp = [# 2 outward vertices + [-ux, -2*uy, 0.0], [0.0, uy, 0.0], + # Layer 1: 7 vertices + [ux, -2*uy, ul], [-ux, -2*uy, ul], [0.0, uy, ul], + [ux, 2*uy, ul+dz], [-ux, 2*uy, ul+dz], [0.0, -uy, ul+dz], + [-ux, 4*uy, ul], + # Layer 2: 7 vertices + [ux, -2*uy, 2*(ul+dz)], [-ux, -2*uy, 2*(ul+dz)], [0.0, uy, 2*(ul+dz)], + [ux, 2*uy, 2*ul+dz], [-ux, 2*uy, 2*ul+dz], [0.0, -uy, 2*ul+dz], + [-ux, 4*uy, 2*(ul+dz)] + ] + + res = [ # 2 outward vertical edges for layer 1 + [lVp[0], lVp[3]], [lVp[1], lVp[4]], + # 6 xy Edges for layer 1 + [lVp[2], lVp[7]], [lVp[3], lVp[7]], [lVp[7], lVp[4]], + [lVp[4], lVp[6]], [lVp[4], lVp[5]], + [lVp[6], lVp[8]], + # 2 outward vertical edges for layer 2 + [lVp[14], lVp[7]], [lVp[13], lVp[6]], + # 6 xy Edges for layer 2 + [lVp[14], lVp[9]], [lVp[14], lVp[10]], [lVp[14], lVp[11]], + [lVp[11], lVp[13]], [lVp[11], lVp[12]], + [lVp[13], lVp[15]] + ] + return res +drawing_globals.lonsEdges = _makeLonsCell() diff --git a/cad/src/graphics/widgets/GLPane.py b/cad/src/graphics/widgets/GLPane.py index df10c8fd0..693e34d3f 100755 --- a/cad/src/graphics/widgets/GLPane.py +++ b/cad/src/graphics/widgets/GLPane.py @@ -128,18 +128,18 @@ from geometry.VQT import V, Q, A, norm, vlen, angleBetween from Numeric import dot import graphics.drawing.drawing_globals as drawing_globals -from graphics.drawing.drawer import glprefs_data_used_by_setup_standard_lights -from graphics.drawing.drawer import drawwiresphere -from graphics.drawing.drawer import drawFullWindow -from graphics.drawing.drawer import drawOriginAsSmallAxis -from graphics.drawing.drawer import drawaxes -from graphics.drawing.drawer import _default_lights -from graphics.drawing.drawer import disable_fog -from graphics.drawing.drawer import enable_fog -from graphics.drawing.drawer import setup_fog -from graphics.drawing.drawer import setup_standard_lights -from graphics.drawing.drawer import glprefs -from graphics.drawing.drawer import setup_drawer +from graphics.drawing.gl_lighting import glprefs_data_used_by_setup_standard_lights +from graphics.drawing.CS_draw_primitives import drawwiresphere +from graphics.drawing.drawers import drawFullWindow +from graphics.drawing.drawers import drawOriginAsSmallAxis +from graphics.drawing.drawers import drawaxes +from graphics.drawing.gl_lighting import _default_lights +from graphics.drawing.gl_lighting import disable_fog +from graphics.drawing.gl_lighting import enable_fog +from graphics.drawing.gl_lighting import setup_fog +from graphics.drawing.gl_lighting import setup_standard_lights +from graphics.drawing.glprefs import glprefs +from graphics.drawing.setup_draw import setup_drawer # note: the list of preloaded_command_classes for the Command Sequencer # has been moved from here (where it didn't belong) to a new file, diff --git a/cad/src/graphics/widgets/GLPane_minimal.py b/cad/src/graphics/widgets/GLPane_minimal.py index c1090a850..cd0e26015 100644 --- a/cad/src/graphics/widgets/GLPane_minimal.py +++ b/cad/src/graphics/widgets/GLPane_minimal.py @@ -31,7 +31,7 @@ from utilities.debug import print_compact_traceback import foundation.env as env -from graphics.drawing.drawer import setup_drawer +from graphics.drawing.setup_draw import setup_drawer from graphics.drawing.draw_grid_lines import setup_draw_grid_lines DEPTH_TWEAK_UNITS = (2.0)**(-32) diff --git a/cad/src/graphics/widgets/ThumbView.py b/cad/src/graphics/widgets/ThumbView.py index d85139d34..6a899630e 100755 --- a/cad/src/graphics/widgets/ThumbView.py +++ b/cad/src/graphics/widgets/ThumbView.py @@ -64,10 +64,10 @@ from OpenGL.GLU import gluPickMatrix, gluUnProject from PyQt4.Qt import Qt from geometry.VQT import V, Q, A -from graphics.drawing.drawer import drawFullWindow -from graphics.drawing.drawer import _default_lights -from graphics.drawing.drawer import setup_standard_lights -from graphics.drawing.drawer import setup_drawer +from graphics.drawing.drawers import drawFullWindow +from graphics.drawing.gl_lighting import _default_lights +from graphics.drawing.gl_lighting import setup_standard_lights +from graphics.drawing.setup_draw import setup_drawer from model.assembly import Assembly import foundation.env as env from utilities import debug_flags diff --git a/cad/src/model/Line.py b/cad/src/model/Line.py index ffc430d61..cd5ec3fb3 100755 --- a/cad/src/model/Line.py +++ b/cad/src/model/Line.py @@ -14,7 +14,7 @@ import foundation.env as env from OpenGL.GL import glPushMatrix from OpenGL.GL import glPopMatrix from OpenGL.GLU import gluProject, gluUnProject -from graphics.drawing.drawer import drawPolyLine +from graphics.drawing.drawers import drawPolyLine from Numeric import dot from math import pi, cos diff --git a/cad/src/model/Plane.py b/cad/src/model/Plane.py index cff5de1be..6f948e7cb 100755 --- a/cad/src/model/Plane.py +++ b/cad/src/model/Plane.py @@ -24,7 +24,8 @@ from OpenGL.GL import glPopMatrix from OpenGL.GL import glTranslatef from OpenGL.GL import glRotatef -from graphics.drawing.drawer import drawLineLoop, drawPlane +from graphics.drawing.drawers import drawLineLoop +from graphics.drawing.drawers import drawPlane from utilities.constants import black, orange, yellow, darkgreen, brown from geometry.VQT import V, Q, cross, planeXline, vlen, norm, ptonline diff --git a/cad/src/model/chem.py b/cad/src/model/chem.py index 8fc8e7550..6cabc3832 100755 --- a/cad/src/model/chem.py +++ b/cad/src/model/chem.py @@ -56,11 +56,11 @@ import string from OpenGL.GL import glPushName from OpenGL.GL import glPopName -from graphics.drawing.drawer import ColorSorter -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawsphere -from graphics.drawing.drawer import drawpolycone -from graphics.drawing.drawer import drawwiresphere +from graphics.drawing.ColorSorter import ColorSorter +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawsphere +from graphics.drawing.CS_draw_primitives import drawpolycone +from graphics.drawing.CS_draw_primitives import drawwiresphere from model.elements import Singlet from model.elements import Hydrogen diff --git a/cad/src/model/chunk.py b/cad/src/model/chunk.py index 560257fc5..0278bcb0e 100755 --- a/cad/src/model/chunk.py +++ b/cad/src/model/chunk.py @@ -107,8 +107,8 @@ import model.bonds as bonds # TODO: import specific functions, since no longer a from model.elements import Singlet from geometry.BoundingBox import BBox -from graphics.drawing.drawer import ColorSorter -from graphics.drawing.drawer import ColorSortedDisplayList +from graphics.drawing.ColorSorter import ColorSorter +from graphics.drawing.ColorSorter import ColorSortedDisplayList ##from drawer import drawlinelist ##from constants import PickedColor @@ -145,7 +145,7 @@ from dna.model.Dna_Constants import getComplementSequence from operations.bond_chains import grow_directional_bond_chain import graphics.drawing.drawing_globals as drawing_globals -from graphics.drawing.drawer import apply_material +from graphics.drawing.gl_lighting import apply_material from graphics.drawables.Selobj import Selobj_API diff --git a/cad/src/model/jigs.py b/cad/src/model/jigs.py index fab764c00..cdb223e67 100755 --- a/cad/src/model/jigs.py +++ b/cad/src/model/jigs.py @@ -52,7 +52,7 @@ from utilities.Log import orangemsg from graphics.rendering.povray.povheader import povpoint from utilities.debug import print_compact_stack, print_compact_traceback import foundation.env as env -from graphics.drawing.drawer import drawwirecube +from graphics.drawing.drawers import drawwirecube from utilities.constants import gensym from utilities.constants import darkgreen diff --git a/cad/src/model/jigs_measurements.py b/cad/src/model/jigs_measurements.py index 1d0073381..10513e4cd 100755 --- a/cad/src/model/jigs_measurements.py +++ b/cad/src/model/jigs_measurements.py @@ -34,7 +34,7 @@ from utilities.Log import redmsg, greenmsg, orangemsg from utilities.debug import print_compact_stack, print_compact_traceback from model.jigs import Jig from graphics.drawing.dimensions import drawLinearDimension, drawAngleDimension, drawDihedralDimension -from graphics.drawing.drawer import drawtext +from graphics.drawing.drawers import drawtext from utilities.constants import black from utilities.prefs_constants import dynamicToolTipAtomDistancePrecision_prefs_key diff --git a/cad/src/model/jigs_motors.py b/cad/src/model/jigs_motors.py index 78dc6946b..6947c6427 100755 --- a/cad/src/model/jigs_motors.py +++ b/cad/src/model/jigs_motors.py @@ -26,10 +26,10 @@ from OpenGL.GL import glPopMatrix import foundation.env as env from geometry.VQT import V, Q, A, norm, cross, vlen -from graphics.drawing.drawer import drawcylinder -from graphics.drawing.drawer import drawRotateSign -from graphics.drawing.drawer import drawbrick -from graphics.drawing.drawer import drawLinearSign +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.drawers import drawRotateSign +from graphics.drawing.drawers import drawbrick +from graphics.drawing.drawers import drawLinearSign from utilities.Log import orangemsg from utilities.Log import redmsg, greenmsg diff --git a/cad/src/model/jigs_planes.py b/cad/src/model/jigs_planes.py index 7d33a4e8a..378fdfd7c 100755 --- a/cad/src/model/jigs_planes.py +++ b/cad/src/model/jigs_planes.py @@ -26,7 +26,7 @@ from OpenGL.GL import glTranslatef from OpenGL.GL import glRotatef from OpenGL.GL import glPopMatrix -from graphics.drawing.drawer import drawLineLoop +from graphics.drawing.drawers import drawLineLoop from graphics.drawing.draw_grid_lines import drawGPGrid from graphics.drawing.draw_grid_lines import drawSiCGrid diff --git a/cad/src/model/virtual_site_indicators.py b/cad/src/model/virtual_site_indicators.py index 0b92f48d6..013b1057d 100644 --- a/cad/src/model/virtual_site_indicators.py +++ b/cad/src/model/virtual_site_indicators.py @@ -12,7 +12,8 @@ not as part of their implementation for minimize. from model.jigs import Jig from utilities.constants import red, orange, yellow, average_value, ave_colors, blue, gray, darkgreen -from graphics.drawing.drawer import drawwirecube, drawline +from graphics.drawing.drawers import drawwirecube +from graphics.drawing.CS_draw_primitives import drawline from geometry.VQT import V, vlen from model.chunk import Chunk diff --git a/cad/src/ne1_ui/MWsemantics.py b/cad/src/ne1_ui/MWsemantics.py index e82920335..f197515b4 100755 --- a/cad/src/ne1_ui/MWsemantics.py +++ b/cad/src/ne1_ui/MWsemantics.py @@ -37,7 +37,7 @@ from PyQt4.Qt import QStatusBar from model.elements import PeriodicTable from model.assembly import Assembly -from graphics.drawing.drawer import get_gl_info_string ## grantham 20051201 +from graphics.drawing.gl_lighting import get_gl_info_string ## grantham 20051201 import os, sys import time diff --git a/cad/src/prototype/example_expr_command.py b/cad/src/prototype/example_expr_command.py index 403901003..454a06279 100644 --- a/cad/src/prototype/example_expr_command.py +++ b/cad/src/prototype/example_expr_command.py @@ -58,7 +58,7 @@ class ExampleCommand2E_PM( ExampleCommand2_PM ): # these imports are not needed in a minimal example like ExampleCommand2: -from graphics.drawing.drawer import drawline +from graphics.drawing.CS_draw_primitives import drawline from utilities.constants import red from geometry.VQT import V from exprs.instance_helpers import get_glpane_InstanceHolder diff --git a/cad/src/prototype/test_connectWithState.py b/cad/src/prototype/test_connectWithState.py index 8342cce2a..211204163 100644 --- a/cad/src/prototype/test_connectWithState.py +++ b/cad/src/prototype/test_connectWithState.py @@ -61,8 +61,8 @@ from utilities.constants import pink, white DX = V(1,0,0) DY = V(0,1,0) ORIGIN = V(0,0,0) -from graphics.drawing.drawer import drawcylinder, drawsphere - +from graphics.drawing.CS_draw_primitives import drawcylinder +from graphics.drawing.CS_draw_primitives import drawsphere from exprs.ExprsMeta import ExprsMeta from exprs.instance_helpers import IorE_guest_mixin from exprs.attr_decl_macros import Instance, State diff --git a/cad/src/temporary_commands/LineMode.py b/cad/src/temporary_commands/LineMode.py index fe06ca48a..9247768c1 100644 --- a/cad/src/temporary_commands/LineMode.py +++ b/cad/src/temporary_commands/LineMode.py @@ -21,7 +21,8 @@ TODOs: from commands.Select.Select_Command import Select_Command from commands.Select.Select_GraphicsMode import Select_GraphicsMode -from graphics.drawing.drawer import drawline, drawsphere +from graphics.drawing.CS_draw_primitives import drawline +from graphics.drawing.CS_draw_primitives import drawsphere from utilities.constants import black, darkred, blue from geometry.VQT import vlen, norm, angleBetween, V, ptonline diff --git a/cad/src/temporary_commands/ZoomToAreaMode.py b/cad/src/temporary_commands/ZoomToAreaMode.py index de376b13e..2c0257334 100755 --- a/cad/src/temporary_commands/ZoomToAreaMode.py +++ b/cad/src/temporary_commands/ZoomToAreaMode.py @@ -28,7 +28,7 @@ from OpenGL.GL import glReadPixelsf from OpenGL.GLU import gluUnProject from geometry.VQT import V, A -from graphics.drawing.drawer import drawrectangle +from graphics.drawing.drawers import drawrectangle from utilities.constants import GL_FAR_Z |