things!
This commit is contained in:
@@ -1,2 +1,7 @@
|
||||
#ifndef PLR_DISPLAY_H
|
||||
#define PLR_DISPLAY_H
|
||||
|
||||
extern int plr_display_x11_main(int argc, char *argv[]);
|
||||
extern int plr_display_dos_main(int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
#include "display.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
#define MODE_VGA_320_200_8 0x13
|
||||
#define MODE_VESA_640_480_8 0x101
|
||||
|
||||
// 8-color VGA palette gradient, lighter shades of lavender to pink
|
||||
#define COLOR_OFFSET 0x50
|
||||
#define COLOR_NUM 8
|
||||
#define COLOR_STEP (HEIGHT / COLOR_NUM)
|
||||
|
||||
/* https://wiki.osdev.org/VESA_Video_Modes */
|
||||
_Packed struct VbeInfoBlock {
|
||||
char VbeSignature[4]; // == "VESA"
|
||||
uint16_t VbeVersion; // == 0x0300 for VBE 3.0
|
||||
uint16_t OemStringPtr[2]; // isa vbeFarPtr
|
||||
uint8_t Capabilities[4];
|
||||
uint16_t VideoModePtr[2]; // isa vbeFarPtr
|
||||
uint16_t TotalMemory; // as # of 64KB blocks
|
||||
uint8_t Reserved[492];
|
||||
};
|
||||
|
||||
_Packed struct ModeInfoBlock {
|
||||
uint16_t
|
||||
attributes; // deprecated, only bit 7 should be of interest to you, and it
|
||||
// indicates the mode supports a linear frame buffer.
|
||||
uint8_t window_a; // deprecated
|
||||
uint8_t window_b; // deprecated
|
||||
uint16_t granularity; // deprecated; used while calculating bank numbers
|
||||
uint16_t window_size;
|
||||
uint16_t segment_a;
|
||||
uint16_t segment_b;
|
||||
uint32_t win_func_ptr; // deprecated; used to switch banks from protected mode
|
||||
// without returning to real mode
|
||||
uint16_t pitch; // number of bytes per horizontal line
|
||||
uint16_t width; // width in pixels
|
||||
uint16_t height; // height in pixels
|
||||
uint8_t w_char; // unused...
|
||||
uint8_t y_char; // ...
|
||||
uint8_t planes;
|
||||
uint8_t bpp; // bits per pixel in this mode
|
||||
uint8_t banks; // deprecated; total number of banks in this mode
|
||||
uint8_t memory_model;
|
||||
uint8_t bank_size; // deprecated; size of a bank, almost always 64 KB but may
|
||||
// be 16 KB...
|
||||
uint8_t image_pages;
|
||||
uint8_t reserved0;
|
||||
|
||||
uint8_t red_mask;
|
||||
uint8_t red_position;
|
||||
uint8_t green_mask;
|
||||
uint8_t green_position;
|
||||
uint8_t blue_mask;
|
||||
uint8_t blue_position;
|
||||
uint8_t reserved_mask;
|
||||
uint8_t reserved_position;
|
||||
uint8_t direct_color_attributes;
|
||||
|
||||
uint32_t framebuffer; // physical address of the linear frame buffer; write
|
||||
// here to draw to the screen
|
||||
uint32_t off_screen_mem_off;
|
||||
uint16_t off_screen_mem_size; // size of memory in the framebuffer but not
|
||||
// being displayed on the screen
|
||||
uint8_t reserved1[206];
|
||||
};
|
||||
|
||||
static char get_video_mode();
|
||||
#pragma aux get_video_mode = "mov ah, 0x0f" \
|
||||
"int 0x10" value[al] modify[ah];
|
||||
|
||||
static void set_video_mode(unsigned char);
|
||||
#pragma aux set_video_mode = "mov ah, 0x00" \
|
||||
"int 0x10" parm[al] modify[ah];
|
||||
|
||||
static void set_vesa_video_mode(unsigned short);
|
||||
#pragma aux set_vesa_video_mode = "mov ax, 0x4f02" \
|
||||
"int 0x10" parm[bx] modify[ah];
|
||||
|
||||
static void wait_for_key();
|
||||
#pragma aux wait_for_key = "mov ah, 0x00" \
|
||||
"int 0x16" modify[ah];
|
||||
|
||||
static short get_vesa_controller_info(struct VbeInfoBlock *);
|
||||
#pragma aux get_vesa_controller_info = "mov ax, 0x4f00" \
|
||||
"int 0x10" parm[es di] value[ax];
|
||||
|
||||
static short get_vesa_mode_info(uint16_t mode, struct ModeInfoBlock *);
|
||||
#pragma aux get_vesa_mode_info = "mov ax, 0x4F01" \
|
||||
"int 0x10" parm[cx][es di] value[ax];
|
||||
|
||||
/* https://wiki.osdev.org/User:Omarrx024/VESA_Tutorial*/
|
||||
static char *find_display_memory(void) {
|
||||
struct VbeInfoBlock *ctrl = (struct VbeInfoBlock *)0x2000;
|
||||
struct ModeInfoBlock *inf = (struct ModeInfoBlock *)0x3000;
|
||||
uint16_t *modes;
|
||||
int i;
|
||||
|
||||
strncpy(ctrl->VbeSignature, "VBE2", 4);
|
||||
if (get_vesa_controller_info(ctrl) != 0x004F)
|
||||
return NULL;
|
||||
|
||||
modes = (uint16_t *)(ctrl->VideoModePtr);
|
||||
for (i = 0; modes[i] != 0xFFFF; ++i) {
|
||||
if (get_vesa_mode_info(modes[i], inf) != 0x004F)
|
||||
continue;
|
||||
|
||||
// Check if this is a graphics mode with linear frame buffer support
|
||||
if ((inf->attributes & 0x80) != 0x80)
|
||||
continue;
|
||||
|
||||
// Check if this is a packed pixel or direct color mode
|
||||
if (inf->memory_model != 4 && inf->memory_model != 6)
|
||||
continue;
|
||||
|
||||
// Check if this is exactly the mode we're looking for
|
||||
if (WIDTH == inf->width && HEIGHT == inf->height && 256 == inf->pitch)
|
||||
return (char *)inf->framebuffer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern int plr_display_dos_main(int argc, char *argv[]) {
|
||||
char far *buf = (char far *)0xA0000; // VGA memory address
|
||||
int x, y;
|
||||
|
||||
unsigned char saved_mode = get_video_mode(); // Save original mode
|
||||
set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode
|
||||
|
||||
buf = find_display_memory();
|
||||
|
||||
/* TODO: Fetch info about the mode, to know the availability */
|
||||
/* as well as base address in memory */
|
||||
/* https://wiki.osdev.org/VESA_Video_Modes */
|
||||
|
||||
// Now draw. We draw pixel-by-pixel by directly setting the video memory like
|
||||
// it was an array. We step the color every 25 pixels so that we have 8 bands
|
||||
// of even height.
|
||||
for (y = 0; y < HEIGHT; y++) {
|
||||
for (x = 0; x < WIDTH; x++) {
|
||||
buf[y * WIDTH + x] = COLOR_OFFSET + y / COLOR_STEP;
|
||||
}
|
||||
}
|
||||
|
||||
wait_for_key();
|
||||
set_video_mode(saved_mode); // Restore original mode
|
||||
|
||||
return 0;
|
||||
}
|
||||
+127
-103
@@ -1,120 +1,144 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../Common/lzw.h"
|
||||
#include "../../Common/mat.h"
|
||||
#include "display.h"
|
||||
|
||||
bool quited = false;
|
||||
|
||||
#define WIDTH 640
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
|
||||
// TODO: correct error handling.
|
||||
extern int plr_display_x11_main(int argc, char *argv[])
|
||||
{
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
if (NULL == display) {
|
||||
fprintf(stderr, "Failed to initialize display");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
extern int plr_display_x11_main(int argc, char *argv[]) {
|
||||
char test_string[] = "what is this?";
|
||||
char *compressed_string = NULL;
|
||||
uint32_t compressed_string_sz = 0;
|
||||
struct com_lzw_table table =
|
||||
com_lzw_infer_table(test_string, sizeof(test_string));
|
||||
bool test = com_lzw_compress(&table, test_string, sizeof(test_string),
|
||||
&compressed_string, &compressed_string_sz);
|
||||
com_lzw_free_table(&table);
|
||||
assert(test);
|
||||
|
||||
Window root = DefaultRootWindow(display);
|
||||
if (None == root) {
|
||||
fprintf(stderr, "No root window found");
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
com_mat_t m0 = com_mat_identity();
|
||||
com_mat_t m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
for (int i = 0; i < 16; ++i)
|
||||
m1.a[i] *= COM_FIXED_FRACUNIT;
|
||||
|
||||
int screen = DefaultScreen(display);
|
||||
Visual *visual = DefaultVisual(display, screen);
|
||||
int depth = DefaultDepth(display, screen);
|
||||
com_mat_t t0 = com_mat_mul(m1, m0);
|
||||
com_mat_t t1 = com_mat_mul_reodered(com_mat_reoder(m1), m0);
|
||||
com_fixed_print(t0.a[4]);
|
||||
com_fixed_print(t1.a[4]);
|
||||
|
||||
Window window = XCreateSimpleWindow(display, root, 0, 0, WIDTH, HEIGHT, 0, 0, 0xffffffff);
|
||||
if (None == window) {
|
||||
fprintf(stderr, "Failed to create window");
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
XSizeHints *hints = XAllocSizeHints();
|
||||
if (hints == NULL) return EXIT_FAILURE;
|
||||
|
||||
// Pinning min and max to the same values disables resizing
|
||||
hints->flags = PMinSize | PMaxSize;
|
||||
hints->min_width = hints->max_width = WIDTH;
|
||||
hints->min_height = hints->max_height = HEIGHT;
|
||||
|
||||
XSetWMNormalHints(display, window, hints);
|
||||
XFree(hints);
|
||||
|
||||
XSelectInput(display, window, ExposureMask | KeyPressMask);
|
||||
XMapWindow(display, window);
|
||||
|
||||
GC gc = XCreateGC(display, window, 0, NULL);
|
||||
|
||||
Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(display, window, & wm_delete_window, 1);
|
||||
|
||||
// TODO: can't be not true
|
||||
int bytes_per_pixel = 4;
|
||||
char *pixel_buffer = (char *)malloc(WIDTH * HEIGHT * bytes_per_pixel);
|
||||
|
||||
XImage *ximage = XCreateImage(
|
||||
display, visual, depth, ZPixmap, 0,
|
||||
pixel_buffer, WIDTH, HEIGHT, 32, 0
|
||||
);
|
||||
|
||||
if (!ximage) {
|
||||
fprintf(stderr, "Failed to create XImage\n");
|
||||
free(pixel_buffer);
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int frame = 0;
|
||||
|
||||
XEvent event;
|
||||
while (!quited) {
|
||||
XNextEvent(display, &event);
|
||||
|
||||
switch(event.type) {
|
||||
case ClientMessage:
|
||||
if(event.xclient.data.l[0] == wm_delete_window) {
|
||||
XDestroyWindow(display, window);
|
||||
quited = true;
|
||||
}
|
||||
break;
|
||||
case Expose:
|
||||
frame += 2;
|
||||
// Fill buffer with a simple color gradient
|
||||
for (int y = 0; y < HEIGHT; y++) {
|
||||
for (int x = 0; x < WIDTH; x++) {
|
||||
int pixel_index = (y * WIDTH + x) * bytes_per_pixel;
|
||||
|
||||
// Assuming standard Little-Endian 32-bit BGRA format
|
||||
pixel_buffer[pixel_index + 0] = (x + frame) % 256; // Blue
|
||||
pixel_buffer[pixel_index + 1] = (y + frame) % 256; // Green
|
||||
pixel_buffer[pixel_index + 2] = (x + y - frame) % 256; // Red
|
||||
pixel_buffer[pixel_index + 3] = 0; // Alpha/Padding
|
||||
}
|
||||
}
|
||||
// Draw the complete image onto the window when exposed
|
||||
XPutImage(
|
||||
display,
|
||||
window, // Target drawable
|
||||
gc, // Graphics Context
|
||||
ximage, // Source XImage
|
||||
0, 0, // Source coordinates (x, y)
|
||||
0, 0, // Destination coordinates (x, y)
|
||||
WIDTH, HEIGHT// Dimensions to copy
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
if (NULL == display) {
|
||||
fprintf(stderr, "Failed to initialize display");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Window root = DefaultRootWindow(display);
|
||||
if (None == root) {
|
||||
fprintf(stderr, "No root window found");
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
int screen = DefaultScreen(display);
|
||||
Visual *visual = DefaultVisual(display, screen);
|
||||
int depth = DefaultDepth(display, screen);
|
||||
|
||||
Window window =
|
||||
XCreateSimpleWindow(display, root, 0, 0, WIDTH, HEIGHT, 0, 0, 0xffffffff);
|
||||
if (None == window) {
|
||||
fprintf(stderr, "Failed to create window");
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
XSizeHints *hints = XAllocSizeHints();
|
||||
if (hints == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Pinning min and max to the same values disables resizing
|
||||
hints->flags = PMinSize | PMaxSize;
|
||||
hints->min_width = hints->max_width = WIDTH;
|
||||
hints->min_height = hints->max_height = HEIGHT;
|
||||
|
||||
XSetWMNormalHints(display, window, hints);
|
||||
XFree(hints);
|
||||
|
||||
XSelectInput(display, window, ExposureMask | KeyPressMask);
|
||||
XMapWindow(display, window);
|
||||
|
||||
GC gc = XCreateGC(display, window, 0, NULL);
|
||||
|
||||
Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(display, window, &wm_delete_window, 1);
|
||||
|
||||
// TODO: can't be not true
|
||||
int bytes_per_pixel = 4;
|
||||
char *pixel_buffer = (char *)malloc(WIDTH * HEIGHT * bytes_per_pixel);
|
||||
|
||||
XImage *ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
|
||||
pixel_buffer, WIDTH, HEIGHT, 32, 0);
|
||||
|
||||
if (!ximage) {
|
||||
fprintf(stderr, "Failed to create XImage\n");
|
||||
free(pixel_buffer);
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int frame = 0;
|
||||
|
||||
XEvent event;
|
||||
while (!quited) {
|
||||
XNextEvent(display, &event);
|
||||
|
||||
switch (event.type) {
|
||||
case ClientMessage:
|
||||
if (event.xclient.data.l[0] == wm_delete_window) {
|
||||
XDestroyWindow(display, window);
|
||||
quited = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Expose:
|
||||
frame += 2;
|
||||
// Fill buffer with a simple color gradient
|
||||
for (int y = 0; y < HEIGHT; y++) {
|
||||
for (int x = 0; x < WIDTH; x++) {
|
||||
int pixel_index = (y * WIDTH + x) * bytes_per_pixel;
|
||||
|
||||
// Assuming standard Little-Endian 32-bit BGRA format
|
||||
pixel_buffer[pixel_index + 0] = (x + frame) % 256; // Blue
|
||||
pixel_buffer[pixel_index + 1] = (y + frame) % 256; // Green
|
||||
pixel_buffer[pixel_index + 2] = (x + y - frame) % 256; // Red
|
||||
pixel_buffer[pixel_index + 3] = 0; // Alpha/Padding
|
||||
}
|
||||
}
|
||||
// Draw the complete image onto the window when exposed
|
||||
XPutImage(display,
|
||||
window, // Target drawable
|
||||
gc, // Graphics Context
|
||||
ximage, // Source XImage
|
||||
0, 0, // Source coordinates (x, y)
|
||||
0, 0, // Destination coordinates (x, y)
|
||||
WIDTH, HEIGHT // Dimensions to copy
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(display);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+13
-5
@@ -1,10 +1,18 @@
|
||||
CC=clang
|
||||
CFLAGS=-lX11
|
||||
DEPS =
|
||||
OBJ = main.o Display/x11.o
|
||||
CFLAGS=-lX11 -Wall -std=c99 -g3 -O3 -fno-inline -msse2
|
||||
DEPS = Display/display.h ../Common/lzw.h ../Common/mat.h ../Common/vec.h ../Common/fixed.h ../Common/def.h ../Common/bits.h
|
||||
OBJ = ../Common/lzw.o ../Common/fixed.o
|
||||
LINUX = main.o Display/x11.o
|
||||
DOS = maindos.c Display/dos.c
|
||||
|
||||
%.o: %.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
player: $(OBJ)
|
||||
$(CC) -o $@ $^ $(CFLAGS)
|
||||
linux: $(LINUX) $(OBJ)
|
||||
$(CC) -o player $^ $(CFLAGS)
|
||||
|
||||
dos: $(DOS) $(DEPS)
|
||||
wcl386 -bt=dos4g -ox -l=dos4g $(DOS)
|
||||
|
||||
clean:
|
||||
rm -r *.o ../*.o
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Inter-process communicating socket, useful for local testing and admin
|
||||
playing.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define MAXBUFFSIZE 4194304 /* 4.0MiB */
|
||||
|
||||
int plr_socket_unix_try_connect(const char *filepath) {
|
||||
int sock = 0;
|
||||
|
||||
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
perror("Error creating client UNIX socket: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un remote = {0};
|
||||
remote.sun_family = AF_UNIX;
|
||||
strcpy(remote.sun_path, filepath);
|
||||
int const remote_len = SUN_LEN(&remote);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+36
-10
@@ -1,13 +1,39 @@
|
||||
Pustina -- Player
|
||||
BYOND-inspired optimized web-driven content player.
|
||||
All logic is processed on the server, whereas player only does display changes and sends unreliable inputs.
|
||||
This allows for no-update and hidden content strategies, allowing for mystic and truly seamlessly progressing world.
|
||||
Locked step multiplayer oriented engine with great restrictions.
|
||||
We do not use abstractions, as the simplicity of the required set of features should allow for platform-specific implementations.
|
||||
|
||||
Restrictions:
|
||||
-- Fixed sized frambuffer, default is 640x480, but platforms can implement their own. Scaling by 2 is possible.
|
||||
-- GIF image format for all drawing purposes. Delta Frame Optimiztion is encouraged.
|
||||
-- Images are 32x32 or multiples of it, aligning to the grid.
|
||||
-- 20 FPS display rate.
|
||||
-- Fonts are in ASCII bitmaps.
|
||||
-- Audio samples are in vorbis format. Music pieces are written in our own simple tracker format, using the same vorbis samples.
|
||||
|
||||
---- Restrictions ----
|
||||
* Fixed sized paletted frambuffer, defaulted to 640x480. Scaling by 2 is possible.
|
||||
* Deterministic logic via Q15.16 fixed point numbers.
|
||||
* .gam image format, derived from .gif. RLE and Delta Frame Optimiztion is added, palette is predefined.
|
||||
* Images are 16x16 or multiples of it, aligning to the grid.
|
||||
* Tile view is capped at 29x29, the rest is allocated to interface.
|
||||
* 30 FPS display rate.
|
||||
* Fonts are in ASCII bitmaps. Tile slicing commands are issued to render them in.
|
||||
* Audio samples are in our own .sam format (s8 frame delta + lzw).
|
||||
* Music pieces are written in our own simple .tam tracker format, using the same .sam sample db.
|
||||
* Connections are over TCP and their supersets (like WebSocket).
|
||||
* Textbox provides another client-controlled view, with history.
|
||||
* Content usage has to be predefined, to allow preloading and compilation.
|
||||
|
||||
|
||||
---- Building ----
|
||||
==== DOS ====
|
||||
Open Watcom 2.0 32bit toolchain is used under Linux host.
|
||||
Place a copy of DOS4GW.EXE alongside the executable.
|
||||
Expect to need to configure $INCLUDE and $LIB variables.
|
||||
|
||||
|
||||
---- .sam format ----
|
||||
Thin sample compressing scheme tailored for use with .tam tracker.
|
||||
Leading and tailing silence is stored as number of frames.
|
||||
Sample data is 1 channel only, but panning can be expressed via graph.
|
||||
Sample bit format is signed 8 bit delta, first frame is delta against 0. Clamping is allowed.
|
||||
Generic LZW compression is applied as the last step.
|
||||
|
||||
|
||||
---- .dab format ---
|
||||
Compressed streamed content database format.
|
||||
It allows for seeked access of required portions only via the content table.
|
||||
Content table stores pathing, content and compression metadata as well as sized offset inside the file.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#include "Display/display.h"
|
||||
|
||||
extern int main(int argc, char *argv[]) {
|
||||
return plr_display_x11_main(argc, argv);
|
||||
return plr_display_x11_main(argc, argv);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "Display/display.h"
|
||||
|
||||
extern int main(int argc, char *argv[]) {
|
||||
return plr_display_dos_main(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user