avatar

阿炳的小站

谁知难过 分一丁目赠我

  • 首页
  • 关于
  • 友链
Home 【翻译】SDL2教程 Lesson 01 环境配置与窗口创建
文章

【翻译】SDL2教程 Lesson 01 环境配置与窗口创建

Posted 2 days ago Updated 2 days ago
By abing
18~23 min read

本文翻译自 https://thenumb.at/cpp-course/sdl2/01/01.html 感谢作者的博文,在我 SDL 学习路上的指导。原文以正体翻译,个人注解则以斜体标出,在不影响阅读的情况下,辅助初学者的理解

导言

本节课程主要介绍 SDL2(Simple DirectMedia Layer 2 简单直接媒体抽象层)库的使用。它是一个(相对)易于使用的库,可以在不依赖特定操作系统功能的情况下,为程序添加多媒体功能。

SDL 提供的功能:

  • 窗口管理

  • 基于软件(CPU)和硬件(GPU)的 2D 图形渲染

  • 输入事件处理机制

  • 时间管理 (时间函数处理)

  • 音频处理

  • 文件 I/O 与库加载

  • 多线程支持

  • 用于 3D 图形的 OpenGL API

SDL 还提供了一些扩展库,用于实现更多功能——例如网络支持、更完善的音频系统、图像加载等。

本节课程我会引用许多 SDL 提供的函数。课程的重点是教你如何使用 SDL 的功能,而不是讲解每个函数的细枝末节等等。因此,每当提到一个 SDL 对象时,都会附上对应的官方文档链接。如果你对函数参数、返回值、副作用,或者对某个结构有疑问,请查阅对应文档——它是非常有价值的学习材料。

SDL官方文档阅读提示:

  • 如果对某些内容有疑问,请查阅文档。

  • 示例代码非常有用!

  • 一定要阅读备注!他们可能展示了意想不到的特性并描述了何时应该释放/保存内存

  • 每个页面底部的 “相关函数” 部分会告诉你还能使用哪些函数。但这不会在每一课里涵盖所有函数。

环境配置

指南:

  • Setup for Dev C++

  • Setup for Visual Studio

  • Other Setup Guides

在使用 SDL 的函数或对象时,你必须包含它们的头文件。SDL.h 文件会自动包含几乎所有需要的内容——在大多数情况下,这就足够了。不过,也有一些函数是在特定的头文件中声明的。如果不确定需要包含什么,请查阅文档。

如果你的编译器设置正确,你就可以使用尖括号(例如 #include <SDL.h>)。这会告诉编译器去它指定的 include 目录中查找头文件。

此部分作者引用上述指南的链接来指引配置 SDL 环境,译者简单讲解一下各个平台配置 SDL的方法,如有需要,则专门开一个教程进行说明

  • macOS:
    使用 homebrew 进行安装,运行 brew install sdl2 sdl2_image sdl2_mixer sdl2_ttf 即可

  • Windows:
    在 github 的 SDL官方仓库 中,下载对应版本的 sdl2 库,解压后,就可以看到其对应的文件, docs 中是对应的文档, include 中则是相关的头文件,lib 中则是对应的dll动态库。然后再将对应的头文件与动态库,根据不同 IDE 的配置,或者是自己的编译脚本中,即可完成添加

初始化 SDL

在进行其他操作前,你必须先整体初始化 SDL 。即通过调用 SDL_Init() 来完成。如果你想初始化 SDL 的所有部分,可以传入参数 SDL_INIT_EVERYTHING。

SDL 也允许你单独初始化库里面的某些子模块。要指定要初始化的部分,可以直接在 SDL_Init() 中传入对应的标志(flags),或者使用 SDL_InitSubSystem() 函数。如果你打算分别初始化各个子系统,那么在最初调用 SDL_Init() 时只需传入 0 即可。

SDL_Init( SDL_INIT_EVERYTHING );

创建窗口

你必须创建一个窗口,供程序的多媒体输入输出使用。从头开始编写一个多窗口应用的时候,你必须定义一个 WinMain 函数,来调用操作系统去获取 句柄 (handles)、创建窗口等操作。而 SDL 提供了一个更简单、跨平台的窗口管理 API,让这些步骤大大简化。

为了管理窗口,SDL 以便利的方式提供了一个结构体 SDL_Window,以及相关函数,例如 SDL_CreateWindow()。

稍微插一句:你可能会注意到,SDL 文档中没有 SDL_Window 结构的详细说明链接。这是因为该结构是不透明(opaque)的,也就是说——你的程序无法直接访问或查看 SDL_Window 内部的实际内容。你只需要持有并操作一个指向 SDL_Window 的指针即可。

SDL_CreateWindow() 的功能也符合直觉:它接收窗口的标题、大小、位置、选项等参数,然后返回一个指向新建 SDL_Window 结构的指针。详细参数说明请参考 SDL 官方文档。

SDL_Window* win = SDL_CreateWindow( "my window", 100, 100, 640, 480, SDL_WINDOW_SHOWN );

大多数 SDL 函数在执行失败时会返回一个特定的值,用于表示错误。例如返回的是指针的函数, NULL 就是这个特定的值。因此,你可以很容易地检查操作是否成功。

在任何 SDL 的函数内发生了错误之后,SDL_GetError() 这个函数允许你接收捕获到的一个 string 的错误信息。

if ( !win ) {
	cout << "Failed to create a window! Error: " << SDL_GetError() << endl;
}

表面

当你创建了一个窗口后,你需要一种方法在其上进行绘制。SDL 将任何可以被绘制的区域——包括已加载的图像——抽象为一个“表面(surface)”。(这适用于软件渲染——在后续章节中,我们将讨论不使用表面的 GPU 渲染。)

结构体 SDL_Surface 以及函数 SDL_LoadBMP() 和 SDL_GetWindowSurface() 提供了软件渲染(也称为 blitting, 位图操作)的 API。

正如你所料,可以使用SDL_GetWindowSurface()来获取窗口的表面(surface)。在你在这个表面上完成绘制之后,通过调用 DL_UpdateWindowSurface() 就能在窗口中看到绘制结果。

SDL_Surface* winSurface = SDL_GetWindowSurface( win );

// do drawing

SDL_UpdateWindowSurface( win );

绘制一个矩形

为了测试你的窗口表面是否有正常工作,你可以用一个颜色填充它。最简单的方法是使用 SDL_FillRect() 。如果想填充整个窗口,简单情况下只需传入 NULL,而无需用一个 SDL_Rect 指针。此外 SDL_FillRect() 接受一个特定格式的数字来表示颜色。要获得这种格式的颜色值,可以调用 SDL_MapRGB() ,并传入表面的格式以及期望的 RGB 数值。

SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 255, 90, 120 ));

关闭

当你的程序完成了所有操作之后,它必须销毁窗口并释放所有资源。你可能会想到,用 SDL_DestroyWindow() 来处理。这个函数会关闭你的窗口,并释放关联的内存资源(包括窗口表面)。

SDL_DestroyWindow( win );
win = NULL;
winSurface = NULL;

最后,要彻底关闭整个 SDL,只需调用 SDL_Quit()。很好理解这段:

SDL_Quit();

附录

文章中所用到的代码完整内容如下:

#include <iostream>
#include <SDL.h>

// You shouldn't really use this statement, but it's fine for small programs
using namespace std;

// You must include the command line parameters for your main function to be recognized by SDL
int main(int argc, char** args) {

	// Pointers to our window and surface
	SDL_Surface* winSurface = NULL;
	SDL_Window* window = NULL;

	// Initialize SDL. SDL_Init will return -1 if it fails.
	if ( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) {
		cout << "Error initializing SDL: " << SDL_GetError() << endl;
		system("pause");
		// End the program
		return 1;
	} 

	// Create our window
	window = SDL_CreateWindow( "Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_SHOWN );

	// Make sure creating the window succeeded
	if ( !window ) {
		cout << "Error creating window: " << SDL_GetError()  << endl;
		system("pause");
		// End the program
		return 1;
	}

	// Get the surface from the window
	winSurface = SDL_GetWindowSurface( window );

	// Make sure getting the surface succeeded
	if ( !winSurface ) {
		cout << "Error getting surface: " << SDL_GetError() << endl;
		system("pause");
		// End the program
		return 1;
	}

	// Fill the window with a white rectangle
	SDL_FillRect( winSurface, NULL, SDL_MapRGB( winSurface->format, 255, 255, 255 ) );

	// Update the window display
	SDL_UpdateWindowSurface( window );

	// Wait
	system("pause");

	// Destroy the window. This will also destroy the surface
	SDL_DestroyWindow( window );

	// Quit SDL
	SDL_Quit();
	
	// End the program
	return 0;
}

License:  CC BY 4.0
Share

Further Reading

OLDER

芯片制造行业上下游介绍 I

NEWER

Recently Updated

  • 【翻译】SDL2教程 Lesson 01 环境配置与窗口创建
  • 芯片制造行业上下游介绍 I
  • 半导体通讯:SECS/GEM 引入与简介
  • Shuffling 的算法艺术
  • 鸟群算法 Boids

Trending Tags

笔记 共赏 实习心得 docker使用技巧 随想沉思 工具技巧 C# 数据结构 git使用技巧

Contents

©2025 阿炳的小站. Some rights reserved.

Using the Halo theme Chirpy