Skip to content

Commit cd42eb0

Browse files
committed
Working multi line text writer
1 parent fa87d73 commit cd42eb0

File tree

10 files changed

+379
-113
lines changed

10 files changed

+379
-113
lines changed

demosys/opengl/texture.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,6 @@ def set_image(self, image, flip=True):
307307
image = image.transpose(Image.FLIP_TOP_BOTTOM)
308308

309309
width, height, depth = image.size[0], image.size[1] // self.layers, self.layers
310-
print(width, height, depth)
311310

312311
self.mglo = self.ctx.texture_array(
313312
(width, height, depth),

demosys/text/base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ def __init__(self):
1919
def draw(self, *args, **kwargs):
2020
raise NotImplementedError()
2121

22-
def _translate_data(self, data):
23-
"""Translate character bytes into texture positions"""
24-
return [self._meta.characters - 1 - self._ct[c] for c in data]
22+
def _translate_string(self, data, length):
23+
"""Translate string into character texture positions"""
24+
for index, char in enumerate(data):
25+
if index == length:
26+
break
27+
28+
yield self._meta.characters - 1 - self._ct[char]
2529

2630
def _init(self, meta: 'Meta'):
2731
self._meta = meta

demosys/text/resources/shaders/demosys/text/textwriter2d.glsl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ in vec3 in_position;
66
in uint in_char_id;
77

88
uniform vec2 char_size;
9+
uniform float line_length;
910

1011
out uint vs_char_id;
1112

1213
void main() {
13-
gl_Position = vec4(in_position + vec3(gl_InstanceID * char_size.x, 0.0, 0.0), 1.0);
14+
float ypos = int(gl_InstanceID / line_length) * char_size.y;
15+
float xpos = mod(gl_InstanceID, line_length) * char_size.x;
16+
gl_Position = vec4(in_position + vec3(xpos, -ypos, 0.0), 1.0);
1417
vs_char_id = in_char_id;
1518
}
1619

demosys/text/resources/shaders/demosys/text/textwriter3d.glsl

Lines changed: 0 additions & 78 deletions
This file was deleted.

demosys/text/writer2d.py

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010

1111
class TextWriter2D(BaseText):
1212

13-
def __init__(self, area, text="", aspect_ratio=1.0):
13+
def __init__(self, area, text_lines=None, aspect_ratio=1.0):
1414
"""
1515
:param area: (x, y) Text area size (number of characters)
1616
:param size: Text size
17-
:param text: Initial text
17+
:param text: Initial text lines
1818
"""
1919
super().__init__()
2020
self.area = area
21-
self._text = text.encode('latin1')
21+
self._text_lines = text_lines
2222

23-
self.projection_bytes = None
23+
self._projection_bytes = None
2424
self._aspect_ratio = 1.0
2525
self.aspect_ratio = aspect_ratio
2626

@@ -29,29 +29,34 @@ def __init__(self, area, text="", aspect_ratio=1.0):
2929
self._shader = shaders.get('demosys/text/textwriter2d.glsl', create=True)
3030
self._config = data.get('demosys/text/meta.json', create=True)
3131

32+
self._string_buffer = None
33+
3234
data.on_loaded(self._post_load)
3335

3436
def _post_load(self):
3537
"""Parse font metadata after resources are loaded"""
3638
self._init(Meta(self._config.data))
3739

38-
self._string_data = self._translate_data(self._text)
39-
self._string_buffer = self.ctx.buffer(
40-
data=numpy.array(self._string_data, dtype=numpy.uint32).tobytes()
41-
)
42-
self._pos = self.ctx.buffer(data=bytes([0] * 4 * 3))
40+
self._string_buffer = self.ctx.buffer(reserve=self.area[0] * 4 * self.area[1])
41+
self._string_buffer.clear(chunk=b'\32')
42+
pos = self.ctx.buffer(data=bytes([0] * 4 * 3))
4343

4444
self._vao = VAO("textwriter", mode=moderngl.POINTS)
45-
self._vao.buffer(self._pos, '3f', 'in_position')
45+
self._vao.buffer(pos, '3f', 'in_position')
4646
self._vao.buffer(self._string_buffer, '1u', 'in_char_id', per_instance=True)
4747

48+
self.text_lines = self._text_lines
49+
4850
@property
49-
def text(self):
50-
return self._text
51+
def text_lines(self):
52+
return self._text_lines
5153

52-
@text.setter
53-
def text(self, value):
54-
self._text = value
54+
@text_lines.setter
55+
def text_lines(self, value):
56+
self._text_lines = value
57+
58+
for i, line in enumerate(self._text_lines):
59+
self.set_text_line(i, line)
5560

5661
@property
5762
def aspect_ratio(self):
@@ -60,7 +65,7 @@ def aspect_ratio(self):
6065
@aspect_ratio.setter
6166
def aspect_ratio(self, value):
6267
self._aspect_ratio = value
63-
self.projection_bytes = matrix44.create_orthogonal_projection_matrix(
68+
self._projection_bytes = matrix44.create_orthogonal_projection_matrix(
6469
-self.aspect_ratio, # left
6570
self.aspect_ratio, # right
6671
-1.0, # bottom
@@ -70,19 +75,39 @@ def aspect_ratio(self, value):
7075
dtype=numpy.float32,
7176
).tobytes()
7277

73-
def draw(self, pos, size=1.0):
78+
def set_text_line(self, line, text):
79+
if line >= self.area[1]:
80+
return
81+
82+
self._string_buffer.clear(size=self.area[0] * 4, offset=self.area[0] * 4 * line, chunk=b'\32')
83+
84+
self._string_buffer.write(
85+
numpy.fromiter(
86+
self._translate_string(text.encode('iso-8859-1'), self.area[0]),
87+
dtype=numpy.uint32
88+
).tobytes(),
89+
offset=(self.area[0] * 4) * line,
90+
)
91+
92+
def draw(self, pos, lenght=-1, size=1.0):
93+
if lenght < 0:
94+
lenght = self.area[0] * self.area[1]
95+
7496
csize = (
7597
self._meta.character_width / self._meta.character_height * size,
7698
1.0 * size,
7799
)
100+
78101
cpos = (
79102
pos[0] - self._aspect_ratio + csize[0] / 2,
80103
-pos[1] + 1.0 - csize[1] / 2,
81104
)
82105

83106
self._texture.use(location=0)
84-
self._shader.uniform("m_proj", self.projection_bytes)
107+
self._shader.uniform("m_proj", self._projection_bytes)
85108
self._shader.uniform("text_pos", cpos)
86109
self._shader.uniform("font_texture", 0)
87110
self._shader.uniform("char_size", csize)
88-
self._vao.draw(self._shader, instances=len(self._string_data))
111+
self._shader.uniform("line_length", self.area[0])
112+
113+
self._vao.draw(self._shader, instances=lenght)

demosys/view/controller.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ def run(manager=None):
6666

6767
# Main loop
6868
frame_time = 60.0 / 1000.0
69-
# time_start = glfw.get_time()
7069
time_start = time.time()
7170
prev_time = window.timer.get_time()
7271

examples/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,16 @@ python manage.py runeffect examples.geocubes
4545
```
4646

4747
![screenshot](https://raw.githubusercontent.com/Contraz/demosys-py/master/examples/images/geocubes.png)
48+
49+
Text Writer
50+
-----------
51+
52+
Example loading a text file displaying it on the screen. The text is drawn using instanced rendering
53+
were each instance is a character in the file. This may not be the most efficient way for drivers
54+
emulating instancing. Text renderer (render to texture) is an alternative.
55+
56+
```bash
57+
python manage.py runeffect examples.textwriter
58+
```
59+
60+
![screenshot](https://raw.githubusercontent.com/Contraz/demosys-py/master/examples/images/textwriter.png)

examples/images/textwriter.png

421 KB
Loading
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import moderngl
1+
import math
2+
import os
3+
24
from demosys.effects import effect
35
from demosys.text import TextWriter2D
4-
# from pyrr import matrix44
56

67

78
class TextEffect(effect.Effect):
89

910
def __init__(self):
1011
super().__init__()
12+
13+
with open(os.path.join(os.path.dirname(__file__), 'sample.txt'), 'r') as fd:
14+
lines = fd.readlines()
15+
1116
self.writer = TextWriter2D(
12-
(10, 1),
17+
(105, len(lines)),
1318
aspect_ratio=self.window_aspect,
14-
text="Hello world! Hello world! Hello world!",
19+
text_lines=lines,
1520
)
1621

17-
def post_load(self):
18-
pass
19-
2022
@effect.bind_target
2123
def draw(self, time, frametime, target):
22-
self.ctx.disable(moderngl.CULL_FACE)
23-
24-
self.writer.draw((0.02, 0.01), size=0.05)
24+
self.writer.draw((0.05, 0.01 - math.fmod(time, 75.0) / 5.0), size=0.05)

0 commit comments

Comments
 (0)