Files
userspace/core/bin/video.c
T
2020-03-27 22:51:32 +02:00

234 lines
5.0 KiB
C

#include <ygg/video.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <termios.h>
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
static int running = 1;
static double mx_d = 40, my_d = 12;
static uint8_t cursor[8] = {
0b11111111,
0b11111110,
0b11111100,
0b11111000,
0b11110000,
0b11100000,
0b11000000,
0b10000000,
};
static uint32_t *vmem;
static size_t vsize;
static void signal_handler(int signum) {
running = 0;
}
static void ms_handle(char *buf, size_t len) {
for (size_t i = 0; i < len / 5; ++i) {
char type = buf[i * 5 + 0];
switch (type) {
case 'd': {
int16_t dx = *(int16_t *) &buf[i * 5 + 1];
int16_t dy = *(int16_t *) &buf[i * 5 + 3];
mx_d += (double) dx / 4.0;
my_d -= (double) dy / 6.0;
if (mx_d < 0) {
mx_d = 0;
}
if (mx_d >= mode.width - 1) {
mx_d = mode.width - 2;
}
if (my_d < 0) {
my_d = 0;
}
if (my_d >= mode.height - 1) {
my_d = mode.height - 2;
}
}
break;
}
}
}
static void rect(int x0, int y0, int x1, int y1, uint32_t col) {
for (int x = MAX(x0, 0); x <= MIN(x1, mode.width - 1); ++x) {
for (int y = MAX(y0, 0); y <= MIN(y1, mode.height - 1); ++y) {
vmem[y * mode.width + x] = col;
}
}
}
static void draw_cursor(int x, int y, uint32_t col) {
for (int i = 0; i < 8; ++i) {
if (i + x >= mode.width) {
break;
}
for (int j = 0; j < 8; ++j) {
if (j + y >= mode.height) {
break;
}
if (!(cursor[j] & (1 << (7 - i)))) {
continue;
}
vmem[(j + y) * mode.width + x + i] = col;
}
}
}
static void render(void) {
static double px, py;
rect(px, py, px + 8, py + 8, 0);
px = mx_d;
py = my_d;
draw_cursor(px, py, 0xFF0000);
}
int main(int argc, char **argv) {
int fd = open("/dev/fb0", O_RDONLY, 0);
int mouse_fd = open("/dev/ps2aux", O_RDONLY, 0);
struct termios tc, tc_old;
struct timeval tv;
fd_set fds;
char buf[512];
ssize_t len;
int no = 0;
tc.c_iflag = 0;
tc.c_lflag = 0;
tc.c_oflag = 0;
if (tcgetattr(STDIN_FILENO, &tc_old) != 0) {
perror("tcgetattr()");
goto end;
}
if (fd < 0 || mouse_fd < 0) {
perror("open()");
return -1;
}
if (ioctl(fd, IOC_GETVMODE, &mode) != 0) {
perror("ioctl()");
goto end;
}
if (tcsetattr(STDIN_FILENO, TCSANOW, &tc) != 0) {
perror("tcsetattr()");
goto end;
}
signal(SIGINT, signal_handler);
printf("Video mode: %dx%d\n", mode.width, mode.height);
vsize = mode.width * mode.height * 4;
vsize = (vsize + 0xFFF) & ~0xFFF;
printf("%u bytes\n", vsize);
printf("You can exit by pressing ^C\n");
printf("Starting video in 1 sec\n");
usleep(1000000);
if (!running) {
// Interrupt happened
close(mouse_fd);
close(fd);
if (tcsetattr(STDIN_FILENO, TCSANOW, &tc_old) != 0) {
perror("tcsetattr()");
goto end;
}
puts2("\033[2J\033[1;1f");
printf("Goodbye\n");
return 0;
}
if (ioctl(fd, IOC_FBCON, &no) != 0) {
perror("ioctl()");
goto end;
}
vmem = mmap(NULL, vsize, 0, MAP_PRIVATE, fd, 0);
assert(vmem);
memset(vmem, 0, vsize);
while (running) {
tv.tv_sec = 0;
tv.tv_usec = 10000;
FD_ZERO(&fds);
FD_SET(mouse_fd, &fds);
FD_SET(STDIN_FILENO, &fds);
int res = select(mouse_fd + 1, &fds, NULL, NULL, &tv);
if (res < 0) {
no = 1;
if (ioctl(fd, IOC_FBCON, &no) != 0) {
perror("ioctl()");
goto end;
}
printf("select() failed\n");
break;
}
if (res > 0) {
if (FD_ISSET(mouse_fd, &fds)) {
len = read(mouse_fd, buf, sizeof(buf));
ms_handle(buf, len);
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
read(STDIN_FILENO, buf, sizeof(buf));
if (buf[0] == 'q') {
break;
}
}
}
render();
}
munmap(vmem, vsize);
no = 1;
if (ioctl(fd, IOC_FBCON, &no) != 0) {
perror("ioctl()");
goto end;
}
if (tcsetattr(STDIN_FILENO, TCSANOW, &tc_old) != 0) {
perror("tcsetattr()");
goto end;
}
puts2("\033[2J\033[1;1f");
printf("Goodbye\n");
end:
close(fd);
return 0;
}