mirror of https://github.com/kivy/kivy.git
svg: fixed vertex glitch (bad absolute position was pushed). And experiment smooth line by default for strokes.
This commit is contained in:
parent
75e3ce77ea
commit
d929a8f0df
|
@ -0,0 +1,18 @@
|
|||
from kivy.core.window import Window
|
||||
from kivy.graphics.svg import Svg
|
||||
from time import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
filename = sys.argv[1]
|
||||
if "PROFILE" in os.environ:
|
||||
import pstats, cProfile
|
||||
cProfile.runctx("Svg(filename)", globals(), locals(), "Profile.prof")
|
||||
s = pstats.Stats("Profile.prof")
|
||||
s.strip_dirs().sort_stats("time").print_callers()
|
||||
else:
|
||||
print("Loading {}".format(filename))
|
||||
start = time()
|
||||
svg = Svg(filename)
|
||||
end = time()
|
||||
print("Loaded in {:.2f}s".format((end - start)))
|
|
@ -0,0 +1,154 @@
|
|||
import sys
|
||||
from glob import glob
|
||||
from os.path import join, dirname
|
||||
from kivy.uix.scatter import Scatter
|
||||
from kivy.uix.widget import Widget
|
||||
from kivy.uix.label import Label
|
||||
from kivy.app import App
|
||||
from kivy.graphics.svg import Svg
|
||||
from kivy.core.window import Window
|
||||
from kivy.uix.floatlayout import FloatLayout
|
||||
from kivy.lang import Builder
|
||||
|
||||
|
||||
smaa_ui = '''
|
||||
#:kivy 1.8.0
|
||||
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
pos_hint: {'top': 1}
|
||||
size_hint_y: None
|
||||
height: '48dp'
|
||||
padding: '2dp'
|
||||
spacing: '2dp'
|
||||
Label:
|
||||
text: 'Quality:'
|
||||
ToggleButton:
|
||||
text: 'Low'
|
||||
group: 'smaa-quality'
|
||||
on_release: app.smaa.quality = 'low'
|
||||
ToggleButton:
|
||||
text: 'Medium'
|
||||
group: 'smaa-quality'
|
||||
on_release: app.smaa.quality = 'medium'
|
||||
ToggleButton:
|
||||
text: 'High'
|
||||
group: 'smaa-quality'
|
||||
on_release: app.smaa.quality = 'high'
|
||||
ToggleButton:
|
||||
text: 'Ultra'
|
||||
group: 'smaa-quality'
|
||||
state: 'down'
|
||||
on_release: app.smaa.quality = 'ultra'
|
||||
|
||||
Label:
|
||||
text: 'Debug:'
|
||||
ToggleButton:
|
||||
text: 'None'
|
||||
group: 'smaa-debug'
|
||||
state: 'down'
|
||||
on_release: app.smaa.debug = ''
|
||||
ToggleButton:
|
||||
text: 'Source'
|
||||
group: 'smaa-debug'
|
||||
on_release: app.smaa.debug = 'source'
|
||||
ToggleButton:
|
||||
text: 'Edges'
|
||||
group: 'smaa-debug'
|
||||
on_release: app.smaa.debug = 'edges'
|
||||
ToggleButton:
|
||||
text: 'Blend'
|
||||
group: 'smaa-debug'
|
||||
on_release: app.smaa.debug = 'blend'
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class SvgWidget(Scatter):
|
||||
|
||||
def __init__(self, filename):
|
||||
super(SvgWidget, self).__init__()
|
||||
with self.canvas:
|
||||
svg = Svg(filename)
|
||||
|
||||
self.size = svg.width, svg.height
|
||||
|
||||
class SvgApp(App):
|
||||
|
||||
def build(self):
|
||||
from kivy.garden.smaa import SMAA
|
||||
|
||||
Window.bind(on_keyboard=self._on_keyboard_handler)
|
||||
|
||||
self.smaa = SMAA()
|
||||
self.effects = [self.smaa, Widget()]
|
||||
self.effect_index = 0
|
||||
self.label = Label(text='SMAA', top=Window.height)
|
||||
self.effect = effect = self.effects[0]
|
||||
self.root = FloatLayout()
|
||||
self.root.add_widget(effect)
|
||||
|
||||
if 0:
|
||||
from kivy.graphics import Color, Rectangle
|
||||
wid = Widget(size=Window.size)
|
||||
with wid.canvas:
|
||||
Color(1, 1, 1, 1)
|
||||
Rectangle(size=Window.size)
|
||||
effect.add_widget(wid)
|
||||
|
||||
if 1:
|
||||
#from kivy.uix.image import Image
|
||||
#root.add_widget(Image(source='data/logo/kivy-icon-512.png', size=(800, 600)))
|
||||
|
||||
filenames = sys.argv[1:]
|
||||
if not filenames:
|
||||
filenames = glob(join(dirname(__file__), '*.svg'))
|
||||
|
||||
for filename in filenames:
|
||||
svg = SvgWidget(filename)
|
||||
effect.add_widget(svg)
|
||||
|
||||
effect.add_widget(self.label)
|
||||
svg.scale = 5.
|
||||
svg.center = Window.center
|
||||
|
||||
if 0:
|
||||
wid = Scatter(size=Window.size)
|
||||
from kivy.graphics import Color, Triangle, Rectangle
|
||||
with wid.canvas:
|
||||
Color(0, 0, 0, 1)
|
||||
Rectangle(size=Window.size)
|
||||
Color(1, 1, 1, 1)
|
||||
w, h = Window.size
|
||||
cx, cy = w / 2., h / 2.
|
||||
Triangle(points=[cx - w * 0.25, cy - h * 0.25,
|
||||
cx, cy + h * 0.25,
|
||||
cx + w * 0.25, cy - h * 0.25])
|
||||
effect.add_widget(wid)
|
||||
|
||||
if 0:
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.slider import Slider
|
||||
effect.add_widget(Button(text='Hello World'))
|
||||
effect.add_widget(Slider(pos=(200, 200)))
|
||||
|
||||
|
||||
control_ui = Builder.load_string(smaa_ui)
|
||||
self.root.add_widget(control_ui)
|
||||
|
||||
def _on_keyboard_handler(self, instance, key, *args):
|
||||
if key == 32:
|
||||
self.effect_index = (self.effect_index + 1) % 2
|
||||
childrens = self.effect.children[:]
|
||||
self.effect.clear_widgets()
|
||||
self.root.remove_widget(self.effect)
|
||||
self.effect = self.effects[self.effect_index]
|
||||
self.root.add_widget(self.effect)
|
||||
for child in reversed(childrens):
|
||||
self.effect.add_widget(child)
|
||||
self.label.text = self.effect.__class__.__name__
|
||||
Window.title = self.label.text
|
||||
|
||||
if __name__ == '__main__':
|
||||
SvgApp().run()
|
||||
|
|
@ -2,66 +2,10 @@ import sys
|
|||
from glob import glob
|
||||
from os.path import join, dirname
|
||||
from kivy.uix.scatter import Scatter
|
||||
from kivy.uix.widget import Widget
|
||||
from kivy.uix.label import Label
|
||||
from kivy.app import App
|
||||
from kivy.graphics.svg import Svg
|
||||
from kivy.core.window import Window
|
||||
from kivy.uix.floatlayout import FloatLayout
|
||||
from kivy.lang import Builder
|
||||
|
||||
|
||||
smaa_ui = '''
|
||||
#:kivy 1.8.0
|
||||
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
pos_hint: {'top': 1}
|
||||
size_hint_y: None
|
||||
height: '48dp'
|
||||
padding: '2dp'
|
||||
spacing: '2dp'
|
||||
Label:
|
||||
text: 'Quality:'
|
||||
ToggleButton:
|
||||
text: 'Low'
|
||||
group: 'smaa-quality'
|
||||
on_release: app.smaa.quality = 'low'
|
||||
ToggleButton:
|
||||
text: 'Medium'
|
||||
group: 'smaa-quality'
|
||||
on_release: app.smaa.quality = 'medium'
|
||||
ToggleButton:
|
||||
text: 'High'
|
||||
group: 'smaa-quality'
|
||||
on_release: app.smaa.quality = 'high'
|
||||
ToggleButton:
|
||||
text: 'Ultra'
|
||||
group: 'smaa-quality'
|
||||
state: 'down'
|
||||
on_release: app.smaa.quality = 'ultra'
|
||||
|
||||
Label:
|
||||
text: 'Debug:'
|
||||
ToggleButton:
|
||||
text: 'None'
|
||||
group: 'smaa-debug'
|
||||
state: 'down'
|
||||
on_release: app.smaa.debug = ''
|
||||
ToggleButton:
|
||||
text: 'Source'
|
||||
group: 'smaa-debug'
|
||||
on_release: app.smaa.debug = 'source'
|
||||
ToggleButton:
|
||||
text: 'Edges'
|
||||
group: 'smaa-debug'
|
||||
on_release: app.smaa.debug = 'edges'
|
||||
ToggleButton:
|
||||
text: 'Blend'
|
||||
group: 'smaa-debug'
|
||||
on_release: app.smaa.debug = 'blend'
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class SvgWidget(Scatter):
|
||||
|
@ -76,79 +20,18 @@ class SvgWidget(Scatter):
|
|||
class SvgApp(App):
|
||||
|
||||
def build(self):
|
||||
from kivy.garden.smaa import SMAA
|
||||
|
||||
Window.bind(on_keyboard=self._on_keyboard_handler)
|
||||
|
||||
self.smaa = SMAA()
|
||||
self.effects = [self.smaa, Widget()]
|
||||
self.effect_index = 0
|
||||
self.label = Label(text='SMAA', top=Window.height)
|
||||
self.effect = effect = self.effects[0]
|
||||
self.root = FloatLayout()
|
||||
self.root.add_widget(effect)
|
||||
|
||||
if 0:
|
||||
from kivy.graphics import Color, Rectangle
|
||||
wid = Widget(size=Window.size)
|
||||
with wid.canvas:
|
||||
Color(1, 1, 1, 1)
|
||||
Rectangle(size=Window.size)
|
||||
effect.add_widget(wid)
|
||||
filenames = sys.argv[1:]
|
||||
if not filenames:
|
||||
filenames = glob(join(dirname(__file__), '*.svg'))
|
||||
|
||||
if 1:
|
||||
#from kivy.uix.image import Image
|
||||
#root.add_widget(Image(source='data/logo/kivy-icon-512.png', size=(800, 600)))
|
||||
|
||||
filenames = sys.argv[1:]
|
||||
if not filenames:
|
||||
filenames = glob(join(dirname(__file__), '*.svg'))
|
||||
|
||||
for filename in filenames:
|
||||
svg = SvgWidget(filename)
|
||||
effect.add_widget(svg)
|
||||
|
||||
effect.add_widget(self.label)
|
||||
for filename in filenames:
|
||||
svg = SvgWidget(filename)
|
||||
self.root.add_widget(svg)
|
||||
svg.scale = 5.
|
||||
svg.center = Window.center
|
||||
|
||||
if 0:
|
||||
wid = Scatter(size=Window.size)
|
||||
from kivy.graphics import Color, Triangle, Rectangle
|
||||
with wid.canvas:
|
||||
Color(0, 0, 0, 1)
|
||||
Rectangle(size=Window.size)
|
||||
Color(1, 1, 1, 1)
|
||||
w, h = Window.size
|
||||
cx, cy = w / 2., h / 2.
|
||||
Triangle(points=[cx - w * 0.25, cy - h * 0.25,
|
||||
cx, cy + h * 0.25,
|
||||
cx + w * 0.25, cy - h * 0.25])
|
||||
effect.add_widget(wid)
|
||||
|
||||
if 0:
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.slider import Slider
|
||||
effect.add_widget(Button(text='Hello World'))
|
||||
effect.add_widget(Slider(pos=(200, 200)))
|
||||
|
||||
|
||||
control_ui = Builder.load_string(smaa_ui)
|
||||
self.root.add_widget(control_ui)
|
||||
|
||||
def _on_keyboard_handler(self, instance, key, *args):
|
||||
if key == 32:
|
||||
self.effect_index = (self.effect_index + 1) % 2
|
||||
childrens = self.effect.children[:]
|
||||
self.effect.clear_widgets()
|
||||
self.root.remove_widget(self.effect)
|
||||
self.effect = self.effects[self.effect_index]
|
||||
self.root.add_widget(self.effect)
|
||||
for child in reversed(childrens):
|
||||
self.effect.add_widget(child)
|
||||
self.label.text = self.effect.__class__.__name__
|
||||
Window.title = self.label.text
|
||||
|
||||
if __name__ == '__main__':
|
||||
SvgApp().run()
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ cdef extern from "math.h":
|
|||
double pow(double x, double y) nogil
|
||||
double atan2(double y, double x) nogil
|
||||
double tan(double) nogil
|
||||
double fabs(double) nogil
|
||||
|
||||
cdef extern from "stdlib.h":
|
||||
ctypedef unsigned long size_t
|
||||
|
|
|
@ -12,6 +12,7 @@ from xml.etree.cElementTree import parse
|
|||
from kivy.graphics.instructions cimport RenderContext
|
||||
from kivy.graphics.vertex_instructions cimport Mesh
|
||||
from kivy.graphics.tesselator cimport Tesselator
|
||||
from kivy.graphics.texture cimport Texture
|
||||
from cpython cimport array
|
||||
from array import array
|
||||
from cython cimport view
|
||||
|
@ -26,9 +27,11 @@ cdef str SVG_FS = '''
|
|||
#endif
|
||||
|
||||
varying vec4 vertex_color;
|
||||
varying vec2 texcoord;
|
||||
uniform sampler2D texture0;
|
||||
|
||||
void main (void) {
|
||||
gl_FragColor = vertex_color / 255.;
|
||||
gl_FragColor = texture2D(texture0, texcoord) * (vertex_color / 255.);
|
||||
}
|
||||
'''
|
||||
|
||||
|
@ -38,14 +41,17 @@ cdef str SVG_VS = '''
|
|||
#endif
|
||||
|
||||
attribute vec2 v_pos;
|
||||
attribute vec2 v_tex;
|
||||
attribute vec4 v_color;
|
||||
uniform mat4 modelview_mat;
|
||||
uniform mat4 projection_mat;
|
||||
varying vec4 vertex_color;
|
||||
varying vec2 texcoord;
|
||||
|
||||
void main (void) {
|
||||
vertex_color = v_color;
|
||||
gl_Position = projection_mat * modelview_mat * vec4(v_pos, 0.0, 1.0);
|
||||
texcoord = v_tex;
|
||||
}
|
||||
'''
|
||||
|
||||
|
@ -213,6 +219,7 @@ cdef object RE_POLYLINE = re.compile(
|
|||
|
||||
cdef list VERTEX_FORMAT = [
|
||||
('v_pos', 2, 'float'),
|
||||
('v_tex', 2, 'float'),
|
||||
('v_color', 4, 'float')]
|
||||
|
||||
def _tokenize_path(pathdef):
|
||||
|
@ -222,6 +229,11 @@ def _tokenize_path(pathdef):
|
|||
for token in RE_FLOAT.findall(x):
|
||||
yield token
|
||||
|
||||
cdef inline float angle(float ux, float uy, float vx, float vy):
|
||||
a = acos((ux * vx + uy * vy) / sqrt((ux ** 2 + uy ** 2) * (vx ** 2 + vy ** 2)))
|
||||
sgn = 1 if ux * vy > uy * vx else -1
|
||||
return sgn * a
|
||||
|
||||
cdef float parse_float(txt):
|
||||
if not txt:
|
||||
return 0.
|
||||
|
@ -429,6 +441,7 @@ cdef class Gradient(object):
|
|||
return 0.
|
||||
|
||||
cdef class LinearGradient(Gradient):
|
||||
cdef float x1, x2, y1, y2
|
||||
params = ['x1', 'x2', 'y1', 'y2', 'stops']
|
||||
|
||||
cdef float grad_value(self, float x, float y):
|
||||
|
@ -436,6 +449,7 @@ cdef class LinearGradient(Gradient):
|
|||
|
||||
|
||||
cdef class RadialGradient(Gradient):
|
||||
cdef float cx, cy, r
|
||||
params = ['cx', 'cy', 'r', 'stops']
|
||||
|
||||
cdef float grad_value(self, float x, float y):
|
||||
|
@ -465,6 +479,7 @@ cdef class Svg(RenderContext):
|
|||
float anchor_y
|
||||
double last_cx
|
||||
double last_cy
|
||||
Texture line_texture
|
||||
|
||||
def __init__(self, filename, anchor_x=0, anchor_y=0,
|
||||
bezier_points=BEZIER_POINTS, circle_points=CIRCLE_POINTS):
|
||||
|
@ -498,7 +513,10 @@ cdef class Svg(RenderContext):
|
|||
self.gradients = GradientContainer()
|
||||
self.anchor_x = anchor_x
|
||||
self.anchor_y = anchor_y
|
||||
|
||||
self.line_texture = Texture.create(
|
||||
size=(2, 1), colorfmt="rgba")
|
||||
self.line_texture.blit_buffer(
|
||||
b"\xff\xff\xff\xff\xff\xff\xff\x00", colorfmt="rgba")
|
||||
self.filename = filename
|
||||
|
||||
property anchor_x:
|
||||
|
@ -695,7 +713,6 @@ cdef class Svg(RenderContext):
|
|||
# Reverse for easy use of .pop()
|
||||
elements.reverse()
|
||||
|
||||
sx = sy = None
|
||||
command = None
|
||||
|
||||
self.new_path()
|
||||
|
@ -722,10 +739,6 @@ cdef class Svg(RenderContext):
|
|||
y = float(elements.pop())
|
||||
self.set_position(x, y, absolute)
|
||||
|
||||
if sx is None:
|
||||
sx = self.x
|
||||
sy = self.y
|
||||
|
||||
# Implicit moveto commands are treated as lineto commands.
|
||||
# So we set command to lineto here, in case there are
|
||||
# further implicit commands after this moveto.
|
||||
|
@ -733,7 +746,6 @@ cdef class Svg(RenderContext):
|
|||
|
||||
elif command == 'Z':
|
||||
self.close_path()
|
||||
sx = sy = None
|
||||
|
||||
elif command == 'L':
|
||||
x = float(elements.pop())
|
||||
|
@ -879,13 +891,16 @@ cdef class Svg(RenderContext):
|
|||
else:
|
||||
self.x += x
|
||||
self.y += y
|
||||
self.loop.append(x)
|
||||
self.loop.append(y)
|
||||
self.loop.append(self.x)
|
||||
self.loop.append(self.y)
|
||||
|
||||
def arc_to(self, float rx, float ry, float phi, float large_arc,
|
||||
float sweep, float x, float y):
|
||||
# This function is made out of magical fairy dust
|
||||
# http://www.w3.org/TR/2003/REC-SVG11-20030114/implnote.html#ArcImplementationNotes
|
||||
cdef float x1, y1, x2, y2, cp, sp, dx, dy, x_, y_, r2, cx_, cy_, cx, cy
|
||||
cdef float psi, delta, ct, st, theta
|
||||
cdef int n_points, i
|
||||
x1 = self.x
|
||||
y1 = self.y
|
||||
x2 = x
|
||||
|
@ -906,17 +921,15 @@ cdef class Svg(RenderContext):
|
|||
cy_ = -r * ry * x_ / rx
|
||||
cx = cp * cx_ - sp * cy_ + .5 * (x1 + x2)
|
||||
cy = sp * cx_ + cp * cy_ + .5 * (y1 + y2)
|
||||
def angle(u, v):
|
||||
a = acos((u[0]*v[0] + u[1]*v[1]) / sqrt((u[0]**2 + u[1]**2) * (v[0]**2 + v[1]**2)))
|
||||
sgn = 1 if u[0]*v[1] > u[1]*v[0] else -1
|
||||
return sgn * a
|
||||
|
||||
psi = angle((1,0), ((x_ - cx_)/rx, (y_ - cy_)/ry))
|
||||
delta = angle(((x_ - cx_)/rx, (y_ - cy_)/ry),
|
||||
((-x_ - cx_)/rx, (-y_ - cy_)/ry))
|
||||
psi = angle(1, 0, (x_ - cx_) / rx, (y_ - cy_) / ry)
|
||||
delta = angle((x_ - cx_) / rx, (y_ - cy_) / ry,
|
||||
(-x_ - cx_) / rx, (-y_ - cy_) / ry)
|
||||
if sweep and delta < 0: delta += pi * 2
|
||||
if not sweep and delta > 0: delta -= pi * 2
|
||||
n_points = max(int(abs(self.circle_points * delta / (2 * pi))), 1)
|
||||
n_points = <int>fabs(self.circle_points * delta / (2 * pi))
|
||||
if n_points < 1:
|
||||
n_points = 1
|
||||
|
||||
for i in xrange(n_points + 1):
|
||||
theta = psi + i * delta / n_points
|
||||
|
@ -927,9 +940,12 @@ cdef class Svg(RenderContext):
|
|||
|
||||
cdef void curve_to(self, float x1, float y1, float x2, float y2,
|
||||
float x, float y):
|
||||
cdef int i
|
||||
cdef float t, t0, t1, t2, t3, px, py
|
||||
cdef list bc
|
||||
if not self.bezier_coefficients:
|
||||
for i in xrange(self.bezier_points+1):
|
||||
t = float(i)/self.bezier_points
|
||||
for i in range(self.bezier_points + 1):
|
||||
t = float(i) / self.bezier_points
|
||||
t0 = (1 - t) ** 3
|
||||
t1 = 3 * t * (1 - t) ** 2
|
||||
t2 = 3 * t ** 2 * (1 - t)
|
||||
|
@ -937,34 +953,19 @@ cdef class Svg(RenderContext):
|
|||
self.bezier_coefficients.append([t0, t1, t2, t3])
|
||||
self.last_cx = x2
|
||||
self.last_cy = y2
|
||||
for i, t in enumerate(self.bezier_coefficients):
|
||||
px = t[0] * self.x + t[1] * x1 + t[2] * x2 + t[3] * x
|
||||
py = t[0] * self.y + t[1] * y1 + t[2] * y2 + t[3] * y
|
||||
for bc in self.bezier_coefficients:
|
||||
t0, t1, t2, t3 = bc
|
||||
px = t0 * self.x + t1 * x1 + t2 * x2 + t3 * x
|
||||
py = t0 * self.y + t1 * y1 + t2 * y2 + t3 * y
|
||||
self.loop.append(px)
|
||||
self.loop.append(py)
|
||||
|
||||
self.x, self.y = px, py
|
||||
|
||||
cdef void end_path(self):
|
||||
if self.loop:
|
||||
if len(self.loop):
|
||||
self.path.append(self.loop)
|
||||
|
||||
"""
|
||||
path = []
|
||||
for orig_loop in self.path:
|
||||
|
||||
if not orig_loop:
|
||||
continue
|
||||
|
||||
loop = [orig_loop[0]]
|
||||
for pt in orig_loop:
|
||||
if (pt[0] - loop[-1][0]) ** 2 + (pt[1] - loop[-1][1]) ** 2 > TOLERANCE:
|
||||
if pt not in loop:
|
||||
loop.append(pt)
|
||||
path.append(loop)
|
||||
"""
|
||||
|
||||
|
||||
tris = None
|
||||
cdef Tesselator tess
|
||||
cdef array.array loop
|
||||
|
@ -992,8 +993,7 @@ cdef class Svg(RenderContext):
|
|||
cdef float x, y, r, g, b, a
|
||||
|
||||
cdef int count = len(path) / 2
|
||||
cdef list indices = range(count)
|
||||
v_vertices = view.array(shape=(count * 6, ),
|
||||
v_vertices = view.array(shape=(count * 8, ),
|
||||
itemsize=sizeof(float),
|
||||
format='f')
|
||||
vertices = v_vertices
|
||||
|
@ -1008,11 +1008,13 @@ cdef class Svg(RenderContext):
|
|||
transform.transform(x, y, &x, &y)
|
||||
vertices[vindex] = x
|
||||
vertices[vindex + 1] = y
|
||||
vertices[vindex + 2] = r
|
||||
vertices[vindex + 3] = g
|
||||
vertices[vindex + 4] = b
|
||||
vertices[vindex + 5] = a
|
||||
vindex += 6
|
||||
vertices[vindex + 2] = 0
|
||||
vertices[vindex + 3] = 0
|
||||
vertices[vindex + 4] = r
|
||||
vertices[vindex + 5] = g
|
||||
vertices[vindex + 6] = b
|
||||
vertices[vindex + 7] = a
|
||||
vindex += 8
|
||||
else:
|
||||
r, g, b, a = fill
|
||||
for index in range(count):
|
||||
|
@ -1021,19 +1023,122 @@ cdef class Svg(RenderContext):
|
|||
transform.transform(x, y, &x, &y)
|
||||
vertices[vindex] = x
|
||||
vertices[vindex + 1] = y
|
||||
vertices[vindex + 2] = r
|
||||
vertices[vindex + 3] = g
|
||||
vertices[vindex + 4] = b
|
||||
vertices[vindex + 5] = a
|
||||
vindex += 6
|
||||
vertices[vindex + 2] = 0
|
||||
vertices[vindex + 3] = 0
|
||||
vertices[vindex + 4] = r
|
||||
vertices[vindex + 5] = g
|
||||
vertices[vindex + 6] = b
|
||||
vertices[vindex + 7] = a
|
||||
vindex += 8
|
||||
|
||||
cdef Mesh mesh = Mesh(fmt=VERTEX_FORMAT, mode=mode)
|
||||
mesh.build_triangle_fan(&vertices[0], vindex, count)
|
||||
|
||||
def push_line_mesh(self, float[:] path, fill, Matrix transform):
|
||||
cdef int index, vindex
|
||||
cdef float ax, ay, bx, by, r, g, b, a
|
||||
cdef int count = len(path) / 2
|
||||
cdef list indices = []
|
||||
cdef list vertices = []
|
||||
vindex = 0
|
||||
|
||||
|
||||
# build internal smooth line
|
||||
cdef float line_width = 0
|
||||
cdef float line_owidth = 1.2
|
||||
width = max(0, (line_width - 1.))
|
||||
owidth = width + line_owidth
|
||||
|
||||
vertices = []
|
||||
indices = []
|
||||
|
||||
if not isinstance(fill, str):
|
||||
r, g, b, a = fill
|
||||
|
||||
for index in range(0, len(path) - 2, 2):
|
||||
ax = path[index]
|
||||
ay = path[index + 1]
|
||||
bx = path[index + 2]
|
||||
by = path[index + 3]
|
||||
transform.transform(ax, ay, &ax, &ay)
|
||||
transform.transform(bx, by, &bx, &by)
|
||||
|
||||
rx = bx - ax
|
||||
ry = by - ay
|
||||
angle = atan2(ry, rx)
|
||||
a1 = angle - PI2
|
||||
a2 = angle + PI2
|
||||
|
||||
cos1 = cos(a1) * width
|
||||
sin1 = sin(a1) * width
|
||||
cos2 = cos(a2) * width
|
||||
sin2 = sin(a2) * width
|
||||
ocos1 = cos(a1) * owidth
|
||||
osin1 = sin(a1) * owidth
|
||||
ocos2 = cos(a2) * owidth
|
||||
osin2 = sin(a2) * owidth
|
||||
|
||||
x1 = ax + cos1
|
||||
y1 = ay + sin1
|
||||
x4 = ax + cos2
|
||||
y4 = ay + sin2
|
||||
x2 = bx + cos1
|
||||
y2 = by + sin1
|
||||
x3 = bx + cos2
|
||||
y3 = by + sin2
|
||||
|
||||
ox1 = ax + ocos1
|
||||
oy1 = ay + osin1
|
||||
ox4 = ax + ocos2
|
||||
oy4 = ay + osin2
|
||||
ox2 = bx + ocos1
|
||||
oy2 = by + osin1
|
||||
ox3 = bx + ocos2
|
||||
oy3 = by + osin2
|
||||
|
||||
if isinstance(fill, str):
|
||||
g = self.gradients[fill]
|
||||
r, g, b, a = g.interp(ax, ay)
|
||||
|
||||
vindex = len(vertices) / 8
|
||||
vertices += [
|
||||
# x, y, u, v, r, g, b, a
|
||||
x1, y1, 0, 0, r, g, b, a,
|
||||
x2, y2, 0, 0, r, g, b, a,
|
||||
x3, y3, 0, 0, r, g, b, a,
|
||||
x4, y4, 0, 0, r, g, b, a,
|
||||
ox1, oy1, 1, 1, r, g, b, a,
|
||||
ox2, oy2, 1, 1, r, g, b, a,
|
||||
ox3, oy3, 1, 1, r, g, b, a,
|
||||
ox4, oy4, 1, 1, r, g, b, a,
|
||||
]
|
||||
|
||||
indices += [vindex + i for i in (
|
||||
0, 4, 5,
|
||||
0, 5, 1,
|
||||
3, 0, 1,
|
||||
3, 1, 2,
|
||||
7, 3, 2,
|
||||
7, 2, 6
|
||||
)]
|
||||
|
||||
if len(indices) > 65000:
|
||||
self._push_line_mesh(vertices, indices)
|
||||
vertices = []
|
||||
indices = []
|
||||
|
||||
if indices:
|
||||
self._push_line_mesh(vertices, indices)
|
||||
|
||||
def _push_line_mesh(self, vertices, indices):
|
||||
Mesh(fmt=VERTEX_FORMAT, mode='triangles',
|
||||
vertices=vertices, indices=indices, texture=self.line_texture)
|
||||
|
||||
def render(self):
|
||||
for path, stroke, tris, fill, transform in self.paths:
|
||||
if tris:
|
||||
for item in tris:
|
||||
self.push_mesh(item, fill, transform, 'triangle_fan')
|
||||
if path:
|
||||
self.push_mesh(path, stroke, transform, 'lines')
|
||||
#self.push_mesh(path, stroke, transform, 'line_loop')
|
||||
self.push_line_mesh(path, stroke, transform)
|
||||
|
|
Loading…
Reference in New Issue