From e283891278b08f5b2421cdc71b529b9a694e1157 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Thu, 8 Sep 2022 21:28:30 -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 | 18 + C++ProjectTemplate | Bin 0 -> 551048 bytes C++ProjectTemplate.html | 1 + C++ProjectTemplate.js | 1 + C++ProjectTemplate.wasm | Bin 0 -> 300705 bytes README.md | 33 + buildtemplate.html | 75 + main.cpp | 74 + 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, 6607 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..7cf8083 --- /dev/null +++ b/C++/scripts/md5 @@ -0,0 +1,3 @@ +build.sh:530634457ea9041267c05d4ced95eee1 - +commit.sh:d03a46e721060c22ccb146e19d27e70a - +web.sh:3dcc2fe7e036359eedd257a864e9a1e1 - diff --git a/C++/scripts/web.sh b/C++/scripts/web.sh new file mode 100755 index 0000000..2e1a1f3 --- /dev/null +++ b/C++/scripts/web.sh @@ -0,0 +1,18 @@ +#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_SDL_MIXER=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_SDL_MIXER=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..9d73bb6f51cbaa2e2c358e1ff9e99658d051015f GIT binary patch literal 551048 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

$%YpotB$wk5z7K}K0vbSjK|yeX+B$U59k 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

g}(=X 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 Z`09FJJ(k2{>HL=ma;MwL3CWLJ{||lGH!}bL 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! 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 + -- + ---[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..4141020 --- /dev/null +++ b/main.cpp @@ -0,0 +1,74 @@ +#define OLC_PGE_APPLICATION +#include "pixelGameEngine.h" + +using namespace std; + +class Example : public olc::PixelGameEngine +{ +public: + Example() + { + sAppName = "Example"; + + } + +public: + vector data; + int TILE_WIDTH=16; + int TILE_HEIGHT=16; + + int tileOffsetX=0; + int tileOffsetY=0; + int TV_WIDTH=TILE_WIDTH*8; + int TV_HEIGHT=TILE_HEIGHT*7; + int MAP_WIDTH=256; + int MAP_HEIGHT=240; + + int TV_POSX=256/4; + int TV_POSY=240/4; + bool OnUserCreate() override + { + SetPixelMode(olc::Pixel::ALPHA); + ConsoleCaptureStdOut(true); + // Called once at the start, so create things here + for (int i=0;i<256*240;i++) { + data.push_back(rand()%255); + } + return true; + } + + bool OnUserUpdate(float fElapsedTime) override + { + + if (GetKey(olc::RIGHT).bPressed) { + tileOffsetX=std::clamp(tileOffsetX+1,0,MAP_WIDTH); + } + if (GetKey(olc::LEFT).bPressed) { + tileOffsetX=std::clamp(tileOffsetX-1,0,MAP_WIDTH); + } + if (GetKey(olc::UP).bPressed) { + tileOffsetY=std::clamp(tileOffsetY-1,0,MAP_HEIGHT); + } + if (GetKey(olc::DOWN).bPressed) { + tileOffsetY=std::clamp(tileOffsetY+1,0,MAP_HEIGHT); + } + for (int x=0;x +#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..65804b4 --- /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 -lpulse -lpulse-simple" +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 +}