<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[勇芳软件工作室]]></title> 
<atom:link href="http://bbs.yfvb.com/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[勇芳官方网站]]></description>
<link>http://bbs.yfvb.com/</link>
<language>zh-cn</language>

<item>
    <title>联系勇芳软件</title>
    <link>http://bbs.yfvb.com/post-337.html</link>
    <description><![CDATA[<h1>联系勇芳软件工作室的方法</h1>
<ol>
<li>QQ：370037607</li>
<li>Emal:370037607@qq.com</li>
<li>每个软件都有客服，点击客服联系</li>
<li>QQ群：<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&amp;k=aZRBW132iCh4qar5pYoGlThGwAa30kgz&amp;authKey=9dNO5Reu8w7kTt8UJoJIqBzxjsjzU2INqu1fnUtKZDdzQPYy7jhknTJnJcZsNwI4&amp;noverify=0&amp;group_code=729670255" title="点击链接加入群聊【勇芳软件下载群】：729670255">点击链接加入群聊【勇芳软件下载群】：729670255</a> 用于下载软件，在群文件下载，人满就踢。</li>
</ol>
<h1>注意</h1>
<p>勇芳就一个人，经常不在电脑前，有事请先留言，不要问在不在<br />
有什么问题，会在24小时内回复。<br />
客服软件不保留记录，不在线就不会回复。可以在QQ上留言。</p>]]></description>
    <pubDate>Thu, 01 Oct 2026 14:31:33 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-337.html</guid>
</item>
<item>
    <title>关于本站相关辅助软件下架的公告</title>
    <link>http://bbs.yfvb.com/post-336.html</link>
    <description><![CDATA[<h1>各位用户：</h1>
<p>大家好。本工作室收到深圳市腾讯计算机系统有限公司发来的知识产权告知文件，现遵照相关要求，对本站全部与 QQ 游戏大厅及其旗下小游戏相关的辅助程序执行下架处理。</p>
<p><strong>自本公告发布起，不再提供上述软件的下载、更新与技术支持，后续也不会继续开发同类型相关工具。</strong></p>
<p>本公告仅用于客观告知用户软件停止分发的事实，<strong>不代表本工作室对相关知识产权争议作出自认</strong>，对于相关争议我方保留相应权利。</p>
<p><strong>感谢大家多年以来的支持、理解与陪伴。</strong></p>
<p>勇芳软件工作室<br />
2026 年 09 月 21 日</p>
<p>联系QQ：<strong>370037607</strong><br />
电子邮件：<strong>370037607@qq.com</strong><br />
还可以下载<a href="https://www.yfvb.com/soft-29.htm" title="勇芳客服">勇芳客服</a>软件，联系勇芳。<br />
注：勇芳就一个人，经常外出不在，有什么问题可以直接留言，不用说在不在。</p>]]></description>
    <pubDate>Mon, 21 Sep 2026 12:34:49 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-336.html</guid>
</item>
<item>
    <title>VisualFreeBasic编译器下载</title>
    <link>http://bbs.yfvb.com/post-334.html</link>
    <description><![CDATA[<p>FreeBasic 的编译器非常多，VisualFreeBasic自带了1个编译器，但只支持多个编译器，可以下载不同的编译器，放到VFB里面。在VFB的选项中自由切换。</p>
<h1>下载</h1>
<p>网盘下载 <a href="https://yfvb.lanzouu.com/b0nzxhdbi">https://yfvb.lanzouu.com/b0nzxhdbi</a>  密码:g47t<br />
FB官网下载 <a href="https://sourceforge.net/projects/fbc/files/">https://sourceforge.net/projects/fbc/files/</a> </p>
<h1>下载后操作</h1>
<p>解压后，保存在 VFB的 Compile 文件里，需要文件夹名分类各个版本的编译器<br />
<img src="http://bbs.yfvb.com/content/uploadfile/202603/47891773543591.png" alt="" /><br />
进入文件夹是这样的<br />
<img src="http://bbs.yfvb.com/content/uploadfile/202603/a7381773543827.png" alt="" /><br />
在VFB里的选项，就可以选择相关的编译器了<br />
<img src="http://bbs.yfvb.com/content/uploadfile/202603/74a71773543716.png" alt="" /></p>
<h1>注意</h1>
<p>大家不需要下载很多版本编译器，只需要下载最新的一个即可。</p>]]></description>
    <pubDate>Sun, 15 Mar 2026 10:32:28 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-334.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_SDL_net 核心 API 集合（CategorySDLNet）</title>
    <link>http://bbs.yfvb.com/post-333.html</link>
    <description><![CDATA[<h1>SDL_net 核心 API 集合（CategorySDLNet）</h1>
<p>SDL_net 是 SDL 官方的网络编程扩展库，它对 BSD Sockets、WinSock 等系统级网络 API 进行了轻量级封装，核心设计目标是简化网络编程复杂度、处理各类边界情况，让开发者无需关注底层协议细节即可实现网络通信。其核心设计理念包括：全异步非阻塞接口（可显式等待操作完成）、抽象化地址管理（屏蔽不同网络协议差异）、简洁优先且不失功能完整性。</p>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>核心概念与使用流程</h2>
<ol>
<li><strong>初始化</strong>：调用 <code>NET_Init()</code> 初始化库，程序退出前调用 <code>NET_Quit()</code> 清理；</li>
<li><strong>地址处理</strong>：通过 <code>NET_ResolveHostname()</code> 解析域名到 <code>NET_Address</code> 对象，或直接构造地址；</li>
<li><strong>通信模式选择</strong>：
<ul>
<li><strong>TCP（流套接字）</strong>：客户端用 <code>NET_CreateClient()</code> 连接服务器，服务器用 <code>NET_CreateServer()</code> 监听并通过 <code>NET_AcceptClient()</code> 接受连接，通过 <code>NET_StreamSocket</code> 收发数据；</li>
<li><strong>UDP（数据报套接字）</strong>：用 <code>NET_CreateDatagramSocket()</code> 创建套接字，通过 <code>NET_SendDatagram()</code>/<code>NET_ReceiveDatagram()</code> 收发数据包；</li>
</ul></li>
<li><strong>异步操作</strong>：所有网络操作非阻塞，可通过 <code>NET_WaitUntil*()</code> 系列函数显式等待操作完成；</li>
<li><strong>测试辅助</strong>：通过模拟网络异常函数（如丢包）测试恶劣网络环境下的程序表现。</li>
</ol>
<hr />
<h2>核心 API 列表（按功能分类）</h2>
<h3>一、基础初始化与版本管理</h3>
<ul>
<li>NET_Init：初始化 SDL_net 库（必须调用，加载底层网络接口）</li>
<li>NET_Quit：清理 SDL_net 所有资源（程序退出前必须调用）</li>
<li>NET_Version：获取当前 SDL_net 版本信息</li>
<li>SDL_NET_MAJOR_VERSION：SDL_net 主版本号宏（如 3 代表 SDL_net 3.x）</li>
<li>SDL_NET_MINOR_VERSION：SDL_net 次版本号宏</li>
<li>SDL_NET_MICRO_VERSION：SDL_net 修订版本号宏</li>
<li>SDL_NET_VERSION：构造版本结构体的宏</li>
<li>SDL_NET_VERSION_ATLEAST：编译期检查版本是否满足最低要求</li>
</ul>
<h3>二、网络地址（NET_Address）管理</h3>
<h4>1. 地址解析与创建</h4>
<ul>
<li>NET_ResolveHostname：异步解析域名/IP 到 NET_Address 对象（后台线程执行 DNS 查询）</li>
<li>NET_GetLocalAddresses：获取本地主机的所有网络地址（返回 NET_Address 数组）</li>
<li>NET_FreeLocalAddresses：释放 <code>NET_GetLocalAddresses</code> 返回的地址数组</li>
</ul>
<h4>2. 地址属性与操作</h4>
<ul>
<li>NET_GetAddressString：将 NET_Address 转换为可读的字符串（如 &quot;192.168.1.1:8080&quot;）</li>
<li>NET_GetAddressStatus：获取地址解析状态（未解析/解析成功/解析失败）</li>
<li>NET_CompareAddresses：比较两个 NET_Address 是否指向同一网络地址</li>
<li>NET_RefAddress：增加 NET_Address 对象的引用计数（防止被提前释放）</li>
<li>NET_UnrefAddress：减少 NET_Address 对象的引用计数，计数为 0 时自动释放</li>
</ul>
<h3>三、TCP 流套接字（StreamSocket）- 客户端</h3>
<ul>
<li>NET_CreateClient：创建 TCP 客户端套接字，发起对指定 NET_Address 的连接</li>
<li>NET_GetConnectionStatus：获取客户端连接状态（未连接/连接中/已连接/连接失败）</li>
<li>NET_WaitUntilConnected：阻塞等待客户端连接完成（支持超时，可非阻塞查询/无限等待）</li>
<li>NET_GetStreamSocketAddress：获取流套接字对应的远端 NET_Address</li>
<li>NET_GetStreamSocketPendingWrites：获取流套接字待发送的字节数</li>
<li>NET_WriteToStreamSocket：向流套接字写入数据（非阻塞，返回实际写入字节数）</li>
<li>NET_ReadFromStreamSocket：从流套接字读取数据（非阻塞，返回实际读取字节数）</li>
<li>NET_WaitUntilInputAvailable：阻塞等待流套接字有可读数据（支持超时）</li>
<li>NET_WaitUntilStreamSocketDrained：阻塞等待套接字待发送数据全部发送完成</li>
<li>NET_DestroyStreamSocket：销毁流套接字，关闭连接</li>
</ul>
<h3>四、TCP 服务器（NET_Server）</h3>
<ul>
<li>NET_CreateServer：创建 TCP 服务器，监听指定 NET_Address 的端口</li>
<li>NET_AcceptClient：接受客户端连接（非阻塞，返回新的 NET_StreamSocket）</li>
<li>NET_DestroyServer：销毁服务器，停止监听端口</li>
</ul>
<h3>五、UDP 数据报套接字（DatagramSocket）</h3>
<ul>
<li>NET_CreateDatagramSocket：创建 UDP 数据报套接字（无连接，支持点对点通信）</li>
<li>NET_SendDatagram：发送 UDP 数据包到指定 NET_Address（非阻塞）</li>
<li>NET_ReceiveDatagram：接收 UDP 数据包（非阻塞，返回数据包和发送方地址）</li>
<li>NET_DestroyDatagram：销毁接收到的 UDP 数据包，释放内存</li>
<li>NET_DestroyDatagramSocket：销毁 UDP 套接字</li>
</ul>
<h3>六、阻塞等待函数（异步操作显式等待）</h3>
<ul>
<li>NET_WaitUntilResolved：阻塞等待地址解析完成（支持超时）</li>
<li>NET_WaitUntilConnected：阻塞等待客户端连接完成</li>
<li>NET_WaitUntilInputAvailable：阻塞等待套接字有可读数据</li>
<li>NET_WaitUntilStreamSocketDrained：阻塞等待套接字发送缓冲区排空</li>
</ul>
<h3>七、网络异常模拟（测试专用）</h3>
<ul>
<li>NET_SimulateAddressResolutionLoss：模拟地址解析失败（测试 DNS 异常）</li>
<li>NET_SimulateStreamPacketLoss：模拟 TCP 流数据包丢失（测试网络不稳定）</li>
<li>NET_SimulateDatagramPacketLoss：模拟 UDP 数据包丢失（测试丢包场景）</li>
</ul>
<h3>八、状态枚举（NET_Status）</h3>
<ul>
<li>核心状态值（隐含在 NET_Status 枚举中）：
<ul>
<li>NET_STATUS_INVALID：无效状态（未初始化/已销毁）</li>
<li>NET_STATUS_RESOLVING：地址解析中</li>
<li>NET_STATUS_RESOLVED：地址解析成功</li>
<li>NET_STATUS_RESOLVE_FAILED：地址解析失败</li>
<li>NET_STATUS_CONNECTING：连接建立中</li>
<li>NET_STATUS_CONNECTED：连接已建立</li>
<li>NET_STATUS_CONNECT_FAILED：连接建立失败</li>
</ul></li>
</ul>
<hr />
<h2>数据类型（Datatypes）</h2>
<ul>
<li>NET_Address：网络地址抽象对象（封装 IP 地址、端口、协议等信息）</li>
<li>NET_DatagramSocket：UDP 数据报套接字对象（无连接，用于收发数据包）</li>
<li>NET_Server：TCP 服务器对象（监听端口，接受客户端连接）</li>
<li>NET_StreamSocket：TCP 流套接字对象（面向连接，可靠的字节流传输）</li>
</ul>
<h2>结构体（Structs）</h2>
<ul>
<li>NET_Datagram：UDP 数据包结构体（包含数据缓冲区、数据长度、发送方地址）</li>
</ul>
<h2>宏定义（Macros）</h2>
<ul>
<li>SDL_NET_MAJOR_VERSION / SDL_NET_MINOR_VERSION / SDL_NET_MICRO_VERSION：版本号宏</li>
<li>SDL_NET_VERSION：构造 SDL_version 结构体的宏</li>
<li>SDL_NET_VERSION_ATLEAST：版本检查宏（如 <code>SDL_NET_VERSION_ATLEAST(3,0,0)</code>）</li>
</ul>
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 及 SDL_net 相关声明（需链接 SDL3 和 SDL3_net 库）
#Include "SDL.bi"
#Include "SDL_net.bi"

' 补充关键常量/类型声明（FreeBASIC 绑定可能缺失）
#Define NET_PORT_ANY 0
Type NET_Status
    value As Integer
End Type
Enum NET_Status_Values
    NET_STATUS_INVALID = 0
    NET_STATUS_RESOLVING
    NET_STATUS_RESOLVED
    NET_STATUS_CONNECT_FAILED
    NET_STATUS_CONNECTING
    NET_STATUS_CONNECTED
End Enum

' 检查 SDL_net 版本
Sub CheckNetVersion()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【检查 SDL_net 版本】")

    Dim As SDL_version ver
    NET_Version(@ver)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SDL_net 版本：%d.%d.%d", ver.major, ver.minor, ver.patch)

    ' 编译期版本检查
    #If SDL_NET_VERSION_ATLEAST(3, 0, 0)
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ 满足 SDL_net 3.0.0 最低版本要求")
    #Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ 不满足 SDL_net 3.0.0 最低版本要求")
    #EndIf
End Sub

' TCP 服务器示例（简单回显服务器）
Sub TCPServerExample(ByVal port As Uint16)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【TCP 回显服务器示例】")

    ' 1. 初始化 SDL_net
    If (NET_Init() = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_net 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 2. 构造服务器地址（监听所有网卡的指定端口）
    Dim As NET_Address Ptr serverAddr = NET_ResolveHostname(NULL, port)
    If (serverAddr = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "解析地址失败：%s", SDL_GetError())
        NET_Quit()
        Exit Sub
    End If

    ' 等待地址解析完成
    If (NET_WaitUntilResolved(serverAddr, -1) = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "地址解析超时")
        NET_UnrefAddress(serverAddr)
        NET_Quit()
        Exit Sub
    End If

    ' 3. 创建 TCP 服务器
    Dim As NET_Server Ptr server = NET_CreateServer(serverAddr)
    If (server = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建服务器失败：%s", SDL_GetError())
        NET_UnrefAddress(serverAddr)
        NET_Quit()
        Exit Sub
    End If
    NET_UnrefAddress(serverAddr)  ' 释放地址引用

    Dim As ZString * 256 addrStr
    NET_GetAddressString(serverAddr, addrStr, sizeof(addrStr))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "服务器已启动，监听地址：%s", addrStr)

    ' 4. 接受客户端连接并处理
    Dim As NET_StreamSocket Ptr clientSocket = NULL
    Dim As SDL_bool running = SDL_TRUE
    Dim As UByte buffer(1023)  ' 1KB 接收缓冲区

    While (running)
        ' 非阻塞接受客户端连接
        clientSocket = NET_AcceptClient(server)
        If (clientSocket &lt;&gt; NULL) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "客户端已连接")

            ' 循环接收并回显数据
            While (running)
                ' 等待有可读数据（超时 100ms）
                If (NET_WaitUntilInputAvailable(clientSocket, 100) = SDL_TRUE) Then
                    ' 读取数据
                    Dim As Sint64 readBytes = NET_ReadFromStreamSocket(clientSocket, @buffer(0), sizeof(buffer))
                    If (readBytes &gt; 0) Then
                        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "收到数据：%.*s", readBytes, @buffer(0))

                        ' 回显数据给客户端
                        Dim As Sint64 writeBytes = NET_WriteToStreamSocket(clientSocket, @buffer(0), readBytes)
                        If (writeBytes &lt; 0) Then
                            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "发送数据失败：%s", SDL_GetError())
                            Exit While
                        End If
                    ElseIf (readBytes = 0) Then
                        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "客户端断开连接")
                        Exit While
                    Else
                        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "读取数据失败：%s", SDL_GetError())
                        Exit While
                    End If
                End If

                ' 处理退出事件（简化示例，实际需处理 SDL 事件）
                Dim As SDL_Event evt
                If (SDL_PollEvent(@evt) AndAlso evt.type = SDL_QUIT) Then
                    running = SDL_FALSE
                End If
            Wend

            ' 关闭客户端连接
            NET_DestroyStreamSocket(clientSocket)
            clientSocket = NULL
        End If

        ' 处理退出事件
        Dim As SDL_Event evt
        If (SDL_PollEvent(@evt) AndAlso evt.type = SDL_QUIT) Then
            running = SDL_FALSE
        End If

        SDL_Delay(10)
    Wend

    ' 5. 释放资源
    If (clientSocket &lt;&gt; NULL) Then
        NET_DestroyStreamSocket(clientSocket)
    End If
    NET_DestroyServer(server)
    NET_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "服务器已停止")
End Sub

' TCP 客户端示例
Sub TCPClientExample(ByVal hostname As ZString Ptr, ByVal port As Uint16)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【TCP 客户端示例】")

    ' 1. 初始化 SDL_net
    If (NET_Init() = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_net 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 2. 解析服务器地址
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "解析地址：%s:%d", hostname, port)
    Dim As NET_Address Ptr serverAddr = NET_ResolveHostname(hostname, port)
    If (serverAddr = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "解析地址失败：%s", SDL_GetError())
        NET_Quit()
        Exit Sub
    End If

    ' 等待地址解析完成（无限等待）
    If (NET_WaitUntilResolved(serverAddr, -1) = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "地址解析失败")
        NET_UnrefAddress(serverAddr)
        NET_Quit()
        Exit Sub
    End If

    ' 打印解析后的地址
    Dim As ZString * 256 addrStr
    NET_GetAddressString(serverAddr, addrStr, sizeof(addrStr))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "解析完成：%s", addrStr)

    ' 3. 创建客户端并连接服务器
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "连接服务器...")
    Dim As NET_StreamSocket Ptr clientSocket = NET_CreateClient(serverAddr)
    If (clientSocket = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建客户端失败：%s", SDL_GetError())
        NET_UnrefAddress(serverAddr)
        NET_Quit()
        Exit Sub
    End If
    NET_UnrefAddress(serverAddr)

    ' 等待连接完成（超时 5 秒）
    If (NET_WaitUntilConnected(clientSocket, 5000) = SDL_FALSE) Then
        Dim As NET_Status status
        NET_GetConnectionStatus(clientSocket, @status)
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "连接失败，状态：%d", status.value)
        NET_DestroyStreamSocket(clientSocket)
        NET_Quit()
        Exit Sub
    End If
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "连接成功！")

    ' 4. 发送测试数据
    Dim As ZString * 64 sendData = "Hello SDL_net Server!"
    Dim As Sint64 writeBytes = NET_WriteToStreamSocket(clientSocket, sendData, Len(sendData))
    If (writeBytes &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "发送数据失败：%s", SDL_GetError())
        NET_DestroyStreamSocket(clientSocket)
        NET_Quit()
        Exit Sub
    End If
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "发送数据：%s", sendData)

    ' 5. 接收服务器回显数据
    Dim As UByte recvBuffer(1023)
    If (NET_WaitUntilInputAvailable(clientSocket, 2000) = SDL_TRUE) Then
        Dim As Sint64 readBytes = NET_ReadFromStreamSocket(clientSocket, @recvBuffer(0), sizeof(recvBuffer))
        If (readBytes &gt; 0) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "收到回显：%.*s", readBytes, @recvBuffer(0))
        End If
    Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "接收超时")
    End If

    ' 6. 等待数据发送完成并关闭连接
    NET_WaitUntilStreamSocketDrained(clientSocket, -1)
    NET_DestroyStreamSocket(clientSocket)
    NET_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "客户端已断开连接")
End Sub

' UDP 通信示例（简单点对点发送）
Sub UDPCommunicationExample(ByVal localPort As Uint16, ByVal targetHost As ZString Ptr, ByVal targetPort As Uint16)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【UDP 通信示例】")

    ' 1. 初始化 SDL_net
    If (NET_Init() = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_net 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 2. 创建 UDP 套接字
    Dim As NET_Address Ptr localAddr = NET_ResolveHostname(NULL, localPort)
    Dim As NET_DatagramSocket Ptr udpSocket = NET_CreateDatagramSocket(localAddr)
    NET_UnrefAddress(localAddr)

    If (udpSocket = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建 UDP 套接字失败：%s", SDL_GetError())
        NET_Quit()
        Exit Sub
    End If
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "UDP 套接字已创建，监听端口：%d", localPort)

    ' 3. 解析目标地址
    Dim As NET_Address Ptr targetAddr = NET_ResolveHostname(targetHost, targetPort)
    If (NET_WaitUntilResolved(targetAddr, 3000) = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "解析目标地址失败")
        NET_UnrefAddress(targetAddr)
        NET_DestroyDatagramSocket(udpSocket)
        NET_Quit()
        Exit Sub
    End If

    ' 4. 发送 UDP 数据包
    Dim As ZString * 64 sendData = "Hello UDP Peer!"
    If (NET_SendDatagram(udpSocket, targetAddr, sendData, Len(sendData)) = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "发送 UDP 数据包失败：%s", SDL_GetError())
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "发送 UDP 数据：%s", sendData)
    End If

    ' 5. 尝试接收响应（超时 2 秒）
    Dim As NET_Datagram Ptr datagram = NULL
    Dim As UByte recvBuffer(1023)
    If (NET_ReceiveDatagram(udpSocket, @datagram, 2000) = SDL_TRUE AndAlso datagram &lt;&gt; NULL) Then
        ' 提取数据包数据
        Dim As Const UByte Ptr data = NET_DatagramGetData(datagram)
        Dim As Sint64 len = NET_DatagramGetLength(datagram)
        Dim As NET_Address Ptr senderAddr = NET_DatagramGetAddress(datagram)

        Dim As ZString * 256 senderStr
        NET_GetAddressString(senderAddr, senderStr, sizeof(senderStr))
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "从 %s 收到 UDP 数据：%.*s", senderStr, len, data)

        NET_DestroyDatagram(datagram)
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "未收到 UDP 响应（超时）")
    End If

    ' 6. 释放资源
    NET_UnrefAddress(targetAddr)
    NET_DestroyDatagramSocket(udpSocket)
    NET_Quit()
End Sub

' 主程序
Sub Main()
    ' 初始化 SDL 核心
    If (SDL_Init(0) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 运行示例（按需取消注释）
    CheckNetVersion()
    ' TCPServerExample(8080)  ' 先启动服务器
    ' TCPClientExample(StrPtr("127.0.0.1"), 8080)  ' 再启动客户端
    ' UDPCommunicationExample(8081, StrPtr("127.0.0.1"), 8082)

    ' 清理 SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>异步非阻塞核心</strong>：</p>
<ul>
<li>SDL_net 所有操作默认非阻塞，调用后立即返回，需通过状态查询（如 <code>NET_GetConnectionStatus</code>）或 <code>NET_WaitUntil*()</code> 等待操作完成；</li>
<li>阻塞函数（<code>NET_WaitUntil*</code>）建议在后台线程使用，避免阻塞主线程（如游戏渲染线程）。</li>
</ul>
</li>
<li>
<p><strong>TCP vs UDP 选择</strong>：</p>
<ul>
<li><strong>TCP（流套接字）</strong>：可靠的字节流传输，自动重传丢失数据、保证顺序，适合需要数据完整性的场景（如登录、文件传输）；</li>
<li><strong>UDP（数据报套接字）</strong>：无连接、不可靠，数据包可能丢失/乱序，但延迟低、开销小，适合实时性要求高的场景（如游戏帧同步、语音）。</li>
</ul>
</li>
<li>
<p><strong>地址引用计数</strong>：</p>
<ul>
<li><code>NET_Address</code> 采用引用计数管理，<code>NET_RefAddress</code> 增加计数，<code>NET_UnrefAddress</code> 减少计数；</li>
<li>确保不再使用的地址调用 <code>NET_UnrefAddress</code>，避免内存泄漏。</li>
</ul>
</li>
<li>
<p><strong>网络异常模拟</strong>：</p>
<ul>
<li><code>NET_Simulate*Loss</code> 系列函数用于测试恶劣网络环境，仅在开发/测试阶段使用，生产环境需禁用；</li>
<li>可模拟 DNS 解析失败、TCP/UDP 丢包，验证程序的容错能力。</li>
</ul>
</li>
<li>
<p><strong>跨平台注意事项</strong>：</p>
<ul>
<li>Windows 系统需确保防火墙允许程序访问网络，监听端口需配置入站规则；</li>
<li>Linux/macOS 需注意端口权限（1024 以下端口需 root 权限）；</li>
<li>移动平台（Android/iOS）需申请网络权限：Android 需 <code>INTERNET</code> 权限，iOS 需关闭 ATS（或配置例外）。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>轻量级封装系统套接字 API，屏蔽跨平台差异（Windows/ Linux/macOS/移动端）；</li>
<li>全异步非阻塞设计，适配游戏/实时应用的主线程模型；</li>
<li>抽象化地址管理，无需关注 IPv4/IPv6 底层细节；</li>
<li>内置网络异常模拟功能，便于测试程序的鲁棒性；</li>
<li>与 SDL 生态无缝集成，可直接结合 SDL 事件循环使用。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>网络操作尽量放在后台线程，避免阻塞主线程；</li>
<li>TCP 通信需处理连接断开、超时等异常，UDP 需自行实现重传/校验逻辑；</li>
<li>频繁使用的 <code>NET_Address</code> 需合理管理引用计数，避免内存泄漏；</li>
<li>服务器监听端口时，优先使用 <code>NET_PORT_ANY</code> 自动分配端口，或选择 1024 以上的非特权端口；</li>
<li>生产环境禁用网络异常模拟函数，避免影响正常通信。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>SDL_net 核心是抽象化的地址（<code>NET_Address</code>）、套接字（TCP 流/UDP 数据报）、服务器（<code>NET_Server</code>）三层结构；</li>
<li><code>NET_Init()</code>/<code>NET_Quit()</code> 是必选的初始化/清理接口；</li>
<li>TCP 适合可靠传输，UDP 适合实时传输，需根据业务场景选择；</li>
<li>所有操作默认非阻塞，可通过 <code>NET_WaitUntil*()</code> 显式等待；</li>
<li>地址对象采用引用计数管理，需正确调用 <code>NET_RefAddress</code>/<code>NET_UnrefAddress</code>。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 12:07:29 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-333.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_SDL_mixer 核心 API 集合（CategorySDLMixer）</title>
    <link>http://bbs.yfvb.com/post-332.html</link>
    <description><![CDATA[<h1>SDL_mixer 核心 API 集合（CategorySDLMixer）</h1>
<p>SDL_mixer 是 SDL 官方的音频混音扩展库，旨在简化复杂的音频处理任务。它提供音频文件解码、多音效混音、基础 3D 定位音频、各类音频特效等核心能力，支持实时混音输出到多个音频设备，也可将混音数据生成到内存缓冲区，甚至能同时完成这两种操作，是 SDL 生态中处理音频播放与混音的核心工具。</p>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>核心概念与使用流程</h2>
<ol>
<li><strong>初始化</strong>：调用 <code>MIX_Init()</code> 初始化库，指定支持的音频格式；</li>
<li><strong>创建混音器</strong>：通过 <code>MIX_CreateMixerDevice()</code>（输出到硬件）或 <code>MIX_CreateMixer()</code>（输出到内存）创建混音器实例；</li>
<li><strong>加载音频</strong>：使用 <code>MIX_LoadAudio()</code> 加载音频文件为可复用的 <code>MIX_Audio</code> 对象；</li>
<li><strong>创建轨道</strong>：通过 <code>MIX_CreateTrack()</code> 创建音频轨道（每轨道对应一个同时播放的音效）；</li>
<li><strong>绑定音频</strong>：用 <code>MIX_SetTrackAudio()</code> 将音频数据绑定到轨道；</li>
<li><strong>播放控制</strong>：调用 <code>MIX_PlayTrack()</code> 播放轨道，支持循环、淡入淡出等效果；</li>
<li><strong>高级控制</strong>：可设置轨道音量、3D 位置、播放速度，或通过标签批量控制多轨道；</li>
<li><strong>清理</strong>：使用完毕后销毁轨道、混音器，调用 <code>MIX_Quit()</code> 释放资源。</li>
</ol>
<hr />
<h2>核心 API 列表（按功能分类）</h2>
<h3>一、基础初始化与版本管理</h3>
<ul>
<li>MIX_Init：初始化 SDL_mixer 库（需指定支持的音频格式，如 MP3/OGG 等）</li>
<li>MIX_Quit：清理 SDL_mixer 所有资源（程序退出前必须调用）</li>
<li>MIX_Version：获取当前 SDL_mixer 版本信息</li>
<li>SDL_MIXER_MAJOR_VERSION：SDL_mixer 主版本号宏（如 3 代表 SDL_mixer 3.x）</li>
<li>SDL_MIXER_MINOR_VERSION：SDL_mixer 次版本号宏</li>
<li>SDL_MIXER_MICRO_VERSION：SDL_mixer 修订版本号宏</li>
<li>SDL_MIXER_VERSION：构造版本结构体的宏</li>
<li>SDL_MIXER_VERSION_ATLEAST：编译期检查版本是否满足最低要求</li>
</ul>
<h3>二、音频数据（MIX_Audio）管理</h3>
<h4>1. 音频加载/销毁</h4>
<ul>
<li>MIX_LoadAudio：从文件加载音频数据为 MIX_Audio 对象（自动解码）</li>
<li>MIX_LoadAudio_IO：从 SDL_IOStream 流加载音频数据</li>
<li>MIX_LoadAudioWithProperties：带自定义属性加载音频（如采样率、声道数）</li>
<li>MIX_LoadAudioNoCopy：加载音频但不复制数据（直接使用内存缓冲区）</li>
<li>MIX_LoadRawAudio：加载原始 PCM 音频数据（无需解码）</li>
<li>MIX_LoadRawAudio_IO：从流加载原始 PCM 音频</li>
<li>MIX_LoadRawAudioNoCopy：加载原始 PCM 音频且不复制数据</li>
<li>MIX_CreateSineWaveAudio：生成正弦波音频数据（用于测试/音效生成）</li>
<li>MIX_DestroyAudio：销毁 MIX_Audio 对象，释放音频数据</li>
</ul>
<h4>2. 音频属性查询</h4>
<ul>
<li>MIX_GetAudioFormat：获取音频的 PCM 格式（如 SDL_AUDIO_F32、SDL_AUDIO_S16）</li>
<li>MIX_GetAudioDuration：获取音频总时长（采样帧数）</li>
<li>MIX_GetAudioProperties：获取音频的元数据（如 ID3 标签、时长、码率等）</li>
<li>MIX_AudioFramesToMS：将音频的采样帧数转换为毫秒</li>
<li>MIX_AudioMSToFrames：将毫秒转换为音频的采样帧数</li>
</ul>
<h3>三、音频解码器（MIX_AudioDecoder）</h3>
<ul>
<li>MIX_CreateAudioDecoder：创建音频解码器实例（通用接口）</li>
<li>MIX_CreateAudioDecoder_IO：从 SDL_IOStream 流创建解码器</li>
<li>MIX_DestroyAudioDecoder：销毁解码器实例</li>
<li>MIX_DecodeAudio：解码音频数据到 PCM 格式</li>
<li>MIX_GetAudioDecoder：获取指定索引的解码器名称（如 &quot;mp3&quot;、&quot;ogg&quot;）</li>
<li>MIX_GetNumAudioDecoders：获取支持的解码器总数</li>
<li>MIX_GetAudioDecoderFormat：获取解码器输出的 PCM 格式</li>
<li>MIX_GetAudioDecoderProperties：获取解码器配置属性</li>
</ul>
<h3>四、混音器（MIX_Mixer）管理</h3>
<h4>1. 混音器创建/销毁</h4>
<ul>
<li>MIX_CreateMixer：创建内存混音器（输出到内存缓冲区）</li>
<li>MIX_CreateMixerDevice：创建设备混音器（输出到音频硬件）</li>
<li>MIX_DestroyMixer：销毁混音器实例</li>
<li>MIX_LockMixer：锁定混音器（防止多线程操作冲突）</li>
<li>MIX_UnlockMixer：解锁混音器</li>
</ul>
<h4>2. 混音器属性控制</h4>
<ul>
<li>MIX_GetMixerFormat：获取混音器输出的 PCM 格式</li>
<li>MIX_GetMixerGain：获取混音器主音量增益（0.0~1.0）</li>
<li>MIX_SetMixerGain：设置混音器主音量增益</li>
<li>MIX_GetMixerFrequencyRatio：获取混音器输出的播放速度比例</li>
<li>MIX_SetMixerFrequencyRatio：设置播放速度比例（&gt;1 加速，&lt;1 减速，同步调整音调）</li>
<li>MIX_GetMixerProperties：获取混音器完整配置属性</li>
<li>MIX_SetPostMixCallback：设置混音后回调（处理最终输出的 PCM 数据）</li>
<li>MIX_Generate：手动触发混音器生成音频数据（内存混音器专用）</li>
</ul>
<h3>五、音频轨道（MIX_Track）管理</h3>
<h4>1. 轨道创建/销毁</h4>
<ul>
<li>MIX_CreateTrack：创建音频轨道（混音器的核心播放单元）</li>
<li>MIX_DestroyTrack：销毁轨道实例</li>
</ul>
<h4>2. 轨道输入绑定</h4>
<ul>
<li>MIX_SetTrackAudio：将 MIX_Audio 绑定到轨道（播放预加载的音频）</li>
<li>MIX_SetTrackAudioStream：将 SDL_AudioStream 绑定到轨道（流式播放）</li>
<li>MIX_SetTrackIOStream：将 SDL_IOStream 绑定到轨道（实时解码播放）</li>
<li>MIX_SetTrackRawIOStream：绑定原始 PCM 数据流到轨道</li>
</ul>
<h4>3. 播放控制</h4>
<ul>
<li>MIX_PlayTrack：播放轨道（支持循环次数、淡入淡出、起始位置等参数）</li>
<li>MIX_PlayAudio：快速播放 MIX_Audio（自动创建临时轨道）</li>
<li>MIX_PauseTrack：暂停指定轨道</li>
<li>MIX_ResumeTrack：恢复暂停的轨道</li>
<li>MIX_StopTrack：停止轨道播放</li>
<li>MIX_PauseAllTracks：暂停所有轨道</li>
<li>MIX_ResumeAllTracks：恢复所有轨道</li>
<li>MIX_StopAllTracks：停止所有轨道</li>
<li>MIX_TrackPlaying：检查轨道是否正在播放</li>
<li>MIX_TrackPaused：检查轨道是否处于暂停状态</li>
</ul>
<h4>4. 轨道属性控制</h4>
<ul>
<li>MIX_GetTrackGain：获取轨道音量增益</li>
<li>MIX_SetTrackGain：设置轨道音量增益（独立于主音量）</li>
<li>MIX_GetTrackFrequencyRatio：获取轨道播放速度比例</li>
<li>MIX_SetTrackFrequencyRatio：设置轨道播放速度（同步调整音调）</li>
<li>MIX_GetTrackLoops：获取轨道循环次数</li>
<li>MIX_SetTrackLoops：设置轨道循环次数（0=播放1次，-1=无限循环）</li>
<li>MIX_GetTrackFadeFrames：获取轨道淡入/淡出的采样帧数</li>
<li>MIX_SetTrackOutputChannelMap：设置轨道输出声道映射（调整音频输出到指定扬声器）</li>
<li>MIX_GetTrackPlaybackPosition：获取轨道当前播放位置（采样帧）</li>
<li>MIX_SetTrackPlaybackPosition：设置轨道播放位置（定位到指定帧）</li>
<li>MIX_GetTrackRemaining：获取轨道剩余播放帧数</li>
</ul>
<h4>5. 3D 与立体声控制</h4>
<ul>
<li>MIX_SetTrack3DPosition：设置轨道的 3D 空间位置（支持距离衰减、空间化）</li>
<li>MIX_GetTrack3DPosition：获取轨道的 3D 位置</li>
<li>MIX_SetTrackStereo：设置轨道的立体声平衡（左右声道音量比例）</li>
</ul>
<h4>6. 轨道标签与批量控制</h4>
<ul>
<li>MIX_TagTrack：为轨道添加自定义标签（如 &quot;music&quot;、&quot;ui_sfx&quot;）</li>
<li>MIX_UntagTrack：移除轨道的指定标签</li>
<li>MIX_GetTrackTags：获取轨道的所有标签</li>
<li>MIX_GetTaggedTracks：获取指定标签的所有轨道</li>
<li>MIX_PlayTag：播放所有带指定标签的轨道</li>
<li>MIX_PauseTag：暂停所有带指定标签的轨道</li>
<li>MIX_ResumeTag：恢复所有带指定标签的轨道</li>
<li>MIX_StopTag：停止所有带指定标签的轨道</li>
<li>MIX_SetTagGain：设置指定标签所有轨道的音量增益</li>
</ul>
<h4>7. 轨道回调函数</h4>
<ul>
<li>MIX_SetTrackRawCallback：设置原始音频回调（解码后、未处理前的 PCM 数据）</li>
<li>MIX_SetTrackCookedCallback：设置处理后音频回调（应用淡入淡出、3D 等效果后的 PCM 数据）</li>
<li>MIX_SetTrackStoppedCallback：设置轨道播放结束回调</li>
</ul>
<h4>8. 时间转换</h4>
<ul>
<li>MIX_TrackFramesToMS：将轨道的采样帧数转换为毫秒</li>
<li>MIX_TrackMSToFrames：将毫秒转换为轨道的采样帧数</li>
<li>MIX_FramesToMS：通用的帧数转毫秒</li>
<li>MIX_MSToFrames：通用的毫秒转帧数</li>
</ul>
<h3>六、音频组（MIX_Group）管理</h3>
<ul>
<li>MIX_CreateGroup：创建音频组（管理一组轨道，单独混音）</li>
<li>MIX_DestroyGroup：销毁音频组</li>
<li>MIX_SetTrackGroup：将轨道加入指定音频组</li>
<li>MIX_GetGroupMixer：获取音频组的混音器实例</li>
<li>MIX_GetGroupProperties：获取音频组属性</li>
<li>MIX_SetGroupPostMixCallback：设置音频组混音后回调（处理组内轨道的混音数据）</li>
</ul>
<h3>七、通用工具函数</h3>
<ul>
<li>MIX_GetTrackMixer：获取轨道所属的混音器</li>
<li>MIX_GetTrackAudio：获取轨道绑定的 MIX_Audio 对象</li>
<li>MIX_GetTrackAudioStream：获取轨道绑定的音频流</li>
</ul>
<hr />
<h2>数据类型（Datatypes）</h2>
<ul>
<li>MIX_Audio：封装解码后的音频数据（PCM 数据、格式、时长等）</li>
<li>MIX_AudioDecoder：音频解码器实例（用于解码各类音频格式）</li>
<li>MIX_Group：音频组对象（管理一组轨道，支持独立混音）</li>
<li>MIX_GroupMixCallback：音频组混音回调函数类型</li>
<li>MIX_Mixer：混音器实例（核心混音单元，分设备/内存两种）</li>
<li>MIX_PostMixCallback：混音后回调函数类型（处理最终输出数据）</li>
<li>MIX_Track：音频轨道对象（混音器的播放单元，每轨道对应一个音效）</li>
<li>MIX_TrackMixCallback：轨道音频回调函数类型（处理原始/处理后数据）</li>
<li>MIX_TrackStoppedCallback：轨道播放结束回调函数类型</li>
</ul>
<h2>结构体（Structs）</h2>
<ul>
<li>MIX_Point3D：3D 空间坐标结构体（用于设置轨道的 3D 位置）</li>
<li>MIX_StereoGains：立体声增益结构体（左右声道音量比例）</li>
</ul>
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 及 SDL_mixer 相关声明（需链接 SDL3 和 SDL3_mixer 库）
#Include "SDL.bi"
#Include "SDL_mixer.bi"

' 补充关键常量/类型声明（FreeBASIC 绑定可能缺失）
#Define MIX_INIT_MP3 1
#Define MIX_INIT_OGG 2
Type MIX_Point3D
    x As Float
    y As Float
    z As Float
End Type

' 检查 SDL_mixer 版本
Sub CheckMixerVersion()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【检查 SDL_mixer 版本】")

    Dim As SDL_version ver
    MIX_Version(@ver)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SDL_mixer 版本：%d.%d.%d", ver.major, ver.minor, ver.patch)

    ' 编译期版本检查
    #If SDL_MIXER_VERSION_ATLEAST(3, 0, 0)
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ 满足 SDL_mixer 3.0.0 最低版本要求")
    #Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ 不满足 SDL_mixer 3.0.0 最低版本要求")
    #EndIf
End Sub

' 轨道播放结束回调函数
Sub TrackStoppedCallback Cdecl (ByVal track As MIX_Track Ptr, ByVal userdata As Any Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【回调】轨道播放结束！")
End Sub

' 基础音频播放示例
Sub BasicAudioPlaybackExample(ByVal audioPath As ZString Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【基础音频播放示例】")

    ' 1. 初始化 SDL_mixer（支持 MP3 和 OGG）
    Dim As Integer initFlags = MIX_INIT_MP3 Or MIX_INIT_OGG
    If (MIX_Init(initFlags) &lt;&gt; initFlags) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_mixer 初始化失败：%s", MIX_GetError())
        Exit Sub
    End If

    ' 2. 创建设备混音器（输出到默认音频设备）
    Dim As MIX_Mixer Ptr mixer = MIX_CreateMixerDevice(NULL)
    If (mixer = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建混音器失败：%s", MIX_GetError())
        MIX_Quit()
        Exit Sub
    End If

    ' 3. 加载音频文件
    Dim As MIX_Audio Ptr audio = MIX_LoadAudio(audioPath)
    If (audio = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "加载音频失败：%s", MIX_GetError())
        MIX_DestroyMixer(mixer)
        MIX_Quit()
        Exit Sub
    End If

    ' 4. 查询音频属性
    Dim As Uint32 audioFormat
    Dim As Integer freq, channels
    MIX_GetAudioFormat(audio, @audioFormat, @freq, @channels)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "音频格式：%u, 采样率：%d Hz, 声道数：%d", audioFormat, freq, channels)

    Dim As Uint64 totalFrames = MIX_GetAudioDuration(audio)
    Dim As Uint64 totalMS = MIX_AudioFramesToMS(audio, totalFrames)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "音频时长：%llu 帧 / %llu 毫秒", totalFrames, totalMS)

    ' 5. 创建音频轨道
    Dim As MIX_Track Ptr track = MIX_CreateTrack(mixer)
    If (track = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建轨道失败：%s", MIX_GetError())
        MIX_DestroyAudio(audio)
        MIX_DestroyMixer(mixer)
        MIX_Quit()
        Exit Sub
    End If

    ' 6. 配置轨道
    MIX_SetTrackAudio(track, audio)          ' 绑定音频数据
    MIX_SetTrackGain(track, 0.8)             ' 设置轨道音量（80%）
    MIX_SetTrackLoops(track, 1)              ' 循环1次（总共播放2次）
    MIX_SetTrackStoppedCallback(track, @TrackStoppedCallback, NULL)  ' 设置结束回调
    MIX_TagTrack(track, "music")             ' 添加标签

    ' 7. 设置 3D 位置（右侧 2 米处）
    Dim As MIX_Point3D pos = {2.0, 0.0, 0.0}
    MIX_SetTrack3DPosition(track, @pos)

    ' 8. 播放轨道
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "开始播放音频...")
    If (MIX_PlayTrack(track, 0, 0, 0) = SDL_FALSE) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "播放轨道失败：%s", MIX_GetError())
    End If

    ' 9. 等待播放完成（简单演示，实际项目需用事件循环）
    While (MIX_TrackPlaying(track))
        SDL_Delay(100)
        ' 打印当前播放进度
        Dim As Uint64 currFrames = MIX_GetTrackPlaybackPosition(track)
        Dim As Uint64 currMS = MIX_TrackFramesToMS(track, currFrames)
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "播放进度：%llu/%llu 毫秒", currMS, totalMS)
    Wend

    ' 10. 释放资源
    MIX_DestroyTrack(track)
    MIX_DestroyAudio(audio)
    MIX_DestroyMixer(mixer)
    MIX_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "音频播放完成")
End Sub

' 批量控制带标签的轨道示例
Sub TagBasedControlExample(ByVal mixer As MIX_Mixer Ptr, ByVal sfxPath As ZString Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【标签批量控制示例】")

    ' 1. 加载音效并创建多个带 "ui_sfx" 标签的轨道
    Dim As MIX_Audio Ptr sfxAudio = MIX_LoadAudio(sfxPath)
    If (sfxAudio = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "加载音效失败：%s", MIX_GetError())
        Exit Sub
    End If

    ' 创建3个UI音效轨道
    For i As Integer = 0 To 2
        Dim As MIX_Track Ptr track = MIX_CreateTrack(mixer)
        If (track &lt;&gt; NULL) Then
            MIX_SetTrackAudio(track, sfxAudio)
            MIX_SetTrackGain(track, 0.5)
            MIX_TagTrack(track, "ui_sfx")
        End If
    Next

    ' 2. 批量播放所有 "ui_sfx" 标签的轨道
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "批量播放 UI 音效...")
    MIX_PlayTag(mixer, "ui_sfx", 0, 0, 0)

    ' 3. 延迟后批量暂停
    SDL_Delay(500)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "批量暂停 UI 音效...")
    MIX_PauseTag(mixer, "ui_sfx")

    ' 4. 延迟后批量恢复
    SDL_Delay(500)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "批量恢复 UI 音效...")
    MIX_ResumeTag(mixer, "ui_sfx")

    ' 5. 等待播放完成
    SDL_Delay(1000)

    ' 6. 释放资源
    MIX_DestroyAudio(sfxAudio)
End Sub

' 主程序
Sub Main()
    ' 初始化 SDL 音频子系统
    If (SDL_Init(SDL_INIT_AUDIO) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 运行示例
    CheckMixerVersion()
    BasicAudioPlaybackExample(StrPtr("background_music.mp3"))  ' 替换为实际音频文件路径
    ' TagBasedControlExample(mixer, StrPtr("ui_click.wav"))  ' 需先创建混音器，此处仅演示

    ' 清理 SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>采样帧与时间转换</strong>：</p>
<ul>
<li>SDL_mixer 中所有时间计算基于「采样帧」（Sample Frame），而非毫秒，确保采样级精度；</li>
<li>立体声 16 位 PCM 音频：1 帧 = 2 采样 × 2 字节 = 4 字节；</li>
<li>不同采样率的音频，相同毫秒对应的帧数不同，需用 <code>MIX_TrackMSToFrames()</code> 等函数转换。</li>
</ul>
</li>
<li>
<p><strong>混音器类型选择</strong>：</p>
<ul>
<li><strong>设备混音器（MIX_CreateMixerDevice）</strong>：输出到音频硬件，适合实时播放；</li>
<li><strong>内存混音器（MIX_CreateMixer）</strong>：输出到内存缓冲区，适合音频录制、离线处理。</li>
</ul>
</li>
<li>
<p><strong>3D 音频限制</strong>：</p>
<ul>
<li>SDL_mixer 仅提供基础 3D 定位（距离衰减、立体声空间化），不支持复杂的 3D 音效（如混响、遮挡）；</li>
<li>如需专业 3D 音频，建议搭配 OpenAL 等专用库；</li>
<li>3D 效果仅在立体声/环绕声设备上生效，单声道设备无效果。</li>
</ul>
</li>
<li>
<p><strong>性能优化要点</strong>：</p>
<ul>
<li>复用 MIX_Audio 对象（加载一次，多次播放），避免重复解码；</li>
<li>复用轨道对象（播放不同音频时仅需调用 <code>MIX_SetTrackAudio()</code>）；</li>
<li>大量音效播放时使用标签批量控制，减少循环遍历；</li>
<li>多线程操作混音器时必须调用 <code>MIX_LockMixer()</code>/<code>MIX_UnlockMixer()</code> 加锁。</li>
</ul>
</li>
<li>
<p><strong>跨平台注意事项</strong>：</p>
<ul>
<li>Windows/macOS 支持主流音频格式（MP3/OGG/WAV/FLAC），Linux 需确保安装对应解码器；</li>
<li>移动平台需将音频文件放入 assets 目录，使用绝对路径加载；</li>
<li>音频设备权限：Android/iOS 需申请音频播放权限（Android 13+ 需 POST_NOTIFICATIONS 权限）。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>一站式音频解决方案：解码、混音、播放、特效全覆盖，无需集成多个音频库；</li>
<li>无缝衔接 SDL 核心库，与 SDL 窗口/事件系统兼容；</li>
<li>支持多轨道混音、3D 定位、播放速度调整等常用功能，满足游戏/多媒体开发需求；</li>
<li>高精度时间控制（采样帧级），支持实时/离线混音；</li>
<li>灵活的回调机制，可自定义音频处理逻辑。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>初始化时仅加载需要的解码器（减少内存占用）；</li>
<li>预加载常用音频为 MIX_Audio 对象，播放时复用轨道；</li>
<li>音效分类管理：用标签区分音乐、UI 音效、环境音效，方便批量控制；</li>
<li>实时音频处理（如音效滤镜）可通过 Raw/Cooked 回调实现；</li>
<li>避免在主线程中长时间阻塞，建议用回调/事件处理播放状态。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>SDL_mixer 是 SDL 的音频混音扩展库，核心是混音器（Mixer）、轨道（Track）、音频数据（Audio）三层结构；</li>
<li><code>MIX_Init()</code>/<code>MIX_Quit()</code> 是必选的初始化/清理接口，需指定支持的音频格式；</li>
<li>轨道是播放的基本单元，支持音量、速度、3D 位置、标签等配置；</li>
<li>时间计算基于采样帧，需通过专用函数转换为毫秒；</li>
<li>标签功能可批量控制多轨道，适合游戏中按类型管理音效。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 12:04:19 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-332.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_SDL_ttf 核心 API 集合（CategoryAPI）</title>
    <link>http://bbs.yfvb.com/post-331.html</link>
    <description><![CDATA[<h1>SDL_ttf 核心 API 集合（CategoryAPI）</h1>
<p>SDL_ttf 是 SDL 的官方字体渲染扩展库，该分类汇总了 SDL_ttf 全量核心 API，涵盖字体加载/管理、文本渲染（Surface/Renderer/GPU 三种模式）、字形/排版控制、多语言文本处理等功能，是 SDL 生态中实现高质量文本渲染的核心接口集合。</p>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>核心 API 列表（按功能分类）</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表 -->
<h3>一、基础初始化与版本管理</h3>
<ul>
<li>TTF_Init：初始化 SDL_ttf 库（必须调用，加载 FreeType/HarfBuzz 依赖）</li>
<li>TTF_Quit：清理 SDL_ttf 资源（程序退出前调用）</li>
<li>TTF_WasInit：检查 SDL_ttf 是否已初始化</li>
<li>TTF_Version：获取当前 SDL_ttf 版本信息</li>
<li>SDL_TTF_MAJOR_VERSION：SDL_ttf 主版本号宏（如 3 代表 SDL_ttf 3.x）</li>
<li>SDL_TTF_VERSION：构造版本结构体的宏</li>
<li>SDL_TTF_VERSION_ATLEAST：编译期检查 SDL_ttf 版本是否满足最低要求</li>
<li>TTF_GetFreeTypeVersion：获取底层 FreeType 库版本</li>
<li>TTF_GetHarfBuzzVersion：获取底层 HarfBuzz 排版库版本</li>
</ul>
<h3>二、字体对象（TTF_Font）管理</h3>
<h4>1. 字体加载/释放</h4>
<ul>
<li>TTF_OpenFont：从文件加载字体文件（指定字号）</li>
<li>TTF_OpenFontIO：从 SDL_IOStream 流加载字体（支持内存字体）</li>
<li>TTF_OpenFontWithProperties：带自定义属性加载字体（如 DPI、字体面索引）</li>
<li>TTF_CloseFont：关闭并释放字体对象</li>
<li>TTF_CopyFont：复制字体对象（继承原字体的样式/属性）</li>
<li>TTF_GetNumFontFaces：获取字体文件中的字体面数量（多字体面文件专用）</li>
</ul>
<h4>2. 字体属性查询</h4>
<ul>
<li>TTF_FontHasGlyph：检查字体是否包含指定 Unicode 字形</li>
<li>TTF_FontIsFixedWidth：检查字体是否为等宽字体（如 Consolas）</li>
<li>TTF_FontIsScalable：检查字体是否为可缩放矢量字体（如 TrueType）</li>
<li>TTF_GetFontAscent：获取字体上行高度（基线到字形顶部的距离）</li>
<li>TTF_GetFontDescent：获取字体下行高度（基线到字形底部的距离）</li>
<li>TTF_GetFontHeight：获取字体总高度（上行+下行）</li>
<li>TTF_GetFontLineSkip：获取字体行间距（两行文本的基线间距）</li>
<li>TTF_GetFontFamilyName：获取字体家族名称（如 &quot;Microsoft YaHei&quot;）</li>
<li>TTF_GetFontStyleName：获取字体样式名称（如 &quot;Bold&quot;）</li>
<li>TTF_GetFontSize：获取字体当前字号</li>
<li>TTF_GetFontWeight：获取字体字重（粗细程度）</li>
<li>TTF_GetFontStyle：获取字体样式标志（粗体/斜体等）</li>
<li>TTF_GetFontDPI：获取字体渲染的 DPI 设置</li>
<li>TTF_GetFontCharSpacing：获取字符间距</li>
<li>TTF_GetFontKerning：获取字距调整开关状态</li>
<li>TTF_GetFontOutline：获取字体描边宽度</li>
<li>TTF_GetFontHinting：获取字体提示模式（影响渲染清晰度）</li>
<li>TTF_GetFontDirection：获取字体默认排版方向</li>
<li>TTF_GetFontWrapAlignment：获取文本换行对齐方式</li>
<li>TTF_GetFontProperties：获取字体完整配置属性</li>
</ul>
<h4>3. 字体属性设置</h4>
<ul>
<li>TTF_SetFontSize：设置字体字号</li>
<li>TTF_SetFontSizeDPI：按 DPI 缩放设置字体字号</li>
<li>TTF_SetFontStyle：设置字体样式（粗体/斜体/下划线等）</li>
<li>TTF_SetFontWeight：设置字体字重（如 TTF_FONT_WEIGHT_BOLD）</li>
<li>TTF_SetFontCharSpacing：设置字符间距</li>
<li>TTF_SetFontKerning：开启/关闭字距调整（优化字符间距）</li>
<li>TTF_SetFontOutline：设置字体描边宽度</li>
<li>TTF_SetFontHinting：设置字体提示模式（如 TTF_HINTING_NORMAL）</li>
<li>TTF_SetFontDirection：设置字体排版方向（LTR/RTL 等）</li>
<li>TTF_SetFontLanguage：设置字体关联的语言</li>
<li>TTF_SetFontScript：设置字体关联的文字脚本（如中文/英文）</li>
<li>TTF_SetFontLineSkip：自定义字体行间距</li>
<li>TTF_SetFontWrapAlignment：设置文本换行对齐方式</li>
<li>TTF_SetFontSDF：开启/关闭 SDF（有符号距离场）渲染（适合缩放）</li>
</ul>
<h4>4. 字体回退（Fallback）</h4>
<ul>
<li>TTF_AddFallbackFont：添加回退字体（主字体无字形时使用）</li>
<li>TTF_RemoveFallbackFont：移除指定回退字体</li>
<li>TTF_ClearFallbackFonts：清空所有回退字体</li>
</ul>
<h3>三、字形（Glyph）操作</h3>
<ul>
<li>TTF_GetGlyphMetrics：获取指定字形的度量信息（宽度、偏移等）</li>
<li>TTF_GetGlyphKerning：获取两个字形间的字距调整值</li>
<li>TTF_GetGlyphImage：获取指定字形的渲染图像</li>
<li>TTF_GetGlyphImageForIndex：按字形索引获取渲染图像</li>
<li>TTF_GetGlyphScript：获取字形所属的文字脚本</li>
<li>TTF_RenderGlyph_Solid：渲染单个字形为纯色 Surface</li>
<li>TTF_RenderGlyph_Shaded：渲染单个字形为带阴影的 Surface</li>
<li>TTF_RenderGlyph_Blended：渲染单个字形为带alpha混合的 Surface</li>
<li>TTF_RenderGlyph_LCD：渲染单个字形为 LCD 优化的 Surface</li>
</ul>
<h3>四、文本渲染（基础接口）</h3>
<ul>
<li>TTF_RenderText_Solid：渲染文本为纯色 Surface（高性能，无抗锯齿）</li>
<li>TTF_RenderText_Shaded：渲染文本为带阴影的 Surface（有抗锯齿）</li>
<li>TTF_RenderText_Blended：渲染文本为 alpha 混合 Surface（高质量抗锯齿）</li>
<li>TTF_RenderText_LCD：渲染文本为 LCD 优化 Surface（高清显示）</li>
<li>TTF_RenderText_Solid_Wrapped：渲染自动换行的纯色文本</li>
<li>TTF_RenderText_Shaded_Wrapped：渲染自动换行的带阴影文本</li>
<li>TTF_RenderText_Blended_Wrapped：渲染自动换行的 alpha 混合文本</li>
<li>TTF_RenderText_LCD_Wrapped：渲染自动换行的 LCD 优化文本</li>
<li>TTF_MeasureString：测量文本渲染后的尺寸（不实际渲染）</li>
<li>TTF_GetStringSize：获取文本的宽高尺寸</li>
<li>TTF_GetStringSizeWrapped：获取自动换行文本的宽高尺寸</li>
</ul>
<h3>五、文本引擎（TextEngine）（高级渲染）</h3>
<h4>1. 引擎创建/销毁</h4>
<ul>
<li>TTF_CreateSurfaceTextEngine：创建基于 Surface 的文本引擎（CPU 渲染）</li>
<li>TTF_CreateRendererTextEngine：创建基于 SDL_Renderer 的文本引擎（2D 硬件加速）</li>
<li>TTF_CreateRendererTextEngineWithProperties：带属性创建 Renderer 文本引擎</li>
<li>TTF_CreateGPUTextEngine：创建基于 GPU 的文本引擎（3D 硬件加速）</li>
<li>TTF_CreateGPUTextEngineWithProperties：带属性创建 GPU 文本引擎</li>
<li>TTF_DestroySurfaceTextEngine：销毁 Surface 文本引擎</li>
<li>TTF_DestroyRendererTextEngine：销毁 Renderer 文本引擎</li>
<li>TTF_DestroyGPUTextEngine：销毁 GPU 文本引擎</li>
</ul>
<h4>2. 文本对象（TTF_Text）管理</h4>
<ul>
<li>TTF_CreateText：创建文本对象（绑定字体和文本内容）</li>
<li>TTF_DestroyText：销毁文本对象</li>
<li>TTF_SetTextString：设置文本对象的内容</li>
<li>TTF_AppendTextString：追加文本到文本对象</li>
<li>TTF_InsertTextString：插入文本到文本对象</li>
<li>TTF_DeleteTextString：删除文本对象的部分内容</li>
<li>TTF_UpdateText：更新文本对象的渲染数据</li>
<li>TTF_SetTextFont：设置文本对象关联的字体</li>
<li>TTF_SetTextColor：设置文本颜色（8位通道）</li>
<li>TTF_SetTextColorFloat：设置文本颜色（浮点通道，0.0-1.0）</li>
<li>TTF_SetTextDirection：设置文本排版方向</li>
<li>TTF_SetTextScript：设置文本所属的文字脚本</li>
<li>TTF_SetTextPosition：设置文本渲染位置</li>
<li>TTF_SetTextWrapWidth：设置文本自动换行宽度</li>
<li>TTF_SetTextWrapWhitespaceVisible：设置是否显示换行空白符</li>
<li>TTF_SetTextEngine：为文本对象绑定文本引擎</li>
<li>TTF_GetTextFont：获取文本对象关联的字体</li>
<li>TTF_GetTextColor：获取文本颜色（8位通道）</li>
<li>TTF_GetTextColorFloat：获取文本颜色（浮点通道）</li>
<li>TTF_GetTextDirection：获取文本排版方向</li>
<li>TTF_GetTextScript：获取文本所属的文字脚本</li>
<li>TTF_GetTextPosition：获取文本渲染位置</li>
<li>TTF_GetTextSize：获取文本渲染后的尺寸</li>
<li>TTF_GetTextWrapWidth：获取文本自动换行宽度</li>
<li>TTF_GetTextEngine：获取文本对象绑定的引擎</li>
</ul>
<h4>3. 高级文本渲染</h4>
<ul>
<li>TTF_DrawSurfaceText：使用 Surface 引擎渲染文本</li>
<li>TTF_DrawRendererText：使用 Renderer 引擎渲染文本</li>
<li>TTF_GetGPUTextDrawData：获取 GPU 文本渲染的绘制数据</li>
<li>TTF_SetGPUTextEngineWinding：设置 GPU 文本引擎的顶点缠绕方向</li>
<li>TTF_GetGPUTextEngineWinding：获取 GPU 文本引擎的顶点缠绕方向</li>
</ul>
<h3>六、文本子串/排版控制</h3>
<ul>
<li>TTF_GetTextSubString：获取文本指定范围的子串</li>
<li>TTF_GetTextSubStringForLine：获取文本指定行的子串</li>
<li>TTF_GetTextSubStringForPoint：获取指定坐标对应的文本子串</li>
<li>TTF_GetTextSubStringsForRange：获取指定范围的所有子串</li>
<li>TTF_GetNextTextSubString：获取下一个文本子串</li>
<li>TTF_GetPreviousTextSubString：获取上一个文本子串</li>
</ul>
<h3>七、常量与枚举</h3>
<h4>1. 字体样式</h4>
<ul>
<li>TTF_STYLE_NORMAL：正常样式</li>
<li>TTF_STYLE_BOLD：粗体</li>
<li>TTF_STYLE_ITALIC：斜体</li>
<li>TTF_STYLE_UNDERLINE：下划线</li>
<li>TTF_STYLE_STRIKETHROUGH：删除线</li>
</ul>
<h4>2. 字体字重</h4>
<ul>
<li>TTF_FONT_WEIGHT_THIN：极细</li>
<li>TTF_FONT_WEIGHT_LIGHT：细体</li>
<li>TTF_FONT_WEIGHT_NORMAL：常规</li>
<li>TTF_FONT_WEIGHT_MEDIUM：中等</li>
<li>TTF_FONT_WEIGHT_BOLD：粗体</li>
<li>TTF_FONT_WEIGHT_BLACK：黑体</li>
</ul>
<h4>3. 文本方向</h4>
<ul>
<li>TTF_DIRECTION_LTR：从左到右（如英文）</li>
<li>TTF_DIRECTION_RTL：从右到左（如阿拉伯语）</li>
<li>TTF_DIRECTION_TTB：从上到下（如竖排中文）</li>
<li>TTF_DIRECTION_BTT：从下到上</li>
<li>TTF_DIRECTION_INVALID：无效方向</li>
</ul>
<h4>4. 字体提示模式</h4>
<ul>
<li>TTF_HINTING_NONE：无提示（模糊）</li>
<li>TTF_HINTING_LIGHT：轻量提示</li>
<li>TTF_HINTING_NORMAL：常规提示</li>
<li>TTF_HINTING_MONO：单色提示（等宽字体优化）</li>
</ul>
<h4>5. 对齐方式</h4>
<ul>
<li>TTF_HORIZONTAL_ALIGN_LEFT：左对齐</li>
<li>TTF_HORIZONTAL_ALIGN_CENTER：居中</li>
<li>TTF_HORIZONTAL_ALIGN_RIGHT：右对齐</li>
</ul>
<h4>6. 图像类型</h4>
<ul>
<li>TTF_IMAGE_SOLID：纯色图像</li>
<li>TTF_IMAGE_SHADED：带阴影图像</li>
<li>TTF_IMAGE_BLENDED：alpha 混合图像</li>
<li>TTF_IMAGE_SDF：SDF 图像</li>
</ul>
<h4>7. 属性常量（PROP）</h4>
<ul>
<li>TTF_PROP_FONT_CREATE_SIZE_FLOAT：字体创建时的字号属性</li>
<li>TTF_PROP_FONT_CREATE_DPI_NUMBER：字体创建时的 DPI 属性</li>
<li>TTF_PROP_RENDERER_TEXT_ENGINE_ATLAS_SIZE：渲染引擎纹理图集尺寸</li>
<li>TTF_PROP_GPU_TEXT_ENGINE_DEVICE：GPU 引擎的设备指针属性</li>
</ul>
<h3>八、工具函数</h3>
<ul>
<li>TTF_StringToTag：将字符串转换为 OpenType 标签</li>
<li>TTF_TagToString：将 OpenType 标签转换为字符串</li>
<li>UNICODE_BOM_NATIVE：本地字节序的 Unicode BOM 常量</li>
</ul>
<!-- 结束类别列表 -->
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 及 SDL_ttf 相关声明（需链接 SDL3 和 SDL3_ttf 库）
#Include "SDL.bi"
#Include "SDL_ttf.bi"

' 补充关键类型/宏声明（FreeBASIC 绑定可能缺失）
#Define TTF_STYLE_BOLD 1
#Define TTF_STYLE_ITALIC 2
#Define TTF_HINTING_NORMAL 2

' 检查 SDL_ttf 版本
Sub CheckTTFVersion()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【检查 SDL_ttf 版本】")

    Dim As SDL_version ver
    TTF_Version(@ver)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SDL_ttf 版本：%d.%d.%d", ver.major, ver.minor, ver.patch)

    ' 编译期版本检查
    #If SDL_TTF_VERSION_ATLEAST(3, 0, 0)
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ 满足 SDL_ttf 3.0.0 最低版本要求")
    #Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ 不满足 SDL_ttf 3.0.0 最低版本要求")
    #EndIf

    ' 打印 FreeType 和 HarfBuzz 版本
    Dim As SDL_version ftVer, hbVer
    TTF_GetFreeTypeVersion(@ftVer)
    TTF_GetHarfBuzzVersion(@hbVer)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "FreeType 版本：%d.%d.%d", ftVer.major, ftVer.minor, ftVer.patch)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "HarfBuzz 版本：%d.%d.%d", hbVer.major, hbVer.minor, hbVer.patch)
End Sub

' 基础文本渲染示例（Surface 模式）
Sub BasicTextRenderExample(ByVal fontPath As ZString Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【基础文本渲染示例】")

    ' 1. 加载字体（字号 24）
    Dim As TTF_Font Ptr font = TTF_OpenFont(fontPath, 24)
    If (font = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "加载字体失败：%s", TTF_GetError())
        Exit Sub
    End If

    ' 2. 设置字体样式（粗体+斜体）
    TTF_SetFontStyle(font, TTF_STYLE_BOLD Or TTF_STYLE_ITALIC)
    TTF_SetFontHinting(font, TTF_HINTING_NORMAL)  ' 开启常规提示

    ' 3. 查询字体属性
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "字体家族：%s", TTF_GetFontFamilyName(font))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "字体高度：%d 像素", TTF_GetFontHeight(font))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "行间距：%d 像素", TTF_GetFontLineSkip(font))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "是否等宽：%s", IIf(TTF_FontIsFixedWidth(font), "是", "否"))

    ' 4. 检查是否包含中文字形
    Dim As Uint32 chineseChar = &amp;H4E2D  ' "中" 字的 Unicode 编码
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "是否包含 '中' 字形：%s", _
        IIf(TTF_FontHasGlyph(font, chineseChar), "是", "否"))

    ' 5. 渲染文本（Blended 模式，高质量抗锯齿）
    Dim As SDL_Color textColor = {255, 255, 255, 255}  ' 白色
    Dim As SDL_Surface Ptr textSurface = TTF_RenderText_Blended(font, "SDL_ttf 文本渲染示例", textColor)
    If (textSurface = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "渲染文本失败：%s", TTF_GetError())
        TTF_CloseFont(font)
        Exit Sub
    End If

    ' 6. 打印文本尺寸
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "文本尺寸：%dx%d 像素", textSurface-&gt;w, textSurface-&gt;h)

    ' 7. 保存渲染结果为 PNG（需链接 SDL_image）
    #If defined(SDL_IMAGE)
        If (IMG_SavePNG(textSurface, "text_render.png") = SDL_TRUE) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "渲染结果已保存为 text_render.png")
        End If
    #EndIf

    ' 8. 释放资源
    SDL_DestroySurface(textSurface)
    TTF_CloseFont(font)
End Sub

' 高级文本引擎示例（Renderer 模式）
Sub AdvancedTextEngineExample(ByVal fontPath As ZString Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【高级文本引擎示例】")

    ' 1. 创建窗口和渲染器
    Dim As SDL_Window Ptr window = SDL_CreateWindow( _
        "SDL_ttf 高级渲染示例", _
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
        800, 600, _
        SDL_WINDOW_SHOWN _
    )
    If (window = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败：%s", SDL_GetError())
        Exit Sub
    End If

    Dim As SDL_Renderer Ptr renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED Or SDL_RENDERER_PRESENTVSYNC)
    If (renderer = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建渲染器失败：%s", SDL_GetError())
        SDL_DestroyWindow(window)
        Exit Sub
    End If

    ' 2. 创建 Renderer 文本引擎
    Dim As TTF_TextEngine Ptr textEngine = TTF_CreateRendererTextEngine(renderer)
    If (textEngine = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建文本引擎失败：%s", TTF_GetError())
        SDL_DestroyRenderer(renderer)
        SDL_DestroyWindow(window)
        Exit Sub
    End If

    ' 3. 加载字体并创建文本对象
    Dim As TTF_Font Ptr font = TTF_OpenFont(fontPath, 32)
    If (font = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "加载字体失败：%s", TTF_GetError())
        TTF_DestroyRendererTextEngine(textEngine)
        SDL_DestroyRenderer(renderer)
        SDL_DestroyWindow(window)
        Exit Sub
    End If

    Dim As TTF_Text Ptr textObj = TTF_CreateText(font, "SDL_ttf 高级文本引擎示例")
    If (textObj = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建文本对象失败：%s", TTF_GetError())
        TTF_CloseFont(font)
        TTF_DestroyRendererTextEngine(textEngine)
        SDL_DestroyRenderer(renderer)
        SDL_DestroyWindow(window)
        Exit Sub
    End If

    ' 4. 设置文本属性
    TTF_SetTextColor(textObj, (SDL_Color){0, 255, 255, 255})  ' 青色
    TTF_SetTextPosition(textObj, 50, 50)  ' 渲染位置 (50,50)
    TTF_SetTextEngine(textObj, textEngine)  ' 绑定文本引擎

    ' 5. 渲染循环
    Dim As SDL_bool running = SDL_TRUE
    Dim As SDL_Event evt
    While (running)
        ' 事件处理
        While (SDL_PollEvent(@evt))
            If (evt.type = SDL_QUIT) Then
                running = SDL_FALSE
            End If
        Wend

        ' 清屏（黑色背景）
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
        SDL_RenderClear(renderer)

        ' 渲染文本
        TTF_DrawRendererText(textObj)

        ' 刷新屏幕
        SDL_RenderPresent(renderer)
    Wend

    ' 6. 释放资源
    TTF_DestroyText(textObj)
    TTF_CloseFont(font)
    TTF_DestroyRendererTextEngine(textEngine)
    SDL_DestroyRenderer(renderer)
    SDL_DestroyWindow(window)
End Sub

' 主程序
Sub Main()
    ' 初始化 SDL 视频子系统
    If (SDL_Init(SDL_INIT_VIDEO) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 初始化 SDL_ttf
    If (TTF_Init() = -1) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_ttf 初始化失败：%s", TTF_GetError())
        SDL_Quit()
        Exit Sub
    End If

    ' 字体文件路径（替换为实际的字体文件，如 simsun.ttf、arial.ttf）
    Dim As ZString Ptr fontPath = StrPtr("simsun.ttf")

    ' 运行示例
    CheckTTFVersion()
    BasicTextRenderExample(fontPath)
    AdvancedTextEngineExample(fontPath)

    ' 清理资源
    TTF_Quit()
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>SDL_ttf 初始化关键</strong>：</p>
<ul>
<li>必须先调用 <code>SDL_Init(SDL_INIT_VIDEO)</code> 初始化视频子系统，再调用 <code>TTF_Init()</code>；</li>
<li><code>TTF_Init()</code> 内部会加载 FreeType（字体渲染）和 HarfBuzz（文本排版），需确保链接这两个库；</li>
<li>程序退出前必须调用 <code>TTF_Quit()</code>，否则会导致内存泄漏。</li>
</ul>
</li>
<li>
<p><strong>字体加载与管理</strong>：</p>
<ul>
<li>支持 TrueType (.ttf)、OpenType (.otf)、WOFF 等主流字体格式；</li>
<li><code>TTF_OpenFontIO</code> 支持从内存流加载字体（适合嵌入资源的游戏/应用）；</li>
<li>多语言文本需使用回退字体（<code>TTF_AddFallbackFont</code>），避免部分字形缺失；</li>
<li>字体对象使用后必须调用 <code>TTF_CloseFont</code> 释放，否则会泄漏资源。</li>
</ul>
</li>
<li>
<p><strong>文本渲染模式选择</strong>：</p>
<ul>
<li><strong>Solid 模式</strong>：高性能、无抗锯齿，适合实时更新的文本（如游戏分数）；</li>
<li><strong>Shaded 模式</strong>：带阴影、有抗锯齿，性能中等，适合静态文本；</li>
<li><strong>Blended 模式</strong>：Alpha 混合、高质量抗锯齿，性能较低，适合UI文本；</li>
<li><strong>LCD 模式</strong>：针对 LCD 屏幕优化，清晰度最高，仅支持部分字体；</li>
<li><strong>文本引擎模式</strong>：硬件加速渲染，适合大量/动态文本（如编辑器、聊天框）。</li>
</ul>
</li>
<li>
<p><strong>多语言排版要点</strong>：</p>
<ul>
<li>支持 RTL（从右到左）、TTB（竖排）等排版方向，适配阿拉伯语、日语等；</li>
<li>中文/日文/韩文等CJK文字需使用支持对应字形的字体；</li>
<li><code>TTF_SetFontScript</code> 可指定文字脚本，优化排版规则。</li>
</ul>
</li>
<li>
<p><strong>跨平台注意事项</strong>：</p>
<ul>
<li>Windows 系统可直接使用系统字体（如 simsun.ttf、microsoftyahei.ttf）；</li>
<li>Linux 系统需确保安装字体文件，或打包字体到应用目录；</li>
<li>macOS 系统字体路径为 <code>/System/Library/Fonts/</code>，如 Arial.ttf；</li>
<li>移动平台需将字体文件放入 assets 目录，使用绝对路径加载。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>无缝衔接 SDL 核心库，渲染的文本可直接用于 SDL 窗口/纹理；</li>
<li>支持多渲染模式（CPU/Surface、2D Renderer、3D GPU），兼顾性能与质量；</li>
<li>完整的字体属性控制（样式、字重、间距、描边等），满足各类UI需求；</li>
<li>支持多语言排版（RTL/TTB、CJK字形、回退字体），适配全球市场；</li>
<li>基于成熟的 FreeType/HarfBuzz 库，渲染质量有保障。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>静态文本优先使用 Blended 模式，动态文本优先使用 Solid 模式；</li>
<li>大量文本渲染优先使用文本引擎（TextEngine），利用硬件加速；</li>
<li>多语言应用务必添加回退字体，避免字形缺失；</li>
<li>高清显示场景使用 LCD 模式或 SDF 渲染，提升文字清晰度；</li>
<li>字体文件建议打包到应用目录，避免依赖系统字体。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>SDL_ttf 是 SDL 的字体渲染扩展库，核心依赖 FreeType 和 HarfBuzz；</li>
<li><code>TTF_Init()</code>/<code>TTF_Quit()</code> 是必选的初始化/清理接口；</li>
<li><code>TTF_Font</code> 是字体对象核心，支持样式、字重、间距等属性配置；</li>
<li>文本渲染分基础模式（Solid/Shaded/Blended）和高级引擎模式（Surface/Renderer/GPU）；</li>
<li>多语言排版需关注文本方向（LTR/RTL）、回退字体和字形检查。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 12:00:35 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-331.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_SDL_image 核心 API 集合（CategoryAPI）</title>
    <link>http://bbs.yfvb.com/post-330.html</link>
    <description><![CDATA[<h1>SDL_image 核心 API 集合（CategoryAPI）</h1>
<p>SDL_image 是 SDL 的官方图像扩展库，该分类汇总了 SDL_image 所有核心 API，涵盖静态图像加载/保存、动画解码/编码、格式检测、GPU 纹理加载等全量功能，是 SDL 生态中处理图像的核心接口集合。</p>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>核心 API 列表（按功能分类）</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表 -->
<h3>一、动画编解码核心接口</h3>
<h4>1. 动画解码器（AnimationDecoder）</h4>
<ul>
<li>IMG_CreateAnimationDecoder：创建动画解码器实例（通用接口）</li>
<li>IMG_CreateAnimationDecoder_IO：从 SDL_IOStream 流创建动画解码器</li>
<li>IMG_CreateAnimationDecoderWithProperties：带自定义属性创建动画解码器（如 GIF 颜色数、AVIF 线程数）</li>
<li>IMG_CloseAnimationDecoder：关闭并释放动画解码器资源</li>
<li>IMG_GetAnimationDecoderFrame：获取解码器指定索引的帧数据</li>
<li>IMG_GetNextAnimationDecoderFrame：获取解码器下一帧数据（逐帧播放）</li>
<li>IMG_GetAnimationDecoderMetadata：获取动画元数据（帧数、循环次数等）</li>
<li>IMG_GetAnimationDecoderPresentationTimestampMS：获取帧的展示时间戳（毫秒）</li>
<li>IMG_GetAnimationDecoderProperties：获取解码器的配置属性</li>
<li>IMG_GetAnimationDecoderStatus：获取解码器当前状态（成功/失败/完成等）</li>
<li>IMG_ResetAnimationDecoder：重置动画解码器到初始状态</li>
</ul>
<h4>2. 动画编码器（AnimationEncoder）</h4>
<ul>
<li>IMG_CreateAnimationEncoder：创建动画编码器实例（通用接口）</li>
<li>IMG_CreateAnimationEncoder_IO：从 SDL_IOStream 流创建动画编码器</li>
<li>IMG_CreateAnimationEncoderWithProperties：带自定义属性创建动画编码器（如质量、关键帧间隔）</li>
<li>IMG_CloseAnimationEncoder：关闭并释放动画编码器资源</li>
<li>IMG_AddAnimationEncoderFrame：向编码器添加单帧数据（用于生成动画）</li>
</ul>
<h4>3. 动画流（AnimationStream）</h4>
<ul>
<li>IMG_CreateAnimationStream：创建动画流实例（实时编解码）</li>
<li>IMG_CreateAnimationStream_IO：从 SDL_IOStream 流创建动画流</li>
<li>IMG_CreateAnimationStreamWithProperties：带自定义属性创建动画流</li>
<li>IMG_CloseAnimationStream：关闭并释放动画流资源</li>
</ul>
<h4>4. 动画数据结构与工具</h4>
<ul>
<li>IMG_Animation：动画数据结构体（包含所有帧、时长、循环等信息）</li>
<li>IMG_LoadAnimation：从文件加载完整动画数据（如 GIF/APNG/WEBP）</li>
<li>IMG_LoadAnimation_IO：从 SDL_IOStream 流加载动画</li>
<li>IMG_LoadAnimationTyped_IO：指定格式从流加载动画（避免自动检测）</li>
<li>IMG_FreeAnimation：释放 IMG_Animation 结构体资源</li>
<li>IMG_SaveAnimation：将动画数据保存为文件</li>
<li>IMG_SaveAnimationTyped_IO：指定格式将动画保存到 SDL_IOStream 流</li>
</ul>
<h4>5. 动画解码器状态枚举</h4>
<ul>
<li>IMG_DECODER_STATUS_OK：解码器状态正常（可继续解码）</li>
<li>IMG_DECODER_STATUS_COMPLETE：解码完成（所有帧已处理）</li>
<li>IMG_DECODER_STATUS_FAILED：解码失败（数据错误/格式不支持）</li>
<li>IMG_DECODER_STATUS_INVALID：解码器实例无效（未初始化/已释放）</li>
</ul>
<h3>二、静态图像加载/保存</h3>
<h4>1. 通用加载接口</h4>
<ul>
<li>IMG_Load：从文件加载图像为 SDL_Surface（自动检测格式）</li>
<li>IMG_Load_IO：从 SDL_IOStream 流加载图像为 SDL_Surface</li>
<li>IMG_LoadTyped_IO：指定格式从流加载图像（如强制按 PNG 解析）</li>
<li>IMG_LoadTexture：从文件加载图像为 SDL_Texture（GPU 纹理，需 SDL_Renderer）</li>
<li>IMG_LoadTexture_IO：从流加载图像为 SDL_Texture</li>
<li>IMG_LoadTextureTyped_IO：指定格式从流加载为 SDL_Texture</li>
<li>IMG_LoadGPUTexture：加载图像为 GPU 原生纹理（如 Vulkan/D3D 纹理）</li>
<li>IMG_LoadGPUTexture_IO：从流加载为 GPU 原生纹理</li>
</ul>
<h4>2. 格式专属加载接口</h4>
<ul>
<li>IMG_LoadBMP_IO/IMG_LoadPNG_IO/IMG_LoadJPG_IO：BMP/PNG/JPG 格式专属加载</li>
<li>IMG_LoadGIF_IO/IMG_LoadWEBP_IO/IMG_LoadAVIF_IO：GIF/WEBP/AVIF 格式专属加载</li>
<li>IMG_LoadICO_IO/IMG_LoadCUR_IO：图标/光标格式加载</li>
<li>IMG_LoadSVG_IO/IMG_LoadSizedSVG_IO：SVG 矢量图加载（支持指定尺寸）</li>
<li>IMG_LoadXPM_IO/IMG_ReadXPMFromArray：XPM 格式加载（支持内存数组）</li>
<li>IMG_LoadANIAnimation_IO/IMG_LoadGIFAnimation_IO：ANI/GIF 动画专属加载</li>
<li>IMG_LoadAPNGAnimation_IO/IMG_LoadWEBPAnimation_IO：APNG/WEBP 动画专属加载</li>
</ul>
<h4>3. 图像保存接口</h4>
<ul>
<li>IMG_Save：将 SDL_Surface 保存为图像文件（自动检测格式）</li>
<li>IMG_SaveTyped_IO：指定格式将图像保存到 SDL_IOStream 流</li>
<li>IMG_SaveBMP/IMG_SavePNG/IMG_SaveJPG：BMP/PNG/JPG 格式专属保存</li>
<li>IMG_SaveGIF/IMG_SaveWEBP/IMG_SaveAVIF：GIF/WEBP/AVIF 格式专属保存</li>
<li>IMG_SaveICO/IMG_SaveCUR：图标/光标格式保存</li>
<li>IMG_SaveANIAnimation_IO/IMG_SaveGIFAnimation_IO：ANI/GIF 动画专属保存</li>
<li>IMG_SaveAPNGAnimation_IO/IMG_SaveWEBPAnimation_IO：APNG/WEBP 动画专属保存</li>
</ul>
<h3>三、格式检测接口</h3>
<ul>
<li>IMG_isBMP/IMG_isPNG/IMG_isJPG：检测数据是否为 BMP/PNG/JPG 格式</li>
<li>IMG_isGIF/IMG_isAVIF/IMG_isWEBP：检测数据是否为 GIF/AVIF/WEBP 格式</li>
<li>IMG_isICO/IMG_isCUR/IMG_isANI：检测数据是否为 ICO/CUR/ANI 格式</li>
<li>IMG_isSVG/IMG_isTIF/IMG_isXPM：检测数据是否为 SVG/TIF/XPM 格式</li>
<li>IMG_isLBM/IMG_isPCX/IMG_isPNM：检测数据是否为 LBM/PCX/PNM 格式</li>
<li>IMG_isQOI/IMG_isXCF/IMG_isXV：检测数据是否为 QOI/XCF/XV 格式</li>
<li>IMG_isJXL：检测数据是否为 JXL（JPEG XL）格式</li>
</ul>
<h3>四、特殊功能接口</h3>
<ul>
<li>IMG_CreateAnimatedCursor：从动画数据创建系统动画光标</li>
<li>IMG_GetClipboardImage：获取剪贴板中的图像数据（SDL_Surface）</li>
<li>IMG_ReadXPMFromArrayToRGB888：从 XPM 数组加载为 RGB888 格式图像</li>
</ul>
<h3>五、属性常量（编解码配置）</h3>
<h4>1. 解码器属性</h4>
<ul>
<li>IMG_PROP_ANIMATION_DECODER_CREATE_FILENAME_STRING：解码器关联的文件名属性</li>
<li>IMG_PROP_ANIMATION_DECODER_CREATE_TYPE_STRING：解码器目标格式（如 &quot;gif&quot;/&quot;avif&quot;）</li>
<li>IMG_PROP_ANIMATION_DECODER_CREATE_GIF_NUM_COLORS_NUMBER：GIF 解码颜色数限制</li>
<li>IMG_PROP_ANIMATION_DECODER_CREATE_AVIF_MAX_THREADS_NUMBER：AVIF 解码最大线程数</li>
<li>IMG_PROP_ANIMATION_DECODER_METADATA_FRAME_COUNT_NUMBER：动画帧数元数据</li>
<li>IMG_PROP_ANIMATION_DECODER_METADATA_LOOP_COUNT_NUMBER：动画循环次数元数据</li>
</ul>
<h4>2. 编码器属性</h4>
<ul>
<li>IMG_PROP_ANIMATION_ENCODER_CREATE_QUALITY_NUMBER：编码质量（0-100）</li>
<li>IMG_PROP_ANIMATION_ENCODER_CREATE_TYPE_STRING：编码器目标格式</li>
<li>IMG_PROP_ANIMATION_ENCODER_CREATE_AVIF_KEYFRAME_INTERVAL_NUMBER：AVIF 关键帧间隔</li>
<li>IMG_PROP_ANIMATION_ENCODER_CREATE_GIF_USE_LUT_BOOLEAN：GIF 编码是否使用颜色查找表</li>
</ul>
<h4>3. 通用属性</h4>
<ul>
<li>IMG_PROP_METADATA_AUTHOR_STRING：图像作者元数据</li>
<li>IMG_PROP_METADATA_COPYRIGHT_STRING：图像版权元数据</li>
<li>IMG_PROP_METADATA_TITLE_STRING：图像标题元数据</li>
<li>IMG_PROP_ANIMATION_STREAM_CREATE_QUALITY_NUMBER：动画流编码质量</li>
</ul>
<h3>六、版本相关宏/函数</h3>
<ul>
<li>IMG_Version：获取当前 SDL_image 库的版本信息</li>
<li>SDL_IMAGE_MAJOR_VERSION：SDL_image 主版本号宏（如 3 代表 SDL_image 3.x）</li>
<li>SDL_IMAGE_VERSION：构造版本结构体的宏</li>
<li>SDL_IMAGE_VERSION_ATLEAST：编译期检查 SDL_image 版本是否满足最低要求</li>
</ul>
<!-- 结束类别列表 -->
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 及 SDL_image 相关声明（需链接 SDL3 和 SDL3_image 库）
#Include "SDL.bi"
#Include "SDL_image.bi"

' 补充关键类型/宏声明（FreeBASIC 绑定可能缺失）
Type IMG_Animation  ' 简化版动画结构体（完整定义需参考 SDL_image 源码）
    frames As SDL_Surface Ptr Ptr  ' 帧数据数组
    delays As Integer Ptr          ' 每帧延迟（毫秒）
    count As Integer               ' 总帧数
    loops As Integer               ' 循环次数（0=无限）
End Type

Declare Function IMG_LoadAnimation CDecl (ByVal file As ZString Ptr) As IMG_Animation Ptr
Declare Sub IMG_FreeAnimation CDecl (ByVal anim As IMG_Animation Ptr)
Declare Function IMG_isGIF CDecl (ByVal src As Const Any Ptr, ByVal len As Size_t) As SDL_bool
Declare Function IMG_SavePNG CDecl (ByVal surface As SDL_Surface Ptr, ByVal file As ZString Ptr) As SDL_bool

' 检查 SDL_image 版本
Sub CheckImageVersion()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【检查 SDL_image 版本】")

    Dim As SDL_version ver
    IMG_Version(@ver)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SDL_image 版本：%d.%d.%d", ver.major, ver.minor, ver.patch)

    ' 编译期版本检查示例
    #If SDL_IMAGE_VERSION_ATLEAST(3, 0, 0)
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ 满足 SDL_image 3.0.0 最低版本要求")
    #Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ 不满足 SDL_image 3.0.0 最低版本要求")
    #EndIf
End Sub

' 加载并显示静态图像（PNG/JPG）
Sub LoadStaticImageExample(ByVal filename As ZString Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【加载静态图像：%s】", filename)

    ' 加载图像为 SDL_Surface
    Dim As SDL_Surface Ptr surface = IMG_Load(filename)
    If (surface = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "加载失败：%s", SDL_GetError())
        Exit Sub
    End If

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "图像信息：%dx%d 像素，%d 位深", _
        surface-&gt;w, surface-&gt;h, surface-&gt;format-&gt;BitsPerPixel)

    ' 保存为 PNG 格式（格式转换示例）
    Dim As ZString * 256 savePath
    SDL_snprintf(@savePath, sizeof(savePath), "saved_%s.png", SDL_GetBasename(filename))
    If (IMG_SavePNG(surface, @savePath) = SDL_TRUE) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "已保存为：%s", savePath)
    End If

    ' 释放资源
    SDL_DestroySurface(surface)
End Sub

' 加载并解析 GIF 动画
Sub LoadGifAnimationExample(ByVal filename As ZString Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【加载 GIF 动画：%s】", filename)

    ' 1. 检测文件是否为 GIF 格式
    Dim As SDL_RWops Ptr rw = SDL_RWFromFile(filename, "rb")
    If (rw = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "打开文件失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 读取文件头用于格式检测
    Dim As UByte header(0 To 3)
    SDL_RWread(rw, @header(0), 1, 4)
    SDL_RWseek(rw, 0, RW_SEEK_SET)  ' 重置文件指针

    If (IMG_isGIF(@header(0), 4) = SDL_TRUE) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ 检测为 GIF 格式文件")
    Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ 非 GIF 格式文件")
        SDL_RWclose(rw)
        Exit Sub
    End If
    SDL_RWclose(rw)

    ' 2. 加载 GIF 动画数据
    Dim As IMG_Animation Ptr anim = IMG_LoadAnimation(filename)
    If (anim = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "加载动画失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 3. 解析动画信息
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "动画总帧数：%d", anim-&gt;count)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "循环次数：%s", IIf(anim-&gt;loops=0, "无限", Str(anim-&gt;loops)))

    ' 打印每帧延迟
    For i As Integer = 0 To anim-&gt;count - 1
        If (anim-&gt;frames[i] &lt;&gt; NULL) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "帧 %d：%dx%d 像素，延迟 %d 毫秒", _
                i, anim-&gt;frames[i]-&gt;w, anim-&gt;frames[i]-&gt;h, anim-&gt;delays[i])
        End If
    Next

    ' 4. 释放动画资源
    IMG_FreeAnimation(anim)
End Sub

' 主程序
Sub Main()
    ' 初始化 SDL 视频子系统（加载图像需要）
    If (SDL_Init(SDL_INIT_VIDEO) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 初始化 SDL_image（加载所有支持的格式）
    Dim As Integer flags = IMG_INIT_PNG Or IMG_INIT_JPG Or IMG_INIT_GIF Or IMG_INIT_WEBP
    If (IMG_Init(flags) &lt;&gt; flags) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_image 初始化失败：%s", IMG_GetError())
        SDL_Quit()
        Exit Sub
    End If

    ' 运行示例
    CheckImageVersion()
    LoadStaticImageExample(StrPtr("test.png"))  ' 替换为实际的图像文件路径
    LoadGifAnimationExample(StrPtr("test.gif")) ' 替换为实际的 GIF 文件路径

    ' 清理资源
    IMG_Quit()
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>SDL_image 初始化与清理</strong>：</p>
<ul>
<li>必须调用 <code>IMG_Init()</code> 初始化并指定支持的格式（如 <code>IMG_INIT_PNG</code>/<code>IMG_INIT_GIF</code>），未指定的格式无法加载；</li>
<li>初始化标志需与返回值对比，确认所有格式都成功初始化；</li>
<li>程序退出前必须调用 <code>IMG_Quit()</code> 释放 SDL_image 资源。</li>
</ul>
</li>
<li>
<p><strong>动画处理关键要点</strong>：</p>
<ul>
<li><code>IMG_Animation</code> 是动画的核心数据结构，包含所有帧的 SDL_Surface、每帧延迟、循环次数；</li>
<li>加载 GIF/APNG 等动画时，优先使用 <code>IMG_LoadAnimation</code>，而非普通的 <code>IMG_Load</code>（后者仅加载第一帧）；</li>
<li>动画帧的延迟单位为毫秒，需结合 SDL_Delay() 实现逐帧播放。</li>
</ul>
</li>
<li>
<p><strong>格式检测规则</strong>：</p>
<ul>
<li><code>IMG_isXXX()</code> 函数仅需传入文件头前几个字节（通常 4-8 字节）即可检测格式；</li>
<li>检测前需确保数据指针有效，且长度不小于格式标识的最小长度；</li>
<li>推荐先检测格式再加载，可提前过滤不支持的文件。</li>
</ul>
</li>
<li>
<p><strong>IOStream 接口优势</strong>：</p>
<ul>
<li><code>_IO</code> 后缀的接口支持从内存流/网络流加载图像，无需写入本地文件；</li>
<li>使用 <code>SDL_IOStream</code> 时可通过 <code>IMG_PROP_*_IOSTREAM_AUTOCLOSE</code> 属性控制流的自动关闭；</li>
<li>适合处理加密/压缩的图像数据（先解密/解压到内存流，再加载）。</li>
</ul>
</li>
<li>
<p><strong>跨平台注意事项</strong>：</p>
<ul>
<li>SVG 加载依赖系统的 SVG 解析库（如 librsvg），部分平台需额外链接；</li>
<li>AVIF/WEBP 等现代格式需确保 SDL_image 编译时启用了对应编解码器；</li>
<li>移动平台需注意文件路径格式（如 Android 的 assets 目录需用 <code>SDL_RWFromFile</code> 配合绝对路径）。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>一站式支持数十种图像格式，无需单独集成各格式的编解码库；</li>
<li>无缝衔接 SDL 核心库，加载的图像可直接用于 SDL 渲染/显示；</li>
<li>支持动画编解码、GPU 纹理加载等高级功能，满足游戏/多媒体开发需求；</li>
<li>跨平台接口统一，无需适配不同系统的图像处理逻辑。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>初始化时仅指定实际需要的格式标志（减少库体积和内存占用）；</li>
<li>加载大图像/动画时优先使用 IOStream 接口，避免内存峰值；</li>
<li>动画播放需注意帧延迟的累积，避免播放速度不一致；</li>
<li>保存图像时指定格式专属接口（如 <code>IMG_SavePNG</code>），比通用 <code>IMG_Save</code> 更稳定。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>SDL_image 是 SDL 的图像扩展库，核心功能包括静态图像加载/保存、动画编解码、格式检测；</li>
<li><code>IMG_Init()</code>/<code>IMG_Quit()</code> 是初始化/清理的必选接口，需指定支持的格式标志；</li>
<li><code>IMG_Animation</code> 结构体封装动画全量数据，<code>IMG_LoadAnimation</code> 用于加载GIF/APNG等动画；</li>
<li><code>_IO</code> 后缀接口支持流操作，适合内存/网络图像处理，<code>_Typed_IO</code> 接口可强制指定格式解析。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 11:57:03 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-330.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_其它功能（CategoryMisc）</title>
    <link>http://bbs.yfvb.com/post-329.html</link>
    <description><![CDATA[<h1>其它功能子系统（CategoryMisc）</h1>
<p>SDL 中无法归类到其他特定子系统的零散 API 函数集合，这类函数功能独立且不隶属于某一核心模块，目前仅包含 URL 打开这一通用功能。</p>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>函数</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryMisc, CategoryAPIFunction -->
<ul>
<li>SDL_OpenURL：调用系统默认程序打开指定的 URL（支持 http/https 网页链接、mailto 邮件链接、file 本地文件链接等），跨平台行为一致，无需关心不同系统的 URL 打开方式差异
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>数据类型</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryMisc, CategoryAPIDatatype -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>结构体</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryMisc, CategoryAPIStruct -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>枚举</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryMisc, CategoryAPIEnum -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>宏</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryMisc, CategoryAPIMacro -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 相关声明（需确保 FreeBASIC 已链接 SDL3 库）
#Include "SDL.bi"

' 补充 SDL_OpenURL 函数声明（FreeBASIC 绑定可能缺失）
Declare Function SDL_OpenURL CDecl (ByVal url As ZString Ptr) As SDL_bool

' 辅助函数：封装 URL 打开逻辑并处理错误
Function OpenURLHelper(ByVal url As ZString Ptr, ByVal desc As ZString Ptr) As SDL_bool
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "尝试打开 %s：%s", desc, url)

    ' 调用 SDL_OpenURL 打开 URL
    Dim As SDL_bool result = SDL_OpenURL(url)

    ' 处理返回结果
    If (result = SDL_TRUE) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ %s 打开成功", desc)
        Return SDL_TRUE
    Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ %s 打开失败：%s", desc, SDL_GetError())
        Return SDL_FALSE
    End If
End Function

' ==================== 示例 1：打开网页链接 ====================
Sub OpenWebURLExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【示例 1：打开网页链接】")

    ' 打开 SDL 官方网站
    OpenURLHelper(StrPtr("https://www.libsdl.org/"), StrPtr("SDL 官方网站"))

    ' 打开带参数的网页链接（如搜索页面）
    OpenURLHelper(StrPtr("https://www.google.com/search?q=SDL+OpenURL"), StrPtr("Google 搜索页面"))
End Sub

' ==================== 示例 2：打开邮件链接 ====================
Sub OpenMailURLExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【示例 2：打开邮件链接】")

    ' 打开系统默认邮件客户端，预填收件人、主题、正文
    Dim As ZString * 256 mailURL
    SDL_snprintf( _
        @mailURL, _
        sizeof(mailURL), _
        "mailto:support@example.com?subject=SDL 反馈&amp;body=我在使用 SDL_OpenURL 时遇到了以下问题：" _
    )
    OpenURLHelper(@mailURL, StrPtr("邮件链接"))
End Sub

' ==================== 示例 3：打开本地文件/文件夹 ====================
Sub OpenLocalFileURLExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【示例 3：打开本地文件/文件夹】")

    ' 注意：本地文件需使用 file:// 协议，且路径格式需适配平台
    #If Defined(SDL_PLATFORM_WINDOWS)
        ' Windows 路径示例（需转义反斜杠，或使用正斜杠）
        Dim As ZString Ptr folderURL = StrPtr("file:///C:/Users/Public/Documents")
        OpenURLHelper(folderURL, StrPtr("Windows 公共文档文件夹"))
    #ElseIf Defined(SDL_PLATFORM_LINUX) Or Defined(SDL_PLATFORM_MACOS)
        ' Linux/macOS 路径示例
        Dim As ZString Ptr folderURL = StrPtr("file:///home/user/Documents")
        OpenURLHelper(folderURL, StrPtr("Linux 文档文件夹"))
    #EndIf
End Sub

' ==================== 示例 4：处理无效 URL ====================
Sub OpenInvalidURLExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【示例 4：处理无效 URL】")

    ' 无效的 URL（无协议头）
    OpenURLHelper(StrPtr("www.example.com"), StrPtr("无效 URL（无协议头）"))

    ' 不存在的本地文件
    OpenURLHelper(StrPtr("file:///不存在的文件路径.txt"), StrPtr("不存在的本地文件"))
End Sub

' ==================== 主程序 ====================
Sub Main()
    ' 初始化 SDL（Misc 子系统无需特定初始化，基础初始化即可）
    If (SDL_Init(0) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 运行示例
    OpenWebURLExample()
    OpenMailURLExample()
    OpenLocalFileURLExample()
    OpenInvalidURLExample()

    ' 清理 SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>URL 格式规范</strong>：</p>
<ul>
<li>SDL_OpenURL 支持标准 RFC 3986 格式的 URL，必须包含协议头（如 <code>http://</code>、<code>mailto:</code>、<code>file://</code>），无协议头的字符串会被判定为无效 URL；</li>
<li>特殊字符（如空格、中文、问号）需进行 URL 编码（如空格替换为 <code>%20</code>，中文转换为 UTF-8 编码的十六进制值）；</li>
<li>本地文件路径需使用 <code>file://</code> 协议，Windows 路径需注意斜杠方向（推荐使用正斜杠 <code>/</code>，避免反斜杠 <code>\</code> 的转义问题）。</li>
</ul>
</li>
<li>
<table>
<thead>
<tr>
<th><strong>跨平台实现逻辑</strong>：</th>
<th>平台</th>
<th>底层实现方式</th>
<th>特殊说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Windows</td>
<td>ShellExecuteW 函数</td>
<td>需要 URL 转换为宽字符格式</td>
</tr>
<tr>
<td>macOS</td>
<td>NSWorkspace 的 openURL 方法</td>
<td>需在主线程调用，否则可能无响应</td>
</tr>
<tr>
<td>Linux</td>
<td>xdg-open 命令（桌面环境）</td>
<td>依赖桌面环境的默认程序配置</td>
</tr>
<tr>
<td>Android</td>
<td>Intent.ACTION_VIEW 意图</td>
<td>需申请 INTERNET 权限（网页链接）</td>
</tr>
<tr>
<td>iOS</td>
<td>UIApplication 的 openURL 方法</td>
<td>需配置 ATS 规则（http 链接）</td>
</tr>
</tbody>
</table>
</li>
<li>
<p><strong>错误处理要点</strong>：</p>
<ul>
<li>SDL_OpenURL 返回 SDL_TRUE 仅表示「成功发起打开请求」，不代表 URL 本身有效或程序能正常打开；</li>
<li>返回 SDL_FALSE 时，可通过 <code>SDL_GetError()</code> 获取具体错误信息（如「无效的 URL 格式」「无默认程序关联」）；</li>
<li>本地文件 URL 失败常见原因：文件不存在、权限不足、无默认文件管理器。</li>
</ul>
</li>
<li>
<p><strong>使用限制</strong>：</p>
<ul>
<li>移动平台（Android/iOS）打开 URL 可能触发应用跳转，需处理应用生命周期变化；</li>
<li>macOS/Linux 下打开 URL 可能需要应用有桌面权限（沙箱环境下需配置）；</li>
<li>避免在子线程中频繁调用 SDL_OpenURL，部分平台（如 macOS）要求主线程调用。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>跨平台统一的 URL 打开接口，无需针对不同系统编写原生代码；</li>
<li>自动适配系统默认程序，符合用户使用习惯；</li>
<li>简单的返回值和错误信息，便于错误处理。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>调用前确保 URL 格式正确（含协议头、特殊字符编码）；</li>
<li>对返回结果进行判断，失败时给出用户友好提示；</li>
<li>本地文件 URL 需做平台适配，避免路径格式错误；</li>
<li>移动平台调用后需处理应用切换/返回的逻辑。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>CategoryMisc 是 SDL 的杂项函数集合，目前仅包含 SDL_OpenURL 一个核心函数；</li>
<li>SDL_OpenURL 可打开网页、邮件、本地文件等各类标准 URL，跨平台行为一致；</li>
<li>URL 必须包含协议头，特殊字符需编码，本地文件需使用 file:// 协议；</li>
<li>返回值仅表示请求发起结果，需结合 SDL_GetError() 排查失败原因。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 10:29:23 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-329.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_GUID 处理（CategoryGUID）</title>
    <link>http://bbs.yfvb.com/post-328.html</link>
    <description><![CDATA[<h1>GUID 处理子系统（CategoryGUID）</h1>
<p>GUID（全局唯一标识符）是一个 128 位的数值，用于唯一标识某个对象/实体——其核心特性是「全局唯一性」，可确保在不同系统、不同场景下不会出现重复值。</p>
<p>SDL 为 GUID 提供了核心的序列化/反序列化能力：支持将二进制格式的 GUID 转换为人类可读的字符串格式，也支持将字符串格式的 GUID 解析回二进制结构，方便存储、传输和展示。</p>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>函数</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryGUID, CategoryAPIFunction -->
<ul>
<li>SDL_GUIDToString：将二进制格式的 SDL_GUID 结构体转换为字符串格式（输出如 &quot;12345678-1234-1234-1234-1234567890ab&quot;），参数需指定输出缓冲区大小以避免溢出</li>
<li>SDL_StringToGUID：将字符串格式的 GUID（标准 UUID 格式）解析为二进制的 SDL_GUID 结构体，解析失败时返回全零的 GUID
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>数据类型</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryGUID, CategoryAPIDatatype -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>结构体</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryGUID, CategoryAPIStruct -->
<ul>
<li>SDL_GUID：存储 128 位 GUID 的二进制结构体，内部包含一个 16 字节的数组（对应 128 位），是 SDL 中表示 GUID 的核心数据结构
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>枚举</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryGUID, CategoryAPIEnum -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>宏</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryGUID, CategoryAPIMacro -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 相关声明（需确保 FreeBASIC 已链接 SDL3 库）
#Include "SDL.bi"

' 补充 SDL_GUID 结构体和函数声明（FreeBASIC 绑定可能缺失）
Type SDL_GUID
    data(0 To 15) As Uint8  ' 16字节 = 128位，存储GUID的二进制数据
End Type

' GUID字符串的标准长度：36个可见字符 + 1个终止符 = 37
Const SDL_GUID_STRING_LENGTH = 37

Declare Sub SDL_GUIDToString CDecl ( _
    ByVal guid As SDL_GUID, _
    ByVal str As ZString Ptr, _
    ByVal maxlen As Size_t _
)

Declare Function SDL_StringToGUID CDecl ( _
    ByVal str As ZString Ptr _
) As SDL_GUID

' 辅助函数：打印二进制 GUID 数据
Sub PrintGUIDBinary(ByVal guid As SDL_GUID)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "GUID 二进制数据（16字节）：")
    For i As Integer = 0 To 15
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "  字节 %2d: 0x%02X", i, guid.data(i))
        ' 每4字节换行，方便阅读
        If ((i + 1) Mod 4 = 0) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "")
        End If
    Next
End Sub

' 辅助函数：比较两个 GUID 是否相等
Function GUIDEquals(ByVal a As SDL_GUID, ByVal b As SDL_GUID) As SDL_bool
    For i As Integer = 0 To 15
        If (a.data(i) &lt;&gt; b.data(i)) Then
            Return SDL_FALSE
        End If
    Next
    Return SDL_TRUE
End Function

' ==================== 示例 1：GUID 转字符串 ====================
Sub GUIDToStringExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【示例 1：GUID 转字符串】")

    ' 构造一个测试用的 GUID（二进制数据）
    Dim As SDL_GUID testGUID
    ' 手动填充测试数据（模拟一个真实的 GUID 二进制值）
    testGUID.data(0)  = &amp;H12 : testGUID.data(1)  = &amp;H34 : testGUID.data(2)  = &amp;H56 : testGUID.data(3)  = &amp;H78
    testGUID.data(4)  = &amp;H90 : testGUID.data(5)  = &amp;HAB : testGUID.data(6)  = &amp;HCD : testGUID.data(7)  = &amp;HEF
    testGUID.data(8)  = &amp;H11 : testGUID.data(9)  = &amp;H22 : testGUID.data(10) = &amp;H33 : testGUID.data(11) = &amp;H44
    testGUID.data(12) = &amp;H55 : testGUID.data(13) = &amp;H66 : testGUID.data(14) = &amp;H77 : testGUID.data(15) = &amp;H88

    ' 打印二进制 GUID
    PrintGUIDBinary(testGUID)

    ' 转换为字符串格式
    Dim As ZString * SDL_GUID_STRING_LENGTH guidStr
    SDL_GUIDToString(testGUID, @guidStr, sizeof(guidStr))

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "GUID 转换为字符串：%s", guidStr)
End Sub

' ==================== 示例 2：字符串转 GUID ====================
Sub StringToGUIDExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【示例 2：字符串转 GUID】")

    ' 标准格式的 GUID 字符串（UUID 格式）
    Dim As ZString Ptr guidStr = StrPtr("12345678-90ab-cdef-1122-334455667788")
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "待解析的 GUID 字符串：%s", guidStr)

    ' 将字符串解析为二进制 GUID
    Dim As SDL_GUID parsedGUID = SDL_StringToGUID(guidStr)

    ' 打印解析后的二进制数据
    PrintGUIDBinary(parsedGUID)

    ' 验证解析结果：转换回字符串，检查是否与原字符串一致
    Dim As ZString * SDL_GUID_STRING_LENGTH checkStr
    SDL_GUIDToString(parsedGUID, @checkStr, sizeof(checkStr))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "解析后转回字符串：%s", checkStr)

    If (SDL_strcmp(guidStr, @checkStr) = 0) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "✓ 解析与转换结果一致")
    Else
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "✗ 解析与转换结果不一致")
    End If
End Sub

' ==================== 示例 3：无效 GUID 字符串处理 ====================
Sub InvalidGUIDStringExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【示例 3：无效 GUID 字符串处理】")

    ' 无效的 GUID 字符串（长度不足、格式错误）
    Dim As ZString Ptr invalidStrs(2) = { _
        StrPtr("12345678-90ab-cdef-1122"),  ' 长度不足
        StrPtr("12345678-90ab-cdef-1122-zzzzzzzzzzzz"),  ' 包含非十六进制字符
        StrPtr("无效的GUID字符串")  ' 完全错误格式
    }

    ' 全零 GUID（用于对比解析失败的情况）
    Dim As SDL_GUID zeroGUID
    For i As Integer = 0 To 15
        zeroGUID.data(i) = 0
    Next

    For i As Integer = 0 To 2
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "解析无效字符串：%s", invalidStrs(i))
        Dim As SDL_GUID parsedGUID = SDL_StringToGUID(invalidStrs(i))

        If (GUIDEquals(parsedGUID, zeroGUID) = SDL_TRUE) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "  → 解析失败，返回全零 GUID")
        Else
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "  → 解析结果非全零（意外情况）")
        End If
    Next
End Sub

' ==================== 主程序 ====================
Sub Main()
    ' 初始化 SDL（GUID 子系统无需特定初始化）
    If (SDL_Init(0) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 运行示例
    GUIDToStringExample()
    StringToGUIDExample()
    InvalidGUIDStringExample()

    ' 清理 SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>GUID 格式规范</strong>：</p>
<ul>
<li>SDL 遵循标准 UUID v4 格式：<code>8-4-4-4-12</code> 共 36 个字符（含 4 个连字符），例如 <code>12345678-1234-1234-1234-1234567890ab</code>；</li>
<li>二进制存储为 16 字节（128 位），字符串格式是其十六进制的可读性表示；</li>
<li>SDL_GUIDToString 的输出缓冲区至少需要 37 字节（36 个字符 + 1 个字符串终止符 <code>\0</code>）。</li>
</ul>
</li>
<li>
<p><strong>解析/转换规则</strong>：</p>
<ul>
<li>SDL_StringToGUID 仅支持标准 UUID 格式的字符串，非标准格式（如无连字符、大小写混合、非十六进制字符）会解析失败；</li>
<li>解析失败时返回<strong>全零的 SDL_GUID</strong>（所有 16 字节均为 0），可通过对比全零 GUID 判断解析是否成功；</li>
<li>SDL_GUIDToString 输出的字符串为小写形式，输入字符串为大写时也可正常解析（大小写不敏感）。</li>
</ul>
</li>
<li>
<p><strong>典型使用场景</strong>：</p>
<ul>
<li>标识游戏控制器/输入设备（SDL 中常用于区分不同的物理设备）；</li>
<li>生成唯一的用户/设备 ID 用于数据存储/传输；</li>
<li>跨平台唯一标识资源（如配置文件、缓存数据）。</li>
</ul>
</li>
<li>
<p><strong>跨平台注意事项</strong>：</p>
<ul>
<li>SDL_GUID 结构体的二进制布局在所有平台一致，可安全序列化/反序列化；</li>
<li>字符串格式的 GUID 无平台差异，是跨平台传输的首选格式；</li>
<li>避免手动修改 SDL_GUID 的二进制数据，如需生成新 GUID，需使用平台原生的 GUID 生成函数（如 Windows 的 CoCreateGuid）。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>提供简单统一的 GUID 序列化/反序列化接口，无需手动处理二进制与字符串的转换；</li>
<li>严格遵循标准 UUID 格式，保证与其他系统/库的兼容性；</li>
<li>解析失败时返回可预测的全零 GUID，便于错误处理。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>转换字符串时，务必使用 <code>SDL_GUID_STRING_LENGTH</code>（37）作为缓冲区大小，避免溢出；</li>
<li>解析字符串后，先对比全零 GUID 判断是否解析成功，再进行后续操作；</li>
<li>存储 GUID 时优先选择字符串格式（易读、易调试），传输/存储体积敏感时使用二进制格式。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>SDL_GUID 是 16 字节的结构体，用于存储 128 位的全局唯一标识符；</li>
<li>SDL_GUIDToString/SDL_StringToGUID 实现 GUID 二进制与字符串的双向转换；</li>
<li>解析无效字符串时返回全零 GUID，可通过对比全零值判断解析结果；</li>
<li>字符串格式遵循标准 UUID 格式（36 字符 + 终止符），缓冲区需至少 37 字节。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 10:23:45 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-328.html</guid>
</item>
<item>
    <title>SDL3_API分类参考_标准工具函数（CategoryStdinc）</title>
    <link>http://bbs.yfvb.com/post-327.html</link>
    <description><![CDATA[<h1>标准工具函数子系统（CategoryStdinc）</h1>
<p>SDL 提供了一套自研的<strong>核心 C 运行时函数实现</strong>，旨在解决跨平台开发中 C 标准库的兼容性问题：</p>
<ol>
<li><strong>解耦运行时依赖</strong>：应用可直接使用这些函数，无需依赖特定的 C 运行时库（甚至无需任何 C 运行时）；</li>
<li><strong>跨平台行为一致</strong>：避免不同平台的 C 函数表现差异（如 Windows/Linux 下 <code>snprintf()</code> 行为不同、<code>itoa()</code> 仅存在于部分平台）；</li>
<li><strong>性能与兼容性兼顾</strong>：对于 <code>SDL_memcpy</code> 等高频函数，SDL 会在底层调用平台原生实现（若其更高效且稳定），既减少库体积又保证性能；</li>
<li><strong>扩展增强功能</strong>：补充了 C 标准未定义但实用的功能（如 <code>SDL_crc32</code> 校验、<code>SDL_strlcpy</code> 安全字符串拷贝）。</li>
</ol>
<!-- END CATEGORY DOCUMENTATION -->
<hr />
<h2>函数</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryStdinc, CategoryAPIFunction -->
<h3>1. 内存管理函数</h3>
<ul>
<li>SDL_malloc：内存分配（替代标准 <code>malloc</code>，跨平台行为一致）</li>
<li>SDL_calloc：分配并清零内存（替代标准 <code>calloc</code>）</li>
<li>SDL_realloc：内存重分配（替代标准 <code>realloc</code>）</li>
<li>SDL_free：释放内存（替代标准 <code>free</code>，需与 SDL 分配函数配对使用）</li>
<li>SDL_aligned_alloc：按指定对齐方式分配内存（如 16 字节对齐）</li>
<li>SDL_aligned_free：释放对齐分配的内存</li>
<li>SDL_GetNumAllocations：获取当前 SDL 分配的内存块数量（调试内存泄漏）</li>
<li>SDL_GetMemoryFunctions：获取当前使用的内存分配函数指针</li>
<li>SDL_SetMemoryFunctions：自定义 SDL 的内存分配函数（如接入自定义内存池）</li>
<li>SDL_GetOriginalMemoryFunctions：获取 SDL 原生的内存函数指针</li>
</ul>
<h3>2. 字符串操作函数</h3>
<ul>
<li>SDL_strlen：计算字符串长度（替代 <code>strlen</code>，仅统计 ASCII 字符）</li>
<li>SDL_utf8strlen：计算 UTF-8 字符串的字符数（而非字节数）</li>
<li>SDL_strlcpy：安全字符串拷贝（防止缓冲区溢出，替代 <code>strcpy</code>）</li>
<li>SDL_strlcat：安全字符串拼接（替代 <code>strcat</code>）</li>
<li>SDL_strcmp/SDL_strncmp：字符串比较（区分大小写）</li>
<li>SDL_strcasecmp/SDL_strncasecmp：字符串比较（不区分大小写）</li>
<li>SDL_strchr/SDL_strrchr：查找字符在字符串中的位置</li>
<li>SDL_strstr/SDL_strnstr：查找子字符串</li>
<li>SDL_strdup/SDL_strndup：字符串拷贝（自动分配内存）</li>
<li>SDL_strtok_r：可重入的字符串分割（替代 <code>strtok</code>，线程安全）</li>
<li>SDL_itoa/SDL_ltoa/SDL_lltoa：整数转字符串（跨平台兼容，标准库无统一实现）</li>
<li>SDL_uitoa/SDL_ultoa/SDL_ulltoa：无符号整数转字符串</li>
<li>SDL_atof/SDL_atoi：字符串转数值（替代 <code>atof</code>/<code>atoi</code>）</li>
<li>SDL_strtod/SDL_strtol/SDL_strtoll：字符串转数值（带错误处理）</li>
<li>SDL_strtoul/SDL_strtoull：字符串转无符号数值</li>
<li>SDL_asprintf/SDL_vasprintf：动态格式化字符串（自动分配内存）</li>
<li>SDL_snprintf/SDL_vsnprintf：安全格式化字符串（防止缓冲区溢出）</li>
<li>SDL_utf8strlcpy：UTF-8 安全字符串拷贝</li>
</ul>
<h3>3. 内存操作函数</h3>
<ul>
<li>SDL_memcpy：内存拷贝（替代 <code>memcpy</code>，平台优化实现）</li>
<li>SDL_memmove：内存移动（处理重叠内存区域，替代 <code>memmove</code>）</li>
<li>SDL_memset：内存填充（替代 <code>memset</code>）</li>
<li>SDL_memset4：按 4 字节单位填充内存（更高效）</li>
<li>SDL_memcmp：内存比较（替代 <code>memcmp</code>）</li>
</ul>
<h3>4. 数学函数</h3>
<ul>
<li>SDL_abs：整数绝对值（替代 <code>abs</code>）</li>
<li>SDL_fabs/SDL_fabsf：浮点数绝对值（替代 <code>fabs</code>/<code>fabsf</code>）</li>
<li>SDL_sin/SDL_sinf/SDL_cos/SDL_cosf：三角函数（正弦/余弦）</li>
<li>SDL_atan/SDL_atanf/SDL_atan2/SDL_atan2f：反正切函数</li>
<li>SDL_acos/SDL_acosf/SDL_asin/SDL_asinf：反余弦/反正弦函数</li>
<li>SDL_tan/SDL_tanf：正切函数</li>
<li>SDL_sqrt/SDL_sqrtf：平方根函数</li>
<li>SDL_pow/SDL_powf：幂函数</li>
<li>SDL_exp/SDL_expf：指数函数</li>
<li>SDL_log/SDL_logf/SDL_log10/SDL_log10f：对数函数</li>
<li>SDL_floor/SDL_floorf：向下取整</li>
<li>SDL_ceil/SDL_ceilf：向上取整</li>
<li>SDL_round/SDL_roundf：四舍五入</li>
<li>SDL_trunc/SDL_truncf：截断小数部分</li>
<li>SDL_lround/SDL_lroundf：四舍五入转长整数</li>
<li>SDL_fmod/SDL_fmodf：取模运算（浮点数）</li>
<li>SDL_copysign/SDL_copysignf：复制符号位</li>
<li>SDL_isinf/SDL_isinff：检测无穷大</li>
<li>SDL_isnan/SDL_isnanf：检测非数值（NaN）</li>
<li>SDL_PI_F/SDL_PI_D：圆周率常量（单/双精度）</li>
</ul>
<h3>5. 字符判断函数</h3>
<ul>
<li>SDL_isalpha/SDL_isdigit/SDL_isalnum：字母/数字/字母数字判断</li>
<li>SDL_islower/SDL_isupper：大小写字母判断</li>
<li>SDL_isspace/SDL_isblank：空白字符判断</li>
<li>SDL_iscntrl/SDL_isprint/SDL_isgraph：控制字符/可打印字符/图形字符判断</li>
<li>SDL_ispunct：标点符号判断</li>
<li>SDL_isxdigit：十六进制字符判断</li>
<li>SDL_tolower/SDL_toupper：字符大小写转换</li>
</ul>
<h3>6. 排序/查找函数</h3>
<ul>
<li>SDL_qsort/SDL_qsort_r：快速排序（<code>qsort_r</code> 为可重入版本，线程安全）</li>
<li>SDL_bsearch/SDL_bsearch_r：二分查找（<code>bsearch_r</code> 为可重入版本）</li>
</ul>
<h3>7. 哈希/校验函数</h3>
<ul>
<li>SDL_crc16/SDL_crc32：计算 CRC16/CRC32 校验值</li>
<li>SDL_murmur3_32：计算 Murmur3 32 位哈希值</li>
</ul>
<h3>8. 环境变量函数</h3>
<ul>
<li>SDL_getenv/SDL_getenv_unsafe：获取环境变量（<code>_unsafe</code> 版本不做安全检查）</li>
<li>SDL_SetEnvironmentVariable/SDL_UnsetEnvironmentVariable：设置/删除环境变量</li>
<li>SDL_GetEnvironmentVariables：获取所有环境变量列表</li>
<li>SDL_CreateEnvironment/SDL_DestroyEnvironment：创建/销毁独立的环境变量上下文</li>
</ul>
<h3>9. 字符编码转换函数</h3>
<ul>
<li>SDL_iconv_open：打开字符编码转换上下文</li>
<li>SDL_iconv：执行编码转换</li>
<li>SDL_iconv_close：关闭转换上下文</li>
<li>SDL_iconv_string：字符串编码转换（简化接口）</li>
<li>SDL_UCS4ToUTF8：UCS4 转 UTF-8 编码</li>
<li>SDL_StepUTF8/SDL_StepBackUTF8：UTF-8 字符串步进/回退（遍历字符）</li>
</ul>
<h3>10. 随机数函数</h3>
<ul>
<li>SDL_srand：设置随机数种子</li>
<li>SDL_rand：生成随机整数（替代 <code>rand</code>）</li>
<li>SDL_randf：生成 0~1 浮点数随机数</li>
<li>SDL_rand_r/SDL_randf_r：可重入的随机数生成（线程安全）</li>
<li>SDL_rand_bits：生成指定位数的随机数</li>
</ul>
<h3>11. 宽字符函数</h3>
<ul>
<li>SDL_wcslen/SDL_wcscmp/SDL_wcsncmp：宽字符串长度/比较</li>
<li>SDL_wcsstr/SDL_wcsnstr：宽字符串查找</li>
<li>SDL_wcslcpy/SDL_wcslcat：宽字符串安全拷贝/拼接</li>
<li>SDL_wcsdup：宽字符串拷贝（自动分配内存）</li>
<li>SDL_wcstol：宽字符串转长整数</li>
</ul>
<h3>12. 格式化输入函数</h3>
<ul>
<li>SDL_sscanf/SDL_vsscanf：安全格式化输入（替代 <code>sscanf</code>）</li>
<li>SDL_swprintf/SDL_vswprintf：宽字符串格式化输出
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>数据类型</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryStdinc, CategoryAPIDatatype -->
<ul>
<li>SDL_malloc_func：内存分配函数指针类型（匹配 <code>SDL_malloc</code> 签名）</li>
<li>SDL_calloc_func：内存分配并清零函数指针类型</li>
<li>SDL_realloc_func：内存重分配函数指针类型</li>
<li>SDL_free_func：内存释放函数指针类型</li>
<li>SDL_CompareCallback：排序/查找比较函数类型</li>
<li>SDL_CompareCallback_r：可重入的比较函数类型（带用户数据）</li>
<li>SDL_Environment：环境变量上下文类型</li>
<li>SDL_iconv_t：字符编码转换上下文类型</li>
<li>SDL_FunctionPointer：通用函数指针类型</li>
<li>SDL_Time：时间类型（跨平台兼容）</li>
<li>Sint8/Sint16/Sint32/Sint64：有符号整数类型（固定位宽）</li>
<li>Uint8/Uint16/Uint32/Uint64：无符号整数类型（固定位宽）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>结构体</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryStdinc, CategoryAPIStruct -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>枚举</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryStdinc, CategoryAPIEnum -->
<ul>
<li>（无）
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h2>宏</h2>
<!-- 请勿手动编辑类别列表，它们是自动生成的，会被覆盖。请在单独页面底部修改标签。 -->
<!-- 开始类别列表：CategoryStdinc, CategoryAPIMacro -->
<h3>1. 类型转换宏</h3>
<ul>
<li>SDL_static_cast：静态类型转换（替代 C++ <code>static_cast</code>）</li>
<li>SDL_reinterpret_cast：重解释类型转换（替代 C++ <code>reinterpret_cast</code>）</li>
<li>SDL_const_cast：常量类型转换（替代 C++ <code>const_cast</code>）</li>
</ul>
<h3>2. 数学/工具宏</h3>
<ul>
<li>SDL_min/SDL_max：取最小值/最大值</li>
<li>SDL_clamp：将值限制在指定范围内（<code>clamp(value, min, max)</code>）</li>
<li>SDL_arraysize：计算数组元素个数（编译期计算，安全）</li>
<li>SDL_FLT_EPSILON：浮点数精度阈值（用于判断浮点数相等）</li>
<li>SDL_SIZE_MAX：size_t 类型的最大值</li>
</ul>
<h3>3. 内存初始化宏</h3>
<ul>
<li>SDL_zero：将变量清零（<code>SDL_zero(var)</code>）</li>
<li>SDL_zeroa：将数组清零（<code>SDL_zeroa(array)</code>）</li>
<li>SDL_zerop：将指针指向的内存清零（<code>SDL_zerop(ptr)</code>）</li>
<li>SDL_copyp：指针拷贝（<code>SDL_copyp(dst, src)</code>）</li>
<li>SDL_stack_alloc：栈内存分配（临时内存，无需释放）</li>
<li>SDL_stack_free：栈内存释放（配套 <code>SDL_stack_alloc</code>）</li>
</ul>
<h3>4. 编译期检查宏</h3>
<ul>
<li>SDL_COMPILE_TIME_ASSERT：编译期断言（失败则编译报错）</li>
</ul>
<h3>5. 格式化输出宏</h3>
<ul>
<li>SDL_PRIs32/SDL_PRIu32：32 位整数格式化占位符（跨平台兼容）</li>
<li>SDL_PRIs64/SDL_PRIu64/SDL_PRIx64：64 位整数格式化占位符</li>
<li>SDL_PRINTF_FORMAT_STRING：标记格式化字符串参数（编译器检查）</li>
<li>SDL_PRINTF_VARARG_FUNC：标记可变参数格式化函数</li>
</ul>
<h3>6. 编码转换宏</h3>
<ul>
<li>SDL_iconv_utf8_locale：UTF-8 转系统本地编码</li>
<li>SDL_iconv_utf8_ucs2/SDL_iconv_utf8_ucs4：UTF-8 转 UCS2/UCS4</li>
<li>SDL_iconv_wchar_utf8：宽字符转 UTF-8</li>
</ul>
<h3>7. 其他宏</h3>
<ul>
<li>SDL_FOURCC：生成四字符码（用于标识媒体格式等）</li>
<li>SDL_SINT64_C/SDL_UINT64_C：64 位常量定义（跨平台兼容）</li>
<li>SDL_INVALID_UNICODE_CODEPOINT：无效 Unicode 码点常量
<!-- 类别列表结束 --></li>
</ul>
<hr />
<h3>FreeBASIC 示例代码</h3>
<pre><code class="language-freebasic">' 引入 SDL 相关声明（需确保 FreeBASIC 已链接 SDL3 库）
#Include "SDL.bi"

' 补充核心函数/宏声明（FreeBASIC 绑定可能缺失）
#Define SDL_PI_F 3.14159265358979323846f
#Define SDL_min(a, b) IIf((a) &lt; (b), (a), (b))
#Define SDL_max(a, b) IIf((a) &gt; (b), (a), (b))
#Define SDL_clamp(x, min_val, max_val) SDL_max(SDL_min((x), (max_val)), (min_val))

' 函数声明补充
Declare Function SDL_utf8strlen CDecl (ByVal str As ZString Ptr) As Size_t
Declare Function SDL_strlcpy CDecl (ByVal dst As ZString Ptr, ByVal src As ZString Ptr, ByVal size As Size_t) As Size_t
Declare Function SDL_crc32 CDecl (ByVal crc As Uint32, ByVal data As Const Any Ptr, ByVal len As Size_t) As Uint32
Declare Sub SDL_zero CDecl (ByRef var As Any)
Declare Function SDL_randf CDecl () As Float
Declare Sub SDL_srand CDecl (ByVal seed As Uint32)

' ==================== 示例 1：安全字符串操作 ====================
Sub StringOperationsExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【安全字符串操作示例】")

    ' 1. SDL_strlcpy 安全拷贝（防止缓冲区溢出）
    Dim As ZString * 10 dstBuffer
    Dim As ZString Ptr src = StrPtr("Hello SDL!")

    ' 拷贝最多 9 个字符 + 终止符，返回原字符串长度
    Dim As Size_t len = SDL_strlcpy(@dstBuffer, src, sizeof(dstBuffer))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "原字符串：%s，长度：%d", src, len)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "拷贝结果：%s（缓冲区大小：%d）", dstBuffer, sizeof(dstBuffer))

    ' 2. UTF-8 字符串长度计算
    Dim As ZString Ptr utf8Str = StrPtr("SDL 中文示例")
    Dim As Size_t byteLen = SDL_strlen(utf8Str)       ' 字节数
    Dim As Size_t charLen = SDL_utf8strlen(utf8Str)   ' 字符数
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "UTF-8 字符串：%s", utf8Str)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "字节长度：%d，字符长度：%d", byteLen, charLen)

    ' 3. 整数转字符串（跨平台兼容）
    Dim As ZString * 32 numStr
    SDL_itoa(-12345, @numStr, 10)  ' 十进制
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "整数转字符串：%s", numStr)
    SDL_uitoa(65535, @numStr, 16)  ' 十六进制
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "无符号整数转十六进制：%s", numStr)
End Sub

' ==================== 示例 2：内存操作与校验 ====================
Sub MemoryOperationsExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【内存操作与校验示例】")

    ' 1. 内存分配与初始化
    Dim As Integer Ptr arr = SDL_calloc(5, sizeof(Integer))
    If (arr = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "内存分配失败")
        Exit Sub
    End If

    ' 填充数据
    For i As Integer = 0 To 4
        arr[i] = i * 10
    Next

    ' 2. 内存拷贝
    Dim As Integer Ptr arrCopy = SDL_malloc(5 * sizeof(Integer))
    SDL_memcpy(arrCopy, arr, 5 * sizeof(Integer))

    ' 打印拷贝结果
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "内存拷贝结果：")
    For i As Integer = 0 To 4
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "  arrCopy[%d] = %d", i, arrCopy[i])
    Next

    ' 3. CRC32 校验
    Dim As Uint32 crc = SDL_crc32(0, arr, 5 * sizeof(Integer))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "数据 CRC32 校验值：0x%08X", crc)

    ' 4. 内存释放
    SDL_free(arr)
    SDL_free(arrCopy)

    ' 5. 内存清零
    Type TestStruct
        a As Integer
        b As Float
        c As ZString * 20
    End Type
    Dim As TestStruct ts
    SDL_zero(ts)  ' 清零整个结构体
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "结构体清零后：a=%d, b=%.2f", ts.a, ts.b)
End Sub

' ==================== 示例 3：数学与随机数 ====================
Sub MathAndRandomExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【数学与随机数示例】")

    ' 1. 数学函数
    Dim As Float angle = SDL_PI_F / 4  ' 45 度
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "sin(45°) = %.4f", SDL_sinf(angle))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "cos(45°) = %.4f", SDL_cosf(angle))
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "sqrt(2) = %.4f", SDL_sqrtf(2.0f))

    ' 2. 数值限制（clamp）
    Dim As Integer val = 150
    Dim As Integer clamped = SDL_clamp(val, 0, 100)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "clamp(150, 0, 100) = %d", clamped)

    ' 3. 随机数
    SDL_srand(SDL_GetTicks())  ' 以时间为种子
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "随机整数：%d", SDL_rand() Mod 100)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "随机浮点数（0~1）：%.4f", SDL_randf())
End Sub

' ==================== 示例 4：环境变量操作 ====================
Sub EnvVarExample()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "【环境变量操作示例】")

    ' 1. 设置环境变量
    SDL_SetEnvironmentVariable(StrPtr("SDL_TEST_VAR"), StrPtr("Hello SDL Env"))

    ' 2. 获取环境变量
    Dim As ZString Ptr envVal = SDL_getenv(StrPtr("SDL_TEST_VAR"))
    If (envVal &lt;&gt; NULL) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "获取环境变量 SDL_TEST_VAR：%s", envVal)
    End If

    ' 3. 删除环境变量
    SDL_UnsetEnvironmentVariable(StrPtr("SDL_TEST_VAR"))
    envVal = SDL_getenv(StrPtr("SDL_TEST_VAR"))
    If (envVal = NULL) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "环境变量 SDL_TEST_VAR 已删除")
    End If
End Sub

' ==================== 主程序 ====================
Sub Main()
    ' 初始化 SDL（Stdinc 子系统无需特定初始化）
    If (SDL_Init(0) &lt; 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败：%s", SDL_GetError())
        Exit Sub
    End If

    ' 运行示例
    StringOperationsExample()
    MemoryOperationsExample()
    MathAndRandomExample()
    EnvVarExample()

    ' 清理 SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf &amp; "程序正常退出")
End Sub

' 运行主程序
Main()</code></pre>
<h3>核心知识点补充</h3>
<ol>
<li>
<p><strong>核心设计理念</strong>：</p>
<ul>
<li>SDL_stdinc 的核心目标是「跨平台一致性」，而非「替代标准库」；</li>
<li>对于底层实现稳定的函数（如 <code>memcpy</code>），SDL 会直接调用平台原生版本，保证性能；</li>
<li>对于行为不一致/缺失的函数（如 <code>itoa</code>/<code>snprintf</code>），SDL 提供自研实现，保证跨平台表现相同。</li>
</ul>
</li>
<li>
<p><strong>内存管理最佳实践</strong>：</p>
<ul>
<li>SDL 内存函数（<code>SDL_malloc</code>/<code>SDL_free</code> 等）必须配对使用，不可混用标准库 <code>free</code>；</li>
<li><code>SDL_calloc</code> 会自动清零内存，优先用于需要初始化的场景；</li>
<li><code>SDL_GetNumAllocations</code> 可用于调试内存泄漏（记录分配/释放的数量差）；</li>
<li>自定义内存函数需在 SDL 初始化前通过 <code>SDL_SetMemoryFunctions</code> 设置。</li>
</ul>
</li>
<li>
<p><strong>字符串安全要点</strong>：</p>
<ul>
<li>优先使用 <code>SDL_strlcpy</code>/<code>SDL_strlcat</code> 替代 <code>strcpy</code>/<code>strcat</code>，避免缓冲区溢出；</li>
<li><code>SDL_utf8strlen</code> 是 UTF-8 字符串的「字符数」统计，<code>SDL_strlen</code> 是「字节数」统计；</li>
<li><code>SDL_asprintf</code> 会自动分配内存，使用后必须调用 <code>SDL_free</code> 释放。</li>
</ul>
</li>
<li>
<p><strong>跨平台兼容注意</strong>：</p>
<ul>
<li>64 位整数格式化需使用 <code>SDL_PRId64</code>/<code>SDL_PRIu64</code> 等宏，避免 <code>%lld</code>/<code>%llu</code> 的平台差异；</li>
<li>整数类型优先使用 <code>Sint32</code>/<code>Uint32</code> 等固定位宽类型，而非 <code>int</code>/<code>long</code>；</li>
<li>随机数函数 <code>SDL_rand</code> 比标准 <code>rand</code> 更稳定，且 <code>SDL_rand_r</code> 保证线程安全。</li>
</ul>
</li>
</ol>
<h3>总结</h3>
<ol>
<li>
<p><strong>核心优势</strong>：</p>
<ul>
<li>解耦 C 运行时依赖，降低跨平台编译复杂度；</li>
<li>统一函数行为，避免不同平台的标准库实现差异；</li>
<li>补充安全/增强功能（如 <code>SDL_strlcpy</code>/<code>SDL_crc32</code>），提升代码健壮性；</li>
<li>底层优化实现，兼顾性能与兼容性。</li>
</ul>
</li>
<li>
<p><strong>使用建议</strong>：</p>
<ul>
<li>新项目优先使用 SDL_stdinc 函数替代标准库函数，减少跨平台问题；</li>
<li>内存分配/释放必须使用 SDL 配套函数（<code>SDL_malloc</code> ↔ <code>SDL_free</code>）；</li>
<li>UTF-8 字符串操作使用 <code>SDL_utf8*</code> 系列函数，避免多字节字符处理错误；</li>
<li>编译期使用 <code>SDL_COMPILE_TIME_ASSERT</code> 检查类型大小、常量等，提前发现问题。</li>
</ul>
</li>
<li>
<p><strong>关键点回顾</strong>：</p>
<ul>
<li>SDL_stdinc 是 SDL 的基础工具集，提供跨平台一致的 C 运行时函数；</li>
<li><code>SDL_strlcpy</code>/<code>SDL_snprintf</code> 等函数解决了标准库字符串操作的安全问题；</li>
<li>内存函数、数学函数、随机数函数均做了跨平台兼容和性能优化；</li>
<li>固定位宽类型（<code>Sint32</code>/<code>Uint64</code>）和格式化宏（<code>SDL_PRIs64</code>）是跨平台开发的关键。</li>
</ul>
</li>
</ol>]]></description>
    <pubDate>Sat, 07 Mar 2026 10:22:44 +0800</pubDate>
    <dc:creator>勇芳</dc:creator>
    <guid>http://bbs.yfvb.com/post-327.html</guid>
</item>
</channel>
</rss>