aboutsummaryrefslogtreecommitdiffstats
path: root/src/ppu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ppu.c')
-rw-r--r--src/ppu.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/ppu.c b/src/ppu.c
new file mode 100644
index 0000000..6c38ab6
--- /dev/null
+++ b/src/ppu.c
@@ -0,0 +1,144 @@
1#include <string.h>
2
3#include "ppu.h"
4
5/*
6Copyright (c) 2021 Devine Lu Linvega
7Copyright (c) 2021 Andrew Alderwick
8Copyright (c) 2021 Bad Diode
9
10Permission to use, copy, modify, and distribute this software for any
11purpose with or without fee is hereby granted, provided that the above
12copyright notice and this permission notice appear in all copies.
13
14THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15WITH REGARD TO THIS SOFTWARE.
16*/
17
18static size_t screen_width = 0;
19static size_t screen_height = 0;
20
21static u32 *framebuffer = 0;
22
23static u32 palette[16];
24static u8 *pixels_buf;
25static u8 *dirty_lines;
26static u8 reqdraw = 0;
27// TODO: Probably should consider this
28// static u32 rgb_order;
29
30static u8 blending[5][16] = {
31 {0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0},
32 {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
33 {1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1},
34 {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
35 {1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}};
36
37void
38ppu_pixel(u8 layer, u16 x, u16 y, u8 color) {
39 size_t idx = y * screen_width + x;
40 u8 *pixel = &pixels_buf[idx], shift = layer * 2;
41 if(x < screen_width && y < screen_height) {
42 *pixel = (*pixel & ~(0x3 << shift)) | (color << shift);
43 }
44 dirty_lines[y] |= 1;
45}
46
47void
48ppu_1bpp(u8 layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) {
49 u16 v, h;
50 for(v = 0; v < 8; v++)
51 for(h = 0; h < 8; h++) {
52 u8 ch1 = (sprite[v] >> (7 - h)) & 0x1;
53 if(ch1 || blending[4][color])
54 ppu_pixel(layer,
55 x + (flipx ? 7 - h : h),
56 y + (flipy ? 7 - v : v),
57 blending[ch1][color]);
58 }
59}
60
61void
62ppu_2bpp(u8 layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) {
63 u16 v, h;
64 for(v = 0; v < 8; v++)
65 for(h = 0; h < 8; h++) {
66 u8 ch1 = ((sprite[v] >> (7 - h)) & 0x1);
67 u8 ch2 = ((sprite[v + 8] >> (7 - h)) & 0x1);
68 u8 ch = ch1 + ch2 * 2;
69 if(ch || blending[4][color])
70 ppu_pixel(layer,
71 x + (flipx ? 7 - h : h),
72 y + (flipy ? 7 - v : v),
73 blending[ch][color]);
74 }
75}
76
77void
78redraw_screen(void) {
79 for (size_t j = 0; j < screen_height; j++) {
80 dirty_lines[j] = 1;
81 }
82}
83
84int
85ppu_init(void) {
86 // Open frambuffer and get the size.
87 int fb = open("/dev/fb0", O_RDWR);
88 if (fb <= 0) {
89 fprintf(stderr, "couldn't open the framebuffer\n");
90 exit(EXIT_FAILURE);
91 }
92 struct fb_var_screeninfo info;
93 if (ioctl(fb, FBIOGET_VSCREENINFO, &info) != 0) {
94 fprintf(stderr, "couldn't get the framebuffer size\n");
95 exit(EXIT_FAILURE);
96 }
97
98 // Mmap the framebuffer to a buffer object.
99 screen_width = info.xres;
100 screen_height = info.yres;
101 size_t len = 4 * screen_width * screen_height;
102 framebuffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
103 if (framebuffer == MAP_FAILED) {
104 fprintf(stderr, "couldn't mmap the framebuffer\n");
105 exit(EXIT_FAILURE);
106 }
107
108 // Allocate intermediate buffers.
109 pixels_buf = malloc(screen_width * screen_height);
110 dirty_lines = malloc(screen_height);
111
112 // Initialize default palette.
113 palette[0] = 0x444444;
114 palette[1] = 0xffffff;
115 palette[2] = 0x7777ff;
116 palette[3] = 0xff7777;
117
118 // Clear pixel buffer memory.
119 memset(pixels_buf, 0, screen_width * screen_height);
120 memset(dirty_lines, 1, screen_height);
121
122 // Make sure we perform an initial screen drawing.
123 reqdraw = 1;
124 redraw_screen();
125
126 return 1;
127}
128
129void
130blit_framebuffer(void) {
131 if (reqdraw == 0) {
132 return;
133 }
134 for (size_t j = 0; j < screen_height; j++) {
135 if (dirty_lines[j] != 0) {
136 for (size_t i = 0; i < screen_width; i++) {
137 size_t idx = i + j * screen_width;
138 framebuffer[idx] = palette[pixels_buf[idx] % 16];
139 }
140 }
141 dirty_lines[j] = 0;
142 }
143 reqdraw = 0;
144}