-1

I am trying to write a setPixel function using SDL2 but this code is not working as expected.

As this function need, I have window, renderer and texture pointer as global variable.

#include <SDL2/SDL.h>
#include <iostream>

using namespace std;

SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* texture = NULL;

bool running = false;



void handleEvents();
void update();
void render();
void setPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b);

int main(int argc, char const *argv[])
{


    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
    {
        cout << "SDL init failed " << SDL_GetError() << "\n";
        return 1;
    }
    
    window = SDL_CreateWindow("Testing_01",
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 
                              800, 640, 
                              SDL_WINDOW_SHOWN);

    if (window == NULL)
    {
        cout << "Window creation failed " << SDL_GetError() << "\n";
        return 1;
    }

    renderer = SDL_CreateRenderer(window, -1, 0);
    if (renderer == NULL)
    {
        cout << "Renderer creation failed " << SDL_GetError() << "\n";
        return 1;
    }

    SDL_SetRenderDrawColor(renderer, 230, 230, 230, 255);

    setPixel(10, 10, 255, 0, 0);

    running = true;
    while (running)
    {
        handleEvents();
        update();
        render();
    }

    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();
    return 0;
}

void handleEvents()
{   
    SDL_Event event;
    const Uint8 *keys = SDL_GetKeyboardState(NULL);

    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT:
                running = false;
                break;
            default:
                break;
        }
    }

    if (keys[SDL_SCANCODE_ESCAPE]) 
    {
       running = false;
    }

    if (keys[SDL_SCANCODE_RIGHT]) 
    {
        printf("Right and Up Keys Pressed.\n");
    }
}

void update()
{

}
        
void render()
{
    SDL_RenderClear(renderer);

    SDL_RenderPresent(renderer);
}

void setPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b)
{   

    // Allocate memory for a pixel buffer.
    Uint32 *pixels = new Uint32[800 * 640];

    // Clear the pixel buffer.
    memset(pixels, 0, 800 * 640 * sizeof(Uint32));

    SDL_Rect rect, bound;
    rect.x = 0;
    rect.y = 0;
    rect.w = 800;
    rect.h = 640;
    bound = rect;

    const SDL_Rect* constRect = &rect;

    Uint32 color;

    texture = SDL_CreateTexture(renderer,
                                SDL_PIXELFORMAT_RGB888,
                                SDL_TEXTUREACCESS_STREAMING, 800,
                                640);

    
    SDL_LockTexture(texture,
                    constRect,
                    (void**) pixels, (int*)( 800 * sizeof(Uint32)));

    color = SDL_MapRGB(SDL_AllocFormat(SDL_PIXELFORMAT_RGBA8888), r, g, b);

    pixels[(y*800)+x] = color;

    SDL_UpdateTexture(texture,
                      constRect,
                      pixels, 800 * sizeof(Uint32));

    delete[] pixels;

    SDL_RenderCopy(renderer, texture, &rect, &bound);

    SDL_UnlockTexture(texture);
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
jdP
  • 1
  • 3
  • 1
    One thing I see is it appears to be a very slow operation to set a single pixel. Also the use of conflicting magic numbers is very bad. In places you use 800 x 640 and in others its 800 by 600 – drescherjm Mar 11 '22 at 14:03
  • Please include full source so we can run the code ourself. – Goswin von Brederlow Mar 11 '22 at 14:08
  • I updated the full code. – jdP Mar 11 '22 at 14:18
  • HI @drescherjm , thank you for leting me know that dealing with pixel like this slow. I need some circle and other shape to draw using sdl2 but it don't have any function for that. So if I able to set a pixel than I can make a circle out of it. So trying to write the function. – jdP Mar 11 '22 at 14:35

2 Answers2

1

You can use SDL_RenderDrawPoint in conjunction with SDL_SetRenderDrawColor to achieve what you want to (assuming you're just aiming to draw pixels straight to the screen). This method doesn't require using an intermediate texture to draw to.

I've changed your set pixel function to:

void setPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b) {
    SDL_SetRenderDrawColor(renderer, r, g, b, SDL_ALPHA_OPAQUE);
    SDL_RenderDrawPoint(renderer, x, y);
}

and your render function to:

void render()
{
    SDL_SetRenderDrawColor(renderer, 230, 230, 230, 255);
    SDL_RenderClear(renderer);
    setPixel(10, 10, 255, 0, 0);
    SDL_RenderPresent(renderer);
}

The pixel will be redrawn each update with the sample I have provided.

You can see this related question for more information.

Ben
  • 116
  • 1
  • 7
  • What about writing the way my setPixel()? Actualy I wanna do somting like this instead using the SDL_RenderDrawPoint() – jdP Mar 11 '22 at 15:07
  • Probably best to edit the question and mention you want to set a pixel in a texture specifically. In that case, this answer may help you https://gamedev.stackexchange.com/questions/98641/how-do-i-modify-textures-in-sdl-with-direct-pixel-access – Ben Mar 11 '22 at 15:17
0

Welcome to SDL2!

You should not lock the texture if you are going to write onto it.