☰
V 语言 gg 图形模块完全指南:从 2D 绘制到多窗口应用
2026/10/3 12:57:25 网站建设 项目流程

V 语言 gg 图形模块完全指南:从 2D 绘制到多窗口应用

【免费下载链接】vSimple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io项目地址: https://gitcode.com/GitHub_Trending/v/v

gg是 V 语言官方自带的简单图形模块,当前基于sokol(sapp/sgl/gfx)实现,用于快速创建需要绘制 2D 图形并响应键盘、鼠标输入的应用。本文以 vlib/gg/README.md 为骨架,结合gg模块源码、x.multiwindow底层实现、examples/gg与vlib/gg测试用例,系统讲解单窗口gg.Context绘图 API、多窗口gg.App门面(facade)、事件/服务/读回(readback)体系与 Troubleshooting 极限调优,帮助读者掌握从画一个多边形到管理多个原生窗口的完整能力。

一、gg是什么

gg是 V 语言的简单图形模块(Simple Graphics Module),其定位在 vlib/gg/README.md 开头即已明确:只需一种方式绘制简单 2D 形状、并对用户键盘/鼠标输入做出反应的应用。它目前基于sokol实现——具体为sapp(应用/窗口/事件循环)、sgl(简单 2D 绘图)、gfx(底层图形接口)三件套,可在 C、JS(WebAssembly)等多个后端编译。

从源码看,gg的核心是 gg.c.v 中的Config结构体(约 105-168 行),它定义了窗口尺寸、标题、背景色、帧回调、事件回调、字体、采样率、交换间隔、拖放等几乎所有单窗口配置项。gg还提供gg.js.v中的Config用于浏览器后端。Event结构体(gg.c.v)封装了 sokol 事件类型sapp.EventType,并携带frame_count、key_code、char_code、key_repeat、modifiers、mouse_button、鼠标坐标、触摸点等字段。

一个典型的单窗口gg应用生命周期是:

module main import gg fn main() { mut context := gg.new_context( bg_color: gg.rgb(174, 198, 255) width: 600 height: 400 window_title: 'Polygons' frame_fn: frame ) context.run() } fn frame(mut ctx gg.Context) { ctx.begin() // ... draw calls ... ctx.end() }

new_context(gg.c.v)返回&Context,context.run()启动事件循环;ctx.begin()会先用bg_color清空整个缓冲(见 gg.c.v 中bg_color的注释),ctx.end()提交本帧绘制命令。frame_fn每帧被调用约 60 次/秒(取决于swap_interval)。

二、绘制 2D 形状:Context绘图 API

gg的Context提供丰富的 2D 绘图方法,覆盖多边形、三角形、圆形、椭圆、圆角矩形、弧形、线条、像素与文字等。这些方法定义在 draw.c.v、image.c.v、text_rendering.c.v 等文件中,并通过draw_fns_api_test.v等测试验证 API 行为。README 给出的经典示例同时演示了三种绘图调用:

fn frame(mut ctx gg.Context) { ctx.begin() ctx.draw_convex_poly([f32(100.0), 100.0, 200.0, 100.0, 300.0, 200.0, 200.0, 300.0, 100.0, 300.0], gg.blue) ctx.draw_poly_empty([f32(50.0), 50.0, 70.0, 60.0, 90.0, 80.0, 70.0, 110.0], gg.black) ctx.draw_triangle_filled(450, 142, 530, 280, 370, 280, gg.red) ctx.end() }
  • draw_convex_poly(vertices, color):以扁平[f32]数组(x0, y0, x1, y1, …)绘制实心凸多边形;
  • draw_poly_empty(vertices, color):绘制空心多边形轮廓;
  • draw_triangle_filled(x1, y1, x2, y2, x3, y3, color):绘制实心三角形。

完整的绘图方法家族(源码确认)包括:draw_rect/draw_rect_filled/draw_rect_empty、draw_rounded_rect_filled/draw_rounded_rect_empty/draw_rounded_rect_border、draw_circle/draw_circle_filled、draw_ellipse/draw_ellipse_filled、draw_arc/draw_arc_sector、draw_line、draw_triangle/draw_triangle_filled、draw_convex_poly/draw_poly_empty、draw_pixel、draw_text等。vlib/gg/testdata下的draw_*.vv文件正是这些绘图原语的可视化回归测试。

除了绘图,Context还支持键盘/鼠标事件回调、图像(image.v,含create_image、create_image_from_file、draw_image等,支持纹理过滤)、文字渲染(text_rendering.v)、帧率显示show_fps()等。颜色由color.v中的Color结构体表示,gg.rgb(r, g, b)、gg.rgba(r, g, b, a)与gg.blue/gg.red/gg.black等内置色板均可使用。

三、单窗口Config配置项全解

Config(gg.c.v)是单窗口gg应用的核心配置,默认值已在源码中给出:

配置项默认值说明
width/height800 / 600窗口初始尺寸
window_title'A GG Window. Set window_title: to change it.'窗口标题
resizabletrue是否允许用户调整窗口大小
bg_color黑色背景色,begin()时用它清屏
init_fnnilSokol 初始化完成后调用一次;部分 gg/Sokol 函数必须在此时或之后调用
frame_fnnil每帧调用(约 60 次/秒,受swap_interval影响)
cleanup_fnnil应用关闭时调用一次,用于清理
update_fnnil每帧开头调用,参数dt为距上次更新的秒数
event_fn/on_eventnil每个用户事件回调(on_event参数顺序相反,计划弃用)
keydown_fn/keyup_fn/char_fnnil按键按下/释放/字符(UTF-8 rune)回调
move_fn/click_fn/unclick_fn/scroll_fnnil鼠标移动/按下/释放/滚轮回调
leave_fn/enter_fnnil鼠标离开/进入窗口回调
resized_fnnil窗口尺寸变化回调
fullscreenfalse启动即全屏(适合游戏/演示/屏保)
scale1.0缩放因子
sample_count0采样数,越大抗锯齿越好但性能开销越大,2通常足够
texture_filter.linear新建图像默认纹理过滤;像素画建议.nearest
swap_interval11=60fps、2=30fps;Windows/macOS/Linux/iOS/HTML5 生效
ui_modefalse仅事件触发时刷新,节省 CPU
enable_dragndropfalse是否启用文件拖放
max_dropped_files1处理的最大拖放文件数
max_dropped_file_path_length2048拖放 UTF-8 路径最大字节数
min_width/min_height0窗口最小尺寸
font_path/custom_bold_font_path/font_bytes_*—字体路径或内嵌字体字节
native_renderingfalsemacOS/iOS 用 Cocoa、Windows 用 GDI+
borderless_windowfalse无原生装饰边框
icon/html5_canvas_name—图标与 HTML5 canvas 名

按键代码在 enums.v 中以KeyCode枚举形式定义(escape=256、enter=257、方向键left/right/up/down、f1~f25、数字小键盘kp_*等);鼠标按键MouseButton(left/right/middle)、组合键Modifier(shift/ctrl/alt/super,flag 枚举)、线型PenLineType(solid/dashed/dotted)也在同文件中。

四、多窗口应用:gg.App门面

从-d gg_multiwindow编译开关开始,gg提供了增量式(additive)多窗口门面gg.App:同一进程可管理多个原生窗口,且不破坏既有单窗口gg.ContextAPI 与行为。

4.1 开启方式

v -d gg_multiwindow run examples/gg/multiwindow.v

gg.App仅在-d gg_multiwindow时编译。普通import gg+gg.new_context()的程序不会加载原生多窗口实现;未开此开关时,gg.AppAPI 面退化为非渲染兼容桩(stub),误用会得到清晰的"compile with -d gg_multiwindow"错误,而不会引入x.multiwindow或原生后端代码。vlib/gg/multiwindow_notd_gg_multiwindow.v正是该桩实现的源码证据。

4.2 底层分层与后端选择

用户通常只import gg;x.multiwindow是底层生命周期/窗口/渲染表面层,供需要直接控制的后端调用者使用。gg.App通过x.multiwindow管理原生窗口与 owner 队列,仅持有渲染初始化后的sokol.gfx/sokol.sgl状态(见 multiwindow_d_gg_multiwindow.v 中App结构体)。

  • 原生应用使用backend: .auto:在运行时/编译时选择合适的平台后端,仅当原生后端不可用时才回退;
  • Linux X11 原生窗口需显式-d x_multiwindow_x11;Wayland 需显式-d sokol_wayland;
  • 测试与无头工具可显式请求backend: .mock,其依赖轻、默认不链接 X11/EGL/OpenGL。

4.3 基本生命周期示例

README 给出的最小多窗口生命周期:

import gg fn main() { mut app := gg.new_app(backend: .auto)! defer { app.stop() or {} } main_window := app.create_window( title: 'Main' width: 800 height: 600 )! app.run( event_fn: fn (event gg.WindowEvent, mut app gg.App) ! { match event.kind { .window_close_requested { app.destroy_window(event.window)! } .window_destroyed { if app.window_ids()!.len == 0 { app.stop()! } } else {} } } )! _ = main_window }

要点:

  • gg.new_app(backend: .auto)!创建应用;app.stop()建议用defer兜底。
  • create_window返回WindowId,配置项在WindowConfig中(见下)。
  • app.run(event_fn: …)启动事件循环;仅生命周期的应用可只用event_fn,无需渲染器。
  • frame_fn/draw_window()需要已具备渲染能力的应用,它们不会重新执行.auto后端选择;需要渲染的程序应使用gg.new_app(require_renderer: true),或渲染前先验证app.capabilities().explicit_swapchain。
  • 在 Xvfb 下做 Linux X11 渲染需要两个开关:
xvfb-run -a v -d gg_multiwindow -d x_multiwindow_x11 run examples/gg/multiwindow.v

4.4AppConfig与WindowConfig

AppConfig(multiwindow_d_gg_multiwindow.v):

字段默认值说明
backend.auto后端策略(.auto/.mock等)
queue_size128事件队列大小
require_rendererfalse是否要求渲染器就绪
app_id''原生应用标识(当前用于 Waylandxdg_toplevelapp id)

WindowConfig(multiwindow_d_gg_multiwindow.v):

字段默认值说明
title'A GG Window'窗口标题
width/height800 / 600窗口尺寸
min_width/min_height0最小尺寸
resizabletrue可调整大小
visibletrue初始可见
high_dpitrue高分屏
borderless/fullscreenfalse无边框/全屏
clear_color透明每窗口清屏色
sample_count1多窗口渲染目标仅支持 1;有渲染回调时其他值会被拒绝(err_multiwindow_render_sample_count_unsupported,见 multiwindow_d_gg_multiwindow.v)
redraw_mode.on_demand重绘模式
init_fn/frame_fn/cleanup_fnnil窗口级回调(回调上下文提供不可变指标、目标快照、有界的帧/通道权限与窗口作用域资源 ID)
owner/modal—模态窗口必须命名同一应用中存活owner;无主模态窗口在原生分配前即被拒绝。销毁 owner 会按子优先顺序销毁其完整拥有窗口树

另外RunConfig(multiwindow_d_gg_multiwindow.v)提供frame_fn、event_fn、input_fn、window_service_fn、readback_fn、app_resource_init_fn/frame_fn/cleanup_fn(跨窗口共享资源)以及max_pending_jobs(默认 64)。

五、多窗口事件体系

gg.App.run()按全局顺序分发四类事件族:

回调事件类型覆盖内容
event_fngg.WindowEvent生命周期:窗口创建、缩放、关闭请求、销毁
input_fngg.WindowInputEvent输入:普通gg.Event附加目标gg.WindowId,保留键/鼠标/滚轮/焦点/窗口状态字段的 gg 侧类型
window_service_fngg.WindowServiceEvent原生服务结果(剪贴板、portal 等)
readback_fn—读回终结结果

关键契约:

  • 幂等性:四个回调中任一个返回错误,run()会将当前事件及后续未处理事件按原顺序重新入队,因此四个处理器都必须是幂等的(不只有 readback 处理器)。
  • frame_count:原生多窗口事件中,gg.Event.frame_count由底层多窗口 owner 轮询周期赋值,同一app.poll_events()调用收集的事件共享同一帧计数。
  • 手工 owner 循环:调用app.poll_events()后,用drain_window_queued_events()(或专用 drain)按精确全局接收顺序消费四类信封;drain_events()、drain_input_events()、drain_window_service_events()各自只消费本族连续前缀,若队首是其他族则返回空且不跳过;没有独立的 gg 读回 drain——经readback_fn(run()内)或规范 drain 的.readback条目消费。
  • 能力驱动输入:使用前先查app.capabilities():input_events、mouse_events、keyboard_events、text_events、focus_events、drop_events、touch_events报告后端实际可投递的能力;cursor_shapes报告app.set_window_cursor(id, shape)是否可更新原生悬停光标;interactive_move_resize报告begin_window_move/begin_window_resize(id, edge)所需原生句柄;native_decorations报告原生/服务端装饰是否生效。能力探测不一定打开显示,因此运行时全局量只在gg.new_app()之后经app.capabilities()才权威。后端必须把不支持的能力类保持为false,不得模拟部分支持。
  • Wayland 细节:touch 需wl_touch、drop 需wl_data_device、交互式移动/缩放需 seat、原生装饰经 xdg-decoration 协商(configure(mode)决定server_side/client_side,被拒时可画客户端回退);光标形状需wp_cursor_shape_manager_v1(无则cursor_shapes == false,未实现wl_cursor_theme客户端回退);fractional-scale-v1 仅在同时存在 viewporter 时使用,否则帧缓冲度量跟随整数wl_outputscale。
  • X11 文本用 XIM/XIC +Xutf8LookupString;X11 文件拖放接受内联或有界 1 MiB ICCCM INCR XDNDtext/uri-list传输,仅在进度时刷新超时、绝不发布部分拖放、源窗口消失也能安全结束。Wayland 文本用 xkb keymap/state 生成按键字符,拖放用wl_data_device/wl_data_offertext/uri-list;两条 Linux 文本路径均尚未实现完整 IME/组合文本。
  • Win32 报告WM_TOUCH的 began/moved/ended 状态;AppKit 还报告touchesCancelledWithEvent:的取消触摸。剪贴板粘贴以事件信号报告,WindowInputEvent不携带剪贴板内容。

六、窗口服务与原生借用

6.1 服务查询:capability-first

对可选操作,应先查询window_operation_capability(window, operation),运行时答案是权威的:

  • .conditional:仍可能要求合成器支持、窗口配置或近期用户动作;
  • .asynchronous:调用不同步权威,也不承诺后续有排队结果;
  • .state_observable:等待状态观测前先检查它。Wayland 最小化是异步且state_observable == false,不保证有最小化状态观测。

用window_state()取最新观测状态;monitor_ids()+monitor_info()取带代际校验的显示器快照。完整观测可权威清除成员资格;部分状态观测保留最后已知 id。显示器名称是描述性的,不是稳定身份。X11 root 工作区/当前桌面变化会刷新完整显示器投影,失败时保留最后快照;Win32 即使无托管窗口也保持应用级显示器投影最新,并在下一个首窗口前刷新。窗口成员观测只含当前可用公共显示器快照中的 id,暂存的原生显示器与度量更新一起可见。

6.2 剪贴板、portal 与原生标识

  • 剪贴板读写返回ClipboardRequestId,需与终结.clipboardWindowServiceEvent匹配;
  • portal 导出返回PortalParentRequestId,就绪事件含不透明标识符与PortalParentLeaseId;外部消费者使用期间保持 lease 存活,之后显式release_portal_parent()。
  • 原生 X11 标识以x11:开头,Wayland xdg-foreign-v2 以wayland:开头,前缀之后全部视为不透明。Wayland 剪贴板用 seat 数据设备、写入需近期输入 serial,portal 导出需 xdg-foreign-v2;若替换源在提交选择前失败,先前发布的剪贴板值保持不变;已被接受的合成器剪贴板发送使用自有有界文本快照,可在替换或取消后完成。
  • X11 每个活动剪贴板读都有独立原生转换请求方,迟到的 inline/failure/INCR 回复不能完成后来的请求;对外部 X11 请求方(含 INCR 分块)的回复使用受检连接,过期请求方只失败该传输而不影响后续剪贴板工作。X11 INCR 读的广告长度是下界,实际增长仅在每请求与聚合剪贴板字节限制内接受。排队剪贴板终结负载跨后端共享16 MiB、64 操作上限,直到服务事件送达或被丢弃前持续计费。

6.3 原生窗口借用with_native_window()

with_native_window()是回调式的。回调内须调用与app.capabilities().backend匹配的访问器:

后端访问器句柄
Win32with_win32HWND
AppKitwith_appkitNSWindow 指针
X11with_x11Display 指针 + X11 Window
Waylandwith_waylandwl_display + wl_surface 指针

NativeWindowLease在外层with_native_window()回调返回时过期;后端句柄更早过期——其嵌套lease.with_*回调返回即过期。严禁在各自回调生命周期之外存储、返回或使用这些授权。

6.4 读回(Readback)

窗口与托管图像读回是异步的:

  • WindowReadbackConfig{}捕获完整目标;rect请求帧缓冲坐标中的正且完全包含的区域。
  • 每次请求准入并排入一个终结结果(.ready/.cancelled/.failed),但回调失败会重放同一排队结果直到确认,处理器必须幂等。
  • .ready结果拥有左上角 RGBA8 字节、显式 stride、尺寸与产生帧submitted_frame;取消/失败不携带像素。
  • 待处理与排队读回共享256 MiB、64 操作上限;生产者先预留紧凑 RGBA8 大小再分配或捕获,存储持续计费直到终结事件送达或被丢弃;待处理请求在窗口/应用拆除时取消。
  • app.capabilities().readback只是当前渲染器的后端级可用性汇总(Mock 有确定性窗口路径;AppKit 需就绪 Metal 渲染器);window_readback_capabilities()报告逐窗口路径可用性。请求仍会校验 app/window 所有权、同窗口图像范围、单采样 2D 渲染目标资格与矩形边界。

端到端示例:

v -d gg_multiwindow run examples/gg/multiwindow_services.v

它以运行时能力为门槛执行操作、查询状态与显示器、关联剪贴板/portal 请求 id、释放 portal lease、使用作用域原生借用,并仅在可用时请求读回。

6.5 后端服务矩阵

后端服务摘要
Mock确定性状态、显示器、剪贴板、portal 与读回(供测试);不支持原生借用。
X11原生状态/显示器、剪贴板、portal(x11:)、作用域借用与原生窗口捕获;焦点仅当存活服务器通告 EWMH_NET_ACTIVE_WINDOW时可用、请求异步、权威状态来自FocusIn/FocusOut。位置与受支持的 WM 最小化/最大化/全屏/恢复请求也异步;ConfigureNotify触发的 root 坐标观测与原生 WM 状态属性事件是权威的。鼠标锁定中心在 resize 后刷新。其他 EWMH、鼠标锁定与渲染图像支持依赖存活服务器/渲染器。
Wayland运行时全局驱动状态/显示器、剪贴板、portal(wayland:)、作用域借用与鼠标锁定;焦点/raise/位置不支持。隐藏/显示重映射保留已配置元数据、所有权、约束、装饰与最大化/全屏意图;无新合成器 configure 时 show 失败且可重试。显示/最小化/最大化/恢复/全屏/鼠标锁定异步,但最小化不可状态观测。渲染读回需活动 GL 路径。
AppKit原生状态/显示器、作用域借用、剪贴板、窗口操作与实时桥报告的标题栏外观;portal 不支持,读回需活动 Metal。
Win32原生状态/显示器(含零窗口观测)、作用域借用、剪贴板与标准窗口操作;焦点/鼠标锁定有条件。焦点丢失事务性释放鼠标锁定,清理失败时保留错误并重试而不产生假的未锁定观测。最大化依赖窗口配置;原生全屏状态未知时全屏/恢复变为不支持。portal/读回当前不支持。

该表仅作方向性参考:始终优先使用逐窗口的实时能力查询而非后端名假设(例如 Wayland 相对鼠标锁定需 relative-pointer 与 pointer-constraints 两个 global)。

6.6 与旧版gg.Context的关系

多窗口事件队列与旧版gg.Context回调完全分离:普通单窗口程序继续使用event_fn、keydown_fn、move_fn、scroll_fn等gg.Context回调,且不 import/初始化x.multiwindow。创建、运行、停止与渲染都应在 owner 线程进行;后台线程用app.post()/app.try_post()调度 owner 侧工作,由 run 循环排空。一个gg.App渲染 owner 不能与同进程的活动旧版gg.Context渲染 owner 共存,但旧版gg.ContextAPI 对普通单窗口程序仍可用。

公开门面将gg.App/WindowId、WindowEvent、WindowInputEvent、WindowServiceEvent、WindowReadbackResult、WindowQueuedEvent映射到x.multiwindow的对应类型;window_state、monitor_ids、window_operation_capability、drain_window_queued_events映射到低层的service_*查询与drain_queued_events。应用代码应留在 gg 侧;不透明 id、lease 与原生句柄不能跨门面互换。

七、逐窗口渲染 API

-d gg_multiwindow下,WindowConfig提供逐窗口清屏色、重绘模式、采样数与 init/frame/cleanup 回调;回调上下文提供不可变指标与目标快照、有界帧/通道权限、app 与窗口作用域托管资源 ID、通道方法与WindowSglContext记录子集。RunConfig提供跨窗口共享资源的 app 资源生命周期回调。

  • 采样数:多窗口渲染目标只支持sample_count: 1,渲染器必需或激活时其他采样数会被拒绝(源码在 multiwindow_d_gg_multiwindow.v)。
  • 窗口捕获:X11/Wayland GL 渲染器激活时,request_window_capture()在绘制后读取gg拥有的帧缓冲,且仅在生产帧提交后发布;request_image_readback()读取托管单采样 2D 渲染目标。无活动 X11 渲染器时窗口捕获回退到原生XGetImage路径(反映 X server drawable,XWayland 下不能保证帧精确合成器呈现)。两者都不是桌面/合成器捕获。结果经RunConfig.readback_fn投递,为左上角 RGBA8 值、支持有界像素区域;操作前先查询window_readback_capabilities()。AppKit 在 Metal 渲染器与私有 pre-present 钩子激活时暴露相同异步契约;GLCore33 与无渲染器 AppKit 构建报告不支持。Win32 读回在该批次仍不支持。
  • 托管 ID:作用域限定于各自 app(及适用时的窗口)。过期、外来或失效 ID 与回调 lease 返回错误,而不是暴露原始gfx.Environment、gfx.Swapchain、原生 drawable、命令缓冲或呈现权限。渲染使用 owner 线程批次、后端签发就绪信用、延迟目标获取、有序定稿与每提交批次一次全局提交。
  • CI 验证:渲染器行为在专用 X11、Wayland、AppKit、Win32 CI lane 中验证,设置VGG_MULTIWINDOW_RUNTIME_PROBES=1、VGG_MULTIWINDOW_RUNTIME_BACKEND、V_MULTIWINDOW_PROBE_BACKEND,并以匹配原生 flag 编译,经进程树 watchdog 运行测试与探针,覆盖多窗口提交、资源清理与替换、过期 lease、回调驱动拆除、恢复与原生故障路径。普通旧版gg.Contextimport 与x.multiwindow及原生多窗口后端依赖保持隔离。实现遵循 V 内置 Sokol 修订版及固定sokol_gfx.h/sokol_gl.h契约。

examples/gg/multiwindow_render_runtime.v是无值守 CI 探针而非交互启动目标;后端 lane 以-d gg_multiwindow加-d x_multiwindow_x11、-d sokol_wayland、-d sokol_metal或-d sokol_d3d11编译,经V_MULTIWINDOW_PROBE_BACKEND选择匹配后端;进程树 watchdog 提供私有父门、执行截止并检查进程清理。所有窗口与渲染器清理成功后,探针输出{"example":"multiwindow_render_runtime","status":"PASS","cleanup":"complete"}。

八、Troubleshooting:顶点/命令上限与性能调优

8.1 症状与默认上限

在同一帧中绘制大量图元时,程序可能超过sokol施加的顶点数与命令数上限,症状是:帧在变复杂后突然变黑。

  • Sokol 顶点默认上限:131072
  • Sokol 命令默认上限:32768

8.2 方案一:编译期提高上限

在程序顶部添加两行 flag 即可:

#flag -D_SGL_DEFAULT_MAX_VERTICES=4194304 #flag -D_SGL_DEFAULT_MAX_COMMANDS=65536

该方案有完整可运行示例:many_thousands_of_circles_overriding_max_vertices.v。其注释(源码确认)提醒:不加 flag 时max_circles > 5040就会只显示蓝屏而无任何圆;提高_SGL_DEFAULT_MAX_VERTICES也会提高默认 RAM 占用(示例在 Ubuntu 20.04 上从约 40MB 升至约 140MB)。README 中的示例值(4194304顶点 /65536命令)可直接套用,具体数值可按需调整。

8.3 方案二:分多个绘制通道

使用多个绘制通道(draw passes),并限制每次通道的绘制调用数,见 many_thousands_of_circles.v。

8.4 方案三:流式纹理单命令上传

把所有绘制先画进一个流式纹理(streaming texture),再将该纹理作为单条绘制命令上传给 GPU,见 random.v 与 random_stars.v。

8.5 方案四:把计算与绘制搬到 GPU 着色器

只向 GPU 上传变化的输入,所有计算与绘制都在着色器中进行——对大量同质粒子/像素类效果最彻底。

九、示例与测试索引

  • 单窗口入门:minimal.v、polygons.v、rectangles.v、moving_square.v、bouncing_balls.v
  • 渲染技巧:draw_pixels.v、draw_unicode_text_with_gg.v、rotating_textured_quad.v、sample_count.v、cursor.v、drag_n_drop.v
  • 多窗口:multiwindow.v(交互示例)、multiwindow_services.v(服务端到端)、multiwindow_render_runtime.v(CI 探针)
  • 测试:draw_fns_api_test.v、color_test.v、image_test.v、text_rendering_test.v、multiwindow_api_d_gg_multiwindow_test.v、multiwindow_services_contract_test.v、multiwindow_render_runtime_contract_test.v、legacy_import_multiwindow_isolation_test.v
  • 绘图原语可视化测试数据:vlib/gg/testdata/draw_*.vv

十、小结

gg以极低门槛覆盖“简单 2D 图形 + 键盘/鼠标输入”的全部需求:单窗口用gg.new_context()+ 绘图 API 即可;需要多原生窗口时,-d gg_multiwindow启用增量门面gg.App,配以能力驱动的四类事件族、服务查询、原生借用与异步读回,底层由x.multiwindow承载。遇到顶点/命令上限导致的突然黑屏,按序尝试提高_SGL_DEFAULT_MAX_VERTICES/_SGL_DEFAULT_MAX_COMMANDS、多绘制通道、流式纹理或 GPU 着色器方案。无论是教学演示、游戏原型还是多窗口工具,gg都是 V 生态中上手最快、文档与示例最完整的图形起点。

【免费下载链接】vSimple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io项目地址: https://gitcode.com/GitHub_Trending/v/v

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询