Search code examples
c++windowssdl-2

Texture not displaying SDL2


I'm trying to make a game in C++ with SDL2, and I can't even get a texture displaying. SDL_GetError() returns nothing. I'm on a windows 10 pro using Visual Studio. Here are my 3 files:

  1. main.cpp
#include "Classes.h"

int MouseX = 0;
int MouseY = 0;
int PlayerX = 0;
int PlayerY = 0;
SDL_Renderer* renderer;
Tile tile = Tile({10, 10, TileTypes::Tile_Grass}, renderer);

EventReturns HandleEvent(SDL_Event* event) {
    switch (event->type) {
    case SDL_QUIT:
        return EventReturns::Event_QUIT;
    case SDL_KEYDOWN:
        switch (event->key.keysym.sym) {
        case SDLK_ESCAPE:
            return EventReturns::Event_TryQuit;
        default:
            return EventReturns::Event_None;
        }
    default:
        return EventReturns::Event_None;
    }
}

int mainLoop(EventReturns eventReturn) {
    SDL_GetMouseState(&MouseX, &MouseY);
    if (eventReturn == EventReturns::Event_QUIT || eventReturn == EventReturns::Event_TryQuit) {
        return 1;
    }
    return 0;
}

void render() {
    SDL_SetRenderDrawColor(renderer, 100, 200, 200, 255);
    SDL_RenderClear(renderer);
    
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    tile.SetPos(0, 0);
    if (tile.Draw(renderer) != 0) {
        SDL_ShowSimpleMessageBox(0, "ERROR", "ERROR: Rect in tile has 0x0 size, Please close this with the task manager", NULL);
    }

    SDL_RenderPresent(renderer);
}

int main(int argc, char* argv[]) {
    SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 2880, 1600, SDL_WINDOW_SHOWN);
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    bool running = true;
    EventReturns eventReturn = EventReturns::Event_None;
    SDL_Event event;
    int quit = 0;
    while (running) {
        while (SDL_PollEvent(&event)) {
            eventReturn = HandleEvent(&event);
        }
        quit = mainLoop(eventReturn);
        render();
        if (quit == 1) {
            running = false;
        }
    }
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}
  1. Classes.h
#pragma once
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#define SpriteSizeMult 1

enum class EventReturns {
    Event_QUIT,
    Event_None,
    Event_TryQuit
};

enum class TileTypes {
    Tile_Grass
};

struct TileStruct {
    int x;
    int y;
    TileTypes type;
};

class Tile {
public:
    Tile(int x, int y, char* TexturePath, SDL_Renderer* renderer);
    Tile(TileStruct structure, SDL_Renderer* renderer);
    Tile();

    int Draw(SDL_Renderer* renderer);

    void SetPos(int x, int y);

private:
    int x = 0;
    int y = 0;
    int TextureWidth = 0;
    int TextureHeight = 0;
    SDL_Texture* texture;
    SDL_Rect rect;
};

SDL_Point getsize(SDL_Texture* texture);
  1. Classes.cpp
#include "Classes.h"

SDL_Point getsize(SDL_Texture* texture) {
    SDL_Point size;
    SDL_QueryTexture(texture, NULL, NULL, &size.x, &size.y);
    return size;
}

Tile::Tile(int x, int y, char* TexturePath, SDL_Renderer* renderer)
{
    this->x = x;
    this->y = y;
    this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load(TexturePath));
    if (this->texture == nullptr) {
        this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/MissingTexture.png"));
        std::cout << IMG_GetError();
    }
    SDL_Point point = getsize(this->texture);
    this->TextureHeight = point.y;
    this->TextureWidth = point.x;
    this->rect = {this->x - ((this->TextureWidth * SpriteSizeMult) / 2), this->y - ((this->TextureHeight * SpriteSizeMult) / 2), this->TextureWidth * SpriteSizeMult, this->TextureHeight * SpriteSizeMult};
}

Tile::Tile(TileStruct structure, SDL_Renderer* renderer)
{
    this->x = structure.x;
    this->y = structure.y;
    switch (structure.type) {
    case TileTypes::Tile_Grass:
        this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/Tiles/Grass.png"));
    default:
        this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/MissingTexture.png"));
    }
    if (this->texture == NULL) {
        this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/MissingTexture.png"));
        if (this->texture == NULL) {
            SDL_ShowSimpleMessageBox(0, "ERROR", "Failed to load texture", NULL);
            SDL_ShowSimpleMessageBox(0, "ERROR", IMG_GetError(), NULL);
        }
    }
    SDL_Point point = getsize(this->texture);
    this->TextureHeight = point.y;
    this->TextureWidth = point.x;
    this->rect = { this->x - ((this->TextureWidth * SpriteSizeMult) / 2), this->y - ((this->TextureHeight * SpriteSizeMult) / 2), this->TextureWidth * SpriteSizeMult, this->TextureHeight * SpriteSizeMult };
}

Tile::Tile() 
{
}

int Tile::Draw(SDL_Renderer* renderer)
{
    if (rect.w == 0 || rect.h == 0) {
        return -1;
    }
    this->rect.x = 0;
    this->rect.y = 0;
    SDL_RenderCopy(renderer, this->texture, NULL, &rect);
    return 0;
}

void Tile::SetPos(int x, int y)
{
    this->x = x;
    this->y = y;
}

I'm sorry for the sheer amount of code that is, but I'd really appreciate the help. If there's any more info I need to put here, just let me know.

I'm fully aware that I should make a Minimal Reproducible Example, but as far as I'm aware, all the code listed here is necessary.

Finally, in case I've been unclear, when running the code the Missing Texture image that should appear isn't showing up.


Solution

  • I can't see SDL_INIT function in your code. You should add this in the beginning of your main function.

    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
        return 1;
    

    You are initialising tile before creating a renderer so the constructor is trying to create a texture without a renderer.

    SDL_Renderer* renderer;
    Tile tile = Tile({10, 10, TileTypes::Tile_Grass}, renderer);
    

    You should do something like this

    #include "Classes.h"
    
    int MouseX = 0;
    int MouseY = 0;
    int PlayerX = 0;
    int PlayerY = 0;
    SDL_Renderer* renderer;
    
    
    EventReturns HandleEvent(SDL_Event* event) {
    switch (event->type) {
    case SDL_QUIT:
        return EventReturns::Event_QUIT;
    case SDL_KEYDOWN:
        switch (event->key.keysym.sym) {
        case SDLK_ESCAPE:
            return EventReturns::Event_TryQuit;
        default:
            return EventReturns::Event_None;
        }
    default:
        return EventReturns::Event_None;
    }
    }
    
    int mainLoop(EventReturns eventReturn) {
    SDL_GetMouseState(&MouseX, &MouseY);
    if (eventReturn == EventReturns::Event_QUIT || eventReturn == EventReturns::Event_TryQuit) {
        return 1;
    }
    return 0;
    }
    
    void render(Tile tile) {
    SDL_SetRenderDrawColor(renderer, 100, 200, 200, 255);
    SDL_RenderClear(renderer);
    
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    tile.SetPos(0, 0);
    if (tile.Draw(renderer) != 0) {
        SDL_ShowSimpleMessageBox(0, "ERROR", "ERROR: Rect in tile has 0x0 size, Please close this with the task manager", NULL);
    }
    
    SDL_RenderPresent(renderer);
    }
    
    int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
        return 1;
    SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 2880, 1600, SDL_WINDOW_SHOWN);
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    Tile tile = Tile({ 10, 10, TileTypes::Tile_Grass }, renderer);
    bool running = true;
    EventReturns eventReturn = EventReturns::Event_None;
    SDL_Event event;
    int quit = 0;
    while (running) {
        while (SDL_PollEvent(&event)) {
            eventReturn = HandleEvent(&event);
        }
        quit = mainLoop(eventReturn);
        render(tile);
        if (quit == 1) {
            running = false;
        }
    }
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
    }