diff --git a/assets/data/characters/pico-speakers.hx b/assets/data/characters/pico-speakers.hx index d59b83f4..67ef39d9 100644 --- a/assets/data/characters/pico-speakers.hx +++ b/assets/data/characters/pico-speakers.hx @@ -14,6 +14,7 @@ function onPlaySingAnim(event) { } function update(elapsed) { - if (getAnimName() == null || (getAnimName().substr(0, 5) == "shoot" && isAnimFinished())) + var animName = getAnimName(); + if (animName == null || (animName.substr(0, 5) == "shoot" && isAnimFinished())) dance(); } \ No newline at end of file diff --git a/assets/shaders/engine/CompatabilityGuide.md b/assets/shaders/engine/CompatabilityGuide.md new file mode 100644 index 00000000..2fe7bc87 --- /dev/null +++ b/assets/shaders/engine/CompatabilityGuide.md @@ -0,0 +1,70 @@ +## Here are guides on common mistakes and advices for writting shaders for flixel and openfl. + +It's important to follow this guide as most shader coders make these mistakes a lot and end up with shaders that only work on certain devices. + +------- +### Common mistakes and how to avoid them +Avoid using `0.` or `.0` for floats, instead, use `0.0` (ending the float number with an `.0`) +(please note that despite half floats working on nVidia gpus, other gpus like AMD gpus don't support this feature) + +Avoid using switch cases, and use if statements where possible. +(switch cases are not supported on macOS or miscellaneous platforms) + +Ints are not recommended when initiating vectors. (ex, vec2(1, 1) is not supported on certain platforms). +And use floats where it's expected. Like mod(1.0, 2.0) instead of mod(1, 2) + +Avoid using the following types: +- ivec2,3,4 +- bvec2,3,4 +- uvec2,3,4 +- uint + +as they are unsupported on certain platforms. + +Avoid using `gl_` at the start of your variables (ex, `float gl_Number` can break your shaders). + +Applying defaults to uniforms is not possible, so please set the defaults in your shader constructor or after initializing the shader. + +Avoid using `u` (ex, 8u) +Avoid initializing variables with the name `input` or `sample`, as those cause the shader to stop working on AMD gpus or other platforms. + +Avoid using the % operator, instead use the mod function. + +Avoid using arrays if possible. + +### Guide to porting shaders from shadertoy.com +This is a sample shader that simply renders the texture of a sprite/camera. +```glsl +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord/iResolution.xy; + + // Time varying pixel color + vec4 col = texture(iChannel0, uv); + + // Output to screen + fragColor = col; +} +``` +We will show each step to converting this shader into an usable openfl/flixel shader + +1. replace ``void mainImage( out vec4 fragColor, in vec2 fragCoord )`` with a simple ``void main()`` (flixel and openfl do not have any parameters since the coords are defined outside the function) +2. replace ``vec2 uv = fragCoord/iResolution.xy;`` with ``vec2 uv = openfl_TextureCoordv`` (or in some cases, add ``vec2 fragCoord = openfl_TextureCoordv*openfl_TextureSize.xy`` before it and replace `iResolution.xy` with ``openfl_TextureSize.xy`` (if the uv value is different than usual)) +3. replace ``vec4 col = texture(iChannel0, uv);`` with ``vec4 col = texture2D(bitmap, uv);`` or ``vec4 col = flixel_texture2D(bitmap, uv);`` (keep in mind bitmap is the pixels of the camera/sprite the shader is aplied to) +4. finally, replace ``fragColor = col;`` with ``gl_FragColor = col;`` + +###### Keep in mind that this covers the most basic on how to convert a shader from shadertoy.com, complex shaders will need more expertise with handling shaders before converting those. + +------- + +### Common Practice: + +Use ``texture2D`` for camera shaders, and FlxGame shaders, and ``flixel_texture2D`` for sprite shaders. +``flixel_texture2D`` applies the .colorTransform, while ``texture2D`` doesn't. + +------- + +Extra: + +Use tabs for indentation \ No newline at end of file diff --git a/assets/shaders/engine/cameraClip.frag b/assets/shaders/engine/cameraClip.frag index d5c2dc35..becd3d1f 100644 --- a/assets/shaders/engine/cameraClip.frag +++ b/assets/shaders/engine/cameraClip.frag @@ -13,5 +13,5 @@ void main() vec2 pixel = gl_FragCoord.xy; if (boxCollision(pixel, clipRect)) gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv.xy); - else gl_FragColor = vec4(0.); + else gl_FragColor = vec4(0.0); } \ No newline at end of file diff --git a/assets/shaders/engine/editorBlur.frag b/assets/shaders/engine/editorBlur.frag index ffcbc755..937aa028 100644 --- a/assets/shaders/engine/editorBlur.frag +++ b/assets/shaders/engine/editorBlur.frag @@ -7,12 +7,9 @@ int steps = 16; int stepsInside = 2; float strength = 0.0075; vec4 getColor(vec2 pos) { - if (pos.x < 0.0) pos.x = 0.0; - else if (pos.x > 1.0 - (1.0 / openfl_TextureSize.x)) pos.x = 1.0 - (1.0 / openfl_TextureSize.x); - if (pos.y < 0.0) pos.y = 0.0; - else if (pos.y > 1.0 - (1.0 / openfl_TextureSize.y)) pos.y = 1.0 - (1.0 / openfl_TextureSize.y); - // return textureCam(bitmap, pos); - return flixel_texture2D(bitmap, pos); + vec2 ps = (pos); + ps = clamp(ps, vec2(0.0), 1.0 - (1.0 / openfl_TextureSize.xy)); + return flixel_texture2D(bitmap, (ps)); } void main() { // vec2 camPos = getCamPos(openfl_TextureCoordv); diff --git a/assets/shaders/engine/editorWaveforms.frag b/assets/shaders/engine/editorWaveforms.frag index c2ea827d..b90ea5ea 100644 --- a/assets/shaders/engine/editorWaveforms.frag +++ b/assets/shaders/engine/editorWaveforms.frag @@ -14,7 +14,7 @@ uniform float pixelOffset; uniform float playerPosition; uniform sampler2D waveformTexture; -uniform ivec2 waveformSize; +uniform vec2 waveformSize; uniform bool lowDetail; @@ -22,7 +22,7 @@ float getAmplitude(vec2 pixel) { float pixelID = floor((pixel.y+pixelOffset)/3.0); // TODO: INVESTIGATE THE 1.+ AND WHY IT WORKS (SRSLY I GOT NO CLUE) -lunar - vec2 wavePixel = vec2(mod(pixelID,waveformSize.x), 1.0+floor(pixelID/waveformSize.x)); + vec2 wavePixel = vec2(mod(pixelID, waveformSize.x), 1.0+floor(pixelID/waveformSize.x)); vec4 waveData = texture2D(waveformTexture, wavePixel / waveformSize); int id = int(mod(wavePixel.x, 3.0)); diff --git a/assets/songs/stress/scripts/tankmenRun.hx b/assets/songs/stress/scripts/tankmenRun.hx index 2b519b11..a7d7a306 100644 --- a/assets/songs/stress/scripts/tankmenRun.hx +++ b/assets/songs/stress/scripts/tankmenRun.hx @@ -8,10 +8,7 @@ var tankmanPool = []; function recycleTankman() { if(tankmanPool.length == 0) { - var a = new TankmenBG(); - a.self = a; - a.fuckingnewfuckingnew(); - return a; + return new TankmenBG(); } else { return tankmanPool.shift(); // can be pop but it causes it to be less random } @@ -73,8 +70,7 @@ function update(elapsed) { } } -class TankmenBG -{ +class TankmenBG { var strumTime = 0; var goingRight = false; var tankSpeed = 0.7; @@ -82,11 +78,9 @@ class TankmenBG var endingOffset = null; var sprite = null; - var self = null; var killed = false; - var fuckingnewfuckingnew = function() - { + function new() { this.sprite = new FlxSprite(); var sprite = this.sprite; @@ -102,8 +96,7 @@ class TankmenBG sprite.updateHitbox(); } - var resetShit = function(x, y, isGoingRight) - { + function resetShit(x, y, isGoingRight) { var sprite = this.sprite; sprite.revive(); sprite.setPosition(x, y); @@ -120,8 +113,7 @@ class TankmenBG sprite.flipX = goingRight; } - var update = function(elapsed) - { + function update(elapsed) { var sprite = this.sprite; sprite.visible = !(sprite.x >= FlxG.width * 1.5 || sprite.x <= FlxG.width * -0.5); @@ -143,8 +135,8 @@ class TankmenBG killed = true; grpTankmanRun.remove(sprite, true); sprite.kill(); - tankmanPool.push(self); - tankmanRun.remove(self); + tankmanPool.push(this); + tankmanRun.remove(this); } if (goingRight) diff --git a/libs.xml b/libs.xml index 67ad3811..6e4b44c4 100644 --- a/libs.xml +++ b/libs.xml @@ -13,7 +13,7 @@ - + diff --git a/source/StringTools.hx b/source/StringTools.hx new file mode 100644 index 00000000..0b495af1 --- /dev/null +++ b/source/StringTools.hx @@ -0,0 +1,632 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import haxe.iterators.StringIterator; +import haxe.iterators.StringKeyValueIterator; + +#if cpp +using cpp.NativeString; +#end + +/** + This class provides advanced methods on Strings. It is ideally used with + `using StringTools` and then acts as an [extension](https://haxe.org/manual/lf-static-extension.html) + to the `String` class. + + If the first argument to any of the methods is null, the result is + unspecified. +**/ +class StringTools { + /** + Encode an URL by using the standard format. + **/ + #if (!java && !cpp && !lua && !eval) inline #end public static function urlEncode(s:String):String { + #if flash + return untyped __global__["encodeURIComponent"](s); + #elseif neko + return untyped new String(_urlEncode(s.__s)); + #elseif js + return untyped encodeURIComponent(s); + #elseif cpp + return untyped s.__URLEncode(); + #elseif java + return postProcessUrlEncode(java.net.URLEncoder.encode(s, "UTF-8")); + #elseif python + return python.lib.urllib.Parse.quote(s, ""); + #elseif hl + var len = 0; + var b = @:privateAccess s.bytes.urlEncode(len); + return @:privateAccess String.__alloc__(b, len); + #elseif lua + s = lua.NativeStringTools.gsub(s, "\n", "\r\n"); + s = lua.NativeStringTools.gsub(s, "([^%w %-%_%.%~])", function(c) { + return lua.NativeStringTools.format("%%%02X", lua.NativeStringTools.byte(c) + ''); + }); + s = lua.NativeStringTools.gsub(s, " ", "+"); + return s; + #else + return null; + #end + } + + #if java + private static function postProcessUrlEncode(s:String):String { + var ret = new StringBuf(); + var i = 0, len = s.length; + while (i < len) { + switch (_charAt(s, i++)) { + case '+'.code: + ret.add('%20'); + case '%'.code if (i <= len - 2): + var c1 = _charAt(s, i++), c2 = _charAt(s, i++); + switch [c1, c2] { + case ['2'.code, '1'.code]: + ret.addChar('!'.code); + case ['2'.code, '7'.code]: + ret.addChar('\''.code); + case ['2'.code, '8'.code]: + ret.addChar('('.code); + case ['2'.code, '9'.code]: + ret.addChar(')'.code); + case ['7'.code, 'E'.code] | ['7'.code, 'e'.code]: + ret.addChar('~'.code); + case _: + ret.addChar('%'.code); + ret.addChar(cast c1); + ret.addChar(cast c2); + } + case var chr: + ret.addChar(cast chr); + } + } + return ret.toString(); + } + #end + + /** + Decode an URL using the standard format. + **/ + #if (!java && !cpp && !lua && !eval) inline #end public static function urlDecode(s:String):String { + #if flash + return untyped __global__["decodeURIComponent"](s.split("+").join(" ")); + #elseif neko + return untyped new String(_urlDecode(s.__s)); + #elseif js + return untyped decodeURIComponent(s.split("+").join(" ")); + #elseif cpp + return untyped s.__URLDecode(); + #elseif java + try + return java.net.URLDecoder.decode(s, "UTF-8") + catch (e:Dynamic) + throw e; + #elseif python + return python.lib.urllib.Parse.unquote(s); + #elseif hl + var len = 0; + var b = @:privateAccess s.bytes.urlDecode(len); + return @:privateAccess String.__alloc__(b, len); + #elseif lua + s = lua.NativeStringTools.gsub(s, "+", " "); + s = lua.NativeStringTools.gsub(s, "%%(%x%x)", function(h) { + return lua.NativeStringTools.char(lua.Lua.tonumber(h, 16)); + }); + s = lua.NativeStringTools.gsub(s, "\r\n", "\n"); + return s; + #else + return null; + #end + } + + /** + Escapes HTML special characters of the string `s`. + + The following replacements are made: + + - `&` becomes `&`; + - `<` becomes `<`; + - `>` becomes `>`; + + If `quotes` is true, the following characters are also replaced: + + - `"` becomes `"`; + - `'` becomes `'`; + **/ + public static function htmlEscape(s:String, ?quotes:Bool):String { + var buf = new StringBuf(); + for (code in #if neko iterator(s) #else new haxe.iterators.StringIteratorUnicode(s) #end) { + switch (code) { + case '&'.code: + buf.add("&"); + case '<'.code: + buf.add("<"); + case '>'.code: + buf.add(">"); + case '"'.code if (quotes): + buf.add("""); + case '\''.code if (quotes): + buf.add("'"); + case _: + buf.addChar(code); + } + } + return buf.toString(); + } + + /** + Unescapes HTML special characters of the string `s`. + + This is the inverse operation to htmlEscape, i.e. the following always + holds: `htmlUnescape(htmlEscape(s)) == s` + + The replacements follow: + + - `&` becomes `&` + - `<` becomes `<` + - `>` becomes `>` + - `"` becomes `"` + - `'` becomes `'` + **/ + public static function htmlUnescape(s:String):String { + return s.split(">") + .join(">") + .split("<") + .join("<") + .split(""") + .join('"') + .split("'") + .join("'") + .split("&") + .join("&"); + } + + /** + Returns `true` if `s` contains `value` and `false` otherwise. + + When `value` is `null`, the result is unspecified. + **/ + public static inline function contains(s:String, value:String):Bool { + #if (js && js_es >= 6) + return (cast s).includes(value); + #else + return s.indexOf(value) != -1; + #end + } + + /** + Tells if the string `s` starts with the string `start`. + + If `start` is `null`, the result is unspecified. + + If `start` is the empty String `""`, the result is true. + **/ + public static #if (java || python || (js && js_es >= 6)) inline #end function startsWith(s:String, start:String):Bool { + #if java + return (cast s : java.NativeString).startsWith(start); + #elseif hl + return @:privateAccess (s.length >= start.length && s.bytes.compare(0, start.bytes, 0, start.length << 1) == 0); + #elseif python + return python.NativeStringTools.startswith(s, start); + #elseif (js && js_es >= 6) + return (cast s).startsWith(start); + #elseif lua + return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start); + #else + return (s.length >= start.length && s.indexOf(start, 0) == 0); + #end + } + + /** + Tells if the string `s` ends with the string `end`. + + If `end` is `null`, the result is unspecified. + + If `end` is the empty String `""`, the result is true. + **/ + public static #if (java || python || (js && js_es >= 6)) inline #end function endsWith(s:String, end:String):Bool { + #if java + return (cast s : java.NativeString).endsWith(end); + #elseif hl + var elen = end.length; + var slen = s.length; + return @:privateAccess (slen >= elen && s.bytes.compare((slen - elen) << 1, end.bytes, 0, elen << 1) == 0); + #elseif python + return python.NativeStringTools.endswith(s, end); + #elseif (js && js_es >= 6) + return (cast s).endsWith(end); + #elseif lua + return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end); + #else + var elen = end.length; + var slen = s.length; + return (slen >= elen && s.lastIndexOf(end, (slen - elen)) == (slen - elen)); + #end + } + + /** + Tells if the character in the string `s` at position `pos` is a space. + + A character is considered to be a space character if its character code + is 9,10,11,12,13 or 32. + + If `s` is the empty String `""`, or if pos is not a valid position within + `s`, the result is false. + **/ + public static function isSpace(s:String, pos:Int):Bool { + #if (python || lua) + if (s.length == 0 || pos < 0 || pos >= s.length) + return false; + #end + var c = StringTools.fastCodeAt(s, pos); + return (c > 8 && c < 14) || c == 32; + } + + /** + Removes leading space characters of `s`. + + This function internally calls `isSpace()` to decide which characters to + remove. + + If `s` is the empty String `""` or consists only of space characters, the + result is the empty String `""`. + **/ + public inline static function ltrim(s:String):String { + var l = s.length; + var r = 0; + while (r < l && isSpace(s, r)) { + r++; + } + if (r > 0) + return s.substr(r, l - r); + else + return s; + } + + /** + Removes trailing space characters of `s`. + + This function internally calls `isSpace()` to decide which characters to + remove. + + If `s` is the empty String `""` or consists only of space characters, the + result is the empty String `""`. + **/ + public inline static function rtrim(s:String):String { + var l = s.length; + var r = 0; + while (r < l && isSpace(s, l - r - 1)) { + r++; + } + if (r > 0) { + return s.substr(0, l - r); + } else { + return s; + } + } + + /** + Removes leading and trailing space characters of `s`. + + This is a convenience function for `ltrim(rtrim(s))`. + **/ + public #if java inline #end static function trim(s:String):String { + #if java + return (cast s : java.NativeString).trim(); + #else + //return ltrim(rtrim(s)); + var l = s.length; + var start = 0; + var end = l; + + // Trim leading spaces + while (start < l && isSpace(s, start)) { + start++; + } + + // Trim trailing spaces + while (end > start && isSpace(s, end - 1)) { + end--; + } + + return (start > 0 || end < l) ? s.substr(start, end - start) : s; + #end + } + + /** + Concatenates `c` to `s` until `s.length` is at least `l`. + + If `c` is the empty String `""` or if `l` does not exceed `s.length`, + `s` is returned unchanged. + + If `c.length` is 1, the resulting String length is exactly `l`. + + Otherwise the length may exceed `l`. + + If `c` is null, the result is unspecified. + **/ + public static function lpad(s:String, c:String, l:Int):String { + if (c.length <= 0) + return s; + + var buf = new StringBuf(); + l -= s.length; + while (buf.length < l) { + buf.add(c); + } + buf.add(s); + return buf.toString(); + } + + /** + Appends `c` to `s` until `s.length` is at least `l`. + + If `c` is the empty String `""` or if `l` does not exceed `s.length`, + `s` is returned unchanged. + + If `c.length` is 1, the resulting String length is exactly `l`. + + Otherwise the length may exceed `l`. + + If `c` is null, the result is unspecified. + **/ + public static function rpad(s:String, c:String, l:Int):String { + if (c.length <= 0) + return s; + + var buf = new StringBuf(); + buf.add(s); + while (buf.length < l) { + buf.add(c); + } + return buf.toString(); + } + + /** + Replace all occurrences of the String `sub` in the String `s` by the + String `by`. + + If `sub` is the empty String `""`, `by` is inserted after each character + of `s` except the last one. If `by` is also the empty String `""`, `s` + remains unchanged. + + If `sub` or `by` are null, the result is unspecified. + **/ + public static function replace(s:String, sub:String, by:String):String { + #if java + if (sub.length == 0) + return s.split(sub).join(by); + else + return (cast s : java.NativeString).replace(sub, by); + #else + return s.split(sub).join(by); + #end + } + + /** + Encodes `n` into a hexadecimal representation. + + If `digits` is specified, the resulting String is padded with "0" until + its `length` equals `digits`. + **/ + public static function hex(n:Int, ?digits:Int) { + #if flash + var n:UInt = n; + var s:String = untyped n.toString(16); + s = s.toUpperCase(); + #else + var s = ""; + var hexChars = "0123456789ABCDEF"; + do { + s = hexChars.charAt(n & 15) + s; + n >>>= 4; + } while (n > 0); + #end + #if python + if (digits != null && s.length < digits) { + var diff = digits - s.length; + for (_ in 0...diff) { + s = "0" + s; + } + } + #else + if (digits != null) + while (s.length < digits) + s = "0" + s; + #end + return s; + } + + /** + Returns the character code at position `index` of String `s`, or an + end-of-file indicator at if `position` equals `s.length`. + + This method is faster than `String.charCodeAt()` on some platforms, but + the result is unspecified if `index` is negative or greater than + `s.length`. + + End of file status can be checked by calling `StringTools.isEof()` with + the returned value as argument. + + This operation is not guaranteed to work if `s` contains the `\0` + character. + **/ + public static #if !eval inline #end function fastCodeAt(s:String, index:Int):Int { + #if neko + return untyped __dollar__sget(s.__s, index); + #elseif cpp + return untyped s.cca(index); + #elseif flash + return untyped s.cca(index); + #elseif java + return (index < s.length) ? cast(_charAt(s, index), Int) : -1; + #elseif js + return (cast s).charCodeAt(index); + #elseif python + return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index)); + #elseif hl + return @:privateAccess s.bytes.getUI16(index << 1); + #elseif lua + #if lua_vanilla + return lua.NativeStringTools.byte(s, index + 1); + #else + return lua.lib.luautf8.Utf8.byte(s, index + 1); + #end + #else + return untyped s.cca(index); + #end + } + + /** + Returns the character code at position `index` of String `s`, or an + end-of-file indicator at if `position` equals `s.length`. + + This method is faster than `String.charCodeAt()` on some platforms, but + the result is unspecified if `index` is negative or greater than + `s.length`. + + This operation is not guaranteed to work if `s` contains the `\0` + character. + **/ + public static #if !eval inline #end function unsafeCodeAt(s:String, index:Int):Int { + #if neko + return untyped __dollar__sget(s.__s, index); + #elseif cpp + return untyped s.cca(index); + #elseif flash + return untyped s.cca(index); + #elseif java + return cast(_charAt(s, index), Int); + #elseif js + return (cast s).charCodeAt(index); + #elseif python + return python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index)); + #elseif hl + return @:privateAccess s.bytes.getUI16(index << 1); + #elseif lua + #if lua_vanilla + return lua.NativeStringTools.byte(s, index + 1); + #else + return lua.lib.luautf8.Utf8.byte(s, index + 1); + #end + #else + return untyped s.cca(index); + #end + } + + /** + Returns an iterator of the char codes. + + Note that char codes may differ across platforms because of different + internal encoding of strings in different runtimes. + For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringIteratorUnicode`. + **/ + public static inline function iterator(s:String):StringIterator { + return new StringIterator(s); + } + + /** + Returns an iterator of the char indexes and codes. + + Note that char codes may differ across platforms because of different + internal encoding of strings in different of runtimes. + For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringKeyValueIteratorUnicode`. + **/ + public static inline function keyValueIterator(s:String):StringKeyValueIterator { + return new StringKeyValueIterator(s); + } + + /** + Tells if `c` represents the end-of-file (EOF) character. + **/ + @:noUsing public static inline function isEof(c:Int):Bool { + #if (flash || cpp || hl) + return c == 0; + #elseif js + return c != c; // fast NaN + #elseif (neko || lua || eval) + return c == null; + #elseif (java || python) + return c == -1; + #else + return false; + #end + } + + /** + Returns a String that can be used as a single command line argument + on Unix. + The input will be quoted, or escaped if necessary. + **/ + @:noCompletion + @:deprecated('StringTools.quoteUnixArg() is deprecated. Use haxe.SysTools.quoteUnixArg() instead.') + public static function quoteUnixArg(argument:String):String { + return inline haxe.SysTools.quoteUnixArg(argument); + } + + /** + Character codes of the characters that will be escaped by `quoteWinArg(_, true)`. + **/ + @:noCompletion + @:deprecated('StringTools.winMetaCharacters is deprecated. Use haxe.SysTools.winMetaCharacters instead.') + public static var winMetaCharacters:Array = cast haxe.SysTools.winMetaCharacters; + + /** + Returns a String that can be used as a single command line argument + on Windows. + The input will be quoted, or escaped if necessary, such that the output + will be parsed as a single argument using the rule specified in + http://msdn.microsoft.com/en-us/library/ms880421 + + Examples: + ```haxe + quoteWinArg("abc") == "abc"; + quoteWinArg("ab c") == '"ab c"'; + ``` + **/ + @:noCompletion + @:deprecated('StringTools.quoteWinArg() is deprecated. Use haxe.SysTools.quoteWinArg() instead.') + public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String { + return inline haxe.SysTools.quoteWinArg(argument, escapeMetaCharacters); + } + + #if java + private static inline function _charAt(str:String, idx:Int):java.StdTypes.Char16 + return (cast str : java.NativeString).charAt(idx); + #end + + #if neko + private static var _urlEncode = neko.Lib.load("std", "url_encode", 1); + private static var _urlDecode = neko.Lib.load("std", "url_decode", 1); + #end + + #if utf16 + static inline var MIN_SURROGATE_CODE_POINT = 65536; + + static inline function utf16CodePointAt(s:String, index:Int):Int { + var c = StringTools.fastCodeAt(s, index); + if (c >= 0xD800 && c <= 0xDBFF) { + c = ((c - 0xD7C0) << 10) | (StringTools.fastCodeAt(s, index + 1) & 0x3FF); + } + return c; + } + #end +} diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx index 40b36a02..97500198 100644 --- a/source/funkin/backend/FunkinSprite.hx +++ b/source/funkin/backend/FunkinSprite.hx @@ -181,10 +181,12 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I animateAtlas.flipX = flipX; animateAtlas.flipY = flipY; animateAtlas.shader = shader; + animateAtlas.shaderEnabled = shaderEnabled; animateAtlas.antialiasing = antialiasing; animateAtlas.skew = skew; animateAtlas.transformMatrix = transformMatrix; animateAtlas.matrixExposed = matrixExposed; + animateAtlas.colorTransform = colorTransform; } } diff --git a/source/funkin/backend/shaders/FunkinShader.hx b/source/funkin/backend/shaders/FunkinShader.hx index 612411e9..b676ae45 100644 --- a/source/funkin/backend/shaders/FunkinShader.hx +++ b/source/funkin/backend/shaders/FunkinShader.hx @@ -457,14 +457,7 @@ vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) } color = vec4(color.rgb / color.a, color.a); - - mat4 colorMultiplier = mat4(0); - colorMultiplier[0][0] = openfl_ColorMultiplierv.x; - colorMultiplier[1][1] = openfl_ColorMultiplierv.y; - colorMultiplier[2][2] = openfl_ColorMultiplierv.z; - colorMultiplier[3][3] = openfl_ColorMultiplierv.w; - - color = clamp(openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0); + color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0); if (color.a > 0.0) { @@ -491,39 +484,9 @@ vec4 textureCam(sampler2D bitmap, vec2 pos) { return flixel_texture2D(bitmap, camToOg(pos)); }"; - public static final fragBody:String = "vec4 color = texture2D (bitmap, openfl_TextureCoordv); - -if (color.a == 0.0) { - - gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0); - -} else if (openfl_HasColorTransform) { - - color = vec4 (color.rgb / color.a, color.a); - - mat4 colorMultiplier = mat4 (0); - colorMultiplier[0][0] = openfl_ColorMultiplierv.x; - colorMultiplier[1][1] = openfl_ColorMultiplierv.y; - colorMultiplier[2][2] = openfl_ColorMultiplierv.z; - colorMultiplier[3][3] = 1.0; // openfl_ColorMultiplierv.w; - - color = clamp (openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0); - - if (color.a > 0.0) { - - gl_FragColor = vec4 (color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav); - - } else { - - gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0); - - } - -} else { - - gl_FragColor = color * openfl_Alphav; - -}"; + public static final fragBody:String = "vec4 color = flixel_texture2D (bitmap, openfl_TextureCoordv); + gl_FragColor = color; +"; public static final vertHeader:String = "attribute float openfl_Alpha; attribute vec4 openfl_ColorMultiplier; attribute vec4 openfl_ColorOffset; diff --git a/source/funkin/backend/shaders/WiggleEffect.hx b/source/funkin/backend/shaders/WiggleEffect.hx index 43dc1caa..21c52690 100644 --- a/source/funkin/backend/shaders/WiggleEffect.hx +++ b/source/funkin/backend/shaders/WiggleEffect.hx @@ -75,18 +75,18 @@ const int EFFECT_TYPE_FLAG = 4; uniform int effectType; /** - * How fast the waves move over time - */ +* How fast the waves move over time +*/ uniform float uSpeed; /** - * Number of waves over time - */ +* Number of waves over time +*/ uniform float uFrequency; /** - * How much the pixels are going to stretch over the waves - */ +* How much the pixels are going to stretch over the waves +*/ uniform float uWaveAmplitude; vec2 sineWave(vec2 pt) diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx index e00e58f8..dd952d19 100644 --- a/source/funkin/game/StrumLine.hx +++ b/source/funkin/game/StrumLine.hx @@ -148,6 +148,11 @@ class StrumLine extends FlxTypedGroup { } } notes.sortNotes(); + + var scrollSpeed = strumLine.scrollSpeed; + if(scrollSpeed == null) if (PlayState.instance != null) scrollSpeed = PlayState.instance.scrollSpeed; + if(scrollSpeed == null) scrollSpeed = 1; + notes.limit = 1500 / scrollSpeed; } public override function update(elapsed:Float) { @@ -179,10 +184,11 @@ class StrumLine extends FlxTypedGroup { if (__updateNote_event.cancelled) return; if (__updateNote_event.__updateHitWindow) { - daNote.canBeHit = (daNote.strumTime > __updateNote_songPos - (PlayState.instance.hitWindow * daNote.latePressWindow) - && daNote.strumTime < __updateNote_songPos + (PlayState.instance.hitWindow * daNote.earlyPressWindow)); + var hitWindow = PlayState.instance.hitWindow; + daNote.canBeHit = (daNote.strumTime > __updateNote_songPos - (hitWindow * daNote.latePressWindow) + && daNote.strumTime < __updateNote_songPos + (hitWindow * daNote.earlyPressWindow)); - if (daNote.strumTime < __updateNote_songPos - PlayState.instance.hitWindow && !daNote.wasGoodHit) + if (daNote.strumTime < __updateNote_songPos - hitWindow && !daNote.wasGoodHit) daNote.tooLate = true; } diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx index 2f5ea12c..27391e0a 100644 --- a/source/funkin/menus/MainMenuState.hx +++ b/source/funkin/menus/MainMenuState.hx @@ -19,8 +19,10 @@ class MainMenuState extends MusicBeatState var optionShit:Array = CoolUtil.coolTextFile(Paths.txt("config/menuItems")); + var bg:FlxSprite; var magenta:FlxSprite; var camFollow:FlxObject; + var versionText:FunkinText; public var canAccessDebugMenus:Bool = true; @@ -32,7 +34,7 @@ class MainMenuState extends MusicBeatState CoolUtil.playMenuSong(); - var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBG')); + bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBG')); add(bg); camFollow = new FlxObject(0, 0, 1, 1); @@ -70,15 +72,16 @@ class MainMenuState extends MusicBeatState FlxG.camera.follow(camFollow, null, 0.06); - var versionShit:FunkinText = new FunkinText(5, FlxG.height - 2, 0, 'Codename Engine v${Application.current.meta.get('version')}\nCommit ${funkin.backend.system.macros.GitCommitMacro.commitNumber} (${funkin.backend.system.macros.GitCommitMacro.commitHash})\n[${controls.getKeyName(SWITCHMOD)}] Open Mods menu\n'); - versionShit.y -= versionShit.height; - versionShit.scrollFactor.set(); - add(versionShit); + versionText = new FunkinText(5, FlxG.height - 2, 0, 'Codename Engine v${Application.current.meta.get('version')}\nCommit ${funkin.backend.system.macros.GitCommitMacro.commitNumber} (${funkin.backend.system.macros.GitCommitMacro.commitHash})\n[${controls.getKeyName(SWITCHMOD)}] Open Mods menu\n'); + versionText.y -= versionText.height; + versionText.scrollFactor.set(); + add(versionText); changeItem(); } var selectedSomethin:Bool = false; + var forceCenterX:Bool = true; override function update(elapsed:Float) { @@ -127,6 +130,7 @@ class MainMenuState extends MusicBeatState super.update(elapsed); + if (forceCenterX) menuItems.forEach(function(spr:FlxSprite) { spr.screenCenter(X);