diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..08eb6f8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,127 @@ +# Checkout config tool: https://zed0.co.uk/clang-format-configurator/ +# Or http://cf.monofraps.net/ +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# https://github.com/01org/parameter-framework/blob/master/.clang-format + +# Tested on: clang-format version 6.0.1 + + +# Common settings +BasedOnStyle: WebKit +TabWidth: 4 +IndentWidth: 4 +UseTab: Never +ColumnLimit: 140 + +# Other languages JavaScript, Proto + +--- +Language: Cpp + +# http://releases.llvm.org/6.0.1/tools/clang/docs/ClangFormatStyleOptions.html#disabling-formatting-on-a-piece-of-code +# int formatted_code; +# // clang-format off +# void unformatted_code ; +# // clang-format on +# void formatted_code_again; + +DisableFormat: false +Standard: Cpp11 + +AccessModifierOffset: -4 +AlignAfterOpenBracket: true +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false + +# Configure each individual brace in BraceWrapping +BreakBeforeBraces: Custom +# Control of individual brace wrapping cases +BraceWrapping: { + AfterClass: 'true' + AfterControlStatement: 'true' + AfterEnum : 'true' + AfterFunction : 'true' + AfterNamespace : 'true' + AfterStruct : 'true' + AfterUnion : 'true' + BeforeCatch : 'true' + BeforeElse : 'true' + IndentBraces : 'false' + AfterExternBlock : 'true' + SplitEmptyFunction : 'false' + SplitEmptyRecord : 'false' + SplitEmptyNamespace : 'true' +} + +BreakAfterJavaFieldAnnotations: true +BreakBeforeInheritanceComma: false +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +BreakStringLiterals: true + +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: false +FixNamespaceComments: true +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +JavaScriptQuotes: Double +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 + +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: Never +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceAfterTemplateKeyword: true + +SortUsingDeclarations: false +SortIncludes: false + +# Comments are for developers, they should arrange them +ReflowComments: false + +IncludeBlocks: Preserve +IndentPPDirectives: None +--- diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b5f6e57 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,65 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +*.h linguist-language=C++ + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7e1cf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,361 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..179a9ca --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,63 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "C:/raylib/raylib/src/**", + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE", + "GRAPHICS_API_OPENGL_33", + "PLATFORM_DESKTOP" + ], + "compilerPath": "C:/raylib/mingw/bin/gcc.exe", + "cStandard": "c99", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-x86" + }, + { + "name": "Mac", + "includePath": [ + "/src/**", + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE", + "GRAPHICS_API_OPENGL_33", + "PLATFORM_DESKTOP" + ], + "macFrameworkPath": [ + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks" + ], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x86" + }, + { + "name": "Linux", + "includePath": [ + "/src/**", + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE", + "GRAPHICS_API_OPENGL_33", + "PLATFORM_DESKTOP" + ], + "compilerPath": "usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x86" + + } + ], + "version": 4 +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..bbdd90a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,60 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/game", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": false + } + ], + "windows": { + "miDebuggerPath": "C:/raylib/mingw/bin/gdb.exe", + }, + "osx": { + "MIMode": "lldb" + }, + "linux": { + "miDebuggerPath": "/usr/bin/gdb", + }, + "preLaunchTask": "build debug" + }, + { + "name": "Run", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "program": "${workspaceFolder}/bin/game", + "MIMode": "gdb", + "windows": { + "program": "${workspaceFolder}/bin/game.exe", + "miDebuggerPath": "C:/raylib/mingw/bin/gdb.exe" + }, + "osx": { + "MIMode": "lldb" + }, + "linux": { + "miDebuggerPath": "/usr/bin/gdb" + }, + "preLaunchTask": "build release", + } + ] + } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e98318a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/*.o": true, + "**/*.exe": true, + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..77f00f4 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,63 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build debug", + "type": "process", + "command": "make", + "args": [ + "PLATFORM=PLATFORM_DESKTOP", + "BUILD_MODE=DEBUG" + ], + "windows": { + "command": "C:/raylib/mingw/bin/mingw32-make.exe", + "args": [ + "RAYLIB_PATH=C:/raylib/raylib", + "PROJECT_NAME=game", + "BUILD_MODE=DEBUG" + ], + }, + "osx": { + "args": [ + "RAYLIB_PATH=/raylib", + "PROJECT_NAME=game", + "BUILD_MODE=DEBUG" + ], + }, + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$gcc" + ] + }, + { + "label": "build release", + "type": "process", + "command": "make", + "args": [ + "PLATFORM=PLATFORM_DESKTOP", + ], + "windows": { + "command": "C:/raylib/mingw/bin/mingw32-make.exe", + "args": [ + "RAYLIB_PATH=C:/raylib/raylib", + "PROJECT_NAME=game" + ], + }, + "osx": { + "args": [ + "RAYLIB_PATH=/raylib", + "PROJECT_NAME=game" + ], + }, + "group": "build", + "problemMatcher": [ + "$gcc" + ] + } + ] +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f20e7d6 --- /dev/null +++ b/Makefile @@ -0,0 +1,406 @@ +#************************************************************************************************** +# +# raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 +# +# Copyright (c) 2013-2019 Ramon Santamaria (@raysan5) +# +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. +# +# 3. This notice may not be removed or altered from any source distribution. +# +#************************************************************************************************** + +.PHONY: all clean + +# Define required raylib variables +PROJECT_NAME ?= game +RAYLIB_VERSION ?= 3.8.0 +RAYLIB_PATH ?= c:/raylib/raylib + +# Define compiler path on Windows +COMPILER_PATH ?= C:/raylib/mingw/bin + +# Define default options +# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB +PLATFORM ?= PLATFORM_DESKTOP + +# Locations of your newly installed library and associated headers. See ../src/Makefile +# On Linux, if you have installed raylib but cannot compile the examples, check that +# the *_INSTALL_PATH values here are the same as those in src/Makefile or point to known locations. +# To enable system-wide compile-time and runtime linking to libraylib.so, run ../src/$ sudo make install RAYLIB_LIBTYPE_SHARED. +# To enable compile-time linking to a special version of libraylib.so, change these variables here. +# To enable runtime linking to a special version of libraylib.so, see EXAMPLE_RUNTIME_PATH below. +# If there is a libraylib in both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, at runtime, +# the library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over the one at RAYLIB_INSTALL_PATH. +# RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths. +#DESTDIR ?= /usr/local +RAYLIB_INSTALL_PATH ?= $(DESTDIR)/lib +# RAYLIB_H_INSTALL_PATH locates the installed raylib header and associated source files. +RAYLIB_H_INSTALL_PATH ?= $(DESTDIR)/include + +# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) +RAYLIB_LIBTYPE ?= STATIC + +# Build mode for project: DEBUG or RELEASE +BUILD_MODE ?= RELEASE + +# Use external GLFW library instead of rglfw module +# TODO: Review usage on Linux. Target version of choice. Switch on -lglfw or -lglfw3 +USE_EXTERNAL_GLFW ?= FALSE + +# Use Wayland display server protocol on Linux desktop +# by default it uses X11 windowing system +USE_WAYLAND_DISPLAY ?= FALSE + +# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! + # ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + export PATH := $(COMPILER_PATH):$(PATH) + else + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + endif + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS=BSD + endif + ifeq ($(UNAMEOS),OpenBSD) + PLATFORM_OS=BSD + endif + ifeq ($(UNAMEOS),NetBSD) + PLATFORM_OS=BSD + endif + ifeq ($(UNAMEOS),DragonFly) + PLATFORM_OS=BSD + endif + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + endif +endif + +# RAYLIB_PATH adjustment for different platforms. +# If using GNU make, we can get the full path to the top of the tree. Windows? BSD? +# Required for ldconfig or other tools that do not perform path expansion. +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + RAYLIB_PREFIX ?= .. + RAYLIB_PATH = $(realpath $(RAYLIB_PREFIX)) + endif +endif +# Default path for raylib on Raspberry Pi, if installed in different path, update it! +# This is not currently used by src/Makefile. Not sure of its origin or usage. Refer to wiki. +# TODO: update install: target in src/Makefile for RPI, consider relation to LINUX. +ifeq ($(PLATFORM),PLATFORM_RPI) + RAYLIB_PATH ?= /home/pi/raylib +endif + +ifeq ($(PLATFORM),PLATFORM_WEB) + # Emscripten required variables + EMSDK_PATH ?= C:/emsdk + EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten + CLANG_PATH = $(EMSDK_PATH)/upstream/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit + NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin + export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH) +endif + +# Define raylib release directory for compiled library. +# RAYLIB_RELEASE_PATH points to provided binaries or your freshly built version +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src + +# EXAMPLE_RUNTIME_PATH embeds a custom runtime location of libraylib.so or other desired libraries +# into each example binary compiled with RAYLIB_LIBTYPE=SHARED. It defaults to RAYLIB_RELEASE_PATH +# so that these examples link at runtime with your version of libraylib.so in ../release/libs/linux +# without formal installation from ../src/Makefile. It aids portability and is useful if you have +# multiple versions of raylib, have raylib installed to a non-standard location, or want to +# bundle libraylib.so with your game. Change it to your liking. +# NOTE: If, at runtime, there is a libraylib.so at both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, +# The library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over RAYLIB_INSTALL_PATH, +# Implemented for LINUX below with CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH) +# To see the result, run readelf -d core/core_basic_window; looking at the RPATH or RUNPATH attribute. +# To see which libraries a built example is linking to, ldd core/core_basic_window; +# Look for libraylib.so.1 => $(RAYLIB_INSTALL_PATH)/libraylib.so.1 or similar listing. +EXAMPLE_RUNTIME_PATH ?= $(RAYLIB_RELEASE_PATH) + +# Define default C compiler: gcc +# NOTE: define g++ compiler if using C++ +CC = g++ + +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + # OSX default compiler + CC = clang + endif + ifeq ($(PLATFORM_OS),BSD) + # FreeBSD, OpenBSD, NetBSD, DragonFly default compiler + CC = clang + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) + # Define RPI cross-compiler + #CC = armv6j-hardfloat-linux-gnueabi-gcc + CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc + endif +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + # HTML5 emscripten compiler + # WARNING: To compile to HTML5, code must be redesigned + # to use emscripten.h and emscripten_set_main_loop() + CC = emcc +endif + +# Define default make program: Mingw32-make +MAKE = mingw32-make + +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + MAKE = make + endif + ifeq ($(PLATFORM_OS),OSX) + MAKE = make + endif +endif + +# Define compiler flags: +# -O0 defines optimization level (no optimization, better for debugging) +# -O1 defines optimization level +# -g include debug information on compilation +# -s strip unnecessary data from build -> do not use in debug builds +# -Wall turns on most, but not all, compiler warnings +# -std=c99 defines C language mode (standard C from 1999 revision) +# -std=gnu99 defines C language mode (GNU C from 1999 revision) +# -Wno-missing-braces ignore invalid warning (GCC bug 53119) +# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec +CFLAGS += -Wall -std=c++17 -D_DEFAULT_SOURCE -Wno-missing-braces + +ifeq ($(BUILD_MODE),DEBUG) + CFLAGS += -g -O0 +else + CFLAGS += -s -O1 +endif + +# Additional flags for compiler (if desired) +#CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + # resource file contains windows executable icon and properties + # -Wl,--subsystem,windows hides the console window + CFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data -Wl,--subsystem,windows + endif + ifeq ($(PLATFORM_OS),LINUX) + ifeq ($(RAYLIB_LIBTYPE),STATIC) + CFLAGS += -D_DEFAULT_SOURCE + endif + ifeq ($(RAYLIB_LIBTYPE),SHARED) + # Explicitly enable runtime link to libraylib.so + CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH) + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + CFLAGS += -std=gnu99 +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + # -Os # size optimization + # -O2 # optimization level 2, if used, also set --memory-init-file 0 + # -s USE_GLFW=3 # Use glfw3 library (context/input management) + # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL! + # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) + # -s USE_PTHREADS=1 # multithreading support + # -s WASM=0 # disable Web Assembly, emitted by default + # -s EMTERPRETIFY=1 # enable emscripten code interpreter (very slow) + # -s EMTERPRETIFY_ASYNC=1 # support synchronous loops by emterpreter + # -s FORCE_FILESYSTEM=1 # force filesystem to load/save files data + # -s ASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off) + # --profiling # include information for code profiling + # --memory-init-file 0 # to avoid an external memory initialization code file (.mem) + # --preload-file resources # specify a resources folder for data compilation + CFLAGS += -Os -s USE_GLFW=3 -s TOTAL_MEMORY=33554432 -s LLD_REPORT_UNDEFINED --preload-file resources + ifeq ($(BUILD_MODE), DEBUG) + CFLAGS += -s ASSERTIONS=1 --profiling + endif + + # Define a custom shell .html and output extension + CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html + EXT = .html +endif + +# Define include paths for required headers +# NOTE: Several external required libraries (stb and others) +INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external + +# Define additional directories containing required header files +ifeq ($(PLATFORM),PLATFORM_RPI) + # RPI required libraries + INCLUDE_PATHS += -I/opt/vc/include + INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux + INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads +endif +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),BSD) + # Consider -L$(RAYLIB_H_INSTALL_PATH) + INCLUDE_PATHS += -I/usr/local/include + endif + ifeq ($(PLATFORM_OS),LINUX) + # Reset everything. + # Precedence: immediately local, installed version, raysan5 provided libs -I$(RAYLIB_H_INSTALL_PATH) -I$(RAYLIB_PATH)/release/include + INCLUDE_PATHS = -I$(RAYLIB_H_INSTALL_PATH) -isystem. -isystem$(RAYLIB_PATH)/src -isystem$(RAYLIB_PATH)/release/include -isystem$(RAYLIB_PATH)/src/external + endif +endif + +# Define library paths containing required libs. +LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src + +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),BSD) + # Consider -L$(RAYLIB_INSTALL_PATH) + LDFLAGS += -L. -Lsrc -L/usr/local/lib + endif + ifeq ($(PLATFORM_OS),LINUX) + # Reset everything. + # Precedence: immediately local, installed version, raysan5 provided libs + LDFLAGS = -L. -L$(RAYLIB_INSTALL_PATH) -L$(RAYLIB_RELEASE_PATH) + endif +endif + +ifeq ($(PLATFORM),PLATFORM_RPI) + LDFLAGS += -L/opt/vc/lib +endif + +# Define any libraries required on linking +# if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + # Libraries for Windows desktop compilation + # NOTE: WinMM library required to set high-res timer resolution + LDLIBS = -lraylib -lopengl32 -lgdi32 -lwinmm + # Required for physac examples + #LDLIBS += -static -lpthread + endif + ifeq ($(PLATFORM_OS),LINUX) + # Libraries for Debian GNU/Linux desktop compiling + # NOTE: Required packages: libegl1-mesa-dev + LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt + + # On X11 requires also below libraries + LDLIBS += -lX11 + # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them + #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + + # On Wayland windowing system, additional libraries requires + ifeq ($(USE_WAYLAND_DISPLAY),TRUE) + LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon + endif + # Explicit link to libc + ifeq ($(RAYLIB_LIBTYPE),SHARED) + LDLIBS += -lc + endif + endif + ifeq ($(PLATFORM_OS),OSX) + # Libraries for OSX 10.9 desktop compiling + # NOTE: Required packages: libopenal-dev libegl1-mesa-dev + LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa + endif + ifeq ($(PLATFORM_OS),BSD) + # Libraries for FreeBSD, OpenBSD, NetBSD, DragonFly desktop compiling + # NOTE: Required packages: mesa-libs + LDLIBS = -lraylib -lGL -lpthread -lm + + # On XWindow requires also below libraries + LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor + endif + ifeq ($(USE_EXTERNAL_GLFW),TRUE) + # NOTE: It could require additional packages installed: libglfw3-dev + LDLIBS += -lglfw + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + # Libraries for Raspberry Pi compiling + # NOTE: Required packages: libasound2-dev (ALSA) + LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + # Libraries for web (HTML5) compiling + LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc +endif + +# Define a recursive wildcard function +rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) + +# Define all source files required +SRC_DIR = src +OBJ_DIR = obj + +# Define all object files from source files +SRC = $(call rwildcard, *.cpp, *.h) +OBJS = $(wildcard lib/*.cpp) $(wildcard src/*.cpp) + +# For Android platform we call a custom Makefile.Android +ifeq ($(PLATFORM),PLATFORM_ANDROID) + MAKEFILE_PARAMS = -f Makefile.Android + export PROJECT_NAME + export SRC_DIR +else + MAKEFILE_PARAMS = $(PROJECT_NAME) +endif + +# Default target entry +# NOTE: We call this Makefile target or Makefile.Android target +all: + $(MAKE) $(MAKEFILE_PARAMS) + +# Project target defined by PROJECT_NAME +$(PROJECT_NAME): $(OBJS) + $(CC) -o bin/$(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + +# Compile source files +# NOTE: This pattern will compile every module defined on $(OBJS) +#%.o: %.c +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) + +# Clean everything +clean: +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),WINDOWS) + del *.o *.exe /s + endif + ifeq ($(PLATFORM_OS),LINUX) + find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv + endif + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -fv *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js +endif + @echo Cleaning done + diff --git a/ack.sfs b/ack.sfs new file mode 100644 index 0000000..1a17874 Binary files /dev/null and b/ack.sfs differ diff --git a/alert.sfs b/alert.sfs new file mode 100644 index 0000000..bae1d18 Binary files /dev/null and b/alert.sfs differ diff --git a/bin/debug.html b/bin/debug.html new file mode 100644 index 0000000..ec9fbd3 --- /dev/null +++ b/bin/debug.html @@ -0,0 +1,199 @@ + + + + + + + raylib HTML5 GAME + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + \ No newline at end of file diff --git a/bin/game.data b/bin/game.data new file mode 100644 index 0000000..79c7eca Binary files /dev/null and b/bin/game.data differ diff --git a/bin/game.exe b/bin/game.exe new file mode 100644 index 0000000..daae69c Binary files /dev/null and b/bin/game.exe differ diff --git a/bin/game.html b/bin/game.html new file mode 100644 index 0000000..205f7d6 --- /dev/null +++ b/bin/game.html @@ -0,0 +1 @@ +raylib HTML5 GAME
\ No newline at end of file diff --git a/bin/game.js b/bin/game.js new file mode 100644 index 0000000..5e2d832 --- /dev/null +++ b/bin/game.js @@ -0,0 +1 @@ +var Module=typeof Module!=="undefined"?Module:{};if(!Module.expectedDataFileDownloads){Module.expectedDataFileDownloads=0}Module.expectedDataFileDownloads++;(function(){var loadPackage=function(metadata){var PACKAGE_PATH="";if(typeof window==="object"){PACKAGE_PATH=window["encodeURIComponent"](window.location.pathname.toString().substring(0,window.location.pathname.toString().lastIndexOf("/"))+"/")}else if(typeof process==="undefined"&&typeof location!=="undefined"){PACKAGE_PATH=encodeURIComponent(location.pathname.toString().substring(0,location.pathname.toString().lastIndexOf("/"))+"/")}var PACKAGE_NAME="bin/game.data";var REMOTE_PACKAGE_BASE="game.data";if(typeof Module["locateFilePackage"]==="function"&&!Module["locateFile"]){Module["locateFile"]=Module["locateFilePackage"];err("warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)")}var REMOTE_PACKAGE_NAME=Module["locateFile"]?Module["locateFile"](REMOTE_PACKAGE_BASE,""):REMOTE_PACKAGE_BASE;var REMOTE_PACKAGE_SIZE=metadata["remote_package_size"];var PACKAGE_UUID=metadata["package_uuid"];function fetchRemotePackage(packageName,packageSize,callback,errback){if(typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string"){require("fs").readFile(packageName,function(err,contents){if(err){errback(err)}else{callback(contents.buffer)}});return}var xhr=new XMLHttpRequest;xhr.open("GET",packageName,true);xhr.responseType="arraybuffer";xhr.onprogress=function(event){var url=packageName;var size=packageSize;if(event.total)size=event.total;if(event.loaded){if(!xhr.addedTotal){xhr.addedTotal=true;if(!Module.dataFileDownloads)Module.dataFileDownloads={};Module.dataFileDownloads[url]={loaded:event.loaded,total:size}}else{Module.dataFileDownloads[url].loaded=event.loaded}var total=0;var loaded=0;var num=0;for(var download in Module.dataFileDownloads){var data=Module.dataFileDownloads[download];total+=data.total;loaded+=data.loaded;num++}total=Math.ceil(total*Module.expectedDataFileDownloads/num);if(Module["setStatus"])Module["setStatus"]("Downloading data... ("+loaded+"/"+total+")")}else if(!Module.dataFileDownloads){if(Module["setStatus"])Module["setStatus"]("Downloading data...")}};xhr.onerror=function(event){throw new Error("NetworkError for: "+packageName)};xhr.onload=function(event){if(xhr.status==200||xhr.status==304||xhr.status==206||xhr.status==0&&xhr.response){var packageData=xhr.response;callback(packageData)}else{throw new Error(xhr.statusText+" : "+xhr.responseURL)}};xhr.send(null)}function handleError(error){console.error("package error:",error)}var fetchedCallback=null;var fetched=Module["getPreloadedPackage"]?Module["getPreloadedPackage"](REMOTE_PACKAGE_NAME,REMOTE_PACKAGE_SIZE):null;if(!fetched)fetchRemotePackage(REMOTE_PACKAGE_NAME,REMOTE_PACKAGE_SIZE,function(data){if(fetchedCallback){fetchedCallback(data);fetchedCallback=null}else{fetched=data}},handleError);function runWithFS(){function assert(check,msg){if(!check)throw msg+(new Error).stack}Module["FS_createPath"]("/","resources",true,true);Module["FS_createPath"]("/resources","shaders",true,true);Module["FS_createPath"]("/resources/shaders","glsl100",true,true);Module["FS_createPath"]("/resources/shaders","glsl330",true,true);function DataRequest(start,end,audio){this.start=start;this.end=end;this.audio=audio}DataRequest.prototype={requests:{},open:function(mode,name){this.name=name;this.requests[name]=this;Module["addRunDependency"]("fp "+this.name)},send:function(){},onload:function(){var byteArray=this.byteArray.subarray(this.start,this.end);this.finish(byteArray)},finish:function(byteArray){var that=this;Module["FS_createDataFile"](this.name,null,byteArray,true,true,true);Module["removeRunDependency"]("fp "+that.name);this.requests[this.name]=null}};var files=metadata["files"];for(var i=0;i1){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",abort);quit_=function(status,toThrow){if(keepRuntimeAlive()){process["exitCode"]=status;throw 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.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){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":function(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;i=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{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&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}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"]||33554432;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}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 exitRuntime(){runtimeExited=true}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()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){{if(Module["onAbort"]){Module["onAbort"](what)}}what+="";err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 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="game.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}else{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={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["xe"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module["asm"]["ze"];addOnInit(Module["asm"]["ye"]);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)&&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={46539:function(){if((window.AudioContext||window.webkitAudioContext)===undefined){return 0}if(typeof miniaudio==="undefined"){miniaudio={};miniaudio.devices=[];miniaudio.track_device=function(device){for(var iDevice=0;iDevice0){if(miniaudio.devices[miniaudio.devices.length-1]==null){miniaudio.devices.pop()}else{break}}};miniaudio.untrack_device=function(device){for(var iDevice=0;iDevicedevice.intermediaryBufferSizeInBytes/channels/4){framesToProcess=device.intermediaryBufferSizeInBytes/channels/4}if(sendSilence){device.intermediaryBufferView.fill(0)}else{for(var iFrame=0;iFramedevice.intermediaryBufferSizeInBytes/channels/4){framesToProcess=device.intermediaryBufferSizeInBytes/channels/4}ccall("ma_device_process_pcm_frames_playback__webaudio","undefined",["number","number","number"],[pDevice,framesToProcess,device.intermediaryBuffer]);if(outputSilence){for(var iChannel=0;iChannel0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){wasmTable.get(func)()}else{wasmTable.get(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}function handleException(e){if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}var toLog=e;err("exception thrown: "+toLog);quit_(1,e)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_allocate_exception(size){return _malloc(size+16)+16}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-16;this.set_type=function(type){HEAP32[this.ptr+4>>2]=type};this.get_type=function(){return HEAP32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAP32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAP32[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_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}}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={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(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:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(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:function(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)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};function getRandomDevice(){if(typeof crypto==="object"&&typeof crypto["getRandomValues"]==="function"){var randomBuffer=new Uint8Array(1);return function(){crypto.getRandomValues(randomBuffer);return randomBuffer[0]}}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");return function(){return crypto_module["randomBytes"](1)[0]}}catch(e){}}return function(){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.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(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){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)}},flush: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)}},flush: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+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!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:function(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:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(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:function(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:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"r+":2,"w":577,"w+":578,"a":1089,"a+":1090},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(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:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(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:function(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:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=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:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};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}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(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:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(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:function(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(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(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:function(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(function(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:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(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:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;ithis.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=function(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);if(typeof Uint8Array!="undefined")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||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(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(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){FS.forceLoadFile(node);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>2]=stat.dev;HEAP32[buf+4>>2]=0;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;HEAP32[buf+32>>2]=0;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;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>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+80>>2]=tempI64[0],HEAP32[buf+84>>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)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},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},get64:function(low,high){return low}};function ___sys_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.open(stream.path,stream.flags,0,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 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14: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))abort(e);return-e.errno}}function ___sys_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd);if(size>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:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=varargs?SYSCALLS.get():0;var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function _abort(){abort()}var readAsmConstArgsArray=[];function readAsmConstArgs(sigPtr,buf){readAsmConstArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){var double=ch<105;if(double&&buf&1)buf++;readAsmConstArgsArray.push(double?HEAPF64[buf++>>1]:HEAP32[buf]);++buf}return readAsmConstArgsArray}function _emscripten_asm_const_int(code,sigPtr,argbuf){var args=readAsmConstArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}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}function getBoundingClientRect(e){return specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{"left":0,"top":0}}function _emscripten_get_element_css_size(target,width,height){target=findEventTarget(target);if(!target)return-4;var rect=getBoundingClientRect(target);HEAPF64[width>>3]=rect.width;HEAPF64[height>>3]=rect.height;return 0}function fillGamepadEventData(eventStruct,e){HEAPF64[eventStruct>>3]=e.timestamp;for(var i=0;i>3]=e.axes[i]}for(var i=0;i>3]=e.buttons[i].value}else{HEAPF64[eventStruct+i*8+528>>3]=e.buttons[i]}}for(var i=0;i>2]=e.buttons[i].pressed}else{HEAP32[eventStruct+i*4+1040>>2]=e.buttons[i]==1}}HEAP32[eventStruct+1296>>2]=e.connected;HEAP32[eventStruct+1300>>2]=e.index;HEAP32[eventStruct+8>>2]=e.axes.length;HEAP32[eventStruct+12>>2]=e.buttons.length;stringToUTF8(e.id,eventStruct+1304,64);stringToUTF8(e.mapping,eventStruct+1368,64)}function _emscripten_get_gamepad_status(index,gamepadState){if(index<0||index>=JSEvents.lastGamepadState.length)return-5;if(!JSEvents.lastGamepadState[index])return-7;fillGamepadEventData(gamepadState,JSEvents.lastGamepadState[index]);return 0}function _emscripten_get_num_gamepads(){return JSEvents.lastGamepadState.length}function __webgl_enable_ANGLE_instanced_arrays(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)};return 1}}function __webgl_enable_OES_vertex_array_object(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)};return 1}}function __webgl_enable_WEBGL_draw_buffers(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)};return 1}}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:[],stringCache:{},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;canvas.getContext=function(ver,attrs){var gl=canvas.getContextSafariWebGL2Fixed(ver,attrs);return ver=="webgl"==gl instanceof WebGLRenderingContext?gl:null}}var ctx=canvas.getContext("webgl",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_ANGLE_instanced_arrays(GLctx);__webgl_enable_OES_vertex_array_object(GLctx);__webgl_enable_WEBGL_draw_buffers(GLctx);{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 _emscripten_glActiveTexture(x0){GLctx["activeTexture"](x0)}function _emscripten_glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glBeginQueryEXT(target,id){GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.queries[id])}function _emscripten_glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _emscripten_glBindBuffer(target,buffer){GLctx.bindBuffer(target,GL.buffers[buffer])}function _emscripten_glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])}function _emscripten_glBindRenderbuffer(target,renderbuffer){GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])}function _emscripten_glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _emscripten_glBindVertexArrayOES(vao){GLctx["bindVertexArray"](GL.vaos[vao])}function _emscripten_glBlendColor(x0,x1,x2,x3){GLctx["blendColor"](x0,x1,x2,x3)}function _emscripten_glBlendEquation(x0){GLctx["blendEquation"](x0)}function _emscripten_glBlendEquationSeparate(x0,x1){GLctx["blendEquationSeparate"](x0,x1)}function _emscripten_glBlendFunc(x0,x1){GLctx["blendFunc"](x0,x1)}function _emscripten_glBlendFuncSeparate(x0,x1,x2,x3){GLctx["blendFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glBufferData(target,size,data,usage){GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}function _emscripten_glBufferSubData(target,offset,size,data){GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _emscripten_glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _emscripten_glClear(x0){GLctx["clear"](x0)}function _emscripten_glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _emscripten_glClearDepthf(x0){GLctx["clearDepth"](x0)}function _emscripten_glClearStencil(x0){GLctx["clearStencil"](x0)}function _emscripten_glColorMask(red,green,blue,alpha){GLctx.colorMask(!!red,!!green,!!blue,!!alpha)}function _emscripten_glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _emscripten_glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCopyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexSubImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_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 _emscripten_glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _emscripten_glCullFace(x0){GLctx["cullFace"](x0)}function _emscripten_glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null}}function _emscripten_glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _emscripten_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 _emscripten_glDeleteQueriesEXT(n,ids){for(var i=0;i>2];var query=GL.queries[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.queries[id]=null}}function _emscripten_glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}function _emscripten_glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _emscripten_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 _emscripten_glDeleteVertexArraysOES(n,vaos){for(var i=0;i>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDepthFunc(x0){GLctx["depthFunc"](x0)}function _emscripten_glDepthMask(flag){GLctx.depthMask(!!flag)}function _emscripten_glDepthRangef(x0,x1){GLctx["depthRange"](x0,x1)}function _emscripten_glDetachShader(program,shader){GLctx.detachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glDisable(x0){GLctx["disable"](x0)}function _emscripten_glDisableVertexAttribArray(index){GLctx.disableVertexAttribArray(index)}function _emscripten_glDrawArrays(mode,first,count){GLctx.drawArrays(mode,first,count)}function _emscripten_glDrawArraysInstancedANGLE(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}var tempFixedLengthArray=[];function _emscripten_glDrawBuffersWEBGL(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawElements(mode,count,type,indices){GLctx.drawElements(mode,count,type,indices)}function _emscripten_glDrawElementsInstancedANGLE(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glEnable(x0){GLctx["enable"](x0)}function _emscripten_glEnableVertexAttribArray(index){GLctx.enableVertexAttribArray(index)}function _emscripten_glEndQueryEXT(target){GLctx.disjointTimerQueryExt["endQueryEXT"](target)}function _emscripten_glFinish(){GLctx["finish"]()}function _emscripten_glFlush(){GLctx["flush"]()}function _emscripten_glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _emscripten_glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _emscripten_glFrontFace(x0){GLctx["frontFace"](x0)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _emscripten_glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _emscripten_glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _emscripten_glGenQueriesEXT(n,ids){for(var i=0;i>2]=0;return}var id=GL.getNewId(GL.queries);query.name=id;GL.queries[id]=query;HEAP32[ids+i*4>>2]=id}}function _emscripten_glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _emscripten_glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _emscripten_glGenVertexArraysOES(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function __glGetActiveAttribOrUniform(funcName,program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}}function _emscripten_glGetActiveAttrib(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}function _emscripten_glGetActiveUniform(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}function _emscripten_glGetAttachedShaders(program,maxCount,count,shaders){var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>2]=len;for(var i=0;i>2]=id}}function _emscripten_glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function writeI53ToI64(ptr,num){HEAPU32[ptr>>2]=num;HEAPU32[ptr+4>>2]=(num-HEAPU32[ptr>>2])/4294967296}function emscriptenWebGLGet(name_,p,type){if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>2]=result[i];break;case 2:HEAPF32[p+i*4>>2]=result[i];break;case 4:HEAP8[p+i>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Unknown object returned from WebGL getParameter("+name_+")! (error: "+e+")");return}}break;default:GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Native code calling glGet"+type+"v("+name_+") and it returns "+result+" of type "+typeof result+"!");return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>2]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _emscripten_glGetBooleanv(name_,p){emscriptenWebGLGet(name_,p,4)}function _emscripten_glGetBufferParameteriv(target,value,data){if(!data){GL.recordError(1281);return}HEAP32[data>>2]=GLctx.getBufferParameter(target,value)}function _emscripten_glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function _emscripten_glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _emscripten_glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>2]=result}function _emscripten_glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _emscripten_glGetProgramInfoLog(program,maxLength,length,infoLog){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i>2]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i>2]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i>2]=program.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(program,pname)}}function _emscripten_glGetQueryObjecti64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;{param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryObjectui64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;{param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectuivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryivEXT(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}function _emscripten_glGetRenderbufferParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getRenderbufferParameter(target,pname)}function _emscripten_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 _emscripten_glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>2]=result.rangeMin;HEAP32[range+4>>2]=result.rangeMax;HEAP32[precision>>2]=result.precision}function _emscripten_glGetShaderSource(shader,bufSize,length,source){var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function stringToNewUTF8(jsString){var length=lengthBytesUTF8(jsString)+1;var cString=_malloc(length);stringToUTF8(jsString,cString,length);return cString}function _emscripten_glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s&&stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _emscripten_glGetTexParameterfv(target,pname,params){if(!params){GL.recordError(1281);return}HEAPF32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTexParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getTexParameter(target,pname)}function jstoi_q(str){return parseInt(str)}function webglGetLeftBracePos(name){return name.slice(-1)=="]"&&name.lastIndexOf("[")}function webglPrepareUniformLocationsBeforeFirstUse(program){var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex0?"["+webglLoc+"]":""))}return webglLoc}else{GL.recordError(1282)}}function emscriptenWebGLGetUniform(program,location,params,type){if(!params){GL.recordError(1281);return}program=GL.programs[program];webglPrepareUniformLocationsBeforeFirstUse(program);var data=GLctx.getUniform(program,webglGetUniformLocation(location));if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break}}}}function _emscripten_glGetUniformfv(program,location,params){emscriptenWebGLGetUniform(program,location,params,2)}function _emscripten_glGetUniformiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function _emscripten_glGetVertexAttribPointerv(index,pname,pointer){if(!pointer){GL.recordError(1281);return}HEAP32[pointer>>2]=GLctx.getVertexAttribOffset(index,pname)}function emscriptenWebGLGetVertexAttrib(index,pname,params,type){if(!params){GL.recordError(1281);return}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>2]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break;case 5:HEAP32[params>>2]=Math.fround(data);break}}else{for(var i=0;i>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;case 5:HEAP32[params+i*4>>2]=Math.fround(data[i]);break}}}}function _emscripten_glGetVertexAttribfv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,2)}function _emscripten_glGetVertexAttribiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,5)}function _emscripten_glHint(x0,x1){GLctx["hint"](x0,x1)}function _emscripten_glIsBuffer(buffer){var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)}function _emscripten_glIsEnabled(x0){return GLctx["isEnabled"](x0)}function _emscripten_glIsFramebuffer(framebuffer){var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)}function _emscripten_glIsProgram(program){program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)}function _emscripten_glIsQueryEXT(id){var query=GL.queries[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)}function _emscripten_glIsRenderbuffer(renderbuffer){var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)}function _emscripten_glIsShader(shader){var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)}function _emscripten_glIsTexture(id){var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)}function _emscripten_glIsVertexArrayOES(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glLineWidth(x0){GLctx["lineWidth"](x0)}function _emscripten_glLinkProgram(program){program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}}function _emscripten_glPixelStorei(pname,param){if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)}function _emscripten_glPolygonOffset(x0,x1){GLctx["polygonOffset"](x0,x1)}function _emscripten_glQueryCounterEXT(id,target){GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.queries[id],target)}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};return colorChannels[format-6402]||1}function heapObjectForWebGLType(type){type-=5120;if(type==1)return HEAPU8;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922)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 _emscripten_glReadPixels(x,y,width,height,format,type,pixels){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 _emscripten_glReleaseShaderCompiler(){}function _emscripten_glRenderbufferStorage(x0,x1,x2,x3){GLctx["renderbufferStorage"](x0,x1,x2,x3)}function _emscripten_glSampleCoverage(value,invert){GLctx.sampleCoverage(value,!!invert)}function _emscripten_glScissor(x0,x1,x2,x3){GLctx["scissor"](x0,x1,x2,x3)}function _emscripten_glShaderBinary(){GL.recordError(1280)}function _emscripten_glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _emscripten_glStencilFunc(x0,x1,x2){GLctx["stencilFunc"](x0,x1,x2)}function _emscripten_glStencilFuncSeparate(x0,x1,x2,x3){GLctx["stencilFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glStencilMask(x0){GLctx["stencilMask"](x0)}function _emscripten_glStencilMaskSeparate(x0,x1){GLctx["stencilMaskSeparate"](x0,x1)}function _emscripten_glStencilOp(x0,x1,x2){GLctx["stencilOp"](x0,x1,x2)}function _emscripten_glStencilOpSeparate(x0,x1,x2,x3){GLctx["stencilOpSeparate"](x0,x1,x2,x3)}function _emscripten_glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _emscripten_glTexParameterf(x0,x1,x2){GLctx["texParameterf"](x0,x1,x2)}function _emscripten_glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _emscripten_glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _emscripten_glTexParameteriv(target,pname,params){var param=HEAP32[params>>2];GLctx.texParameteri(target,pname,param)}function _emscripten_glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _emscripten_glUniform1f(location,v0){GLctx.uniform1f(webglGetUniformLocation(location),v0)}var miniTempWebGLFloatBuffers=[];function _emscripten_glUniform1fv(location,count,value){if(count<=288){var view=miniTempWebGLFloatBuffers[count-1];for(var i=0;i>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform1i(location,v0){GLctx.uniform1i(webglGetUniformLocation(location),v0)}var __miniTempWebGLIntBuffers=[];function _emscripten_glUniform1iv(location,count,value){if(count<=288){var view=__miniTempWebGLIntBuffers[count-1];for(var i=0;i>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform2f(location,v0,v1){GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)}function _emscripten_glUniform2fv(location,count,value){if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform2i(location,v0,v1){GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)}function _emscripten_glUniform2iv(location,count,value){if(count<=144){var view=__miniTempWebGLIntBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform3f(location,v0,v1,v2){GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)}function _emscripten_glUniform3fv(location,count,value){if(count<=96){var view=miniTempWebGLFloatBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform3i(location,v0,v1,v2){GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)}function _emscripten_glUniform3iv(location,count,value){if(count<=96){var view=__miniTempWebGLIntBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)}function _emscripten_glUniform4fv(location,count,value){if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform4i(location,v0,v1,v2,v3){GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)}function _emscripten_glUniform4iv(location,count,value){if(count<=72){var view=__miniTempWebGLIntBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}function _emscripten_glUniformMatrix2fv(location,count,transpose,value){if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}function _emscripten_glUniformMatrix3fv(location,count,transpose,value){if(count<=32){var view=miniTempWebGLFloatBuffers[9*count-1];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*36>>2)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}function _emscripten_glUniformMatrix4fv(location,count,transpose,value){if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}function _emscripten_glUseProgram(program){program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program}function _emscripten_glValidateProgram(program){GLctx.validateProgram(GL.programs[program])}function _emscripten_glVertexAttrib1f(x0,x1){GLctx["vertexAttrib1f"](x0,x1)}function _emscripten_glVertexAttrib1fv(index,v){GLctx.vertexAttrib1f(index,HEAPF32[v>>2])}function _emscripten_glVertexAttrib2f(x0,x1,x2){GLctx["vertexAttrib2f"](x0,x1,x2)}function _emscripten_glVertexAttrib2fv(index,v){GLctx.vertexAttrib2f(index,HEAPF32[v>>2],HEAPF32[v+4>>2])}function _emscripten_glVertexAttrib3f(x0,x1,x2,x3){GLctx["vertexAttrib3f"](x0,x1,x2,x3)}function _emscripten_glVertexAttrib3fv(index,v){GLctx.vertexAttrib3f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2])}function _emscripten_glVertexAttrib4f(x0,x1,x2,x3,x4){GLctx["vertexAttrib4f"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttrib4fv(index,v){GLctx.vertexAttrib4f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2],HEAPF32[v+12>>2])}function _emscripten_glVertexAttribDivisorANGLE(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribPointer(index,size,type,normalized,stride,ptr){GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _emscripten_glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;abortOnCannotGrowMemory(requestedSize)}function _emscripten_run_script(ptr){eval(UTF8ToString(ptr))}function _emscripten_sample_gamepad_data(){return(JSEvents.lastGamepadState=navigator.getGamepads?navigator.getGamepads():navigator.webkitGetGamepads?navigator.webkitGetGamepads():null)?0:-1}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 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(wasmTable.get(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_click_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerMouseEventCallback(target,userData,useCapture,callbackfunc,4,"click",targetThread);return 0}function registerGamepadEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.gamepadEvent)JSEvents.gamepadEvent=_malloc(1432);var gamepadEventHandlerFunc=function(ev){var e=ev||event;var gamepadEvent=JSEvents.gamepadEvent;fillGamepadEventData(gamepadEvent,e["gamepad"]);if(wasmTable.get(callbackfunc)(eventTypeId,gamepadEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:gamepadEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_gamepadconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){if(!navigator.getGamepads&&!navigator.webkitGetGamepads)return-1;registerGamepadEventCallback(2,userData,useCapture,callbackfunc,26,"gamepadconnected",targetThread);return 0}function _emscripten_set_gamepaddisconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){if(!navigator.getGamepads&&!navigator.webkitGetGamepads)return-1;registerGamepadEventCallback(2,userData,useCapture,callbackfunc,27,"gamepaddisconnected",targetThread);return 0}function callUserCallback(func,synchronous){if(ABORT){return}if(synchronous){func();return}try{func()}catch(e){handleException(e)}}function safeSetTimeout(func,timeout){return setTimeout(function(){callUserCallback(func)},timeout)}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=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"]||function(){};canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||function(){};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",function(ev){if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},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:1};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"]?function(){canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null)||(canvasContainer["webkitRequestFullScreen"]?function(){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/h0){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 _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){var browserIterationFunc=wasmTable.get(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)}function registerUiEventCallback(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread){if(!JSEvents.uiEvent)JSEvents.uiEvent=_malloc(36);target=findEventTarget(target);var uiEventHandlerFunc=function(ev){var e=ev||event;if(e.target!=target){return}var b=document.body;if(!b){return}var uiEvent=JSEvents.uiEvent;HEAP32[uiEvent>>2]=e.detail;HEAP32[uiEvent+4>>2]=b.clientWidth;HEAP32[uiEvent+8>>2]=b.clientHeight;HEAP32[uiEvent+12>>2]=innerWidth;HEAP32[uiEvent+16>>2]=innerHeight;HEAP32[uiEvent+20>>2]=outerWidth;HEAP32[uiEvent+24>>2]=outerHeight;HEAP32[uiEvent+28>>2]=pageXOffset;HEAP32[uiEvent+32>>2]=pageYOffset;if(wasmTable.get(callbackfunc)(eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)}function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",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 touches={};var 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){var 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(wasmTable.get(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_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread);return 0}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 _emscripten_thread_sleep(msecs){var start=_emscripten_get_now();while(_emscripten_get_now()-start>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}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))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _glActiveTexture(x0){GLctx["activeTexture"](x0)}function _glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _glBindBuffer(target,buffer){GLctx.bindBuffer(target,GL.buffers[buffer])}function _glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])}function _glBindRenderbuffer(target,renderbuffer){GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])}function _glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _glBlendEquation(x0){GLctx["blendEquation"](x0)}function _glBlendFunc(x0,x1){GLctx["blendFunc"](x0,x1)}function _glBufferData(target,size,data,usage){GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}function _glBufferSubData(target,offset,size,data){GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _glClear(x0){GLctx["clear"](x0)}function _glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _glClearDepthf(x0){GLctx["clearDepth"](x0)}function _glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}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 _glCullFace(x0){GLctx["cullFace"](x0)}function _glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null}}function _glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}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 _glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[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 _glDepthFunc(x0){GLctx["depthFunc"](x0)}function _glDetachShader(program,shader){GLctx.detachShader(GL.programs[program],GL.shaders[shader])}function _glDisable(x0){GLctx["disable"](x0)}function _glDisableVertexAttribArray(index){GLctx.disableVertexAttribArray(index)}function _glDrawArrays(mode,first,count){GLctx.drawArrays(mode,first,count)}function _glDrawElements(mode,count,type,indices){GLctx.drawElements(mode,count,type,indices)}function _glEnable(x0){GLctx["enable"](x0)}function _glEnableVertexAttribArray(index){GLctx.enableVertexAttribArray(index)}function _glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _glFrontFace(x0){GLctx["frontFace"](x0)}function _glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _glGetActiveUniform(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}function _glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function _glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>2]=result}function _glGetProgramInfoLog(program,maxLength,length,infoLog){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i>2]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i>2]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i>2]=program.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(program,pname)}}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 _glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s&&stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _glGetUniformLocation(program,name){name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}function _glUniform1i(location,v0){GLctx.uniform1i(webglGetUniformLocation(location),v0)}function _glUniform1iv(location,count,value){if(count<=288){var view=__miniTempWebGLIntBuffers[count-1];for(var i=0;i>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}function _glUniform2fv(location,count,value){if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}function _glUniform2iv(location,count,value){if(count<=144){var view=__miniTempWebGLIntBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}function _glUniform3fv(location,count,value){if(count<=96){var view=miniTempWebGLFloatBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}function _glUniform3iv(location,count,value){if(count<=96){var view=__miniTempWebGLIntBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}function _glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)}function _glUniform4fv(location,count,value){if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}function _glUniform4iv(location,count,value){if(count<=72){var view=__miniTempWebGLIntBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}function _glUniformMatrix4fv(location,count,transpose,value){if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}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 GLFW_Window(id,width,height,title,monitor,share){this.id=id;this.x=0;this.y=0;this.fullscreen=false;this.storedX=0;this.storedY=0;this.width=width;this.height=height;this.storedWidth=width;this.storedHeight=height;this.title=title;this.monitor=monitor;this.share=share;this.attributes=GLFW.hints;this.inputModes={208897:212993,208898:0,208899:0};this.buttons=0;this.keys=new Array;this.domKeys=new Array;this.shouldClose=0;this.title=null;this.windowPosFunc=null;this.windowSizeFunc=null;this.windowCloseFunc=null;this.windowRefreshFunc=null;this.windowFocusFunc=null;this.windowIconifyFunc=null;this.framebufferSizeFunc=null;this.mouseButtonFunc=null;this.cursorPosFunc=null;this.cursorEnterFunc=null;this.scrollFunc=null;this.dropFunc=null;this.keyFunc=null;this.charFunc=null;this.userptr=null}var GLFW={WindowFromId:function(id){if(id<=0||!GLFW.windows)return null;return GLFW.windows[id-1]},joystickFunc:null,errorFunc:null,monitorFunc:null,active:null,windows:null,monitors:null,monitorString:null,versionString:null,initialTime:null,extensions:null,hints:null,defaultHints:{131073:0,131074:0,131075:1,131076:1,131077:1,135169:8,135170:8,135171:8,135172:8,135173:24,135174:8,135175:0,135176:0,135177:0,135178:0,135179:0,135180:0,135181:0,135182:0,135183:0,139265:196609,139266:1,139267:0,139268:0,139269:0,139270:0,139271:0,139272:0},DOMToGLFWKeyCode:function(keycode){switch(keycode){case 32:return 32;case 222:return 39;case 188:return 44;case 173:return 45;case 189:return 45;case 190:return 46;case 191:return 47;case 48:return 48;case 49:return 49;case 50:return 50;case 51:return 51;case 52:return 52;case 53:return 53;case 54:return 54;case 55:return 55;case 56:return 56;case 57:return 57;case 59:return 59;case 61:return 61;case 187:return 61;case 65:return 65;case 66:return 66;case 67:return 67;case 68:return 68;case 69:return 69;case 70:return 70;case 71:return 71;case 72:return 72;case 73:return 73;case 74:return 74;case 75:return 75;case 76:return 76;case 77:return 77;case 78:return 78;case 79:return 79;case 80:return 80;case 81:return 81;case 82:return 82;case 83:return 83;case 84:return 84;case 85:return 85;case 86:return 86;case 87:return 87;case 88:return 88;case 89:return 89;case 90:return 90;case 219:return 91;case 220:return 92;case 221:return 93;case 192:return 94;case 27:return 256;case 13:return 257;case 9:return 258;case 8:return 259;case 45:return 260;case 46:return 261;case 39:return 262;case 37:return 263;case 40:return 264;case 38:return 265;case 33:return 266;case 34:return 267;case 36:return 268;case 35:return 269;case 20:return 280;case 145:return 281;case 144:return 282;case 44:return 283;case 19:return 284;case 112:return 290;case 113:return 291;case 114:return 292;case 115:return 293;case 116:return 294;case 117:return 295;case 118:return 296;case 119:return 297;case 120:return 298;case 121:return 299;case 122:return 300;case 123:return 301;case 124:return 302;case 125:return 303;case 126:return 304;case 127:return 305;case 128:return 306;case 129:return 307;case 130:return 308;case 131:return 309;case 132:return 310;case 133:return 311;case 134:return 312;case 135:return 313;case 136:return 314;case 96:return 320;case 97:return 321;case 98:return 322;case 99:return 323;case 100:return 324;case 101:return 325;case 102:return 326;case 103:return 327;case 104:return 328;case 105:return 329;case 110:return 330;case 111:return 331;case 106:return 332;case 109:return 333;case 107:return 334;case 16:return 340;case 17:return 341;case 18:return 342;case 91:return 343;case 93:return 348;default:return-1}},getModBits:function(win){var mod=0;if(win.keys[340])mod|=1;if(win.keys[341])mod|=2;if(win.keys[342])mod|=4;if(win.keys[343])mod|=8;return mod},onKeyPress:function(event){if(!GLFW.active||!GLFW.active.charFunc)return;if(event.ctrlKey||event.metaKey)return;var charCode=event.charCode;if(charCode==0||charCode>=0&&charCode<=31)return;wasmTable.get(GLFW.active.charFunc)(GLFW.active.id,charCode)},onKeyChanged:function(keyCode,status){if(!GLFW.active)return;var key=GLFW.DOMToGLFWKeyCode(keyCode);if(key==-1)return;var repeat=status&&GLFW.active.keys[key];GLFW.active.keys[key]=status;GLFW.active.domKeys[keyCode]=status;if(!GLFW.active.keyFunc)return;if(repeat)status=2;wasmTable.get(GLFW.active.keyFunc)(GLFW.active.id,key,keyCode,status,GLFW.getModBits(GLFW.active))},onGamepadConnected:function(event){GLFW.refreshJoysticks()},onGamepadDisconnected:function(event){GLFW.refreshJoysticks()},onKeydown:function(event){GLFW.onKeyChanged(event.keyCode,1);if(event.keyCode===8||event.keyCode===9){event.preventDefault()}},onKeyup:function(event){GLFW.onKeyChanged(event.keyCode,0)},onBlur:function(event){if(!GLFW.active)return;for(var i=0;i0){if(eventButton==1){eventButton=2}else{eventButton=1}}return eventButton},onMouseenter:function(event){if(!GLFW.active)return;if(event.target!=Module["canvas"]||!GLFW.active.cursorEnterFunc)return;wasmTable.get(GLFW.active.cursorEnterFunc)(GLFW.active.id,1)},onMouseleave:function(event){if(!GLFW.active)return;if(event.target!=Module["canvas"]||!GLFW.active.cursorEnterFunc)return;wasmTable.get(GLFW.active.cursorEnterFunc)(GLFW.active.id,0)},onMouseButtonChanged:function(event,status){if(!GLFW.active)return;Browser.calculateMouseEvent(event);if(event.target!=Module["canvas"])return;var eventButton=GLFW.DOMToGLFWMouseButton(event);if(status==1){GLFW.active.buttons|=1<0?Math.max(delta,1):Math.min(delta,-1);GLFW.wheelPos+=delta;if(!GLFW.active||!GLFW.active.scrollFunc||event.target!=Module["canvas"])return;var sx=0;var sy=0;if(event.type=="mousewheel"){sx=event.wheelDeltaX;sy=event.wheelDeltaY}else{sx=event.deltaX;sy=event.deltaY}wasmTable.get(GLFW.active.scrollFunc)(GLFW.active.id,sx,sy);event.preventDefault()},onCanvasResize:function(width,height){if(!GLFW.active)return;var resizeNeeded=true;if(document["fullscreen"]||document["fullScreen"]||document["mozFullScreen"]||document["webkitIsFullScreen"]){GLFW.active.storedX=GLFW.active.x;GLFW.active.storedY=GLFW.active.y;GLFW.active.storedWidth=GLFW.active.width;GLFW.active.storedHeight=GLFW.active.height;GLFW.active.x=GLFW.active.y=0;GLFW.active.width=screen.width;GLFW.active.height=screen.height;GLFW.active.fullscreen=true}else if(GLFW.active.fullscreen==true){GLFW.active.x=GLFW.active.storedX;GLFW.active.y=GLFW.active.storedY;GLFW.active.width=GLFW.active.storedWidth;GLFW.active.height=GLFW.active.storedHeight;GLFW.active.fullscreen=false}else if(GLFW.active.width!=width||GLFW.active.height!=height){GLFW.active.width=width;GLFW.active.height=height}else{resizeNeeded=false}if(resizeNeeded){Browser.setCanvasSize(GLFW.active.width,GLFW.active.height,true);GLFW.onWindowSizeChanged();GLFW.onFramebufferSizeChanged()}},onWindowSizeChanged:function(){if(!GLFW.active)return;if(!GLFW.active.windowSizeFunc)return;wasmTable.get(GLFW.active.windowSizeFunc)(GLFW.active.id,GLFW.active.width,GLFW.active.height)},onFramebufferSizeChanged:function(){if(!GLFW.active)return;if(!GLFW.active.framebufferSizeFunc)return;wasmTable.get(GLFW.active.framebufferSizeFunc)(GLFW.active.id,GLFW.active.width,GLFW.active.height)},getTime:function(){return _emscripten_get_now()/1e3},setWindowTitle:function(winid,title){var win=GLFW.WindowFromId(winid);if(!win)return;win.title=UTF8ToString(title);if(GLFW.active.id==win.id){document.title=win.title}},setJoystickCallback:function(cbfun){GLFW.joystickFunc=cbfun;GLFW.refreshJoysticks()},joys:{},lastGamepadState:null,lastGamepadStateFrame:null,refreshJoysticks:function(){if(Browser.mainLoop.currentFrameNumber!==GLFW.lastGamepadStateFrame||!Browser.mainLoop.currentFrameNumber){GLFW.lastGamepadState=navigator.getGamepads?navigator.getGamepads():navigator.webkitGetGamepads?navigator.webkitGetGamepads:null;GLFW.lastGamepadStateFrame=Browser.mainLoop.currentFrameNumber;for(var joy=0;joy0},getCursorPos:function(winid,x,y){setValue(x,Browser.mouseX,"double");setValue(y,Browser.mouseY,"double")},getMousePos:function(winid,x,y){setValue(x,Browser.mouseX,"i32");setValue(y,Browser.mouseY,"i32")},setCursorPos:function(winid,x,y){},getWindowPos:function(winid,x,y){var wx=0;var wy=0;var win=GLFW.WindowFromId(winid);if(win){wx=win.x;wy=win.y}if(x){setValue(x,wx,"i32")}if(y){setValue(y,wy,"i32")}},setWindowPos:function(winid,x,y){var win=GLFW.WindowFromId(winid);if(!win)return;win.x=x;win.y=y},getWindowSize:function(winid,width,height){var ww=0;var wh=0;var win=GLFW.WindowFromId(winid);if(win){ww=win.width;wh=win.height}if(width){setValue(width,ww,"i32")}if(height){setValue(height,wh,"i32")}},setWindowSize:function(winid,width,height){var win=GLFW.WindowFromId(winid);if(!win)return;if(GLFW.active.id==win.id){if(width==screen.width&&height==screen.height){Browser.requestFullscreen()}else{Browser.exitFullscreen();Browser.setCanvasSize(width,height);win.width=width;win.height=height}}if(!win.windowSizeFunc)return;wasmTable.get(win.windowSizeFunc)(win.id,width,height)},createWindow:function(width,height,title,monitor,share){var i,id;for(i=0;i0)throw"glfwCreateWindow only supports one window at time currently";id=i+1;if(width<=0||height<=0)return 0;if(monitor){Browser.requestFullscreen()}else{Browser.setCanvasSize(width,height)}for(i=0;i0;if(i==GLFW.windows.length){if(useWebGL){var contextAttributes={antialias:GLFW.hints[135181]>1,depth:GLFW.hints[135173]>0,stencil:GLFW.hints[135174]>0,alpha:GLFW.hints[135172]>0};Module.ctx=Browser.createContext(Module["canvas"],true,true,contextAttributes)}else{Browser.init()}}if(!Module.ctx&&useWebGL)return 0;var win=new GLFW_Window(id,width,height,title,monitor,share);if(id-1==GLFW.windows.length){GLFW.windows.push(win)}else{GLFW.windows[id-1]=win}GLFW.active=win;return win.id},destroyWindow:function(winid){var win=GLFW.WindowFromId(winid);if(!win)return;if(win.windowCloseFunc)wasmTable.get(win.windowCloseFunc)(win.id);GLFW.windows[win.id-1]=null;if(GLFW.active.id==win.id)GLFW.active=null;for(var i=0;i>2]=ret}return ret}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["FS_unlink"]=FS.unlink;var GLctx;for(var i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i+1)}var __miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<288;++i){__miniTempWebGLIntBuffers[i]=__miniTempWebGLIntBuffersStorage.subarray(0,i+1)}Module["requestFullscreen"]=function Module_requestFullscreen(lockPointer,resizeCanvas){Browser.requestFullscreen(lockPointer,resizeCanvas)};Module["requestAnimationFrame"]=function Module_requestAnimationFrame(func){Browser.requestAnimationFrame(func)};Module["setCanvasSize"]=function Module_setCanvasSize(width,height,noUpdates){Browser.setCanvasSize(width,height,noUpdates)};Module["pauseMainLoop"]=function Module_pauseMainLoop(){Browser.mainLoop.pause()};Module["resumeMainLoop"]=function Module_resumeMainLoop(){Browser.mainLoop.resume()};Module["getUserMedia"]=function Module_getUserMedia(){Browser.getUserMedia()};Module["createContext"]=function Module_createContext(canvas,useWebGL,setInModule,webGLContextAttributes){return Browser.createContext(canvas,useWebGL,setInModule,webGLContextAttributes)};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?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 asmLibraryArg={"re":GetCanvasHeight,"se":GetCanvasWidth,"a":___assert_fail,"_":___cxa_allocate_exception,"Z":___cxa_throw,"N":___sys_fcntl64,"$a":___sys_getcwd,"bb":___sys_ioctl,"cb":___sys_open,"L":_abort,"f":_emscripten_asm_const_int,"pe":_emscripten_get_element_css_size,"je":_emscripten_get_gamepad_status,"ke":_emscripten_get_num_gamepads,"Qd":_emscripten_glActiveTexture,"Pd":_emscripten_glAttachShader,"ee":_emscripten_glBeginQueryEXT,"Od":_emscripten_glBindAttribLocation,"Nd":_emscripten_glBindBuffer,"Md":_emscripten_glBindFramebuffer,"Ld":_emscripten_glBindRenderbuffer,"Kd":_emscripten_glBindTexture,"Yd":_emscripten_glBindVertexArrayOES,"Jd":_emscripten_glBlendColor,"Id":_emscripten_glBlendEquation,"Hd":_emscripten_glBlendEquationSeparate,"Gd":_emscripten_glBlendFunc,"Ed":_emscripten_glBlendFuncSeparate,"Dd":_emscripten_glBufferData,"Cd":_emscripten_glBufferSubData,"Bd":_emscripten_glCheckFramebufferStatus,"Ad":_emscripten_glClear,"zd":_emscripten_glClearColor,"yd":_emscripten_glClearDepthf,"xd":_emscripten_glClearStencil,"wd":_emscripten_glColorMask,"vd":_emscripten_glCompileShader,"td":_emscripten_glCompressedTexImage2D,"sd":_emscripten_glCompressedTexSubImage2D,"rd":_emscripten_glCopyTexImage2D,"qd":_emscripten_glCopyTexSubImage2D,"pd":_emscripten_glCreateProgram,"od":_emscripten_glCreateShader,"nd":_emscripten_glCullFace,"md":_emscripten_glDeleteBuffers,"ld":_emscripten_glDeleteFramebuffers,"kd":_emscripten_glDeleteProgram,"ge":_emscripten_glDeleteQueriesEXT,"jd":_emscripten_glDeleteRenderbuffers,"id":_emscripten_glDeleteShader,"hd":_emscripten_glDeleteTextures,"Xd":_emscripten_glDeleteVertexArraysOES,"gd":_emscripten_glDepthFunc,"fd":_emscripten_glDepthMask,"ed":_emscripten_glDepthRangef,"dd":_emscripten_glDetachShader,"cd":_emscripten_glDisable,"bd":_emscripten_glDisableVertexAttribArray,"ad":_emscripten_glDrawArrays,"Td":_emscripten_glDrawArraysInstancedANGLE,"Ud":_emscripten_glDrawBuffersWEBGL,"$c":_emscripten_glDrawElements,"Sd":_emscripten_glDrawElementsInstancedANGLE,"_c":_emscripten_glEnable,"Zc":_emscripten_glEnableVertexAttribArray,"de":_emscripten_glEndQueryEXT,"Yc":_emscripten_glFinish,"Xc":_emscripten_glFlush,"Wc":_emscripten_glFramebufferRenderbuffer,"Vc":_emscripten_glFramebufferTexture2D,"Uc":_emscripten_glFrontFace,"Tc":_emscripten_glGenBuffers,"Rc":_emscripten_glGenFramebuffers,"he":_emscripten_glGenQueriesEXT,"Qc":_emscripten_glGenRenderbuffers,"Pc":_emscripten_glGenTextures,"Wd":_emscripten_glGenVertexArraysOES,"Sc":_emscripten_glGenerateMipmap,"Oc":_emscripten_glGetActiveAttrib,"Nc":_emscripten_glGetActiveUniform,"Mc":_emscripten_glGetAttachedShaders,"Lc":_emscripten_glGetAttribLocation,"Kc":_emscripten_glGetBooleanv,"Jc":_emscripten_glGetBufferParameteriv,"Ic":_emscripten_glGetError,"Hc":_emscripten_glGetFloatv,"Gc":_emscripten_glGetFramebufferAttachmentParameteriv,"Fc":_emscripten_glGetIntegerv,"Dc":_emscripten_glGetProgramInfoLog,"Ec":_emscripten_glGetProgramiv,"_d":_emscripten_glGetQueryObjecti64vEXT,"ae":_emscripten_glGetQueryObjectivEXT,"Zd":_emscripten_glGetQueryObjectui64vEXT,"$d":_emscripten_glGetQueryObjectuivEXT,"be":_emscripten_glGetQueryivEXT,"Cc":_emscripten_glGetRenderbufferParameteriv,"Ac":_emscripten_glGetShaderInfoLog,"zc":_emscripten_glGetShaderPrecisionFormat,"yc":_emscripten_glGetShaderSource,"Bc":_emscripten_glGetShaderiv,"xc":_emscripten_glGetString,"wc":_emscripten_glGetTexParameterfv,"vc":_emscripten_glGetTexParameteriv,"sc":_emscripten_glGetUniformLocation,"uc":_emscripten_glGetUniformfv,"tc":_emscripten_glGetUniformiv,"pc":_emscripten_glGetVertexAttribPointerv,"rc":_emscripten_glGetVertexAttribfv,"qc":_emscripten_glGetVertexAttribiv,"oc":_emscripten_glHint,"mc":_emscripten_glIsBuffer,"lc":_emscripten_glIsEnabled,"kc":_emscripten_glIsFramebuffer,"jc":_emscripten_glIsProgram,"fe":_emscripten_glIsQueryEXT,"ic":_emscripten_glIsRenderbuffer,"hc":_emscripten_glIsShader,"gc":_emscripten_glIsTexture,"Vd":_emscripten_glIsVertexArrayOES,"fc":_emscripten_glLineWidth,"ec":_emscripten_glLinkProgram,"dc":_emscripten_glPixelStorei,"cc":_emscripten_glPolygonOffset,"ce":_emscripten_glQueryCounterEXT,"bc":_emscripten_glReadPixels,"ac":_emscripten_glReleaseShaderCompiler,"$b":_emscripten_glRenderbufferStorage,"_b":_emscripten_glSampleCoverage,"Zb":_emscripten_glScissor,"Yb":_emscripten_glShaderBinary,"Xb":_emscripten_glShaderSource,"Wb":_emscripten_glStencilFunc,"Vb":_emscripten_glStencilFuncSeparate,"Ub":_emscripten_glStencilMask,"Tb":_emscripten_glStencilMaskSeparate,"Sb":_emscripten_glStencilOp,"Rb":_emscripten_glStencilOpSeparate,"Qb":_emscripten_glTexImage2D,"Pb":_emscripten_glTexParameterf,"Ob":_emscripten_glTexParameterfv,"Nb":_emscripten_glTexParameteri,"Mb":_emscripten_glTexParameteriv,"Lb":_emscripten_glTexSubImage2D,"Kb":_emscripten_glUniform1f,"Jb":_emscripten_glUniform1fv,"Ib":_emscripten_glUniform1i,"Hb":_emscripten_glUniform1iv,"Gb":_emscripten_glUniform2f,"Fb":_emscripten_glUniform2fv,"Eb":_emscripten_glUniform2i,"Db":_emscripten_glUniform2iv,"Cb":_emscripten_glUniform3f,"Bb":_emscripten_glUniform3fv,"zb":_emscripten_glUniform3i,"yb":_emscripten_glUniform3iv,"xb":_emscripten_glUniform4f,"wb":_emscripten_glUniform4fv,"vb":_emscripten_glUniform4i,"ub":_emscripten_glUniform4iv,"tb":_emscripten_glUniformMatrix2fv,"sb":_emscripten_glUniformMatrix3fv,"rb":_emscripten_glUniformMatrix4fv,"qb":_emscripten_glUseProgram,"ob":_emscripten_glValidateProgram,"nb":_emscripten_glVertexAttrib1f,"mb":_emscripten_glVertexAttrib1fv,"lb":_emscripten_glVertexAttrib2f,"kb":_emscripten_glVertexAttrib2fv,"jb":_emscripten_glVertexAttrib3f,"ib":_emscripten_glVertexAttrib3fv,"hb":_emscripten_glVertexAttrib4f,"gb":_emscripten_glVertexAttrib4fv,"Rd":_emscripten_glVertexAttribDivisorANGLE,"fb":_emscripten_glVertexAttribPointer,"db":_emscripten_glViewport,"Xa":_emscripten_memcpy_big,"Ya":_emscripten_resize_heap,"X":_emscripten_run_script,"le":_emscripten_sample_gamepad_data,"qe":_emscripten_set_canvas_element_size,"sa":_emscripten_set_click_callback_on_thread,"ma":_emscripten_set_gamepadconnected_callback_on_thread,"la":_emscripten_set_gamepaddisconnected_callback_on_thread,"Va":_emscripten_set_main_loop,"ta":_emscripten_set_resize_callback_on_thread,"na":_emscripten_set_touchcancel_callback_on_thread,"pa":_emscripten_set_touchend_callback_on_thread,"oa":_emscripten_set_touchmove_callback_on_thread,"ra":_emscripten_set_touchstart_callback_on_thread,"_a":_emscripten_thread_sleep,"W":_exit,"O":_fd_close,"ab":_fd_read,"Wa":_fd_seek,"M":_fd_write,"U":_glActiveTexture,"D":_glAttachShader,"k":_glBindAttribLocation,"b":_glBindBuffer,"g":_glBindFramebuffer,"G":_glBindRenderbuffer,"e":_glBindTexture,"Ab":_glBlendEquation,"i":_glBlendFunc,"t":_glBufferData,"x":_glBufferSubData,"Ka":_glCheckFramebufferStatus,"P":_glClear,"Q":_glClearColor,"Ua":_glClearDepthf,"Ga":_glCompileShader,"Sa":_glCompressedTexImage2D,"Ea":_glCreateProgram,"Ia":_glCreateShader,"eb":_glCullFace,"r":_glDeleteBuffers,"La":_glDeleteFramebuffers,"H":_glDeleteProgram,"Ma":_glDeleteRenderbuffers,"p":_glDeleteShader,"I":_glDeleteTextures,"pb":_glDepthFunc,"q":_glDetachShader,"A":_glDisable,"s":_glDisableVertexAttribArray,"Fd":_glDrawArrays,"ud":_glDrawElements,"T":_glEnable,"l":_glEnableVertexAttribArray,"z":_glFramebufferRenderbuffer,"o":_glFramebufferTexture2D,"Za":_glFrontFace,"u":_glGenBuffers,"Na":_glGenFramebuffers,"Qa":_glGenRenderbuffers,"K":_glGenTextures,"Ja":_glGetActiveUniform,"w":_glGetAttribLocation,"nc":_glGetFloatv,"F":_glGetFramebufferAttachmentParameteriv,"Ca":_glGetProgramInfoLog,"y":_glGetProgramiv,"Fa":_glGetShaderInfoLog,"E":_glGetShaderiv,"n":_glGetString,"v":_glGetUniformLocation,"Da":_glLinkProgram,"Ta":_glPixelStorei,"Oa":_glReadPixels,"Pa":_glRenderbufferStorage,"Ha":_glShaderSource,"J":_glTexImage2D,"R":_glTexParameterf,"c":_glTexParameteri,"Ba":_glUniform1fv,"V":_glUniform1i,"ua":_glUniform1iv,"Aa":_glUniform2fv,"xa":_glUniform2iv,"za":_glUniform3fv,"wa":_glUniform3iv,"ne":_glUniform4f,"ya":_glUniform4fv,"va":_glUniform4iv,"qa":_glUniformMatrix4fv,"m":_glUseProgram,"j":_glVertexAttribPointer,"Ra":_glViewport,"B":_glfwCreateWindow,"ia":_glfwDefaultWindowHints,"oe":_glfwDestroyWindow,"C":_glfwGetPrimaryMonitor,"h":_glfwGetTime,"ha":_glfwGetVideoModes,"ja":_glfwInit,"ue":_glfwMakeContextCurrent,"ba":_glfwSetCharCallback,"ve":_glfwSetCursorEnterCallback,"$":_glfwSetCursorPosCallback,"da":_glfwSetDropCallback,"ka":_glfwSetErrorCallback,"ca":_glfwSetKeyCallback,"aa":_glfwSetMouseButtonCallback,"we":_glfwSetScrollCallback,"ea":_glfwSetWindowFocusCallback,"fa":_glfwSetWindowIconifyCallback,"ie":_glfwSetWindowShouldClose,"ga":_glfwSetWindowSizeCallback,"me":_glfwSwapBuffers,"te":_glfwSwapInterval,"Y":_glfwTerminate,"d":_glfwWindowHint,"S":_time};var asm=createWasm();var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["ye"]).apply(null,arguments)};var _main=Module["_main"]=function(){return(_main=Module["_main"]=Module["asm"]["Ae"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["Be"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["Ce"]).apply(null,arguments)};var _ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=function(){return(_ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=Module["asm"]["De"]).apply(null,arguments)};var _ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=function(){return(_ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=Module["asm"]["Ee"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["Fe"]).apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return(stackSave=Module["stackSave"]=Module["asm"]["Ge"]).apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return(stackRestore=Module["stackRestore"]=Module["asm"]["He"]).apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return(stackAlloc=Module["stackAlloc"]=Module["asm"]["Ie"]).apply(null,arguments)};Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["FS_unlink"]=FS.unlink;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module["_main"];var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exit(ret,true);return ret}catch(e){return handleException(e)}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){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()}}Module["run"]=run;function exit(status,implicit){EXITSTATUS=status;if(keepRuntimeAlive()){}else{exitRuntime()}procExit(status)}function procExit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}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/bin/game.wasm b/bin/game.wasm new file mode 100644 index 0000000..4c726c7 Binary files /dev/null and b/bin/game.wasm differ diff --git a/bin/index.html b/bin/index.html new file mode 100644 index 0000000..1f5f3e2 --- /dev/null +++ b/bin/index.html @@ -0,0 +1,204 @@ + + + + + + + Airobics - a Ludum Dare game by mausimus + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + \ No newline at end of file diff --git a/bin/libgcc_s_dw2-1.dll b/bin/libgcc_s_dw2-1.dll new file mode 100644 index 0000000..1b79afc Binary files /dev/null and b/bin/libgcc_s_dw2-1.dll differ diff --git a/bin/libstdc++-6.dll b/bin/libstdc++-6.dll new file mode 100644 index 0000000..21f9ea6 Binary files /dev/null and b/bin/libstdc++-6.dll differ diff --git a/bin/wasm-server.py b/bin/wasm-server.py new file mode 100644 index 0000000..77aad1d --- /dev/null +++ b/bin/wasm-server.py @@ -0,0 +1,24 @@ +# Python 3 + +import sys +import socketserver +from http.server import SimpleHTTPRequestHandler + +class WasmHandler(SimpleHTTPRequestHandler): + def end_headers(self): + # Include additional response headers here. CORS for example: + #self.send_header('Access-Control-Allow-Origin', '*') + SimpleHTTPRequestHandler.end_headers(self) + + +# Python 3.7.5 adds in the WebAssembly Media Type. If this is an older +# version, add in the Media Type. +if sys.version_info < (3, 7, 5): + WasmHandler.extensions_map['.wasm'] = 'application/wasm' + + +if __name__ == '__main__': + PORT = 8080 + with socketserver.TCPServer(("", PORT), WasmHandler) as httpd: + print("Listening on port {}. Press Ctrl+C to stop.".format(PORT)) + httpd.serve_forever() diff --git a/deps/libgcc_s_dw2-1.dll b/deps/libgcc_s_dw2-1.dll new file mode 100644 index 0000000..1b79afc Binary files /dev/null and b/deps/libgcc_s_dw2-1.dll differ diff --git a/deps/libstdc++-6.dll b/deps/libstdc++-6.dll new file mode 100644 index 0000000..21f9ea6 Binary files /dev/null and b/deps/libstdc++-6.dll differ diff --git a/deps/wasm-server.py b/deps/wasm-server.py new file mode 100644 index 0000000..77aad1d --- /dev/null +++ b/deps/wasm-server.py @@ -0,0 +1,24 @@ +# Python 3 + +import sys +import socketserver +from http.server import SimpleHTTPRequestHandler + +class WasmHandler(SimpleHTTPRequestHandler): + def end_headers(self): + # Include additional response headers here. CORS for example: + #self.send_header('Access-Control-Allow-Origin', '*') + SimpleHTTPRequestHandler.end_headers(self) + + +# Python 3.7.5 adds in the WebAssembly Media Type. If this is an older +# version, add in the Media Type. +if sys.version_info < (3, 7, 5): + WasmHandler.extensions_map['.wasm'] = 'application/wasm' + + +if __name__ == '__main__': + PORT = 8080 + with socketserver.TCPServer(("", PORT), WasmHandler) as httpd: + print("Listening on port {}. Press Ctrl+C to stop.".format(PORT)) + httpd.serve_forever() diff --git a/game.code-workspace b/game.code-workspace new file mode 100644 index 0000000..c254df9 --- /dev/null +++ b/game.code-workspace @@ -0,0 +1,60 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "raylib.h": "c", + "math.h": "c", + "blocks.h": "c", + "stdio.h": "c", + "*.m": "c", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "ctime": "cpp", + "list": "cpp", + "unordered_set": "cpp" + } + } +} \ No newline at end of file diff --git a/ideas.txt b/ideas.txt new file mode 100644 index 0000000..dd97291 --- /dev/null +++ b/ideas.txt @@ -0,0 +1,19 @@ + +- weather, need to avoid or big penalty or force altitude + +- map has: + - entry points + - exit points + - airways? but they don't need to be followed + - runways? + +- VIP planes +- military planes + +- you can tell a plane to: + - change direction / target + - change speed + - change altitude + - follow airway + +- score is total delays (minutes) diff --git a/landed.sfs b/landed.sfs new file mode 100644 index 0000000..34f1538 Binary files /dev/null and b/landed.sfs differ diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..4ca6bd8 --- /dev/null +++ b/make.bat @@ -0,0 +1 @@ +mingw32-make PLATFORM=PLATFORM_DESKTOP diff --git a/makeweb.bat b/makeweb.bat new file mode 100644 index 0000000..b817501 --- /dev/null +++ b/makeweb.bat @@ -0,0 +1 @@ +mingw32-make PLATFORM=PLATFORM_WEB -B diff --git a/new.sfs b/new.sfs new file mode 100644 index 0000000..9828dbb Binary files /dev/null and b/new.sfs differ diff --git a/resources/ack.ogg b/resources/ack.ogg new file mode 100644 index 0000000..63ca73c Binary files /dev/null and b/resources/ack.ogg differ diff --git a/resources/ack.wav b/resources/ack.wav new file mode 100644 index 0000000..4cc3671 Binary files /dev/null and b/resources/ack.wav differ diff --git a/resources/ack2.wav b/resources/ack2.wav new file mode 100644 index 0000000..fdf00be Binary files /dev/null and b/resources/ack2.wav differ diff --git a/resources/alert.ogg b/resources/alert.ogg new file mode 100644 index 0000000..f9db9e1 Binary files /dev/null and b/resources/alert.ogg differ diff --git a/resources/alert.wav b/resources/alert.wav new file mode 100644 index 0000000..c4dd609 Binary files /dev/null and b/resources/alert.wav differ diff --git a/resources/clouds.png b/resources/clouds.png new file mode 100644 index 0000000..684a6a0 Binary files /dev/null and b/resources/clouds.png differ diff --git a/resources/end.ogg b/resources/end.ogg new file mode 100644 index 0000000..6f0da1d Binary files /dev/null and b/resources/end.ogg differ diff --git a/resources/landed.wav b/resources/landed.wav new file mode 100644 index 0000000..c30f76a Binary files /dev/null and b/resources/landed.wav differ diff --git a/resources/music.ogg b/resources/music.ogg new file mode 100644 index 0000000..5accaf8 Binary files /dev/null and b/resources/music.ogg differ diff --git a/resources/new.wav b/resources/new.wav new file mode 100644 index 0000000..636f5e7 Binary files /dev/null and b/resources/new.wav differ diff --git a/resources/noise.ogg b/resources/noise.ogg new file mode 100644 index 0000000..ebbc643 Binary files /dev/null and b/resources/noise.ogg differ diff --git a/resources/note.wav b/resources/note.wav new file mode 100644 index 0000000..ebe3350 Binary files /dev/null and b/resources/note.wav differ diff --git a/resources/shaders/glsl100/base.fs b/resources/shaders/glsl100/base.fs new file mode 100644 index 0000000..c112642 --- /dev/null +++ b/resources/shaders/glsl100/base.fs @@ -0,0 +1,23 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// NOTE: Add here your custom variables + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture2D(texture0, fragTexCoord); + + // NOTE: Implement here your fragment shader code + + gl_FragColor = texelColor*colDiffuse; +} \ No newline at end of file diff --git a/resources/shaders/glsl100/base.vs b/resources/shaders/glsl100/base.vs new file mode 100644 index 0000000..923a859 --- /dev/null +++ b/resources/shaders/glsl100/base.vs @@ -0,0 +1,27 @@ +#version 100 + +// Input vertex attributes +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +attribute vec3 vertexNormal; +attribute vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; + +// Output vertex attributes (to fragment shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying float lineLen; +// NOTE: Add here your custom variables + +void main() +{ + // Send vertex attributes to fragment shader + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + lineLen = vertexPosition.z; + + // Calculate final vertex position + gl_Position = mvp*vec4(vec3(vertexPosition.xy, 0), 1.0); +} \ No newline at end of file diff --git a/resources/shaders/glsl100/glow.fs b/resources/shaders/glsl100/glow.fs new file mode 100644 index 0000000..542c5c6 --- /dev/null +++ b/resources/shaders/glsl100/glow.fs @@ -0,0 +1,65 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform sampler2D texture1; +uniform vec4 colDiffuse; +uniform int axis; +uniform float xs; +uniform float ys; + +// Output fragment color +const float r = 16.0; +const float rr = 256.0; +const float oneover2rr = 0.001953125; +const float boost = 0.75; +const float w0 = 0.035857934; + +vec4 gauss(int axis) +{ + vec2 pos = fragTexCoord; + + float d,w; + vec2 p=pos; + vec4 col=vec4(0.0,0.0,0.0,0.0); + if (axis==0) + { + d = xs; + p.x+=-r*d; + for (float x=-r;x<=r;x++) + { + w=w0*exp((-x*x)*oneover2rr); + col+=texture2D(texture0,p)*w; + p.x+=d; + } + } + if (axis==1) + { + d = ys; + p.y+=-r*d; + for (float y=-r;y<=r;y++) + { + w=w0*exp((-y*y)*oneover2rr); + col+=texture2D(texture0,p)*w; + p.y+=d; + } + } + return col; +} + +void main() + { + gl_FragColor = gauss(axis); + if(axis == 1) + { + vec4 texValue = texture2D(texture1, fragTexCoord); + gl_FragColor *= boost; + gl_FragColor = vec4(max(gl_FragColor.r, texValue.r), max(gl_FragColor.g, texValue.g), max(gl_FragColor.b, texValue.b), 1.0); + } + } \ No newline at end of file diff --git a/resources/shaders/glsl100/vector.fs b/resources/shaders/glsl100/vector.fs new file mode 100644 index 0000000..311f221 --- /dev/null +++ b/resources/shaders/glsl100/vector.fs @@ -0,0 +1,37 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying float lineLen; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +//out vec4 finalColor; + +void main() +{ + // Texel color fetching from texture sampler + //vec4 texelColor = texture(texture0, fragTexCoord); + //vec4 lineColor = texelColor*colDiffuse; + + //float edgeAdj = abs(fragTexCoord.y) > 0.75 ? (1.0 - ((abs(fragTexCoord.y) - 0.75) / 0.25)) : 1.0; + //float edgeDist = 0;//0.01 / lineLen;//0.25 / lineLen; // clamp(lineLen, 0, 1); + //float edgeAdj = abs(fragTexCoord.y) > (1 - edgeDist) ? (1.0 - ((abs(fragTexCoord.y) - (1 - edgeDist)) / edgeDist)) : 1.0; + + //vec4 finalColor = fragColor * (1.0 - abs(fragTexCoord.x));// * min(edgeAdj, 1); + //gl_FragColor = vec4(finalColor.xyz, 0.85); + + float edgeDist = lineLen; + float edgeAdj = abs(fragTexCoord.y) > (1.0 - edgeDist) ? (1.0 - ((abs(fragTexCoord.y) - (1.0 - edgeDist)) / edgeDist)) : 1.0; + + gl_FragColor = fragColor * (1.0 - abs(fragTexCoord.x)) * min(edgeAdj, 1.0); + + //gl_FragColor = vec4(1, 1, 1, 1); + //fragColor = vec4(1,0,0,1);//colDiffuse; +} diff --git a/resources/shaders/glsl330/base.fs b/resources/shaders/glsl330/base.fs new file mode 100644 index 0000000..f1418df --- /dev/null +++ b/resources/shaders/glsl330/base.fs @@ -0,0 +1,25 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// NOTE: Add here your custom variables + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture(texture0, fragTexCoord); + + // NOTE: Implement here your fragment shader code + + finalColor = texelColor*colDiffuse; +} + diff --git a/resources/shaders/glsl330/base.vs b/resources/shaders/glsl330/base.vs new file mode 100644 index 0000000..7422d24 --- /dev/null +++ b/resources/shaders/glsl330/base.vs @@ -0,0 +1,28 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; + +// Output vertex attributes (to fragment shader) +out vec2 fragTexCoord; +out vec4 fragColor; +out float lineLen; + +// NOTE: Add here your custom variables + +void main() +{ + // Send vertex attributes to fragment shader + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + lineLen = vertexPosition.z; + + // Calculate final vertex position + gl_Position = mvp*vec4(vec3(vertexPosition.xy, 0), 1.0); +} \ No newline at end of file diff --git a/resources/shaders/glsl330/glow.fs b/resources/shaders/glsl330/glow.fs new file mode 100644 index 0000000..fc7366e --- /dev/null +++ b/resources/shaders/glsl330/glow.fs @@ -0,0 +1,61 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform sampler2D texture1; +uniform vec4 colDiffuse; +uniform int axis; +uniform float xs; // inverted now +uniform float ys; + +// Output fragment color +out vec4 finalColor; + +const float r = 16; +const float rr = 256; +const float oneover2rr = 0.001953125; +const float boost = 0.75; +const float w0 = 0.035857934; + +vec4 gauss(int axis) +{ + vec2 pos = fragTexCoord; + + float x,y,d,w; + vec2 p=pos; + vec4 col=vec4(0.0,0.0,0.0,0.0); + if (axis==0) for (d=xs,x=-r,p.x+=x*d;x<=r;x++,p.x+=d){ w=w0*exp((-x*x)*oneover2rr); col+=texture(texture0,p)*w; } + if (axis==1) for (d=ys,y=-r,p.y+=y*d;y<=r;y++,p.y+=d){ w=w0*exp((-y*y)*oneover2rr); col+=texture(texture0,p)*w; } + return col; +} + +// org +/* +vec4 gauss(int axis) +{ + vec2 pos = fragTexCoord; + + float x,y,rr=r*r,d,w,w0; + vec2 p=pos; + vec4 col=vec4(0.0,0.0,0.0,0.0); + w0=0.5135/pow(r,0.96); + if (axis==0) for (d=1.0/xs,x=-r,p.x+=x*d;x<=r;x++,p.x+=d){ w=w0*exp((-x*x)/(2.0*rr)); col+=texture(texture0,p)*w; } + if (axis==1) for (d=1.0/ys,y=-r,p.y+=y*d;y<=r;y++,p.y+=d){ w=w0*exp((-y*y)/(2.0*rr)); col+=texture(texture0,p)*w; } + return col; +} +*/ + +void main() + { + finalColor = gauss(axis); + if(axis == 1) + { + vec4 texValue = texture(texture1, fragTexCoord); + finalColor *= boost; + finalColor = vec4(max(finalColor.r, texValue.r), max(finalColor.g, texValue.g), max(finalColor.b, texValue.b), 1); + } + } diff --git a/resources/shaders/glsl330/vector.fs b/resources/shaders/glsl330/vector.fs new file mode 100644 index 0000000..3d23555 --- /dev/null +++ b/resources/shaders/glsl330/vector.fs @@ -0,0 +1,21 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; +in float lineLen; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + float edgeDist = lineLen; + float edgeAdj = abs(fragTexCoord.y) > (1 - edgeDist) ? (1.0 - ((abs(fragTexCoord.y) - (1 - edgeDist)) / edgeDist)) : 1.0; + + finalColor = fragColor * (1 - abs(fragTexCoord.x)) * min(edgeAdj, 1); +} diff --git a/resources/sound.ogg b/resources/sound.ogg new file mode 100644 index 0000000..9c92c90 Binary files /dev/null and b/resources/sound.ogg differ diff --git a/resources/start.ogg b/resources/start.ogg new file mode 100644 index 0000000..72fb8f6 Binary files /dev/null and b/resources/start.ogg differ diff --git a/resources/tick.ogg b/resources/tick.ogg new file mode 100644 index 0000000..5363dbd Binary files /dev/null and b/resources/tick.ogg differ diff --git a/resources/win.ogg b/resources/win.ogg new file mode 100644 index 0000000..b9d9170 Binary files /dev/null and b/resources/win.ogg differ diff --git a/src/AirGame.cpp b/src/AirGame.cpp new file mode 100644 index 0000000..61dd4cc --- /dev/null +++ b/src/AirGame.cpp @@ -0,0 +1,584 @@ +#include "AirGame.h" +#include "SelectScreen.h" +#include "GameScreen.h" + +float NormalizeAngle(float a) +{ + while(a < 0) + { + a += twopi; + } + while(a >= twopi) + { + a -= twopi; + } + return a; +} + +float AngleDist(float a1, float a2) +{ + return std::min(twopi - fabs(a1 - a2), fabs(a1 - a2)); +} + +AirGame::AirGame() : Game() +{ + timeScale = 1; + m_noise = false; +} + +void AirGame::CreateScreens() +{ + //int sn = 0; + m_screens.push_back(new SelectScreen(0, this)); + m_screens.push_back(new GameScreen(1, this)); +} + +void AirGame::OnStart(double totalTime) +{ + noiseMusic = LoadMusicStream("resources/noise.ogg"); + //newSound = LoadSound("resources/new.wav"); +} + +void AirGame::OnTick(double deltaTime, double totalTime) +{ + UpdateMusicStream(noiseMusic); + if(m_noise && !IsMusicStreamPlaying(noiseMusic)) + { + PlayMusicStream(noiseMusic); + } else if(!m_noise && IsMusicStreamPlaying(noiseMusic)) + { + StopMusicStream(noiseMusic); + } + + _gt = totalTime; + + m_flashOn = ((int)totalTime) % 2 == 0; + + if(m_activeScreen->m_no == 0) + return; + + if(m_gameOver) + return; + + //deltaTime *= TIME_SCALE; + //totalTime *= TIME_SCALE; + int prevGameTime = m_gameTime; + m_gameTime = static_cast(totalTime - m_startTime); + + if(m_gameTime / SPAWN_PAUSE != prevGameTime / SPAWN_PAUSE) + { + board->SpawnPlane(totalTime, m_gameTime); + } + + if(m_gameTime / AREA_PAUSE != prevGameTime / AREA_PAUSE) + { + board->SpawnArea(totalTime); + } + + for(auto a : board->areas) + { + a->Tick(totalTime); + } + + for(auto p1 : board->planes) + { + p1->Tick(deltaTime); + if(p1->incoming && p1->mode != PlaneMode::Exited && totalTime - p1->started > SPAWN_TIME) + { + // only if we'd not be under alert + bool alert = false; + for(auto p2 : board->planes) + { + if(p1->id != p2->id && p2->mode != PlaneMode::Exited) + { + if(p1->type != PlaneType::Military || p2->type != PlaneType::Military) // Military can't alert each other + { + float dx = p2->position.x - p1->position.x; + float dy = p2->position.y - p1->position.y; + if(fabsf(dx) < PLANE_ALERT_DIST * 1.5f && fabsf(dy) < PLANE_ALERT_DIST * 1.5f) + { + //float d = sqrt(dx * dx + dy * dy); + /*if(d < PLANE_CRASH_DIST) + { + // crash! + } + else*/ + //if(d < PLANE_ALERT_DIST * 1.5f) // safe distance + { + alert = true; + break; + } + } + } + } + } + if(!alert) + p1->incoming = false; // launch up + } + } + + // cleanup exited planes + board->planes.remove_if([](const Plane* p) { return p->mode == PlaneMode::Exited; }); + // TODO: delete + + // cleanup areas + board->areas.remove_if([totalTime](const Area* a) { return a->endTime < totalTime; }); +} + +void AirGame::OnSwitchScreen(int prevScreen, int nextScreen) { } + +Exit* Board::FindExit(const std::string& code) +{ + for(auto e : exits) + { + if(e->code == code) + return e; + } + return nullptr; +} + +int Area::_id = 0; + +Area::Area(AreaType type, Vector2 start, float w, float h, float dx, float dy) : + id(_id++), type(type), center(start), start(start), w(w), h(h), dx(dx), dy(dy) +{ } + +void Area::Tick(double totalTime) +{ + // move + center.x = start.x + (totalTime - startTime) / (endTime - startTime) * dx; + center.y = start.y + (totalTime - startTime) / (endTime - startTime) * dy; +} + +int Exit::_id = 0; + +Exit::Exit(const std::string& code, + const std::string& name, + Vector2 location, + ExitType type, + float heading, + float width, + float length, + float tx, + float ty) : + id(_id++), + code {code}, name {name}, location {location}, type {type}, heading {heading}, width {width}, length {length}, tx {tx}, ty {ty} +{ + this->tx = -0.5f * AIRPORT_LENGTH * sin(heading); + this->ty = -0.5f * AIRPORT_LENGTH * -cos(heading); +} + +int Plane::_id = 0; + +Plane::Plane(const std::string& callSign, Vector2 position, Exit* exit, PlaneMode mode, PlaneType type) : + id(_id++), callSign {callSign}, origin {"UNK"}, position {position}, extraDelay {0}, speedScale {1.0f}, type {type}, exit {exit}, selected {false}, + entry_heading {NAN}, delay_done{false} +{ + this->heading = 0; + this->height = 10; + this->target_height = 10; + this->speed = DEFAULT_SPEED; + this->target_speed = DEFAULT_SPEED; + this->incoming = true; + if(type == PlaneType::Cargo) + { + this->speedScale = 0.6f; + } + else if(type == PlaneType::Military) + { + this->speedScale = 1.5f; + } + if(exit != nullptr) + { + this->target = exit->location; + this->directionString = std::string("r") + exit->code; + } + else + { + this->directionString = ""; + } + this->mode = mode; + this->entry = (Vector2) {NAN, NAN}; + this->previousPosition = position; + this->expTime = NAN; + this->areaSpeed = 1.0f; +} + +void Plane::TurnTowards(float target, float dt) +{ + // change heading towards a + float rtd = target - heading; + if(rtd < 0) + rtd += twopi; + if(rtd > twopi) + rtd -= twopi; + if(rtd < pi) + { + // turn right + heading += ANGLE_SPEED * dt * speedScale; + } + else + { + // turn left + heading -= ANGLE_SPEED * dt * speedScale; + } + heading = fmodf(heading, twopi); +} + +void Plane::Tick(float dt) +{ + previousPosition = position; + + if(mode == PlaneMode::Static) + return; + + if(mode == PlaneMode::Target && exit != nullptr) + { + // check if we're within target, if yes switch to destination + float dx = target.x - position.x; + float dy = target.y - position.y; + if(fabsf(dx) < TARGET_THRESH && fabsf(dy) < TARGET_THRESH) + { + mode = PlaneMode::Destination; + target = exit->location; + } + } + // update heading towards destination + if(mode == PlaneMode::Target || mode == PlaneMode::Destination) + { + // do we need to adjust our heading? + float dx = target.x - position.x; + float dy = target.y - position.y; + float a = atan2f(-dy, -dx) - pi2; + if(a < 0) + { + a += twopi; + } + if(target_heading != a) + { + target_heading = a; + } + } + + if(fabsf(AngleDist(NormalizeAngle(heading), NormalizeAngle(target_heading))) > twopi / 180.0f) + { + TurnTowards(target_heading, dt); + } + + if(speed > target_speed) + { + speed -= ACCELERATION * dt; + speed = std::max(speed, target_speed); + } + else if(speed < target_speed) + { + speed += ACCELERATION * dt; + speed = std::min(speed, target_speed); + } + + if(height > target_height) + { + height -= VERT_SPEED * dt; + height = std::max(height, target_height); + } + else if(height < target_height) + { + height += VERT_SPEED * dt; + height = std::min(height, target_height); + } + + position.x += speed * sin(heading) * dt * speedScale * areaSpeed; + position.y += speed * -cos(heading) * dt * speedScale * areaSpeed; +} + +void Plane::Touch(double totalTime) +{ + if(!std::isnan(touchTime)) + return; + + // calculate expected time since we touch first time + touchTime = totalTime; + float dx = (target.x - position.x); + float dy = (target.y - position.y); + float d = sqrt(dx * dx + dy * dy); + if(target_speed != 0) + expTime = d / (target_speed * speedScale); + else + expTime = NAN; +} + +inline float Random(float min, float max) +{ + return min + (max - min) * (rand() % 100) / 100.0f; +} + +void Board::SpawnArea(double startTime) +{ + auto type = (AreaType)(rand() % 2); + + float sx = type == AreaType::Weather ? Random(-10.0f, 10.0f) : Random(-8.0f, 8.0f); + float sy = type == AreaType::Weather ? Random(-7.0f, 7.0f) : Random(-5.0f, 5.0f); + + float dx = type == AreaType::Weather ? Random(-4.0f, 4.0f) : 0; + float dy = type == AreaType::Weather ? Random(-3.0f, 3.0f) : 0; + + float w = type == AreaType::Weather ? Random(1.0f, 3.0f) : Random(1.0f, 2.0f); + float h = type == AreaType::Weather ? Random(1.0f, 3.0f) : Random(1.0f, 2.0f); + + auto a = new Area(type, (Vector2) {sx, sy}, w, h, dx, dy); + a->startTime = startTime; + a->endTime = startTime + AREA_MIN_TIME + (AREA_MAX_TIME - AREA_MIN_TIME) * (rand() % 100) / 100.0f; + + for(auto ea : areas) + { + // no on top of each other + if(ea->IsAbove(a->center) || a->IsAbove(ea->center)) + return; + } + + if(type == AreaType::NoFly) + { + for(auto e : exits) + { + if(a->IsAbove(e->location)) // no exits within nofly + { + return; + } + } + } + + areas.push_back(a); +} + +bool Area::IsAbove(Vector2 p) +{ + return (p.x <= center.x + (w / 2)) && (p.x >= center.x - (w / 2)) && (p.y <= center.y + (h / 2)) && (p.y >= center.y - (h / 2)); +} + +void Board::SpawnPlane(double startTime, double gameTime) +{ + //return; + + //PlaySoundMulti(newSound); + + int rtype = rand() % 12; + auto type = rtype == 0 ? PlaneType::Military : (rtype == 1 ? PlaneType::VIP : (rtype < 5 ? PlaneType::Cargo : PlaneType::Passenger)); + //auto type = (PlaneType)(rand() % 4); + + if(gameTime < 60 && type == PlaneType::VIP) + type = PlaneType::Passenger; + + if(gameTime < 120 && type == PlaneType::Military) + type = PlaneType::Passenger; + + int entry = rand() % exits.size(); + int exit = rand() % exits.size(); + while(exit == entry || (type == PlaneType::Military && exits[exit]->type == ExitType::Airport)) + { + exit = rand() % exits.size(); + } + const std::string& prefix = type == PlaneType::Military ? "MX" : airlines[rand() % airlines.size()]; + const std::string callSign = prefix + std::to_string(rand() % 100); + + // move forward a bit so we don't spawn so close + Vector2 location = exits[entry]->location; + location.x += 0.5f * sin(exits[entry]->heading); + location.y += 0.5f * -cos(exits[entry]->heading); + + auto p = new Plane(callSign, location, exits[exit], PlaneMode::Destination, type); + p->heading = exits[entry]->heading; + if(p->heading < 0) + p->heading += twopi; + + p->started = startTime; + p->origin = exits[entry]->code; + if(exits[entry]->type == ExitType::Exit) + { + p->heading += pi; // came out of a corridor + if(p->heading >= twopi) + p->heading -= twopi; + + // also shake position a bit? + float shakeHeading = p->heading + pi2; // 90 deg angle + p->position.x += 2.0f * sin(shakeHeading); + p->position.y += 2.0f * -cos(shakeHeading); + } + + p->touchTime = NAN; + + planes.push_back(p); +} + +float Plane::Delay(double totalTime) +{ + if(delay_done) + return 0; + + if(type == PlaneType::Military) + return 0; + + if(std::isnan(touchTime) || std::isnan(expTime)) + return extraDelay; + + auto d = (float)((totalTime - touchTime) - expTime) * (type == PlaneType::VIP ? 3 : 1); + return d + extraDelay; +} + +float Plane::ExpDelay(double totalTime) +{ + if(delay_done) + return 0; + + if(type == PlaneType::Military) + return 0; + + if(mode == PlaneMode::Exited || mode == PlaneMode::Static) + return 0; + + if(std::isnan(touchTime) || exit == nullptr || std::isnan(expTime)) + return extraDelay; + + // calculate expected time + float remTime = 0; + if(target_speed != 0 && speedScale != 0) + { + float dx = exit->location.x - position.x; + float dy = exit->location.y - position.y; + float d = sqrt(dx * dx + dy * dy); + remTime = d / (target_speed * speedScale); + } + + return extraDelay + ((totalTime + remTime) - (touchTime + expTime)) * (type == PlaneType::VIP ? 3 : 1); +} + +Board::Board(Map m) +{ + if(m != Map::None) + { + airlines.push_back("AB"); + airlines.push_back("CD"); + airlines.push_back("EF"); + airlines.push_back("GH"); + airlines.push_back("IJ"); + airlines.push_back("KL"); + airlines.push_back("MN"); + airlines.push_back("OP"); + airlines.push_back("QR"); + airlines.push_back("ST"); + + exits.push_back(new Exit {"NORTH", "NORTH EXIT", (Vector2) {0, -8.5f}, ExitType::Exit, 0, CORRIDOR_WIDTH, CORRIDOR_LENGTH}); + exits.push_back(new Exit {"SOUTH", "SOUTH EXIT", (Vector2) {0, 8.5}, ExitType::Exit, -pi, CORRIDOR_WIDTH, CORRIDOR_LENGTH}); + exits.push_back(new Exit {"EAST", "EAST EXIT", (Vector2) {10.5f, 0}, ExitType::Exit, pi2, CORRIDOR_WIDTH, CORRIDOR_LENGTH}); + exits.push_back(new Exit {"WEST", "WEST EXIT", (Vector2) {-10.5f, 0}, ExitType::Exit, 3 * pi2, CORRIDOR_WIDTH, CORRIDOR_LENGTH}); + } + if(m == Map::Tokyo || m == Map::None) + { + exits.push_back(new Exit { + "NRT", "Narita", (Vector2) {9.0f - 4.0f, -2.0f + 2.0f}, ExitType::Airport, -0.4f + twopi, AIRPORT_WIDTH, AIRPORT_LENGTH}); + exits.push_back(new Exit { + "HND", "Haneda", (Vector2) {-1.0f - 2.0f, 2.0f + 2.0f}, ExitType::Airport, 0.4f + twopi, AIRPORT_WIDTH, AIRPORT_LENGTH}); + exits.push_back(new Exit {"IBR", + "Ibaraki", + (Vector2) {9.5f - 4.0f, -7.0f + 1.0f}, + ExitType::Airport, + 0.2f, + AIRPORT_WIDTH / 2.0f, + AIRPORT_LENGTH}); // Ibaraki + exits.push_back(new Exit {"OKO", + "Yokota", + (Vector2) {-4.0f - 2.0f, -2.0f}, + ExitType::Airport, + -0.2f + twopi, + AIRPORT_WIDTH / 2.0f, + AIRPORT_LENGTH}); // Yokota + } + if(m == Map::SF || m == Map::None) + { + exits.push_back( + new Exit {"SFO", "San Francisco", (Vector2) {-2.5f - 2.0f, -1.25f}, ExitType::Airport, 1.75f, AIRPORT_WIDTH, AIRPORT_LENGTH}); + exits.push_back(new Exit {"OAK", "Oakland", (Vector2) {1.5f - 2.4f, -4.75f}, ExitType::Airport, 2.9f, AIRPORT_WIDTH, AIRPORT_LENGTH}); + exits.push_back( + new Exit {"SJC", "San Jose", (Vector2) {7.5f - 2.0f, 5.7f}, ExitType::Airport, -0.2f + twopi, AIRPORT_WIDTH / 2.0f, AIRPORT_LENGTH}); + } + if(m == Map::London || m == Map::None) + { + exits.push_back(new Exit {"LHR", "Heathrow", (Vector2) {-5.2f, 1.6f}, ExitType::Airport, 1.75f, AIRPORT_WIDTH, AIRPORT_LENGTH}); + + exits.push_back(new Exit {"LCY", "City", (Vector2) {0.75f, 0.5f}, ExitType::Airport, 2.9f, AIRPORT_WIDTH, AIRPORT_LENGTH}); + + exits.push_back( + new Exit {"LGW", "Gatwick", (Vector2) {-1.5f, 6.7f}, ExitType::Airport, -0.2f + twopi, AIRPORT_WIDTH / 2.0f, AIRPORT_LENGTH}); + + exits.push_back(new Exit {"LTN", "Luton", (Vector2) {-4.0f, -6.7f}, ExitType::Airport, 2.7f, AIRPORT_WIDTH / 2.0f, AIRPORT_LENGTH}); + + exits.push_back( + new Exit {"STN", "Stansted", (Vector2) {3.75f, -6.7f}, ExitType::Airport, 4.0f, AIRPORT_WIDTH / 2.0f, AIRPORT_LENGTH}); + } +} + +Vector2 Exit::LocalPos(Vector2 modelPos) +{ + float s = sin(-heading); + float c = cos(-heading); + float dx = modelPos.x - location.x; + float dy = modelPos.y - location.y; + float rx = dx * c - dy * s; + float ry = dx * s + dy * c; + return (Vector2) {rx, ry}; +} + +bool Exit::IsAbove(Vector2 p) +{ + auto localPos = LocalPos(p); + return fabsf(localPos.x) <= width / 2 && localPos.y <= 0 && localPos.y >= -length / 2; +} + +bool Exit::GoodPass(Vector2 entry, Vector2 exit, float entry_heading) +{ + float a1 = NormalizeAngle(heading); + float a2 = NormalizeAngle(entry_heading); + + // OK if we entered within 90 degs + auto adiff = AngleDist(a1, a2); + return adiff < pi2; +} + +void AirGame::StartMap(Map m) +{ + m_map = m; + board = new Board(m); + timeScale = 1; + + switch (m) + { + case Map::SF: + SPAWN_PAUSE = 11; + break; + + case Map::Tokyo: + SPAWN_PAUSE = 9; + break; + + case Map::London: + SPAWN_PAUSE = 6; + break; + + default: + break; + } + + SwitchScreen(1); + + m_startTime = _gt; + m_gameOver = false; + m_winner = false; + m_selection = true; + board->SpawnPlane(_gt, 0); + //board->SpawnArea(_gt); +} + +void AirGame::SelectMap() +{ + timeScale = 1; + SwitchScreen(0); +} \ No newline at end of file diff --git a/src/AirGame.h b/src/AirGame.h new file mode 100644 index 0000000..1d71250 --- /dev/null +++ b/src/AirGame.h @@ -0,0 +1,304 @@ +#pragma once + +#include "Game.h" + +#define C_AMBER1 \ + CLITERAL(Color) \ + { \ + 255, 204, 0, 255 \ + } +#define C_AMBER2 \ + CLITERAL(Color) \ + { \ + 255, 176, 0, 255 \ + } +#define C_AMBER3 \ + CLITERAL(Color) \ + { \ + 127, 78, 0, 255 \ + } + +#define C_GREEN1 \ + CLITERAL(Color) \ + { \ + 0, 255, 51, 255 \ + } +#define C_GREEN3 \ + CLITERAL(Color) \ + { \ + 0, 127, 25, 255 \ + } + +#define C_BLUE0 \ + CLITERAL(Color) \ + { \ + 200, 240, 255, 255 \ + } +#define C_BLUE1 \ + CLITERAL(Color) \ + { \ + 82, 198, 255, 255 \ + } +#define C_BLUE2 \ + CLITERAL(Color) \ + { \ + 63, 150, 191, 255 \ + } +#define C_BLUE3 \ + CLITERAL(Color) \ + { \ + 42, 100, 127, 255 \ + } +#define C_BLUE4 \ + CLITERAL(Color) \ + { \ + 21, 50, 63, 255 \ + } +#define C_BLUE45 \ + CLITERAL(Color) \ + { \ + 14, 35, 40, 255 \ + } +#define C_BLUE5 \ + CLITERAL(Color) \ + { \ + 8, 20, 25, 255 \ + } + +#define C_WHITE1 \ + CLITERAL(Color) \ + { \ + 0xff, 0xff, 0xff, 255 \ + } +#define C_WHITE2 \ + CLITERAL(Color) \ + { \ + 0xaa, 0xaa, 0xaa, 255 \ + } +#define C_WHITE3 \ + CLITERAL(Color) \ + { \ + 0x55, 0x55, 0x55, 255 \ + } + +#define C_RED \ + CLITERAL(Color) \ + { \ + 252, 84, 116, 255 \ + } +#define C_VIP \ + CLITERAL(Color) \ + { \ + 245, 166, 0, 255 \ + } +#define C_MIL \ + CLITERAL(Color) \ + { \ + 84, 190, 98, 255 \ + } + +constexpr float AIRPORT_WIDTH = 0.3f; +constexpr float AIRPORT_LENGTH = 0.75f; +constexpr float CORRIDOR_WIDTH = 2.5f; +constexpr float CORRIDOR_LENGTH = 0.2f; +constexpr float EXIT_RADIUS = 0.2f; +constexpr float ANGLE_SPEED = 0.2f; +constexpr float VERT_SPEED = 0.1f; +constexpr float ACCELERATION = 0.1f; +constexpr float DEFAULT_SPEED = 0.1f; +constexpr double SPAWN_TIME = 20.0; // time a new plane is immune +constexpr int AREA_PAUSE = 50; +constexpr float AREA_MIN_TIME = 100; +constexpr float AREA_MAX_TIME = 300; +constexpr float TARGET_THRESH = 0.2f; +constexpr float PLANE_ALERT_DIST = 0.5f; +constexpr float PLANE_CRASH_DIST = 0.1f; + +enum class Map +{ + None = 0, + SF = 1, + Tokyo = 2, + London = 3 +}; + +enum class PlaneMode +{ + Heading = 0, + Destination = 1, + Target = 2, + Airway = 3, + Exited = 4, + Static = 5 +}; + +enum class PlaneType +{ + Passenger = 0, + Cargo = 1, + VIP = 2, + Military = 3 +}; + +enum class ExitType +{ + Exit = 0, + Airport = 1 +}; + +class Exit +{ +private: + static int _id; + + Vector4 entryLine; + Vector4 exitLine; + + Vector2 LocalPos(Vector2 modelPos); + +public: + Exit(const std::string& code, + const std::string& name, + Vector2 location, + ExitType type, + float heading, + float width, + float length, + float tx = 0, + float ty = 0); + bool IsAbove(Vector2 p); + bool GoodPass(Vector2 entry, Vector2 exit, float entry_heading); + + int id; + std::string code; + std::string name; + Vector2 location; + ExitType type; + float heading; + float width; + float length; + float tx; // text offset + float ty; +}; + +class Plane +{ +private: + static int _id; + + void TurnTowards(float target, float dt); + +public: + Plane(const std::string& callSign, Vector2 position, Exit* exit, PlaneMode mode, PlaneType type); + + void Tick(float dt); + float Delay(double totalTime); + float ExpDelay(double totalTime); + + void Touch(double totalTime); + + int id; + std::string callSign; + std::string origin; + Vector2 position; + Vector2 previousPosition; + float speed; + float target_speed; + float height; + float target_height; + float heading; + float target_heading; + float extraDelay; + float speedScale; + float areaSpeed; + Vector2 target; + PlaneMode mode; + PlaneType type; + Exit* exit; + bool selected; + bool incoming; + double started; + double touchTime; + float expTime; + std::unordered_set alerts; + std::string directionString; + Vector2 entry; + float entry_heading; + bool delay_done; +}; + +enum class AreaType +{ + NoFly = 0, + Weather = 1 +}; + +class Area +{ +private: + static int _id; + +public: + Area(AreaType type, Vector2 start, float w, float h, float dx, float dy); + + bool IsAbove(Vector2 p); + void Tick(double totalTime); + + int id; + std::string name; + AreaType type; + double startTime; + double endTime; + Vector2 center; + Vector2 start; + float w; + float h; + float dx; + float dy; +}; + +class Board +{ +public: + Board(Map m); + + Exit* FindExit(const std::string& code); + void SpawnPlane(double totalTime, double gameTime); + void SpawnArea(double totalTime); + + std::vector airlines; + std::list planes; + std::vector exits; + std::list areas; +}; + +class AirGame : public Game +{ +protected: + virtual void CreateScreens(); + virtual void OnTick(double deltaTime, double totalTime); + virtual void OnStart(double totalTime); + virtual void OnSwitchScreen(int prevScreen, int nextScreen); + +private: + double _gt; + Sound newSound; + Music noiseMusic; + int SPAWN_PAUSE = 10; + +public: + AirGame(); + void StartMap(Map m); + void SelectMap(); + + double m_startTime; + int m_gameTime; + bool m_gameOver; + bool m_winner; + bool m_flashOn; + bool m_selection; + int timeScale; + Map m_map; + bool m_noise; + Board* board; +}; \ No newline at end of file diff --git a/src/Assets.cpp b/src/Assets.cpp new file mode 100644 index 0000000..48e4d8e --- /dev/null +++ b/src/Assets.cpp @@ -0,0 +1,1357 @@ +#include "Assets.h" + +Assets::Assets() +{ + GenerateChars(); +} + +void Assets::Load() { } + +void Assets::Unload() { } + +void Assets::Render(float thick) +{ + for(const auto& c : _chars) + { + c.second->Render(thick); + } + for(const auto& c : _chars2) + { + c.second->Render(thick); + } + for(const auto& c : _chars4) + { + c.second->Render(thick); + } +} + +void Assets::AddChar(char c, VectorObject* vo) +{ + vo->Flip(0, 1); + vo->Center(); + vo->CenterY(-CHAR_MIDPOINT); + vo->Scale(CHAR_SCALE); + _chars.insert(std::pair(c, vo)); + + auto vo2 = new VectorObject(*vo); + vo2->Scale(CHAR_SCALE * 2.0f); + vo2->_width = vo->_width * 2; + _chars2.insert(std::pair(c, vo2)); + + auto vo4 = new VectorObject(*vo); + vo4->Scale(CHAR_SCALE * 4.0f); + vo4->_width = vo->_width * 4; + _chars4.insert(std::pair(c, vo4)); +} + +VectorObject* Assets::GetChar(char c, int zoom) +{ + std::map& chars = zoom == 1 ? _chars : (zoom == 2 ? _chars2 : _chars4); + const auto& fc = chars.find(c); + if(fc == chars.end()) + { + return chars.at(' '); + } + return fc->second; +} + +void Assets::GenerateChars() +{ + VectorObject* vo; + + vo = new VectorObject(); + vo->_width = 0.1f; + AddChar(' ', vo); + + vo = new VectorObject(); + vo->moveTo(0, 0); + vo->lineTo(0, 15); + vo->lineTo(3, 18); + vo->lineTo(9, 18); + vo->lineTo(12, 15); + vo->lineTo(12, 0); + vo->moveTo(0, 9); + vo->lineTo(12, 9); + AddChar('A', vo); + + vo = new VectorObject(); + vo->moveTo(18, 0); + vo->lineTo(18, 18); + vo->lineTo(27, 18); + vo->lineTo(30, 15); + vo->lineTo(30, 12); + vo->lineTo(27, 9); + vo->lineTo(18, 9); + vo->moveTo(27, 9); + vo->lineTo(30, 6); + vo->lineTo(30, 3); + vo->lineTo(27, 0); + vo->lineTo(18, 0); + AddChar('B', vo); + + vo = new VectorObject(); + vo->moveTo(48, 3); + vo->lineTo(45, 0); + vo->lineTo(39, 0); + vo->lineTo(36, 3); + vo->lineTo(36, 15); + vo->lineTo(39, 18); + vo->lineTo(45, 18); + vo->lineTo(48, 15); + AddChar('C', vo); + + vo = new VectorObject(); + vo->moveTo(54, 0); + vo->lineTo(54, 18); + vo->lineTo(63, 18); + vo->lineTo(66, 15); + vo->lineTo(66, 3); + vo->lineTo(63, 0); + vo->lineTo(54, 0); + AddChar('D', vo); + + vo = new VectorObject(); + vo->moveTo(72, 0); + vo->lineTo(72, 18); + vo->lineTo(84, 18); + vo->moveTo(72, 9); + vo->lineTo(81, 9); + vo->moveTo(72, 0); + vo->lineTo(84, 0); + AddChar('E', vo); + + vo = new VectorObject(); + vo->moveTo(90, 0); + vo->lineTo(90, 18); + vo->lineTo(102, 18); + vo->moveTo(90, 9); + vo->lineTo(99, 9); + AddChar('F', vo); + + vo = new VectorObject(); + vo->moveTo(120, 15); + vo->lineTo(117, 18); + vo->lineTo(111, 18); + vo->lineTo(108, 15); + vo->lineTo(108, 3); + vo->lineTo(111, 0); + vo->lineTo(117, 0); + vo->lineTo(120, 3); + vo->lineTo(120, 8); + vo->lineTo(113, 8); + AddChar('G', vo); + + vo = new VectorObject(); + vo->moveTo(126, 0); + vo->lineTo(126, 18); + vo->moveTo(138, 0); + vo->lineTo(138, 18); + vo->moveTo(126, 9); + vo->lineTo(138, 9); + AddChar('H', vo); + + vo = new VectorObject(); + vo->moveTo(146, 0); + vo->lineTo(154, 0); + vo->moveTo(150, 0); + vo->lineTo(150, 18); + vo->moveTo(146, 18); + vo->lineTo(154, 18); + AddChar('I', vo); + + vo = new VectorObject(); + vo->moveTo(162, 2); + vo->lineTo(165, 0); + vo->lineTo(167, 0); + vo->lineTo(170, 2); + vo->lineTo(170, 18); + vo->moveTo(166, 18); + vo->lineTo(174, 18); + AddChar('J', vo); + + vo = new VectorObject(); + vo->moveTo(180, 0); + vo->lineTo(180, 18); + vo->moveTo(192, 18); + vo->lineTo(180, 6); + vo->moveTo(183, 9); + vo->lineTo(192, 0); + AddChar('K', vo); + + vo = new VectorObject(); + vo->moveTo(198, 0); + vo->lineTo(198, 18); + vo->moveTo(198, 0); + vo->lineTo(210, 0); + AddChar('L', vo); + + vo = new VectorObject(); + vo->moveTo(216, 0); + vo->lineTo(216, 18); + vo->lineTo(222, 5); + vo->lineTo(228, 18); + vo->lineTo(228, 0); + AddChar('M', vo); + + vo = new VectorObject(); + vo->moveTo(234, 0); + vo->lineTo(234, 18); + vo->lineTo(246, 0); + vo->lineTo(246, 18); + AddChar('N', vo); + + vo = new VectorObject(); + vo->moveTo(255, 0); + vo->lineTo(252, 3); + vo->lineTo(252, 15); + vo->lineTo(255, 18); + vo->lineTo(261, 18); + vo->lineTo(264, 15); + vo->lineTo(264, 3); + vo->lineTo(261, 0); + vo->lineTo(255, 0); + AddChar('O', vo); + + vo = new VectorObject(); + vo->moveTo(270, 0); + vo->lineTo(270, 18); + vo->lineTo(279, 18); + vo->lineTo(282, 15); + vo->lineTo(282, 11); + vo->lineTo(279, 8); + vo->lineTo(270, 8); + AddChar('P', vo); + + vo = new VectorObject(); + vo->moveTo(291, 0); + vo->lineTo(288, 3); + vo->lineTo(288, 15); + vo->lineTo(291, 18); + vo->lineTo(297, 18); + vo->lineTo(300, 15); + vo->lineTo(300, 3); + vo->lineTo(297, 0); + vo->lineTo(291, 0); + vo->moveTo(295, 5); + vo->lineTo(302, -2); + AddChar('Q', vo); + + vo = new VectorObject(); + vo->moveTo(306, 0); + vo->lineTo(306, 18); + vo->lineTo(315, 18); + vo->lineTo(318, 15); + vo->lineTo(318, 11); + vo->lineTo(315, 8); + vo->lineTo(306, 8); + vo->moveTo(313, 8); + vo->lineTo(318, 0); + AddChar('R', vo); + + vo = new VectorObject(); + vo->moveTo(324, 2); + vo->lineTo(327, 0); + vo->lineTo(333, 0); + vo->lineTo(336, 3); + vo->lineTo(336, 6); + vo->lineTo(333, 9); + vo->lineTo(327, 9); + vo->lineTo(324, 12); + vo->lineTo(324, 15); + vo->lineTo(327, 18); + vo->lineTo(333, 18); + vo->lineTo(336, 16); + AddChar('S', vo); + + vo = new VectorObject(); + vo->moveTo(348, 0); + vo->lineTo(348, 18); + vo->moveTo(342, 18); + vo->lineTo(354, 18); + AddChar('T', vo); + + vo = new VectorObject(); + vo->moveTo(360, 18); + vo->lineTo(360, 3); + vo->lineTo(363, 0); + vo->lineTo(369, 0); + vo->lineTo(372, 3); + vo->lineTo(372, 18); + AddChar('U', vo); + + vo = new VectorObject(); + vo->moveTo(0, 18); + vo->lineTo(2, 0); + vo->lineTo(6, 12); + vo->lineTo(10, 0); + vo->lineTo(12, 18); + AddChar('W', vo); + + vo = new VectorObject(); + vo->moveTo(378, 18); + vo->lineTo(384, 0); + vo->lineTo(390, 18); + AddChar('V', vo); + + vo = new VectorObject(); + vo->moveTo(396, 0); + vo->lineTo(408, 18); + vo->moveTo(396, 18); + vo->lineTo(408, 0); + AddChar('X', vo); + + vo = new VectorObject(); + vo->moveTo(420, 0); + vo->lineTo(420, 7); + vo->lineTo(414, 18); + vo->moveTo(420, 7); + vo->lineTo(426, 18); + AddChar('Y', vo); + + vo = new VectorObject(); + vo->moveTo(432, 0); + vo->lineTo(444, 18); + vo->lineTo(432, 18); + vo->moveTo(444, 0); + vo->lineTo(432, 0); + AddChar('Z', vo); + + vo = new VectorObject(); + vo->moveTo(452, 3); + vo->lineTo(460, 15); + vo->moveTo(462, 12); + vo->lineTo(462, 6); + vo->lineTo(459, 0); + vo->lineTo(453, 0); + vo->lineTo(450, 6); + vo->lineTo(450, 12); + vo->lineTo(453, 18); + vo->lineTo(459, 18); + vo->lineTo(462, 12); + AddChar('0', vo); + + vo = new VectorObject(); + vo->moveTo(474, 0); + vo->lineTo(474, 18); + vo->lineTo(468, 12); + AddChar('1', vo); + + vo = new VectorObject(); + vo->moveTo(486, 15); + vo->lineTo(489, 18); + vo->lineTo(495, 18); + vo->lineTo(498, 15); + vo->lineTo(498, 11); + vo->lineTo(488, 5); + vo->lineTo(486, 0); + vo->lineTo(498, 0); + AddChar('2', vo); + + vo = new VectorObject(); + vo->moveTo(504, 16); + vo->lineTo(507, 18); + vo->lineTo(513, 18); + vo->lineTo(516, 15); + vo->lineTo(516, 11); + vo->lineTo(513, 9); + vo->lineTo(507, 9); + vo->moveTo(513, 9); + vo->lineTo(516, 7); + vo->lineTo(516, 3); + vo->lineTo(513, 0); + vo->lineTo(507, 0); + vo->lineTo(504, 2); + AddChar('3', vo); + + vo = new VectorObject(); + vo->moveTo(531, 0); + vo->lineTo(531, 18); + vo->lineTo(522, 6); + vo->lineTo(534, 6); + AddChar('4', vo); + + vo = new VectorObject(); + vo->moveTo(540, 2); + vo->lineTo(543, 0); + vo->lineTo(549, 0); + vo->lineTo(552, 2); + vo->lineTo(552, 8); + vo->lineTo(549, 10); + vo->lineTo(543, 10); + vo->lineTo(540, 9); + vo->lineTo(542, 18); + vo->lineTo(552, 18); + AddChar('5', vo); + + vo = new VectorObject(); + vo->moveTo(558, 7); + vo->lineTo(561, 10); + vo->lineTo(567, 10); + vo->lineTo(570, 7); + vo->lineTo(570, 3); + vo->lineTo(567, 0); + vo->lineTo(561, 0); + vo->lineTo(558, 3); + vo->lineTo(558, 10); + vo->lineTo(561, 15); + vo->lineTo(565, 18); + vo->lineTo(568, 18); + AddChar('6', vo); + + vo = new VectorObject(); + vo->moveTo(576, 18); + vo->lineTo(588, 18); + vo->lineTo(580, 0); + AddChar('7', vo); + + vo = new VectorObject(); + vo->moveTo(597, 10); + vo->lineTo(594, 13); + vo->lineTo(594, 16); + vo->lineTo(597, 19); + vo->lineTo(603, 19); + vo->lineTo(606, 16); + vo->lineTo(606, 13); + vo->lineTo(603, 10); + vo->lineTo(597, 10); + vo->lineTo(594, 7); + vo->lineTo(594, 3); + vo->lineTo(597, 0); + vo->lineTo(603, 0); + vo->lineTo(606, 3); + vo->lineTo(606, 7); + vo->lineTo(603, 10); + AddChar('8', vo); + + vo = new VectorObject(); + vo->moveTo(614, 0); + vo->lineTo(617, 0); + vo->lineTo(621, 3); + vo->lineTo(624, 8); + vo->lineTo(624, 15); + vo->lineTo(621, 18); + vo->lineTo(615, 18); + vo->lineTo(612, 15); + vo->lineTo(612, 11); + vo->lineTo(615, 8); + vo->lineTo(621, 8); + vo->lineTo(624, 11); + AddChar('9', vo); + + vo = new VectorObject(); + vo->moveTo(636, 1); + vo->lineTo(636, -1); + AddChar('.', vo); + + vo = new VectorObject(); + vo->moveTo(652, -4); + vo->lineTo(654, 1); + vo->lineTo(654, 1); + AddChar(',', vo); + + vo = new VectorObject(); + vo->moveTo(671, -4); + vo->lineTo(673, 0); + vo->lineTo(673, 0); + vo->moveTo(673, 10); + vo->lineTo(673, 7); + AddChar(';', vo); + + vo = new VectorObject(); + vo->moveTo(690, 2); + vo->lineTo(690, 5); + vo->moveTo(690, 11); + vo->lineTo(690, 14); + AddChar(':', vo); + + vo = new VectorObject(); + vo->moveTo(708, 2); + vo->lineTo(708, 0); + vo->moveTo(708, 5); + vo->lineTo(708, 18); + AddChar('!', vo); + + vo = new VectorObject(); + vo->moveTo(732, 2); + vo->lineTo(730, 0); + vo->lineTo(723, 0); + vo->lineTo(720, 3); + vo->lineTo(720, 15); + vo->lineTo(723, 18); + vo->lineTo(729, 18); + vo->lineTo(732, 15); + vo->lineTo(732, 6); + vo->lineTo(725, 6); + vo->lineTo(725, 13); + vo->lineTo(732, 13); + AddChar('@', vo); + + vo = new VectorObject(); + vo->moveTo(740, 0); + vo->lineTo(742, 18); + vo->moveTo(746, 0); + vo->lineTo(748, 18); + vo->moveTo(738, 13); + vo->lineTo(750, 13); + vo->moveTo(738, 5); + vo->lineTo(750, 5); + AddChar('#', vo); + + vo = new VectorObject(); + vo->moveTo(756, 3); + vo->lineTo(759, 1); + vo->lineTo(765, 1); + vo->lineTo(768, 3); + vo->lineTo(768, 7); + vo->lineTo(765, 9); + vo->lineTo(759, 9); + vo->lineTo(756, 11); + vo->lineTo(756, 15); + vo->lineTo(759, 17); + vo->lineTo(765, 17); + vo->lineTo(768, 15); + vo->moveTo(762, 19); + vo->lineTo(762, -1); + AddChar('$', vo); + + vo = new VectorObject(); + vo->moveTo(774, 0); + vo->lineTo(786, 18); + vo->moveTo(780, 14); + vo->lineTo(777, 10); + vo->lineTo(774, 14); + vo->lineTo(777, 18); + vo->lineTo(780, 14); + vo->moveTo(783, 8); + vo->lineTo(786, 4); + vo->lineTo(783, 0); + vo->lineTo(780, 4); + vo->lineTo(783, 8); + AddChar('%', vo); + + vo = new VectorObject(); + vo->moveTo(792, 7); + vo->lineTo(798, 16); + vo->lineTo(804, 7); + AddChar('^', vo); + + vo = new VectorObject(); + vo->moveTo(822, 5); + vo->lineTo(818, 0); + vo->lineTo(812, 0); + vo->lineTo(810, 4); + vo->lineTo(819, 14); + vo->lineTo(817, 18); + vo->lineTo(813, 18); + vo->lineTo(811, 14); + vo->lineTo(822, 0); + AddChar('&', vo); + + vo = new VectorObject(); + vo->moveTo(831, 2); + vo->lineTo(837, 16); + vo->moveTo(831, 16); + vo->lineTo(837, 2); + vo->moveTo(828, 9); + vo->lineTo(840, 9); + AddChar('*', vo); + + vo = new VectorObject(); + vo->moveTo(858, -2); + vo->lineTo(852, 4); + vo->lineTo(852, 14); + vo->lineTo(858, 20); + AddChar('(', vo); + + vo = new VectorObject(); + vo->moveTo(864, -2); + vo->lineTo(870, 4); + vo->lineTo(870, 14); + vo->lineTo(864, 20); + AddChar(')', vo); + + vo = new VectorObject(); + vo->moveTo(882, 9); + vo->lineTo(894, 9); + AddChar('-', vo); + + vo = new VectorObject(); + vo->moveTo(900, 4); + vo->lineTo(912, 4); + vo->moveTo(900, 14); + vo->lineTo(912, 14); + AddChar('=', vo); + + vo = new VectorObject(); + vo->moveTo(924, 2); + vo->lineTo(924, 16); + vo->moveTo(918, 9); + vo->lineTo(930, 9); + AddChar('+', vo); + + vo = new VectorObject(); + vo->moveTo(918, 0); + vo->lineTo(936, 0); + AddChar('_', vo); + + vo = new VectorObject(); + vo->moveTo(936, 0); + vo->lineTo(948, 18); + AddChar('/', vo); + + vo = new VectorObject(); + vo->moveTo(948, 0); + vo->lineTo(936, 18); + AddChar('\\', vo); + + vo = new VectorObject(); + vo->moveTo(954, 15); + vo->lineTo(957, 18); + vo->lineTo(963, 18); + vo->lineTo(966, 15); + vo->lineTo(966, 11); + vo->lineTo(960, 7); + vo->lineTo(960, 4); + vo->moveTo(960, 2); + vo->lineTo(960, 0); + AddChar('?', vo); + + vo = new VectorObject(); + vo->moveTo(984, 0); + vo->lineTo(972, 9); + vo->lineTo(984, 18); + AddChar('<', vo); + + vo = new VectorObject(); + vo->moveTo(990, 0); + vo->lineTo(1002, 9); + vo->lineTo(990, 18); + AddChar('>', vo); + + vo = new VectorObject(); + vo->moveTo(1020, 20); + vo->lineTo(1014, 20); + vo->lineTo(1014, -2); + vo->lineTo(1020, -2); + AddChar('[', vo); + + vo = new VectorObject(); + vo->moveTo(1026, -2); + vo->lineTo(1032, -2); + vo->lineTo(1032, 20); + vo->lineTo(1026, 20); + AddChar(']', vo); + + vo = new VectorObject(); + vo->moveTo(1056, -2); + vo->lineTo(1051, 1); + vo->lineTo(1051, 6); + vo->lineTo(1048, 9); + vo->lineTo(1051, 12); + vo->lineTo(1051, 17); + vo->lineTo(1056, 20); + AddChar('{', vo); + + vo = new VectorObject(); + vo->moveTo(1062, -2); + vo->lineTo(1067, 1); + vo->lineTo(1067, 6); + vo->lineTo(1070, 9); + vo->lineTo(1067, 12); + vo->lineTo(1067, 17); + vo->lineTo(1062, 20); + AddChar('}', vo); + + vo = new VectorObject(); + // + // vo->moveTo(1080, 18); + //vo->lineTo(1092, 0); + + vo->moveTo(1080, 18); + vo->lineTo(1080, 16); + AddChar('\'', vo); + + vo = new VectorObject(); + vo->moveTo(1103, 18); + vo->lineTo(1103, 18); + vo->lineTo(1105, 14); + AddChar('`', vo); + + vo = new VectorObject(); + vo->moveTo(0, 9); + vo->lineTo(6, 18); + vo->lineTo(12, 9); + vo->moveTo(6, 0); + vo->lineTo(6, 18); + AddChar('u', vo); + + vo = new VectorObject(); + vo->moveTo(0, 9); + vo->lineTo(6, 0); + vo->lineTo(12, 9); + vo->moveTo(6, 18); + vo->lineTo(6, 0); + AddChar('d', vo); + + vo = new VectorObject(); + vo->moveTo(9, 3); + vo->lineTo(0, 9); + vo->lineTo(9, 15); + vo->moveTo(18, 9); + vo->lineTo(0, 9); + AddChar('l', vo); + + vo = new VectorObject(); + vo->moveTo(9, 3); + vo->lineTo(18, 9); + vo->lineTo(9, 15); + vo->moveTo(0, 9); + vo->lineTo(18, 9); + AddChar('r', vo); +} + +VectorObject* Assets::Plane() +{ + auto vo = new VectorObject(); + auto& ctx = *vo; + + ctx.moveTo(39.286594, 35.986019); + ctx.lineTo(39.498511, 25.929167); + ctx.lineTo(42.144346, 22.716370); + ctx.lineTo(44.601191, 25.740179); + ctx.lineTo(44.852248, 35.925918); + ctx.lineTo(57.452381, 45.829613); + ctx.lineTo(58.208334, 49.892857); + ctx.lineTo(44.723361, 44.905634); + ctx.lineTo(44.879929, 51.172604); + ctx.lineTo(48.475452, 56.337351); + ctx.lineTo(41.958720, 55.011077); + ctx.lineTo(34.773814, 56.431845); + ctx.lineTo(38.931553, 51.140179); + ctx.lineTo(39.120540, 44.884673); + ctx.lineTo(25.314913, 49.996033); + ctx.lineTo(25.803595, 45.569057); + ctx.lineTo(39.286594, 35.986019); + + vo->Center(); + vo->Scale(0.01f); + //vo->_solid = true; + return vo; +} + +VectorObject* Assets::Airport(float w, float l) +{ + auto vo = new VectorObject(); + + //vo->moveTo(0, 0); + //vo->lineTo(w, 0); + + vo->moveTo(0, 0); + vo->lineTo(w / 2, -l / 4); + vo->lineTo(w, 0); + + vo->moveTo(0, -l / 4); + vo->lineTo(w / 2, -l / 2); + vo->lineTo(w, -l / 4); + + vo->moveTo(0, -l / 2); + vo->lineTo(w / 2, -3 * l / 4); + vo->lineTo(w, -l / 2); + + vo->moveTo(0, -3 * l / 4); + vo->lineTo(w / 2, -l); + vo->lineTo(w, -3 * l / 4); + + //vo->moveTo(0, -l); + //vo->lineTo(w, -l); + + vo->Center(w / 2, 0); + //vo->Scale(0.1f); + return vo; +} + +VectorObject* Assets::Tokyo() +{ + auto vo = new VectorObject(); + auto& ctx = *vo; + + // #path75 + ctx.beginPath(); + ctx.moveTo(-235.128100, 279.563930); + ctx.lineTo(-229.584520, 268.873150); + ctx.lineTo(-199.383070, 255.776940); + ctx.lineTo(-168.112530, 257.647820); + ctx.lineTo(-151.274550, 264.062290); + ctx.lineTo(-139.514690, 279.563930); + ctx.stroke(); + + // #path77 + ctx.beginPath(); + ctx.moveTo(-122.142170, 280.098470); + ctx.lineTo(-118.934940, 268.338610); + ctx.lineTo(-130.962070, 264.596830); + ctx.lineTo(-138.445620, 231.188140); + ctx.lineTo(-102.096960, 203.392110); + ctx.lineTo(-114.391360, 182.812360); + ctx.lineTo(-99.691534, 176.397890); + ctx.lineTo(-89.000753, 184.683240); + ctx.lineTo(-75.102737, 171.587040); + ctx.lineTo(-49.979402, 194.572220); + ctx.lineTo(-65.748304, 217.824670); + ctx.lineTo(-88.198944, 227.713640); + ctx.lineTo(-88.198944, 240.809840); + ctx.lineTo(-101.027880, 242.948000); + ctx.lineTo(-103.967850, 258.716900); + ctx.lineTo(-94.613413, 268.338610); + ctx.lineTo(-94.880682, 279.296660); + ctx.stroke(); + + // #path79 + ctx.beginPath(); + ctx.moveTo(7.216277, 279.563930); + ctx.lineTo(10.690781, 255.776940); + ctx.lineTo(5.879930, 238.404420); + ctx.lineTo(18.708867, 202.055760); + ctx.lineTo(64.946495, 163.836220); + ctx.lineTo(97.286108, 165.439840); + ctx.lineTo(98.622456, 154.481790); + ctx.lineTo(93.544335, 154.214520); + ctx.lineTo(57.730218, 93.811604); + ctx.lineTo(40.090429, 47.841245); + ctx.lineTo(38.754082, 22.183371); + ctx.lineTo(47.841245, 9.354434); + ctx.stroke(); + + // #path85 + ctx.beginPath(); + ctx.moveTo(28.597838, 101.295150); + ctx.lineTo(1.069078, 56.126599); + ctx.lineTo(-10.156242, 54.522984); + ctx.lineTo(5.078121, 72.162772); + ctx.lineTo(1.069078, 77.775433); + ctx.lineTo(-28.063300, 74.568198); + ctx.lineTo(-24.856066, 82.853554); + ctx.lineTo(0.534539, 89.802561); + ctx.lineTo(-1.603617, 98.889725); + ctx.lineTo(26.192414, 105.036920); + ctx.lineTo(28.597838, 101.295150); + ctx.stroke(); + + // #path202 + ctx.beginPath(); + ctx.moveTo(-114.124090, 167.845260); + ctx.lineTo(-121.874900, 151.541820); + ctx.stroke(); + + // #path204 + ctx.beginPath(); + ctx.moveTo(-121.874900, 151.541820); + ctx.lineTo(-116.529510, 145.661890); + ctx.lineTo(-114.391360, 135.505650); + ctx.lineTo(-120.271290, 127.220300); + ctx.lineTo(-135.238380, 97.553378); + ctx.lineTo(-131.763880, 87.664405); + ctx.lineTo(-139.247420, 65.213765); + ctx.lineTo(-154.749060, 39.021351); + ctx.lineTo(-143.256470, 22.183371); + ctx.lineTo(-141.652850, 9.621703); + ctx.stroke(); + + // #path206 + ctx.beginPath(); + ctx.moveTo(-235.215270, 186.286860); + ctx.lineTo(-225.575480, 183.346900); + ctx.lineTo(-204.461190, 171.587040); + ctx.lineTo(-182.812360, 170.785230); + ctx.lineTo(-164.905300, 175.596080); + ctx.lineTo(-145.661890, 169.716150); + ctx.lineTo(-139.514690, 171.854300); + ctx.lineTo(-114.124090, 167.845260); + ctx.lineTo(-114.391360, 182.812360); + ctx.stroke(); + + // #path208 + ctx.beginPath(); + ctx.moveTo(-114.124090, 167.845260); + ctx.lineTo(-83.655362, 161.698060); + ctx.lineTo(-64.144687, 171.854310); + ctx.lineTo(-42.495855, 179.605120); + ctx.lineTo(-21.648832, 166.776190); + ctx.lineTo(0.267270, 138.980150); + ctx.lineTo(30.735996, 128.289370); + ctx.lineTo(44.099472, 110.115050); + ctx.stroke(); + + // #path210 + ctx.beginPath(); + ctx.moveTo(-121.874900, 151.541820); + ctx.lineTo(-145.929160, 149.670930); + ctx.lineTo(-166.508920, 126.685760); + ctx.lineTo(-185.752320, 107.442350); + ctx.lineTo(-189.226830, 81.784475); + ctx.lineTo(-218.893740, 59.333835); + ctx.lineTo(-230.326300, 34.745039); + ctx.lineTo(-235.048000, 23.786988); + ctx.stroke(); + + // #path212 + ctx.beginPath(); + ctx.moveTo(-75.102735, 171.587040); + ctx.lineTo(-83.655362, 161.698060); + ctx.lineTo(-85.800595, 150.812500); + ctx.lineTo(-93.738095, 140.040180); + ctx.lineTo(-96.194941, 130.023810); + ctx.lineTo(-120.271290, 127.220300); + ctx.stroke(); + + // #path214 + ctx.beginPath(); + ctx.moveTo(-120.271290, 127.220300); + ctx.lineTo(-137.394340, 134.748510); + ctx.lineTo(-145.929160, 149.670930); + ctx.lineTo(-145.661890, 169.716150); + ctx.stroke(); + + // #path216 + ctx.beginPath(); + ctx.moveTo(-145.661890, 169.716150); + ctx.lineTo(-140.040180, 182.373510); + ctx.lineTo(-130.590770, 192.767860); + ctx.lineTo(-116.605650, 201.461310); + ctx.lineTo(-107.534230, 208.453870); + ctx.stroke(); + + // #path218 + ctx.beginPath(); + ctx.moveTo(-114.391360, 182.812360); + ctx.lineTo(-115.849700, 195.035710); + ctx.lineTo(-120.385420, 207.130950); + ctx.lineTo(-146.843750, 219.793150); + ctx.lineTo(-168.766370, 211.099700); + ctx.lineTo(-186.909230, 230.187500); + ctx.lineTo(-205.052080, 234.345240); + ctx.lineTo(-218.092260, 246.062500); + ctx.lineTo(-235.492640, 244.107770); + ctx.stroke(); + + vo->Center(); + vo->Scale(0.066f); + //vo->_solid = true; + return vo; +} + +VectorObject* Assets::Inlay() +{ + float w = 21.95; + float h = 17.95; + + auto vo = new VectorObject(); + + for(int x = 1; x < 5; x++) + for(int y = 1; y < 5; y++) + { + float x1 = w * (x / 5.0); + float y1 = h * (y / 5.0); + vo->AddLine(x1 - 0.1f, y1, x1 + 0.1f, y1); + vo->AddLine(x1, y1 - 0.1f, x1, y1 + 0.1f); + } + + vo->Center(); + return vo; +} + +VectorObject* Assets::Outline() +{ + float w = 21.95; + float h = 17.95; + //outline = VectorObject::Rectangle(21.95, 17.95); + + auto vo = new VectorObject(); + vo->lineTo(w, 0); + vo->lineTo(w, h); + vo->lineTo(0, h); + vo->lineTo(0, 0); + + // add tings? + for(int i = 1; i < 5; i++) + { + float w1 = w * (i / 5.0); + vo->AddLine(w1, 0, w1, 0.1f); + vo->AddLine(w1, h, w1, h - 0.1f); + + float h1 = h * (i / 5.0); + vo->AddLine(0, h1, 0.1f, h1); + vo->AddLine(w - 0.1f, h1, w, h1); + } + vo->Center(); + + return vo; +} + +VectorObject* Assets::SF() +{ + auto vo = new VectorObject(); + auto& ctx = *vo; + + // #path109 + ctx.beginPath(); + ctx.moveTo(17.008928, 246.818450); + ctx.lineTo(24.946428, 192.011900); + ctx.lineTo(6.425595, 151.568450); + ctx.lineTo(4.157738, 130.779760); + ctx.lineTo(-21.544643, 104.699400); + ctx.lineTo(-13.607143, 69.169643); + ctx.lineTo(-13.229167, 38.175595); + ctx.lineTo(-18.142857, -17.008929); + ctx.lineTo(-4.157738, -28.348214); + ctx.lineTo(29.482143, -24.190476); + ctx.lineTo(40.821429, 10.961310); + ctx.lineTo(31.372024, 20.410714); + ctx.lineTo(33.261905, 54.806548); + ctx.lineTo(42.333333, 75.217262); + ctx.lineTo(65.389881, 84.288691); + ctx.lineTo(84.666667, 111.880950); + ctx.lineTo(111.502980, 127.000000); + ctx.lineTo(142.497020, 152.324400); + ctx.lineTo(182.184520, 160.639880); + ctx.lineTo(207.886900, 146.654760); + ctx.stroke(); + + // #path113 + ctx.beginPath(); + ctx.moveTo(207.886900, 146.654760); + ctx.lineTo(198.815470, 132.291660); + ctx.lineTo(150.812500, 106.211310); + ctx.lineTo(103.943450, 20.788690); + ctx.lineTo(91.848214, 21.922619); + ctx.lineTo(78.619048, 3.023810); + ctx.lineTo(85.800595, -2.267857); + ctx.lineTo(49.892857, -17.386905); + ctx.lineTo(56.696429, -38.931548); + ctx.lineTo(65.011905, -42.333333); + ctx.lineTo(59.342262, -66.901786); + ctx.stroke(); + + // #path115 + ctx.beginPath(); + ctx.moveTo(-62.933221, -66.653600); + ctx.lineTo(-24.946428, -36.285715); + ctx.lineTo(-4.913691, -37.419643); + ctx.lineTo(-3.401786, -53.294643); + ctx.lineTo(-16.714797, -66.607654); + ctx.stroke(); + + // #path220 + ctx.beginPath(); + ctx.moveTo(158.758100, -66.015573); + ctx.lineTo(179.872390, -37.952272); + ctx.lineTo(208.470230, 22.183371); + ctx.lineTo(227.980910, 75.637276); + ctx.lineTo(199.383070, 108.511430); + ctx.lineTo(222.635520, 155.283600); + ctx.lineTo(242.146190, 192.968600); + ctx.lineTo(219.161010, 207.133880); + ctx.lineTo(209.539310, 209.806580); + ctx.lineTo(183.079630, 209.539310); + ctx.lineTo(171.052500, 201.253950); + ctx.lineTo(149.403670, 202.323030); + ctx.lineTo(110.382310, 171.319770); + ctx.lineTo(84.724440, 152.343630); + ctx.lineTo(66.817382, 141.385580); + ctx.lineTo(64.946495, 125.082140); + ctx.lineTo(46.772167, 114.124090); + ctx.lineTo(12.027129, 70.024616); + ctx.lineTo(14.967094, 63.342878); + ctx.lineTo(-3.741773, 32.072343); + ctx.lineTo(-2.405426, 18.441597); + ctx.lineTo(6.147199, 15.768902); + ctx.lineTo(9.621703, 8.285355); + ctx.stroke(); + + // #path222 + ctx.beginPath(); + ctx.moveTo(9.621703, 8.285355); + ctx.lineTo(23.519718, 6.949008); + ctx.lineTo(29.132379, -0.267270); + ctx.lineTo(23.786988, -14.699824); + ctx.lineTo(29.482143, -24.190476); + ctx.stroke(); + + // #path224 + ctx.beginPath(); + ctx.moveTo(21.381562, -9.087164); + ctx.lineTo(23.519718, 6.949008); + ctx.lineTo(29.132379, 33.675960); + ctx.lineTo(20.045215, 44.901281); + ctx.lineTo(25.657875, 65.481034); + ctx.lineTo(40.090429, 80.180858); + ctx.lineTo(63.877417, 95.949760); + ctx.lineTo(82.051745, 118.667670); + ctx.lineTo(111.502980, 127.000000); + ctx.stroke(); + + // #path226 + ctx.beginPath(); + ctx.moveTo(111.502980, 127.000000); + ctx.lineTo(151.007280, 165.439840); + ctx.lineTo(233.593570, 196.175830); + ctx.lineTo(267.536800, 245.620700); + ctx.stroke(); + + // #path228 + ctx.beginPath(); + ctx.moveTo(277.693040, 21.916101); + ctx.lineTo(208.470230, 22.183371); + ctx.lineTo(181.208740, 21.381562); + ctx.lineTo(138.712880, 29.132379); + ctx.lineTo(122.943980, 10.423512); + ctx.lineTo(107.709620, 16.303441); + ctx.stroke(); + + vo->Center(); + //vo->Center(50.0f, 90.0f); + + vo->Scale(0.057f); + //vo->_solid = true; + return vo; +} + +VectorObject* Assets::London() +{ + auto vo = new VectorObject(); + auto& ctx = *vo; + + // #path139 + ctx.beginPath(); + ctx.moveTo(260.458670, 134.971110); + ctx.lineTo(244.284350, 148.869130); + ctx.stroke(); + + // #path141 + ctx.beginPath(); + ctx.moveTo(244.284350, 148.869130); + ctx.lineTo(215.953780, 143.256460); + ctx.lineTo(212.479270, 151.007280); + ctx.lineTo(177.734240, 154.749060); + ctx.lineTo(176.130620, 167.043450); + ctx.lineTo(160.628990, 169.983420); + ctx.lineTo(155.016330, 163.568950); + ctx.lineTo(148.601860, 164.370760); + ctx.lineTo(146.196430, 167.845260); + ctx.lineTo(136.307460, 159.559910); + ctx.lineTo(128.289370, 159.292640); + ctx.lineTo(125.349410, 152.878170); + ctx.lineTo(117.865860, 150.205470); + ctx.lineTo(110.916850, 151.809090); + ctx.lineTo(104.235120, 156.887210); + ctx.lineTo(96.484299, 155.283600); + ctx.lineTo(91.673448, 152.610900); + ctx.lineTo(92.207987, 156.619940); + ctx.lineTo(92.742526, 159.559910); + ctx.lineTo(90.604370, 159.827180); + ctx.lineTo(87.397136, 158.758100); + ctx.lineTo(86.862596, 157.154480); + ctx.lineTo(86.328057, 154.214520); + ctx.lineTo(84.457171, 152.878170); + ctx.lineTo(82.586284, 153.679980); + ctx.lineTo(80.715397, 155.016330); + ctx.lineTo(75.102737, 152.878170); + ctx.lineTo(70.291886, 152.878170); + ctx.lineTo(68.955538, 156.619940); + ctx.lineTo(67.619190, 159.827180); + ctx.lineTo(63.877417, 160.361720); + ctx.lineTo(59.066566, 161.163530); + ctx.lineTo(57.462948, 164.638030); + ctx.lineTo(54.790253, 166.508920); + ctx.lineTo(50.781210, 164.370760); + ctx.lineTo(48.643054, 159.827180); + ctx.lineTo(46.772167, 158.758100); + ctx.lineTo(44.901281, 159.292640); + ctx.lineTo(43.832203, 163.301680); + ctx.lineTo(41.159507, 165.172570); + ctx.lineTo(39.288621, 160.094450); + ctx.lineTo(36.081386, 159.827180); + ctx.lineTo(31.270535, 163.301680); + ctx.lineTo(33.943230, 169.983420); + ctx.lineTo(29.666918, 172.923380); + ctx.stroke(); + + // #path143 + ctx.beginPath(); + ctx.moveTo(260.665900, 182.010550); + ctx.lineTo(252.035160, 178.803310); + ctx.lineTo(234.128110, 172.121580); + ctx.stroke(); + + // #path145 + ctx.beginPath(); + ctx.moveTo(234.128110, 172.121580); + ctx.lineTo(233.860830, 182.277820); + ctx.lineTo(225.308210, 192.968600); + ctx.lineTo(210.875660, 191.899520); + ctx.lineTo(195.106760, 182.545090); + ctx.lineTo(212.479270, 180.406930); + ctx.lineTo(215.151970, 175.328810); + ctx.lineTo(229.317250, 175.061540); + ctx.lineTo(230.386330, 167.043450); + ctx.lineTo(225.575480, 163.836220); + ctx.stroke(); + + // #path147 + ctx.beginPath(); + ctx.moveTo(225.575480, 163.836220); + ctx.lineTo(184.415970, 159.827170); + ctx.lineTo(181.208740, 170.785230); + ctx.lineTo(163.568950, 173.190650); + ctx.lineTo(157.154480, 172.388850); + ctx.lineTo(152.610900, 167.043450); + ctx.lineTo(147.532780, 170.517960); + ctx.lineTo(134.436570, 161.965330); + ctx.lineTo(128.556640, 161.965330); + ctx.lineTo(123.745790, 155.550870); + ctx.lineTo(116.529510, 152.343630); + ctx.lineTo(110.916850, 153.679980); + ctx.lineTo(105.304190, 156.619940); + ctx.stroke(); + + // #path164 + ctx.beginPath(); + ctx.moveTo(122.943980, 214.884700); + ctx.lineTo(122.943980, 197.512180); + ctx.stroke(); + + // #path166 + ctx.beginPath(); + ctx.moveTo(122.943980, 197.512180); + ctx.lineTo(138.980150, 177.734230); + ctx.lineTo(138.980150, 169.716150); + ctx.lineTo(145.127350, 160.094450); + ctx.lineTo(148.334590, 136.307460); + ctx.lineTo(141.118310, 118.133130); + ctx.lineTo(116.796780, 99.424264); + ctx.lineTo(104.235120, 96.751569); + ctx.lineTo(96.484299, 99.424264); + ctx.lineTo(71.360964, 96.217030); + ctx.lineTo(49.177593, 98.622456); + ctx.lineTo(39.021351, 87.397136); + ctx.lineTo(16.837980, 88.466214); + ctx.lineTo(8.819894, 90.604370); + ctx.lineTo(6.414469, 98.889725); + ctx.lineTo(-2.138156, 103.433310); + ctx.lineTo(-10.423512, 134.436570); + ctx.lineTo(-4.543582, 142.721930); + ctx.lineTo(-3.474504, 157.956290); + ctx.lineTo(-12.294398, 175.596080); + ctx.lineTo(-12.294398, 187.088670); + ctx.lineTo(0.801809, 207.668420); + ctx.lineTo(17.639789, 215.953780); + ctx.lineTo(29.399648, 213.548350); + ctx.lineTo(33.675960, 219.161010); + ctx.lineTo(39.021351, 219.428280); + ctx.lineTo(48.108515, 230.119060); + ctx.lineTo(60.670183, 226.377290); + ctx.lineTo(82.853554, 231.455410); + ctx.lineTo(91.138909, 225.842750); + ctx.lineTo(98.355186, 226.644560); + ctx.lineTo(118.400400, 220.497360); + ctx.lineTo(122.943980, 214.884700); + ctx.stroke(); + + // #path168 + ctx.beginPath(); + ctx.moveTo(70.291885, 152.878170); + ctx.lineTo(57.730217, 144.058270); + ctx.stroke(); + + // #path170 + ctx.beginPath(); + ctx.moveTo(57.730217, 144.058270); + ctx.lineTo(45.970359, 124.013060); + ctx.lineTo(39.021351, 113.055010); + ctx.lineTo(26.459683, 108.244160); + ctx.lineTo(15.234363, 79.379050); + ctx.stroke(); + + // #path172 + ctx.beginPath(); + ctx.moveTo(15.234363, 79.379050); + ctx.lineTo(11.492589, 74.568197); + ctx.lineTo(10.423512, 44.901281); + ctx.lineTo(-3.474504, 22.450640); + ctx.lineTo(-13.363476, -3.474504); + ctx.stroke(); + + // #path176 + ctx.beginPath(); + ctx.moveTo(75.102735, 152.878170); + ctx.lineTo(87.129865, 140.316500); + ctx.lineTo(100.493340, 125.616680); + ctx.lineTo(116.796780, 99.424264); + ctx.lineTo(121.607640, 90.069831); + ctx.lineTo(120.004020, 77.775433); + ctx.lineTo(129.625720, 51.048480); + ctx.lineTo(128.289370, 44.901281); + ctx.lineTo(135.238380, 28.330570); + ctx.lineTo(130.962070, -2.939965); + ctx.stroke(); + + // #path178 + ctx.beginPath(); + ctx.moveTo(70.291885, 152.878170); + ctx.lineTo(53.988443, 157.421750); + ctx.lineTo(30.468726, 157.154480); + ctx.lineTo(-3.474504, 157.956290); + ctx.stroke(); + + // #path180 + ctx.beginPath(); + ctx.moveTo(-3.474504, 157.956290); + ctx.lineTo(-18.976136, 159.025370); + ctx.lineTo(-22.450640, 153.145440); + ctx.lineTo(-37.952273, 151.809090); + ctx.lineTo(-72.162772, 176.932430); + ctx.lineTo(-80.475257, 182.812360); + ctx.lineTo(-94.442350, 178.536040); + ctx.stroke(); + + // #path182 + ctx.beginPath(); + ctx.moveTo(70.291885, 152.878170); + ctx.lineTo(83.388090, 162.767140); + ctx.lineTo(102.898770, 168.914340); + ctx.lineTo(138.980150, 177.734230); + ctx.stroke(); + + // #path188 + ctx.beginPath(); + ctx.moveTo(138.980150, 177.734230); + ctx.lineTo(168.112530, 183.881430); + ctx.lineTo(180.406930, 187.623210); + ctx.lineTo(192.166790, 209.272040); + ctx.lineTo(200.184880, 209.272040); + ctx.lineTo(214.617430, 203.659380); + ctx.lineTo(231.722680, 216.221050); + ctx.lineTo(260.467720, 216.755590); + ctx.stroke(); + + // #path190 + ctx.beginPath(); + ctx.moveTo(67.619189, 159.827180); + ctx.lineTo(68.688267, 172.656110); + ctx.lineTo(70.826425, 201.521220); + ctx.lineTo(60.670183, 226.377290); + ctx.stroke(); + + // #path192 + ctx.beginPath(); + ctx.moveTo(60.670183, 226.377290); + ctx.lineTo(70.024616, 232.524480); + ctx.lineTo(66.015573, 267.269530); + ctx.lineTo(52.652097, 287.047470); + ctx.stroke(); + + vo->Center(); + vo->Scale(0.062f); + //vo->_solid = true; + return vo; +} \ No newline at end of file diff --git a/src/Assets.h b/src/Assets.h new file mode 100644 index 0000000..36b595d --- /dev/null +++ b/src/Assets.h @@ -0,0 +1,37 @@ +#pragma once + +#include "stdafx.h" +#include "VectorBatch.h" + +constexpr float CHAR_SCALE = 0.01f; +constexpr int CHAR_RAW_MIDPOINT = 9; +constexpr float CHAR_HEIGHT = 2 * CHAR_RAW_MIDPOINT * CHAR_SCALE; +constexpr float CHAR_KERNING = 5.0f * CHAR_SCALE; +constexpr float CHAR_MIDPOINT = CHAR_RAW_MIDPOINT * CHAR_SCALE; + +class Assets +{ +public: + VectorObject* GetChar(char c, int zoom); + VectorObject* Plane(); + VectorObject* Airport(float w, float l); + VectorObject* Outline(); + VectorObject* Inlay(); + + VectorObject* Tokyo(); + VectorObject* SF(); + VectorObject* London(); + + Assets(); + void Load(); + void Unload(); + void Render(float thick); + +private: + void GenerateChars(); + void AddChar(char c, VectorObject* vo); + + std::map _chars; + std::map _chars2; + std::map _chars4; +}; diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 0000000..9d0c4fd --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,85 @@ +#include "Game.h" +#include "Assets.h" +#include "Screen.h" + +#include "GameScreen.h" + +Game::Game() : m_activeScreen {nullptr}, m_frameCounter {}, m_mouseX {}, m_mouseY {} { } + +void Game::Load() +{ + m_assets = new Assets(); + m_assets->Load(); + + CreateScreens(); + + for(auto& s : m_screens) + { + s->Load(); + } +} + +void Game::Start(double totalTime) +{ + OnStart(totalTime); + SwitchScreen(0); +} + +void Game::End() +{ + if(m_activeScreen) + m_activeScreen->Leave(); + + for(auto& s : m_screens) + { + s->Unload(); + delete s; + } + + m_assets->Unload(); +} + +void Game::Render(float thick) +{ + m_assets->Render(thick); +} + +void Game::Tick(double deltaTime, double totalTime) +{ + m_frameCounter++; + + OnTick(deltaTime, totalTime); + m_activeScreen->Tick(deltaTime, totalTime); +} + +void Game::DrawBackground() +{ + m_activeScreen->DrawBackground(); +} + +void Game::DrawPixels(Color* framebuffer, Rectangle* rect, bool* fullFrame) +{ + m_activeScreen->DrawPixels(framebuffer, rect, fullFrame); +} + +void Game::DrawShapes() +{ + m_activeScreen->DrawShapes(); +} + +void Game::DrawVectors(float thick) +{ + m_activeScreen->DrawVectors(thick); +} + +void Game::SwitchScreen(int sc) +{ + if(m_activeScreen) + m_activeScreen->Leave(); + + OnSwitchScreen(m_activeScreen ? m_activeScreen->m_no : -1, sc); + + m_activeScreen = m_screens[sc]; + m_screenTime = GetTime(); + m_activeScreen->Enter(); +} \ No newline at end of file diff --git a/src/Game.h b/src/Game.h new file mode 100644 index 0000000..f7700f0 --- /dev/null +++ b/src/Game.h @@ -0,0 +1,56 @@ +#pragma once + +#include "stdafx.h" + +constexpr int screenWidth = 1840;//1920; +constexpr int screenHeight = 1035;//1080; +constexpr int aspectH = 16; +constexpr int aspectV = 9; +constexpr int screenSize = screenWidth * screenHeight; +constexpr float thickFactor = 0.065f; + +#define WINDOW_TITLE "Airobics" +#define FULLSCREEN_KEY KEY_F +//#define GLOW +#define TARGET_FPS 0 + +#define DRAW_PIXELS +#define DRAW_SHAPES +#define DRAW_BACKGROUND + +class Screen; +class Assets; + +class Game +{ +protected: + std::vector m_screens; + Screen* m_activeScreen; + + virtual void CreateScreens() = 0; + virtual void OnTick(double deltaTime, double totalTime) = 0; + virtual void OnStart(double totalTime) = 0; + virtual void OnSwitchScreen(int prevScreen, int nextScreen) = 0; + +public: + Assets* m_assets; + + int m_frameCounter; + float m_mouseX; + float m_mouseY; + double m_screenTime; + + Game(); + + void Load(); + void Start(double totalTime); + void Render(float thick); + void Tick(double deltaTime, double totalTime); + void DrawBackground(); + void DrawPixels(Color* framebuffer, Rectangle* rect, bool* fullFrame); + void DrawShapes(); + void DrawVectors(float thick); + void End(); + + void SwitchScreen(int sn); +}; diff --git a/src/GameScreen.cpp b/src/GameScreen.cpp new file mode 100644 index 0000000..f1bf8ac --- /dev/null +++ b/src/GameScreen.cpp @@ -0,0 +1,966 @@ +#include "GameScreen.h" +#include "VectorBatch.h" +#include "rlgl.h" + +#define PANEL_COLOR C_BLUE1 + +constexpr float TIME_PANEL_X = 6.5f; +constexpr float TIME_PANEL_X2 = 11.5f; +constexpr float TIME_PANEL_Y = -8.5f; +constexpr float MESSAGES_X = TIME_PANEL_X; +constexpr float MESSAGES_Y = 0.0f; +constexpr float HINT_PANEL_X = TIME_PANEL_X; +constexpr float HINT_PANEL_Y = -1.5f; +constexpr float PLANE_PANEL_X = TIME_PANEL_X; +constexpr float PLANE_PANEL_X2 = 11.5f; +constexpr float PLANE_PANEL_Y = -6.0f; +constexpr float TEXT_HEIGHT = CHAR_HEIGHT * 3.0f; +constexpr float BOUND_X = 12.0f + 2.0f; +constexpr float BOUND_Y = 9.0f + 2.0f; +const int GAME_TIME = 720; + +GameScreen::GameScreen(int no, AirGame* game) : Screen(no, game) { } + +void GameScreen::Load() +{ + alertMusic = LoadMusicStream("resources/alert.ogg"); + landedSound = LoadSound("resources/landed.wav"); + ackSound = LoadSound("resources/ack.ogg"); + alertSound = LoadSound("resources/alert.ogg"); + tickSound = LoadSound("resources/tick.ogg"); + startSound = LoadSound("resources/start.ogg"); + endSound = LoadSound("resources/end.ogg"); + winSound = LoadSound("resources/win.ogg"); + rect = VectorObject::Rectangle(0.5f, 0.6f); + tri = VectorObject::Triangle(0.4f, 0.3f); + circ = VectorObject::Circle(0.1f); + tri->_solid = true; + rect->_solid = false; + panelBG = VectorObject::Rectangle(10.0f, 18.0f); + panelBG->_solid = true; + panelGO = VectorObject::Rectangle(10.0f, 5.0f); + panelGO->_solid = true; + panelGOutline = VectorObject::Rectangle(10.0f, 5.0f); + restartOutline = VectorObject::Rectangle(4.0f, 0.7f); + speedOutline = VectorObject::Rectangle(0.5f, 0.7f); + focusOutline = VectorObject::Rectangle(1.2f, 0.7f); + exitObj = VectorObject::Circle(0.2f); + airportObj = VectorObject::Circle(0.1f); + planeObj = m_game->m_assets->Plane(); + planeSelected = VectorObject::Rectangle(0.5f, 0.5f); + planeTarget = VectorObject::Rectangle(0.25f, 0.25f); + airportCircle = VectorObject::DottedCircle(2.0f); + outline = m_game->m_assets->Outline(); + inlay = m_game->m_assets->Inlay(); +} + +void GameScreen::Enter() +{ + prevGameTime = 0; + switch(m_game->m_map) + { + default: + case Map::Tokyo: + map = m_game->m_assets->Tokyo(); + break; + + case Map::London: + map = m_game->m_assets->London(); + break; + + case Map::SF: + map = m_game->m_assets->SF(); + break; + } + + messages.clear(); + exitObjs.clear(); + areaObjs.clear(); + + // init + x_shift = -5.0f; + y_shift = 0.0f; + zoom = 1.0f; + mouse_release_time = 0; + selectedPlane = nullptr; + + // prerender exits + for(auto e : m_game->board->exits) + { + auto vo = m_game->m_assets->Airport(e->width, e->length); + //vo->_solid = true; + exitObjs.insert(std::make_pair(e->id, vo)); + } + + for(auto p : m_game->board->planes) + { + if(p->callSign == "M") + { + mousePlane = p; + } + } + + finishTime = NAN; + + Message("THEN CLICK ON MAP TO REROUTE"); + Message("CLICK ON A PLANE TO SELECT"); + Message(" "); + Message("AVOID PLANE COLLISIONS!"); + Message(" "); + Message("GOOD MORNING & GOOD LUCK"); + Message(" "); + m_delay = 0; + totalDelay = 0; + m_alerts = 0; + + PlaySoundMulti(startSound); +} + +void GameScreen::AddDelay(Plane* p) +{ + if(!p->delay_done) + { + auto nd = p->ExpDelay(totalTime); + auto ed = p->ExpDelay(totalTime); + if(!std::isnan(nd) && p->type != PlaneType::Military) + { + m_delay += nd; + } + p->delay_done = true; + } +} + +void GameScreen::Leave() { } + +void GameScreen::Unload() { } + +void GameScreen::Tick(double deltaTime, double totalTime) +{ + UpdateMusicStream(alertMusic); + if(!m_game->m_gameOver) + { + this->totalTime = totalTime; + this->deltaTime = deltaTime; + } + else + { + if(IsMusicStreamPlaying(alertMusic)) + { + StopMusicStream(alertMusic); + } + if(m_game->timeScale != 1) + m_game->timeScale = 1; + if(std::isnan(finishTime)) + finishTime = totalTime; + } + + if(m_game->m_gameTime != prevGameTime && m_game->m_gameTime % 7 == 0) + { + PlaySoundMulti(tickSound); + prevGameTime = m_game->m_gameTime; + } + + if(m_game->m_gameTime >= GAME_TIME) // 12hr shift 06:00 - 18:00 + { + if(!m_game->m_gameOver) + { + PlaySoundMulti(winSound); + } + m_game->m_gameOver = true; + m_game->m_winner = true; + if(std::isnan(finishTime)) + finishTime = totalTime; + + //return; + } + + mx = m_game->m_mouseX / zoom - x_shift; + my = m_game->m_mouseY / zoom - y_shift; + + // DEBUG! + /* + if(mousePlane != nullptr) + { + mousePlane->position = (Vector2) {mx, my}; + + if(IsKeyPressed(KEY_M)) + { + mousePlane->mode = PlaneMode::Static; + } + } + + if(IsKeyPressed(KEY_W)) + { + m_game->m_gameOver = true; + m_game->m_winner = true; + PlaySoundMulti(winSound); + } + if(IsKeyPressed(KEY_L)) + { + m_game->m_gameOver = true; + m_game->m_winner = false; + PlaySoundMulti(endSound); + } +*/ + + if(!m_game->m_gameOver && (IsKeyPressed(KEY_P) || IsKeyPressed(KEY_SPACE))) + { + messages.push_back("NO PAUSING!!!"); + } + + // iterate selectable objects + if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + if(IsHoveringRestartButton() || IsHoveringRestartButton2()) + { + Restart(); + return; + } + int h = IsHoveringSpeedButton(); + if(h) + m_game->timeScale = h; + + int f = IsHoveringFocusButton(); + if(f == 1) + m_game->m_noise = true; + else if(f == -1) + m_game->m_noise = false; + + if(m_game->m_gameOver) + return; + + if(mx < 16 - 5) // only on the plane view + { + // find selected object + bool foundSelection = false; + for(auto p : m_game->board->planes) + { + if(p->mode == PlaneMode::Exited) + continue; + + if(foundSelection) + { + p->selected = false; + } + else if(fabsf(mx - p->position.x) < planeObj->_width && fabsf(my - p->position.y) < planeObj->_height) + { + if(p->selected) + { + p->selected = false; + continue; // deselect and look for next selection + } + else + { + p->selected = true; + foundSelection = true; + selectedPlane = p; + } + } + else + { + p->selected = false; + } + } + + if(foundSelection) + { + mouse_state = MouseState::SetTarget; + } + else if(selectedPlane != nullptr && selectedPlane->mode != PlaneMode::Exited && selectedPlane->type != PlaneType::Military) + { + selectedPlane->Touch(totalTime); // mark start of delay + + selectedPlane->target = (Vector2) {mx, my}; + selectedPlane->mode = PlaneMode::Target; + selectedPlane->selected = true; // keep selection + PlaySoundMulti(ackSound); + } + } + } + + mouse_click = (Vector2) {mx, my}; + + if(IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + mouse_release_time = totalTime; + } + + // DEBUG only? hover exits + /* + mc = WHITE; + for(auto e : m_game->board->exits) + { + if(e->IsAbove((Vector2) {mx, my})) + { + mc = YELLOW; + } + }*/ + + CheckPlanes(); + CheckCollisions(); +} + +bool GoodPass(Vector2 entry, Vector2 exit, Exit* area) +{ + return false; +} + +void GameScreen::DrawBackground() { } + +void GameScreen::DrawPixels(Color* framebuffer, Rectangle* rect, bool* fullFrame) { } + +void GameScreen::DrawShapes() { } + +bool GameScreen::IsHoveringRestartButton() +{ + if(m_game->m_gameOver) + { + return (mx >= -restartOutline->_width / 2 - x_shift) && (mx <= restartOutline->_width / 2 - x_shift) && + (my >= 1.8f - restartOutline->_height / 2) && (my <= 1.8f + restartOutline->_height / 2); + } + return false; +} + +bool GameScreen::IsHoveringRestartButton2() +{ + if(!m_game->m_gameOver) + { + return (mx >= restart2Loc.x + -restartOutline->_width / 2 - x_shift) && + (mx <= restart2Loc.x + restartOutline->_width / 2 - x_shift) && (my >= restart2Loc.y - restartOutline->_height / 2) && + (my <= restart2Loc.y + restartOutline->_height / 2); + } + return false; +} + +int GameScreen::IsHoveringSpeedButton() +{ + if(!m_game->m_gameOver) + { + if((mx >= speed1Loc.x + -speedOutline->_width / 2 - x_shift) && (mx <= speed1Loc.x + speedOutline->_width / 2 - x_shift) && + (my >= speed1Loc.y - speedOutline->_height / 2) && (my <= speed1Loc.y + speedOutline->_height / 2)) + return 1; + if((mx >= speed2Loc.x + -speedOutline->_width / 2 - x_shift) && (mx <= speed2Loc.x + speedOutline->_width / 2 - x_shift) && + (my >= speed2Loc.y - speedOutline->_height / 2) && (my <= speed2Loc.y + speedOutline->_height / 2)) + return 2; + if((mx >= speed3Loc.x + -speedOutline->_width / 2 - x_shift) && (mx <= speed3Loc.x + speedOutline->_width / 2 - x_shift) && + (my >= speed3Loc.y - speedOutline->_height / 2) && (my <= speed3Loc.y + speedOutline->_height / 2)) + return 3; + if((mx >= speed4Loc.x + -speedOutline->_width / 2 - x_shift) && (mx <= speed4Loc.x + speedOutline->_width / 2 - x_shift) && + (my >= speed4Loc.y - speedOutline->_height / 2) && (my <= speed4Loc.y + speedOutline->_height / 2)) + return 4; + } + return 0; +} + +int GameScreen::IsHoveringFocusButton() +{ + if(!m_game->m_gameOver) + { + if((mx >= focusOnLoc.x + -focusOutline->_width / 2 - x_shift) && (mx <= focusOnLoc.x + focusOutline->_width / 2 - x_shift) && + (my >= focusOnLoc.y - focusOutline->_height / 2) && (my <= focusOnLoc.y + focusOutline->_height / 2)) + return 1; + if((mx >= focusOffLoc.x + -focusOutline->_width / 2 - x_shift) && (mx <= focusOffLoc.x + focusOutline->_width / 2 - x_shift) && + (my >= focusOffLoc.y - focusOutline->_height / 2) && (my <= focusOffLoc.y + focusOutline->_height / 2)) + return -1; + } + return 0; +} + +void GameScreen::DrawGameOver() +{ + // BG + rlEnd(); + rlSetBlendMode(BLEND_ALPHA); + rlBegin(RL_TRIANGLES); + m_vectorBatch.DrawObject(panelGO, (Vector2) {0, 0}, 0, C_BLUE5); + rlEnd(); + rlSetBlendMode(BLEND_CUSTOM); + rlBegin(RL_TRIANGLES); + m_vectorBatch.DrawObject(panelGOutline, (Vector2) {0, 0}, 0, C_BLUE1); + + if(!m_game->m_winner) + { + DrawText("COULDN'T EVEN PASS", 0, -2.0f, C_BLUE0, 0, 0, 2); + DrawText("A TRAINING SIMULATION...", 0, -1.2f, C_BLUE0, 0, 0, 2); + + if(m_game->m_flashOn) + { + DrawText("YOU'RE FIRED!!!", 0, 0.3f, C_BLUE0, 0, 0, 2); + } + } + else + { + DrawText("EXCELLENT JOB!", 0, -1.6f, C_BLUE0, 0, 0, 2); + + if(m_alerts == 0) + { + if(m_game->m_flashOn) + { + DrawText("ASK FOR A RAISE!!!", 0, 0.1f, C_BLUE0, 0, 0, 2); + } + } + else + { + DrawText("BACK TO WORK TOMORROW.", 0, 0.1f, C_BLUE0, 0, 0, 2); + } + } + + Color c = C_BLUE2; + if(IsHoveringRestartButton()) + { + c = C_BLUE0; + } + + DrawText(m_game->m_winner ? "AGAIN!" : "REAPPLY", 0, 1.8f, c, 0, 0, 2); + m_vectorBatch.DrawObject(restartOutline, (Vector2) {0, 1.8f}, 0, c); +} + +void GameScreen::DrawVectors() +{ + m_vectorBatch.DrawObject(map, (Vector2) {x_shift, 0}, 0, C_BLUE45); + + DrawBoard(); + DrawPanels(); + + if(m_game->m_gameOver) + DrawGameOver(); + + m_vectorBatch.DrawObject(&m_mouseCursor, (Vector2) {m_game->m_mouseX, m_game->m_mouseY}, 0, mc); +} + +Vector2 GameScreen::ScreenPos(Vector2 modelPos) +{ + return (Vector2) {(modelPos.x + x_shift) * zoom, (modelPos.y + y_shift) * zoom}; +} + +void GameScreen::DrawPlane(Plane* plane) +{ + Vector2 screenPos = ScreenPos(plane->position); + + Color c = C_BLUE0; + if(plane->type == PlaneType::VIP) + c = C_VIP; + + c = (plane->incoming || plane->mode == PlaneMode::Heading) ? C_BLUE3 : (plane->alerts.size() ? C_RED : c); + + if(plane->type == PlaneType::Military) + c = C_MIL; // always visible + + m_vectorBatch.DrawObject(planeObj, screenPos, plane->heading * RAD2DEG, c); + DrawText(plane->callSign, screenPos.x, screenPos.y + 0.35f, c, 0, -1); + if(plane->exit != nullptr) + DrawText(plane->exit->code, screenPos.x, screenPos.y + 0.35f + CHAR_HEIGHT + 0.1f, c, 0, -1); + + if(plane->selected) + { + m_vectorBatch.DrawObject(planeSelected, screenPos, 0, c); + + // show its target + Vector2 targetPos = ScreenPos(plane->target); + m_vectorBatch.DrawObject(planeTarget, targetPos, 0, c); + + // line to target + m_vectorBatch.DrawLine(screenPos.x, screenPos.y, targetPos.x, targetPos.y, c); + + // if target not destination, also draw destination + if(plane->mode == PlaneMode::Target && plane->exit != nullptr) + { + Vector2 exitPos = ScreenPos(plane->exit->location); + // line to exit + m_vectorBatch.DrawLine(targetPos.x, targetPos.y, exitPos.x, exitPos.y, c); + m_vectorBatch.DrawObject(planeTarget, exitPos, 0, c); + } + } +} + +void GameScreen::DrawExit(Exit* exit) +{ + Vector2 screenPos = ScreenPos(exit->location); + + auto vectorObj = exitObjs.at(exit->id); + + switch(exit->type) + { + case ExitType::Exit: + m_vectorBatch.DrawObject(vectorObj, screenPos, exit->heading * RAD2DEG, C_BLUE3); + if(exit->code == "EAST" || exit->code == "WEST") + DrawText(exit->name, (screenPos.x - x_shift) * 0.97f + x_shift, screenPos.y, C_BLUE3, 0, 0, 1, 1); + else + DrawText(exit->name, screenPos.x, screenPos.y * 0.97f, C_BLUE3, 0, 0, 1, 0); + //DrawText(exit->code, screenPos.x, screenPos.y + 0.5f, C_BLUE3, 0, -1); + break; + + case ExitType::Airport: + m_vectorBatch.DrawObject(vectorObj, screenPos, exit->heading * RAD2DEG, C_BLUE1); + m_vectorBatch.DrawObject(airportCircle, screenPos, 0, C_BLUE45); + DrawText(exit->code, screenPos.x + exit->tx, screenPos.y + exit->ty, C_BLUE2, 0, 0); + break; + + default: + break; + } +} + +void GameScreen::DrawArea(Area* area) +{ + Vector2 screenPos = ScreenPos(area->center); + + if(areaObjs.find(area->id) == areaObjs.end()) + { + // precreate object + auto ao = VectorObject::Rectangle(area->w, area->h); + areaObjs.insert(std::make_pair(area->id, ao)); + } + + auto vectorObj = areaObjs.at(area->id); + + switch(area->type) + { + case AreaType::NoFly: + m_vectorBatch.DrawObject(vectorObj, screenPos, 0, C_BLUE3); + DrawText("NO FLY", screenPos.x, screenPos.y, C_BLUE3, 0, 0); + break; + + case AreaType::Weather: + m_vectorBatch.DrawObject(vectorObj, screenPos, 0, C_BLUE3); + DrawText("STORM", screenPos.x, screenPos.y, C_BLUE3, 0, 0); + break; + + default: + break; + } +} + +void GameScreen::DrawBoard() +{ + // outline + m_vectorBatch.DrawObject(outline, (Vector2) {x_shift, 0}, 0, haveAlerts && m_game->m_flashOn ? C_RED : C_BLUE1); + m_vectorBatch.DrawObject(inlay, (Vector2) {x_shift, 0}, 0, C_BLUE3); + + // draw exits + for(auto exit : m_game->board->exits) + { + DrawExit(exit); + } + + // draw areas + for(auto area : m_game->board->areas) + { + DrawArea(area); + } + + // draw planes + for(auto plane : m_game->board->planes) + { + if(plane->mode != PlaneMode::Exited) + { + DrawPlane(plane); + } + } +} + +void GameScreen::DrawPanels() +{ + // BG + rlEnd(); + rlSetBlendMode(BLEND_ALPHA); + rlBegin(RL_TRIANGLES); + m_vectorBatch.DrawObject(panelBG, (Vector2) {16 - 5, 0}, 0, C_BLUE5); + rlEnd(); + rlSetBlendMode(BLEND_CUSTOM); + rlBegin(RL_TRIANGLES); + + // draw time panel + { + float yPos = TIME_PANEL_Y; + char timeString[20]; + int timeLeft = GAME_TIME - m_game->m_gameTime; + std::snprintf(timeString, 20, "%02d:%02d", /*6 +*/ timeLeft /*m_game->m_gameTime*/ / 60, timeLeft /*m_game->m_gameTime*/ % 60); + DrawText("TIME LEFT", TIME_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + DrawText(std::string(timeString), TIME_PANEL_X2, yPos, C_BLUE0 /* PANEL_COLOR*/, -1, -1, 2); + yPos += TEXT_HEIGHT; + + char delayString[20]; + if(!m_game->m_gameOver) + { + int delay = (int)m_delay; + // add provisional delay of planes in flight + float provisionalDelay = 0; + for(auto p : m_game->board->planes) + { + //if(p->mode != PlaneMode::Exited && p->mode != PlaneMode::Heading && !p->delay_done) + if(!p->delay_done) + { + auto edelay = p->ExpDelay(m_game->m_gameOver ? finishTime : totalTime); + if(edelay < 0) + { + edelay = 0; + } + provisionalDelay += edelay; + } + } + delay += (int)provisionalDelay; + totalDelay = delay; + } + + if(!m_game->m_gameOver || m_game->m_flashOn || (m_game->m_gameOver && !m_game->m_winner)) + { + DrawText("ALERTS", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + std::snprintf(delayString, 20, "%03d", m_alerts); + DrawText(std::string(delayString), TIME_PANEL_X2, yPos, C_BLUE0 /* PANEL_COLOR*/, -1, -1, 2); + } + yPos += TEXT_HEIGHT; + //if(!m_game->m_gameOver || m_game->m_flashOn || (m_game->m_gameOver && !m_game->m_winner)) + { + DrawText("TOTAL DELAYS", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + std::snprintf(delayString, 20, "%02d:%02d", totalDelay / 60, totalDelay % 60); + DrawText(std::string(delayString), TIME_PANEL_X2, yPos, C_BLUE0 /* PANEL_COLOR*/, -1, -1, 2); + } + } + + m_vectorBatch.DrawLine(TIME_PANEL_X - 0.5f, PLANE_PANEL_Y - 0.5f, TIME_PANEL_X + 10.0f, PLANE_PANEL_Y - 0.5F, C_BLUE1); + m_vectorBatch.DrawLine(TIME_PANEL_X - 0.5f, MESSAGES_Y - 0.5f, TIME_PANEL_X + 10.0f, MESSAGES_Y - 0.5F, C_BLUE1); + + // draw plane info + if(selectedPlane != nullptr && selectedPlane->mode != PlaneMode::Exited) + { + if(selectedPlane->type == PlaneType::Military) + { + if(m_game->m_flashOn) + DrawText("CANNOT REROUTE MILITARY", HINT_PANEL_X, HINT_PANEL_Y, PANEL_COLOR, -1, -1, 2); + } + else + { + DrawText("CLICK TO REROUTE", HINT_PANEL_X, HINT_PANEL_Y, PANEL_COLOR, -1, -1, 2); + } + + float yPos = PLANE_PANEL_Y; + DrawText("CALL SIGN", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + DrawText(selectedPlane->callSign, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + + DrawText("DESTINATION", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + if(selectedPlane->exit != nullptr) + { + DrawText(selectedPlane->exit->code, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + } + yPos += TEXT_HEIGHT; + + bool typeFlash = false; + std::string typeString, speedString; + switch(selectedPlane->type) + { + case PlaneType::Passenger: + typeString = "PASSENGER"; + speedString = "FAST"; + break; + case PlaneType::Cargo: + typeString = "CARGO"; + speedString = "SLOW"; + break; + case PlaneType::Military: + typeString = "MILITARY"; + speedString = "SUPERSONIC"; + typeFlash = true; + break; + case PlaneType::VIP: + typeString = "VIP"; + speedString = "FAST"; + typeFlash = true; + break; + default: + typeString = ""; + speedString = ""; + break; + } + + DrawText("TYPE", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + if(!typeFlash || m_game->m_flashOn) + DrawText(typeString, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + + DrawText("SPEED", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + DrawText(speedString, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + + DrawText("ORIGIN", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + DrawText(selectedPlane->origin, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + + char planeDelayString[20]; + int planeDelay = (int)selectedPlane->ExpDelay(m_game->m_gameOver ? finishTime : totalTime); + std::snprintf(planeDelayString, 20, "%02d:%02d", planeDelay / 60, planeDelay % 60); + + DrawText("DELAY", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + DrawText(planeDelayString, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + + char effectsString[20] = ""; + bool flash = false; + if(selectedPlane->alerts.size()) + { + flash = true; + std::snprintf(effectsString, 20, "ALERT"); + } + else if(selectedPlane->incoming || selectedPlane->mode == PlaneMode::Heading) + { + std::snprintf(effectsString, 20, "CHANGING ALT"); + } + else if(selectedPlane->areaSpeed != 1.0f) + { + flash = true; + std::snprintf(effectsString, 20, "SPEED X%.1f", selectedPlane->areaSpeed); + } + else if(m_game->board->areas.size() && selectedPlane->type != PlaneType::Military) + { + for(auto a : m_game->board->areas) + { + if(a->type == AreaType::NoFly && a->IsAbove(selectedPlane->position)) + { + flash = true; + std::snprintf(effectsString, 20, "NO FLY DELAY"); + break; + } + } + } + if(strlen(effectsString) == 0) + { + std::snprintf(effectsString, 20, "CRUISING"); + } + DrawText("STATUS", PLANE_PANEL_X, yPos, PANEL_COLOR, -1, -1, 2); + if(!flash || m_game->m_flashOn) + DrawText(effectsString, PLANE_PANEL_X2, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + } + else + { + DrawText("NO PLANE SELECTED", PLANE_PANEL_X, PLANE_PANEL_Y, PANEL_COLOR, -1, -1, 2); + } + + { + // draw 10 messages + float yPos = MESSAGES_Y; + for(int i = messages.size() - 1; i >= 0 && i >= (int)messages.size() - (int)10; i--) + { + if(messages[i][0] != 'C' || messages[i][1] != 'R' || m_game->m_flashOn) + DrawText(messages[i], MESSAGES_X, yPos, PANEL_COLOR, -1, -1, 2); + yPos += TEXT_HEIGHT; + } + } + + Color c = C_BLUE2; + if(IsHoveringRestartButton2()) + { + c = C_BLUE0; + } + DrawText("RESTART", restart2Loc.x, restart2Loc.y, c, 0, 0, 2); + m_vectorBatch.DrawObject(restartOutline, restart2Loc, 0, c); + + int hover = IsHoveringSpeedButton(); + DrawText("SPEED", PLANE_PANEL_X, restart2Loc.y, PANEL_COLOR, -1, 0, 2); + DrawText("1", speed1Loc.x, speed1Loc.y, hover == 1 ? C_BLUE0 : C_BLUE2, 0, 0, 2); + DrawText("2", speed2Loc.x, speed2Loc.y, hover == 2 ? C_BLUE0 : C_BLUE2, 0, 0, 2); + DrawText("3", speed3Loc.x, speed3Loc.y, hover == 3 ? C_BLUE0 : C_BLUE2, 0, 0, 2); + DrawText("4", speed4Loc.x, speed4Loc.y, hover == 4 ? C_BLUE0 : C_BLUE2, 0, 0, 2); + if(m_game->timeScale == 1) + m_vectorBatch.DrawObject(speedOutline, speed1Loc, 0, hover == 1 ? C_BLUE0 : C_BLUE2); + if(m_game->timeScale == 2) + m_vectorBatch.DrawObject(speedOutline, speed2Loc, 0, hover == 2 ? C_BLUE0 : C_BLUE2); + if(m_game->timeScale == 3) + m_vectorBatch.DrawObject(speedOutline, speed3Loc, 0, hover == 3 ? C_BLUE0 : C_BLUE2); + if(m_game->timeScale == 4) + m_vectorBatch.DrawObject(speedOutline, speed4Loc, 0, hover == 4 ? C_BLUE0 : C_BLUE2); + + int fhover = IsHoveringFocusButton(); + DrawText("FOCUS", PLANE_PANEL_X, focusOnLoc.y, PANEL_COLOR, -1, 0, 2); + DrawText("ON", focusOnLoc.x, focusOnLoc.y, fhover == 1 ? C_BLUE0 : C_BLUE2, 0, 0, 2); + DrawText("OFF", focusOffLoc.x, focusOffLoc.y, fhover == -1 ? C_BLUE0 : C_BLUE2, 0, 0, 2); + if(m_game->m_noise) + m_vectorBatch.DrawObject(focusOutline, focusOnLoc, 0, fhover == 1 ? C_BLUE0 : C_BLUE2); + else + m_vectorBatch.DrawObject(focusOutline, focusOffLoc, 0, fhover == -1 ? C_BLUE0 : C_BLUE2); +} + +void GameScreen::Message(const std::string& msg) +{ + messages.push_back(msg); +} + +void GameScreen::PlaneMissed(Plane* p) +{ + // draw time panel + char msg[100]; + std::snprintf(msg, 100, "%s MISSED", p->callSign.c_str()); + Message(msg); +} + +void GameScreen::PlaneLanded(Plane* p) +{ + // draw time panel + char msg[100]; + int delay = (int)p->Delay(totalTime); + if(delay < 1) + std::snprintf(msg, 100, "%s ON TIME", p->callSign.c_str()); + else + std::snprintf(msg, 100, "%s DELAYED %02d:%02d", p->callSign.c_str(), delay / 60, delay % 60); + + PlaySoundMulti(landedSound); + Message(msg); +} + +void GameScreen::RemovePlane(Plane* p, PlaneMode mode) +{ + p->mode = mode; + + // clear alerts + if(p->alerts.size()) + { + for(auto p2 : m_game->board->planes) + { + if(p2->alerts.size()) + { + p2->alerts.erase(p->id); + } + } + p->alerts.clear(); + } + + // clear selection + if(p->selected) + { + p->selected = false; + selectedPlane = nullptr; + } +} + +void GameScreen::CheckPlanes() +{ + for(auto p : m_game->board->planes) + { + // if plane is over its exit + if(p->mode != PlaneMode::Exited) + { + if(p->exit->IsAbove(p->position)) + { + if(p->exit->type == ExitType::Exit) + { + // we hit our target corridor, just go away off screen + AddDelay(p); + RemovePlane(p, PlaneMode::Heading); // just go away from the screen + } + else + { + PlaneLanded(p); + AddDelay(p); + RemovePlane(p, PlaneMode::Exited); + } + } + + // disappear planes off the board + if((p->position.x < -BOUND_X || p->position.x > BOUND_X) || (p->position.y < -BOUND_Y || p->position.y > BOUND_Y)) + { + AddDelay(p); + RemovePlane(p, PlaneMode::Exited); + } + + if(p->type != PlaneType::Military) + { + p->areaSpeed = 1.0f; + if(m_game->board->areas.size()) + { + for(auto a : m_game->board->areas) + { + if(a->IsAbove(p->position)) + { + if(a->type == AreaType::Weather) + { + p->areaSpeed = 0.5f; // slow down 2x + if(std::isnan(p->touchTime)) + { + // we need to add as extra delay + p->extraDelay += deltaTime; + } + } + else if(a->type == AreaType::NoFly) + { + m_delay += deltaTime * 3; // 3x delay + p->extraDelay += deltaTime * 3; + } + } + } + } + } + } + } +} + +void GameScreen::CheckCollisions() +{ + if(m_game->m_gameOver) + return; + haveAlerts = false; + for(auto p1 : m_game->board->planes) + { + if(p1->mode == PlaneMode::Exited || p1->incoming || p1->mode == PlaneMode::Heading) + continue; + + for(auto p2 : m_game->board->planes) + { + if(p2->mode == PlaneMode::Exited || p2->incoming || p2->mode == PlaneMode::Heading) + continue; + + if(p1->id < p2->id && (p1->type != PlaneType::Military || p2->type != PlaneType::Military)) // Military can't alert each other + { + float dx = p2->position.x - p1->position.x; + float dy = p2->position.y - p1->position.y; + if(fabsf(dx) < PLANE_ALERT_DIST && fabsf(dy) < PLANE_ALERT_DIST) + { + float d = sqrt(dx * dx + dy * dy); + if(d < PLANE_CRASH_DIST) + { + // crash! + char alertString[40]; + std::snprintf(alertString, 40, "CRASH: %s AND %s", p1->callSign.c_str(), p2->callSign.c_str()); + messages.push_back(alertString); + + m_game->m_gameOver = true; + m_game->m_winner = false; + if(std::isnan(finishTime)) + finishTime = totalTime; + + PlaySoundMulti(endSound); + } + else if(d < PLANE_ALERT_DIST) + { + haveAlerts = true; + // if not already alerted + if(p1->alerts.find(p2->id) == p1->alerts.end() || p2->alerts.find(p1->id) == p2->alerts.end()) + { + m_alerts++; + p1->alerts.insert(p2->id); + p2->alerts.insert(p1->id); + char alertString[40]; + std::snprintf(alertString, 40, "ALERT: %s AND %s", p1->callSign.c_str(), p2->callSign.c_str()); + messages.push_back(alertString); + } + } + } + else if(p1->alerts.size() || p2->alerts.size()) + { + // TODO: don't do every time? + p1->alerts.erase(p2->id); + p2->alerts.erase(p1->id); + } + } + } + } + if(haveAlerts && !IsMusicStreamPlaying(alertMusic)) + PlayMusicStream(alertMusic); + else if(!haveAlerts && IsMusicStreamPlaying(alertMusic)) + StopMusicStream(alertMusic); +} + +void GameScreen::Restart() +{ + m_game->SelectMap(); +} \ No newline at end of file diff --git a/src/GameScreen.h b/src/GameScreen.h new file mode 100644 index 0000000..1428399 --- /dev/null +++ b/src/GameScreen.h @@ -0,0 +1,99 @@ +#include "Screen.h" +#include "AirGame.h" + +enum class MouseState +{ + Default = 0, + SetTarget = 1 +}; + +class GameScreen : public Screen +{ +public: + GameScreen(int no, AirGame* game); + virtual void Load(); + virtual void Enter(); + virtual void Tick(double deltaTime, double totalTime); + virtual void DrawBackground(); + virtual void DrawPixels(Color* framebuffer, Rectangle* rect, bool* fullFrame); + virtual void DrawShapes(); + virtual void DrawVectors(); + virtual void DrawGameOver(); + + virtual void Leave(); + virtual void Unload(); + +private: + void DrawBoard(); + void DrawPanels(); + void Restart(); + void DrawPlane(Plane* plane); + void DrawExit(Exit* exit); + void DrawArea(Area* area); + void CheckPlanes(); + void CheckCollisions(); + void RemovePlane(Plane* p, PlaneMode mode); + void PlaneLanded(Plane* p); + void PlaneMissed(Plane* p); + void AddDelay(Plane* p); + void Message(const std::string& msg); + bool IsHoveringRestartButton(); + bool IsHoveringRestartButton2(); + int IsHoveringSpeedButton(); + int IsHoveringFocusButton(); + + Vector2 ScreenPos(Vector2 modelPos); + + float x_shift, y_shift, zoom; + double mouse_release_time; + Vector2 mouse_click; + MouseState mouse_state; + double totalTime; + double finishTime; + double deltaTime; + VectorObject* exitObj; + VectorObject* airportObj; + VectorObject* planeObj; + VectorObject* planeSelected; + VectorObject* planeTarget; + std::vector messages; + std::map exitObjs; + std::map areaObjs; + Plane* selectedPlane; + float m_delay; + int m_alerts; + int totalDelay; + Sound landedSound; + Sound ackSound; + Sound alertSound; + Sound tickSound; + Sound startSound; + Sound endSound; + Sound winSound; + float mx, my; + int prevGameTime = 0; + bool haveAlerts; + VectorObject* rect; + VectorObject* tri; + VectorObject* circ; + VectorObject* map; + VectorObject* panelBG; + VectorObject* panelGO; + VectorObject* panelGOutline; + VectorObject* restartOutline; + VectorObject* speedOutline; + VectorObject* focusOutline; + VectorObject* airportCircle; + VectorObject* outline; + VectorObject* inlay; + Plane* mousePlane = nullptr; + Color mc = WHITE; + Vector2 restart2Loc {13.5f, 8.2f}; + Vector2 speed1Loc {9.0f, 8.2f}; + Vector2 speed2Loc {9.5f, 8.2f}; + Vector2 speed3Loc {10.0f, 8.2f}; + Vector2 speed4Loc {10.5f, 8.2f}; + Vector2 focusOnLoc {9.5f, 7.2f}; + Vector2 focusOffLoc {11.0f, 7.2f}; + Music alertMusic; +}; diff --git a/src/Screen.cpp b/src/Screen.cpp new file mode 100644 index 0000000..c253869 --- /dev/null +++ b/src/Screen.cpp @@ -0,0 +1,81 @@ +#include "Screen.h" + +Screen::Screen(int no, AirGame* game) : m_game {game}, m_no {no} +{ + m_mouseCursor.AddLine(-0.20f, -0.20f, -0.10f, -0.10f); + m_mouseCursor.AddLine(0.10f, 0.10f, 0.20f, 0.20f); + + m_mouseCursor.AddLine(-0.20f, 0.20f, -0.10f, 0.10f); + m_mouseCursor.AddLine(0.10f, -0.10f, 0.20f, -0.20f); +} + +Screen::~Screen() { } + +void Screen::DrawVectors(float thick) +{ + m_vectorBatch.Thick(thick); + m_vectorBatch.Begin(); + + DrawVectors(); + + m_vectorBatch.End(); +} + +// hAlign/vAlign state which corner (x,y) represent: (-1,-1) = top/left, (1,1) = bottom/right +void Screen::DrawText(const std::string& text, float x, float y, Color c, int hAlign, int vAlign, int zoom, int v) +{ + if(hAlign == 0 || hAlign == 1) + { + float tw = 0; + for(auto ch : text) + { + auto vo = m_game->m_assets->GetChar(ch, zoom); + tw += vo->_width + CHAR_KERNING * zoom; + } + tw -= CHAR_KERNING * zoom; // last char + if(hAlign == 0) + { + if(v) + y += tw / 2; + else + x -= tw / 2; + } + else + { + if(v) + y += tw; + else + x -= tw; + } + } + + if(vAlign == -1) + { + if(v) + x += zoom * CHAR_HEIGHT / 2; + else + y += zoom * CHAR_HEIGHT / 2; + } + else if(vAlign == 1) + { + if(v) + x -= zoom * CHAR_HEIGHT / 2; + else + y -= zoom * CHAR_HEIGHT / 2; + } + + for(auto ch : text) + { + auto vo = m_game->m_assets->GetChar(ch, zoom); + if(v) + { + m_vectorBatch.DrawObject(vo, (Vector2) {x + zoom * CHAR_HEIGHT / 2, y + (vo->_width / 2)}, v ? -90.0f : 0.0f, c); + y -= vo->_width + zoom * CHAR_KERNING; + } + else + { + m_vectorBatch.DrawObject(vo, (Vector2) {x + (vo->_width / 2), y + zoom * CHAR_HEIGHT / 2}, v ? 90.0f : 0.0f, c); + x += vo->_width + zoom * CHAR_KERNING; + } + } +} \ No newline at end of file diff --git a/src/Screen.h b/src/Screen.h new file mode 100644 index 0000000..1d7a441 --- /dev/null +++ b/src/Screen.h @@ -0,0 +1,33 @@ +#pragma once + +#include "AirGame.h" +#include "Assets.h" + +class Screen +{ +protected: + AirGame *m_game; + VectorBatch m_vectorBatch; + VectorObject m_mouseCursor; + + void DrawText(const std::string& text, float x, float y, Color c, int hAlign = 0, int vAlign = 0, int zoom = 1, int v = 0); + + inline Assets* Assets() { return m_game->m_assets; } + +public: + int m_no; + + void DrawVectors(float thick); + + Screen(int no, AirGame* game); + virtual void Load() = 0; + virtual void Enter() = 0; + virtual void Tick(double deltaTime, double totalTime) = 0; + virtual void DrawBackground() = 0; + virtual void DrawPixels(Color* framebuffer, Rectangle *rect, bool* fullFrame) = 0; + virtual void DrawShapes() = 0; + virtual void DrawVectors() = 0; + virtual void Leave() = 0; + virtual void Unload() = 0; + virtual ~Screen(); +}; \ No newline at end of file diff --git a/src/SelectScreen.cpp b/src/SelectScreen.cpp new file mode 100644 index 0000000..acaf72d --- /dev/null +++ b/src/SelectScreen.cpp @@ -0,0 +1,131 @@ +#include "SelectScreen.h" +#include "VectorBatch.h" + +SelectScreen::SelectScreen(int no, AirGame* game) : Screen(no, game) +{ + tokyo = m_game->m_assets->Tokyo(); + tokyo->Scale(tokyo->_s * 0.25f); + sf = m_game->m_assets->SF(); + sf->Scale(sf->_s * 0.25f); + london = m_game->m_assets->London(); + london->Scale(london->_s * 0.25f); + + mapOutline = VectorObject::Rectangle(22 * 0.25f, 18 * 0.25f); + hoverMap = Map::None; + + airport = VectorObject::Circle(0.05f); + + auto b = new Board(Map::None); + for(auto a : b->exits) + { + if(a->type == ExitType::Airport) + { + float xOfs = 32.0f; + if(a->code == "SFO" || a->code == "OAK" || a->code == "SJC") + xOfs = -32.0f; + else if(a->code == "NRT" || a->code == "HND" || a->code == "OKO" || a->code == "IBR") + xOfs = 0; + airports.push_back((Vector2) {a->location.x + xOfs, a->location.y}); + } + } + delete b; +} + +void SelectScreen::Load() +{ + gameMusic = LoadMusicStream("resources/music.ogg"); +} + +void SelectScreen::Enter() +{ + PlayMusicStream(gameMusic); +} + +void SelectScreen::Tick(double deltaTime, double totalTime) +{ + UpdateMusicStream(gameMusic); + + float mx, my; + + mx = m_game->m_mouseX; + my = m_game->m_mouseY; + + hoverMap = Map::None; + if(my >= -1.5f && my <= 5.5f) + { + float w2 = 22 * 0.25f / 2; + //-8 0 8 + if(mx >= -8.0f - w2 && mx <= -8.0f + w2) + hoverMap = Map::SF; + else if(mx >= 0.0f - w2 && mx <= 0.0f + w2) + hoverMap = Map::Tokyo; + else if(mx >= 8.0f - w2 && mx <= 8.0f + w2) + hoverMap = Map::London; + } + + if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && hoverMap != Map::None) + { + m_game->StartMap(hoverMap); + } +} + +void SelectScreen::DrawBackground() { } + +void SelectScreen::DrawPixels(Color* framebuffer, Rectangle* rect, bool* fullFrame) { } + +void SelectScreen::DrawShapes() { } + +void SelectScreen::DrawVectors() +{ + DrawText("AIROBICS", 0.0f, -7.5f, C_BLUE0, 0, 0, 4); + + DrawText("AIR TRAFFIC CONTROLLER TRAINING PROGRAMME", 0.0f, -6.0f, C_BLUE1, 0, 0, 2); + //DrawText("ROUTE PLANES TO AVOID COLLISIONS", 0.0f, -5.5f, C_BLUE1, 0, 0, 1); + + if(m_game->m_flashOn) + DrawText("CHOOSE TRAINING LOCATION", 0.0f, -3.5f, C_BLUE1, 0, 0, 2); + + float ofsY = 2.0f; + Color c; + + // choose map + c = hoverMap == Map::SF ? C_BLUE0 : C_BLUE2; + DrawText("SAN FRANCISCO", -8.0f, -3.0f + ofsY, c, 0, 0, 2); + m_vectorBatch.DrawObject(sf, (Vector2) {-8, 0 + ofsY}, 0, c); + m_vectorBatch.DrawObject(mapOutline, (Vector2) {-8, 0 + ofsY}, 0, c); + DrawText("EASY", -8.0f, 3.0f + ofsY, c, 0, 0, 2); + + c = hoverMap == Map::Tokyo ? C_BLUE0 : C_BLUE2; + DrawText("TOKYO", 0.0f, -3.0f + ofsY, c, 0, 0, 2); + m_vectorBatch.DrawObject(tokyo, (Vector2) {0, 0 + ofsY}, 0, c); + m_vectorBatch.DrawObject(mapOutline, (Vector2) {0, 0 + ofsY}, 0, c); + DrawText("MEDIUM", 0.0f, 3.0f + ofsY, c, 0, 0, 2); + + c = hoverMap == Map::London ? C_BLUE0 : C_BLUE2; + DrawText("LONDON", 8.0f, -3.0f + ofsY, c, 0, 0, 2); + m_vectorBatch.DrawObject(london, (Vector2) {8, 0 + ofsY}, 0, c); + m_vectorBatch.DrawObject(mapOutline, (Vector2) {8, 0 + ofsY}, 0, c); + DrawText("HARD", 8.0f, 3.0f + ofsY, c, 0, 0, 2); + + DrawText("@MAUSIMUS", 15.9f, 8.55f, C_BLUE3, 1, 1, 1); + DrawText("LUDUM DARE 49", 15.9f, 8.9f, C_BLUE3, 1, 1, 1); + + m_vectorBatch.DrawObject(&m_mouseCursor, (Vector2) {m_game->m_mouseX, m_game->m_mouseY}, 0, WHITE); + + // hack in airports + for(const auto& a : airports) + m_vectorBatch.DrawObject(airport, (Vector2) {a.x * 0.25f, a.y * 0.25f + ofsY}, 0, C_BLUE1); + +#ifdef PLATFORM_DESKTOP + DrawText("PRESS F FOR FULLSCREEN", 0.0f, 7.8f, C_BLUE1, 0, 0, 2); +#endif +} + +void SelectScreen::DrawGameOver() { } + +void SelectScreen::Leave() +{ + StopMusicStream(gameMusic); +} + +void SelectScreen::Unload() { } diff --git a/src/SelectScreen.h b/src/SelectScreen.h new file mode 100644 index 0000000..6a3994c --- /dev/null +++ b/src/SelectScreen.h @@ -0,0 +1,29 @@ +#include "Screen.h" +#include "AirGame.h" + +class SelectScreen : public Screen +{ +public: + SelectScreen(int no, AirGame* game); + virtual void Load(); + virtual void Enter(); + virtual void Tick(double deltaTime, double totalTime); + virtual void DrawBackground(); + virtual void DrawPixels(Color* framebuffer, Rectangle* rect, bool* fullFrame); + virtual void DrawShapes(); + virtual void DrawVectors(); + virtual void DrawGameOver(); + + virtual void Leave(); + virtual void Unload(); + +private: + VectorObject* tokyo; + VectorObject* sf; + VectorObject* london; + VectorObject* mapOutline; + VectorObject* airport; + Map hoverMap; + std::vector airports; + Music gameMusic; +}; \ No newline at end of file diff --git a/src/VectorBatch.cpp b/src/VectorBatch.cpp new file mode 100644 index 0000000..bcb1ad0 --- /dev/null +++ b/src/VectorBatch.cpp @@ -0,0 +1,311 @@ +#include "stdafx.h" +#include "rlgl.h" +#include "VectorBatch.h" + +#define BATCH_SIZE 1200 + +Vector2 texCoords[6] = {(Vector2) {1, -1}, (Vector2) {1, 1}, (Vector2) {-1, 1}, (Vector2) {-1, 1}, (Vector2) {-1, -1}, (Vector2) {1, -1}}; + +VectorObject::VectorObject() : _thick(0), _width(0), _height(0), _solid(false), _s(1), _cx(0), _cy(0), _x(0), _y(0) { } + +void VectorObject::AddLine(float x0, float y0, float x1, float y1) +{ + lines.push_back((Vector4) {x0, y0, x1, y1}); +} + +void VectorObject::RenderLine(float x0, float y0, float x1, float y1, float thick) +{ + float dx = x1 - x0; + float dy = y1 - y0; + float len = sqrtf(dx * dx + dy * dy); + dx /= len; + dy /= len; + + // extend each line by half thick + x0 -= dx * 0.5f * thick; + x1 += dx * 0.5f * thick; + y0 -= dy * 0.5f * thick; + y1 += dy * 0.5f * thick; + + const float px = 0.5f * thick * (-dy); + const float py = 0.5f * thick * dx; + + vertices.push_back((Vector2) {x0 + px, y0 + py}); + vertices.push_back((Vector2) {x1 + px, y1 + py}); + vertices.push_back((Vector2) {x1 - px, y1 - py}); + + vertices.push_back((Vector2) {x1 - px, y1 - py}); + vertices.push_back((Vector2) {x0 - px, y0 - py}); + vertices.push_back((Vector2) {x0 + px, y0 + py}); + + len += thick; + len = thick / len; + lengths.push_back(len); + lengths.push_back(len); + lengths.push_back(len); + lengths.push_back(len); + lengths.push_back(len); + lengths.push_back(len); +} + +void VectorObject::RenderSolid() +{ + // render triangles vs center + for(unsigned i = 0; i < lines.size(); i++) + { + float x0 = _s * (lines[i].x - _cx); + float y0 = _s * (lines[i].y - _cy); + float x1 = _s * (lines[i].z - _cx); + float y1 = _s * (lines[i].w - _cy); + + solids.push_back((Vector2) {x0, y0}); + solids.push_back((Vector2) {x1, y1}); + solids.push_back((Vector2) {0, 0}); + } +} + +void VectorObject::Render(float thick) +{ + vertices.clear(); + + if(_solid) + RenderSolid(); + + float maxX = -1000000, minX = 1000000; + float maxY = -1000000, minY = 1000000; + for(unsigned i = 0; i < lines.size(); i++) + { + float x0 = _s * (lines[i].x - _cx); + float y0 = _s * (lines[i].y - _cy); + float x1 = _s * (lines[i].z - _cx); + float y1 = _s * (lines[i].w - _cy); + RenderLine(x0, y0, x1, y1, thick); + maxX = std::max(maxX, std::max(x0, x1)); + minX = std::min(minX, std::min(x0, x1)); + maxY = std::max(maxY, std::max(y0, y1)); + minY = std::min(minY, std::min(y0, y1)); + } + if(_width == 0) // unless overriden + { + _width = maxX - minX; + } + if(_height == 0) // unless overriden + { + _height = maxY - minY; + } + _thick = thick; +} + +void VectorObject::Draw(Color color) +{ + if(solids.size()) + { + rlCheckRenderBatchLimit(solids.size()); + + for(unsigned i = 0; i < solids.size(); i++) + { + rlTexCoord2f(0, 0); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex3f(solids[i].x, solids[i].y, 0); + } + } + + unsigned bc = BATCH_SIZE; + for(unsigned i = 0; i < vertices.size(); i++) + { + if(bc++ == BATCH_SIZE) + { + rlCheckRenderBatchLimit(BATCH_SIZE); + bc = 0; + } + const auto& tc = texCoords[i % 6]; + rlTexCoord2f(tc.x, tc.y); + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex3f(vertices[i].x, vertices[i].y, lengths[i]); + } +} + +void VectorObject::moveTo(double x, double y) +{ + _x = (float)x; + _y = (float)y; +} + +void VectorObject::lineTo(double x, double y) +{ + AddLine((float)_x, (float)_y, (float)x, (float)y); + moveTo(x, y); +} + +void VectorObject::Flip(int x, int y) +{ + for(unsigned i = 0; i < lines.size(); i++) + { + if(x) + { + lines[i].x *= -1; + lines[i].z *= -1; + } + if(y) + { + lines[i].y *= -1; + lines[i].w *= -1; + } + } +} + +void VectorObject::Center(float x, float y) +{ + _cx = x; + _cy = y; +} + +void VectorObject::CenterY(float y) +{ + _cy = y; +} + +void VectorObject::Scale(float s) +{ + _s = s; +} + +void VectorObject::Center() +{ + if(!lines.size()) + return; + + float maxX = -1000000, minX = 1000000, maxY = -1000000, minY = 1000000; + for(unsigned i = 0; i < lines.size(); i++) + { + minX = std::min(minX, std::min(lines[i].x, lines[i].z)); + minY = std::min(minY, std::min(lines[i].y, lines[i].w)); + maxX = std::max(maxX, std::max(lines[i].x, lines[i].z)); + maxY = std::max(maxY, std::max(lines[i].y, lines[i].w)); + } + _cx = (maxX + minX) / 2; + _cy = (maxY + minY) / 2; +} + +VectorObject* VectorObject::Rectangle(float w, float h) +{ + auto vo = new VectorObject(); + vo->lineTo(w, 0); + vo->lineTo(w, h); + vo->lineTo(0, h); + vo->lineTo(0, 0); + vo->Center(); + return vo; +} + +VectorObject* VectorObject::Triangle(float w, float h) +{ + auto vo = new VectorObject(); + vo->lineTo(w, 0); + vo->lineTo(w / 2, h); + vo->lineTo(0, 0); + vo->Center(); + return vo; +} + +VectorObject* VectorObject::Regular(float r, int n, int dotted) +{ + auto vo = new VectorObject(); + vo->moveTo(0, r); + if(dotted) + { + for(int i = 1; i < n + 1; i += 2) + { + float x = r * sin(6.28318531f * i / n); + float y = r * cos(6.28318531f * i / n); + float px = r * sin(6.28318531f * (i - 1) / n); + float py = r * cos(6.28318531f * (i - 1) / n); + vo->AddLine(px, py, x, y); + // vo->lineTo(x, y); + } + } + else + { + for(int i = 1; i < n + 1; i++) + { + float x = r * sin(6.28318531f * i / n); + float y = r * cos(6.28318531f * i / n); + vo->lineTo(x, y); + } + } + vo->Center(); + return vo; +} + +VectorObject* VectorObject::Ellipse(float r1, float r2, int n) +{ + auto vo = new VectorObject(); + vo->moveTo(0, r1); + for(int i = 1; i < n + 1; i++) + { + // i = 0 to n + // need 0 to 0; with 1 in the middle + float rr = 1.0f - fabsf((2.0f * i / n) - 1.0f); + float r = r1 + (r2 - r1) * rr; + float x = r * sin(6.28318531f * i / n); + float y = r * cos(6.28318531f * i / n); + vo->lineTo(x, y); + } + vo->Center(); + return vo; +} + +VectorObject* VectorObject::Circle(float r) +{ + return Regular(r, 32, 0); +} + +VectorObject* VectorObject::DottedCircle(float r) +{ + return Regular(r, 64, 1); +} + +VectorBatch::VectorBatch() : _thick(0.02f) { } + +void VectorBatch::Begin() +{ + //rlSetBlendMode(BLEND_ADDITIVE); + rlDisableBackfaceCulling(); + rlDisableDepthTest(); + rlSetBlendFactors(0, 0, 0x8008); // GL_MAX + rlSetBlendMode(BLEND_CUSTOM); + rlBegin(RL_TRIANGLES); +} + +void VectorBatch::DrawLine(float sx, float sy, float ex, float ey, Color color) +{ + // ad-hoc line + VectorObject lo; + lo.AddLine(sx, sy, ex, ey); + lo.Render(_thick); + lo.Draw(color); +} + +void VectorBatch::DrawObject(VectorObject* obj, Vector2 pos, float rot, Color color) +{ + rlPushMatrix(); + rlTranslatef(pos.x, pos.y, 0); + rlRotatef(rot, 0, 0, 1); + + if(obj->_thick != _thick) + obj->Render(_thick); + + obj->Draw(color); + rlPopMatrix(); +} + +void VectorBatch::Thick(float thick) +{ + _thick = thick; +} + +void VectorBatch::End() +{ + rlEnd(); + rlSetBlendMode(BLEND_ALPHA); +} diff --git a/src/VectorBatch.h b/src/VectorBatch.h new file mode 100644 index 0000000..1130bc2 --- /dev/null +++ b/src/VectorBatch.h @@ -0,0 +1,64 @@ +#pragma once + +class VectorObject +{ +public: + VectorObject(); + void AddLine(float sx, float sy, float ex, float ey); + void Center(float x, float y); // center specific coord + void CenterY(float y); // center y only for text + void Center(); // auto center bounding box + void Flip(int x, int y); + void Scale(float s); // scale + void Render(float thick); + void Draw(Color color); + + // Inkscape + void moveTo(double x, double y); + void lineTo(double x, double y); + void stroke() { } + void beginPath() { } + + // multiple cached versions per thickness? + float _thick; + float _width; + float _height; + bool _solid; + + static VectorObject* Rectangle(float w, float h); + static VectorObject* Triangle(float w, float h); + static VectorObject* Regular(float r, int n, int d); + static VectorObject* Ellipse(float r1, float r2, int n); + static VectorObject* Circle(float r); + static VectorObject* DottedCircle(float r); + + float _s; // scale + float _cx; // center + float _cy; + +private: + void RenderLine(float sx, float sy, float ex, float ey, float thick); + void RenderSolid(); + + float _x; // temporary during construction + float _y; + + std::vector lines; // source lines + std::vector vertices; // rendered triangles + std::vector solids; // rendered solids + std::vector lengths; +}; + +class VectorBatch +{ +public: + VectorBatch(); + void DrawObject(VectorObject* obj, Vector2 pos, float rot, Color color); + void DrawLine(float sx, float sy, float ex, float ey, Color color); // ad-hoc, slow! + void Begin(); + void End(); + + void Thick(float thick); + + float _thick; +}; diff --git a/src/Window.cpp b/src/Window.cpp new file mode 100644 index 0000000..4b569d3 --- /dev/null +++ b/src/Window.cpp @@ -0,0 +1,297 @@ +#include "stdafx.h" +#include "AirGame.h" +#include "utils.h" + +#if defined(PLATFORM_WEB) +#include +#endif + +#if defined(PLATFORM_DESKTOP) +#define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB +#define GLSL_VERSION 100 +#endif + +#ifdef GLOW +#define SHADER_PATH "resources/shaders/glsl%i/glow.fs" +#else +#define SHADER_PATH "resources/shaders/glsl%i/base.fs" +#endif + +bool firstFrame = true; +Shader glowShader; +RenderTexture2D vectorTarget; +RenderTexture2D processingTarget; +Rectangle textureRect {0, 0, 0, 0}; +Rectangle renderRect {0, 0, 0, 0}; +AirGame game; +Vector2 topLeft {0, 0}; +double totalTime; +Camera2D camera; +Shader vectorShader; +float thick; +int axisUniform; +int texture1Location; +int xsUniform; +int ysUniform; +int orgW, orgH; +const int zero = 0; +const int one = 1; +int pw, ph; +const float TIME_SCALE = 2.0f; +double previousTime; + +#ifdef GLOW +bool glow = true; +#else +bool glow = false; +#endif + +#ifdef DRAW_PIXELS +Color framebuffer[screenWidth * screenHeight]; +Rectangle bufferRect; +bool fullFrame; +#endif + +void UpdateDrawFrame(void); + +void UpdateRenderSize(Rectangle& renderRect) +{ + auto viewportWidth = GetScreenWidth(); + auto viewportHeight = GetScreenHeight(); + + if(pw == viewportWidth && ph == viewportHeight) + return; + + TraceLog(LOG_WARNING, "UpdateRenderSize %d %d", viewportWidth, viewportHeight); + + pw = viewportWidth; + ph = viewportHeight; + + renderRect.width = viewportWidth; + renderRect.height = viewportHeight; + if(renderRect.width * aspectV != renderRect.height * aspectH) + { + if(renderRect.width * aspectV > renderRect.height * aspectH) + { + renderRect.width = (renderRect.height * aspectH) / aspectV; + } + else + { + renderRect.height = (renderRect.width * aspectV) / aspectH; + } + } + renderRect.x = (viewportWidth - renderRect.width) / 2; + renderRect.y = (viewportHeight - renderRect.height) / 2; + SetMouseOffset(-renderRect.x, -renderRect.y); + + if(!firstFrame) + { + UnloadRenderTexture(vectorTarget); + UnloadRenderTexture(processingTarget); + } + + vectorTarget = LoadRenderTexture(renderRect.width, renderRect.height); // 16x9 render size + SetTextureFilter(vectorTarget.texture, TEXTURE_FILTER_BILINEAR); + SetTextureWrap(vectorTarget.texture, TEXTURE_WRAP_CLAMP); + + processingTarget = LoadRenderTexture(renderRect.width, renderRect.height); // 16x9 render size + SetTextureFilter(processingTarget.texture, TEXTURE_FILTER_BILINEAR); + SetTextureWrap(processingTarget.texture, TEXTURE_WRAP_CLAMP); + + textureRect.width = renderRect.width; + textureRect.height = -renderRect.height; + + camera.zoom = (renderRect.height / 2) / 9.0f; + camera.offset = (Vector2) {renderRect.width / 2, renderRect.height / 2}; + camera.rotation = 0; + + thick = thickFactor / (renderRect.height / 1000.0f); + + float oneOverWidth = 1 / renderRect.width; + float oneOverHeight = 1 / renderRect.height; + + SetShaderValue(glowShader, xsUniform, &oneOverWidth, SHADER_UNIFORM_FLOAT); + SetShaderValue(glowShader, ysUniform, &oneOverHeight, SHADER_UNIFORM_FLOAT); + + game.Render(thick); +} + +int main() +{ + SetConfigFlags(FLAG_WINDOW_RESIZABLE); + InitWindow(screenWidth, screenHeight, WINDOW_TITLE); + SetWindowState(FLAG_VSYNC_HINT); + InitAudioDevice(); + SetWindowMinSize(screenWidth / 4, screenHeight / 4); + glowShader = LoadShader(0, TextFormat(SHADER_PATH, GLSL_VERSION)); + vectorShader = LoadShader(TextFormat("resources/shaders/glsl%i/base.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/vector.fs", GLSL_VERSION)); + + axisUniform = GetShaderLocation(glowShader, "axis"); + xsUniform = GetShaderLocation(glowShader, "xs"); + ysUniform = GetShaderLocation(glowShader, "ys"); + texture1Location = GetShaderLocation(glowShader, "texture1"); + + std::srand((unsigned)std::time(0)); + + game.Load(); + + UpdateRenderSize(renderRect); + + HideCursor(); + previousTime = GetTime(); + totalTime = previousTime * TIME_SCALE; + game.Start(totalTime); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(TARGET_FPS); + while(!WindowShouldClose()) + { + UpdateDrawFrame(); + } +#endif + + game.End(); + UnloadRenderTexture(vectorTarget); + UnloadRenderTexture(processingTarget); + CloseAudioDevice(); + CloseWindow(); + + return 0; +} + +void UpdateDrawFrame() +{ +#ifdef FULLSCREEN_KEY + if(IsKeyPressed(FULLSCREEN_KEY)) + { +#if defined(PLATFORM_WEB) +// ToggleFullscreen(); +#else + if(IsWindowFullscreen()) + { + ToggleFullscreen(); + SetWindowSize(orgW, orgH); + } + else + { + orgW = GetScreenWidth(); + orgH = GetScreenHeight(); + auto m = GetCurrentMonitor(); + auto w = GetMonitorWidth(m); + auto h = GetMonitorHeight(m); + SetWindowSize(w, h); + ToggleFullscreen(); + } + + UpdateRenderSize(renderRect); +#endif + } +#endif + + if(IsKeyPressed(KEY_ONE)) + { + game.timeScale = 1; + } + if(IsKeyPressed(KEY_TWO)) + { + game.timeScale = 2; + } + if(IsKeyPressed(KEY_THREE)) + { + game.timeScale = 3; + } + if(IsKeyPressed(KEY_FOUR)) + { + game.timeScale = 4; + } +/* + if(IsKeyPressed(KEY_G)) + { + glow = !glow; + } +*/ + game.m_mouseX = 9 * (GetMouseX() - renderRect.width / 2) / (renderRect.height / 2); + game.m_mouseY = 9 * (GetMouseY() - renderRect.height / 2) / (renderRect.height / 2); + + auto currentTime = GetTime(); + auto timeDelta = currentTime - previousTime; + previousTime = currentTime; + + auto scaledDelta = timeDelta * TIME_SCALE * game.timeScale; + totalTime += scaledDelta; + game.Tick(scaledDelta, totalTime); + + bool windowResized = IsWindowResized(); + if(windowResized) + { + UpdateRenderSize(renderRect); + } + + BeginDrawing(); + { + +#ifdef DRAW_BACKGROUND + BeginTextureMode(vectorTarget); + game.DrawBackground(); + EndTextureMode(); +#endif + + /* +#ifdef DRAW_PIXELS + game.DrawPixels(framebuffer, &bufferRect, &fullFrame); + if(fullFrame) + UpdateTexture(target.texture, framebuffer); + else + UpdateTextureRec(target.texture, bufferRect, framebuffer); +#endif +*/ + +#ifdef DRAW_SHAPES + BeginTextureMode(vectorTarget); + ClearBackground(BLACK); + BeginMode2D(camera); + BeginShaderMode(vectorShader); + game.DrawVectors(thick); + EndMode2D(); + EndShaderMode(); + EndTextureMode(); +#endif + + if(glow) + { + BeginTextureMode(processingTarget); + BeginShaderMode(glowShader); + SetShaderValue(glowShader, axisUniform, &zero, SHADER_UNIFORM_INT); + //ClearBackground(BLACK); + DrawTexturePro( + vectorTarget.texture, textureRect, (Rectangle) {0, 0, textureRect.width, -textureRect.height}, (Vector2) {0, 0}, 0, WHITE); + EndShaderMode(); + EndTextureMode(); + + BeginShaderMode(glowShader); + SetShaderValue(glowShader, axisUniform, &one, SHADER_UNIFORM_INT); + SetShaderValueTexture(glowShader, texture1Location, vectorTarget.texture); + if(windowResized || firstFrame) + { + ClearBackground(BLACK); + firstFrame = false; + } + DrawTexturePro(processingTarget.texture, textureRect, renderRect, topLeft, 0, WHITE); + EndShaderMode(); + } + else + { + if(windowResized || firstFrame) + { + ClearBackground(BLACK); + firstFrame = false; + } + DrawTexturePro(vectorTarget.texture, textureRect, renderRect, topLeft, 0, WHITE); + } + EndDrawing(); + } +} \ No newline at end of file diff --git a/src/stdafx.h b/src/stdafx.h new file mode 100644 index 0000000..3170b7c --- /dev/null +++ b/src/stdafx.h @@ -0,0 +1,17 @@ +#pragma once + +#include "raylib.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr float pi = 3.141592f; +constexpr float pi2 = pi / 2; +constexpr float twopi = 2 * pi;