From 584336fed2c7001366aac1875dd8a1f23ac500c7 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Fri, 26 Aug 2022 14:16:27 -0500 Subject: [PATCH] Initial commit --- C++/scripts/build.sh | 7 + C++/scripts/commit.sh | 20 + C++/scripts/filelist | 3 + C++/scripts/md5 | 3 + C++/scripts/web.sh | 17 + C++ProjectTemplate | Bin 0 -> 538960 bytes C++ProjectTemplate.html | 1 + C++ProjectTemplate.js | 1 + C++ProjectTemplate.wasm | Bin 0 -> 300705 bytes README.md | 33 + buildtemplate.html | 75 + main.cpp | 46 + pixelGameEngine.h | 6191 ++++++++++++++++++++++++++++++++++++++ sig | 9 + utils/.coauthors | 1 + utils/.updateDirectories | 5 + utils/define.sh | 26 + utils/filelist | 5 + utils/main.sh | 28 + utils/md5 | 4 + utils/search.sh | 103 + 21 files changed, 6578 insertions(+) create mode 100755 C++/scripts/build.sh create mode 100755 C++/scripts/commit.sh create mode 100644 C++/scripts/filelist create mode 100644 C++/scripts/md5 create mode 100755 C++/scripts/web.sh create mode 100755 C++ProjectTemplate create mode 100644 C++ProjectTemplate.html create mode 100644 C++ProjectTemplate.js create mode 100755 C++ProjectTemplate.wasm create mode 100644 README.md create mode 100644 buildtemplate.html create mode 100644 main.cpp create mode 100644 pixelGameEngine.h create mode 100755 sig create mode 100644 utils/.coauthors create mode 100644 utils/.updateDirectories create mode 100755 utils/define.sh create mode 100644 utils/filelist create mode 100644 utils/main.sh create mode 100644 utils/md5 create mode 100644 utils/search.sh diff --git a/C++/scripts/build.sh b/C++/scripts/build.sh new file mode 100755 index 0000000..0656a8a --- /dev/null +++ b/C++/scripts/build.sh @@ -0,0 +1,7 @@ +#Compiles the entire program then runs it, producing an executable. +#C++ +printf "Running program...\n\n\n" +if g++ $(find . -type f -name "*.cpp") ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then + ./${PROJECT_NAME} "$@" +fi +printf "\n\n" diff --git a/C++/scripts/commit.sh b/C++/scripts/commit.sh new file mode 100755 index 0000000..2693b46 --- /dev/null +++ b/C++/scripts/commit.sh @@ -0,0 +1,20 @@ +#Adds a commit message and pushes project to github repository. +#C++ +COMMIT_MESSAGE="$*" +FIRST_LINE=true +while IFS= read -r line +do +if [ "$FIRST_LINE" = true ]; then + COMMIT_MESSAGE+=" + +Co-authored-by: $line" +FIRST_LINE=false +else + COMMIT_MESSAGE+=" +Co-authored-by: $line" +fi +done < utils/.coauthors +git add -u +git add * +git commit -m "$COMMIT_MESSAGE" +git push \ No newline at end of file diff --git a/C++/scripts/filelist b/C++/scripts/filelist new file mode 100644 index 0000000..5f624fd --- /dev/null +++ b/C++/scripts/filelist @@ -0,0 +1,3 @@ +build.sh +commit.sh +web.sh diff --git a/C++/scripts/md5 b/C++/scripts/md5 new file mode 100644 index 0000000..3e77b3f --- /dev/null +++ b/C++/scripts/md5 @@ -0,0 +1,3 @@ +build.sh:530634457ea9041267c05d4ced95eee1 - +commit.sh:d03a46e721060c22ccb146e19d27e70a - +web.sh:241ce74055952325f82f009b494df250 - diff --git a/C++/scripts/web.sh b/C++/scripts/web.sh new file mode 100755 index 0000000..eef8c5b --- /dev/null +++ b/C++/scripts/web.sh @@ -0,0 +1,17 @@ +#Compiles emscripten instance of this project for the web. +#C++ +if [ -d "assets" ]; then + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp") -o ${PROJECT_NAME}.html -I pixelGameEngine.h --preload-file ./assets +else + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp") -o ${PROJECT_NAME}.html -I pixelGameEngine.h +fi + +cp buildtemplate.html ${PROJECT_NAME}.html +sed -i "s/_REPLACEME_/$PROJECT_NAME.js/" ${PROJECT_NAME}.html + +if [ "$1" == "headless" ]; then + echo "Running as headless web server" + emrun --no_browser ${PROJECT_NAME}.html +else + emrun --serve_after_close ${PROJECT_NAME}.html +fi diff --git a/C++ProjectTemplate b/C++ProjectTemplate new file mode 100755 index 0000000000000000000000000000000000000000..dc59e7a1cd0c8e4b938a5c15df93a4c59a04fde9 GIT binary patch literal 538960 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%0Dk=^y=-z9|tY* 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 Q{9hlIJ8dNcl3!c@1=sk>ivR!s literal 0 HcmV?d00001 diff --git a/C++ProjectTemplate.html b/C++ProjectTemplate.html new file mode 100644 index 0000000..9add032 --- /dev/null +++ b/C++ProjectTemplate.html @@ -0,0 +1 @@ +Emscripten-Generated Codeimage/svg+xml
    Downloading...
    Resize canvasLock/hide mouse pointer    
    \ No newline at end of file diff --git a/C++ProjectTemplate.js b/C++ProjectTemplate.js new file mode 100644 index 0000000..497bb5a --- /dev/null +++ b/C++ProjectTemplate.js @@ -0,0 +1 @@ +var Module=typeof Module!="undefined"?Module:{};var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;function logExceptionOnExit(e){if(e instanceof ExitStatus)return;let toLog=e;err("exiting due to exception: "+toLog)}var fs;var nodePath;var requireNodeFS;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}requireNodeFS=()=>{if(!nodePath){fs=require("fs");nodePath=require("path")}};read_=function shell_read(filename,binary){requireNodeFS();filename=nodePath["normalize"](filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror)=>{requireNodeFS();filename=nodePath["normalize"](filename);fs.readFile(filename,function(err,data){if(err)onerror(err);else onload(data.buffer)})};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!="undefined"){module["exports"]=Module}process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",function(reason){throw reason});quit_=(status,toThrow)=>{if(keepRuntimeAlive()){process["exitCode"]=status;throw toThrow}logExceptionOnExit(toThrow);process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var POINTER_SIZE=4;var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heapOrArray,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,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)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function keepRuntimeAlive(){return noExitRuntime}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){{if(Module["onAbort"]){Module["onAbort"](what)}}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="C++ProjectTemplate.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary(wasmBinaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(wasmBinaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={"env":asmLibraryArg,"wasi_snapshot_preview1":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["memory"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module["asm"]["__indirect_function_table"];addOnInit(Module["asm"]["__wasm_call_ctors"]);removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(function(instance){return instance}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;var ASM_CONSTS={38620:()=>{window.onunload=Module._olc_OnPageUnload},38664:($0,$1)=>{Module._olc_EmscriptenShellCss="width: 100%; height: 70vh; margin-left: auto; margin-right: auto;";Module._olc_WindowAspectRatio=$0/$1;Module.canvas.parentNode.addEventListener("resize",function(e){if(e.defaultPrevented){e.stopPropagation();return}var viewWidth=e.detail.width;var viewHeight=e.detail.width/Module._olc_WindowAspectRatio;if(viewHeight>e.detail.height){viewHeight=e.detail.height;viewWidth=e.detail.height*Module._olc_WindowAspectRatio}if(Module.canvas.parentNode.className=="emscripten_border")Module.canvas.parentNode.style.cssText=Module._olc_EmscriptenShellCss+" width: "+viewWidth.toString()+"px; height: "+viewHeight.toString()+"px;";Module.canvas.setAttribute("width",viewWidth);Module.canvas.setAttribute("height",viewHeight);if(document.fullscreenElement!=null){var top=(e.detail.height-viewHeight)/2;var left=(e.detail.width-viewWidth)/2;Module.canvas.style.position="fixed";Module.canvas.style.top=top.toString()+"px";Module.canvas.style.left=left.toString()+"px";Module.canvas.style.width="";Module.canvas.style.height=""}Module._olc_PGE_UpdateWindowSize(viewWidth,viewHeight);Module.canvas.focus();e.stopPropagation()});Module._olc_ResizeCanvas=function(){setTimeout(function(){if(Module.canvas.parentNode.className=="emscripten_border")Module.canvas.parentNode.style.cssText=Module._olc_EmscriptenShellCss;Module.canvas.style.cssText="width: 100%; height: 100%; outline: none;";var resizeEvent=new CustomEvent("resize",{detail:{width:Module.canvas.clientWidth,height:Module.canvas.clientHeight},bubbles:true,cancelable:true});Module.canvas.dispatchEvent(resizeEvent)},50)};document.body.style.cssText+=" overscroll-behavior-y: contain;";if(Module.canvas.parentNode.className=="emscripten_border"){document.body.style.margin="0";Module.canvas.parentNode.style.cssText=Module._olc_EmscriptenShellCss}Module._olc_ResizeCanvas();var resizeObserver=new ResizeObserver(function(entries){Module._olc_ResizeCanvas()}).observe(Module.canvas.parentNode);var mutationObserver=new MutationObserver(function(mutationsList,observer){for(var i=0;i0){callbacks.shift()(Module)}}function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function handleException(e){if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)}function jsStackTrace(){var error=new Error;if(!error.stack){try{throw new Error}catch(e){error=e}if(!error.stack){return"(no stack trace available)"}}return error.stack.toString()}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function ___cxa_allocate_exception(size){return _malloc(size+24)+24}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>2]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=prev-1;return prev===1};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw ptr}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:(l,r)=>{return PATH.normalize(l+"/"+r)}};function getRandomDevice(){if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){var randomBuffer=new Uint8Array(1);return()=>{crypto.getRandomValues(randomBuffer);return randomBuffer[0]}}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");return()=>crypto_module["randomBytes"](1)[0]}catch(e){}}return()=>abort("randomDevice")}var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var TTY={ttys:[],init:function(){},shutdown:function(){},register:function(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open:function(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.fsync(stream.tty)},fsync:function(stream){stream.tty.ops.fsync(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};function mmapAlloc(size){abort()}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr:function(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup:function(parent,name){throw FS.genericErrors[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir:function(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink:function(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read:function(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)}var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(FS.cwd(),path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(p=>!!p),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:node=>{var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:(parentid,name)=>{var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:node=>{var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagModes:{"r":0,"r+":2,"w":577,"w+":578,"a":1089,"a+":1090},modeStringToFlags:str=>{var flags=FS.flagModes[str];if(typeof flags=="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:flag=>{var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:(fd_start=0,fd_end=FS.MAX_OPEN_FDS)=>{for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd_start,fd_end)=>{if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}},flags:{get:function(){return this.shared.flags},set:function(val){this.shared.flags=val}},position:{get:function(){return this.shared.position},set:function(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts:mount=>{var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:(populate,callback)=>{if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(path,mode,dev)=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(path,mode)=>{var dirs=path.split("/");var d="";for(var i=0;i{if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(old_path,new_path)=>{var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(path,mode,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(path,uid,gid,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(path,atime,mtime)=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;node.node_ops.setattr(node,{timestamp:Math.max(atime,mtime)})},open:(path,flags,mode)=>{if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS.modeStringToFlags(flags):flags;mode=typeof mode=="undefined"?438:mode;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;if(typeof path=="object"){node=path}else{path=PATH.normalize(path);try{var lookup=FS.lookupPath(path,{follow:!(flags&131072)});node=lookup.node}catch(e){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(Module["logReadFiles"]&&!(flags&1)){if(!FS.readFiles)FS.readFiles={};if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream||!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error('Invalid encoding type "'+opts.encoding+'"')}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile:(path,data,opts={})=>{opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices:()=>{FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var random_device=getRandomDevice();FS.createDevice("/dev","random",random_device);FS.createDevice("/dev","urandom",random_device);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories:()=>{FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount:()=>{var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams:()=>{if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode},findObject:(path,dontResolveLastLink)=>{var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath:(path,dontResolveLastLink)=>{try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath:(parent,path,canRead,canWrite)=>{parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){}parent=current}return current},createFile:(parent,name,properties,canRead,canWrite)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS.getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS.getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;i{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS.getMode(!!input,!!output);if(!FS.createDevice.major)FS.createDevice.major=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i{for(var i=0;i{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return true;if(typeof XMLHttpRequest!="undefined"){throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.")}else if(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error("Cannot load without read() or XMLHttpRequest.")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}LazyUint8Array.prototype.get=function LazyUint8Array_get(idx){if(idx>this.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node},createPreloadedFile:(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency("cp "+fullname);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(Browser.handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}},indexedDB:()=>{return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB},DB_NAME:()=>{return"EM_FS_"+window.location.pathname},DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=()=>{out("creating db");var db=openRequest.result;db.createObjectStore(FS.DB_STORE_NAME)};openRequest.onsuccess=()=>{var db=openRequest.result;var transaction=db.transaction([FS.DB_STORE_NAME],"readwrite");var files=transaction.objectStore(FS.DB_STORE_NAME);var ok=0,fail=0,total=paths.length;function finish(){if(fail==0)onload();else onerror()}paths.forEach(path=>{var putRequest=files.put(FS.analyzePath(path).object.contents,path);putRequest.onsuccess=()=>{ok++;if(ok+fail==total)finish()};putRequest.onerror=()=>{fail++;if(ok+fail==total)finish()}});transaction.onerror=onerror};openRequest.onerror=onerror},loadFilesFromDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=onerror;openRequest.onsuccess=()=>{var db=openRequest.result;try{var transaction=db.transaction([FS.DB_STORE_NAME],"readonly")}catch(e){onerror(e);return}var files=transaction.objectStore(FS.DB_STORE_NAME);var ok=0,fail=0,total=paths.length;function finish(){if(fail==0)onload();else onerror()}paths.forEach(path=>{var getRequest=files.get(path);getRequest.onsuccess=()=>{if(FS.analyzePath(path).exists){FS.unlink(path)}FS.createDataFile(PATH.dirname(path),PATH.basename(path),getRequest.result,true,true,true);ok++;if(ok+fail==total)finish()};getRequest.onerror=()=>{fail++;if(ok+fail==total)finish()}});transaction.onerror=onerror};openRequest.onerror=onerror}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=FS.getStream(dirfd);if(!dirstream)throw new FS.ErrnoError(8);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat:function(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;tempI64=[Math.floor(stat.atime.getTime()/1e3)>>>0,(tempDouble=Math.floor(stat.atime.getTime()/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAP32[buf+64>>2]=0;tempI64=[Math.floor(stat.mtime.getTime()/1e3)>>>0,(tempDouble=Math.floor(stat.mtime.getTime()/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAP32[buf+80>>2]=0;tempI64=[Math.floor(stat.ctime.getTime()/1e3)>>>0,(tempDouble=Math.floor(stat.ctime.getTime()/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];HEAP32[buf+96>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+104>>2]=tempI64[0],HEAP32[buf+108>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream}};function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function __emscripten_date_now(){return Date.now()}var nowIsMonotonic=true;function __emscripten_get_now_is_monotonic(){return nowIsMonotonic}function __emscripten_throw_longjmp(){throw Infinity}function _abort(){abort("")}function _emscripten_set_main_loop_timing(mode,value){Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(!Browser.mainLoop.running){Browser.mainLoop.running=true}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){_emscripten_get_now=()=>{var t=process["hrtime"]();return t[0]*1e3+t[1]/1e6}}else _emscripten_get_now=()=>performance.now();function _proc_exit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}function exitJS(status,implicit){EXITSTATUS=status;_proc_exit(status)}function maybeExit(){}function setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming){assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}out('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object"&&SDL.audio&&SDL.audio.queueNewAudioData)SDL.audio.queueNewAudioData();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0)_emscripten_set_main_loop_timing(0,1e3/fps);else _emscripten_set_main_loop_timing(1,1);Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}function callUserCallback(func){if(ABORT){return}try{func()}catch(e){handleException(e)}}function safeSetTimeout(func,timeout){return setTimeout(function(){callUserCallback(func)},timeout)}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}}var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{assert(img.complete,"Image "+name+" could not be decoded");var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;Browser.URLObject.revokeObjectURL(url);if(onload)onload(byteArray)};img.onerror=event=>{out("Image "+url+" could not be decoded");if(onerror)onerror()};img.src=url};Module["preloadPlugins"].push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;if(onload)onload(byteArray)}function fail(){if(done)return;done=true;preloadedAudios[name]=new Audio;if(onerror)onerror()}if(Browser.hasBlobConstructor){try{var b=new Blob([byteArray],{type:Browser.getMimetype(name)})}catch(e){return fail()}var url=Browser.URLObject.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err("warning: browser could not fully decode audio "+name+", trying slower base64 approach");function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(function(){finish(audio)},1e4)}else{return fail()}};Module["preloadPlugins"].push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},handledByPreloadPlugin:function(byteArray,fullname,finish,onerror){Browser.init();var handled=false;Module["preloadPlugins"].forEach(function(plugin){if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled},createContext:function(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:2};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])Module["onFullscreen"](Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||function(){};CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout:function(func){return safeSetTimeout(func)},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(function(){callUserCallback(func)})},getMimetype:function(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(function(listener){listener(canvas.width,canvas.height)})},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h>2];if(param==12321){var alphaSize=HEAP32[attribList+4>>2];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>2];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>2];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>2];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>2];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>2]=1}if(config&&config_size>0){HEAP32[config>>2]=62002}EGL.setErrorCode(12288);return 1}};function _eglChooseConfig(display,attrib_list,configs,config_size,numConfigs){return EGL.chooseConfig(display,attrib_list,configs,config_size,numConfigs)}function __webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"))}function __webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"))}function __webgl_enable_WEBGL_multi_draw(ctx){return!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"))}var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode){if(!GL.lastError){GL.lastError=errorCode}},getNewId:function(table){var ret=GL.counter++;for(var i=table.length;i>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},createContext:function(canvas,webGLContextAttributes){if(!canvas.getContextSafariWebGL2Fixed){canvas.getContextSafariWebGL2Fixed=canvas.getContext;function fixedGetContext(ver,attrs){var gl=canvas.getContextSafariWebGL2Fixed(ver,attrs);return ver=="webgl"==gl instanceof WebGLRenderingContext?gl:null}canvas.getContext=fixedGetContext}var ctx=canvas.getContext("webgl2",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:function(ctx,webGLContextAttributes){var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:function(contextHandle){GL.currentContext=GL.contexts[contextHandle];Module.ctx=GLctx=GL.currentContext&&GL.currentContext.GLctx;return!(contextHandle&&!GLctx)},getContext:function(contextHandle){return GL.contexts[contextHandle]},deleteContext:function(contextHandle){if(GL.currentContext===GL.contexts[contextHandle])GL.currentContext=null;if(typeof JSEvents=="object")JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas);if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas)GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined;GL.contexts[contextHandle]=null},initExtensions:function(context){if(!context)context=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;__webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);__webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}__webgl_enable_WEBGL_multi_draw(GLctx);var exts=GLctx.getSupportedExtensions()||[];exts.forEach(function(ext){if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};function _eglCreateContext(display,config,hmm,contextAttribs){if(display!=62e3){EGL.setErrorCode(12296);return 0}var glesContextVersion=1;for(;;){var param=HEAP32[contextAttribs>>2];if(param==12440){glesContextVersion=HEAP32[contextAttribs+4>>2]}else if(param==12344){break}else{EGL.setErrorCode(12292);return 0}contextAttribs+=8}if(glesContextVersion<2||glesContextVersion>3){EGL.setErrorCode(12293);return 0}EGL.contextAttributes.majorVersion=glesContextVersion-1;EGL.contextAttributes.minorVersion=0;EGL.context=GL.createContext(Module["canvas"],EGL.contextAttributes);if(EGL.context!=0){EGL.setErrorCode(12288);GL.makeContextCurrent(EGL.context);Module.useWebGL=true;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});GL.makeContextCurrent(null);return 62004}else{EGL.setErrorCode(12297);return 0}}function _eglCreateWindowSurface(display,config,win,attrib_list){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}EGL.setErrorCode(12288);return 62006}function _eglDestroyContext(display,context){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}GL.deleteContext(EGL.context);EGL.setErrorCode(12288);if(EGL.currentContext==context){EGL.currentContext=0}return 1}function _eglDestroySurface(display,surface){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 1}if(EGL.currentReadSurface==surface){EGL.currentReadSurface=0}if(EGL.currentDrawSurface==surface){EGL.currentDrawSurface=0}EGL.setErrorCode(12288);return 1}function _eglGetDisplay(nativeDisplayType){EGL.setErrorCode(12288);return 62e3}function _eglInitialize(display,majorVersion,minorVersion){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(majorVersion){HEAP32[majorVersion>>2]=1}if(minorVersion){HEAP32[minorVersion>>2]=4}EGL.defaultDisplayInitialized=true;EGL.setErrorCode(12288);return 1}function _eglMakeCurrent(display,draw,read,context){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=0&&context!=62004){EGL.setErrorCode(12294);return 0}if(read!=0&&read!=62006||draw!=0&&draw!=62006){EGL.setErrorCode(12301);return 0}GL.makeContextCurrent(context?EGL.context:null);EGL.currentContext=context;EGL.currentDrawSurface=draw;EGL.currentReadSurface=read;EGL.setErrorCode(12288);return 1}function _eglSwapBuffers(){if(!EGL.defaultDisplayInitialized){EGL.setErrorCode(12289)}else if(!Module.ctx){EGL.setErrorCode(12290)}else if(Module.ctx.isContextLost()){EGL.setErrorCode(12302)}else{EGL.setErrorCode(12288);return 1}return 0}function _eglSwapInterval(display,interval){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(interval==0)_emscripten_set_main_loop_timing(0,0);else _emscripten_set_main_loop_timing(1,interval);EGL.setErrorCode(12288);return 1}function _eglTerminate(display){if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.defaultDisplayInitialized=false;EGL.setErrorCode(12288);return 1}var readAsmConstArgsArray=[];function readAsmConstArgs(sigPtr,buf){readAsmConstArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){buf+=ch!=105&buf;readAsmConstArgsArray.push(ch==105?HEAP32[buf]:HEAPF64[buf++>>1]);++buf}return readAsmConstArgsArray}function _emscripten_asm_const_int(code,sigPtr,argbuf){var args=readAsmConstArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}function _emscripten_cancel_main_loop(){Browser.mainLoop.pause();Browser.mainLoop.func=null}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function getHeapMax(){return 2147483648}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}let alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var JSEvents={inEventHandler:0,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence2?UTF8ToString(cString):cString}var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];function findEventTarget(target){target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):undefined);return domElement}var wasmTableMirror=[];function getWasmTableEntry(funcPtr){var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func}function registerFocusEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=function(ev){var e=ev||event;var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(getWasmTableEntry(callbackfunc)(eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_blur_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerFocusEventCallback(target,userData,useCapture,callbackfunc,12,"blur",targetThread);return 0}function findCanvasEventTarget(target){return findEventTarget(target)}function _emscripten_set_canvas_element_size(target,width,height){var canvas=findCanvasEventTarget(target);if(!canvas)return-4;canvas.width=width;canvas.height=height;return 0}function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread);return 0}function registerKeyEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(176);var keyEventHandlerFunc=function(e){var keyEventData=JSEvents.keyEvent;HEAPF64[keyEventData>>3]=e.timeStamp;var idx=keyEventData>>2;HEAP32[idx+2]=e.location;HEAP32[idx+3]=e.ctrlKey;HEAP32[idx+4]=e.shiftKey;HEAP32[idx+5]=e.altKey;HEAP32[idx+6]=e.metaKey;HEAP32[idx+7]=e.repeat;HEAP32[idx+8]=e.charCode;HEAP32[idx+9]=e.keyCode;HEAP32[idx+10]=e.which;stringToUTF8(e.key||"",keyEventData+44,32);stringToUTF8(e.code||"",keyEventData+76,32);stringToUTF8(e.char||"",keyEventData+108,32);stringToUTF8(e.locale||"",keyEventData+140,32);if(getWasmTableEntry(callbackfunc)(eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread);return 0}function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread);return 0}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){var browserIterationFunc=getWasmTableEntry(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)}function getBoundingClientRect(e){return specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{"left":0,"top":0}}function fillMouseEventData(eventStruct,e,target){HEAPF64[eventStruct>>3]=e.timeStamp;var idx=eventStruct>>2;HEAP32[idx+2]=e.screenX;HEAP32[idx+3]=e.screenY;HEAP32[idx+4]=e.clientX;HEAP32[idx+5]=e.clientY;HEAP32[idx+6]=e.ctrlKey;HEAP32[idx+7]=e.shiftKey;HEAP32[idx+8]=e.altKey;HEAP32[idx+9]=e.metaKey;HEAP16[idx*2+20]=e.button;HEAP16[idx*2+21]=e.buttons;HEAP32[idx+11]=e["movementX"];HEAP32[idx+12]=e["movementY"];var rect=getBoundingClientRect(target);HEAP32[idx+13]=e.clientX-rect.left;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;fillMouseEventData(JSEvents.mouseEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread);return 0}function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread);return 0}function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread);return 0}function registerTouchEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1696);target=findEventTarget(target);var touchEventHandlerFunc=function(e){var t,touches={},et=e.touches;for(var i=0;i>3]=e.timeStamp;var idx=touchEvent>>2;HEAP32[idx+3]=e.ctrlKey;HEAP32[idx+4]=e.shiftKey;HEAP32[idx+5]=e.altKey;HEAP32[idx+6]=e.metaKey;idx+=7;var targetRect=getBoundingClientRect(target);var numTouches=0;for(var i in touches){t=touches[i];HEAP32[idx+0]=t.identifier;HEAP32[idx+1]=t.screenX;HEAP32[idx+2]=t.screenY;HEAP32[idx+3]=t.clientX;HEAP32[idx+4]=t.clientY;HEAP32[idx+5]=t.pageX;HEAP32[idx+6]=t.pageY;HEAP32[idx+7]=t.isChanged;HEAP32[idx+8]=t.onTarget;HEAP32[idx+9]=t.clientX-targetRect.left;HEAP32[idx+10]=t.clientY-targetRect.top;idx+=13;if(++numTouches>31){break}}HEAP32[touchEvent+8>>2]=numTouches;if(getWasmTableEntry(callbackfunc)(eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread);return 0}function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread);return 0}function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread);return 0}function registerWheelEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(104);var wheelHandlerFunc=function(ev){var e=ev||event;var wheelEvent=JSEvents.wheelEvent;fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+72>>3]=e["deltaX"];HEAPF64[wheelEvent+80>>3]=e["deltaY"];HEAPF64[wheelEvent+88>>3]=e["deltaZ"];HEAP32[wheelEvent+96>>2]=e["deltaMode"];if(getWasmTableEntry(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:wheelHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target=findEventTarget(target);if(typeof target.onwheel!="undefined"){registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread);return 0}else{return-1}}function _emscripten_set_window_title(title){setWindowTitle(UTF8ToString(title))}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAPU32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function doReadv(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function convertI32PairToI53Checked(lo,hi){return hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var offset=convertI32PairToI53Checked(offset_low,offset_high);if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function doWritev(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}var tempRet0=0;function getTempRet0(){return tempRet0}var _getTempRet0=getTempRet0;function _glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _glBindBuffer(target,buffer){if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])}function _glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _glBindVertexArray(vao){GLctx["bindVertexArray"](GL.vaos[vao])}function _glBlendFunc(x0,x1){GLctx["blendFunc"](x0,x1)}function _glBufferData(target,size,data,usage){if(true){if(data&&size){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _glClear(x0){GLctx["clear"](x0)}function _glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id}function _glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _glDeleteProgram(id){if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null}function _glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _glDeleteTextures(n,textures){for(var i=0;i>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _glDrawArrays(mode,first,count){GLctx.drawArrays(mode,first,count)}function _glEnable(x0){GLctx["enable"](x0)}function _glEnableVertexAttribArray(index){GLctx.enableVertexAttribArray(index)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _glGetShaderInfoLog(shader,maxLength,length,infoLog){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glLinkProgram(program){program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}}function computeUnpackAlignedImageSize(width,height,sizePerPixel,alignment){function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize}function __colorChannelsInGlTextureFormat(format){var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1}function heapObjectForWebGLType(type){type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16}function heapAccessShiftForWebGLHeap(heap){return 31-Math.clz32(heap.BYTES_PER_ELEMENT)}function emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat){var heap=heapObjectForWebGLType(type);var shift=heapAccessShiftForWebGLHeap(heap);var byteSize=1<>shift,pixels+bytes>>shift)}function _glReadPixels(x,y,width,height,format,type,pixels){if(true){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}return}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(true){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _glUseProgram(program){program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program}function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function setTempRet0(val){tempRet0=val}var _setTempRet0=setTempRet0;function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":function(date){var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&__isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!__isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":function(date){return date.tm_wday},"%W":function(date){var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":function(date){return(date.tm_year+1900).toString().substring(2)},"%Y":function(date){return date.tm_year+1900},"%z":function(date){var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}function uleb128Encode(n,target){if(n<128){target.push(n)}else{target.push(n%128|128,n>>7)}}function sigToWasmTypes(sig){var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64","p":"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run(); diff --git a/C++ProjectTemplate.wasm b/C++ProjectTemplate.wasm new file mode 100755 index 0000000000000000000000000000000000000000..2263b1dc6918bd2216e3cd3b6a7681ab391a1ada GIT binary patch literal 300705 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

    B)1{lOFfz^~AWxoSuL$^34i! zKu1jyJX*ibh&gq4RQ;+j$O#|KNptXv9P2pVbUSU;~wkkJf+)z4&=3N!@R* z5%HXv1kV2jl7N-<3m^f?c{CDO3YL`TrV`Y#rN(gV+HZbyc&aAS(8oLMIjxcDO0se5&5QvC9xceqgG*C_<|$NOkF%G`kQP6wFjPDm>GvvY)QJPxEY2Wkh2>r<_t<+WAGAMD z>>d8c)B>~3EO@?-*#)nt{LAviWG=9+yFd2>$4oXiWsBg2;eH$=(SFn27f=&)yg0~b zSQ{HoITAS^CZxsZD3njmTTGJaBurKjvVMT%cK89$yfsA}X{T8V$Y{}2{L{wT!#Kl2 zn^ILoIUx#Fe9=*&*)~d#sh+sArGMR!Fj4nghV0etiqhdM&rYtfn1)@qft$ba?Btac zJLJ)JNN8JePq+-l?W`;PR)6;=ql*C%5Y^ph42VEZv;6eI&K3s%wnku0^2(y|;+D3X z+fpX>V_$(1SOWx?wAMa0p$^hgwOKrg6W0{RyZqy5O8fG(R(t?P@Vt0i&RUy3s-rSM ztvkr=2(jTyT1^H>qoO&$x;y3vp4I3Y6ecV+L;>{Y7>kpcV3JG@U?aY>MM+h^7n{aE z35X#Xg3%DjuQA_fF!F1F$-!XIC9PeZlQ_d}lQNJVxn&%vEYJhl(r-6Nz>+tktcItQ ztiLScdSyX&l1!;D3&5CV20*%G9Mlk2cKWjBARBSLvW)7C!ql!F@nya&&G9YIhjn}m zrtvb6OS9TQItSA^U>eXdO#`CG0%WYcH zYCda-$T@A|sHdN&O@Y_ac?627IXZ2ULPfYkEdH8PxMmH1jt)DHQ$&68g%9{{oQ}3| z`vK>Kx=6|!_&=48UC~)@lAk+*M#H{b2jgKh~kWP}1`2njxE&h?Q(#U-|UyMLt87%5s zNM~`rI$t%P#{S2mG-gGhUjKW~XRk#EbqU!aq2DqD6_rucFZGk_opX^UAPhw{z4jUb z!jYi)5UeyIo2D0&=7va}P%&8Uw7vt}Zxn z=KMk$+f<%Scb;Sty|YRPuqIhoJb9|KhC#alw9chAk!Gs1RykQjrZ4WrK$>)5C#3)P z#!k-lKRj=FisG;86#ClSd7{21z!ttPqK|xC$j%JD)_2xXH7j!mF6*2J2@fT^!Hb3) zGKM1-gY?WGe+lIVWV%g4wjq_7jpvfvC^?P%iLk(@*oG!u8^ytEn*N27w|C$$`lC=@ za5kB!nGT(&#XPtng{7%YHgkJ5uUP(*g{$a2pJ*=`}C(`szq z(zwu0Ya6DH6ipfcM3|P>DUPO%63wZ*m9l&0d8K=-4KbY~bWiVlY6%KWp}}HKbw<(a!}S>Xm_L=WvqD-E=ORSrsKk-a`2| zxC^UW@Dt}2+&Xi?z$kO4*0KRoF2Rb+x3ns&Z1;x1yrc_e57q{tsS2zmU|2dRg^C5s zTF)pJ&AvIVkqio&y*5~R>q!b!59EvsEX(5oY*~_~nlG6umNEQmnPx*W5VedXXanmg zSm=2F1t?7JW1UWmp4+NLJKw*ZKbZ}n(hUal7VdCeWjQuQX?cn!3*{or;K`hJyu`~J zgQyS;T|#=G$Fq_ts!M2YOS~p9tn*%D#?H{vmdjZvocHQc72`)`+Bz`{h4WsC3+KHO z3g^8N>Ob!_0dg=J)ScrT?_O~B9j3iH33%#{8?@AzutK;Wy%=#!)(`EqG%1TBx*wqqBRs`**c`*4mB zQ$q`7wiTgPp*Het#;nm6eS)U46id8-ZA*WkyI#;s%tImgnuY}Gh}jWj5{yr#WFqD+ z)fCaxkd{j?w5b-0XHH>WOKp3Z2iK(>Fdd~w^H@XPztDyVD45=9;uRJx=Nvz2Yy*`G zoyl5@eKjQ*6=Pcv|41Mc=*!gR_7t2pryah@*gQjClGe7NYXwUO+>(!0PLx7ZN>*;( zR+ASiF(34ZO0|-tbWWB5)nRt$%dA6y7z0i&K)iW`VOk6>5O3sdZ&I+}7%pa7gc(y! z_eHbh`$j22HK6fz?~lVfv0xk%=^rFvf%4kLRD2ui2Z9aE$e_KU@V^lK0kCpj5^%K1 z4Tk$-vtx54OzQQFL?A_cnMRg;9fs#PA>i zgz`NUbRvY%@pEMxdHsb8K(zUYc~uWFO|gC~#2oy^Af|bQ0%~emH}GNEq`LSE!p82@ z{=X6%MZzLwomX{6tn@91Sk8!!B|6=7?i_Rq6j z*hjn?R8PP{JjhG{<$ael2TD{kH%jSJH!~R@jAtoyFW9%;-WXvSs%l~daN^z8{^A75*Dkn@gVS}1Q(-f`h`~%4{_NuWNg4 zRSeDYai|U!ho3RTu~9h0jV_XRnXEGG4{SflI?KCsk-SS5$%|udfjcQcmi0FD4W3+T z&AmQa$ON*5Oy*n2Oacp;2)B@#1Qs%rz(QscaHFw&?&4$`lhPyrNkmG+Hb$U8>4PY# zpb0+tr7hTVnjtEE=q<=YYbe51XUt4WaAA@+-Q5BGc)tv3$6U6@6ee^S3qP4dHt^3% zU|^%Xp=DlnxE}B&pNz8v>sUX=z@20oim&R=`l}hgniUg@*!9?@Y+*T4`36{$U z0-M$j0-+Z@kvK$KWGrcVOUo79#{<1fb+}k%*R@sJmQ&((O)I zd?bYHpV%@>T_(JGVM|-oqD0+Tt$uxC(SFJAQTEGke>y|I&Y9n@HUHNAf;8s!>l~rl zC;L&&791E}g}Ixmp8{som>(D7Yr@A^L@MUe6-(t@t4-42o6f_8kEso8WirGsCwv-m z{@|t2nYif3Acb7O@EG|f!h}y4$a3@s@}*3lX(lFe|Ff7QbhJ?_5Ey40mNTNnmi>iv zKoG6464eg+l}hV+llwmm>(m%+C7M64X*ax}!;e5J`5@{KfJCLWX`E$zgW{UurWRzY z#67_BN@58tb73q3tT53%7gz|oIl!VD1}r&q0G7%ESO)kmut;GuZ2~-w95uoKUzR23 zj%M|(tlk8-%1Wi00(iWXb7$HblojT;Z3eI`t6WQEW%Xv-R90`MEy!dIqNdVBNwzR2 z_ape`xuTJx%MrxqB~f1vqY(7CAt=jL1zZCSU6H}`IM;F{oL5LY!2NYJBlRws3}Y>~omk*|=3Em_vlV@bYk98(om4-~DuWx*-Us)i)&G~W6c2`Z13pw>&! z$Q!*XGEE_Ap$e-mnBef9J@&NEZD6f;t|)i|yh+41EBVXPiZ$Xq4}cJS8@q8gGFU+LF?P7G%@yNK~M+n=N!| z4zo`>dEQ}#KP^6|7-4+KB_AMX-|H9`W)anqV(EgoH3gef=cPNhSh65)U4b8XUb?3i zD;LDAFIFvxdqy$7AnyEP`GUA-7b_OTU05tz5ck|-bV1xj#n_xURNSW4-SKs)gMu%~ zTU&Mb5*EQ_9r_{2Y1sj+jm5|@kV7VofYi^6VX}mmT9{OX<95({(F5NVcKc)5j_TX=&5 zp&b?-+JU!HS2zs2Wp*y|SYBlzOSQ9tu8n%um`6hiOA$bSsvUOt(NcV%q@MYMm~^xI z;tmIVbVjA(=E( zY(ZhG(g_kaw{_TZ0jP0;U`2CVeT2AO+65k6%a`C{SjB?KB^dH#Zn_hZn#8i4e91H^ z3oTzD9{Xj5%$*Efx0U14UgUdLjaY_l&0>0Fnw7k%)vyWJi2(8x$;wj%dq}Uw`Q5JhP2B z)KOr%oeX`2?*Ig5x3mmud<$i-LXESwFvl{Sx5vd%fEO-lSQ=Pm-b*yfPTe2~xu|6& z#!l02t}pSpLna{|2nfm5{rWeo;HHXKk$i&#qj+#3nPu+lwJWxuU619<-0_M9jrYpG ztI1igMG!;Q7{v0Ce5J*YuqwqR9Mlg`JF6HYrVnW62=t+BUA|!OhOcWzLEZ-yPF19V z;iH*K=ZqNXIzlaLL_jNfb^FdF8z9)eE6HjR_gzh9b-svrL3YmwH+n&%x(&?gDr4{d5Z_KgqTz$W!r4J(y{|Npy$0ATv`N5Ato9Hz2rxO4VMx@76HI@`mZ zSPVAeO1lbqJfU`$S^lxR~EP%>4aV z-%Lx|ZnBp|q31qN``ac$s?*>3my@-rq2#xJD@5FV^Cym`EW~<8ybXkl-CO?X4exsW z#?~~!kG#`@FCh5#4_NTcv7+y`@C5{q9<$&x3BKj~7JL%Hul=VRRRml5-KX!{r{L2G ze)Y|NprFj2_r1e{+X>$F6AP;5yZ-v-yGZa7f?xZ|``-0?8(VKtbq_!C@%w*&W9#<` ze&S2t|17}^3EuSP+aDmfUn$=5rmuaO@NW=2aMOprM(}!q@A=^D*9qR}%eeLMj*Tt$ zf4ZCQ{OU1+&sO3e{+)u_*m~C+{z<`C5&Xnk-}wN+odh3#0Pj+r>tt9xx4}N@R*T&YHl<%fH|K<&ZrO&@*-_2hoxRv00 zK4`(;B}o6?wRYE8 z{q{dRtnkeWKlI^u|CI1eR?3|xK2X`%($Q=)|M^=F5PX}WKk*d{|DnR4dBno6C;0Fq zH+_#JZ&36fe&ikBuWoETi{Sgd^0prn+(huE&%fnv?(H@H3R;J750}!QUhJ>HEI)$K=Gsf)>84 zAbW!$01IAC@NeF0MRUZiyZKKo_!@$Te{|q(Hch;fLz{*(m+;|EI9K6Q;XThZUF z{4YJeug4Gc_@N$ur^hKh{y~p_)Z?G@_}_Z`vmQUy<7aw2qQ{$NHLM5h`7V3jV$XNm z^N;QMC-yvO&)e*I$e!=B=Uw)MtSIM*J^##}AF=0Adw#;6pRwm>?Rm_e57_hb_WYtf zziiLr_WX)HziQ8~+4HaM`AvKN4}1RK_WX`LziZF$+4H15|JI)W%bwr2=MU`p!}8g| z%^`Kh9lbBfW;l0J2Ug8g;gaui#R^W`72(1mjNS?D6I!HC_&bVog#!2OonP3Lm-bx(JrJZn8R{FJ4`zrt(v zTs8#WRLu?s5aMLe5?;+YcBAG&lA3X!OZ&BuU)Q2Io8y{S3%WciumEk29LuqAJajUI z(nZk zB2}LKW5VTH@vg+c5z$hHRA1_pj5zyA?IH+!$wFmCYUNWJUZ*bUCS-YJNQgB%byRfw@Z=3_ZftXu3dMXQ2F%coXfjtB+LdV7yaA0Rf5x9WwjpdbSsrerl-Grl}l+YZ8RQbk=DPM<+v zvBWNVk>5Sq%jBnJ3>}#IWctDvh#PdbS*1!@DXiD^BDE@jX*zwEv$!=QOQThCb@Iz5 zOzjL8z;8#nfE$>3Ub*Z|bowW1*r;xUQM720C`B6w!Q zIGvHXG@QHx-3>5mm&H4Ao90w|6HO4?Dp#J63#2IEfDE;ry<_i~i{g|m`LCH{xB`zU zD;k)S!3zO(4dMso=u!sPT*ej0geH+%V=0GsUT2|3gclBvRLvlxm5O+Ln6nw^wL;*N zduO+u)DtP;I(0{T%&b>@DRMoPAm=1M=8c2i0x%9Q<%OIjjQA>0mX=kfGa#Ho8o)Bn z{wjtV`hiOYqE^O2vp^MG*|gbkZJhwAgE0hYws(xVyvy-PJQtdm37TvTU~mLQ%DEi> zb?(|sxENmQ@L_YGX*v)=z(^J~Ih{g(nJR-AHI!U|PDk;U(I5thIJl|aYH-CQna}hd z9Ge9WU8`n;R?e(@Cl z&Q{K#LSAb3csPy@7IfT0%F4}8ocNjhnD2xbV9UwMmW@*WG1_RUDn8Lq!q2+@`7M5e z_La$xrWd4<`(wz3vS((Jtt`X1q=?)NuS5s4=Fu4;4-_i)Vt)Vbuz93@ls?@uh}#O0 zL-!2kiHqEU*ba@3dmVLkuvPNdT1{n=yY~BAk(hwkQ{WFSby0gG$9A(;MXVB#5!`y0 zm@rc;z@R)*v1%B3$x~xq zgGS=yUG9x0Y#NABNWyuhF>L&DV|dJhb7-b0r<%ROxSOzYlbx^+v)0-&en(2SCa@7uY^8scGwN~f8g6JR*6Nnbd)^-67z&WCAR|VX#6>-cga(v;~mP{3~m_v=-T%FWKKj|5f3-g z!5!(YS}0}2Gygokr)Ubj*tRPKTk1Z=exD&OO1(mum)WafUQN3D~7ki0n=?<-o9 z@y-%?e&^r$d$A&2!w0v>N=$la!%KijYqK7vu7X|HUd4L~=q9@Ma%p&yGuXsNqrKxQNzytUW;hc;YYUO0GaLx2qveeKIgBHf>V4{f*#S%ma?BMPI< zxVPV=5M3J<{|j}lf5D-9O0cO_<@g*-chW$Rx~Z6nJ@?v%0T2J<@Bc6Vv|%TxVHI(= z=ANBl%<4NV?pl%q&B^n`nb`1K-3Hb?^zL}-DJfWesO;{&2L&xR`|eor>7k-}2=xw( z`-9s*#$?zLi$4UA_TOq*4>Ff6;>_;NliLmz4YD6Bl7p}TCOh)VZ3mfQlad=9D$;|8 zP&AKrOE?fpAU{h!Z#&38AwW*0$stKq+HuOKb|>wd0wQ-JL_O%EEbe%SJ66UWEUGl) zo)S(JSrUg)&5(OwVA^evWj5rF*HbA*bgS8F2qeQGlAz_yI@Q%sz z_U&M{cL>(*xzrH+WkOm{3h~msKm>nDAlvTk(!!~GyXAD_qUbj{7DhNmRe1!6 z;oQPC5GXNfFIyS?`gj%5*sCc668@H*Jc97lg>KixVMe@$lw>b5VQy3DQCFJdb&!){ zm1F4Khw2#Rt6VgxAXd@geMJI4%c0lkrIyIixIEdjc|6P3#_=w9>i$F@#$fXBBme!| zU%&BZcRU#Fnv8c8s2+^>WM}{F*`LO7+`A>U6DJdl^-TRmU5<1DJC~@_!+MP~`L{n~d7Jy$icRD05tal-CN$j**I#b8VMhFWWoo4yz1IA6kOPv8R9(Q?+f&z2 z%BgEEA9rsb=DiSH6;2(VJb&N4hq6@>{fpZNk|J^h5s!ccvv?zRZ|uEr_B+fY2mhBz zQ_O5shLD_~L@A}1&rBRnGP*$by$+EqFV8fWsPcWi1R4u0T)1xWbTk!%5n<95 z?N$!uu}?b`X2xntZQ3dgx0B5AG9AQHPh`ZRHA$`D+LAn)QYgDpTBfvtPNJq-R*Dk2 zqvTT_?_$-=m##^PDGW_P!1D@2&McJ7WI!;T{l_rx4l4){QqkHms9YAS#447adJn9i zqZ4`qEV|H9he()^i<&5blB_1`p3WTY_QW1@cl3PTC97Yxx4e>kP`cSFxV1R~R{*(9+Ew9MgB@@vmygaGcN{X=kX+*JNLh6I9h* zq{M4-ZBc<@V3~xijNram$6C<4b`;fL^$JJ(9aw=lgaD^17JN0pav)6Z_6@@R2V-Hs z^qj0T$;o)BLSh)|KDlpX+O1kGWnaKf&rPQ9dIi66ku>&XXX~H|)V=UXKu-;d&}!6+8{9Z9P1>e&1fW zV|IVyRmbB|F!>qfnVA?4fB|RgER)HoL`gtv|oT)o`!%h`{6-C9Gu;Kg&!C=Hk!}cbQUT+3nYK9pc?xCi4WBVF9;1dkeC#Q?4$gafttsfLgd#gH# z*$P(g)fTADSIS){sgdh)gDE7{1D+u;dS z0bbQEmha`oU^gFENUlvci@XNA-3jPC8}03|h;*@NTj0n&Pw7OmON+O_n7nfJ;hhv5 zy@GCPPgx2T@0IFO?a@iua*+r1;`Y}FCJnn20TycjmLc(!oZ7CY0JdCwt#D8CeN%Z zfp>|-st}S0>toMMM|KbFig!R->)GTk%0g@=o*g2eSa#1cG z(2)DUn5j|wQWRt@VYl4ltL>JE7;pJ1l{)gN*@b|C;pd0sG@6@^I$>tPLE&Y2!T>-K zfA)eXn%RBxCkyd>?waH3L(pV~IWd0y#M`TfCs*z(1;^}$9RhUP7dMNr*o&|y+rtBF zpjZXNjcJ&??@VCv<5d*;m1wH{->}Y5V>_ezs&~=zM)$_kq?$HZMFA8y5QP!lilH;hcR5$mZfsb6z55f)eUf zyfB|%nKVxQ;PyRUNFu1uKzIzZr8D-pTMhoLm;S2KORH`6^oGvz(2;y=m|7v7mc8qs zNGf~kr6>U3il$u+x0FbOo??u)AblD$+8Gl%R#-qY4KuB}=UhH+ry`6_4*aU93Z7Q6 z{kNnVom>su1cP9*)%M3hM)CVqqMQ;Je`c&sI3^UuSHG6cEj)4#%HwNIv0SXs&=~fF zG-mJ2%Jvb9sB=#NQ4w2csH`f|tn*1s!1dQMb2`)l|0Tm_Jzm~d(5B8xI)~FwtXA7^ zq==3h+~$qoVxu=_a|IF3^c!~XFhb@H5&s0B6X)!K@ z{J$BEATdGT_*mEGJJi10`u|EcN73YK)cXMbQH`z*0qlLbOxER-b*$WS5ipfN632}s z;C=1?l#oCKZ~u0`6cbO@RcJZeXj0rLR1;fUCL?w#@_Ttm@Uj-o^L_I@vzKTnVu;w# z$hJkAeXVcy^=kGQ>#(!&$z)%?e8*(Ivlw+abfypg3bdm6viq53(SROgWqiXU&;f#U z`e3Z*9r5JuAWiQL8g?S_r+2KT{aPQ5lksmb7xGczFQOU+9vD(- zIwc(G;VO4w3-c5g00v%tNSj3ycfcp+CB+_OdKiCr5s&AFp?6@9j4LaMwbL`>TT+j_ z2U1#sI^=u#Y(-uj=W8WjKF^HLbI=O9!=4B1c}rp}!JYC$KVy;meWCZ- z5031#p?N4SG@@o#^dp(UiQEisK6-om7Rz)Zpvg(0$sB|{PSOCtSzqUIL$?PZl#;cX zLJ0)?`&oN`Y{C1r>5)*&(KrJ)2J#gW#q8mcGDr4QQ-O%xF)w}FNMAPedkTFS>~5~& z!JQ;ioh5k;QnI@%Pi-4Y8sy%Azwo9i$b@Tsik)1YWl1U7Bw7ufOtNVfAI*=iYb4o( z;?n%^mr5`q+4>TA$)+U{{fSV*5(zNkO{WWzO+T3XtT zEhQT*sc3!30qLger(xntAKx492C-1L{HP zpWu@l+*l;z?9gGm7}~d|P4xqtfR!6F8`(<5g|ZvnH{TYsOXcT+hC1HYO*``$p#W74 zjB5*&S6mY@|Ig@-A!67dE%rZF@-qCn2nwWEs|t%}3zbPPVHmb1*bq3pN=hkt3<)U< zEd^Xutv!N_&KdHcow8M`Tmj)l2(=*IJddLL2WoylGgB1vBptp3i5$5QfEg`cJ~{X+ zG>hJ;!NcweOg_@c;q9E(z|f#s82wdgOYn5m(_GlG2wcHf^`- zHHY(2EXF>1ub2c5h01y+^(*zbW`X!IuM2NB>-EbQzLthzwQbV)my&0$yaT)78KF8! zGm3(L^F*4>WiJ&Ivb>qG_xl&TXFz;?CT<5oWRAxYKKG+AbHb$#-_WhohOwN~2BN?h z?J@(c6~f^I=NY}76;9BD8$?jSr-nA^%Z*d-NbAsCn12Zqf_+7v3LvthSB2)I~q3)y_N>9 zN08$_=P7HzL-ssj&y%tIJrs02H0D8T%rHIN35m1XD)DF+FgH&E@*!)>R!YbQ^pm)x zuoG4!LRJOa^TE(UiAk1FZF48@He1{`Poj{dvzGLjJ&~8h9QE1IG?D--&5@+tQKfZq ziikfkv?#{Rbn9*|4bblxo$=d*8efQP4ie@DY>0Tg(; z6BaBY%+^_iS(*>MdivF{Gh~Mrz1iMS@)&80>&j`t&Ofgh%6qQkGilu*_FWGIu~M(fk`&_UZZSw9@;0^^*?Ip3l5SxGc`*1jFZ z=;RFo##Mev$SB&J0cS=kv|j9zZnyk)_9)Ve(c5)BdIb6C53`8cKNFC)NXVmvRU~wv ze-z|qynCsr+hW_CsX2py{4<=Cp-CJYB@{FSGPuRJ3>w_t-Qop^va#Sf$HH;=F&e;4 z@TQ8J0Ym0i?b*($>XZaVV4vT)^|o1V@8Y2-kUed_dYe`u;Y~?DynS< zemWXt4kcDai7Av=?W07(+W$MU1wup?qyaDRf_qZL&W_2}kh19O@)T)>H((m5WbFMG zl}VqGy2Y@P68!iUIZG>~;*NO8A249u!bz(6a+w1dU+ulYVw#Y$pO$@&kpyqEPL zSxK%mGnRdSwf%0gx>FoR6y76$PO;nRsciI%axcTX!v{DD8?wh6 zz`>wwHk*2p20MU4b~a+xga$kC$G4#P_S9AN{uG*n$Y4;GEXAG*dcs3VriL%cm-~ie z5eD;ejW;iI%u9@)p6hCkdD&IrA!&@Mx^uO&YQUBPBWc`sU`;Y zI*x*|Nq;6ekkOH~z(&VAD1G8onnlHJ_khNWTmkkBHH%Qa)RsYvc9UWh)3`6Z`$ON2 zHvK$JvLXksw6iGEyZq!Hbuj6n@(<^=$;Pf7lk0b)lKdPU^`)wZwaE{>?Z$6>_Rqin z-WW^Qmq8|4AUR1!(i&-AbNcThY$m$HSPAbj3HpbJNyGTx}ldm3Ua9X=bB`{H_$H94hWP^^hF^fjrJ@8gAJr?&^+JO>=Ut8rN=NKts&7Lue8q+ z3C)9nVL?r~FoyNzmXIW<^FCdi8Fd_8r!g7O7$0j@Ub`n zn*mnU9Ro~$?%dL%kyhFV6Sz0{zS|~f9r&b{O1dU|R0+^$c+H@1O&sOHgEU169wrPvO04F&^ z)pe_c;#Ef2jitJ%Qf9!qZq3^4l$H%(0Jz~>G;aA=%fu!#noqRUiG0hr=HJa!0W!i9 zmWKaqNwNg?1+HpgOr1DZ-Pswv?gCwSQg;_}Oian!7&1*OaSW0dxYx0TN57^zwjCjv z$g^SqbSj37Durw;{AJaLRz&6le$C5}`z4GAehpFF(0NhJZ{7~^R@R|7J${Pwq6AIa zZX&|Jh7SHqnjKT!nYKoi4Jd{#Z!u^BSkBA#Z7QP0(dWJwV3Q^icX!$}h3!3Y`%l1Q zhJoT`U=nhv>eD+YhBJWT4(HQy*bzX0Gs?goU{0G;lX4-jo%1;0Z&c&UK^@zOe&bi{ zkV878W0Ig99iI&%Hn(<~${&~cIn5LoBu(nesD4pR%bknhwX+Hbdo3O8wp5Y9fSSe5 zY%sKdh1PSRQwRM+uXUUZ$J?dTP^55h8K97Vhy#CY;|pTT_iGt_8`|~$T)Y(Cua4gmWP3iBhy4S-3*(VI(9>Rovr*+?L$dHl1&^C$}xK{?6l;)5Xc)a z`4-5)lqAE`>QIE5L{!}CX=`1SgfZbo>c>Qp^LyIzi}dW(V!h-bpD9&AKmFXgb!*Uf zOXtYarACPs4a_ii_I5Q#f?UFxQ>jC5luR7~cbGmg<9Pu1#RU)+pnl41>qhOyFu)4` zTkg5IncjxAOm|7a=*VPN;i4tCn%i1L3j=Okpx~q|PCEjsgt=QoMvBl)q?huO?SruX z3(^UZ1HHk&prt6-HhHc6UR&3$%q=@j7~JP*R%|#3^7pr3LSf8lgdp}NKi~KjFYJ`eIfnA)98EmYh0~OL-ALnxIgIII30SByV*OH(eQ6*bhtJ&G&EY%@1&ZJ zjt-8-qoWlVrTU0^H#9IbnvIeM7z}Wj!^YMi2WaPY`BPWYBy43NiM7LOw-&U-Du(J2 z%NQ%;)tXKZUqgvHa;XXP?EP3-{$PD%)Ep~+anO}+Yxn82zlj5>dznz+{13~dGpHTM zO}RQp@HK#09h_!;4_+ytrB=g_dA6nZ&S*wY^U>6oM4u8+9JNCaGtqU2zg*{RKewB>qF54 zSJR@Elc|c%JQpOw7t7^7+^a602pTh9jZO4Nm{XRk56>ES%x5F$`tc<%87u)G^4&hDgrOZofY%24xB|8nmu~w^~bQhQy>0 zYxaP;D7paTY2;(z9x#``i&N|1Z^C4xzQnYUkQ$;)swsk*^N|xW4Nx`<8pY|Aa=cvWsz0Ipr{y1X0H(-mBP{T z=|b)j+KifsKoyTD)tuQr77v(XkCh4UN zNlL}pM=Oyy@MHhwF%tkoOJLE}w8B|ugN>}&8X9hoa8`fNB((QW!i;KYDj_<&@YVT= z))g=M3J3m~UOoO?Tx|TfNZpSjtv?9j65BQVKjTRCpiOdLYUj=0|5dZ-|@!pgJ5u(Y)Oi{)7 z-+6nGX^}bS{&Rdam{{#lps}s$?K()KmlL#cjo0FeXuNtlWMp3c3e1?4e4PIRtBbR( zeqsMi5*DPZbuWY)1H`)A&X?>{``exhXxh~1HKl8;=%y0&DZw{q#BzWs`XUm_^GoDPkk|1){V-316_ z&y>jSnbKFza!1$Gb$K8K@qC56<cmWg#tV#+1BPPJ}jdDypDy`bx^dcWnZQ_9XV zr`f|)8im!A*O*HyIGt%-UY2}>OOLsrzD$-O@*6nau=@`t9Lh<~sbbilgo>$A<~rqm zvm1`0|DZ)9@tuNll=(S6nL4ug^4ihctPj8a#V@);{rzFofj%{8E?X8h3)S=CjutfN zOHm+9>dw*!Sf!+0AZI|7FcgBesONM;QzfV(K{2sL>TVp4$K{>?O=3ws z!u##PZzdx`l}oi!|kw_N0Q#(!1tchyWYYT2JBuDEKEDoT@@wrS? zMWn$yAw?lj-oy(!QiN=9 zgj8cx>sQ)64m3`LN0mlPbX247XY=Y?{CVwYT-Sm7m_~VXT+1ac2aA6HaxSzQ*ZQy~ zJ12IrHkNr?xo$D|WE!~N)#Q6V2rN{E23Ys=fEI(`tL|HETx$qf18YD@-6#i=zPcE^ zmSkv`A~a|NcUOtdTExw=u)na=rJ@dKOQ!~*YdQb|^Fi%ZN1Kp`oHSIVL|{8h;Lemz zdMVm3o7LFkz-Bd`G^NQ|;p6h~aT^1Kz$qcNM#EZAEcb1oU_5-vfG^Paxkyr^DQ3BZ z*D0rX6t(L(v*&QW1Y@$OO}p4rf}{n_UM~ZhqtodltCJu_mcmR!16;(U9^p+n&pk!O zZW{L~+hUWwY7xx*lpGxCHYM%~H%@p*w$77{EM3R)K<;_P-YdRXMFv+BdvXYP0q6#| z!Yss)I9*zoZ1}||;^wK0V+}EeknlzKS+%FGY{enA#64ANNl=OOs0#}uNQq~8js>q;BKd=1Uz^TTp{k9QsjapNEYw)k z>2;oJnE*>}?4rHy8`=+pgpLBQ;FbbmoiGL5>+ygy?hHcPot9tJmPqN|3bKO z2Gv@8g#{TH4TITQNlaPFT{})UfYO1S*>-!>+p`IVSGJr;guna%n#tBNSE@y_ylQS|?WT>qeo;oZP#ux1ynf@{hWVAImVL=~ zb_6Vzy<2*(JRP^J1}nhb*fUwK>j~^gyM^_Max%!KcPq*r%VJ1H=~lW3Ydu zMM7@oGd6p`y<0?O@+9aRpJc_Q+Y9s}O^q^F1MH+1U|WLK>}1wd&>f#im^!7mM+ivd zGq`m-;Yh`T%e(UAcQvi3A*g5+o3xQb^zh=#UC|*gb}wb|VE&Ft68m~MZ;JI;uN4|V$+|1SH!LyuWQW5<3<`=`g^GrpIE z{28QzqK<1!d}q}f){&Ck=0)oahSkaGjW-(v;47@GbMlj>+qV@}VW(BiGEU8Z=C%); zsq;E}^nf^1GOSnCSCgItczrQxtJWC&RjwH)0vE^3ZW-7uRJM9auNIiLhkGE& zQd)&U6R|q7n-C7GZTcPDJC;1`mj#o&f}ZV(<7iq&l>32hsRWvdi375_-Z0y1X@#Fz9j_ zy6gFpZg}qU2ICg+5p!G^y)EEdy!A{@m_u<^kqWQ?07IM@rx&XeW($9e)0ZMavoIBR zlV?FXv|C|d0Gou5MeY{L;$t+brWm_~6?B`@<+8@%M1v97RdG+l)PU3;Jf^%9d%^;0 z=eLg~oB%`F-y|?|P&!^kKS_$=+MIINvRnK8|NZ^d>(qcB91FerWEq&rvx45pD%F%G z%a-%Xm90VUsIX?nRCdG%;SrjVNv_ltC0uaaqIDD_JsAIOMTA&(PPt}}K|kOgU{ik+ zok@@U0cOm3a8s1ALr_K}gI4yzgn{Qm4{)keQ)diFV%;FByn~?WG=-%&7DYU!GP6+T z#pI}YTlk7rwQROv6q=1*s&%IEm8`LVhAwNNYS&a9NFcW-3M)n(tU-sKm`!~Jo6s!< z$V)4Ho6*Yh6q-svFSS#n!lo#ld>clChT;I6R{P><7+WZersMQdH8HhvHZT!t69%1+ zCp{MB2a{Er8I!k;@-J;w@y9awRn3|yopyyOp1D$u9Uq$JY~_$>D>NJlNlBg50NN4t z&{ReseB~Uh&M&$v1=_8V4V(#30ayZ+sLOrWiq9jVFkum~x_+iH_JER>!tk<9RqkVg zesndx>!nr^(N}7}a$M|@I1}H7C{n5IY1=W>fJVK@ca|d+4z|AER2(%0}uU> zw(@8MEPCpaFj6wIiDVl#x-2B{y#}@m;Vi?l=ZZGy{TrkrTKu8#p6Vgerxn zo+xnI_9gJXuHMVQ;B0|yhIJctNCrwFQYsEss6kICEc{DZREEMAl)j!>M2`kt+p(gJlF2d7%2-QpsxFR9EuN+D zc7Zei73qr3`6mr4frwvLXkn{=q4VCu3vF)WZKV@4Ffy~mo@4G*l!?_H>E56*_I_lf zn|g}_LnFXn#)-HD_D0mTHy|mqH@vro@yra(WZJ1%0lwmgis}S^uVh!+^T(=E$D(~3y0tkaWq@R{x)ii`!w5*8JmD=HRm94>NF55M@H*{ zOU*l_TU6+6C?BS)6oX@0A_|MqL%>g1VZcur zO`bm(ex`<>b}5gdRfUbEc^<@_wd5Ey5q@@g2#6_r*jNc$CeEg5cJ`5-b%aF2RG`Uo zEibdP=HMsI@5j$-u)M&}YH4|?=RM0ypTKkp3+~h+VU1b{@M1*Eya*>>Aw};-pIqZs5wqn-7EEdck?}{snE~=uELhFkc2u&q9K@ z!9Wp*7tJs>EQ?@3L8RV^c{jFP^B z392u{0Tde%3-TO4g<6gx_V|cJ+dul4IcE)j-D*r^R4i#RrgqFuLU?wOt#dCBzVIX1;Cd>5Lu)a0i%xNgd;1|%}Cg$P1M zpI3soi%>HWQTDkex9ZR}d^`Mf9Dpwi!B1O@Yzj^styi)_|6pE_`xvO?SX+x-i+GJ^^!KlT=@6x|)EsRs>Dg zD(KQ^AWo&}s;^)wze-J)U;UacMnuumbd|JU(={abo=lJ(0H|QQeyEgJUeirX%MZjb zU(>C0dxXA?rYmhW$LrT)o%9VOOUOy#i)y;Wo2E-g#ehmpS2QNo!P^=-n$N}@+yEB< zy4QC#vZZDO66&q3#jFM=oU&{ENJQ^Y6pf8||B?v=)3Xep7O|RoWhY_$FJGH>r9hGHl(}3MX@L(zns$7CmRKWij01&0hVJ#H=V zMsmBTSz$QK7eO=gN16#G+>sN~8&v-)G*c((0=HbvMKcr6)(Ft_3}{B@`p|5lgf=vz z@I}##_{9yXMFs_$@$f~BoR z-E(X$mdchgnvv|I3SJ%>!ahEo27UvUA#z{R@547H&foF zAQ=bMu{glH8o$O_G)X^VevYoVfdD+$214T(eTo~U_zQy@I6k-9$Q+Q z2n@Lqf)xouuP#_CX^j=8`~nD`>_lf~)Wmyf<6v(067j`yN1Dp%-u{#gVUP@VWPGzv z#xrXrKCJtGWReDJ6?LuI=gl(B#p7M5mnlmMw=roJH7OGmLj^rPY(8GCg$p>WXU1(MoIRjsDa6ix!BgzC`sale53{h1(MJ_Iz+#{EDMaV^&;1KbKT>KW+3Ayw_8n&@wjfc~umPvKl4=|!6=#q?K;64mA zuM8VZb{Oxdi!X#y7FQ%iTw;tRM`d2cs^}Hm9rVYkNLq=~I0H9bq(qRaY%OyITEJsC zR-zOQmLje(w5rptq8 zzI^F%43TD|Ee6(yW04Y8kTd3~FRw1!`>o7+s} zdo8l-oDfX2?4_Dl`LNw}T#(-3s^`{smV8Euc)Yq0U#ZhVqYW_HZMpy@YF{a#sa(F7 z+-=+`kj2t)8;WD7?c(axr^q&*OE;TK5n3>V3{X5Gr zhre8vS2t^NSq`_Cau7{ls$!u0MY^l={$DQ{*Xk_R?3XDhm6G~?y~GMlLQK9FZ8m07 zp26o((*A0$n)AzNtMp}47KChH(KqVSj__LtIDyz0iZ}9AxiLi3i`^tE200pJ5-4*s zaj1MwZ6rbGqjb9l1X;2dAfWJ4+#XbR3f#kyDr$3hMNx|P7h$BNBPIRLYxZ~v`@OX= zNQ!&LZiO%a8}^8m5ldXXdxH=9S*`oSZ`WwJ6P)VG}dzDt~4EVgEO}V_5DFFR$rj4&hx$>o=WQ9^Q zttqFtmorj)*^Mie$#frx@%;UJOSo3{LNo)4t}2?eDL*Kb2~n{(VbW>KE()EnIb(`kOg<%bm86<Wrhb=>Sz$cXP(D9%BKjIEi(e22H3;K40xi_wSWvomX{80|-~S;xK)?n$t*m)y1nk zvkN=&c<+vIa|0@Wx@Vy%FHCT@Mf2?cYdT%xn8 z9QPSfZY1UwpOGP6O_O_!59S6>QI75ny5g>x7DM0a<$@qC8QFh`cipw<^IsQ-9~YXbgo1~ zHSTJLuh(!j70GjE;jjoS7%Nz0U$>IbEpgUF{YgT92!+lBkmrdyqSxw3`5IF^PqW$K zq`G_9j%dREsrJb-I3{XK7vtE7Gmp3Lk#*bUo*ggsl5PaJ3k`9n?aVIu7VK)SX?Fv6 zj7e<8o4aM3&@38#@VP4Q|FuAhHG>4}G7!UzQp^e5S5bIBxFuW50YD5gtp-AyOzW=* zPDMIIOJ81#6aI&|6O_)@H(=N7OGS}JBPOL5%^qq~4SglCu?TYFda_=A`%N>>P<;2I zE#0QVIsr}cuzgIQ;mvHtem&~Amns~y6Ql~)O(MXcLuCDnaNIeSr9R}l(3%E2uv>_{R+;v6*cXC+9Yy~UErVTrA$!_FXMdvWBu zpM1lQL3^?OsQoEiM7sI`)qrB|NOltF#?Me1v9}s4k;@XgyickI}qzP6N>(-^6GgmgosfXLaV z&Ymz;UT|*-8TXd4!z691$Q>{_^6_k`;zq7FRtQ&6M9pMuC|-AG=9rXHKDY93?r>pT!nAYLXhEKB!XU% zkL~54Cx5n}wAGYdtq@8)`E(5#7~T0|(-r<_<9R)pQ-u zMZ^bU#SCPxsP$IVHCEIsX=}GA8lm;QocBg?+0G0CH?FNCkrrb|aR#2%ybjb5B4k1Y zT2*#x!=BvVgvfqQ-5st5*4*26vq86Hmv#{zZFFd_rX|@me9JiDwkEAaT3=O~A%IZV zC+H7fn~Ijvx~_2G=NeVccMf1^f%R-XT{gr;`4Ob}MURl7($Xkx5-ruruphdC0ywuA zHNYmtsiNUcuV(NGGvq`qky5baCFA@+NNDt6)}-%AnyaXWcC?j{@3F%42qfP5&YWG1Wo5drx%vg}PU zr~SBxSbxk1dt57vZIuF?N+vv)Jjt8L5O89W->A-b*Zj*e8tBML?(lPc5n-j@%Tk=+=B!GGQtAwoy4B+-x z@ugvIUxgX!p6+p(ZI?pAxmWPr^bmgi@(Ml%P-?m9oLxkrnB9AH)vVz!y83RMPj<2< z+tpL8uu$j00N)t1inV(;;WlPwrF0Wu@~R>!Zvsr`*8iTFm}IgjcA(a)&Ee8Nno81$ zgQC?OGZy4xrvBeTvoGsU7Ss>!Epqu_|E+_nGWJ!19b5@jR)S%o2|=r5oQ72E1HZ=_%dfj;wB8-wI z%xXe=LvGH@JR+q+(z(=>B=}L1yphYh7-e7>plcLB&_6PG*TLaiiFKe1esn$f+hJVFI(z| z94%fmRyU{R9T)KTl|Ds(gtztA<5qAvdr5`q^#Cu?u|zk)jCNm1KVMo>tn zFEEbZ(rlpvfjk7`UAVzfk3CK*2QmlR=q9FOMXDw=l#oqj>JHi{yCjZxKM_y8XWyFr zrEUhj*Y6v3$pZkBpfzi(ylz~AKcm zebG*xLKjcs0E;FsGT)a!ZZ32$n!F*jq%PGV>HeIJc6jf1S=h|X#7@xFo5sq+<(vpG zvH*PV#f#)5DXU)GtI=yo*?inxp#=}4q*y^^1p17GZAf`9y}|YeofXHW_H0G?!=FUj z2WBV6GqfS)hO$U5`(}Kr?uMU4<~A096L$mZ3pYxF;v6eq7ie_6Jkm+QsliWN}FQ{GAI%o#!>YkwJJ=Lc5Q_7%*qh z_7>LuGXo_R7xo>U0|kc37DDlI&cLA_8{n?rvh`Eh9cenCgC2D~`2^GR3~ub!Fhl1) zd7n1w%CNcTzNGy^oxeep(?J|?rDRw8ilTmTq<<4{n|N1wzVKUJpoB^1Ja*8$C{ko`}|$Xmaq(lbz%2OF-8IL z`mm9uVLtuPd?%aEOhJdi3DCCGTBJt~3{ z{cmSuf3*Wr0w|{w$%FvRxt#=9j>1YDeYO2zhj#eGX?Bum8x2+}XH2raMi~fcvb~9O zPUFFbgsJwI6aGUbu@$6c5UhJ_AD7jplGzhNK@z0)o2WG-5h?suX83#iD~TN=BZA;3 z3q#;!I@paoA`u(JYIY8mvPTnP2bHxyl!^!V_x$GggKPvu0nhb5(ekIvVBp5Kxv|#) zG0yLK8m&;f_|F540|%F7)|HMbk^FjzJ;)4 zS7I)moKSQry9qNJ5`fqKThYChZe?b}DxHk1)7{#BAT{LU*CpK-LIbeYYHoiVn&ZKN zNY`cOs%GA@=-vvD+sL=hD1^m#k&%eA}(SfM1@tAZnw4HTae* zun?G$iyWRe?KBem@I4NB;4I&Un*3-Q5x}g@KmUu&htF(tLoI_lq6fi za^T*J=vER5lzfPBcueYO;unUdJDqgr!{;+I`GcNMMwMw|$GG`S2&#Yr0!$-}0RaXC zF+m2~h{OZ|2FqAr0g4e|G9qz6#s)-UgJ>Kqf`aG!TWgH+H0>J7Qq9f7r}Rv>~{Qd%>Xhcq)8Hc=o-zX0GFGC!%o@Z$e`MCkHUcmFhQb`5(rFb3z zZ65*K`|*J7Y1!Knf{2k^h66%a3VHA-a=2XLMzO#1#MvM&W}9Xyve-&NqQ_54Qjj%= zZBw@AB9d@%PPPHyhn2YmyHl|83CogwcmS{gceCK$z-bMV6<-7HMh`;G1J>qJZ|F|R z+8TWn&zNAvia0jZ*e&y6ygQJX4F#FHGf1yqp z#XysQ-%AqW%eVt1L}_veO^mm*AXJ6q7F+A6bPFkr$svQ`Zqjhq(mR&`ZIbghYQ>mz z7@5c|hf?t=#!0`*yk?8fuVqsw%q7(5?P>lYV;78pQz5de#J`vzSZgIkITv6i!V!59 zBt-1YKT^t>*=p*Svv$r`%~RE%^8oizjY(%$`C3ykZqQpJ4)TME&CP71fm_!o^&)nE zaK)6vQcMDRVWgHMLZYCSnSdY00XW5Dvvb3I$sk69JQhu$(-KwQG_;!aH2*}3U+xPz z$CDtM<+nOa8X7OEb0AQ>*r#QT`R=w9LH?7x#CUhRz8d*{-9D+h)Kg&?ps5zU$+HsL z2~8sCLB|60To|3s@)tx#<*RXMM=RRMV%Fpqs+pLSv>iIQ2~Nu_h=2E-zdWXw@ArW?{ztXe1vGs8ZDTWC}Bcc4- z?A1v;7Sq)=ecimZr)WcsVhw@Vgi+w~g{+1(iY#yW`%QWYc6%@9{QAyhmO|-N znnW=;rjWpzZ%rK^9Wu4yeAb9QR@noF!1V*#DZ=G5(T$`M+giWFmntw{yhJ{qTJ5Tf zJAzEDHcaOMawc`yTWiKYlJ{cKDFKEM?f#EyRgcfrRIviz%S6$1Pr*Df~@|jgpc9E^$V&`Y{Y;ZWnRo!B*J$B*imXHR~ z!N&Z3V#Jt+f|_BH?~T@4Df!-*RzmPifvGdHN{#0AA`P5;%${;tA1@yIb&1$M%3A){ zsR(PFf7pmR0~FEFIK>f*&ZR*-csiukMU0J+)R=5TpjC`h_#s`^cricJGWK7v;mbXVT8y`_6DKVHF>-z{%1Oy%({fp zq8}}d8-I9aRwPUY4H-%~tKX5@n{Xn}2#D@wW$ANh%f6B;k$%Lx_*u-dr{CoeEn-qP z;k;*V>k+Yq{5jF>2Px>3%82A9w($g?O%)eF0ZCa7>_Wg<8&)IsrNQwFNe8IG>?nk@ zy?iTnG7^Vyl4FB%3eX|m&YZ?T%k;_4_=c8vMSL5MLPq^@JDi0bi99R|Iz*{{sw8U! zj!Q^>4AP|foI%A`TSo`gWeUS)*q)PwZL1feZQ>r!gt%C}2>R-$e|e;HiaMqi&a$%{7Ahn zI{>kPG0dFOg~~}?3~LODVTr^rM#(5-XJvLIZ81RnxPrjt z+ziZ+#0BFqla?=h0`KOZZ;IvdC-RT6Nkq;h9;iE%KHtsS%w8y@CF1nwoRDI;?Zqju z2l-T1Xas(urkQxLPHs!8unTNS&NLk+k=m1~n>WxSeXk4Oo5J@q?K_*LxRzWgJo~Q+ z?Ab5dh1Ue)IbsMtJ=RtDCP?o$5?d2@HiI#qwv9MrvE3ZG@e&_)A->sPK{0`DeexXa zbR5JmeToBu{SyL?r>rhJ)YSHeIh*p%pArT6w#|$?p8`=K`H>l8*OrJ^m zeW{sQLherua4Xndi7vPc(1g< zl7Btz1LYuExYifvpGz4FNOv(`L^^$r^GVHQfk94ZyG4r< z;O`Pl;>FH?u&-d`CJzDKe5x1|I&Z=jSoPLU8Zl|gEwN5-pwb=(`9c=>C;$tzA# zm9eXULznhoyUB)VHO6l452rRy`?fXbVgyOwt2glkxs5sb!C-&Iwzf=yVk$H-c1}nl zT|?8N_BKI6B%xs+Vvgu@!b`W+>aFdjg&V|`onpbZGCN9^cH^sQJ>_HX#5R`_50AVwjE)`HQS>{SEy8;kvdBa*uqfgs|9aXpWr zWMDi5DOjjh&9owfG`NMmEMj8>md3lrhxZD$L7~)wx)3dikv$n|Vg2gnKZ@;6cr{7O zN%nt1QOV0(ZZJ8Ce2J}?MDS$e0yxsc0Y1^gU{7V%(`l)Qva1XhP9!wrA*IRN&0m3N z0aUa3#AS}KuxXWc9ajLNEcx1KU2R>VYOR?<)r3lPJ&YgB=9O%&Is)BgDcVmIdlj&w z%Yvawtp|8|T;h{*vX6d!in#zxVdqzaL*$aQ45rlE;*A_20pX=WBpTF!(D5t{PLfQ6|OH#7U@lBMvyazNb&*Z%hHjIWHo7(dC8idx0xa^BiPV z&b@lsy5e$bwk~4VR~JK18Q)y!LRou1RJ~6gdx2Jaq3Zr9ohKFn^RUVm%~qVUk^Qfc zmL-ymLzEvVms_SYRq6&M}rj=lYoRZCL8M&$Nwdse<9y z3geO#qmG5WrP{Dm0VA_LEjkkP1a}}M`ONNzhqaT9<@o^DI$$(p`SdKL&_x`$ z5Zd%QJON5-h(4)oks_u|_Qo~2Xi z1D`w3*wD3S1R3FwomQd5M*-?+bYWitZt+q!e@HZqPSrBpUuH;Q0hU2$+{l+?1+JmY z0-Z;uWwObDETXZ-#Z!oPbsXNk1T4LG#Jpt__o=p_rv0E-CihFg*wZN=@ zXr2}cg^(lNv-0nGB$oy234&OmtiUCd6`2~jp2%E7JhEfrGQ6`|hSw7-rQ5inzmnBU z4-Lylv{g2vJ3YCwre1vwuQ3eA<;>N;8Teslu-6(JOUCqHJeD-#I38=-uhgD5#>QF@ zk_kE!T9$u>ri5g{V`?M%>DE^C!Q>JvB`AM3G-!eBa`q zwGgV&YW_5_OWRvA2y}V>eW1@Z7y4QF*OT>iUi?cFx{rrKhNC#ne^r>UpnPJO!W;-S zxCluj1(88z9&8aRBwTiEQp7(n@gNA*Tm-&Y%y&*;>Sv#eYX6;}TKoOd40N}Jms*vo zD)y={XlN~~J{=e-HuhrgqVCNgtchOuYNAKDNYkHK7drPX-sMOanuNrp=C56 zu!=R~hWQQ{4brykWlxo`F6}~z-?YI2AztT=*`f8QrOJ3C@`sAvPE{ieHvZBu2kCRkgvDr`q^1q%|xU!Egfg z7HMukJj*{i7O8jnMcT{c_9V#YY4l3>DId1`l!fxAKAPftcg8{y#S_K$SX-sFWz=p1w;7sUvbAn2T=3X@k1>XO8YapM(`Z7_Qb2MT5^PJIIxat^M&<*&YZ zFuvq;#uMrSh%|6xZ>9JXm8)wjH;=!xcXqdVV{a9Wtm>ZqlHSVGuUfL;%FS=3W9r=F zo^LT*zTW%rSw zOrP2@lyuLA>aB!3e1acr`?4u+7evR!>Oatpecb2tJ;Go}>Yk~M8*WvOd*%u*)aZ|C zlW|}4hz738Y~W*I;7zuyHgE0DFeBUhtGg?I+eGlDjU7m=;#l4z95gjE|J~J^Wr4Vw zNm>NTrw+*4qVcG2`=telX5r?*>@BetLFbj5xBiyUdu6wCLx0tubyxjKZ&lXK-8Qz0 zfsJ5A|6#IC$q8Z|XvyiS3>*MfBIe6pBtE|~@OfSld_dL#7jfg|-yzv+oP15Tk=bcw z$0aI2^%V*!RR8LMF=Qu z?|u5qY%l7qcNGMp6#a-M#`M+bwnc|Zf_Tb67B%CH@1R*RIEmN9w(Efi^h_rF=ybTO zPoKI@_xPu8Rml*=mOz{O>Zr++!h9AbnGh;DimZ@uhIv}_zjYbEgm1XMFtOqc9o9jU zCrzJoQ^bizjMYJ{8v1s*I$0Z$=+-?x)PAVn)|o4ToOLBU=|$X^E*m03imM@b4aeNY zX+jg_a**9F}F95+$DU3eZe^JZg_$~x6u@Cwk)jlxtor>U|o z$oD}+pm-J%E|cJBl1P0724!hg#%-%(+0lg4H}pzH7|a9mwpEJ0Tiej2@2=0Pt;0U-2N1jdTK`)@B3oRkd;$aA%rl6#m!;H zOw>??Y%Qy}Z31+Icl$cgBa~`hQ%P{$RaOv5o*Y6Ubc$JxaNItQYM@Ts&ku zHc9qxg-?jKQL+6?@kP3Wd{_A1drxA&59vGm^B9aqT;C;Q%R07vAt0!fU@dj^)hNCQVz1+ypG2}C@lL6y8!XB40r@piXpW$_w18*1 z7NBk#=>*r);>Q>Oqx_v{*J5GB++x)=v-iiM=Dz5_FyFnxvjSGp=j1+(DMYwM7>7{E zrsq&&h3cpLvzag_A~?>-t;a};$S-O;e=07D#L&5|R1gnk!EcL*A4=PyL3Pdg42&Up z+B1}^v~3+GwvUeW!-3zuytpTtD_WOap8X>BZ2--&FKvvnI_#)IvFC{xOa4d7nv?CG zH?jGljmUXlRJ>1_9~#Omx5WGhrK4PyJy8@YGJ#&kFh5EG6ePNcns9s}`$&h~H8=e< z%5@OFO^sFBqpt{leXgpZ5nJ+XZ$LUzH=S}&67rhN4qJ7xdNP&^CNVtqS}7n!2JKt_ zC>PAVOgbGCRvFPD$^$k^*60*#6nxNhfhqbzOP#|esxz5XY*)@Ua6n>h$q<7*CNc`o z_3Sj&R3Am4WDdqpXbzf%Ik@TO;1s~9LC~iqsTU7qxso-N-)+3o*2y75FcOh0Z6R;> zq*+r8WpDr$=EICb8as8HxtxtdDVQ24IDRQfJ0H?2{`6(rI&|~$VxH8C$wR3WOC94? zOl7tzbuP6}5Ph&ZWG^$*eepPO*+?@Zw%XC?LPu=4rumZ3tm;i!)y=jlW+@4(GOoin z=(dXt4oO_?+9{}D=%Ark3;ni6KpWhNY^>US1=FG_&%jxY+K^_^(BiHD01wf;0su&* z%vYAe!vN1kJ!2J3fCFrD^HW$NsIqAJ0Bp>PfwVs49&=@VGFt4Bt%mVS)52AeF(TI~ z0mA3cnqssiE(vYUd6DB11LZH^6UWWjAP}-?djW~*-wCf|P|;&*_zh{VhE8M!>dR#d z??r}*W-X+G0vi1?+yXROIYN37(Z}gcK-s3rYc_-7k*<>%2ACEyQy10OnCL>vA{$hw zC2U$2wId#}{-{PRC3dPNtoI%h3N2?#r#Nyuq=j0yUTAl?$ezjq=IMoNvv)O;_SS~B zF(7>%nS>0Vl42d9SG0kzTN0@XJcVnP_93iEW&q`};S}!XI`@njNaRJhV-R9Bw}i;T z3=&3;Y{X2%u$8E3Rw7xtMRIKOKos|KOg~zUbi<54tX(t?aq+KVa5mcxMG}e>xr9eA zPD#$gt`+(x*kd?!&>z3i|2tBlbt)yiCF2tf z&!SGLh_AB$3_J9HZRCq5wjOIBuat;pZisJqCM*iUzlMa$EIvllE@s&6n^^w-e4@bRMV6Jyl9%c|b(QAC= z%v}vPXzP|Ajv5V3#(xrM8W04{hhm>C_Ug5RiBSQ^Jw^l!S%>DUja!}w6I;m|yU<2y z+Rzb;P9&v^68e*6A(~2}7~G`W$ea>o;F(IW;9?2XM3x)QajzxQg_3mX#~PE*QVwTwoP!)K84SeJ zJX(jlQ$FbKl;NC$Y#DMCi=*=7f;@7G$za?sHk^N5147U#zQlu^ zZ({uNnn}ucGzfR6l0wOD2)b~LiE%uCJ+j3(Bme-Uvy4ODPa<$#)p4AF z3tvm9Zp_J!tI6#nA9hzv0B(_Dt6-W{ZnFCmpQs*FK0ywfFS4>GrptUwDhcgh` zzChNgO5!jk44TN_AgbM)p~flE<8BKgFe9C4hCUN*KfX-*dCcypw z8V>77rT{C;qQ(U=yvy+Njiqf&{NLGmLnN2wU=kk01P9lHDKu3si=;4=(3(?Xw4ilm zU+4*ynfSrj_>u2a^E2{Q42#1T{De;7(6Aq$+~QuTk&w8fhi^$Q$o?Yr&g@7mW)Br3 zdCrFhwu`jBxj`qQ0^2#nMD8eC@|_J5`$)W&Go)lG5B#NULB0Vmi1U(LC_|SJsus+$2iv&Zq z!)yX}ND(m{Y)-N#N9v-;{AVLhO#vrnz&6@+Jq+W;E>q;ltg^C;=dq6J`5{u!wh?&Kf%{`X~!czQlPfbGs`V-wT zoV+EVY~&f~$8{&%Qp9SJt%EUiGhc&L(JJ9=mSG7P-45Vj=cw)Q#z#`ejG$51gtga|zPz!?$P)eI>gMw-V z-)a@ZPrx!@9A#gOYf)~oJ^2ez8nj2Txn?6(RMEe)d{> zCA>MuguxeQOq-5t*_dvSIn8K|IlHq+=ZdDFZfxAA?!Yn3TKs?{_a4)VVSfUcB#=@M#fu!UYR!C4#A>K=X^-1xAKge-f z&p)SzXOJ4c-J?1i<2cjQaDPnb!!lwRV!qbAaARnlv=*)ti%Vkb1QoizPT-zH>!dM( z=|Jnmu9Wn*7fvGjEm|j=QO5_Xfw-K}?+`In$F}T0e_M;mC)<>31o%Y$ocEqN-uuqR zGh$H%i796q+rASgX%+puMwcs$Qvz;)iDjesi}*laxJWu+j2m)9y%%9+px(D|&VLvy zm!#f?l_#Oz5W_ZjnEtK|R~4+n!|b~xl%v_V#9Swjn}vj% zA&!62)s_P;lo_^>Ajr0}J5w1Qmr|1l`tcECKwq=ZucF4ir=}~jv0CZMi7Tz=RA(hI!>O4{b*{Im4R_PfrHc%y&QXEu4AB;` zSMX&j^oHnbq&Gxg)sq2RMTh1$hK;CTsQF)b#p1NOO=}T zT&2$6+rYVNsP)rRsFC!SP^e=}?B(vW%*2YtiXwbKc3TwTe@LXj75na24L714`(sm^ z?=ZDl`u>mtZRN0thG-1Of?b6zo(bxos1#_iU70yz1O}{%rU~*XRooTDzN}_an6u)^ zdfGN!ncEY1Z#Ld2ImYDA2O z5pmy70TI6e&D6H|uDUIHN3ccjlxx`b<4Y04geXtXJNXVMeI+?1_O zdTN)Mvg7Q-ocMgH1yEuebKw6#k(!Znq9T+|B*)g7wbOr$msbfWpqLE29ROA&!q`kh z;nqSWY$#lXr=etSkmUAZy|%lo?KQp)dL3-AWByvZf_+#-r~)V{565Xm>2Wp4sX`tH zZi*FukvF7F*yl0`?PSYM$#&K%!ptlH`jRkDh%kG8Bh3D`+k&CDWg~)W+XVO}WF6*n zU6fs&F27e}VuHoCh}(OE4lhGnTWPg8I*J~BCV@gPNoSK; z+6N`rr{IZJaBOZaneD8x_Z*oInQyH!{QO~qQe<(T`0d+qJS9HnW5h$_WuX4R9pivp zGj2Y84~-9v_RzR%Ne_(^?xFFCpOyE;%hLinJ>-4yN_pCj@V?lV*1a!2#;;TMzIX*Y z^FJ-`i@%oIWZoAwzl)C{zEA!C*y}M%yApscC-ql2Z1Ny?&*m>LT?0n=E8rBkl)nP6LNmyo zZgio}d>g|P$EvuT31oUOY-?%dA9YTrLSSAc{Yl*YiFqpwMs4e7k+;I((cTJ2g15r6 zDhh3`{iamOxFRlJDKg zg9zHdw{8ymFSHi=FB~S^0Gv;}2d7p!gYp#|802CF8yn%kz#Fq{aBF&Lu))G1s{zQX zx}uN)d8?M;)EyXpzEW-X?@X`MWp~maJ1eY}xJTpHG>y-NzO`Tz04S=Tr7r zoU&ziG9TrX`F`KAy38pPp7sikN=iErOp(|k_;t5^9!4bFCs}i^%bKGtDmTYeBkRk+ zHS=!r}<5IrgTNKKJ9n<F=l~w#U z7e-Z0T^I!#r7-%)_WKxEquTEiY`yiGReS)A(IV;5fsw}g9}G3eg4J=^{k|ZQ`hFiG zY1r>GN%Ic#;PCyvn#{Rizwbm^iM(OIFUXwC^%>mn)4tVUzfb#Ch;N9sKe7G3d8T3_ z2&=Z?cfy3#3}Lkt5q;B-Zv8PEbDR*9Z4FgSf;51vw*7ny@qfOpzq@R}%kTaDoLKzy ziAA}E_LCqMBL9$jkh|Q8!W*3Q(USa&8ZNmLwcpAA$#l1AbtWS=L{A+ZWs`W9v6BWq6s;QHIF}_E&6UD$z zvJ*AvQf(({0HV=6;dq@VsFS`EHJ@rDC$2VBma;4@y`fUGVYt-^rlBQZ_av02rqS$w z=?#^`BTY?@bi(VVrc>EaS!`x{Sn5!dDs)wH$nhF;7!N&%6&&Pehc|d8n5gkLUd4L-%oY51LlouTR~um6oz!VI?)7D>fR^*3yxk;J zC;Ukzp2R|Zx5&LI&7V(AJv|8LHFRsCZ?X>M!ye0_j77PnJ5zz3!nkMvVK*aX9}4h1 z6a^}}`AJVpb&bY>i1=5R7e9VN0W<+_eu(RN8ti@I17#vs@eGlkXKX1ZfsW;;17FY* zd&U-pph)sBDmtz)9fP@EV5d^%1yl>@e93caZHl-lgJ=jJTzY}o_7$;h79ENlR2*5c zsQzi;5izje>dckhF+m3lj$JWsKfG4_vOJF>2CO|RN;DK!FDjl`d(525HOZo}P=4?R zs8db{FWK--wie&jMxUC(^Gt1=gD}ORQdK)2U$$1WW>1NG^3QZ&tgu7x3& zM#ed@2?VtRuBl<4np4&yL~|U=mbeQW;|VG6Q-4gLZP$9GGoBtAflVDeIW=ZQ+;!V0 z@g}MX7|Uo7(`o3vYVrY)stq73Hs#Ayh23~V6fc(p%dUre0&oAR!S-fbRIfoy0;247 z#|R3eL!_^!Vid+-1V zt6hc6Vdar8_hVtXp8}Qg#qrppQl|j%#oc~vK>T=0$bCbXLmbbK;75@-!vPRXh6mxx z-OqH!a9Cb6BCxxJ+}D~rN0S4EZD<4ptD~*HF1~c@`GP!jJ!kQF!z9-XxFPZj#&Rv= zrV%+dDF*?Qc%`TS|DNw1bVJR8XNn8Z@lt)(Y9dDdcwN3Ejy0ky(vcjBezo1BXm zs@nNYeTa?*M%uDt`1&yMS<(k|#ILG4Br*Y;fU#PyhPWq>?Ml>P?n&-#iQYy|y!@8J>#DB3MNqS@3H1J=ugLHba zi&m9%DNap+4z>|yt%#ULMH6@^MFg-dK1pUeOr{wlBR|CeSSaL!d{2m%L!bj6Z}s5u z;_KnmLY&>yjK`N`xs%#E9b%>m(Zt1GRiGd-i~%zh!8M*SU^RB@m%+IMGX=K9%_ag} z5$lYu1$^QhwWSs_)TOG!$2~CArE+wb`#x)*ITzp5sco^fn;Q8K*`w!|F|jgqmt_Ih z$wAnkU7=r@Eb9n{L1{Ey@^7 zx5mDksB++tzx)CQcueLSsesziRlRmTQQ<7sKvd$oRH9z-DH9d;p~9c++iZ=mZ3 zV~YkS1ZBxM?+~4@`cBZAdf(M!==nhni!nI!U|b&B4%9H_K>)-U_RtzMLg-i*-Aq8k z{g#!WQ9Nke16j*oJO4l^bY+Yj>ys<=@rR&VU?6SrjxlE-^X^bmF_8BJa(l$(%mrGb zF{#bgXzVrYstbQR1?io>!k4iNyv9~5pTROf ziBehMVWlki1eUX`LSl5IYytlA^%6A%A3eXF{*6kEHQX|i|X1|2?h^c zzN|v_9L!^((U3|gt^f_GKj$Fm$+xXbVJ49E3zD|9z)ZVZl7%j#jUTZE#%IvRjXgp~ z!8IOM3(N^(xxiG&NaF}?{1g{hAoQn19012iqv6k*IGhUH7x&$D@}D)_2RiwDx#wkq z7nZkzU6zqLIZm+%Udd95FoH^{lan*(NYYp zN^e}4airdOEKs!hf!;{DN2oWRfUt=zTgL{3ZAfn%$}>uD1RPG^PM{V^nmJ9q@q`E* zV_2j&I)PiDH`2(d>WxO@med=K$kp}6J+{L?AaZ+x-WUwd3-rc4CiL*RNOR=b(yAkb za#(d#J)*@h4zM}4lz+4wpTThLm7(!&DfTpnRmh-e915Do$78?nn?nrTOIz6u5l7>C zEaSM0WgL4fV~ao!mqfVqSjMSh8MpFJvJz0RZ`T(gNmEu`k1lc#0h>;C5)cJh3$zL` zkDQw-2yYRwo0xGefQy<)skRP>;~Psse?cT#5%!TcMD&!Vu$w|xNU#spkDmu|QTyAa zjA2ypo%(EXX5!mdncu8MTy5)Tf1A3+m4lQX*_Un;w^w%5HHhPQD%!bMr4*Pj;f}G1B!vE`L zChVL#01x(;q;NZCeh+5ube2xALe;gF7F^qnG__193fKS{SUEZcj=?R3YV?dl>C~hr z_Dg5WBZ2_a$MWsfV1+~C>V}$d@;%5dMI;=fm7`zS%q|}d+8uGOR^t{3AVa3Ltc(B# zN>4TTMwB(M@)HuIbV;yC8Jpj;$0tdIGaW2r-!v>BWso?yP+7m*dS6gY}vGm_r|&ffMr6Y;G+FPmSlEXy^*y_VDR4j z^QrWvQTAq+$;S2GyfdlwX2N^(>{EnIv*6bCT3;So+?UPOv=oi}xLtUR=utE*lDTNn zp=l^;asQO)YNNO>x_B*LpW=&WTp0{(J~h~YskT+n&pGC7;ZT!VrrsQAw6F`E4NQxD z-~+hdZyWYQ7ZE?c)9A&vqCC2`UmIMO^>|BMdmt}|LHU-IXW2sBpr$%y`yFsVcL4iJ zD9{qhI_}k$gVq+xEA-)V^`4#u9C_=cLlvq9xo24$Ib$kBliQk5!#$-$)pWy#oti6S z#7clW^*^SC>lLPcJ&IR1RyS9-+N)Qu9_Qccsp*{0m1ilOL)U-t#?M`S-zgN}x<=}Kv7c;q zpD|q7;+i-&~;P8<`u1)@3*3L(vzi5%j{5DpQ331UL#j%wtZ59Xj# z5I$Qy()yz&)hf&1h2QFLB3P5QR`<6n%HM%k4mjx+Ff zap-P7DRAA2?{*3Hfvn+ym;1h55NL$KC;bfL2}u(*zNH8 zibo(a2WFSYV{{us5vD^jm&;qLxF19JTn%@kHpgq0rc^{PGk!OKN&XPmvisBF4jZRq z?(3YcQ}Q!~DQ_Wjnu&K9bzBFCz-`7Rr-4==e`*uqR2|I&mqUU>7D2p|01GC;h~!xC zb*X2T%XpFFCU@isiFhMk#PAW!bj?!RC9}q9N!;i}rz>&45;X(-M$Tjr6w&2iTDe~A#0oCy-^36t;FAl7mJ*;EFOATYk7n)PT-SAD2xyHW>^^iQ&f_Zssj96`>)$1D;#f!w2k{;Q zGWhwW4F2%23|>9|)8^^Q;9>Qhmz+N&hL<%WhJz!IPz*1QBc3=}X&1*rI)~#N4Qc5& zM?zX4uM?KGaV7|Zx+WRD*ck}W8qzyLTD5Jjh*Z0nuZYw#wbcdqWe0j%0{pTyovr|1 zRhEu`|LFr+CN1*plPpq#Izky_5_AP(8F48f1-z59;IW{aO ziFLO5C?)&zE6F~vOqc9Ie+kM1$^I2C(t!QTOZMlxWIsCxUu$Hqh@~;lW19CXm=pQy znL~-mP$&eLPYAhacIo_;9K4e9kAx~`m_}V8!CcizXC?Z%m$nR6vW{~?EtRETH&38q zNc>Sx&FYoVvTVO;_JU!Pq5?QiV{Rn?GdJYv$P^cP7Eh9b+BA`PQijE;E$k!6pcZSb zNc{ekVkOgETF}q`&~^7%H^gS=(uf^mLPKGBnZ|3&4BuHS&0V~u6Ys|^_7F>e?9wjb z1Vi1S4H5O00c}&oiX)4r!4u?MJ~$~`!71I0%q)w(-U*-roO}@JUf+D8Uena(5#8*y z>TqPYd?E;^WK|qP#!oGb3c-U)@*lg;5MJH^jP1VenJq7!)6IOSd$tcvfgQe`bUM=} z(BTe}oJ>}8tF zOv-HN_dX#?zmeaT_G90#YS?}iue4vq4pOl(|16uujvjK1C(Zp|9|0j9qf-0ICRE|e zUNPT2kD2YzGlkRir>f&08|T!H%~`+DjjvTSO(6z2D(8Jte)YVpHul&)8u{mN{P6a& zZ>9lZN@ry$=0g#S?_y!(^u`<&b&7>FlgOD8Ag9^kAl?D32$C}Ff)g6v>*9pISTJJO zRxBr8Pi8uO9mTK^li?bxa2v<5ui-#P#FO2>YBr!(>g~IJ)oeiXsL}jlvGMt8`}_eO zxVX2vAF%po*I<@iQ*PFILw#7U3-85k=8AhGj=iX=+A~^yzwH@gHBfj@Sq~zMV7rk) zkiAiCly5pFa@{iQhOPuk;guxeMph5mj#*q1wi<`8{|opaBbfGep|_6Mbe#7ZN}_w; z%o%rMG(Kp8si7t9{Q8-b@+!ui>}>#L`fC#g)FL{>-ARD3Lr#i1=BH;|KjyllO!X3-d-5tawAcpg}M%ahaz9iR{F-YFsscK6&o#dkA@|?d6@>zX& za}Qg15hrtW+#YFW(1bE{GxqRtTi_nrx9Fm2Ugx1gRadaE=JH+5-YR>Hbw&N_oyDre z*rruU2n@9zcUQ@iA?}`KA{9L&db7eaTbKHNZz3jICd_zMm^fvkW8^~z3LT7t1-FR* zNY;+BzZ?v<5%NLag9`m<_CyGeC5b{%g9o>*)3oPxkkm0x7!&YF;~&BzgJS5)3SC@W zf_Pz-oINmiFyAF%P8HS2Ix*Cg4qH}xw=uH;knMI42=RKzvCO5Mr>3jdL5bhQ-6#x4 zOot%vFa=xNUBk?Aev16e7&0@#;#}a*m4J^WaglzlhZZxNe9yZt$?n1wrwY7tl&jH*}+c?2f<0SvgNl}z}uJNN;Q2m`37 z0ccNfU9f-mVxzy7ovTb1w`Y4`T7N~{8;AT^Sd?+R6&H2ALdb-rYKP{Rf`d;H>=ub( z+&V(#QCE|s9&VHOlCTj7vqILu)&{S5#)9K&Uox&?2I~L}g2wh_WY1XAxu0zfCOlD~dHQa^;05=OGM6cF;AuBj(hc zvv(ar4fjFY>11;@keY$=;&SjMbe6`hP$#!$JcS3ZMJZD&@>bAS8|C&c5OZr0HSG!g z%Wq8jI$NhVrsL)BYMvwa9~~uAR|t^ddzvghB${UaZeSugDz+-1;%z%a>GpS;@f8Vi zSx0DmlhZ!?s0MW`}wt{f;+sT<%h!&0(3_<&%c88l{VDj0hu*GdJ` z9+OmguTBY9rQrSOTcVEkN(y))T^lV+ul5RIZO)`iPpcw`=0^6dkXodrS+ERW&B9fD ztb}9ok1^URSt?=q+I_wjg1@{dvlQFCuQI&L6@+pvE=`luo)9PhMA{z{@ibo%)Q7E} zGOv+t@;tm0bpbns2X;DV=U$cSjsccAz8m>x=%p3bRl%uMDs+yaD5glN8+4T~kIZ6M z*K@f&ye9z2s>|Oh0oMB((^nl0O7oqpBL@!H&K>b@0;qYK{1YIc*|I{ z*mYM0Ppad2ayX1|CQ$i(UjElzy+y2XbBNGgx^co%?~_m1@01-n(}7Tyn31g#;nMqF zOm&hku&>axI{7XOIuQG<^?FZAiy_J$OufNl=vmcTIU?f1>!W;|5+!}rV>=u&WflMh zeR?0i!*U_19h#s|-x?>glsekbK1oW-a+Yi6R*JbkZK2SLBT%sGhV|(WYZyVF-sAf8 z9&7xg_Bl^$xcr`yKE2<;KUcget@P>Y8DSNdQ>kw~iAqg9r>#=^I2Zxlmp@{nz~rW5 z%d&%zth?7tf?_S=O*Klp7GOCc2Hed29++Y2SU^-cKSrrZ8EDtXjL9Y0U8k&F*DD{W zMIe@I*S{ypVo19_auV%Y@6n#6UCTqCq_peVxl*~_R4LcpMang%Qd6!u+`N=>{l4W? z+xN@Nz|lXJW2IbI&s@3IvT^0w77+QCQLd}9b>;eopIHx3uFoxr;iFNmZP%wbedXGA zh#>5yy+rwYOu0ry$^Z5=lxsC!D%WAlNy@d^r-o`=q+AnZcM9?k1$4Dq``GYLEv4nv zY6?y+F8J6{sO!qxNfl~8doFboO>_ViN-NfjW(6}56_ee?JiH5z<0(~=yMmU&}^Ooi*gFCSW0a~XbjUr z7(vxx!bO-yuOq0>Mlw!UeSS06EA^qSK0Damy5Q>bxu!m!dnVQA+VG`1+tou$!5~23 z6jkSZq3Vpt=BjfJz?V>+#TqA#K~CA{gngc}>imRCb$)d!Iof32pfrQL*_};4=D)8z zFsQwoJ;;W_ZS75&tT{?AQ+$^py$m^1;-T$Y68t?ah0H~InM!gfA}TnahJ<+%y-Zty z(#zNfe6LQk)buh5;nK^Xs^QgAdfCTQ7@q589N^?o5-WY6mo?DKj5wA07;j5`tQ7QI z$I)4&VFDp`9=T_uwpqyyuSQua#JK2y57v8iM%EGcEZxY9HsFY+PW-Gl~eko|N{ z7F@g4Q3K;KCT2!6j>z_7{4>eULCu&J(dX!iLVj^fiyUpAF6qzOxm7+!Z9Bn0mSy!N z1{;paCBkTq3R~w`^oBZ)9Cb-|AV%*sOeVXe=nx`jpC5I!?ahGWQMMN3FJfV(lteVK z{OwZ0kvOw#EE10AuW7ofci2_E|LmGqQ1vR^(o{T^&fiDBDF}6jxkJ@@4dIixs+7B2f!-0tBe+{C zGbug+(~n#Ol!@vXz)*;8goa2L$Vz9NBw4*XGW>4bv-QRj_B=Uy^gIvwheBC~l%io7 zTJEN?cJaO^0_3kWIQVW6{HU1=6>Mj8oE=QxBOT8_(8RPX;l@w)A4c6WZ$b;XjeVy- z6OdupMfNNPW-S)*Sg^X1p8wa7?K=Ka1Xjd7wU?~x@ zTZWu$lY zI~XB5AP9ZCK$m!yClALVCu4#MLrB;&)m~s%y0}OQyQisdokS7?6YZWV_$s@n79>^R z(c`~dn2#ORdOka?6t+~Md0|UcCDHmg7FtzkwXvm2AlSjPBy6cBY^Xj)yN60Bq0#JL zM+adi&H}j1pFpKOH6~|V`x-DAT`!oV|=bp z5o6lT?(}nI3e~3A^k9Q>TE@$13bB<+|3o}2d!sx3JhJC9pOR;;KMgg(_7O(1f?}G3 z72O$WsSIqcms>5ltgL3(m3g(dg6RomW*LcN|PVPceo z5YStTt?aPDTHerLV43a2(@1X>ZL21ex%2Ky&2rvbVG!~ODZ4addrcI<0Yb!U6qh7b+~WFH4>rmda!NEOzc}4OE7-CS^5dFxq=)R!)3~kOoqgp7g02@T z*#=2%3yibV@)jv_Opp(Xbta>{wlgp6feGAW2=P-%;|P3yz|uF_XJ8ByJl^3vf}NmZ z-jlMSp1?X*u?tc4A%`K6Ms+}h^CjX{`r%UMOUy~0S2!*@^KetWa+bWKt)lhEVjbdF zI3bD9c3>WC_QMuBfq9s|iW`7?_lV`o0O`!5DXV+<5Sv0V=RI6d{Nn?FdP8(m3?ss> zWBsi$5$v8!V97*+h}Aas;rA5y_MKnw1QRhkGSsV?9ShRQo=$1GUMQXHYqPp;5iCjZ zIV_#*lF4;v!+G#7+d-?O6MMH~_}w_!$#!z--6Skk^U!P1s z*`J<7K%o{^qAhnJStX$8`BDPP03OTBC`c(1R)d&gLtLMnutjh@9f&FW)BMAu#1sO4 zRAP#B-Hz$E(}rzPA#g7cQ}%SWfNQ0gvZQqKzEflWn2X2NqF}R}bW-Lkr4z9Tmrj&A ziF8sHMuu^RuOz?WvD&@5bn?1Z6*qa+Lh0men|2dY&RQs>tf~nqt6WIAQ9{aBM+qrt zfi9%9M+hmaOh{=CBoxuX?pdcSqgb@2z@?|5j+!hE2J^K*M)4b_wS8&w%!0h7jMDC& zZQh-A8D(ft#(_&2Wi@`hii=F2QIIPcMZTfI=G&GkZx;;6|4b~y1f1#aRL|XypemKH zLT17usPYwbQ$6g@_;^<6%O#cWjLSTG zsANSDoRY3pJ#A5|GU}v1rT9X1HSwIw^5MWk9$oeZKz)btlvhK5ODyS zb5!~L2r*|#h&hWPW!d|J5OS>4z6%I=$r?ntqU_X<-Dgk7-C&e_cBU!P7Wd)Gy(qReYx^!s~gjxf87?wfwd}$$Mz#vXt4lz#Q zqKJ(iW!^Z&;dCI1Tvz85HCY5sQOP3W6c#ZQCBYS1LEmJNW2VM7Got2fbt_LZzq*;d zBaYnAg-uKgvhsB2973?=GzXsUI-DS(OMi08(`DNqZh>?WeUP}i*L*`l5UNX|2dK+> zY;lMz+EjByv?(|SmLlZIA6rna7vN_QjB*)5Fou~Q*p33?SBKzSS`?N%fj$*wzn~nb zVv>=zzZ)~HejoXvm&mTH&Kd+K1-&<$K%cD>Gf7!x|*OC|@IE7A@56D$XmdA$RY=&8uz$e^+oC%_f+EL>`AHH&`yv0!i z@0EuH0t?JQo8Q>#Tb%xw`RGe-jjxnDoFXvAR|wV$@WBUNf4A^KG4Mi&9`UODzo3aC z%F#xz?G4Dz+;G!ps$w@NH~{ngd;+FXbDH1GF{b>cmh625026BJjvo^o`%GVlpN83K z{-G8x3?r1wE!MS0x@lipm(bUy-TJ3P5#g!{?GTvh6l-_ioV#Ga^73Mwww~w;q=VAJ zW=`jm5<;6uAX@iBnQb{?+ zh-q6^b>g>ai~lkXQfQ~?B7 zOXr`)G}OU`Nd@hpFGB6t@+fRec&C&#Si4YOt$#*_vQ=sv(ECGhpYc19L+C%CJ76>@ zE5V$wGPCSOx;O<5@jJF)1xni{F?3I49;bR^$hILW)Yu>Snh}9_@APh9EoR07|Yf}n3U^RvXt$K}cZVLR#PhtUA z4Id)-^ytN!vqWn$&fm}eLt>;P6EyQXgp>IVN%paEsApFfsNHa{?BmFOyYH1KL*e4O zdlO#lDqmb%z1V&%$v@s?NjXS;p&13$B8zo?4=xfmHH5jWY$mqwGW54{4VaV-tMxufaIpb z(KBM$YO(Vn%NUDpb7&E0kf(UCDzP_|*nHFc{QSP=(*PJZ^Oc3L-*_Ri6(_1fhrJUI zmh-~zVxH|UpS2_Y_UN`!h~e$_>g`c~d&?`rTYeWis<+4d?RDG3TYeWitGCDf?TOcg zxBNCQPH%Vqy9V?fuMcneZ9by@cDujbc6E5m??PL4{&t7IJzl=$ccD!~f4kG)-v5SB zmfyvZ>g}%3?i<5feiuipx4ZrA&2I{C`CS~V-tO_Yhu<9D^1C=*z1?eXnNC(KBYl@; zii`VSWr?J?_SK;n8H-(2u>(WJ?kkHu_?l4cx~oDlG8Vh5VuuIC^1sqLKJwa-k2l4h zD&NtC`A+=zkdHUT-YVa5%U7J(8Q$`{n6GeX-e^$6U*D<{kUDL(! z?Bo|=oXnOcv6JI zE5iG5B;W1?9xY;}EL~!&Mi(h#b_oXb6dut{E_792Qk9LO5egC>rYfi+>aw3`X7Va8 zf+U-b(%D49a(YqNChF@Xv*|UpDrj5gj|9Oc!__)?!A2PUizu0;D^%cn5&}}Fg26AW zA}WhYdO>hUD9j$u$h_CZ_PY!sCM6h9$X3upjZ|V#?1NMfflig3tTa@DQ9~UXW37Q5 zM^3AOGW$sy_@&TAO@<}{+rtpNkw4sPBN4ta7Wy|IU$WLuv>;Io=2EJfK~QqBWzr^# zpB^3_)i2s6N?>WptRtFTkH)!#3GH#kk`9=A6BoW#iVOc%(BUNW0DRgbso;mqVCQTM zGiq>WOib%gIUZHTBD)i=c5HwvcdLdF5S`90h4S7oG#DjKR3p;V(k4Qf)$a3zzZ;BT^!EeAt0m2xV z8t@mUy-1%o-LTr&{Tis;YRW`t7G($Tvq*Pm13$l&ZP^32I2*%o;d>i4d7{T7m%)7-lfM;`orf z2%{m|Tz_n?Hx8A`z0^umRu$y2pQ$_eXKIt1-Kw>{NdUZ(T2SmJi^e5u<;2LoU(z2p z8J{i3TnBx}AU%_X9U2|)PF~9Kw=pj^?poAjcYKcBpt0`wmZmmfIpRn?PWdubFy3XS zOb5S#M5Zmtx&8{p?xyBhpdspqRnTFbQ+!631hPktR^%`;IE{fRQ%TeUwhl-GI@S{! z6XXzFNg2rU2bz6uE!0yEGwUgASm;ovZ;lk2s*qAJ8drSQZhN9jOFhq#VT+d;Cfa{c+ z5K1yNP+Q+{*)Xi^ka{95j|>+~;-aB8JHEr~eT8(xFM0&soN|~>z!S_q-Lz~^ulz<* zPzvlfPd=fP*$6->OgE6H>ysV;(_DDq3TV}xtqSvJmd1R>>X^@Xmco1wQ4UwCFrQQT zvh&GlNm#$a@i(WLT-I(}bJWE=VEqci`W|i!y)km`U}IAjpK$|RpX(>IgWA-xDCW7K zY%Pe#juP-tdO9qPa)>G9JXHz!QAGWVzE$T-FFW62Obn9DN6 zyrD6y2qmdW{hHLrSZ_jT4w+!@!Gazfh|_1#H(ry@Y&B>S1@%IwUg@+ptt&tCZLew#~OfXps*sQ92^P zsJmf-f`?&oLd;qL<}6d2y6%jo(-zWqo7^m$Y?(?sQ9_Tx!UV^gy2Xa|q(vnJ7OKmx zR?kx|UV+)yxUFA2ttg;{JD|#nem269 zzVVY-=Lqxv!6m^LX4z)HMod8stOcR|a0}oIQF#vU7hmB2we%Y!T2+0Ly+H?h4Pl|9 z+6QD{P$Xfi6QN*6^~u2$3BlG7%mmBi;8~y|uwNR!{~lzQwVEajsA|SRBD7~|2)&ae zhS6~&6zF4U1Bn_}C=^F=L+tVFEN3snBhI$9s(l0(UJRfRPb3$!y%D)-%q5?QF7~

    ngvH-e-Y$xkbPP(%y&Fo()$MSu`$Yq`*Z|(ERa~&h1Svf*E*+!u#>!;r3

    C32niHzf_ZCV+vz`~5I8S90ZUWjoF+nC35r>~;FJPx*)en4_)g|?dUQy=+h->`<;Y$Eiol8UK z9wZtKqX$$rR#pn%8zT`szLFj^hmjN5!QgFuJr>VRHKPQ|2TyDk97Z)QbJO!CJK~Z& z2|&^Y7C+104tKrQbC`PDnebXLy0pi)R3O9eA~`93&o?;r1K^-UeRdx}fe4on9w4U+W!Wqf zo5F;ks3ks8Sio2y_z!X(P$4)#RMk5remhinqD51Xu$U(dHPJji~3#C~KEgL@Q6N4|1@MDoM ziRGb{F~A=7WN{1vG>t79h!0bX+>p5(Bnv@xBIyVdLA91@YKb}coW<0D?`#kK)G9QD zfvwJEct2u+W=S%)6tidb!RkRiaWw>BVP67W)mCA}>ea#dKZHE(al0TGHsJdu zuj{kU;QNp-6IVo3*@7N0>cxCt#+y28KXtwj2ANzSJy`OH$p9TKfQ5CQ8BQc>18col zC_B{U6-%>X2+K)Ci&GXoDn^KgFAk;ocOH0h8u9IhJ6t39E{Pm)Cry`0f&(6Cl*BCT zk_1Z*NC*|B6PXY@qRt}V0LOTq=Hm8J9yC;9m4QzaWZ10b+A01IXMTuI#{95!#C7IJ zW|3T$L$jnX0S$?cB+aW+ys)alcpf!~=c%H=^O{f>8JL@oisu!gE5`Q%i(p{}4hZuL zBQ5)Mh0`Y&2vMv=m53O(uxmyfMRaOZ2_jXpxj>afwj>J#sx)BA41d6sIaxoTN`#*m z!vSn#C1q+3D3f*DC{wkhWqxv*Un+CQguTF%OsO>z!@OT2!_Wl3iuk1L=vc}ve;~us z?8vmHNT}oCbI|gEsZa+w0rv_=AAo99ABr387*VSi?EEm|fSKaLu%XsqvfE-FLu^RB_Av$4GiW3R%M}a=#39&lU_Zvl z>g=adK%*}F%;gnhKW9e}jj;1<_XL>}pWDArl=g4S6n2_rB6m+e&-CLmQ=6JLL>+Uj z*bt3{1EA9Var!f7G>aL?4{hib2cC$ZL6#|b@}|i|$32OwCkjt(7!=(1ucezN8}9qp@|z}cnqk$5za=_0o0|2E--&EV{G_j( z?selQ)!7x2uGD*O?H4ZTHELF-_3bZ|aE*?EAifjTUy#Jx%Iv zA5X<^Cd7uYJhs1@DNk|BRQ{?~agfyQmO4!8U6#6!)b*A+Mrx;}PLTSnrM7=FDgMe* z*O1zAu4>su>TiBQsT)Xr>xoM3CH2D%O6@20;c2A~k@|moO5IKBWh<3pEWYc@Sky6? zl)kcat>ZqFVqy-2Vko@OP_hRB!j2LMSCv56d9(z=v2QK}0`Ck6dzb9`XdDN48Np8E=GVCY0+mnY#?)Bu|BoBDn|hd{-92A}cFdu@a`hUkgbw zNy)1A>)+_vQBrTPXAhEkORi`0-%g5Gu2t$PQa?CHshy;LY^m!=z24sL zA@yZjDz}ijZ=>=ZAoV_bdl#wquhFw3q`ckxNnK;h>^P}6Jzj6OF^(TvPj`^oV`Z-; zb=wNP-A(GRY{A`3>eJQ+@N%32UIl{}PVpt20w@EVvSr2#!>O+;Qwiv6OF$pHzXbH5 zvSbBl-Wj0z4uB?4vD5MTZjyUFd6eYco_vtxgPxrKr=+;*9kvFpB6+PRcaq%W$?Hh& z_v9XuM?858$?fm7Vh2d>_T*h84|?(l$zz_ppXB^5%X^&U4o_~QySqHOgJkH#wIuiW z)7>QZdGcnGhdjBDiV^)p_T`4MFMF%L>?#XZec_$;h40W8@)Wxq95;}>!IRYLy`k2EEQXri z8;UM~4DYQs>%d#y=~?x#=9L^6w|tRmUY#=wT?pLlxl5 zf?UwRk*dI5VCc-Z1vc~34M)Bx~1Y}4^+^% zx)<^}*;;kLI*My_{@+ym^650&K!>#V#3sBkXLGFb!Qs|5hdoEOMJkYgo6U** zSR+eHVEyZs_i18_KWYfN{wTRbmjhtcdmfv7vS1Mywr@kklAz}ou5F?emVp0YD|<=> z9VBiVO~lPpk0gZrAQ{<%j=GGTNimQ#y?MU;Z)-m9-ZS>tex*^AJ=I28#9cP!Vl!Cb zL5<0CGA@pPPf~6_lFU3aX{rfF;TW>%7sdA7A{qR8E=UGsZNfI2vU}PuV99lp z_JGY~gu#A$4#N$RSY)iB4ENv=UWh$T-VrQDC260{$s$t@S=ZzIL+D@(z%{eXH8Xaj zD4^?B_RGY?&a+N{QeUSakkUu=ObeKhC>+(&43)uVwa?2h0s>jJ+3j()Z7L;FU}82b ze3CRWnQ{$A91kmD)U04cD!@n^z6iz(U_>E@QL7H4c7PEeslb4F8@waZ(g+x|7s9}_ zQ`a+nfE>t(4O~!SRLJ~?oL$MDZ>nYjoWq?pD4YVLAAn<^<>9xaesxV+zq*FpQh-wp zQ;XqH;_Yp%!%QszQS?}88CCEpg~s8x2cNR#L~(V1m=JxV6SxNGo+O*LrqcI@ee-}sP^AZ)GJ}ICOC`~)Ud9r;YQh53c}SJlft6*<`|&SRS^ct zm5usIqU`tTlukn~#(h=0IYAIoGlBLo%!>BemrmTQQndEfc_?XRwF9%^7|i@;_5^1rO-tXNbF| zfb9mSs<_=yM5m$i1Cq`3Oc~wbnMcqLef^_~v}ny3>M6#x%o)soLnb4UG~u((_GmO5 zCYfWUd;Dr43W&i}&?nuA6hS56904Q9t;J-Vqn!2Z|H0B&6ApCpZ^GI`6}6ShxVkJz zv`>+B9Uo*#CKXfH5ibhR5jd1qo+w{Seh`Fp3u_O<3%q554A~sU7fK7^vMEg$`QRQz z!p`2Ykg|SPBE^}au6xbqQ=_gQX$?`=9|!6xRasaj0;^|?X(54C7M)JiZDVGzGD2&~ zF)I^jt&0#wYduQZ^0Zd$QVU8|%DGTBu#=Npt2w(Zd11=c?7-lHf>wF4nT~*Rc@OyGBbkf$Pd(hP4c`nFEAe2^ZfP61=*j+PQJMj7vhQoT&xw%p|-;fK4)kK*`_$EE69c%R&QT z77JdP6Ck%B%t)8uCj_!f&$+2WjIGRD%eiJIi<1A3z4wl5;(7kZ4{1R_0g+-27E}-n zML-B#=%DnXVuJtyB9I{6j$JGW_AZJAR1|v)2E~RI#a^+C1+aJdKKGI!FW)cUpYQkg z`#yeu{Vq)QW@mS2cV>2W?)Gx<&@xK)#q-!oa85YIn`TMUo79z^;y5%5I>+(T2d1IEr=pejU#&cJ%_;P#`<-$RZva&1VfX8%f*(y;GmR=OpOkx=PYma5!(jw1|V!nf)Y$*51#vJ({9$-THpbVFy zf^A=A%i$PD&@aw>RU6c2Zj~FPyfy!Km5WxA(tkyC!<}l;NjP6 zh|W7`;s-Bwt@^^HD&c8%(rcK$J`yyHc?#3-O-|*rkKx8l84MFMMPW#Y-iRS#(O}G6 zMdvBWfgzD!GpI3!M4lhO5HNZ?r;9!k$KBj8o?nuUk_q2_w?Vp$Hq?lb$zo{qnmj(P zC@pINkG08VMpg*$Zcz{0pycr=Sp{ZT7z;5bW-O2#1}&ce|4|o)JxDQ4yQyPpLf}Mj zs7-$SgQ)9)8hKC`gHlXPCT>M!fpV=dHD!}l<~s3{KXNw$lcSp&X$#|$wbeYyP4F~Q zi?-yG9Dy5J!dwLxXdA9o^COvVWCZ`$?Uh&=W3gm{$juR4p)*Fej7`dW!Yl{GB#AIx zVeEYw!-Q3l%Mff7A?N>@K`FSAc(%o;H5dPH4;!-tBl-J0g(3W&r*eyzO;<8}x#7!X z!I(ZqFJCQ)REX&}k5F@cD?DqXP={&@_W^r)$lUFLj9@t!i5Byi3$Cg9Gom6<7P%(1 zl}#Tl#q@#4$FyfAe*bQ*Q;F3v<-2L7ny8~!%+$i~LJ)EjAI*~aXkwXYkr)+m42+vb zVa*n{juoicLqJE&zi?x6h%+FwU*>-_{@D?t<8H0lYNR7Lx9x^sLZBnK{e#(w7aB54 z0IJ|Y4m`y`c{9Vq1W;hMngg26_21;v!oG;c|1oDe{k^89rXh&rZa?nvKqjx5s15wd zfAZbgiF~iJAm6`CG;NsBKyeR{gvBOGGWFsChD6+JLWqpFR*>KGUnyIq)QvrJI>rEf>+0h|UrA{ap_Q_g zWfWMnZaX|==fRXMZJ{GQj{?!zc&6|29??B zG8(Itt)VE@0V{OIA z006fi$&E&e3vdRw0B8U?UZXu8QdfW*z#ZTL@C0}Pya7IdNmTbtL28;%EMnVmIBY>$ z>y%VMjF8Dl7Q_lOl2h1mNn(DwlQ<)tohgX1Wv2+U1xZe=g(8Alv&CV8Yz1b^7Q2f< z%Mc0U#Hq>bG=6eQk|5REgPoR=%9P6#3uD>Ie4(g!pYcpXY-e`5AUi!HRnS{jrZ3ZC zAGVpSt%?8J9ZcenMIU=7iDUTbWIWDnP9L_cmo{vEkT}h$^?w$zQWUXf^O+9*XAx^f z5nDE&8J%1bilH|PMmF}ABb14bor1ntS#sF@m~L2(b7IFQMWRDOc|TJySR&fqq?eZ2 zePzYQ_GNP{IekgZK2D5K&Y7$X#j z(%H#^WO3?PDny*cPT;4p)5T(FKs1&eJvLoHP&Pk_5t@KVOI|oF$S;gdMkbC^WDzy7 zV-hk%iH?6zkR=jliT<4!_>V@s1ktG(eDr1@U&N%z!n8D@D4y*%j2$bCAp&8j8A)TQ zu!M}%v{*h)G6YOIL=Y>IorUsYF@zMFAtH&tm`S`+g$#zAp2_`s#`fz;M3Ko)g3$>@ zv4U*M!ko=!bB1zo#u;kP8H#fYPPREGn~kh+5s{t{#m5O^*{R|zDorpZ10qBgLD^!= z70iY#DnOh`x<{pm;v>@p>5*~5B-lAymFiiRN_ql2K9xU~2reZf zoyvfIQc}dJ>EJ_TpCn+D3Tf$lj3bqFmXvbMh|fq%r-;JR5>U8#EGhg{ezG7P9Am^8 zqIAkv&NRi{)sOurQPHDR0VI%0WGxh>V^GblrGi}Xm*r#$Vd(l9D8p`!hKyLnO#f5yTM734jsA!X<&9ue&=t zB~=VN6tH8G_-TYqb2$$|rZ7g}Cln?AYdJW4alDAJ`TuOD*;~jZ23`u`v(v^VM~jol z*kv}~?0V(mBQrxj+DOK6q)|{s3=vBjA7%sJ!WY4uWMYn$`41;HmJEIxh5@(4Xn{17 zC=jIl*;aGcetV`gX0kBe?H^)pk=qUglaMNg)xqVa3sL$HbBIY0#3VB2@MkfZALJ%$gFrcp`4XqchQq#W5j(LUCGTG;Gn)F$Ol7O8EoEkb+cCU&o&Qjy*%!JyV)T$P7njvFZHO^vG0r zlt^JRKOUBz%H%US87Z;+bU`H6YBA%rV#LXaxv&Z%W??e1rcna{EoLwy=Trd}JrR|b z9_#2x97GCPEh%?0O|Xc|#>Y6Z3=y-CQi|2-pL39nwHj`R_>eRp~R1^{4ZFiZQmv~&zSx#f7U6p`7F zMPE*f2~+dWLQG98 zC;!mcf7Hax6UsQpiX&6wqa)MBk<5x7hZQ&$G8Hix6Vo@3ya7Uh~%dtHi{GpvLa<{e+M*(jMCE;!9jC#@>2hZK^TA4T#*S>WLb&< zrp6Faz(>aBswP!hs}g}iWq@0LlNRiVZ4aM z(t_p@{mxOi4_R>Q$QFtaj--k)5lC|}Ox%$^HbnrjwFn^)G0T=9hNN)YjIaJDsd<5J z;s2OA3fVFYp6|F!c{}b=r@T; z;$e>eDACda|3Q#lBs5DSR)9-OG$L{R|yqlLib_Q%MPl6O2M2|{INV4`4b76JftLmq3l6qF!6K^)5zYq|8|dWvL+ zLGn!e=g<9-W*L ziRc4s9xfM~uexK2;}9XpN5SSvE}N|+93a;+OlS}@UPc z0Tn|+*~oY}PoTZs{Q}(wMTU5~`i1%Wd-h>2b5ID^(->OI>lQ~gAQET9C&(;G zmdj`*171-UPBA4F^O8YuZz2^7lU&U(LnhbrUvm{c$=AmtL{=`68bytyMo`255XV0+ z<1Ac;Mhv5R^4UG3**#;~J$)1*U<4Hu80tHe8bS@G!keQma-l(-rffAP809a&*}-s* z7C^ZIHnFp20t$H|GX70aFrgHyIH^hnQ$bW972p~`1^H91{*<44q^qAFHHaEW`Qo-7 zxt^D~XPKKJi%NL^zQq{9N(n z8{mceiypYwD7)w-w~GE;)yQ1=Z>t_dcg3ws8n-i@DK2hsI#L`fYa84CcJ>YfD0j>7 zFfR)S%F5Et(#9UQMEn1T|7JotW+CO{8X_rOi0et>5p8iZ)ymS^(#jflSp%ba4m=)* z!=&DPE1M9WgMU2V%HEpiKnJ;s32tp4EGBeo4v!NU#o=)5$rnk3IE2V~u9HQ2{m~9G<7GkGp*| z(lD-Tm>Y-3OR{sfbpzeUCII<#5XZ_7hI3s0_~6_sG%!BN&(%IT-r6=yG{`cR=~LuzHq2@-+Maj_4MC*=p(TZNJaTmh6lhl_Ts#B>nXp0)}W`^4MY1Uf|}@Vvt~ zJV&0N8!wjQ;>b$~;Q4WQG+!LR<8lJ+`C`%lO&Z{GI1Xqa*pI^*=4xxj=h^v)e7ROa zo|liGzk`)O)Z^#vU`0dpB6m8%o{mB}`v}~oCiTb=qW$fViUZ^P2h)&&n}vg293P`C^`Xa0uN$i0J{-fW0-x11E#&!TrTp3NTi4MJp|&0lwmi8Npa&dI5NXINkRMG_o4}YsK}hX*cFsZm@kv~s ztt|(s506keoG4jp6~tipf)=7kYjj||aI`%qDA3wtBu#UI60AMK{dxAnC~J?fc%FSy zg0*+}Xqpoi$Z@xFu;+vk`7s9-7)NAbB@T?|+6USvi`~4#kS4jhd4_SUZFzh*&scja zTUTLVY?8f|JwMVp%!gxT6YL_d4@(Rt9Y6yy2^=v}o|i3BuB*3)EoT774=EQZ&($7u zunn|Fc}V?t1I)|_;y47x!W`nGxHf~GgE-z%cJ?;DK^U=(ixn6I@$3Slf*3ke-aCj< zA?XFh;SfvYa3F1BUiLhX@X&Z7lh`nkk9|Z!U|g6V7b(v@iDQp^o@)XJMu1b9y?P}{PriUcCx!NaL*^|OZ<@KS3C=Mn$ z8c0A2A=HAQG3;3pOd+!0QtT4L1$F^Fu-u)T3hknJgoN34cCsx_tD(}1PU zVyU!m&r)x%-h;(5WXX>n?bXx`nlX~EK$z5!)gB*K435@f{F^`*b9>i}XxRi%AvYK8r}s*g-*(2}_GDI6yog0YF+94M+sY`U6Ff%>f7@(A&?(M$r{T zu6+E<*s{LlAT0)vqX%{^SxCFf({A$AM4mbzT@Gl4GUPlLBGzu*p|#<9iqe6w=BrcG zj=30vp%S&glA?03J89Dix=K@`sBaYYA_p6z85q|~w1XYb6hn$K9Y;~qkxx;du2U#R zQ8gCin;f5R(X9`q&T@L8Nm2Kmzx3G={%+@!Z*JMz1E!rNMIS!Z@HIIy$?Y}h_Sc73 zIn5baw_?G2?ObK+V@hajy@$!q9XH_t>!D|xxF3nLAK6cMji zxz?h5ajV}!k*k}#ho_ek4jml2I6QEKRs~goX-QR(LkkCKgS6Giw9`nD5BVa8qAgN})Tf%LCX!EZifRHT z!$~>P25Fz0|PE7rSH-?g4I@T}R^(Jwo!9Cq9B@VIYkGrdlk zZjO6quypWsyZxD;+T;aXwA>-8@3MB(eV3z?eko0HJ!Z0=|4_Fe__EcmF>f_;eXIJE z2EXPY40`X4mxMPE%8;yRm1N%9U1>!eU|s>UR&ay8!j7i!~Q_l=e7$1FZJ6g zZs@u$@&PTK+(hwmDs+PKtJzV7wVaf)Mir0gC-lP>U+odQ@riBv-VZFF*=LM~F2C73 zq4Le z)6@PL`#x&;=2jU;thm)jSW-7&?4hsP{_`(%9=Yb8MRMsI=ZWP%Te(d=t{1ZKO1J0@ zkE~O7zf<#?dCFk$((9&io1fWb?*G(!;GDA^hONA9HhSwz$8m?hwF$_(*k#n(`<9{| z^)8c+{!(_IR@p9eQBC)lqQ^FAd)}*i&pK^5WZ8{g@mrqTXC3&gIcV;=j>A{oF;Cp~ z%4z(O?`;DYTct* z;oDYv-K^b0qEn|X+_3xjl}GQC+jX~b4~E`{Xu0Q*vZrID-dq{lNtYupcoWAk= zGs~#AgU`@}?AgnU51zUC;){lHp8>uR!m+t4N)A=ss{7iygPG&NVWY>*S-JJ_+1oF_ zX?8Ss8Zbq8_zFfZ%NfYL+-Yz+R_w^6$&KA!8BazuI=~M+ZiVCofpHQ+nw^Llc=KOF8OUefe$b4+m?kFg}s2 zzTm^?l>VDy>WY@cuC<YX z@7QIdea0Mmf8X`!^odt*cX;*WUUKlhs~=9!sF^l+c~ZNI;>6f-U!#A%t`f`%9HFFt zD@iRT#<}gckJ_yHXV@aAQ944uC$3S~Qpdz^xco$!>wQ&a(9ap#R}%NN-t?__U;m`# zyWOr=9l68%D%t)x>85qYhzFjRw6EWdaK5~4JLi_EBXvJGC-}x01Aeu1--o>>-B0Wp zykg1WOKmrmA6$E|Rd3d8)yUnqv`+P?)7&*{g1DcqU&7FBo%zR{E#mg)yWY)I8*@iV z!oITHOy^od?u=byy6)Srw&{s zVhfZ;#60^DoR}ERPwI4&BbX6DMZbHqL@jCjCZ&$YKCq?^Innmxsas`&pt=KkFApA_ zJ7M;r9}ha;i}tm+-TwWAnt1}htKWz6cl%!q-shN3Ns1nEj$C!!^kCqPB{!XuPh8&k z{loQ|(RD)iAGbudUbEv%s}DxqPP0()c-mRnCep9<)~X5G_qbzJgSNW1>ZPNjd2}XQ ztE%U|gduxoh}jxf;|{HR!oS$&>-|y7t8Vq_w!FG*Z}E-OhR%B;rfBcAbQ)29pfu@l z1$)}TH~aTUS86@lue|cguJi%k*Iw?-y0WId=^d4626xl+G-Do5cZyx?GCEni7en{ za{Lg<=6h=U=s|Y7eQuj;-}LL)dgrHs%63uXR9q_?q8@}lh%au)6IqQtD)gGShkvfa zv^YuO6>(3yM+qTIvb4@Cdutv!WYDTxKU3B4qfUoU_SP)ly>QrGbCuD1Mr>)iaop-s z^}e}lZ}siGsTHFXtCEcdAf(61I(O+ts68WB&k_@sRwJxl`qJ1N5 zno7X&J<0?4rtw=o8$?z6dkcNEwKd(RFWT(! zaQF2)Yd*Y@d~qpkKO}oqs`V>pyP8t9;QjG~z8IUNteent+o{@^{PiQ zw+&{t(iz^bba0fvm0d-vqA=9Mpci zMoMazO6NPfW~fQ7Zp`dn{K((qLT~C#w8&|W`p-2NpB>p;GHuK&s;_-@yswR>%e4$n zM45DAW7n@<%f^katy$Ig&fZ_omUa#2z zJxDiOkeJ!|(*^4vWuL-Vj63qfj+?V8)M5DXOOv8DZQX03rTWewF^XT-Z%VJZK2P49 zdN^p?&zY8U<{O8c-#^J-?fZ@8yo$1)HE|z0Eg89JY^09kbz}39d;0R;CXODzv`wKM zz5bc@&=VQkI`y>4AJ6-G?@EL8*}gezmzsULS?a$?ul5Ny?9Q}^(-Ti0oZ?k@Z;+-& zsy0VtsPW2vZeVp#{fsqVT`M=Q?GZ%XK55`oUU)ZCzwJu@w9!YLUmN^Xo111osN3B! zDV~QOT~`{q@lBkwsPNLl-m8i~_tMcG!#5wTzb&rv$eWQH?@#((OFLA|8uo6!<;T7I zee;)`y8gQ6=dN7iG9%N-xs%<`TR3f)V=&@0Z}`UqwWx*Kt&W^4@W|QzA@73f@H3yH zU4{plKIok2diaLvi}nSb7o?OW>u7x%oF(LTynkvO`%qEc%%5&M%UAXizzn;e3wz^O zt1)WA9g)-irKcA+mKMH^(R`xQlQS)&VWQdX5-)%0Y`ZI!7q$0oR^fHha2r29>GC~# z{<3F7UyR)L*1Kc=(r#S`T{;?(QhaBTvr_sswK!d`!fuV!D$gZnufKMj_hxQn=^Fj+ zuQsQ7nY_AP7hhdI??dL-hv(06X{UL2&7iq117~zzuW@gU`~CEe z?I-qK^?7T&PE{?PZ*ITTVB+G7OV_!#c5-VMa-{IYcjr&>MdkWsFYL^|mF+)cVa!>Z z=UO%)Vu9)74mUO{U6{lkA~G%9cPQC>?)(1RggsVU(6dgI-V4&toNns(Dempl6i!Ha zu)*xYDm*Sjhw;fBfGcpEC1kmdfL&>-hAQSWA+f%>|2oQh!0u~f z(_V(J+UQ<$LA_&Wzv^oz%NEV|4Dskusq%b+`!kOHnVaLpK8~fQE+(~E8<2Nv*yGUL zRx!IqZF~Cs=X-&w*};0Js9Mpj1HLa7=<6mVS3dalE@##xogtQAygp=RZ|v^;ekGoR z%07Djqh;sC8RyS>>{ue{WSNz?uh`_wo8FaOHy8a3|JA+g)FGREP1^R{_UYIj+kGo+ zu19nB5OIbx+UD&fL6+wRntU-tjBZc%fpS8C?R$sQy@fbJ|v?9A%%^*|x?v*n7WI zxz?pcmv;xIuN*MO<@ljRb&2%Jfi}`!Yku}Qcz;vLFb%DKT3f?*)=%u(quSnkqjhb4 zw^;Z68)hy}Z9Dvg*@8purfD>k-O1IC&u?X8ac1h}Z+w+m5d)?R@;>W*yRdViQ3o~s zfJ37eZx^-iy0C};x|H`%j7@_iD^AQxa$ED(_V{GeH6DFtoIG(ZBrouz(e+D)mnQqV zCiSW+I#L(O{j%%9{eDIfv*+<{jUKKU5~dq^W&f#fVYPw{S6l6l8~fmq%U9?A%O)o- zz0{QJIz9b>=G_nBcQaCzCtJLGSo}D4(yJp+R&({D&#oKzsJD-j(4bXB-G^(9;tiR_ z4ZQVa{y*Fw(l9OYs%rGTnJ?9D6l*@`e|s`RGNDauYs-gPJAw`07%6{QaB_y8DDB42 z)?>eRdUa{r`&>N>C&Fq(6qt|no_4`Gvdj$b`_9m{_Z_B3x|dXDh}9* z>j&SsB{{TD#W6H&cY=g#U^wtzq30&)#LB=?=L!lPk4atcWWCvOXltU!&`txk^?vd+ ztt#Ze>TL_GG6xQbSz&48pM7aY*JY(cS4{M)Kew>Qz`e02e>|JJ#UzUFwahxN+nP?| zO7no6^`Fj+=J8g}h)S7%c*>~<;g35;NL!U^2E}dZxoehg)~KiF-|kfzS2R57{@v2~ z33+Y}`&h+ol!tkb)=1wxS8D287hPDyy86y9yRYTq6)Pu<|L*;*pu^kZNt3?MT({2u zYRb?2kd>WGsf_fglcz1QwMhD0w{50DI|%9?yt>>!LhgXLfLO(3x}3cTHNs zswwLF$hy71_Ta8DuMd=1DPK!JP-lDmsoIFRm5t@qXSzPn4*2MDq*I4syR5$-QIFEU zb^F;bhorr_K8q8oO1e3ko@afcu-~C0d;h zesjn4xzyI}O~JLI;gycZW_nh$IfnF34gWGhkmozMqgw9>JaQEmw6(d<6ybjd4=?`6T_)Jc=)=F`Q%bjL? zj}I8VE;(xMq&wEJoz(W`{VaRNU!uQaS^9=^*#?vS7k;klI&o2@)#}uYm^7W@rz_re zIgq()l*Rj?7n3_#_y78-X4*F61GzK445n`w+CB>Yc`Zy?ue@=>lM!B)nl7t~A3m`7 z*5*jBs|~{nW>OA*)XQ7nLR3py<=ykyd)L}bIPB)R2Q2%Y*G#Vm#H0`Cd-Pq+1y&(< z)Ak2vJvz+qX?j}o(&;e~?4t2m$J{RTv}EfPojA7nt@*>H&+s~qz2BpMTI)_56!q)5 zYd}}E&z%}$%~p1pvHHx%Hx37swep_67KO&BEqH2G_o|^Qt969`^MvW=v~#UjJoZ#UOrQA&DULbNjf7!Com$Urc<`BFUZ#&2Qtol@~AOMOjW-e|Mi}! z!}XfY)Ke2z1RJ`9e9k|tkzD!p_&JZ=MfTVWO?YTYKilPb>Ail2TbhWe%r{*``WkP%~+PZ zE5NEv?8H51dhKr?SoCH=r&`lKtF{e0a^yupXKvEjS>k?5CNE}fdpF=jRM=6T)5SN+ zjR~WD=6xHe={@4Yf=;K_p1%=gZ2aWWgJJzVhTc!VuenB=J@0zu%k4{8e&)KN*Rw;G zr!;*Kc#S-;qxQDV$8otSE_d5Fxdm8e=e{WUaV7Pe)cESe(Po2>^m*9GEj>J1TtDXg zi%r_2&OAHyB`|tTbSIO+CsyVDFdTT+e%FP7B=fb}Tjm>k-RU|&Rp-#rDTBJdIi53P zwBa80?P1yL&8xdRWiNWMrs?M5whvZCmJIExVxu|Y(vo>?hCEI4U+w;(>h!HGbF?P2 zkEOh!rXCqIORe_uRZsJ*(0rqhOKNID^@hx@a@BVipNgb^KI`;hIDh%hW7c-G&$E<{jQfnK}0xUM5P)H>m6NdU{oCuWkXg6ApGRI?!ch=JeGg z`Ug7R*`;4N``rVzwug!q_xqM$T|CLA_`CC$HWQYF+$+7lV!T<%@rPq|HN1Zf%eZ#m z_-I@kk9qR^XKQkUAMq%h|vkhlMb`q#z>X7etpg3M<(ih?YB7C zI=9_5VLRT^4f{^tyWi{i+V)eTIs|mIiI`Eociw(F_0q%@9|xH#Z)UyOWa3_6uSCHC zOjpvpcKU2-h&XD}w7%PJsuVZ64SD7Cq`J^Mv+?n~>a6%11AFx7^t$M6KapVflQWO( zq#?U9(m&X_u;L6RR#p^zT|Vsi;m{wRopzjk9w|tQy5sW6X8FgUy*0VV7w5ahw$nHM z#T#;E=;^5sZz~-$n=sRJ%(H81hj}6Xr>>;7(N6z3XK?-Isx>|)eEU_6-F`S{ZQin_ z$I~RGq8&PmroFk-UqzU+bBNg>jq0ZCxdxIw76lG34jdofUDuNnIZcqZxaXtKm!!M) zsu{GG~`l%iB@>$=+p04_Bp~oJUZpHbG`XUQEBb>y6l><{hW**6ieMbzyFy1 zc*21XV@7Sb_P`` zP24Hh!rlOWm`Sz4jr6v7UEfDav$0(iHf1PQ5I~30XQfek>ezi^r2se-rBOlYsJF&> z6o3u95Gg621KJlI8IB?0;ZKZsNdFc07d{0r)1&xD2TJeD5#7lD6woTmb; zK|cZh*gaxliw(bur8G7o#ZClkD!>i+6V!(QS=jDlbpXB?{M~VmT`QI&@T=h84(Hf{ zW0?Wpi^3wqBz@MQ$(Lc6lS&*~FQn~)e19t*`U9SH`;IM0r{YZ&D%>@hs{t5NTc(8TM zGHjv$Ea3K_UzF=V9(XU{JCG87vjE<}>rtP`6WhTo%v+7Ma{W&RP6NL$*S{EeKj24^ z5_?(z2n7C1uK&Ny|6^#M=sya;M)~zfDL@W@2mB%EME^qpM!*Z?`p*XL0Q|CC{|Uf* z1K)*|=xa8>2l!jmC;I=}{I8PhKNe+rpnM5ZQhqwX19%%^Z%q=|IsMZ4dpi>Z3UPLa0C7n^@%=)0XhI*BG>;o z;Euqr$@M=PxEb($NQpe>00sj8i26kTf1Cdo%mMM~s76W|5>4eAs9j{J30!#t80)GrT=}!c} z82F+;=6{V`|3c9FfW8MQ>2EH;7x;VBC;I%`{68nxzW`-=qWm_bL|!uhp1@zBKGFY3 zKxg2qCx&D)ZTL3?TR2wiK;1B#e>J$C{ZT_E@>puo%x}*FSq@?^bfIIN# zs894i9MBQ?GP(Z819t*`L$3cs;O4*&Ak_rS1q=fI8TH9{{x<(F$@L$PGQCiKCsM+1 z7Qh>L1L_lbD(3$>x&9UN|AAcpVwCBJ@=~O20Sf?uz_C}Vsze#8Dk-&7)ulSBD(UE| zs#3PP9Qs*w81`l?o>K1WX#FV?|7=QU70#?)6vV4{j3MIDYs1EGp0 zLX@@$VA@fJR7a{So|ZDl!<JJ(+(|> zkG}lVo|1iZsMFM0)K@}4BgrqpoE2$`{DY5W! zEgdBzCAJbriKi6RlD~qdf*0XpfR7f!gTWBB9+%WRw#7Vlq-0)I(_$J!0dSkqg&=T8mv$h$XJw~HDh;pb$ztbE--UyhrlGj3GAWX5FCi}sHj=yspt`-fba z$4#HnzNYL}1N|-UYxkUsb0zmb-RqNB-9YotJmUv^j^dtKm0{$0x`AF%V>A3oQ9gIt z`%`CKjyBNAymA@0ZSL2kq5B%>9}PbjcG#E4{p_7;zHmGEt?rlNeAI=z;c|`j z>!Jo)QD=liE!(Rr>Ysd+boVQA`Rb&qRuxWRdw&MY6-K>IA(^s;@&9Lf0LiQI#!4YafM z{qV-F3nVY+&vW=Xx`CF4wxj3e&gEvD6TccB(?FZP(#>3bYpLYw2$kuz!yD+RevU4m zU$5kDJ(OTIE3AQD<1q8w)aMH%op1f<7UbVR&#&C<;VPcPy*@8`wv$%_JyGRJnd-P4 z?$Wyx3w-GYdU0{_7nAJ=q&{H5X!t4y3F`L}LYPc~|x z_qNtbooYXqtEv2C^9;QPdcnDixeN70+`;`^N_J{B(EGQQ`Dge~^UzaJ?|4fMb-H6sVyTfl8Hh~3TlQBSK3&vVKtnkjj^ZeirfPxW*{(4g~g z1}>DGD{-{n^0uDNvk30^MSX=N?xt$;j@R|{6}!bQFD{Rfd|vm|_RjNqx_!rsdyI`& zNS+qAtF(ArPbd4CZSh$*gWJtk&u{bndU}qq_qZs%MUqZA+f_Vo*VDsu4Sg1D87eWe z{A|+tdOh87rEmPIz7r(Nii2)_yj)M~Za*INCdQp>k;{)_U96`YV%3~9;+ArUP@Uhn zo~@_HDzCr&@Vtmy%{{hn!>M|jqt}+sYg)v;Uvs0;tg@ai+d1yY#r#ZeFEhJqx25%T zR&Cg;^3IF6+V_60*e$_$ipEg3ix)_?^j(v=`%pdYTeRrz`TMgZZgH13+}>YLM>@1E zKXpG_GBt3`VDr88^rsQyUwi4zl(bzq^6bW4sDI<9k!t@%+}pkO*?I4*r&U+Y>33lH zc<#^B%dYB`*3%kcogO`m$>;V7^SP(Kt)6~)$~b7oXc6Tjym()?9k~FcIA0n zucCT-=+MF0_bx7y^z0Ts)nP+D9cw%(XRFQ-Zd!@o)$sN8bnkAXqz!u(NiH}|j$2z; zPftB$JF8T0v_yJaGeZw}eM$1chWHpszYYTK?sfHa@a)5GHEP6U3*W!R+H zuGy0G$k#72fR|02TQRVHrX+pJCZCnS=R6DVVr@KAQWftu_!aP)s~V%utgk9> z`4hf&Pm;6^IdjhAa6P^C>xXXc?h7SB0r%HUEw85s<;C4dIy*yhSp96u+lqR+*Tn+! zA3Miz^Baq%7M!T3kEFGJ*#Am0w|n=;#xZB=>6mWO-BeD_k_euT93OYSp1x-F=<&=> zbGbGa17EMI#(X*=skwZlKr*tY%Wmasm~U3~tF6xGbBFHXv|D?tp58MoO*CCNoh$u0 zHarpYYww!8WfvYym5h5|BTdBon`LuuVOEEE+|rt1E7rZJr@!60JaEDId`aB?`F+&u z>*>Qg?hd|H87}$WKJeg%_w_XI(`M&38}lWO5l`o*euexOl{$R5o*?la_5EFD6YO=) z(8Nde1(Jbk>p5kr4fKV3k*#kurE{+w8L%BwN+MT{w^=r!fv(c_b~BYEH^Tp?cYm~e$9&1#_&f_AJh{eVZ*`Sa=5c!sjjzC=ytNKb0bmCpaAt9Ag@;m9G> z5<+DSm6l(=CS`xFy~*0tshpuk5o#5o4)rw5%Dg5`4%&ZhV{~^Jl}D&`g!;u|R%wT8 z(rfW$YoAPiCSmHb8NRDP&CXg9dGxBZ)}_xPVMi5NU5epLs8OAc&*fj0o}cdL)9+?G z*;s2o62635JaZ;T<*L+CbLyM-Zg*vUt{~JpLiG`b`)#g~MlBAWd1@D1R=1E)b610! zvwY<}?;7dCoRe4mBYMiHIfPn5sO*P_AHBFDy=i`6MVIlWGHMjVmr!TlZ#OLWij*$9 zv|s;h`xex?zfpM%-!-V4ed)VvpDWVL+o8RC3^OQ~NrT}_sLO@NmY=ySRSA2ZAlcbf zMx_|Ogj&39+lctf(#GPcHmACFmGQ0pK*md`K0Ch7RlO{Y8>ag6M6s!?ZUv#{t_3we z?NN`SYH1tg50mN>wPe&nLMb;A5@~WkiEk3M0XxAvy5ksx|8#RaFOQ^h2$wr4R zNoR3aY%?38E$dYj!*?C1QFqUkHeQtW*g13c0aJ4smB;WU)J8LrdasL8ohCXgu%Dr< zS8PJ9BGih&M3WI0q#YB^9w|6%BCAU=d}80&P#2luS*CV+p7gNx9~62+V^C< zgqm-WKJ)lF>4F1ut;zz7WpyhEwTe(HassN}pOwbtU!Y?G4$JJSkWlLgwd_$>N%ynT zm&d&B#?I?0>oY^mUH=zq4#SsFgFdVt7E&dBeD#>ht;=Szx={>YLak;C3MZeDYJ9sh zSz4};6~mWMYjs-XZaXaQ)eH38Chk zOEULAA?0TG=O5EDbY`rbp;rBkT1e{F5o&%H_Kz`@Qpd1f{xh@R%CwNf@ZAV%W7jVs zOO8ufC&n0Z=J$~Cjbiu`YE-{#W(ST*mlo+7ZOpN3L9O~5mB;WU)cooRlWtTzflNTPAp4mG5MgIYEU&c_Y z{zfe%b?XSV(CWHpyQBYn{B>-pQG`pR{{@ckQ= z&G04EoT7R=!7iyr(SpoT6ZGX`Ce%8Hs$0Qny;E9{XE$waghdN#ZV9RTFVtGBm98ZW z)p*Q3w{23tlj<^N`qR+#Ez; z!YOVI*k=BZphfqrhwf6FskL7#l8v%DVjXEQrGf{+EMW}_#{D;-; zqq}q-$yF1|`^+QMIzp{@*}8^0KwH0AQ!>BHYng>n4Bs+Pc@ZN=*&L#8dzU+o(Csc4 z#%sctP@_ucpBa6Gewy&vJSV@Mtj~pnTE*0rC=H!0p=-7eJ9XJh5lInh9ig&YPaAOh zC|&FMY-d7+g{&@*P;+;IT6$VDS%J5~Vy{6_F9;4r>TU^X;Fp>4D z_7&kvsEyqxnQuKt+pci%$lD^9Mj@fr5o*p%E&k=>^!mM1&Lyo;metK6)ZE>m=C?2V zA*iHtQwMb~?srNi4IZJE5NestH0Od7boTzAVPmJsy)B#J%TU)pdD`nFeR`ts=?feA zcxzu0zJ#hX?`Xh~Q*^c^x9{9binxPNbN7Ink}+4W@f7{gWcAbex(fXgY6+nRdCZuf zdzw~tFG$geQ^eqedKOfJ0k3u*JwspaTemgLSzRtjLVQVxpYIMERz-`O3WxT7r!E^U z#cEdf5Vre49qJ$DFs7O=2zX;~XZ06Z!-a%eLa0&vc#9L&blpp? z!CWJGP?bSV&x|=ff6P@n<9fWt z#a{i&WtTDx-$SHj!?m?lSLuy6TX)Q5Tgs>u!@Q&3rEsPa#dB**9cWOSWMk{96{SJ4HSiP%{#@^%oDzOm`W$KdcBC}(rGZUO9QX!pi3DYI z&?eIM*!^LCZHgvzm@@bV?Gh=YhxU+m(Io`tOGA$-gKzv{gOlpep#$Z*uv|&AjRIo| zXi%<|$W+otOGw)rl3eCXL!T*tZ_s{{G6t}(qe_}D_1hB)^QB?H6v8+D{`|EoAw@;X ze*Kw)bL>4*0io$Ok&)I`_W$w5I8WJc!co4*Vid$deqT;HF%@77AeyrS*aI8@0|3~o z{nz&^V{ef;zMu^vifMo^&^QCg!#*@M18@-h&I7QQ$sD|BiozZ(g?&2e2g(y5d9#6I z?~{6gvOfSaHBr<}(B>c?`+`gxq0+{s7tr zfIV$$JAfQHkbf!C9RRsK43NFz4exUFjR^>iw6el`_fjMAx*)u0)i=fy2g;J4^@pME z2|;r`tNzXJhQr$n@!qEYQk@axJk(d%ppBfV?Dd9!uQ?rj&!8STlmMjv%24Vb?TG(( z+R=fo$;Ym`$ zrXvyJOh|FaPje0*nilw7UmN1b3D>f9E)MwyO8b%khw(W zF3H=2^Syuy-~>qCKH&QS325UyfQ7tH01m(d@Bw+XfPBCN01su!(b8urc(n9c3LY(e z7LTbZvkiqmRg`OKqoh4@w6xJP=q~}1r|_c+eL6JHU&!yjO`v}lA>$MLFjmr6au7Q^ zfb<|h&ci|RhFDKh0CrJ^G6&&IeTXx~(Kk-E&X9=ZDBy4Fj1;sAz%c;vXEZ=D4o)QA zPlGA7_DTg&v(F3~MH7Rz}Y$9W~7C65!p|7|ThiTqOl1rIBR2i~KnU;-NRs*@Ic zzTlj!9j5_j02uDSt{qj#Cr?qF11Q!G1)r8gejV({FEJ zXk^@>W2eqty0T5Wb(aSwqAL)m zRv`MVKr~u`^`rs;X9WVyinah90D{5_%-f1~0DVAvfC0b|U<5$?T7kf@q9dRapfjKg zpeq2Z_rQl%f`29WSAu^f_*a5|CHPl@euJTBxsu z`dX;3b%%`SzMcwZA$gC;?;}Vkn~REf$hj8Q;5JaK5KlehWFTIm=N=Xj#Fz`t1H%11 zLww!w<{%OU^`BfPM zBZ6fXKMahC`!O&I17m_I3=9_qvTFdcP-9>ug2$syB>a{|+r%M4uuQND!ID^*iJ>7_ zJUk?ezadyWJVa3tECs>h0V#@N155zj0NnvS06hVwfL?&!fIa{-fH|Nqzye?i=m+2c ztN_*k8-OAhv%|SPfH>oSb1Vwy#RJ_H;0AyY|MjI!zQ`X47zFSG_yYm}fq)=DFdzgF z3J3#)0|osz$CzA$~C_hro~RhzhQs! z|69WU*&C^nAi-pS2p|Te0LB1P0cn7AKn5TakOjyFj0KDX{LK>hphW{>0I>i8APx`@ zNC3byG`|t+{|*0tv4q0cN}5)`FJJl5F?egM?3GQ~L(MHxf`q>RtF^O%lcKES`0R2J zvVP2r`q=wbSXNX!vpc)9YQ-ARVSrcAyS2jI;azduB`2Us9dIBor-1~~t)#p_AkHGd)?4B+c$2jku0w=ToYWhb)TsmhzUDS%f!G9$9)-~bj zqSAjI@9aAsOB{)h@3ySRaP$w*U(P?_UvM1$4UfYU@E=e)(QR4(l?3TO2~WZQKp)e1 z!J1#{mvB+0uB)^3>X7{0*%}4U0R5C*rx=}Xbed@a6`d|-fld!P4F&DzQE!J}RyK#~ znxQJvDW6rVu`25)Nu(rBgS0`XmHFe zbw(?@%x!V!@P6&CNwn*B`Y@Ngg!qcRwgAJcIY)4qt9&L$4U zrqXL-s>i2ddMWZ{@NyUj=fNxBl~5Ve#Q9Z0`Qy-vO_lICgne>5;*Z1m*p$y#A$4YX z4UC7^!t3DmQ0;T#Rh1*5u^$-1XP5Dr#HM`ONS#emkOmhr!2j{A_SqJlXCpRMYUO#* z`1G(TpE=|Oa3Nd-Z-6(#o1iMsw&*BQxy^Hf_2m4jR;~C5!825R7xLZk9(XUj4=#iE!v~-Mm%}Wm%-DbW7@2X6=aQw|LKznits>uVvcOeY zMq5mKIHMC}bmxkA;{MnPlhJItDWfK2Gqk`QxB^%eDYxLb z(HuT*_Y$Xne2^-HVhxzO+FMOMoaO#yR({LMc;fC@e^2qaeTZ(#axStR=0OK^!iV8X zm=Bd%7LQd_mZy5Glx68yttTE8T$N?fXxhVBZ11u12Uo=tn-l%ZxdEcfRiG>uAQ!?S zxEij3kHEE{N66A&O#P$qG3bURuoRYo$q1P zias4z@@nVc#D(rAbaf0pq{;{g?i<$9rqS4?eWQW0V+H!ezZ^6UE0EX0N>~M}VGZ`)U1(g@z9gwa>b6EfK-Xfb({8?TxVX#qg-O#0Lpb^ zWxT_jgm!Rnuro;k5u1xo#dyrb82)RV%Dy1BebjFvo=qmUPe#RdI#UN1^4}|8lv@5< zR~BdWX5;@;$WOy(;Ir^K*aA1hR`@)aV{Iqfc}x4%<`Oz}c2Zw9mhT%p`}kwhfG@=~ z9$6XF<+LeAl>rk|AHEK-{RQL~;Y+X$Zh>3jHrNigL%H9?qvqWNR!8w$qo27GG_8<3R|ZX?2dHz~rIy~Q#7iHUG8@~4pzp3bQy z_!}&XaBvJAd@I7k5fM)9wepW|iYIoC-fJTKnThb{$X~!OOHq35tQ*Ny&i@_5;2(Y} zXe~dt++w`0M^=tYKW)LeW!&|}k@=PJ`)lMr_)V1GVorWGXVR~h-5KoA!xTN!ZH8G8 zJRF%uy#u25&7?he2s590WnX<0&|=!vU-c+G*=YsY(u18Soylfj8?w@m;#bUF5ZH*) z335cu|28AYOWWaGv>lE;*dN5G?QlHW4#%MFOF%IxZ~0YSxdr2@{u+ZG7^b&o8N3nhXA#g_ESK`?|5~_(FASJh3~*Y7;h#T&0rfq|2f~S=MdJ@l}Xz zJ9f%W+pe8qEgsL#IZ4NM94FCZZ4C|*cm62%A_-HCX>l#yi6{eWc?#2o64rM zZZ?z6X1#3AOM15FcquRKxn9Q0dY+fd5n>MaIZWs1mZOR9bNk|n)uYCcpk{ropMY9> zHeWbhx4KP>7R{R7w!pSC8l$%Mf*x!7EB^YUq^Bs}jXas$z-X4~XX&feyUROBzZLz< zph~|}pN6XSH%036k-oFTU&SxnL-u#0zYA1)k-z6i{{j981MnxfAN~w~0hLbrN$;-^ z*83aVe~0~07Oy_G%x{ZI(SNekfIazE*=uY+P+|K)whzF;D%)IZ7qmwjSAKmV+ZU}b zUhN*j#vxE?Hf;~Heb}^(Gi^uMJ_<9sa;0^b)d`zp(V^X6#dfZiOr*%)c-qx}MwgR} zT;kT~HK3z-RMsQwkdNT&nD5WF{nfS$#bvl6??axWFVR(GV`U%z@NH1f u_IRRB{jL0Ns`9x{awn#dXUXSXuxXpoznz_|`m!E5QvJqYoO--r + -- + ---[script files.sh] +``` + +The `sig` script will display by default any scripts in the `scripts` folder, therefore when creating a project, copy over the scripts folder of the desired language into your project then the `sig` script handles the rest appropriately. If your project requires multiple languages and build setups, then you can use the `sig2` command, which has an additional parameter to specify the language when running it. When setting up a multi-language setup, you'll just copy the entire folder to include the programming language itself. So a multi-language project structure may look something like this: +``` + -C + --scripts + ---build.sh + ---clean.sh + ---make.sh + -Java + --scripts + ---build.sh + ---clean.sh + ---jar.sh +``` diff --git a/buildtemplate.html b/buildtemplate.html new file mode 100644 index 0000000..7e6698d --- /dev/null +++ b/buildtemplate.html @@ -0,0 +1,75 @@ + + + + + + + + Emscripten-Generated Code + + + + + + + + + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..05849a6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,46 @@ +#define OLC_PGE_APPLICATION +#include "pixelGameEngine.h" + +using namespace std; + +class Example : public olc::PixelGameEngine +{ +public: + Example() + { + sAppName = "Example"; + } + +public: + bool OnUserCreate() override + { + SetPixelMode(olc::Pixel::ALPHA); + ConsoleCaptureStdOut(true); + // Called once at the start, so create things here + for (int x = 0; x < ScreenWidth(); x++) + for (int y = 0; y < ScreenHeight(); y++) + Draw(x, y, olc::Pixel(rand() % 255, rand() % 255, rand()% 255)); + for (int x=0;x<50;x++) { + for (int y=0;y<50;y++) { + Draw(x, y, olc::Pixel(255, 0, 0, 128)); + } + } + return true; + } + + bool OnUserUpdate(float fElapsedTime) override + { + // called once per frame + return true; + } +}; + + +int main() +{ + Example demo; + if (demo.Construct(256, 240, 4, 4)) + demo.Start(); + + return 0; +} \ No newline at end of file diff --git a/pixelGameEngine.h b/pixelGameEngine.h new file mode 100644 index 0000000..37ffb75 --- /dev/null +++ b/pixelGameEngine.h @@ -0,0 +1,6191 @@ +#pragma region license_and_help +/* + olcPixelGameEngine.h + + +-------------------------------------------------------------+ + | OneLoneCoder Pixel Game Engine v2.19 | + | "What do you need? Pixels... Lots of Pixels..." - javidx9 | + +-------------------------------------------------------------+ + + What is this? + ~~~~~~~~~~~~~ + olc::PixelGameEngine is a single file, cross platform graphics and userinput + framework used for games, visualisations, algorithm exploration and learning. + It was developed by YouTuber "javidx9" as an assistive tool for many of his + videos. The goal of this project is to provide high speed graphics with + minimal project setup complexity, to encourage new programmers, younger people, + and anyone else that wants to make fun things. + + However, olc::PixelGameEngine is not a toy! It is a powerful and fast utility + capable of delivering high resolution, high speed, high quality applications + which behave the same way regardless of the operating system or platform. + + This file provides the core utility set of the olc::PixelGameEngine, including + window creation, keyboard/mouse input, main game thread, timing, pixel drawing + routines, image/sprite loading and drawing routines, and a bunch of utility + types to make rapid development of games/visualisations possible. + + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2022 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions or derivations of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce the above + copyright notice. This list of conditions and the following disclaimer must be + reproduced in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may + be used to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + https://www.youtube.com/javidx9extra + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + Patreon: https://www.patreon.com/javidx9 + Community: https://community.onelonecoder.com + + + + Compiling in Linux + ~~~~~~~~~~~~~~~~~~ + You will need a modern C++ compiler, so update yours! + To compile use the command: + + g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng -lstdc++fs -std=c++17 + + On some Linux configurations, the frame rate is locked to the refresh + rate of the monitor. This engine tries to unlock it but may not be + able to, in which case try launching your program like this: + + vblank_mode=0 ./YourProgName + + + + Compiling in Code::Blocks on Windows + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Well I wont judge you, but make sure your Code::Blocks installation + is really up to date - you may even consider updating your C++ toolchain + to use MinGW32-W64. + + Guide for installing recent GCC for Windows: + https://www.msys2.org/ + Guide for configuring code::blocks: + https://solarianprogrammer.com/2019/11/05/install-gcc-windows/ + https://solarianprogrammer.com/2019/11/16/install-codeblocks-gcc-windows-build-c-cpp-fortran-programs/ + + Add these libraries to "Linker Options": + user32 gdi32 opengl32 gdiplus Shlwapi dwmapi stdc++fs + + Set these compiler options: -std=c++17 + + + + Compiling on Mac - EXPERIMENTAL! PROBABLY HAS BUGS + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Yes yes, people use Macs for C++ programming! Who knew? Anyway, enough + arguing, thanks to Mumflr the PGE is now supported on Mac. Now I know nothing + about Mac, so if you need support, I suggest checking out the instructions + here: https://github.com/MumflrFumperdink/olcPGEMac + + clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL + -framework GLUT -framework Carbon -lpng YourSource.cpp -o YourProgName + + + + Compiling with Emscripten (New & Experimental) + ~~~~~~~~~~~~~~~~~~~~~~~~~ + Emscripten compiler will turn your awesome C++ PixelGameEngine project into WASM! + This means you can run your application in teh browser, great for distributing + and submission in to jams and things! It's a bit new at the moment. + + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 ./YourSource.cpp -o pge.html + + + + Using stb_image.h + ~~~~~~~~~~~~~~~~~ + The PGE will load png images by default (with help from libpng on non-windows systems). + However, the excellent "stb_image.h" can be used instead, supporting a variety of + image formats, and has no library dependence - something we like at OLC studios ;) + To use stb_image.h, make sure it's in your code base, and simply: + + #define OLC_IMAGE_STB + + Before including the olcPixelGameEngine.h header file. stb_image.h works on many systems + and can be downloaded here: https://github.com/nothings/stb/blob/master/stb_image.h + + + + Multiple cpp file projects? + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + As a single header solution, the OLC_PGE_APPLICATION definition is used to + insert the engine implementation at a project location of your choosing. + The simplest way to setup multifile projects is to create a file called + "olcPixelGameEngine.cpp" which includes the following: + + #define OLC_PGE_APPLICATION + #include "olcPixelGameEngine.h" + + That's all it should include. You can also include PGEX includes and + defines in here too. With this in place, you dont need to + #define OLC_PGE_APPLICATION anywhere, and can simply include this + header file as an when you need to. + + + + Ports + ~~~~~ + olc::PixelGameEngine has been ported and tested with varying degrees of + success to: WinXP, Win7, Win8, Win10, Various Linux, Raspberry Pi, + Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are + interested in the details of these ports, come and visit the Discord! + + + + Thanks + ~~~~~~ + I'd like to extend thanks to Ian McKay, Bispoo, Eremiell, slavka, Kwizatz77, gurkanctn, Phantim, + IProgramInCPP, JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice, + dandistine, Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, Alexio, SaladinAkara + & MagetzUb for advice, ideas and testing, and I'd like to extend my appreciation to the + 250K YouTube followers, 80+ Patreons, 4.8K Twitch followers and 10K Discord server members + who give me the motivation to keep going with all this :D + + Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka, + @Dragoneye, @Gorbit99, @dandistine & @Mumflr + + Special thanks to those who bring gifts! + GnarGnarHead.......Domina + Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2, Skully + Marti Morta........Gris + Danicron...........Terraria + SaladinAkara.......Aseprite, Inside, Quern: Undying Thoughts, Outer Wilds + AlterEgo...........Final Fantasy XII - The Zodiac Age + SlicEnDicE.........Noita, Inside + TGD................Voucher Gift + + Special thanks to my Patreons too - I wont name you on here, but I've + certainly enjoyed my tea and flapjacks :D + + + + Author + ~~~~~~ + David Barr, aka javidx9, �OneLoneCoder 2018, 2019, 2020, 2021, 2022 +*/ +#pragma endregion + +#pragma region version_history +/* + 2.01: Made renderer and platform static for multifile projects + 2.02: Added Decal destructor, optimised Pixel constructor + 2.03: Added FreeBSD flags, Added DrawStringDecal() + 2.04: Windows Full-Screen bug fixed + 2.05: +DrawPartialWarpedDecal() - draws a warped decal from a subset image + +DrawPartialRotatedDecal() - draws a rotated decal from a subset image + 2.06: +GetTextSize() - returns area occupied by multiline string + +GetWindowSize() - returns actual window size + +GetElapsedTime() - returns last calculated fElapsedTime + +GetWindowMouse() - returns actual mouse location in window + +DrawExplicitDecal() - bow-chikka-bow-bow + +DrawPartialDecal(pos, size) - draws a partial decal to specified area + +FillRectDecal() - draws a flat shaded rectangle as a decal + +GradientFillRectDecal() - draws a rectangle, with unique colour corners + +Modified DrawCircle() & FillCircle() - Thanks IanM-Matrix1 (#PR121) + +Gone someway to appeasing pedants + 2.07: +GetPixelSize() - returns user specified pixel size + +GetScreenPixelSize() - returns actual size in monitor pixels + +Pixel Cohesion Mode (flag in Construct()) - disallows arbitrary window scaling + +Working VSYNC in Windows windowed application - now much smoother + +Added string conversion for olc::vectors + +Added comparator operators for olc::vectors + +Added DestroyWindow() on windows platforms for serial PGE launches + +Added GetMousePos() to stop TarriestPython whinging + 2.08: Fix SetScreenSize() aspect ratio pre-calculation + Fix DrawExplicitDecal() - stupid oversight with multiple decals + Disabled olc::Sprite copy constructor + +olc::Sprite Duplicate() - produces a new clone of the sprite + +olc::Sprite Duplicate(pos, size) - produces a new sprite from the region defined + +Unary operators for vectors + +More pedant mollification - Thanks TheLandfill + +ImageLoader modules - user selectable image handling core, gdi+, libpng, stb_image + +Mac Support via GLUT - thanks Mumflr! + 2.09: Fix olc::Renderable Image load error - Thanks MaGetzUb & Zij-IT for finding and moaning about it + Fix file rejection in image loaders when using resource packs + Tidied Compiler defines per platform - Thanks slavka + +Pedant fixes, const correctness in parts + +DecalModes - Normal, Additive, Multiplicative blend modes + +Pixel Operators & Lerping + +Filtered Decals - If you hate pixels, then erase this file + +DrawStringProp(), GetTextSizeProp(), DrawStringPropDecal() - Draws non-monospaced font + 2.10: Fix PixelLerp() - oops my bad, lerped the wrong way :P + Fix "Shader" support for strings - thanks Megarev for crying about it + Fix GetTextSizeProp() - Height was just plain wrong... + +vec2d operator overloads (element wise *=, /=) + +vec2d comparison operators... :| yup... hmmmm... + +vec2d ceil(), floor(), min(), max() functions - surprising how often I do it manually + +DrawExplicitDecal(... uint32_t elements) - complete control over convex polygons and lines + +DrawPolygonDecal() - to keep Bispoo happy, required significant rewrite of EVERYTHING, but hey ho + +Complete rewrite of decal renderer + +OpenGL 3.3 Renderer (also supports Raspberry Pi) + +PGEX Break-In Hooks - with a push from Dandistine + +Wireframe Decal Mode - For debug overlays + 2.11: Made PGEX hooks optional - (provide true to super constructor) + 2.12: Fix for MinGW compiler non-compliance :( - why is its sdk structure different?? why??? + 2.13: +GetFontSprite() - allows access to font data + 2.14: Fix WIN32 Definition reshuffle + Fix DrawPartialDecal() - messed up dimension during renderer experiment, didnt remove junk code, thanks Alexio + Fix? Strange error regarding GDI+ Image Loader not knowing about COM, SDK change? + 2.15: Big Reformat + +WASM Platform (via Emscripten) - Big Thanks to OLC Community - See Platform for details + +Sample Mode for Decals + +Made olc_ConfigureSystem() accessible + +Added OLC_----_CUSTOM_EX for externalised platforms, renderers and image loaders + =Refactored olc::Sprite pixel data store + -Deprecating LoadFromPGESprFile() + -Deprecating SaveToPGESprFile() + Fix Pixel -= operator (thanks Au Lit) + 2.16: FIX Emscripten JS formatting in VS IDE (thanks Moros) + +"Headless" Mode + +DrawLineDecal() + +Mouse Button Constants + +Move Constructor for olc::Renderable + +Polar/Cartesian conversion for v2d_generic + +DrawRotatedStringDecal()/DrawRotatedStringPropDecal() (thanks Oso-Grande/Sopadeoso (PR #209)) + =Using olc::Renderable for layer surface + +Major Mac and GLUT Update (thanks Mumflr) + 2.17: +Clipping for DrawLine() functions + +Reintroduced sub-pixel decals + +Modified DrawPartialDecal() to quantise and correctly sample from tile atlasses + +olc::Sprite::GetPixel() - Clamp Mode + 2.18: +Option to not "dirty" layers with SetDrawTarget() - Thanks TerasKasi! + =Detection for Mac M1, fix for scroll wheel interrogation - Thanks ruarq! + 2.19: Textual Input(of)course Edition! + =Built in font is now olc::Renderable + +EnablePixelTransfer() - Gate if layer content transfers occur (speedup in decal only apps) + +TextEntryEnable() - Enables/Disables text entry mode + +TextEntryGetString() - Gets the current accumulated string in text entry mode + +TextEntryGetCursor() - Gets the current cursor position in text entry mode + +IsTextEntryEnabled() - Returns true if text entry mode is activated + +OnTextEntryComplete() - Override is called when user presses "ENTER" in text entry mode + +Potential for regional keyboard mappings - needs volunteers to do this + +ConsoleShow() - Opens built in command console + +ConsoleClear() - Clears built in command console output + +ConsoleOut() - Stream strings to command console output + +ConsoleCaptureStdOut() - Capture std::cout by redirecting to built-in console + +IsConsoleShowing() - Returns true if console is currently active + +OnConsoleCommand() - Override is called when command is entered into built in console + + !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! + !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !! +*/ +#pragma endregion + +#pragma region hello_world_example +// O------------------------------------------------------------------------------O +// | Example "Hello World" Program (main.cpp) | +// O------------------------------------------------------------------------------O +/* + +#define OLC_PGE_APPLICATION +#include "olcPixelGameEngine.h" + +// Override base class with your custom functionality +class Example : public olc::PixelGameEngine +{ +public: + Example() + { + // Name your application + sAppName = "Example"; + } + +public: + bool OnUserCreate() override + { + // Called once at the start, so create things here + return true; + } + + bool OnUserUpdate(float fElapsedTime) override + { + // Called once per frame, draws random coloured pixels + for (int x = 0; x < ScreenWidth(); x++) + for (int y = 0; y < ScreenHeight(); y++) + Draw(x, y, olc::Pixel(rand() % 256, rand() % 256, rand() % 256)); + return true; + } +}; + +int main() +{ + Example demo; + if (demo.Construct(256, 240, 4, 4)) + demo.Start(); + return 0; +} + +*/ +#pragma endregion + +#ifndef OLC_PGE_DEF +#define OLC_PGE_DEF + +#pragma region std_includes +// O------------------------------------------------------------------------------O +// | STANDARD INCLUDES | +// O------------------------------------------------------------------------------O +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma endregion + +#define PGE_VER 219 + +// O------------------------------------------------------------------------------O +// | COMPILER CONFIGURATION ODDITIES | +// O------------------------------------------------------------------------------O +#pragma region compiler_config +#define USE_EXPERIMENTAL_FS +#if defined(_WIN32) + #if _MSC_VER >= 1920 && _MSVC_LANG >= 201703L + #undef USE_EXPERIMENTAL_FS + #endif +#endif +#if defined(__linux__) || defined(__MINGW32__) || defined(__EMSCRIPTEN__) || defined(__FreeBSD__) || defined(__APPLE__) + #if __cplusplus >= 201703L + #undef USE_EXPERIMENTAL_FS + #endif +#endif + +#if !defined(OLC_KEYBOARD_UK) + #define OLC_KEYBOARD_UK +#endif + + +#if defined(USE_EXPERIMENTAL_FS) || defined(FORCE_EXPERIMENTAL_FS) + // C++14 + #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING + #include + namespace _gfs = std::experimental::filesystem::v1; +#else + // C++17 + #include + namespace _gfs = std::filesystem; +#endif + +#if defined(UNICODE) || defined(_UNICODE) + #define olcT(s) L##s +#else + #define olcT(s) s +#endif + +#define UNUSED(x) (void)(x) + +// O------------------------------------------------------------------------------O +// | PLATFORM SELECTION CODE, Thanks slavka! | +// O------------------------------------------------------------------------------O + +// Platform +#if !defined(OLC_PLATFORM_WINAPI) && !defined(OLC_PLATFORM_X11) && !defined(OLC_PLATFORM_GLUT) && !defined(OLC_PLATFORM_EMSCRIPTEN) + #if !defined(OLC_PLATFORM_CUSTOM_EX) + #if defined(_WIN32) + #define OLC_PLATFORM_WINAPI + #endif + #if defined(__linux__) || defined(__FreeBSD__) + #define OLC_PLATFORM_X11 + #endif + #if defined(__APPLE__) + #define GL_SILENCE_DEPRECATION + #define OLC_PLATFORM_GLUT + #endif + #if defined(__EMSCRIPTEN__) + #define OLC_PLATFORM_EMSCRIPTEN + #endif + #endif +#endif + +// Start Situation +#if defined(OLC_PLATFORM_GLUT) || defined(OLC_PLATFORM_EMSCRIPTEN) + #define PGE_USE_CUSTOM_START +#endif + +// Renderer +#if !defined(OLC_GFX_OPENGL10) && !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) + #if !defined(OLC_GFX_CUSTOM_EX) + #if defined(OLC_PLATFORM_EMSCRIPTEN) + #define OLC_GFX_OPENGL33 + #else + #define OLC_GFX_OPENGL10 + #endif + #endif +#endif + +// Image loader +#if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG) + #if !defined(OLC_IMAGE_CUSTOM_EX) + #if defined(_WIN32) + #define OLC_IMAGE_GDI + #endif + #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__) + #define OLC_IMAGE_LIBPNG + #endif + #endif +#endif + + +// O------------------------------------------------------------------------------O +// | PLATFORM-SPECIFIC DEPENDENCIES | +// O------------------------------------------------------------------------------O +#if !defined(OLC_PGE_HEADLESS) +#if defined(OLC_PLATFORM_WINAPI) + #define _WINSOCKAPI_ // Thanks Cornchipss + #if !defined(VC_EXTRALEAN) + #define VC_EXTRALEAN + #endif + #if !defined(NOMINMAX) + #define NOMINMAX + #endif + + // In Code::Blocks + #if !defined(_WIN32_WINNT) + #ifdef HAVE_MSMF + #define _WIN32_WINNT 0x0600 // Windows Vista + #else + #define _WIN32_WINNT 0x0500 // Windows 2000 + #endif + #endif + + #include + #undef _WINSOCKAPI_ +#endif + +#if defined(OLC_PLATFORM_X11) + namespace X11 + { + #include + #include + } +#endif + +#if defined(OLC_PLATFORM_GLUT) + #if defined(__linux__) + #include + #include + #endif + #if defined(__APPLE__) + #include + #include + #include + #endif +#endif +#endif +#pragma endregion + +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine INTERFACE DECLARATION | +// O------------------------------------------------------------------------------O +#pragma region pge_declaration +namespace olc +{ + class PixelGameEngine; + class Sprite; + + // Pixel Game Engine Advanced Configuration + constexpr uint8_t nMouseButtons = 5; + constexpr uint8_t nDefaultAlpha = 0xFF; + constexpr uint32_t nDefaultPixel = (nDefaultAlpha << 24); + constexpr uint8_t nTabSizeInSpaces = 4; + enum rcode { FAIL = 0, OK = 1, NO_FILE = -1 }; + + // O------------------------------------------------------------------------------O + // | olc::Pixel - Represents a 32-Bit RGBA colour | + // O------------------------------------------------------------------------------O + struct Pixel + { + union + { + uint32_t n = nDefaultPixel; + struct { uint8_t r; uint8_t g; uint8_t b; uint8_t a; }; + }; + + enum Mode { NORMAL, MASK, ALPHA, CUSTOM }; + + Pixel(); + Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = nDefaultAlpha); + Pixel(uint32_t p); + Pixel& operator = (const Pixel& v) = default; + bool operator ==(const Pixel& p) const; + bool operator !=(const Pixel& p) const; + Pixel operator * (const float i) const; + Pixel operator / (const float i) const; + Pixel& operator *=(const float i); + Pixel& operator /=(const float i); + Pixel operator + (const Pixel& p) const; + Pixel operator - (const Pixel& p) const; + Pixel& operator +=(const Pixel& p); + Pixel& operator -=(const Pixel& p); + Pixel inv() const; + }; + + Pixel PixelF(float red, float green, float blue, float alpha = 1.0f); + Pixel PixelLerp(const olc::Pixel& p1, const olc::Pixel& p2, float t); + + + // O------------------------------------------------------------------------------O + // | USEFUL CONSTANTS | + // O------------------------------------------------------------------------------O + static const Pixel + GREY(192, 192, 192), DARK_GREY(128, 128, 128), VERY_DARK_GREY(64, 64, 64), + RED(255, 0, 0), DARK_RED(128, 0, 0), VERY_DARK_RED(64, 0, 0), + YELLOW(255, 255, 0), DARK_YELLOW(128, 128, 0), VERY_DARK_YELLOW(64, 64, 0), + GREEN(0, 255, 0), DARK_GREEN(0, 128, 0), VERY_DARK_GREEN(0, 64, 0), + CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64), + BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64), + MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64), + WHITE(255, 255, 255), BLACK(0, 0, 0), BLANK(0, 0, 0, 0); + + // Thanks to scripticuk and others for updating the key maps + // NOTE: The GLUT platform will need updating, open to contributions ;) + enum Key + { + NONE, + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + UP, DOWN, LEFT, RIGHT, + SPACE, TAB, SHIFT, CTRL, INS, DEL, HOME, END, PGUP, PGDN, + BACK, ESCAPE, RETURN, ENTER, PAUSE, SCROLL, + NP0, NP1, NP2, NP3, NP4, NP5, NP6, NP7, NP8, NP9, + NP_MUL, NP_DIV, NP_ADD, NP_SUB, NP_DECIMAL, PERIOD, + EQUALS, COMMA, MINUS, + OEM_1, OEM_2, OEM_3, OEM_4, OEM_5, OEM_6, OEM_7, OEM_8, + CAPS_LOCK, ENUM_END + }; + + namespace Mouse + { + static constexpr int32_t LEFT = 0; + static constexpr int32_t RIGHT = 1; + static constexpr int32_t MIDDLE = 2; + }; + + // O------------------------------------------------------------------------------O + // | olc::HWButton - Represents the state of a hardware button (mouse/key/joy) | + // O------------------------------------------------------------------------------O + struct HWButton + { + bool bPressed = false; // Set once during the frame the event occurs + bool bReleased = false; // Set once during the frame the event occurs + bool bHeld = false; // Set true for all frames between pressed and released events + }; + + + + + // O------------------------------------------------------------------------------O + // | olc::vX2d - A generic 2D vector type | + // O------------------------------------------------------------------------------O +#if !defined(OLC_IGNORE_VEC2D) + template + struct v2d_generic + { + T x = 0; + T y = 0; + v2d_generic() : x(0), y(0) {} + v2d_generic(T _x, T _y) : x(_x), y(_y) {} + v2d_generic(const v2d_generic& v) : x(v.x), y(v.y) {} + v2d_generic& operator=(const v2d_generic& v) = default; + T mag() const { return T(std::sqrt(x * x + y * y)); } + T mag2() const { return x * x + y * y; } + v2d_generic norm() const { T r = 1 / mag(); return v2d_generic(x * r, y * r); } + v2d_generic perp() const { return v2d_generic(-y, x); } + v2d_generic floor() const { return v2d_generic(std::floor(x), std::floor(y)); } + v2d_generic ceil() const { return v2d_generic(std::ceil(x), std::ceil(y)); } + v2d_generic max(const v2d_generic& v) const { return v2d_generic(std::max(x, v.x), std::max(y, v.y)); } + v2d_generic min(const v2d_generic& v) const { return v2d_generic(std::min(x, v.x), std::min(y, v.y)); } + v2d_generic cart() { return { std::cos(y) * x, std::sin(y) * x }; } + v2d_generic polar() { return { mag(), std::atan2(y, x) }; } + T dot(const v2d_generic& rhs) const { return this->x * rhs.x + this->y * rhs.y; } + T cross(const v2d_generic& rhs) const { return this->x * rhs.y - this->y * rhs.x; } + v2d_generic operator + (const v2d_generic& rhs) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y); } + v2d_generic operator - (const v2d_generic& rhs) const { return v2d_generic(this->x - rhs.x, this->y - rhs.y); } + v2d_generic operator * (const T& rhs) const { return v2d_generic(this->x * rhs, this->y * rhs); } + v2d_generic operator * (const v2d_generic& rhs) const { return v2d_generic(this->x * rhs.x, this->y * rhs.y); } + v2d_generic operator / (const T& rhs) const { return v2d_generic(this->x / rhs, this->y / rhs); } + v2d_generic operator / (const v2d_generic& rhs) const { return v2d_generic(this->x / rhs.x, this->y / rhs.y); } + v2d_generic& operator += (const v2d_generic& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; } + v2d_generic& operator -= (const v2d_generic& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; } + v2d_generic& operator *= (const T& rhs) { this->x *= rhs; this->y *= rhs; return *this; } + v2d_generic& operator /= (const T& rhs) { this->x /= rhs; this->y /= rhs; return *this; } + v2d_generic& operator *= (const v2d_generic& rhs) { this->x *= rhs.x; this->y *= rhs.y; return *this; } + v2d_generic& operator /= (const v2d_generic& rhs) { this->x /= rhs.x; this->y /= rhs.y; return *this; } + v2d_generic operator + () const { return { +x, +y }; } + v2d_generic operator - () const { return { -x, -y }; } + bool operator == (const v2d_generic& rhs) const { return (this->x == rhs.x && this->y == rhs.y); } + bool operator != (const v2d_generic& rhs) const { return (this->x != rhs.x || this->y != rhs.y); } + const std::string str() const { return std::string("(") + std::to_string(this->x) + "," + std::to_string(this->y) + ")"; } + friend std::ostream& operator << (std::ostream& os, const v2d_generic& rhs) { os << rhs.str(); return os; } + operator v2d_generic() const { return { static_cast(this->x), static_cast(this->y) }; } + operator v2d_generic() const { return { static_cast(this->x), static_cast(this->y) }; } + operator v2d_generic() const { return { static_cast(this->x), static_cast(this->y) }; } + }; + + // Note: joshinils has some good suggestions here, but they are complicated to implement at this moment, + // however they will appear in a future version of PGE + template inline v2d_generic operator * (const float& lhs, const v2d_generic& rhs) + { return v2d_generic((T)(lhs * (float)rhs.x), (T)(lhs * (float)rhs.y)); } + template inline v2d_generic operator * (const double& lhs, const v2d_generic& rhs) + { return v2d_generic((T)(lhs * (double)rhs.x), (T)(lhs * (double)rhs.y)); } + template inline v2d_generic operator * (const int& lhs, const v2d_generic& rhs) + { return v2d_generic((T)(lhs * (int)rhs.x), (T)(lhs * (int)rhs.y)); } + template inline v2d_generic operator / (const float& lhs, const v2d_generic& rhs) + { return v2d_generic((T)(lhs / (float)rhs.x), (T)(lhs / (float)rhs.y)); } + template inline v2d_generic operator / (const double& lhs, const v2d_generic& rhs) + { return v2d_generic((T)(lhs / (double)rhs.x), (T)(lhs / (double)rhs.y)); } + template inline v2d_generic operator / (const int& lhs, const v2d_generic& rhs) + { return v2d_generic((T)(lhs / (int)rhs.x), (T)(lhs / (int)rhs.y)); } + + // To stop dandistine crying... + template inline bool operator < (const v2d_generic& lhs, const v2d_generic& rhs) + { return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x); } + template inline bool operator > (const v2d_generic& lhs, const v2d_generic& rhs) + { return lhs.y > rhs.y || (lhs.y == rhs.y && lhs.x > rhs.x); } + + typedef v2d_generic vi2d; + typedef v2d_generic vu2d; + typedef v2d_generic vf2d; + typedef v2d_generic vd2d; +#endif + + + + + + + // O------------------------------------------------------------------------------O + // | olc::ResourcePack - A virtual scrambled filesystem to pack your assets into | + // O------------------------------------------------------------------------------O + struct ResourceBuffer : public std::streambuf + { + ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size); + std::vector vMemory; + }; + + class ResourcePack : public std::streambuf + { + public: + ResourcePack(); + ~ResourcePack(); + bool AddFile(const std::string& sFile); + bool LoadPack(const std::string& sFile, const std::string& sKey); + bool SavePack(const std::string& sFile, const std::string& sKey); + ResourceBuffer GetFileBuffer(const std::string& sFile); + bool Loaded(); + private: + struct sResourceFile { uint32_t nSize; uint32_t nOffset; }; + std::map mapFiles; + std::ifstream baseFile; + std::vector scramble(const std::vector& data, const std::string& key); + std::string makeposix(const std::string& path); + }; + + + class ImageLoader + { + public: + ImageLoader() = default; + virtual ~ImageLoader() = default; + virtual olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) = 0; + virtual olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) = 0; + }; + + + // O------------------------------------------------------------------------------O + // | olc::Sprite - An image represented by a 2D array of olc::Pixel | + // O------------------------------------------------------------------------------O + class Sprite + { + public: + Sprite(); + Sprite(const std::string& sImageFile, olc::ResourcePack* pack = nullptr); + Sprite(int32_t w, int32_t h); + Sprite(const olc::Sprite&) = delete; + ~Sprite(); + + public: + olc::rcode LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack = nullptr); + + public: + int32_t width = 0; + int32_t height = 0; + enum Mode { NORMAL, PERIODIC, CLAMP }; + enum Flip { NONE = 0, HORIZ = 1, VERT = 2 }; + + public: + void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL); + Pixel GetPixel(int32_t x, int32_t y) const; + bool SetPixel(int32_t x, int32_t y, Pixel p); + Pixel GetPixel(const olc::vi2d& a) const; + bool SetPixel(const olc::vi2d& a, Pixel p); + Pixel Sample(float x, float y) const; + Pixel SampleBL(float u, float v) const; + Pixel* GetData(); + olc::Sprite* Duplicate(); + olc::Sprite* Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize); + std::vector pColData; + Mode modeSample = Mode::NORMAL; + + static std::unique_ptr loader; + }; + + // O------------------------------------------------------------------------------O + // | olc::Decal - A GPU resident storage of an olc::Sprite | + // O------------------------------------------------------------------------------O + class Decal + { + public: + Decal(olc::Sprite* spr, bool filter = false, bool clamp = true); + Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr); + virtual ~Decal(); + void Update(); + void UpdateSprite(); + + public: // But dont touch + int32_t id = -1; + olc::Sprite* sprite = nullptr; + olc::vf2d vUVScale = { 1.0f, 1.0f }; + }; + + enum class DecalMode + { + NORMAL, + ADDITIVE, + MULTIPLICATIVE, + STENCIL, + ILLUMINATE, + WIREFRAME, + MODEL3D, + }; + + enum class DecalStructure + { + LINE, + FAN, + STRIP, + LIST + }; + + // O------------------------------------------------------------------------------O + // | olc::Renderable - Convenience class to keep a sprite and decal together | + // O------------------------------------------------------------------------------O + class Renderable + { + public: + Renderable() = default; + Renderable(Renderable&& r) : pSprite(std::move(r.pSprite)), pDecal(std::move(r.pDecal)) {} + Renderable(const Renderable&) = delete; + olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr, bool filter = false, bool clamp = true); + void Create(uint32_t width, uint32_t height, bool filter = false, bool clamp = true); + olc::Decal* Decal() const; + olc::Sprite* Sprite() const; + + private: + std::unique_ptr pSprite = nullptr; + std::unique_ptr pDecal = nullptr; + }; + + + // O------------------------------------------------------------------------------O + // | Auxilliary components internal to engine | + // O------------------------------------------------------------------------------O + + struct DecalInstance + { + olc::Decal* decal = nullptr; + std::vector pos; + std::vector uv; + std::vector w; + std::vector tint; + olc::DecalMode mode = olc::DecalMode::NORMAL; + olc::DecalStructure structure = olc::DecalStructure::FAN; + uint32_t points = 0; + }; + + struct LayerDesc + { + olc::vf2d vOffset = { 0, 0 }; + olc::vf2d vScale = { 1, 1 }; + bool bShow = false; + bool bUpdate = false; + olc::Renderable pDrawTarget; + uint32_t nResID = 0; + std::vector vecDecalInstance; + olc::Pixel tint = olc::WHITE; + std::function funcHook = nullptr; + }; + + class Renderer + { + public: + virtual ~Renderer() = default; + virtual void PrepareDevice() = 0; + virtual olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) = 0; + virtual olc::rcode DestroyDevice() = 0; + virtual void DisplayFrame() = 0; + virtual void PrepareDrawing() = 0; + virtual void SetDecalMode(const olc::DecalMode& mode) = 0; + virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) = 0; + virtual void DrawDecal(const olc::DecalInstance& decal) = 0; + virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) = 0; + virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) = 0; + virtual void ReadTexture(uint32_t id, olc::Sprite* spr) = 0; + virtual uint32_t DeleteTexture(const uint32_t id) = 0; + virtual void ApplyTexture(uint32_t id) = 0; + virtual void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) = 0; + virtual void ClearBuffer(olc::Pixel p, bool bDepth) = 0; + static olc::PixelGameEngine* ptrPGE; + }; + + class Platform + { + public: + virtual ~Platform() = default; + virtual olc::rcode ApplicationStartUp() = 0; + virtual olc::rcode ApplicationCleanUp() = 0; + virtual olc::rcode ThreadStartUp() = 0; + virtual olc::rcode ThreadCleanUp() = 0; + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) = 0; + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) = 0; + virtual olc::rcode SetWindowTitle(const std::string& s) = 0; + virtual olc::rcode StartSystemEventLoop() = 0; + virtual olc::rcode HandleSystemEvent() = 0; + static olc::PixelGameEngine* ptrPGE; + }; + + class PGEX; + + // The Static Twins (plus one) + static std::unique_ptr renderer; + static std::unique_ptr platform; + static std::map mapKeys; + + // O------------------------------------------------------------------------------O + // | olc::PixelGameEngine - The main BASE class for your application | + // O------------------------------------------------------------------------------O + class PixelGameEngine + { + public: + PixelGameEngine(); + virtual ~PixelGameEngine(); + public: + olc::rcode Construct(int32_t screen_w, int32_t screen_h, int32_t pixel_w, int32_t pixel_h, + bool full_screen = false, bool vsync = false, bool cohesion = false); + olc::rcode Start(); + + public: // User Override Interfaces + // Called once on application startup, use to load your resources + virtual bool OnUserCreate(); + // Called every frame, and provides you with a time per frame value + virtual bool OnUserUpdate(float fElapsedTime); + // Called once on application termination, so you can be one clean coder + virtual bool OnUserDestroy(); + + // Called when a text entry is confirmed with "enter" key + virtual void OnTextEntryComplete(const std::string& sText); + // Called when a console command is executed + virtual bool OnConsoleCommand(const std::string& sCommand); + + public: // Hardware Interfaces + // Returns true if window is currently in focus + bool IsFocused() const; + // Get the state of a specific keyboard button + HWButton GetKey(Key k) const; + // Get the state of a specific mouse button + HWButton GetMouse(uint32_t b) const; + // Get Mouse X coordinate in "pixel" space + int32_t GetMouseX() const; + // Get Mouse Y coordinate in "pixel" space + int32_t GetMouseY() const; + // Get Mouse Wheel Delta + int32_t GetMouseWheel() const; + // Get the mouse in window space + const olc::vi2d& GetWindowMouse() const; + // Gets the mouse as a vector to keep Tarriest happy + const olc::vi2d& GetMousePos() const; + + static const std::map& GetKeyMap() { return mapKeys; } + + public: // Utility + // Returns the width of the screen in "pixels" + int32_t ScreenWidth() const; + // Returns the height of the screen in "pixels" + int32_t ScreenHeight() const; + // Returns the width of the currently selected drawing target in "pixels" + int32_t GetDrawTargetWidth() const; + // Returns the height of the currently selected drawing target in "pixels" + int32_t GetDrawTargetHeight() const; + // Returns the currently active draw target + olc::Sprite* GetDrawTarget() const; + // Resize the primary screen sprite + void SetScreenSize(int w, int h); + // Specify which Sprite should be the target of drawing functions, use nullptr + // to specify the primary screen + void SetDrawTarget(Sprite* target); + // Gets the current Frames Per Second + uint32_t GetFPS() const; + // Gets last update of elapsed time + float GetElapsedTime() const; + // Gets Actual Window size + const olc::vi2d& GetWindowSize() const; + // Gets pixel scale + const olc::vi2d& GetPixelSize() const; + // Gets actual pixel scale + const olc::vi2d& GetScreenPixelSize() const; + + public: // CONFIGURATION ROUTINES + // Layer targeting functions + void SetDrawTarget(uint8_t layer, bool bDirty = true); + void EnableLayer(uint8_t layer, bool b); + void SetLayerOffset(uint8_t layer, const olc::vf2d& offset); + void SetLayerOffset(uint8_t layer, float x, float y); + void SetLayerScale(uint8_t layer, const olc::vf2d& scale); + void SetLayerScale(uint8_t layer, float x, float y); + void SetLayerTint(uint8_t layer, const olc::Pixel& tint); + void SetLayerCustomRenderFunction(uint8_t layer, std::function f); + + std::vector& GetLayers(); + uint32_t CreateLayer(); + + // Change the pixel mode for different optimisations + // olc::Pixel::NORMAL = No transparency + // olc::Pixel::MASK = Transparent if alpha is < 255 + // olc::Pixel::ALPHA = Full transparency + void SetPixelMode(Pixel::Mode m); + Pixel::Mode GetPixelMode(); + // Use a custom blend function + void SetPixelMode(std::function pixelMode); + // Change the blend factor from between 0.0f to 1.0f; + void SetPixelBlend(float fBlend); + + + + public: // DRAWING ROUTINES + // Draws a single Pixel + virtual bool Draw(int32_t x, int32_t y, Pixel p = olc::WHITE); + bool Draw(const olc::vi2d& pos, Pixel p = olc::WHITE); + // Draws a line from (x1,y1) to (x2,y2) + void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF); + void DrawLine(const olc::vi2d& pos1, const olc::vi2d& pos2, Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF); + // Draws a circle located at (x,y) with radius + void DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE, uint8_t mask = 0xFF); + void DrawCircle(const olc::vi2d& pos, int32_t radius, Pixel p = olc::WHITE, uint8_t mask = 0xFF); + // Fills a circle located at (x,y) with radius + void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE); + void FillCircle(const olc::vi2d& pos, int32_t radius, Pixel p = olc::WHITE); + // Draws a rectangle at (x,y) to (x+w,y+h) + void DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); + void DrawRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p = olc::WHITE); + // Fills a rectangle at (x,y) to (x+w,y+h) + void FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); + void FillRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p = olc::WHITE); + // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3) + void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); + void DrawTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p = olc::WHITE); + // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3) + void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); + void FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p = olc::WHITE); + // Draws an entire sprite at location (x,y) + void DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); + void DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); + // Draws an area of a sprite at location (x,y), where the + // selected area is (ox,oy) to (ox+w,oy+h) + void DrawPartialSprite(int32_t x, int32_t y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); + void DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); + // Draws a single line of text - traditional monospaced + void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + olc::vi2d GetTextSize(const std::string& s); + // Draws a single line of text - non-monospaced + void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + void DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1); + olc::vi2d GetTextSizeProp(const std::string& s); + + // Decal Quad functions + void SetDecalMode(const olc::DecalMode& mode); + void SetDecalStructure(const olc::DecalStructure& structure); + // Draws a whole decal, with optional scale and tinting + void DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); + // Draws a region of a decal, with optional scale and tinting + void DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); + void DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); + // Draws fully user controlled 4 vertices, pos(pixels), uv(pixels), colours + void DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements = 4); + // Draws a decal with 4 arbitrary points, warping the texture to look "correct" + void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint = olc::WHITE); + void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint = olc::WHITE); + void DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint = olc::WHITE); + // As above, but you can specify a region of a decal source sprite + void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); + void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); + void DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); + // Draws a decal rotated to specified angle, wit point of rotation offset + void DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); + void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE); + // Draws a multiline string as a decal, with tiniting and scaling + void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + // Draws a single shaded filled rectangle as a decal + void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE); + // Draws a corner shaded rectangle as a decal + void GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR); + // Draws an arbitrary convex textured polygon using GPU + void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint = olc::WHITE); + void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& depth, const std::vector& uv, const olc::Pixel tint = olc::WHITE); + void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector& tint); + + // Draws a line in Decal Space + void DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p = olc::WHITE); + void DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawRotatedStringPropDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + // Clears entire draw target to Pixel + void Clear(Pixel p); + // Clears the rendering back buffer + void ClearBuffer(Pixel p, bool bDepth = true); + // Returns the font image + olc::Sprite* GetFontSprite(); + + // Clip a line segment to visible area + bool ClipLineToScreen(olc::vi2d& in_p1, olc::vi2d& in_p2); + + // Dont allow PGE to mark layers as dirty, so pixel graphics don't update + void EnablePixelTransfer(const bool bEnable = true); + + // Command Console Routines + void ConsoleShow(const olc::Key &keyExit, bool bSuspendTime = true); + bool IsConsoleShowing() const; + void ConsoleClear(); + std::stringstream& ConsoleOut(); + void ConsoleCaptureStdOut(const bool bCapture); + + // Text Entry Routines + void TextEntryEnable(const bool bEnable, const std::string& sText = ""); + std::string TextEntryGetString() const; + int32_t TextEntryGetCursor() const; + bool IsTextEntryEnabled() const; + + + + private: + void UpdateTextEntry(); + void UpdateConsole(); + + public: + + // Experimental Lightweight 3D Routines ================ +#ifdef OLC_ENABLE_EXPERIMENTAL + // Set Manual View Matrix + void LW3D_View(const std::array& m); + // Set Manual World Matrix + void LW3D_World(const std::array& m); + // Set Manual Projection Matrix + void LW3D_Projection(const std::array& m); + + // Draws a vector of vertices, interprted as individual triangles + void LW3D_DrawTriangles(olc::Decal* decal, const std::vector>& pos, const std::vector& tex, const std::vector& col); + + void LW3D_ModelTranslate(const float x, const float y, const float z); + + // Camera convenience functions + void LW3D_SetCameraAtTarget(const float fEyeX, const float fEyeY, const float fEyeZ, + const float fTargetX, const float fTargetY, const float fTargetZ, + const float fUpX = 0.0f, const float fUpY = 1.0f, const float fUpZ = 0.0f); + void LW3D_SetCameraAlongDirection(const float fEyeX, const float fEyeY, const float fEyeZ, + const float fDirX, const float fDirY, const float fDirZ, + const float fUpX = 0.0f, const float fUpY = 1.0f, const float fUpZ = 0.0f); + + // 3D Rendering Flags + void LW3D_EnableDepthTest(const bool bEnableDepth); + void LW3D_EnableBackfaceCulling(const bool bEnableCull); +#endif + public: // Branding + std::string sAppName; + + private: // Inner mysterious workings + olc::Sprite* pDrawTarget = nullptr; + Pixel::Mode nPixelMode = Pixel::NORMAL; + float fBlendFactor = 1.0f; + olc::vi2d vScreenSize = { 256, 240 }; + olc::vf2d vInvScreenSize = { 1.0f / 256.0f, 1.0f / 240.0f }; + olc::vi2d vPixelSize = { 4, 4 }; + olc::vi2d vScreenPixelSize = { 4, 4 }; + olc::vi2d vMousePos = { 0, 0 }; + int32_t nMouseWheelDelta = 0; + olc::vi2d vMousePosCache = { 0, 0 }; + olc::vi2d vMouseWindowPos = { 0, 0 }; + int32_t nMouseWheelDeltaCache = 0; + olc::vi2d vWindowSize = { 0, 0 }; + olc::vi2d vViewPos = { 0, 0 }; + olc::vi2d vViewSize = { 0,0 }; + bool bFullScreen = false; + olc::vf2d vPixel = { 1.0f, 1.0f }; + bool bHasInputFocus = false; + bool bHasMouseFocus = false; + bool bEnableVSYNC = false; + float fFrameTimer = 1.0f; + float fLastElapsed = 0.0f; + int nFrameCount = 0; + bool bSuspendTextureTransfer = false; + Renderable fontRenderable; + std::vector vLayers; + uint8_t nTargetLayer = 0; + uint32_t nLastFPS = 0; + bool bPixelCohesion = false; + DecalMode nDecalMode = DecalMode::NORMAL; + DecalStructure nDecalStructure = DecalStructure::FAN; + std::function funcPixelMode; + std::chrono::time_point m_tp1, m_tp2; + std::vector vFontSpacing; + + // Command Console Specific + bool bConsoleShow = false; + bool bConsoleSuspendTime = false; + olc::Key keyConsoleExit = olc::Key::F1; + std::stringstream ssConsoleOutput; + std::streambuf* sbufOldCout = nullptr; + olc::vi2d vConsoleSize; + olc::vi2d vConsoleCursor = { 0,0 }; + olc::vf2d vConsoleCharacterScale = { 1.0f, 2.0f }; + std::vector sConsoleLines; + std::list sCommandHistory; + std::list::iterator sCommandHistoryIt; + + // Text Entry Specific + bool bTextEntryEnable = false; + std::string sTextEntryString = ""; + int32_t nTextEntryCursor = 0; + std::vector> vKeyboardMap; + + + + // State of keyboard + bool pKeyNewState[256] = { 0 }; + bool pKeyOldState[256] = { 0 }; + HWButton pKeyboardState[256] = { 0 }; + + // State of mouse + bool pMouseNewState[nMouseButtons] = { 0 }; + bool pMouseOldState[nMouseButtons] = { 0 }; + HWButton pMouseState[nMouseButtons] = { 0 }; + + // The main engine thread + void EngineThread(); + + + // If anything sets this flag to false, the engine + // "should" shut down gracefully + static std::atomic bAtomActive; + + public: + // "Break In" Functions + void olc_UpdateMouse(int32_t x, int32_t y); + void olc_UpdateMouseWheel(int32_t delta); + void olc_UpdateWindowSize(int32_t x, int32_t y); + void olc_UpdateViewport(); + void olc_ConstructFontSheet(); + void olc_CoreUpdate(); + void olc_PrepareEngine(); + void olc_UpdateMouseState(int32_t button, bool state); + void olc_UpdateKeyState(int32_t key, bool state); + void olc_UpdateMouseFocus(bool state); + void olc_UpdateKeyFocus(bool state); + void olc_Terminate(); + void olc_Reanimate(); + bool olc_IsRunning(); + + // At the very end of this file, chooses which + // components to compile + virtual void olc_ConfigureSystem(); + + // NOTE: Items Here are to be deprecated, I have left them in for now + // in case you are using them, but they will be removed. + // olc::vf2d vSubPixelOffset = { 0.0f, 0.0f }; + + public: // PGEX Stuff + friend class PGEX; + void pgex_Register(olc::PGEX* pgex); + + private: + std::vector vExtensions; + }; + + + + // O------------------------------------------------------------------------------O + // | PGE EXTENSION BASE CLASS - Permits access to PGE functions from extension | + // O------------------------------------------------------------------------------O + class PGEX + { + friend class olc::PixelGameEngine; + public: + PGEX(bool bHook = false); + + protected: + virtual void OnBeforeUserCreate(); + virtual void OnAfterUserCreate(); + virtual bool OnBeforeUserUpdate(float &fElapsedTime); + virtual void OnAfterUserUpdate(float fElapsedTime); + + protected: + static PixelGameEngine* pge; + }; +} + +#pragma endregion + +#endif // OLC_PGE_DEF + + +// O------------------------------------------------------------------------------O +// | START OF OLC_PGE_APPLICATION | +// O------------------------------------------------------------------------------O +#ifdef OLC_PGE_APPLICATION +#undef OLC_PGE_APPLICATION + +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine INTERFACE IMPLEMENTATION (CORE) | +// | Note: The core implementation is platform independent | +// O------------------------------------------------------------------------------O +#pragma region pge_implementation +namespace olc +{ + // O------------------------------------------------------------------------------O + // | olc::Pixel IMPLEMENTATION | + // O------------------------------------------------------------------------------O + Pixel::Pixel() + { r = 0; g = 0; b = 0; a = nDefaultAlpha; } + + Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) + { n = red | (green << 8) | (blue << 16) | (alpha << 24); } // Thanks jarekpelczar + + Pixel::Pixel(uint32_t p) + { n = p; } + + bool Pixel::operator==(const Pixel& p) const + { return n == p.n; } + + bool Pixel::operator!=(const Pixel& p) const + { return n != p.n; } + + Pixel Pixel::operator * (const float i) const + { + float fR = std::min(255.0f, std::max(0.0f, float(r) * i)); + float fG = std::min(255.0f, std::max(0.0f, float(g) * i)); + float fB = std::min(255.0f, std::max(0.0f, float(b) * i)); + return Pixel(uint8_t(fR), uint8_t(fG), uint8_t(fB), a); + } + + Pixel Pixel::operator / (const float i) const + { + float fR = std::min(255.0f, std::max(0.0f, float(r) / i)); + float fG = std::min(255.0f, std::max(0.0f, float(g) / i)); + float fB = std::min(255.0f, std::max(0.0f, float(b) / i)); + return Pixel(uint8_t(fR), uint8_t(fG), uint8_t(fB), a); + } + + Pixel& Pixel::operator *=(const float i) + { + this->r = uint8_t(std::min(255.0f, std::max(0.0f, float(r) * i))); + this->g = uint8_t(std::min(255.0f, std::max(0.0f, float(g) * i))); + this->b = uint8_t(std::min(255.0f, std::max(0.0f, float(b) * i))); + return *this; + } + + Pixel& Pixel::operator /=(const float i) + { + this->r = uint8_t(std::min(255.0f, std::max(0.0f, float(r) / i))); + this->g = uint8_t(std::min(255.0f, std::max(0.0f, float(g) / i))); + this->b = uint8_t(std::min(255.0f, std::max(0.0f, float(b) / i))); + return *this; + } + + Pixel Pixel::operator + (const Pixel& p) const + { + uint8_t nR = uint8_t(std::min(255, std::max(0, int(r) + int(p.r)))); + uint8_t nG = uint8_t(std::min(255, std::max(0, int(g) + int(p.g)))); + uint8_t nB = uint8_t(std::min(255, std::max(0, int(b) + int(p.b)))); + return Pixel(nR, nG, nB, a); + } + + Pixel Pixel::operator - (const Pixel& p) const + { + uint8_t nR = uint8_t(std::min(255, std::max(0, int(r) - int(p.r)))); + uint8_t nG = uint8_t(std::min(255, std::max(0, int(g) - int(p.g)))); + uint8_t nB = uint8_t(std::min(255, std::max(0, int(b) - int(p.b)))); + return Pixel(nR, nG, nB, a); + } + + Pixel& Pixel::operator += (const Pixel& p) + { + this->r = uint8_t(std::min(255, std::max(0, int(r) + int(p.r)))); + this->g = uint8_t(std::min(255, std::max(0, int(g) + int(p.g)))); + this->b = uint8_t(std::min(255, std::max(0, int(b) + int(p.b)))); + return *this; + } + + Pixel& Pixel::operator -= (const Pixel& p) // Thanks Au Lit + { + this->r = uint8_t(std::min(255, std::max(0, int(r) - int(p.r)))); + this->g = uint8_t(std::min(255, std::max(0, int(g) - int(p.g)))); + this->b = uint8_t(std::min(255, std::max(0, int(b) - int(p.b)))); + return *this; + } + + Pixel Pixel::inv() const + { + uint8_t nR = uint8_t(std::min(255, std::max(0, 255 - int(r)))); + uint8_t nG = uint8_t(std::min(255, std::max(0, 255 - int(g)))); + uint8_t nB = uint8_t(std::min(255, std::max(0, 255 - int(b)))); + return Pixel(nR, nG, nB, a); + } + + Pixel PixelF(float red, float green, float blue, float alpha) + { return Pixel(uint8_t(red * 255.0f), uint8_t(green * 255.0f), uint8_t(blue * 255.0f), uint8_t(alpha * 255.0f)); } + + Pixel PixelLerp(const olc::Pixel& p1, const olc::Pixel& p2, float t) + { return (p2 * t) + p1 * (1.0f - t); } + + // O------------------------------------------------------------------------------O + // | olc::Sprite IMPLEMENTATION | + // O------------------------------------------------------------------------------O + Sprite::Sprite() + { width = 0; height = 0; } + + Sprite::Sprite(const std::string& sImageFile, olc::ResourcePack* pack) + { LoadFromFile(sImageFile, pack); } + + Sprite::Sprite(int32_t w, int32_t h) + { + width = w; height = h; + pColData.resize(width * height); + pColData.resize(width * height, nDefaultPixel); + } + + Sprite::~Sprite() + { pColData.clear(); } + + void Sprite::SetSampleMode(olc::Sprite::Mode mode) + { modeSample = mode; } + + Pixel Sprite::GetPixel(const olc::vi2d& a) const + { return GetPixel(a.x, a.y); } + + bool Sprite::SetPixel(const olc::vi2d& a, Pixel p) + { return SetPixel(a.x, a.y, p); } + + Pixel Sprite::GetPixel(int32_t x, int32_t y) const + { + if (modeSample == olc::Sprite::Mode::NORMAL) + { + if (x >= 0 && x < width && y >= 0 && y < height) + return pColData[y * width + x]; + else + return Pixel(0, 0, 0, 0); + } + else + { + if (modeSample == olc::Sprite::Mode::PERIODIC) + return pColData[abs(y % height) * width + abs(x % width)]; + else + return pColData[std::max(0, std::min(y, height-1)) * width + std::max(0, std::min(x, width-1))]; + } + } + + bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p) + { + if (x >= 0 && x < width && y >= 0 && y < height) + { + pColData[y * width + x] = p; + return true; + } + else + return false; + } + + Pixel Sprite::Sample(float x, float y) const + { + int32_t sx = std::min((int32_t)((x * (float)width)), width - 1); + int32_t sy = std::min((int32_t)((y * (float)height)), height - 1); + return GetPixel(sx, sy); + } + + Pixel Sprite::SampleBL(float u, float v) const + { + u = u * width - 0.5f; + v = v * height - 0.5f; + int x = (int)floor(u); // cast to int rounds toward zero, not downward + int y = (int)floor(v); // Thanks @joshinils + float u_ratio = u - x; + float v_ratio = v - y; + float u_opposite = 1 - u_ratio; + float v_opposite = 1 - v_ratio; + + olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0)); + olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0)); + olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1)); + olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1)); + + return olc::Pixel( + (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio), + (uint8_t)((p1.g * u_opposite + p2.g * u_ratio) * v_opposite + (p3.g * u_opposite + p4.g * u_ratio) * v_ratio), + (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio)); + } + + Pixel* Sprite::GetData() + { return pColData.data(); } + + + olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack) + { + UNUSED(pack); + return loader->LoadImageResource(this, sImageFile, pack); + } + + olc::Sprite* Sprite::Duplicate() + { + olc::Sprite* spr = new olc::Sprite(width, height); + std::memcpy(spr->GetData(), GetData(), width * height * sizeof(olc::Pixel)); + spr->modeSample = modeSample; + return spr; + } + + olc::Sprite* Sprite::Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize) + { + olc::Sprite* spr = new olc::Sprite(vSize.x, vSize.y); + for (int y = 0; y < vSize.y; y++) + for (int x = 0; x < vSize.x; x++) + spr->SetPixel(x, y, GetPixel(vPos.x + x, vPos.y + y)); + return spr; + } + + // O------------------------------------------------------------------------------O + // | olc::Decal IMPLEMENTATION | + // O------------------------------------------------------------------------------O + Decal::Decal(olc::Sprite* spr, bool filter, bool clamp) + { + id = -1; + if (spr == nullptr) return; + sprite = spr; + id = renderer->CreateTexture(sprite->width, sprite->height, filter, clamp); + Update(); + } + + Decal::Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr) + { + if (spr == nullptr) return; + id = nExistingTextureResource; + } + + void Decal::Update() + { + if (sprite == nullptr) return; + vUVScale = { 1.0f / float(sprite->width), 1.0f / float(sprite->height) }; + renderer->ApplyTexture(id); + renderer->UpdateTexture(id, sprite); + } + + void Decal::UpdateSprite() + { + if (sprite == nullptr) return; + renderer->ApplyTexture(id); + renderer->ReadTexture(id, sprite); + } + + Decal::~Decal() + { + if (id != -1) + { + renderer->DeleteTexture(id); + id = -1; + } + } + + void Renderable::Create(uint32_t width, uint32_t height, bool filter, bool clamp) + { + pSprite = std::make_unique(width, height); + pDecal = std::make_unique(pSprite.get(), filter, clamp); + } + + olc::rcode Renderable::Load(const std::string& sFile, ResourcePack* pack, bool filter, bool clamp) + { + pSprite = std::make_unique(); + if (pSprite->LoadFromFile(sFile, pack) == olc::rcode::OK) + { + pDecal = std::make_unique(pSprite.get(), filter, clamp); + return olc::rcode::OK; + } + else + { + pSprite.release(); + pSprite = nullptr; + return olc::rcode::NO_FILE; + } + } + + olc::Decal* Renderable::Decal() const + { return pDecal.get(); } + + olc::Sprite* Renderable::Sprite() const + { return pSprite.get(); } + + // O------------------------------------------------------------------------------O + // | olc::ResourcePack IMPLEMENTATION | + // O------------------------------------------------------------------------------O + + + //============================================================= + // Resource Packs - Allows you to store files in one large + // scrambled file - Thanks MaGetzUb for debugging a null char in std::stringstream bug + ResourceBuffer::ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size) + { + vMemory.resize(size); + ifs.seekg(offset); ifs.read(vMemory.data(), vMemory.size()); + setg(vMemory.data(), vMemory.data(), vMemory.data() + size); + } + + ResourcePack::ResourcePack() { } + ResourcePack::~ResourcePack() { baseFile.close(); } + + bool ResourcePack::AddFile(const std::string& sFile) + { + const std::string file = makeposix(sFile); + + if (_gfs::exists(file)) + { + sResourceFile e; + e.nSize = (uint32_t)_gfs::file_size(file); + e.nOffset = 0; // Unknown at this stage + mapFiles[file] = e; + return true; + } + return false; + } + + bool ResourcePack::LoadPack(const std::string& sFile, const std::string& sKey) + { + // Open the resource file + baseFile.open(sFile, std::ifstream::binary); + if (!baseFile.is_open()) return false; + + // 1) Read Scrambled index + uint32_t nIndexSize = 0; + baseFile.read((char*)&nIndexSize, sizeof(uint32_t)); + + std::vector buffer(nIndexSize); + for (uint32_t j = 0; j < nIndexSize; j++) + buffer[j] = baseFile.get(); + + std::vector decoded = scramble(buffer, sKey); + size_t pos = 0; + auto read = [&decoded, &pos](char* dst, size_t size) { + memcpy((void*)dst, (const void*)(decoded.data() + pos), size); + pos += size; + }; + + auto get = [&read]() -> int { char c; read(&c, 1); return c; }; + + // 2) Read Map + uint32_t nMapEntries = 0; + read((char*)&nMapEntries, sizeof(uint32_t)); + for (uint32_t i = 0; i < nMapEntries; i++) + { + uint32_t nFilePathSize = 0; + read((char*)&nFilePathSize, sizeof(uint32_t)); + + std::string sFileName(nFilePathSize, ' '); + for (uint32_t j = 0; j < nFilePathSize; j++) + sFileName[j] = get(); + + sResourceFile e; + read((char*)&e.nSize, sizeof(uint32_t)); + read((char*)&e.nOffset, sizeof(uint32_t)); + mapFiles[sFileName] = e; + } + + // Don't close base file! we will provide a stream + // pointer when the file is requested + return true; + } + + bool ResourcePack::SavePack(const std::string& sFile, const std::string& sKey) + { + // Create/Overwrite the resource file + std::ofstream ofs(sFile, std::ofstream::binary); + if (!ofs.is_open()) return false; + + // Iterate through map + uint32_t nIndexSize = 0; // Unknown for now + ofs.write((char*)&nIndexSize, sizeof(uint32_t)); + uint32_t nMapSize = uint32_t(mapFiles.size()); + ofs.write((char*)&nMapSize, sizeof(uint32_t)); + for (auto& e : mapFiles) + { + // Write the path of the file + size_t nPathSize = e.first.size(); + ofs.write((char*)&nPathSize, sizeof(uint32_t)); + ofs.write(e.first.c_str(), nPathSize); + + // Write the file entry properties + ofs.write((char*)&e.second.nSize, sizeof(uint32_t)); + ofs.write((char*)&e.second.nOffset, sizeof(uint32_t)); + } + + // 2) Write the individual Data + std::streampos offset = ofs.tellp(); + nIndexSize = (uint32_t)offset; + for (auto& e : mapFiles) + { + // Store beginning of file offset within resource pack file + e.second.nOffset = (uint32_t)offset; + + // Load the file to be added + std::vector vBuffer(e.second.nSize); + std::ifstream i(e.first, std::ifstream::binary); + i.read((char*)vBuffer.data(), e.second.nSize); + i.close(); + + // Write the loaded file into resource pack file + ofs.write((char*)vBuffer.data(), e.second.nSize); + offset += e.second.nSize; + } + + // 3) Scramble Index + std::vector stream; + auto write = [&stream](const char* data, size_t size) { + size_t sizeNow = stream.size(); + stream.resize(sizeNow + size); + memcpy(stream.data() + sizeNow, data, size); + }; + + // Iterate through map + write((char*)&nMapSize, sizeof(uint32_t)); + for (auto& e : mapFiles) + { + // Write the path of the file + size_t nPathSize = e.first.size(); + write((char*)&nPathSize, sizeof(uint32_t)); + write(e.first.c_str(), nPathSize); + + // Write the file entry properties + write((char*)&e.second.nSize, sizeof(uint32_t)); + write((char*)&e.second.nOffset, sizeof(uint32_t)); + } + std::vector sIndexString = scramble(stream, sKey); + uint32_t nIndexStringLen = uint32_t(sIndexString.size()); + // 4) Rewrite Map (it has been updated with offsets now) + // at start of file + ofs.seekp(0, std::ios::beg); + ofs.write((char*)&nIndexStringLen, sizeof(uint32_t)); + ofs.write(sIndexString.data(), nIndexStringLen); + ofs.close(); + return true; + } + + ResourceBuffer ResourcePack::GetFileBuffer(const std::string& sFile) + { return ResourceBuffer(baseFile, mapFiles[sFile].nOffset, mapFiles[sFile].nSize); } + + bool ResourcePack::Loaded() + { return baseFile.is_open(); } + + std::vector ResourcePack::scramble(const std::vector& data, const std::string& key) + { + if (key.empty()) return data; + std::vector o; + size_t c = 0; + for (auto s : data) o.push_back(s ^ key[(c++) % key.size()]); + return o; + }; + + std::string ResourcePack::makeposix(const std::string& path) + { + std::string o; + for (auto s : path) o += std::string(1, s == '\\' ? '/' : s); + return o; + }; + + // O------------------------------------------------------------------------------O + // | olc::PixelGameEngine IMPLEMENTATION | + // O------------------------------------------------------------------------------O + PixelGameEngine::PixelGameEngine() + { + sAppName = "Undefined"; + olc::PGEX::pge = this; + + // Bring in relevant Platform & Rendering systems depending + // on compiler parameters + olc_ConfigureSystem(); + } + + PixelGameEngine::~PixelGameEngine() + {} + + + olc::rcode PixelGameEngine::Construct(int32_t screen_w, int32_t screen_h, int32_t pixel_w, int32_t pixel_h, bool full_screen, bool vsync, bool cohesion) + { + bPixelCohesion = cohesion; + vScreenSize = { screen_w, screen_h }; + vInvScreenSize = { 1.0f / float(screen_w), 1.0f / float(screen_h) }; + vPixelSize = { pixel_w, pixel_h }; + vWindowSize = vScreenSize * vPixelSize; + bFullScreen = full_screen; + bEnableVSYNC = vsync; + vPixel = 2.0f / vScreenSize; + + if (vPixelSize.x <= 0 || vPixelSize.y <= 0 || vScreenSize.x <= 0 || vScreenSize.y <= 0) + return olc::FAIL; + return olc::OK; + } + + + void PixelGameEngine::SetScreenSize(int w, int h) + { + vScreenSize = { w, h }; + vInvScreenSize = { 1.0f / float(w), 1.0f / float(h) }; + for (auto& layer : vLayers) + { + layer.pDrawTarget.Create(vScreenSize.x, vScreenSize.y); + layer.bUpdate = true; + } + SetDrawTarget(nullptr); + renderer->ClearBuffer(olc::BLACK, true); + renderer->DisplayFrame(); + renderer->ClearBuffer(olc::BLACK, true); + renderer->UpdateViewport(vViewPos, vViewSize); + } + +#if !defined(PGE_USE_CUSTOM_START) + olc::rcode PixelGameEngine::Start() + { + if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL; + + // Construct the window + if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL; + olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y); + + // Start the thread + bAtomActive = true; + std::thread t = std::thread(&PixelGameEngine::EngineThread, this); + + // Some implementations may form an event loop here + platform->StartSystemEventLoop(); + + // Wait for thread to be exited + t.join(); + + if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL; + + return olc::OK; + } +#endif + + void PixelGameEngine::SetDrawTarget(Sprite* target) + { + if (target) + { + pDrawTarget = target; + } + else + { + nTargetLayer = 0; + pDrawTarget = vLayers[0].pDrawTarget.Sprite(); + } + } + + void PixelGameEngine::SetDrawTarget(uint8_t layer, bool bDirty) + { + if (layer < vLayers.size()) + { + pDrawTarget = vLayers[layer].pDrawTarget.Sprite(); + vLayers[layer].bUpdate = bDirty; + nTargetLayer = layer; + } + } + + void PixelGameEngine::EnableLayer(uint8_t layer, bool b) + { if (layer < vLayers.size()) vLayers[layer].bShow = b; } + + void PixelGameEngine::SetLayerOffset(uint8_t layer, const olc::vf2d& offset) + { SetLayerOffset(layer, offset.x, offset.y); } + + void PixelGameEngine::SetLayerOffset(uint8_t layer, float x, float y) + { if (layer < vLayers.size()) vLayers[layer].vOffset = { x, y }; } + + void PixelGameEngine::SetLayerScale(uint8_t layer, const olc::vf2d& scale) + { SetLayerScale(layer, scale.x, scale.y); } + + void PixelGameEngine::SetLayerScale(uint8_t layer, float x, float y) + { if (layer < vLayers.size()) vLayers[layer].vScale = { x, y }; } + + void PixelGameEngine::SetLayerTint(uint8_t layer, const olc::Pixel& tint) + { if (layer < vLayers.size()) vLayers[layer].tint = tint; } + + void PixelGameEngine::SetLayerCustomRenderFunction(uint8_t layer, std::function f) + { if (layer < vLayers.size()) vLayers[layer].funcHook = f; } + + std::vector& PixelGameEngine::GetLayers() + { return vLayers; } + + uint32_t PixelGameEngine::CreateLayer() + { + LayerDesc ld; + ld.pDrawTarget.Create(vScreenSize.x, vScreenSize.y); + vLayers.push_back(std::move(ld)); + return uint32_t(vLayers.size()) - 1; + } + + Sprite* PixelGameEngine::GetDrawTarget() const + { return pDrawTarget; } + + int32_t PixelGameEngine::GetDrawTargetWidth() const + { + if (pDrawTarget) + return pDrawTarget->width; + else + return 0; + } + + int32_t PixelGameEngine::GetDrawTargetHeight() const + { + if (pDrawTarget) + return pDrawTarget->height; + else + return 0; + } + + uint32_t PixelGameEngine::GetFPS() const + { return nLastFPS; } + + bool PixelGameEngine::IsFocused() const + { return bHasInputFocus; } + + HWButton PixelGameEngine::GetKey(Key k) const + { return pKeyboardState[k]; } + + HWButton PixelGameEngine::GetMouse(uint32_t b) const + { return pMouseState[b]; } + + int32_t PixelGameEngine::GetMouseX() const + { return vMousePos.x; } + + int32_t PixelGameEngine::GetMouseY() const + { return vMousePos.y; } + + const olc::vi2d& PixelGameEngine::GetMousePos() const + { return vMousePos; } + + int32_t PixelGameEngine::GetMouseWheel() const + { return nMouseWheelDelta; } + + int32_t PixelGameEngine::ScreenWidth() const + { return vScreenSize.x; } + + int32_t PixelGameEngine::ScreenHeight() const + { return vScreenSize.y; } + + float PixelGameEngine::GetElapsedTime() const + { return fLastElapsed; } + + const olc::vi2d& PixelGameEngine::GetWindowSize() const + { return vWindowSize; } + + const olc::vi2d& PixelGameEngine::GetPixelSize() const + { return vPixelSize; } + + const olc::vi2d& PixelGameEngine::GetScreenPixelSize() const + { return vScreenPixelSize; } + + const olc::vi2d& PixelGameEngine::GetWindowMouse() const + { return vMouseWindowPos; } + + bool PixelGameEngine::Draw(const olc::vi2d& pos, Pixel p) + { return Draw(pos.x, pos.y, p); } + + // This is it, the critical function that plots a pixel + bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p) + { + if (!pDrawTarget) return false; + + if (nPixelMode == Pixel::NORMAL) + { + return pDrawTarget->SetPixel(x, y, p); + } + + if (nPixelMode == Pixel::MASK) + { + if (p.a == 255) + return pDrawTarget->SetPixel(x, y, p); + } + + if (nPixelMode == Pixel::ALPHA) + { + Pixel d = pDrawTarget->GetPixel(x, y); + float a = (float)(p.a / 255.0f) * fBlendFactor; + float c = 1.0f - a; + float r = a * (float)p.r + c * (float)d.r; + float g = a * (float)p.g + c * (float)d.g; + float b = a * (float)p.b + c * (float)d.b; + return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b/*, (uint8_t)(p.a * fBlendFactor)*/)); + } + + if (nPixelMode == Pixel::CUSTOM) + { + return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y))); + } + + return false; + } + + + void PixelGameEngine::DrawLine(const olc::vi2d& pos1, const olc::vi2d& pos2, Pixel p, uint32_t pattern) + { DrawLine(pos1.x, pos1.y, pos2.x, pos2.y, p, pattern); } + + void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern) + { + int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; + dx = x2 - x1; dy = y2 - y1; + + auto rol = [&](void) { pattern = (pattern << 1) | (pattern >> 31); return pattern & 1; }; + + olc::vi2d p1(x1, y1), p2(x2, y2); + //if (!ClipLineToScreen(p1, p2)) + // return; + x1 = p1.x; y1 = p1.y; + x2 = p2.x; y2 = p2.y; + + // straight lines idea by gurkanctn + if (dx == 0) // Line is vertical + { + if (y2 < y1) std::swap(y1, y2); + for (y = y1; y <= y2; y++) if (rol()) Draw(x1, y, p); + return; + } + + if (dy == 0) // Line is horizontal + { + if (x2 < x1) std::swap(x1, x2); + for (x = x1; x <= x2; x++) if (rol()) Draw(x, y1, p); + return; + } + + // Line is Funk-aye + dx1 = abs(dx); dy1 = abs(dy); + px = 2 * dy1 - dx1; py = 2 * dx1 - dy1; + if (dy1 <= dx1) + { + if (dx >= 0) + { + x = x1; y = y1; xe = x2; + } + else + { + x = x2; y = y2; xe = x1; + } + + if (rol()) Draw(x, y, p); + + for (i = 0; x < xe; i++) + { + x = x + 1; + if (px < 0) + px = px + 2 * dy1; + else + { + if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) y = y + 1; else y = y - 1; + px = px + 2 * (dy1 - dx1); + } + if (rol()) Draw(x, y, p); + } + } + else + { + if (dy >= 0) + { + x = x1; y = y1; ye = y2; + } + else + { + x = x2; y = y2; ye = y1; + } + + if (rol()) Draw(x, y, p); + + for (i = 0; y < ye; i++) + { + y = y + 1; + if (py <= 0) + py = py + 2 * dx1; + else + { + if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) x = x + 1; else x = x - 1; + py = py + 2 * (dx1 - dy1); + } + if (rol()) Draw(x, y, p); + } + } + } + + void PixelGameEngine::DrawCircle(const olc::vi2d& pos, int32_t radius, Pixel p, uint8_t mask) + { DrawCircle(pos.x, pos.y, radius, p, mask); } + + void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask) + { // Thanks to IanM-Matrix1 #PR121 + if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius) + return; + + if (radius > 0) + { + int x0 = 0; + int y0 = radius; + int d = 3 - 2 * radius; + + while (y0 >= x0) // only formulate 1/8 of circle + { + // Draw even octants + if (mask & 0x01) Draw(x + x0, y - y0, p);// Q6 - upper right right + if (mask & 0x04) Draw(x + y0, y + x0, p);// Q4 - lower lower right + if (mask & 0x10) Draw(x - x0, y + y0, p);// Q2 - lower left left + if (mask & 0x40) Draw(x - y0, y - x0, p);// Q0 - upper upper left + if (x0 != 0 && x0 != y0) + { + if (mask & 0x02) Draw(x + y0, y - x0, p);// Q7 - upper upper right + if (mask & 0x08) Draw(x + x0, y + y0, p);// Q5 - lower right right + if (mask & 0x20) Draw(x - y0, y + x0, p);// Q3 - lower lower left + if (mask & 0x80) Draw(x - x0, y - y0, p);// Q1 - upper left left + } + + if (d < 0) + d += 4 * x0++ + 6; + else + d += 4 * (x0++ - y0--) + 10; + } + } + else + Draw(x, y, p); + } + + void PixelGameEngine::FillCircle(const olc::vi2d& pos, int32_t radius, Pixel p) + { FillCircle(pos.x, pos.y, radius, p); } + + void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p) + { // Thanks to IanM-Matrix1 #PR121 + if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius) + return; + + if (radius > 0) + { + int x0 = 0; + int y0 = radius; + int d = 3 - 2 * radius; + + auto drawline = [&](int sx, int ex, int y) + { + for (int x = sx; x <= ex; x++) + Draw(x, y, p); + }; + + while (y0 >= x0) + { + drawline(x - y0, x + y0, y - x0); + if (x0 > 0) drawline(x - y0, x + y0, y + x0); + + if (d < 0) + d += 4 * x0++ + 6; + else + { + if (x0 != y0) + { + drawline(x - x0, x + x0, y - y0); + drawline(x - x0, x + x0, y + y0); + } + d += 4 * (x0++ - y0--) + 10; + } + } + } + else + Draw(x, y, p); + } + + void PixelGameEngine::DrawRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p) + { DrawRect(pos.x, pos.y, size.x, size.y, p); } + + void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) + { + DrawLine(x, y, x + w, y, p); + DrawLine(x + w, y, x + w, y + h, p); + DrawLine(x + w, y + h, x, y + h, p); + DrawLine(x, y + h, x, y, p); + } + + void PixelGameEngine::Clear(Pixel p) + { + int pixels = GetDrawTargetWidth() * GetDrawTargetHeight(); + Pixel* m = GetDrawTarget()->GetData(); + for (int i = 0; i < pixels; i++) m[i] = p; + } + + void PixelGameEngine::ClearBuffer(Pixel p, bool bDepth) + { renderer->ClearBuffer(p, bDepth); } + + olc::Sprite* PixelGameEngine::GetFontSprite() + { return fontRenderable.Sprite(); } + + bool PixelGameEngine::ClipLineToScreen(olc::vi2d& in_p1, olc::vi2d& in_p2) + { + // https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm + static constexpr int SEG_I = 0b0000, SEG_L = 0b0001, SEG_R = 0b0010, SEG_B = 0b0100, SEG_T = 0b1000; + auto Segment = [&vScreenSize = vScreenSize](const olc::vi2d& v) + { + int i = SEG_I; + if (v.x < 0) i |= SEG_L; else if (v.x > vScreenSize.x) i |= SEG_R; + if (v.y < 0) i |= SEG_B; else if (v.y > vScreenSize.y) i |= SEG_T; + return i; + }; + + int s1 = Segment(in_p1), s2 = Segment(in_p2); + + while (true) + { + if (!(s1 | s2)) return true; + else if (s1 & s2) return false; + else + { + int s3 = s2 > s1 ? s2 : s1; + olc::vi2d n; + if (s3 & SEG_T) { n.x = in_p1.x + (in_p2.x - in_p1.x) * (vScreenSize.y - in_p1.y) / (in_p2.y - in_p1.y); n.y = vScreenSize.y; } + else if (s3 & SEG_B) { n.x = in_p1.x + (in_p2.x - in_p1.x) * (0 - in_p1.y) / (in_p2.y - in_p1.y); n.y = 0; } + else if (s3 & SEG_R) { n.x = vScreenSize.x; n.y = in_p1.y + (in_p2.y - in_p1.y) * (vScreenSize.x - in_p1.x) / (in_p2.x - in_p1.x); } + else if (s3 & SEG_L) { n.x = 0; n.y = in_p1.y + (in_p2.y - in_p1.y) * (0 - in_p1.x) / (in_p2.x - in_p1.x); } + if (s3 == s1) { in_p1 = n; s1 = Segment(in_p1); } + else { in_p2 = n; s2 = Segment(in_p2); } + } + } + return true; + } + + void PixelGameEngine::EnablePixelTransfer(const bool bEnable) + { + bSuspendTextureTransfer = !bEnable; + } + + + void PixelGameEngine::FillRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p) + { FillRect(pos.x, pos.y, size.x, size.y, p); } + + void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) + { + int32_t x2 = x + w; + int32_t y2 = y + h; + + if (x < 0) x = 0; + if (x >= (int32_t)GetDrawTargetWidth()) x = (int32_t)GetDrawTargetWidth(); + if (y < 0) y = 0; + if (y >= (int32_t)GetDrawTargetHeight()) y = (int32_t)GetDrawTargetHeight(); + + if (x2 < 0) x2 = 0; + if (x2 >= (int32_t)GetDrawTargetWidth()) x2 = (int32_t)GetDrawTargetWidth(); + if (y2 < 0) y2 = 0; + if (y2 >= (int32_t)GetDrawTargetHeight()) y2 = (int32_t)GetDrawTargetHeight(); + + for (int i = x; i < x2; i++) + for (int j = y; j < y2; j++) + Draw(i, j, p); + } + + void PixelGameEngine::DrawTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p) + { DrawTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); } + + void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) + { + DrawLine(x1, y1, x2, y2, p); + DrawLine(x2, y2, x3, y3, p); + DrawLine(x3, y3, x1, y1, p); + } + + void PixelGameEngine::FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p) + { FillTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); } + + // https://www.avrfreaks.net/sites/default/files/triangles.c + void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) + { + auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); }; + + int t1x, t2x, y, minx, maxx, t1xp, t2xp; + bool changed1 = false; + bool changed2 = false; + int signx1, signx2, dx1, dy1, dx2, dy2; + int e1, e2; + // Sort vertices + if (y1 > y2) { std::swap(y1, y2); std::swap(x1, x2); } + if (y1 > y3) { std::swap(y1, y3); std::swap(x1, x3); } + if (y2 > y3) { std::swap(y2, y3); std::swap(x2, x3); } + + t1x = t2x = x1; y = y1; // Starting points + dx1 = (int)(x2 - x1); + if (dx1 < 0) { dx1 = -dx1; signx1 = -1; } + else signx1 = 1; + dy1 = (int)(y2 - y1); + + dx2 = (int)(x3 - x1); + if (dx2 < 0) { dx2 = -dx2; signx2 = -1; } + else signx2 = 1; + dy2 = (int)(y3 - y1); + + if (dy1 > dx1) { std::swap(dx1, dy1); changed1 = true; } + if (dy2 > dx2) { std::swap(dy2, dx2); changed2 = true; } + + e2 = (int)(dx2 >> 1); + // Flat top, just process the second half + if (y1 == y2) goto next; + e1 = (int)(dx1 >> 1); + + for (int i = 0; i < dx1;) { + t1xp = 0; t2xp = 0; + if (t1x < t2x) { minx = t1x; maxx = t2x; } + else { minx = t2x; maxx = t1x; } + // process first line until y value is about to change + while (i < dx1) { + i++; + e1 += dy1; + while (e1 >= dx1) { + e1 -= dx1; + if (changed1) t1xp = signx1;//t1x += signx1; + else goto next1; + } + if (changed1) break; + else t1x += signx1; + } + // Move line + next1: + // process second line until y value is about to change + while (1) { + e2 += dy2; + while (e2 >= dx2) { + e2 -= dx2; + if (changed2) t2xp = signx2;//t2x += signx2; + else goto next2; + } + if (changed2) break; + else t2x += signx2; + } + next2: + if (minx > t1x) minx = t1x; + if (minx > t2x) minx = t2x; + if (maxx < t1x) maxx = t1x; + if (maxx < t2x) maxx = t2x; + drawline(minx, maxx, y); // Draw line from min to max points found on the y + // Now increase y + if (!changed1) t1x += signx1; + t1x += t1xp; + if (!changed2) t2x += signx2; + t2x += t2xp; + y += 1; + if (y == y2) break; + } + next: + // Second half + dx1 = (int)(x3 - x2); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; } + else signx1 = 1; + dy1 = (int)(y3 - y2); + t1x = x2; + + if (dy1 > dx1) { // swap values + std::swap(dy1, dx1); + changed1 = true; + } + else changed1 = false; + + e1 = (int)(dx1 >> 1); + + for (int i = 0; i <= dx1; i++) { + t1xp = 0; t2xp = 0; + if (t1x < t2x) { minx = t1x; maxx = t2x; } + else { minx = t2x; maxx = t1x; } + // process first line until y value is about to change + while (i < dx1) { + e1 += dy1; + while (e1 >= dx1) { + e1 -= dx1; + if (changed1) { t1xp = signx1; break; }//t1x += signx1; + else goto next3; + } + if (changed1) break; + else t1x += signx1; + if (i < dx1) i++; + } + next3: + // process second line until y value is about to change + while (t2x != x3) { + e2 += dy2; + while (e2 >= dx2) { + e2 -= dx2; + if (changed2) t2xp = signx2; + else goto next4; + } + if (changed2) break; + else t2x += signx2; + } + next4: + + if (minx > t1x) minx = t1x; + if (minx > t2x) minx = t2x; + if (maxx < t1x) maxx = t1x; + if (maxx < t2x) maxx = t2x; + drawline(minx, maxx, y); + if (!changed1) t1x += signx1; + t1x += t1xp; + if (!changed2) t2x += signx2; + t2x += t2xp; + y += 1; + if (y > y3) return; + } + } + + void PixelGameEngine::DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale, uint8_t flip) + { DrawSprite(pos.x, pos.y, sprite, scale, flip); } + + void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale, uint8_t flip) + { + if (sprite == nullptr) + return; + + int32_t fxs = 0, fxm = 1, fx = 0; + int32_t fys = 0, fym = 1, fy = 0; + if (flip & olc::Sprite::Flip::HORIZ) { fxs = sprite->width - 1; fxm = -1; } + if (flip & olc::Sprite::Flip::VERT) { fys = sprite->height - 1; fym = -1; } + + if (scale > 1) + { + fx = fxs; + for (int32_t i = 0; i < sprite->width; i++, fx += fxm) + { + fy = fys; + for (int32_t j = 0; j < sprite->height; j++, fy += fym) + for (uint32_t is = 0; is < scale; is++) + for (uint32_t js = 0; js < scale; js++) + Draw(x + (i * scale) + is, y + (j * scale) + js, sprite->GetPixel(fx, fy)); + } + } + else + { + fx = fxs; + for (int32_t i = 0; i < sprite->width; i++, fx += fxm) + { + fy = fys; + for (int32_t j = 0; j < sprite->height; j++, fy += fym) + Draw(x + i, y + j, sprite->GetPixel(fx, fy)); + } + } + } + + void PixelGameEngine::DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale, uint8_t flip) + { DrawPartialSprite(pos.x, pos.y, sprite, sourcepos.x, sourcepos.y, size.x, size.y, scale, flip); } + + void PixelGameEngine::DrawPartialSprite(int32_t x, int32_t y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale, uint8_t flip) + { + if (sprite == nullptr) + return; + + int32_t fxs = 0, fxm = 1, fx = 0; + int32_t fys = 0, fym = 1, fy = 0; + if (flip & olc::Sprite::Flip::HORIZ) { fxs = w - 1; fxm = -1; } + if (flip & olc::Sprite::Flip::VERT) { fys = h - 1; fym = -1; } + + if (scale > 1) + { + fx = fxs; + for (int32_t i = 0; i < w; i++, fx += fxm) + { + fy = fys; + for (int32_t j = 0; j < h; j++, fy += fym) + for (uint32_t is = 0; is < scale; is++) + for (uint32_t js = 0; js < scale; js++) + Draw(x + (i * scale) + is, y + (j * scale) + js, sprite->GetPixel(fx + ox, fy + oy)); + } + } + else + { + fx = fxs; + for (int32_t i = 0; i < w; i++, fx += fxm) + { + fy = fys; + for (int32_t j = 0; j < h; j++, fy += fym) + Draw(x + i, y + j, sprite->GetPixel(fx + ox, fy + oy)); + } + } + } + + void PixelGameEngine::SetDecalMode(const olc::DecalMode& mode) + { nDecalMode = mode; } + + void PixelGameEngine::SetDecalStructure(const olc::DecalStructure& structure) + { nDecalStructure = structure; } + + void PixelGameEngine::DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint) + { + olc::vf2d vScreenSpacePos = + { + (pos.x * vInvScreenSize.x) * 2.0f - 1.0f, + -((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) + }; + + + olc::vf2d vScreenSpaceDim = + { + ((pos.x + source_size.x * scale.x) * vInvScreenSize.x) * 2.0f - 1.0f, + -(((pos.y + source_size.y * scale.y) * vInvScreenSize.y) * 2.0f - 1.0f) + }; + + olc::vf2d vWindow = olc::vf2d(vViewSize); + olc::vf2d vQuantisedPos = ((vScreenSpacePos * vWindow) + olc::vf2d(0.5f, 0.5f)).floor() / vWindow; + olc::vf2d vQuantisedDim = ((vScreenSpaceDim * vWindow) + olc::vf2d(0.5f, -0.5f)).ceil() / vWindow; + + DecalInstance di; + di.points = 4; + di.decal = decal; + di.tint = { tint, tint, tint, tint }; + di.pos = { { vQuantisedPos.x, vQuantisedPos.y }, { vQuantisedPos.x, vQuantisedDim.y }, { vQuantisedDim.x, vQuantisedDim.y }, { vQuantisedDim.x, vQuantisedPos.y } }; + olc::vf2d uvtl = (source_pos + olc::vf2d(0.0001f, 0.0001f)) * decal->vUVScale; + olc::vf2d uvbr = (source_pos + source_size - olc::vf2d(0.0001f, 0.0001f)) * decal->vUVScale; + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; + di.w = { 1,1,1,1 }; + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) + { + olc::vf2d vScreenSpacePos = + { + (pos.x * vInvScreenSize.x) * 2.0f - 1.0f, + ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f + }; + + olc::vf2d vScreenSpaceDim = + { + vScreenSpacePos.x + (2.0f * size.x * vInvScreenSize.x), + vScreenSpacePos.y - (2.0f * size.y * vInvScreenSize.y) + }; + + DecalInstance di; + di.points = 4; + di.decal = decal; + di.tint = { tint, tint, tint, tint }; + di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } }; + olc::vf2d uvtl = (source_pos) * decal->vUVScale; + olc::vf2d uvbr = uvtl + ((source_size) * decal->vUVScale); + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; + di.w = { 1,1,1,1 }; + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + + void PixelGameEngine::DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale, const olc::Pixel& tint) + { + olc::vf2d vScreenSpacePos = + { + (pos.x * vInvScreenSize.x) * 2.0f - 1.0f, + ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f + }; + + olc::vf2d vScreenSpaceDim = + { + vScreenSpacePos.x + (2.0f * (float(decal->sprite->width) * vInvScreenSize.x)) * scale.x, + vScreenSpacePos.y - (2.0f * (float(decal->sprite->height) * vInvScreenSize.y)) * scale.y + }; + + DecalInstance di; + di.decal = decal; + di.points = 4; + di.tint = { tint, tint, tint, tint }; + di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } }; + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; + di.w = { 1, 1, 1, 1 }; + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements) + { + DecalInstance di; + di.decal = decal; + di.pos.resize(elements); + di.uv.resize(elements); + di.w.resize(elements); + di.tint.resize(elements); + di.points = elements; + for (uint32_t i = 0; i < elements; i++) + { + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[i] = uv[i]; + di.tint[i] = col[i]; + di.w[i] = 1.0f; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint) + { + DecalInstance di; + di.decal = decal; + di.points = uint32_t(pos.size()); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + for (uint32_t i = 0; i < di.points; i++) + { + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[i] = uv[i]; + di.tint[i] = tint; + di.w[i] = 1.0f; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector &tint) + { + DecalInstance di; + di.decal = decal; + di.points = uint32_t(pos.size()); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + for (uint32_t i = 0; i < di.points; i++) + { + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[i] = uv[i]; + di.tint[i] = tint[i]; + di.w[i] = 1.0f; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& depth, const std::vector& uv, const olc::Pixel tint) + { + DecalInstance di; + di.decal = decal; + di.points = uint32_t(pos.size()); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + for (uint32_t i = 0; i < di.points; i++) + { + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[i] = uv[i]; + di.tint[i] = tint; + di.w[i] = 1.0f; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + +#ifdef OLC_ENABLE_EXPERIMENTAL + // Lightweight 3D + void PixelGameEngine::LW3D_DrawTriangles(olc::Decal* decal, const std::vector>& pos, const std::vector& tex, const std::vector& col) + { + DecalInstance di; + di.decal = decal; + di.points = uint32_t(pos.size()); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + for (uint32_t i = 0; i < di.points; i++) + { + di.pos[i] = { pos[i][0], pos[i][1] }; + di.w[i] = pos[i][2]; + di.uv[i] = tex[i]; + di.tint[i] = col[i]; + } + di.mode = DecalMode::MODEL3D; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } +#endif + + void PixelGameEngine::DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p) + { + DecalInstance di; + di.decal = nullptr; + di.points = uint32_t(2); + di.pos.resize(di.points); + di.uv.resize(di.points); + di.w.resize(di.points); + di.tint.resize(di.points); + di.pos[0] = { (pos1.x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos1.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[0] = { 0.0f, 0.0f }; + di.tint[0] = p; + di.w[0] = 1.0f; + di.pos[1] = { (pos2.x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos2.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + di.uv[1] = { 0.0f, 0.0f }; + di.tint[1] = p; + di.w[1] = 1.0f; + di.mode = olc::DecalMode::WIREFRAME; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) + { + olc::vf2d vNewSize = (size - olc::vf2d(0.375f, 0.375f)).ceil(); + std::array points = { { {pos}, {pos.x, pos.y + vNewSize.y}, {pos + vNewSize}, {pos.x + vNewSize.x, pos.y} } }; + std::array uvs = { {{0,0},{0,0},{0,0},{0,0}} }; + std::array cols = { {col, col, col, col} }; + DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4); + } + + void PixelGameEngine::GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR) + { + std::array points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } }; + std::array uvs = { {{0,0},{0,0},{0,0},{0,0}} }; + std::array cols = { {colTL, colBL, colBR, colTR} }; + DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4); + } + + void PixelGameEngine::DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& scale, const olc::Pixel& tint) + { + DecalInstance di; + di.decal = decal; + di.pos.resize(4); + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; + di.w = { 1, 1, 1, 1 }; + di.tint = { tint, tint, tint, tint }; + di.points = 4; + di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale; + di.pos[1] = (olc::vf2d(0.0f, float(decal->sprite->height)) - center) * scale; + di.pos[2] = (olc::vf2d(float(decal->sprite->width), float(decal->sprite->height)) - center) * scale; + di.pos[3] = (olc::vf2d(float(decal->sprite->width), 0.0f) - center) * scale; + float c = cos(fAngle), s = sin(fAngle); + for (int i = 0; i < 4; i++) + { + di.pos[i] = pos + olc::vf2d(di.pos[i].x * c - di.pos[i].y * s, di.pos[i].x * s + di.pos[i].y * c); + di.pos[i] = di.pos[i] * vInvScreenSize * 2.0f - olc::vf2d(1.0f, 1.0f); + di.pos[i].y *= -1.0f; + di.w[i] = 1; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + + void PixelGameEngine::DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint) + { + DecalInstance di; + di.decal = decal; + di.points = 4; + di.tint = { tint, tint, tint, tint }; + di.w = { 1, 1, 1, 1 }; + di.pos.resize(4); + di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale; + di.pos[1] = (olc::vf2d(0.0f, source_size.y) - center) * scale; + di.pos[2] = (olc::vf2d(source_size.x, source_size.y) - center) * scale; + di.pos[3] = (olc::vf2d(source_size.x, 0.0f) - center) * scale; + float c = cos(fAngle), s = sin(fAngle); + for (int i = 0; i < 4; i++) + { + di.pos[i] = pos + olc::vf2d(di.pos[i].x * c - di.pos[i].y * s, di.pos[i].x * s + di.pos[i].y * c); + di.pos[i] = di.pos[i] * vInvScreenSize * 2.0f - olc::vf2d(1.0f, 1.0f); + di.pos[i].y *= -1.0f; + } + + olc::vf2d uvtl = source_pos * decal->vUVScale; + olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale); + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + + void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) + { + DecalInstance di; + di.points = 4; + di.decal = decal; + di.tint = { tint, tint, tint, tint }; + di.w = { 1, 1, 1, 1 }; + di.pos.resize(4); + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; + olc::vf2d center; + float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y)); + if (rd != 0) + { + olc::vf2d uvtl = source_pos * decal->vUVScale; + olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale); + di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; + + rd = 1.0f / rd; + float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd; + float sn = ((pos[2].x - pos[0].x) * (pos[0].y - pos[1].y) - (pos[2].y - pos[0].y) * (pos[0].x - pos[1].x)) * rd; + if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) center = pos[0] + rn * (pos[2] - pos[0]); + float d[4]; for (int i = 0; i < 4; i++) d[i] = (pos[i] - center).mag(); + for (int i = 0; i < 4; i++) + { + float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3]; + di.uv[i] *= q; di.w[i] *= q; + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + } + + void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint) + { + // Thanks Nathan Reed, a brilliant article explaining whats going on here + // http://www.reedbeta.com/blog/quadrilateral-interpolation-part-1/ + DecalInstance di; + di.points = 4; + di.decal = decal; + di.tint = { tint, tint, tint, tint }; + di.w = { 1, 1, 1, 1 }; + di.pos.resize(4); + di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} }; + olc::vf2d center; + float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y)); + if (rd != 0) + { + rd = 1.0f / rd; + float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd; + float sn = ((pos[2].x - pos[0].x) * (pos[0].y - pos[1].y) - (pos[2].y - pos[0].y) * (pos[0].x - pos[1].x)) * rd; + if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) center = pos[0] + rn * (pos[2] - pos[0]); + float d[4]; for (int i = 0; i < 4; i++) d[i] = (pos[i] - center).mag(); + for (int i = 0; i < 4; i++) + { + float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3]; + di.uv[i] *= q; di.w[i] *= q; + di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f }; + } + di.mode = nDecalMode; + di.structure = nDecalStructure; + vLayers[nTargetLayer].vecDecalInstance.push_back(di); + } + } + + void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint) + { DrawWarpedDecal(decal, pos.data(), tint); } + + void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint) + { DrawWarpedDecal(decal, &pos[0], tint); } + + void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) + { DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint); } + + void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) + { DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint); } + + void PixelGameEngine::DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale) + { + olc::vf2d spos = { 0.0f, 0.0f }; + for (auto c : sText) + { + if (c == '\n') + { + spos.x = 0; spos.y += 8.0f * scale.y; + } + else if (c == '\t') + { + spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialDecal(pos + spos, fontRenderable.Decal(), {float(ox) * 8.0f, float(oy) * 8.0f}, {8.0f, 8.0f}, scale, col); + spos.x += 8.0f * scale.x; + } + } + } + + void PixelGameEngine::DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale) + { + olc::vf2d spos = { 0.0f, 0.0f }; + for (auto c : sText) + { + if (c == '\n') + { + spos.x = 0; spos.y += 8.0f * scale.y; + } + else if (c == '\t') + { + spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialDecal(pos + spos, fontRenderable.Decal(), { float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(vFontSpacing[c - 32].y), 8.0f }, scale, col); + spos.x += float(vFontSpacing[c - 32].y) * scale.x; + } + } + } + // Thanks Oso-Grande/Sopadeoso For these awesom and stupidly clever Text Rotation routines... duh XD + void PixelGameEngine::DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale) + { + olc::vf2d spos = center; + for (auto c : sText) + { + if (c == '\n') + { + spos.x = center.x; spos.y -= 8.0f; + } + else if (c == '\t') + { + spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialRotatedDecal(pos, fontRenderable.Decal(), fAngle, spos, { float(ox) * 8.0f, float(oy) * 8.0f }, { 8.0f, 8.0f }, scale, col); + spos.x -= 8.0f; + } + } + } + + void PixelGameEngine::DrawRotatedStringPropDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale) + { + olc::vf2d spos = center; + for (auto c : sText) + { + if (c == '\n') + { + spos.x = center.x; spos.y -= 8.0f; + } + else if (c == '\t') + { + spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialRotatedDecal(pos, fontRenderable.Decal(), fAngle, spos, { float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(vFontSpacing[c - 32].y), 8.0f }, scale, col); + spos.x -= float(vFontSpacing[c - 32].y); + } + } + } + + olc::vi2d PixelGameEngine::GetTextSize(const std::string& s) + { + olc::vi2d size = { 0,1 }; + olc::vi2d pos = { 0,1 }; + for (auto c : s) + { + if (c == '\n') { pos.y++; pos.x = 0; } + else if (c == '\t') { pos.x += nTabSizeInSpaces; } + else pos.x++; + size.x = std::max(size.x, pos.x); + size.y = std::max(size.y, pos.y); + } + return size * 8; + } + + void PixelGameEngine::DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale) + { DrawString(pos.x, pos.y, sText, col, scale); } + + void PixelGameEngine::DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col, uint32_t scale) + { + int32_t sx = 0; + int32_t sy = 0; + Pixel::Mode m = nPixelMode; + // Thanks @tucna, spotted bug with col.ALPHA :P + if (m != Pixel::CUSTOM) // Thanks @Megarev, required for "shaders" + { + if (col.a != 255) SetPixelMode(Pixel::ALPHA); + else SetPixelMode(Pixel::MASK); + } + for (auto c : sText) + { + if (c == '\n') + { + sx = 0; sy += 8 * scale; + } + else if (c == '\t') + { + sx += 8 * nTabSizeInSpaces * scale; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + + if (scale > 1) + { + for (uint32_t i = 0; i < 8; i++) + for (uint32_t j = 0; j < 8; j++) + if (fontRenderable.Sprite()->GetPixel(i + ox * 8, j + oy * 8).r > 0) + for (uint32_t is = 0; is < scale; is++) + for (uint32_t js = 0; js < scale; js++) + Draw(x + sx + (i * scale) + is, y + sy + (j * scale) + js, col); + } + else + { + for (uint32_t i = 0; i < 8; i++) + for (uint32_t j = 0; j < 8; j++) + if (fontRenderable.Sprite()->GetPixel(i + ox * 8, j + oy * 8).r > 0) + Draw(x + sx + i, y + sy + j, col); + } + sx += 8 * scale; + } + } + SetPixelMode(m); + } + + olc::vi2d PixelGameEngine::GetTextSizeProp(const std::string& s) + { + olc::vi2d size = { 0,1 }; + olc::vi2d pos = { 0,1 }; + for (auto c : s) + { + if (c == '\n') { pos.y += 1; pos.x = 0; } + else if (c == '\t') { pos.x += nTabSizeInSpaces * 8; } + else pos.x += vFontSpacing[c - 32].y; + size.x = std::max(size.x, pos.x); + size.y = std::max(size.y, pos.y); + } + + size.y *= 8; + return size; + } + + void PixelGameEngine::DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale) + { DrawStringProp(pos.x, pos.y, sText, col, scale); } + + void PixelGameEngine::DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col, uint32_t scale) + { + int32_t sx = 0; + int32_t sy = 0; + Pixel::Mode m = nPixelMode; + + if (m != Pixel::CUSTOM) + { + if (col.a != 255) SetPixelMode(Pixel::ALPHA); + else SetPixelMode(Pixel::MASK); + } + for (auto c : sText) + { + if (c == '\n') + { + sx = 0; sy += 8 * scale; + } + else if (c == '\t') + { + sx += 8 * nTabSizeInSpaces * scale; + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + + if (scale > 1) + { + for (int32_t i = 0; i < vFontSpacing[c - 32].y; i++) + for (int32_t j = 0; j < 8; j++) + if (fontRenderable.Sprite()->GetPixel(i + ox * 8 + vFontSpacing[c - 32].x, j + oy * 8).r > 0) + for (int32_t is = 0; is < int(scale); is++) + for (int32_t js = 0; js < int(scale); js++) + Draw(x + sx + (i * scale) + is, y + sy + (j * scale) + js, col); + } + else + { + for (int32_t i = 0; i < vFontSpacing[c - 32].y; i++) + for (int32_t j = 0; j < 8; j++) + if (fontRenderable.Sprite()->GetPixel(i + ox * 8 + vFontSpacing[c - 32].x, j + oy * 8).r > 0) + Draw(x + sx + i, y + sy + j, col); + } + sx += vFontSpacing[c - 32].y * scale; + } + } + SetPixelMode(m); + } + + void PixelGameEngine::SetPixelMode(Pixel::Mode m) + { nPixelMode = m; } + + Pixel::Mode PixelGameEngine::GetPixelMode() + { return nPixelMode; } + + void PixelGameEngine::SetPixelMode(std::function pixelMode) + { + funcPixelMode = pixelMode; + nPixelMode = Pixel::Mode::CUSTOM; + } + + void PixelGameEngine::SetPixelBlend(float fBlend) + { + fBlendFactor = fBlend; + if (fBlendFactor < 0.0f) fBlendFactor = 0.0f; + if (fBlendFactor > 1.0f) fBlendFactor = 1.0f; + } + + std::stringstream& PixelGameEngine::ConsoleOut() + { return ssConsoleOutput; } + + bool PixelGameEngine::IsConsoleShowing() const + { return bConsoleShow; } + + void PixelGameEngine::ConsoleShow(const olc::Key& keyExit, bool bSuspendTime) + { + if (bConsoleShow) + return; + + bConsoleShow = true; + bConsoleSuspendTime = bSuspendTime; + TextEntryEnable(true); + keyConsoleExit = keyExit; + pKeyboardState[keyConsoleExit].bHeld = false; + pKeyboardState[keyConsoleExit].bPressed = false; + pKeyboardState[keyConsoleExit].bReleased = true; + } + + void PixelGameEngine::ConsoleClear() + { sConsoleLines.clear(); } + + void PixelGameEngine::ConsoleCaptureStdOut(const bool bCapture) + { + if(bCapture) + sbufOldCout = std::cout.rdbuf(ssConsoleOutput.rdbuf()); + else + std::cout.rdbuf(sbufOldCout); + } + + void PixelGameEngine::UpdateConsole() + { + if (GetKey(keyConsoleExit).bPressed) + { + TextEntryEnable(false); + bConsoleSuspendTime = false; + bConsoleShow = false; + return; + } + + // Keep Console sizes based in real screen dimensions + vConsoleCharacterScale = olc::vf2d(1.0f, 2.0f) / (olc::vf2d(vViewSize) * vInvScreenSize); + vConsoleSize = (vViewSize / olc::vi2d(8, 16)) - olc::vi2d(2, 4); + + // If console has changed size, simply reset it + if (vConsoleSize.y != sConsoleLines.size()) + { + vConsoleCursor = { 0,0 }; + sConsoleLines.clear(); + sConsoleLines.resize(vConsoleSize.y); + } + + auto TypeCharacter = [&](const char c) + { + if (c >= 32 && c < 127) + { + sConsoleLines[vConsoleCursor.y].append(1, c); + vConsoleCursor.x++; + } + + if( c == '\n' || vConsoleCursor.x >= vConsoleSize.x) + { + vConsoleCursor.y++; vConsoleCursor.x = 0; + } + + if (vConsoleCursor.y >= vConsoleSize.y) + { + vConsoleCursor.y = vConsoleSize.y - 1; + for (size_t i = 1; i < vConsoleSize.y; i++) + sConsoleLines[i - 1] = sConsoleLines[i]; + sConsoleLines[vConsoleCursor.y].clear(); + } + }; + + // Empty out "std::cout", parsing as we go + while (ssConsoleOutput.rdbuf()->sgetc() != -1) + { + char c = ssConsoleOutput.rdbuf()->sbumpc(); + TypeCharacter(c); + } + + // Draw Shadow + GradientFillRectDecal({ 0,0 }, olc::vf2d(vScreenSize), olc::PixelF(0, 0, 0.5f, 0.5f), olc::PixelF(0, 0, 0.25f, 0.5f), olc::PixelF(0, 0, 0.25f, 0.5f), olc::PixelF(0, 0, 0.25f, 0.5f)); + + // Draw the console buffer + SetDecalMode(olc::DecalMode::NORMAL); + for (int32_t nLine = 0; nLine < vConsoleSize.y; nLine++) + DrawStringDecal(olc::vf2d( 1, 1 + float(nLine) ) * vConsoleCharacterScale * 8.0f, sConsoleLines[nLine], olc::WHITE, vConsoleCharacterScale); + + // Draw Input State + FillRectDecal(olc::vf2d(1 + float((TextEntryGetCursor() + 1)), 1 + float((vConsoleSize.y - 1))) * vConsoleCharacterScale * 8.0f, olc::vf2d(8, 8) * vConsoleCharacterScale, olc::DARK_CYAN); + DrawStringDecal(olc::vf2d(1, 1 + float((vConsoleSize.y - 1))) * vConsoleCharacterScale * 8.0f, std::string(">") + TextEntryGetString(), olc::YELLOW, vConsoleCharacterScale); + } + + + + void PixelGameEngine::TextEntryEnable(const bool bEnable, const std::string& sText) + { + if (bEnable) + { + nTextEntryCursor = int32_t(sText.size()); + sTextEntryString = sText; + bTextEntryEnable = true; + } + else + { + bTextEntryEnable = false; + } + } + + std::string PixelGameEngine::TextEntryGetString() const + { return sTextEntryString; } + + int32_t PixelGameEngine::TextEntryGetCursor() const + { return nTextEntryCursor; } + + bool PixelGameEngine::IsTextEntryEnabled() const + { return bTextEntryEnable; } + + + void PixelGameEngine::UpdateTextEntry() + { + // Check for typed characters + for (const auto& key : vKeyboardMap) + if (GetKey(std::get<0>(key)).bPressed) + { + sTextEntryString.insert(nTextEntryCursor, GetKey(olc::Key::SHIFT).bHeld ? std::get<2>(key) : std::get<1>(key)); + nTextEntryCursor++; + } + + // Check for command characters + if (GetKey(olc::Key::LEFT).bPressed) + nTextEntryCursor = std::max(0, nTextEntryCursor - 1); + if (GetKey(olc::Key::RIGHT).bPressed) + nTextEntryCursor = std::min(int32_t(sTextEntryString.size()), nTextEntryCursor + 1); + if (GetKey(olc::Key::BACK).bPressed && nTextEntryCursor > 0) + { + sTextEntryString.erase(nTextEntryCursor-1, 1); + nTextEntryCursor = std::max(0, nTextEntryCursor - 1); + } + if (GetKey(olc::Key::DEL).bPressed && nTextEntryCursor < sTextEntryString.size()) + sTextEntryString.erase(nTextEntryCursor, 1); + + if (GetKey(olc::Key::UP).bPressed) + { + if (!sCommandHistory.empty()) + { + if (sCommandHistoryIt != sCommandHistory.begin()) + sCommandHistoryIt--; + + nTextEntryCursor = int32_t(sCommandHistoryIt->size()); + sTextEntryString = *sCommandHistoryIt; + } + } + + if (GetKey(olc::Key::DOWN).bPressed) + { + if (!sCommandHistory.empty()) + { + if (sCommandHistoryIt != sCommandHistory.end()) + { + sCommandHistoryIt++; + if (sCommandHistoryIt != sCommandHistory.end()) + { + nTextEntryCursor = int32_t(sCommandHistoryIt->size()); + sTextEntryString = *sCommandHistoryIt; + } + else + { + nTextEntryCursor = 0; + sTextEntryString = ""; + } + } + } + } + + if (GetKey(olc::Key::ENTER).bPressed) + { + if (bConsoleShow) + { + std::cout << ">" + sTextEntryString + "\n"; + if (OnConsoleCommand(sTextEntryString)) + { + sCommandHistory.push_back(sTextEntryString); + sCommandHistoryIt = sCommandHistory.end(); + } + sTextEntryString.clear(); + nTextEntryCursor = 0; + } + else + { + OnTextEntryComplete(sTextEntryString); + TextEntryEnable(false); + } + } + } + + // User must override these functions as required. I have not made + // them abstract because I do need a default behaviour to occur if + // they are not overwritten + + bool PixelGameEngine::OnUserCreate() + { return false; } + + bool PixelGameEngine::OnUserUpdate(float fElapsedTime) + { UNUSED(fElapsedTime); return false; } + + bool PixelGameEngine::OnUserDestroy() + { return true; } + + void PixelGameEngine::OnTextEntryComplete(const std::string& sText) { UNUSED(sText); } + bool PixelGameEngine::OnConsoleCommand(const std::string& sCommand) { UNUSED(sCommand); return false; } + + + // Externalised API + void PixelGameEngine::olc_UpdateViewport() + { + int32_t ww = vScreenSize.x * vPixelSize.x; + int32_t wh = vScreenSize.y * vPixelSize.y; + float wasp = (float)ww / (float)wh; + + if (bPixelCohesion) + { + vScreenPixelSize = (vWindowSize / vScreenSize); + vViewSize = (vWindowSize / vScreenSize) * vScreenSize; + } + else + { + vViewSize.x = (int32_t)vWindowSize.x; + vViewSize.y = (int32_t)((float)vViewSize.x / wasp); + + if (vViewSize.y > vWindowSize.y) + { + vViewSize.y = vWindowSize.y; + vViewSize.x = (int32_t)((float)vViewSize.y * wasp); + } + } + + vViewPos = (vWindowSize - vViewSize) / 2; + } + + void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y) + { + vWindowSize = { x, y }; + olc_UpdateViewport(); + } + + void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta) + { nMouseWheelDeltaCache += delta; } + + void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y) + { + // Mouse coords come in screen space + // But leave in pixel space + bHasMouseFocus = true; + vMouseWindowPos = { x, y }; + // Full Screen mode may have a weird viewport we must clamp to + x -= vViewPos.x; + y -= vViewPos.y; + vMousePosCache.x = (int32_t)(((float)x / (float)(vWindowSize.x - (vViewPos.x * 2)) * (float)vScreenSize.x)); + vMousePosCache.y = (int32_t)(((float)y / (float)(vWindowSize.y - (vViewPos.y * 2)) * (float)vScreenSize.y)); + if (vMousePosCache.x >= (int32_t)vScreenSize.x) vMousePosCache.x = vScreenSize.x - 1; + if (vMousePosCache.y >= (int32_t)vScreenSize.y) vMousePosCache.y = vScreenSize.y - 1; + if (vMousePosCache.x < 0) vMousePosCache.x = 0; + if (vMousePosCache.y < 0) vMousePosCache.y = 0; + } + + void PixelGameEngine::olc_UpdateMouseState(int32_t button, bool state) + { pMouseNewState[button] = state; } + + void PixelGameEngine::olc_UpdateKeyState(int32_t key, bool state) + { pKeyNewState[key] = state; } + + void PixelGameEngine::olc_UpdateMouseFocus(bool state) + { bHasMouseFocus = state; } + + void PixelGameEngine::olc_UpdateKeyFocus(bool state) + { bHasInputFocus = state; } + + void PixelGameEngine::olc_Reanimate() + { bAtomActive = true; } + + bool PixelGameEngine::olc_IsRunning() + { return bAtomActive; } + + void PixelGameEngine::olc_Terminate() + { bAtomActive = false; } + + void PixelGameEngine::EngineThread() + { + // Allow platform to do stuff here if needed, since its now in the + // context of this thread + if (platform->ThreadStartUp() == olc::FAIL) return; + + // Do engine context specific initialisation + olc_PrepareEngine(); + + // Create user resources as part of this thread + for (auto& ext : vExtensions) ext->OnBeforeUserCreate(); + if (!OnUserCreate()) bAtomActive = false; + for (auto& ext : vExtensions) ext->OnAfterUserCreate(); + + while (bAtomActive) + { + // Run as fast as possible + while (bAtomActive) { olc_CoreUpdate(); } + + // Allow the user to free resources if they have overrided the destroy function + if (!OnUserDestroy()) + { + // User denied destroy for some reason, so continue running + bAtomActive = true; + } + } + + platform->ThreadCleanUp(); + } + + void PixelGameEngine::olc_PrepareEngine() + { + // Start OpenGL, the context is owned by the game thread + if (platform->CreateGraphics(bFullScreen, bEnableVSYNC, vViewPos, vViewSize) == olc::FAIL) return; + + // Construct default font sheet + olc_ConstructFontSheet(); + + // Create Primary Layer "0" + CreateLayer(); + vLayers[0].bUpdate = true; + vLayers[0].bShow = true; + SetDrawTarget(nullptr); + + m_tp1 = std::chrono::system_clock::now(); + m_tp2 = std::chrono::system_clock::now(); + } + + + void PixelGameEngine::olc_CoreUpdate() + { + // Handle Timing + m_tp2 = std::chrono::system_clock::now(); + std::chrono::duration elapsedTime = m_tp2 - m_tp1; + m_tp1 = m_tp2; + + // Our time per frame coefficient + float fElapsedTime = elapsedTime.count(); + fLastElapsed = fElapsedTime; + + if (bConsoleSuspendTime) + fElapsedTime = 0.0f; + + // Some platforms will need to check for events + platform->HandleSystemEvent(); + + // Compare hardware input states from previous frame + auto ScanHardware = [&](HWButton* pKeys, bool* pStateOld, bool* pStateNew, uint32_t nKeyCount) + { + for (uint32_t i = 0; i < nKeyCount; i++) + { + pKeys[i].bPressed = false; + pKeys[i].bReleased = false; + if (pStateNew[i] != pStateOld[i]) + { + if (pStateNew[i]) + { + pKeys[i].bPressed = !pKeys[i].bHeld; + pKeys[i].bHeld = true; + } + else + { + pKeys[i].bReleased = true; + pKeys[i].bHeld = false; + } + } + pStateOld[i] = pStateNew[i]; + } + }; + + ScanHardware(pKeyboardState, pKeyOldState, pKeyNewState, 256); + ScanHardware(pMouseState, pMouseOldState, pMouseNewState, nMouseButtons); + + // Cache mouse coordinates so they remain consistent during frame + vMousePos = vMousePosCache; + nMouseWheelDelta = nMouseWheelDeltaCache; + nMouseWheelDeltaCache = 0; + + if (bTextEntryEnable) + { + UpdateTextEntry(); + } + + // Handle Frame Update + bool bExtensionBlockFrame = false; + for (auto& ext : vExtensions) bExtensionBlockFrame |= ext->OnBeforeUserUpdate(fElapsedTime); + if (!bExtensionBlockFrame) + { + if (!OnUserUpdate(fElapsedTime)) bAtomActive = false; + } + for (auto& ext : vExtensions) ext->OnAfterUserUpdate(fElapsedTime); + + if (bConsoleShow) + { + SetDrawTarget((uint8_t)0); + UpdateConsole(); + } + + // Display Frame + renderer->UpdateViewport(vViewPos, vViewSize); + renderer->ClearBuffer(olc::BLACK, true); + + // Layer 0 must always exist + vLayers[0].bUpdate = true; + vLayers[0].bShow = true; + SetDecalMode(DecalMode::NORMAL); + renderer->PrepareDrawing(); + + for (auto layer = vLayers.rbegin(); layer != vLayers.rend(); ++layer) + { + if (layer->bShow) + { + if (layer->funcHook == nullptr) + { + renderer->ApplyTexture(layer->pDrawTarget.Decal()->id); + if (!bSuspendTextureTransfer && layer->bUpdate) + { + layer->pDrawTarget.Decal()->Update(); + layer->bUpdate = false; + } + + renderer->DrawLayerQuad(layer->vOffset, layer->vScale, layer->tint); + + // Display Decals in order for this layer + for (auto& decal : layer->vecDecalInstance) + renderer->DrawDecal(decal); + layer->vecDecalInstance.clear(); + } + else + { + // Mwa ha ha.... Have Fun!!! + layer->funcHook(); + } + } + } + + + + // Present Graphics to screen + renderer->DisplayFrame(); + + // Update Title Bar + fFrameTimer += fElapsedTime; + nFrameCount++; + if (fFrameTimer >= 1.0f) + { + nLastFPS = nFrameCount; + fFrameTimer -= 1.0f; + std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount); + platform->SetWindowTitle(sTitle); + nFrameCount = 0; + } + } + + void PixelGameEngine::olc_ConstructFontSheet() + { + std::string data; + data += "?Q`0001oOch0o01o@F40o000000000"; + data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400"; + data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000"; + data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000"; + data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000"; + data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000"; + data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000"; + data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000"; + data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000"; + data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000"; + data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000"; + data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000"; + data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000"; + data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0"; + data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`SetPixel(px, py, olc::Pixel(k, k, k, k)); + if (++py == 48) { px++; py = 0; } + } + } + + fontRenderable.Decal()->Update(); + + constexpr std::array vSpacing = { { + 0x03,0x25,0x16,0x08,0x07,0x08,0x08,0x04,0x15,0x15,0x08,0x07,0x15,0x07,0x24,0x08, + 0x08,0x17,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x24,0x15,0x06,0x07,0x16,0x17, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x17,0x08,0x08,0x17,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x17,0x08,0x08,0x08,0x08,0x17,0x08,0x15,0x08,0x15,0x08,0x08, + 0x24,0x18,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x33,0x17,0x17,0x33,0x18,0x17,0x17, + 0x17,0x17,0x17,0x17,0x07,0x17,0x17,0x18,0x18,0x17,0x17,0x07,0x33,0x07,0x08,0x00, } }; + + for (auto c : vSpacing) vFontSpacing.push_back({ c >> 4, c & 15 }); + + // UK Standard Layout +#ifdef OLC_KEYBOARD_UK + vKeyboardMap = + { + {olc::Key::A, "a", "A"}, {olc::Key::B, "b", "B"}, {olc::Key::C, "c", "C"}, {olc::Key::D, "d", "D"}, {olc::Key::E, "e", "E"}, + {olc::Key::F, "f", "F"}, {olc::Key::G, "g", "G"}, {olc::Key::H, "h", "H"}, {olc::Key::I, "i", "I"}, {olc::Key::J, "j", "J"}, + {olc::Key::K, "k", "K"}, {olc::Key::L, "l", "L"}, {olc::Key::M, "m", "M"}, {olc::Key::N, "n", "N"}, {olc::Key::O, "o", "O"}, + {olc::Key::P, "p", "P"}, {olc::Key::Q, "q", "Q"}, {olc::Key::R, "r", "R"}, {olc::Key::S, "s", "S"}, {olc::Key::T, "t", "T"}, + {olc::Key::U, "u", "U"}, {olc::Key::V, "v", "V"}, {olc::Key::W, "w", "W"}, {olc::Key::X, "x", "X"}, {olc::Key::Y, "y", "Y"}, + {olc::Key::Z, "z", "Z"}, + + {olc::Key::K0, "0", ")"}, {olc::Key::K1, "1", "!"}, {olc::Key::K2, "2", "\""}, {olc::Key::K3, "3", "#"}, {olc::Key::K4, "4", "$"}, + {olc::Key::K5, "5", "%"}, {olc::Key::K6, "6", "^"}, {olc::Key::K7, "7", "&"}, {olc::Key::K8, "8", "*"}, {olc::Key::K9, "9", "("}, + + {olc::Key::NP0, "0", "0"}, {olc::Key::NP1, "1", "1"}, {olc::Key::NP2, "2", "2"}, {olc::Key::NP3, "3", "3"}, {olc::Key::NP4, "4", "4"}, + {olc::Key::NP5, "5", "5"}, {olc::Key::NP6, "6", "6"}, {olc::Key::NP7, "7", "7"}, {olc::Key::NP8, "8", "8"}, {olc::Key::NP9, "9", "9"}, + {olc::Key::NP_MUL, "*", "*"}, {olc::Key::NP_DIV, "/", "/"}, {olc::Key::NP_ADD, "+", "+"}, {olc::Key::NP_SUB, "-", "-"}, {olc::Key::NP_DECIMAL, ".", "."}, + + {olc::Key::PERIOD, ".", ">"}, {olc::Key::EQUALS, "=", "+"}, {olc::Key::COMMA, ",", "<"}, {olc::Key::MINUS, "-", "_"}, {olc::Key::SPACE, " ", " "}, + + {olc::Key::OEM_1, ";", ":"}, {olc::Key::OEM_2, "/", "?"}, {olc::Key::OEM_3, "\'", "@"}, {olc::Key::OEM_4, "[", "{"}, + {olc::Key::OEM_5, "\\", "|"}, {olc::Key::OEM_6, "]", "}"}, {olc::Key::OEM_7, "#", "~"}, + + // {olc::Key::TAB, "\t", "\t"} + }; +#endif + } + + void PixelGameEngine::pgex_Register(olc::PGEX* pgex) + { + if (std::find(vExtensions.begin(), vExtensions.end(), pgex) == vExtensions.end()) + vExtensions.push_back(pgex); + } + + + PGEX::PGEX(bool bHook) { if(bHook) pge->pgex_Register(this); } + void PGEX::OnBeforeUserCreate() {} + void PGEX::OnAfterUserCreate() {} + bool PGEX::OnBeforeUserUpdate(float& fElapsedTime) { return false; } + void PGEX::OnAfterUserUpdate(float fElapsedTime) {} + + // Need a couple of statics as these are singleton instances + // read from multiple locations + std::atomic PixelGameEngine::bAtomActive{ false }; + olc::PixelGameEngine* olc::PGEX::pge = nullptr; + olc::PixelGameEngine* olc::Platform::ptrPGE = nullptr; + olc::PixelGameEngine* olc::Renderer::ptrPGE = nullptr; + std::unique_ptr olc::Sprite::loader = nullptr; +}; +#pragma endregion + +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Renderers - the draw-y bits | +// O------------------------------------------------------------------------------O + +#if !defined(OLC_PGE_HEADLESS) + +#pragma region renderer_ogl10 +// O------------------------------------------------------------------------------O +// | START RENDERER: OpenGL 1.0 (the original, the best...) | +// O------------------------------------------------------------------------------O +#if defined(OLC_GFX_OPENGL10) + +#if defined(OLC_PLATFORM_WINAPI) + #include + #include + #if !defined(__MINGW32__) + #pragma comment(lib, "Dwmapi.lib") + #endif + typedef BOOL(WINAPI wglSwapInterval_t) (int interval); + static wglSwapInterval_t* wglSwapInterval = nullptr; + typedef HDC glDeviceContext_t; + typedef HGLRC glRenderContext_t; +#endif + +#if defined(__linux__) || defined(__FreeBSD__) + #include +#endif + +#if defined(OLC_PLATFORM_X11) + namespace X11 + { + #include + } + typedef int(glSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); + static glSwapInterval_t* glSwapIntervalEXT; + typedef X11::GLXContext glDeviceContext_t; + typedef X11::GLXContext glRenderContext_t; +#endif + +#if defined(__APPLE__) + #define GL_SILENCE_DEPRECATION + #include + #include + #include +#endif + +namespace olc +{ + class Renderer_OGL10 : public olc::Renderer + { + private: +#if defined(OLC_PLATFORM_GLUT) + bool mFullScreen = false; +#else + glDeviceContext_t glDeviceContext = 0; + glRenderContext_t glRenderContext = 0; +#endif + + bool bSync = false; + olc::DecalMode nDecalMode = olc::DecalMode(-1); // Thanks Gusgo & Bispoo + olc::DecalStructure nDecalStructure = olc::DecalStructure(-1); +#if defined(OLC_PLATFORM_X11) + X11::Display* olc_Display = nullptr; + X11::Window* olc_Window = nullptr; + X11::XVisualInfo* olc_VisualInfo = nullptr; +#endif + + public: + void PrepareDevice() override + { +#if defined(OLC_PLATFORM_GLUT) + //glutInit has to be called with main() arguments, make fake ones + int argc = 0; + char* argv[1] = { (char*)"" }; + glutInit(&argc, argv); + glutInitWindowPosition(0, 0); + glutInitWindowSize(512, 512); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); + // Creates the window and the OpenGL context for it + glutCreateWindow("OneLoneCoder.com - Pixel Game Engine"); + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +#endif + } + + olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) override + { +#if defined(OLC_PLATFORM_WINAPI) + // Create Device Context + glDeviceContext = GetDC((HWND)(params[0])); + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + PFD_MAIN_PLANE, 0, 0, 0, 0 + }; + + int pf = 0; + if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return olc::FAIL; + SetPixelFormat(glDeviceContext, pf, &pfd); + + if (!(glRenderContext = wglCreateContext(glDeviceContext))) return olc::FAIL; + wglMakeCurrent(glDeviceContext, glRenderContext); + + // Remove Frame cap + wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapInterval && !bVSYNC) wglSwapInterval(0); + bSync = bVSYNC; +#endif + +#if defined(OLC_PLATFORM_X11) + using namespace X11; + // Linux has tighter coupling between OpenGL and X11, so we store + // various "platform" handles in the renderer + olc_Display = (X11::Display*)(params[0]); + olc_Window = (X11::Window*)(params[1]); + olc_VisualInfo = (X11::XVisualInfo*)(params[2]); + + glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE); + glXMakeCurrent(olc_Display, *olc_Window, glDeviceContext); + + XWindowAttributes gwa; + XGetWindowAttributes(olc_Display, *olc_Window, &gwa); + glViewport(0, 0, gwa.width, gwa.height); + + glSwapIntervalEXT = nullptr; + glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"); + + if (glSwapIntervalEXT == nullptr && !bVSYNC) + { + printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n"); + printf(" Don't worry though, things will still work, it's just the\n"); + printf(" frame rate will be capped to your monitors refresh rate - javidx9\n"); + } + + if (glSwapIntervalEXT != nullptr && !bVSYNC) + glSwapIntervalEXT(olc_Display, *olc_Window, 0); +#endif + +#if defined(OLC_PLATFORM_GLUT) + mFullScreen = bFullScreen; + if (!bVSYNC) + { +#if defined(__APPLE__) + GLint sync = 0; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync); +#endif + } +#else + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +#endif + return olc::rcode::OK; + } + + olc::rcode DestroyDevice() override + { +#if defined(OLC_PLATFORM_WINAPI) + wglDeleteContext(glRenderContext); +#endif + +#if defined(OLC_PLATFORM_X11) + glXMakeCurrent(olc_Display, None, NULL); + glXDestroyContext(olc_Display, glDeviceContext); +#endif + +#if defined(OLC_PLATFORM_GLUT) + glutDestroyWindow(glutGetWindow()); +#endif + return olc::rcode::OK; + } + + void DisplayFrame() override + { +#if defined(OLC_PLATFORM_WINAPI) + SwapBuffers(glDeviceContext); + if (bSync) DwmFlush(); // Woooohooooooo!!!! SMOOOOOOOTH! +#endif + +#if defined(OLC_PLATFORM_X11) + X11::glXSwapBuffers(olc_Display, *olc_Window); +#endif + +#if defined(OLC_PLATFORM_GLUT) + glutSwapBuffers(); +#endif + } + + void PrepareDrawing() override + { + + //ClearBuffer(olc::GREEN, true); + glEnable(GL_BLEND); + nDecalMode = DecalMode::NORMAL; + nDecalStructure = DecalStructure::FAN; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + void SetDecalMode(const olc::DecalMode& mode) + { + if (mode != nDecalMode) + { + switch (mode) + { + case olc::DecalMode::NORMAL: + case olc::DecalMode::MODEL3D: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case olc::DecalMode::ADDITIVE: + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + case olc::DecalMode::MULTIPLICATIVE: + glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + break; + case olc::DecalMode::STENCIL: + glBlendFunc(GL_ZERO, GL_SRC_ALPHA); + break; + case olc::DecalMode::ILLUMINATE: + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + break; + case olc::DecalMode::WIREFRAME: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + } + + nDecalMode = mode; + } + } + + void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) override + { + glBegin(GL_QUADS); + glColor4ub(tint.r, tint.g, tint.b, tint.a); + glTexCoord2f(0.0f * scale.x + offset.x, 1.0f * scale.y + offset.y); + glVertex3f(-1.0f /*+ vSubPixelOffset.x*/, -1.0f /*+ vSubPixelOffset.y*/, 0.0f); + glTexCoord2f(0.0f * scale.x + offset.x, 0.0f * scale.y + offset.y); + glVertex3f(-1.0f /*+ vSubPixelOffset.x*/, 1.0f /*+ vSubPixelOffset.y*/, 0.0f); + glTexCoord2f(1.0f * scale.x + offset.x, 0.0f * scale.y + offset.y); + glVertex3f(1.0f /*+ vSubPixelOffset.x*/, 1.0f /*+ vSubPixelOffset.y*/, 0.0f); + glTexCoord2f(1.0f * scale.x + offset.x, 1.0f * scale.y + offset.y); + glVertex3f(1.0f /*+ vSubPixelOffset.x*/, -1.0f /*+ vSubPixelOffset.y*/, 0.0f); + glEnd(); + } + + void DrawDecal(const olc::DecalInstance& decal) override + { + SetDecalMode(decal.mode); + + if (decal.decal == nullptr) + glBindTexture(GL_TEXTURE_2D, 0); + else + glBindTexture(GL_TEXTURE_2D, decal.decal->id); + + if (nDecalMode == DecalMode::MODEL3D) + { +#ifdef OLC_ENABLE_EXPERIMENTAL + glMatrixMode(GL_PROJECTION); glPushMatrix(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); + + glEnable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0f, 1.0f, -1.0f, 1.0f, 1, 1000); + + #pragma comment (lib, "winmm.lib") + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, -40, -200); + glRotatef(float(clock()) * 0.1f, 1, 0, 0); + glRotatef(float(clock()) * 0.1f * 2, 0, 1, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glBegin(GL_TRIANGLES); + + + // Render as 3D Spatial Entity + for (uint32_t n = 0; n < decal.points; n++) + { + glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a); + glTexCoord2f(decal.uv[n].x, decal.uv[n].y); + glVertex3f(decal.pos[n].x, decal.pos[n].y, decal.w[n]); + } + + glEnd(); + + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); + glDisable(GL_DEPTH_TEST); +#endif + } + else + { + if (nDecalMode == DecalMode::WIREFRAME) + glBegin(GL_LINE_LOOP); + else + { + if(decal.structure == olc::DecalStructure::FAN) + glBegin(GL_TRIANGLE_FAN); + else if(decal.structure == olc::DecalStructure::STRIP) + glBegin(GL_TRIANGLE_STRIP); + else if(decal.structure == olc::DecalStructure::LIST) + glBegin(GL_TRIANGLES); + } + + // Render as 2D Spatial entity + for (uint32_t n = 0; n < decal.points; n++) + { + glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a); + glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]); + glVertex2f(decal.pos[n].x, decal.pos[n].y); + } + + glEnd(); + } + + + //glDisable(GL_DEPTH_TEST); + } + + uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override + { + UNUSED(width); + UNUSED(height); + uint32_t id = 0; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + if (filtered) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + if (clamp) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + return id; + } + + uint32_t DeleteTexture(const uint32_t id) override + { + glDeleteTextures(1, &id); + return id; + } + + void UpdateTexture(uint32_t id, olc::Sprite* spr) override + { + UNUSED(id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spr->width, spr->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); + } + + void ReadTexture(uint32_t id, olc::Sprite* spr) override + { + glReadPixels(0, 0, spr->width, spr->height, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); + } + + void ApplyTexture(uint32_t id) override + { + glBindTexture(GL_TEXTURE_2D, id); + } + + void ClearBuffer(olc::Pixel p, bool bDepth) override + { + glClearColor(float(p.r) / 255.0f, float(p.g) / 255.0f, float(p.b) / 255.0f, float(p.a) / 255.0f); + glClear(GL_COLOR_BUFFER_BIT); + if (bDepth) glClear(GL_DEPTH_BUFFER_BIT); + } + + void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) override + { + glViewport(pos.x, pos.y, size.x, size.y); + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END RENDERER: OpenGL 1.0 (the original, the best...) | +// O------------------------------------------------------------------------------O +#pragma endregion + +#pragma region renderer_ogl33 +// O------------------------------------------------------------------------------O +// | START RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) | +// O------------------------------------------------------------------------------O +#if defined(OLC_GFX_OPENGL33) + +#if defined(OLC_PLATFORM_WINAPI) + #include + #include + #if !defined(__MINGW32__) + #pragma comment(lib, "Dwmapi.lib") + #endif + typedef void __stdcall locSwapInterval_t(GLsizei n); + typedef HDC glDeviceContext_t; + typedef HGLRC glRenderContext_t; + #define CALLSTYLE __stdcall + #define OGL_LOAD(t, n) (t*)wglGetProcAddress(#n) +#endif + +#if defined(__linux__) || defined(__FreeBSD__) + #include +#endif + +#if defined(OLC_PLATFORM_X11) + namespace X11 + { + #include + } + typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); + typedef X11::GLXContext glDeviceContext_t; + typedef X11::GLXContext glRenderContext_t; + #define CALLSTYLE + #define OGL_LOAD(t, n) (t*)glXGetProcAddress((unsigned char*)#n); +#endif + +#if defined(__APPLE__) + #define GL_SILENCE_DEPRECATION + #include + #include + #include +#endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + #include + #include + #define GL_GLEXT_PROTOTYPES + #include + #include + #define CALLSTYLE + typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval); + #define GL_CLAMP GL_CLAMP_TO_EDGE + #define OGL_LOAD(t, n) n; +#endif + +namespace olc +{ + typedef char GLchar; + typedef ptrdiff_t GLsizeiptr; + typedef GLuint CALLSTYLE locCreateShader_t(GLenum type); + typedef GLuint CALLSTYLE locCreateProgram_t(void); + typedef void CALLSTYLE locDeleteShader_t(GLuint shader); +#if defined(OLC_PLATFORM_EMSCRIPTEN) + typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); +#else + typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +#endif + typedef void CALLSTYLE locCompileShader_t(GLuint shader); + typedef void CALLSTYLE locLinkProgram_t(GLuint program); + typedef void CALLSTYLE locDeleteProgram_t(GLuint program); + typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader); + typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer); + typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers); + typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); + typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index); + typedef void CALLSTYLE locUseProgram_t(GLuint program); + typedef void CALLSTYLE locBindVertexArray_t(GLuint array); + typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays); + typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); + + constexpr size_t OLC_MAX_VERTS = 128; + + class Renderer_OGL33 : public olc::Renderer + { + private: +#if defined(OLC_PLATFORM_EMSCRIPTEN) + EGLDisplay olc_Display; + EGLConfig olc_Config; + EGLContext olc_Context; + EGLSurface olc_Surface; +#endif + +#if defined(OLC_PLATFORM_GLUT) + bool mFullScreen = false; +#else + #if !defined(OLC_PLATFORM_EMSCRIPTEN) + glDeviceContext_t glDeviceContext = 0; + glRenderContext_t glRenderContext = 0; + #endif +#endif + bool bSync = false; + olc::DecalMode nDecalMode = olc::DecalMode(-1); // Thanks Gusgo & Bispoo +#if defined(OLC_PLATFORM_X11) + X11::Display* olc_Display = nullptr; + X11::Window* olc_Window = nullptr; + X11::XVisualInfo* olc_VisualInfo = nullptr; +#endif + + private: + locCreateShader_t* locCreateShader = nullptr; + locShaderSource_t* locShaderSource = nullptr; + locCompileShader_t* locCompileShader = nullptr; + locDeleteShader_t* locDeleteShader = nullptr; + locCreateProgram_t* locCreateProgram = nullptr; + locDeleteProgram_t* locDeleteProgram = nullptr; + locLinkProgram_t* locLinkProgram = nullptr; + locAttachShader_t* locAttachShader = nullptr; + locBindBuffer_t* locBindBuffer = nullptr; + locBufferData_t* locBufferData = nullptr; + locGenBuffers_t* locGenBuffers = nullptr; + locVertexAttribPointer_t* locVertexAttribPointer = nullptr; + locEnableVertexAttribArray_t* locEnableVertexAttribArray = nullptr; + locUseProgram_t* locUseProgram = nullptr; + locBindVertexArray_t* locBindVertexArray = nullptr; + locGenVertexArrays_t* locGenVertexArrays = nullptr; + locSwapInterval_t* locSwapInterval = nullptr; + locGetShaderInfoLog_t* locGetShaderInfoLog = nullptr; + + uint32_t m_nFS = 0; + uint32_t m_nVS = 0; + uint32_t m_nQuadShader = 0; + uint32_t m_vbQuad = 0; + uint32_t m_vaQuad = 0; + + struct locVertex + { + float pos[3]; + olc::vf2d tex; + olc::Pixel col; + }; + + locVertex pVertexMem[OLC_MAX_VERTS]; + + olc::Renderable rendBlankQuad; + + public: + void PrepareDevice() override + { +#if defined(OLC_PLATFORM_GLUT) + //glutInit has to be called with main() arguments, make fake ones + int argc = 0; + char* argv[1] = { (char*)"" }; + glutInit(&argc, argv); + glutInitWindowPosition(0, 0); + glutInitWindowSize(512, 512); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); + // Creates the window and the OpenGL context for it + glutCreateWindow("OneLoneCoder.com - Pixel Game Engine"); + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +#endif + } + + olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) override + { + // Create OpenGL Context +#if defined(OLC_PLATFORM_WINAPI) + // Create Device Context + glDeviceContext = GetDC((HWND)(params[0])); + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + PFD_MAIN_PLANE, 0, 0, 0, 0 + }; + + int pf = 0; + if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return olc::FAIL; + SetPixelFormat(glDeviceContext, pf, &pfd); + + if (!(glRenderContext = wglCreateContext(glDeviceContext))) return olc::FAIL; + wglMakeCurrent(glDeviceContext, glRenderContext); + + // Set Vertical Sync + locSwapInterval = OGL_LOAD(locSwapInterval_t, "wglSwapIntervalEXT"); + if (locSwapInterval && !bVSYNC) locSwapInterval(0); + bSync = bVSYNC; +#endif + +#if defined(OLC_PLATFORM_X11) + using namespace X11; + // Linux has tighter coupling between OpenGL and X11, so we store + // various "platform" handles in the renderer + olc_Display = (X11::Display*)(params[0]); + olc_Window = (X11::Window*)(params[1]); + olc_VisualInfo = (X11::XVisualInfo*)(params[2]); + + glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE); + glXMakeCurrent(olc_Display, *olc_Window, glDeviceContext); + + XWindowAttributes gwa; + XGetWindowAttributes(olc_Display, *olc_Window, &gwa); + glViewport(0, 0, gwa.width, gwa.height); + + locSwapInterval = OGL_LOAD(locSwapInterval_t, "glXSwapIntervalEXT"); + + if (locSwapInterval == nullptr && !bVSYNC) + { + printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n"); + printf(" Don't worry though, things will still work, it's just the\n"); + printf(" frame rate will be capped to your monitors refresh rate - javidx9\n"); + } + + if (locSwapInterval != nullptr && !bVSYNC) + locSwapInterval(olc_Display, *olc_Window, 0); +#endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + EGLint const attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; + EGLint const context_config[] = { EGL_CONTEXT_CLIENT_VERSION , 2, EGL_NONE }; + EGLint num_config; + + olc_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(olc_Display, nullptr, nullptr); + eglChooseConfig(olc_Display, attribute_list, &olc_Config, 1, &num_config); + + /* create an EGL rendering context */ + olc_Context = eglCreateContext(olc_Display, olc_Config, EGL_NO_CONTEXT, context_config); + olc_Surface = eglCreateWindowSurface(olc_Display, olc_Config, NULL, nullptr); + eglMakeCurrent(olc_Display, olc_Surface, olc_Surface, olc_Context); + //eglSwapInterval is currently a NOP, plement anyways in case it becomes supported + locSwapInterval = &eglSwapInterval; + locSwapInterval(olc_Display, bVSYNC ? 1 : 0); +#endif + +#if defined(OLC_PLATFORM_GLUT) + mFullScreen = bFullScreen; + if (!bVSYNC) + { +#if defined(__APPLE__) + GLint sync = 0; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync); +#endif + } +#else + #if !defined(OLC_PLATFORM_EMSCRIPTEN) + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + #endif +#endif + // Load External OpenGL Functions + locCreateShader = OGL_LOAD(locCreateShader_t, glCreateShader); + locCompileShader = OGL_LOAD(locCompileShader_t, glCompileShader); + locShaderSource = OGL_LOAD(locShaderSource_t, glShaderSource); + locDeleteShader = OGL_LOAD(locDeleteShader_t, glDeleteShader); + locCreateProgram = OGL_LOAD(locCreateProgram_t, glCreateProgram); + locDeleteProgram = OGL_LOAD(locDeleteProgram_t, glDeleteProgram); + locLinkProgram = OGL_LOAD(locLinkProgram_t, glLinkProgram); + locAttachShader = OGL_LOAD(locAttachShader_t, glAttachShader); + locBindBuffer = OGL_LOAD(locBindBuffer_t, glBindBuffer); + locBufferData = OGL_LOAD(locBufferData_t, glBufferData); + locGenBuffers = OGL_LOAD(locGenBuffers_t, glGenBuffers); + locVertexAttribPointer = OGL_LOAD(locVertexAttribPointer_t, glVertexAttribPointer); + locEnableVertexAttribArray = OGL_LOAD(locEnableVertexAttribArray_t, glEnableVertexAttribArray); + locUseProgram = OGL_LOAD(locUseProgram_t, glUseProgram); + locGetShaderInfoLog = OGL_LOAD(locGetShaderInfoLog_t, glGetShaderInfoLog); +#if !defined(OLC_PLATFORM_EMSCRIPTEN) + locBindVertexArray = OGL_LOAD(locBindVertexArray_t, glBindVertexArray); + locGenVertexArrays = OGL_LOAD(locGenVertexArrays_t, glGenVertexArrays); +#else + locBindVertexArray = glBindVertexArrayOES; + locGenVertexArrays = glGenVertexArraysOES; +#endif + + // Load & Compile Quad Shader - assumes no errors + m_nFS = locCreateShader(0x8B30); + const GLchar* strFS = +#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN) + "#version 300 es\n" + "precision mediump float;" +#else + "#version 330 core\n" +#endif + "out vec4 pixel;\n""in vec2 oTex;\n" + "in vec4 oCol;\n""uniform sampler2D sprTex;\n""void main(){pixel = texture(sprTex, oTex) * oCol;}"; + locShaderSource(m_nFS, 1, &strFS, NULL); + locCompileShader(m_nFS); + + m_nVS = locCreateShader(0x8B31); + const GLchar* strVS = +#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN) + "#version 300 es\n" + "precision mediump float;" +#else + "#version 330 core\n" +#endif + "layout(location = 0) in vec3 aPos;\n""layout(location = 1) in vec2 aTex;\n" + "layout(location = 2) in vec4 aCol;\n""out vec2 oTex;\n""out vec4 oCol;\n" + "void main(){ float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex; oCol = aCol;}"; + locShaderSource(m_nVS, 1, &strVS, NULL); + locCompileShader(m_nVS); + + m_nQuadShader = locCreateProgram(); + locAttachShader(m_nQuadShader, m_nFS); + locAttachShader(m_nQuadShader, m_nVS); + locLinkProgram(m_nQuadShader); + + // Create Quad + locGenBuffers(1, &m_vbQuad); + locGenVertexArrays(1, &m_vaQuad); + locBindVertexArray(m_vaQuad); + locBindBuffer(0x8892, m_vbQuad); + + locVertex verts[OLC_MAX_VERTS]; + locBufferData(0x8892, sizeof(locVertex) * OLC_MAX_VERTS, verts, 0x88E0); + locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(locVertex), 0); locEnableVertexAttribArray(0); + locVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(locVertex), (void*)(3 * sizeof(float))); locEnableVertexAttribArray(1); + locVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(locVertex), (void*)(5 * sizeof(float))); locEnableVertexAttribArray(2); + locBindBuffer(0x8892, 0); + locBindVertexArray(0); + + // Create blank texture for spriteless decals + rendBlankQuad.Create(1, 1); + rendBlankQuad.Sprite()->GetData()[0] = olc::WHITE; + rendBlankQuad.Decal()->Update(); + return olc::rcode::OK; + } + + olc::rcode DestroyDevice() override + { +#if defined(OLC_PLATFORM_WINAPI) + wglDeleteContext(glRenderContext); +#endif + +#if defined(OLC_PLATFORM_X11) + glXMakeCurrent(olc_Display, None, NULL); + glXDestroyContext(olc_Display, glDeviceContext); +#endif + +#if defined(OLC_PLATFORM_GLUT) + glutDestroyWindow(glutGetWindow()); +#endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + eglMakeCurrent(olc_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(olc_Display, olc_Context); + eglDestroySurface(olc_Display, olc_Surface); + eglTerminate(olc_Display); + olc_Display = EGL_NO_DISPLAY; + olc_Surface = EGL_NO_SURFACE; + olc_Context = EGL_NO_CONTEXT; +#endif + return olc::rcode::OK; + } + + void DisplayFrame() override + { +#if defined(OLC_PLATFORM_WINAPI) + SwapBuffers(glDeviceContext); + if (bSync) DwmFlush(); // Woooohooooooo!!!! SMOOOOOOOTH! +#endif + +#if defined(OLC_PLATFORM_X11) + X11::glXSwapBuffers(olc_Display, *olc_Window); +#endif + +#if defined(OLC_PLATFORM_GLUT) + glutSwapBuffers(); +#endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + eglSwapBuffers(olc_Display, olc_Surface); +#endif + } + + void PrepareDrawing() override + { + glEnable(GL_BLEND); + nDecalMode = DecalMode::NORMAL; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + locUseProgram(m_nQuadShader); + locBindVertexArray(m_vaQuad); + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(locVertex), 0); locEnableVertexAttribArray(0); + locVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(locVertex), (void*)(3 * sizeof(float))); locEnableVertexAttribArray(1); + locVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(locVertex), (void*)(5 * sizeof(float))); locEnableVertexAttribArray(2); +#endif + } + + void SetDecalMode(const olc::DecalMode& mode) override + { + if (mode != nDecalMode) + { + switch (mode) + { + case olc::DecalMode::NORMAL: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; + case olc::DecalMode::ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; + case olc::DecalMode::MULTIPLICATIVE: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; + case olc::DecalMode::STENCIL: glBlendFunc(GL_ZERO, GL_SRC_ALPHA); break; + case olc::DecalMode::ILLUMINATE: glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); break; + case olc::DecalMode::WIREFRAME: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; + } + + nDecalMode = mode; + } + } + + void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) override + { + locBindBuffer(0x8892, m_vbQuad); + locVertex verts[4] = { + {{-1.0f, -1.0f, 1.0}, {0.0f * scale.x + offset.x, 1.0f * scale.y + offset.y}, tint}, + {{+1.0f, -1.0f, 1.0}, {1.0f * scale.x + offset.x, 1.0f * scale.y + offset.y}, tint}, + {{-1.0f, +1.0f, 1.0}, {0.0f * scale.x + offset.x, 0.0f * scale.y + offset.y}, tint}, + {{+1.0f, +1.0f, 1.0}, {1.0f * scale.x + offset.x, 0.0f * scale.y + offset.y}, tint}, + }; + + locBufferData(0x8892, sizeof(locVertex) * 4, verts, 0x88E0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + + void DrawDecal(const olc::DecalInstance& decal) override + { + SetDecalMode(decal.mode); + if (decal.decal == nullptr) + glBindTexture(GL_TEXTURE_2D, rendBlankQuad.Decal()->id); + else + glBindTexture(GL_TEXTURE_2D, decal.decal->id); + + locBindBuffer(0x8892, m_vbQuad); + + for (uint32_t i = 0; i < decal.points; i++) + pVertexMem[i] = { { decal.pos[i].x, decal.pos[i].y, decal.w[i] }, { decal.uv[i].x, decal.uv[i].y }, decal.tint[i] }; + + locBufferData(0x8892, sizeof(locVertex) * decal.points, pVertexMem, 0x88E0); + + if (nDecalMode == DecalMode::WIREFRAME) + glDrawArrays(GL_LINE_LOOP, 0, decal.points); + else + glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points); + } + + uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override + { + UNUSED(width); + UNUSED(height); + uint32_t id = 0; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + + if (filtered) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + if (clamp) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } +#if !defined(OLC_PLATFORM_EMSCRIPTEN) + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#endif + return id; + } + + uint32_t DeleteTexture(const uint32_t id) override + { + glDeleteTextures(1, &id); + return id; + } + + void UpdateTexture(uint32_t id, olc::Sprite* spr) override + { + UNUSED(id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spr->width, spr->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); + } + + void ReadTexture(uint32_t id, olc::Sprite* spr) override + { + glReadPixels(0, 0, spr->width, spr->height, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData()); + } + + void ApplyTexture(uint32_t id) override + { + glBindTexture(GL_TEXTURE_2D, id); + } + + void ClearBuffer(olc::Pixel p, bool bDepth) override + { + glClearColor(float(p.r) / 255.0f, float(p.g) / 255.0f, float(p.b) / 255.0f, float(p.a) / 255.0f); + glClear(GL_COLOR_BUFFER_BIT); + if (bDepth) glClear(GL_DEPTH_BUFFER_BIT); + } + + void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) override + { + glViewport(pos.x, pos.y, size.x, size.y); + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) | +// O------------------------------------------------------------------------------O +#pragma endregion + +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Image loaders | +// O------------------------------------------------------------------------------O + +#pragma region image_gdi +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: GDI+, Windows Only, always exists, a little slow | +// O------------------------------------------------------------------------------O +#if defined(OLC_IMAGE_GDI) + +#define min(a, b) ((a < b) ? a : b) +#define max(a, b) ((a > b) ? a : b) +#include +#include +#if defined(__MINGW32__) // Thanks Gusgo & Dandistine, but c'mon mingw!! wtf?! + #include +#else + #include +#endif +#include +#undef min +#undef max + +#if !defined(__MINGW32__) + #pragma comment(lib, "gdiplus.lib") + #pragma comment(lib, "Shlwapi.lib") +#endif + +namespace olc +{ + // Thanks @MaGetzUb for this, which allows sprites to be defined + // at construction, by initialising the GDI subsystem + static class GDIPlusStartup + { + public: + GDIPlusStartup() + { + Gdiplus::GdiplusStartupInput startupInput; + GdiplusStartup(&token, &startupInput, NULL); + } + + ULONG_PTR token; + + ~GDIPlusStartup() + { + // Well, MarcusTU thought this was important :D + Gdiplus::GdiplusShutdown(token); + } + } gdistartup; + + class ImageLoader_GDIPlus : public olc::ImageLoader + { + private: + std::wstring ConvertS2W(std::string s) + { +#ifdef __MINGW32__ + wchar_t* buffer = new wchar_t[s.length() + 1]; + mbstowcs(buffer, s.c_str(), s.length()); + buffer[s.length()] = L'\0'; +#else + int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + wchar_t* buffer = new wchar_t[count]; + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); +#endif + std::wstring w(buffer); + delete[] buffer; + return w; + } + + public: + ImageLoader_GDIPlus() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + // clear out existing sprite + spr->pColData.clear(); + + // Open file + UNUSED(pack); + Gdiplus::Bitmap* bmp = nullptr; + if (pack != nullptr) + { + // Load sprite from input stream + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + bmp = Gdiplus::Bitmap::FromStream(SHCreateMemStream((BYTE*)rb.vMemory.data(), UINT(rb.vMemory.size()))); + } + else + { + // Check file exists + if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; + + // Load sprite from file + bmp = Gdiplus::Bitmap::FromFile(ConvertS2W(sImageFile).c_str()); + } + + if (bmp->GetLastStatus() != Gdiplus::Ok) return olc::rcode::FAIL; + spr->width = bmp->GetWidth(); + spr->height = bmp->GetHeight(); + + spr->pColData.resize(spr->width * spr->height); + + for (int y = 0; y < spr->height; y++) + for (int x = 0; x < spr->width; x++) + { + Gdiplus::Color c; + bmp->GetPixel(x, y, &c); + spr->SetPixel(x, y, olc::Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha())); + } + delete bmp; + return olc::rcode::OK; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END IMAGE LOADER: GDI+ | +// O------------------------------------------------------------------------------O +#pragma endregion + +#pragma region image_libpng +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: libpng, default on linux, requires -lpng (libpng-dev) | +// O------------------------------------------------------------------------------O +#if defined(OLC_IMAGE_LIBPNG) +#include +namespace olc +{ + void pngReadStream(png_structp pngPtr, png_bytep data, png_size_t length) + { + png_voidp a = png_get_io_ptr(pngPtr); + ((std::istream*)a)->read((char*)data, length); + } + + class ImageLoader_LibPNG : public olc::ImageLoader + { + public: + ImageLoader_LibPNG() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + UNUSED(pack); + + // clear out existing sprite + spr->pColData.clear(); + + //////////////////////////////////////////////////////////////////////////// + // Use libpng, Thanks to Guillaume Cottenceau + // https://gist.github.com/niw/5963798 + // Also reading png from streams + // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/ + png_structp png; + png_infop info; + + auto loadPNG = [&]() + { + png_read_info(png, info); + png_byte color_type; + png_byte bit_depth; + png_bytep* row_pointers; + spr->width = png_get_image_width(png, info); + spr->height = png_get_image_height(png, info); + color_type = png_get_color_type(png, info); + bit_depth = png_get_bit_depth(png, info); + if (bit_depth == 16) png_set_strip_16(png); + if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); + if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); + if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) + png_set_filler(png, 0xFF, PNG_FILLER_AFTER); + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + png_read_update_info(png, info); + row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * spr->height); + for (int y = 0; y < spr->height; y++) { + row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); + } + png_read_image(png, row_pointers); + //////////////////////////////////////////////////////////////////////////// + // Create sprite array + spr->pColData.resize(spr->width * spr->height); + // Iterate through image rows, converting into sprite format + for (int y = 0; y < spr->height; y++) + { + png_bytep row = row_pointers[y]; + for (int x = 0; x < spr->width; x++) + { + png_bytep px = &(row[x * 4]); + spr->SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3])); + } + } + + for (int y = 0; y < spr->height; y++) // Thanks maksym33 + free(row_pointers[y]); + free(row_pointers); + png_destroy_read_struct(&png, &info, nullptr); + }; + + png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png) goto fail_load; + + info = png_create_info_struct(png); + if (!info) goto fail_load; + + if (setjmp(png_jmpbuf(png))) goto fail_load; + + if (pack == nullptr) + { + FILE* f = fopen(sImageFile.c_str(), "rb"); + if (!f) return olc::rcode::NO_FILE; + png_init_io(png, f); + loadPNG(); + fclose(f); + } + else + { + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + std::istream is(&rb); + png_set_read_fn(png, (png_voidp)&is, pngReadStream); + loadPNG(); + } + + return olc::rcode::OK; + + fail_load: + spr->width = 0; + spr->height = 0; + spr->pColData.clear(); + return olc::rcode::FAIL; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END IMAGE LOADER: | +// O------------------------------------------------------------------------------O +#pragma endregion + +#pragma region image_stb +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: stb_image.h, all systems, very fast | +// O------------------------------------------------------------------------------O +// Thanks to Sean Barrett - https://github.com/nothings/stb/blob/master/stb_image.h +// MIT License - Copyright(c) 2017 Sean Barrett + +// Note you need to download the above file into your project folder, and +// #define OLC_IMAGE_STB +// #define OLC_PGE_APPLICATION +// #include "olcPixelGameEngine.h" + +#if defined(OLC_IMAGE_STB) +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +namespace olc +{ + class ImageLoader_STB : public olc::ImageLoader + { + public: + ImageLoader_STB() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + UNUSED(pack); + // clear out existing sprite + spr->pColData.clear(); + // Open file + stbi_uc* bytes = nullptr; + int w = 0, h = 0, cmp = 0; + if (pack != nullptr) + { + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + bytes = stbi_load_from_memory((unsigned char*)rb.vMemory.data(), rb.vMemory.size(), &w, &h, &cmp, 4); + } + else + { + // Check file exists + if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; + bytes = stbi_load(sImageFile.c_str(), &w, &h, &cmp, 4); + } + + if (!bytes) return olc::rcode::FAIL; + spr->width = w; spr->height = h; + spr->pColData.resize(spr->width * spr->height); + std::memcpy(spr->pColData.data(), bytes, spr->width * spr->height * 4); + delete[] bytes; + return olc::rcode::OK; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: stb_image.h | +// O------------------------------------------------------------------------------O +#pragma endregion + +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Platforms | +// O------------------------------------------------------------------------------O + +#pragma region platform_windows +// O------------------------------------------------------------------------------O +// | START PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 | +// O------------------------------------------------------------------------------O +#if defined(OLC_PLATFORM_WINAPI) + +#if defined(_WIN32) && !defined(__MINGW32__) + #pragma comment(lib, "user32.lib") // Visual Studio Only + #pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add + #pragma comment(lib, "opengl32.lib") // these libs to your linker input +#endif + +namespace olc +{ + class Platform_Windows : public olc::Platform + { + private: + HWND olc_hWnd = nullptr; + std::wstring wsAppName; + + std::wstring ConvertS2W(std::string s) + { +#ifdef __MINGW32__ + wchar_t* buffer = new wchar_t[s.length() + 1]; + mbstowcs(buffer, s.c_str(), s.length()); + buffer[s.length()] = L'\0'; +#else + int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + wchar_t* buffer = new wchar_t[count]; + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); +#endif + std::wstring w(buffer); + delete[] buffer; + return w; + } + + public: + virtual olc::rcode ApplicationStartUp() override { return olc::rcode::OK; } + virtual olc::rcode ApplicationCleanUp() override { return olc::rcode::OK; } + virtual olc::rcode ThreadStartUp() override { return olc::rcode::OK; } + + virtual olc::rcode ThreadCleanUp() override + { + renderer->DestroyDevice(); + PostMessage(olc_hWnd, WM_DESTROY, 0, 0); + return olc::OK; + } + + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override + { + if (renderer->CreateDevice({ olc_hWnd }, bFullScreen, bEnableVSYNC) == olc::rcode::OK) + { + renderer->UpdateViewport(vViewPos, vViewSize); + return olc::rcode::OK; + } + else + return olc::rcode::FAIL; + } + + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override + { + WNDCLASS wc; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.hInstance = GetModuleHandle(nullptr); + wc.lpfnWndProc = olc_WindowEvent; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.lpszMenuName = nullptr; + wc.hbrBackground = nullptr; + wc.lpszClassName = olcT("OLC_PIXEL_GAME_ENGINE"); + RegisterClass(&wc); + + // Define window furniture + DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_THICKFRAME; + + olc::vi2d vTopLeft = vWindowPos; + + // Handle Fullscreen + if (bFullScreen) + { + dwExStyle = 0; + dwStyle = WS_VISIBLE | WS_POPUP; + HMONITOR hmon = MonitorFromWindow(olc_hWnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO mi = { sizeof(mi) }; + if (!GetMonitorInfo(hmon, &mi)) return olc::rcode::FAIL; + vWindowSize = { mi.rcMonitor.right, mi.rcMonitor.bottom }; + vTopLeft.x = 0; + vTopLeft.y = 0; + } + + // Keep client size as requested + RECT rWndRect = { 0, 0, vWindowSize.x, vWindowSize.y }; + AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); + int width = rWndRect.right - rWndRect.left; + int height = rWndRect.bottom - rWndRect.top; + + olc_hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE"), olcT(""), dwStyle, + vTopLeft.x, vTopLeft.y, width, height, NULL, NULL, GetModuleHandle(nullptr), this); + + // Create Keyboard Mapping + mapKeys[0x00] = Key::NONE; + mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E; + mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J; + mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O; + mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T; + mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y; + mapKeys[0x5A] = Key::Z; + + mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4; + mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8; + mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12; + + mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP; + //mapKeys[VK_RETURN] = Key::ENTER;// mapKeys[VK_RETURN] = Key::RETURN; + + mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE; + mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME; + mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS; + mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL; + mapKeys[VK_SPACE] = Key::SPACE; + + mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4; + mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9; + + mapKeys[VK_NUMPAD0] = Key::NP0; mapKeys[VK_NUMPAD1] = Key::NP1; mapKeys[VK_NUMPAD2] = Key::NP2; mapKeys[VK_NUMPAD3] = Key::NP3; mapKeys[VK_NUMPAD4] = Key::NP4; + mapKeys[VK_NUMPAD5] = Key::NP5; mapKeys[VK_NUMPAD6] = Key::NP6; mapKeys[VK_NUMPAD7] = Key::NP7; mapKeys[VK_NUMPAD8] = Key::NP8; mapKeys[VK_NUMPAD9] = Key::NP9; + mapKeys[VK_MULTIPLY] = Key::NP_MUL; mapKeys[VK_ADD] = Key::NP_ADD; mapKeys[VK_DIVIDE] = Key::NP_DIV; mapKeys[VK_SUBTRACT] = Key::NP_SUB; mapKeys[VK_DECIMAL] = Key::NP_DECIMAL; + + // Thanks scripticuk + mapKeys[VK_OEM_1] = Key::OEM_1; // On US and UK keyboards this is the ';:' key + mapKeys[VK_OEM_2] = Key::OEM_2; // On US and UK keyboards this is the '/?' key + mapKeys[VK_OEM_3] = Key::OEM_3; // On US keyboard this is the '~' key + mapKeys[VK_OEM_4] = Key::OEM_4; // On US and UK keyboards this is the '[{' key + mapKeys[VK_OEM_5] = Key::OEM_5; // On US keyboard this is '\|' key. + mapKeys[VK_OEM_6] = Key::OEM_6; // On US and UK keyboards this is the ']}' key + mapKeys[VK_OEM_7] = Key::OEM_7; // On US keyboard this is the single/double quote key. On UK, this is the single quote/@ symbol key + mapKeys[VK_OEM_8] = Key::OEM_8; // miscellaneous characters. Varies by keyboard + mapKeys[VK_OEM_PLUS] = Key::EQUALS; // the '+' key on any keyboard + mapKeys[VK_OEM_COMMA] = Key::COMMA; // the comma key on any keyboard + mapKeys[VK_OEM_MINUS] = Key::MINUS; // the minus key on any keyboard + mapKeys[VK_OEM_PERIOD] = Key::PERIOD; // the period key on any keyboard + mapKeys[VK_CAPITAL] = Key::CAPS_LOCK; + return olc::OK; + } + + virtual olc::rcode SetWindowTitle(const std::string& s) override + { +#ifdef UNICODE + SetWindowText(olc_hWnd, ConvertS2W(s).c_str()); +#else + SetWindowText(olc_hWnd, s.c_str()); +#endif + return olc::OK; + } + + virtual olc::rcode StartSystemEventLoop() override + { + MSG msg; + while (GetMessage(&msg, NULL, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return olc::OK; + } + + virtual olc::rcode HandleSystemEvent() override { return olc::rcode::FAIL; } + + // Windows Event Handler - this is statically connected to the windows event system + static LRESULT CALLBACK olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + switch (uMsg) + { + case WM_MOUSEMOVE: + { + // Thanks @ForAbby (Discord) + uint16_t x = lParam & 0xFFFF; uint16_t y = (lParam >> 16) & 0xFFFF; + int16_t ix = *(int16_t*)&x; int16_t iy = *(int16_t*)&y; + ptrPGE->olc_UpdateMouse(ix, iy); + return 0; + } + case WM_SIZE: ptrPGE->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0; + case WM_MOUSEWHEEL: ptrPGE->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); return 0; + case WM_MOUSELEAVE: ptrPGE->olc_UpdateMouseFocus(false); return 0; + case WM_SETFOCUS: ptrPGE->olc_UpdateKeyFocus(true); return 0; + case WM_KILLFOCUS: ptrPGE->olc_UpdateKeyFocus(false); return 0; + case WM_KEYDOWN: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], true); return 0; + case WM_KEYUP: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], false); return 0; + case WM_SYSKEYDOWN: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], true); return 0; + case WM_SYSKEYUP: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], false); return 0; + case WM_LBUTTONDOWN:ptrPGE->olc_UpdateMouseState(0, true); return 0; + case WM_LBUTTONUP: ptrPGE->olc_UpdateMouseState(0, false); return 0; + case WM_RBUTTONDOWN:ptrPGE->olc_UpdateMouseState(1, true); return 0; + case WM_RBUTTONUP: ptrPGE->olc_UpdateMouseState(1, false); return 0; + case WM_MBUTTONDOWN:ptrPGE->olc_UpdateMouseState(2, true); return 0; + case WM_MBUTTONUP: ptrPGE->olc_UpdateMouseState(2, false); return 0; + case WM_CLOSE: ptrPGE->olc_Terminate(); return 0; + case WM_DESTROY: PostQuitMessage(0); DestroyWindow(hWnd); return 0; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 | +// O------------------------------------------------------------------------------O +#pragma endregion + +#pragma region platform_linux +// O------------------------------------------------------------------------------O +// | START PLATFORM: LINUX | +// O------------------------------------------------------------------------------O +#if defined(OLC_PLATFORM_X11) +namespace olc +{ + class Platform_Linux : public olc::Platform + { + private: + X11::Display* olc_Display = nullptr; + X11::Window olc_WindowRoot; + X11::Window olc_Window; + X11::XVisualInfo* olc_VisualInfo; + X11::Colormap olc_ColourMap; + X11::XSetWindowAttributes olc_SetWindowAttribs; + + public: + virtual olc::rcode ApplicationStartUp() override + { + return olc::rcode::OK; + } + + virtual olc::rcode ApplicationCleanUp() override + { + XDestroyWindow(olc_Display, olc_Window); + return olc::rcode::OK; + } + + virtual olc::rcode ThreadStartUp() override + { + return olc::rcode::OK; + } + + virtual olc::rcode ThreadCleanUp() override + { + renderer->DestroyDevice(); + return olc::OK; + } + + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override + { + if (renderer->CreateDevice({ olc_Display, &olc_Window, olc_VisualInfo }, bFullScreen, bEnableVSYNC) == olc::rcode::OK) + { + renderer->UpdateViewport(vViewPos, vViewSize); + return olc::rcode::OK; + } + else + return olc::rcode::FAIL; + } + + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override + { + using namespace X11; + XInitThreads(); + + // Grab the deafult display and window + olc_Display = XOpenDisplay(NULL); + olc_WindowRoot = DefaultRootWindow(olc_Display); + + // Based on the display capabilities, configure the appearance of the window + GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; + olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs); + olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone); + olc_SetWindowAttribs.colormap = olc_ColourMap; + + // Register which events we are interested in receiving + olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask; + + // Create the window + olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, vWindowPos.x, vWindowPos.y, + vWindowSize.x, vWindowSize.y, + 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, + CWColormap | CWEventMask, &olc_SetWindowAttribs); + + Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true); + XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1); + + XMapWindow(olc_Display, olc_Window); + XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine"); + + if (bFullScreen) // Thanks DragonEye, again :D + { + Atom wm_state; + Atom fullscreen; + wm_state = XInternAtom(olc_Display, "_NET_WM_STATE", False); + fullscreen = XInternAtom(olc_Display, "_NET_WM_STATE_FULLSCREEN", False); + XEvent xev{ 0 }; + xev.type = ClientMessage; + xev.xclient.window = olc_Window; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = (bFullScreen ? 1 : 0); // the action (0: off, 1: on, 2: toggle) + xev.xclient.data.l[1] = fullscreen; // first property to alter + xev.xclient.data.l[2] = 0; // second property to alter + xev.xclient.data.l[3] = 0; // source indication + XMapWindow(olc_Display, olc_Window); + XSendEvent(olc_Display, DefaultRootWindow(olc_Display), False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XFlush(olc_Display); + XWindowAttributes gwa; + XGetWindowAttributes(olc_Display, olc_Window, &gwa); + vWindowSize.x = gwa.width; + vWindowSize.y = gwa.height; + } + + // Create Keyboard Mapping + mapKeys[0x00] = Key::NONE; + mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E; + mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J; + mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O; + mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T; + mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y; + mapKeys[0x7A] = Key::Z; + + mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4; + mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8; + mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12; + + mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP; + mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER; + + mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE; + mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME; + mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS; + mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL; + mapKeys[XK_space] = Key::SPACE; mapKeys[XK_period] = Key::PERIOD; + + mapKeys[XK_0] = Key::K0; mapKeys[XK_1] = Key::K1; mapKeys[XK_2] = Key::K2; mapKeys[XK_3] = Key::K3; mapKeys[XK_4] = Key::K4; + mapKeys[XK_5] = Key::K5; mapKeys[XK_6] = Key::K6; mapKeys[XK_7] = Key::K7; mapKeys[XK_8] = Key::K8; mapKeys[XK_9] = Key::K9; + + mapKeys[XK_KP_0] = Key::NP0; mapKeys[XK_KP_1] = Key::NP1; mapKeys[XK_KP_2] = Key::NP2; mapKeys[XK_KP_3] = Key::NP3; mapKeys[XK_KP_4] = Key::NP4; + mapKeys[XK_KP_5] = Key::NP5; mapKeys[XK_KP_6] = Key::NP6; mapKeys[XK_KP_7] = Key::NP7; mapKeys[XK_KP_8] = Key::NP8; mapKeys[XK_KP_9] = Key::NP9; + mapKeys[XK_KP_Multiply] = Key::NP_MUL; mapKeys[XK_KP_Add] = Key::NP_ADD; mapKeys[XK_KP_Divide] = Key::NP_DIV; mapKeys[XK_KP_Subtract] = Key::NP_SUB; mapKeys[XK_KP_Decimal] = Key::NP_DECIMAL; + + // These keys vary depending on the keyboard. I've included comments for US and UK keyboard layouts + mapKeys[XK_semicolon] = Key::OEM_1; // On US and UK keyboards this is the ';:' key + mapKeys[XK_slash] = Key::OEM_2; // On US and UK keyboards this is the '/?' key + mapKeys[XK_asciitilde] = Key::OEM_3; // On US keyboard this is the '~' key + mapKeys[XK_bracketleft] = Key::OEM_4; // On US and UK keyboards this is the '[{' key + mapKeys[XK_backslash] = Key::OEM_5; // On US keyboard this is '\|' key. + mapKeys[XK_bracketright] = Key::OEM_6; // On US and UK keyboards this is the ']}' key + mapKeys[XK_apostrophe] = Key::OEM_7; // On US keyboard this is the single/double quote key. On UK, this is the single quote/@ symbol key + mapKeys[XK_numbersign] = Key::OEM_8; // miscellaneous characters. Varies by keyboard. I believe this to be the '#~' key on UK keyboards + mapKeys[XK_equal] = Key::EQUALS; // the '+' key on any keyboard + mapKeys[XK_comma] = Key::COMMA; // the comma key on any keyboard + mapKeys[XK_minus] = Key::MINUS; // the minus key on any keyboard + + mapKeys[XK_Caps_Lock] = Key::CAPS_LOCK; + + return olc::OK; + } + + virtual olc::rcode SetWindowTitle(const std::string& s) override + { + X11::XStoreName(olc_Display, olc_Window, s.c_str()); + return olc::OK; + } + + virtual olc::rcode StartSystemEventLoop() override + { + return olc::OK; + } + + virtual olc::rcode HandleSystemEvent() override + { + using namespace X11; + // Handle Xlib Message Loop - we do this in the + // same thread that OpenGL was created so we dont + // need to worry too much about multithreading with X11 + XEvent xev; + while (XPending(olc_Display)) + { + XNextEvent(olc_Display, &xev); + if (xev.type == Expose) + { + XWindowAttributes gwa; + XGetWindowAttributes(olc_Display, olc_Window, &gwa); + ptrPGE->olc_UpdateWindowSize(gwa.width, gwa.height); + } + else if (xev.type == ConfigureNotify) + { + XConfigureEvent xce = xev.xconfigure; + ptrPGE->olc_UpdateWindowSize(xce.width, xce.height); + } + else if (xev.type == KeyPress) + { + KeySym sym = XLookupKeysym(&xev.xkey, 0); + ptrPGE->olc_UpdateKeyState(mapKeys[sym], true); + XKeyEvent* e = (XKeyEvent*)&xev; // Because DragonEye loves numpads + XLookupString(e, NULL, 0, &sym, NULL); + ptrPGE->olc_UpdateKeyState(mapKeys[sym], true); + } + else if (xev.type == KeyRelease) + { + KeySym sym = XLookupKeysym(&xev.xkey, 0); + ptrPGE->olc_UpdateKeyState(mapKeys[sym], false); + XKeyEvent* e = (XKeyEvent*)&xev; + XLookupString(e, NULL, 0, &sym, NULL); + ptrPGE->olc_UpdateKeyState(mapKeys[sym], false); + } + else if (xev.type == ButtonPress) + { + switch (xev.xbutton.button) + { + case 1: ptrPGE->olc_UpdateMouseState(0, true); break; + case 2: ptrPGE->olc_UpdateMouseState(2, true); break; + case 3: ptrPGE->olc_UpdateMouseState(1, true); break; + case 4: ptrPGE->olc_UpdateMouseWheel(120); break; + case 5: ptrPGE->olc_UpdateMouseWheel(-120); break; + default: break; + } + } + else if (xev.type == ButtonRelease) + { + switch (xev.xbutton.button) + { + case 1: ptrPGE->olc_UpdateMouseState(0, false); break; + case 2: ptrPGE->olc_UpdateMouseState(2, false); break; + case 3: ptrPGE->olc_UpdateMouseState(1, false); break; + default: break; + } + } + else if (xev.type == MotionNotify) + { + ptrPGE->olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y); + } + else if (xev.type == FocusIn) + { + ptrPGE->olc_UpdateKeyFocus(true); + } + else if (xev.type == FocusOut) + { + ptrPGE->olc_UpdateKeyFocus(false); + } + else if (xev.type == ClientMessage) + { + ptrPGE->olc_Terminate(); + } + } + return olc::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | END PLATFORM: LINUX | +// O------------------------------------------------------------------------------O +#pragma endregion + +#pragma region platform_glut +// O------------------------------------------------------------------------------O +// | START PLATFORM: GLUT (used to make it simple for Apple) | +// O------------------------------------------------------------------------------O +// +// VERY IMPORTANT!!! The Apple port was originally created by @Mumflr (discord) +// and the repo for the development of this project can be found here: +// https://github.com/MumflrFumperdink/olcPGEMac which contains maccy goodness +// and support on how to setup your build environment. +// +// "MASSIVE MASSIVE THANKS TO MUMFLR" - Javidx9 +#if defined(OLC_PLATFORM_GLUT) +namespace olc { + + class Platform_GLUT : public olc::Platform + { + public: + static std::atomic* bActiveRef; + + virtual olc::rcode ApplicationStartUp() override { + return olc::rcode::OK; + } + + virtual olc::rcode ApplicationCleanUp() override + { + return olc::rcode::OK; + } + + virtual olc::rcode ThreadStartUp() override + { + return olc::rcode::OK; + } + + virtual olc::rcode ThreadCleanUp() override + { + renderer->DestroyDevice(); + return olc::OK; + } + + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override + { + if (renderer->CreateDevice({}, bFullScreen, bEnableVSYNC) == olc::rcode::OK) + { + renderer->UpdateViewport(vViewPos, vViewSize); + return olc::rcode::OK; + } + else + return olc::rcode::FAIL; + } + + static void ExitMainLoop() { + if (!ptrPGE->OnUserDestroy()) { + *bActiveRef = true; + return; + } + platform->ThreadCleanUp(); + platform->ApplicationCleanUp(); + exit(0); + } + +#if defined(__APPLE__) + static void scrollWheelUpdate(id selff, SEL _sel, id theEvent) { + static const SEL deltaYSel = sel_registerName("deltaY"); + +#if defined(__aarch64__) // Thanks ruarq! + double deltaY = ((double (*)(id, SEL))objc_msgSend)(theEvent, deltaYSel); +#else + double deltaY = ((double (*)(id, SEL))objc_msgSend_fpret)(theEvent, deltaYSel); +#endif + + for (int i = 0; i < abs(deltaY); i++) { + if (deltaY > 0) { + ptrPGE->olc_UpdateMouseWheel(-1); + } + else if (deltaY < 0) { + ptrPGE->olc_UpdateMouseWheel(1); + } + } + } +#endif + static void ThreadFunct() { +#if defined(__APPLE__) + static bool hasEnabledCocoa = false; + if (!hasEnabledCocoa) { + // Objective-C Wizardry + Class NSApplicationClass = objc_getClass("NSApplication"); + + // NSApp = [NSApplication sharedApplication] + SEL sharedApplicationSel = sel_registerName("sharedApplication"); + id NSApp = ((id(*)(Class, SEL))objc_msgSend)(NSApplicationClass, sharedApplicationSel); + // window = [NSApp mainWindow] + SEL mainWindowSel = sel_registerName("mainWindow"); + id window = ((id(*)(id, SEL))objc_msgSend)(NSApp, mainWindowSel); + + // [window setStyleMask: NSWindowStyleMaskClosable | ~NSWindowStyleMaskResizable] + SEL setStyleMaskSel = sel_registerName("setStyleMask:"); + ((void (*)(id, SEL, NSUInteger))objc_msgSend)(window, setStyleMaskSel, 7); + + hasEnabledCocoa = true; + } +#endif + if (!*bActiveRef) { + ExitMainLoop(); + return; + } + glutPostRedisplay(); + } + + static void DrawFunct() { + ptrPGE->olc_CoreUpdate(); + } + + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override + { +#if defined(__APPLE__) + Class GLUTViewClass = objc_getClass("GLUTView"); + + SEL scrollWheelSel = sel_registerName("scrollWheel:"); + bool resultAddMethod = class_addMethod(GLUTViewClass, scrollWheelSel, (IMP)scrollWheelUpdate, "v@:@"); + assert(resultAddMethod); +#endif + + renderer->PrepareDevice(); + + if (bFullScreen) + { + vWindowSize.x = glutGet(GLUT_SCREEN_WIDTH); + vWindowSize.y = glutGet(GLUT_SCREEN_HEIGHT); + glutFullScreen(); + } + else + { + if (vWindowSize.x > glutGet(GLUT_SCREEN_WIDTH) || vWindowSize.y > glutGet(GLUT_SCREEN_HEIGHT)) + { + perror("ERROR: The specified window dimensions do not fit on your screen\n"); + return olc::FAIL; + } + glutReshapeWindow(vWindowSize.x, vWindowSize.y - 1); + } + + // Create Keyboard Mapping + mapKeys[0x00] = Key::NONE; + mapKeys['A'] = Key::A; mapKeys['B'] = Key::B; mapKeys['C'] = Key::C; mapKeys['D'] = Key::D; mapKeys['E'] = Key::E; + mapKeys['F'] = Key::F; mapKeys['G'] = Key::G; mapKeys['H'] = Key::H; mapKeys['I'] = Key::I; mapKeys['J'] = Key::J; + mapKeys['K'] = Key::K; mapKeys['L'] = Key::L; mapKeys['M'] = Key::M; mapKeys['N'] = Key::N; mapKeys['O'] = Key::O; + mapKeys['P'] = Key::P; mapKeys['Q'] = Key::Q; mapKeys['R'] = Key::R; mapKeys['S'] = Key::S; mapKeys['T'] = Key::T; + mapKeys['U'] = Key::U; mapKeys['V'] = Key::V; mapKeys['W'] = Key::W; mapKeys['X'] = Key::X; mapKeys['Y'] = Key::Y; + mapKeys['Z'] = Key::Z; + + mapKeys[GLUT_KEY_F1] = Key::F1; mapKeys[GLUT_KEY_F2] = Key::F2; mapKeys[GLUT_KEY_F3] = Key::F3; mapKeys[GLUT_KEY_F4] = Key::F4; + mapKeys[GLUT_KEY_F5] = Key::F5; mapKeys[GLUT_KEY_F6] = Key::F6; mapKeys[GLUT_KEY_F7] = Key::F7; mapKeys[GLUT_KEY_F8] = Key::F8; + mapKeys[GLUT_KEY_F9] = Key::F9; mapKeys[GLUT_KEY_F10] = Key::F10; mapKeys[GLUT_KEY_F11] = Key::F11; mapKeys[GLUT_KEY_F12] = Key::F12; + + mapKeys[GLUT_KEY_DOWN] = Key::DOWN; mapKeys[GLUT_KEY_LEFT] = Key::LEFT; mapKeys[GLUT_KEY_RIGHT] = Key::RIGHT; mapKeys[GLUT_KEY_UP] = Key::UP; + mapKeys[13] = Key::ENTER; + + mapKeys[127] = Key::BACK; mapKeys[27] = Key::ESCAPE; + mapKeys[9] = Key::TAB; mapKeys[GLUT_KEY_HOME] = Key::HOME; + mapKeys[GLUT_KEY_END] = Key::END; mapKeys[GLUT_KEY_PAGE_UP] = Key::PGUP; mapKeys[GLUT_KEY_PAGE_DOWN] = Key::PGDN; mapKeys[GLUT_KEY_INSERT] = Key::INS; + mapKeys[32] = Key::SPACE; mapKeys[46] = Key::PERIOD; + + mapKeys[48] = Key::K0; mapKeys[49] = Key::K1; mapKeys[50] = Key::K2; mapKeys[51] = Key::K3; mapKeys[52] = Key::K4; + mapKeys[53] = Key::K5; mapKeys[54] = Key::K6; mapKeys[55] = Key::K7; mapKeys[56] = Key::K8; mapKeys[57] = Key::K9; + + // NOTE: MISSING KEYS :O + + glutKeyboardFunc([](unsigned char key, int x, int y) -> void { + switch (glutGetModifiers()) { + case 0: //This is when there are no modifiers + if ('a' <= key && key <= 'z') key -= 32; + break; + case GLUT_ACTIVE_SHIFT: + ptrPGE->olc_UpdateKeyState(Key::SHIFT, true); + break; + case GLUT_ACTIVE_CTRL: + if ('a' <= key && key <= 'z') key -= 32; + ptrPGE->olc_UpdateKeyState(Key::CTRL, true); + break; + case GLUT_ACTIVE_ALT: + if ('a' <= key && key <= 'z') key -= 32; + break; + } + + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], true); + }); + + glutKeyboardUpFunc([](unsigned char key, int x, int y) -> void { + switch (glutGetModifiers()) { + case 0: //This is when there are no modifiers + if ('a' <= key && key <= 'z') key -= 32; + break; + case GLUT_ACTIVE_SHIFT: + ptrPGE->olc_UpdateKeyState(Key::SHIFT, false); + break; + case GLUT_ACTIVE_CTRL: + if ('a' <= key && key <= 'z') key -= 32; + ptrPGE->olc_UpdateKeyState(Key::CTRL, false); + break; + case GLUT_ACTIVE_ALT: + if ('a' <= key && key <= 'z') key -= 32; + //No ALT in PGE + break; + } + + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], false); + }); + + //Special keys + glutSpecialFunc([](int key, int x, int y) -> void { + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], true); + }); + + glutSpecialUpFunc([](int key, int x, int y) -> void { + if (mapKeys[key]) + ptrPGE->olc_UpdateKeyState(mapKeys[key], false); + }); + + glutMouseFunc([](int button, int state, int x, int y) -> void { + switch (button) { + case GLUT_LEFT_BUTTON: + if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(0, false); + else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(0, true); + break; + case GLUT_MIDDLE_BUTTON: + if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(2, false); + else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(2, true); + break; + case GLUT_RIGHT_BUTTON: + if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(1, false); + else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(1, true); + break; + } + }); + + auto mouseMoveCall = [](int x, int y) -> void { + ptrPGE->olc_UpdateMouse(x, y); + }; + + glutMotionFunc(mouseMoveCall); + glutPassiveMotionFunc(mouseMoveCall); + + glutEntryFunc([](int state) -> void { + if (state == GLUT_ENTERED) ptrPGE->olc_UpdateKeyFocus(true); + else if (state == GLUT_LEFT) ptrPGE->olc_UpdateKeyFocus(false); + }); + + glutDisplayFunc(DrawFunct); + glutIdleFunc(ThreadFunct); + + return olc::OK; + } + + virtual olc::rcode SetWindowTitle(const std::string& s) override + { + glutSetWindowTitle(s.c_str()); + return olc::OK; + } + + virtual olc::rcode StartSystemEventLoop() override { + glutMainLoop(); + return olc::OK; + } + + virtual olc::rcode HandleSystemEvent() override + { + return olc::OK; + } + }; + + std::atomic* Platform_GLUT::bActiveRef{ nullptr }; + + //Custom Start + olc::rcode PixelGameEngine::Start() + { + if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL; + + // Construct the window + if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL; + olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y); + + if (platform->ThreadStartUp() == olc::FAIL) return olc::FAIL; + olc_PrepareEngine(); + if (!OnUserCreate()) return olc::FAIL; + Platform_GLUT::bActiveRef = &bAtomActive; + glutWMCloseFunc(Platform_GLUT::ExitMainLoop); + bAtomActive = true; + platform->StartSystemEventLoop(); + + //This code will not even be run but why not + if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL; + + return olc::OK; + } +} + +#endif +// O------------------------------------------------------------------------------O +// | END PLATFORM: GLUT | +// O------------------------------------------------------------------------------O +#pragma endregion + + +#pragma region platform_emscripten +// O------------------------------------------------------------------------------O +// | START PLATFORM: Emscripten - Totally Game Changing... | +// O------------------------------------------------------------------------------O + +// +// Firstly a big mega thank you to members of the OLC Community for sorting this +// out. Making a browser compatible version has been a priority for quite some +// time, but I lacked the expertise to do it. This awesome feature is possible +// because a group of former strangers got together and formed friendships over +// their shared passion for code. If anything demonstrates how powerful helping +// each other can be, it's this. - Javidx9 + +// Emscripten Platform: MaGetzUb, Moros1138, Slavka, Dandistine, Gorbit99, Bispoo +// also: Ishidex, Gusgo99, SlicEnDicE, Alexio + + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + +#include +#include + +extern "C" +{ + EMSCRIPTEN_KEEPALIVE inline int olc_OnPageUnload() + { olc::platform->ApplicationCleanUp(); return 0; } +} + +namespace olc +{ + class Platform_Emscripten : public olc::Platform + { + public: + + virtual olc::rcode ApplicationStartUp() override + { return olc::rcode::OK; } + + virtual olc::rcode ApplicationCleanUp() override + { ThreadCleanUp(); return olc::rcode::OK; } + + virtual olc::rcode ThreadStartUp() override + { return olc::rcode::OK; } + + virtual olc::rcode ThreadCleanUp() override + { renderer->DestroyDevice(); return olc::OK; } + + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override + { + if (renderer->CreateDevice({}, bFullScreen, bEnableVSYNC) == olc::rcode::OK) + { + renderer->UpdateViewport(vViewPos, vViewSize); + return olc::rcode::OK; + } + else + return olc::rcode::FAIL; + } + + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override + { + emscripten_set_canvas_element_size("#canvas", vWindowSize.x, vWindowSize.y); + + mapKeys[DOM_PK_UNKNOWN] = Key::NONE; + mapKeys[DOM_PK_A] = Key::A; mapKeys[DOM_PK_B] = Key::B; mapKeys[DOM_PK_C] = Key::C; mapKeys[DOM_PK_D] = Key::D; + mapKeys[DOM_PK_E] = Key::E; mapKeys[DOM_PK_F] = Key::F; mapKeys[DOM_PK_G] = Key::G; mapKeys[DOM_PK_H] = Key::H; + mapKeys[DOM_PK_I] = Key::I; mapKeys[DOM_PK_J] = Key::J; mapKeys[DOM_PK_K] = Key::K; mapKeys[DOM_PK_L] = Key::L; + mapKeys[DOM_PK_M] = Key::M; mapKeys[DOM_PK_N] = Key::N; mapKeys[DOM_PK_O] = Key::O; mapKeys[DOM_PK_P] = Key::P; + mapKeys[DOM_PK_Q] = Key::Q; mapKeys[DOM_PK_R] = Key::R; mapKeys[DOM_PK_S] = Key::S; mapKeys[DOM_PK_T] = Key::T; + mapKeys[DOM_PK_U] = Key::U; mapKeys[DOM_PK_V] = Key::V; mapKeys[DOM_PK_W] = Key::W; mapKeys[DOM_PK_X] = Key::X; + mapKeys[DOM_PK_Y] = Key::Y; mapKeys[DOM_PK_Z] = Key::Z; + mapKeys[DOM_PK_0] = Key::K0; mapKeys[DOM_PK_1] = Key::K1; mapKeys[DOM_PK_2] = Key::K2; + mapKeys[DOM_PK_3] = Key::K3; mapKeys[DOM_PK_4] = Key::K4; mapKeys[DOM_PK_5] = Key::K5; + mapKeys[DOM_PK_6] = Key::K6; mapKeys[DOM_PK_7] = Key::K7; mapKeys[DOM_PK_8] = Key::K8; + mapKeys[DOM_PK_9] = Key::K9; + mapKeys[DOM_PK_F1] = Key::F1; mapKeys[DOM_PK_F2] = Key::F2; mapKeys[DOM_PK_F3] = Key::F3; mapKeys[DOM_PK_F4] = Key::F4; + mapKeys[DOM_PK_F5] = Key::F5; mapKeys[DOM_PK_F6] = Key::F6; mapKeys[DOM_PK_F7] = Key::F7; mapKeys[DOM_PK_F8] = Key::F8; + mapKeys[DOM_PK_F9] = Key::F9; mapKeys[DOM_PK_F10] = Key::F10; mapKeys[DOM_PK_F11] = Key::F11; mapKeys[DOM_PK_F12] = Key::F12; + mapKeys[DOM_PK_ARROW_UP] = Key::UP; mapKeys[DOM_PK_ARROW_DOWN] = Key::DOWN; + mapKeys[DOM_PK_ARROW_LEFT] = Key::LEFT; mapKeys[DOM_PK_ARROW_RIGHT] = Key::RIGHT; + mapKeys[DOM_PK_SPACE] = Key::SPACE; mapKeys[DOM_PK_TAB] = Key::TAB; + mapKeys[DOM_PK_SHIFT_LEFT] = Key::SHIFT; mapKeys[DOM_PK_SHIFT_RIGHT] = Key::SHIFT; + mapKeys[DOM_PK_CONTROL_LEFT] = Key::CTRL; mapKeys[DOM_PK_CONTROL_RIGHT] = Key::CTRL; + mapKeys[DOM_PK_INSERT] = Key::INS; mapKeys[DOM_PK_DELETE] = Key::DEL; mapKeys[DOM_PK_HOME] = Key::HOME; + mapKeys[DOM_PK_END] = Key::END; mapKeys[DOM_PK_PAGE_UP] = Key::PGUP; mapKeys[DOM_PK_PAGE_DOWN] = Key::PGDN; + mapKeys[DOM_PK_BACKSPACE] = Key::BACK; mapKeys[DOM_PK_ESCAPE] = Key::ESCAPE; + mapKeys[DOM_PK_ENTER] = Key::ENTER; mapKeys[DOM_PK_NUMPAD_EQUAL] = Key::EQUALS; + mapKeys[DOM_PK_NUMPAD_ENTER] = Key::ENTER; mapKeys[DOM_PK_PAUSE] = Key::PAUSE; + mapKeys[DOM_PK_SCROLL_LOCK] = Key::SCROLL; + mapKeys[DOM_PK_NUMPAD_0] = Key::NP0; mapKeys[DOM_PK_NUMPAD_1] = Key::NP1; mapKeys[DOM_PK_NUMPAD_2] = Key::NP2; + mapKeys[DOM_PK_NUMPAD_3] = Key::NP3; mapKeys[DOM_PK_NUMPAD_4] = Key::NP4; mapKeys[DOM_PK_NUMPAD_5] = Key::NP5; + mapKeys[DOM_PK_NUMPAD_6] = Key::NP6; mapKeys[DOM_PK_NUMPAD_7] = Key::NP7; mapKeys[DOM_PK_NUMPAD_8] = Key::NP8; + mapKeys[DOM_PK_NUMPAD_9] = Key::NP9; + mapKeys[DOM_PK_NUMPAD_MULTIPLY] = Key::NP_MUL; mapKeys[DOM_PK_NUMPAD_DIVIDE] = Key::NP_DIV; + mapKeys[DOM_PK_NUMPAD_ADD] = Key::NP_ADD; mapKeys[DOM_PK_NUMPAD_SUBTRACT] = Key::NP_SUB; + mapKeys[DOM_PK_NUMPAD_DECIMAL] = Key::NP_DECIMAL; + mapKeys[DOM_PK_PERIOD] = Key::PERIOD; mapKeys[DOM_PK_EQUAL] = Key::EQUALS; + mapKeys[DOM_PK_COMMA] = Key::COMMA; mapKeys[DOM_PK_MINUS] = Key::MINUS; + mapKeys[DOM_PK_CAPS_LOCK] = Key::CAPS_LOCK; + mapKeys[DOM_PK_SEMICOLON] = Key::OEM_1; mapKeys[DOM_PK_SLASH] = Key::OEM_2; mapKeys[DOM_PK_BACKQUOTE] = Key::OEM_3; + mapKeys[DOM_PK_BRACKET_LEFT] = Key::OEM_4; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_5; mapKeys[DOM_PK_BRACKET_RIGHT] = Key::OEM_6; + mapKeys[DOM_PK_QUOTE] = Key::OEM_7; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_8; + + // Keyboard Callbacks + emscripten_set_keydown_callback("#canvas", 0, 1, keyboard_callback); + emscripten_set_keyup_callback("#canvas", 0, 1, keyboard_callback); + + // Mouse Callbacks + emscripten_set_wheel_callback("#canvas", 0, 1, wheel_callback); + emscripten_set_mousedown_callback("#canvas", 0, 1, mouse_callback); + emscripten_set_mouseup_callback("#canvas", 0, 1, mouse_callback); + emscripten_set_mousemove_callback("#canvas", 0, 1, mouse_callback); + + // Touch Callbacks + emscripten_set_touchstart_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchmove_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchend_callback("#canvas", 0, 1, touch_callback); + + // Canvas Focus Callbacks + emscripten_set_blur_callback("#canvas", 0, 1, focus_callback); + emscripten_set_focus_callback("#canvas", 0, 1, focus_callback); + +#pragma warning disable format + EM_ASM( window.onunload = Module._olc_OnPageUnload; ); + + // IMPORTANT! - Sorry About This... + // + // In order to handle certain browser based events, such as resizing and + // going to full screen, we have to effectively inject code into the container + // running the PGE. Yes, I vomited about 11 times too when the others were + // convincing me this is the future. Well, this isnt the future, and if it + // were to be, I want no part of what must be a miserable distopian free + // for all of anarchic code injection to get rudimentary events like "Resize()". + // + // Wake up people! Of course theres a spoon. There has to be to keep feeding + // the giant web baby. + + + // Fullscreen and Resize Observers + EM_ASM({ + + // cache for reuse + Module._olc_EmscriptenShellCss = "width: 100%; height: 70vh; margin-left: auto; margin-right: auto;"; + + // width / height = aspect ratio + Module._olc_WindowAspectRatio = $0 / $1; + Module.canvas.parentNode.addEventListener("resize", function(e) { + + if (e.defaultPrevented) { e.stopPropagation(); return; } + var viewWidth = e.detail.width; + var viewHeight = e.detail.width / Module._olc_WindowAspectRatio; + if (viewHeight > e.detail.height) + { + viewHeight = e.detail.height; + viewWidth = e.detail.height * Module._olc_WindowAspectRatio; + } + + if (Module.canvas.parentNode.className == 'emscripten_border') + Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss + " width: " + viewWidth.toString() + "px; height: " + viewHeight.toString() + "px;"; + + Module.canvas.setAttribute("width", viewWidth); + Module.canvas.setAttribute("height", viewHeight); + + if (document.fullscreenElement != null) + { + var top = (e.detail.height - viewHeight) / 2; + var left = (e.detail.width - viewWidth) / 2; + Module.canvas.style.position = "fixed"; + Module.canvas.style.top = top.toString() + "px"; + Module.canvas.style.left = left.toString() + "px"; + Module.canvas.style.width = ""; + Module.canvas.style.height = ""; + } + + // trigger PGE update + Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight); + // this is really only needed when enter/exiting fullscreen + Module.canvas.focus(); + // prevent this event from ever affecting the document beyond this element + e.stopPropagation(); + }); + + // helper function to prevent repeating the same code everywhere + Module._olc_ResizeCanvas = function() + { + // yes, we still have to wait, sigh.. + setTimeout(function() + { + // if default template, stretch width as well + if (Module.canvas.parentNode.className == 'emscripten_border') + Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss; + + // override it's styling so we can get it's stretched size + Module.canvas.style.cssText = "width: 100%; height: 100%; outline: none;"; + + // setup custom resize event + var resizeEvent = new CustomEvent('resize', + { + detail: { + width: Module.canvas.clientWidth, + height : Module.canvas.clientHeight + }, + bubbles : true, + cancelable : true + }); + + // trigger custom resize event on canvas element + Module.canvas.dispatchEvent(resizeEvent); + }, 50); + }; + + + // Disable Refresh Gesture on mobile + document.body.style.cssText += " overscroll-behavior-y: contain;"; + + if (Module.canvas.parentNode.className == 'emscripten_border') + { + // force body to have no margin in emscripten's minimal shell + document.body.style.margin = "0"; + Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss; + } + + Module._olc_ResizeCanvas(); + + // observe and react to resizing of the container element + var resizeObserver = new ResizeObserver(function(entries) {Module._olc_ResizeCanvas();}).observe(Module.canvas.parentNode); + + // observe and react to changes that occur when entering/exiting fullscreen + var mutationObserver = new MutationObserver(function(mutationsList, observer) + { + // a change has occurred, let's check them out! + for (var i = 0; i < mutationsList.length; i++) + { + // cycle through all of the newly added elements + for (var j = 0; j < mutationsList[i].addedNodes.length; j++) + { + // if this element is a our canvas, trigger resize + if (mutationsList[i].addedNodes[j].id == 'canvas') + Module._olc_ResizeCanvas(); + } + } + }).observe(Module.canvas.parentNode, + { + attributes: false, + childList : true, + subtree : false + }); + + // add resize listener on window + window.addEventListener("resize", function(e) { Module._olc_ResizeCanvas(); }); + + }, vWindowSize.x, vWindowSize.y); // Fullscreen and Resize Observers +#pragma warning restore format + return olc::rcode::OK; + } + + // Interface PGE's UpdateWindowSize, for use in Javascript + void UpdateWindowSize(int width, int height) + { + ptrPGE->olc_UpdateWindowSize(width, height); + } + + //TY Gorbit + static EM_BOOL focus_callback(int eventType, const EmscriptenFocusEvent* focusEvent, void* userData) + { + if (eventType == EMSCRIPTEN_EVENT_BLUR) + { + ptrPGE->olc_UpdateKeyFocus(false); + ptrPGE->olc_UpdateMouseFocus(false); + } + else if (eventType == EMSCRIPTEN_EVENT_FOCUS) + { + ptrPGE->olc_UpdateKeyFocus(true); + ptrPGE->olc_UpdateMouseFocus(true); + } + + return 0; + } + + //TY Moros + static EM_BOOL keyboard_callback(int eventType, const EmscriptenKeyboardEvent* e, void* userData) + { + if (eventType == EMSCRIPTEN_EVENT_KEYDOWN) + ptrPGE->olc_UpdateKeyState(mapKeys[emscripten_compute_dom_pk_code(e->code)], true); + + // THANK GOD!! for this compute function. And thanks Dandistine for pointing it out! + if (eventType == EMSCRIPTEN_EVENT_KEYUP) + ptrPGE->olc_UpdateKeyState(mapKeys[emscripten_compute_dom_pk_code(e->code)], false); + + //Consume keyboard events so that keys like F1 and F5 don't do weird things + return EM_TRUE; + } + + //TY Moros + static EM_BOOL wheel_callback(int eventType, const EmscriptenWheelEvent* e, void* userData) + { + if (eventType == EMSCRIPTEN_EVENT_WHEEL) + ptrPGE->olc_UpdateMouseWheel(-1 * e->deltaY); + + return EM_TRUE; + } + + //TY Bispoo + static EM_BOOL touch_callback(int eventType, const EmscriptenTouchEvent* e, void* userData) + { + // Move + if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) + { + ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY); + } + + // Start + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) + { + ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY); + ptrPGE->olc_UpdateMouseState(0, true); + } + + // End + if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) + { + ptrPGE->olc_UpdateMouseState(0, false); + } + + return EM_TRUE; + } + + //TY Moros + static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent* e, void* userData) + { + //Mouse Movement + if (eventType == EMSCRIPTEN_EVENT_MOUSEMOVE) + ptrPGE->olc_UpdateMouse(e->targetX, e->targetY); + + + //Mouse button press + if (e->button == 0) // left click + { + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) + ptrPGE->olc_UpdateMouseState(0, true); + else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP) + ptrPGE->olc_UpdateMouseState(0, false); + } + + if (e->button == 2) // right click + { + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) + ptrPGE->olc_UpdateMouseState(1, true); + else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP) + ptrPGE->olc_UpdateMouseState(1, false); + + } + + if (e->button == 1) // middle click + { + if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) + ptrPGE->olc_UpdateMouseState(2, true); + else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP) + ptrPGE->olc_UpdateMouseState(2, false); + + //at the moment only middle mouse needs to consume events. + return EM_TRUE; + } + + return EM_FALSE; + } + + + virtual olc::rcode SetWindowTitle(const std::string& s) override + { emscripten_set_window_title(s.c_str()); return olc::OK; } + + virtual olc::rcode StartSystemEventLoop() override + { return olc::OK; } + + virtual olc::rcode HandleSystemEvent() override + { return olc::OK; } + + static void MainLoop() + { + olc::Platform::ptrPGE->olc_CoreUpdate(); + if (!ptrPGE->olc_IsRunning()) + { + if (ptrPGE->OnUserDestroy()) + { + emscripten_cancel_main_loop(); + platform->ApplicationCleanUp(); + } + else + { + ptrPGE->olc_Reanimate(); + } + } + } + }; + + //Emscripten needs a special Start function + //Much of this is usually done in EngineThread, but that isn't used here + olc::rcode PixelGameEngine::Start() + { + if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL; + + // Construct the window + if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL; + olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y); + + // Some implementations may form an event loop here + if (platform->ThreadStartUp() == olc::FAIL) return olc::FAIL; + + // Do engine context specific initialisation + olc_PrepareEngine(); + + // Consider the "thread" started + bAtomActive = true; + + // Create user resources as part of this thread + for (auto& ext : vExtensions) ext->OnBeforeUserCreate(); + if (!OnUserCreate()) bAtomActive = false; + for (auto& ext : vExtensions) ext->OnAfterUserCreate(); + + platform->StartSystemEventLoop(); + + //This causes a heap memory corruption in Emscripten for some reason + //Platform_Emscripten::bActiveRef = &bAtomActive; + emscripten_set_main_loop(&Platform_Emscripten::MainLoop, 0, 1); + + // Wait for thread to be exited + if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL; + return olc::OK; + } +} + +extern "C" +{ + EMSCRIPTEN_KEEPALIVE inline void olc_PGE_UpdateWindowSize(int width, int height) + { + emscripten_set_canvas_element_size("#canvas", width, height); + // Thanks slavka + ((olc::Platform_Emscripten*)olc::platform.get())->UpdateWindowSize(width, height); + } +} + +#endif +// O------------------------------------------------------------------------------O +// | END PLATFORM: Emscripten | +// O------------------------------------------------------------------------------O +#pragma endregion + + +#endif // Headless + +// O------------------------------------------------------------------------------O +// | olcPixelGameEngine Auto-Configuration | +// O------------------------------------------------------------------------------O +#pragma region pge_config +namespace olc +{ + void PixelGameEngine::olc_ConfigureSystem() + { + +#if !defined(OLC_PGE_HEADLESS) + +#if defined(OLC_IMAGE_GDI) + olc::Sprite::loader = std::make_unique(); +#endif + +#if defined(OLC_IMAGE_LIBPNG) + olc::Sprite::loader = std::make_unique(); +#endif + +#if defined(OLC_IMAGE_STB) + olc::Sprite::loader = std::make_unique(); +#endif + +#if defined(OLC_IMAGE_CUSTOM_EX) + olc::Sprite::loader = std::make_unique(); +#endif + + + + +#if defined(OLC_PLATFORM_WINAPI) + platform = std::make_unique(); +#endif + +#if defined(OLC_PLATFORM_X11) + platform = std::make_unique(); +#endif + +#if defined(OLC_PLATFORM_GLUT) + platform = std::make_unique(); +#endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + platform = std::make_unique(); +#endif + +#if defined(OLC_PLATFORM_CUSTOM_EX) + platform = std::make_unique(); +#endif + + + +#if defined(OLC_GFX_OPENGL10) + renderer = std::make_unique(); +#endif + +#if defined(OLC_GFX_OPENGL33) + renderer = std::make_unique(); +#endif + +#if defined(OLC_GFX_OPENGLES2) + renderer = std::make_unique(); +#endif + +#if defined(OLC_GFX_DIRECTX10) + renderer = std::make_unique(); +#endif + +#if defined(OLC_GFX_DIRECTX11) + renderer = std::make_unique(); +#endif + +#if defined(OLC_GFX_CUSTOM_EX) + renderer = std::make_unique(); +#endif + + // Associate components with PGE instance + platform->ptrPGE = this; + renderer->ptrPGE = this; +#else + olc::Sprite::loader = nullptr; + platform = nullptr; + renderer = nullptr; +#endif + } +} + +#pragma endregion + +#endif // End OLC_PGE_APPLICATION + +// O------------------------------------------------------------------------------O +// | END OF OLC_PGE_APPLICATION | +// O------------------------------------------------------------------------------O + diff --git a/sig b/sig new file mode 100755 index 0000000..f50df4f --- /dev/null +++ b/sig @@ -0,0 +1,9 @@ +export AUTO_UPDATE=true + +source utils/define.sh + +define PROJECT_NAME "C++ProjectTemplate" +define CUSTOM_PARAMS "-std=c++17 -lX11 -lGL -lpthread -lpng -lstdc++fs -lasound" +define LANGUAGE "C++" + +source utils/main.sh diff --git a/utils/.coauthors b/utils/.coauthors new file mode 100644 index 0000000..b904d0f --- /dev/null +++ b/utils/.coauthors @@ -0,0 +1 @@ +sigonasr2 diff --git a/utils/.updateDirectories b/utils/.updateDirectories new file mode 100644 index 0000000..56274ea --- /dev/null +++ b/utils/.updateDirectories @@ -0,0 +1,5 @@ +Java/ +C/ +C++/ +scripts/ +utils/ \ No newline at end of file diff --git a/utils/define.sh b/utils/define.sh new file mode 100755 index 0000000..214fc50 --- /dev/null +++ b/utils/define.sh @@ -0,0 +1,26 @@ +export VARS=("") + +export LANGUAGE="" + +function define() { + VARS+=("$1") + value="${*:2}" + eval export "$1"='$value' +} + +if [[ $(pwd) != *"SigScript" && $AUTO_UPDATE = "true" && $1 != "update" ]]; then + source utils/search.sh + + find . -type f -name md5 -delete + find . -type f -name filelist -delete + + #Check for hashes + FILES=$(cat utils/.updateDirectories) + for f in $FILES + do + search $f + check $f + done +else + echo "Dev build, no checks required." +fi \ No newline at end of file diff --git a/utils/filelist b/utils/filelist new file mode 100644 index 0000000..95ad5ff --- /dev/null +++ b/utils/filelist @@ -0,0 +1,5 @@ +.coauthors +define.sh +main.sh +search.sh +.updateDirectories diff --git a/utils/main.sh b/utils/main.sh new file mode 100644 index 0000000..0a4c92a --- /dev/null +++ b/utils/main.sh @@ -0,0 +1,28 @@ +if [ -z "$1" ] + then + echo "" + echo " Usage: ./sig {args}" + echo "" + printf "====\tCurrent Configuration" + printf "\t=====================" + for t in ${VARS[@]} + do + printf "\n\t%-15s%20s" $t ${!t} + done + printf "\n=====================================================" + echo "" + echo "" + echo " Command List:" + FILES=$(ls -1A ./$LANGUAGE/scripts 2>/dev/null | sed -e 's/\.sh$//' | sed -e 's/^/ /') + for f in $FILES + do + if [ -f "./$LANGUAGE/scripts/$f.sh" ]; then + DESC="$(head -n1 ./$LANGUAGE/scripts/$f.sh)" + printf "\n\t%-15s%-65s" $f "${DESC:1}" + fi + done + echo "" + exit +fi + +./$LANGUAGE/scripts/$1.sh "${@:2}" \ No newline at end of file diff --git a/utils/md5 b/utils/md5 new file mode 100644 index 0000000..349fa70 --- /dev/null +++ b/utils/md5 @@ -0,0 +1,4 @@ +define.sh:3ecab0dffe2adfb950f3eb7c7061b750 - +main.sh:4e6e9f0650ec790ce2c4364db94f0caa - +search.sh:30e1842e9a13452ea883bb6516d28e1c - +.updateDirectories:971afb892e8280cb4c9ad43fb72a46a0 - diff --git a/utils/search.sh b/utils/search.sh new file mode 100644 index 0000000..6707c16 --- /dev/null +++ b/utils/search.sh @@ -0,0 +1,103 @@ +function search() { + FILES2=$(ls -A $1 2>/dev/null) + for g in $FILES2 + do + if [ -d $1$g ]; + then + echo "$1$g is a directory" + search $1$g/ + else + echo "$1$g is a file" + if [ $g != "md5" ] && [ $g != "filelist" ] && [ $g != ".package.files" ]; then + if [ $g != ".coauthors" ] && [ $g != "version_info" ]; then + SUM=$(md5sum < $1$g) + echo "$g:$SUM" >> $1md5 + fi + echo "$g" >> $1filelist + else + echo " ignoring $g..." + fi + fi + done +} + +function check() { + echo "Check $1" + FILES2=$(ls -A $1 2>/dev/null) + if [ -f "$1/md5" ]; + then + echo " md5: http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1md5" + curl -H 'Cache-Control: no-cache, no-store' -s "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1md5" --output /tmp/out + cmp -s $1/md5 /tmp/out + if [ "$?" -ne 0 ] + then + echo " Differences detected!" + cat /tmp/out + while IFS= read -r line + do + IFS=':' read -ra split <<< $line + g="${split[0]}" + echo "LINE -- $g" + if [ "$g" != "md5" ] && [ "$g" != "filelist" ] && [ "$g" != ".package.files" ]; then + if [ -f $1$g ]; + then + if [ "$g" != ".coauthors" ] && [ "$g" != "version_info" ]; then + echo "++Redownload $1$g..." + if [ -f "$1$g" ]; then + curl -H 'Cache-Control: no-cache, no-store' "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1$g" --output $1$g + else + echo "===Could not find directory, assuming regular scripts directory exists." + curl -H 'Cache-Control: no-cache, no-store' "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1$g" --output $LANGUAGE/scripts/$g + fi + fi + else + echo "++==Downloading $1$g..." + curl -H 'Cache-Control: no-cache, no-store' "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1$g" --output $1$g + fi + fi + done < /tmp/out + fi + fi + if [ -f "$1/filelist" ]; + then + echo " filelist: http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1filelist" + curl -H 'Cache-Control: no-cache, no-store' -s "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1filelist" --output /tmp/out + cmp -s $1/filelist /tmp/out + if [ "$?" -ne 0 ] + then + echo " Differences detected!" + cat /tmp/out + while IFS= read -r line + do + IFS=':' read -ra split <<< $line + g="${split[0]}" + echo "LINE -- $g" + if [ "$g" != "md5" ] && [ "$g" != "filelist" ] && [ "$g" != ".package.files" ]; then + if [ -f $1$g ]; + then + if [ "$g" != ".coauthors" ] && [ "$g" != "version_info" ]; then + echo "++Redownload $1$g..." + if [ -f "$1$g" ]; then + curl -H 'Cache-Control: no-cache, no-store' "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1$g" --output $1$g + else + echo "===Could not find directory, assuming regular scripts directory exists." + curl -H 'Cache-Control: no-cache, no-store' "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1$g" --output $LANGUAGE/scripts/$g + fi + fi + else + echo "++==Downloading $1$g..." + curl -H 'Cache-Control: no-cache, no-store' "http://sig.projectdivar.com/sigonasr2/SigScript/raw/branch/main/$1$g" --output $1$g + fi + fi + done < /tmp/out + fi + fi + for g in $FILES2 + do + if [ -d $1$g ]; + then + echo "$1$g is a directory" + check $1$g/ + fi + done +}