这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

相关库

小熊猫C++发行版集成的部分C/C++库使用说明

本章是小熊猫C++发行版中集成的部分C/C++库的教程和使用介绍。

小熊猫C++在发行版所带的编译器中集成了若干教学中常用的库以方便学生使用,包括:

1 - EGE

兼容BGI的简易作图库

EGE(Easy Graphics Engine),是windows下的简易绘图库,是一个类似BGI(graphics.h)的面向C/C++语言新手的图形库,它的目标也是为了替代TC的BGI库而存在。

它的使用方法与TC中的graphics.h相当接近,对新手来说,简单,友好,容易上手,免费开源,而且接口意义直观,即使是完全没有接触过图形编程的,也能迅速学会基本的绘图。

编译使用ege库的程序

单文件方式

如果直接使用单文件方式编写ege程序(不创建项目),直接在程序中包含ege.h,编译即可。小熊猫C++的自动链接功能会自动在编译时链接相关的库。

如需修改编译时的链接参数,可通过“工具”菜单→“选项”打开“选项”对话框,在“编译器”→“自动链接”页中找到ege.h,修改相关的链接参数。

项目方式

如果要在项目中使用ege库,请使用新建项目向导中的“多媒体”→“EGE绘图”模板创建项目,即可正常编译。

小熊猫C++ 2.22或更早的版本,请使用新建项目向导中的“多媒体”→“Graphics.h”模板创建项目。

如需修改编译时的链接参数,可以通过“项目”菜单→“项目属性”打开“项目选项”对话框,修改自定义选项。

控制台显示

为了方便调试,缺省编译得到的可执行文件在运行时会显示控制台窗口。如果不想显示它,可以:

  • 单文件方式开发:在自动链接参数中增加-mwindows参数。
  • 项目方式开发:在“项目选项”对话框的“通用”页中,将程序类型改为“Win32图形界面程序”。

2 - raylib

简单并且易于使用的游戏编程库

raylib是一个以简单易用为目标的跨平台游戏绘图库,它的特点包括:

  • 免费开源(基于类似于BSD的zlib授权协议)
  • 跨平台支持:Windows, Linux, MacOS, RPI, Android, HTML5等
  • 全部用C语言实现
  • 简单易用
  • 使用OpenGL硬件加速(1.1, 2.1, 3.3, 4.3 or ES 2.0)
  • 支持多种字体(XNA SpriteFonts, BMfonts, TTF, SDF)
  • 支持多种材质格式,包括压缩材质(DXT, ETC, ASTC)
  • 全面支持3D,包括Shapes,Models,Billboards, Heightmaps等
  • 材质系统支持包括经典贴图和PBR贴图
  • 支持动画3d模型(Animated 3d models)
  • 支持多种着色器,包括模型着色器(Model shaders)和后处理着色器(Postprocessing shaders)
  • 提供数学模块,支持矢量、矩阵和四元数(Quaternion)运算
  • 支持多种音乐格式的载入和流媒体播放(WAV, OGG, MP3, FLAC, XM, MOD)
  • 提供50多种编程语言的绑定

教程

raylib和rdrawing中文使用教程

示例程序

下面这个程序绘制了一个旋转的立方体(其实是摄像机在围绕立方体旋转):

#include <raylib.h>
#include <math.h>

int main(void)
{
	// 初始化
	const int screenWidth = 640;
	const int screenHeight = 480;
	
	//启用反锯齿
	SetConfigFlags(FLAG_MSAA_4X_HINT);
	
	//初始化窗口
	InitWindow(screenWidth, screenHeight, "Sample");
	
	// 初始化摄像机
	Camera3D camera = { 0 };
	camera.position = (Vector3){ 40.0f, 20.0f, 0.0f }; //相机所在位置{x,y,z}
	camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; //相机朝向位置{x,y,z}
	camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; //相机正上方朝向矢量
	camera.fovy = 70.0f; //相机视野宽度
	camera.projection = CAMERA_PERSPECTIVE; //采用透视投影
	
	//设置动画帧率(刷新率,fps)为30帧/秒
	SetTargetFPS(30);
	//--------------------------------------------------------------------------------------
	int angle=0; //多边形旋转角度

	// 主游戏循环
	while (!WindowShouldClose())    //关闭窗口或者按ESC键时返回true
	{
		
		double time = GetTime(); 
		// 每次循环更新一帧
		// 摄像机围绕y轴转动
		double cameraTime = time*0.3;
		camera.position.x = (float)cos(cameraTime)*40.0f;
		camera.position.z = (float)sin(cameraTime)*40.0f;
		
		BeginDrawing();
		
		ClearBackground(WHITE);
			//以摄像机视角绘制3d内容
			BeginMode3D(camera);
				DrawCube(Vector3{0,0,0},10,10,10,VIOLET);
				DrawCubeWires(Vector3{0,0,0},10,10,10,BLACK);
			EndMode3D();
		EndDrawing();
	}
	
	//关闭窗口
	CloseWindow();
	
	return 0;
}

对于初学者来说,只要了解了OpenGL的3维坐标系,以及摄像机投影的各项基本参数,很快就可以用raylib编写动画程序啦。

3 - rdrawing

基于raylib的2维绘图库

rdrawing是raylib的扩展库raylib-drawing中的一个子库,提供了诸如绘制指定线宽的线段、填充圆形、填充任意形状多边形等raylib缺少的2d绘图功能。

教程

raylib和rdrawing中文使用教程

示例

#include <raylib.h>
#include <rdrawing.h>
#include <time.h>

#define SHRINK_FRAMES 2

Image genBodyImage();

int main() {
	InitWindow(800,600,"Doraemon");
	SetTraceLogLevel(LOG_WARNING);
	SetTargetFPS(30);
	
	Image img=genBodyImage();
	
	Texture texture = LoadTextureFromImage(img);
	
	while(!WindowShouldClose()) {
		BeginDrawing();
		ClearBackground(WHITE);
		DrawTexture(texture,0,0,WHITE);
		EndDrawing();
	}
	
	//Clean up
	UnloadTexture(texture);
	UnloadImage(img);
	CloseWindow();
}

Image genBodyImage(){
	Image img=GenImageColor(800,600,WHITE);
	// 画头
	Color fillColor = (Color){7,190,234,255};
	Color color=BLACK;
	ImageFillRoundRectEx(&img,265, 94, 270, 260, 124, 124,fillColor);
	ImageDrawRoundRectEx(&img,265, 94, 270, 260, 124, 124,1,color);
	
	fillColor = WHITE;								// 脸
	ImageFillEllipseEx(&img, 400, 256, 115, 95, fillColor);
	
	ImageFillRoundRectEx(&img,337, 131, 63, 74, 28, 28, fillColor);			// 右眼
	ImageDrawRoundRectEx(&img,337, 131, 63, 74, 28, 28,1, color);			
	ImageFillRoundRectEx(&img,400, 131, 63, 74, 28, 28, fillColor);			// 左眼
	ImageDrawRoundRectEx(&img,400, 131, 63, 74, 28, 28,1, color);	
	
	fillColor = BLACK;
	ImageFillCircleEx(&img,384,184,6, fillColor);							// 右眼球
	ImageFillCircleEx(&img,416,184,6, fillColor);							// 左眼球
	
	fillColor = (Color){201, 62, 0, 255};						// 鼻子
	ImageFillCircleEx(&img, 400, 208, 15, fillColor);
	
	ImageDrawLineEx(&img,400,223,400,296,1,color);		// 人中
	ImageDrawArcEx(&img,400, 192, 108, 108, PI * 5 / 4, PI * 7 / 4,1,color);	// 嘴
	
	ImageDrawLineEx(&img,358, 227, 310, 209,1,color);							// 胡子
	ImageDrawLineEx(&img,442, 227, 490, 209,1,color);
	ImageDrawLineEx(&img,359, 235, 308, 235,1,color);
	ImageDrawLineEx(&img,441, 235, 492, 235,1,color);
	ImageDrawLineEx(&img,358, 243, 310, 261,1,color);
	ImageDrawLineEx(&img,442, 243, 490, 261,1,color);	
	
	// 画身体
	ImageDrawLineEx(&img, 319, 332, 262, 372,1,color);					// 手臂(上)
	ImageDrawLineEx(&img, 481, 332, 538, 372,1,color);
	ImageDrawLineEx(&img, 304, 396, 284, 410,1,color);					// 手臂(下)
	ImageDrawLineEx(&img, 496, 396, 516, 410,1,color);
	
	ImageDrawLineEx(&img, 304, 385, 304, 478,1,color);					// 腿外侧
	ImageDrawLineEx(&img, 496, 385, 496, 478,1,color);
	ImageDrawArcEx(&img, 400, 479, 15,11,0,PI,1,color);				// 腿内侧
	
	fillColor=WHITE;						// 手
	ImageFillCircleEx(&img, 260,399,27, fillColor);
	ImageDrawCircleEx(&img, 260,399,27, 1, color);
	ImageFillCircleEx(&img, 540,399,27, fillColor);
	ImageDrawCircleEx(&img, 540,399,27, 1, color);
	ImageFillRoundRectEx(&img,288,478,110,27,12,12,fillColor);			// 脚
	ImageDrawRoundRectEx(&img,288,478,110,27,12,12,1,color);			
	ImageFillRoundRectEx(&img,402,478,110,27,12,12,fillColor);
	ImageDrawRoundRectEx(&img,402,478,110,27,12,12,1,color);			
	
	fillColor=(Color){7,190,234,255};							// 身体填充蓝色
	ImageFloodFill(&img,400,400,BLACK,fillColor);
	
	fillColor=WHITE;						// 肚皮
	ImageFillCircleEx(&img,400,381,75,fillColor);
	ImageFillRectangleEx(&img,340,304,120,20,fillColor); // 用白色矩形擦掉多余的肚皮
	
	ImageDrawSectorEx(&img,400,381,58, 58,PI,2*PI,1,color); // 口袋 
	
	// 画铃铛
	fillColor=(Color){169, 38, 0,255};				// 绳子
	ImageFillRoundRectEx(&img,300,323,200,19,12,12,fillColor);
	
	fillColor=(Color){245, 237, 38,255};			// 铃铛外形
	ImageFillCircleEx(&img,400,349,19,fillColor);
	
	fillColor=BLACK;						// 铃铛上的洞
	ImageFillEllipseEx(&img,400,354,4,4,fillColor);
	ImageDrawLineEx(&img,400,357,400,368,3,color);	
	
	ImageDrawLineEx(&img,384,340,416,340,1,color);					// 铃铛上的纹路
	ImageDrawLineEx(&img,384,344,418,344,1,color);
	return img;
}

Image genShrinkImage0() {
	Image img = GenImageColor(800,600, BLANK);
	Color fillColor=WHITE;
	Color color=BLACK;
	ImageFillRoundRectEx(&img,337, 131, 63, 74, 28, 28, fillColor);			// 右眼
	ImageFillRoundRectEx(&img,400, 131, 63, 74, 28, 28, fillColor);			// 左眼
	ImageDrawRoundRectEx(&img,337, 131, 63, 74, 28, 28,1, color);			
	ImageDrawRoundRectEx(&img,400, 131, 63, 74, 28, 28,1, color);	
	
	fillColor = BLACK;
	ImageFillCircleEx(&img,384,184,6, fillColor);							// 右眼球
	ImageFillCircleEx(&img,416,184,6, fillColor);							// 左眼球
	fillColor = (Color){201, 62, 0, 255};						// 鼻子
	ImageFillCircleEx(&img, 400, 208, 15, fillColor);
	return img;
}

Image genShrinkImage1() {
	Image img = GenImageColor(800,600, BLANK);
	Color fillColor=WHITE;
	Color color=BLACK;
	ImageFillRoundRectEx(&img,337, 131, 63, 74, 28, 28, fillColor);			// 右眼
	ImageFillRoundRectEx(&img,400, 131, 63, 74, 28, 28, fillColor);			// 左眼
	ImageDrawRoundRectEx(&img,337, 150, 63, 37, 28, 28, 1, color);
	ImageDrawRoundRectEx(&img,400, 150, 63, 37, 28, 28, 1, color);
	
	ImageFillRectangleEx(&img,337,168,63,19,fillColor);
	ImageFillRectangleEx(&img,400,168,63,19,fillColor);
	
	ImageDrawRoundRectEx(&img,337, 131, 63, 74, 28, 28,1, color);			
	ImageDrawRoundRectEx(&img,400, 131, 63, 74, 28, 28,1, color);	
	
	fillColor = BLACK;
	ImageFillCircleEx(&img,384,184,6, fillColor);							// 右眼球
	ImageFillCircleEx(&img,416,184,6, fillColor);							// 左眼球
	fillColor = (Color){201, 62, 0, 255};						// 鼻子
	ImageFillCircleEx(&img, 400, 208, 15, fillColor);
	return img;
}

Image genShrinkImage2() {
	Image img=GenImageColor(800,600,BLANK);
	Color fillColor=WHITE;
	Color color=BLACK;
	ImageFillRoundRectEx(&img,337, 131, 63, 74, 28, 28, fillColor);			// 右眼
	ImageFillRoundRectEx(&img,400, 131, 63, 74, 28, 28, fillColor);			// 左眼
	
	ImageDrawLineEx(&img,337,168,399,168,1,color);
	ImageDrawLineEx(&img,400,168,462,168,1,color);
	
	ImageDrawRoundRectEx(&img,337, 131, 63, 74, 28, 28,1, color);			
	ImageDrawRoundRectEx(&img,400, 131, 63, 74, 28, 28,1, color);
	fillColor = (Color){201, 62, 0, 255};						// 鼻子
	ImageFillCircleEx(&img, 400, 208, 15, fillColor);
	return img;
}

Image genShrinkImage3(){
	Image img=GenImageColor(800,600,BLANK);
	Color fillColor=WHITE;
	Color color=BLACK;
	ImageFillRoundRectEx(&img,337, 131, 63, 74, 28, 28, fillColor);			// 右眼
	ImageFillRoundRectEx(&img,400, 131, 63, 74, 28, 28, fillColor);			// 左眼
	ImageDrawRoundRectEx(&img,337, 150, 63, 37, 28, 28, 1, color);
	ImageDrawRoundRectEx(&img,400, 150, 63, 37, 28, 28, 1, color);
	
	ImageFillRectangleEx(&img,337,150,63,19,fillColor);
	ImageFillRectangleEx(&img,400,150,63,19,fillColor);
	
	ImageDrawRoundRectEx(&img,337, 131, 63, 74, 28, 28,1, color);			
	ImageDrawRoundRectEx(&img,400, 131, 63, 74, 28, 28,1, color);
	fillColor = (Color){201, 62, 0, 255};						// 鼻子
	ImageFillCircleEx(&img, 400, 208, 15, fillColor);
	return img;
}

Image genShrinkImage4() {
	Image img=GenImageColor(800,600,BLANK);
	Color fillColor=WHITE;
	Color color=BLACK;
	ImageFillRoundRectEx(&img,337, 131, 63, 74, 28, 28, fillColor);			// 右眼
	ImageFillRoundRectEx(&img,400, 131, 63, 74, 28, 28, fillColor);			// 左眼
	
	ImageDrawRoundRectEx(&img,337, 131, 63, 74, 28, 28,1, color);			
	ImageDrawRoundRectEx(&img,400, 131, 63, 74, 28, 28,1, color);	
	fillColor = (Color){201, 62, 0, 255};						// 鼻子
	ImageFillCircleEx(&img, 400, 208, 15, fillColor);
	return img;
}

函数列表

函数名 功能
ImageDrawPointEx 使用指定的大小,在Image对象中画一个点
ImageDrawArcEx 使用指定的线宽和颜色,在Image对象中画一段椭圆弧
ImageDrawCubicBezierEx 使用指定的线宽和颜色,绘制三次贝塞尔曲线
ImageDrawLineEx 使用指定的线宽和颜色,在Image对象中画一条线段
ImageDrawPolylineEx 使用指定的线宽和颜色,在Image对象中画一条多义线(polyline)
ImageDrawRectangleEx 使用指定的线宽和颜色,在Image对象中画一个矩形(仅轮廓线)
ImageDrawRoundRectEx 使用指定的线宽和颜色,在Image对象中画一个圆角矩形(仅轮廓线)
ImageDrawCircleEx 使用指定的线宽和颜色,在Image对象中画一个圆(仅轮廓线)
ImageDrawEllipseEx 使用指定的线宽和颜色,在Image对象中画一个椭圆(仅轮廓线)
ImageDrawPolygonEx 使用指定的线宽和颜色,在Image对象中画一个多边形(仅轮廓线)
ImageDrawSectorEx 使用指定的线宽和颜色,在Image对象中画一个扇形(仅轮廓线)
ImageFillCircleEx 使用指定的颜色,绘制一个填充的圆
ImageFillEllipseEx 使用指定的颜色,绘制一个填充的椭圆
ImageFillTriangleEx 使用指定的颜色,绘制一个填充的三角形
ImageFillRectangleEx 使用指定的颜色,绘制一个填充的矩形
ImageFillRoundRectEx 使用指定的颜色,绘制一个填充的圆角矩形
ImageFillPolygonEx 使用指定的颜色,绘制一个填充的多边形
ImageFillSectorEx 使用指定的颜色,绘制一个填充的扇形
ImageFloodFill 泛洪填充(当遇到颜色为border color的像素时停止)

4 - 海龟作图(rturtle)

基于raylib和rdrawing的海龟作图库

rturtle教程

5 - {fmt}

{fmt}是一个开源的格式化库,用于替代C的stdio和C++的iostream。

特色:

  • 简便的格式化API,提供本地化用的位置参数。
  • 实现C++ 20 std::format
  • 和python的format类似的格式化字符串语法
  • 使用Dragonbox算法提供快速IEEE 754浮点数格式化和舍入,
  • 可移植的Unicode支持
  • 安全的printf实现,包括POSIX位置参数扩展。
  • 可扩展:支持用户自定义类型
  • 高效:比默认的标准库实现中的(s)printf、iostream、to_string和to_chars更快
  • 源代码和编译后代码尺寸小
  • 可靠:拥有广泛的测试并持续改进
  • 容易使用:无外部依赖,MIT许可
  • 可移植性:在不同平台上提供一致的输出结果,支持旧编译器
  • 代码整洁,不会产生编译警告
  • 默认与本地化环境(Locale)无关
  • 通过FMT_HEADR_ONLY宏,可以作为header-only库使用

代码示例

打印到标准输出

#include <fmt/core.h>

int main() {
  fmt::print("Hello, world!\n");
}

格式化字符串

std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."
Format a string using positional arguments (run)

std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."

打印chrono时长

#include <fmt/chrono.h>

int main() {
  using namespace std::literals::chrono_literals;
  fmt::print("Default format: {} {}\n", 42s, 100ms);
  fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}

输出:

Default format: 42s 100ms
strftime-like format: 03:15:30

打印容器

#include <vector>
#include <fmt/ranges.h>

int main() {
  std::vector<int> v = {1, 2, 3};
  fmt::print("{}\n", v);
}

输出:

[1, 2, 3]

在编译期检查格式化字符串

下面的代码在C++20中产生编译器错误,因为对字符串参数来说d是非法的格式符

std::string s = fmt::format("{:d}", "I am not a number");

输出到文件

#include <fmt/os.h>

int main() {
  auto out = fmt::output_file("guide.txt");
  out.print("Don't {}", "Panic");
}

运行速度是fprintf的5到9倍。