1#[macro_use]
2extern crate anyhow;
3
4use nvg::renderer::*;
5use slab::Slab;
6use std::ffi::c_void;
7
8struct Shader {
9 prog: gl::types::GLuint,
10 frag: gl::types::GLuint,
11 vert: gl::types::GLuint,
12 loc_viewsize: i32,
13 loc_tex: i32,
14 loc_frag: u32,
15}
16
17impl Drop for Shader {
18 fn drop(&mut self) {
19 unsafe {
20 gl::DeleteProgram(self.prog);
21 gl::DeleteShader(self.vert);
22 gl::DeleteShader(self.frag);
23 }
24 }
25}
26
27impl Shader {
28 unsafe fn load() -> anyhow::Result<Shader> {
29 let mut status: gl::types::GLint = std::mem::zeroed();
30 let prog = gl::CreateProgram();
31 let vert = gl::CreateShader(gl::VERTEX_SHADER);
32 let frag = gl::CreateShader(gl::FRAGMENT_SHADER);
33 let vert_source =
34 std::ffi::CString::from_vec_unchecked(include_bytes!("shader.vert").to_vec());
35 let frag_source =
36 std::ffi::CString::from_vec_unchecked(include_bytes!("shader.frag").to_vec());
37
38 gl::ShaderSource(
39 vert,
40 1,
41 [vert_source.as_ptr()].as_ptr() as *const *const i8,
42 std::ptr::null(),
43 );
44 gl::ShaderSource(
45 frag,
46 1,
47 [frag_source.as_ptr()].as_ptr() as *const *const i8,
48 std::ptr::null(),
49 );
50
51 gl::CompileShader(vert);
52 gl::GetShaderiv(vert, gl::COMPILE_STATUS, &mut status);
53 if status != gl::TRUE as i32 {
54 return Err(shader_error(vert, "shader.vert"));
55 }
56
57 gl::CompileShader(frag);
58 gl::GetShaderiv(frag, gl::COMPILE_STATUS, &mut status);
59 if status != gl::TRUE as i32 {
60 return Err(shader_error(vert, "shader.frag"));
61 }
62
63 gl::AttachShader(prog, vert);
64 gl::AttachShader(prog, frag);
65
66 let name_vertex = std::ffi::CString::new("vertex").unwrap();
67 let name_tcoord = std::ffi::CString::new("tcoord").unwrap();
68 gl::BindAttribLocation(prog, 0, name_vertex.as_ptr() as *const i8);
69 gl::BindAttribLocation(prog, 1, name_tcoord.as_ptr() as *const i8);
70
71 gl::LinkProgram(prog);
72 gl::GetProgramiv(prog, gl::LINK_STATUS, &mut status);
73 if status != gl::TRUE as i32 {
74 return Err(program_error(prog));
75 }
76
77 let name_viewsize = std::ffi::CString::new("viewSize").unwrap();
78 let name_tex = std::ffi::CString::new("tex").unwrap();
79 let name_frag = std::ffi::CString::new("frag").unwrap();
80
81 Ok(Shader {
82 prog,
83 frag,
84 vert,
85 loc_viewsize: gl::GetUniformLocation(prog, name_viewsize.as_ptr() as *const i8),
86 loc_tex: gl::GetUniformLocation(prog, name_tex.as_ptr() as *const i8),
87 loc_frag: gl::GetUniformBlockIndex(prog, name_frag.as_ptr() as *const i8),
88 })
89 }
90}
91
92enum ShaderType {
93 FillGradient,
94 FillImage,
95 Simple,
96 Image,
97}
98
99#[derive(PartialEq, Eq)]
100enum CallType {
101 Fill,
102 ConvexFill,
103 Stroke,
104 Triangles,
105}
106
107struct Blend {
108 src_rgb: gl::types::GLenum,
109 dst_rgb: gl::types::GLenum,
110 src_alpha: gl::types::GLenum,
111 dst_alpha: gl::types::GLenum,
112}
113
114impl From<CompositeOperationState> for Blend {
115 fn from(state: CompositeOperationState) -> Self {
116 Blend {
117 src_rgb: convert_blend_factor(state.src_rgb),
118 dst_rgb: convert_blend_factor(state.dst_rgb),
119 src_alpha: convert_blend_factor(state.src_alpha),
120 dst_alpha: convert_blend_factor(state.dst_alpha),
121 }
122 }
123}
124
125struct Call {
126 call_type: CallType,
127 image: Option<usize>,
128 path_offset: usize,
129 path_count: usize,
130 triangle_offset: usize,
131 triangle_count: usize,
132 uniform_offset: usize,
133 blend_func: Blend,
134}
135
136struct Texture {
137 tex: gl::types::GLuint,
138 width: usize,
139 height: usize,
140 texture_type: TextureType,
141 flags: ImageFlags,
142}
143
144impl Drop for Texture {
145 fn drop(&mut self) {
146 unsafe { gl::DeleteTextures(1, &self.tex) }
147 }
148}
149
150struct GLPath {
151 fill_offset: usize,
152 fill_count: usize,
153 stroke_offset: usize,
154 stroke_count: usize,
155}
156
157#[derive(Default)]
158#[allow(dead_code)]
159struct FragUniforms {
160 scissor_mat: [f32; 12],
161 paint_mat: [f32; 12],
162 inner_color: Color,
163 outer_color: Color,
164 scissor_ext: [f32; 2],
165 scissor_scale: [f32; 2],
166 extent: [f32; 2],
167 radius: f32,
168 feather: f32,
169 stroke_mult: f32,
170 stroke_thr: f32,
171 tex_type: i32,
172 type_: i32,
173}
174
175pub struct Renderer {
176 shader: Shader,
177 textures: Slab<Texture>,
178 view: Extent,
179 vert_buf: gl::types::GLuint,
180 vert_arr: gl::types::GLuint,
181 frag_buf: gl::types::GLuint,
182 frag_size: usize,
183 calls: Vec<Call>,
184 paths: Vec<GLPath>,
185 vertexes: Vec<Vertex>,
186 uniforms: Vec<u8>,
187}
188
189impl Drop for Renderer {
190 fn drop(&mut self) {
191 unsafe {
192 gl::DeleteBuffers(1, &self.frag_buf);
193 gl::DeleteBuffers(1, &self.vert_buf);
194 gl::DeleteVertexArrays(1, &self.vert_arr);
195 }
196 }
197}
198
199impl Renderer {
200 pub fn create() -> anyhow::Result<Renderer> {
201 unsafe {
202 let shader = Shader::load()?;
203
204 let mut vert_arr: gl::types::GLuint = std::mem::zeroed();
205 gl::GenVertexArrays(1, &mut vert_arr);
206
207 let mut vert_buf: gl::types::GLuint = std::mem::zeroed();
208 gl::GenBuffers(1, &mut vert_buf);
209
210 gl::UniformBlockBinding(shader.prog, shader.loc_frag, 0);
211 let mut frag_buf: gl::types::GLuint = std::mem::zeroed();
212 gl::GenBuffers(1, &mut frag_buf);
213
214 let mut align = std::mem::zeroed();
215 gl::GetIntegerv(gl::UNIFORM_BUFFER_OFFSET_ALIGNMENT, &mut align);
216
217 let frag_size = std::mem::size_of::<FragUniforms>() + (align as usize)
218 - std::mem::size_of::<FragUniforms>() % (align as usize);
219
220 gl::Finish();
221
222 Ok(Renderer {
223 shader,
224 textures: Default::default(),
225 view: Default::default(),
226 vert_buf,
227 vert_arr,
228 frag_buf,
229 frag_size,
230 calls: Default::default(),
231 paths: Default::default(),
232 vertexes: Default::default(),
233 uniforms: Default::default(),
234 })
235 }
236 }
237
238 unsafe fn set_uniforms(&self, offset: usize, img: Option<usize>) {
239 gl::BindBufferRange(
240 gl::UNIFORM_BUFFER,
241 0,
242 self.frag_buf,
243 (offset * self.frag_size) as isize,
244 std::mem::size_of::<FragUniforms>() as isize,
245 );
246
247 if let Some(img) = img {
248 if let Some(texture) = self.textures.get(img) {
249 gl::BindTexture(gl::TEXTURE_2D, texture.tex);
250 }
251 } else {
252 gl::BindTexture(gl::TEXTURE_2D, 0);
253 }
254 }
255
256 unsafe fn do_fill(&self, call: &Call) {
257 let paths = &self.paths[call.path_offset..call.path_offset + call.path_count];
258
259 gl::Enable(gl::STENCIL_TEST);
260 gl::StencilMask(0xff);
261 gl::StencilFunc(gl::ALWAYS, 0, 0xff);
262 gl::ColorMask(gl::FALSE, gl::FALSE, gl::FALSE, gl::FALSE);
263
264 self.set_uniforms(call.uniform_offset, call.image);
265
266 gl::StencilOpSeparate(gl::FRONT, gl::KEEP, gl::KEEP, gl::INCR_WRAP);
267 gl::StencilOpSeparate(gl::BACK, gl::KEEP, gl::KEEP, gl::DECR_WRAP);
268 gl::Disable(gl::CULL_FACE);
269 for path in paths {
270 gl::DrawArrays(
271 gl::TRIANGLE_FAN,
272 path.fill_offset as i32,
273 path.fill_count as i32,
274 );
275 }
276 gl::Enable(gl::CULL_FACE);
277
278 gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
279
280 self.set_uniforms(call.uniform_offset + 1, call.image);
281
282 gl::StencilFunc(gl::EQUAL, 0x00, 0xff);
283 gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP);
284 for path in paths {
285 gl::DrawArrays(
286 gl::TRIANGLE_STRIP,
287 path.stroke_offset as i32,
288 path.stroke_count as i32,
289 );
290 }
291
292 gl::StencilFunc(gl::NOTEQUAL, 0x00, 0xff);
293 gl::StencilOp(gl::ZERO, gl::ZERO, gl::ZERO);
294 gl::DrawArrays(
295 gl::TRIANGLE_STRIP,
296 call.triangle_offset as i32,
297 call.triangle_count as i32,
298 );
299
300 gl::Disable(gl::STENCIL_TEST);
301 }
302
303 unsafe fn do_contex_fill(&self, call: &Call) {
304 let paths = &self.paths[call.path_offset..call.path_offset + call.path_count];
305 self.set_uniforms(call.uniform_offset, call.image);
306 for path in paths {
307 gl::DrawArrays(
308 gl::TRIANGLE_FAN,
309 path.fill_offset as i32,
310 path.fill_count as i32,
311 );
312 if path.stroke_count > 0 {
313 gl::DrawArrays(
314 gl::TRIANGLE_STRIP,
315 path.stroke_offset as i32,
316 path.stroke_count as i32,
317 );
318 }
319 }
320 }
321
322 unsafe fn do_stroke(&self, call: &Call) {
323 let paths = &self.paths[call.path_offset..call.path_offset + call.path_count];
324
325 gl::Enable(gl::STENCIL_TEST);
326 gl::StencilMask(0xff);
327 gl::StencilFunc(gl::EQUAL, 0x0, 0xff);
328 gl::StencilOp(gl::KEEP, gl::KEEP, gl::INCR);
329 self.set_uniforms(call.uniform_offset + 1, call.image);
330 for path in paths {
331 gl::DrawArrays(
332 gl::TRIANGLE_STRIP,
333 path.stroke_offset as i32,
334 path.stroke_count as i32,
335 );
336 }
337
338 self.set_uniforms(call.uniform_offset, call.image);
339 gl::StencilFunc(gl::EQUAL, 0x0, 0xff);
340 gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP);
341 for path in paths {
342 gl::DrawArrays(
343 gl::TRIANGLE_STRIP,
344 path.stroke_offset as i32,
345 path.stroke_count as i32,
346 );
347 }
348
349 gl::ColorMask(gl::FALSE, gl::FALSE, gl::FALSE, gl::FALSE);
350 gl::StencilFunc(gl::ALWAYS, 0x0, 0xff);
351 gl::StencilOp(gl::ZERO, gl::ZERO, gl::ZERO);
352 for path in paths {
353 gl::DrawArrays(
354 gl::TRIANGLE_STRIP,
355 path.stroke_offset as i32,
356 path.stroke_count as i32,
357 );
358 }
359 gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
360
361 gl::Disable(gl::STENCIL_TEST);
362 }
363
364 unsafe fn do_triangles(&self, call: &Call) {
365 self.set_uniforms(call.uniform_offset, call.image);
366 gl::DrawArrays(
367 gl::TRIANGLES,
368 call.triangle_offset as i32,
369 call.triangle_count as i32,
370 );
371 }
372
373 fn convert_paint(
374 &self,
375 paint: &Paint,
376 scissor: &Scissor,
377 width: f32,
378 fringe: f32,
379 stroke_thr: f32,
380 ) -> FragUniforms {
381 let mut frag = FragUniforms {
382 scissor_mat: Default::default(),
383 paint_mat: Default::default(),
384 inner_color: premul_color(paint.inner_color),
385 outer_color: premul_color(paint.outer_color),
386 scissor_ext: Default::default(),
387 scissor_scale: Default::default(),
388 extent: Default::default(),
389 radius: 0.0,
390 feather: 0.0,
391 stroke_mult: 0.0,
392 stroke_thr,
393 tex_type: 0,
394 type_: 0,
395 };
396
397 if scissor.extent.width < -0.5 || scissor.extent.height < -0.5 {
398 frag.scissor_ext[0] = 1.0;
399 frag.scissor_ext[1] = 1.0;
400 frag.scissor_scale[0] = 1.0;
401 frag.scissor_scale[1] = 1.0;
402 } else {
403 frag.scissor_mat = xform_to_3x4(scissor.xform.inverse());
404 frag.scissor_ext[0] = scissor.extent.width;
405 frag.scissor_ext[1] = scissor.extent.height;
406 frag.scissor_scale[0] = (scissor.xform.0[0] * scissor.xform.0[0]
407 + scissor.xform.0[2] * scissor.xform.0[2])
408 .sqrt()
409 / fringe;
410 frag.scissor_scale[1] = (scissor.xform.0[1] * scissor.xform.0[1]
411 + scissor.xform.0[3] * scissor.xform.0[3])
412 .sqrt()
413 / fringe;
414 }
415
416 frag.extent = [paint.extent.width, paint.extent.height];
417 frag.stroke_mult = (width * 0.5 + fringe * 0.5) / fringe;
418
419 let mut invxform = Transform::default();
420
421 if let Some(img) = paint.image {
422 if let Some(texture) = self.textures.get(img) {
423 if texture.flags.contains(ImageFlags::FLIPY) {
424 let m1 = Transform::translate(0.0, frag.extent[1] * 0.5) * paint.xform;
425 let m2 = Transform::scale(1.0, -1.0) * m1;
426 let m1 = Transform::translate(0.0, -frag.extent[1] * 0.5) * m2;
427 invxform = m1.inverse();
428 } else {
429 invxform = paint.xform.inverse();
430 };
431
432 frag.type_ = ShaderType::FillImage as i32;
433 match texture.texture_type {
434 TextureType::RGBA => {
435 frag.tex_type = if texture.flags.contains(ImageFlags::PREMULTIPLIED) {
436 0
437 } else {
438 1
439 }
440 }
441 TextureType::Alpha => frag.tex_type = 2,
442 }
443 }
444 } else {
445 frag.type_ = ShaderType::FillGradient as i32;
446 frag.radius = paint.radius;
447 frag.feather = paint.feather;
448 invxform = paint.xform.inverse();
449 }
450
451 frag.paint_mat = xform_to_3x4(invxform);
452
453 frag
454 }
455
456 fn append_uniforms(&mut self, uniforms: FragUniforms) {
457 self.uniforms
458 .resize(self.uniforms.len() + self.frag_size, 0);
459 unsafe {
460 let idx = self.uniforms.len() - self.frag_size;
461 let p = self.uniforms.as_mut_ptr().add(idx) as *mut FragUniforms;
462 *p = uniforms;
463 }
464 }
465}
466
467impl renderer::Renderer for Renderer {
468 fn edge_antialias(&self) -> bool {
469 true
470 }
471
472 fn create_texture(
473 &mut self,
474 texture_type: TextureType,
475 width: usize,
476 height: usize,
477 flags: ImageFlags,
478 data: Option<&[u8]>,
479 ) -> anyhow::Result<ImageId> {
480 let tex = unsafe {
481 let mut tex: gl::types::GLuint = std::mem::zeroed();
482 gl::GenTextures(1, &mut tex);
483 gl::BindTexture(gl::TEXTURE_2D, tex);
484 gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
485
486 match texture_type {
487 TextureType::RGBA => {
488 gl::TexImage2D(
489 gl::TEXTURE_2D,
490 0,
491 gl::RGBA as i32,
492 width as i32,
493 height as i32,
494 0,
495 gl::RGBA,
496 gl::UNSIGNED_BYTE,
497 match data {
498 Some(data) => data.as_ptr() as *const c_void,
499 None => std::ptr::null(),
500 },
501 );
502 }
503 TextureType::Alpha => {
504 gl::TexImage2D(
505 gl::TEXTURE_2D,
506 0,
507 gl::R8 as i32,
508 width as i32,
509 height as i32,
510 0,
511 gl::RED,
512 gl::UNSIGNED_BYTE,
513 match data {
514 Some(data) => data.as_ptr() as *const c_void,
515 None => std::ptr::null(),
516 },
517 );
518 }
519 }
520
521 if flags.contains(ImageFlags::GENERATE_MIPMAPS) {
522 if flags.contains(ImageFlags::NEAREST) {
523 gl::TexParameteri(
524 gl::TEXTURE_2D,
525 gl::TEXTURE_MIN_FILTER,
526 gl::NEAREST_MIPMAP_NEAREST as i32,
527 );
528 } else {
529 gl::TexParameteri(
530 gl::TEXTURE_2D,
531 gl::TEXTURE_MIN_FILTER,
532 gl::LINEAR_MIPMAP_LINEAR as i32,
533 );
534 }
535 } else {
536 if flags.contains(ImageFlags::NEAREST) {
537 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
538 } else {
539 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
540 }
541 }
542
543 if flags.contains(ImageFlags::NEAREST) {
544 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
545 } else {
546 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
547 }
548
549 if flags.contains(ImageFlags::REPEATX) {
550 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
551 } else {
552 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
553 }
554
555 if flags.contains(ImageFlags::REPEATY) {
556 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
557 } else {
558 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
559 }
560
561 gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
562
563 if flags.contains(ImageFlags::GENERATE_MIPMAPS) {
564 gl::GenerateMipmap(gl::TEXTURE_2D);
565 }
566
567 gl::BindTexture(gl::TEXTURE_2D, 0);
568 tex
569 };
570
571 let id = self.textures.insert(Texture {
572 tex,
573 width,
574 height,
575 texture_type,
576 flags,
577 });
578 Ok(id)
579 }
580
581 fn delete_texture(&mut self, img: ImageId) -> anyhow::Result<()> {
582 if let Some(texture) = self.textures.get(img) {
583 unsafe { gl::DeleteTextures(1, &texture.tex) }
584 self.textures.remove(img);
585 Ok(())
586 } else {
587 bail!("texture '{}' not found", img);
588 }
589 }
590
591 fn update_texture(
592 &mut self,
593 img: ImageId,
594 x: usize,
595 y: usize,
596 width: usize,
597 height: usize,
598 data: &[u8],
599 ) -> anyhow::Result<()> {
600 if let Some(texture) = self.textures.get(img) {
601 unsafe {
602 gl::BindTexture(gl::TEXTURE_2D, texture.tex);
603 gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
604
605 match texture.texture_type {
606 TextureType::RGBA => gl::TexSubImage2D(
607 gl::TEXTURE_2D,
608 0,
609 x as i32,
610 y as i32,
611 width as i32,
612 height as i32,
613 gl::RGBA,
614 gl::UNSIGNED_BYTE,
615 data.as_ptr() as *const c_void,
616 ),
617 TextureType::Alpha => gl::TexSubImage2D(
618 gl::TEXTURE_2D,
619 0,
620 x as i32,
621 y as i32,
622 width as i32,
623 height as i32,
624 gl::RED,
625 gl::UNSIGNED_BYTE,
626 data.as_ptr() as *const c_void,
627 ),
628 }
629
630 gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
631 gl::BindTexture(gl::TEXTURE_2D, 0);
632 }
633 Ok(())
634 } else {
635 bail!("texture '{}' not found", img);
636 }
637 }
638
639 fn texture_size(&self, img: ImageId) -> anyhow::Result<(usize, usize)> {
640 if let Some(texture) = self.textures.get(img) {
641 Ok((texture.width, texture.height))
642 } else {
643 bail!("texture '{}' not found", img);
644 }
645 }
646
647 fn viewport(&mut self, extent: Extent, _device_pixel_ratio: f32) -> anyhow::Result<()> {
648 self.view = extent;
649 Ok(())
650 }
651
652 fn cancel(&mut self) -> anyhow::Result<()> {
653 self.vertexes.clear();
654 self.paths.clear();
655 self.calls.clear();
656 self.uniforms.clear();
657 Ok(())
658 }
659
660 fn flush(&mut self) -> anyhow::Result<()> {
661 if !self.calls.is_empty() {
662 unsafe {
663 gl::UseProgram(self.shader.prog);
664
665 gl::Enable(gl::CULL_FACE);
666 gl::CullFace(gl::BACK);
667 gl::FrontFace(gl::CCW);
668 gl::Enable(gl::BLEND);
669 gl::Disable(gl::DEPTH_TEST);
670 gl::Disable(gl::SCISSOR_TEST);
671 gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
672 gl::StencilMask(0xffffffff);
673 gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP);
674 gl::StencilFunc(gl::ALWAYS, 0, 0xffffffff);
675 gl::ActiveTexture(gl::TEXTURE0);
676 gl::BindTexture(gl::TEXTURE_2D, 0);
677
678 gl::BindBuffer(gl::UNIFORM_BUFFER, self.frag_buf);
679 gl::BufferData(
680 gl::UNIFORM_BUFFER,
681 self.uniforms.len() as isize,
682 self.uniforms.as_ptr() as *const c_void,
683 gl::STREAM_DRAW,
684 );
685
686 gl::BindVertexArray(self.vert_arr);
687 gl::BindBuffer(gl::ARRAY_BUFFER, self.vert_buf);
688 gl::BufferData(
689 gl::ARRAY_BUFFER,
690 (self.vertexes.len() * std::mem::size_of::<Vertex>()) as isize,
691 self.vertexes.as_ptr() as *const c_void,
692 gl::STREAM_DRAW,
693 );
694 gl::EnableVertexAttribArray(0);
695 gl::EnableVertexAttribArray(1);
696 gl::VertexAttribPointer(
697 0,
698 2,
699 gl::FLOAT,
700 gl::FALSE,
701 std::mem::size_of::<Vertex>() as i32,
702 std::ptr::null(),
703 );
704 gl::VertexAttribPointer(
705 1,
706 2,
707 gl::FLOAT,
708 gl::FALSE,
709 std::mem::size_of::<Vertex>() as i32,
710 (2 * std::mem::size_of::<f32>()) as *const c_void,
711 );
712
713 gl::Uniform1i(self.shader.loc_tex, 0);
714 gl::Uniform2fv(
715 self.shader.loc_viewsize,
716 1,
717 &self.view as *const Extent as *const f32,
718 );
719
720 gl::BindBuffer(gl::UNIFORM_BUFFER, self.frag_buf);
721
722 for call in &self.calls {
723 let blend = &call.blend_func;
724
725 gl::BlendFuncSeparate(
726 blend.src_rgb,
727 blend.dst_rgb,
728 blend.src_alpha,
729 blend.dst_alpha,
730 );
731
732 match call.call_type {
733 CallType::Fill => self.do_fill(&call),
734 CallType::ConvexFill => self.do_contex_fill(&call),
735 CallType::Stroke => self.do_stroke(&call),
736 CallType::Triangles => self.do_triangles(&call),
737 }
738 }
739
740 gl::DisableVertexAttribArray(0);
741 gl::DisableVertexAttribArray(1);
742 gl::BindVertexArray(0);
743 gl::Disable(gl::CULL_FACE);
744 gl::BindBuffer(gl::ARRAY_BUFFER, 0);
745 gl::UseProgram(0);
746 gl::BindTexture(gl::TEXTURE_2D, 0);
747 }
748 }
749
750 self.vertexes.clear();
751 self.paths.clear();
752 self.calls.clear();
753 self.uniforms.clear();
754 Ok(())
755 }
756
757 fn fill(
758 &mut self,
759 paint: &Paint,
760 composite_operation: CompositeOperationState,
761 scissor: &Scissor,
762 fringe: f32,
763 bounds: Bounds,
764 paths: &[Path],
765 ) -> anyhow::Result<()> {
766 let mut call = Call {
767 call_type: CallType::Fill,
768 image: paint.image,
769 path_offset: self.paths.len(),
770 path_count: paths.len(),
771 triangle_offset: 0,
772 triangle_count: 4,
773 uniform_offset: 0,
774 blend_func: composite_operation.into(),
775 };
776
777 if paths.len() == 1 && paths[0].convex {
778 call.call_type = CallType::ConvexFill;
779 }
780
781 let mut offset = self.vertexes.len();
782 for path in paths {
783 let fill = path.get_fill();
784 let mut gl_path = GLPath {
785 fill_offset: 0,
786 fill_count: 0,
787 stroke_offset: 0,
788 stroke_count: 0,
789 };
790
791 if !fill.is_empty() {
792 gl_path.fill_offset = offset;
793 gl_path.fill_count = fill.len();
794 self.vertexes.extend(fill);
795 offset += fill.len();
796 }
797
798 let stroke = path.get_stroke();
799 if !stroke.is_empty() {
800 gl_path.stroke_offset = offset;
801 gl_path.stroke_count = stroke.len();
802 self.vertexes.extend(stroke);
803 offset += stroke.len();
804 }
805
806 self.paths.push(gl_path);
807 }
808
809 if call.call_type == CallType::Fill {
810 call.triangle_offset = offset;
811 self.vertexes
812 .push(Vertex::new(bounds.max.x, bounds.max.y, 0.5, 1.0));
813 self.vertexes
814 .push(Vertex::new(bounds.max.x, bounds.min.y, 0.5, 1.0));
815 self.vertexes
816 .push(Vertex::new(bounds.min.x, bounds.max.y, 0.5, 1.0));
817 self.vertexes
818 .push(Vertex::new(bounds.min.x, bounds.min.y, 0.5, 1.0));
819
820 call.uniform_offset = self.uniforms.len() / self.frag_size;
821 self.append_uniforms(FragUniforms {
822 stroke_thr: -1.0,
823 type_: ShaderType::Simple as i32,
824 ..FragUniforms::default()
825 });
826 self.append_uniforms(self.convert_paint(paint, scissor, fringe, fringe, -1.0));
827 } else {
828 call.uniform_offset = self.uniforms.len() / self.frag_size;
829 self.append_uniforms(self.convert_paint(paint, scissor, fringe, fringe, -1.0));
830 }
831
832 self.calls.push(call);
833 Ok(())
834 }
835
836 fn stroke(
837 &mut self,
838 paint: &Paint,
839 composite_operation: CompositeOperationState,
840 scissor: &Scissor,
841 fringe: f32,
842 stroke_width: f32,
843 paths: &[Path],
844 ) -> anyhow::Result<()> {
845 let mut call = Call {
846 call_type: CallType::Stroke,
847 image: paint.image,
848 path_offset: self.paths.len(),
849 path_count: paths.len(),
850 triangle_offset: 0,
851 triangle_count: 0,
852 uniform_offset: 0,
853 blend_func: composite_operation.into(),
854 };
855
856 let mut offset = self.vertexes.len();
857 for path in paths {
858 let mut gl_path = GLPath {
859 fill_offset: 0,
860 fill_count: 0,
861 stroke_offset: 0,
862 stroke_count: 0,
863 };
864
865 let stroke = path.get_stroke();
866 if !stroke.is_empty() {
867 gl_path.stroke_offset = offset;
868 gl_path.stroke_count = stroke.len();
869 self.vertexes.extend(stroke);
870 offset += stroke.len();
871 self.paths.push(gl_path);
872 }
873 }
874
875 call.uniform_offset = self.uniforms.len() / self.frag_size;
876 self.append_uniforms(self.convert_paint(paint, scissor, stroke_width, fringe, -1.0));
877 self.append_uniforms(self.convert_paint(
878 paint,
879 scissor,
880 stroke_width,
881 fringe,
882 1.0 - 0.5 / 255.0,
883 ));
884
885 self.calls.push(call);
886 Ok(())
887 }
888
889 fn triangles(
890 &mut self,
891 paint: &Paint,
892 composite_operation: CompositeOperationState,
893 scissor: &Scissor,
894 vertexes: &[Vertex],
895 ) -> anyhow::Result<()> {
896 let call = Call {
897 call_type: CallType::Triangles,
898 image: paint.image,
899 path_offset: 0,
900 path_count: 0,
901 triangle_offset: self.vertexes.len(),
902 triangle_count: vertexes.len(),
903 uniform_offset: self.uniforms.len() / self.frag_size,
904 blend_func: composite_operation.into(),
905 };
906
907 self.calls.push(call);
908 self.vertexes.extend(vertexes);
909
910 let mut uniforms = self.convert_paint(paint, scissor, 1.0, 1.0, -1.0);
911 uniforms.type_ = ShaderType::Image as i32;
912 self.append_uniforms(uniforms);
913 Ok(())
914 }
915}
916
917fn shader_error(shader: gl::types::GLuint, filename: &str) -> anyhow::Error {
918 unsafe {
919 let mut data: [gl::types::GLchar; 512 + 1] = std::mem::zeroed();
920 let mut len: gl::types::GLsizei = std::mem::zeroed();
921 gl::GetShaderInfoLog(shader, 512, &mut len, data.as_mut_ptr());
922 if len > 512 {
923 len = 512;
924 }
925 data[len as usize] = 0;
926 let err_msg = std::ffi::CStr::from_ptr(data.as_ptr());
927 anyhow!(
928 "failed to compile shader: {}: {}",
929 filename,
930 err_msg.to_string_lossy()
931 )
932 }
933}
934
935fn program_error(prog: gl::types::GLuint) -> anyhow::Error {
936 unsafe {
937 let mut data: [gl::types::GLchar; 512 + 1] = std::mem::zeroed();
938 let mut len: gl::types::GLsizei = std::mem::zeroed();
939 gl::GetProgramInfoLog(prog, 512, &mut len, data.as_mut_ptr());
940 if len > 512 {
941 len = 512;
942 }
943 data[len as usize] = 0;
944 let err_msg = std::ffi::CStr::from_ptr(data.as_ptr());
945 anyhow!("failed to link program: {}", err_msg.to_string_lossy())
946 }
947}
948
949fn convert_blend_factor(factor: BlendFactor) -> gl::types::GLenum {
950 match factor {
951 BlendFactor::Zero => gl::ZERO,
952 BlendFactor::One => gl::ONE,
953 BlendFactor::SrcColor => gl::SRC_COLOR,
954 BlendFactor::OneMinusSrcColor => gl::ONE_MINUS_SRC_COLOR,
955 BlendFactor::DstColor => gl::DST_COLOR,
956 BlendFactor::OneMinusDstColor => gl::ONE_MINUS_DST_COLOR,
957 BlendFactor::SrcAlpha => gl::SRC_ALPHA,
958 BlendFactor::OneMinusSrcAlpha => gl::ONE_MINUS_SRC_ALPHA,
959 BlendFactor::DstAlpha => gl::DST_ALPHA,
960 BlendFactor::OneMinusDstAlpha => gl::ONE_MINUS_DST_ALPHA,
961 BlendFactor::SrcAlphaSaturate => gl::SRC_ALPHA_SATURATE,
962 }
963}
964
965#[inline]
966fn premul_color(color: Color) -> Color {
967 Color {
968 r: color.r * color.a,
969 g: color.g * color.a,
970 b: color.b * color.a,
971 a: color.a,
972 }
973}
974
975#[inline]
976fn xform_to_3x4(xform: Transform) -> [f32; 12] {
977 let mut m = [0f32; 12];
978 let t = &xform.0;
979 m[0] = t[0];
980 m[1] = t[1];
981 m[2] = 0.0;
982 m[3] = 0.0;
983 m[4] = t[2];
984 m[5] = t[3];
985 m[6] = 0.0;
986 m[7] = 0.0;
987 m[8] = t[4];
988 m[9] = t[5];
989 m[10] = 1.0;
990 m[11] = 0.0;
991 m
992}