I have a game written using SDL2, and the SDL2 renderer (hardware accelerated) for drawing. Is there a trick to draw filled quads or triangles?
At the moment I'm filling them by just drawing lots of lines (SDL_Drawlines), but the performance stinks.
I don't want to go into OpenGL.
SDL_RenderGeometry()/SDL_RenderGeometryRaw() were added in SDL 2.0.18:
Added SDL_RenderGeometry() and SDL_RenderGeometryRaw() to allow rendering of arbitrary shapes using the SDL 2D render API
Example:
// g++ main.cpp `pkg-config --cflags --libs sdl2`
#include <SDL.h>
#include <vector>
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_Window* window = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN );
SDL_Renderer* renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
const std::vector< SDL_Vertex > verts =
{
{ SDL_FPoint{ 400, 150 }, SDL_Color{ 255, 0, 0, 255 }, SDL_FPoint{ 0 }, },
{ SDL_FPoint{ 200, 450 }, SDL_Color{ 0, 0, 255, 255 }, SDL_FPoint{ 0 }, },
{ SDL_FPoint{ 600, 450 }, SDL_Color{ 0, 255, 0, 255 }, SDL_FPoint{ 0 }, },
};
bool running = true;
while( running )
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
{
if( ( SDL_QUIT == ev.type ) ||
( SDL_KEYDOWN == ev.type && SDL_SCANCODE_ESCAPE == ev.key.keysym.scancode ) )
{
running = false;
break;
}
}
SDL_SetRenderDrawColor( renderer, 0, 0, 0, SDL_ALPHA_OPAQUE );
SDL_RenderClear( renderer );
SDL_RenderGeometry( renderer, nullptr, verts.data(), verts.size(), nullptr, 0 );
SDL_RenderPresent( renderer );
}
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
SDL_Quit();
return 0;
}
Note that due to the API lacking a data channel for Z coordinates only affine texturing is achievable.
Not possible. SDL2 does not include a full-fledged rendering engine.
Some options:
You could adopt Skia (the graphics library used in Chrome, among ohters) and then either stick with a software renderer, or instantiate an OpenGL context and use the hardware backend.
You could use another 2D drawing library such as Raylib
Or just bite the bullet and draw your triangles using OpenGL.
Related
I created an OpenGL window using SDL2 but the background keeps switching between black and yellow.
#include <SDL2/SDL.h>
#include <GL/glew.h>
#define SCREEN_WIDTH 500
#define SCREEN_HEIGHT 500
int main( int argc, char** argv )
{
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
SDL_Window* gWindow = SDL_CreateWindow(
"Title",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_OPENGL);
SDL_GL_CreateContext( gWindow );
glewExperimental = GL_TRUE;
glewInit();
glPointSize(3);
glClearColor(1,1,0,0);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SetSwapInterval(1);
int quit=0;
SDL_Event event;
while( !quit )
{
while(SDL_PollEvent( &event ))
{
if( event.type == SDL_QUIT )
quit = 1;
}
SDL_GL_SwapWindow( gWindow );
}
SDL_DestroyWindow(gWindow);
return 0;
}
I expect the background to be yellow, as defined with glClearColor(1,1,0,0), without flickering while the program runs. Is there something wrong in the code?
The reason for flickering is that you're using double buffering but do not clear one of the buffers with the yellow color (i.e. note that you're calling glClear only once in your code).
I suggest you call glClear every frame. To fix your code, you can move the call into the loop, just before the SDL_GL_SwapWindow:
while( !quit )
{
while(SDL_PollEvent( &event ))
{
if( event.type == SDL_QUIT )
quit = 1;
}
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow( gWindow );
}
I am trying to figure out the SDL2 library in C++, and can't seem to properly configure code to simply draw a rectangle to the screen. What should I do differently?
#include <SDL.h>
bool success = true; //success flag for functions, etc
int ScreenWidth = 640; //screen width and height for SDL window
int ScreenHeight = 480; //
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
SDL_Window* window = SDL_CreateWindow( "Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ScreenWidth, ScreenHeight, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF);
bool quit = false;
SDL_Event event;
while (!quit)
{
SDL_RenderClear(renderer);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
}
SDL_Rect box;
box.w = 30;
box.h = 30;
box.x = 50;
box.y = 50;
SDL_SetRenderDrawColor(renderer, 0xFF,0x00,0x00,0xFF);
SDL_RenderFillRect(renderer, &box);
SDL_RenderPresent(renderer);
}
return 0; //because main is an int task
}
EDIT: This is the full file.
I expect it to draw a red rectangle on the screen, but the window is completely red (of the correct size, name, etc. that quits correctly).
You must call SDL_RenderPresent after all your rendering calls. In this case after SDL_RenderFillRect(...)
SDL_RenderClear is used at the beginning of a rendering loop to clear the buffer.
Example from SDL2's Wiki
SDL_SetRenderDrawColor() affects both SDL_RenderFillRect() and SDL_RenderClear().
After drawing the red square you need to re-set the color to white before the next SDL_RenderClear() call:
#include <SDL2/SDL.h>
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" );
SDL_Window* window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN );
SDL_Renderer* renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
bool running = true;
while( running )
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
{
if( SDL_QUIT == ev.type )
{
running = false;
break;
}
}
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( renderer );
SDL_Rect box;
box.w = 30;
box.h = 30;
box.x = 50;
box.y = 50;
SDL_SetRenderDrawColor( renderer, 0xFF, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &box );
SDL_RenderPresent( renderer );
}
return 0;
}
I figured it out!
I needed to put SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); inside of the loop so it would reset the renderer to white each tick. I just had it set it back to white once at the beginning so SDL_RenderClear was filling the window with the current draw color (which was red). Thanks to TinfoilPancakes and genpfault for helping me!
Here is a minimal SDL-1.2 text output example (stripped from the lazyfoo tutorial for ttf):
#include <SDL.h>
#include <SDL_ttf.h>
#include <string>
SDL_Surface *message = NULL;
SDL_Surface *screen = NULL;
SDL_Event event;
TTF_Font *font = NULL;
SDL_Color color = { 255, 255, 255 };
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
TTF_Init();
SDL_WM_SetCaption( "Test message", NULL );
font = TTF_OpenFont( "anyttffont.ttf", 20 );
message = TTF_RenderText_Solid(
font, "My test message", color );
SDL_Rect offset;
offset.x = 0;
offset.y = 150;
SDL_BlitSurface( message, NULL, screen, &offset );
SDL_Flip( screen );
bool quit = false;
while( quit == false )
while( SDL_PollEvent( &event ) )
if( event.type == SDL_QUIT )
quit = true;
SDL_FreeSurface( message );
TTF_CloseFont( font );
TTF_Quit();
SDL_Quit();
return 0;
}
The resulting executable redraws the window automatically after re-exposing it (after minimizing or obscuring).
Is it possible to do something like this in SDL-2?
I tried the equivalent tutorial from lazyfoo for SDL-2, but this has code to constantly re-render the text in the event loop. It stops re-drawing when the render code is moved in front of the loop. I also tried rewriting it using the window surface directly and then using SDL_UpdateWindowSurface(gWindow);, but this behaves the same way.
I am using SDL2 in windowed mode on Windows 7 64bit to create a small game.
I get tearing at the same height of the window despite having VSYNC active. The weird thing is that the movement in itself is fluid, but there is this line, about 50px from the bottom, where tearing is noticeable. It always stays there, without moving or anything.
The weird thing is that if I crate a smaller window, I get tearing at exactly the same height from the bottom.
I tried taking screens of it but it doesn't show the tearing.
I have no idea if this is a problem of SDL2, a problem with Windows, a problem with my pc or a problem in my source file. I have tried looking online for a solution but I could not find anything like this problem.
It is a first for me since I have been playing with a lot of SDL games in the past in windowed mode and none had this problem.
Here is a snippet of the source I have been using:
#include <stdio.h>
#include <SDL.h>
#include <SDL_image.h>
const int SCREEN_WIDTH = 400;
const int SCREEN_HEIGHT = 300;
bool init( SDL_Window** window, SDL_Renderer** renderer ) {
SDL_Init(SDL_INIT_VIDEO);
*window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
*renderer = SDL_CreateRenderer(*window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
int flags = IMG_INIT_PNG;
IMG_Init(flags);
return true;
}
void close( SDL_Texture** image, SDL_Window** window ) {
SDL_DestroyTexture( *image );
*image = NULL;
SDL_DestroyWindow( *window );
*window = NULL;
SDL_Quit();
}
int main(int argc, char* argv[]) {
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* image = NULL;
const SDL_Rect rect = { 0, 0, SCREEN_WIDTH, 200 };
SDL_Rect rectImage, rectImageOriginal;
int w, h;
SDL_QueryTexture(image, NULL, NULL, &w, &h);
rectImage = { 0, 0, w, h };
rectImageOriginal = rectImage;
init( window, renderer );
image = IMG_LoadTexture( renderer, path );
while (running) {
[... here I move rectImage ...]
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 200, 0, 0, 255);
SDL_RenderFillRect(renderer, NULL);
SDL_RenderCopy(renderer, image, &rectImageOriginal, &rectImage);
SDL_RenderPresent(renderer);
}
close(&image, &window);
}
I recently started programming with SDL and I've been following some tutorials on gamedevgeek and lazyfoo. I got to show images on the screen, but when I tried to move them I realized the screen was not updating correctly, making the sprite leave a trace, like in this image:
As you can see, the sprite started out in the top left corner, and it left a trace throughout its path to the bottom right.
Some info that can help:
I'm using a raspberry pi with raspbian.
I'm using SDL 1.2.
What have I tried:
I tried changing the last parameter of SDL_SetVideoMode to SDL_HWSURFACE, SDL_SWSURFACE, SDL_DOUBLEBUF, SDL_FULLSCREEN
I tried to switch between SDL_Flip(screen) and SDL_UpdateRect(screen, 0, 0, 0, 0); when I changed the parameter of SDL_SetVideoMode.
Here is my code.
#include "SDL.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
int main ( int argc, char *argv[] )
{
SDL_Surface *screen, *temp, *sprite;
SDL_Rect rcSprite;
SDL_Event event;
Uint8 *keystate;
int colorkey, gameover;
SDL_Init(SDL_INIT_VIDEO);
// screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_DOUBLEBUF | SDL_FULLSCREEN);
// screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_HWSURFACE);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_SWSURFACE);
temp = SDL_LoadBMP("sprite.bmp");
sprite = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
colorkey = SDL_MapRGB(screen->format, 255, 0, 255);
SDL_SetColorKey(sprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, colorkey);
rcSprite.x = 0;
rcSprite.y = 0;
gameover = 0;
while (!gameover)
{
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
gameover = 1;
break;
}
break;
}
}
keystate = SDL_GetKeyState(NULL);
if (keystate[SDLK_LEFT] )
rcSprite.x -= 2;
if (keystate[SDLK_RIGHT] )
rcSprite.x += 2;
if (keystate[SDLK_UP] )
rcSprite.y -= 2;
if (keystate[SDLK_DOWN] )
rcSprite.y += 2;
SDL_BlitSurface(sprite, NULL, screen, &rcSprite);
// SDL_Flip(screen);
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
SDL_FreeSurface(sprite);
SDL_FreeSurface(grass);
SDL_Quit();
return 0;
}
What am I doing wrong? Needless to say that I'm very new to the linux world, as well as the raspberry pi's, as well as SDL's :)
You call to SDL_SetVideoMode() is incorrect, your code should not compile, enable your compiler warnings.
The function takes four arguments:
SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags);
so it should be something like:
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32 , SDL_SWSURFACE);
if( !screen )
//print your warning and exit.
Also your screen surface is never cleared and the sprite remains. Either redraw the entire screen with sprites or clear the surface
SDL_FillRect( screen , NULL , 0x0 ) ; //fills the entire surface with 0x0 .