diff options
| -rw-r--r-- | Makefile | 27 | ||||
| m--------- | lib/qoi | 0 | ||||
| -rw-r--r-- | res/continue.png | bin | 0 -> 279 bytes | |||
| -rw-r--r-- | res/music.mp3 | bin | 0 -> 197056 bytes | |||
| -rw-r--r-- | src/all.c | 38 | ||||
| -rw-r--r-- | src/img.c | 95 | ||||
| -rw-r--r-- | src/index.html.in | 13 | ||||
| -rw-r--r-- | src/types.c | 1 | 
8 files changed, 171 insertions, 3 deletions
| @@ -1,4 +1,4 @@ -build/main: src/all.c src/all.h +build/main: src/all.c src/all.h build/images.c src/types.c src/levels.c src/tick.c  	mkdir -p build  	gcc -Wall -Wextra -Wpedantic -DSDL $$(pkg-config --libs sdl3) -o build/main src/all.c @@ -7,11 +7,34 @@ build/main.wasm: src/all.c src/all.h  	clang --target=wasm32 -nostdlib -DWASM -Wall -Wextra -Wpedantic \  		-Wl,--no-entry -fno-builtin -o build/main.wasm src/all.c +build/music.mp3.b64: res/music.mp3 +	mkdir -p build +	(printf '"data:audio/mpeg;base64,'; base64 < res/music.mp3 | tr -d '\n'; printf '"') > build/music.mp3.b64 +  build/main.wasm.b64: build/main.wasm +	mkdir -p build  	(printf '"'; base64 < build/main.wasm | tr -d '\n'; printf '"') > build/main.wasm.b64 -build/index.html: src/index.html.in build/main.wasm.b64 +build/index.html: src/index.html.in build/main.wasm.b64 build/music.mp3.b64 +	mkdir -p build  	clang -E -P -undef -nostdinc -x c -o build/index.html src/index.html.in +build/img: src/img.c +	mkdir -p build +	gcc -Wall -Wextra -Wpedantic -o build/img src/img.c + +build/%.qoi: res/%.png +	mkdir -p build +	magick $< $@ + +build/images.c: build/continue.qoi build/img +	mkdir -p build +	(\ +		build/img pixels build/continue.qoi 1 && \ +		echo 'Image images[] = {{0},' && \ +		build/img image build/continue.qoi 1 && \ +		echo '};' \ +	) > build/images.c +  clean:  	rm -r build diff --git a/lib/qoi b/lib/qoi new file mode 160000 +Subproject d0cf1dfcc371f894da88a8d5fb3b08c2e8ad747 diff --git a/res/continue.png b/res/continue.pngBinary files differ new file mode 100644 index 0000000..d93dd6f --- /dev/null +++ b/res/continue.png diff --git a/res/music.mp3 b/res/music.mp3Binary files differ new file mode 100644 index 0000000..dac1000 --- /dev/null +++ b/res/music.mp3 @@ -139,6 +139,7 @@ static DrawList *render(State *state, UI *ui, Arena *a) {  		.h = cellHeight,  		.fill = {255, 0, 0, 63},  		.border = {255, 0, 0, 255}, +		.image = 1,  	};  	drawList->els[drawList->len++] = (DrawElement) { @@ -218,6 +219,16 @@ static void update(Game *game, uint64_t now, Arena a) {  #include <SDL3/SDL.h> +typedef struct { +	int width, height; +	Color colors[16]; +	const char *pixels; +} Image; + +#include "../build/images.c" + +SDL_Texture *textures[sizeof(images) / sizeof(images[0])]; +  int main(int argc, char **argv) {  	(void) argc;  	(void) argv; @@ -254,6 +265,23 @@ int main(int argc, char **argv) {  	SDL_Renderer *r = SDL_CreateRendererWithProperties(renderProps);  	SDL_DestroyProperties(renderProps);  	SDL_SetRenderDrawBlendMode(r, SDL_BLENDMODE_BLEND); + +	for (int j = 1; j < (int) (sizeof(images) / sizeof(images[0])); j++) { +		textures[j] = SDL_CreateTexture( +			r, +			SDL_PIXELFORMAT_ABGR8888, +			SDL_TEXTUREACCESS_STATIC, +			images[j].width, +			images[j].height +		); +		SDL_SetTextureScaleMode(textures[j], SDL_SCALEMODE_NEAREST); +		Arena scratch = a; +		Color *pixels = new(&scratch, images[j].width * images[j].height, Color); +		for (int i = 0; i < images[j].width * images[j].height; i++) { +			pixels[i] = images[j].colors[(int) images[j].pixels[i]]; +		} +		SDL_UpdateTexture(textures[j], NULL, pixels, images[j].width * 4); +	}  	for (;;) {  		uint64_t now = SDL_GetTicks(); @@ -289,6 +317,7 @@ int main(int argc, char **argv) {  		DrawList *drawList = render(&game->state, &game->ui, &scratch);  		SDL_SetRenderDrawColor(r, 0, 0, 0, 255);  		SDL_RenderFillRect(r, NULL); +  		for (int i = 0; i < drawList->len; i++) {  			SDL_FRect rect = {  				.x = (float) drawList->els[i].x, @@ -314,6 +343,10 @@ int main(int argc, char **argv) {  				drawList->els[i].border.a  			);  			SDL_RenderRect(r, &rect); + +			if (drawList->els[i].image != 0) { +				SDL_RenderTexture(r, textures[drawList->els[i].image], NULL, &rect); +			}  		}  		update(game, now, a); @@ -336,7 +369,10 @@ void game_init(void) {  	perm.end = heap + MEM_SIZE;  	game = new(&perm, 1, Game); -	game->state.grid[0] = 1; +	xmemcpy(&game->state.grid, &levels[0].grid, sizeof(game->state.grid)); +	game->state.goalx = levels[0].goalx; +	game->state.goaly = levels[0].goaly; +	game->state.playing = 0;  }  __attribute((export_name("game_render"))) diff --git a/src/img.c b/src/img.c new file mode 100644 index 0000000..09f000b --- /dev/null +++ b/src/img.c @@ -0,0 +1,95 @@ +#define QOI_IMPLEMENTATION +#include "../lib/qoi/qoi.h" + +#include <stdio.h> + +typedef struct { +	unsigned char r, g, b, a; +} Color; + +int pixels(char *index, char *filename) { +	qoi_desc desc; +	Color *pixels = qoi_read(filename, &desc, 4); + +	Color colors[16]; +	int colorsLen = 0; +	char *compressed = malloc(desc.width * desc.height); + +	for (int i = 0; i < (int) (desc.width * desc.height); i++) { +		char c = -1; +		for (int j = 0; j < colorsLen; j++) { +			if (*((int *) &colors[j]) == *((int *) pixels + i)) { +				c = j; +				break; +			} +		} +		if (c == -1) { +			c = colorsLen; +			if (colorsLen >= 16) { +				return 1; +			} +			colors[colorsLen++] = pixels[i]; +		} +		compressed[i] = c; +	} + +	printf("const char imagePixels%s[%d * %d] = {\n", index, desc.width, desc.height); +	for (int y = 0; y < (int) desc.height; y++) { +		for (int x = 0; x < (int) desc.width; x++) { +			printf("%d,", compressed[x + y * desc.width]); +		} +		printf("\n"); +	} +	printf("};\n"); + +	return 0; +} + +int image(char *index, char *filename) { +	qoi_desc desc; +	Color *pixels = qoi_read(filename, &desc, 4); + +	Color colors[16]; +	int colorsLen = 0; +	char *compressed = malloc(desc.width * desc.height); + +	for (int i = 0; i < (int) (desc.width * desc.height); i++) { +		char c = -1; +		for (int j = 0; j < colorsLen; j++) { +			if (*((int *) &colors[j]) == *((int *) pixels + i)) { +				c = j; +				break; +			} +		} +		if (c == -1) { +			c = colorsLen; +			if (colorsLen >= 16) { +				return 1; +			} +			colors[colorsLen++] = pixels[i]; +		} +		compressed[i] = c; +	} + +	printf("{\n.width = %d,\n.height = %d,\n.colors = {\n", desc.width, desc.height); +	for (int i = 0; i < colorsLen; i++) { +		printf("\t{%u, %u, %u, %u},\n", colors[i].r, colors[i].g, colors[i].b, colors[i].a); +	} +	printf("},\n.pixels = imagePixels%s,\n},\n", index); + +	return 0; +} + +int main(int argc, char **argv) { +	if (argc != 4) { +		return 1; +	} + +	if (!strcmp(argv[1], "pixels")) { +		return pixels(argv[3], argv[2]); +	} else if (!strcmp(argv[1], "image")) { +		return image(argv[3], argv[2]); +	} else { +		return 1; +	} +} diff --git a/src/index.html.in b/src/index.html.in index 8d0ccea..aca8b6d 100644 --- a/src/index.html.in +++ b/src/index.html.in @@ -36,6 +36,9 @@ const INPUT_PAUSE_PLAY = 3;  const WASM =  #include "../build/main.wasm.b64" +const MUSIC = +#include "../build/music.mp3.b64" +  async function main() {      let bytes   = Uint8Array.from(atob(WASM), function(c) {          return c.charCodeAt(0); @@ -48,6 +51,12 @@ async function main() {      let ctx     = canvas.getContext("2d");      let memory  = exports.memory; +	const audio = new Audio(); +	audio.src = MUSIC; +	audio.volume = 0.2; +	audio.loop = true; +	let musicPlaying = false; +  	const start = Date.now();  	function now() {  		return Date.now() - start; @@ -94,6 +103,10 @@ async function main() {  			e.preventDefault();  			exports.game_update(INPUT_RCLICK, mousex, mousey, now());  		} +		if (!musicPlaying) { +			musicPlaying = true; +			audio.play(); +		}  	});  	canvas.addEventListener("contextmenu", function (e) { diff --git a/src/types.c b/src/types.c index 8e8ba1d..bfe0d7d 100644 --- a/src/types.c +++ b/src/types.c @@ -17,6 +17,7 @@ typedef struct {  	int x, y, w, h;  	Color fill;  	Color border; +	int image;  } DrawElement;  typedef struct { | 
