Compare commits
2 Commits
706789c81b
...
197ebcd615
| Author | SHA1 | Date | |
|---|---|---|---|
| 197ebcd615 | |||
| ecd411a9de |
+1
-8
@@ -1,13 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
// --- Security headers ---
|
|
||||||
header_remove('X-Powered-By');
|
|
||||||
header('X-Frame-Options: DENY');
|
|
||||||
header('X-Content-Type-Options: nosniff');
|
|
||||||
header('Referrer-Policy: strict-origin-when-cross-origin');
|
|
||||||
header('Content-Security-Policy: default-src \'self\'');
|
|
||||||
|
|
||||||
// --- Routing ---
|
// --- Routing ---
|
||||||
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||||
|
|
||||||
@@ -18,7 +11,7 @@ if ($uri === false || $uri === null) {
|
|||||||
|
|
||||||
$routes = [
|
$routes = [
|
||||||
'/' => 'web/pages/home.php',
|
'/' => 'web/pages/home.php',
|
||||||
'/about' => 'web/pages/about.php',
|
'/sim' => 'web/pages/sim.php',
|
||||||
];
|
];
|
||||||
|
|
||||||
$base = realpath(ROOT . '/web/pages');
|
$base = realpath(ROOT . '/web/pages');
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?php require ROOT . '/web/partials/head.php'; ?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
background-color: black;
|
||||||
|
max-width: 2200px;
|
||||||
|
}
|
||||||
|
.game_wrapper {
|
||||||
|
max-width: 1500px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
font-family: sans-serif;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.game_title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
margin: 20px 0 12px 0;
|
||||||
|
}
|
||||||
|
canvas.game_canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
/* match this to your actual internal render resolution ratio */
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
border: 0px none;
|
||||||
|
background-color: black;
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.too_small_message {
|
||||||
|
display: none;
|
||||||
|
color: white;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
.game_info {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 20px auto 40px auto;
|
||||||
|
padding: 0 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
.game_info strong {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.game_info a {
|
||||||
|
color: #9cf;
|
||||||
|
}
|
||||||
|
.game_info p {
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
/* Below this width, hide the canvas and show the message instead */
|
||||||
|
@media (max-width: 950px) {
|
||||||
|
canvas.game_canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.too_small_message {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="game_wrapper">
|
||||||
|
<h1 class="game_title">Octal Cookie - Chip 8 Simulator</h1>
|
||||||
|
|
||||||
|
<canvas class="game_canvas" id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1" onmousedown="event.target.focus()" onkeydown="event.preventDefault()"></canvas>
|
||||||
|
|
||||||
|
<div class="game_info">
|
||||||
|
<p><strong>Click inside the simulator to focus it</strong>, click outside to release focus.</p>
|
||||||
|
<p>Keypad is mapped to <strong>1234 / QWER / ASDF / ZXCV</strong>.</p>
|
||||||
|
<hr>
|
||||||
|
<p>A CHIP-8 emulator built in Odin and Raylib as a refresher project.</p>
|
||||||
|
|
||||||
|
<p> Functional Work in progress, not perfect.</p>
|
||||||
|
<p> Planned new features when time allows: </p>
|
||||||
|
<p><strong>Instruction Quirks with gui to toggle on/off</strong></p>
|
||||||
|
<p><strong>Super Chip8 implementation</strong></p>
|
||||||
|
</br><a href="https://gitea.sc.koldsoftware.com/jasonhilder/octal_cookie" target="_blank" rel="noopener">View source on Gitea →</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="too_small_message">
|
||||||
|
Your screen is too small to run this app. Please use a larger window or device.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/web/static/apps/sim/odin.js"></script>
|
||||||
|
<script src="/web/static/apps/sim/init.js"></script>
|
||||||
|
<script src="/web/static/apps/sim/index.js"></script>
|
||||||
|
|
||||||
|
<?php require ROOT . '/web/partials/footer.php'; ?>
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Executable
BIN
Binary file not shown.
@@ -0,0 +1,76 @@
|
|||||||
|
var odinMemoryInterface = new odin.WasmMemoryInterface();
|
||||||
|
odinMemoryInterface.setIntSize(4);
|
||||||
|
var odinImports = odin.setupDefaultImports(odinMemoryInterface);
|
||||||
|
|
||||||
|
// The Module is used as configuration for emscripten.
|
||||||
|
var Module = {
|
||||||
|
// This is called by emscripten when it starts up.
|
||||||
|
instantiateWasm: (imports, successCallback) => {
|
||||||
|
const newImports = {
|
||||||
|
...odinImports,
|
||||||
|
...imports
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebAssembly.instantiateStreaming(fetch("/web/static/apps/sim/index.wasm"), newImports).then(function(output) {
|
||||||
|
var e = output.instance.exports;
|
||||||
|
odinMemoryInterface.setExports(e);
|
||||||
|
odinMemoryInterface.setMemory(e.memory);
|
||||||
|
return successCallback(output.instance);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// This happens a bit after `instantiateWasm`, when everything is
|
||||||
|
// done setting up. At that point we can run code.
|
||||||
|
onRuntimeInitialized: () => {
|
||||||
|
var e = wasmExports;
|
||||||
|
|
||||||
|
// Calls any procedure marked with @init
|
||||||
|
e._start();
|
||||||
|
|
||||||
|
// See source/main_web/main_web.odin for main_start,
|
||||||
|
// main_update and main_end.
|
||||||
|
e.main_start();
|
||||||
|
|
||||||
|
function send_resize() {
|
||||||
|
var canvas = document.getElementById('canvas');
|
||||||
|
e.web_window_size_changed(canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', function(event) {
|
||||||
|
send_resize();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
// This can probably be done better: Ideally we'd feed the
|
||||||
|
// initial size to `main_start`. But there seems to be a
|
||||||
|
// race condition. `canvas` doesn't have it's correct size yet.
|
||||||
|
send_resize();
|
||||||
|
|
||||||
|
// Runs the "main loop".
|
||||||
|
function do_main_update() {
|
||||||
|
if (!e.main_update()) {
|
||||||
|
e.main_end();
|
||||||
|
|
||||||
|
// Calls procedures marked with @fini
|
||||||
|
e._end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.requestAnimationFrame(do_main_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.requestAnimationFrame(do_main_update);
|
||||||
|
},
|
||||||
|
print: (function() {
|
||||||
|
var element = document.getElementById("output");
|
||||||
|
if (element) element.value = ''; // clear browser cache
|
||||||
|
return function(text) {
|
||||||
|
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||||
|
console.log(text);
|
||||||
|
if (element) {
|
||||||
|
element.value += text + "\n";
|
||||||
|
element.scrollTop = element.scrollHeight; // focus on bottom
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(),
|
||||||
|
canvas: (function() {
|
||||||
|
return document.getElementById("canvas");
|
||||||
|
})()
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -111,10 +111,3 @@ function checkOffsets() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const debugToggle = document.querySelector(".debug-toggle");
|
|
||||||
function onDebugToggle() {
|
|
||||||
document.body.classList.toggle("debug", debugToggle.checked);
|
|
||||||
}
|
|
||||||
debugToggle.addEventListener("change", onDebugToggle);
|
|
||||||
onDebugToggle();
|
|
||||||
|
|||||||
Reference in New Issue
Block a user