How does one draw with pixels in SDL2.0?
I'm trying to get familiar with C++, but this is very difficult to do without pretty pictures, so I'm trying to get a very basic graphics display thing running. All I really want it to do is give me a window, let me draw rgbα pixels on it, and access information about those pixels. There may be other things I want that I'm not aware of, but that's all that's on my list right now. My research on this has lead me to try using SDL, the current version being 2.0.
Almost all my graphics experience comes from using JavaScript on a <canvas>. Most of the other bit comes from my calculator, which has this really awesome Pxl-On() command, so easy.
I'm using MinGW for my C++, if it matters. Also, if there's something better** out there than SDL2.0 for what I need, advice welcome.
** "better" means "contains what functionality I need, but less total functionality than SDL2.0, and/or has a more intuitive/less complex*** API than SDL2.0."
*** Less lines of code to accomplish the same task.
Runnable example
Draws a diagonal red line pixel by pixel on the screen using SDL_RenderDrawPoint.
main.c
#include <stdlib.h>
#include <SDL2/SDL.h>
#define WINDOW_WIDTH 600
int main(void) {
SDL_Event event;
SDL_Renderer *renderer;
SDL_Window *window;
int i;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
for (i = 0; i < WINDOW_WIDTH; ++i)
SDL_RenderDrawPoint(renderer, i, i);
SDL_RenderPresent(renderer);
while (1) {
if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
break;
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
GitHub upstream.
Compile and run:
gcc -std=c89 -Wextra -pedantic-errors -o main.out main.c -lSDL2
./main.out
If you want to set a large rectangle of pixels at once, e.g. the entire screen or a sprite, use SDL_Texture + SDL_RenderCopy and possibly SDL_TEXTUREACCESS_STREAMING, as that will be much faster. Examples at:
What is a Blit in SDL?
Rendering pixels from array of RGB values in SDL 1.2?
Tested on libsdl 2.0.2, Ubuntu 15.10.
I don't know how your code is structured. Assuming you have a SDL_Window and a SDL_Renderer, you just have to call SDL_RenderDrawPoint(renderer, x, y).
If you don't have a renderer nor window, you can create both with SDL_CreateWindowAndRenderer(). For example:
SDL_Window *window;
SDL_Renderer *renderer;
SDL_CreateWindowAndRenderer(800, 600, 0, &window, &renderer);
//Probably on a loop
SDL_RenderDrawPoint(renderer, 400, 300); //Renders on middle of screen.
SDL_RenderPresent(renderer);
This should draw a pixel on the middle of screen. To read a pixel is a little more complicated. You can use SDL_RenderReadPixels(), it is made for read an area, but you can always specify an area of 1x1. Read the wiki page if you really need it.
If you are having much trouble with SDL2 a recommend you to read the Lazy Foo tutorials. The SDL2 section still a work in progress, but there is enough material to begin learning.
I find Python + PySDL2 more easy to prototype with. Debug is also funny, because it is veeeery slooow for pixel graphics. =) Here is the complete code:
"""
The code is placed into public domain
by anatoly techtonik <techtonik#gmail.com>
"""
import sdl2
import sdl2.ext
sdl2.ext.init()
window = sdl2.ext.Window('', size=(300, 100))
window.show()
renderer = sdl2.ext.Renderer(window)
renderer.draw_point([10,10], sdl2.ext.Color(255,255,255))
renderer.present()
running = True
while running:
for e in sdl2.ext.get_events():
if e.type == sdl2.SDL_QUIT:
running = False
break
if e.type == sdl2.SDL_KEYDOWN:
if e.key.keysym.sym == sdl2.SDLK_ESCAPE:
running = False
break
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 months ago.
Improve this question
I'm starting a new project in SDL2 and as I'm still trying out different architectural approaches I usually start out by bringing up a white window to confirm that the new approach I'm trying out satisfies at least the bare minimum to get started with SDL2.
This time, I wanted to try wrapping my application into a separate Application class so as to unclutter main, like so:
#include <SDL2/SDL.h>
#include <stdio.h>
#include <string>
#include "HApplication/HApplication.h"
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main(int argc, char *argv[])
{
HApplication application = HApplication( SCREEN_WIDTH, SCREEN_HEIGHT );
bool hasStarted = application.checkRunning();
if ( hasStarted ){
application.run();
}
else{
std::string msg = "Application failed to initialize.";
SDL_LogError( SDL_LOG_CATEGORY_ERROR, msg.c_str() );
}
// add error codes
return 0;
}
Now, the run method in HApplication is meant to reflect the main loop until the user exits. For test purposes, I'd just like to get two lines crossing in the middle on a white background. After initializing SDL, the window, and the renderer, which all work out fine, I'm presented with a window filled completely back, although I've used very similar code successfully before:
void HApplication::run()
{
// while user doesn't quit, keep going
bool userQuit = false;
SDL_Event e
while( !userQuit )
{
// handle queued events
while ( SDL_PollEvent( &e ) != 0 )
{
if ( e.type == SDL_QUIT )
{
userQuit = true;
}
}
// clear screen
SDL_SetRenderDrawColor( appRenderer, 255, 255, 255, 255);
SDL_RenderClear( appRenderer );
// draw cross
SDL_SetRenderDrawColor( appRenderer, 0, 0, 0, 255 );
SDL_RenderDrawLine( appRenderer, 0, screenHeight/2, screenWidth, screenHeight/2);
SDL_SetRenderDrawColor( appRenderer, 0, 0, 0, 255 );
SDL_RenderDrawLine( appRenderer, screenWidth/2 , 0, screenWidth/2, screenHeight);
// update screen with new scene
SDL_RenderPresent( appRenderer );
SDL_UpdateWindowSurface( appWindow );
}
close();
}
I'm not quite sure why this happens, especially since I can see what I want stepping through the loop step-by-step using the debugger. I am quite honestly pretty much at a loss at where to even start.
I tried looking on Google and Stackoverflow for similar questions. However, these were mostly addressing problems with loading textures, which I haven't even gotten to yet.
If possible, I would like to keep a separate class handling game logic and resources.
EDIT: It seems like I needed to get rid of SDL_UpdateWindow. However, I'm not quite sure why. If anyone has an explanation, I'd be happy to hear!
SDL has both a CPU rendering API and a GPU one.
Everything that works with a SDL_Renderer belongs to the GPU API. For example, you can make a SDL_Texture and use SDL_RenderCopy to render it. The final step is to call SDL_RenderPresent so that everything that was rendered gets displayed.
SDL_UpdateWindowSurface is part of the CPU API. To use this API, you can for example draw to a SDL_Surface and then use SDL_BlitSurface with SDL_GetWindowSurface to render to the window's surface. The final step is to call SDL_UpdateWindowSurface to display the changes, which is the equivalent to SDL_Flip in SDL 1.2.
In short: after the SDL_RenderPresent call, you get what you wanted, but after the SDL_UpdateWindowSurface call, you overwrite that with the CPU window surface which is probably initialized to black. Just remove that SDL_UpdateWindowSurface call and use the GPU API only.
Every time I attempt to run my application it creates a window perfectly fine but when moving the mouse about it becomes obvious that it freezes briefly for a few seconds. I also had this issue in a previous SDL project but didn't fix it as it wasn't very vital but I could never find a solution for it.
I tried looking up my issue but couldn't find anything that matches the issue I'm facing, despite this I attempted a few things that I felt could work like slightly different implementations of an event loop.
I'm not 100% sure on what EVERY line of SDL related code does but I took it from a previous project so I knew what it did at one point but it's not too hard to work out.
int width = 160;
int height = 144;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Window Title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width * 4, height * 4, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
bool quit = false;
while (!quit)
{
SDL_Event E;
while (SDL_PollEvent(&E))
{
if (E.type == SDL_QUIT)
quit = true;
}
}
I expect the window to display smoothly and not have this freezing occur every few seconds. I'm not sure if it only occurs when the mouse is moving or if it happens to freeze every few seconds despite this as the cursor is the only way I have to test it. I saw one post that talked about flooding the event queue but that solution didn't seem to work for me.
Any help is appreciated.
I've recently decided to dive into writing a C++ game using SDL as one of my libraries. During the course of my program writing and learning about SDL, I stumbled across a peculiar bug in my program, and decided to replicate it in an SSCCE to make sure that I wasn't crazy.
The problem appears to be that when I pass SDL_RENDERER_PRESENTVSYNC as a flag to SDL_CreateRenderer, I get inconsistent rendering. To compare, I ran the program 50 times with, and 50 times without the flag, and made that the only change to my program in each case. Without the flag, the display worked 100% of the time. With the flag on, it only rendered successfully 13 out of the 50 times.
Here's the program:
#include <SDL2/SDL.h>
#include <iostream>
int main(int argc, char** argv)
{
if(SDL_Init(SDL_INIT_VIDEO) != 0)
{
std::cerr << "Unable to initialize SDL: " << SDL_GetError() << std::endl;
return -1;
}
SDL_Window* win = SDL_CreateWindow("Testing",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(win, -1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
for(int x = 0; x < 640; x+=32)
{
for(int y = 0; y < 480; y+=32)
{
SDL_Rect rect = {x+1, y+1, 31, 31};
SDL_RenderFillRect(renderer, &rect);
}
}
SDL_RenderPresent(renderer);
SDL_Delay(500);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
If it makes a difference, I'm compiling and testing the program on Ubuntu 15.04, GCC/G++ 4.9.2, Compiled and linked against SDL 2.0.2.
Being so new to SDL, and still relatively new to both C++ and C (I come from a Java background), I think it's very likely that I've made a simple error that I'm not catching, but I can't think of what I might have done.
For those seeing this question in the future, the problem appears to have resolved itself a little over a year later, as I can no longer replicate my own SSCCE. It may be a change of environment, as I am not using the same system and am now using an Nvidia Graphics Card. The problem, though I can no longer verify this, was almost certainly in the environment or the hardware. That same laptop ended up failing (motherboard issues) a mere month or two later, so take from that what you will. Consider checking your hardware health and attempting a completely clean environment if you are experiencing this same issue.
I'm trying to display a texture onto the screen but all I'm getting is a black window.
No SDL Errors are being reported. There's a good chance that I'm missing something stupid, but I can't see it. Hopefully another set of eyes will help. Feel free to ask for more code/info.
main.cpp
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * grass;
SDL_Rect g_dst;
SDL_Event event;
Game app;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("tmp", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
g_dst.x = g_dst.y = 0;
g_dst.w = 640;
g_dst.h = 480;
grass = IMG_LoadTexture(renderer, "grass.bmp");
while (app.isRunning()) {
app.pollEvents(&event);
app.render_init();
app.render(grass, NULL, &g_dst);
app.render_end();
}
//SDL_Quit() is handled by the Game class' destructor
Game.cpp
//Only functions used for rendering are shown
void render_init(Uint8 red=0, Uint8 green=0, Uint8 blue=0, Uint8 alpha=255)
{
SDL_SetRenderDrawColor(renderer, red, green, blue, alpha);
SDL_RenderClear(renderer);
}
void render(SDL_Texture * texture, SDL_Rect * src, SDL_Rect * dest) {
SDL_RenderCopy(renderer, texture, src, dest);
}
void render_end() { SDL_RenderPresent(renderer); }
First of all, you're initializing everything? please don't do that frequently, mind you that you're also initializing MANY unnecessary stuffs like for game controllers, etc. if the app gets bigger then the efficiency and the possibility of this app running at a smoot speed is at stake.
I also noticed that you are declaring variables in the .cpp file, do that in the header file and just recall the header to the cpp file that will be using it.
You want to render the grass right? and render it as much as the screens size.
(I'll just assume that you used this in the game.cpp part, which is the very first file, thus, not regarding any classes made)
int winWidth = 680; //The reason for this is just in case you make the window resizable
int winHeight = 480; //then the texture would also resize along with the window
SDL_Window *window = window = SDL_CreateWindow("The Space Project", 100, 100, winWidth, winHeight, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = NULL; //I've set this to NULL so that we can know if
the reason as to why your image is not rendering is because the renderer is not properly working.
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
if(renderer == NULL)
{
cout >> "Renderer is not working" >> endl;
//This shows a line at the command prompt that your renderer doesn't have any output, thus, only having a NULL as an equivalent
}
SDL_Texture* grass= NULL;
grass= IMG_LoadTexture(renderer, "grass.bmp"); //As you can see, I've set the grass to Null again
if(grass == NULL)
{
cout >> "Grass have failed to initialize" >> endl;
/*I don't normally do this but it's very important if you really need trouble shooting guides
but this time, were here to check IF the grass.bmp entered the SDL_Texture grass, so if the system can't find the .bmp file then it would show this error
since the grass (SDL_Texture) still doesn't have anything inside it (NULL)*/
}
SDL_Rect grass_rect;
grass_rect.x = 0;
grass_rect.y = 0;
grass_rect.w = winWidth;
grass_rect.h = winHeight;
//Loop part, I'll skip some of it
while (!quit && mainEvent->type != SDL_QUIT) //!quit is just an imaginary Boolean I've typed)
{
SDL_PollEvent(mainEvent); //Let's say you created the event already
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass, NULL, &grass_rect);
//The NULL part is also similar to a rect but it's a limiting type, we didn't assign anything to it
since I assumed that you wanted the whole image to be rendered
SDL_RenderPresent(renderer);
}
I revised the code and made it more efficient since your code called for useless extras which might result in lower performance.
I also notice that you tried calling for color changes?
use this
SDL_SetTextureColorMod(texture, red-value, green-value, blue-value);
and put it in the loops part under the render present of the same texture.
SDL_SetTextureColorMod(grass, 250, 250, 250);
Doing this would set all color values to 250, thus, having a white color, this change your texture color to white.
You're also wasting space on making the app.is running(), you could easily replace it with a boolean, which consumes much less space or you could omit it if you don't have an exit button inside the application and just make your loop read the SDL_QUIT, this saves space for the file, mind the efficiency.
If this still doesn't work then try replacing the image your using, make a simple one on paint name it something like "grass.png" or anything then try it again.
Don't forget to put the file in the proper folder, in the DEBUG folder if you haven't specified a folder, and also put it in the app folder so it would also read it when it executes as an .exe file and not as part of the debug command.
I wish to have a semi-transparent SDL background (nothing to do with sub-surfaces or images), such that instead of having a black background it is actually transparent, but the other things I draw are not. My current code is a slightly modified copy of Code::Blocks' SDL project, similar to how various applications have rounded borders or odd shapes besides rectangles.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
int main ( int argc, char** argv )
{
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
// initialize SDL video
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "Unable to init SDL: %s\n", SDL_GetError() );
return 1;
}
// make sure SDL cleans up before exit
atexit(SDL_Quit);
// create a new window
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_NOFRAME);
if ( !screen )
{
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
return 1;
}
// load an image
SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
if (!bmp)
{
printf("Unable to load bitmap: %s\n", SDL_GetError());
return 1;
}
// centre the bitmap on screen
SDL_Rect dstrect;
dstrect.x = (screen->w - bmp->w) / 2;
dstrect.y = (screen->h - bmp->h) / 2;
// program main loop
bool done = false;
while (!done)
{
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event))
{
// check for messages
switch (event.type)
{
// exit if the window is closed
case SDL_QUIT:
done = true;
break;
// check for keypresses
case SDL_KEYDOWN:
{
// exit if ESCAPE is pressed
if (event.key.keysym.sym == SDLK_ESCAPE)
done = true;
break;
}
} // end switch
} // end of message processing
// DRAWING STARTS HERE
// clear screen
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
// draw bitmap
SDL_BlitSurface(bmp, 0, screen, &dstrect);
// DRAWING ENDS HERE
// finally, update the screen :)
SDL_Flip(screen);
} // end main loop
// free loaded bitmap
SDL_FreeSurface(bmp);
// all is well ;)
printf("Exited cleanly\n");
return 0;
}
I think what you're trying to do is in fact a shaped window (parts of the window are transparent depending on a mask that you provide). It seems there's no way to do that with SDL 1.2, however there is a SDL_SetWindowShape function just for this in SDL 1.3 for which you can find a pre-release snapshot here but it's not even in beta yet so I suggest waiting until it's officialy released :)
this is a link to a pretty neat article about development of an older application for Mac OS 9, which did not have support for shaped windows, either.
It's actually a neat article in general about software development.
But the idea seems pretty smart, and I wonder if you might be able to get it working here, too. Instead of trying to make a transparent background, they actually take a screen-shot of the computer right where their window is going to go, and then use that screen shot for their background. When the user drags the window around on the screen, they continue to update the background with new screen-shots. I think this might be more complicated than you were hoping for, but it's certainly an interesting idea.