-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtut1.c
More file actions
113 lines (93 loc) · 3.63 KB
/
Copy pathtut1.c
File metadata and controls
113 lines (93 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <stdbool.h>
// Playdate Target Spec
#define GAME_WIDTH 400
#define GAME_HEIGHT 240
int main() {
int fb_fd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
char *fbp = 0;
// 1. Open the raw Linux framebuffer file
fb_fd = open("/dev/fb0", O_RDWR);
if (fb_fd == -1) {
perror("Error: cannot open framebuffer device /dev/fb0");
return 1;
}
// 2. Read screen configuration metadata
if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
close(fb_fd);
return 2;
}
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
close(fb_fd);
return 3;
}
// Extract native uConsole display resolutions
int screen_width = vinfo.xres;
int screen_height = vinfo.yres;
int bpp = vinfo.bits_per_pixel;
// Calculate total buffer mapping allocation requirements
screensize = finfo.line_length * screen_height;
// 3. Map physical video memory directly to a CPU array pointer
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if ((intptr_t)fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
close(fb_fd);
return 4;
}
// 4. Create our internal virtual 1-bit playdate screen array (0=Black, 1=White)
uint8_t game_pixels[GAME_WIDTH * GAME_HEIGHT];
memset(game_pixels, 0, sizeof(game_pixels));
int frame_count = 0;
bool running = true;
printf("uConsole R01 Framebuffer Engine Live at %dx%d (%dbpp).\n", screen_width, screen_height, bpp);
printf("Press Ctrl+C to terminate application.\n");
// 5. Ultimate High-Speed Software Loop
while (running) {
frame_count++;
// Clear local virtual playdate canvas buffer array to 0 (Black)
memset(game_pixels, 0, sizeof(game_pixels));
// RENDER OBJECT: Animate a simple bouncing playdate block
int box_size = 40;
int box_x = (frame_count % (GAME_WIDTH - box_size));
int box_y = 100;
for (int y = box_y; y < box_y + box_size; y++) {
for (int x = box_x; x < box_x + box_size; x++) {
game_pixels[y * GAME_WIDTH + x] = 1;
}
}
// 6. Fast Integer Scaling Pipeline to the Native Screen Frame
// Stretch 400x240 grid linearly into the hardware memory dimensions
for (int y = 0; y < screen_height; y++) {
// Map line index down into 240 pixels coordinate space
int game_y = (y * GAME_HEIGHT) / screen_height;
uint8_t *src_row = &game_pixels[game_y * GAME_WIDTH];
// Target memory pointer block matching current row index
uint32_t *dest_row = (uint32_t *)(fbp + (y * finfo.line_length));
for (int x = 0; x < screen_width; x++) {
// Map screen coordinate space down into 400 pixels grid width
int game_x = (x * GAME_WIDTH) / screen_width;
// Pick Color Mode: Retrosynthesis Cream (#FFFFE0) or Jet Black (#000000)
dest_row[x] = src_row[game_x] ? 0xFFFFE0 : 0x000000;
}
}
// Cap framerate pace explicitly to maintain hardware sync comfort
usleep(16666); // Locked solid target 60FPS
}
// Cleanup memory footprints cleanly
munmap(fbp, screensize);
close(fb_fd);
return 0;
}