论坛的首页
勇芳的软件
教程和帮助
VisualFreeBasic编程文档
勇芳系列软件帮助说明教程
留言或交流
登录
搜索
登录
搜索
勇芳
累计撰写
330
篇文章
累计收到
0
条评论
首页
栏目
论坛的首页
勇芳的软件
教程和帮助
VisualFreeBasic编程文档
勇芳系列软件帮助说明教程
留言或交流
登录
作者 【1】 的文章
2026-3-6
SDL3_API分类参考_按键码(CategoryKeycode)
按键码子系统(CategoryKeycode) 该模块定义了用于标识键盘按键和修饰键的核心常量,是 SDL 键盘输入处理的基础数据类型定义模块。 函数 (无) 数据类型 SDL_Keycode:按键码类型(用于标识键盘上的「符号键」,如 SDLK_a 代表字母 A、SDLK_ESCAPE 代表 ESC 键,与键盘布局相关) SDL_Keymod:修饰键状态类型(用于标识 Shift/Ctrl/Alt/GUI 等修饰键的按下状态,可通过位运算组合多个修饰键) 结构体 (无) 枚举 (无) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库) #Include "SDL.bi" ' 辅助函数:解析修饰键状态并返回描述字符串 Function GetModStateString(ByVal modState As SDL_Keymod) As String Dim As String modStr = "" ' 位运算判断修饰键状态(支持多键组合) If (modState And SDL_MOD_SHIFT) Then modStr &= "Shift " If (modState And SDL_MOD_CTRL) Then modStr &= "Ctrl " If (modState And SDL_MOD_ALT) Then modStr &= "Alt " If (modState And SDL_MOD_GUI) Then modStr &= "GUI " ' Windows/Command 键 If (modState And SDL_MOD_CAPS) Then modStr &= "CapsLock " If (modState And SDL_MOD_NUM) Then modStr &= "NumLock " If (modStr = "") Then modStr = "无修饰键" Return modStr End Function ' 辅助函数:打印按键码相关信息 Sub PrintKeycodeInfo(ByVal keycode As SDL_Keycode) Dim As ZString Ptr keyName = SDL_GetKeyName(keycode) Dim As SDL_Scancode scancode = SDL_GetScancodeFromKey(keycode) Dim As ZString Ptr scName = SDL_GetScancodeName(scancode) SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _ "按键码:0x%X | 按键名称:%s | 对应扫描码:0x%X | 扫描码名称:%s", _ keycode, keyName, scancode, scName) SDL_free(keyName) SDL_free(scName) End Sub ' 主程序 Dim As SDL_Window Ptr window = NULL Dim As SDL_Event evt Dim As Boolean quit = False ' 1. 初始化 SDL If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 2. 创建窗口 window = SDL_CreateWindow("SDL Keycode 示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 600, 400, SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError()) SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL_Keycode / SDL_Keymod 示例 ===") SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按任意键查看按键码信息 | 按 F1 查看当前修饰键状态 | 按 ESC 退出") ' 3. 主事件循环 While (Not quit) While (SDL_PollEvent(@evt)) Select Case evt.type ' 窗口关闭事件 Case SDL_QUITEVENT quit = True ' 键盘按键事件 Case SDL_EVENT_KEY_DOWN Select Case evt.key.key Case SDLK_ESCAPE SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下 ESC 键,退出程序") quit = True Case SDLK_F1 ' 获取并打印当前修饰键状态 Dim As SDL_Keymod modState = SDL_GetModState() SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "当前修饰键状态:%s", GetModStateString(modState)) Case Else ' 打印按键码详细信息 SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "==== 按键信息 ====") PrintKeycodeInfo(evt.key.key) ' 打印该按键的修饰键状态 SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "按下时的修饰键:%s", GetModStateString(evt.key.mod)) End Select ' 手动设置修饰键示例(按 F2 模拟按下 Shift+Ctrl) Case SDL_EVENT_KEY_UP If (evt.key.key = SDLK_F2) Then Dim As SDL_Keymod newModState = SDL_MOD_SHIFT Or SDL_MOD_CTRL SDL_SetModState(newModState) SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "手动设置修饰键状态为:%s", GetModStateString(newModState)) End If End Select Wend SDL_Delay(10) Wend ' 4. 清理资源 SDL_DestroyWindow(window) SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出") End 0 核心常量补充说明 在实际使用中,SDL 预定义了大量常用的 SDL_Keycode 常量,以下是最常用的分类: 类别 示例常量 说明 字母键 SDLK_a, SDLK_b, SDLK_Z 大小写统一用大写字母标识 数字键 SDLK_0, SDLK_1, SDLK_9 主键盘数字键 功能键 SDLK_F1, SDLK_F2, SDLK_F12 功能键 F1-F12 控制键 SDLK_ESCAPE, SDLK_RETURN, SDLK_TAB 常用控制键 方向键 SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT 方向键 修饰键 无(修饰键用 SDL_Keymod 表示) Shift/Ctrl/Alt 等 SDL_Keymod 常用常量: SDL_MOD_SHIFT:Shift 键(左/右 Shift 均适用) SDL_MOD_CTRL:Ctrl 键(左/右 Ctrl 均适用) SDL_MOD_ALT:Alt 键(左/右 Alt 均适用) SDL_MOD_GUI:GUI 键(Windows 键/苹果 Command 键) SDL_MOD_CAPS:CapsLock 锁定状态 SDL_MOD_NUM:NumLock 锁定状态 总结 SDL_Keycode 是标识「按键符号」的核心类型,与键盘布局绑定(如 SDLK_a 始终代表字母 A,无论键盘布局如何); SDL_Keymod 是标识修饰键状态的类型,支持位运算组合(如 SDL_MOD_SHIFT Or SDL_MOD_CTRL 表示同时按下 Shift+Ctrl); 该模块无独立函数,仅定义基础数据类型和常量,需配合键盘子系统(CategoryKeyboard)的函数使用(如 SDL_GetKeyName、SDL_GetModState)。 SDL3 键盘使用最佳实践 核心前提 键盘输入看似简单,但一旦超出你常用的语言/地区范围(甚至在同一地区),就会变得异常复杂。 几乎所有游戏,无论采用何种输入方案,都应该提供按键绑定配置功能: 这不仅能解决不同键盘布局的适配问题; 还能让用户将按键调整到最舒适的位置(尤其对行动不便的用户)。 即使不做可视化配置界面,至少也要提供配置文件——这会让很多用户感激不尽! 四种核心使用场景 SDL 处理键盘输入主要有四种常见方式,应用可能在不同场景下混用不同方式。 场景1:「101键游戏手柄」模式 很多游戏把键盘当作「超多按键的手柄」,而非文本输入工具。典型例子是 FPS 游戏的「WASD」移动: 你关心的是物理按键位置,而非按键上印的符号; 比如法语键盘对应「ZQSD」、日语平假名键盘对应「てちとし」,但都是键盘上相同的物理位置。 这种场景下应使用 SDL_Scancode(扫描码): 扫描码绑定物理按键位置,与按键上的符号无关; 底层默认参考美式 QWERTY 键盘布局,这恰好符合「只关心位置」的需求。 事件(Events) vs 状态(States) 处理键盘/鼠标/手柄按键时,开发者常先想到事件,但两者的选择会直接影响体验: 概念区别 事件(Events):系统/SDL 通知你「发生了某件事」(如按键按下/释放),不一定需要立即响应; 适合「单次动作」(如跳跃、换弹); 事件不会每帧触发,即使有按键重复,也会有延迟。 状态(States):代表「事件处理完成后按键的最新状态」; 适合「持续动作」(如移动); 可在每一帧查询,避免事件重复的延迟问题。 按键重复(Key Repeat)说明 按键事件不会每帧发送,SDL 也无法感知你的帧循环时机; 系统会触发「按键重复事件」:首次重复延迟约1秒,之后每200ms一次(具体值由系统/用户设置决定); 用事件处理移动会导致「卡顿」(类似文本编辑器按住按键的字符输入间隔)。 实战示例 状态查询(适合持续动作) 通过 SDL_GetKeyboardState 获取按键状态数组(索引为扫描码),SDL 管理数组生命周期,建议缓存以减少调用次数。 ' 功能:返回玩家移动方向(1=前进,-1=后退,0=不动) Function GetMoveDirection() As Integer Dim As UByte Ptr keyStates = SDL_GetKeyboardState(NULL) Dim As Integer direction = 0 ' 同时按下前进/后退键时,方向抵消(符合直觉) If (keyStates[SDL_SCANCODE_W] = 1) Then direction += 1 ' 美式键盘 W 键位置:前进 End If If (keyStates[SDL_SCANCODE_S] = 1) Then direction -= 1 ' 美式键盘 S 键位置:后退 End If Return direction End Function 事件处理(适合单次动作) 从 SDL_EVENT_KEY_DOWN/UP 事件中提取 scancode 字段,触发单次动作。 Enum Action ACTION_NONE ACTION_RELOAD ACTION_JUMP End Enum ' 功能:根据按键事件返回玩家要执行的动作 Function GetPlayerAction(ByRef evt As SDL_Event) As Action If (evt.type <> SDL_EVENT_KEY_DOWN) Then Return ACTION_NONE End If Select Case evt.key.scancode Case SDL_SCANCODE_R Return ACTION_RELOAD ' R 键位置:换弹 Case SDL_SCANCODE_SPACE Return ACTION_JUMP ' 空格键位置:跳跃 Case Else Return ACTION_NONE End Select End Function 场景2:「特定按键」模式 部分游戏需要检测「按键上的符号」,而非物理位置: 比如「按 I 打开背包」—— 不管 I 键在键盘的哪个位置; 也包括 ESC 取消、Enter 确认等通用按键。 (但仍建议提供按键绑定!有些键盘可能没有 I 键。) 这种场景下应使用 SDL_Keycode(按键码): 按键码绑定「符号」,与物理位置无关; 同样从 SDL_EVENT_KEY_DOWN/UP 事件中获取。 ' 功能:循环等待用户按下 ESC 键退出 Dim As Boolean quitApp = False Dim As SDL_Event evt While (Not quitApp) While (SDL_PollEvent(@evt)) If (evt.type = SDL_EVENT_KEY_DOWN) Then If (evt.key.key = SDLK_ESCAPE) Then quitApp = True SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下 ESC,退出程序") End If End If Wend SDL_Delay(10) Wend 场景3:「聊天框/文本输入」模式 Unicode 处理极其复杂!如果需要输入文本(如角色命名、聊天框),绝对不要用按键事件——这无法适配全球不同的键盘和语言。 正确做法: 调用 SDL_StartTextInput 启用文本输入; 监听 SDL_EVENT_TEXT_INPUT 事件(系统会返回 UTF-8 编码的 Unicode 字符串); 输入完成后调用 SDL_StopTextInput。 这种方式的优势: 适配系统原生输入方式(如移动平台弹出虚拟键盘、多语言输入法候选词); 你无法自己实现覆盖全球所有语言的输入方案,不要尝试基于按键事件造轮子。 缺点:虚拟键盘可能遮挡游戏界面,需要提前设计布局。 ' 功能:实现简单的文本输入框 Dim As Boolean inputComplete = False Dim As String inputText = "" Dim As SDL_Rect inputArea = Type<SDL_Rect>(100, 100, 400, 50) ' 输入区域 Dim As Integer cursorPos = 0 Dim As SDL_Event evt Dim As SDL_Window Ptr window = SDL_CreateWindow("文本输入示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 600, 400, SDL_WINDOW_SHOWN) ' 设置文本输入区域并启用输入 SDL_SetTextInputArea(window, @inputArea, cursorPos) SDL_StartTextInput(window) While (Not inputComplete) While (SDL_PollEvent(@evt)) Select Case evt.type Case SDL_EVENT_KEY_DOWN ' ESC 取消 / Enter 确认 If (evt.key.key = SDLK_ESCAPE Or evt.key.key = SDLK_RETURN) Then SDL_StopTextInput(window) inputComplete = True SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "输入完成:%s", inputText) End If Case SDL_EVENT_TEXT_INPUT ' 追加输入的文本(UTF-8 编码) inputText &= *evt.text.text SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "当前输入:%s", inputText) End Select Wend ' 更新输入区域(适配输入法候选词位置) SDL_SetTextInputArea(window, @inputArea, cursorPos) SDL_Delay(10) Wend SDL_DestroyWindow(window) 全屏游戏如需自定义输入法UI,可设置 SDL_HINT_IME_IMPLEMENTED_UI 提示,并处理 SDL_EVENT_TEXT_EDITING 和 SDL_EVENT_TEXT_EDITING_CANDIDATES 事件。参考示例:testime.c 场景4:「文本编辑器」模式 这是特殊场景,非必要不要使用——多数时候你只是想「错误地从零实现聊天框」。 如果要做 SDL 版 Vim 这类工具,需要处理: 修饰键组合(如 Shift+Z 两次); 小键盘方向键(NumLock 切换数字/方向); 按键事件与文本输入事件的关联。 此时需要同时处理按键事件和输入事件,并通过 SDL_GetKeyFromScancode 获取带修饰键的按键码: ' 功能:检测按下的 $ 键(美式键盘 Shift+4 / 法语键盘直接按 $) Dim As Boolean quitApp = False Dim As SDL_Event evt While (Not quitApp) While (SDL_PollEvent(@evt)) If (evt.type = SDL_EVENT_KEY_DOWN) Then ' 获取带修饰键的按键码 Dim As SDL_Keycode keycode = SDL_GetKeyFromScancode(evt.key.scancode, evt.key.mod, False) If (keycode = Asc("$")) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下了 $ 键!") End If ' ESC 退出 If (evt.key.key = SDLK_ESCAPE) Then quitApp = True End If End If Wend SDL_Delay(10) Wend 注意:很多按键不生成字符,部分字符需要多键组合/输入法生成,这是小众需求,不适合通用输入场景。 向用户展示按键名称 实现自定义按键绑定时,需要在UI中显示按键名称(如「按 [空格] 跳跃」),应使用 SDL_GetKeyName 配合按键码: ' 功能:打印用户按下的按键名称 Dim As Boolean quitApp = False Dim As SDL_Event evt While (Not quitApp) While (SDL_PollEvent(@evt)) If (evt.type = SDL_EVENT_KEY_DOWN) Then Dim As ZString Ptr keyName = SDL_GetKeyName(evt.key.key) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "你按下了 %s 键", keyName) SDL_free(keyName) ' 释放字符串 ' ESC 退出 If (evt.key.key = SDLK_ESCAPE) Then quitApp = True End If End If Wend SDL_Delay(10) Wend 注意:SDL_GetKeyName 仅返回大写字符,这适合向用户展示「按这个符号的按键」。 完整示例(整合所有场景) #Include "SDL.bi" Enum PlayerAction ACTION_NONE ACTION_JUMP ACTION_RELOAD End Enum ' 获取移动方向(状态查询) Function GetMoveDirection() As Integer Dim As UByte Ptr keyStates = SDL_GetKeyboardState(NULL) Dim As Integer dir = 0 If (keyStates[SDL_SCANCODE_W]) Then dir += 1 If (keyStates[SDL_SCANCODE_S]) Then dir -= 1 Return dir End Function ' 获取玩家动作(事件处理) Function GetPlayerAction(ByRef evt As SDL_Event) As PlayerAction If (evt.type <> SDL_EVENT_KEY_DOWN) Then Return ACTION_NONE Select Case evt.key.scancode Case SDL_SCANCODE_SPACE: Return ACTION_JUMP Case SDL_SCANCODE_R: Return ACTION_RELOAD Case Else: Return ACTION_NONE End Select End Function ' 主程序 Dim As SDL_Window Ptr window = NULL Dim As SDL_Event evt Dim As Boolean quit = False, textInputActive = False Dim As String chatText = "" ' 初始化 SDL If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 创建窗口 window = SDL_CreateWindow("SDL 键盘最佳实践示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 800, 600, SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError()) SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 操作说明 ===") SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "W/S:移动(状态查询)| 空格:跳跃/R:换弹(事件)| T:打开聊天框 | ESC:退出") ' 主循环 While (Not quit) ' 处理移动(每帧查询状态) Dim As Integer moveDir = GetMoveDirection() If (moveDir <> 0) Then Static As Integer lastDir = 0 If (moveDir <> lastDir) Then SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "移动方向:%s", IIf(moveDir=1, "前进", "后退")) lastDir = moveDir End If End If ' 处理事件 While (SDL_PollEvent(@evt)) Select Case evt.type Case SDL_QUITEVENT quit = True Case SDL_EVENT_KEY_DOWN ' ESC 退出 If (evt.key.key = SDLK_ESCAPE) Then quit = True End If ' T 键打开聊天框 If (evt.key.key = SDLK_t And Not textInputActive) Then textInputActive = True chatText = "" SDL_StartTextInput(window) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "聊天框已打开,输入文本后按 Enter 发送") End If ' 处理玩家动作 Dim As PlayerAction action = GetPlayerAction(evt) Select Case action Case ACTION_JUMP: SDL_LogInfo(SDL_LOG_CATEGORY_GAME, "玩家跳跃") Case ACTION_RELOAD: SDL_LogInfo(SDL_LOG_CATEGORY_GAME, "玩家换弹") End Select Case SDL_EVENT_TEXT_INPUT If (textInputActive) Then chatText &= *evt.text.text SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "聊天输入:%s", chatText) End If Case SDL_EVENT_KEY_UP ' Enter 发送聊天 If (evt.key.key = SDLK_RETURN And textInputActive) Then SDL_StopTextInput(window) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "发送聊天:%s", chatText) textInputActive = False End If End Select Wend SDL_Delay(10) Wend ' 清理资源 SDL_DestroyWindow(window) SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出") End 0 总结 核心原则:始终提供按键绑定配置,适配不同键盘和用户需求; 场景选择: 物理位置(移动)→ 扫描码 + 状态查询; 按键符号(ESC/Enter)→ 按键码 + 事件; 文本输入(聊天/命名)→ SDL_StartTextInput + 文本输入事件; 复杂编辑器 → 混合按键/输入事件 + 修饰键处理; 关键避坑:不要基于按键事件实现多语言文本输入,依赖系统原生输入法接口。
2026年-3月-6日
6 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_键盘(CategoryKeyboard)
键盘子系统(CategoryKeyboard) SDL 提供的键盘管理功能集,用于处理键盘设备检测、按键状态查询、文本输入等核心键盘交互逻辑。 关于不同类型程序中键盘输入的最佳实践,可参考官方文档: https://wiki.libsdl.org/SDL3/BestKeyboardPractices 函数 SDL_ClearComposition:清空当前的输入法候选文本(适用于中文/日文等输入法的组合输入状态) SDL_GetKeyboardFocus:获取当前拥有键盘焦点的 SDL 窗口(返回 SDL_Window 指针) SDL_GetKeyboardNameForID:根据键盘设备 ID 获取对应的设备名称(如 "USB Keyboard") SDL_GetKeyboards:枚举系统中所有已连接的键盘设备(返回设备 ID 列表及数量) SDL_GetKeyboardState:获取当前所有按键的状态(返回一个字节数组,索引为扫描码,值为 1 表示按下,0 表示释放) SDL_GetKeyFromName:根据按键名称(如 "A"、"Escape")获取对应的 SDL_Keycode(按键码,与键盘布局相关) SDL_GetKeyFromScancode:将 SDL_Scancode(扫描码,与硬件位置相关)转换为 SDL_Keycode(按键码) SDL_GetKeyName:根据 SDL_Keycode 获取对应的按键名称(如 SDLK_a 返回 "A") SDL_GetModState:获取当前的键盘修饰键状态(如 Shift/Ctrl/Alt 是否按下,返回 SDL_Keymod 组合值) SDL_GetScancodeFromKey:将 SDL_Keycode(按键码)转换为 SDL_Scancode(扫描码) SDL_GetScancodeFromName:根据扫描码名称(如 "ScanCode_A")获取对应的 SDL_Scancode SDL_GetScancodeName:根据 SDL_Scancode 获取对应的扫描码名称(如 SDL_SCANCODE_A 返回 "A") SDL_GetTextInputArea:获取当前设置的文本输入区域(用于移动平台虚拟键盘的位置适配) SDL_HasKeyboard:检查系统是否连接了至少一个键盘设备(返回布尔值) SDL_HasScreenKeyboardSupport:检查当前平台是否支持屏幕虚拟键盘(如手机/平板,返回布尔值) SDL_ResetKeyboard:重置键盘状态(清除所有按键按下状态,恢复修饰键为默认) SDL_ScreenKeyboardShown:检查屏幕虚拟键盘是否处于显示状态(返回布尔值) SDL_SetModState:手动设置键盘修饰键状态(仅用于模拟,不会实际改变物理按键状态) SDL_SetScancodeName:自定义扫描码的名称(覆盖系统默认名称) SDL_SetTextInputArea:设置文本输入区域(移动平台虚拟键盘会避开该区域显示) SDL_StartTextInput:启用文本输入功能(激活输入法,触发 SDL_TextInputEvent 事件) SDL_StartTextInputWithProperties:带属性的文本输入启用(指定输入类型,如数字/密码) SDL_StopTextInput:停止文本输入功能(禁用输入法,不再接收文本输入事件) SDL_TextInputActive:检查文本输入功能是否处于激活状态(返回布尔值) 数据类型 SDL_KeyboardID:键盘设备唯一标识类型(用于区分多个连接的键盘设备) 结构体 (无) 枚举 SDL_Capitalization:文本大小写规则枚举(如 SDL_CAPITALIZATION_NONE/SDL_CAPITALIZATION_SENTENCES,用于控制输入文本的大小写) SDL_TextInputType:文本输入类型枚举(如 SDL_TEXT_INPUT_TYPE_TEXT/SDL_TEXT_INPUT_TYPE_NUMBER/SDL_TEXT_INPUT_TYPE_PASSWORD,限定输入内容类型) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库) #Include "SDL.bi" ' 辅助函数:打印修饰键状态 Sub PrintModState() Dim As SDL_Keymod modState = SDL_GetModState() Dim As String modStr = "" If (modState And SDL_MOD_SHIFT) Then modStr &= "Shift " If (modState And SDL_MOD_CTRL) Then modStr &= "Ctrl " If (modState And SDL_MOD_ALT) Then modStr &= "Alt " If (modState And SDL_MOD_GUI) Then modStr &= "GUI " ' Windows/Command 键 If (modStr = "") Then modStr = "无" SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "当前修饰键状态:%s", modStr) End Sub ' 主程序 Dim As SDL_Window Ptr window = NULL Dim As SDL_Event evt Dim As UByte Ptr keyState = NULL Dim As SDL_KeyboardID Ptr keyboardIDs = NULL Dim As Integer keyboardCount = 0 Dim As Integer quit = 0 Dim As String inputText = "" ' 1. 初始化 SDL If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 2. 检查键盘设备 If (Not SDL_HasKeyboard()) Then SDL_LogError(SDL_LOG_CATEGORY_INPUT, "系统未检测到键盘设备") SDL_Quit() End 1 End If ' 枚举键盘设备 keyboardCount = SDL_GetKeyboards(0, NULL) If (keyboardCount > 0) Then keyboardIDs = Callocate(keyboardCount * SizeOf(SDL_KeyboardID)) keyboardCount = SDL_GetKeyboards(keyboardCount, keyboardIDs) SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "检测到 %d 个键盘设备", keyboardCount) For i As Integer = 0 To keyboardCount - 1 Dim As ZString Ptr kbName = SDL_GetKeyboardNameForID(keyboardIDs[i]) SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "键盘 %d:%s", i, kbName) SDL_free(kbName) Next End If ' 3. 创建窗口 window = SDL_CreateWindow("SDL 键盘输入示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 600, 400, SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError()) SDL_Quit() End 1 End If ' 4. 启用文本输入功能 SDL_StartTextInput() SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "文本输入功能已启用") SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 键盘操作示例 ===") SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按 ESC 退出 | 按任意键测试按键检测 | 输入文本将显示在日志中 | 按 F1 打印修饰键状态") ' 5. 主事件循环 While (quit = 0) ' 获取当前按键状态(实时查询,非事件驱动) keyState = SDL_GetKeyboardState(NULL) ' 处理事件队列 While (SDL_PollEvent(@evt)) Select Case evt.type ' 窗口关闭事件 Case SDL_QUITEVENT quit = 1 ' 键盘按键事件(按下/释放) Case SDL_KEYDOWN Select Case evt.key.keysym.sym Case SDLK_ESCAPE SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "ESC 键按下,退出程序") quit = 1 Case SDLK_F1 PrintModState() Case Else ' 打印按键信息(扫描码 + 按键码 + 名称) Dim As SDL_Scancode scancode = evt.key.keysym.scancode Dim As SDL_Keycode keycode = evt.key.keysym.sym Dim As ZString Ptr scName = SDL_GetScancodeName(scancode) Dim As ZString Ptr kName = SDL_GetKeyName(keycode) SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _ "按键按下 - 扫描码:%s (0x%X) | 按键码:%s (0x%X)", _ scName, scancode, kName, keycode) SDL_free(scName) SDL_free(kName) End Select ' 文本输入事件(输入法处理后的完整文本) Case SDL_TEXTINPUT inputText &= *evt.text.text SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "文本输入:%s | 累计输入:%s", evt.text.text, inputText) ' 文本编辑事件(输入法组合状态,如中文拼音) Case SDL_TEXTEDITING SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "文本编辑:%s (光标位置:%d,选择长度:%d)", _ evt.edit.text, evt.edit.start, evt.edit.length) End Select Wend ' 实时检测特定按键(非事件驱动) If (keyState[SDL_SCANCODE_SPACE] = 1) Then Static As Integer spacePressed = 0 If (Not spacePressed) Then SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "空格键被按住(实时检测)") spacePressed = 1 End If Else spacePressed = 0 End If SDL_Delay(10) Wend ' 6. 清理资源 SDL_StopTextInput() If (keyboardIDs <> NULL) Then Deallocate(keyboardIDs) End If SDL_DestroyWindow(window) SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出,累计输入文本:%s", inputText) End 0 总结 SDL 键盘子系统分两类核心能力: 按键状态查询:SDL_GetKeyboardState 实时获取按键状态(非事件驱动),SDL_KEYDOWN/UP 事件驱动检测; 文本输入处理:SDL_StartTextInput 启用输入法,通过 SDL_TEXTINPUT 事件接收完整文本(适配多语言输入法); FreeBASIC 中使用时需区分「扫描码(Scancode)」和「按键码(Keycode)」: 扫描码:与硬件位置绑定(如 SDL_SCANCODE_A 始终对应键盘 A 键位置); 按键码:与键盘布局绑定(如不同语言键盘的 A 键可能对应不同 Keycode); 关键接口: 设备管理:SDL_GetKeyboards/SDL_GetKeyboardNameForID; 状态查询:SDL_GetKeyboardState/SDL_GetModState; 文本输入:SDL_StartTextInput/SDL_TEXTINPUT 事件。
2026年-3月-6日
5 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_事件(CategoryEvents)
事件子系统(CategoryEvents) SDL 事件队列的管理核心模块,是应用与「外部交互」的核心通道——几乎所有和现实世界的交互信息(用户操作、硬件插拔、系统状态变化等)都会流经事件队列。 核心使用方式 应用通常在「新帧开始」时处理事件队列: 最常用:循环调用 SDL_PollEvent() 直到返回 false(无事件),逐个处理或忽略事件; 回调模式:若使用主回调函数,事件会在 SDL_AppIterate() 调用前通过 SDL_AppEvent() 逐个传入,此时无需调用 SDL_PollEvent(); 其他控制方式: SDL_PeepEvents():功能更丰富,但使用复杂度更高; SDL_WaitEvent():阻塞进程直到有事件发生(低功耗硬件场景更友好); SDL_AddEventWatch():注册回调,有新事件时触发。 自定义事件 应用也可主动生成事件: SDL_PushEvent():将自定义事件推入队列,供后续读取; SDL_RegisterEvents():注册自定义事件类型,确保其 ID 不与系统内置类型冲突。 函数 SDL_AddEventWatch:注册事件监听回调(有新事件加入队列时触发该回调) SDL_EventEnabled:检查指定类型的事件是否被启用(返回布尔值) SDL_FilterEvents:对事件队列中的事件批量应用过滤器(筛选/修改事件) SDL_FlushEvent:清空事件队列中指定类型的单个事件 SDL_FlushEvents:清空事件队列中指定类型范围的所有事件 SDL_GetEventDescription:获取指定事件类型的文本描述(如 "SDL_QUIT" 对应 "Quit requested") SDL_GetEventFilter:获取当前设置的全局事件过滤器 SDL_GetWindowFromEvent:从事件对象中提取关联的 SDL_Window 指针 SDL_HasEvent:检查事件队列中是否存在指定类型的单个事件(返回布尔值) SDL_HasEvents:检查事件队列中是否存在指定类型范围的任意事件(返回布尔值) SDL_PeepEvents:从事件队列中读取/移除事件(支持批量操作,比 PollEvent 更灵活) SDL_PollEvent:从事件队列中取出一个事件(非阻塞,无事件时返回 false) SDL_PumpEvents:强制更新事件队列(收集系统输入事件,SDL 内部自动调用,一般无需手动调用) SDL_PushEvent:将自定义事件推入事件队列(返回是否成功) SDL_RegisterEvents:注册自定义事件类型(指定数量,返回起始事件 ID,避免类型冲突) SDL_RemoveEventWatch:移除已注册的事件监听回调 SDL_SetEventEnabled:启用/禁用指定类型的事件(禁用后该事件不会进入队列) SDL_SetEventFilter:设置全局事件过滤器(可拦截/修改所有事件) SDL_WaitEvent:阻塞等待事件队列中有事件(直到有事件时取出并返回) SDL_WaitEventTimeout:带超时的阻塞等待事件(超时后返回 false,避免永久阻塞) 数据类型 SDL_EventFilter:事件过滤器回调类型(用于拦截/修改事件,返回布尔值表示是否保留事件) 结构体 SDL_AudioDeviceEvent:音频设备事件(设备添加/移除) SDL_CameraDeviceEvent:摄像头设备事件(设备添加/移除/授权) SDL_ClipboardEvent:剪贴板事件(内容变化) SDL_CommonEvent:所有事件的公共基结构体(包含时间戳、事件类型等通用字段) SDL_DisplayEvent:显示设备事件(分辨率变化、显示连接/断开) SDL_DropEvent:拖放事件(文件拖入窗口) SDL_Event:核心事件联合体(包含所有类型的事件结构体) SDL_GamepadAxisEvent:游戏手柄轴事件(摇杆/扳机移动) SDL_GamepadButtonEvent:游戏手柄按键事件(按下/释放) SDL_GamepadDeviceEvent:游戏手柄设备事件(连接/断开) SDL_GamepadSensorEvent:游戏手柄传感器事件(陀螺仪/加速度计数据) SDL_GamepadTouchpadEvent:游戏手柄触摸板事件 SDL_JoyAxisEvent:摇杆轴事件(传统摇杆设备) SDL_JoyBallEvent:摇杆轨迹球事件 SDL_JoyBatteryEvent:摇杆电池事件(电量变化) SDL_JoyButtonEvent:摇杆按键事件 SDL_JoyDeviceEvent:摇杆设备事件(连接/断开) SDL_JoyHatEvent:摇杆方向键事件 SDL_KeyboardDeviceEvent:键盘设备事件(连接/断开) SDL_KeyboardEvent:键盘事件(按键按下/释放) SDL_MouseButtonEvent:鼠标按键事件(按下/释放) SDL_MouseDeviceEvent:鼠标设备事件(连接/断开) SDL_MouseMotionEvent:鼠标移动事件 SDL_MouseWheelEvent:鼠标滚轮事件 SDL_PenAxisEvent:手写笔轴事件(压力/倾斜变化) SDL_PenButtonEvent:手写笔按键事件 SDL_PenMotionEvent:手写笔移动事件 SDL_PenProximityEvent:手写笔接近/离开事件 SDL_PenTouchEvent:手写笔触摸事件 SDL_PinchFingerEvent:捏合手势事件(多点触控) SDL_QuitEvent:退出事件(用户请求关闭应用) SDL_RenderEvent:渲染事件(渲染目标刷新) SDL_SensorEvent:传感器事件(加速度计/陀螺仪等) SDL_TextEditingCandidatesEvent:文本编辑候选词事件(输入法候选词) SDL_TextEditingEvent:文本编辑事件(输入法正在输入) SDL_TextInputEvent:文本输入事件(完成的文本输入) SDL_TouchFingerEvent:触摸手指事件(按下/移动/抬起) SDL_UserEvent:自定义用户事件(可携带自定义数据) SDL_WindowEvent:窗口事件(大小变化、移动、最小化、关闭等) 枚举 SDL_EventAction:事件操作枚举(用于 SDL_PeepEvents,如 SDL_ADDEVENT/SDL_PEEKEVENT/SDL_GETEVENT) SDL_EventType:事件类型枚举(所有内置事件的类型 ID,如 SDL_QUIT/SDL_KEYDOWN 等) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库) #Include "SDL.bi" ' 自定义事件类型 ID Dim As Uint32 CUSTOM_EVENT_ID ' 事件过滤器回调:拦截并打印键盘事件 Function EventFilter Cdecl (ByVal userdata As Any Ptr, ByVal evt As SDL_Event Ptr) As Integer Select Case evt->type Case SDL_KEYDOWN SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "过滤器拦截:按键 %d 按下", evt->key.keysym.sym) ' 返回 1 保留事件,返回 0 丢弃事件 Return 1 Case SDL_KEYUP SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "过滤器拦截:按键 %d 释放", evt->key.keysym.sym) Return 1 Case Else Return 1 ' 保留其他事件 End Select End Function ' 事件监听回调:打印所有新事件 Sub EventWatchCallback Cdecl (ByVal userdata As Any Ptr, ByVal evt As SDL_Event Ptr) Dim As ZString Ptr evtDesc = SDL_GetEventDescription(evt->type) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "事件监听:%s (类型 ID: %d)", evtDesc, evt->type) End Sub ' 发送自定义事件的线程函数 Sub SendCustomEventThread Cdecl (ByVal data As Any Ptr) Dim As Integer i = 0 While (i < 5) ' 构造自定义事件 Dim As SDL_Event customEvt customEvt.type = CUSTOM_EVENT_ID customEvt.user.code = 100 + i customEvt.user.data1 = Cast(Any Ptr, i) customEvt.user.data2 = NULL ' 推入事件队列 If (SDL_PushEvent(@customEvt) > 0) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "线程:发送自定义事件 %d", i) End If SDL_Delay(1000) i += 1 Wend End Sub ' 主程序 Dim As SDL_Window Ptr window = NULL Dim As SDL_Event evt Dim As SDL_Thread Ptr thread = NULL Dim As Integer quit = 0 ' 1. 初始化 SDL If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 2. 注册自定义事件类型(1 个自定义类型) CUSTOM_EVENT_ID = SDL_RegisterEvents(1) If (CUSTOM_EVENT_ID = SDL_INVALID_EVENT) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "注册自定义事件失败") SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "自定义事件 ID:%d", CUSTOM_EVENT_ID) ' 3. 创建窗口 window = SDL_CreateWindow("SDL 事件系统示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 600, 400, SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError()) SDL_Quit() End 1 End If ' 4. 设置事件过滤器和监听回调 SDL_SetEventFilter(@EventFilter, NULL) SDL_AddEventWatch(@EventWatchCallback, NULL) ' 5. 创建线程发送自定义事件 thread = SDL_CreateThread(@SendCustomEventThread, "CustomEventThread", NULL) If (thread = NULL) Then SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "创建线程失败:%s", SDL_GetError()) End If SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 事件处理示例 ===") SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按 ESC 退出 | 按任意键触发键盘事件 | 等待自定义事件...") ' 6. 主事件循环 While (quit = 0) ' 非阻塞读取事件 While (SDL_PollEvent(@evt)) Select Case evt.type ' 窗口关闭事件 Case SDL_QUITEVENT SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "收到退出事件") quit = 1 ' 键盘事件 Case SDL_KEYDOWN If (evt.key.keysym.sym = SDLK_ESCAPE) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "ESC 键按下,退出程序") quit = 1 End If ' 窗口事件 Case SDL_WINDOWEVENT Select Case evt.window.event Case SDL_WINDOWEVENT_RESIZED SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "窗口大小变化:%dx%d", _ evt.window.data1, evt.window.data2) End Select ' 自定义事件 Case CUSTOM_EVENT_ID SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "收到自定义事件:code=%d, data1=%d", _ evt.user.code, Cast(Integer, evt.user.data1)) ' 其他事件 Case Else ' 忽略 End Select Wend SDL_Delay(10) ' 降低 CPU 占用 Wend ' 7. 清理资源 SDL_RemoveEventWatch(@EventWatchCallback, NULL) If (thread <> NULL) Then SDL_WaitThread(thread, NULL) End If SDL_DestroyWindow(window) SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出") End 0 总结 SDL 事件子系统是应用交互的核心,SDL_PollEvent 是最常用的事件读取接口(非阻塞),SDL_WaitEvent 适用于低功耗场景(阻塞); FreeBASIC 中使用时需注意: 自定义事件需通过 SDL_RegisterEvents 注册 ID,避免冲突; 事件过滤器(SDL_SetEventFilter)可全局拦截事件,监听回调(SDL_AddEventWatch)仅监听不拦截; SDL_PushEvent 可跨线程发送事件,是线程间通信的常用方式; 核心流程:初始化 → 注册自定义事件(可选)→ 设置过滤器/监听(可选)→ 事件循环处理 → 清理资源。
2026年-3月-6日
4 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_摄像头(CategoryCamera)
摄像头子系统(CategoryCamera) SDL 库提供的视频采集功能,专门用于读取摄像头(如网络摄像头)等视频源的输入数据。 通过这组 API,应用可实现以下功能: 枚举、查询系统中的摄像头设备; 打开摄像头并获取逐帧视频数据(以 SDL_Surface 形式返回); 将视频帧上传至 SDL_Texture 渲染,或直接处理内存中的像素数据。 权限说明 多数平台会对摄像头访问做权限管控: 应用首次访问摄像头时,系统会弹出 UI 向用户请求授权; 授权结果可通过两种方式获取: 主动查询:调用 SDL_GetCameraPermissionState(); 事件监听:等待 SDL_EVENT_CAMERA_DEVICE_APPROVED(授权通过)或 SDL_EVENT_CAMERA_DEVICE_DENIED(授权拒绝)事件; 无权限管控的平台会立即返回「授权通过」状态,摄像头打开后即可获取帧数据。 功能限制 SDL 摄像头仅提供原始视频帧,不输出编码后的视频文件(应用可自行将帧编码为任意格式); 该 API 不提供摄像头硬件的音频数据: 多数摄像头无麦克风; 即使有,直播/视频通话等场景通常也需独立麦克风; 音频采集需通过 SDL 音频 API 实现,与摄像头硬件无关。 摄像头使用注意事项 消费级摄像头设备打开后需要「预热时间」: 刚打开的摄像头可能先输出几帧全黑画面,或曝光不足的图像; 若需自动抓拍单帧、或无预览直接录制视频,建议丢弃前几帧(甚至前几秒)的数据,再使用有效帧。 函数 SDL_AcquireCameraFrame:获取摄像头的最新视频帧(返回 SDL_Surface 指针,用完需调用 Release 释放) SDL_CloseCamera:关闭已打开的摄像头设备(释放摄像头资源) SDL_GetCameraDriver:获取指定索引的摄像头驱动名称(如 "uvc" 表示 USB 视频类驱动) SDL_GetCameraFormat:获取摄像头当前使用的视频格式(分辨率、像素格式、帧率等) SDL_GetCameraID:获取摄像头设备的唯一标识 ID(SDL_CameraID 类型) SDL_GetCameraName:获取摄像头设备的友好名称(如 "USB Camera (046d:0825)") SDL_GetCameraPermissionState:查询摄像头的权限状态(授权中/已授权/已拒绝,参考 SDL_CameraPermissionState) SDL_GetCameraPosition:获取摄像头的物理位置(前置/后置/未指定,参考 SDL_CameraPosition) SDL_GetCameraProperties:获取摄像头的详细属性(如支持的最大分辨率、是否自动对焦等) SDL_GetCameras:枚举系统中的所有摄像头设备(返回设备列表及数量) SDL_GetCameraSupportedFormats:获取摄像头支持的所有视频格式(分辨率、帧率、像素格式组合) SDL_GetCurrentCameraDriver:获取当前正在使用的摄像头驱动名称 SDL_GetNumCameraDrivers:获取系统中可用的摄像头驱动数量 SDL_OpenCamera:打开指定的摄像头设备(传入设备 ID 和期望的视频格式,返回 SDL_Camera 句柄) SDL_ReleaseCameraFrame:释放已获取的摄像头视频帧(与 Acquire 成对使用,避免内存泄漏) 数据类型 SDL_Camera:摄像头设备句柄类型(标识已打开的摄像头) SDL_CameraID:摄像头设备唯一标识类型(用于区分不同摄像头) 结构体 SDL_CameraSpec:摄像头规格结构体(指定期望的分辨率、帧率、像素格式等参数) 枚举 SDL_CameraPermissionState:摄像头权限状态枚举(SDL_CAMERA_PERMISSION_UNKNOWN/GRANTED/DENIED/PENDING) SDL_CameraPosition:摄像头物理位置枚举(SDL_CAMERA_POSITION_UNKNOWN/FRONT/BACK) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库) #Include "SDL.bi" ' 错误处理辅助函数 Sub CheckError(ByVal msg As String) Dim As ZString Ptr err = SDL_GetError() If (*err <> 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%s:%s", msg, err) SDL_ClearError() End 1 End If End Sub ' 主程序 Dim As SDL_CameraID Ptr cameraIDs = NULL Dim As Integer cameraCount = 0 Dim As SDL_Camera Ptr camera = NULL Dim As SDL_CameraSpec cameraSpec Dim As SDL_Surface Ptr frame = NULL Dim As SDL_Window Ptr window = NULL Dim As SDL_Renderer Ptr renderer = NULL Dim As SDL_Texture Ptr texture = NULL Dim As SDL_Rect dstRect Dim As SDL_CameraPermissionState permState Dim As Integer quit = 0, frameCount = 0 Dim As SDL_Event evt ' 1. 初始化 SDL(需启用视频子系统) If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 2. 枚举系统中的摄像头设备 cameraCount = SDL_GetCameras(0, NULL) If (cameraCount <= 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "未检测到摄像头设备") SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "检测到 %d 个摄像头设备", cameraCount) ' 分配内存并获取摄像头 ID 列表 cameraIDs = Callocate(cameraCount * SizeOf(SDL_CameraID)) cameraCount = SDL_GetCameras(cameraCount, cameraIDs) For i As Integer = 0 To cameraCount - 1 Dim As ZString Ptr camName = SDL_GetCameraName(cameraIDs[i]) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头 %d:%s", i, camName) SDL_free(camName) ' 释放名称字符串 Next ' 3. 配置摄像头规格(期望 640x480,30fps,RGBA8888 格式) cameraSpec.w = 640 cameraSpec.h = 480 cameraSpec.fps = 30 cameraSpec.format = SDL_PIXELFORMAT_RGBA8888 ' 4. 打开第一个摄像头 camera = SDL_OpenCamera(cameraIDs[0], @cameraSpec) If (camera = NULL) Then CheckError("打开摄像头失败") GoTo cleanup End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头已打开,等待权限授权...") ' 5. 等待摄像头权限授权(循环查询直到授权完成) Do permState = SDL_GetCameraPermissionState(camera) Select Case permState Case SDL_CAMERA_PERMISSION_GRANTED SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头权限已授权") Exit Do Case SDL_CAMERA_PERMISSION_DENIED SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "摄像头权限被拒绝") GoTo cleanup Case SDL_CAMERA_PERMISSION_PENDING SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "权限请求中...") SDL_Delay(500) Case Else SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "权限状态未知,默认授权") Exit Do End Select Loop ' 6. 创建窗口和渲染器(用于显示摄像头画面) window = SDL_CreateWindow("SDL 摄像头示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 640, 480, SDL_WINDOW_SHOWN) renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED) If (window = NULL Or renderer = NULL) Then CheckError("创建窗口/渲染器失败") GoTo cleanup End If dstRect = Type<SDL_Rect>(0, 0, 640, 480) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "=== 摄像头预览开始 ===") SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "按 ESC 退出 | 摄像头预热中,前几帧可能黑屏") ' 7. 主循环:获取并渲染摄像头帧 While (quit = 0) ' 处理事件 While (SDL_PollEvent(@evt)) Select Case evt.type Case SDL_QUITEVENT quit = 1 Case SDL_KEYDOWN If (evt.key.keysym.sym = SDLK_ESCAPE) Then quit = 1 End If ' 监听摄像头权限事件(可选) Case SDL_EVENT_CAMERA_DEVICE_APPROVED SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "收到摄像头授权通过事件") Case SDL_EVENT_CAMERA_DEVICE_DENIED SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "收到摄像头授权拒绝事件") quit = 1 End Select Wend ' 获取摄像头帧(非阻塞) frame = SDL_AcquireCameraFrame(camera) If (frame <> NULL) Then frameCount += 1 ' 跳过前 10 帧预热数据 If (frameCount > 10) Then ' 创建/更新纹理 If (texture = NULL) Then texture = SDL_CreateTextureFromSurface(renderer, frame) Else SDL_UpdateTexture(texture, NULL, frame->pixels, frame->pitch) End If ' 渲染纹理 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255) SDL_RenderClear(renderer) SDL_RenderTexture(renderer, texture, NULL, @dstRect) SDL_RenderPresent(renderer) End If ' 释放帧(必须调用,否则摄像头会阻塞) SDL_ReleaseCameraFrame(camera, frame) End If SDL_Delay(10) ' 控制循环频率 Wend ' 8. 清理资源 cleanup: ' 释放纹理/渲染器/窗口 If (texture <> NULL) Then SDL_DestroyTexture(texture) If (renderer <> NULL) Then SDL_DestroyRenderer(renderer) If (window <> NULL) Then SDL_DestroyWindow(window) ' 关闭摄像头 If (camera <> NULL) Then SDL_CloseCamera(camera) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "摄像头已关闭") End If ' 释放摄像头 ID 列表 If (cameraIDs <> NULL) Then Deallocate(cameraIDs) End If ' 退出 SDL SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "程序正常退出,共渲染 %d 帧", frameCount - 10) End 0 总结 SDL 摄像头子系统核心流程:SDL_GetCameras 枚举设备 → SDL_OpenCamera 打开设备 → SDL_AcquireCameraFrame 获取帧 → SDL_ReleaseCameraFrame 释放帧; FreeBASIC 中使用时需注意: 必须处理权限状态(SDL_GetCameraPermissionState 或监听授权事件); 摄像头帧需「获取-释放」成对使用,且建议跳过前几帧预热数据; 帧数据(SDL_Surface)可转换为 SDL_Texture 渲染,或直接处理像素; 关键限制:仅输出原始视频帧,无音频/编码功能,音频需通过 SDL 音频 API 单独采集。
2026年-3月-6日
6 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_Metal 支持(CategoryMetal)
Metal 适配子系统(CategoryMetal) SDL 提供一套专门用于在 SDL 窗口上创建 Metal 图层(Layer)和视图(View)的函数集,仅适用于 Apple 平台(macOS/iOS)。 这组接口主要用于平台级别的「粘合层」开发: 多数 macOS/iOS 应用使用 SDL 时无需调用这些函数; 仅在需要与系统级 Metal 渲染深度集成(如自定义渲染管线、原生 Metal 视图交互)时,这组 API 才会发挥作用。 函数 SDL_Metal_CreateView:为 SDL 窗口创建 Metal 视图(SDL_MetalView),绑定窗口与 Metal 渲染上下文 SDL_Metal_DestroyView:销毁由 SDL 创建的 Metal 视图(释放关联的 Metal 资源和视图对象) SDL_Metal_GetLayer:获取 SDL 窗口关联的 Metal 图层(CAMetalLayer),用于原生 Metal 渲染配置 数据类型 SDL_MetalView:Metal 视图句柄类型(指向 SDL 封装的原生 Metal 视图对象) 结构体 (无) 枚举 (无) 宏 (无) FreeBASIC 示例代码 ' 注意:该代码仅适用于 macOS/iOS 平台,需编译时链接 SDL3 库 ' 编译示例(macOS):fbc -lSDL3 metal_sdl.bas #Include "SDL.bi" ' 声明 Apple 平台原生类型(简化示例,实际需引入 Metal/Cocoa 头文件) Type CAMetalLayer Ptr ' 原生 Metal 图层类型 Type id ' Objective-C 对象类型 ' 错误处理辅助函数 Sub CheckSDLError(ByVal msg As String) Dim As ZString Ptr err = SDL_GetError() If (*err <> 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%s:%s", msg, err) SDL_ClearError() End 1 End If End Sub ' 主程序 Dim As SDL_Window Ptr window = NULL Dim As SDL_MetalView metalView = NULL Dim As CAMetalLayer Ptr metalLayer = NULL ' 1. 初始化 SDL 视频子系统 If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 2. 创建支持 Metal 的 SDL 窗口 ' SDL_WINDOW_METAL 标志:告知 SDL 窗口需兼容 Metal 渲染 window = SDL_CreateWindow("SDL + Metal 示例 (macOS)", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 800, 600, SDL_WINDOW_METAL Or SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "创建 SDL 窗口失败:%s", SDL_GetError()) SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "SDL 窗口创建成功") ' 3. 获取 SDL 窗口关联的 Metal 图层 metalLayer = Cast(CAMetalLayer Ptr, SDL_Metal_GetLayer(window)) If (metalLayer = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取 Metal Layer 失败") GoTo cleanup End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "成功获取 CAMetalLayer 指针:%p", metalLayer) ' 4. 为 SDL 窗口创建 Metal 视图 metalView = SDL_Metal_CreateView(window) If (metalView = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "创建 Metal View 失败") GoTo cleanup End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "成功创建 SDL_MetalView:%p", metalView) ' 5. 模拟 Metal 渲染逻辑(示例仅占位,实际需调用原生 Metal API) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "=== Metal 集成示例 ===") SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "已完成 SDL 与 Metal 的基础绑定") SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "可通过 CAMetalLayer 配置 Metal 渲染管线") SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "按任意键退出程序...") ' 等待用户输入(macOS 控制台输入) Dim As String dummy Input dummy ' 6. 清理资源 cleanup: ' 销毁 Metal 视图(必须在窗口销毁前调用) If (metalView <> NULL) Then SDL_Metal_DestroyView(metalView) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "Metal View 已销毁") End If ' 销毁 SDL 窗口 If (window <> NULL) Then SDL_DestroyWindow(window) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "SDL 窗口已销毁") End If ' 退出 SDL SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "程序正常退出") End 0 总结 SDL Metal 子系统仅适配 Apple 平台(macOS/iOS),核心作用是桥接 SDL 窗口与原生 Metal 渲染,非跨平台场景无需使用; 关键接口:SDL_Metal_GetLayer 获取原生 CAMetalLayer(用于配置 Metal 渲染)、SDL_Metal_CreateView 创建 SDL 封装的 Metal 视图,需配合 SDL_WINDOW_METAL 窗口标志使用; 多数 SDL 应用无需直接操作 Metal 接口,仅在需要深度定制 Metal 渲染管线、与原生 iOS/macOS 界面集成时,才需调用这组函数。
2026年-3月-6日
5 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_Vulkan 支持(CategoryVulkan)
Vulkan 适配子系统(CategoryVulkan) SDL 提供一套专门用于在 SDL 窗口上创建 Vulkan 渲染表面(Surface)的函数集。 Vulkan 大部分功能可脱离 SDL 独立运行,但在初始化阶段需要 SDL 提供少量关键支持: 调用 SDL_Vulkan_GetInstanceExtensions() 获取创建 VkInstance 所需的平台相关扩展; 调用 SDL_Vulkan_GetVkGetInstanceProcAddr() 获取查询 Vulkan 入口点的适配函数; 调用 SDL_Vulkan_CreateSurface() 创建最终的 Vulkan 表面,完成 SDL 窗口与 Vulkan 渲染的绑定。 与 OpenGL 不同:Vulkan 的「上下文创建」「窗口缓冲区交换」等核心逻辑由 Vulkan API 直接处理,因此 SDL 无需提供 SDL_GL_SwapWindow() 等接口的 Vulkan 等效实现——这些接口在 Vulkan 中无必要。 函数 SDL_Vulkan_CreateSurface:为 SDL 窗口创建 Vulkan 渲染表面(VkSurfaceKHR),完成窗口与 Vulkan 的绑定 SDL_Vulkan_DestroySurface:销毁由 SDL 创建的 Vulkan 表面(释放关联资源) SDL_Vulkan_GetInstanceExtensions:获取创建 VkInstance 所需的平台特定扩展列表(如 Windows 下的 VK_KHR_win32_surface) SDL_Vulkan_GetPresentationSupport:检查指定的 Vulkan 物理设备/队列族是否支持在 SDL 窗口上进行图像展示 SDL_Vulkan_GetVkGetInstanceProcAddr:获取 Vulkan 实例的函数地址查询入口(vkGetInstanceProcAddr),适配不同平台的函数加载逻辑 SDL_Vulkan_LoadLibrary:加载系统中的 Vulkan 动态库(如 Windows 下的 vulkan-1.dll,Linux 下的 libvulkan.so) SDL_Vulkan_UnloadLibrary:卸载已加载的 Vulkan 动态库(释放库资源) 数据类型 (无) 结构体 (无) 枚举 (无) 宏 (无) FreeBASIC 示例代码 ' 注意:需提前安装 Vulkan SDK,并在编译时链接 Vulkan 库和 SDL 库 ' 编译示例:fbc -lSDL3 -lvulkan vulkan_sdl.bas ' 引入 SDL 和 Vulkan 头文件 #Include "SDL.bi" #Include "vulkan/vulkan.bi" ' 类型别名(简化 Vulkan 函数指针声明) Type PFN_vkGetInstanceProcAddr As Function (ByVal instance As VkInstance, ByVal pName As ZString Ptr) As PFN_vkVoidFunction Type PFN_vkCreateInstance As Function (ByVal pCreateInfo As VkInstanceCreateInfo Ptr, ByVal pAllocator As VkAllocationCallbacks Ptr, ByVal pInstance As VkInstance Ptr) As VkResult Type PFN_vkDestroyInstance As Function (ByVal instance As VkInstance, ByVal pAllocator As VkAllocationCallbacks Ptr) As Void ' 错误处理辅助函数 Sub CheckResult(ByVal res As VkResult, ByVal msg As String) If (res <> VK_SUCCESS) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%s 失败,错误码:%d", msg, res) End 1 End If End Sub ' 主程序 Dim As SDL_Window Ptr window = NULL Dim As VkInstance vulkanInstance Dim As VkSurfaceKHR vulkanSurface Dim As ZString Ptr extensions = NULL Dim As UInteger extensionCount = 0 Dim As PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL Dim As PFN_vkCreateInstance vkCreateInstance = NULL Dim As PFN_vkDestroyInstance vkDestroyInstance = NULL Dim As VkInstanceCreateInfo createInfo Dim As VkResult res ' 1. 初始化 SDL 视频子系统 If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 2. 加载 Vulkan 动态库 If (SDL_Vulkan_LoadLibrary(NULL) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "加载 Vulkan 库失败:%s", SDL_GetError()) SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "Vulkan 库加载成功") ' 3. 创建 SDL 窗口(需指定 Vulkan 兼容标志) window = SDL_CreateWindow("SDL + Vulkan 示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 800, 600, SDL_WINDOW_VULKAN Or SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "创建 SDL 窗口失败:%s", SDL_GetError()) SDL_Vulkan_UnloadLibrary() SDL_Quit() End 1 End If ' 4. 获取 Vulkan 实例所需的扩展列表 If (SDL_Vulkan_GetInstanceExtensions(window, @extensionCount, NULL) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取扩展列表长度失败:%s", SDL_GetError()) goto cleanup End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "需要 %d 个 Vulkan 扩展", extensionCount) If (extensionCount > 0) Then extensions = Callocate(extensionCount * SizeOf(ZString Ptr)) If (SDL_Vulkan_GetInstanceExtensions(window, @extensionCount, extensions) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取扩展列表失败:%s", SDL_GetError()) goto cleanup End If ' 打印扩展名称 For i As Integer = 0 To extensionCount - 1 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "扩展 %d:%s", i, extensions[i]) Next End If ' 5. 获取 Vulkan 入口函数 vkGetInstanceProcAddr = SDL_Vulkan_GetVkGetInstanceProcAddr() If (vkGetInstanceProcAddr = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取 vkGetInstanceProcAddr 失败") goto cleanup End If ' 6. 创建 Vulkan 实例 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO createInfo.enabledExtensionCount = extensionCount createInfo.ppEnabledExtensionNames = extensions createInfo.enabledLayerCount = 0 createInfo.ppEnabledLayerNames = NULL vkCreateInstance = Cast(PFN_vkCreateInstance, vkGetInstanceProcAddr(NULL, "vkCreateInstance")) res = vkCreateInstance(@createInfo, NULL, @vulkanInstance) CheckResult(res, "创建 VkInstance") SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "VkInstance 创建成功") ' 7. 为 SDL 窗口创建 Vulkan 表面 If (SDL_Vulkan_CreateSurface(window, vulkanInstance, NULL, @vulkanSurface) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "创建 Vulkan Surface 失败:%s", SDL_GetError()) goto cleanup End If SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "Vulkan Surface 创建成功") ' 8. 检查展示支持(示例:使用第一个物理设备的第0个队列族) Dim As VkPhysicalDevice physicalDevices(0 To 10) Dim As UInteger physDevCount = 0 Dim As PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = Cast(PFN_vkEnumeratePhysicalDevices, vkGetInstanceProcAddr(vulkanInstance, "vkEnumeratePhysicalDevices")) res = vkEnumeratePhysicalDevices(vulkanInstance, @physDevCount, NULL) CheckResult(res, "枚举物理设备") res = vkEnumeratePhysicalDevices(vulkanInstance, @physDevCount, @physicalDevices(0)) CheckResult(res, "获取物理设备列表") If (physDevCount > 0) Then Dim As Integer support = SDL_Vulkan_GetPresentationSupport(vulkanInstance, physicalDevices(0), 0) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "物理设备 0 队列族 0 是否支持展示:%s", IIf(support, "是", "否")) End If ' 等待用户输入后清理 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "按任意键退出...") Dim As String dummy Input dummy ' 9. 清理资源 cleanup: If (vulkanSurface <> VK_NULL_HANDLE) Then Dim As PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = Cast(PFN_vkDestroySurfaceKHR, vkGetInstanceProcAddr(vulkanInstance, "vkDestroySurfaceKHR")) vkDestroySurfaceKHR(vulkanInstance, vulkanSurface, NULL) End If If (vulkanInstance <> VK_NULL_HANDLE) Then vkDestroyInstance = Cast(PFN_vkDestroyInstance, vkGetInstanceProcAddr(vulkanInstance, "vkDestroyInstance")) vkDestroyInstance(vulkanInstance, NULL) End If If (extensions <> NULL) Then Deallocate(extensions) End If If (window <> NULL) Then SDL_DestroyWindow(window) End If SDL_Vulkan_UnloadLibrary() SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "程序正常退出") End 0 总结 SDL Vulkan 子系统核心作用是桥接 SDL 窗口与 Vulkan 渲染,关键接口是 SDL_Vulkan_CreateSurface(创建渲染表面)和 SDL_Vulkan_GetInstanceExtensions(获取平台扩展); FreeBASIC 中使用时,需先加载 Vulkan 动态库(SDL_Vulkan_LoadLibrary),创建带 SDL_WINDOW_VULKAN 标志的 SDL 窗口,再按「获取扩展→创建 VkInstance→创建 Surface」的流程初始化; Vulkan 的核心逻辑(如缓冲区交换、命令提交)由 Vulkan API 直接处理,SDL 仅负责窗口与 Vulkan 的基础绑定,无需额外的渲染同步接口。
2026年-3月-6日
5 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_剪贴板(CategoryClipboard)
剪贴板子系统(CategoryClipboard) SDL 提供对系统剪贴板的完整访问能力,既能读取其他进程写入的剪贴板内容,也能将自身数据发布到剪贴板中。 SDL 剪贴板不仅支持文本,还能按 MIME 类型访问和发布任意格式的数据。 基础用法(文本) 获取/发布纯文本到系统剪贴板非常简单,只需分别调用 SDL_GetClipboardText() 和 SDL_SetClipboardText(): 处理的是 UTF-8 编码 的 C 字符串; 数据传输和编码转换由 SDL 完全托管,无需手动处理。 剪贴板回调(非文本数据) 当剪贴板包含非文本数据时,逻辑会更复杂: 系统剪贴板可存储任意类型数据,甚至同一数据的多种格式(如绘图软件复制图片时,同时提供 BMP/JPG/PNG 格式); 读取非文本数据: 用 SDL_HasClipboardData() 判断目标 MIME 类型是否存在; 用 SDL_GetClipboardMimeTypes() 获取剪贴板支持的所有 MIME 类型列表; 用 SDL_GetClipboardData() 指定 MIME 类型读取对应数据。 写入非文本数据: 调用 SDL_SetClipboardData() 时,无需直接传入数据,只需指定支持的 MIME 类型和回调函数; 仅当其他程序请求粘贴时,SDL 才会触发回调生成对应格式的数据——避免提前拷贝大量数据,也支持为同一内容提供多格式(如 PNG/JPG),仅在被请求时才编码。 主选择区(Primary Selection) X11/Wayland 系统除常规剪贴板外,还有「主选择区」(选中但未显式复制的文本): SDL 提供 SDL_GetPrimarySelectionText()/SDL_SetPrimarySelectionText() 操作该区域; 无此概念的平台(如 Windows/macOS)也支持这些 API,但仅在应用内保存字符串,系统不会外部修改该内容。 函数 SDL_ClearClipboardData:清空系统剪贴板的所有数据(包括所有 MIME 类型) SDL_GetClipboardData:按指定 MIME 类型读取剪贴板数据(返回数据缓冲区和长度) SDL_GetClipboardMimeTypes:获取剪贴板中可用的所有 MIME 类型列表(返回字符串数组) SDL_GetClipboardText:读取剪贴板中的 UTF-8 文本内容(最常用的文本读取接口) SDL_GetPrimarySelectionText:读取 X11/Wayland 主选择区的 UTF-8 文本(其他平台返回应用内缓存) SDL_HasClipboardData:判断剪贴板是否包含指定 MIME 类型的数据(返回布尔值) SDL_HasClipboardText:判断剪贴板是否包含文本数据(快捷接口,等价于检查 text/plain 类型) SDL_HasPrimarySelectionText:判断主选择区是否包含文本数据 SDL_SetClipboardData:设置剪贴板的非文本数据(传入 MIME 类型列表和数据生成回调) SDL_SetClipboardText:设置剪贴板的 UTF-8 文本内容(最常用的文本写入接口) SDL_SetPrimarySelectionText:设置 X11/Wayland 主选择区的文本(其他平台仅缓存到应用内) 数据类型 SDL_ClipboardCleanupCallback:剪贴板数据清理回调类型(释放 SDL_SetClipboardData 生成的数据缓冲区) SDL_ClipboardDataCallback:剪贴板数据生成回调类型(当其他程序请求粘贴时,生成指定 MIME 类型的数据) 结构体 (无) 枚举 (无) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL 库) #Include "SDL.bi" ' 非文本数据回调:生成 PNG 格式数据(示例) Function ClipboardDataCallback Cdecl (ByVal mimetype As ZString Ptr, ByVal userdata As Any Ptr, ByVal size As UInteger Ptr) As UByte Ptr ' 模拟 PNG 数据(实际应从文件/内存读取真实数据) Static As UByte pngData(0 To 10) = { &H89, &H50, &H4E, &H47, &H0D, &H0A, &H1A, &H0A, 0, 0, 0 } *size = 11 ' 数据长度 Return @pngData(0) End Function ' 数据清理回调:释放生成的剪贴板数据 Sub ClipboardCleanupCallback Cdecl (ByVal data As UByte Ptr, ByVal userdata As Any Ptr) ' 示例中使用静态数据,无需释放;实际应释放动态分配的内存 SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板数据已清理") End Sub ' 主程序 Dim As ZString Ptr clipText Dim As Integer hasText Dim As ZString Ptr mimeTypes(0 To 0) ' MIME 类型列表 Dim As Integer quit = 0 Dim As SDL_Event evt ' 初始化 SDL If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError()) End 1 End If ' 创建窗口(SDL 剪贴板 API 需初始化视频子系统,窗口可隐藏) Dim As SDL_Window Ptr window = SDL_CreateWindow("SDL 剪贴板示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 400, 300, SDL_WINDOW_SHOWN) If (window = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError()) SDL_Quit() End 1 End If SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 剪贴板操作示例 ===") SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按 C 复制文本 | 按 V 粘贴文本 | 按 P 设置非文本数据 | 按 ESC 退出") ' 主循环 While (quit = 0) While (SDL_PollEvent(@evt)) Select Case evt.type Case SDL_QUITEVENT quit = 1 Case SDL_KEYDOWN Select Case evt.key.keysym.sym ' 1. 复制文本到剪贴板 Case SDLK_c If (SDL_SetClipboardText("SDL 剪贴板示例 - UTF-8 文本 🎮") = 0) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "已复制文本到剪贴板") Else SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "复制文本失败:%s", SDL_GetError()) End If ' 2. 粘贴剪贴板文本 Case SDLK_v hasText = SDL_HasClipboardText() If (hasText) Then clipText = SDL_GetClipboardText() If (clipText <> NULL) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板文本:%s", clipText) SDL_free(clipText) ' 必须释放返回的字符串 End If Else SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板无文本数据") End If ' 3. 设置非文本数据(PNG 格式) Case SDLK_p mimeTypes(0) = "image/png" ' 支持的 MIME 类型 If (SDL_SetClipboardData(1, @mimeTypes(0), _ @ClipboardDataCallback, @ClipboardCleanupCallback, NULL) = 0) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "已设置 PNG 格式剪贴板数据") ' 检查是否存在该 MIME 类型 If (SDL_HasClipboardData("image/png")) Then SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板包含 image/png 数据") End If Else SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "设置非文本数据失败:%s", SDL_GetError()) End If ' 退出程序 Case SDLK_ESCAPE quit = 1 End Select End Select Wend SDL_Delay(10) Wend ' 清理资源 SDL_DestroyWindow(window) SDL_Quit() End 0 总结 SDL 剪贴板核心接口分两类:SDL_Get/SetClipboardText 处理 UTF-8 文本(最常用),SDL_Get/SetClipboardData 处理任意 MIME 类型数据; FreeBASIC 中使用文本接口时,需注意 SDL_GetClipboardText 返回的字符串必须用 SDL_free 释放,避免内存泄漏; 非文本数据需通过回调函数生成,仅在被请求时才编码/拷贝数据,SDL_HasClipboardData 可提前判断目标格式是否存在。
2026年-3月-6日
6 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_表面(CategorySurface)
表面(Surface)子系统(CategorySurface) SDL Surface 是系统内存(RAM) 中的像素缓冲区,适用于处理未存储在 GPU 显存中的图像数据——可便捷地传递、修改图像,无需依赖硬件加速。 SDL_Surface 提供了完善的多格式图像管理能力,以及一套实用的像素数据操作工具集,包括:表面间像素拷贝、图像矩形填充、格式转换等。 SDL 内置了简易的图片加载函数: BMP 加载:SDL_LoadBMP() PNG 加载:SDL_LoadPNG() SDL 本身不支持其他格式(如 JPG/PNG 以外),但可通过外部优秀库扩展(如官方配套的 SDL_image)。 线程安全说明 这些函数整体线程安全:不同线程可操作不同 Surface;禁止两个线程同时修改同一个 Surface。 函数 SDL_AddSurfaceAlternateImage:为 Surface 添加备用图像(多分辨率/格式适配) SDL_BlitSurface:基础表面拷贝(将源 Surface 绘制到目标 Surface,支持裁剪) SDL_BlitSurface9Grid:9宫格模式拷贝 Surface(拉伸时边缘不变形) SDL_BlitSurfaceScaled:缩放拷贝 Surface(自动适配目标尺寸) SDL_BlitSurfaceTiled:平铺拷贝 Surface(重复绘制填满目标区域) SDL_BlitSurfaceTiledWithScale:带缩放的平铺拷贝 Surface SDL_BlitSurfaceUnchecked:无参数校验的快速表面拷贝(性能更高,需确保参数合法) SDL_BlitSurfaceUncheckedScaled:无校验的缩放表面拷贝 SDL_ClearSurface:清空 Surface(用预设颜色填充整个表面) SDL_ConvertPixels:像素格式转换(直接处理像素缓冲区,不依赖 Surface) SDL_ConvertPixelsAndColorspace:像素格式+颜色空间双重转换 SDL_ConvertSurface:转换 Surface 的像素格式(生成新 Surface) SDL_ConvertSurfaceAndColorspace:转换 Surface 的像素格式+颜色空间 SDL_CreateSurface:创建空 Surface(指定尺寸、像素格式) SDL_CreateSurfaceFrom:从已有像素缓冲区创建 Surface(复用内存) SDL_CreateSurfacePalette:为 Surface 创建调色板(索引色格式专用) SDL_DestroySurface:销毁 Surface(释放内存和资源) SDL_DuplicateSurface:复制 Surface(生成独立的新 Surface) SDL_FillSurfaceRect:填充 Surface 中的单个矩形区域 SDL_FillSurfaceRects:批量填充 Surface 中的多个矩形区域 SDL_FlipSurface:翻转 Surface(水平/垂直/180度,参考 SDL_FlipMode) SDL_GetSurfaceAlphaMod:获取 Surface 的透明度调制值(0-255) SDL_GetSurfaceBlendMode:获取 Surface 的混合模式 SDL_GetSurfaceClipRect:获取 Surface 的裁剪矩形(仅绘制矩形内区域) SDL_GetSurfaceColorKey:获取 Surface 的颜色键(透明色) SDL_GetSurfaceColorMod:获取 Surface 的颜色调制值(RGB 偏移) SDL_GetSurfaceColorspace:获取 Surface 的颜色空间(如 sRGB、BT.709) SDL_GetSurfaceImages:获取 Surface 关联的所有备用图像 SDL_GetSurfacePalette:获取 Surface 的调色板(索引色格式) SDL_GetSurfaceProperties:获取 Surface 的属性集合(格式、标志位等) SDL_LoadBMP:从文件加载 BMP 图像到 Surface SDL_LoadBMP_IO:从自定义 IO 流加载 BMP 图像到 Surface SDL_LoadPNG:从文件加载 PNG 图像到 Surface SDL_LoadPNG_IO:从自定义 IO 流加载 PNG 图像到 Surface SDL_LoadSurface:通用图像加载(自动识别格式,需 SDL_image 支持) SDL_LoadSurface_IO:从自定义 IO 流通用加载图像到 Surface SDL_LockSurface:锁定 Surface(获取可读写的像素缓冲区,修改前必须调用) SDL_MapSurfaceRGB:将 RGB 颜色转换为 Surface 格式的像素值(无 Alpha) SDL_MapSurfaceRGBA:将 RGBA 颜色转换为 Surface 格式的像素值 SDL_PremultiplyAlpha:预乘 Alpha 通道(优化混合计算) SDL_PremultiplySurfaceAlpha:为 Surface 预乘 Alpha 通道 SDL_ReadSurfacePixel:读取 Surface 中指定坐标的像素值(整型) SDL_ReadSurfacePixelFloat:读取 Surface 中指定坐标的像素值(浮点型) SDL_RemoveSurfaceAlternateImages:移除 Surface 的所有备用图像 SDL_RotateSurface:旋转 Surface(指定角度,生成新 Surface) SDL_SaveBMP:将 Surface 保存为 BMP 文件 SDL_SaveBMP_IO:将 Surface 保存到自定义 IO 流(BMP 格式) SDL_SavePNG:将 Surface 保存为 PNG 文件 SDL_SavePNG_IO:将 Surface 保存到自定义 IO 流(PNG 格式) SDL_ScaleSurface:缩放 Surface(指定尺寸和缩放模式,生成新 Surface) SDL_SetSurfaceAlphaMod:设置 Surface 的透明度调制值 SDL_SetSurfaceBlendMode:设置 Surface 的混合模式 SDL_SetSurfaceClipRect:设置 Surface 的裁剪矩形 SDL_SetSurfaceColorKey:设置 Surface 的颜色键(指定透明色) SDL_SetSurfaceColorMod:设置 Surface 的颜色调制值(调整整体色调) SDL_SetSurfaceColorspace:设置 Surface 的颜色空间 SDL_SetSurfacePalette:设置 Surface 的调色板(索引色格式) SDL_SetSurfaceRLE:启用/禁用 Surface 的 RLE 压缩(优化透明色渲染) SDL_StretchSurface:拉伸 Surface(适配目标尺寸,旧接口,推荐用 SDL_ScaleSurface) SDL_SurfaceHasAlternateImages:判断 Surface 是否关联了备用图像 SDL_SurfaceHasColorKey:判断 Surface 是否设置了颜色键(透明色) SDL_SurfaceHasRLE:判断 Surface 是否启用了 RLE 压缩 SDL_UnlockSurface:解锁 Surface(完成像素修改后提交,与 Lock 成对使用) SDL_WriteSurfacePixel:向 Surface 指定坐标写入像素值(整型) SDL_WriteSurfacePixelFloat:向 Surface 指定坐标写入像素值(浮点型) 数据类型 SDL_SurfaceFlags:Surface 标志位类型(存储 Surface 的属性,如是否有 Alpha、是否 RLE 压缩) 结构体 SDL_Surface:Surface 核心结构体(包含像素缓冲区、尺寸、格式、调色板等信息) 枚举 SDL_FlipMode:翻转模式枚举(SDL_FLIP_NONE/SDL_FLIP_HORIZONTAL/SDL_FLIP_VERTICAL/SDL_FLIP_BOTH) SDL_ScaleMode:缩放模式枚举(SDL_SCALEMODE_NEAREST/SDL_SCALEMODE_LINEAR 等,控制缩放插值方式) 宏 SDL_MUSTLOCK:判断 Surface 是否必须锁定才能修改像素(返回布尔值) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL 库) #Include "SDL.bi" ' 错误处理辅助函数 Sub CheckError(byval msg as string) dim as zstring ptr err = SDL_GetError() if (*err <> 0) then SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%s:%s", msg, err) SDL_ClearError() end if End Sub ' 主程序示例 Dim As SDL_Surface Ptr bmpSurface = NULL, newSurface = NULL Dim As SDL_Rect dstRect Dim As UInteger pixelColor Dim As UByte r, g, b, a ' 1. 初始化 SDL if (SDL_Init(SDL_INIT_VIDEO) < 0) then CheckError("SDL 初始化失败") end 1 end if ' 2. 加载 BMP 图像到 Surface bmpSurface = SDL_LoadBMP("test.bmp") if (bmpSurface = NULL) then CheckError("加载 BMP 失败") SDL_Quit() end 1 end if SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "加载的 BMP 尺寸:%dx%d", bmpSurface->w, bmpSurface->h) ' 3. 创建新 Surface(与源图像同格式,尺寸加倍) newSurface = SDL_CreateSurface(bmpSurface->w * 2, bmpSurface->h * 2, bmpSurface->format->format) if (newSurface = NULL) then CheckError("创建新 Surface 失败") SDL_DestroySurface(bmpSurface) SDL_Quit() end 1 end if ' 4. 填充新 Surface 背景为白色 pixelColor = SDL_MapSurfaceRGB(newSurface, 255, 255, 255) SDL_FillSurfaceRect(newSurface, NULL, pixelColor) CheckError("填充 Surface 失败") ' 5. 拷贝源 Surface 到新 Surface 的指定位置 dstRect.x = 50 : dstRect.y = 50 : dstRect.w = bmpSurface->w : dstRect.h = bmpSurface->h SDL_BlitSurface(bmpSurface, NULL, newSurface, @dstRect) CheckError("Surface 拷贝失败") ' 6. 修改 Surface 像素(读取并改写左上角像素) if (SDL_MUSTLOCK(newSurface)) then if (SDL_LockSurface(newSurface) < 0) then CheckError("锁定 Surface 失败") goto cleanup end if end if ' 读取左上角像素 pixelColor = SDL_ReadSurfacePixel(newSurface, 0, 0) SDL_GetRGBA(pixelColor, newSurface->format, @r, @g, @b, @a) SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "左上角像素原始颜色:R=%d, G=%d, B=%d, A=%d", r, g, b, a) ' 改写为红色 pixelColor = SDL_MapSurfaceRGBA(newSurface, 255, 0, 0, 255) SDL_WriteSurfacePixel(newSurface, 0, 0, pixelColor) if (SDL_MUSTLOCK(newSurface)) then SDL_UnlockSurface(newSurface) end if ' 7. 保存修改后的 Surface 为新 BMP if (SDL_SaveBMP(newSurface, "output.bmp") < 0) then CheckError("保存 BMP 失败") end if ' 8. 缩放 Surface(缩小为原尺寸的 50%) Dim As SDL_Surface Ptr scaledSurface = SDL_ScaleSurface(newSurface, _ newSurface->w / 2, newSurface->h / 2, SDL_SCALEMODE_LINEAR) if (scaledSurface <> NULL) then SDL_SavePNG(scaledSurface, "scaled.png") SDL_DestroySurface(scaledSurface) end if ' 9. 清理资源 cleanup: if (bmpSurface <> NULL) then SDL_DestroySurface(bmpSurface) if (newSurface <> NULL) then SDL_DestroySurface(newSurface) SDL_Quit() SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "程序执行完成") end 0 总结 SDL Surface 是系统内存中的像素缓冲区,核心优势是无需 GPU 即可操作像素,SDL_LoadBMP/SDL_SaveBMP 是最基础的加载/保存函数; FreeBASIC 中使用 Surface 需遵循「锁定-修改-解锁」流程(SDL_LockSurface/SDL_UnlockSurface),SDL_MUSTLOCK 宏可判断是否需要锁定; 关键操作:SDL_BlitSurface(拷贝)、SDL_FillSurfaceRect(填充)、SDL_ConvertSurface(格式转换),修改像素前务必确认 Surface 已锁定,避免内存错误。
2026年-3月-6日
7 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_矩形与点运算(CategoryRect)
矩形与点运算子系统(CategoryRect) SDL 提供的矩形和 2D 点管理辅助函数集,包含整型和浮点型两个版本,覆盖矩形相交、包含、合并等常用几何运算。 函数 SDL_GetRectAndLineIntersection:计算整型矩形与线段的交点(修改线段坐标为交点) SDL_GetRectAndLineIntersectionFloat:计算浮点型矩形与线段的交点(修改线段坐标为交点) SDL_GetRectEnclosingPoints:计算包含所有整型点的最小包围矩形 SDL_GetRectEnclosingPointsFloat:计算包含所有浮点型点的最小包围矩形 SDL_GetRectIntersection:计算两个整型矩形的交集(返回交集矩形) SDL_GetRectIntersectionFloat:计算两个浮点型矩形的交集(返回交集矩形) SDL_GetRectUnion:计算两个整型矩形的并集(返回覆盖两个矩形的最小矩形) SDL_GetRectUnionFloat:计算两个浮点型矩形的并集(返回覆盖两个矩形的最小矩形) SDL_HasRectIntersection:判断两个整型矩形是否相交(返回布尔值) SDL_HasRectIntersectionFloat:判断两个浮点型矩形是否相交(返回布尔值) SDL_PointInRect:判断整型点是否在整型矩形内(包含边界) SDL_PointInRectFloat:判断浮点型点是否在浮点型矩形内(包含边界) SDL_RectEmpty:判断整型矩形是否为空(宽/高≤0 则为空) SDL_RectEmptyFloat:判断浮点型矩形是否为空(宽/高≤0 则为空) SDL_RectsEqual:判断两个整型矩形是否完全相等 SDL_RectsEqualEpsilon:判断两个浮点型矩形是否近似相等(指定误差阈值) SDL_RectsEqualFloat:判断两个浮点型矩形是否完全相等 SDL_RectToFRect:将整型 SDL_Rect 转换为浮点型 SDL_FRect 数据类型 (无) 结构体 SDL_FPoint:浮点型 2D 点结构体(x、y 为单精度浮点) SDL_FRect:浮点型矩形结构体(x、y 为左上角坐标,w、h 为宽高,均为单精度浮点) SDL_Point:整型 2D 点结构体(x、y 为 32 位整型) SDL_Rect:整型矩形结构体(x、y 为左上角坐标,w、h 为宽高,均为 32 位整型) 枚举 (无) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL 库) #Include "SDL.bi" ' 主程序示例 Sub PrintRectInfo(rect As SDL_Rect, name As String) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s:x=%d, y=%d, w=%d, h=%d", _ name, rect.x, rect.y, rect.w, rect.h) End Sub Sub PrintFRectInfo(frect As SDL_FRect, name As String) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s:x=%.2f, y=%.2f, w=%.2f, h=%.2f", _ name, frect.x, frect.y, frect.w, frect.h) End Sub ' 主函数 Dim As SDL_Rect rect1, rect2, intersectRect, unionRect Dim As SDL_FRect frect1, frect2, fIntersectRect Dim As SDL_Point point1, point2(0 To 2) Dim As SDL_FPoint fpoint1 Dim As Integer hasIntersect, isPointInRect ' 1. 整型矩形运算示例 rect1 = Type<SDL_Rect>(100, 100, 200, 200) ' 矩形1:(100,100) 宽200 高200 rect2 = Type<SDL_Rect>(150, 150, 200, 200) ' 矩形2:(150,150) 宽200 高200 PrintRectInfo(rect1, "矩形1") PrintRectInfo(rect2, "矩形2") ' 判断矩形是否相交 hasIntersect = SDL_HasRectIntersection(@rect1, @rect2) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "矩形1与矩形2是否相交:%s", IIf(hasIntersect, "是", "否")) ' 计算交集 If (SDL_GetRectIntersection(@rect1, @rect2, @intersectRect)) Then PrintRectInfo(intersectRect, "矩形交集") End If ' 计算并集 SDL_GetRectUnion(@rect1, @rect2, @unionRect) PrintRectInfo(unionRect, "矩形并集") ' 判断点是否在矩形内 point1 = Type<SDL_Point>(120, 120) ' 点1:(120,120) isPointInRect = SDL_PointInRect(@point1, @rect1) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "点(%d,%d)是否在矩形1内:%s", _ point1.x, point1.y, IIf(isPointInRect, "是", "否")) ' 计算包围点集的最小矩形 point2(0) = Type<SDL_Point>(50, 50) point2(1) = Type<SDL_Point>(250, 150) point2(2) = Type<SDL_Point>(150, 250) SDL_GetRectEnclosingPoints(@point2(0), 3, @rect1) ' 计算包含3个点的最小矩形 PrintRectInfo(rect1, "包围3个点的最小矩形") ' 2. 浮点型矩形运算示例 frect1 = Type<SDL_FRect>(100.5, 100.5, 200.0, 200.0) frect2 = Type<SDL_FRect>(150.5, 150.5, 200.0, 200.0) PrintFRectInfo(frect1, "浮点矩形1") PrintFRectInfo(frect2, "浮点矩形2") ' 计算浮点矩形交集 If (SDL_GetRectIntersectionFloat(@frect1, @frect2, @fIntersectRect)) Then PrintFRectInfo(fIntersectRect, "浮点矩形交集") End If ' 判断浮点点是否在浮点矩形内 fpoint1 = Type<SDL_FPoint>(120.5, 120.5) isPointInRect = SDL_PointInRectFloat(@fpoint1, @frect1) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "浮点点(%.2f,%.2f)是否在浮点矩形1内:%s", _ fpoint1.x, fpoint1.y, IIf(isPointInRect, "是", "否")) ' 3. 整型矩形转浮点矩形 Dim As SDL_FRect convFRect SDL_RectToFRect(@rect1, @convFRect) PrintFRectInfo(convFRect, "整型矩形1转换为浮点矩形") ' 4. 判断矩形是否为空 Dim As SDL_Rect emptyRect = Type<SDL_Rect>(0, 0, -100, 100) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "空矩形判断:%s", IIf(SDL_RectEmpty(@emptyRect), "是空矩形", "非空矩形")) End 0 总结 SDL 矩形子系统核心是 SDL_Rect(整型)和 SDL_FRect(浮点型)两类结构体,配套函数覆盖相交、包含、合并等所有常用几何运算; FreeBASIC 中使用时,需注意函数参数为结构体指针,SDL_HasRectIntersection/SDL_PointInRect 是最常用的判断类函数,SDL_GetRectIntersection/SDL_GetRectUnion 是核心计算类函数; 浮点型函数(后缀 Float)适用于高精度几何运算,整型函数性能更高,可根据场景选择,SDL_RectToFRect 可快速完成整型到浮点型的转换。
2026年-3月-6日
5 阅读
0 评论
VisualFreeBasic编程文档
2026-3-6
SDL3_API分类参考_混合模式(CategoryBlendmode)
混合模式子系统(CategoryBlendmode) 混合模式用于定义两种颜色的混合规则:SDL 既提供满足基础需求的标准混合模式,也支持创建自定义混合模式(可指定对颜色分量执行的数学运算规则)。 函数 SDL_ComposeCustomBlendMode:组合自定义混合模式(指定源因子、目标因子、混合运算,生成自定义 SDL_BlendMode) 数据类型 SDL_BlendMode:混合模式类型(包含标准模式和自定义模式的句柄) 结构体 (无) 枚举 SDL_BlendFactor:混合因子枚举(定义源/目标颜色的加权系数,如 SDL_BLENDFACTOR_SRC_ALPHA、SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA) SDL_BlendOperation:混合运算枚举(定义源颜色和目标颜色的计算方式,如 SDL_BLENDOPERATION_ADD、SDL_BLENDOPERATION_SUBTRACT) 宏 (无) FreeBASIC 示例代码 ' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL 库) #Include "SDL.bi" ' 主程序示例 Dim As SDL_Window Ptr window = NULL Dim As SDL_Renderer Ptr renderer = NULL Dim As SDL_Texture Ptr texture1 = NULL, texture2 = NULL Dim As SDL_Rect rect1, rect2 Dim As SDL_BlendMode customBlendMode ' 自定义混合模式 Dim As Integer quit = 0 Dim As SDL_Event evt ' 初始化函数 Function InitBlendModeDemo() As Integer ' 初始化 SDL 视频子系统 If (SDL_Init(SDL_INIT_VIDEO) < 0) Then SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL 初始化失败:%s", SDL_GetError()) Return 0 End If ' 创建窗口和渲染器 window = SDL_CreateWindow("SDL 混合模式示例", _ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _ 800, 600, SDL_WINDOW_SHOWN) renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED) If (window = NULL Or renderer = NULL) Then SDL_LogError(SDL_LOG_CATEGORY_RENDER, "创建窗口/渲染器失败:%s", SDL_GetError()) Return 0 End If ' 创建两个半透明矩形纹理 ' 纹理1:红色半透明 texture1 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, _ SDL_TEXTUREACCESS_TARGET, 200, 200) SDL_SetRenderTarget(renderer, texture1) SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128) ' 红,半透明 SDL_RenderClear(renderer) SDL_SetRenderTarget(renderer, NULL) ' 纹理2:绿色半透明 texture2 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, _ SDL_TEXTUREACCESS_TARGET, 200, 200) SDL_SetRenderTarget(renderer, texture2) SDL_SetRenderDrawColor(renderer, 0, 255, 0, 128) ' 绿,半透明 SDL_RenderClear(renderer) SDL_SetRenderTarget(renderer, NULL) ' 定义绘制位置(重叠) rect1.x = 200 : rect1.y = 150 : rect1.w = 200 : rect1.h = 200 rect2.x = 300 : rect2.y = 250 : rect2.w = 200 : rect2.h = 200 ' 1. 使用标准混合模式(SDL_BLENDMODE_BLEND) SDL_SetTextureBlendMode(texture1, SDL_BLENDMODE_BLEND) SDL_SetTextureBlendMode(texture2, SDL_BLENDMODE_BLEND) ' 2. 创建自定义混合模式(加法混合:源*1 + 目标*1) customBlendMode = SDL_ComposeCustomBlendMode( _ SDL_BLENDFACTOR_ONE, ' 源因子:源颜色完全保留 SDL_BLENDFACTOR_ONE, ' 目标因子:目标颜色完全保留 SDL_BLENDOPERATION_ADD, ' 混合运算:加法 SDL_BLENDFACTOR_ONE, ' Alpha 源因子 SDL_BLENDFACTOR_ONE, ' Alpha 目标因子 SDL_BLENDOPERATION_ADD ' Alpha 混合运算 ) Return 1 End Function ' 渲染函数 Sub RenderFrame(useCustomBlend As Integer) ' 清空背景为白色 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255) SDL_RenderClear(renderer) ' 根据参数切换混合模式 If (useCustomBlend) Then SDL_SetTextureBlendMode(texture1, customBlendMode) SDL_SetTextureBlendMode(texture2, customBlendMode) SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "使用自定义加法混合模式") Else SDL_SetTextureBlendMode(texture1, SDL_BLENDMODE_BLEND) SDL_SetTextureBlendMode(texture2, SDL_BLENDMODE_BLEND) SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "使用标准混合模式") End If ' 绘制两个重叠纹理 SDL_RenderTexture(renderer, texture1, NULL, @rect1) SDL_RenderTexture(renderer, texture2, NULL, @rect2) ' 提交渲染结果 SDL_RenderPresent(renderer) End Sub ' 清理资源 Sub Cleanup() If (texture1 <> NULL) Then SDL_DestroyTexture(texture1) If (texture2 <> NULL) Then SDL_DestroyTexture(texture2) If (renderer <> NULL) Then SDL_DestroyRenderer(renderer) If (window <> NULL) Then SDL_DestroyWindow(window) SDL_Quit() End Sub ' 主程序 If (InitBlendModeDemo() = 0) Then Cleanup() End 1 End If Dim As Integer useCustom = 0 ' 主循环 While (quit = 0) While (SDL_PollEvent(@evt)) Select Case evt.type Case SDL_QUITEVENT quit = 1 Case SDL_KEYDOWN ' 按空格键切换混合模式 If (evt.key.keysym.sym = SDLK_SPACE) Then useCustom = Not useCustom End If End Select Wend ' 渲染帧(切换混合模式) RenderFrame(useCustom) ' 控制帧率 SDL_Delay(16) Wend Cleanup() End 0 总结 SDL 混合模式核心是 SDL_BlendMode 类型,标准模式(如 SDL_BLENDMODE_BLEND)满足基础需求,自定义模式需通过 SDL_ComposeCustomBlendMode 组合混合因子和运算规则; FreeBASIC 中使用时,需先通过 SDL_SetTextureBlendMode/SDL_SetRenderDrawBlendMode 为纹理/渲染器设置混合模式,再执行绘制操作; 混合因子(SDL_BlendFactor)定义源/目标颜色的权重,混合运算(SDL_BlendOperation)定义颜色的计算方式(加法/减法等),二者共同决定最终混合效果。
2026年-3月-6日
5 阅读
0 评论
VisualFreeBasic编程文档
3
4
5
6
7