Search code examples
c++enumsevent-handlingsdl-2

Fixing code that uses enums to organize event handling


When I ran the following code, I expected a result where pressing one of three buttons would each trigger a matching state that would render a matching image adjacent to those buttons, allowing me to rotate through fresh images at leisure with each successive button press.

Instead of that happy scenario, any initial button press skips right to the last image...or does nothing...or renders a blank white screen depending on how I fiddle with my placement of the initial state declaration and whether I place the state switch within or without the event handling switch. The whole system breaks and stops dead in its tracks. What is going on, and how do I fix it?

#include <string>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "cleanup.h"

SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect* clip = NULL;

const int LONGBUTTON_HEIGHT = 128;
const int LONGBUTTON_WIDTH = 256;

int Screen_Width  = 640;
int Screen_Height = 480;

int mouse_x;
int mouse_y;

int alphabutton_x = 0;
int alphabutton_y = 5;
int alphabutton_h = Screen_Width / 10;
int alphabutton_w = Screen_Width / 5;

int betabutton_x = 0;
int betabutton_y = 0.5 * (Screen_Width / 5) + 5;
int betabutton_h = Screen_Width / 10;
int betabutton_w = Screen_Width / 5;

int gammabutton_x = 0;
int gammabutton_y = 1 * (Screen_Width / 5) + 5;
int gammabutton_h = Screen_Width / 10;
int gammabutton_w = Screen_Width / 5;

int alpha_x = Screen_Width / 5;
int alpha_y = 0;
int alpha_h = Screen_Height;
int alpha_w = (4* Screen_Width)/5;

int beta_x = Screen_Width / 5;
int beta_y = 0;
int beta_h = Screen_Height;
int beta_w = (4* Screen_Width)/5;

int gamma_x = Screen_Width / 5;
int gamma_y = 0;
int gamma_h = Screen_Height;
int gamma_w = (4* Screen_Width)/5;

enum alphaButtonSprite {ALPHA_DEFAULT, ALPHA_HOVER, ALPHA_INACTIVE, ALPHA_PRESSED, ALPHA_TOTAL};
enum betaButtonSprite {BETA_DEFAULT, BETA_HOVER, BETA_INACTIVE, BETA_PRESSED, BETA_TOTAL};
enum gammaButtonSprite {GAMMA_DEFAULT, GAMMA_HOVER, GAMMA_INACTIVE, GAMMA_PRESSED, GAMMA_TOTAL};

enum State {ALPHA_STATE, BETA_STATE, GAMMA_STATE};

State state;

SDL_Texture* loadTexture(const std::string& file, SDL_Renderer* renderer)
{
    SDL_Texture* texture = IMG_LoadTexture(renderer, file.c_str());
    return texture;
}

void renderTexture(SDL_Texture* texture, SDL_Renderer* renderer, SDL_Rect dest,
    SDL_Rect* clip = nullptr)
{
    SDL_RenderCopy(renderer, texture, clip, &dest);
}

void renderTexture(SDL_Texture* texture, SDL_Renderer* renderer, int x, int y, int h, int w,
    SDL_Rect* clip = nullptr)
{
    SDL_Rect dest;
    dest.x = x;
    dest.y = y;
    dest.h = h;
    dest.w = w;

    renderTexture(texture, renderer, dest, clip);
}

// Main Function
int main(int, char**) 
{
    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window* window = SDL_CreateWindow("New Window", SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED, Screen_Width, Screen_Height, SDL_WINDOW_RESIZABLE);

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    SDL_Texture* longbutton_image = loadTexture("longbuttonSpriteSheet.png", renderer);
    SDL_Texture* alpha_image = loadTexture("alphaImage.png", renderer);
    SDL_Texture* beta_image = loadTexture("betaImage.png", renderer);
    SDL_Texture* gamma_image = loadTexture("gammaImage.png", renderer);

    state = BETA_STATE;

    SDL_Rect alpha_clips[alphaButtonSprite::ALPHA_TOTAL];
    for (int i = 0; i < alphaButtonSprite::ALPHA_TOTAL; i++)
    {
        alpha_clips[i].x = i * LONGBUTTON_WIDTH;
        alpha_clips[i].y = 0;
        alpha_clips[i].w = LONGBUTTON_WIDTH;
        alpha_clips[i].h = LONGBUTTON_HEIGHT;
    }
    int usealpha_Clip = ALPHA_DEFAULT;

    SDL_Rect beta_clips[betaButtonSprite::BETA_TOTAL];
    for (int i = 0; i < betaButtonSprite::BETA_TOTAL; i++)
    {
        beta_clips[i].x = i * LONGBUTTON_WIDTH;
        beta_clips[i].y = 4 * LONGBUTTON_HEIGHT;
        beta_clips[i].w = LONGBUTTON_WIDTH;
        beta_clips[i].h = LONGBUTTON_HEIGHT;
    }
    int usebeta_Clip = BETA_DEFAULT;

    SDL_Rect gamma_clips[gammaButtonSprite::GAMMA_TOTAL];
    for (int i = 0; i < gammaButtonSprite::GAMMA_TOTAL; i++)
    {
        gamma_clips[i].x = i * LONGBUTTON_WIDTH;
        gamma_clips[i].y = 5 * LONGBUTTON_HEIGHT;
        gamma_clips[i].w = LONGBUTTON_WIDTH;
        gamma_clips[i].h = LONGBUTTON_HEIGHT;
    }
    int usegamma_Clip = GAMMA_DEFAULT;

    SDL_Event e;
    bool quit = false;
    while (!quit)
    {
        while (SDL_PollEvent(&e))
        {
            switch (e.type)
            {
            case SDL_MOUSEBUTTONDOWN:
                mouse_x = e.button.x;
                mouse_y = e.button.y;

                if ((mouse_x <= (alphabutton_x + alphabutton_w)) && (mouse_x > alphabutton_x) &&
                    (mouse_y <= (alphabutton_y + alphabutton_h)) && (mouse_y > alphabutton_y))
                    usealpha_Clip = ALPHA_PRESSED;
                    state = ALPHA_STATE;

                if ((mouse_x <= (betabutton_x + betabutton_w)) && (mouse_x > betabutton_x) &&
                    (mouse_y <= (betabutton_y + betabutton_h)) && (mouse_y > betabutton_y))
                    usebeta_Clip = BETA_PRESSED;
                    state = BETA_STATE;

                if ((mouse_x <= (gammabutton_x + gammabutton_w)) && (mouse_x > gammabutton_x) &&
                    (mouse_y <= (gammabutton_y + gammabutton_h)) && (mouse_y > gammabutton_y))
                    usegamma_Clip = GAMMA_PRESSED;
                    state = GAMMA_STATE;
                break;
            }
        }

        switch (state)
        {
        case ALPHA_STATE:
            SDL_RenderClear(renderer);
            renderTexture(longbutton_image, renderer, alphabutton_x, alphabutton_y, alphabutton_h, alphabutton_w, &alpha_clips[usealpha_Clip]);
            renderTexture(longbutton_image, renderer, betabutton_x, betabutton_y, betabutton_h, betabutton_w, &beta_clips[usebeta_Clip]);
            renderTexture(longbutton_image, renderer, gammabutton_x, gammabutton_y, gammabutton_h, gammabutton_w, &gamma_clips[usegamma_Clip]);
            renderTexture(alpha_image, renderer, alpha_x, alpha_y, alpha_h, alpha_w, nullptr);
            SDL_RenderPresent(renderer);
            break;

        case BETA_STATE:
            SDL_RenderClear(renderer);
            renderTexture(longbutton_image, renderer, alphabutton_x, alphabutton_y, alphabutton_h, alphabutton_w, &alpha_clips[usealpha_Clip]);
            renderTexture(longbutton_image, renderer, betabutton_x, betabutton_y, betabutton_h, betabutton_w, &beta_clips[usebeta_Clip]);
            renderTexture(longbutton_image, renderer, gammabutton_x, gammabutton_y, gammabutton_h, gammabutton_w, &gamma_clips[usegamma_Clip]);
            renderTexture(beta_image, renderer, beta_x, beta_y, beta_h, beta_w, nullptr);
            SDL_RenderPresent(renderer);
            break;

        case GAMMA_STATE:
            SDL_RenderClear(renderer);
            renderTexture(longbutton_image, renderer, alphabutton_x, alphabutton_y, alphabutton_h, alphabutton_w, &alpha_clips[usealpha_Clip]);
            renderTexture(longbutton_image, renderer, betabutton_x, betabutton_y, betabutton_h, betabutton_w, &beta_clips[usebeta_Clip]);
            renderTexture(longbutton_image, renderer, gammabutton_x, gammabutton_y, gammabutton_h, gammabutton_w, &gamma_clips[usegamma_Clip]);
            renderTexture(gamma_image, renderer, gamma_x, gamma_y, gamma_h, gamma_w, nullptr);
            SDL_RenderPresent(renderer);
            break;
        }



        }

        //Destroy the various items
        cleanup(longbutton_image, alpha_image, beta_image, gamma_image, renderer, window);
        IMG_Quit();
        SDL_Quit();

        return 0;
    }

Solution

  • Found the answer to this one. In the mousebuttondown event switch cases, just put the state code before the useclip code. Why it makes a difference, I don't know, but it works. Cough...Also, doing it in the mousebuttonup switch cases instead of mousebuttondown works even better.