Fastest way to draw filled quad/triangle with the SDL2 renderer?
Asked Answered
R

2

14

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.

Repeater answered 5/10, 2021 at 9:12 Comment(1)
Not sure whether you will find a reasonable alternative to OpenGL (excluding the proprietary / OS specific siblings Direct3d and Metal). I once painted an HUD in Qt / QPainter (annotations to my rendered 3d contents) hoping on the fact that Qt seems to use OpenGL for this under the hood as well. After having received complaints about poor performance, I ported the code to "hand-written" OpenGL, and mission succeeded. Of course, there might be other APIs which do a better job...Sanford
S
18

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:

screenshot

// 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.

Scandinavia answered 5/10, 2021 at 13:49 Comment(4)
Should make SDL_Renderer-based backends for immediate-mode GUIs like nuklear viable too.Scandinavia
Thanks for making me aware of nuklear. I'm using dear-imgui (with a intermediate lib to render imgui with the SDL2 renderer - a bit slow) in my game, but that looks very nice as well.Repeater
RE: SDL_Renderer backend...Scandinavia
Just as a follow up, I just built the latest SDL source, and have drawn a filled triangle for the first time. Heady days indeed, thanks. I'd not have noticed this as I only check the official releases.Repeater
E
0

Here is my basic example:

#include <stdio.h>
#include <stdlib.h>
#include <SDL.h>

int width=1280,height=720;
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Event e;

SDL_Vertex triangleVertex[3]=
{
 {
  { 0,0}, /* first point location */ 
  { 255, 0, 0, 0xFF }, /* first color */ 
  { 0.f, 0.f }
 },
 {
  { 0, 720 }, /* second point location */ 
  { 0,255,0, 0xFF }, /* second color */
  { 0.f, 0.f }
 },
 {
  { 640, 360 }, /* third point location */ 
  { 0,0,255, 0xFF }, /* third color */
  { 0.f, 0.f }
 }
};


int main(int argc, char** argv)
{
 if(SDL_Init(SDL_INIT_VIDEO)){printf( "SDL could not initialize! SDL_Error: %s\n",SDL_GetError());return -1;}

 window = SDL_CreateWindow( "SDL Chaste Triangle",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,width,height,0);
 if(window==NULL){printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );return -1;}

 renderer = SDL_CreateRenderer(window,-1,0);
 if(renderer==NULL){printf( "Renderer could not be created! SDL_Error: %s\n", SDL_GetError() );return -1;}
    
 SDL_SetRenderDrawColor(renderer,0,0,0,255);
 SDL_RenderClear(renderer);
 if( SDL_RenderGeometry(renderer, NULL, triangleVertex, 3, NULL, 0) < 0 ) {SDL_Log("%s\n", SDL_GetError());}

 SDL_RenderPresent(renderer);
    
 while(e.type != SDL_KEYUP && e.type != SDL_QUIT) /*wait until any key is pressed and then released*/
 {
  SDL_PollEvent( &e );
 }
    
 SDL_DestroyRenderer(renderer);
 SDL_DestroyWindow(window);
 SDL_Quit();
 return 0;
}

/*
 This file is the Chastity's modification of an example from here:

 https://daywithstars.github.io/sdl2/geometry/2021/12/03/SDL2-new-geometry-rendering-SDL_RenderGeometry.html

 Unlike the original, this one is compatible with the C89 standard which Chastity always uses.

 Compile and run on Linux with this command:
 gcc -Wall -ansi -pedantic main.c -o main `sdl2-config --cflags --libs` -lm && ./main
*/

I have this one and some more examples at my github project.

https://github.com/chastitywhiterose/SDL_Chaste_Triangle

It is possible to draw any shape with enough triangles and so I made the project to help me in future games I make.

Episcopal answered 5/3, 2023 at 5:10 Comment(1)
Awesome, I figured out how to share the code in the answer. I had to select the text and use CTRL+K. I'm new to stack overflow and I joined just because of the SDL Triangle question. I don't blame the OP for not wanting to mess with OpenGL!Episcopal

© 2022 - 2025 — McMap. All rights reserved.