From f1245c70297eb1d52f13c395fa67ec65bc6e3b38 Mon Sep 17 00:00:00 2001 From: String Date: Sun, 14 Sep 2025 21:49:32 -0500 Subject: [PATCH 1/3] Finally fixed the shaders + added new ones (holy shit) --- .gitignore | 3 +- .prettierignore | 3 +- .vscode/settings.json | 1 + COMPILING.md | 70 +- assets/shaders/ntsc.frag | 193 ++ assets/shaders/skew.frag | 29 + assets/shaders/vcrlines.frag | 81 + project.hxp | 1922 +++++++++-------- setup/install-libs-macos-linux.sh | 19 + setup/install-libs-windows.bat | 20 + source/InitState.hx | 61 +- source/starcore/backend/util/FlixelUtil.hx | 77 +- source/starcore/shaders/GrainShader.hx | 6 +- source/starcore/shaders/GrayscaleShader.hx | 7 +- source/starcore/shaders/HueShiftShader.hx | 4 +- source/starcore/shaders/NTSCShader.hx | 13 + source/starcore/shaders/ScanlineShader.hx | 4 +- source/starcore/shaders/SkewShader.hx | 13 + source/starcore/shaders/TiltshiftShader.hx | 4 +- source/starcore/shaders/VCRLinesShader.hx | 19 + source/starcore/shaders/VCRMario85Shader.hx | 4 +- .../starcore/shaders/bases/UpdatedShader.hx | 21 + 22 files changed, 1517 insertions(+), 1057 deletions(-) create mode 100644 assets/shaders/ntsc.frag create mode 100644 assets/shaders/skew.frag create mode 100644 assets/shaders/vcrlines.frag create mode 100644 setup/install-libs-macos-linux.sh create mode 100644 setup/install-libs-windows.bat create mode 100644 source/starcore/shaders/NTSCShader.hx create mode 100644 source/starcore/shaders/SkewShader.hx create mode 100644 source/starcore/shaders/VCRLinesShader.hx create mode 100644 source/starcore/shaders/bases/UpdatedShader.hx diff --git a/.gitignore b/.gitignore index 5b271f2..5dc73c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # HaxeFlixel -export/ dump/ +export/ +.haxelib/ # macOS .DS_Store diff --git a/.prettierignore b/.prettierignore index 0a972be..419d53b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ # Ignore artifacts -export/ dump/ +export/ +.haxelib/ diff --git a/.vscode/settings.json b/.vscode/settings.json index d9dcb3c..96d4664 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,6 +22,7 @@ "Haxe", "IBEAM", "keybinds", + "NTSC", "NUMPADEIGHT", "NUMPADFIVE", "NUMPADFOUR", diff --git a/COMPILING.md b/COMPILING.md index 4c3cf13..3831a7d 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -1,27 +1,61 @@ -# 1. Downloading Your Environment +# How to Compile Starcore's Source Code -If you don't have it already, it is strongly advised that you download [VS Code](https://code.visualstudio.com/), as -it has great support for HaxeFlixel! +This guide will provide you every step needed to compile and run Starcore. +__**Please read and follow each step carefully in order for the game to compile and run successfully.**__ -(Note that when you download the game's code and open it in VS Code, some recommended extensions will pop up in -your notifications. Make sure to ***NOT*** ignore those and download those extensions, as -they will greatly help you with development!) +## Global Setup (Every Platform) -# 2. Running the Setup File +These are the necessary steps required to compile the game on __***every***__ platform. If you're on either Windows, macOS, or Linux, then read the applicable sub section in section `Extra Steps (for Running and Configuring the Game on Other Platforms)` below. -This game uses a programming language/game engine called [HaxeFlixel](https://haxeflixel.com/). -It's very robust and has extremely similar syntax to many programming languages (mostly Java), so -if you have any kind of experience with a language that uses block coding (coding with braces `{}`), -then it will be very easy to adapt to if you want to learn it! +1. Download the [Haxe programming language](https://haxe.org/download/version/4.3.6). + - When you download the necessary installer, just use the default options and configurations. -Simply read the [`README.txt`](setup/README.txt/) file in the [setup](setup/) folder and follow the simple instructions it provides. +2. Download the [Git version control software made by GitHub](https://www.git-scm.com). + - Similar to when you installed Haxe, just simply use the default configurations when going through the installer. -# 3. Building the Game +3. Open your operating system's terminal (or Command Prompt, if you're a Windows user). -To actually build and run the game, simply select the -build type (desktop STRONGLY recommended). You can find it at the bottom left -corner of the editor. +4. Run `cd path/of/your/clone/here`. This is where the game's code will be stored, with `path/of/your/clone/here` being the folder location. -![Build Type Location](docs/build-type-loc.png/) +> [!TIP] +> If you're on Windows, it's recommended for your clone's code to be placed in your Documents folder (or, if you have GitHub Desktop installed, in `Documents/GitHub`). -Once you're ready, press `Ctrl` + `Shift` + `B` and the game will start building! +5. Run `git clone https://github.com/stringfromjava/Starcore.git` to install the game's code. **Note that this might take a while depending on your internet speed**. + +6. When it is done installing, run `cd Starcore` to set the path to be the game's source code. + +> [!IMPORTANT] +> When you need to run a command for the game, make sure your terminal's current directory is set to be the game's code (that's what the `cd` command is for). This also applies for when you are compiling the game with the `lime` command, which we will install in a little bit. + +7. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install **Haxe Module Manager** (this is the library that will automatically install all of the game's dependencies). + +8. Run `hmm install` to start installing all of the game's dependencies. **This will take a bit, so be patient**. + +> [!TIP] +> If the libraries do not install correctly, then you can run the `.bat` file or `.sh` file (according to your sysrtem) + +9. Run `haxelib run lime setup` to setup the lime command. + - This will allow you to compile and run the game on many common platforms, such as every major desktop platform (Windows, macOS, Linux, etc.), both popular mobile systems (Android and iOS), and more. + +10. Run `lime test html5 --connect 6000` to compile and run the game on the web. + - You can find the compiled code in the `export/test` folder. + +> [!TIP] +> You can replace `html5` with other platforms to compile it accordingly. + +## Extra Steps (for Running and Configuring the Game on Other Platforms) + +### Windows + +1. Navigate to the [setup](setup/) folder and run the `msvs-setup.bat` file to install Visual Studio. + - This will install everything needed to compile the game to become a Windows application. **This can take a while, so please be patient.** + +2. When it is done installing, you can then run `lime test windows --connect 6000` to compile the game for Windows. + +### macOS + +You can learn how to compile the game for macOS [here](https://lime.openfl.org/docs/advanced-setup/macos/). + +### Linux + +You can learn how to compile the game for Linux [here](https://lime.openfl.org/docs/advanced-setup/linux/). diff --git a/assets/shaders/ntsc.frag b/assets/shaders/ntsc.frag new file mode 100644 index 0000000..8c66061 --- /dev/null +++ b/assets/shaders/ntsc.frag @@ -0,0 +1,193 @@ +#pragma header + +#pragma format R8G8B8A8_SRGB + +#define NTSC_CRT_GAMMA 2.5 +#define NTSC_MONITOR_GAMMA 2.0 + +#define TWO_PHASE +#define COMPOSITE +//#define THREE_PHASE +// #define SVIDEO + +// begin params +#define PI 3.14159265 + +#if defined(TWO_PHASE) + #define CHROMA_MOD_FREQ (4.0 * PI / 15.0) +#elif defined(THREE_PHASE) + #define CHROMA_MOD_FREQ (PI / 3.0) +#endif + +#if defined(COMPOSITE) + #define SATURATION 1.0 + #define BRIGHTNESS 1.0 + #define ARTIFACTING 1.0 + #define FRINGING 1.0 +#elif defined(SVIDEO) + #define SATURATION 1.0 + #define BRIGHTNESS 1.0 + #define ARTIFACTING 0.0 + #define FRINGING 0.0 +#endif +// end params + +uniform int uFrame; +uniform float uInterlace; + +// fragment compatibility #defines + +#if defined(COMPOSITE) || defined(SVIDEO) +mat3 mix_mat = mat3( + BRIGHTNESS, FRINGING, FRINGING, + ARTIFACTING, 2.0 * SATURATION, 0.0, + ARTIFACTING, 0.0, 2.0 * SATURATION +); +#endif + +// begin ntsc-rgbyuv +const mat3 yiq2rgb_mat = mat3( + 1.0, 0.956, 0.6210, + 1.0, -0.2720, -0.6474, + 1.0, -1.1060, 1.7046); + +vec3 yiq2rgb(vec3 yiq) +{ + return yiq * yiq2rgb_mat; +} + +const mat3 yiq_mat = mat3( + 0.2989, 0.5870, 0.1140, + 0.5959, -0.2744, -0.3216, + 0.2115, -0.5229, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return col * yiq_mat; +} +// end ntsc-rgbyuv + +#define TAPS 32 +const float luma_filter[TAPS + 1] = float[TAPS + 1]( + -0.000174844, + -0.000205844, + -0.000149453, + -0.000051693, + 0.000000000, + -0.000066171, + -0.000245058, + -0.000432928, + -0.000472644, + -0.000252236, + 0.000198929, + 0.000687058, + 0.000944112, + 0.000803467, + 0.000363199, + 0.000013422, + 0.000253402, + 0.001339461, + 0.002932972, + 0.003983485, + 0.003026683, + -0.001102056, + -0.008373026, + -0.016897700, + -0.022914480, + -0.021642347, + -0.008863273, + 0.017271957, + 0.054921920, + 0.098342579, + 0.139044281, + 0.168055832, + 0.178571429); + +const float chroma_filter[TAPS + 1] = float[TAPS + 1]( + 0.001384762, + 0.001678312, + 0.002021715, + 0.002420562, + 0.002880460, + 0.003406879, + 0.004004985, + 0.004679445, + 0.005434218, + 0.006272332, + 0.007195654, + 0.008204665, + 0.009298238, + 0.010473450, + 0.011725413, + 0.013047155, + 0.014429548, + 0.015861306, + 0.017329037, + 0.018817382, + 0.020309220, + 0.021785952, + 0.023227857, + 0.024614500, + 0.025925203, + 0.027139546, + 0.028237893, + 0.029201910, + 0.030015081, + 0.030663170, + 0.031134640, + 0.031420995, + 0.031517031); + +vec4 pass1(vec2 uv) +{ + vec2 fragCoord = uv * openfl_TextureSize; + + vec4 cola = texture2D(bitmap, uv).rgba; + vec3 yiq = rgb2yiq(cola.rgb); + + #if defined(TWO_PHASE) + float chroma_phase = PI * (mod(fragCoord.y, 2.0) + float(uFrame)); + #elif defined(THREE_PHASE) + float chroma_phase = 0.6667 * PI * (mod(fragCoord.y, 3.0) + float(uFrame)); + #endif + + float mod_phase = chroma_phase + fragCoord.x * CHROMA_MOD_FREQ; + + float i_mod = cos(mod_phase); + float q_mod = sin(mod_phase); + + if(uInterlace == 1.0) { + yiq.yz *= vec2(i_mod, q_mod); // Modulate. + yiq *= mix_mat; // Cross-talk. + yiq.yz *= vec2(i_mod, q_mod); // Demodulate. + } + return vec4(yiq, cola.a); +} + +vec4 fetch_offset(vec2 uv, float offset, float one_x) { + return pass1(uv + vec2((offset - 0.5) * one_x, 0.0)).xyzw; +} + +void main() +{ + vec2 uv = openfl_TextureCoordv; + vec2 fragCoord = uv * openfl_TextureSize; + + float one_x = 1.0 / openfl_TextureSize.x; + vec4 signal = vec4(0.0); + + for (int i = 0; i < TAPS; i++) + { + float offset = float(i); + + vec4 sums = fetch_offset(uv, offset - float(TAPS), one_x) * 2; + + signal += sums * vec4(luma_filter[i], chroma_filter[i], chroma_filter[i], 1.0); + } + signal += pass1(uv - vec2(0.5 / openfl_TextureSize.x, 0.0)).xyzw * + vec4(luma_filter[TAPS], chroma_filter[TAPS], chroma_filter[TAPS], 1.0); + + vec3 rgb = yiq2rgb(signal.xyz); + gl_FragColor = vec4(pow(rgb, vec3(NTSC_CRT_GAMMA / NTSC_MONITOR_GAMMA)), flixel_texture2D(bitmap, uv).a); +} \ No newline at end of file diff --git a/assets/shaders/skew.frag b/assets/shaders/skew.frag new file mode 100644 index 0000000..1448043 --- /dev/null +++ b/assets/shaders/skew.frag @@ -0,0 +1,29 @@ +//SHADERTOY PORT FIX +#pragma header +vec2 uv = openfl_TextureCoordv.xy; +vec2 fragCoord = openfl_TextureCoordv*openfl_TextureSize; +vec2 iResolution = openfl_TextureSize; +uniform float iTime; +#define iChannel0 bitmap +#define texture flixel_texture2D +#define fragColor gl_FragColor +#define mainImage main +//SHADERTOY PORT FIX + +uniform float skew = 0.0; + + + +float lerpp(float a, float b, float t){ + return a + (b - a) * t; +} +void main(void){ + float dfb = uv.y; + vec4 c = vec4(0.0,0.0,0.0,0.0); + vec2 pos = uv; + pos.x = uv.x+(skew*dfb); + if(pos.x > 0 && pos.x < 1){ + gl_FragColor = flixel_texture2D( bitmap, pos); + } + +} diff --git a/assets/shaders/vcrlines.frag b/assets/shaders/vcrlines.frag new file mode 100644 index 0000000..25d99bc --- /dev/null +++ b/assets/shaders/vcrlines.frag @@ -0,0 +1,81 @@ +#pragma header + +#ifdef GL_ES +precision mediump float; +#endif + +uniform float time; +uniform vec2 resolution; + +float pi = 3.14159265359; +float curvature = 0.065; +float vignetteStrength = 0.4; +float theScanLine = 0.0; + +vec2 curve(vec2 inp) +{ + inp.x = inp.x - sin(inp.y * pi) * curvature * (inp.x - 0.5); + inp.y = inp.y - sin(inp.x * pi) * curvature * (inp.y - 0.5); + return inp; +} + +vec2 zoomOut(vec2 inp) +{ + float zoom = 1.0 + 1.3 * curvature; + return vec2(0.5, 0.5) + ((inp - vec2(0.5, 0.5)) * zoom); +} + +float lerp(float a, float b, float c) +{ + return a + c * (b - a); +} + +vec4 vignette(vec2 inp) +{ + float t = 0.0; + t = lerp(0.5, vignetteStrength * distance(inp, vec2(0.5, 0.5)), 0.98); + return vec4(t, t, t, 1.0); +} + +vec4 staticc(vec2 inp) +{ + float t = 0.0; + t = cos(inp.y * resolution.y) * 2.0; + + float val = sin(100.0 + time * cos(100.0 + time) * 2.0) * 14.0 * inp.y; + val = clamp(val, -1.55, 1.55); + t += tan(val) * 0.05; + + return vec4(t, t, t, 1.0); +} + +bool inRect(vec2 rect, vec2 rectDim, vec2 inp) +{ + vec2 clamped = clamp(inp, rect, rectDim); + return (clamped.x == inp.x && clamped.y == inp.y); +} + +void main(void) +{ + vec2 uv = zoomOut(curve(openfl_TextureCoordv.xy)); + vec4 col; + theScanLine = sin(time * pi + uv.y) + tan(time - uv.y * uv.y) - cos(uv.y); + + if (inRect(vec2(0.0, 0.0), vec2(1.0, 1.0), uv)) + { + if (inRect(vec2(0.0, theScanLine), vec2(1.0, theScanLine + 0.1), uv)) + uv.x -= sin(theScanLine - uv.y) * 0.04; // Scanline distortion is determined by the last number + + // FIXED: use `bitmap` and `texture` + col = texture(bitmap, uv); + + col -= vignette(uv); + col += staticc(uv) * 0.015; + } + else + { + col = vec4(0.0, 0.0, 0.0, 1.0); + } + + gl_FragColor = col; +} diff --git a/project.hxp b/project.hxp index 85ae40f..bd55c57 100644 --- a/project.hxp +++ b/project.hxp @@ -16,853 +16,859 @@ using StringTools; @:nullSafety class Project extends HXProject { - // - // METADATA - // =========================== - - /** - * The game's version number, as a Semantic Versioning string with no prefix. - * REMEMBER TO CHANGE THIS WHEN THE GAME UPDATES! - * You only have to change it here, the rest of the game will query this value. - */ - static final VERSION:String = '0.1.0-prealpha'; - - /** - * The game's name. Used as the default window title. - */ - static final TITLE:String = 'Starcore'; - - /** - * The name of the generated executable file. - * For example, `STARCORE` will create a file called `STARCORE.exe`. - */ - static final EXECUTABLE_NAME:String = 'STARCORE'; - - /** - * The relative location of the source code. - */ - static final SOURCE_DIR:String = 'source'; - - /** - * The fully qualified class path for the game's preloader. - * Particularly important on HTML5 but it's used on all platforms. - */ - static final PRELOADER:String = 'flixel.system.FlxPreloader'; - - /** - * A package name used for identifying the app on various app stores. - */ - static final PACKAGE_NAME:String = 'com.bitmapstudios.starcore'; - - /** - * The fully qualified class path for the entry point class to execute when launching the game. - * It's where `public static function main():Void` goes. - */ - static final MAIN_CLASS:String = 'Main'; - - /** - * The company name for the game. - * This appears as metadata in many places. - */ - static final COMPANY:String = 'BitMap Studios'; - - /** - * Path to the Haxe script run before building the game. - */ - // static final PREBUILD_HX:String = 'source/Prebuild.hx'; - /** - * Path to the Haxe script run after building the game. - */ - // static final POSTBUILD_HX:String = 'source/Postbuild.hx'; - - /** - * Asset path globs to always exclude from asset libraries. - */ - static final EXCLUDE_ASSETS:Array = ['.*', 'cvs', 'thumbs.db', 'desktop.ini', '*.hash', '*.md']; - - /** - * Asset path globs to exclude on web platforms. - */ - static final EXCLUDE_ASSETS_WEB:Array = ['*.ogg']; - - /** - * Asset path globs to exclude on native platforms. - */ - static final EXCLUDE_ASSETS_NATIVE:Array = ['*.mp3']; - - // - // FEATURE FLAGS - // ========================================== - - /** - * Allows the game to be displayed in the user's Discord "Activity" box - * (it can still be disabled by the user in-game if the option is off). - */ - static final DISCORD_RPC_ALLOWED:FeatureFlag = 'DISCORD_RPC_ALLOWED'; - - /** - * Enables the game to use advanced shaders, giving it a more unsettling and unnerving vibe. - * Sort of like the analog horror videos you see on YouTube. - */ - static final ADVANCED_SHADERS_ALLOWED:FeatureFlag = 'ADVANCED_SHADERS_ALLOWED'; - - /** - * Allows the developer(s) to use built-in editors, - * such as creating animations for entities. - */ - static final DEBUG_EDITORS_ALLOWED:FeatureFlag = 'DEBUG_EDITORS_ALLOWED'; - - /** - * Permits the game to use a built-in logging system, which writes all - * current logs to a new text file inside of a folder called `logs`, - * located in the games output folder. - */ - static final LOGGING_ALLOWED:FeatureFlag = 'LOGGING_ALLOWED'; - - /** - * Enables the game to programmatically change sounds and add - * all kinds of effects to them. - */ - static final SOUND_FILTERS_ALLOWED:FeatureFlag = 'SOUND_FILTERS_ALLOWED'; - - public function new() - { - super(); - - flair(); - configureApp(); - - displayTarget(); - configureOutputDir(); - configureFeatureFlags(); - configureCompileDefines(); - configureHaxelibs(); - configureAssets(); - configureIcons(); // TODO: Implement code when icons are made! - } - - /** - * Display some fancy info before initializing. - */ - function flair() - { - info('STARCORE'); - info('Setting up build...'); - info('Target Version: ' + VERSION); - info('Git Branch: ' + getGitBranch()); - info('Git Commit: ' + getGitCommit()); - info('Git Modified? ' + getGitModified()); - info('Display? ' + isDisplay()); - info('-------------------------------------------------------------'); - } - - /** - * Apply basic project metadata, such as the game title and version number, - * as well as info like the package name and company (used by various app stores). - */ - function configureApp() - { - // - // METADATA - // ====================================== - this.meta.title = TITLE; - this.meta.version = VERSION; - this.meta.packageName = PACKAGE_NAME; - this.meta.company = COMPANY; - this.meta.description = 'A space themed, open world survival sandbox game.'; - this.meta.companyId = COMPANY; - this.meta.companyUrl = COMPANY; - - // - // CODE - // ================================= - this.sources.push(SOURCE_DIR); // Source code location (more than one can be added) - - // - // PREBUILD & POSTBUILD - // ================================================== - // this.preBuildCallbacks.push(buildHaxeCLICommand(PREBUILD_HX)); - // this.postBuildCallbacks.push(buildHaxeCLICommand(POSTBUILD_HX)); - - // - // APP - // ========================== - this.app.main = MAIN_CLASS; - this.app.preloader = PRELOADER; - this.app.file = EXECUTABLE_NAME; - // These values are only used by the SWF target - // this.app.path - // this.app.init - // this.app.swfVersion - // this.app.url - - // - // WINDOW - // ===================================== - this.window.fps = 60; - this.window.width = (!isMobile()) ? 960 : 0; - this.window.height = (!isMobile()) ? 720 : 0; - this.window.background = 0xFF000000; - this.window.fullscreen = true; - this.window.resizable = isWeb(); - this.window.orientation = (isDesktop() || isMobile()) ? Orientation.LANDSCAPE : Orientation.AUTO; - this.window.hardware = true; - this.window.vsync = false; - this.window.allowHighDPI = true; // Force / allow high DPI - } - - /** - * Log information about the configured target platform. - */ - function displayTarget() - { - // Display the target operating system - switch (this.target) - { - case Platform.WINDOWS: - info('Target Platform: Windows'); - case Platform.MAC: - info('Target Platform: MacOS'); - case Platform.LINUX: - info('Target Platform: Linux'); - case Platform.ANDROID: - info('Target Platform: Android'); - case Platform.IOS: - info('Target Platform: IOS'); - case Platform.HTML5: - info('Target Platform: HTML5'); - // See lime.tools.Platform for a full list - // case Platform.EMSCRITEN: - // case Platform.AIR: - // case Platform.BLACKBERRY: - // case Platform.CONSOLE_PC: - // case Platform.FIREFOX: - // case Platform.FLASH: - // case Platform.PS3: - // case Platform.PS4: - // case Platform.TIZEN: - // case Platform.TVOS: - // case Platform.VITA: - // case Platform.WEBOS: - // case Platform.WIIU: - // case Platform.XBOX1: - default: - error('Unsupported platform (got ${target})'); - } - - switch (this.platformType) - { - case PlatformType.DESKTOP: - info('Target Platform Type: Desktop'); - case PlatformType.MOBILE: - info('Target Platform Type: Mobile'); - case PlatformType.WEB: - info('Target Platform Type: Web'); - case PlatformType.CONSOLE: - info('Target Platform Type: Console'); - default: - error('Unknown target platform type (got ${platformType})'); - } - - // Print whether we are using HXCPP, HashLink, or something else - if (isWeb()) - { - info('Target Language: JavaScript (HTML5)'); - } - else if (isHashLink()) - { - info('Target Language: HashLink'); - } - else if (isNeko()) - { - info('Target Language: Neko'); - } - else if (isJava()) - { - info('Target Language: Java'); - } - else if (isNodeJS()) - { - info('Target Language: JavaScript (NodeJS)'); - } - else if (isCSharp()) - { - info('Target Language: C#'); - } - else if (isCPlusPlus()) - { - info('Target Language: C++'); - } - else - { - info('Target Language: Unknown'); - } - - for (arch in this.architectures) - { - // Display the list of target architectures - switch (arch) - { - case Architecture.X86: - info('Architecture: x86'); - case Architecture.X64: - info('Architecture: x64'); - case Architecture.ARMV5: - info('Architecture: ARMv5'); - case Architecture.ARMV6: - info('Architecture: ARMv6'); - case Architecture.ARMV7: - info('Architecture: ARMv7'); - case Architecture.ARMV7S: - info('Architecture: ARMv7S'); - case Architecture.ARM64: - info('Architecture: ARMx64'); - case Architecture.MIPS: - info('Architecture: MIPS'); - case Architecture.MIPSEL: - info('Architecture: MIPSEL'); - case null: - if (!isWeb()) - { - error('Unsupported architecture (got null on non-web platform)'); - } - else - { - info('Architecture: Web'); - } - default: - error('Unsupported architecture (got ${arch})'); - } - } - } - - /** - * Apply various feature flags based on the target platform and the user-provided build flags. - */ - function configureFeatureFlags() - { - // Enable Discord rich presence - // (works only for Windows) - DISCORD_RPC_ALLOWED.apply(this, isWindows()); - - // Enable dope ass screen filters - // (if the platform is on desktop) - ADVANCED_SHADERS_ALLOWED.apply(this, isDesktop()); - - // Enable the editors if the game is in debug mode, - // otherwise, disable them of course - DEBUG_EDITORS_ALLOWED.apply(this, isDesktop() && isDebug()); - - // Enables dope ass logging - // (only works on desktop) - LOGGING_ALLOWED.apply(this, isDesktop()); - - // Allows the game to programmatically change sounds - // (only works on desktop) - SOUND_FILTERS_ALLOWED.apply(this, isDesktop()); - - info('-------------------------------------------------------------'); - } - - /** - * Set compilation flags which are not feature flags. - */ - function configureCompileDefines() - { - // Enable OpenFL's error handler - // Required for the crash logger - setHaxedef('openfl-enable-handle-error'); - - // Enable stack trace tracking. Good for debugging but has a (minor) performance impact - setHaxedef('HXCPP_CHECK_POINTER'); - setHaxedef('HXCPP_STACK_LINE'); - setHaxedef('HXCPP_STACK_TRACE'); - setHaxedef('hscriptPos'); - - setHaxedef('safeMode'); - - // Disable the built in pause screen when unfocusing the game - setHaxedef('FLX_NO_FOCUS_LOST_SCREEN'); - - // Disable the Flixel debugger entirely, since it - // messes with the filters sometimes - setHaxedef('FLX_NO_DEBUG'); - - if (isRelease()) - { - // Improve performance on Nape - setHaxedef('NAPE_RELEASE_BUILD'); - } - - // Cleaner looking compiler errors - setHaxedef('message.reporting', 'pretty'); - } - - function configureOutputDir() - { - // Set the output directory - // Depends on the target platform and build type - var buildDir = 'export/${isDebug() ? 'debug' : isRelease() ? 'release' : 'test'}'; - buildDir += '/'; - info('Output Directory: $buildDir'); - app.path = buildDir; - info('-------------------------------------------------------------'); - } - - function configureHaxelibs() - { - // - // FLIXEL - // ================== - - // Convert the game to run on other platforms - addHaxelib('lime'); - // Many frontend and backend utilities for the game's display - addHaxelib('openfl'); - // Core game library - addHaxelib('flixel'); - // Additional utilities for Flixel - addHaxelib('flixel-addons'); - // VSCode debug support - if (isDebug()) - { - addHaxelib('hxcpp-debug-server'); - } - - // - // CUSTOM - // =================== - - // Manipulating sound effects programmatically - if (SOUND_FILTERS_ALLOWED.isEnabled(this)) - { - addHaxelib('flxsoundfilters'); - } - - // Discord rich presence - if (DISCORD_RPC_ALLOWED.isEnabled(this)) - { - addHaxelib('hxdiscord_rpc'); - } - } - - function configureAssets() - { - // Add font assets - addAssetPath('assets/fonts', 'assets/fonts', 'default', ['*.ttf'], []); - - // Add entity assets - addAssetPath('assets/entities/data', 'assets/entities/data', 'default', ['*.json'], []); - addAssetPath('assets/entities/textures', 'assets/entities/textures', 'default', ['*.png', '*.xml'], []); - - // Add tile assets - addAssetPath('assets/tiles/data', 'assets/tiles/data', 'default', ['*.json'], []); - addAssetPath('assets/tiles/textures', 'assets/tiles/textures', 'default', ['*.png'], []); - - // Add shared image assets - addAssetPath('assets/shared/images', 'assets/shared/images', 'default', ['*.png'], []); - - // Add shader frag assets - addAssetPath('assets/shaders', 'assets/shaders', 'default', ['*.frag'], []); - - // Add shared music and sound assets for web (.mp3) - if (isWeb()) - { - addAssetPath('assets/shared/music', 'assets/shared/music', 'default', ['*.mp3'], ['*.ogg']); - addAssetPath('assets/shared/sounds', 'assets/shared/sounds', 'default', ['*.mp3'], ['*.ogg']); - } - - // Add shared music and sound assets for desktop (.ogg) - if (isDesktop()) - { - addAssetPath('assets/shared/music', 'assets/shared/music', 'default', ['*.ogg'], ['*.mp3']); - addAssetPath('assets/shared/sounds', 'assets/shared/sounds', 'default', ['*.ogg'], ['*.mp3']); - } - - info('-------------------------------------------------------------'); - } - - /** - * Configure the application's favicon and executable icon. - */ - function configureIcons() {} - - // - // HELPER FUNCTIONS - // (Easy functions to make the code more readable) - // ======================================================================== - - public function isWeb():Bool - { - return this.platformType == PlatformType.WEB; - } - - public function isMobile():Bool - { - return this.platformType == PlatformType.MOBILE; - } - - public function isDesktop():Bool - { - return this.platformType == PlatformType.DESKTOP; - } - - public function isConsole():Bool - { - return this.platformType == PlatformType.CONSOLE; - } - - public function is32Bit():Bool - { - return this.architectures.contains(Architecture.X86); - } - - public function is64Bit():Bool - { - return this.architectures.contains(Architecture.X64); - } - - public function isWindows():Bool - { - return this.target == Platform.WINDOWS; - } - - public function isMac():Bool - { - return this.target == Platform.MAC; - } - - public function isLinux():Bool - { - return this.target == Platform.LINUX; - } - - public function isAndroid():Bool - { - return this.target == Platform.ANDROID; - } - - public function isIOS():Bool - { - return this.target == Platform.IOS; - } - - public function isHashLink():Bool - { - return this.targetFlags.exists('hl'); - } - - public function isNeko():Bool - { - return this.targetFlags.exists('neko'); - } - - public function isJava():Bool - { - return this.targetFlags.exists('java'); - } - - public function isNodeJS():Bool - { - return this.targetFlags.exists('nodejs'); - } - - public function isCSharp():Bool - { - return this.targetFlags.exists('cs'); - } - - public function isCPlusPlus():Bool - { - return this.defines.exists('cpp'); // Why in defines and not target flags... - } - - public function isDisplay():Bool - { - return this.command == 'display'; - } - - public function isDebug():Bool - { - return this.debug; - } - - public function isRelease():Bool - { - return this.defines.exists('final'); - } - - public function getHaxedef(name:String):Null - { - return this.haxedefs.get(name); - } - - public function setHaxedef(name:String, ?value:String):Void - { - if (value == null) - value = ''; - - this.haxedefs.set(name, value); - } - - public function unsetHaxedef(name:String):Void - { - this.haxedefs.remove(name); - } - - public function getDefine(name:String):Null - { - return this.defines.get(name); - } - - public function hasDefine(name:String):Bool - { - return this.defines.exists(name); - } - - /** - * Add a library to the list of dependencies for the project. - * - * @param name The name of the library to add. - * @param version The version of the library to add. Optional. - */ - public function addHaxelib(name:String, version:String = ''):Void - { - this.haxelibs.push(new Haxelib(name, version)); - } - - /** - * Add a `haxeflag` to the project. - */ - public function addHaxeFlag(value:String):Void - { - this.haxeflags.push(value); - } - - /** - * Call a Haxe build macro. - */ - public function addHaxeMacro(value:String):Void - { - addHaxeFlag('--macro ${value}'); - } - - /** - * Add an icon to the project. - * - * @param icon The path to the icon. - * @param size The size of the icon. Optional. - */ - public function addIcon(icon:String, ?size:Int):Void - { - this.icons.push(new Icon(icon, size)); - } - - /** - * Add an asset to the game build. - * - * @param path The path the asset is located at. - * @param rename The path the asset should be placed. - * @param library The asset library to add the asset to. `null` = 'default' - * @param embed Whether to embed the asset in the executable. - */ - public function addAsset(path:String, ?rename:String, ?library:String, embed:Bool = false):Void - { - // path, rename, type, embed, setDefaults - var asset = new Asset(path, rename, null, embed, true); - @:nullSafety(Off) - { - asset.library = library ?? 'default'; - } - this.assets.push(asset); - } - - /** - * Add an entire path of assets to the game build. - * - * @param path The path the assets are located at. - * @param rename The path the assets should be placed. - * @param library The asset library to add the assets to. `null` = 'default' - * @param include An optional array to include specific asset names. - * @param exclude An optional array to exclude specific asset names. - * @param embed Whether to embed the assets in the executable. - */ - public function addAssetPath(path:String, ?rename:String, library:String, ?include:Array, ?exclude:Array, embed:Bool = false):Void - { - // Argument parsing. - if (path == '') - return; - - if (include == null) - include = []; - - if (exclude == null) - exclude = []; - - var targetPath = rename ?? path; - if (targetPath != '') - targetPath += '/'; - - // Validate path - if (!sys.FileSystem.exists(path)) - { - error('Could not find asset path "${path}".'); - } - else if (!sys.FileSystem.isDirectory(path)) - { - error('Could not parse asset path "${path}", expected a directory.'); - } - else - { - info('Adding asset path ${path}...'); - } - - for (file in sys.FileSystem.readDirectory(path)) - { - if (sys.FileSystem.isDirectory('${path}/${file}')) - { - // Attempt to recursively add all assets in the directory - if (this.filter(file, ['*'], exclude)) - { - addAssetPath('${path}/${file}', '${targetPath}${file}', library, include, exclude, embed); - } - } - else - { - if (this.filter(file, include, exclude)) - { - addAsset('${path}/${file}', '${targetPath}${file}', library, embed); - } - } - } - } - - /** - * Add an asset library to the game build. - * - * @param name The name of the library. - * @param embed - * @param preload - */ - public function addAssetLibrary(name:String, embed:Bool = false, preload:Bool = false):Void - { - // sourcePath, name, type, embed, preload, generate, prefix - var sourcePath = ''; - this.libraries.push(new Library(sourcePath, name, null, embed, preload, false, '')); - } - - // - // PROCESS FUNCTIONS - // - - /** - * A CLI command to run a command in the shell. - */ - public function buildCLICommand(cmd:String):CLICommand - { - return CommandHelper.fromSingleString(cmd); - } - - /** - * A CLI command to run a Haxe script via `--interp`. - */ - public function buildHaxeCLICommand(path:String):CLICommand - { - return CommandHelper.interpretHaxe(path); - } - - public function getGitCommit():String - { - // Cannibalized from GitCommit.hx - var process = new sys.io.Process('git', ['rev-parse', 'HEAD']); - if (process.exitCode() != 0) - { - var message = process.stderr.readAll().toString(); - error('[ERROR] Could not determine current git commit; is this a proper Git repository?'); - } - - var commitHash:String = process.stdout.readLine(); - var commitHashSplice:String = commitHash.substr(0, 7); - - process.close(); - - return commitHashSplice; - } - - public function getGitBranch():String - { - // Cannibalized from GitCommit.hx - var branchProcess = new sys.io.Process('git', ['rev-parse', '--abbrev-ref', 'HEAD']); - - if (branchProcess.exitCode() != 0) - { - var message = branchProcess.stderr.readAll().toString(); - error('Could not determine current git branch; is this a proper Git repository?'); - } - - var branchName:String = branchProcess.stdout.readLine(); - - branchProcess.close(); - - return branchName; - } - - public function getGitModified():Bool - { - var branchProcess = new sys.io.Process('git', ['status', '--porcelain']); - - if (branchProcess.exitCode() != 0) - { - var message = branchProcess.stderr.readAll().toString(); - error('Could not determine current git status; is this a proper Git repository?'); - } - - var output:String = ''; - try - { - output = branchProcess.stdout.readLine(); - } - catch (e) - { - if (e.message == 'Eof') - { - // Do nothing - // Eof = No output - } - else - { - // Rethrow other exceptions - throw e; - } - } - - branchProcess.close(); - - return output.length > 0; - } - - // - // LOGGING FUNCTIONS - // ============================== - - /** - * Display an info message. This should not interfere with the build process. - */ - public function info(message:String):Void - { - if (command != 'display') - { - Log.info('[INFO] ${message}'); - } - } - - /** - * Display an error message. This should stop the build process. - */ - public function error(message:String):Void - { - Log.error('${message}'); - } + // + // METADATA + // =========================== + + /** + * The game's version number, as a Semantic Versioning string with no prefix. + * REMEMBER TO CHANGE THIS WHEN THE GAME UPDATES! + * You only have to change it here, the rest of the game will query this value. + */ + static final VERSION:String = '0.1.0-demo'; + + /** + * The game's name. Used as the default window title. + */ + static final TITLE:String = 'Starcore'; + + /** + * The name of the generated executable file. + * For example, `STARCORE` will create a file called `STARCORE.exe`. + */ + static final EXECUTABLE_NAME:String = 'STARCORE'; + + /** + * The relative location of the source code. + */ + static final SOURCE_DIR:String = 'source'; + + /** + * The fully qualified class path for the game's preloader. + * Particularly important on HTML5 but it's used on all platforms. + */ + static final PRELOADER:String = 'flixel.system.FlxPreloader'; + + /** + * A package name used for identifying the app on various app stores. + */ + static final PACKAGE_NAME:String = 'com.bitmapstudios.starcore'; + + /** + * The fully qualified class path for the entry point class to execute when launching the game. + * It's where `public static function main():Void` goes. + */ + static final MAIN_CLASS:String = 'Main'; + + /** + * The company name for the game. + * This appears as metadata in many places. + */ + static final COMPANY:String = 'BitMap Studios'; + + /** + * Path to the Haxe script run before building the game. + */ + // static final PREBUILD_HX:String = 'source/Prebuild.hx'; + /** + * Path to the Haxe script run after building the game. + */ + // static final POSTBUILD_HX:String = 'source/Postbuild.hx'; + + /** + * Asset path globs to always exclude from asset libraries. + */ + static final EXCLUDE_ASSETS:Array = ['.*', 'cvs', 'thumbs.db', 'desktop.ini', '*.hash', '*.md']; + + /** + * Asset path globs to exclude on web platforms. + */ + static final EXCLUDE_ASSETS_WEB:Array = ['*.ogg']; + + /** + * Asset path globs to exclude on native platforms. + */ + static final EXCLUDE_ASSETS_NATIVE:Array = ['*.mp3']; + + // + // FEATURE FLAGS + // ========================================== + + /** + * Allows the game to be displayed in the user's Discord "Activity" box + * (it can still be disabled by the user in-game if the option is off). + */ + static final DISCORD_RPC_ALLOWED:FeatureFlag = 'DISCORD_RPC_ALLOWED'; + + /** + * Enables the game to use advanced shaders, giving it a more unsettling and unnerving vibe. + * Sort of like the analog horror videos you see on YouTube. + */ + static final ADVANCED_SHADERS_ALLOWED:FeatureFlag = 'ADVANCED_SHADERS_ALLOWED'; + + /** + * Allows the developer(s) to use built-in editors, + * such as creating animations for entities. + */ + static final DEBUG_EDITORS_ALLOWED:FeatureFlag = 'DEBUG_EDITORS_ALLOWED'; + + /** + * Permits the game to use a built-in logging system, which writes all + * current logs to a new text file inside of a folder called `logs`, + * located in the games output folder. + */ + static final LOGGING_ALLOWED:FeatureFlag = 'LOGGING_ALLOWED'; + + /** + * Enables the game to programmatically change sounds and add + * all kinds of effects to them. + */ + static final SOUND_FILTERS_ALLOWED:FeatureFlag = 'SOUND_FILTERS_ALLOWED'; + + public function new() + { + super(); + + flair(); + configureApp(); + + displayTarget(); + configureOutputDir(); + configureFeatureFlags(); + configureCompileDefines(); + configureHaxelibs(); + configureAssets(); + configureIcons(); // TODO: Implement code when icons are made! + } + + /** + * Display some fancy info before initializing. + */ + function flair() + { + info('STARCORE'); + info('Setting up build...'); + info('Target Version: ' + VERSION); + info('Git Branch: ' + getGitBranch()); + info('Git Commit: ' + getGitCommit()); + info('Git Modified? ' + getGitModified()); + info('Display? ' + isDisplay()); + logSeparator(); + } + + /** + * Apply basic project metadata, such as the game title and version number, + * as well as info like the package name and company (used by various app stores). + */ + function configureApp() + { + // + // METADATA + // ====================================== + this.meta.title = TITLE; + this.meta.version = VERSION; + this.meta.packageName = PACKAGE_NAME; + this.meta.company = COMPANY; + this.meta.description = 'A space themed, open world survival sandbox game.'; + this.meta.companyId = COMPANY; + this.meta.companyUrl = COMPANY; + + // + // CODE + // ================================= + this.sources.push(SOURCE_DIR); // Source code location (more than one can be added) + + // + // PREBUILD & POSTBUILD + // ================================================== + // this.preBuildCallbacks.push(buildHaxeCLICommand(PREBUILD_HX)); + // this.postBuildCallbacks.push(buildHaxeCLICommand(POSTBUILD_HX)); + + // + // APP + // ========================== + this.app.main = MAIN_CLASS; + this.app.preloader = PRELOADER; + this.app.file = EXECUTABLE_NAME; + // These values are only used by the SWF target + // this.app.path + // this.app.init + // this.app.swfVersion + // this.app.url + + // + // WINDOW + // ===================================== + this.window.fps = 60; + this.window.width = (!isMobile()) ? 960 : 0; + this.window.height = (!isMobile()) ? 720 : 0; + this.window.background = 0xFF000000; + this.window.fullscreen = false; + this.window.resizable = isWeb(); + this.window.orientation = (isDesktop() || isMobile()) ? Orientation.LANDSCAPE : Orientation.AUTO; + this.window.hardware = true; + this.window.vsync = false; + this.window.allowHighDPI = true; // Force / allow high DPI + } + + /** + * Log information about the configured target platform. + */ + function displayTarget() + { + // Display the target operating system + switch (this.target) + { + case Platform.WINDOWS: + info('Target Platform: Windows'); + case Platform.MAC: + info('Target Platform: MacOS'); + case Platform.LINUX: + info('Target Platform: Linux'); + case Platform.ANDROID: + info('Target Platform: Android'); + case Platform.IOS: + info('Target Platform: IOS'); + case Platform.HTML5: + info('Target Platform: HTML5'); + // See lime.tools.Platform for a full list + // case Platform.EMSCRITEN: + // case Platform.AIR: + // case Platform.BLACKBERRY: + // case Platform.CONSOLE_PC: + // case Platform.FIREFOX: + // case Platform.FLASH: + // case Platform.PS3: + // case Platform.PS4: + // case Platform.TIZEN: + // case Platform.TVOS: + // case Platform.VITA: + // case Platform.WEBOS: + // case Platform.WIIU: + // case Platform.XBOX1: + default: + error('Unsupported platform (got ${target})'); + } + + switch (this.platformType) + { + case PlatformType.DESKTOP: + info('Target Platform Type: Desktop'); + case PlatformType.MOBILE: + info('Target Platform Type: Mobile'); + case PlatformType.WEB: + info('Target Platform Type: Web'); + case PlatformType.CONSOLE: + info('Target Platform Type: Console'); + default: + error('Unknown target platform type (got ${platformType})'); + } + + // Print whether we are using HXCPP, HashLink, or something else. + if (isWeb()) + { + info('Target Language: JavaScript (HTML5)'); + } + else if (isHashLink()) + { + info('Target Language: HashLink'); + } + else if (isNeko()) + { + info('Target Language: Neko'); + } + else if (isJava()) + { + info('Target Language: Java'); + } + else if (isNodeJS()) + { + info('Target Language: JavaScript (NodeJS)'); + } + else if (isCSharp()) + { + info('Target Language: C#'); + } + else if (isCPlusPlus()) + { + info('Target Language: C++'); + } + else + { + info('Target Language: Unknown'); + } + + for (arch in this.architectures) + { + // Display the list of target architectures. + switch (arch) + { + case Architecture.X86: + info('Architecture: x86'); + case Architecture.X64: + info('Architecture: x64'); + case Architecture.ARMV5: + info('Architecture: ARMv5'); + case Architecture.ARMV6: + info('Architecture: ARMv6'); + case Architecture.ARMV7: + info('Architecture: ARMv7'); + case Architecture.ARMV7S: + info('Architecture: ARMv7S'); + case Architecture.ARM64: + info('Architecture: ARMx64'); + case Architecture.MIPS: + info('Architecture: MIPS'); + case Architecture.MIPSEL: + info('Architecture: MIPSEL'); + case null: + if (!isWeb()) + { + error('Unsupported architecture (got null on non-web platform)'); + } + else + { + info('Architecture: Web'); + } + default: + error('Unsupported architecture (got ${arch})'); + } + } + } + + /** + * Apply various feature flags based on the target platform and the user-provided build flags. + */ + function configureFeatureFlags() + { + // Enable Discord rich presence + // (works only for Windows). + DISCORD_RPC_ALLOWED.apply(this, isWindows()); + + // Enable dope ass screen filters + // (if the platform is on desktop). + ADVANCED_SHADERS_ALLOWED.apply(this, isDesktop()); + + // Enable the editors if the game is in debug mode, + // otherwise, disable them of course. + DEBUG_EDITORS_ALLOWED.apply(this, isDesktop() && isDebug()); + + // Enables dope ass logging + // (only works on desktop). + LOGGING_ALLOWED.apply(this, isDesktop()); + + // Allows the game to programmatically change sounds + // (only works on desktop). + SOUND_FILTERS_ALLOWED.apply(this, isDesktop()); + + logSeparator(); + } + + /** + * Set compilation flags which are not feature flags. + */ + function configureCompileDefines() + { + // Enable OpenFL's error handler. + // Required for the crash logger. + setHaxedef('openfl-enable-handle-error'); + + // Enable stack trace tracking. Good for debugging but has a (minor) performance impact. + setHaxedef('HXCPP_CHECK_POINTER'); + setHaxedef('HXCPP_STACK_LINE'); + setHaxedef('HXCPP_STACK_TRACE'); + setHaxedef('hscriptPos'); + + setHaxedef('safeMode'); + + // Disable the built in pause screen when unfocusing the game. + setHaxedef('FLX_NO_FOCUS_LOST_SCREEN'); + + // Disable the Flixel debugger entirely, since it + // messes with the filters sometimes. + setHaxedef('FLX_NO_DEBUG'); + + if (isRelease()) + { + // Improve performance on Nape. + setHaxedef('NAPE_RELEASE_BUILD'); + } + + // Cleaner looking compiler errors. + setHaxedef('message.reporting', 'pretty'); + } + + function configureOutputDir() + { + // Set the output directory. + // Depends on the target platform and build type. + var buildDir = 'export/${isDebug() ? 'debug' : isRelease() ? 'release' : 'test'}'; + buildDir += '/'; + info('Output Directory: $buildDir'); + app.path = buildDir; + logSeparator(); + } + + function configureHaxelibs() + { + // + // FLIXEL + // ================== + + // Convert the game to run on other platforms. + addHaxelib('lime'); + // Many frontend and backend utilities for the game's display. + addHaxelib('openfl'); + // Core game library. + addHaxelib('flixel'); + // Additional utilities for Flixel. + addHaxelib('flixel-addons'); + // VSCode debug support. + if (isDebug()) + { + addHaxelib('hxcpp-debug-server'); + } + + // + // CUSTOM + // =================== + + // Manipulate sound effects programmatically. + if (SOUND_FILTERS_ALLOWED.isEnabled(this)) + { + addHaxelib('flxsoundfilters'); + } + + // Discord rich presence. + if (DISCORD_RPC_ALLOWED.isEnabled(this)) + { + addHaxelib('hxdiscord_rpc'); + } + } + + function configureAssets() + { + // Add font assets. + addAssetPath('assets/fonts', 'assets/fonts', 'default', ['*.ttf'], []); + + // Add entity assets. + addAssetPath('assets/entities/data', 'assets/entities/data', 'default', ['*.json'], []); + addAssetPath('assets/entities/textures', 'assets/entities/textures', 'default', ['*.png', '*.xml'], []); + + // Add tile assets. + addAssetPath('assets/tiles/data', 'assets/tiles/data', 'default', ['*.json'], []); + addAssetPath('assets/tiles/textures', 'assets/tiles/textures', 'default', ['*.png'], []); + + // Add shared image assets. + addAssetPath('assets/shared/images', 'assets/shared/images', 'default', ['*.png'], []); + + // Add shader frag assets. + addAssetPath('assets/shaders', 'assets/shaders', 'default', ['*.frag'], []); + + if (isWeb()) + { + // Add shared music and sound assets for web (.mp3). + addAssetPath('assets/shared/music', 'assets/shared/music', 'default', ['*.mp3'], ['*.ogg']); + addAssetPath('assets/shared/sounds', 'assets/shared/sounds', 'default', ['*.mp3'], ['*.ogg']); + } + else if (isDesktop()) + { + // Add shared music and sound assets for desktop (.ogg). + addAssetPath('assets/shared/music', 'assets/shared/music', 'default', ['*.ogg'], ['*.mp3']); + addAssetPath('assets/shared/sounds', 'assets/shared/sounds', 'default', ['*.ogg'], ['*.mp3']); + } + } + + /** + * Configure the application's favicon and executable icon. + */ + function configureIcons() {} + + // + // HELPER FUNCTIONS + // (Easy functions to make the code more readable.) + // ======================================================================== + + public function isWeb():Bool + { + return this.platformType == PlatformType.WEB; + } + + public function isMobile():Bool + { + return this.platformType == PlatformType.MOBILE; + } + + public function isDesktop():Bool + { + return this.platformType == PlatformType.DESKTOP; + } + + public function isConsole():Bool + { + return this.platformType == PlatformType.CONSOLE; + } + + public function is32Bit():Bool + { + return this.architectures.contains(Architecture.X86); + } + + public function is64Bit():Bool + { + return this.architectures.contains(Architecture.X64); + } + + public function isWindows():Bool + { + return this.target == Platform.WINDOWS; + } + + public function isMac():Bool + { + return this.target == Platform.MAC; + } + + public function isLinux():Bool + { + return this.target == Platform.LINUX; + } + + public function isAndroid():Bool + { + return this.target == Platform.ANDROID; + } + + public function isIOS():Bool + { + return this.target == Platform.IOS; + } + + public function isHashLink():Bool + { + return this.targetFlags.exists('hl'); + } + + public function isNeko():Bool + { + return this.targetFlags.exists('neko'); + } + + public function isJava():Bool + { + return this.targetFlags.exists('java'); + } + + public function isNodeJS():Bool + { + return this.targetFlags.exists('nodejs'); + } + + public function isCSharp():Bool + { + return this.targetFlags.exists('cs'); + } + + public function isCPlusPlus():Bool + { + return this.defines.exists('cpp'); // Why in defines and not target flags... + } + + public function isDisplay():Bool + { + return this.command == 'display'; + } + + public function isDebug():Bool + { + return this.debug; + } + + public function isRelease():Bool + { + return this.defines.exists('final'); + } + + public function getHaxedef(name:String):Null + { + return this.haxedefs.get(name); + } + + public function setHaxedef(name:String, ?value:String):Void + { + if (value == null) + value = ''; + + this.haxedefs.set(name, value); + } + + public function unsetHaxedef(name:String):Void + { + this.haxedefs.remove(name); + } + + public function getDefine(name:String):Null + { + return this.defines.get(name); + } + + public function hasDefine(name:String):Bool + { + return this.defines.exists(name); + } + + /** + * Add a library to the list of dependencies for the project. + * + * @param name The name of the library to add. + * @param version The version of the library to add. Optional. + */ + public function addHaxelib(name:String, version:String = ''):Void + { + this.haxelibs.push(new Haxelib(name, version)); + } + + /** + * Add a `haxeflag` to the project. + */ + public function addHaxeFlag(value:String):Void + { + this.haxeflags.push(value); + } + + /** + * Call a Haxe build macro. + */ + public function addHaxeMacro(value:String):Void + { + addHaxeFlag('--macro ${value}'); + } + + /** + * Add an icon to the project. + * + * @param icon The path to the icon. + * @param size The size of the icon. Optional. + */ + public function addIcon(icon:String, ?size:Int):Void + { + this.icons.push(new Icon(icon, size)); + } + + /** + * Add an asset to the game build. + * + * @param path The path the asset is located at. + * @param rename The path the asset should be placed. + * @param library The asset library to add the asset to. `null` = 'default' + * @param embed Whether to embed the asset in the executable. + */ + public function addAsset(path:String, ?rename:String, ?library:String, embed:Bool = false):Void + { + // path, rename, type, embed, setDefaults + var asset = new Asset(path, rename, null, embed, true); + @:nullSafety(Off) + { + asset.library = library ?? 'default'; + } + this.assets.push(asset); + } + + /** + * Add an entire path of assets to the game build. + * + * @param path The path the assets are located at. + * @param rename The path the assets should be placed. + * @param library The asset library to add the assets to. `null` = 'default' + * @param include An optional array to include specific asset names. + * @param exclude An optional array to exclude specific asset names. + * @param embed Whether to embed the assets in the executable. + */ + public function addAssetPath(path:String, ?rename:String, library:String, ?include:Array, ?exclude:Array, embed:Bool = false):Void + { + // Argument parsing. + if (path == '') + return; + + if (include == null) + include = []; + + if (exclude == null) + exclude = []; + + var targetPath = rename ?? path; + if (targetPath != '') + targetPath += '/'; + + // Validate path + if (!sys.FileSystem.exists(path)) + { + error('Could not find asset path "${path}".'); + } + else if (!sys.FileSystem.isDirectory(path)) + { + error('Could not parse asset path "${path}", expected a directory.'); + } + else + { + info('Adding asset path ${path}...'); + } + + for (file in sys.FileSystem.readDirectory(path)) + { + if (sys.FileSystem.isDirectory('${path}/${file}')) + { + // Attempt to recursively add all assets in the directory + if (this.filter(file, ['*'], exclude)) + { + addAssetPath('${path}/${file}', '${targetPath}${file}', library, include, exclude, embed); + } + } + else + { + if (this.filter(file, include, exclude)) + { + addAsset('${path}/${file}', '${targetPath}${file}', library, embed); + } + } + } + } + + /** + * Add an asset library to the game build. + * + * @param name The name of the library. + * @param embed + * @param preload + */ + public function addAssetLibrary(name:String, embed:Bool = false, preload:Bool = false):Void + { + // sourcePath, name, type, embed, preload, generate, prefix + var sourcePath = ''; + this.libraries.push(new Library(sourcePath, name, null, embed, preload, false, '')); + } + + // + // PROCESS FUNCTIONS + // + + /** + * A CLI command to run a command in the shell. + */ + public function buildCLICommand(cmd:String):CLICommand + { + return CommandHelper.fromSingleString(cmd); + } + + /** + * A CLI command to run a Haxe script via `--interp`. + */ + public function buildHaxeCLICommand(path:String):CLICommand + { + return CommandHelper.interpretHaxe(path); + } + + public function getGitCommit():String + { + // Cannibalized from GitCommit.hx + var process = new sys.io.Process('git', ['rev-parse', 'HEAD']); + if (process.exitCode() != 0) + { + var message = process.stderr.readAll().toString(); + error('[ERROR] Could not determine current git commit; is this a proper Git repository?'); + } + + var commitHash:String = process.stdout.readLine(); + var commitHashSplice:String = commitHash.substr(0, 7); + + process.close(); + + return commitHashSplice; + } + + public function getGitBranch():String + { + // Cannibalized from GitCommit.hx + var branchProcess = new sys.io.Process('git', ['rev-parse', '--abbrev-ref', 'HEAD']); + + if (branchProcess.exitCode() != 0) + { + var message = branchProcess.stderr.readAll().toString(); + error('Could not determine current git branch; is this a proper Git repository?'); + } + + var branchName:String = branchProcess.stdout.readLine(); + + branchProcess.close(); + + return branchName; + } + + public function getGitModified():Bool + { + var branchProcess = new sys.io.Process('git', ['status', '--porcelain']); + + if (branchProcess.exitCode() != 0) + { + var message = branchProcess.stderr.readAll().toString(); + error('Could not determine current git status; is this a proper Git repository?'); + } + + var output:String = ''; + try + { + output = branchProcess.stdout.readLine(); + } + catch (e) + { + if (e.message == 'Eof') + { + // Do nothing + // Eof = No output + } + else + { + // Rethrow other exceptions + throw e; + } + } + + branchProcess.close(); + + return output.length > 0; + } + + // + // LOGGING FUNCTIONS + // ============================== + + /** + * Display an info message. This should not interfere with the build process. + */ + public function info(message:String):Void + { + if (command != 'display') + { + Log.info('[INFO] ${message}'); + } + } + + /** + * Display an error message. This should stop the build process. + */ + public function error(message:String):Void + { + Log.error('${message}'); + } + + /** + * Display a very long line to separate sections of the game's + * setup, mainly for easy readability. + */ + public function logSeparator():Void + { + info('-------------------------------------------------------------'); + } } /** @@ -871,115 +877,115 @@ class Project extends HXProject */ abstract FeatureFlag(String) { - static final INVERSE_PREFIX:String = 'NO_'; - - public function new(input:String) - { - this = input; - } - - @:from - public static function fromString(input:String):FeatureFlag - { - return new FeatureFlag(input); - } - - /** - * Enable/disable a feature flag if it is unset, and handle the inverse flag. - * Doesn't override a feature flag that was set explicitly. - * @param enableByDefault Whether to enable this feature flag if it is unset. - */ - public function apply(project:Project, enableByDefault:Bool = false):Void - { - // TODO: Name this function better? - - if (isEnabled(project)) - { - // If this flag was already enabled, disable the inverse - project.info('Enabling feature flag ${this}'); - getInverse().disable(project, false); - } - else if (getInverse().isEnabled(project)) - { - // If the inverse flag was already enabled, disable this flag - project.info('Disabling feature flag ${this}'); - disable(project, false); - } - else - { - if (enableByDefault) - { - // Enable this flag if it was unset, and disable the inverse - project.info('Enabling feature flag ${this}'); - enable(project, true); - } - else - { - // Disable this flag if it was unset, and enable the inverse - project.info('Disabling feature flag ${this}'); - disable(project, true); - } - } - } - - /** - * Enable this feature flag by setting the appropriate compile define. - * - * @param project The project to modify. - * @param andInverse Also disable the feature flag's inverse. - */ - public function enable(project:Project, andInverse:Bool = true) - { - project.setHaxedef(this, ''); - if (andInverse) - { - getInverse().disable(project, false); - } - } - - /** - * Disable this feature flag by removing the appropriate compile define. - * - * @param project The project to modify. - * @param andInverse Also enable the feature flag's inverse. - */ - public function disable(project:Project, andInverse:Bool = true) - { - project.unsetHaxedef(this); - if (andInverse) - { - getInverse().enable(project, false); - } - } - - /** - * Query if this feature flag is enabled. - * @param project The project to query. - */ - public function isEnabled(project:Project):Bool - { - // Check both Haxedefs and Defines for this flag - return project.haxedefs.exists(this) || project.defines.exists(this); - } - - /** - * Query if this feature flag's inverse is enabled. - */ - public function isDisabled(project:Project):Bool - { - return getInverse().isEnabled(project); - } - - /** - * Return the inverse of this feature flag. - * @return A new feature flag that is the inverse of this one. - */ - public function getInverse():FeatureFlag - { - if (this.startsWith(INVERSE_PREFIX)) - { - return this.substring(INVERSE_PREFIX.length); - } - return INVERSE_PREFIX + this; - } + static final INVERSE_PREFIX:String = 'NO_'; + + public function new(input:String) + { + this = input; + } + + @:from + public static function fromString(input:String):FeatureFlag + { + return new FeatureFlag(input); + } + + /** + * Enable/disable a feature flag if it is unset, and handle the inverse flag. + * Doesn't override a feature flag that was set explicitly. + * @param enableByDefault Whether to enable this feature flag if it is unset. + */ + public function apply(project:Project, enableByDefault:Bool = false):Void + { + // TODO: Name this function better? + + if (isEnabled(project)) + { + // If this flag was already enabled, disable the inverse + project.info('Enabling feature flag ${this}'); + getInverse().disable(project, false); + } + else if (getInverse().isEnabled(project)) + { + // If the inverse flag was already enabled, disable this flag + project.info('Disabling feature flag ${this}'); + disable(project, false); + } + else + { + if (enableByDefault) + { + // Enable this flag if it was unset, and disable the inverse + project.info('Enabling feature flag ${this}'); + enable(project, true); + } + else + { + // Disable this flag if it was unset, and enable the inverse + project.info('Disabling feature flag ${this}'); + disable(project, true); + } + } + } + + /** + * Enable this feature flag by setting the appropriate compile define. + * + * @param project The project to modify. + * @param andInverse Also disable the feature flag's inverse. + */ + public function enable(project:Project, andInverse:Bool = true) + { + project.setHaxedef(this, ''); + if (andInverse) + { + getInverse().disable(project, false); + } + } + + /** + * Disable this feature flag by removing the appropriate compile define. + * + * @param project The project to modify. + * @param andInverse Also enable the feature flag's inverse. + */ + public function disable(project:Project, andInverse:Bool = true) + { + project.unsetHaxedef(this); + if (andInverse) + { + getInverse().enable(project, false); + } + } + + /** + * Query if this feature flag is enabled. + * @param project The project to query. + */ + public function isEnabled(project:Project):Bool + { + // Check both Haxedefs and Defines for this flag + return project.haxedefs.exists(this) || project.defines.exists(this); + } + + /** + * Query if this feature flag's inverse is enabled. + */ + public function isDisabled(project:Project):Bool + { + return getInverse().isEnabled(project); + } + + /** + * Return the inverse of this feature flag. + * @return A new feature flag that is the inverse of this one. + */ + public function getInverse():FeatureFlag + { + if (this.startsWith(INVERSE_PREFIX)) + { + return this.substring(INVERSE_PREFIX.length); + } + return INVERSE_PREFIX + this; + } } diff --git a/setup/install-libs-macos-linux.sh b/setup/install-libs-macos-linux.sh new file mode 100644 index 0000000..2dc9f8d --- /dev/null +++ b/setup/install-libs-macos-linux.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Shell script to install all Haxe libraries from hmm.json +# Make sure you have Haxe and Haxelib installed and in your PATH + +# Install haxelib dependencies +haxelib install lime 8.2.2 +haxelib install openfl 9.4.1 +haxelib install flixel 6.1.0 +haxelib install flixel-addons 3.3.2 +haxelib install flixel-tools 1.5.1 +haxelib install hxcpp-debug-server 1.2.4 +haxelib install hxdiscord_rpc 1.3.0 +haxelib install hxcpp 4.3.2 +haxelib install hxp 1.3.0 + +# Install git dependencies +haxelib git flxsoundfilters https://github.com/TheZoroForce240/FlxSoundFilters + +echo "All libraries installed!" diff --git a/setup/install-libs-windows.bat b/setup/install-libs-windows.bat new file mode 100644 index 0000000..2422d7a --- /dev/null +++ b/setup/install-libs-windows.bat @@ -0,0 +1,20 @@ +@echo off +REM Batch script to install all Haxe libraries from hmm.json +REM Make sure you have Haxe and Haxelib installed and in your PATH + +REM Install haxelib dependencies +haxelib install lime 8.2.2 +haxelib install openfl 9.4.1 +haxelib install flixel 6.1.0 +haxelib install flixel-addons 3.3.2 +haxelib install flixel-tools 1.5.1 +haxelib install hxcpp-debug-server 1.2.4 +haxelib install hxdiscord_rpc 1.3.0 +haxelib install hxcpp 4.3.2 +haxelib install hxp 1.3.0 + +REM Install git dependencies +haxelib git flxsoundfilters https://github.com/TheZoroForce240/FlxSoundFilters + +echo All libraries installed! +pause diff --git a/source/InitState.hx b/source/InitState.hx index e1b61be..c7db9be 100644 --- a/source/InitState.hx +++ b/source/InitState.hx @@ -33,10 +33,9 @@ class InitState extends FlxState { override public function create():Void { - // Setup the logger for Starcore + // Setup the logger for Starcore. LoggerUtil.initialize(); - // Log that we are setting up Starcore LoggerUtil.log('INITIALIZING STARCORE SETUP', INFO, false); // Load all of the player's settings and options @@ -50,7 +49,7 @@ class InitState extends FlxState // Add the processes that always run in the background addBackgroundProcesses(); - // Add the event listeners + // Add the event listeners which will always run in the background. addEventListeners(); // Register all of the entities that are in the game @@ -65,22 +64,23 @@ class InitState extends FlxState function configureFlixelSettings():Void { - // Log info LoggerUtil.log('Configuring Flixel settings'); - // Set the cursor to be the system default, rather than using a custom cursor - // TODO: Maybe use a custom cursor? + // Configure Starcore's Flixel utility class. + FlixelUtil.configure(); + + // Set the cursor to be the system default, rather than using a custom cursor. + // NOTE: Maybe use a custom cursor (that isn't Flixel's)? FlxG.mouse.useSystemCursor = true; - // Set auto pause to false + // Disable auto pausing entirely (we never want this enabled). FlxG.autoPause = false; - // Set the stage and scaling modes + // Set the stage and scaling modes. Lib.current.stage.align = 'tl'; Lib.current.stage.scaleMode = StageScaleMode.NO_SCALE; - // Disable the binds for increasing/decreasing/muting - // the Flixel master volume + // Disable the binds for increasing/decreasing/muting the Flixel master volume. FlxG.sound.volumeUpKeys = []; FlxG.sound.volumeDownKeys = []; FlxG.sound.muteKeys = []; @@ -88,21 +88,20 @@ class InitState extends FlxState // Set the default font FlxAssets.FONT_DEFAULT = PathUtil.ofFont('Born2bSportyFS'); - // Set the stage quality + // Set the stage quality.. #if !web FlxG.stage.quality = StageQuality.LOW; #else FlxG.stage.quality = StageQuality.MEDIUM; #end - // Make the window borderless when it is - // not in fullscreen mode - // TODO: Figure out how to make it draggable + // Make the window borderless when it is not in fullscreen mode. + // TODO: Figure out how to make it draggable. #if desktop Application.current.window.borderless = true; #end - // Disable the right-click context menu for HTML5 + // Disable the right-click context menu for HTML5. #if web Browser.document.addEventListener('contextmenu', (e) -> { @@ -118,7 +117,7 @@ class InitState extends FlxState CacheUtil.grainShader = new GrainShader(); // Configure the event listener for detecting caps lock - // if the target is set to HTML5 + // if the target is set to HTML5. #if web untyped __js__(' window.__haxe_capslock__ = false; @@ -131,38 +130,24 @@ class InitState extends FlxState #end } - function addBackgroundProcesses():Void - { - // Log info - LoggerUtil.log('Adding background processes'); - // Update the shaders that need to - // constantly be reset - FlxG.signals.postUpdate.add(() -> - { - #if ADVANCED_SHADERS_ALLOWED - CacheUtil.vcrMario85Shader.update(FlxG.elapsed); - #end - CacheUtil.grainShader.update(FlxG.elapsed); - }); - } + function addBackgroundProcesses():Void {} function addEventListeners():Void { - // Log info LoggerUtil.log('Adding event listeners'); #if desktop - // Minimize volume when the window is out of focus + // Minimize volume when the window is out of focus. Application.current.window.onFocusIn.add(() -> { - // Bring the volume back up when the window is focused again + // Bring the volume back up when the window is focused again. if (ClientPrefs.getOption('minimizeVolume') && !CacheUtil.isWindowFocused) { // Set back to one decimal place (0.1) when the screen gains focus again - // (note that if the user had the volume all the way down, it will be set to zero) + // (note that if the user had the volume all the way down, it will be set to zero). FlxG.sound.volume = (!(Math.abs(FlxG.sound.volume) < FlxMath.EPSILON)) ? 0.1 : 0; CacheUtil.isWindowFocused = true; - // Set the volume back to the last volume used + // Set the volume back to the last volume used. FlxTween.num(FlxG.sound.volume, CacheUtil.lastVolumeUsed, 0.3, {type: FlxTweenType.ONESHOT}, (v:Float) -> { FlxG.sound.volume = v; @@ -171,10 +156,10 @@ class InitState extends FlxState }); Application.current.window.onFocusOut.add(() -> { - // Minimize the volume when the window loses focus + // Minimize the volume when the window loses focus. if (ClientPrefs.getOption('minimizeVolume') && CacheUtil.isWindowFocused) { - // Set the last volume used to the current volume + // Set the last volume used to the current volume. CacheUtil.lastVolumeUsed = FlxG.sound.volume; CacheUtil.isWindowFocused = false; // Tween the volume to 0.05 @@ -187,7 +172,7 @@ class InitState extends FlxState #end // Delete all save data if CTRL + BACKSPACE - // is pressed on debug mode in the web version + // is pressed on debug mode in the web version. #if (web && debug) FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, (_) -> { diff --git a/source/starcore/backend/util/FlixelUtil.hx b/source/starcore/backend/util/FlixelUtil.hx index a23cb25..01afa57 100644 --- a/source/starcore/backend/util/FlixelUtil.hx +++ b/source/starcore/backend/util/FlixelUtil.hx @@ -6,15 +6,18 @@ import flixel.FlxState; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.input.keyboard.FlxKey; import flixel.sound.FlxSound; +import flixel.system.FlxAssets.FlxShader; import flixel.tweens.FlxTween; import flixel.util.FlxColor; import flixel.util.FlxTimer; import haxe.Exception; +import openfl.filters.BitmapFilter; import openfl.filters.ShaderFilter; import starcore.backend.api.DiscordClient; import starcore.backend.data.ClientPrefs.ShaderModeType; import starcore.backend.data.Constants; import starcore.shaders.*; +import starcore.shaders.bases.UpdatedShader; #if SOUND_FILTERS_ALLOWED import flixel.sound.filters.FlxFilteredSound; import flixel.sound.filters.FlxSoundFilter; @@ -49,6 +52,27 @@ final class FlixelUtil { function new() {} + static var currentShadersApplied:Array = []; + + /** + * Configures the Flixel utility class. + * + * This should only be called once, when the game first starts up. + */ + public static function configure():Void + { + FlxG.signals.postUpdate.add(() -> + { + for (shader in currentShadersApplied) + { + if (shader != null && Std.isOfType(shader, UpdatedShader)) + { + (cast shader : UpdatedShader).update(FlxG.elapsed); + } + } + }); + } + /** * Fades into a state with a cool transition effect. * @@ -136,35 +160,42 @@ final class FlixelUtil */ public static function setFilters(?mode:ShaderModeType):Void { + // Completely reset the filters. + currentShadersApplied.splice(0, currentShadersApplied.length); + var toAdd:Array = []; + switch (mode) { #if ADVANCED_SHADERS_ALLOWED case DEFAULT | null: - FlxG.game.setFilters([ - new ShaderFilter(CacheUtil.vcrBorderShader), - new ShaderFilter(CacheUtil.vcrMario85Shader), - new ShaderFilter(CacheUtil.grainShader), - new ShaderFilter(new Hq2xShader()), - new ShaderFilter(new TiltshiftShader()) - ]); + currentShadersApplied = [ + new Hq2xShader(), + new TiltshiftShader(), + new NTSCShader(), + new SkewShader(), + new VCRLinesShader(), + new GrainShader() + ]; #end case FAST: - FlxG.game.setFilters([ - new ShaderFilter(CacheUtil.grainShader), - new ShaderFilter(new ScanlineShader()), - new ShaderFilter(new Hq2xShader()), - new ShaderFilter(new TiltshiftShader()) - ]); + currentShadersApplied = [new GrainShader(), new Hq2xShader(), new TiltshiftShader(), new ScanlineShader()]; case MINIMAL: - FlxG.game.setFilters([ - new ShaderFilter(CacheUtil.grainShader), - new ShaderFilter(new Hq2xShader()) - ]); + currentShadersApplied = [new GrainShader(), new Hq2xShader()]; case NONE: - FlxG.game.setFilters([]); + currentShadersApplied = []; default: - FlxG.game.setFilters([]); + currentShadersApplied = []; + } + // Apply all the shaders as ShaderFilters. + for (shader in currentShadersApplied) + { + if (shader != null) + { + toAdd.push(new ShaderFilter(shader)); + } } + + FlxG.game.setFilters(toAdd); } /** @@ -257,7 +288,7 @@ final class FlixelUtil * ### *NOTE: If `FlxKey.PLUS` is passed down, it will be returned as `=` if `shiftVariant` is false!* * * @param key The key to be converted. - * @param shiftVariant If the key should be converted to the variant when the + * @param shiftVariant If the key should be converted to its shift variant when the * user is pressing shift (i.e. `a` would become `A`, `;` would * become `:`, etc.). Default value is `false`. * @return The converted character. @@ -481,15 +512,11 @@ final class FlixelUtil */ public static function closeGame(sysShutdown:Bool = true):Void { - // Log info LoggerUtil.log('SHUTTING DOWN STARCORE', INFO, false); - // Save all of the user's data SaveUtil.saveAll(); - // Shutdown Discord rich presence DiscordClient.shutdown(); - // Shutdown the logging system LoggerUtil.shutdown(); - // Close the game respectfully + if (sysShutdown) { #if web diff --git a/source/starcore/shaders/GrainShader.hx b/source/starcore/shaders/GrainShader.hx index 488e4c1..f35f98d 100644 --- a/source/starcore/shaders/GrainShader.hx +++ b/source/starcore/shaders/GrainShader.hx @@ -1,15 +1,15 @@ package starcore.shaders; -import openfl.Lib; -import flixel.addons.display.FlxRuntimeShader; import openfl.Assets; +import openfl.Lib; import starcore.backend.util.PathUtil; +import starcore.shaders.bases.UpdatedShader; /** * Adds a grainy effect to the screen like an old TV * (hence the name). */ -class GrainShader extends FlxRuntimeShader +class GrainShader extends UpdatedShader { public function new() { diff --git a/source/starcore/shaders/GrayscaleShader.hx b/source/starcore/shaders/GrayscaleShader.hx index ea172ca..e6514d5 100644 --- a/source/starcore/shaders/GrayscaleShader.hx +++ b/source/starcore/shaders/GrayscaleShader.hx @@ -9,17 +9,14 @@ import starcore.backend.util.PathUtil; */ class GrayscaleShader extends FlxRuntimeShader { - public var amount:Float = 1; - public function new(amount:Float = 1) { super(Assets.getText(PathUtil.ofFrag('grayscale'))); - setAmount(amount); + setFloat("_amount", amount); } public function setAmount(value:Float):Void { - amount = value; - setFloat("_amount", amount); + setFloat("_amount", value); } } diff --git a/source/starcore/shaders/HueShiftShader.hx b/source/starcore/shaders/HueShiftShader.hx index f1f0082..348493a 100644 --- a/source/starcore/shaders/HueShiftShader.hx +++ b/source/starcore/shaders/HueShiftShader.hx @@ -1,8 +1,8 @@ package starcore.filters; -import starcore.backend.util.PathUtil; -import openfl.Assets; import flixel.addons.display.FlxRuntimeShader; +import openfl.Assets; +import starcore.backend.util.PathUtil; /** * Allows a sprite to shift its colors diff --git a/source/starcore/shaders/NTSCShader.hx b/source/starcore/shaders/NTSCShader.hx new file mode 100644 index 0000000..4fce353 --- /dev/null +++ b/source/starcore/shaders/NTSCShader.hx @@ -0,0 +1,13 @@ +package starcore.shaders; + +import flixel.addons.display.FlxRuntimeShader; +import openfl.Assets; +import starcore.backend.util.PathUtil; + +class NTSCShader extends FlxRuntimeShader +{ + public function new() + { + super(Assets.getText(PathUtil.ofFrag('ntsc'))); + } +} diff --git a/source/starcore/shaders/ScanlineShader.hx b/source/starcore/shaders/ScanlineShader.hx index b649ad3..0e85a86 100644 --- a/source/starcore/shaders/ScanlineShader.hx +++ b/source/starcore/shaders/ScanlineShader.hx @@ -1,8 +1,8 @@ package starcore.shaders; -import starcore.backend.util.PathUtil; -import openfl.Assets; import flixel.addons.display.FlxRuntimeShader; +import openfl.Assets; +import starcore.backend.util.PathUtil; /** * Adds old TV lines across the screen. diff --git a/source/starcore/shaders/SkewShader.hx b/source/starcore/shaders/SkewShader.hx new file mode 100644 index 0000000..812ffd8 --- /dev/null +++ b/source/starcore/shaders/SkewShader.hx @@ -0,0 +1,13 @@ +package starcore.shaders; + +import flixel.addons.display.FlxRuntimeShader; +import openfl.Assets; +import starcore.backend.util.PathUtil; + +class SkewShader extends FlxRuntimeShader +{ + public function new() + { + super(Assets.getText(PathUtil.ofFrag('skew'))); + } +} diff --git a/source/starcore/shaders/TiltshiftShader.hx b/source/starcore/shaders/TiltshiftShader.hx index bcec1d0..8c1e1fa 100644 --- a/source/starcore/shaders/TiltshiftShader.hx +++ b/source/starcore/shaders/TiltshiftShader.hx @@ -1,8 +1,8 @@ package starcore.shaders; -import starcore.backend.util.PathUtil; -import openfl.utils.Assets; import flixel.addons.display.FlxRuntimeShader; +import openfl.utils.Assets; +import starcore.backend.util.PathUtil; /** * Adds a slight blur to the top and bottom edges of the screen. diff --git a/source/starcore/shaders/VCRLinesShader.hx b/source/starcore/shaders/VCRLinesShader.hx new file mode 100644 index 0000000..d034103 --- /dev/null +++ b/source/starcore/shaders/VCRLinesShader.hx @@ -0,0 +1,19 @@ +package starcore.shaders; + +import flixel.FlxG; +import openfl.Assets; +import starcore.backend.util.PathUtil; +import starcore.shaders.bases.UpdatedShader; + +class VCRLinesShader extends UpdatedShader +{ + public function new() + { + super(Assets.getText(PathUtil.ofFrag('vcrlines'))); + } + + public function update(elapsed:Float):Void + { + setFloat('time', FlxG.game.ticks * FlxG.elapsed); + } +} diff --git a/source/starcore/shaders/VCRMario85Shader.hx b/source/starcore/shaders/VCRMario85Shader.hx index f45a77e..7698316 100644 --- a/source/starcore/shaders/VCRMario85Shader.hx +++ b/source/starcore/shaders/VCRMario85Shader.hx @@ -1,8 +1,8 @@ package starcore.shaders; -import flixel.addons.display.FlxRuntimeShader; import openfl.Assets; import starcore.backend.util.PathUtil; +import starcore.shaders.bases.UpdatedShader; // https://www.shadertoy.com/view/ldjGzV // https://www.shadertoy.com/view/Ms23DR @@ -12,7 +12,7 @@ import starcore.backend.util.PathUtil; /** * Gives the screen a creepy, old Super Mario-like vibe. */ -class VCRMario85Shader extends FlxRuntimeShader +class VCRMario85Shader extends UpdatedShader { public function new() { diff --git a/source/starcore/shaders/bases/UpdatedShader.hx b/source/starcore/shaders/bases/UpdatedShader.hx new file mode 100644 index 0000000..b25cb90 --- /dev/null +++ b/source/starcore/shaders/bases/UpdatedShader.hx @@ -0,0 +1,21 @@ +package starcore.shaders.bases; + +import flixel.addons.display.FlxRuntimeShader; + +/** + * Base class for shaders that need to be updated every frame. + */ +abstract class UpdatedShader extends FlxRuntimeShader +{ + public function new(?fragCode:String) + { + super(fragCode); + } + + /** + * Function which is called every frame to update the shader. + * + * @param elapsed The amount of time (in seconds) since the last frame. + */ + public abstract function update(elapsed:Float):Void; +} From c470af442b06d50771724482bd5800f4f065225d Mon Sep 17 00:00:00 2001 From: String Date: Sun, 14 Sep 2025 21:56:40 -0500 Subject: [PATCH 2/3] Made some last minute changes --- .gitignore | 2 +- .prettierignore | 2 +- COMPILING.md | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 5dc73c0..6aedad1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # HaxeFlixel +.haxelib/ dump/ export/ -.haxelib/ # macOS .DS_Store diff --git a/.prettierignore b/.prettierignore index 419d53b..412614c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,4 @@ # Ignore artifacts +.haxelib/ dump/ export/ -.haxelib/ diff --git a/COMPILING.md b/COMPILING.md index 3831a7d..28bb2a0 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -32,7 +32,7 @@ These are the necessary steps required to compile the game on __***every***__ pl 8. Run `hmm install` to start installing all of the game's dependencies. **This will take a bit, so be patient**. > [!TIP] -> If the libraries do not install correctly, then you can run the `.bat` file or `.sh` file (according to your sysrtem) +> If the libraries do not install correctly, then you can run the `.bat` file or `.sh` file (according to your system). 9. Run `haxelib run lime setup` to setup the lime command. - This will allow you to compile and run the game on many common platforms, such as every major desktop platform (Windows, macOS, Linux, etc.), both popular mobile systems (Android and iOS), and more. @@ -43,6 +43,9 @@ These are the necessary steps required to compile the game on __***every***__ pl > [!TIP] > You can replace `html5` with other platforms to compile it accordingly. +> [!IMPORTANT] +> If ever, for some reason, the shaders make the screen become black, it is advised you clear your computer's `Temp/` directory. If the issue persists, then please take a look at the [contributing](CONTRIBUTING.md) file for info on how to report a bug. + ## Extra Steps (for Running and Configuring the Game on Other Platforms) ### Windows From dc06e2881b5b75acbb3dac7f97cd30a3ab60dc8a Mon Sep 17 00:00:00 2001 From: String Date: Sun, 14 Sep 2025 22:09:51 -0500 Subject: [PATCH 3/3] Merge conflicts --- .prettierignore | 1 - COMPILING.md | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 3829f4c..8ba024c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,5 +2,4 @@ .haxelib/ dump/ export/ -dump/ temp/ diff --git a/COMPILING.md b/COMPILING.md index 9136560..e23e352 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -31,6 +31,9 @@ These are the necessary steps required to compile on the game on __***every***__ 8. Run `hmm install` to start installing all of the game's dependencies. **This will take a bit, so be patient**. +> [!TIP] +> If the libraries do not install correctly, then you can run the `.bat` file or `.sh` file (according to your system). + 9. Run `haxelib run lime setup` to setup the lime command. - This will allow you to compile and run the game on many common platforms, such as every major desktop platform (Windows, macOS, Linux, etc.), both popular mobile systems (Android and iOS), and more. @@ -40,6 +43,9 @@ These are the necessary steps required to compile on the game on __***every***__ > [!TIP] > You can replace `html5` with other platforms to compile it accordingly. +> [!IMPORTANT] +> If ever, for some reason, the shaders make the screen become black, it is advised you clear your computer's `Temp/` directory. If the issue persists, then please take a look at the [contributing](CONTRIBUTING.md) file for info on how to report a bug. + ## Extra Steps (for Running and Configuring the Game on Other Platforms) ### Windows