一、准备

最近,闲来无事,研究了一下SDL2,发现SDL2作为一个开放的平台,确实比较简单,而且在多媒体方面,图像操作方面,跨平台方面确实有优势,实在不行了还有源码可以参考,但也有其不方便的一面,如没有文字显示功能,一个简单的抠图,就难倒一片人,2D作图还行,3D作图就更困难了。OpenGL作为同样跨平台的工具,在2D,3D方面有其独到之处,特别是在可编程管线方面,更加灵活高效。当然,还有一个选择就是QT,但QT也有其不足之处,尤其是发布时体量过大,如不搞大型工程,没有必要。另外,QT自成体系,学习起来需要付出一定的代价。

SDL2目前已经发布到2.20稳定版了,我的感觉,有2.07版就够用的 了。当然在新的版本开发也不错。

OpenGL就更加复杂了,网上的资料有的很陈旧,OpenGL本身也没有像SDL一样的持续发布的系统,还有,OpenGL自身就是一个状态机,在多线程方面有其天生的缺陷,不过与SDL2结合起来没有问题,因为SDL2自身,在显示方面,多线程就是一个弱项。

SDL2 与OpenGL结合,OpenGL版本有2.1就够用了,版本过高,在跨平台时可能会有问题。当然也可以选用更高的版本,但从所需要的功能来看,2.1已经够用了,如不设置,SDL2缺省是使用OpenGL 2.1,目前,win10所支持的版本为4.2,在win10上可能选用更高的版本,但从解决需求的角度来看,没有必要。版本高了没法向下兼容。

SDL2 直接从网上下载安装就行了,这里我就不再多重复了,这里重点说OpenGL版本,在SDL2 上OpenGL可以直接用,有例子可以直接参考,但受到很大局限,只能支持固定管线,而OpenGL用到的是GLSL 可编程管线,只能求助第三方工具,网上的资料多数用到GLUT,这是一个老掉牙的东西,2000年之后就没有过更新,而且,只支持32位,我一看就连碰都不碰,推荐可选的有GLAD和GLEW,GLAD的优势是不需要额外的库,使用简单,GLEW的优势是功能齐全,一个库包含了OPENGL所有的东西。可根据情况选用。至于资源,网上都有,到官网上下就可以了,就不重复了。

GLAD和GLEW都不需要安装,直接将相关文件解压后拷贝到相关目录中就可以了。

这是Iib目录文件分 x86和 x64

Sdl2dll

Sdl2.lib

Sdl2main.lib

Glew32.lib

Glew32s.lib

在以上工作完成之后 ,就可以开始编程了

我用的是VS2019

先是建立一个空的C++控制台项目 我是建立一个名为glsdltest的项目,在D盘根目录 下,

在vs2019主页面上点击文件->新建,选择建立空的C++控制台项目,选择项目名和所

在目录,完成即可,

要使用SDL和OpenGL在完成新建空项目后进行以下几步工作

1.是添加包含目录 打开项目->属性,打开VC++项,所有平台

在包含目录上加上 SDL2和附件目录 我的电脑是这样:

d:\sdl2\include;$(IncludePath)

2.添加库目录 32位和64位平台分别加

32位X86下,在库目录上添加库的目录,我的电脑是这样

d:\sdl2\lib\x86;$(LibraryPath)

如使用64位编程,在x64下添加库目录 我的电脑是这样 :

d:\sdl2\lib\x64;$(LibraryPath)

3.添加链接资源,点开链接器  在输入->附加依赖项加加上相关资源 我的电脑是这样

winmm.lib;opengl32.lib;sdl2.lib;sdl2main.lib;glew32s.lib;%(AdditionalDependencies);

其中:只用GLAD的,可以不加glew32s.lib;

4.建议,将VS 默认字符集改为UTF8 字符集。

到这里,编程环境就基本上配置好了。

现在可以按F5编译运行了,因为没有输入任何新的语句,程序跳出控制台,打印Hello World!

然后提示结束。

5.如使用GLAD请将glad.c 拷贝到项目目录下,并使用项目->添加现有项,加入项目中。

准备工作至此结束。

#include <iostream>int main()
{std::cout << "Hello World!\n";
}

二、第一个窗口

在SDL2上建立一个窗口是很简单的,由于是C++程序,我们需要新建一个类,点击项目->添加类

CMain 将main函数改成以下这个样子

main.app


#include "cmain.h"
#include <SDL.h>int main(int argc, char* argv[])
{SDL_Init((Uint32)(SDL_INIT_VIDEO));CMain a;return 0;
}

这时按下F5试一下,在X86下正常,但x64下报错,0xc000007b 这是DLL文件位数错,将64位的SDL.DLL拷贝到生成目录下就可以了,32位运行环境也需要将相应的SDL.DLL拷贝到相应生成目录中去,注意运行、调试,32位,64位共有4个目录,每个目录都需要拷贝。如只将SDL.DLL拷贝到运行目录中,一但更换编译位数,就会报错。好,继续往下进行。

打开一个窗口很简单,在cmain.app 和cmain.h 输入如下

cmain.h

#pragma once
#include <SDL.h>//系统基本显示画面尺度
#define PictureWidth   640
#define PictureHeight  400#define RealWidth  640
#define RealHeight 400#define WindowWidth  800
#define WindowHeight 500class CMain
{
public:SDL_Window* gpWindow;SDL_Renderer* gpSdlRender;CMain();
};

cmain.app

#include "cmain.h"CMain::CMain():gpWindow(nullptr),gpSdlRender(nullptr)
{//建立窗口 不显示gpWindow = SDL_CreateWindow("SDL2 + Opengl 演示 ......",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WindowWidth, WindowHeight,SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);//在此加载其他内容//显示窗口SDL_ShowWindow(gpWindow);//延时5秒SDL_Delay(5000);
}

这时按F5还会报错,没有找到入口,,这时,需要定义程序的入口点,按下项目->属性->链接器->系统->子系统,将入口修改为WinDow窗口,这时按F5一个窗口出现在我们面前,延时5秒后自动退出。

三、加入OpenGL

以上操作还不涉及OpenGL,在头文件 上输入以下代码:

#define  GLAD
//#define GLEW#ifdef  GLEW
#define GLEW_STATIC
#endif//如不显示文字,可注释掉以下语句
#include <Windows.h>#ifdef GLAD
#include <glad/glad.h>
#else#ifdef GLEW
#include <GL/glew.h>
#else #include <GL/GL.h>
#include <GL/GLU.h>
#define GL_GLEXT_PROTOTYPES
#include <SDL_opengl.h>
#include <SDL_opengl_glext.h>
#endif#endif

这样可以方便的在GLAD和GLEW之间切换,

另一部分代码在窗口和渲染器建立之后载入,载入的代码和顺序如下:

    glPreInit();gpWindow = SDL_CreateWindow("SDL2 + Opengl 演示 ......",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WindowWidth, WindowHeight,SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
#if 0//置opengl 上下文,gpgl_Context = SDL_GL_CreateContext(gpWindow);if (!gpgl_Context)exit(2);#elsegpSdlRender = SDL_CreateRenderer(gpWindow, -1, SDL_RENDERER_ACCELERATED);//检查是否支持OPENGL,如不支持退出,退出码 8SDL_RendererInfo rendererInfo;SDL_GetRendererInfo(gpSdlRender, &rendererInfo);if (strncmp(rendererInfo.name, "opengl", 6)) exit(8);#endif
#ifdef GLAD//装入glad函数指针if (!gladLoadGLLoader(SDL_GL_GetProcAddress))exit(2);
#else#ifdef GLEWif (glewInit())exit(2);
#endif#endif

这里要说明的是,载入OpenGL上下文有两种方法,可以用SDL2自带的SDL_CreateRenderer,如果该渲染器支持OpenGL,也可以用SDL2建立OpenGL上下文命令SDL_GL_CreateContext。if(0)改成if(1)都可以,反正我的运行环境都支持。如果不先输入

SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");

这条命令,SDL2建立的渲染器可能不支持OPENGL上下文。

还有,glPreInit();要在窗口建立之前:内容见最后的例子:

注意!如想在OpenGL的着色器中使用SDL纹理,必须使用SDL 的渲染器隐式提供的OpenGL上下文,而不能使用OpenGL上下文,。

至此,已经可以运行OpenGL的各项命令了。

四、OpenGL坐标体系

OpenGL坐标体系非常复杂,有2D坐标系(x,y),3D坐标系,(x,y,z),正投影。透视投影,裁剪坐标系,视觉坐标系,世界坐标系,物体坐标系,彻底搞清楚这些坐标的区别和变换方法,需要很长的时间,好在目前需要的是与SDL2相适应的坐标方式,既最简单的2D变换方式,所谓2D变换方式,主要涉及点与点之间,面与面之间,矩形与矩形之间的简单变换。如在window图形编程中经常用到的    BitBlt 函数,可以实现不同矩形之间图像的拷贝和变换。而OpenGL作为图像处理专用工具,在2D作图时,不仅可以在不同的图像之间拷贝、转换和融合,还可以对图像轻而易举的进行拉伸和拓扑变形,对图像进行各种魔幻般的变换。为了实现这些功能,OpenGL最小2D坐标单元,是一个又一个的三角形,各种矩形和其他复杂的形状,都是由一个个的三角形拼接而成的。这些三角形的顶点,构成OpenGL的顶点坐标系。无论多复杂的图形,多复杂的物体,落实到计算机屏幕,都要统一成一个平面,因此2D坐标系是OpenGL的最终表现形式,而三角顶点坐标构成OpenGL的基本顶点坐标系。

有了三角顶点坐标,可以拼接几乎任意的图形,最简单的是矩形拼接,由两个三角形组成,我们定义矩形的四个顶点,每个顶点由两个数字(x,y)组成,共有8个数字,但如果是正四边形,只要用四个数字就可以描述了。SDL中有一个描述矩形的结构 SDL_Rect 分别是左上角的坐标和矩形的长度和宽度,而所有计算机的图片,都是正四边形的,这些图片的任意矩形边界,都可以用该结构描述。事实是OpenGL对图片(纹理)的描述,用的(u,v)坐标系,正好能从上述结构转换而成。

OpenGL对坐标进行归一化处理,正常情况下,顶点坐标范围在-1到1之间,纹理坐标在0到1之间。而且,颜色深度等计量范围大都在绝对值1的范围内,这与其他图形处理系统,有很大的区别。这样做的优点是很明显的,一是不同大小的纹理,可以统一处理,省去了不少计算量,二是,对不同大小的渲染目标,也可以统一处理。

顶点坐标载入有多种方法,一是逐个三角形输入,一个矩形有两个三角形组成,需要载入6个顶点,如矩形{a左下,b左上,c右上,d右下},第一个三角形{a,b,c},第二个三角形{a,c,d},共需要6个点的坐标,二是连续三角形输入,三是三角扇形多边形输入,对于矩形,只需要输入4个点,{a,b,c,d},这是在sdl+OPengl中用得最多的。

对于纹理坐标就比较简单了,按矩形{a,b,c,d}逐点输入就可以了。之后的例子中将介绍到。

五、GLSL 着色器

对于SDL2与OpenGL结合应用来讲,GLSL着色器及其相关操作非常关键,也是整个应用程序显示效率提高的关键,与SDL2纹理一样,GLSL着色器及其相关操作是针对GPU的,OpenGL实际起到扩展和补充SDL纹理的作用,而且因其可编程的特点,使用起来更加灵活便利。在这里我不想介绍其语法之类的东西,只介绍如何操作,如何具体使用。

GLSL  着色器有两种编制形式,一是文件,一是字符串,如何使用全凭个人喜好。以下就是顶点着色器字符串的简单形式

const static GLchar* const vertexShader =
"#version 130\n\
in vec2 position;\n\
in vec2 TexCoord;\n\
out vec2 sTexCoord;\n\
void main()\n\
{\gl_Position = vec4(position, 0.0, 1.0) ;\n\sTexCoord = TexCoord ;\
}";

注意:中间行每行用 “\”结束,后面不能有可见和不可见字符,字符串最后面记得加分号,否则会报错。注释行必须以“\n\”结束,否则,就认为下一行接着注释。

片元着色器:

const static GLchar* const fragmentShader =
"#version 130\n\
uniform sampler2D v_tex;\n\
in vec2 sTexCoord;\n\
out vec4 outColor;\n\
void main()\n\
{\outColor  = texture(v_tex,sTexCoord);\
}" ;

做过GLSL的会发现,以上着色器中间只载入了一个2D纹理,而没有载入顶点颜色,这是因为在针对SDL2的应用中,还未发现顶点颜色的用途。以上着色器的实际作用是将纹理渲染出来。

着色器的载入和编译,

 inline GLuint loadShader(GLenum shaderType, const GLchar* source){GLuint shaderId = glCreateShader(shaderType);glShaderSource(shaderId, 1, &source, NULL);glCompileShader(shaderId);GLint result = GL_FALSE;glGetShaderiv(shaderId, GL_COMPILE_STATUS, &result);return shaderId;}inline GLuint compileProgram(GLuint fragmentShaderId, GLuint vertexShaderId){GLuint programId = glCreateProgram();glAttachShader(programId, vertexShaderId);glAttachShader(programId, fragmentShaderId);glLinkProgram(programId);return programId;}//编译着色器,返回应该是大于0的正数v_verticesID = loadShader(GL_VERTEX_SHADER, vertexShader);v_fragmentID = loadShader(GL_FRAGMENT_SHADER, fragmentShader);v_programID = compileProgram(v_verticesID, v_fragmentID);

六、OpenGL纹理和SDL纹理

由于是状态机的关系,OpenGL纹理在系统内部调用只是用 了一个正整数,而不是像其他系统要用固定的结构和指针来描述,管理纹理并没有统一的结构,每个开发者管理纹理所使用的结构不一定相同,这给开发者以更大的自由度的同时,也带来了更大的难度。所幸的是,SDL纹理在设计时,设计成可以作为GLSL纹理使用,这大大地方便了开发者,这比单独用OpenGL开发简单的多了,这也是sdl与OpenGL的GLSL结合开发的优势所在。

sdl纹理建立有多种方式,可以直接新建空纹理,也可以从SDL表面上建立

例如根据BMP文件建立纹理,只需要3步

 //以下载入图片生成纹理SDL_Surface* tst1 = SDL_LoadBMP("tst1.bmp");SDL_Texture* txt1 = SDL_CreateTextureFromSurface(gpSdlRender, tst1);SDL_FreeSurface(tst1);

第一步将图片生成SDL表面,第二步根据渲染器和表面生成纹理,第三步删除表面。

由此可以提出,使用SDL纹理是相当简单的事情,甚至不用关心纹理的内部结构。

对纹理的使用也相当简单,

        glEnable(GL_TEXTURE_2D);//绑定第一个纹理if(rpText1){glActiveTexture(GL_TEXTURE0);SDL_GL_BindTexture(rpText1, 0, 0);}//绑定第二个纹理if(rpText2){glActiveTexture(GL_TEXTURE1);SDL_GL_BindTexture(rpText2, 0, 0);}

使用完成之后,释放资源

    glActiveTexture(GL_TEXTURE0);if(rpText1) SDL_GL_UnbindTexture(rpText1);glActiveTexture(GL_TEXTURE1);if (rpText2) SDL_GL_UnbindTexture(rpText2);

渲染到纹理,是OpenGL结合进SDL2的一个重要功能,渲染到纹理,能极大的提高渲染效果,简化GLSL的设计,将一些复杂的渲染过程,简化到分多个简单步骤来实现。

我们要渲染的对象叫帧缓存。也叫FBO。帧缓存是一个包含纹理和深度缓存(可选择)区的容器。 由于是2D应用,作为渲染的纹理,可以使用32位的RGBA,如果是3D 应用,还应该加上一个深度纹理。

所幸的是,sdl2同样设计了渲染到纹理,可以将一个纹理作为渲染对象,加入渲染器中,这时所有的渲染结果不再是屏幕,而是绑入渲染器的纹理。至于深度缓存什么的,也不必单独设置,只要在窗口建立之前,设置一个参数就可以了。当然,OpenGL在单独使用时,支持一次渲染到多个纹理,但sdl2目前并不支持。

渲染到SDL2纹理也很简单,一是建立纹理时需要单独声明,

    gpRenderTexture = SDL_CreateTexture(gpSdlRender, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,RealWidth, RealHeight);

共有5个参数,第一个参数是所依托的渲染器指针,第二项是格式,ARGB 从高到低各占8个字节。第三项必须指明可以作为渲染目标,第四第五项是宽度和高度。

二是需要绑定

SDL_SetRenderTarget(gpSdlRender, rpRender);

如第二个参数为0 则去除绑定,所有输入将指向窗口。

七、向GLSL输入参数

总的说,GLSL参数着色器接收两类参数,一类是坐标,一类是常数(变量),这两类参数输入所用的方法是完全不一的,其中坐标输入有很多种方案可供选择,什么VBO,VAO等等,而且不同的OpenGL版本支持的方案也不完全相同,这里作为SDL2的应用,只介绍最直接,最简单的方案。

读取GLSL变量ID

顶点变量 ID

    v_texcoordID = glGetAttribLocation(v_programID, "TexCoord");v_vertexID = glGetAttribLocation(v_programID, "position");

常量ID

    v_texID = glGetUniformLocation(v_programID, "v_tex");v_tex1ID = glGetUniformLocation(v_programID, "v_tex1");v_dataID = glGetUniformLocation(v_programID, "v_data");

使用

    glUseProgram(v_programID);glEnableVertexAttribArray(v_vertexID);glEnableVertexAttribArray(v_texcoordID);//数据glUniform4fv(v_dataID, 20, (const float*)dataBuf);//纹理IDglUniform1i(v_texID, 0);glUniform1i(v_tex1ID, 1);

其中datBuf是一个SDL_fColor数组,因为应用中要载入两个调色版和其他一些控制数据,将其放入一个数组中比较方便。

typedef struct SDL_fColor
{GLfloat r;GLfloat g;GLfloat b;GLfloat a;
} SDL_fColor;

sdl坐标与OpenGL坐标转换见后面的例子中。setRectToArr函数。

至此,在SDL2环境下运行OpenGL的GLSL着色器所有的环节已经介绍完成了,其实现顺序如下:

准备阶段:初始化SDL,运行SDL的OpenGL前置程序,建立SDL渲染器,运行GLAD或GLEW载入命令。初始阶段:编制顶点着色器,片元着色器,编译着色器,取着色器变量ID,准备SDL纹理。运行阶段:绑定纹理,对着色器赋值,运行glDrawArrays函数,然后运行SDL_GL_SwapWindow 或SDL_RenderPresent,最后清理。一个最简单的示例如下:

cmain.app

//cmain.cpp
#include "cmain.h"const static GLchar* const vertexShader =
"#version 130\n\
in vec2 position;\n\
in vec2 TexCoord;\n\
out vec2 sTexCoord;\n\
void main()\n\
{\n\gl_Position = vec4(position, 0.0, 1.0) ;\n\sTexCoord = TexCoord ;\n\
}";const static GLchar* const fragmentShader =
"#version 130\n\
uniform vec4 v_data[20];\n\
uniform sampler2D v_tex;\n\
uniform sampler2D v_tex1;\n\
in vec2 sTexCoord;\n\
out vec4 outColor;\n\
void main()\n\
{\n\
//数组v_data 0 color,1 mode\n\
//mode.x ==mode ,mode.y = alpha\n\
\n\
vec4 v_color = v_data[0];\n\
vec4 v_mode = v_data[1];\n\
\n\
vec4 t0 = texture(v_tex,sTexCoord);\n\
vec4 t1 = texture(v_tex1,sTexCoord);\n\
int x = int(v_mode.x +0.001);\n\
if(x == 0)\n\
//混合两个纹理\n\{ \n\outColor = t0 * v_mode.y + t1 * (1.0 - v_mode.y);\n\outColor *= v_color;\n\outColor.a = 1.0;\n\}\n\
if(x == 1)\n\
//拷贝后乘Alpha\n\{\n\outColor = t0;\n\outColor *= v_color;\n\outColor *= v_mode.y;\n\outColor.a = 1.0;\n\}\n\
if(x == 3)\n\
//过滤全为零在点\n\{\n\if((t0.r ==  0.0 && t0.g == 0.0 && t0.b == 0.0 && t0.a == 0.0)  )\n\{\//抛弃 \n \discard;\}\n\outColor = t0;\n\outColor *= v_color;\n\outColor *= v_mode.y;\n\outColor.a = 1.0;\n\}\n\
if(x == 6)\n\
//执行字模拷贝,用取得的纹理颜色值乘颜色\n\{\n\if((t0.r < 0.1  )  )\n\{\//抛弃 \n \discard;\}\n\outColor = v_color;// * t0.r;\n\outColor *= v_mode.y;\n\outColor.a = 1.0;\n\}\n\
if(x == 10.0)\n\
//翻转屏幕\n\
{\n\outColor = texture(v_tex,vec2(sTexCoord.x,1.0 - sTexCoord.y));\n\
}\n\
}";CMain::CMain()
{glPreInit();gpWindow = SDL_CreateWindow("SDL2 + Opengl 演示 ......",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WindowWidth, WindowHeight,SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");gpSdlRender = SDL_CreateRenderer(gpWindow, -1, SDL_RENDERER_ACCELERATED);
#ifdef GLAD//装入glad函数指针if (!gladLoadGLLoader(SDL_GL_GetProcAddress))exit(2);
#else#ifdef GLEWif (glewInit())exit(2);
#endif#endif//creat GLSL SHADERv_verticesID = loadShader(GL_VERTEX_SHADER, vertexShader);v_fragmentID = loadShader(GL_FRAGMENT_SHADER, fragmentShader);v_programID = compileProgram(v_verticesID, v_fragmentID);v_texID = glGetUniformLocation(v_programID, "v_tex");v_tex1ID = glGetUniformLocation(v_programID, "v_tex1");v_dataID = glGetUniformLocation(v_programID, "v_data");v_texcoordID = glGetAttribLocation(v_programID, "TexCoord");v_vertexID = glGetAttribLocation(v_programID, "position");SDL_Event evt;//以下载入图片生成纹理SDL_Surface* tst1 = SDL_LoadBMP("tst1.bmp");SDL_Texture* txt1 = SDL_CreateTextureFromSurface(gpSdlRender, tst1);SDL_FreeSurface(tst1);SDL_ShowWindow(gpWindow);RenderBlendCopy(gpRenderTexture, txt1);RenderPresent(gpRenderTexture);while (true){while (SDL_PollEvent(&evt)){if (evt.type == SDL_QUIT){SDL_DestroyTexture(txt1);return;}}SDL_Delay(10);}
}VOID CMain::RenderBlendCopy(SDL_Texture* rpRender, SDL_Texture* rpText1, SDL_Texture* rpText2, const WORD rAlpha, const WORD mode, const SDL_Color* rColor, const SDL_Rect* dstRect, const SDL_Rect* srcRect)
{/*模式功能//mode = 0.0 混合 v_mode.y 混合因子//mode = 1.0 拷贝后乘颜色//mode = 2.0 置成单一颜色//mode = 3.0 过滤拷贝全为零的点不拷贝//mode = 4.0 与颜色混合,v_mode.y 混合因子//mode = 6.0 显示字模//mode = 10.0 实现显示反转* */{SIZE msSize = { PictureWidth,PictureHeight };if (rpText1){SDL_QueryTexture(rpText1, 0, 0, (int*)&msSize.cx, (int*)&msSize.cy);}else if (rpText2)SDL_QueryTexture(rpText1, 0, 0, (int*)&msSize.cx, (int*)&msSize.cy);elsemsSize = { 0,0 };SIZE mdSize = { RealWidth,RealHeight };if (rpRender){SDL_QueryTexture(rpRender, 0, 0, (int*)&mdSize.cx, (int*)&mdSize.cy);glViewport(0, 0, mdSize.cx, mdSize.cy);}else{SDL_Rect zView = { 0,0,0,0 };SDL_GetWindowSize(gpWindow, &zView.w, &zView.h);if (KeepAspectRatio && (fabs((double)zView.w / zView.h - 1.6) > 0.02)){double ra = (double)zView.w / zView.h - 1.6;if (ra > 0){zView.x = (zView.w - zView.h * 1.6) / 2;zView.w -= zView.x * 2;}else{zView.y = (zView.h - zView.w / 1.6) / 2;zView.h -= zView.y * 2;}}glViewport(zView.x, zView.y, zView.w, zView.h);}setRectToArr(srcRect, dstRect, msSize, mdSize);SDL_Color vColor = { 255,255,255,255 };if (rColor == NULL)rColor = &vColor;elserColor = rColor;int err = 0;err = glGetError() + err;// 绑定渲染目标if (SDL_SetRenderTarget(gpSdlRender, rpRender))exit(9);glActiveTexture(GL_TEXTURE0);if (rpText1){glEnable(GL_TEXTURE_2D);glActiveTexture(GL_TEXTURE0);SDL_GL_BindTexture(rpText1, 0, 0);}if (rpText2){glEnable(GL_TEXTURE_2D);glActiveTexture(GL_TEXTURE1);SDL_GL_BindTexture(rpText2, 0, 0);}glUseProgram(v_programID);glEnableVertexAttribArray(v_vertexID);glEnableVertexAttribArray(v_texcoordID);err = glGetError() + err;glVertexAttribPointer(v_vertexID, 2, GL_FLOAT, GL_FALSE, 0, g_vertices);glVertexAttribPointer(v_texcoordID, 2, GL_FLOAT, GL_FALSE, 0, g_texcoord);err = glGetError() + err;SDL_fColor dataBuf[20];dataBuf[0] = { (GLfloat)(rColor->r * Div255),(GLfloat)(rColor->g * Div255),(GLfloat)(rColor->b * Div255),(GLfloat)(rColor->a * Div255) };dataBuf[1] = { (GLfloat)(mode), (GLfloat)(rAlpha * Div255) ,0.0,0.0 };glUniform4fv(v_dataID, 20, (const float*)dataBuf);glUniform1i(v_texID, 0);glUniform1i(v_tex1ID, 1);glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glDisableVertexAttribArray(v_vertexID);glDisableVertexAttribArray(v_texcoordID);glActiveTexture(GL_TEXTURE0);if (rpText1) SDL_GL_UnbindTexture(rpText1);glActiveTexture(GL_TEXTURE1);if (rpText2) SDL_GL_UnbindTexture(rpText2);SDL_SetRenderTarget(gpSdlRender, 0);glUseProgram(0);glDisable(GL_TEXTURE_2D);}
}VOID CMain::RenderPresent(SDL_Texture* text)
{RenderBlendCopy(NULL, text, NULL, 255, 10);SDL_GL_SwapWindow(gpWindow);//SDL_RenderPresent(gpSdlRender);
}VOID CMain::glPreInit()
{//要求在主窗口建立之前//opengl 3.1//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);//SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); //设置多缓存的个数//SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
}

cmain.h

#pragma once
#ifndef CMAIN_H
#define CMAIN_H
#define  GLAD
//#define GLEW #ifdef  GLEW
#define GLEW_STATIC
#endif#include <Windows.h>#ifdef GLAD
#include <glad/glad.h>
#else#ifdef GLEW
#include <GL/glew.h>
#else #include <GL/GL.h>
#include <GL/GLU.h>
#define GL_GLEXT_PROTOTYPES
#include <SDL_opengl.h>
#include <SDL_opengl_glext.h>
#endif#endif#include <SDL.h>using namespace std;//系统基本显示画面尺度
#define PictureWidth   640
#define PictureHeight  400#define RealWidth  640
#define RealHeight 400#define WindowWidth  800
#define WindowHeight 500const GLfloat Div255 = 1.0F / 255.0F;//保持图片显示比例
const int KeepAspectRatio = 1;typedef struct SDL_fColor
{GLfloat r;GLfloat g;GLfloat b;GLfloat a;
} SDL_fColor;class CMain
{
public:SDL_Window* gpWindow = NULL;SDL_Renderer* gpSdlRender = NULL;SDL_Texture* gpRenderTexture = NULL;
public:CMain();VOID RenderBlendCopy(SDL_Texture* rpRender, SDL_Texture* rpText1, SDL_Texture* rpText2 = NULL,const WORD rAlpha = 255, const WORD mode = 1, const SDL_Color* rColor = NULL,const SDL_Rect* dstRect = NULL, const SDL_Rect* srcRect = NULL);VOID RenderPresent(SDL_Texture* text);private:VOID glPreInit();GLfloat g_vertices[8] = {0};//位置顶点数组GLfloat g_texcoord[8] = {0};//纹理顶点数组GLuint v_verticesID = 0;//顶点IDGLuint v_fragmentID = 0;//片断IDGLuint v_programID = 0;//GLSL过程IDGLint  v_vertexID = 0;    //位置顶点数组IDGLint  v_texcoordID = 0; //纹理顶点数组1IDGLint  v_texID = 0;//纹理1 IDGLint  v_tex1ID = 0;//纹理2 IDGLint  v_dataID = 0;//数据数组ID
private:inline GLuint loadShader(GLenum shaderType, const GLchar* source){GLuint shaderId = glCreateShader(shaderType);glShaderSource(shaderId, 1, &source, NULL);glCompileShader(shaderId);GLint result = GL_FALSE;glGetShaderiv(shaderId, GL_COMPILE_STATUS, &result);return shaderId;}inline GLuint compileProgram(GLuint fragmentShaderId, GLuint vertexShaderId){GLuint programId = glCreateProgram();glAttachShader(programId, vertexShaderId);glAttachShader(programId, fragmentShaderId);glLinkProgram(programId);return programId;}inline VOID setRectToArr(const SDL_Rect* src, const SDL_Rect* dst, const SIZE srcSize, const SIZE  dstSize){//转换成数组GLfloat minx, miny, maxx, maxy;GLfloat minu, maxu, minv, maxv;if (dst && dst->w && dst->h && dstSize.cx && dstSize.cy){minx = (GLfloat)dst->x / (GLfloat)dstSize.cx * 2.0F - 1.0F;maxx = (GLfloat)(dst->x + dst->w) / (GLfloat)dstSize.cx * 2.0F - 1.0F;miny = (GLfloat)dst->y / dstSize.cy * 2.0F - 1.0F;maxy = (GLfloat)(dst->y + dst->h) / (GLfloat)dstSize.cy * 2.0F - 1.0F;}else{minx = -1.0f;maxx = 1.0f;miny = -1.0f;maxy = 1.0f;}if (src && src->w && src->h && srcSize.cx && srcSize.cy){minu = ((GLfloat)src->x / (GLfloat)srcSize.cx);maxu = ((GLfloat)src->x + src->w) / (GLfloat)srcSize.cx;minv = ((GLfloat)src->y / (GLfloat)srcSize.cy);maxv = ((GLfloat)(src->y + src->h)) / (GLfloat)srcSize.cy;}else{minu = 0.0f;maxu = 1.0f;minv = 0.0f;maxv = 1.0f;}g_vertices[0] = minx;g_vertices[1] = miny;g_vertices[2] = maxx;g_vertices[3] = miny;g_vertices[4] = maxx;g_vertices[5] = maxy;g_vertices[6] = minx;g_vertices[7] = maxy;g_texcoord[0] = minu;g_texcoord[1] = minv;g_texcoord[2] = maxu;g_texcoord[3] = minv;g_texcoord[4] = maxu;g_texcoord[5] = maxv;g_texcoord[6] = minu;g_texcoord[7] = maxv;}};#endif

main.app内容未变

好!今天就写到这,下一篇将介绍如何加入中文及特效的实现。

SDL2 + OPENGL GLSL 实践相关推荐

  1. OpenGL GLSL Shader Subroutines函数的实例

    OpenGL GLSL Shader Subroutines函数 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <shader.h> ...

  2. 皮肤的实时3S渲染(OpenGL + GLSL)

    人的皮肤之所以看上去比较柔和自然,主要是由于各层皮肤对光线的散射,通过实验测试表明,光线接触到皮肤时,有大约96%被皮肤各层散射了,只有大约4%被反射.下面就是光线经过皮肤散射和反射的示意图(摘录自G ...

  3. OpenGL, GLSL, DirectX, HLSL中的矩阵存储形式

    (原文地址:http://alvincc-tech.blogspot.com/2010/10/opengl-glsl-directx-hlsl.html) OpenGL, GLSL, DirectX, ...

  4. sdl2 opengl d3d9的mipmap和各项异性过滤渲染

    sdl支持的驱动 列出后可以根据自己的需求去做,如果没有驱动就使用software去做就好了,以下列出对比,视频源为1280 720 的摄像头,使用RGB24来测试 opengl CPU占用率在1.3 ...

  5. Linux之SDL2+OpenGL+EGL绘制(十六)

    1.概述  SDL:窗口系统(基于X11或WayLand协议) OpenGL(与硬件无关):通过法命令给GPU完成绘制工作. EGL(与硬件相关):是窗口系统(SDL)和OpenGL媒介 # emac ...

  6. openGL GLSL texture()函数详解

    前言 一般,在三维项目添加纹理的时候,经常会看到有和纹理操作的函数,先看一段片元着色器程序:在片元着色器中 #version 450 coreout vec4 FragColor;in vec2 Te ...

  7. Android音视频 - OpenGL GLSL基础

    上节在绘制三角形的时候,简单讲解了一些着色器,GLSL 的相关概念,可能看的云里雾里的.不要担心,在本节中,我将详细讲解着色语言 GL Shader Language(GLSL)的一些基本的概念. P ...

  8. Modern OpenGL - GLSL着色语言2:GLSL入口函数和GLSL中的变量

    文章目录 1 GLSL的入口函数和基本结构 2 GLSL中的变量声明 3 GLSL中变量的作用域 4 GLSL中变量的初始化 5 GLSL中变量的隐式转换 1 GLSL的入口函数和基本结构 对于很多编 ...

  9. Modern OpenGL - GLSL着色语言3:GLSL中的数据类型

    文章目录 1 GLSL的基本数据类型 2 GLSL的聚合类型:向量和矩阵 2.1 向量 2.1.1 向量初始化 2.1.1.1 向量初始化 2.1.1.2 向量构造函数的截短 2.1.1.3 向量构造 ...

  10. OpenGL 编程实践 之 改变屏幕分辨率和颜色深度

    程序运行的结果是改变屏幕的分辨率和颜色深度. 一.程序的编写: 1. 新建和配置工程 新建一个工程,然后在Project->Setting->Link 中,加入OpenGL 相关几个lib ...

最新文章

  1. ACM——模拟(hard) 刷题总结
  2. 《Effective STL》学习笔记(第四部分)
  3. java web总结:tomcat使用教程
  4. NSLocalizedString 实现国际化
  5. vxe-table安装和使用
  6. .net 动软代码生成器
  7. 【HIHOCODER 1133】 二分·二分查找之k小数
  8. 缓存-问题:缓存穿透 缓存雪崩 缓存击穿
  9. 整理python笔记001(列表(深浅copy),元祖,字典,集合)
  10. 程序员,建立你的商业意识
  11. oracle中主键自增长,Oracle中给主键设置自增长
  12. Socket网络编程——(一)
  13. 湖南师范大学2018年大学生程序设计竞赛新生赛 F-小名的回答
  14. 2021年中国苹果及苹果加工品进出口情况:我国苹果干进出口均价均有所上涨[图]
  15. android 自动下一首,Android播播放完SD卡指定文件夹音乐之后,自动播放下一首
  16. 多边形的扫描转换算法——扫描线算法(计算机图形学)
  17. 【electron】 打包应用修改图标和进程名字
  18. linux质控命令,RNA-seq摸索:2.sra下载数据→fastqc质控→hisat2/bowtie2/STAR/salmon比对→Samtools格式转换→IGV可视化结果...
  19. apisix健康检查测试
  20. 微博登入php,ThinkPHP接入微博登录

热门文章

  1. 苹果cmsv10仿片库网PC+WAP美化高端免费自适应模板
  2. JAVA JDK API(中文) 1.6、1.8
  3. 全三轨磁条卡读写器|写卡器MSR606的驱动安装与Demo软件测试操作指南
  4. 在线ERD工具DrawERD
  5. 一个免费提升独立站转化率神器-tidio实时在线客服聊天工具
  6. 基于51单片机的流水灯(C语言)
  7. linux chmod -r,linux chmod -R 777 / 的危害
  8. freetextbox java_FreeTextBox使用详解 (版本3.1.1)
  9. useragent大全
  10. Android 音视频开发学习思路大纲