rewrite progress

rahh
This commit is contained in:
Julia 2024-03-25 00:34:59 -05:00
parent 1b1cf7e940
commit 636dabd8b1
26 changed files with 1710 additions and 0 deletions

21
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.22000.0",
"compilerPath": "C:/mingw64/bin/gcc.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-gcc-x64"
}
],
"version": 4
}

55
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,55 @@
{
"files.associations": {
"pthread.h": "c",
"fumotris.h": "c",
"string.h": "c",
"input.h": "c",
"stdint.h": "c",
"iso646.h": "c",
"win.h": "c",
"array": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"string_view": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"limits": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"typeinfo": "cpp",
"execution": "cpp"
}
}

1
checksums.txt Normal file
View file

@ -0,0 +1 @@
{"source\\main.c": "3d2369e9333b52142cb9f019e877e434", "source\\io\\controller.c": "4459cc302f4b70b072f39b43e87a0c08", "source\\io\\input.c": "d3336a096a3ac2d792292d84dd20fb8f", "source\\io\\platforms\\win.c": "4eb14343a9cb40a7f6a9d9e43329c46e", "source\\io\\platforms\\winio.c": "b3a5e9d8f2e8ab4ec38d14007e4fc3f4"}

BIN
objects/controller.o Normal file

Binary file not shown.

BIN
objects/input.o Normal file

Binary file not shown.

BIN
objects/main.o Normal file

Binary file not shown.

BIN
objects/win.o Normal file

Binary file not shown.

94
run.py Normal file
View file

@ -0,0 +1,94 @@
import os, sys
import json, hashlib
def walk_source(path):
source_paths = []
subdirs = []
for dirpath, dirnames, filenames in os.walk(path):
source_paths += [os.path.join(dirpath, f) for f in filenames if f.endswith(".c")]
subdirs.append(dirpath)
return (source_paths, subdirs)
def get_checksums(source_files):
checksums = {}
for path in source_files:
with open(path, "rb") as source_file:
source = source_file.read()
checksum = hashlib.md5(source).hexdigest()
checksums[path] = checksum
return checksums
def read_checksum_file():
checksums = {}
if not os.path.exists("checksums.txt"):
return checksums
with open("checksums.txt", "rb") as checksum_file:
checksums = json.loads(checksum_file.read())
return checksums
def write_checksum_file(checksums):
with open("checksums.txt", "w+") as checksum_file:
checksum_file.write(json.dumps(checksums))
def get_object_names(path):
object_names = []
for file in os.listdir(path):
if os.path.isfile(os.path.join(path, file)):
name = os.path.splitext(os.path.basename(file))[0]
object_names.append(name)
return object_names
def build(source_path, obj_path, out_path, recompile = False):
source_paths, subdirs = walk_source(source_path)
if recompile:
result = os.system(f"gcc {' '.join(source_paths)} -I {' -I '.join(subdirs)} -o {out_path} -pthread -Wall -std=c17 -pedantic")
print(result)
return
checksums_before = read_checksum_file()
checksums_now = get_checksums(source_paths)
object_names = get_object_names(obj_path)
compile_list = []
for path in checksums_now:
name = os.path.splitext(os.path.basename(path))[0]
if path not in checksums_before or checksums_before[path] != checksums_now[path] or name not in object_names:
compile_list.append(path)
if name in object_names:
object_names.remove(name)
for object_name in object_names:
os.remove(f"{obj_path}\\{object_name}.o")
for path in compile_list:
name = os.path.splitext(os.path.basename(path))[0]
os.system(f"gcc -c {path} -I {' -I '.join(subdirs)} -o {obj_path}\\{name}.o -pthread -Wall -std=c17 -pedantic")
write_checksum_file(checksums_now)
print(os.system(f"gcc {obj_path}\\*.o -o {out_path} -pthread -Wall -std=c17 -pedantic"))
build(sys.argv[1], sys.argv[2], sys.argv[3], True)

17
source/fumotris.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <stdint.h>
#define nullptr ((void*)0)
typedef uint8_t u8;
typedef uint_fast8_t u8f;
typedef uint16_t u16;
typedef uint_fast16_t u16f;
typedef uint32_t u32;
typedef uint_fast32_t u32f;
typedef uint64_t u64;
typedef uint_fast64_t u64f;

21
source/game/gametime.c Normal file
View file

@ -0,0 +1,21 @@
#include <time.h>
#include <stdbool.h>
#ifdef _WIN32
#include "win.h"
#endif
double GetTime()
{
struct timespec ts;
timespec_get(&ts, TIME_UTC);
return ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
}
bool Wait(double seconds)
{
#ifdef _WIN32
return WindowsWait(seconds);
#endif
}

6
source/game/gametime.h Normal file
View file

@ -0,0 +1,6 @@
#pragma once
#include <stdbool.h>
double GetTime();
bool Wait(double seconds);

79
source/game/tetr.c Normal file
View file

@ -0,0 +1,79 @@
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
#include "term.h"
struct TetrMap {
size_t wid;
size_t hgt;
size_t area;
int x;
int y;
u8 rot;
u8 *blks;
};
struct TetrMap NewTetrMap(size_t wid, size_t hgt)
{
return (struct TetrMap) {
wid, hgt, wid * hgt,
0, 0, 0,
};
}
void TetrMapToTermBuf(struct TetrMap *map, struct TermBuf *term)
{
static const u8f blk_colors[8] = { 8, 14, 11, 13, 10, 9, 12, 3 };
for (size_t y = 0; y < map->hgt; y++) {
for (size_t x = 0; x < map->wid; x++) {
size_t map_i = y * map->wid + x;
size_t buf_i = (y + map->y) * term->wid + (x + map->x) * 2;
struct CharBlk4 *a = &term->blks[buf_i];
struct CharBlk4 *b = &term->blks[buf_i + 1];
if (map->blks[map_i] == 0) {
a->ch = '(';
b->ch = ')';
} else {
a->ch = '[';
b->ch = ']';
}
u8 fg = blk_colors[map->blks[map_i]];
a->fg = fg;
b->fg = fg;
}
}
}
bool TetrCollisionCheck(struct TetrMap *board, struct TetrMap *piece, int dx, int dy)
{
size_t i = 0;
for (size_t y = piece->y + dy; y < piece->y + piece->hgt + dy; y++) {
for (size_t x = piece->x + dx; x < piece->x + piece->wid + dx; x++) {
if(piece->blks[i] == 0)
goto next;
if(y >= board->hgt or x >= board->wid)
return false;
size_t board_i = y * board->wid + x;
if(board->blks[board_i] != 0)
return false;
next:
i++;
}
}
return true;
}

28
source/game/tetr.h Normal file
View file

@ -0,0 +1,28 @@
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
#include "term.h"
struct TetrMap {
size_t wid;
size_t hgt;
size_t area;
int x;
int y;
u8 rot;
u8 *blks;
};
struct TetrMap NewTetrMap(size_t wid, size_t hgt);
void TetrMapToTermBuf(struct TetrMap *map, struct TermBuf *term);
bool TetrCollisionCheck(struct TetrMap *board, struct TetrMap *piece, int dx, int dy);

265
source/io/ctrl.c Normal file
View file

@ -0,0 +1,265 @@
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
#define IO_BUF_SIZE 8
enum InputType {
KEY,
AXIS,
JOYSTICK,
WINDOW,
ESCAPE
};
struct InputRecord {
enum InputType type;
u16 id;
union {
struct {
u32 value;
bool is_down;
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
double timestamp;
};
struct InputResult {
size_t count;
struct InputRecord buf[IO_BUF_SIZE];
};
struct Axis {
union {
struct {
u32 value;
bool is_down;
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
double last_pressed;
double last_released;
};
enum KeyCode {
LEFT,
RIGHT,
SOFT_DROP,
HARD_DROP,
ROTATE_CCW,
ROTATE_CW,
ROTATE_180,
SWAP,
ESC
};
enum AxisCode {
VSCROLL,
HSCROLL
};
enum JoystickCode {
MOUSE
};
typedef u32 hashtype;
hashtype Hash(void *item, size_t size)
{
u8* data = (u8*)item;
u32 h = 98317;
for (size_t i = 0; i < size; i++) {
h ^= data[i];
h *= 0x5bd1e995;
h ^= h >> 15;
}
return h;
}
struct ident {
u16 id;
enum InputType type;
};
hashtype hash_ident(u16f id, enum InputType type)
{
struct ident obj = { id, type };
return Hash(&obj, sizeof(struct ident));
}
struct ctrl_bkt {
hashtype bind_hash;
size_t index;
hashtype code_hash;
struct Axis axis;
};
struct Ctrl {
size_t capacity;
size_t filled;
struct ctrl_bkt *bkts;
pthread_mutex_t mutex;
};
typedef struct Ctrl Ctrl;
Ctrl NewCtrl(struct ctrl_bkt *bkts_prealloc, size_t capacity)
{
Ctrl ctrl;
ctrl.capacity = capacity;
ctrl.filled = 0;
memset(bkts_prealloc, 0, sizeof(struct ctrl_bkt) * capacity);
ctrl.bkts = bkts_prealloc;
ctrl.mutex = PTHREAD_MUTEX_INITIALIZER;
return ctrl;
}
struct ctrl_bkt *get_bkt(Ctrl *ctrl, size_t i)
{
return &ctrl->bkts[i];
}
struct ctrl_bkt *find_bind(Ctrl *ctrl, hashtype bind_hash, hashtype search)
{
size_t i = bind_hash % ctrl->capacity;
struct ctrl_bkt *next;
for (size_t offset = 0; offset < ctrl->capacity; offset++) {
i = (i + 1) % ctrl->capacity;
next = get_bkt(ctrl, i);
if (next->bind_hash != search)
continue;
return next;
}
return nullptr;
}
struct ctrl_bkt *find_code(Ctrl *ctrl, size_t *i, hashtype search)
{
struct ctrl_bkt *next;
for (size_t offset = 0; offset < ctrl->capacity; offset++) {
*i = (*i + 1) % ctrl->capacity;
next = get_bkt(ctrl, *i);
if (next->code_hash != search)
continue;
return next;
}
return nullptr;
}
bool CtrlMap(Ctrl *ctrl, u16f bind, u16f code, enum InputType type)
{
if (ctrl->filled == ctrl->capacity)
return false;
hashtype bind_hash = hash_ident(bind, type);
struct ctrl_bkt *bind_bkt = find_bind(ctrl, bind_hash, 0);
bind_bkt->bind_hash = bind_hash;
hashtype code_hash = hash_ident(code, type);
size_t code_i = code_hash % ctrl->capacity;
struct ctrl_bkt *code_bkt = find_code(ctrl, &code_i, 0);
code_bkt->code_hash = code_hash;
bind_bkt->index = code_i;
ctrl->filled += 1;
return true;
}
struct Axis *find_bind_axis(Ctrl *ctrl, u16f bind, enum InputType type)
{
hashtype bind_hash = hash_ident(bind, KEY);
struct ctrl_bkt *bind_bkt = find_bind(ctrl, bind_hash, bind_hash);
if (bind_bkt == nullptr)
return nullptr;
return &get_bkt(ctrl, bind_bkt->index)->axis;
}
struct Axis *CtrlGet(Ctrl *ctrl, u16f code, enum InputType type)
{
hashtype code_hash = hash_ident(code, type);
size_t code_i = code_hash % ctrl->capacity;
struct ctrl_bkt *code_bkt = find_code(ctrl, &code_i, code_hash);
if (code_bkt == nullptr)
return nullptr;
return &code_bkt->axis;
}
bool CtrlUpdateKey(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, KEY);
if (axis == nullptr)
return false;
if (record->data.axis.is_down) {
axis->last_pressed = record->timestamp;
} else {
axis->last_released = record->timestamp;
}
axis->data.axis.is_down = record->data.axis.is_down;
return true;
}
bool CtrlUpdateAxis(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, AXIS);
if (axis == nullptr)
return false;
axis->data.axis.value = record->data.axis.value;
axis->last_pressed = record->timestamp;
return true;
}
bool CtrlUpdateJoystick(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, JOYSTICK);
if (axis == nullptr)
return false;
axis->data.joystick.x = record->data.joystick.x;
axis->data.joystick.y = record->data.joystick.y;
axis->last_pressed = record->timestamp;
return true;
}
bool CtrlUpdateWindow(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, WINDOW);
if (axis == nullptr)
return false;
axis->data.joystick.x = record->data.joystick.x;
axis->data.joystick.y = record->data.joystick.y;
axis->last_pressed = record->timestamp;
return true;
}

114
source/io/ctrl.h Normal file
View file

@ -0,0 +1,114 @@
#pragma once
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
#define IO_BUF_SIZE 8
enum InputType {
KEY,
AXIS,
JOYSTICK,
WINDOW,
ESCAPE
};
struct InputRecord {
enum InputType type;
u16 id;
union {
struct {
u32 value;
bool is_down;
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
double timestamp;
};
struct InputResult {
size_t count;
struct InputRecord buf[IO_BUF_SIZE];
};
struct Axis {
union {
struct {
u32 value;
bool is_down;
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
double last_pressed;
double last_released;
};
enum KeyCode {
LEFT,
RIGHT,
SOFT_DROP,
HARD_DROP,
ROTATE_CCW,
ROTATE_CW,
ROTATE_180,
SWAP,
ESC
};
enum AxisCode {
VSCROLL,
HSCROLL
};
enum JoystickCode {
MOUSE
};
typedef u32 hashtype;
struct ctrl_bkt {
hashtype bind_hash;
size_t index;
hashtype code_hash;
struct Axis axis;
};
struct Ctrl {
size_t capacity;
size_t filled;
struct ctrl_bkt *bkts;
pthread_mutex_t mutex;
};
typedef struct Ctrl Ctrl;
Ctrl NewCtrl(struct ctrl_bkt *bkts_prealloc, size_t capacity);
bool CtrlMap(Ctrl *ctrl, u16f bind, u16f code, enum InputType type);
struct Axis *CtrlGet(Ctrl *ctrl, u16f code, enum InputType type);
bool CtrlUpdateKey(Ctrl *ctrl, struct InputRecord *record);
bool CtrlUpdateAxis(Ctrl *ctrl, struct InputRecord *record);
bool CtrlUpdateJoystick(Ctrl *ctrl, struct InputRecord *record);
bool CtrlUpdateWindow(Ctrl *ctrl, struct InputRecord *record);

79
source/io/input.c Normal file
View file

@ -0,0 +1,79 @@
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "ctrl.h"
#include "fumotris.h"
#include "gametime.h"
#ifdef _WIN32
#include "win.h"
#endif
bool dispatch(Ctrl *ctrl, struct InputRecord *record)
{
switch (record->type) {
case KEY:
return CtrlUpdateKey(ctrl, record);
case AXIS:
return CtrlUpdateAxis(ctrl, record);
case JOYSTICK:
return CtrlUpdateJoystick(ctrl, record);
case WINDOW:
return CtrlUpdateWindow(ctrl, record);
case ESCAPE:
default:
return false;
}
}
bool write_result(Ctrl *ctrl, struct InputResult *result)
{
double now = GetTime();
pthread_mutex_lock(&ctrl->mutex);
for (size_t i = 0; i < result->count; i++) {
if (result->buf[i].type == ESCAPE)
return false;
result->buf[i].timestamp = now;
dispatch(ctrl, &result->buf[i]);
}
pthread_mutex_unlock(&ctrl->mutex);
return true;
}
void *block_input(void *args)
{
Ctrl *ctrl = args;
struct InputResult result;
input_loop:
bool success;
#ifdef _WIN32
success = WindowsBlockInput(&result);
#endif
if (!success) {
exit(1);
}
if (!write_result(ctrl, &result)) {
return nullptr;
}
goto input_loop;
return nullptr;
}
void StartInput(Ctrl *ctrl)
{
pthread_t input_thread;
pthread_create(&input_thread, nullptr, block_input, ctrl);
//pthread_join(input_thread, nullptr);
}

11
source/io/input.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include <iso646.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "ctrl.h"
#include "fumotris.h"
void StartInput(Ctrl *ctrl);

32
source/io/platforms/win.c Normal file
View file

@ -0,0 +1,32 @@
#include <iso646.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "input.h"
#include "winhandler.h"
bool WindowsInit()
{
if (!WinInitInputHandle())
return false;
if (!WinInitTimer())
return false;
if(!WinInitConsole())
return false;
return true;
}
bool WindowsBlockInput(struct InputResult *result)
{
return WinBlockInput(result);
}
bool WindowsWait(double seconds)
{
return WinWait(seconds);
}

14
source/io/platforms/win.h Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include <iso646.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "input.h"
bool WindowsInit();
bool WindowsBlockInput(struct InputResult *result);
bool WindowsWait(double seconds);

View file

@ -0,0 +1,140 @@
#include <iso646.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "fumotris.h"
#include "input.h"
struct Windows {
HANDLE input_handle;
HANDLE timer;
};
static struct Windows windows;
bool WinInitInputHandle()
{
windows.input_handle = GetStdHandle(STD_INPUT_HANDLE);
if (windows.input_handle == INVALID_HANDLE_VALUE)
return false;
return true;
}
bool WinInitTimer()
{
windows.timer = CreateWaitableTimer(NULL, TRUE, NULL);
if (!windows.timer)
return false;
return true;
}
bool WinInitConsole()
{
DWORD mode = ENABLE_EXTENDED_FLAGS
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
| ENABLE_VIRTUAL_TERMINAL_PROCESSING;
return SetConsoleMode(windows.input_handle, mode);
}
void set_key_record(struct InputRecord *record, KEY_EVENT_RECORD win_key)
{
record->type = KEY;
record->id = win_key.wVirtualKeyCode;
record->data.axis.is_down = win_key.bKeyDown;
if (win_key.wVirtualKeyCode == VK_ESCAPE)
record->type = ESCAPE;
}
bool set_mouse_record(struct InputRecord *record, MOUSE_EVENT_RECORD win_mouse)
{
switch (win_mouse.dwEventFlags) {
case MOUSE_WHEELED:
record->type = AXIS;
record->id = 0;
record->data.axis.value = win_mouse.dwButtonState;
break;
case MOUSE_HWHEELED:
record->type = AXIS;
record->id = 1;
record->data.axis.value = win_mouse.dwButtonState;
break;
case MOUSE_MOVED:
record->type = JOYSTICK;
record->id = 0;
record->data.joystick.x = win_mouse.dwMousePosition.X;
record->data.joystick.y = win_mouse.dwMousePosition.Y;
break;
default:
return false;
}
return true;
}
void set_window_record(struct InputRecord *record, WINDOW_BUFFER_SIZE_RECORD win_resize)
{
record->type = WINDOW;
record->data.joystick.x = win_resize.dwSize.X;
record->data.joystick.y = win_resize.dwSize.Y;
}
bool dispatch_record(struct InputRecord *record, INPUT_RECORD win_record)
{
switch (win_record.EventType) {
case KEY_EVENT:
set_key_record(record, win_record.Event.KeyEvent);
return true;
case MOUSE_EVENT:
return set_mouse_record(record, win_record.Event.MouseEvent);
case WINDOW_BUFFER_SIZE_EVENT:
set_window_record(record, win_record.Event.WindowBufferSizeEvent);
return true;
default:
record->type = ESCAPE;
}
return true;
}
bool WinBlockInput(struct InputResult *result)
{
INPUT_RECORD buf[8];
DWORD count;
if (!ReadConsoleInput(windows.input_handle, buf, 8, &count))
return false;
size_t unused_offset = 0;
for (size_t i = 0; i < count; i++) {
struct InputRecord record;
bool include = dispatch_record(&record, buf[i]);
if (record.type == ESCAPE)
return false;
if (!include)
unused_offset += 1;
result->buf[i - unused_offset] = record;
}
result->count = count - unused_offset;
return true;
}
bool WinWait(double seconds)
{
LARGE_INTEGER duration;
duration.QuadPart = (u64)(-10000000.0 * seconds);
if (!SetWaitableTimer(windows.timer, &duration, 0, NULL, NULL, FALSE))
return false;
DWORD result = WaitForSingleObject(windows.timer, INFINITE);
if (result != WAIT_OBJECT_0)
return false;
return true;
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <iso646.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "fumotris.h"
bool WinInitInputHandle();
bool WinInitTimer();
bool WinInitConsole();
bool WinBlockInput(struct InputResult *result);
bool WinWait(double seconds);

128
source/io/term.c Normal file
View file

@ -0,0 +1,128 @@
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
struct CharBlk4 {
char ch;
u8 bg : 4;
u8 fg : 4;
};
struct TermBuf {
size_t wid;
size_t hgt;
size_t area;
struct CharBlk4 *blks;
};
struct TermBuf NewTermBuf(size_t wid, size_t hgt)
{
return (struct TermBuf) {
wid, hgt, wid * hgt
};
}
size_t TermMaxChars(struct TermBuf *term)
{
static const size_t max_color_str_len = 10;
static const size_t reset_str_len = 7;
return reset_str_len
+ (max_color_str_len + 1) * term->area
+ (term->hgt - 1)
+ 1;
}
size_t printcol4(char *buf, size_t at, size_t max, u8f col, char ch)
{
if (col < 8)
col += 30;
else
col += 82;
return snprintf(buf + at, max - at, "\x1b[%um%c", col, ch);
}
size_t printblk4(char *buf, size_t at, size_t max, struct CharBlk4 *blk)
{
u8f bg;
if (blk->bg < 8)
bg = blk->bg + 40;
else
bg = blk->bg + 92;
u8f fg;
if (blk->fg < 8)
fg = blk->fg + 30;
else
fg = blk->fg + 82;
return snprintf(buf + at, max - at, "\x1b[%u;%um%c", bg, fg, blk->ch);
}
size_t TermBufToChars(struct TermBuf *term, char *buf, size_t max_chars)
{
u8f last_bg = 0;
u8f last_fg = 0;
size_t filled = snprintf(buf, max_chars, "\x1b[H\x1b[0m");
for(size_t y = 0; y < term->hgt; y++) {
for(size_t x = 0; x < term->wid; x++) {
size_t i = y * term->wid + x;
struct CharBlk4 *blk = &term->blks[i];
// DEBUG
if (blk->ch == 0)
blk->ch = '#';
// DEBUG
if (blk->bg != 0 and blk->bg != last_bg) {
last_bg = blk->bg;
if (blk->fg != 0 and blk->fg != last_fg) {
filled += printblk4(buf, filled, max_chars, blk);
last_fg = blk->fg;
} else {
filled += printcol4(buf, filled, max_chars, blk->bg, blk->ch);
}
} else if (blk->fg != 0 and blk->fg != last_fg) {
filled += printcol4(buf, filled, max_chars, blk->fg, blk->ch);
last_fg = blk->fg;
} else {
buf[filled] = blk->ch;
filled += 1;
}
}
buf[filled] = '\n';
filled += 1;
}
buf[filled] = 0;
return filled;
}
/*int main()
{
struct TermBuf term;
term.wid = 20;
term.hgt = 10;
term.area = 20 * 10;
struct CharBlk4 blks[term.area];
memset(&blks, 0, sizeof(struct CharBlk4) * term.area);
term.blks = blks;
size_t out_max = TermMaxChars(&term);
char out[out_max];
memset(out, 0, out_max);
TermBufToChars(&term, out, out_max);
puts(out);
return 0;
}*/

29
source/io/term.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
struct CharBlk4 {
char ch;
u8 bg : 4;
u8 fg : 4;
};
struct TermBuf {
size_t wid;
size_t hgt;
size_t area;
struct CharBlk4 *blks;
};
struct TermBuf NewTermBuf(size_t wid, size_t hgt);
size_t TermMaxChars(struct TermBuf *term);
size_t TermBufToChars(struct TermBuf *term, char *buf, size_t max_chars);

136
source/main.c Normal file
View file

@ -0,0 +1,136 @@
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "control.h"
#include "fumotris.h"
#include "term.h"
#include "tetr.h"
#ifdef _WIN32
#include "win.h"
#endif
const enum KeyCode key_codes[] = {
LEFT,
RIGHT,
SOFT_DROP,
HARD_DROP,
ROTATE_CCW,
ROTATE_CW,
ROTATE_180,
SWAP,
ESC
};
const u16f key_binds[] = {
0x25,
0x27,
0x28,
0x20,
'Z',
'X',
'A',
'C',
0x1B
};
const enum AxisCode axis_codes[] = {
VSCROLL,
HSCROLL
};
const u16f axis_binds[] = { 0, 1 };
u8 I[16] = {
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
0, 0, 0, 0
};
void Loop(Ctrl *ctrl)
{
struct TermBuf term = NewTermBuf(20, 20);
struct CharBlk4 term_blks[term.area];
memset(term_blks, 0, sizeof(struct CharBlk4) * term.area);
term.blks = term_blks;
size_t out_max = TermMaxChars(&term);
char out[out_max];
memset(out, 0, out_max);
struct TetrMap board = NewTetrMap(10, 20);
u8 board_blks[board.area];
memset(board_blks, 0, board.area);
board.blks = board_blks;
struct TetrMap falling = NewTetrMap(4, 4);
u8 falling_blks[falling.area];
memcpy(falling_blks, I, falling.area);
falling.blks = falling_blks;
for (int i = 0; i < 7779997; i++) {
TetrMapToTermBuf(&board, &term);
TetrMapToTermBuf(&falling, &term);
size_t size = TermBufToChars(&term, out, out_max);
//puts(out);
puts("\x1b[H");
//falling.y += 1;
for(int j = 0; j < ctrl->capacity; j++) {
printf("val:%u, is_down:%u, x:%u, y:%u, press:%f, relse:%f\n",
ctrl->bkts[j].axis.data.axis.value, ctrl->bkts[j].axis.data.axis.is_down,
ctrl->bkts[j].axis.data.joystick.x, ctrl->bkts[j].axis.data.joystick.y,
ctrl->bkts[j].axis.last_pressed, ctrl->bkts[j].axis.last_released);
}
/*
struct Axis *axis = CtrlGet(ctrl, LEFT, KEY);
struct Axis *right = CtrlGet(ctrl, RIGHT, KEY);
printf("ctrl:%u\n", axis);
printf("ctrl:%u\n", right);
printf("%f\n", axis->last_pressed);
if (axis->data.axis.is_down) {
printf("left");
falling.x -= 1;
}
if (right->data.axis.is_down) {
printf("right");
falling.x += 1;
}*/
WindowsWait(0.1);
}
}
int main()
{
WindowsInit();
struct ctrl_bkt bkts[16];
Ctrl ctrl = NewCtrl(bkts, 16);
for (size_t i = 0; i < 9; i++) {
CtrlMap(&ctrl, key_binds[i], key_codes[i], KEY);
}
for (size_t i = 0; i < 2; i++) {
CtrlMap(&ctrl, axis_codes[i], axis_binds[i], AXIS);
}
CtrlMap(&ctrl, 0, MOUSE, JOYSTICK);
CtrlMap(&ctrl, 0, 0, WINDOW);
printf("set controls\n");
StartInput(&ctrl);
Loop(&ctrl);
return 0;
}

422
source/test.cpp Normal file
View file

@ -0,0 +1,422 @@
#include <iostream>
#include <stdlib.h>
#include <windows.h>
using namespace std;
void gotoxy(int x, int y);
void setcolor(WORD color);
void setForeGroundAndBackGroundColor(int ForeGroundColor,int BackGroundColor);
void clearscreen();
void drawpixel( unsigned char x, unsigned char y, unsigned char Color);
void drawpixel2( unsigned char x, unsigned char y, unsigned char Color, char character);
void drawcircle(int x, int y, int a, int b, int color);
void drawline(int x0, int y0, int x1, int y1, int color);
void drawfilledrectangle(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char bkcol);
void drawframe(unsigned x,unsigned y,unsigned sx,unsigned sy,unsigned char col,unsigned char col2,char text_[]);
void drawwindow(unsigned x,unsigned y,unsigned sx,unsigned sy,unsigned char col,unsigned char col2,unsigned char bkcol,char text_[]);
int main()
{
gotoxy(1,23);
setcolor(7);
clearscreen();
cout<<"click anywhere in console window to write - hello world -\n\n\n\n\n\n\n\n\n\n\n\n\n"
"Press Ctrl+C to Exit";
HANDLE hout= GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD InputRecord;
DWORD Events;
COORD coord;
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 25;
cci.bVisible = FALSE;
SetConsoleCursorInfo(hout, &cci);
SetConsoleMode(hin, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
bool EXITGAME = false;
int buttonX=1, buttonY=1;
drawpixel(buttonX,buttonY ,1);
gotoxy(buttonX+2,buttonY);
setcolor(3);
cout<<"<----- a button \n";
while( !EXITGAME )
{
ReadConsoleInput(hin, &InputRecord, 1, &Events);
switch ( InputRecord.EventType ){
case KEY_EVENT: // keyboard input
switch (InputRecord.Event.KeyEvent.wVirtualKeyCode)
{
case VK_ESCAPE:
EXITGAME = TRUE;
break;
case VK_SPACE:
break;
case VK_RETURN:
break;
case VK_LEFT:
// left key move player left
cout<<"VK_LEFT = "<<InputRecord.Event.KeyEvent.wVirtualKeyCode <<" \n";
break;
case VK_RIGHT:
// right key move player right
cout<<"VK_RIGHT = "<<InputRecord.Event.KeyEvent.wVirtualKeyCode <<" \n";
break;
case VK_UP:
// up key move player up
cout<<"VK_UP = "<<InputRecord.Event.KeyEvent.wVirtualKeyCode <<" \n";
break;
case VK_DOWN:
// up key move player down
cout<<"VK_DOWN = "<<InputRecord.Event.KeyEvent.wVirtualKeyCode <<" \n";
break;
}//switch
//---------------------------------------------------------------------------------
break;
case MOUSE_EVENT: // mouse input
if(InputRecord.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
coord.X = InputRecord.Event.MouseEvent.dwMousePosition.X;
coord.Y = InputRecord.Event.MouseEvent.dwMousePosition.Y;
SetConsoleCursorPosition(hout,coord);
SetConsoleTextAttribute(hout,rand() %7+9);
if ( (InputRecord.Event.MouseEvent.dwMousePosition.X == buttonX ) &&
( InputRecord.Event.MouseEvent.dwMousePosition.Y == buttonY) ){
clearscreen();
gotoxy(1,1);
setcolor(7);
drawpixel(buttonX,buttonY ,1);
setcolor(3);
cout<<" mybutton was pressed \n";
setcolor(7);
Sleep(500);
drawpixel(buttonX,buttonY ,1);
gotoxy(buttonX+2,buttonY);
setcolor(3);
cout<<"<----- a button \n";
}
cout<<"Hello world at "<< InputRecord.Event.MouseEvent.dwMousePosition.X <<" x "<< InputRecord.Event.MouseEvent.dwMousePosition.Y<<" ";
}// mouse
break;
case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing
;
break;
case FOCUS_EVENT: // disregard focus events
case MENU_EVENT: // disregard menu events
break;
default:
cout<<"Unknown event type \n";
break;
}
FlushConsoleInputBuffer(hin);
}
gotoxy(1,23);
setcolor(7);
clearscreen();
cout<<"\n";
return 0;
}
void gotoxy(int x, int y){
COORD coord;
coord.X = x; coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
return;
}
//*****************************************************************************
void setcolor(WORD color){
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
return;
}
//*****************************************************************************
//
// colors:
// 0 = Black
// 1 = Blue
// 2 = Green
// 3 = Cyan
// 4 = Red
// 5 = Magenta
// 6 = Yellow
// 7 = LightGray
// 8 = DarkGray
// 9 = LightBlue
// 10 = LightGreen
// 11 = LightCyan
// 12 = LightRed
// 13 = LightMagenta
// 14 = LightYellow
// 15 = White
//
//*****************************************************************************
void setForeGroundAndBackGroundColor(int ForeGroundColor,int BackGroundColor){
int color=16*BackGroundColor+ForeGroundColor;
setcolor(color);
}
//*****************************************************************************
void clearscreen(){
COORD coordScreen = { 0, 0 };
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwConSize;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole, &csbi);
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
GetConsoleScreenBufferInfo(hConsole, &csbi);
FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
SetConsoleCursorPosition(hConsole, coordScreen);
return;
}
//*****************************************************************************
void drawpixel( unsigned char x, unsigned char y, unsigned char Color){
setcolor(Color);
gotoxy(x,y);printf("Û");
}
//*****************************************************************************
void drawpixel2( unsigned char x, unsigned char y, unsigned char Color, char character){
setcolor(Color);
gotoxy(x,y);printf("%c",character);
}
//*****************************************************************************
void drawcircle(int x, int y, int a, int b, int color){
int wx, wy;
int thresh;
int asq = a * a;
int bsq = b * b;
int xa, ya;
drawpixel(x, y+b, color);
drawpixel(x, y-b, color);
wx = 0;
wy = b;
xa = 0;
ya = asq * 2 * b;
thresh = asq / 4 - asq * b;
for (;;) {
thresh += xa + bsq;
if (thresh >= 0) {
ya -= asq * 2;
thresh -= ya;
wy--;
}
xa += bsq * 2;
wx++;
if (xa >= ya)
break;
drawpixel(x+wx, y-wy, color);
drawpixel(x-wx, y-wy, color);
drawpixel(x+wx, y+wy, color);
drawpixel(x-wx, y+wy, color);
}
drawpixel(x+a, y, color);
drawpixel(x-a, y, color);
wx = a;
wy = 0;
xa = bsq * 2 * a;
ya = 0;
thresh = bsq / 4 - bsq * a;
for (;;) {
thresh += ya + asq;
if (thresh >= 0) {
xa -= bsq * 2;
thresh = thresh - xa;
wx--;
}
ya += asq * 2;
wy++;
if (ya > xa)
break;
drawpixel(x+wx, y-wy, color);
drawpixel(x-wx, y-wy, color);
drawpixel(x+wx, y+wy, color);
drawpixel(x-wx, y+wy, color);
}
}
//*****************************************************************************
void drawline(int x0, int y0, int x1, int y1, int color){
int pix = color;
int dy = y1 - y0;
int dx = x1 - x0;
int stepx, stepy;
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
dy <<= 1; // dy is now 2*dy
dx <<= 1; // dx is now 2*dx
drawpixel( x0, y0,pix);
if (dx > dy) {
int fraction = dy - (dx >> 1); // same as 2*dy - dx
while (x0 != x1) {
if (fraction >= 0) {
y0 += stepy;
fraction -= dx; // same as fraction -= 2*dx
}
x0 += stepx;
fraction += dy; // same as fraction -= 2*dy
drawpixel( x0, y0,pix);
}
} else {
int fraction = dx - (dy >> 1);
while (y0 != y1) {
if (fraction >= 0) {
x0 += stepx;
fraction -= dy;
}
y0 += stepy;
fraction += dx;
drawpixel( x0, y0,pix);
}
}
}
//*****************************************************************************
void drawframe(unsigned x,unsigned y,unsigned sx,unsigned sy,unsigned char col,unsigned char col2,char text_[]){
unsigned i,j,m;{
m=(sx-x); //differential
j=m/8; //adjust
j=j-1; //more adjustment
gotoxy(x,y);printf("É"); //Top left corner of drawframe
gotoxy(sx,y);printf("»"); //Top right corner of drawframe
gotoxy(x,sy);printf("È"); //Bottom left corner of drawframe
gotoxy(sx,sy);printf("¼"); //Bottom right corner of drawframe
for (i=x+1;i<sx;i++){
gotoxy(i,y);printf("Í"); // Top horizontol line
gotoxy(i,sy);printf("Í"); // Bottom Horizontal line
}
for (i=y+1;i<sy;i++){
gotoxy(x,i);printf("º"); //Left Vertical line
gotoxy(sx,i);printf("º"); //Right Vertical Line
}
gotoxy(x+j,y);printf(text_); //put Title
gotoxy(1,24);
}
}
//*****************************************************************************
void drawfilledrectangle(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char bkcol){
int x,y;
setcolor(bkcol); //Set to color bkcol
for (y=y1;y<y2;y++){ //Fill Y Region Loop
for (x=x1;x<x2;x++) { //Fill X region Loop
gotoxy(x,y);printf(" "); //Draw Solid space
}
}
}
//*****************************************************************************
void drawwindow(unsigned x,unsigned y,unsigned sx,unsigned sy,
unsigned char col, unsigned char col2,unsigned char bkcol,char text_[]){
drawfilledrectangle(x,y,sx,sy,bkcol);
drawframe(x,y,sx,sy,col,col2,text_);
}
//*****************************************************************************
void drawcolorpalette(){
for (int i=0;i<16;i++){
for (int j=0;j<16;j++){
setForeGroundAndBackGroundColor(i,j);
gotoxy(i*4,j);printf("%d",(i*j)+1);
}
}
}
//*****************************************************************************

BIN
test.exe Normal file

Binary file not shown.