Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafaquraish committed May 20, 2024
0 parents commit 61685d4
Show file tree
Hide file tree
Showing 9 changed files with 408 additions and 0 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Build Workflow
name: build

# Run on Push
on: [push]


jobs:
build:
# Run this on a default linux machine
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master

- uses: mymindstorm/setup-emsdk@v11

- name: Checkout ocen repo
uses: actions/checkout@v3
with:
repository: ocen-lang/ocen
path: ocen

- name: Build ocen
run: |
cd ocen
./meta/bootstrap.sh
echo "OCEN_ROOT=${{ github.workspace }}/ocen" >> $GITHUB_ENV
echo "${{ github.workspace }}/ocen/bootstrap" >> $GITHUB_PATH
- name: Build Wasm
run: |
cd ${{ github.workspace }}
./meta/build_wasm.sh
./meta/multi_build_wasm.sh
- name: Deploy 🚀
uses: JamesIves/[email protected]
with:
branch: gh-pages # The branch the action should deploy to.
folder: build
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.dSYM
*out
*.c
build
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Ocen WASM Template

This is a template using the `std::og` library in [ocen](https://github.com/ocen-lang/ocen)
to draw some graphics to the screen. `std::og` is a set of wrappers around `SDL` to make it
a friendlier API for fast-protoyping (loosely inspired by `p5.js` / `raylib`).

This repository demonstrates how to compile such an application to WebAssembly using `emscripten`,
and has a sample github workflow to automatically build and deploy the application to github pages.

## Customization

- The `assets` folder is automatically bundled into the generated `wasm` (can be changed in `build_wasm.sh`).
Any files you want to be available to the application should be placed in this folder.

- `assets/index.html` is the default HTML template for the application. It only works with the default emscriptem
build, and assumes the files generated are `index.js` and `index.wasm`.

- `assets/multi-canvas.html` is a demonstration of how to load in different compiled WASM modules into the same
page. This requires building the WASM modules with different names (`-s MODULARIZE=1 -s EXPORT_NAME="FOO"` flags).
This is demonstrated in `./meta/multi_build_wasm.sh`.

## Building

### Native SDL build

Need to have `SDL2` installed on your system, and should be able to compile C code with `-lSDL2 -lz`

```shell
$ ocen main.oc -o main
$ ./main
```

### Emscripten build, Local toolchain

Need to have `emscripten` installed locally, and activated so that `emcc` is in your path.

```shell
$ ./meta/build_wasm.sh
$ python3 -m http.server build/
```

### Emscripten build, Docker

Must have docker installed on your system, and running.

```shell
$ ./meta/build_wasm_docker.sh
$ python3 -m http.server build/
```
69 changes: 69 additions & 0 deletions assets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>RayCast</title>
<style>
body {
font-family: "Andale Mono", monospace;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
margin-top: 5vh;
background-color: #e0e0e0;
}

#canvas {
display: block;
background-color: #000;
}

#canvas2 {
display: block;
background-color: #000;
}

code {
background-color: #686868;
padding: 2pt;
color: #f8f8f2;
border-radius: 2px;
}

li {
margin: 4pt;
}

</style>
</head>
<body>
<h1>Ocen WASM Demo</h1>
<a href="https://github.com/ocen-lang/og-wasm-template">View Source On GitHub</a>
<br>
<p> This demo was written in the <a href="https://github.com/ocen-lang/ocen">Ocen</a>, and compiled to the web using Emscripten. </p>

<p> Use <code>Up</code> and <code>Down</code> keys to zoom in/out </p>
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>

<br> <a href="https://ocen-lang.github.io/og-wasm-template/multi-canvas.html">Check out the multi-canvas template</a>

<script type='text/javascript'>
var canvas = document.getElementById('canvas');
var Module = {
canvas,
preRun: [function() {
// This is needed if you want the keyboard events to only be captured by the
// canvas when it is focused. By default, every canvas on the page will react
// to all keyboard events. Without this, any text-boxes / etc on the page will
// also not work properly, as the keyboard events will be captured by the canvas.
ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = "#canvas";
}]
};
</script>
<script async type="text/javascript" src="index.js"></script>
</body>
</html>
86 changes: 86 additions & 0 deletions assets/multi-canvas.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>RayCast</title>
<style>
body {
font-family: "Andale Mono", monospace;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
margin-top: 5vh;
background-color: #e0e0e0;
}

#canvas {
display: block;
background-color: #000;
}

#canvas2 {
display: block;
background-color: #000;
}

code {
background-color: #686868;
padding: 2pt;
color: #f8f8f2;
border-radius: 2px;
}

li {
margin: 4pt;
}

</style>
</head>
<body>
<h1>Ocen WASM Demo - Multi Canvas</h1>
<a href="https://github.com/ocen-lang/og-wasm-template">View Source On GitHub</a>
<br>
<p> This demo was written in the <a href="https://github.com/ocen-lang/ocen">Ocen</a>, and compiled to the web using Emscripten. </p>
<p> Use <code>Up</code> and <code>Down</code> keys to zoom in/out </p>

<canvas id="canvas1" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
<input type="text" style="margin:5pt;" id="input" placeholder="Textbox to try">
<canvas id="canvas2" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>

<br> <a href="https://ocen-lang.github.io/og-wasm-template">Check out the single-canvas template</a>


<!-- NOTE: We need to load these first, >>without<< the async tag -->
<script type="text/javascript" src="mod1.js"></script>
<script type="text/javascript" src="mod2.js"></script>

<script type='text/javascript'>
// Get the canvases
var canvas1 = document.getElementById('canvas1');
var canvas2 = document.getElementById('canvas2');

// Helper function to load a module with a canvas. Split this up into separate
// calls if you wish to customize the preRun or other settings.
function makeModule(ModuleName, canvas) {
ModuleName({
canvas,
// This is needed if you want the keyboard events to only be captured by the
// canvas when it is focused. By default, every canvas on the page will react
// to all keyboard events. Without this, any text-boxes / etc on the page will
// also not work properly, as the keyboard events will be captured by the canvas.
preRun: [function(mod) {
mod.ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = "#canvas";
}]
})
}
// // Load the modules
makeModule(Module1, canvas1);
makeModule(Module2, canvas2);

</script>
</body>
</html>
47 changes: 47 additions & 0 deletions main.oc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import std::og

def main() {
let rows = 20i32
let cols = 20i32
let cell_size = 20i32

og::init((cols * cell_size) as u32, (rows * cell_size) as u32, "Demo")

let off = 0i32
let frames = 0
while og::is_running() {
if og::is_key_pressed(Escape) {
break
}

if og::is_key_pressed(Up) {
cell_size += 1
}
if og::is_key_pressed(Down) {
cell_size -= 1
}

for let i = -1; i < rows + 1; i++ {
for let j = -1; j < cols + 1; j++ {
og::draw_rect(
(j * cell_size + off) as i32,
(i * cell_size + off) as i32,
(cell_size) as i32,
(cell_size) as i32,
if (i + j) % 2 == 0 then og::colors::BLACK else og::colors::WHITE
)
}
}

frames++
if frames % 20 == 0 {
if (off == cell_size) {
off = 0
}
off++
}
}
og::quit()
}


48 changes: 48 additions & 0 deletions meta/build_wasm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

set -xe

mkdir -p build

if [[ -z "$1" ]]; then
ocen main.oc -n -c build/main.c
FILE=build/main.c
else
FILE=$1
fi


cp assets/index.html build/

# GUIDE for flags:
#------------------
# -O3: Optimize the code.
# -DOC_NO_BACKTRACE: Disable backtrace: Ocen specific, required, since WASM doesn't have execinfo.h
# -s USE_SDL=2: Use SDL2 for graphics. (`std::og` is based on SDL2)
# -s USE_ZLIB=1: Use zlib for compression. (`std::image::png` uses zlib)
# -s ALLOW_MEMORY_GROWTH=1: Allow memory to grow dynamically.
# --preload-file assets: Bundle the `assets` directory into generated WASM data
# --use-preload-plugins: Use the plugins in the preload file.
# -o build/index.js: Output file name (JS + corresponding WASM file)
# -s ASYNCIFY=1: Enable asyncify (allows `while` loops in the code for main event loop)
#
# Optional flags (not used here, but needed for multi-wasm pages)
# ----------------------------------------------------------------
# -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0: Without this, SDL always assumes single canvas with ID `#canvas`.
# -s MODULARIZE=1: Generate a module that can be loaded into the same HTML page.
# -s EXPORT_NAME="'Module1'": Name of the module. This is used in the HTML file to load the module.
# -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ENV"]': Export the ENV object to the module. This is needed so we can configure
# the module to not capture keyboard events outside the canvas. Look at
# `assets/multi-canvas.html` or `assets/index.html` for more details.


emcc $FILE \
-O3 \
-DOC_NO_BACKTRACE \
-s USE_SDL=2 \
-s USE_ZLIB=1 \
-s ALLOW_MEMORY_GROWTH=1 \
--preload-file assets \
--use-preload-plugins \
-o build/index.js \
-s ASYNCIFY=1
6 changes: 6 additions & 0 deletions meta/build_wasm_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

set -xe

ocen main.oc -n -c build/main.c
docker run --rm -v $(PWD):/mnt/ -w /mnt/ emscripten/emsdk ./meta/build_wasm.sh build/main.c
Loading

0 comments on commit 61685d4

Please sign in to comment.