Почему SDL2 Renderer ничего не рисует в моем окне? - PullRequest
0 голосов
/ 24 апреля 2020

В настоящее время я работаю над интерпретатором Chip-8 в C. Для рендеринга я использую библиотеку SDL2. Проблема в том, что я не могу нарисовать прямоугольник на экране. Функция SDL_RenderClear также не работает. Возможно, это Makefile, но я уже пытался изменить флаг консоли в компоновщике на windows. Кто-нибудь может мне помочь?

Мой код:

main. c

#include "chip.h"

#define NO_ROM_INSERTED 1

const int PIXEL_SIZE = 20;
const int CHIP_WIDTH = 64;
const int CHIP_HEIGHT = 32;

const int SCREEN_WIDTH = CHIP_WIDTH * PIXEL_SIZE;
const int SCREEN_HEIGHT = CHIP_HEIGHT * PIXEL_SIZE;

int main(int argc, char **argv)
{
    SDL_Window *window = NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Event event;
    int quit = 0;

    Chip *chip = (Chip*)malloc(sizeof(Chip));
    chipInitialize(chip);

    chip->gfx[23] = 0x01;

    /*Checks if a ROM file is inserted by an argument*/
    if(argc < 2)    
    {
        printf("Error, no Rom inserted");
        return NO_ROM_INSERTED;
    }
    else
    {
        printf("\n%s loaded into memory\n", argv[argc-1]);
    }

    loadProgramInMemory(chip, "./Roms/TETRIS");


    if(!init(window, renderer, SCREEN_WIDTH, SCREEN_HEIGHT))
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {   
        while(!quit)
        {
            while(SDL_PollEvent(&event) != 0)
            {
                if(event.type == SDL_QUIT)
                {
                    quit = 1;
                }
            }

            // Clear screen
            SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0xFF, 0xFF);
            SDL_RenderClear(renderer);

            for(int i = 0; i < CHIP_HEIGHT; i++)
            {
                for(int j = 0; j < CHIP_WIDTH; j++)
                {
                    if(chip->gfx[i * CHIP_WIDTH + j] > 0x00) //Translates the one dimensional gfx to two dimensional screen
                    {
                        SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
                        SDL_Rect fillRect = {CHIP_WIDTH * i, CHIP_HEIGHT * j, PIXEL_SIZE, PIXEL_SIZE};
                        SDL_RenderFillRect(renderer, &fillRect);
                    }
                }
            }
            // Update screen
            SDL_RenderPresent(renderer);
        }
    }

    close(window, renderer);

    free(chip);

    return 0;
}

chip.h

#include "window.h"

typedef struct chip{

unsigned char memory[4096];

unsigned short opcode;
unsigned short pc;
unsigned short stack[16];
unsigned short sp;

unsigned char gfx[64 * 32];

unsigned char V[16];
unsigned short I;

unsigned char delayTimer;
unsigned char soundTimer;

}Chip;

void chipInitialize(Chip *chip);
void loadFontInMemory(Chip *chip);
void loadProgramInMemory(Chip *chip, char *program);

чип. c

#include "chip.h"

void chipInitialize(Chip *chip)
{
    chip->pc            = 0x200;            // Set program counter to 0x200
    chip->opcode        = 0x0000;           // Reset current opcode
    chip->I             = 0x0000;           // Reset index register
    chip->sp            = 0x0000;           // Reset stack pointer

    chip->delayTimer    = 0x00;             // Reset delay timer
    chip->soundTimer    = 0x00;             // Reset sound timer

    for(int i = 0; i < 64 * 32; i++)        // Reset the graphics
        chip->gfx[i] = 0x00;

    for(int i = 0; i < 16; i++)             // Reset the stack
        chip->stack[i] = 0x0000;

    for(int i = 0; i < 4069; i++)           // Reset memory
        chip->memory[i] = 0x00;

    for(int i = 0; i < 16; i++)             // Reset registers
        chip->V[i] = 0x00;

    loadFontInMemory(chip);                 // Loads the font-set into memory
}

void loadProgramInMemory(Chip *chip, char *program)
{
    int bufferSize = 0xFFF - 0x200;         // Size of the memory which is reserved for the program
    unsigned char buffer[bufferSize];
    FILE *ptr;

    ptr = fopen(program, "rb");
    fread(buffer, bufferSize, 1, ptr);

    for(int i = 0; i < bufferSize; i++)
    chip->memory[i + 512] = buffer[i];  // Reads in the program and stores it in memory at location 0x200 or 512
}

void loadFontInMemory(Chip *chip)
{
    // Zero                         // Six                          // C
    chip->memory[0x000] = 0xF0;     chip->memory[0x01E] = 0xF0;     chip->memory[0x03C] = 0xF0;
    chip->memory[0x001] = 0x90;     chip->memory[0x01F] = 0x80;     chip->memory[0x03D] = 0x80;
    chip->memory[0x002] = 0x90;     chip->memory[0x020] = 0xF0;     chip->memory[0x03E] = 0x80;
    chip->memory[0x003] = 0x90;     chip->memory[0x021] = 0x90;     chip->memory[0x03F] = 0x80;
    chip->memory[0x004] = 0xF0;     chip->memory[0x022] = 0xF0;     chip->memory[0x040] = 0xF0;

    // One                          // Seven                        // D
    chip->memory[0x005] = 0x20;     chip->memory[0x023] = 0xF0;     chip->memory[0x041] = 0xE0;
    chip->memory[0x006] = 0x60;     chip->memory[0x024] = 0x10;     chip->memory[0x042] = 0x90;
    chip->memory[0x007] = 0x20;     chip->memory[0x025] = 0x20;     chip->memory[0x043] = 0x90;
    chip->memory[0x008] = 0x20;     chip->memory[0x026] = 0x40;     chip->memory[0x044] = 0x90;
    chip->memory[0x009] = 0x70;     chip->memory[0x027] = 0x40;     chip->memory[0x045] = 0xE0;

    // Two                          // Eight                        // E
    chip->memory[0x00A] = 0xF0;     chip->memory[0x028] = 0xF0;     chip->memory[0x046] = 0xF0;
    chip->memory[0x00B] = 0x10;     chip->memory[0x029] = 0x90;     chip->memory[0x047] = 0x80;
    chip->memory[0x00C] = 0xF0;     chip->memory[0x02A] = 0xF0;     chip->memory[0x048] = 0xF0;
    chip->memory[0x00D] = 0x80;     chip->memory[0x02B] = 0x90;     chip->memory[0x049] = 0x80;
    chip->memory[0x00E] = 0xF0;     chip->memory[0x02C] = 0xF0;     chip->memory[0x04A] = 0xF0;

    // Three                        // Nine                         // F
    chip->memory[0x00F] = 0xF0;     chip->memory[0x02D] = 0xF0;     chip->memory[0x04B] = 0xF0;
    chip->memory[0x010] = 0x10;     chip->memory[0x02E] = 0x90;     chip->memory[0x04C] = 0x80;
    chip->memory[0x011] = 0xF0;     chip->memory[0x02F] = 0xF0;     chip->memory[0x04D] = 0xF0;
    chip->memory[0x012] = 0x10;     chip->memory[0x030] = 0x10;     chip->memory[0x04E] = 0x80;
    chip->memory[0x013] = 0xF0;     chip->memory[0x031] = 0xF0;     chip->memory[0x04F] = 0x80;

    // Four                         // A
    chip->memory[0x014] = 0x90;     chip->memory[0x032] = 0xF0;
    chip->memory[0x015] = 0x90;     chip->memory[0x033] = 0x90;
    chip->memory[0x016] = 0xF0;     chip->memory[0x034] = 0xF0;
    chip->memory[0x017] = 0x10;     chip->memory[0x035] = 0x90;
    chip->memory[0x018] = 0x10;     chip->memory[0x036] = 0x90;

    // Five                         // B
    chip->memory[0x019] = 0xF0;     chip->memory[0x037] = 0xE0;
    chip->memory[0x01A] = 0x80;     chip->memory[0x038] = 0x90;
    chip->memory[0x01B] = 0xF0;     chip->memory[0x039] = 0xE0;
    chip->memory[0x01C] = 0x10;     chip->memory[0x03A] = 0x90;
    chip->memory[0x01D] = 0xF0;     chip->memory[0x03B] = 0xE0;
}

window.h

#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>

int init(SDL_Window *window, SDL_Renderer* renderer, const 
int width, const int height);
void close(SDL_Window *window, SDL_Renderer* renderer);

окно . c

#include "window.h"

int init(SDL_Window *window, SDL_Renderer *renderer, const 
int width, const int height)
{
//Initialization flag
int success = 1;

//Initialize SDL
if( SDL_Init(SDL_INIT_VIDEO) < 0)
{
    printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
    success = 0;
}
else
{
    //Create window
    window = SDL_CreateWindow( "Chip-8 Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN );
    if( window == NULL )
    {
        printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError());
        success = 0;
    }
    else
    {
        renderer = SDL_CreateRenderer(window, -1, 0);
        if(renderer == NULL)
        {
            printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
            success = 0;
        }
        else
        {
            SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0xFF, 0xFF);
        }
    }
}

return success;
}

 void close(SDL_Window *window, SDL_Renderer* renderer)
{
//Destroy window
SDL_DestroyWindow( window );
window = NULL;

SDL_DestroyRenderer(renderer);
renderer = NULL;
//Quit SDL subsystems
SDL_Quit();
}

Makefile

OBJS = main.c chip.c window.c

OBJ_NAME = Emulator

all : $(OBJS)
gcc $(OBJS) -IC:\code\SDL2\i686-w64-mingw32\include -LC:\code\SDL2\i686-w64-mingw32\lib -w -Wl,-subsystem,console -lmingw32 -lSDL2main -lSDL2 -o $(OBJ_NAME)

1 Ответ

0 голосов
/ 24 апреля 2020

Позвольте мне начать с рекомендации - если вам вообще интересен ответ, пожалуйста, не усложняйте ответ на ваш вопрос, чем он должен быть. Подумайте, как это выглядит для других - некоторый объем кода, с проблемой, по-видимому, в том, чтобы ничего не рисовать; почему в этом примере должно быть 6 файлов? Почему это зависит от внешнего файла, которого у нас нет и, следовательно, у нас буквально нет способа проверить? Конечно, можно уменьшить его до 30 строк одного файла с помощью только инициализации и рендеринга - буквально подойдет любой «привет мир» для SDL2. И когда он работает, а ваш код - нет, вы начинаете проверять, что отличается.

Теперь к вашему вопросу. Вы не можете извлечь что-либо из вашего основного l oop, потому что ваши window и renderer здесь равны NULL - он был инициализирован как NULL и никогда не был установлен в другое значение. Похоже, у вас неправильное представление о том, как работают аргументы функции - в C аргументы функции передаются по значению, и любая модификация этого значения выполняется в локальной копии функции. Когда вы передаете int, функция получает копию этого int и не возвращает sh никаких изменений обратно. Если вы передаете SDL_Window*, то вы передаете значение этого указателя (в вашем случае, NULL); когда вы делаете SDL_CreateWindow, вы присваиваете его локальной переменной, и однажды angain не может вернуть его вызывающей стороне, где она остается NULL. Таким образом, все ваши вызовы рендеринга передают NULL как средство рендеринга, которое, естественно, не является действительным средством рендеринга.

То же самое появляется в вашем close - вы пытаетесь сбросить переданные копии в NULL, но это делает нет смысла, так как вы не можете изменить внешнее значение, только локально-функциональное копирование.

Классы программирования часто учат, что есть «передача по значению» и «передача по ссылке», что, я полагаю, является источником это замешательство. Я бы скорее сказал, что в C нет передачи по ссылке, вы всегда передаете значение, но указатель также является значением. Чтобы иметь возможность изменять данные, мы передаем указатель на эти данные; чтобы преобразовать int, вы можете передать int*, но чтобы изменить SDL_Window*, вам нужно получить указатель на указатель - SDL_Window**. Посмотрите, как это делает сам SDL: https://wiki.libsdl.org/SDL_CreateWindowAndRenderer.

Итак, вкратце - сделайте ваш init равным int init(SDL_Window **window, SDL_Renderer** renderer, int width, int height); (вам не нужно const int здесь также, поскольку это копии ширины и высоты), и соответственно измените его код. И проверьте значения window и renderer после этого вызова (отладчик, отладка printf, if(window==NULL) все идет). init может быть что-то вроде

int init(SDL_Window **owindow, SDL_Renderer **orenderer,
        int width, int height)
{
    SDL_Window *window = NULL;
    SDL_Renderer *renderer = NULL;

    //Initialization flag
    int success = 1;

    //Initialize SDL
    if( SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = 0;
    }
    else
    {
        //Create window
        window = SDL_CreateWindow( "Chip-8 Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN );
        if( window == NULL )
        {
            printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError());
            success = 0;
        }
        else
        {
            renderer = SDL_CreateRenderer(window, -1, 0);
            if(renderer == NULL)
            {
                printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
                success = 0;
            }
            else
            {
                SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0xFF, 0xFF);
            }
        }
    }

    *owindow = window;
    *orenderer = renderer;
    return success;
}

Конечно, вызов init должен быть изменен на init(&window, &renderer, SCREEN_WIDTH, SCREEN_HEIGHT).

Пока мы на этом, еще две вещи:

  • Заголовочные файлы должны иметь включать ограждения , иначе это может вызвать проблемы, если вы когда-либо включите его (прямо или косвенно) несколько раз.

  • никогда, никогда не вызывайте вашу функцию close. В системах linux / UNIX он (без каких-либо проблем) рухнет. Подумайте о другом имени, которое не зарезервировано широко распространенными операционными системами.

...