~groovestomp/gsnes

3b365fbeef990c057e3fc39ecfdda82c27fb42f9 — GrooveStomp 1 year, 5 months ago 99bb14a
Graphical Rendering

- Adds sprite rendering capabilities
- Renders the state of the PPU buffer to the display
- Reconfigures the display window to match the NES display
7 files changed, 81 insertions(+), 32 deletions(-)

M graphics.c
M graphics.h
M main.c
M ppu.c
M ppu.h
M sprite.c
M sprite.h
M graphics.c => graphics.c +23 -0
@@ 22,6 22,7 @@
#define STB_TRUETYPE_IMPLEMENTATION
#include "external/stb_truetype.h"
#include "graphics.h"
#include "sprite.h"

//! \brief A mostly generic implementation of swap
//!


@@ 329,3 330,25 @@ void GraphicsDrawText(struct graphics *graphics, int x, int y, char *string, int
                }
        }
}

void GraphicsDrawSprite(struct graphics *graphics, int x, int y, struct sprite *sprite, int scale) {
        if (NULL == sprite) return;

        if (scale > 1) {
                for (int i = 0; i < sprite->width; i++)
                        for (int j = 0; j < sprite->height; j++)
                                for (int is = 0; is < scale; is++)
                                        for (int js = 0; js < scale; js++) {
                                                uint32_t color = SpriteGetPixel(sprite, i, j);
                                                int xp = x + (i * scale) + is;
                                                int yp = y + (j * scale) + js;
                                                GraphicsPutPixel(graphics, xp, yp, color);
                                        }
        } else {
                for (int i = 0; i < sprite->width; i++)
                        for (int j = 0; j < sprite->height; j++) {
                                uint32_t color = SpriteGetPixel(sprite, i, j);
                                GraphicsPutPixel(graphics, x + i, y + j, color);
                        }
        }
}

M graphics.h => graphics.h +12 -0
@@ 19,6 19,8 @@
#ifndef GRAPHICS_VERSION
#define GRAPHICS_VERSION "0.2-gstxt" //!< include guard and version info

struct sprite;

//! \brief Creates and initializes new graphics state.
//!
//! \param[in] title The title displayed in the window titlebar


@@ 104,4 106,14 @@ GraphicsDrawText(struct graphics *graphics, int x, int y, char *string, int font
void
GraphicsDrawLine(struct graphics *graphics, int x1, int y1, int x2, int y2, uint32_t color);

//! \brief Draws a sprite starting with lower left corner at (x,y)
//!
//! \param[in,out] graphics
//! \param[in] x x coordinate to start drawing from
//! \param[in] y y coordinate to start drawing from
//! \param[in] sprite sprite to draw
//! \param[in] scale integer scale of sprite
void
GraphicsDrawSprite(struct graphics *graphics, int x, int y, struct sprite *sprite, int scale);

#endif // GRAPHICS_VERSION

M main.c => main.c +19 -13
@@ 46,10 46,14 @@
 NOP
 NOP
*/
static char *program = "A2 0A 8E 00 00 A2 03 8E 01 00 AC 00 00 A9 00 18 6D 01 00 88 D0 FA 8D 02 00 EA EA EA";
static const char *program = "A2 0A 8E 00 00 A2 03 8E 01 00 AC 00 00 A9 00 18 6D 01 00 88 D0 FA 8D 02 00 EA EA EA";

static int WIDTH = 1200;
static int HEIGHT = 800;
static const int FONT_SCALE = 25;

static const int NES_SCREEN_WIDTH = 256 * 3;
static const int NES_SCREEN_HEIGHT = 240 * 3;
static const int WIDTH = NES_SCREEN_WIDTH + 250;
static const int HEIGHT = NES_SCREEN_HEIGHT;

static struct cpu *cpu = NULL;
static struct ppu *ppu = NULL;


@@ 148,7 152,7 @@ void LoadRom(struct bus *bus, char *data) {
}

void DrawCpuState(int x, int y) {
        GraphicsDrawText(graphics, x, y, "CPU State", 25, 0x000000FF);
        GraphicsDrawText(graphics, x, y, "CPU State", FONT_SCALE, 0x000000FF);
        char **cpu_state = CpuDebugStateInit(cpu);
        for (int i = 0; i < 7; i++) {
                GraphicsDrawText(graphics, x, (y - 20) - (18 * i), cpu_state[i], 15, 0x000000FF);


@@ 157,7 161,7 @@ void DrawCpuState(int x, int y) {
}

void DrawDisassembly(struct disassembly *disassembly, int x, int y, int numLines) {
        GraphicsDrawText(graphics, x, y, "Disassembly", 25, 0x000000FF);
        GraphicsDrawText(graphics, x, y, "Disassembly", FONT_SCALE, 0x000000FF);

        int pc = DisassemblyFindPc(disassembly, cpu);



@@ 170,11 174,11 @@ void DrawDisassembly(struct disassembly *disassembly, int x, int y, int numLines

        for (int i = min; i < max; i++) {
                if (NULL == disassembly || NULL == disassembly->map || NULL == disassembly->map[i]) {
                        GraphicsDrawLine(graphics, x, (y - 25) - (9 * i), x + 100, (y - 15) - (9 * i), ColorBlack.rgba);
                        GraphicsDrawLine(graphics, x, (y - FONT_SCALE) - (9 * i), x + 100, (y - 15) - (9 * i), ColorBlack.rgba);
                } else if (i == pc) {
                        GraphicsDrawText(graphics, x, (y - 25) - (18 * i), disassembly->map[i]->text, 15, ColorBlue.rgba);
                        GraphicsDrawText(graphics, x, (y - FONT_SCALE) - (18 * i), disassembly->map[i]->text, 15, ColorBlue.rgba);
                } else {
                        GraphicsDrawText(graphics, x, (y - 25) - (18 * i), disassembly->map[i]->text, 15, ColorBlack.rgba);
                        GraphicsDrawText(graphics, x, (y - FONT_SCALE) - (18 * i), disassembly->map[i]->text, 15, ColorBlack.rgba);
                }
        }
}


@@ 190,7 194,7 @@ int main(int argc, char **argv) {
        BusWrite(bus, 0xFFFD, 0x80);

        // Disassemble
        struct disassembly *disassembly = DisassemblyInit(cpu, 0x0000, 0x00FF);
        struct disassembly *disassembly = DisassemblyInit(cpu, 0x00000, 0x00FF);

        struct timespec frameEnd;
        struct timespec frameStart;


@@ 247,11 251,13 @@ int main(int argc, char **argv) {
                if (InputIsKeyPressed(input, KEY_SPACE)) isEmulating = !isEmulating;
                if (InputIsKeyPressed(input, KEY_R)) BusReset(bus);

                GraphicsDrawLine(graphics, 811, 0, 811, 800, 0x000000FF);
                DrawCpuState(820, 775);
                GraphicsDrawLine(graphics, NES_SCREEN_WIDTH, 0, NES_SCREEN_WIDTH, HEIGHT, 0x000000FF);
                DrawCpuState(NES_SCREEN_WIDTH + 10, HEIGHT - 30);

                GraphicsDrawLine(graphics, NES_SCREEN_WIDTH, HEIGHT - 175, WIDTH, HEIGHT - 175, 0x000000FF);
                DrawDisassembly(disassembly, NES_SCREEN_WIDTH + 10, HEIGHT - 175 - 30, 25);

                GraphicsDrawLine(graphics, 811, 630, 1200, 630, 0x000000FF);
                DrawDisassembly(disassembly, 820, 600, 25);
                GraphicsDrawSprite(graphics, 0, 0, PpuScreen(ppu), 3);

                GraphicsEnd(graphics);
        }

M ppu.c => ppu.c +4 -0
@@ 291,3 291,7 @@ int PpuIsFrameComplete(struct ppu *ppu) {
void PpuResetFrameCompletion(struct ppu *ppu) {
        ppu->isFrameComplete = false;
}

struct sprite *PpuScreen(struct ppu *ppu) {
        return ppu->screen;
}

M ppu.h => ppu.h +4 -0
@@ 19,6 19,7 @@

struct ppu;
struct cart;
struct sprite;

struct ppu *
PpuInit();


@@ 41,4 42,7 @@ PpuIsFrameComplete(struct ppu *ppu);
void
PpuResetFrameCompletion(struct ppu *ppu);

struct sprite *
PpuScreen(struct ppu *ppu);

#endif // PPU_VERSION

M sprite.c => sprite.c +11 -14
@@ 20,19 20,13 @@
#include "sprite.h"
#include "color.h"

struct sprite {
        struct color *pixels;
        uint32_t width;
        uint32_t height;
};

struct sprite *SpriteInit(unsigned int width, unsigned int height) {
        struct sprite *sprite = (struct sprite *)malloc(sizeof(struct sprite));
        if (NULL == sprite) {
                return NULL;
        }

        sprite->pixels = (struct color *)malloc(sizeof(struct color) * width * height);
        sprite->pixels = (uint32_t *)calloc(width * height, sizeof(uint32_t));
        if (NULL == sprite->pixels) {
                free(sprite);
                return NULL;


@@ 59,21 53,24 @@ void SpriteDeinit(struct sprite *sprite) {

void SpriteSetPixel(struct sprite *sprite, unsigned int x, unsigned int y, uint32_t rgba) {
        if (x >= 0 && x < sprite->width && y >= 0 && y < sprite->height) {
                sprite->pixels[y * sprite->width + x] = ColorInitInt(rgba);
                sprite->pixels[y * sprite->width + x] = rgba;
        }
}

uint32_t SpriteGetPixel(struct sprite *sprite, unsigned int x, unsigned int y) {
        if (x >= 0 && x < sprite->width && y >= 0 && y < sprite->height) {
                return sprite->pixels[y * sprite->width + x];
        }
        return ColorBlack.rgba;
}

uint32_t SpriteSample(struct sprite *sprite, float x, float y) {
        int32_t sx = fminf(x * (float)sprite->width, sprite->width - 1);
        int32_t sy = fminf(y * (float)sprite->height, sprite->height - 1);

        if (sx >= 0 && sx < sprite->width && sy >= 0 && sy < sprite->height) {
                return sprite->pixels[sy * sprite->width + sx].rgba;
                return sprite->pixels[sy * sprite->width + sx];
        }

        return ColorInitFloats(0, 0, 0, 0).rgba;
}

struct color *SpriteData(struct sprite *sprite) {
        return sprite->pixels;
        return ColorBlack.rgba;
}

M sprite.h => sprite.h +8 -5
@@ 16,8 16,11 @@
//! \file sprite.h
#include <stdint.h>

struct sprite;
struct color;
struct sprite {
        uint32_t *pixels;
        uint32_t width;
        uint32_t height;
};

struct sprite *
SpriteInit(unsigned int width, unsigned int height);


@@ 29,7 32,7 @@ void
SpriteSetPixel(struct sprite *sprite, unsigned int x, unsigned int y, uint32_t rgba);

uint32_t
SpriteSample(struct sprite *sprite, float x, float y);
SpriteGetPixel(struct sprite *sprite, unsigned int x, unsigned int y);

struct color *
SpriteData(struct sprite *sprite);
uint32_t
SpriteSample(struct sprite *sprite, float x, float y);