Rust文本渲染库Glyphon的使用,Glyphon为Rust应用提供高效跨平台文本排版与渲染解决方案

Rust文本渲染库Glyphon的使用

Glyphon为Rust应用提供高效跨平台文本排版与渲染解决方案

什么是Glyphon?

Glyphon是一个为wgpu提供简单2D文本渲染的库,它通过以下方式工作:

  • 使用cosmic-text进行字形形状计算/布局/栅格化
  • 使用etagere将字形打包到纹理图集
  • 使用wgpu从纹理图集采样渲染文本

为了避免额外的渲染通道,渲染使用现有的渲染通道(遵循wgpu的Encapsulating Graphics Work wiki页面中描述的中间件模式)。

许可证

该项目采用以下许可证之一:

  • Apache License, Version 2.0
  • zlib License
  • MIT License

安装

在项目目录中运行以下Cargo命令:

cargo add glyphon

或者在Cargo.toml中添加以下行:

glyphon = "0.9.0"

完整示例代码

use glyphon::{Attrs, Color, Family, FontSystem, SwashCache, TextArea, TextAtlas, TextRenderer};
use wgpu::{Device, Queue, TextureFormat};

fn main() {
    // 初始化wgpu设备、队列和表面纹理格式
    let (device, queue, format) = init_wgpu();
    
    // 创建字体系统
    let mut font_system = FontSystem::new();
    
    // 创建字形缓存
    let mut swash_cache = SwashCache::new();
    
    // 创建文本图集
    let mut atlas = TextAtlas::new(&device, &queue, format);
    
    // 创建文本渲染器
    let mut text_renderer = TextRenderer::new(&mut atlas, &device, None, None);
    
    // 准备要渲染的文本
    let text = "Hello, Glyphon!";
    let bounds = (0.0, 0.0, 300.0, 200.0);
    let color = Color::rgb(255, 255, 255);
    let size = 16.0;
    
    let text_area = TextArea {
        text,
        bounds,
        color,
        attrs: Attrs::new().family(Family::SansSerif).size(size),
        ..Default::default()
    };
    
    // 在渲染循环中:
    // 1. 更新图集
    atlas.trim();
    
    // 2. 准备文本渲染
    text_renderer.queue_text(&font_system, &mut swash_cache, &text_area);
    
    // 3. 在渲染通道中
    let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
        // ... 其他参数
        label: Some("text_render_pass"),
    });
    
    // 4. 渲染文本
    text_renderer.draw(&mut atlas, &device, &queue, &mut render_pass).unwrap();
}

fn init_wgpu() -> (wgpu::Device, wgpu::Queue, wgpu::TextureFormat) {
    // 这里应包含实际的wgpu初始化代码
    unimplemented!()
}

更完整的示例代码

use winit::{
    event::{Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop},
    window::WindowBuilder,
};
use wgpu::{
    Backends, Device, DeviceDescriptor, Instance, InstanceDescriptor, PresentMode, Queue,
    RequestAdapterOptions, Surface, SurfaceConfiguration, TextureFormat, TextureUsages,
};
use glyphon::{Attrs, Color, Family, FontSystem, SwashCache, TextArea, TextAtlas, TextRenderer};

async fn run() {
    // 1. 创建窗口和wgpu实例
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();
    
    let instance = Instance::new(InstanceDescriptor {
        backends: Backends::all(),
        ..Default::default()
    });
    
    let surface = unsafe { instance.create_surface(&window) }.unwrap();
    
    // 2. 初始化适配器、设备和队列
    let adapter = instance
        .request_adapter(&RequestAdapterOptions {
            power_preference: wgpu::PowerPreference::HighPerformance,
            force_fallback_adapter: false,
            compatible_surface: Some(&surface),
        })
        .await
        .unwrap();
    
    let (device, queue) = adapter
        .request_device(
            &DeviceDescriptor {
                features: wgpu::Features::empty(),
                limits: wgpu::Limits::default(),
                label: None,
            },
            None,
        )
        .await
        .unwrap();
    
    // 3. 配置表面
    let surface_caps = surface.get_capabilities(&adapter);
    let surface_format = surface_caps
        .formats
        .iter()
        .copied()
        .find(|f| f.describe().srgb)
        .unwrap_or(surface_caps.formats[0]);
    
    let config = SurfaceConfiguration {
        usage: TextureUsages::RENDER_ATTACHMENT,
        format: surface_format,
        width: window.inner_size().width,
        height: window.inner_size().height,
        present_mode: PresentMode::Fifo,
        alpha_mode: surface_caps.alpha_modes[0],
        view_formats: vec![],
    };
    
    surface.configure(&device, &config);
    
    // 4. 初始化Glyphon
    let mut font_system = FontSystem::new();
    let mut swash_cache = SwashCache::new();
    let mut atlas = TextAtlas::new(&device, &queue, surface_format);
    let mut text_renderer = TextRenderer::new(&mut atlas, &device, None, None);
    
    // 5. 准备渲染的文本
    let text_area = TextArea {
        text: "Hello, Glyphon! 这是一个中文示例",
        bounds: (20.0, 20.0, 300.0, 200.0),
        color: Color::rgb(255, 255, 255),
        attrs: Attrs::new().family(Family::SansSerif).size(24.0),
        ..Default::default()
    };
    
    // 6. 事件循环
    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;
        
        match event {
            Event::RedrawRequested(_) => {
                // 7. 渲染流程
                let frame = surface.get_current_texture().unwrap();
                let view = frame.texture.create_view(&wgpu::TextureViewDescriptor::default());
                
                let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
                    label: Some("Render Encoder"),
                });
                
                {
                    // 8. 更新文本图集
                    atlas.trim();
                    
                    // 9. 准备文本渲染
                    text_renderer.queue_text(&font_system, &mut swash_cache, &text_area);
                    
                    // 10. 创建渲染通道
                    let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                        label: Some("Render Pass"),
                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                            view: &view,
                            resolve_target: None,
                            ops: wgpu::Operations {
                                load: wgpu::LoadOp::Clear(wgpu::Color {
                                    r: 0.1,
                                    g: 0.2,
                                    b: 0.3,
                                    a: 1.0,
                                }),
                                store: wgpu::StoreOp::Store,
                            },
                        })],
                        depth_stencil_attachment: None,
                    });
                    
                    // 11. 渲染文本
                    text_renderer.draw(&mut atlas, &device, &queue, &mut render_pass).unwrap();
                }
                
                queue.submit(std::iter::once(encoder.finish()));
                frame.present();
            }
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
                WindowEvent::Resized(size) => {
                    if size.width > 0 && size.height > 0 {
                        config.width = size.width;
                        config.height = size.height;
                        surface.configure(&device, &config);
                        window.request_redraw();
                    }
                }
                _ => {}
            },
            _ => {}
        }
    });
}

fn main() {
    pollster::block_on(run());
}

1 回复

Glyphon: Rust中的高效跨平台文本渲染库

介绍

Glyphon是一个专为Rust设计的文本渲染库,提供高效的跨平台文本排版与渲染解决方案。它特别适合需要高质量文本渲染的应用程序,如GUI工具、游戏、编辑器等。

Glyphon的主要特点:

  • 跨平台支持(Windows、macOS、Linux等)
  • 高性能文本渲染
  • 支持多种字体格式
  • 灵活的布局和样式控制
  • 与现有Rust图形生态良好集成

安装

在Cargo.toml中添加依赖:

[dependencies]
glyphon = "0.3"

完整示例demo

下面是一个完整的Glyphon使用示例,展示如何初始化、加载字体并渲染文本:

use glyphon::{FontSystem, TextAtlas, TextRenderer, TextArea, Metrics, FontId, TextProperties};
use glyphon::{Attrs, Family, TextBuffer, Alignment, Wrap};
use wgpu::{Device, Queue, CommandEncoder, TextureFormat, RenderPass};

struct GlyphonDemo {
    font_system: FontSystem,
    atlas: TextAtlas,
    renderer: TextRenderer,
}

impl GlyphonDemo {
    fn new(device: &Device, queue: &Queue, format: TextureFormat) -> Self {
        // 1. 初始化字体系统
        let mut font_system = FontSystem::new();
        
        // 加载字体
        font_system.db_mut().load_system_fonts();
        
        // 2. 创建文本图集
        let mut atlas = TextAtlas::new(device, queue, format);
        
        // 3. 创建文本渲染器
        let renderer = TextRenderer::new(&mut atlas, device);
        
        Self {
            font_system,
            atlas,
            renderer,
        }
    }
    
    fn render_simple_text(
        &mut self,
        device: &Device,
        queue: &Queue,
        encoder: &mut CommandEncoder,
    ) {
        // 创建简单文本区域
        let text_area = TextArea {
            text: "Hello, Glyphon!",
            font: FontId(0), // 使用第一个加载的字体
            color: [1.0, 1.0, 1.0, 1.0], // 白色文本
            metrics: Metrics::new(24.0, 28.0), // 字体大小24px,行高28px
            bounds: (400.0, 200.0), // 边界框大小
            position: (50.0, 50.0), // 位置
            properties: TextProperties::default(),
        };
        
        // 准备渲染
        self.renderer.prepare(
            device,
            queue,
            &mut self.font_system,
            &mut self.atlas,
            [text_area],
        ).unwrap();
        
        // 在渲染通道中绘制文本
        let mut render_pass = encoder.begin_render_pass(...);
        self.renderer.render(&self.atlas, &mut render_pass).unwrap();
    }
    
    fn render_rich_text(
        &mut self,
        device: &Device,
        queue: &Queue,
        encoder: &mut CommandEncoder,
    ) {
        // 创建富文本缓冲区
        let mut buffer = TextBuffer::new(&mut self.font_system, Metrics::new(16.0, 20.0));
        
        buffer.set_text(
            &mut self.font_system,
            "Glyphon支持富文本渲染:粗体、斜体和颜色",
            Attrs::new()
                .family(Family::SansSerif)
                .color([0.9, 0.9, 0.9, 1.0]), // 浅灰色文本
        );
        
        // 设置粗体范围
        buffer.set_span(
            &mut self.font_system,
            14..16, // "粗体"的范围
            Attrs::new().weight(glyphon::Weight::BOLD),
        );
        
        // 设置斜体范围
        buffer.set_span(
            &mut self.font_system,
            18..20, // "斜体"的范围
            Attrs::new().style(glyphon::Style::Italic),
        );
        
        // 设置颜色范围
        buffer.set_span(
            &mut self.font_system,
            22..24, // "颜色"的范围
            Attrs::new().color([1.0, 0.5, 0.2, 1.0]), // 橙色
        );
        
        // 定义文本区域
        let text_area = TextArea {
            buffer: &buffer,
            bounds: (500.0, 100.0),
            position: (50.0, 150.0),
        };
        
        // 准备渲染
        self.renderer.prepare(
            device,
            queue,
            &mut self.font_system,
            &mut self.atlas,
            [text_area],
        ).unwrap();
        
        // 在渲染通道中绘制文本
        let mut render_pass = encoder.begin_render_pass(...);
        self.renderer.render(&self.atlas, &mut render_pass).unwrap();
    }
    
    fn render_wrapped_text(
        &mut self,
        device: &Device,
        queue: &Queue,
        encoder: &mut CommandEncoder,
    ) {
        // 创建带换行的文本缓冲区
        let mut buffer = TextBuffer::new(&mut self.font_system, Metrics::new(14.0, 18.0));
        
        buffer.set_text(
            &mut self.font_system,
            "这是一段很长的文本,Glyphon可以根据指定的宽度自动换行,支持按单词换行和对齐方式设置。",
            Attrs::new().family(Family::SansSerif),
        );
        
        // 设置换行方式
        buffer.set_wrap(&mut self.font_system, Wrap::Word); // 按单词换行
        buffer.set_align(Alignment::Center); // 居中对齐
        
        // 定义文本区域
        let text_area = TextArea {
            buffer: &buffer,
            bounds: (300.0, 200.0), // 定义换行宽度
            position: (100.0, 300.0),
        };
        
        // 准备渲染
        self.renderer.prepare(
            device,
            queue,
            &mut self.font_system,
            &mut self.atlas,
            [text_area],
        ).unwrap();
        
        // 在渲染通道中绘制文本
        let mut render_pass = encoder.begin_render_pass(...);
        self.renderer.render(&self.atlas, &mut render_pass).unwrap();
    }
}

// 使用示例
fn main() {
    // 假设已经初始化了wgpu的Device、Queue等
    let (device, queue, format) = init_wgpu();
    
    // 创建Glyphon演示实例
    let mut glyphon_demo = GlyphonDemo::new(&device, &queue, format);
    
    // 创建命令编码器
    let mut encoder = device.create_command_encoder(...);
    
    // 渲染简单文本
    glyphon_demo.render_simple_text(&device, &queue, &mut encoder);
    
    // 渲染富文本
    glyphon_demo.render_rich_text(&device, &queue, &mut encoder);
    
    // 渲染带换行的文本
    glyphon_demo.render_wrapped_text(&device, &queue, &mut encoder);
    
    // 提交命令
    queue.submit(Some(encoder.finish()));
}

// 初始化wgpu的函数(简化版)
fn init_wgpu() -> (Device, Queue, TextureFormat) {
    // 实际项目中需要完整的wgpu初始化代码
    unimplemented!()
}

关键点说明

  1. 初始化流程

    • 创建FontSystem管理字体
    • 创建TextAtlas存储字形纹理
    • 创建TextRenderer负责实际渲染
  2. 文本渲染步骤

    • 准备文本内容(简单文本或富文本)
    • 调用prepare方法准备渲染数据
    • 在wgpu的渲染通道中调用render方法绘制
  3. 性能优化

    • 重用FontSystemTextAtlasTextRenderer实例
    • 批量处理文本渲染调用
    • 合理设置文本图集大小

这个完整示例展示了Glyphon的核心功能,包括简单文本渲染、富文本样式设置以及自动换行文本处理。实际使用时,可以根据需要调整字体大小、颜色、位置等参数。

回到顶部