-
-
Notifications
You must be signed in to change notification settings - Fork 488
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved D template #1891
Improved D template #1891
Changes from all commits
e016e4e
290c028
d59733f
cd85552
acc3534
942abfc
1e4707e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
DUB_FLAGS = --quiet --build release --compiler ldc2 --arch wasm32-unknown-unknown-wasm | ||
ifneq ($(origin WASI_SDK_PATH), undefined) | ||
override DUB_FLAGS += --config wasi | ||
endif | ||
|
||
build: | ||
dub build ${DUB_FLAGS} | ||
|
||
clean: | ||
rm -rf cart.wasm .dub |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,69 @@ | ||
# D Starter Project Template | ||
|
||
This is a D TIC-80 starter template. To build the D source files: | ||
## Pre-requisites | ||
|
||
- [LDC](https://wiki.dlang.org/LDC) | ||
- [WASI libc](https://github.com/WebAssembly/wasi-libc) | ||
|
||
### WASI libc | ||
|
||
WASI libc's [README](https://github.com/WebAssembly/wasi-libc#usage) states | ||
that "the easiest way to get started with this is to use wask-sdk, which | ||
includes a build of WASI libc in its sysroot." | ||
|
||
Just [building WASI libc from source](https://github.com/WebAssembly/wasi-libc#building-from-source) | ||
works too, for the purpose of programming TIC-80 games in D. Let's say you | ||
install into ```$HOME/wasi-sdk/share/wasi-sysroot```, which then look like this: | ||
|
||
``` | ||
% ./build.sh | ||
% ls -l | ||
total 12 | ||
drwxr-xr-x 10 pierce pierce 4096 Apr 24 16:19 include/ | ||
drwxr-xr-x 3 pierce pierce 4096 Apr 24 16:19 lib/ | ||
drwxr-xr-x 3 pierce pierce 4096 Apr 24 16:19 share/ | ||
``` | ||
|
||
To import the resulting WASM file into a cartridge: | ||
## Files in this template | ||
|
||
- ```buildcart.sh``` - convenience script to build and run the game cartridge | ||
- ```buildwasm.sh``` - convenience script to build and run the Wasm program | ||
- ```dub.json``` - D's dub package description file | ||
- ```Makefile``` - convenience Makefile that invokes ```dub``` | ||
- ```wasmdemo.wasmp``` - TIC-80 Wasm 'script' file. Note the embedded game assets data at the end of the file. | ||
|
||
## Building your game | ||
|
||
Define the environment variable WASI_SDK_PATH; e.g., if you installed WASI | ||
libc into ```$HOME/wasi-sdk/share/wasi-sysroot```, then ```export WASI_SDK_PATH=$HOME/wasi-sdk```. | ||
|
||
Edit ```src/main.d``` to implement your game. You are of course free to | ||
organize your code in more than one D source file. | ||
|
||
If you create sprites, map, music, etc., for your game, remember to | ||
replace the game asset data at the end of ```wasmdemo.wasmp``` with | ||
your creations. | ||
|
||
To build the Wasm file, execute ```make```. This generates ```cart.wasm``` | ||
in the current directory. To run: | ||
|
||
``` | ||
% tic80 --fs . | ||
tic80 prompt> load wasmdemo.wasmp | ||
tic80 prompt> import binary cart.wasm | ||
tic80 prompt> save game.tic | ||
tic80 prompt> exit | ||
% tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary cart.wasm & run & exit' | ||
``` | ||
|
||
Or, on the command line: | ||
The script ```buildwasm.sh``` contains above steps as a convenience. | ||
|
||
To build a TIC-80 cartridge, first build the Wasm file, then build the | ||
cartridge file: | ||
|
||
``` | ||
% tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary cart.wasm & save game.tic & exit' | ||
``` | ||
|
||
Now, run ```game.tic```: | ||
You can then run your cartridge as follows: | ||
|
||
``` | ||
% tic80 --fs . --cmd 'load game.tic & run & exit' | ||
``` | ||
|
||
The script ```buildcart.sh``` does the above steps as a convenience. | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/bin/sh | ||
rm -f game.tic | ||
make clean | ||
make | ||
tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary cart.wasm & save game.tic & exit' | ||
tic80 --fs . --cmd 'load game.tic & run & exit' | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/sh | ||
make clean | ||
make | ||
tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary cart.wasm & run & exit' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just me, but nothing about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fine calling it |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "cart", | ||
"targetType": "executable", | ||
"configurations": [ | ||
{ | ||
"name": "raw", | ||
"dflags": [ | ||
"-betterC" | ||
], | ||
"lflags": [ | ||
"--strip-all", | ||
"--allow-undefined", | ||
"--stack-first", | ||
"--no-entry" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We also need to pull over:
But with TIC-80 specific values, which I think would mean 256kb memory and 96kb "reserved"... which I THINK means stack-size should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me run some tests with the numbers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the numbers for TIC-80 would be, for 8k actual stack:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did we ever get this changed? |
||
] | ||
}, | ||
{ | ||
"name": "wasi", | ||
"dflags": [ | ||
"-betterC", | ||
"-Xcc", | ||
"$WASI_SDK_PATH/share/wasi-sysroot" | ||
], | ||
"lflags": [ | ||
"--strip-all", | ||
"--allow-undefined", | ||
"--stack-first", | ||
"--no-entry", | ||
"$WASI_SDK_PATH/share/wasi-sysroot/lib/wasm32-wasi/libc.a" | ||
] | ||
} | ||
], | ||
"toolchainRequirements": { | ||
"dmd": "no", | ||
"gdc": "no", | ||
"ldc": ">=1.11.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,55 @@ extern(C): | |
|
||
struct MouseData { | ||
short x; short y; | ||
short scrollx; short scrolly; | ||
byte scrollx; byte scrolly; | ||
bool left; bool middle; bool right; | ||
} | ||
|
||
const int WIDTH = 240; | ||
const int HEIGHT = 136; | ||
|
||
// These are pointers. | ||
const FRAMEBUFFER_PTR = cast(ubyte*)0; | ||
const TILES_PTR = cast(ubyte*)0x4000; | ||
const SPRITES_PTR = cast(ubyte*)0x6000; | ||
const MAP_PTR = cast(ubyte*)0x8000; | ||
const GAMEPADS_PTR = cast(ubyte*)0xFF80; | ||
const MOUSE_PTR = cast(ubyte*)0xFF84; | ||
const KEYBOARD_PTR = cast(ubyte*)0xFF88; | ||
const SFX_STATE_PTR = cast(ubyte*)0xFF8C; | ||
const SOUND_REGISTERS_PTR = cast(ubyte*)0xFF9C; | ||
const WAVEFORMS_PTR = cast(ubyte*)0xFFE4; | ||
const SFX_PTR = cast(ubyte*)0x100E4; | ||
const MUSIC_PATTERNS_PTR = cast(ubyte*)0x11164; | ||
const MUSIC_TRACKS_PTR = cast(ubyte*)0x13E64; | ||
const SOUND_STATE_PTR = cast(ubyte*)0x13FFC; | ||
const STEREO_VOLUME_PTR = cast(ubyte*)0x14000; | ||
const PERSISTENT_MEMORY_PTR = cast(ubyte*)0x14004; | ||
const SPRITE_FLAGS_PTR = cast(ubyte*)0x14404; | ||
const SYSTEM_FONT_PTR = cast(ubyte*)0x14604; | ||
const WASM_FREE_RAM_PTR = cast(ubyte*)0x18000; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you really think we should provide this out of the box? Does D not allocate globals and such things starting here automatically? (like C) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose you are referring to WASM_FREE_RAM_PTR? Since TIC-80 allows peeking and poking anywhere, I put this in as well. But yes, generally the game programmer will leave to D to manage memory. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know. I'm just not sure we want to encourage this. Someone who knows what they are doing can add that line to their own source easily enough without us including it in the core examples. And if they do not know what they are doing they probably shouldn't be using Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's leave it out then. |
||
|
||
// These are bounded arrays. | ||
ubyte[] FRAMEBUFFER() { return (cast(ubyte*)0)[0..16319]; } // VRAM bank 0 screen area | ||
ubyte[] TILES() { return (cast(ubyte*)0x4000)[0..8191]; } | ||
ubyte[] SPRITES() { return (cast(ubyte*)0x4000)[0..8191]; } | ||
ubyte[] MAP() { return (cast(ubyte*)0x8000)[0..32639]; } | ||
ubyte[] GAMEPADS() { return (cast(ubyte*)0xFF80)[0..3]; } | ||
ubyte[] MOUSE() { return (cast(ubyte*)0xFF84)[0..3]; } | ||
ubyte[] KEYBOARD() { return (cast(ubyte*)0xFF88)[0..3]; } | ||
ubyte[] SFX_STATE() { return (cast(ubyte*)0xFF8C)[0..15]; } | ||
ubyte[] SOUND_REGISTERS() { return (cast(ubyte*)0xFF9C)[0..71]; } | ||
ubyte[] WAVEFORMS() { return (cast(ubyte*)0xFFE4)[0..255]; } | ||
ubyte[] SFX() { return (cast(ubyte*)0x100E4)[0..4223]; } | ||
ubyte[] MUSIC_PATTERNS() { return (cast(ubyte*)0x11164)[0..11519]; } | ||
ubyte[] MUSIC_TRACKS() { return (cast(ubyte*)0x13E64)[0..407]; } | ||
ubyte[] SOUND_STATE() { return (cast(ubyte*)0x13FFC)[0..3]; } | ||
ubyte[] STEREO_VOLUME() { return (cast(ubyte*)0x14000)[0..3]; } | ||
ubyte[] PERSISTENT_MEMORY() { return (cast(ubyte*)0x14004)[0..1023]; } | ||
ubyte[] SPRITE_FLAGS() { return (cast(ubyte*)0x14404)[0..511]; } | ||
ubyte[] SYSTEM_FONT() { return (cast(ubyte*)0x14604)[0..2047]; } | ||
ubyte[] WASM_FREE_RAM() { return (cast(ubyte*)0x18000)[0..163839]; } // 160kb | ||
|
||
int btn(int id); | ||
bool btnp(int id, int hold, int period); | ||
void circ(int x, int y, int radius, int color); | ||
|
@@ -25,7 +67,7 @@ int font(char* text, int x, int y, ubyte transcolors, int colorcount, int width, | |
bool fset(int id, ubyte flag, bool value); | ||
bool key(int keycode); | ||
bool keyp(int keycode, int hold, int period); | ||
void line(int x0, int y0, int x1, int y1, int color); | ||
void line(float x0, float y0, float x1, float y1, byte color); | ||
void map(int x, int y, int w, int h, int sx, int sy, ubyte transcolors, int colorcount, int scale, int remap); | ||
void memcpy(uint copyto, uint copyfrom, uint length); | ||
void memset(uint addr, ubyte value, uint length); | ||
|
@@ -34,27 +76,27 @@ void mouse(MouseData* data); | |
void mset(int x, int y, bool value); | ||
void music(int track, int frame, int row, bool loop, bool sustain, int tempo, int speed); | ||
ubyte peek(int addr, int bits); | ||
int print(const char* txt, int x, int y, int color, int fixed, int scale, int alt); | ||
ubyte peek4(uint addr4); | ||
ubyte peek2(uint addr2); | ||
ubyte peek1(uint bitaddr); | ||
void pix(int x, int y, int color); | ||
uint pmem(uint index, uint value); | ||
void poke(uint addr, ubyte value, int bits); | ||
void poke4(uint addr4, ubyte value); | ||
void poke2(uint addr2, ubyte value); | ||
void poke1(uint bitaddr, ubyte value); | ||
void poke(int addr, byte value, byte bits); | ||
void poke4(int addr4, byte value); | ||
void poke2(int addr2, byte value); | ||
void poke1(int bitaddr, byte value); | ||
int print(const char* txt, int x, int y, int color, int fixed, int scale, int alt); | ||
void rect(int x, int y, int w, int h, int color); | ||
void rectb(int x, int y, int w, int h, int color); | ||
void reset(); | ||
void sfx(int id, int note, int octave, int duration, int channel, int volumeLeft, int volumeRight, int speed); | ||
void spr(int id, int x, int y, uint* transcolors, uint colorcount, int scale, int flip, int rotate, int w, int h); | ||
void sync(int mask, int bank, bool tocart); | ||
void trace(const char* txt, int color); | ||
void textri(float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, int texsrc, ubyte transcolors, int colorcount, float z1, float z2, float z3, bool persp); | ||
void ttri(float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, int texsrc, ubyte transcolors, int colorcount, float z1, float z2, float z3, bool persp); | ||
void tri(float x1, float y1, float x2, float y2, float x3, float y3, int color); | ||
void trib(float x1, float y1, float x2, float y2, float x3, float y3, int color); | ||
int time(); | ||
float time(); | ||
int tstamp(); | ||
int vbank(int bank); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to invoke tic80 twice vs doing it all in a single session?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intention is to demonstrate the two separate actions -- creating a .tic file from necessary artifacts, and running the .tic directly without reference to said artifacts -- for the programmer who is new to this console.