summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--themes/dist/output.js837
-rwxr-xr-xthemes/dist/output.wasmbin139473 -> 147254 bytes
-rw-r--r--themes/resources/grass-blade.pngbin0 -> 314986 bytes
-rw-r--r--themes/src/Renderer3d.cpp42
-rw-r--r--themes/src/Renderer3d.h12
-rw-r--r--themes/src/autumn/AutumnTheme.cpp23
-rw-r--r--themes/src/autumn/AutumnTheme.hpp20
-rw-r--r--themes/src/autumn/LeafParticleRender.cpp (renamed from themes/src/LeafParticleRender.cpp)6
-rw-r--r--themes/src/autumn/LeafParticleRender.h (renamed from themes/src/LeafParticleRender.h)6
-rw-r--r--themes/src/autumn/TreeShape.cpp (renamed from themes/src/TreeShape.cpp)2
-rw-r--r--themes/src/autumn/TreeShape.h (renamed from themes/src/TreeShape.h)6
-rw-r--r--themes/src/main.cpp283
-rw-r--r--themes/src/shader_fetcher.cpp69
-rw-r--r--themes/src/shader_fetcher.hpp19
-rw-r--r--themes/src/shaders/renderer2d.frag0
-rw-r--r--themes/src/shaders/renderer2d.vert0
-rw-r--r--themes/src/shaders/renderer3d.frag7
-rw-r--r--themes/src/shaders/renderer3d.vert15
-rw-r--r--themes/src/spring/GrassRenderer.cpp29
-rw-r--r--themes/src/spring/GrassRenderer.hpp33
-rw-r--r--themes/src/spring/SpringTheme.cpp198
-rw-r--r--themes/src/spring/SpringTheme.hpp41
-rw-r--r--themes/src/summer/SummerTheme.cpp (renamed from themes/src/SummerTheme.cpp)6
-rw-r--r--themes/src/summer/SummerTheme.h (renamed from themes/src/SummerTheme.h)4
-rw-r--r--themes/src/winter/Snowflake.cpp (renamed from themes/src/Snowflake.cpp)8
-rw-r--r--themes/src/winter/Snowflake.h (renamed from themes/src/Snowflake.h)8
-rw-r--r--themes/src/winter/Windfield.cpp (renamed from themes/src/Windfield.cpp)4
-rw-r--r--themes/src/winter/Windfield.hpp (renamed from themes/src/Windfield.hpp)5
-rw-r--r--themes/src/winter/WinterTheme.cpp20
-rw-r--r--themes/src/winter/WinterTheme.hpp18
30 files changed, 887 insertions, 834 deletions
diff --git a/themes/dist/output.js b/themes/dist/output.js
index 079be8d..e814b4e 100644
--- a/themes/dist/output.js
+++ b/themes/dist/output.js
@@ -1,5 +1,4 @@
-
-
+// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
@@ -15,13 +14,9 @@
// can continue to use Module afterwards as well.
var Module = typeof Module != 'undefined' ? Module : {};
-// See https://caniuse.com/mdn-javascript_builtins_object_assign
-
-// See https://caniuse.com/mdn-javascript_builtins_bigint64array
-
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
-// {{PRE_JSES}}
+
// Sometimes an existing Module object exists with properties
// meant to overwrite the default module functionality. Here
@@ -84,32 +79,26 @@ function logExceptionOnExit(e) {
if (ENVIRONMENT_IS_NODE) {
if (typeof process == 'undefined' || !process.release || process.release.name !== 'node') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)');
+ // `require()` is no-op in an ESM module, use `createRequire()` to construct
+ // the require()` function. This is only necessary for multi-environment
+ // builds, `-sENVIRONMENT=node` emits a static import declaration instead.
+ // TODO: Swap all `require()`'s with `import()`'s?
+ // These modules will usually be used on Node.js. Load them eagerly to avoid
+ // the complexity of lazy-loading.
+ var fs = require('fs');
+ var nodePath = require('path');
+
if (ENVIRONMENT_IS_WORKER) {
- scriptDirectory = require('path').dirname(scriptDirectory) + '/';
+ scriptDirectory = nodePath.dirname(scriptDirectory) + '/';
} else {
scriptDirectory = __dirname + '/';
}
// include: node_shell_read.js
-
-
-// These modules will usually be used on Node.js. Load them eagerly to avoid
-// the complexity of lazy-loading. However, for now we must guard on require()
-// actually existing: if the JS is put in a .mjs file (ES6 module) and run on
-// node, then we'll detect node as the environment and get here, but require()
-// does not exist (since ES6 modules should use |import|). If the code actually
-// uses the node filesystem then it will crash, of course, but in the case of
-// code that never uses it we don't want to crash here, so the guarding if lets
-// such code work properly. See discussion in
-// https://github.com/emscripten-core/emscripten/pull/17851
-var fs, nodePath;
-if (typeof require === 'function') {
- fs = require('fs');
- nodePath = require('path');
-}
-
read_ = (filename, binary) => {
- filename = nodePath['normalize'](filename);
+ // We need to re-wrap `file://` strings to URLs. Normalizing isn't
+ // necessary in that case, the path should already be absolute.
+ filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
return fs.readFileSync(filename, binary ? undefined : 'utf8');
};
@@ -123,7 +112,8 @@ readBinary = (filename) => {
};
readAsync = (filename, onload, onerror) => {
- filename = nodePath['normalize'](filename);
+ // See the comment in the `read_` function.
+ filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
fs.readFile(filename, function(err, data) {
if (err) onerror(err);
else onload(data.buffer);
@@ -153,7 +143,10 @@ readAsync = (filename, onload, onerror) => {
// not be needed with node v15 and about because it is now the default
// behaviour:
// See https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
- process['on']('unhandledRejection', function(reason) { throw reason; });
+ var nodeMajor = process.version.match(/^v(\d+)\./)[1];
+ if (nodeMajor < 15) {
+ process['on']('unhandledRejection', function(reason) { throw reason; });
+ }
quit_ = (status, toThrow) => {
if (keepRuntimeAlive()) {
@@ -191,6 +184,10 @@ if (ENVIRONMENT_IS_SHELL) {
setTimeout(() => onload(readBinary(f)), 0);
};
+ if (typeof clearTimeout == 'undefined') {
+ globalThis.clearTimeout = (id) => {};
+ }
+
if (typeof scriptArgs != 'undefined') {
arguments_ = scriptArgs;
} else if (typeof arguments != 'undefined') {
@@ -240,9 +237,7 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
// be done differently.
{
// include: web_or_worker_shell_read.js
-
-
- read_ = (url) => {
+read_ = (url) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
@@ -327,110 +322,8 @@ var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js';
assert(!ENVIRONMENT_IS_SHELL, "shell environment detected but not enabled at build time. Add 'shell' to `-sENVIRONMENT` to enable.");
-
-
-var STACK_ALIGN = 16;
-var POINTER_SIZE = 4;
-
-function getNativeTypeSize(type) {
- switch (type) {
- case 'i1': case 'i8': case 'u8': return 1;
- case 'i16': case 'u16': return 2;
- case 'i32': case 'u32': return 4;
- case 'i64': case 'u64': return 8;
- case 'float': return 4;
- case 'double': return 8;
- default: {
- if (type[type.length - 1] === '*') {
- return POINTER_SIZE;
- }
- if (type[0] === 'i') {
- const bits = Number(type.substr(1));
- assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type);
- return bits / 8;
- }
- return 0;
- }
- }
-}
-
-// include: runtime_debug.js
-
-
-function legacyModuleProp(prop, newName) {
- if (!Object.getOwnPropertyDescriptor(Module, prop)) {
- Object.defineProperty(Module, prop, {
- configurable: true,
- get: function() {
- abort('Module.' + prop + ' has been replaced with plain ' + newName + ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)');
- }
- });
- }
-}
-
-function ignoredModuleProp(prop) {
- if (Object.getOwnPropertyDescriptor(Module, prop)) {
- abort('`Module.' + prop + '` was supplied but `' + prop + '` not included in INCOMING_MODULE_JS_API');
- }
-}
-
-// forcing the filesystem exports a few things by default
-function isExportedByForceFilesystem(name) {
- return name === 'FS_createPath' ||
- name === 'FS_createDataFile' ||
- name === 'FS_createPreloadedFile' ||
- name === 'FS_unlink' ||
- name === 'addRunDependency' ||
- // The old FS has some functionality that WasmFS lacks.
- name === 'FS_createLazyFile' ||
- name === 'FS_createDevice' ||
- name === 'removeRunDependency';
-}
-
-function missingLibrarySymbol(sym) {
- if (typeof globalThis !== 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) {
- Object.defineProperty(globalThis, sym, {
- configurable: true,
- get: function() {
- // Can't `abort()` here because it would break code that does runtime
- // checks. e.g. `if (typeof SDL === 'undefined')`.
- var msg = '`' + sym + '` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line';
- // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in
- // library.js, which means $name for a JS name with no prefix, or name
- // for a JS name like _name.
- var librarySymbol = sym;
- if (!librarySymbol.startsWith('_')) {
- librarySymbol = '$' + sym;
- }
- msg += " (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=" + librarySymbol + ")";
- if (isExportedByForceFilesystem(sym)) {
- msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
- }
- warnOnce(msg);
- return undefined;
- }
- });
- }
-}
-
-function unexportedRuntimeSymbol(sym) {
- if (!Object.getOwnPropertyDescriptor(Module, sym)) {
- Object.defineProperty(Module, sym, {
- configurable: true,
- get: function() {
- var msg = "'" + sym + "' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)";
- if (isExportedByForceFilesystem(sym)) {
- msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
- }
- abort(msg);
- }
- });
- }
-}
-
-// end include: runtime_debug.js
-
-
+// end include: shell.js
+// include: preamble.js
// === Preamble library stuff ===
// Documentation for the public APIs defined in this file must be updated in:
@@ -477,8 +370,6 @@ function assert(condition, text) {
// builds with assertions.
// include: runtime_strings.js
-
-
// runtime_strings.js: String related runtime functions that are part of both
// MINIMAL_RUNTIME and regular runtime.
@@ -522,7 +413,7 @@ function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
if ((u0 & 0xF0) == 0xE0) {
u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
} else {
- if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!');
+ if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!');
u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
}
@@ -612,7 +503,7 @@ function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {
heap[outIdx++] = 0x80 | (u & 63);
} else {
if (outIdx + 3 >= endIdx) break;
- if (u > 0x10FFFF) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).');
+ if (u > 0x10FFFF) warnOnce('Invalid Unicode code point ' + ptrToString(u) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).');
heap[outIdx++] = 0xF0 | (u >> 18);
heap[outIdx++] = 0x80 | ((u >> 12) & 63);
heap[outIdx++] = 0x80 | ((u >> 6) & 63);
@@ -670,8 +561,6 @@ function lengthBytesUTF8(str) {
// Memory management
var HEAP,
-/** @type {!ArrayBuffer} */
- buffer,
/** @type {!Int8Array} */
HEAP8,
/** @type {!Uint8Array} */
@@ -689,32 +578,26 @@ var HEAP,
/** @type {!Float64Array} */
HEAPF64;
-function updateGlobalBufferAndViews(buf) {
- buffer = buf;
- Module['HEAP8'] = HEAP8 = new Int8Array(buf);
- Module['HEAP16'] = HEAP16 = new Int16Array(buf);
- Module['HEAP32'] = HEAP32 = new Int32Array(buf);
- Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf);
- Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf);
- Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf);
- Module['HEAPF32'] = HEAPF32 = new Float32Array(buf);
- Module['HEAPF64'] = HEAPF64 = new Float64Array(buf);
+function updateMemoryViews() {
+ var b = wasmMemory.buffer;
+ Module['HEAP8'] = HEAP8 = new Int8Array(b);
+ Module['HEAP16'] = HEAP16 = new Int16Array(b);
+ Module['HEAP32'] = HEAP32 = new Int32Array(b);
+ Module['HEAPU8'] = HEAPU8 = new Uint8Array(b);
+ Module['HEAPU16'] = HEAPU16 = new Uint16Array(b);
+ Module['HEAPU32'] = HEAPU32 = new Uint32Array(b);
+ Module['HEAPF32'] = HEAPF32 = new Float32Array(b);
+ Module['HEAPF64'] = HEAPF64 = new Float64Array(b);
}
-var STACK_SIZE = 5242880;
-if (Module['STACK_SIZE']) assert(STACK_SIZE === Module['STACK_SIZE'], 'the stack size can no longer be determined at runtime')
-
-var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;legacyModuleProp('INITIAL_MEMORY', 'INITIAL_MEMORY');
+assert(!Module['STACK_SIZE'], 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time')
-assert(INITIAL_MEMORY >= STACK_SIZE, 'INITIAL_MEMORY should be larger than STACK_SIZE, was ' + INITIAL_MEMORY + '! (STACK_SIZE=' + STACK_SIZE + ')');
-
-// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined,
'JS engine does not provide full typed array support');
-// If memory is defined in wasm, the user can't provide it.
+// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY
assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally');
-assert(INITIAL_MEMORY == 16777216, 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically');
+assert(!Module['INITIAL_MEMORY'], 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically');
// include: runtime_init_table.js
// In regular non-RELOCATABLE mode the table is exported
@@ -724,12 +607,16 @@ var wasmTable;
// end include: runtime_init_table.js
// include: runtime_stack_check.js
-
-
// Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode.
function writeStackCookie() {
var max = _emscripten_stack_get_end();
assert((max & 3) == 0);
+ // If the stack ends at address zero we write our cookies 4 bytes into the
+ // stack. This prevents interference with the (separate) address-zero check
+ // below.
+ if (max == 0) {
+ max += 4;
+ }
// The stack grow downwards towards _emscripten_stack_get_end.
// We write cookies to the final two words in the stack and detect if they are
// ever overwritten.
@@ -742,19 +629,23 @@ function writeStackCookie() {
function checkStackCookie() {
if (ABORT) return;
var max = _emscripten_stack_get_end();
+ // See writeStackCookie().
+ if (max == 0) {
+ max += 4;
+ }
var cookie1 = HEAPU32[((max)>>2)];
var cookie2 = HEAPU32[(((max)+(4))>>2)];
if (cookie1 != 0x2135467 || cookie2 != 0x89BACDFE) {
- abort('Stack overflow! Stack cookie has been overwritten at 0x' + max.toString(16) + ', expected hex dwords 0x89BACDFE and 0x2135467, but received 0x' + cookie2.toString(16) + ' 0x' + cookie1.toString(16));
+ abort('Stack overflow! Stack cookie has been overwritten at ' + ptrToString(max) + ', expected hex dwords 0x89BACDFE and 0x2135467, but received ' + ptrToString(cookie2) + ' ' + ptrToString(cookie1));
}
// Also test the global address 0 for integrity.
- if (HEAPU32[0] !== 0x63736d65 /* 'emsc' */) abort('Runtime error: The application has corrupted its heap memory area (address zero)!');
+ if (HEAPU32[0] !== 0x63736d65 /* 'emsc' */) {
+ abort('Runtime error: The application has corrupted its heap memory area (address zero)!');
+ }
}
// end include: runtime_stack_check.js
// include: runtime_assertions.js
-
-
// Endianness check
(function() {
var h16 = new Int16Array(1);
@@ -777,14 +668,12 @@ function keepRuntimeAlive() {
}
function preRun() {
-
if (Module['preRun']) {
if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
while (Module['preRun'].length) {
addOnPreRun(Module['preRun'].shift());
}
}
-
callRuntimeCallbacks(__ATPRERUN__);
}
@@ -837,8 +726,6 @@ function addOnPostRun(cb) {
}
// include: runtime_math.js
-
-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
@@ -971,11 +858,7 @@ function abort(what) {
throw e;
}
-// {{MEM_INITIALIZER}}
-
// include: memoryprofiler.js
-
-
// end include: memoryprofiler.js
// show errors on likely calls to FS when it was not included
var FS = {
@@ -998,8 +881,6 @@ Module['FS_createDataFile'] = FS.createDataFile;
Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
// include: URIUtils.js
-
-
// Prefix of data URIs emitted by SINGLE_FILE and related options.
var dataURIPrefix = 'data:application/octet-stream;base64,';
@@ -1090,8 +971,8 @@ function getBinaryPromise() {
function createWasm() {
// prepare imports
var info = {
- 'env': asmLibraryArg,
- 'wasi_snapshot_preview1': asmLibraryArg,
+ 'env': wasmImports,
+ 'wasi_snapshot_preview1': wasmImports,
};
// Load the wasm module and create an instance of using native support in the JS engine.
// handle a generated wasm instance, receiving its exports and
@@ -1108,7 +989,7 @@ function createWasm() {
// mode.
// TODO(sbc): Read INITIAL_MEMORY out of the wasm file in post-link mode.
//assert(wasmMemory.buffer.byteLength === 16777216);
- updateGlobalBufferAndViews(wasmMemory.buffer);
+ updateMemoryViews();
wasmTable = Module['asm']['__indirect_function_table'];
assert(wasmTable, "table not found in wasm exports");
@@ -1118,7 +999,7 @@ function createWasm() {
removeRunDependency('wasm-instantiate');
}
- // we can't run yet (except in a pthread, where we have a custom sync instantiator)
+ // wait for the pthread pool (if any)
addRunDependency('wasm-instantiate');
// Prefer streaming instantiation if available.
@@ -1211,16 +1092,100 @@ function createWasm() {
var tempDouble;
var tempI64;
-// === Body ===
+// include: runtime_debug.js
+function legacyModuleProp(prop, newName) {
+ if (!Object.getOwnPropertyDescriptor(Module, prop)) {
+ Object.defineProperty(Module, prop, {
+ configurable: true,
+ get: function() {
+ abort('Module.' + prop + ' has been replaced with plain ' + newName + ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)');
+ }
+ });
+ }
+}
-var ASM_CONSTS = {
-
-};
+function ignoredModuleProp(prop) {
+ if (Object.getOwnPropertyDescriptor(Module, prop)) {
+ abort('`Module.' + prop + '` was supplied but `' + prop + '` not included in INCOMING_MODULE_JS_API');
+ }
+}
+
+// forcing the filesystem exports a few things by default
+function isExportedByForceFilesystem(name) {
+ return name === 'FS_createPath' ||
+ name === 'FS_createDataFile' ||
+ name === 'FS_createPreloadedFile' ||
+ name === 'FS_unlink' ||
+ name === 'addRunDependency' ||
+ // The old FS has some functionality that WasmFS lacks.
+ name === 'FS_createLazyFile' ||
+ name === 'FS_createDevice' ||
+ name === 'removeRunDependency';
+}
+function missingGlobal(sym, msg) {
+ if (typeof globalThis !== 'undefined') {
+ Object.defineProperty(globalThis, sym, {
+ configurable: true,
+ get: function() {
+ warnOnce('`' + sym + '` is not longer defined by emscripten. ' + msg);
+ return undefined;
+ }
+ });
+ }
+}
+
+missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer');
+
+function missingLibrarySymbol(sym) {
+ if (typeof globalThis !== 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) {
+ Object.defineProperty(globalThis, sym, {
+ configurable: true,
+ get: function() {
+ // Can't `abort()` here because it would break code that does runtime
+ // checks. e.g. `if (typeof SDL === 'undefined')`.
+ var msg = '`' + sym + '` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line';
+ // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in
+ // library.js, which means $name for a JS name with no prefix, or name
+ // for a JS name like _name.
+ var librarySymbol = sym;
+ if (!librarySymbol.startsWith('_')) {
+ librarySymbol = '$' + sym;
+ }
+ msg += " (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=" + librarySymbol + ")";
+ if (isExportedByForceFilesystem(sym)) {
+ msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
+ }
+ warnOnce(msg);
+ return undefined;
+ }
+ });
+ }
+ // Any symbol that is not included from the JS libary is also (by definttion)
+ // not exported on the Module object.
+ unexportedRuntimeSymbol(sym);
+}
+function unexportedRuntimeSymbol(sym) {
+ if (!Object.getOwnPropertyDescriptor(Module, sym)) {
+ Object.defineProperty(Module, sym, {
+ configurable: true,
+ get: function() {
+ var msg = "'" + sym + "' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)";
+ if (isExportedByForceFilesystem(sym)) {
+ msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
+ }
+ abort(msg);
+ }
+ });
+ }
+}
+// end include: runtime_debug.js
+// === Body ===
+// end include: preamble.js
/** @constructor */
function ExitStatus(status) {
@@ -1257,6 +1222,11 @@ var ASM_CONSTS = {
return null;
}
+ function ptrToString(ptr) {
+ assert(typeof ptr === 'number');
+ return '0x' + ptr.toString(16).padStart(8, '0');
+ }
+
/**
* @param {number} ptr
@@ -1541,6 +1511,7 @@ var ASM_CONSTS = {
}
var wasmTableMirror = [];
+
function getWasmTableEntry(funcPtr) {
var func = wasmTableMirror[funcPtr];
if (!func) {
@@ -1568,13 +1539,14 @@ var ASM_CONSTS = {
}
function emscripten_realloc_buffer(size) {
+ var b = wasmMemory.buffer;
try {
// round size grow request up to wasm page size (fixed 64KB per spec)
- wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16); // .grow() takes a delta compared to the previous size
- updateGlobalBufferAndViews(wasmMemory.buffer);
+ wasmMemory.grow((size - b.byteLength + 65535) >>> 16); // .grow() takes a delta compared to the previous size
+ updateMemoryViews();
return 1 /*success*/;
} catch(e) {
- err('emscripten_realloc_buffer: Attempted to grow heap from ' + buffer.byteLength + ' bytes to ' + size + ' bytes, but got error: ' + e);
+ err('emscripten_realloc_buffer: Attempted to grow heap from ' + b.byteLength + ' bytes to ' + size + ' bytes, but got error: ' + e);
}
// implicit 0 return to save code size (caller will cast "undefined" into 0
// anyhow)
@@ -1633,6 +1605,7 @@ var ASM_CONSTS = {
return false;
}
+
function findCanvasEventTarget(target) { return findEventTarget(target); }
function _emscripten_set_canvas_element_size(target, width, height) {
var canvas = findCanvasEventTarget(target);
@@ -1642,6 +1615,9 @@ var ASM_CONSTS = {
return 0;
}
+
+
+
function fillMouseEventData(eventStruct, e, target) {
assert(eventStruct % 4 == 0);
HEAPF64[((eventStruct)>>3)] = e.timeStamp;
@@ -1668,13 +1644,13 @@ var ASM_CONSTS = {
HEAP32[idx + 14] = e.clientY - rect.top;
}
+
+
function registerMouseEventCallback(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) {
if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc( 72 );
target = findEventTarget(target);
- var mouseEventHandlerFunc = function(ev) {
- var e = ev || event;
-
+ var mouseEventHandlerFunc = function(e = event) {
// TODO: Make this access thread safe, or this could update live while app is reading it.
fillMouseEventData(JSEvents.mouseEvent, e, target);
@@ -1696,13 +1672,14 @@ var ASM_CONSTS = {
return 0;
}
+
+
function registerUiEventCallback(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) {
if (!JSEvents.uiEvent) JSEvents.uiEvent = _malloc( 36 );
target = findEventTarget(target);
- var uiEventHandlerFunc = function(ev) {
- var e = ev || event;
+ var uiEventHandlerFunc = function(e = event) {
if (e.target != target) {
// Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that
// was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log
@@ -1760,25 +1737,18 @@ var ASM_CONSTS = {
openRequest.onsuccess = (event) => onsuccess(event.target.result);
openRequest.onerror = (error) => onerror(error);
},staticInit:function() {
- var isMainThread = true;
-
var onsuccess = (db) => {
Fetch.dbInstance = db;
-
- if (isMainThread) {
- removeRunDependency('library_fetch_init');
- }
+ removeRunDependency('library_fetch_init');
};
+
var onerror = () => {
Fetch.dbInstance = false;
-
- if (isMainThread) {
- removeRunDependency('library_fetch_init');
- }
+ removeRunDependency('library_fetch_init');
};
- Fetch.openDatabase('emscripten_filesystem', 1, onsuccess, onerror);
- if (typeof ENVIRONMENT_IS_FETCH_WORKER == 'undefined' || !ENVIRONMENT_IS_FETCH_WORKER) addRunDependency('library_fetch_init');
+ addRunDependency('library_fetch_init');
+ Fetch.openDatabase('emscripten_filesystem', 1, onsuccess, onerror);
}};
function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) {
@@ -1957,6 +1927,12 @@ var ASM_CONSTS = {
if (e instanceof ExitStatus || e == 'unwind') {
return EXITSTATUS;
}
+ checkStackCookie();
+ if (e instanceof WebAssembly.RuntimeError) {
+ if (_emscripten_stack_get_current() <= 0) {
+ err('Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to ' + 65536 + ')');
+ }
+ }
quit_(1, e);
}
function callUserCallback(func) {
@@ -2092,6 +2068,7 @@ var ASM_CONSTS = {
onerror(fetch, 0, e);
}
}
+
function _emscripten_start_fetch(fetch, successcb, errorcb, progresscb, readystatechangecb) {
// Avoid shutting down the runtime since we want to wait for the async
// response.
@@ -2238,6 +2215,7 @@ var ASM_CONSTS = {
// Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted.
return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw'));
}
+
var GL = {counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode) {
if (!GL.lastError) {
GL.lastError = errorCode;
@@ -2392,7 +2370,7 @@ var ASM_CONSTS = {
canvas.getContext = fixedGetContext;
}
- var ctx =
+ var ctx =
(webGLContextAttributes.majorVersion > 1)
?
canvas.getContext("webgl2", webGLContextAttributes)
@@ -2492,7 +2470,10 @@ var ASM_CONSTS = {
});
}};
+
var __emscripten_webgl_power_preferences = ['default', 'low-power', 'high-performance'];
+
+
function _emscripten_webgl_do_create_context(target, attributes) {
assert(attributes);
var a = attributes >> 2;
@@ -2569,6 +2550,10 @@ var ASM_CONSTS = {
assert(hi === (hi|0)); // hi should be a i32
return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN;
}
+
+
+
+
function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
return 70;
}
@@ -2584,12 +2569,15 @@ var ASM_CONSTS = {
buffer.push(curr);
}
}
+
function flush_NO_FILESYSTEM() {
// flush anything remaining in the buffers during shutdown
_fflush(0);
if (printCharBuffers[1].length) printChar(1, 10);
if (printCharBuffers[2].length) printChar(2, 10);
}
+
+
function _fd_write(fd, iov, iovcnt, pnum) {
// hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0
var num = 0;
@@ -2809,11 +2797,13 @@ var ASM_CONSTS = {
HEAP32[(((buffers)+(i*4))>>2)] = id;
}
}
+
function _glGenBuffers(n, buffers) {
__glGenObject(n, buffers, 'createBuffer', GL.buffers
);
}
+
function _glGenVertexArrays(n, arrays) {
__glGenObject(n, arrays, 'createVertexArray', GL.vaos
);
@@ -2918,6 +2908,7 @@ var ASM_CONSTS = {
function webglGetLeftBracePos(name) {
return name.slice(-1) == ']' && name.lastIndexOf('[');
}
+
function webglPrepareUniformLocationsBeforeFirstUse(program) {
var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation
uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint]
@@ -2957,6 +2948,8 @@ var ASM_CONSTS = {
}
}
}
+
+
function _glGetUniformLocation(program, name) {
name = UTF8ToString(name);
@@ -3035,6 +3028,7 @@ var ASM_CONSTS = {
}
var miniTempWebGLFloatBuffers = [];
+
function _glUniformMatrix4fv(location, count, transpose, value) {
if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible.
@@ -3104,6 +3098,7 @@ var ASM_CONSTS = {
GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
}
+
function _proc_exit(code) {
EXITSTATUS = code;
if (!keepRuntimeAlive()) {
@@ -3134,12 +3129,10 @@ var miniTempWebGLFloatBuffersStorage = new Float32Array(288);
miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i+1);
}
;
-var ASSERTIONS = true;
-
function checkIncomingModuleAPI() {
ignoredModuleProp('fetchSettings');
}
-var asmLibraryArg = {
+var wasmImports = {
"_emscripten_fetch_free": __emscripten_fetch_free,
"_localtime_js": __localtime_js,
"_tzset_js": __tzset_js,
@@ -3199,112 +3192,58 @@ var asmLibraryArg = {
};
var asm = createWasm();
/** @type {function(...*):?} */
-var ___wasm_call_ctors = Module["___wasm_call_ctors"] = createExportWrapper("__wasm_call_ctors");
-
+var ___wasm_call_ctors = createExportWrapper("__wasm_call_ctors");
/** @type {function(...*):?} */
var _main = Module["_main"] = createExportWrapper("main");
-
/** @type {function(...*):?} */
-var _malloc = Module["_malloc"] = createExportWrapper("malloc");
-
+var _free = createExportWrapper("free");
/** @type {function(...*):?} */
-var _free = Module["_free"] = createExportWrapper("free");
-
+var _malloc = createExportWrapper("malloc");
/** @type {function(...*):?} */
-var ___errno_location = Module["___errno_location"] = createExportWrapper("__errno_location");
-
+var ___errno_location = createExportWrapper("__errno_location");
/** @type {function(...*):?} */
var _fflush = Module["_fflush"] = createExportWrapper("fflush");
-
/** @type {function(...*):?} */
-var _emscripten_stack_init = Module["_emscripten_stack_init"] = function() {
- return (_emscripten_stack_init = Module["_emscripten_stack_init"] = Module["asm"]["emscripten_stack_init"]).apply(null, arguments);
+var _emscripten_stack_init = function() {
+ return (_emscripten_stack_init = Module["asm"]["emscripten_stack_init"]).apply(null, arguments);
};
/** @type {function(...*):?} */
-var _emscripten_stack_get_free = Module["_emscripten_stack_get_free"] = function() {
- return (_emscripten_stack_get_free = Module["_emscripten_stack_get_free"] = Module["asm"]["emscripten_stack_get_free"]).apply(null, arguments);
+var _emscripten_stack_get_free = function() {
+ return (_emscripten_stack_get_free = Module["asm"]["emscripten_stack_get_free"]).apply(null, arguments);
};
/** @type {function(...*):?} */
-var _emscripten_stack_get_base = Module["_emscripten_stack_get_base"] = function() {
- return (_emscripten_stack_get_base = Module["_emscripten_stack_get_base"] = Module["asm"]["emscripten_stack_get_base"]).apply(null, arguments);
+var _emscripten_stack_get_base = function() {
+ return (_emscripten_stack_get_base = Module["asm"]["emscripten_stack_get_base"]).apply(null, arguments);
};
/** @type {function(...*):?} */
-var _emscripten_stack_get_end = Module["_emscripten_stack_get_end"] = function() {
- return (_emscripten_stack_get_end = Module["_emscripten_stack_get_end"] = Module["asm"]["emscripten_stack_get_end"]).apply(null, arguments);
+var _emscripten_stack_get_end = function() {
+ return (_emscripten_stack_get_end = Module["asm"]["emscripten_stack_get_end"]).apply(null, arguments);
};
/** @type {function(...*):?} */
-var stackSave = Module["stackSave"] = createExportWrapper("stackSave");
-
+var stackSave = createExportWrapper("stackSave");
/** @type {function(...*):?} */
-var stackRestore = Module["stackRestore"] = createExportWrapper("stackRestore");
-
+var stackRestore = createExportWrapper("stackRestore");
+/** @type {function(...*):?} */
+var stackAlloc = createExportWrapper("stackAlloc");
/** @type {function(...*):?} */
-var stackAlloc = Module["stackAlloc"] = createExportWrapper("stackAlloc");
+var _emscripten_stack_get_current = function() {
+ return (_emscripten_stack_get_current = Module["asm"]["emscripten_stack_get_current"]).apply(null, arguments);
+};
/** @type {function(...*):?} */
var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji");
-
-
-
+// include: postamble.js
// === Auto-generated postamble setup entry stuff ===
-
-var unexportedRuntimeSymbols = [
- 'run',
- 'UTF8ArrayToString',
- 'UTF8ToString',
- 'stringToUTF8Array',
- 'stringToUTF8',
- 'lengthBytesUTF8',
- 'addOnPreRun',
- 'addOnInit',
- 'addOnPreMain',
- 'addOnExit',
- 'addOnPostRun',
- 'addRunDependency',
- 'removeRunDependency',
- 'FS_createFolder',
- 'FS_createPath',
- 'FS_createDataFile',
- 'FS_createPreloadedFile',
- 'FS_createLazyFile',
- 'FS_createLink',
- 'FS_createDevice',
- 'FS_unlink',
- 'getLEB',
- 'getFunctionTables',
- 'alignFunctionTables',
- 'registerFunctions',
- 'prettyPrint',
- 'getCompilerSetting',
- 'out',
- 'err',
- 'callMain',
- 'abort',
- 'keepRuntimeAlive',
- 'wasmMemory',
- 'stackAlloc',
- 'stackSave',
- 'stackRestore',
- 'getTempRet0',
- 'setTempRet0',
- 'writeStackCookie',
- 'checkStackCookie',
- 'ptrToString',
+var missingLibrarySymbols = [
'zeroMemory',
'stringToNewUTF8',
- 'exitJS',
- 'getHeapMax',
- 'emscripten_realloc_buffer',
- 'ENV',
- 'ERRNO_CODES',
- 'ERRNO_MESSAGES',
'setErrNo',
'inetPton4',
'inetNtop4',
@@ -3312,19 +3251,11 @@ var unexportedRuntimeSymbols = [
'inetNtop6',
'readSockaddr',
'writeSockaddr',
- 'DNS',
'getHostByName',
- 'Protocols',
- 'Sockets',
'getRandomDevice',
- 'warnOnce',
'traverseStack',
- 'UNWIND_CACHE',
'convertPCtoSourceLocation',
- 'readAsmConstArgsArray',
- 'readAsmConstArgs',
- 'mainThreadEM_ASM',
- 'jstoi_q',
+ 'readEmAsmArgs',
'jstoi_s',
'getExecutableName',
'listenOnce',
@@ -3332,25 +3263,27 @@ var unexportedRuntimeSymbols = [
'dynCallLegacy',
'getDynCaller',
'dynCall',
- 'handleException',
'runtimeKeepalivePush',
'runtimeKeepalivePop',
- 'callUserCallback',
'maybeExit',
'safeSetTimeout',
'asmjsMangle',
'asyncLoad',
'alignMemory',
'mmapAlloc',
+ 'handleAllocator',
+ 'getNativeTypeSize',
+ 'STACK_SIZE',
+ 'STACK_ALIGN',
+ 'POINTER_SIZE',
+ 'ASSERTIONS',
'writeI53ToI64',
'writeI53ToI64Clamped',
'writeI53ToI64Signaling',
'writeI53ToU64Clamped',
'writeI53ToU64Signaling',
- 'readI53FromI64',
'readI53FromU64',
'convertI32PairToI53',
- 'convertI32PairToI53Checked',
'convertU32PairToI53',
'getCFunc',
'ccall',
@@ -3359,10 +3292,9 @@ var unexportedRuntimeSymbols = [
'sigToWasmTypes',
'generateFuncType',
'convertJsFunctionToWasm',
- 'freeTableIndexes',
- 'functionsInTableMap',
'getEmptyTableSlot',
'updateTableMap',
+ 'getFunctionAddress',
'addFunction',
'removeFunction',
'reallyNegative',
@@ -3370,40 +3302,24 @@ var unexportedRuntimeSymbols = [
'strLen',
'reSign',
'formatString',
- 'setValue',
- 'getValue',
- 'PATH',
- 'PATH_FS',
'intArrayFromString',
'intArrayToString',
'AsciiToString',
'stringToAscii',
- 'UTF16Decoder',
'UTF16ToString',
'stringToUTF16',
'lengthBytesUTF16',
'UTF32ToString',
'stringToUTF32',
'lengthBytesUTF32',
- 'allocateUTF8',
'allocateUTF8OnStack',
'writeStringToMemory',
'writeArrayToMemory',
'writeAsciiToMemory',
- 'SYSCALLS',
'getSocketFromFD',
'getSocketAddress',
- 'JSEvents',
'registerKeyEventCallback',
- 'specialHTMLTargets',
- 'maybeCStringToJsString',
- 'findEventTarget',
- 'findCanvasEventTarget',
- 'getBoundingClientRect',
- 'fillMouseEventData',
- 'registerMouseEventCallback',
'registerWheelEventCallback',
- 'registerUiEventCallback',
'registerFocusEventCallback',
'fillDeviceOrientationEventData',
'registerDeviceOrientationEventCallback',
@@ -3420,8 +3336,6 @@ var unexportedRuntimeSymbols = [
'hideEverythingExceptGivenElement',
'restoreHiddenElements',
'setLetterbox',
- 'currentFullscreenStrategy',
- 'restoreOldWindowedStyle',
'softFullscreenResizeWebGLRenderTarget',
'doRequestFullscreen',
'fillPointerlockChangeEventData',
@@ -3443,213 +3357,151 @@ var unexportedRuntimeSymbols = [
'demangleAll',
'jsStackTrace',
'stackTrace',
- 'ExitStatus',
'getEnvStrings',
'checkWasiClock',
- 'flush_NO_FILESYSTEM',
- 'dlopenMissingError',
'createDyncallWrapper',
'setImmediateWrapped',
'clearImmediateWrapped',
'polyfillSetImmediate',
- 'uncaughtExceptionCount',
- 'exceptionLast',
- 'exceptionCaught',
+ 'newNativePromise',
+ 'getPromise',
'ExceptionInfo',
'exception_addRef',
'exception_decRef',
- 'Browser',
'setMainLoop',
- 'wget',
- 'FS',
- 'MEMFS',
- 'TTY',
- 'PIPEFS',
- 'SOCKFS',
'_setNetworkCallback',
- 'tempFixedLengthArray',
- 'miniTempWebGLFloatBuffers',
'heapObjectForWebGLType',
'heapAccessShiftForWebGLHeap',
- 'GL',
'emscriptenWebGLGet',
'computeUnpackAlignedImageSize',
'emscriptenWebGLGetTexPixelData',
'emscriptenWebGLGetUniform',
- 'webglGetUniformLocation',
- 'webglPrepareUniformLocationsBeforeFirstUse',
- 'webglGetLeftBracePos',
'emscriptenWebGLGetVertexAttrib',
'emscriptenWebGLGetBufferBinding',
'emscriptenWebGLValidateMapBufferTarget',
'writeGLArray',
- 'AL',
'SDL_unicode',
'SDL_ttfContext',
'SDL_audio',
+ 'GLFW_Window',
+ 'runAndAbortIfError',
+ 'emscriptenWebGLGetIndexed',
+ 'ALLOC_NORMAL',
+ 'ALLOC_STACK',
+ 'allocate',
+];
+missingLibrarySymbols.forEach(missingLibrarySymbol)
+
+var unexportedSymbols = [
+ 'run',
+ 'UTF8ArrayToString',
+ 'UTF8ToString',
+ 'stringToUTF8Array',
+ 'stringToUTF8',
+ 'lengthBytesUTF8',
+ 'addOnPreRun',
+ 'addOnInit',
+ 'addOnPreMain',
+ 'addOnExit',
+ 'addOnPostRun',
+ 'addRunDependency',
+ 'removeRunDependency',
+ 'FS_createFolder',
+ 'FS_createPath',
+ 'FS_createDataFile',
+ 'FS_createPreloadedFile',
+ 'FS_createLazyFile',
+ 'FS_createLink',
+ 'FS_createDevice',
+ 'FS_unlink',
+ 'out',
+ 'err',
+ 'callMain',
+ 'abort',
+ 'keepRuntimeAlive',
+ 'wasmMemory',
+ 'stackAlloc',
+ 'stackSave',
+ 'stackRestore',
+ 'getTempRet0',
+ 'setTempRet0',
+ 'writeStackCookie',
+ 'checkStackCookie',
+ 'ptrToString',
+ 'exitJS',
+ 'getHeapMax',
+ 'emscripten_realloc_buffer',
+ 'ENV',
+ 'ERRNO_CODES',
+ 'ERRNO_MESSAGES',
+ 'DNS',
+ 'Protocols',
+ 'Sockets',
+ 'timers',
+ 'warnOnce',
+ 'UNWIND_CACHE',
+ 'readEmAsmArgsArray',
+ 'jstoi_q',
+ 'handleException',
+ 'callUserCallback',
+ 'readI53FromI64',
+ 'convertI32PairToI53Checked',
+ 'freeTableIndexes',
+ 'functionsInTableMap',
+ 'setValue',
+ 'getValue',
+ 'PATH',
+ 'PATH_FS',
+ 'UTF16Decoder',
+ 'allocateUTF8',
+ 'SYSCALLS',
+ 'JSEvents',
+ 'specialHTMLTargets',
+ 'maybeCStringToJsString',
+ 'findEventTarget',
+ 'findCanvasEventTarget',
+ 'getBoundingClientRect',
+ 'fillMouseEventData',
+ 'registerMouseEventCallback',
+ 'registerUiEventCallback',
+ 'currentFullscreenStrategy',
+ 'restoreOldWindowedStyle',
+ 'ExitStatus',
+ 'flush_NO_FILESYSTEM',
+ 'dlopenMissingError',
+ 'promiseMap',
+ 'uncaughtExceptionCount',
+ 'exceptionLast',
+ 'exceptionCaught',
+ 'Browser',
+ 'wget',
+ 'FS',
+ 'MEMFS',
+ 'TTY',
+ 'PIPEFS',
+ 'SOCKFS',
+ 'tempFixedLengthArray',
+ 'miniTempWebGLFloatBuffers',
+ 'GL',
+ 'webglGetUniformLocation',
+ 'webglPrepareUniformLocationsBeforeFirstUse',
+ 'webglGetLeftBracePos',
+ 'AL',
'SDL',
'SDL_gfx',
'GLUT',
'EGL',
- 'GLFW_Window',
'GLFW',
'GLEW',
'IDBStore',
- 'runAndAbortIfError',
- 'emscriptenWebGLGetIndexed',
- 'ALLOC_NORMAL',
- 'ALLOC_STACK',
- 'allocate',
'Fetch',
'fetchDeleteCachedData',
'fetchLoadCachedData',
'fetchCacheData',
'fetchXHR',
];
-unexportedRuntimeSymbols.forEach(unexportedRuntimeSymbol);
-var missingLibrarySymbols = [
- 'ptrToString',
- 'zeroMemory',
- 'stringToNewUTF8',
- 'setErrNo',
- 'inetPton4',
- 'inetNtop4',
- 'inetPton6',
- 'inetNtop6',
- 'readSockaddr',
- 'writeSockaddr',
- 'getHostByName',
- 'getRandomDevice',
- 'traverseStack',
- 'convertPCtoSourceLocation',
- 'readAsmConstArgs',
- 'mainThreadEM_ASM',
- 'jstoi_s',
- 'getExecutableName',
- 'listenOnce',
- 'autoResumeAudioContext',
- 'dynCallLegacy',
- 'getDynCaller',
- 'dynCall',
- 'runtimeKeepalivePush',
- 'runtimeKeepalivePop',
- 'maybeExit',
- 'safeSetTimeout',
- 'asmjsMangle',
- 'asyncLoad',
- 'alignMemory',
- 'mmapAlloc',
- 'writeI53ToI64',
- 'writeI53ToI64Clamped',
- 'writeI53ToI64Signaling',
- 'writeI53ToU64Clamped',
- 'writeI53ToU64Signaling',
- 'readI53FromU64',
- 'convertI32PairToI53',
- 'convertU32PairToI53',
- 'getCFunc',
- 'ccall',
- 'cwrap',
- 'uleb128Encode',
- 'sigToWasmTypes',
- 'generateFuncType',
- 'convertJsFunctionToWasm',
- 'getEmptyTableSlot',
- 'updateTableMap',
- 'addFunction',
- 'removeFunction',
- 'reallyNegative',
- 'unSign',
- 'strLen',
- 'reSign',
- 'formatString',
- 'intArrayFromString',
- 'intArrayToString',
- 'AsciiToString',
- 'stringToAscii',
- 'UTF16ToString',
- 'stringToUTF16',
- 'lengthBytesUTF16',
- 'UTF32ToString',
- 'stringToUTF32',
- 'lengthBytesUTF32',
- 'allocateUTF8OnStack',
- 'writeStringToMemory',
- 'writeArrayToMemory',
- 'writeAsciiToMemory',
- 'getSocketFromFD',
- 'getSocketAddress',
- 'registerKeyEventCallback',
- 'registerWheelEventCallback',
- 'registerFocusEventCallback',
- 'fillDeviceOrientationEventData',
- 'registerDeviceOrientationEventCallback',
- 'fillDeviceMotionEventData',
- 'registerDeviceMotionEventCallback',
- 'screenOrientation',
- 'fillOrientationChangeEventData',
- 'registerOrientationChangeEventCallback',
- 'fillFullscreenChangeEventData',
- 'registerFullscreenChangeEventCallback',
- 'JSEvents_requestFullscreen',
- 'JSEvents_resizeCanvasForFullscreen',
- 'registerRestoreOldStyle',
- 'hideEverythingExceptGivenElement',
- 'restoreHiddenElements',
- 'setLetterbox',
- 'softFullscreenResizeWebGLRenderTarget',
- 'doRequestFullscreen',
- 'fillPointerlockChangeEventData',
- 'registerPointerlockChangeEventCallback',
- 'registerPointerlockErrorEventCallback',
- 'requestPointerLock',
- 'fillVisibilityChangeEventData',
- 'registerVisibilityChangeEventCallback',
- 'registerTouchEventCallback',
- 'fillGamepadEventData',
- 'registerGamepadEventCallback',
- 'registerBeforeUnloadEventCallback',
- 'fillBatteryEventData',
- 'battery',
- 'registerBatteryEventCallback',
- 'setCanvasElementSize',
- 'getCanvasElementSize',
- 'demangle',
- 'demangleAll',
- 'jsStackTrace',
- 'stackTrace',
- 'getEnvStrings',
- 'checkWasiClock',
- 'createDyncallWrapper',
- 'setImmediateWrapped',
- 'clearImmediateWrapped',
- 'polyfillSetImmediate',
- 'ExceptionInfo',
- 'exception_addRef',
- 'exception_decRef',
- 'setMainLoop',
- '_setNetworkCallback',
- 'heapObjectForWebGLType',
- 'heapAccessShiftForWebGLHeap',
- 'emscriptenWebGLGet',
- 'computeUnpackAlignedImageSize',
- 'emscriptenWebGLGetTexPixelData',
- 'emscriptenWebGLGetUniform',
- 'emscriptenWebGLGetVertexAttrib',
- 'emscriptenWebGLGetBufferBinding',
- 'emscriptenWebGLValidateMapBufferTarget',
- 'writeGLArray',
- 'SDL_unicode',
- 'SDL_ttfContext',
- 'SDL_audio',
- 'GLFW_Window',
- 'runAndAbortIfError',
- 'emscriptenWebGLGetIndexed',
- 'ALLOC_NORMAL',
- 'ALLOC_STACK',
- 'allocate',
-];
-missingLibrarySymbols.forEach(missingLibrarySymbol)
+unexportedSymbols.forEach(unexportedRuntimeSymbol);
+
var calledRun;
@@ -3660,11 +3512,11 @@ dependenciesFulfilled = function runCaller() {
if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
};
-function callMain(args) {
+function callMain() {
assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on Module["onRuntimeInitialized"])');
assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
- var entryFunction = Module['_main'];
+ var entryFunction = _main;
var argc = 0;
var argv = 0;
@@ -3694,8 +3546,7 @@ function stackCheckInit() {
}
/** @type {function(Array=)} */
-function run(args) {
- args = args || arguments_;
+function run() {
if (runDependencies > 0) {
return;
@@ -3725,7 +3576,7 @@ function run(args) {
if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']();
- if (shouldRunNow) callMain(args);
+ if (shouldRunNow) callMain();
postRun();
}
@@ -3789,6 +3640,4 @@ if (Module['noInitialRun']) shouldRunNow = false;
run();
-
-
-
+// end include: postamble.js
diff --git a/themes/dist/output.wasm b/themes/dist/output.wasm
index ab6ef25..1b24bbd 100755
--- a/themes/dist/output.wasm
+++ b/themes/dist/output.wasm
Binary files differ
diff --git a/themes/resources/grass-blade.png b/themes/resources/grass-blade.png
new file mode 100644
index 0000000..286cc23
--- /dev/null
+++ b/themes/resources/grass-blade.png
Binary files differ
diff --git a/themes/src/Renderer3d.cpp b/themes/src/Renderer3d.cpp
index 5f9ce88..00315de 100644
--- a/themes/src/Renderer3d.cpp
+++ b/themes/src/Renderer3d.cpp
@@ -8,32 +8,8 @@
// Note: In the 'transform' attribute, the transform.x is the scale,
// transform.y is the rotation, and transform.zw is the translatiob.
-const char* vertexShader =
- "attribute vec4 position; \n"
- "attribute vec4 color; \n"
- "attribute vec4 normal; \n"
- "uniform mat4 projection; \n"
- "uniform mat4 view; \n"
- "uniform mat4 model; \n"
- "varying lowp vec4 VertexColor; \n"
- "varying lowp vec4 VertexNormal; \n"
- "void main() { \n"
- " vec4 fragmentPosition = projection * view * model * position; \n"
- " gl_Position = fragmentPosition; \n"
- " VertexColor = color; \n"
- " VertexNormal = normal; \n"
- "}";
-
-const char* fragmentShader =
- "varying lowp vec4 VertexColor; \n"
- "varying lowp vec4 VertexNormal; \n"
- "void main() { \n"
- " const lowp vec3 lightDirection = vec3(0.0, 1.0, 0.0);\n"
- " gl_FragColor = vec4(VertexColor.xyz * dot(VertexNormal.xyz, lightDirection), 1); \n"
- "}";
-
EM_BOOL onScreenSizeChanged_3D(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) {
- Renderer3D* renderer = (Renderer3D*)userData;
+ Renderer3d* renderer = (Renderer3d*)userData;
EMSCRIPTEN_RESULT result = emscripten_set_canvas_element_size( renderer->context->query, uiEvent->documentBodyClientWidth, uiEvent->documentBodyClientHeight);
if (result != EMSCRIPTEN_RESULT_SUCCESS) {
@@ -44,9 +20,9 @@ EM_BOOL onScreenSizeChanged_3D(int eventType, const EmscriptenUiEvent *uiEvent,
return true;
}
-void Renderer3D::load(WebglContext* inContext) {
+void Renderer3d::load(WebglContext* inContext, const char* vertexShader, const char* fragmentShader) {
context = inContext;
- printf("Compiling Renderer2d shader...\n");
+ printf("Compiling Renderer3d shader...\n");
shader = loadShader(vertexShader, fragmentShader);
useShader(shader);
@@ -59,12 +35,12 @@ void Renderer3D::load(WebglContext* inContext) {
projection = Mat4x4().getPerspectiveProjection(0.1, 1000.f, 0.872f, static_cast<f32>(context->width) / static_cast<f32>(context->height));
view = Mat4x4().getLookAt({ 0, 25, 75 }, { 0, 15, 0 }, { 0, 1, 0 });
- logger_info("Renderer2d shader compiled.\n");
+ logger_info("Renderer3d shader compiled.\n");
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, onScreenSizeChanged_3D);
}
-void Renderer3D::render() {
+void Renderer3d::render() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
@@ -78,7 +54,7 @@ void Renderer3D::render() {
setShaderMat4(uniforms.view, view);
}
-void Renderer3D::unload() {
+void Renderer3d::unload() {
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
glDeleteProgram(shader);
@@ -126,7 +102,7 @@ inline i32 readToken(i32 i, const char* content, char* output) {
return i;
}
-Mesh3d Mesh3d_fromObj(Renderer3D* renderer, const char* content, const i32 len) {
+Mesh3d Mesh3d_fromObj(Renderer3d* renderer, const char* content, const i32 len) {
Mesh3d result;
result.vertices.allocate(2048);
result.indices.allocate(2048);
@@ -218,7 +194,7 @@ Mesh3d Mesh3d_fromObj(Renderer3D* renderer, const char* content, const i32 len)
return result;
}
-void Mesh3d::load(Renderer3D* renderer) {
+void Mesh3d::load(Renderer3d* renderer) {
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
@@ -254,7 +230,7 @@ void Mesh3d::unload() {
indices.deallocate();
}
-void Mesh3d::render(Renderer3D* renderer) {
+void Mesh3d::render(Renderer3d* renderer) {
setShaderMat4(renderer->uniforms.model, model);
glBindVertexArray(vao);
diff --git a/themes/src/Renderer3d.h b/themes/src/Renderer3d.h
index 7e89c93..5b2c8c8 100644
--- a/themes/src/Renderer3d.h
+++ b/themes/src/Renderer3d.h
@@ -5,7 +5,7 @@
#include "types.h"
#include <string>
-struct Renderer3D;
+struct Renderer3d;
struct Vertex3d {
Vector4 position;
@@ -21,13 +21,13 @@ struct Mesh3d {
matte::List<u32> indices;
Mat4x4 model;
- void load(Renderer3D* renderer);
- void render(Renderer3D* renderer);
+ void load(Renderer3d* renderer);
+ void render(Renderer3d* renderer);
void unload();
};
struct WebglContext;
-struct Renderer3D {
+struct Renderer3d {
WebglContext* context = NULL;
Mat4x4 projection;
Mat4x4 view;
@@ -46,11 +46,11 @@ struct Renderer3D {
i32 model;
} uniforms;
- void load(WebglContext* context);
+ void load(WebglContext* context, const char* vertexShader, const char* fragmentShader);
void render();
void unload();
};
-Mesh3d Mesh3d_fromObj(Renderer3D* renderer, const char* content, const i32 len);
+Mesh3d Mesh3d_fromObj(Renderer3d* renderer, const char* content, const i32 len);
#endif
diff --git a/themes/src/autumn/AutumnTheme.cpp b/themes/src/autumn/AutumnTheme.cpp
new file mode 100644
index 0000000..6e6fe2b
--- /dev/null
+++ b/themes/src/autumn/AutumnTheme.cpp
@@ -0,0 +1,23 @@
+#include "AutumnTheme.hpp"
+#include "../Renderer2d.h"
+
+void AutumnTheme::load(Renderer2d* renderer) {
+ renderer->clearColor = Vector4(252, 210, 153, 255).toNormalizedColor();
+ auto lr = tree.load(renderer);
+ leafParticles.load(renderer, &lr);
+}
+
+void AutumnTheme::update(f32 dtSeconds) {
+ tree.update(dtSeconds);
+ leafParticles.update(dtSeconds);
+}
+
+void AutumnTheme::render(Renderer2d* renderer) {
+ tree.render(renderer);
+ leafParticles.render(renderer);
+}
+
+void AutumnTheme::unload() {
+ tree.unload();
+ leafParticles.unload();
+} \ No newline at end of file
diff --git a/themes/src/autumn/AutumnTheme.hpp b/themes/src/autumn/AutumnTheme.hpp
new file mode 100644
index 0000000..18da959
--- /dev/null
+++ b/themes/src/autumn/AutumnTheme.hpp
@@ -0,0 +1,20 @@
+#ifndef AUTUMN_THEME_HPP
+#define AUTUMN_THEME_HPP
+
+#include "TreeShape.h"
+#include "LeafParticleRender.h"
+#include "../types.h"
+
+struct Renderer2d;
+
+struct AutumnTheme {
+ TreeShape tree;
+ LeafParticleRender leafParticles;
+
+ void load(Renderer2d* renderer);
+ void update(f32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+};
+
+#endif \ No newline at end of file
diff --git a/themes/src/LeafParticleRender.cpp b/themes/src/autumn/LeafParticleRender.cpp
index 0c6fbca..fee3df2 100644
--- a/themes/src/LeafParticleRender.cpp
+++ b/themes/src/autumn/LeafParticleRender.cpp
@@ -1,8 +1,8 @@
#include "LeafParticleRender.h"
-#include "Renderer2d.h"
-#include "mathlib.h"
+#include "../Renderer2d.h"
+#include "../mathlib.h"
#include "TreeShape.h"
-#include "types.h"
+#include "../types.h"
#include <math.h>
const i32 verticesPerLeaf = 6;
diff --git a/themes/src/LeafParticleRender.h b/themes/src/autumn/LeafParticleRender.h
index 713d9f6..f6efe1f 100644
--- a/themes/src/LeafParticleRender.h
+++ b/themes/src/autumn/LeafParticleRender.h
@@ -1,6 +1,6 @@
-#include "Renderer2d.h"
-#include "mathlib.h"
-#include "types.h"
+#include "../Renderer2d.h"
+#include "../mathlib.h"
+#include "../types.h"
struct TreeShapeLoadResult;
diff --git a/themes/src/TreeShape.cpp b/themes/src/autumn/TreeShape.cpp
index a3ae8f7..9738fd5 100644
--- a/themes/src/TreeShape.cpp
+++ b/themes/src/autumn/TreeShape.cpp
@@ -1,5 +1,5 @@
#include "TreeShape.h"
-#include "mathlib.h"
+#include "../mathlib.h"
#include <cstdio>
#include <cstdlib>
#include <cfloat>
diff --git a/themes/src/TreeShape.h b/themes/src/autumn/TreeShape.h
index 32b00d3..fc0d11e 100644
--- a/themes/src/TreeShape.h
+++ b/themes/src/autumn/TreeShape.h
@@ -1,6 +1,6 @@
-#include "Renderer2d.h"
-#include "types.h"
-#include "mathlib.h"
+#include "../Renderer2d.h"
+#include "../types.h"
+#include "../mathlib.h"
struct TreeLoadData {
f32 trunkHeight = 96.f; // Height of the trunk start
diff --git a/themes/src/main.cpp b/themes/src/main.cpp
index f8771d4..4e1a646 100644
--- a/themes/src/main.cpp
+++ b/themes/src/main.cpp
@@ -1,13 +1,12 @@
#include "WebglContext.h"
#include "MainLoop.h"
#include "Renderer2d.h"
-#include "Renderer3d.h"
#include "mathlib.h"
#include "types.h"
-#include "TreeShape.h"
-#include "SummerTheme.h"
-#include "LeafParticleRender.h"
-#include "Snowflake.h"
+#include "summer/SummerTheme.h"
+#include "autumn/AutumnTheme.hpp"
+#include "spring/SpringTheme.hpp"
+#include "winter/WinterTheme.hpp"
#include <cstdio>
#include <emscripten/fetch.h>
@@ -20,55 +19,6 @@ enum Theme {
Summer
};
-struct AutumnTheme {
- TreeShape tree;
- LeafParticleRender leafParticles;
-
- void load(Renderer2d* renderer);
- void update(f32 dtSeconds);
- void render(Renderer2d* renderer);
- void unload();
-};
-
-struct WinterTheme {
- SnowflakeParticleRenderer spr;
-
- void load(Renderer2d* renderer);
- void update(f32 dtSeconds);
- void render(Renderer2d* renderer);
- void unload();
-};
-
-enum class BunnyAnimationState {
- Loading = 0,
- Loaded,
- PreHop,
- Hopping,
- Idle
-};
-
-struct SpringTheme {
- BunnyAnimationState state;
- f32 bunnySpeed = 5.f;
- Vector3 bunnyPosition = Vector3(0, 0, 0);
- Vector3 bunnyTarget = Vector3(0, 0, 0);
- Vector3 hopIncrement = Vector3(0, 0, 0);
-
- f32 numHops = 0;
- f32 hopCount = 0;
- f32 bunnyHopAnimationTimer = 0.f;
- f32 stateTimer = 0.f;
- f32 bunnyRotation = 0.f;
- f32 targetRotation = 0.f;
-
- Mesh3d bunnyMesh;
-
- void load(Renderer3D* renderer);
- void update(f32 dtSeconds);
- void render(Renderer3D* renderer);
- void unload();
-};
-
void load(Theme theme);
void unload();
void update(f32 dtSeconds, void* userData);
@@ -80,7 +30,6 @@ EM_BOOL selectSummer(int eventType, const EmscriptenMouseEvent* mouseEvent, void
WebglContext context;
Renderer2d renderer2d;
-Renderer3D renderer3d;
MainLoop mainLoop;
Theme activeTheme = Theme::Default;
AutumnTheme autumnTheme;
@@ -120,10 +69,10 @@ void load(Theme theme) {
renderer2d.load(&context);
winterTheme.load(&renderer2d);
break;
- case Theme::Spring:
- renderer3d.load(&context);
- springTheme.load(&renderer3d);
+ case Theme::Spring: {
+ springTheme.load(&context);
break;
+ }
case Theme::Summer:
renderer2d.load(&context);
summerTheme.load(&renderer2d);
@@ -163,8 +112,7 @@ void update(f32 dtSeconds, void* userData) {
winterTheme.render(&renderer2d);
break;
case Theme::Spring:
- renderer3d.render();
- springTheme.render(&renderer3d);
+ springTheme.render();
break;
case Theme::Summer:
renderer2d.render();
@@ -197,7 +145,6 @@ void unload() {
if (mainLoop.isRunning) {
mainLoop.stop();
renderer2d.unload();
- renderer3d.unload();
}
}
@@ -230,216 +177,4 @@ EM_BOOL selectSummer(int eventType, const EmscriptenMouseEvent* mouseEvent, void
printf("Summer theme selected\n");
load(Theme::Summer);
return true;
-}
-
-// -- Autumn theme
-void AutumnTheme::load(Renderer2d* renderer) {
- renderer->clearColor = Vector4(252, 210, 153, 255).toNormalizedColor();
- auto lr = tree.load(renderer);
- leafParticles.load(renderer, &lr);
-}
-
-void AutumnTheme::update(f32 dtSeconds) {
- tree.update(dtSeconds);
- leafParticles.update(dtSeconds);
-}
-
-void AutumnTheme::render(Renderer2d* renderer) {
- tree.render(renderer);
- leafParticles.render(renderer);
-}
-
-void AutumnTheme::unload() {
- tree.unload();
- leafParticles.unload();
-}
-
-// -- Winter theme
-void WinterTheme::load(Renderer2d* renderer) {
- renderer->clearColor = Vector4(200, 229, 239, 255).toNormalizedColor();
- SnowflakeLoadParameters lp;
- spr.load(lp, renderer);
-}
-
-void WinterTheme::update(f32 dtSeconds) {
- spr.update(dtSeconds);
-}
-
-void WinterTheme::render(Renderer2d* renderer) {
- spr.render(renderer);
-}
-
-void WinterTheme::unload() {
- spr.unload();
-}
-
-// -- Spring theme
-void onBunnySuccess(emscripten_fetch_t *fetch) {
- springTheme.state = BunnyAnimationState::Loaded;
- printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
- const i32 len = fetch->numBytes;
- springTheme.bunnyMesh = Mesh3d_fromObj(&renderer3d, fetch->data, len);
- // The data is now available at fetch->data[0] through fetch->data[fetch->numBytes-1];
- emscripten_fetch_close(fetch); // Free data associated with the fetch.
-}
-
-void onBunnyFail(emscripten_fetch_t *fetch) {
- printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status);
- emscripten_fetch_close(fetch); // Also free data on failure.
-}
-
-void SpringTheme::load(Renderer3D* renderer) {
- springTheme.state = BunnyAnimationState::Loading;
- renderer->clearColor = Vector4(160, 231, 160, 255.f).toNormalizedColor();
-
- emscripten_fetch_attr_t attr;
- emscripten_fetch_attr_init(&attr);
- strcpy(attr.requestMethod, "GET");
- attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
- attr.onsuccess = onBunnySuccess;
- attr.onerror = onBunnyFail;
- emscripten_fetch(&attr, "themes/resources/bunny.obj");
-}
-
-inline Vector3 bunnyLerp(Vector3& start, Vector3& target, f32 t) {
- t = 3 * t *t - 2 * t * t * t;
- return start + ((target - start) * t);
-}
-
-inline f32 verticalHopLerp(f32 start, f32 target, f32 t) {
- f32 ogt = t;
- t = 3 * t *t - 2 * t * t * t;
- if (ogt >= 0.5f) t = 1.f - t;
- return start + ((target - start) * t);
-}
-
-inline f32 rotationLerp(f32 start, f32 target, f32 t) {
- return start + ((target - start) * t);
-}
-
-void SpringTheme::update(f32 dtSeconds) {
- switch (state) {
- case BunnyAnimationState::Loading: return;
- case BunnyAnimationState::Loaded:
- state = BunnyAnimationState::Idle;
- stateTimer = 0.f;
- bunnyHopAnimationTimer = 0.f;
- break;
- case BunnyAnimationState::Idle: {
- bunnyHopAnimationTimer += dtSeconds;
- const f32 HOP_FREQUENCY = 6.f;
-
- if (bunnyHopAnimationTimer > stateTimer) {
- state = BunnyAnimationState::PreHop;
- f32 xDir = 1;
- f32 yDir = 1;
- if (bunnyTarget.x > 0) xDir = -1;
- if (bunnyTarget.z > 0) yDir = -1;
- bunnyTarget = bunnyPosition + Vector3(randomFloatBetween(0, xDir * 25), 0, randomFloatBetween(0, yDir * 25));
- auto direction = (bunnyTarget - bunnyPosition);
- auto distance = direction.length();
- direction = direction.normalize();
- numHops = ceil(distance / HOP_FREQUENCY);
- hopCount = 0;
-
- targetRotation = PI - atan2(direction.y, direction.x);
- stateTimer = ((bunnyTarget - bunnyPosition).length() / bunnySpeed) / numHops;
- bunnyHopAnimationTimer = 0.f;
- hopIncrement = (bunnyTarget - bunnyPosition) / numHops;
- }
- break;
- }
- case BunnyAnimationState::PreHop: {
- const f32 ROTATION_TIME = 0.5f;
- bunnyHopAnimationTimer += dtSeconds;
- f32 current = bunnyRotation + (targetRotation - bunnyRotation) * (bunnyHopAnimationTimer / ROTATION_TIME);
- bunnyMesh.model = Mat4x4().rotate(0, current, 0).translate(bunnyPosition);
-
- if (bunnyHopAnimationTimer > ROTATION_TIME) {
- bunnyRotation = targetRotation;
- bunnyHopAnimationTimer = 0;
- state = BunnyAnimationState::Hopping;
- }
- break;
- }
- case BunnyAnimationState::Hopping: {
- bunnyHopAnimationTimer += dtSeconds;
- f32 t = bunnyHopAnimationTimer / stateTimer;
-
- Vector3 nextPosition = bunnyPosition + hopIncrement;
- auto renderPos = bunnyLerp(bunnyPosition, nextPosition, t);
- if ((renderPos - nextPosition).length() < 0.01f) {
- hopCount += 1;
- bunnyHopAnimationTimer = 0.f;
- bunnyPosition = nextPosition;
- }
-
- renderPos.y = verticalHopLerp(0.f, 4.f, t);
-
- const f32 RMAX = PI / 16.f;
- f32 zRotation = 0;
- f32 start = 0.f;
- f32 end = PI / 8.f;
- f32 startTime = 0.f;
- f32 endTime = 0.f;
- bool disableRot = false;
-
- if (t >= 0.9f) {
- disableRot = true;
- }
- else if (t >= 0.7f) {
- start = -RMAX;
- end = 0.f;
- startTime = 0.7f;
- endTime = 0.9f;
- }
- else if (t >= 0.50f) {
- start = 0.f;
- end = -RMAX;
- startTime = 0.50f;
- endTime = 0.70f;
- }
- else if (t >= 0.40f) {
- disableRot = true;
- }
- else if (t >= 0.20f) {
- start = RMAX;
- end = 0.f;
- startTime = 0.20f;
- endTime = 0.40f;
- }
- else {
- start = 0.f;
- end = RMAX;
- startTime = 0.f;
- endTime = 0.20f;
- }
-
-
- if (!disableRot) {
- f32 totalTime = endTime - startTime;
- zRotation = rotationLerp(start, end, (totalTime - (endTime - t)) / totalTime);
- }
-
- bunnyMesh.model = Mat4x4().getZRotationMatrix(zRotation).rotate(0, bunnyRotation, 0).translate(renderPos);
- if (hopCount == numHops) {
- bunnyPosition = bunnyTarget;
- bunnyHopAnimationTimer = 0.f;
- state = BunnyAnimationState::Idle;
- stateTimer = randomFloatBetween(0.5f, 1.f);
- }
- break;
- }
- }
-}
-
-void SpringTheme::render(Renderer3D* renderer) {
- renderer->render();
- if (state != BunnyAnimationState::Loading) {
- bunnyMesh.render(renderer);
- }
-}
-
-void SpringTheme::unload() {
- bunnyMesh.unload();
-}
+} \ No newline at end of file
diff --git a/themes/src/shader_fetcher.cpp b/themes/src/shader_fetcher.cpp
new file mode 100644
index 0000000..19ef983
--- /dev/null
+++ b/themes/src/shader_fetcher.cpp
@@ -0,0 +1,69 @@
+#include "shader_fetcher.hpp"
+#include "types.h"
+#include <cstdio>
+#include <emscripten/fetch.h>
+
+struct FetchtimeData {
+ ShaderFetchResult result;
+ ShaderFetchPaths paths_data;
+ void (*cb)(ShaderFetchResult*);
+};
+
+void on_failure(emscripten_fetch_t *fetch) {
+ FetchtimeData* ftd = (FetchtimeData*)fetch->userData;
+ printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status);
+ emscripten_fetch_close(fetch); // Also free data on failure.
+ ftd->cb(nullptr);
+}
+
+void on_fragment_shader(emscripten_fetch_t *fetch) {
+ FetchtimeData* ftd = (FetchtimeData*)fetch->userData;
+ printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
+ const i32 len = fetch->numBytes;
+ char* data = (char*)fetch->data;
+ data[len - 1] = '\0';
+ ftd->result.fragment = data;
+ emscripten_fetch_close(fetch); // Free data associated with the fetch.
+
+ ftd->cb(&ftd->result);
+ delete ftd;
+}
+
+void on_vertex_shader(emscripten_fetch_t *fetch) {
+
+ FetchtimeData* ftd = (FetchtimeData*)fetch->userData;
+ printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
+ const i32 len = fetch->numBytes;
+ char* data = (char*)fetch->data;
+ data[len - 1] = '\0';
+
+ ftd->result.vertex = data;
+ emscripten_fetch_close(fetch); // Free data associated with the fetch.
+
+ // Fetch fragment shader next
+ emscripten_fetch_attr_t attr;
+ emscripten_fetch_attr_init(&attr);
+ strcpy(attr.requestMethod, "GET");
+ attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
+ attr.onsuccess = on_fragment_shader;
+ attr.onerror = on_failure;
+ auto* request = emscripten_fetch(&attr, ftd->paths_data.fragment);
+ request->userData = ftd;
+}
+
+void fetch_shader(ShaderFetchPaths paths, void (*cb)(ShaderFetchResult*), void* user_data) {
+ FetchtimeData* ftd = new FetchtimeData();
+ ftd->cb = cb;
+ ftd->paths_data = paths;
+ ftd->result.user_data = user_data;
+
+ // Fetch vertex shader
+ emscripten_fetch_attr_t attr;
+ emscripten_fetch_attr_init(&attr);
+ strcpy(attr.requestMethod, "GET");
+ attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
+ attr.onsuccess = on_vertex_shader;
+ attr.onerror = on_failure;
+ auto* request = emscripten_fetch(&attr, paths.vertex);
+ request->userData = ftd;
+} \ No newline at end of file
diff --git a/themes/src/shader_fetcher.hpp b/themes/src/shader_fetcher.hpp
new file mode 100644
index 0000000..aef25b4
--- /dev/null
+++ b/themes/src/shader_fetcher.hpp
@@ -0,0 +1,19 @@
+#ifndef SHADER_FETCHER_HPP
+#define SHADER_FETCHER_HPP
+
+#include <string>
+
+struct ShaderFetchPaths {
+ const char* vertex;
+ const char* fragment;
+};
+
+struct ShaderFetchResult {
+ std::string vertex;
+ std::string fragment;
+ void* user_data;
+};
+
+void fetch_shader(ShaderFetchPaths, void (*cb)(ShaderFetchResult*), void* user_data = nullptr);
+
+#endif \ No newline at end of file
diff --git a/themes/src/shaders/renderer2d.frag b/themes/src/shaders/renderer2d.frag
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/themes/src/shaders/renderer2d.frag
diff --git a/themes/src/shaders/renderer2d.vert b/themes/src/shaders/renderer2d.vert
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/themes/src/shaders/renderer2d.vert
diff --git a/themes/src/shaders/renderer3d.frag b/themes/src/shaders/renderer3d.frag
new file mode 100644
index 0000000..2f50347
--- /dev/null
+++ b/themes/src/shaders/renderer3d.frag
@@ -0,0 +1,7 @@
+varying lowp vec4 VertexColor;
+varying lowp vec4 VertexNormal;
+
+void main() {
+ const lowp vec3 lightDirection = vec3(0.0, 1.0, 0.0);
+ gl_FragColor = vec4(VertexColor.xyz * dot(VertexNormal.xyz, lightDirection), 1);
+}
diff --git a/themes/src/shaders/renderer3d.vert b/themes/src/shaders/renderer3d.vert
new file mode 100644
index 0000000..026285f
--- /dev/null
+++ b/themes/src/shaders/renderer3d.vert
@@ -0,0 +1,15 @@
+attribute vec4 position;
+attribute vec4 color;
+attribute vec4 normal;
+uniform mat4 projection;
+uniform mat4 view;
+uniform mat4 model;
+varying lowp vec4 VertexColor;
+varying lowp vec4 VertexNormal;
+
+void main() {
+ vec4 fragmentPosition = projection * view * model * position;
+ gl_Position = fragmentPosition;
+ VertexColor = color;
+ VertexNormal = normal;
+}
diff --git a/themes/src/spring/GrassRenderer.cpp b/themes/src/spring/GrassRenderer.cpp
new file mode 100644
index 0000000..b69d111
--- /dev/null
+++ b/themes/src/spring/GrassRenderer.cpp
@@ -0,0 +1,29 @@
+#include "GrassRenderer.hpp"
+#include "Renderer3d.h"
+
+void GrassRenderer::load(GrassRendererLoadData params, Renderer3d* renderer) {
+ const f32 COLUMN_INCREMENT = GRASS_BLADES_PER_COL / params.area.x;
+ const f32 ROW_INCREMENT = GRASS_BLADES_PER_ROW / params.area.y;
+ for (i32 r = 0; r < GRASS_BLADES_PER_ROW; r++) {
+ i32 indexOffset = r * GRASS_BLADES_PER_ROW;
+ f32 y = ROW_INCREMENT * r;
+ for (i32 c = 0; c < GRASS_BLADES_PER_COL; c++) {
+ f32 x = COLUMN_INCREMENT * c;
+ i32 index = indexOffset + c;
+ grassBlades[index].position = Vector3(x, y, 0);
+ grassBlades[index].top_offset = Vector2(0, 0);
+ }
+ }
+}
+
+void GrassRenderer::update(f32 seconds) {
+
+}
+
+void GrassRenderer::render(Renderer3d* renderer) {
+
+}
+
+void GrassRenderer::unload() {
+
+}
diff --git a/themes/src/spring/GrassRenderer.hpp b/themes/src/spring/GrassRenderer.hpp
new file mode 100644
index 0000000..8c96724
--- /dev/null
+++ b/themes/src/spring/GrassRenderer.hpp
@@ -0,0 +1,33 @@
+#ifndef GRASS_RENDERER_HPP
+#define GRASS_RENDERER_HPP
+
+#include "Renderer3d.h"
+#include "mathlib.h"
+#include "types.h"
+
+const i32 GRASS_BLADES_PER_ROW = 24;
+const i32 GRASS_BLADES_PER_COL = 24;
+const i32 NUM_GRASS_BLADES = GRASS_BLADES_PER_ROW * GRASS_BLADES_PER_COL;
+
+struct GrassRendererLoadData {
+ Vector2 origin = Vector2(0, 0);
+ Vector2 area = Vector2(480, 480);
+ f32 grassHeight = 12.f;
+};
+
+struct GrassUpdateData {
+ Vector3 position;
+ Vector2 top_offset;
+};
+
+struct GrassRenderer {
+
+ GrassUpdateData grassBlades[NUM_GRASS_BLADES];
+
+ void load(GrassRendererLoadData params, Renderer3d* renderer);
+ void update(f32 dtSeconds);
+ void render(Renderer3d* renderer);
+ void unload();
+};
+
+#endif
diff --git a/themes/src/spring/SpringTheme.cpp b/themes/src/spring/SpringTheme.cpp
new file mode 100644
index 0000000..abe8c6e
--- /dev/null
+++ b/themes/src/spring/SpringTheme.cpp
@@ -0,0 +1,198 @@
+#include "SpringTheme.hpp"
+#include "../Renderer3d.h"
+#include "../shader_fetcher.hpp"
+#include <cstdio>
+#include <emscripten/fetch.h>
+
+void onBunnySuccess(emscripten_fetch_t *fetch) {
+ SpringTheme* springTheme = (SpringTheme*)fetch->userData;
+ springTheme->state = SpringThemeState::LoadedBunny;
+ printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);
+ const i32 len = fetch->numBytes;
+ springTheme->bunnyMesh = Mesh3d_fromObj(&springTheme->renderer, fetch->data, len);
+ // The data is now available at fetch->data[0] through fetch->data[fetch->numBytes-1];
+ emscripten_fetch_close(fetch); // Free data associated with the fetch.
+}
+
+void onBunnyFail(emscripten_fetch_t *fetch) {
+ printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status);
+ emscripten_fetch_close(fetch); // Also free data on failure.
+}
+
+inline void fetch_bunny(SpringTheme* theme) {
+ emscripten_fetch_attr_t attr;
+ emscripten_fetch_attr_init(&attr);
+ strcpy(attr.requestMethod, "GET");
+ attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
+ attr.onsuccess = onBunnySuccess;
+ attr.onerror = onBunnyFail;
+ auto* bunny_fetch = emscripten_fetch(&attr, "themes/resources/bunny.obj");
+ bunny_fetch->userData = theme;
+}
+
+inline void on_shaders_loader(ShaderFetchResult* result) {
+ SpringTheme* theme = (SpringTheme*)result->user_data;
+ theme->renderer.load(theme->renderer.context, result->vertex.c_str(), result->fragment.c_str());
+ theme->state = SpringThemeState::LoadedShader;
+ fetch_bunny(theme);
+}
+
+void SpringTheme::load(WebglContext* context) {
+ state = SpringThemeState::Loading;
+ renderer.context = context;
+ renderer.clearColor = Vector4(160, 231, 160, 255.f).toNormalizedColor();
+
+ fetch_shader(
+ {
+ "themes/src/shaders/renderer3d.vert",
+ "themes/src/shaders/renderer3d.frag"
+ },
+ on_shaders_loader,
+ this
+ );
+}
+
+inline Vector3 bunnyLerp(Vector3& start, Vector3& target, f32 t) {
+ t = 3 * t *t - 2 * t * t * t;
+ return start + ((target - start) * t);
+}
+
+inline f32 verticalHopLerp(f32 start, f32 target, f32 t) {
+ f32 ogt = t;
+ t = 3 * t *t - 2 * t * t * t;
+ if (ogt >= 0.5f) t = 1.f - t;
+ return start + ((target - start) * t);
+}
+
+inline f32 rotationLerp(f32 start, f32 target, f32 t) {
+ return start + ((target - start) * t);
+}
+
+void SpringTheme::update(f32 dtSeconds) {
+ switch (state) {
+ case SpringThemeState::Loading: return;
+ case SpringThemeState::LoadedShader: return;
+ case SpringThemeState::LoadedBunny:
+ state = SpringThemeState::Idle;
+ stateTimer = 0.f;
+ bunnyHopAnimationTimer = 0.f;
+ break;
+ case SpringThemeState::Idle: {
+ bunnyHopAnimationTimer += dtSeconds;
+ const f32 HOP_FREQUENCY = 6.f;
+
+ if (bunnyHopAnimationTimer > stateTimer) {
+ state = SpringThemeState::PreHop;
+ f32 xDir = 1;
+ f32 yDir = 1;
+ if (bunnyTarget.x > 0) xDir = -1;
+ if (bunnyTarget.z > 0) yDir = -1;
+ bunnyTarget = bunnyPosition + Vector3(randomFloatBetween(0, xDir * 25), 0, randomFloatBetween(0, yDir * 25));
+ auto direction = (bunnyTarget - bunnyPosition);
+ auto distance = direction.length();
+ direction = direction.normalize();
+ numHops = ceil(distance / HOP_FREQUENCY);
+ hopCount = 0;
+
+ targetRotation = PI - atan2(direction.y, direction.x);
+ stateTimer = ((bunnyTarget - bunnyPosition).length() / bunnySpeed) / numHops;
+ bunnyHopAnimationTimer = 0.f;
+ hopIncrement = (bunnyTarget - bunnyPosition) / numHops;
+ }
+ break;
+ }
+ case SpringThemeState::PreHop: {
+ const f32 ROTATION_TIME = 0.5f;
+ bunnyHopAnimationTimer += dtSeconds;
+ f32 current = bunnyRotation + (targetRotation - bunnyRotation) * (bunnyHopAnimationTimer / ROTATION_TIME);
+ bunnyMesh.model = Mat4x4().rotate(0, current, 0).translate(bunnyPosition);
+
+ if (bunnyHopAnimationTimer > ROTATION_TIME) {
+ bunnyRotation = targetRotation;
+ bunnyHopAnimationTimer = 0;
+ state = SpringThemeState::Hopping;
+ }
+ break;
+ }
+ case SpringThemeState::Hopping: {
+ bunnyHopAnimationTimer += dtSeconds;
+ f32 t = bunnyHopAnimationTimer / stateTimer;
+
+ Vector3 nextPosition = bunnyPosition + hopIncrement;
+ auto renderPos = bunnyLerp(bunnyPosition, nextPosition, t);
+ if ((renderPos - nextPosition).length() < 0.01f) {
+ hopCount += 1;
+ bunnyHopAnimationTimer = 0.f;
+ bunnyPosition = nextPosition;
+ }
+
+ renderPos.y = verticalHopLerp(0.f, 4.f, t);
+
+ const f32 RMAX = PI / 16.f;
+ f32 zRotation = 0;
+ f32 start = 0.f;
+ f32 end = PI / 8.f;
+ f32 startTime = 0.f;
+ f32 endTime = 0.f;
+ bool disableRot = false;
+
+ if (t >= 0.9f) {
+ disableRot = true;
+ }
+ else if (t >= 0.7f) {
+ start = -RMAX;
+ end = 0.f;
+ startTime = 0.7f;
+ endTime = 0.9f;
+ }
+ else if (t >= 0.50f) {
+ start = 0.f;
+ end = -RMAX;
+ startTime = 0.50f;
+ endTime = 0.70f;
+ }
+ else if (t >= 0.40f) {
+ disableRot = true;
+ }
+ else if (t >= 0.20f) {
+ start = RMAX;
+ end = 0.f;
+ startTime = 0.20f;
+ endTime = 0.40f;
+ }
+ else {
+ start = 0.f;
+ end = RMAX;
+ startTime = 0.f;
+ endTime = 0.20f;
+ }
+
+
+ if (!disableRot) {
+ f32 totalTime = endTime - startTime;
+ zRotation = rotationLerp(start, end, (totalTime - (endTime - t)) / totalTime);
+ }
+
+ bunnyMesh.model = Mat4x4().getZRotationMatrix(zRotation).rotate(0, bunnyRotation, 0).translate(renderPos);
+ if (hopCount == numHops) {
+ bunnyPosition = bunnyTarget;
+ bunnyHopAnimationTimer = 0.f;
+ state = SpringThemeState::Idle;
+ stateTimer = randomFloatBetween(0.5f, 1.f);
+ }
+ break;
+ }
+ }
+}
+
+void SpringTheme::render() {
+ renderer.render();
+ if (state != SpringThemeState::Loading) {
+ bunnyMesh.render(&renderer);
+ }
+}
+
+void SpringTheme::unload() {
+ renderer.unload();
+ bunnyMesh.unload();
+}
diff --git a/themes/src/spring/SpringTheme.hpp b/themes/src/spring/SpringTheme.hpp
new file mode 100644
index 0000000..0866921
--- /dev/null
+++ b/themes/src/spring/SpringTheme.hpp
@@ -0,0 +1,41 @@
+#ifndef SPRING_THEME_HPP
+#define SPRING_THEME_HPP
+
+#include "../mathlib.h"
+#include "../types.h"
+#include "../Renderer3d.h"
+
+
+enum class SpringThemeState {
+ Loading = 0,
+ LoadedShader,
+ LoadedBunny,
+ PreHop,
+ Hopping,
+ Idle
+};
+
+struct SpringTheme {
+ Renderer3d renderer;
+ SpringThemeState state;
+ f32 bunnySpeed = 5.f;
+ Vector3 bunnyPosition = Vector3(0, 0, 0);
+ Vector3 bunnyTarget = Vector3(0, 0, 0);
+ Vector3 hopIncrement = Vector3(0, 0, 0);
+
+ f32 numHops = 0;
+ f32 hopCount = 0;
+ f32 bunnyHopAnimationTimer = 0.f;
+ f32 stateTimer = 0.f;
+ f32 bunnyRotation = 0.f;
+ f32 targetRotation = 0.f;
+
+ Mesh3d bunnyMesh;
+
+ void load(WebglContext*);
+ void update(f32 dtSeconds);
+ void render();
+ void unload();
+};
+
+#endif \ No newline at end of file
diff --git a/themes/src/SummerTheme.cpp b/themes/src/summer/SummerTheme.cpp
index 20bb310..406cd22 100644
--- a/themes/src/SummerTheme.cpp
+++ b/themes/src/summer/SummerTheme.cpp
@@ -1,7 +1,7 @@
#include "SummerTheme.h"
-#include "Renderer2d.h"
-#include "list.h"
-#include "mathlib.h"
+#include "../Renderer2d.h"
+#include "../list.h"
+#include "../mathlib.h"
#include <vector>
void SummerTheme::load(Renderer2d* renderer) {
diff --git a/themes/src/SummerTheme.h b/themes/src/summer/SummerTheme.h
index 1d9093a..4a9f76b 100644
--- a/themes/src/SummerTheme.h
+++ b/themes/src/summer/SummerTheme.h
@@ -1,6 +1,6 @@
#pragma once
-#include "types.h"
-#include "Renderer2d.h"
+#include "../types.h"
+#include "../Renderer2d.h"
#include <vector>
struct Sun {
diff --git a/themes/src/Snowflake.cpp b/themes/src/winter/Snowflake.cpp
index 452a716..57f1a8f 100644
--- a/themes/src/Snowflake.cpp
+++ b/themes/src/winter/Snowflake.cpp
@@ -1,7 +1,7 @@
#include "Snowflake.h"
-#include "Renderer2d.h"
-#include "mathlib.h"
-#include "list.h"
+#include "../Renderer2d.h"
+#include "../mathlib.h"
+#include "../list.h"
#include <cstdio>
/*
@@ -142,7 +142,7 @@ inline void resetFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData*
inline void updateFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud, i32 s, f32 dtSeconds) {
ud->velocity = ud->velocity + Vector2(0, -(GRAVITY * dtSeconds));
- if (addWind) ud->velocity += renderer->windSpeed;
+ //if (addWind) ud->velocity += renderer->windSpeed;
ud->position += ud->velocity * dtSeconds;
ud->rotation += ud->rotateVelocity * dtSeconds;
diff --git a/themes/src/Snowflake.h b/themes/src/winter/Snowflake.h
index c147469..ad027f6 100644
--- a/themes/src/Snowflake.h
+++ b/themes/src/winter/Snowflake.h
@@ -1,9 +1,9 @@
#ifndef SNOWFLAKE_H
#define SNOWFLAKE_H
-#include "types.h"
-#include "mathlib.h"
-#include "list.h"
+#include "../types.h"
+#include "../mathlib.h"
+#include "../list.h"
#include "Windfield.hpp"
struct Renderer2d;
@@ -31,7 +31,7 @@ struct SnowflakeParticleRenderer {
f32 windIntervalSeconds = 1.5;
i32 numSnowflakes = 0;
f32 timeUntilNextWindSeconds = 0;
- WindField wind;
+ WindField<100, 100, 10> wind;
SnowflakeUpdateData* updateData;
u32 vao;
diff --git a/themes/src/Windfield.cpp b/themes/src/winter/Windfield.cpp
index 3a7563f..88fb74b 100644
--- a/themes/src/Windfield.cpp
+++ b/themes/src/winter/Windfield.cpp
@@ -2,7 +2,7 @@
template <i32 Width, i32 Height, i32 CellDimension>
-void WindField<Width, Height, CellDimension>::load(f32 ttl, Vector2 origin) {
+void WindField<Width, Height, CellDimension>::load(f32 cellSizePixels, i32 fieldWithCells, i32 fieldHeightCells, f32 ttl, Vector2 origin) {
this->ttl = ttl;
this->origin = origin;
this->end = this->origin + Vector2(Width * CellDimension, Height * CellDimension);
@@ -21,7 +21,7 @@ Vector2 WindField<Width, Height, CellDimension>::getWindFactor(Vector2& v) {
Vector2 positionInField = v - this->origin;
i32 cellX = static_cast<i32>(Width / positionInField.x);
i32 cellY = static_cast<i32>(Height / positionInField.y);
- return field[cellX, cellY];
+ return field[cellX][cellY];
}
return Vector2();
diff --git a/themes/src/Windfield.hpp b/themes/src/winter/Windfield.hpp
index 5935c5d..5bf0c38 100644
--- a/themes/src/Windfield.hpp
+++ b/themes/src/winter/Windfield.hpp
@@ -1,13 +1,14 @@
#ifndef WIND_FIELD_HPP
#define WIND_FIELD_HPP
-#include "types.h"
-#include "mathlib.h"
+#include "../types.h"
+#include "../mathlib.h"
/**
A Windfield represents a field of vectors in a rectangular region.
The Width and Height are given in units of CellDimenions. The CellDimension
is given in pixels.
*/
+template <i32 Width, i32 Height, i32 CellDimension>
struct WindField {
f32 ttl = 0.f;
Vector2 origin;
diff --git a/themes/src/winter/WinterTheme.cpp b/themes/src/winter/WinterTheme.cpp
new file mode 100644
index 0000000..2686988
--- /dev/null
+++ b/themes/src/winter/WinterTheme.cpp
@@ -0,0 +1,20 @@
+#include "WinterTheme.hpp"
+#include "../Renderer2d.h"
+
+void WinterTheme::load(Renderer2d* renderer) {
+ renderer->clearColor = Vector4(200, 229, 239, 255).toNormalizedColor();
+ SnowflakeLoadParameters lp;
+ spr.load(lp, renderer);
+}
+
+void WinterTheme::update(f32 dtSeconds) {
+ spr.update(dtSeconds);
+}
+
+void WinterTheme::render(Renderer2d* renderer) {
+ spr.render(renderer);
+}
+
+void WinterTheme::unload() {
+ spr.unload();
+}
diff --git a/themes/src/winter/WinterTheme.hpp b/themes/src/winter/WinterTheme.hpp
new file mode 100644
index 0000000..5b8cc95
--- /dev/null
+++ b/themes/src/winter/WinterTheme.hpp
@@ -0,0 +1,18 @@
+#ifndef WINTER_THEME_HPP
+#define WINTER_THEME_HPP
+
+#include "Snowflake.h"
+#include "../types.h"
+
+struct Renderer2d;
+
+struct WinterTheme {
+ SnowflakeParticleRenderer spr;
+
+ void load(Renderer2d* renderer);
+ void update(f32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+};
+
+#endif \ No newline at end of file