How to create a surface from many textures or renderer - c

I would like to be able to create a bitmap with SDL2.
For this I want to use SDL_SaveBMP.
However, I do not know how to create the SDL_Surface that I need.
I have to save a map created from a lot of textures.
How can I do?
EDIT : this work, but not when I use the function SDL_CreateWindowAndRenderer like SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_MAXIMIZED|SDL_WINDOW_RESIZABLE, &window, &renderer); :
#include <stdlib.h>
#include <stdio.h>
#include <SDL.h>
int main(int argc, char *argv[])
{
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Init(SDL_INIT_VIDEO);
//window = SDL_CreateWindow("Title", 200, 200, 500, 500, 0);
SDL_CreateWindowAndRenderer(500, 500, SDL_WINDOW_MAXIMIZED|SDL_WINDOW_RESIZABLE, &window, &renderer);
SDL_Surface *screenshot = SDL_CreateRGBSurface(0, 500, 500, 32, 0, 0, 0, 0);
//SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 60, 10, 255, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_RenderReadPixels(renderer, NULL, 0, screenshot->pixels, screenshot->pitch);
SDL_SaveBMP(screenshot, "screenshot.bmp");
SDL_FreeSurface(screenshot);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

Related

Cannot get SDL_SetTextureColorMod to work

I am trying to change the color of the image displayed. The image contains characters in black and I want to display them in red. So I am trying to use SDL_SetTextureColorMod but it seems I am doing it wrong since the image rendered is still black. Does someone see the problem with my code?
#include "SDL.h"
#include <stdio.h>
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window;
SDL_Renderer *renderer;
SDL_CreateWindowAndRenderer(640, 480, 0, &window, &renderer);
SDL_Surface *surface = SDL_LoadBMP("font.bmp");
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
int keep_going = 1;
while (keep_going) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
keep_going = 0;
}
}
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
int ret = SDL_SetTextureColorMod(texture, 255, 0, 0);
if(ret != 0){
printf("%s",SDL_GetError());
}
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_Quit();
return 0;
}
The image I'm using:

When i can access to SDL_Rendrerer after maximizing window?

I try to redraw window only when is need, but when window is resize in a hop (for example maximize), SDL_Renderer is not usable in new size some time after action.
Here is my simple example code:
#include <SDL2/SDL.h>
bool redraw = true;
void draw(SDL_Renderer* renderer, SDL_Rect& rect)
{
SDL_SetRenderDrawColor(renderer, 0, 0, 50, 0xFF);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 90, 90, 90, 0xFF);
SDL_RenderDrawLine(renderer, 0, 0, rect.w, rect.h);
SDL_RenderPresent(renderer);
redraw = false;
}
SDL_Rect resize(const SDL_Event& event)
{
int win_w = (int) event.window.data1;
int win_h = (int) event.window.data2;
SDL_Rect rect = {0, 0, win_w, win_h};
redraw = true;
return rect;
}
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Maximize test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800, 450, 0);
SDL_SetWindowResizable(window, SDL_TRUE);
SDL_Renderer* renderer = SDL_CreateRenderer(
window, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
bool running = true;
SDL_Event event;
SDL_Rect rect = {0, 0, 800, 450};
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_WINDOWEVENT:
switch (event.window.event) {
case SDL_WINDOWEVENT_RESIZED:
rect = resize(event);
break;
}
break;
}
if (redraw) {
draw(renderer, rect);
}
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
return 0;
}
At first, I try to get new renderer size SDL_GetRendererOutputSize in same result like getting size from event.
When I try to resize window with typical mouse motion actions, it works fine. But maximize or window manager resizing to one screen side does not work.
I try to use different event like SDL_WINDOWEVENT_SIZE_CHANGED, but with same result.
And yes, normally, I checks all SDL calls, with SDL_RenderDrawLine but without any errors.

Why am I getting a spurious white pixel when I render a texture in SDL?

I'm using SDL2 to draw some stuff on screen. Here is some code:
#include <SDL.h>
void main()
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 500, 500, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Texture *texture;
{
SDL_Surface *window_surface = SDL_GetWindowSurface(window);
Uint32 pixel_format = window_surface->format->format;
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, 48, 48, 8, pixel_format);
texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
SDL_FreeSurface(window_surface);
}
SDL_Rect target_rectangle;
target_rectangle.x = 100;
target_rectangle.y = 100;
target_rectangle.w = 48;
target_rectangle.h = 48;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawLine(renderer, 0, 50, 50, 0);
SDL_RenderCopy(renderer, texture, 0, &target_rectangle);
SDL_RenderPresent(renderer);
SDL_Event event;
while(1)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
return;
break;
}
}
SDL_Delay(10);
}
}
The code creates some dummy blank texture texture. I get the same behavior with a texture loaded from a bitmap file. These lines are the important ones:
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawLine(renderer, 0, 50, 50, 0);
SDL_RenderCopy(renderer, texture, 0, &target_rectangle);
SDL_RenderPresent(renderer);
So draw a line somewhere in white pixels, and then copy the dummy texture to the screen, and display it all. When I do this, I get a white pixel at the bottom right of the texture.
As I said, I also get this when the texture comes from a bitmap using code like this:
SDL_Surface *bitmap_surface = SDL_LoadBMP("test.bmp");
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, bitmap_surface);
SDL_FreeSurface(bitmap_surface);

Rendering in a small section of my window

I am currently working with SDL2. I am on Mac OS and I'm using xCode.
I have created a function to draw lines using randomly generated points.
However, when I try to render the lines, they are only render in a subset of my window (top left square).
Here's my code.
main.c
#include <SDL2/SDL.h>
#include "utils.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
// Prototypes
void drawRandomPoints( int pointsNo, SDL_Renderer *renderer );
void drawRandomLines( int linesNo, SDL_Renderer *renderer );
int main( int argc, const char * argv[] ) {
SDL_Init( SDL_INIT_VIDEO );
SDL_Window *window = SDL_CreateWindow( "Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL );
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
int running = 1;
SDL_Event event;
while( running ) {
while( SDL_PollEvent( &event ) ) {
if( event.type == SDL_QUIT ) {
running = 0;
}
}
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_RenderClear( renderer );
// Draw a point
SDL_SetRenderDrawColor( renderer, 255, 0, 0, 255 );
drawRandomLines( 100, renderer );
SDL_RenderPresent( renderer );
}
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
SDL_Quit();
return 0;
}
void drawRandomPoints( int pointsNo, SDL_Renderer *renderer ) {
int i = 0;
for( i = 0; i < pointsNo; ++i ) {
SDL_SetRenderDrawColor( renderer, getRandomColor(), getRandomColor(), getRandomColor(), 255 );
SDL_RenderDrawPoint( renderer, getRandomNumber( 0, SCREEN_WIDTH ), getRandomNumber( 0, SCREEN_HEIGHT ) );
}
}
void drawRandomLines( int linesNo, SDL_Renderer *renderer ) {
int i = 0;
for( i = 0; i < linesNo; ++i ) {
SDL_SetRenderDrawColor( renderer, getRandomColor(), getRandomColor(), getRandomColor(), 255 );
SDL_RenderDrawLine( renderer, getRandomNumber( 0, SCREEN_WIDTH ), getRandomNumber( 0, SCREEN_HEIGHT ), getRandomNumber( 0, SCREEN_WIDTH ), getRandomNumber( 0, SCREEN_HEIGHT ) );
}
}
utils.c
#include "utils.h"
#include <stdlib.h>
#include <time.h>
int getRandomNumber( int min, int max ) {
static int init = 0;
if( !init ) {
srand( time( NULL ) );
init = 1;
}
return ( rand() % ( max - min + 1 ) ) + min;
}
int getRandomColor() {
return getRandomNumber( 0, 255 );
}
Here's the result when compiling.
SDL window
You're only using a VGA size screen by defining these;
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
Try this
int SCREEN_WIDTH=640;
int SCREEN_HEIGHT=480;
and add to main like this;
SDL_Window *window = SDL_CreateWindow( "Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL );
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
SDL_GL_GetDrawableSize(window,&SCREEN_WIDTH,&SCREEN_HEIGHT);

libX11: XPutImage first call

I've created XImage using XCreateImage and use XPutImage to display it on window, but XPutImage shows this picture only on second call of it. Why this happens?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
void draw(char *rgb_out, int w, int h)
{
int i = 0;
for (i = 0;i < w*h;i += 4) {
rgb_out[i + 1] = 0;
rgb_out[i + 2] = 0;
rgb_out[i + 3] = 0;
}
return;
}
XImage *create_ximage(Display *display, Visual *visual, int width, int height)
{
char *image32 = (char *)malloc(width * height * 4);
draw(image32, width, height);
return XCreateImage(display, visual, 24,
ZPixmap, 0, image32,
width, height, 32, 0);
}
int main(int argc, char **argv)
{
int win_b_color;
int win_w_color;
XEvent xev;
Window window;
GC gc;
Display *display = XOpenDisplay(NULL);
Visual *visual;
XImage *ximage;
win_b_color = BlackPixel(display, DefaultScreen(display));
win_w_color = BlackPixel(display, DefaultScreen(display));
window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0, 600, 400, 0,
win_b_color, win_w_color);
gc = XCreateGC(display, window, 0, NULL);
visual = DefaultVisual(display, 0);
XMapWindow(display, window);
XFlush(display);
ximage = create_ximage(display, visual, 100, 100);
while (1) {
int r;
r = XPutImage(display, window,
gc, ximage, 0, 0, 0, 0,
100, 100);
printf("RES: %i\n", r);
XSync(display, 1);
XFlush(display);
getchar();
}
return 0;
}
The trick is to wait that the windows is mapped. You can do this by Expose event.
int main(int argc, char **argv)
{
int win_b_color;
int win_w_color;
XEvent xev;
Window window;
GC gc;
Display *display = XOpenDisplay(NULL);
Visual *visual;
XImage *ximage;
win_b_color = BlackPixel(display, DefaultScreen(display));
win_w_color = BlackPixel(display, DefaultScreen(display));
window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0, 600, 400, 0,
win_b_color, win_w_color);
visual = DefaultVisual(display, 0);
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
XFlush(display);
gc = XCreateGC(display, window, 0, NULL);
ximage = create_ximage(display, visual, 100, 100);
XEvent event;
bool exit = false;
while (!exit) {
int r;
XNextEvent(display, &event);
if (event.type == Expose)
{
r = XPutImage(display, window,
gc, ximage, 0, 0, 0, 0,
100, 100);
printf("RES: %i\n", r);
}
else if (event.type == KeyPress)
exit = true;
}
return 0;
}

Resources