配置好SDL之后,就想在SDL中使用openGL,原以为会像在GLFW中那样简单的,实际上确花费了一整个下午不断查看文档,实例才搞定问题。
总结如下:
1)SDL对OpenGL进行了部分的封装,一些OpenGL的函数需要用SDL来实现,而不是像GLFW中那样直接用;
2)SDL的事件机制花费了一些时间来理解;
3)在处理OpenGL窗口大小变化的时候,需要先调用SDL_SetVideoMode才可以得到正确结果。
最终基本实现了一个opengl的小型框架,包括一些简单的事件处理。
代码:
/*****************************************************************************
Copyright: 2012, ustc All rights reserved.
contact:[email protected]
File name: main.c
Description:using opengl in SDL.
Author:Silang Quan
Version: 1.0
Date: 2012.12.01
*****************************************************************************/
#include
#include
#include
#include
#include
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT =800;
const int SCREEN_BPP = 32;
SDL_Surface *screen;
//Whether the window is windowed or not
bool windowed;
//Whether the window is fine
bool windowOK;
void quit( int code )
{
SDL_Quit( );
/* Exit program. */
exit( code );
}
void toggle_fullscreen()
{
//If the screen is windowed
if( windowed == true )
{
//Set the screen to fullscreen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL|SDL_RESIZABLE| SDL_FULLSCREEN );
//If there's an error
if( screen == NULL )
{
windowOK = false;
return;
}
//Set the window state flag
windowed = false;
}
//If the screen is fullscreen
else if( windowed == false )
{
//Window the screen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL|SDL_RESIZABLE );
//If there's an error
if( screen == NULL )
{
windowOK = false;
return;
}
//Set the window state flag
windowed = true;
}
}
void handleKeyEvent( SDL_keysym* keysym )
{
switch( keysym->sym )
{
case SDLK_ESCAPE:
quit( 0 );
break;
case SDLK_SPACE:
break;
case SDLK_F1:
toggle_fullscreen();
break;
default:
break;
}
}
void resizeGL(int width,int height)
{
if ( height == 0 )
{
height = 1;
}
//Reset View
glViewport( 0, 0, (GLint)width, (GLint)height );
//Choose the Matrix mode
glMatrixMode( GL_PROJECTION );
//reset projection
glLoadIdentity();
//set perspection
gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 );
//choose Matrix mode
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
void handleEvents()
{
// Our SDL event placeholder.
SDL_Event event;
//Grab all the events off the queue.
while( SDL_PollEvent( &event ) ) {
switch( event.type ) {
case SDL_KEYDOWN:
// Handle key Event
handleKeyEvent( &event.key.keysym );
break;
case SDL_QUIT:
// Handle quit requests (like Ctrl-c).
quit( 0 );
break;
case SDL_VIDEORESIZE:
//Handle resize event
screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 16,
SDL_OPENGL|SDL_RESIZABLE);
if ( screen )
{
resizeGL(screen->w, screen->h);
}
break;
}
}
}
void initSDL(int width,int height,int bpp,int flags)
{
// First, initialize SDL's video subsystem.
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
fprintf( stderr, "Video initialization failed: %s\n",
SDL_GetError( ) );
quit( 1 );
}
atexit(SDL_Quit);
//Set some Attribute of OpenGL in SDL
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
//Set the video mode
screen= SDL_SetVideoMode( width, height, bpp,flags);
if(!screen )
{
fprintf( stderr, "Video mode set failed: %s\n",SDL_GetError( ) );
quit( 1 );
windowed=false;
}
else windowed=true;
resizeGL(screen->w, screen->h);
//Set caption
SDL_WM_SetCaption( "OpenGL Test", NULL );
}
void renderGL()
{
// Clear the color and depth buffers.
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// We don't want to modify the projection matrix. */
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
// Move down the z-axis.
glTranslatef( 0.0, 0.0, -5.0 );
//Draw a square
glBegin(GL_QUADS);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f(-1.0f , -1.0f , 1.0f );
glColor3f(0.0f,1.0f,0.0f);
glVertex3f( 1.0f , -1.0f , 1.0f );
glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 1.0f , 1.0f , 1.0f );
glColor3f(1.0f,1.0f,0.0f);
glVertex3f(-1.0f , 1.0f , 1.0f );
glEnd();
SDL_GL_SwapBuffers( );
}
void initGL( int width, int height )
{
float ratio = (float) width / (float) height;
// Our shading model--Gouraud (smooth).
glShadeModel( GL_SMOOTH );
// Set the clear color.
glClearColor( 0, 0, 0, 0 );
// Setup our viewport.
glViewport( 0, 0, width, height );
//Change to the projection matrix and set our viewing volume.
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0, ratio, 1.0, 100.0 );
}
int main( int argc, char* argv[] )
{
// Color depth in bits of our window.
int flags= SDL_OPENGL|SDL_RESIZABLE;
//Set the SDL
initSDL(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,flags);
//Set the OpenGL
initGL(SCREEN_WIDTH, SCREEN_HEIGHT );
//main loop
while(true)
{
/* Process incoming events. */
handleEvents( );
/* Draw the screen. */
renderGL( );
}
return 0;
}
编译命令:
g++ main.c -o mian -lSDL -lglut -lGLU
#in opensuse
g++ main.c -o main -lSDL -lGL -lGLU
SDLOpenGLFramework
这里给一个C++写的OpenGL编程框架。
https://github.com/SilangQuan/SDLOpenGLFramework
SDL2中接口改变了很多,下面是一个简单的可运行的例子。
环境:Windows 10 64bit VS2015 SDL2.0.4
#define GLUT_DISABLE_ATEXIT_HACK
#include "SDL/SDL.h"
#include
#include "GL/glew.h"
#include "GL/wglew.h"
#include
#include
#include
#include "iostream"
#include
using namespace std;
#include
#define _USE_MATH_DEFINES
#include
#include
constexpr int SCREEN_WIDTH = 800;
constexpr int SCREEN_HEIGHT = 600;
constexpr int OPENGL_MAJOR_VERSION = 2;
constexpr int OPENGL_MINOR_VERSION = 1;
constexpr SDL_GLprofile OPENGL_PROFILE = SDL_GLprofile::SDL_GL_CONTEXT_PROFILE_CORE;
void perspectiveGL(GLdouble fovY, GLdouble aspect, GLdouble zNear, GLdouble zFar) {
GLdouble fW, fH;
fH = tan(fovY / 360 * M_PI) * zNear;
fW = fH * aspect;
glFrustum(-fW, fW, -fH, fH, zNear, zFar);
}
void Display_InitGL() {
/* Enable smooth shading */
glShadeModel(GL_SMOOTH);
/* Set the background red */
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
/* Depth buffer setup */
glClearDepth(1.0f);
/* Enables Depth Testing */
glEnable(GL_DEPTH_TEST);
/* The Type Of Depth Test To Do */
glDepthFunc(GL_LEQUAL);
/* Really Nice Perspective Calculations */
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
/* function to reset our viewport after a window resize */
int Display_SetViewport(int width, int height) {
/* Height / width ration */
GLfloat ratio;
/* Protect against a divide by zero */
if (height == 0) {
height = 1;
}
ratio = (GLfloat)width / (GLfloat)height;
/* Setup our viewport. */
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
/* change to the projection matrix and set our viewing volume. */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* Set our perspective */
perspectiveGL(45.0f, ratio, 0.1f, 100.0f);
/* Make sure we're chaning the model view and not the projection */
glMatrixMode(GL_MODELVIEW);
/* Reset The View */
glLoadIdentity();
return 1;
}
void Display_Render(SDL_Window* displayWindow) {
/* Clear The Screen And The Depth Buffer */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1, 1, 0, 1.0);
/* Move Left 1.5 Units And Into The Screen 6.0 */
glLoadIdentity();
glTranslatef(-1.5f, 0.0f, -6.0f);
glBegin(GL_TRIANGLES); /* Drawing Using Triangles */
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f); /* Top */
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f); /* Bottom Left */
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 0.0f); /* Bottom Right */
glEnd(); /* Finished Drawing The Triangle */
/* Move Right 3 Units */
glTranslatef(3.0f, 0.0f, 0.0f);
glBegin(GL_QUADS); /* Draw A Quad */
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glColor3f(1.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd(); /* Done Drawing The Quad */
SDL_GL_SwapWindow(displayWindow);
}
int main(int argc, char *argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "There was an error initing SDL2: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, OPENGL_PROFILE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_MAJOR_VERSION);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_MINOR_VERSION);
SDL_Window* displayWindow = SDL_CreateWindow("SDL2 X OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL);
if (displayWindow == nullptr) {
std::cerr << "There was an error creating the window: " << SDL_GetError() << std::endl;
return 1;
}
else
{
cout << "Creating SDL_Window created.............." << endl;
}
SDL_GLContext context = SDL_GL_CreateContext(displayWindow);
if (context == nullptr) {
std::cerr << "There was an error creating OpenGL context: " << SDL_GetError() << std::endl;
return 1;
}
else
{
cout << "Creating OpenGL context created.............." << endl;
}
GLenum err = glewInit();
if (err != GLEW_OK)
{
cout << "-----------------GLEW init failed!------------- " << glewGetErrorString(err) << endl;
exit(EXIT_FAILURE);
}
else
{
cout << "GLEW init successful!" << endl;
}
const unsigned char *version = glGetString(GL_VERSION);
if (version == nullptr)
{
std::cerr << "There was an error with OpenGL configuration:" << std::endl;
return 1;
}
else
{
cout << "OpenGL Version: " << version << endl;
}
SDL_GL_MakeCurrent(displayWindow, context);
Display_InitGL();
Display_SetViewport(SCREEN_WIDTH, SCREEN_HEIGHT);
Display_Render(displayWindow);
SDL_Delay(2000);
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(displayWindow);
SDL_Quit();
return 0;
}
SDL英文教程-http://lazyfoo.net/