bspy 4.0__py3-none-any.whl → 4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bspy/splineOpenGLFrame.py CHANGED
@@ -1,6 +1,8 @@
1
+ from collections import namedtuple
1
2
  import numpy as np
2
- import tkinter as tk
3
3
  from OpenGL.GL import *
4
+ from OpenGL.GLU import *
5
+ from bspy.manifold import Manifold
4
6
  import OpenGL.GL.shaders as shaders
5
7
  try:
6
8
  from pyopengltk import OpenGLFrame
@@ -958,6 +960,48 @@ class SplineOpenGLFrame(OpenGLFrame):
958
960
  discard;
959
961
  }
960
962
  """
963
+
964
+ trimmedSurfaceFragmentShaderCode = """
965
+ #version 410 core
966
+
967
+ flat in SplineInfo
968
+ {
969
+ int uOrder, vOrder;
970
+ int uN, vN;
971
+ int uKnot, vKnot;
972
+ float uFirst, vFirst;
973
+ float uSpan, vSpan;
974
+ float u, v;
975
+ float uInterval, vInterval;
976
+ } inData;
977
+ in vec3 worldPosition;
978
+ in vec3 splineColor;
979
+ in vec3 normal;
980
+ in vec2 parameters;
981
+ in vec2 pixelPer;
982
+
983
+ uniform vec4 uFillColor;
984
+ uniform vec4 uLineColor;
985
+ uniform vec3 uLightDirection;
986
+ uniform int uOptions;
987
+ uniform sampler2D uTrimTextureMap;
988
+
989
+ out vec4 color;
990
+
991
+ void main()
992
+ {
993
+ vec2 tex = vec2((parameters.x - inData.uFirst) / inData.uSpan, (parameters.y - inData.vFirst) / inData.vSpan);
994
+ float specular = pow(abs(dot(normal, normalize(uLightDirection + worldPosition / length(worldPosition)))), 25.0);
995
+ bool line = (uOptions & (1 << 2)) > 0 && (pixelPer.x * (parameters.x - inData.uFirst) < 1.5 || pixelPer.x * (inData.uFirst + inData.uSpan - parameters.x) < 1.5);
996
+ line = line || ((uOptions & (1 << 2)) > 0 && (pixelPer.y * (parameters.y - inData.vFirst) < 1.5 || pixelPer.y * (inData.vFirst + inData.vSpan - parameters.y) < 1.5));
997
+ line = line || ((uOptions & (1 << 3)) > 0 && pixelPer.x * (parameters.x - inData.u) < 1.5);
998
+ line = line || ((uOptions & (1 << 3)) > 0 && pixelPer.y * (parameters.y - inData.v) < 1.5);
999
+ color = line ? uLineColor : ((uOptions & (1 << 1)) > 0 ? vec4(splineColor, uFillColor.a) : vec4(0.0, 0.0, 0.0, 0.0));
1000
+ color.rgb = (0.3 + 0.5 * abs(dot(normal, uLightDirection)) + 0.2 * specular) * color.rgb;
1001
+ if (color.a * texture(uTrimTextureMap, tex).r == 0.0)
1002
+ discard;
1003
+ }
1004
+ """
961
1005
 
962
1006
  def __init__(self, *args, eye=(0.0, 0.0, 3.0), center=(0.0, 0.0, 0.0), up=(0.0, 1.0, 0.0), draw_func=None, **kw):
963
1007
  OpenGLFrame.__init__(self, *args, **kw)
@@ -972,6 +1016,9 @@ class SplineOpenGLFrame(OpenGLFrame):
972
1016
  self.origin = None
973
1017
  self.button = None
974
1018
  self.mode = self.ROTATE
1019
+
1020
+ self.computeBSplineCode = self.computeBSplineCode.format(maxOrder=self.maxOrder)
1021
+ self.computeSurfaceSamplesCode = self.computeSurfaceSamplesCode.format(maxOrder=self.maxOrder)
975
1022
 
976
1023
  self.SetBackgroundColor(0.0, 0.2, 0.2)
977
1024
 
@@ -1114,6 +1161,31 @@ class SplineOpenGLFrame(OpenGLFrame):
1114
1161
  #print("GL_SHADING_LANGUAGE_VERSION: ", glGetString(GL_SHADING_LANGUAGE_VERSION))
1115
1162
  #print("GL_MAX_TESS_GEN_LEVEL: ", glGetIntegerv(GL_MAX_TESS_GEN_LEVEL))
1116
1163
 
1164
+ # Set up frameBuffer into which we draw surface trims.
1165
+ self.frameBuffer = glGenFramebuffers(1)
1166
+ glBindFramebuffer(GL_FRAMEBUFFER, self.frameBuffer)
1167
+
1168
+ # Create the texture buffer for surface trims.
1169
+ self.trimTextureBuffer = glGenTextures(1)
1170
+ glActiveTexture(GL_TEXTURE1)
1171
+ glBindTexture(GL_TEXTURE_2D, self.trimTextureBuffer)
1172
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
1173
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
1174
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
1175
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
1176
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
1177
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 512, 512, 0, GL_RED, GL_UNSIGNED_BYTE, None)
1178
+ glActiveTexture(GL_TEXTURE0)
1179
+
1180
+ # Attach trim texture buffer to framebuffer and validate framebuffer.
1181
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, self.trimTextureBuffer, 0)
1182
+ glDrawBuffers(1, (GL_COLOR_ATTACHMENT0,))
1183
+ if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE:
1184
+ raise ValueError("Framebuffer incomplete")
1185
+
1186
+ # Set framebuffer back to default.
1187
+ glBindFramebuffer(GL_FRAMEBUFFER, 0)
1188
+
1117
1189
  # Set up GL texture buffer for spline data
1118
1190
  self.splineDataBuffer = glGenBuffers(1)
1119
1191
  self.splineTextureBuffer = glGenTextures(1)
@@ -1132,13 +1204,12 @@ class SplineOpenGLFrame(OpenGLFrame):
1132
1204
  glBufferData(GL_ARRAY_BUFFER, 4 * 4, np.array([0,0,0,0], np.float32), GL_STATIC_DRAW)
1133
1205
 
1134
1206
  # Compile shaders and link programs
1135
- self.computeBSplineCode = self.computeBSplineCode.format(maxOrder=self.maxOrder)
1136
- self.computeSurfaceSamplesCode = self.computeSurfaceSamplesCode.format(maxOrder=self.maxOrder)
1137
1207
  try:
1138
1208
  # Must create CurveProgram first, because it checks and potentially resets tessellationEnabled flag.
1139
1209
  self.curveProgram = CurveProgram(self)
1140
- self.surface3Program = SurfaceProgram(self, 3, "", "", "", "splineColor = uFillColor.rgb;")
1141
- self.surface4Program = SurfaceProgram(self, 4,
1210
+ self.surface3Program = SurfaceProgram(self, False, 3, "", "", "", "splineColor = uFillColor.rgb;")
1211
+ self.trimmedSurface3Program = SurfaceProgram(self, True, 3, "", "", "", "splineColor = uFillColor.rgb;")
1212
+ self.surface4Program = SurfaceProgram(self, False, 4,
1142
1213
  """
1143
1214
  vec4 kVec = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
1144
1215
  vec3 pVec;
@@ -1152,7 +1223,27 @@ class SplineOpenGLFrame(OpenGLFrame):
1152
1223
  pVec = abs(fract(uFillColor.xxx + kVec.xyz) * 6.0 - kVec.www);
1153
1224
  splineColor = uFillColor.z * mix(kVec.xxx, clamp(pVec - kVec.xxx, 0.0, 1.0), splineColor.r);
1154
1225
  """)
1155
- self.surface6Program = SurfaceProgram(self, 6, "", "splineColor = vec3(0.0, 0.0, 0.0);",
1226
+ self.trimmedSurface4Program = SurfaceProgram(self, True, 4,
1227
+ """
1228
+ vec4 kVec = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
1229
+ vec3 pVec;
1230
+ """, "splineColor = vec3(0.0, 0.0, 0.0);",
1231
+ """
1232
+ splineColor.r += uBSpline[uB] * vBSpline[vB] * texelFetch(uSplineData, i+3).x;
1233
+ """,
1234
+ # Taken from http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
1235
+ # uFillColor is passed in as HSV
1236
+ """
1237
+ pVec = abs(fract(uFillColor.xxx + kVec.xyz) * 6.0 - kVec.www);
1238
+ splineColor = uFillColor.z * mix(kVec.xxx, clamp(pVec - kVec.xxx, 0.0, 1.0), splineColor.r);
1239
+ """)
1240
+ self.surface6Program = SurfaceProgram(self, False, 6, "", "splineColor = vec3(0.0, 0.0, 0.0);",
1241
+ """
1242
+ splineColor.r += uBSpline[uB] * vBSpline[vB] * texelFetch(uSplineData, i+3).x;
1243
+ splineColor.g += uBSpline[uB] * vBSpline[vB] * texelFetch(uSplineData, i+4).x;
1244
+ splineColor.b += uBSpline[uB] * vBSpline[vB] * texelFetch(uSplineData, i+5).x;
1245
+ """, "")
1246
+ self.trimmedSurface6Program = SurfaceProgram(self, True, 6, "", "splineColor = vec3(0.0, 0.0, 0.0);",
1156
1247
  """
1157
1248
  splineColor.r += uBSpline[uB] * vBSpline[vB] * texelFetch(uSplineData, i+3).x;
1158
1249
  splineColor.g += uBSpline[uB] * vBSpline[vB] * texelFetch(uSplineData, i+4).x;
@@ -1168,6 +1259,7 @@ class SplineOpenGLFrame(OpenGLFrame):
1168
1259
  print(badLine)
1169
1260
  quit()
1170
1261
 
1262
+ # Set default draw parameters.
1171
1263
  glUseProgram(0)
1172
1264
  glEnable( GL_DEPTH_TEST )
1173
1265
  glClearColor(self.backgroundColor[0], self.backgroundColor[1], self.backgroundColor[2], self.backgroundColor[3])
@@ -1185,7 +1277,7 @@ class SplineOpenGLFrame(OpenGLFrame):
1185
1277
  defaultAnchorDistance = np.linalg.norm(self.defaultEye - self.defaultCenter)
1186
1278
  clipDistance = defaultAnchorDistance / np.sqrt(3.0)
1187
1279
  near = 0.01 * defaultAnchorDistance / 3.0
1188
- far = defaultAnchorDistance + clipDistance
1280
+ far = 3.0 * defaultAnchorDistance
1189
1281
  top = clipDistance * near / defaultAnchorDistance # Choose frustum that displays [-clipDistance,clipDistance] in y for z = -defaultAnchorDistance
1190
1282
  glFrustum(-top*xExtent, top*xExtent, -top, top, near, far)
1191
1283
  #glOrtho(-xExtent, xExtent, -1.0, 1.0, -1.0, 1.0)
@@ -1196,8 +1288,11 @@ class SplineOpenGLFrame(OpenGLFrame):
1196
1288
 
1197
1289
  self.curveProgram.ResetBounds(self)
1198
1290
  self.surface3Program.ResetBounds(self)
1291
+ self.trimmedSurface3Program.ResetBounds(self)
1199
1292
  self.surface4Program.ResetBounds(self)
1293
+ self.trimmedSurface4Program.ResetBounds(self)
1200
1294
  self.surface6Program.ResetBounds(self)
1295
+ self.trimmedSurface6Program.ResetBounds(self)
1201
1296
 
1202
1297
  glUseProgram(0)
1203
1298
  glMatrixMode(GL_MODELVIEW)
@@ -1449,6 +1544,122 @@ class SplineOpenGLFrame(OpenGLFrame):
1449
1544
  if not "animate" in spline.metadata:
1450
1545
  spline.metadata["animate"] = None
1451
1546
 
1547
+ @staticmethod
1548
+ def tessellate2DSolid(solid):
1549
+ """
1550
+ Returns an array of triangles that tessellate the given 2D solid
1551
+ """
1552
+ assert solid.dimension == 2
1553
+ assert solid.containsInfinity == False
1554
+
1555
+ # First, collect all manifold contour endpoints, accounting for slight numerical error.
1556
+ class Endpoint:
1557
+ def __init__(self, curve, t, clockwise, isStart, otherEnd=None):
1558
+ self.curve = curve
1559
+ self.t = t
1560
+ self.xy = curve.manifold.evaluate((t,))
1561
+ self.clockwise = clockwise
1562
+ self.isStart = isStart
1563
+ self.otherEnd = otherEnd
1564
+ self.connection = None
1565
+ endpoints = []
1566
+ for curve in solid.boundaries:
1567
+ curve.domain.boundaries.sort(key=lambda boundary: (boundary.manifold.evaluate(0.0), -boundary.manifold.normal(0.0)))
1568
+ leftB = 0
1569
+ rightB = 0
1570
+ boundaryCount = len(curve.domain.boundaries)
1571
+ while leftB < boundaryCount:
1572
+ if curve.domain.boundaries[leftB].manifold.normal(0.0) < 0.0:
1573
+ leftPoint = curve.domain.boundaries[leftB].manifold.evaluate(0.0)[0]
1574
+ while rightB < boundaryCount:
1575
+ rightPoint = curve.domain.boundaries[rightB].manifold.evaluate(0.0)[0]
1576
+ if leftPoint - Manifold.minSeparation < rightPoint and curve.domain.boundaries[rightB].manifold.normal(0.0) > 0.0:
1577
+ t = curve.manifold.tangent_space(leftPoint)[:,0]
1578
+ n = curve.manifold.normal(leftPoint)
1579
+ clockwise = t[0] * n[1] - t[1] * n[0] > 0.0
1580
+ ep1 = Endpoint(curve, leftPoint, clockwise, rightPoint >= leftPoint)
1581
+ ep2 = Endpoint(curve, rightPoint, clockwise, rightPoint < leftPoint, ep1)
1582
+ ep1.otherEnd = ep2
1583
+ endpoints.append(ep1)
1584
+ endpoints.append(ep2)
1585
+ leftB = rightB
1586
+ rightB += 1
1587
+ break
1588
+ rightB += 1
1589
+ leftB += 1
1590
+
1591
+ # Second, collect all valid pairings of endpoints (normal not flipped between segments).
1592
+ Connection = namedtuple('Connection', ('distance', 'ep1', 'ep2'))
1593
+ connections = []
1594
+ for i, ep1 in enumerate(endpoints[:-1]):
1595
+ for ep2 in endpoints[i+1:]:
1596
+ if (ep1.clockwise == ep2.clockwise and ep1.isStart != ep2.isStart) or \
1597
+ (ep1.clockwise != ep2.clockwise and ep1.isStart == ep2.isStart):
1598
+ connections.append(Connection(np.linalg.norm(ep1.xy - ep2.xy), ep1, ep2))
1599
+
1600
+ # Third, only keep closest pairings (prune the rest).
1601
+ connections.sort(key=lambda connection: -connection.distance)
1602
+ while connections:
1603
+ connection = connections.pop()
1604
+ connection.ep1.connection = connection.ep2
1605
+ connection.ep2.connection = connection.ep1
1606
+ connections = [c for c in connections if c.ep1 is not connection.ep1 and c.ep1 is not connection.ep2 and \
1607
+ c.ep2 is not connection.ep1 and c.ep2 is not connection.ep2]
1608
+
1609
+ # Fourth, set up GLUT to tesselate the solid.
1610
+ tess = gluNewTess()
1611
+ gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD)
1612
+ vertices = []
1613
+ def beginCallback(type=None):
1614
+ vertices = []
1615
+ def edgeFlagDataCallback(flag, polygonData):
1616
+ pass # Forces triangulation of polygons rather than triangle fans or strips
1617
+ def vertexCallback(vertex, otherData=None):
1618
+ vertices.append(vertex[:2])
1619
+ def combineCallback(vertex, neighbors, neighborWeights, outData=None):
1620
+ outData = vertex
1621
+ return outData
1622
+ def endCallback():
1623
+ pass
1624
+ gluTessCallback(tess, GLU_TESS_BEGIN, beginCallback)
1625
+ gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, edgeFlagDataCallback)
1626
+ gluTessCallback(tess, GLU_TESS_VERTEX, vertexCallback)
1627
+ gluTessCallback(tess, GLU_TESS_COMBINE, combineCallback)
1628
+ gluTessCallback(tess, GLU_TESS_END, endCallback)
1629
+
1630
+ # Fifth, trace the contours from pairing to pairing, using GLUT to tesselate the interior.
1631
+ gluTessBeginPolygon(tess, 0)
1632
+ while endpoints:
1633
+ start = endpoints[0]
1634
+ if not start.isStart:
1635
+ start = start.otherEnd
1636
+ # Run backwards until you hit start again or hit an end.
1637
+ if start.connection is not None:
1638
+ originalStart = start
1639
+ next = start.connection
1640
+ start = None
1641
+ while next is not None and start is not originalStart:
1642
+ start = next.otherEnd
1643
+ next = start.connection
1644
+ # Run forwards submitting vertices for the contour.
1645
+ next = start
1646
+ gluTessBeginContour(tess)
1647
+ while next is not None:
1648
+ endpoints.remove(next)
1649
+ endpoints.remove(next.otherEnd)
1650
+ subdivisions = max(int(abs(next.otherEnd.t - next.t) / 0.1), 20) if isinstance(next.curve.manifold, Spline) else 2
1651
+ for t in np.linspace(next.t, next.otherEnd.t, subdivisions):
1652
+ xy = next.curve.manifold.evaluate((t,))
1653
+ vertex = (*xy, 0.0)
1654
+ gluTessVertex(tess, vertex, vertex)
1655
+ next = next.otherEnd.connection
1656
+ if next is start:
1657
+ break
1658
+ gluTessEndContour(tess)
1659
+ gluTessEndPolygon(tess)
1660
+ gluDeleteTess(tess)
1661
+ return np.array(vertices, np.float32)
1662
+
1452
1663
  def _DrawPoints(self, spline, drawCoefficients):
1453
1664
  """
1454
1665
  Draw spline points for an nInd == 0 or order == 1 spline within a `SplineOpenGLFrame`. The self will call this method for you.
@@ -1530,14 +1741,15 @@ class SplineOpenGLFrame(OpenGLFrame):
1530
1741
  fillColor = spline.metadata["fillColor"]
1531
1742
  if spline.nDep <= 3:
1532
1743
  nDep = 3
1533
- program = self.surface3Program
1744
+ program = self.trimmedSurface3Program if "trim" in spline.cache else self.surface3Program
1534
1745
  elif spline.nDep == 4:
1535
1746
  nDep = 4
1747
+ program = self.trimmedSurface4Program if "trim" in spline.cache else self.surface4Program
1536
1748
  program = self.surface4Program
1537
1749
  fillColor = self.ConvertRGBToHSV(fillColor[0], fillColor[1], fillColor[2], fillColor[3])
1538
1750
  elif spline.nDep <= 6:
1539
1751
  nDep = 6
1540
- program = self.surface6Program
1752
+ program = self.trimmedSurface6Program if "trim" in spline.cache else self.surface6Program
1541
1753
  else:
1542
1754
  raise ValueError("Can't draw surface.")
1543
1755
 
@@ -1595,14 +1807,15 @@ class SplineOpenGLFrame(OpenGLFrame):
1595
1807
  lineColor = spline.metadata["lineColor"].copy()
1596
1808
  if spline.nDep <= 3:
1597
1809
  nDep = 3
1598
- program = self.surface3Program
1810
+ program = self.trimmedSurface3Program if "trim" in spline.cache else self.surface3Program
1599
1811
  elif spline.nDep == 4:
1600
1812
  nDep = 4
1813
+ program = self.trimmedSurface4Program if "trim" in spline.cache else self.surface4Program
1601
1814
  program = self.surface4Program
1602
1815
  fillColor = self.ConvertRGBToHSV(fillColor[0], fillColor[1], fillColor[2], fillColor[3])
1603
1816
  elif spline.nDep <= 6:
1604
1817
  nDep = 6
1605
- program = self.surface6Program
1818
+ program = self.trimmedSurface6Program if "trim" in spline.cache else self.surface6Program
1606
1819
  else:
1607
1820
  raise ValueError("Can't draw surface.")
1608
1821
  fillColor[3] *= 0.5
@@ -1669,6 +1882,33 @@ class SplineOpenGLFrame(OpenGLFrame):
1669
1882
  """
1670
1883
  Draw a spline within a `SplineOpenGLFrame`.
1671
1884
  """
1885
+ # Fill trim stencil.
1886
+ if "trim" in spline.cache:
1887
+ # Draw trim tessellation into trim texture framebuffer.
1888
+ glBindFramebuffer(GL_FRAMEBUFFER, self.frameBuffer)
1889
+ glDisable(GL_DEPTH_TEST)
1890
+ glViewport(0,0,512,512)
1891
+ glClearColor(0.0, 0.0, 0.0, 1.0)
1892
+ glClear(GL_COLOR_BUFFER_BIT)
1893
+ glMatrixMode(GL_PROJECTION)
1894
+ glLoadIdentity()
1895
+ bounds = spline.domain()
1896
+ glOrtho(bounds[0, 0], bounds[0, 1], bounds[1, 0], bounds[1, 1], -1.0, 1.0)
1897
+ glColor3f(1.0, 0.0, 0.0)
1898
+ glBegin(GL_TRIANGLES)
1899
+ for vertex in spline.cache["trim"]:
1900
+ glVertex2fv(vertex)
1901
+ glEnd()
1902
+ glFlush()
1903
+ # Reset view for main framebuffer.
1904
+ glBindFramebuffer(GL_FRAMEBUFFER, 0)
1905
+ glEnable(GL_DEPTH_TEST)
1906
+ glViewport(0, 0, self.width, self.height)
1907
+ glClearColor(self.backgroundColor[0], self.backgroundColor[1], self.backgroundColor[2], self.backgroundColor[3])
1908
+ glMatrixMode(GL_PROJECTION)
1909
+ glLoadMatrixf(self.projection)
1910
+ glMatrixMode(GL_MODELVIEW)
1911
+
1672
1912
  # Retrieve transposed float32 coefficients.
1673
1913
  coefs = spline.cache["coefs32"]
1674
1914
 
@@ -1754,8 +1994,12 @@ class CurveProgram:
1754
1994
 
1755
1995
  class SurfaceProgram:
1756
1996
  """ Compile surface program """
1757
- def __init__(self, frame, nDep, splineColorDeclarations, initializeSplineColor, computeSplineColor, postProcessSplineColor):
1997
+ def __init__(self, frame, trimmed, nDep, splineColorDeclarations, initializeSplineColor, computeSplineColor, postProcessSplineColor):
1758
1998
  if frame.tessellationEnabled:
1999
+ if trimmed:
2000
+ compiledFragmentShader = shaders.compileShader(frame.trimmedSurfaceFragmentShaderCode, GL_FRAGMENT_SHADER)
2001
+ else:
2002
+ compiledFragmentShader = shaders.compileShader(frame.surfaceFragmentShaderCode, GL_FRAGMENT_SHADER)
1759
2003
  self.surfaceProgram = shaders.compileProgram(
1760
2004
  shaders.compileShader(frame.surfaceVertexShaderCode, GL_VERTEX_SHADER),
1761
2005
  shaders.compileShader(frame.surfaceTCShaderCode.format(
@@ -1770,7 +2014,7 @@ class SurfaceProgram:
1770
2014
  computeSplineColor=computeSplineColor,
1771
2015
  postProcessSplineColor=postProcessSplineColor,
1772
2016
  maxOrder=frame.maxOrder), GL_TESS_EVALUATION_SHADER),
1773
- shaders.compileShader(frame.surfaceFragmentShaderCode, GL_FRAGMENT_SHADER),
2017
+ compiledFragmentShader,
1774
2018
  validate = False)
1775
2019
  else:
1776
2020
  self.surfaceProgram = shaders.compileProgram(
@@ -1787,6 +2031,7 @@ class SurfaceProgram:
1787
2031
  maxOrder=frame.maxOrder), GL_GEOMETRY_SHADER),
1788
2032
  shaders.compileShader(frame.surfaceSimpleFragmentShaderCode, GL_FRAGMENT_SHADER))
1789
2033
 
2034
+ # Initialize program parameters.
1790
2035
  glUseProgram(self.surfaceProgram)
1791
2036
  self.aSurfaceParameters = glGetAttribLocation(self.surfaceProgram, "aParameters")
1792
2037
  glBindBuffer(GL_ARRAY_BUFFER, frame.parameterBuffer)
@@ -1800,7 +2045,10 @@ class SurfaceProgram:
1800
2045
  self.uSurfaceOptions = glGetUniformLocation(self.surfaceProgram, 'uOptions')
1801
2046
  self.uSurfaceSplineData = glGetUniformLocation(self.surfaceProgram, 'uSplineData')
1802
2047
  glUniform1i(self.uSurfaceSplineData, 0) # GL_TEXTURE0 is the spline buffer texture
1803
-
2048
+ if trimmed and frame.tessellationEnabled:
2049
+ self.uTrimTextureMap = glGetUniformLocation(self.surfaceProgram, 'uTrimTextureMap')
2050
+ glUniform1i(self.uTrimTextureMap, 1) # GL_TEXTURE1 is the trim texture map
2051
+
1804
2052
  def ResetBounds(self, frame):
1805
2053
  """Reset bounds and other frame configuration for surface program"""
1806
2054
  glUseProgram(self.surfaceProgram)