rewrite it in rust #1

Merged
SonicSwordcane merged 20 commits from riir into main 2024-11-10 23:34:55 +00:00
18 changed files with 11 additions and 532 deletions
Showing only changes of commit 62b34ea760 - Show all commits

2
Cargo.lock generated
View File

@ -1953,7 +1953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "shrooms-vb-native"
name = "shrooms-vb"
version = "0.1.0"
dependencies = [
"anyhow",

View File

@ -1,5 +1,5 @@
[package]
name = "shrooms-vb-native"
name = "shrooms-vb"
version = "0.1.0"
edition = "2021"
@ -24,3 +24,6 @@ winit = "0.30"
[build-dependencies]
cc = "1"
[profile.release]
lto = true

View File

@ -1,15 +1,15 @@
# Shrooms VB (native)
An SDL-based implementation of shrooms-vb.
A native implementation of shrooms-vb. Written in Rust, using winit, wgpu, and Dear ImGui. Should run on any major OS.
## Setup
Install the following dependencies:
- `gcc` (or MinGW on Windows) (or whatever, just set `CC`)
- `pkg-config`
- sdl2
- `cargo`
Run
```sh
make build
```
cargo build --release
```
The executable will be in `target/release/shrooms-vb[.exe]`

View File

@ -1,12 +0,0 @@
#ifndef SHROOMS_VB_NATIVE_ASSETS_
#define SHROOMS_VB_NATIVE_ASSETS_
#include <stdint.h>
extern const uint8_t _binary_assets_lefteye_bin_start;
const uint8_t *LEFT_EYE_DEFAULT = &_binary_assets_lefteye_bin_start;
extern const uint8_t _binary_assets_righteye_bin_start;
const uint8_t *RIGHT_EYE_DEFAULT = &_binary_assets_righteye_bin_start;
#endif

Binary file not shown.

Binary file not shown.

65
audio.c
View File

@ -1,65 +0,0 @@
#include <audio.h>
#include <stdio.h>
void audioCallback(void *userdata, uint8_t *stream, int len) {
AudioContext *aud;
SDL_assert(len == 834 * 4);
aud = userdata;
if (!aud->filled) {
/* too little data, play silence */
SDL_memset4(stream, 0, 834);
return;
}
SDL_memcpy4(stream, aud->buffers[aud->current], 834);
++aud->current;
aud->current %= 2;
aud->filled -= 1;
}
int audioInit(AudioContext *aud) {
SDL_AudioSpec spec;
spec.freq = 41700;
spec.format = AUDIO_S16;
spec.channels = 2;
spec.samples = 834;
spec.callback = &audioCallback;
spec.userdata = aud;
aud->id = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0);
aud->paused = true;
if (!aud->id) {
fprintf(stderr, "could not open audio device: %s\n", SDL_GetError());
return -1;
}
aud->current = 0;
aud->filled = 0;
return 0;
}
int audioUpdate(AudioContext *aud, void *data, uint32_t bytes) {
int filled;
if (!aud->id) return -1;
SDL_assert(bytes == 834 * 4);
SDL_LockAudioDevice(aud->id);
if (aud->filled < 2) {
int next = (aud->current + aud->filled) % 2;
SDL_memcpy4(aud->buffers[next], data, bytes / 4);
aud->filled += 1;
}
filled = aud->filled;
SDL_UnlockAudioDevice(aud->id);
if (aud->paused) {
SDL_PauseAudioDevice(aud->id, false);
aud->paused = false;
}
while (filled > 1) {
SDL_Delay(0);
filled = aud->filled;
}
return 0;
}

18
audio.h
View File

@ -1,18 +0,0 @@
#ifndef SHROOMS_VB_NATIVE_AUDIO_
#define SHROOMS_VB_NATIVE_AUDIO_
#include <SDL2/SDL.h>
#include <stdbool.h>
typedef struct {
SDL_AudioDeviceID id;
bool paused;
uint32_t buffers[2][834];
int current;
int filled;
} AudioContext;
int audioInit(AudioContext *aud);
int audioUpdate(AudioContext *aud, void *data, uint32_t bytes);
#endif

11
cli.c
View File

@ -1,11 +0,0 @@
#include <cli.h>
#include <stdio.h>
int parseCLIArgs(int argc, char **argv, CLIArgs *args) {
if (argc != 2) {
fprintf(stderr, "usage: %s /path/to/rom.vb\n", argv[0]);
return 1;
}
args->filename = argv[1];
return 0;
}

10
cli.h
View File

@ -1,10 +0,0 @@
#ifndef SHROOMS_VB_NATIVE_CLI_
#define SHROOMS_VB_NATIVE_CLI_
typedef struct {
char *filename;
} CLIArgs;
int parseCLIArgs(int argc, char **argv, CLIArgs *args);
#endif

View File

@ -1,65 +0,0 @@
#include <controller.h>
#define VB_PWR 0x0001
#define VB_SGN 0x0002
#define VB_A 0x0004
#define VB_B 0x0008
#define VB_RT 0x0010
#define VB_LT 0x0020
#define VB_RU 0x0040
#define VB_RR 0x0080
#define VB_LR 0x0100
#define VB_LL 0x0200
#define VB_LD 0x0400
#define VB_LU 0x0800
#define VB_STA 0x1000
#define VB_SEL 0x2000
#define VB_RL 0x4000
#define VB_RD 0x8000
static uint16_t symToMask(SDL_KeyCode sym) {
switch (sym) {
default: return 0;
case SDLK_a:
return VB_SEL;
case SDLK_s:
return VB_STA;
case SDLK_d:
return VB_B;
case SDLK_f:
return VB_A;
case SDLK_e:
return VB_LT;
case SDLK_r:
return VB_RT;
case SDLK_i:
return VB_RU;
case SDLK_j:
return VB_RL;
case SDLK_k:
return VB_RD;
case SDLK_l:
return VB_RR;
case SDLK_UP:
return VB_LU;
case SDLK_LEFT:
return VB_LL;
case SDLK_DOWN:
return VB_LD;
case SDLK_RIGHT:
return VB_LR;
}
}
void ctrlInit(ControllerState *ctrl) {
ctrl->keys = VB_SGN;
}
void ctrlKeyDown(ControllerState *ctrl, SDL_Keycode sym) {
ctrl->keys |= symToMask(sym);
}
void ctrlKeyUp(ControllerState *ctrl, SDL_Keycode sym) {
ctrl->keys &= ~symToMask(sym);
}
uint16_t ctrlKeys(ControllerState *ctrl) {
return ctrl->keys;
}

View File

@ -1,16 +0,0 @@
#ifndef SHROOMS_VB_NATIVE_CONTROLLER_
#define SHROOMS_VB_NATIVE_CONTROLLER_
#include <SDL2/SDL.h>
#include <stdint.h>
typedef struct {
uint16_t keys;
} ControllerState;
void ctrlInit(ControllerState *ctrl);
void ctrlKeyDown(ControllerState *ctrl, SDL_Keycode sym);
void ctrlKeyUp(ControllerState *ctrl, SDL_Keycode sym);
uint16_t ctrlKeys(ControllerState *ctrl);
#endif

71
game.c
View File

@ -1,71 +0,0 @@
#include <audio.h>
#include <assets.h>
#include <controller.h>
#include <game.h>
#include <SDL2/SDL.h>
#include <stdbool.h>
#include <time.h>
typedef struct {
GraphicsContext *gfx;
AudioContext aud;
int16_t audioBuffer[834 * 2];
} GameState;
int onFrame(VB *sim) {
static uint8_t leftEye[384*224];
static uint8_t rightEye[384*224];
GameState *state;
void *samples;
uint32_t samplePairs;
state = vbGetUserData(sim);
vbGetPixels(sim, leftEye, 1, 384, rightEye, 1, 384);
gfxUpdateLeftEye(state->gfx, leftEye);
gfxUpdateRightEye(state->gfx, rightEye);
samples = vbGetSamples(sim, NULL, NULL, &samplePairs);
audioUpdate(&state->aud, samples, samplePairs * 4);
vbSetSamples(sim, samples, VB_S16, 834);
gfxRender(state->gfx);
return 1;
}
#define MAX_STEP_CLOCKS 20000000
int runGame(VB *sim, GraphicsContext *gfx) {
uint32_t clocks;
SDL_Event event;
GameState state;
ControllerState ctrl;
state.gfx = gfx;
audioInit(&state.aud);
vbSetSamples(sim, &state.audioBuffer, VB_S16, 834);
vbSetUserData(sim, &state);
vbSetFrameCallback(sim, &onFrame);
ctrlInit(&ctrl);
gfxUpdateLeftEye(gfx, LEFT_EYE_DEFAULT);
gfxUpdateRightEye(gfx, RIGHT_EYE_DEFAULT);
while (1) {
clocks = MAX_STEP_CLOCKS;
vbEmulate(sim, &clocks);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
return 0;
}
if (event.type == SDL_KEYDOWN) {
ctrlKeyDown(&ctrl, event.key.keysym.sym);
}
if (event.type == SDL_KEYUP) {
ctrlKeyUp(&ctrl, event.key.keysym.sym);
}
}
vbSetKeys(sim, ctrlKeys(&ctrl));
}
}

9
game.h
View File

@ -1,9 +0,0 @@
#ifndef SHROOMS_VB_NATIVE_GAME_
#define SHROOMS_VB_NATIVE_GAME_
#include "graphics.h"
#include "shrooms-vb-core/core/vb.h"
int runGame(VB *sim, GraphicsContext *gfx);
#endif

View File

@ -1,92 +0,0 @@
#include <graphics.h>
static void copyScreenTexture(uint8_t *dst, const uint8_t *src, int pitch) {
int x, y, i;
uint8_t color;
int delta = pitch / 384;
for (y = 0; y < 224; ++y) {
for (x = 0; x < 384; x += 1) {
color = src[(y * 384) + x];
for (i = 0; i < delta; ++i) {
dst[(y * pitch) + (x * delta) + i] = color;
}
}
}
}
int gfxInit(GraphicsContext *gfx) {
gfx->window = SDL_CreateWindow("Shrooms VB",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
1536, 896, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
if (!gfx->window) {
fprintf(stderr, "Error creating window: %s\n", SDL_GetError());
return 1;
}
gfx->renderer = SDL_CreateRenderer(gfx->window, -1, 0);
if (!gfx->renderer) {
fprintf(stderr, "Error creating renderer: %s\n", SDL_GetError());
goto cleanup_window;
}
gfx->winSurface = SDL_GetWindowSurface(gfx->window);
if (!gfx->winSurface) {
fprintf(stderr, "Error getting surface: %s\n", SDL_GetError());
goto cleanup_window;
}
gfx->leftEye = SDL_CreateTexture(gfx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224);
if (!gfx->leftEye) {
fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError());
goto cleanup_window;
}
SDL_SetTextureColorMod(gfx->leftEye, 0xff, 0, 0);
gfx->rightEye = SDL_CreateTexture(gfx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224);
if (!gfx->rightEye) {
fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError());
goto cleanup_left_eye;
}
SDL_SetTextureColorMod(gfx->rightEye, 0, 0xc6, 0xf0);
SDL_SetTextureBlendMode(gfx->rightEye, SDL_BLENDMODE_ADD);
return 0;
cleanup_left_eye:
SDL_DestroyTexture(gfx->leftEye);
cleanup_window:
SDL_DestroyWindow(gfx->window);
return 1;
}
void gfxDestroy(GraphicsContext *gfx) {
SDL_DestroyTexture(gfx->rightEye);
SDL_DestroyTexture(gfx->leftEye);
SDL_DestroyWindow(gfx->window);
}
static void gfxUpdateEye(SDL_Texture *eye, const uint8_t *bytes) {
void *target;
int pitch;
if (SDL_LockTexture(eye, NULL, &target, &pitch)) {
fprintf(stderr, "Error locking buffer for eye: %s\n", SDL_GetError());
return;
}
copyScreenTexture(target, bytes, pitch);
SDL_UnlockTexture(eye);
}
void gfxUpdateLeftEye(GraphicsContext *gfx, const uint8_t *bytes) {
gfxUpdateEye(gfx->leftEye, bytes);
}
void gfxUpdateRightEye(GraphicsContext *gfx, const uint8_t *bytes) {
gfxUpdateEye(gfx->rightEye, bytes);
}
void gfxRender(GraphicsContext *gfx) {
SDL_RenderClear(gfx->renderer);
SDL_RenderCopy(gfx->renderer, gfx->leftEye, NULL, NULL);
SDL_RenderCopy(gfx->renderer, gfx->rightEye, NULL, NULL);
SDL_RenderPresent(gfx->renderer);
}

View File

@ -1,22 +0,0 @@
#ifndef SHROOMS_VB_NATIVE_GRAPHICS_
#define SHROOMS_VB_NATIVE_GRAPHICS_
#include <SDL2/SDL.h>
typedef struct {
SDL_Window *window;
SDL_Surface *winSurface;
SDL_Renderer *renderer;
SDL_Texture *leftEye;
SDL_Texture *rightEye;
} GraphicsContext;
int gfxInit(GraphicsContext *gfx);
void gfxDestroy(GraphicsContext *gfx);
void gfxUpdateLeftEye(GraphicsContext *gfx, const uint8_t *bytes);
void gfxUpdateRightEye(GraphicsContext *gfx, const uint8_t *bytes);
void gfxRender(GraphicsContext *gfx);
#endif

85
main.c
View File

@ -1,85 +0,0 @@
#include <cli.h>
#include <game.h>
#include <graphics.h>
#include <SDL2/SDL.h>
#include "shrooms-vb-core/core/vb.h"
#include <stdio.h>
uint8_t *readROM(char *filename, uint32_t *size) {
FILE *file = fopen(filename, "rb");
uint8_t *rom;
long filesize;
if (!file) {
perror("could not open file");
return NULL;
}
if (fseek(file, 0, SEEK_END)) {
perror("could not seek file end");
return NULL;
}
filesize = ftell(file);
if (filesize == -1) {
perror("could not read file size");
return NULL;
}
if (fseek(file, 0, SEEK_SET)) {
perror("could not seek file start");
return NULL;
}
*size = (uint32_t) filesize;
rom = malloc(*size);
if (!rom) {
perror("could not allocate ROM");
return NULL;
}
fread(rom, 1, *size, file);
if (ferror(file)) {
perror("could not read file");
return NULL;
}
if (fclose(file)) {
perror("could not close file");
return NULL;
}
return rom;
}
int main(int argc, char **argv) {
VB *sim;
uint8_t *rom;
uint32_t romSize;
GraphicsContext gfx;
CLIArgs args;
int status;
if (parseCLIArgs(argc, argv, &args)) {
return 1;
}
rom = readROM(args.filename, &romSize);
if (!rom) {
return 1;
}
sim = malloc(vbSizeOf());
vbInit(sim);
vbSetCartROM(sim, rom, romSize);
if (SDL_Init(SDL_INIT_EVERYTHING)) {
fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError());
return 1;
}
if (gfxInit(&gfx)) {
SDL_Quit();
return 1;
}
status = runGame(sim, &gfx);
SDL_Quit();
return status;
}

View File

@ -1,48 +0,0 @@
CC?=gcc
LD?=ld
SHROOMSFLAGS=shrooms-vb-core/core/vb.c -I shrooms-vb-core/core
msys_version := $(if $(findstring Msys, $(shell uname -o)),$(word 1, $(subst ., ,$(shell uname -r))),0)
ifeq ($(msys_version), 0)
SDL2FLAGS=$(shell pkg-config sdl2 --cflags --libs)
BINLINKFLAGS=-z noexecstack
else
SDL2FLAGS=$(shell pkg-config sdl2 --cflags --libs) -mwindows -mconsole
BINLINKFLAGS=
endif
.PHONY: clean build
clean:
@rm -rf shrooms-vb output
CFILES := $(foreach dir,./,$(notdir $(wildcard $(dir)/*.c)))
BINFILES := $(foreach dir,assets/,$(notdir $(wildcard $(dir)/*.bin)))
COBJS := $(CFILES:%.c=output/%.o)
SHROOMSOBJS := output/vb.o
BINOBJS := $(BINFILES:%.bin=output/%.o)
OFILES := $(COBJS) $(SHROOMSOBJS) $(BINOBJS)
output/%.o: %.c
@mkdir -p output
@$(CC) -c -o $@ $< -I . \
-I shrooms-vb-core/core $(SDL2FLAGS) \
-O3 -flto -fno-strict-aliasing \
-Werror -std=c90 -Wall -Wextra -Wpedantic
output/vb.o: shrooms-vb-core/core/vb.c
@mkdir -p output
@$(CC) -c -o $@ $< -I . \
-I shrooms-vb-core/core $(SDL2FLAGS) \
-O3 -flto -fno-strict-aliasing \
-Werror -std=c90 -Wall -Wextra -Wpedantic
output/%.o: assets/%.bin
@mkdir -p output
@$(LD) -r -b binary $(BINLINKFLAGS) -o $@ $<
shrooms-vb: $(OFILES)
@$(CC) -o $@ $(OFILES) $(SDL2FLAGS) -flto
build: shrooms-vb