Fix every internal_merge issues

This commit is contained in:
Ralty
2026-03-01 14:15:02 +07:00
parent 143cc447c8
commit c20c29250d
17 changed files with 1046 additions and 1205 deletions
@@ -47,7 +47,7 @@ class MultiFramesCollection extends FlxFramesCollection
public function addFrames(collection:FlxFramesCollection) {
if (collection == null || collection.frames == null) return;
collection.parent.useCount++;
collection.parent.incrementUseCount();
parentedFrames.push(collection);
for(f in collection.frames) {
@@ -63,7 +63,7 @@ class MultiFramesCollection extends FlxFramesCollection
if(parentedFrames != null) {
for(collection in parentedFrames) {
if(collection != null)
collection.parent.useCount--;
collection.parent.decrementUseCount();
}
parentedFrames = null;
}
+284 -575
View File
@@ -1,17 +1,20 @@
package funkin.backend.shaders;
import haxe.Exception;
import haxe.io.Path;
import flixel.graphics.FlxGraphic;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxSignal.FlxTypedSignal;
import haxe.Exception;
import flixel.util.FlxStringUtil;
import hscript.IHScriptCustomBehaviour;
import lime.utils.Float32Array;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import openfl.display.Shader;
import openfl.display3D._internal.GLProgram;
import openfl.display3D._internal.GLShader;
import openfl.display3D.Program3D;
import openfl.utils._internal.Log;
using StringTools;
@@ -20,14 +23,94 @@ using StringTools;
@:access(openfl.display.ShaderInput)
@:access(openfl.display.ShaderParameter)
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
#if REGION /* Backward Compatibility */
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
private static var FRAGMENT_SHADER = 0;
private static var VERTEX_SHADER = 1;
public var glslVer(get, set):String;
inline function get_glslVer():String return glVersion;
inline function set_glslVer(v:String):String return glVersion = v;
public var glRawFragmentSource(get, set):String;
inline function get_glRawFragmentSource():String return __glFragmentSourceRaw;
inline function set_glRawFragmentSource(v:String):String return __glFragmentSourceRaw = v;
public var glRawVertexSource(get, set):String;
inline function get_glRawVertexSource():String return __glVertexSourceRaw;
inline function set_glRawVertexSource(v:String):String return __glVertexSourceRaw = v;
// Unused... cne-openfl uses a different system
var __cancelNextProcessGLData:Bool = false;
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
#end
public static function getShaderCode(key:String, isFragment = true):Null<String> {
var path = "shaders/" + key;
key = Path.withoutExtension(key);
final ext = Path.extension(path);
if (ext == "") path = path + (isFragment ? ".frag" : ".vert");
else isFragment = ext != "vert";
path = Paths.getPath(path);
return Assets.exists(path) ? Assets.getText(path) : null;
}
private static function processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String
return Shader.processGLSLText(_processGLSLText(source, glVersion, isFragment, pragmas), glVersion, isFragment);
private static function _processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String {
var injectedFragColor = StringTools.contains(source, "out vec4"), canInjectFragColorFix = switch (glVersion) {
case "300 es", "330", "400", "410", "420", "430", "440", "450", "460": isFragment;
default: false;
};
if (pragmas != null) {
final pragmaKeyword = ~/#pragma (\w+)/g;
source = pragmaKeyword.map(source, (_) -> {
var name = pragmaKeyword.matched(1);
if (!pragmas.exists(name)) return '#pragma $name';
var pragma = pragmas.get(name);
if (name == "header" && canInjectFragColorFix && !injectedFragColor) {
injectedFragColor = true;
if (!StringTools.contains(pragma, "out vec4")) return processGLSLText(Shader.fragColorHeaderFix + pragma, glVersion, isFragment, pragmas);
}
return processGLSLText(pragma, glVersion, isFragment, pragmas);
});
}
inline function tryGetShaderCode(key:String) {
final s = getShaderCode(key, isFragment);
if (s == null) {
Logs.traceColored([
Logs.logText('[Shader] ', RED),
Logs.logText('Failed to import shader $key', RED),
]);
return "";
}
return s;
}
final includeKeyword = ~/#include ['"](.+)['"]/g;
final importKeyword = ~/#import\s+<(.*)>/g;
source = importKeyword.map(source, (_) ->
return processGLSLText(tryGetShaderCode(importKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
return source = includeKeyword.map(source, (_) ->
return processGLSLText(tryGetShaderCode(includeKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
}
private static var __defaultsAvailable:Bool;
private static var __glFragmentSourceDefault:String;
private static var __glVertexSourceDefault:String;
private static var __glFragmentPragmasDefault:Map<String, String>;
private static var __glVertexPragmasDefault:Map<String, String>;
private static var __glFragmentExtensionsDefault:Array<ShaderExtension>;
private static var __glVertexExtensionsDefault:Array<ShaderExtension>;
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
public var glslVer:String = Flags.DEFAULT_GLSL_VERSION;
public var fileName:String = "FunkinShader";
public var fragFileName:String = "FunkinShader";
public var vertFileName:String = "FunkinShader";
@@ -36,221 +119,54 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
public var fragmentPrefix:String = "";
public var vertexPrefix:String = "";
/**
* Creates a new shader from the specified fragment and vertex source.
* Accepts `#pragma header`.
* @param frag Fragment source (pass `null` to use default)
* @param vert Vertex source (pass `null` to use default)
* @param glslVer Version of GLSL to use (defaults to 120)
*/
public override function new(frag:String, vert:String, glslVer:String = null) {
if (glslVer == null) glslVer = Flags.DEFAULT_GLSL_VERSION;
if (frag == null) frag = ShaderTemplates.defaultFragmentSource;
if (vert == null) vert = ShaderTemplates.defaultVertexSource;
this.glFragmentSource = frag;
this.glVertexSource = vert;
private var __immediate:Bool;
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String,
?fragmentExtensions:Array<ShaderExtension>, ?vertexExtensions:Array<ShaderExtension>, immediate = false
) {
if (!__defaultsAvailable) {
__glFragmentSourceDefault = __glFragmentSourceRaw;
__glVertexSourceDefault = __glVertexSourceRaw;
__glFragmentPragmasDefault = __glFragmentPragmas.copy();
__glVertexPragmasDefault = __glVertexPragmas.copy();
__glFragmentExtensionsDefault = __glFragmentExtensions ?? [];
__glVertexExtensionsDefault = __glVertexExtensions ?? [];
__defaultsAvailable = true;
}
__immediate = immediate;
if (version != null) glVersion = version;
if (vertexExtensions != null) glVertexExtensions = vertexExtensions;
if (fragmentExtensions != null) glFragmentExtensions = fragmentExtensions;
if (vertexSource != null) glVertexSource = vertexSource;
if (fragmentSource != null) glFragmentSource = fragmentSource;
this.glslVer = glslVer;
super();
if (!__isGenerated) {
__isGenerated = true;
__init();
}
}
static var IMPORT_REGEX = ~/#import\s+<(.*)>/;
public function loadShader(name:String, ?version:String, immediate = false):FunkinShader {
final fragment = getShaderCode(name, true), vertex = getShaderCode(name, false);
private function processImports(value:String, type:Int):String
{
while(IMPORT_REGEX.match(value))
{
var importPath = IMPORT_REGEX.matched(1);
var importSource = Assets.getText("assets/shaders/" + importPath);
if(importSource == null) {
var fileName = type == FRAGMENT_SHADER ? fragFileName : vertFileName;
Logs.traceColored([
Logs.logText('[Shader] ', RED),
Logs.logText('Failed to import shader ${importPath} in ${fileName}', RED),
]);
} else {
value = value.replace(IMPORT_REGEX.matched(0), importSource);
}
}
return value;
glVersion = version;
glVertexSource = vertex ?? __glVertexSourceDefault;
glFragmentSource = fragment ?? __glFragmentSourceDefault;
if (immediate) __init();
return this;
}
static var ERROR_POS_REGEX = ~/(\d+):(\d+): (.*)/g;
static var ERROR_REGEX = ~/ERROR: (\d+):(\d+): (.*)/g;
static var ERROR_REGEX_2 = ~/(\d+)\((\d+)\) : error ([^:]+): (.*)/g;
@:noCompletion private override function __createGLShader(source:String, type:Int):GLShader
{
var gl = __context.gl;
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var shaderInfoLog = gl.getShaderInfoLog(shader);
var hasInfoLog = shaderInfoLog != null && StringTools.trim(shaderInfoLog) != "";
var compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (hasInfoLog || compileStatus == 0)
{
var isVertexShader = type == gl.VERTEX_SHADER;
var messageBuf = new StringBuf();
messageBuf.add((compileStatus == 0) ? "Error" : "Info");
if(isVertexShader) {
messageBuf.add(" compiling vertex shader");
if(vertFileName != null && vertFileName.length > 0) {
messageBuf.add(" (" + vertFileName + ")");
}
} else {
messageBuf.add(" compiling fragment shader");
if(fragFileName != null && fragFileName.length > 0) {
messageBuf.add(" (" + fragFileName + ")");
}
}
messageBuf.add("\n");
var errorPositions = [];
var regex = null;
var tmp = shaderInfoLog;
if(shaderInfoLog.contains(" : error ")) {
regex = ERROR_REGEX_2;
while(regex.match(tmp)) {
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(4)));
tmp = regex.matchedRight();
}
} else if(shaderInfoLog.contains("ERROR: ")) {
regex = ERROR_REGEX;
while(regex.match(tmp)) {
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
tmp = regex.matchedRight();
}
} else {
regex = ERROR_POS_REGEX;
while(regex.match(tmp)) {
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
tmp = regex.matchedRight();
}
}
var splitSource = source.split("\n");
for(error in errorPositions) {
messageBuf.add("ERROR: Line: " + error.line);
if(error.column > 0) {
messageBuf.add(", Column: " + error.column);
}
messageBuf.add(", " + error.message);
if(error.line < splitSource.length) {
messageBuf.add("\nLine: ");
messageBuf.add(splitSource[error.line-1].trim());
}
messageBuf.add("\n\n");
}
var hasErrorPosition = errorPositions.length > 0;
if(hasErrorPosition) {
messageBuf.add("Raw shader info log:\n");
}
messageBuf.add(shaderInfoLog);
messageBuf.add("\n");
messageBuf.add(source);
var message = messageBuf.toString();
if (compileStatus == 0) Log.error(message);
else if (hasInfoLog) Log.debug(message);
override function __initGL():Void {
if (__immediate) {
__context = FlxG.stage.context3D;
__enable();
}
return shader;
}
@:noCompletion private override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram
{
var program:GLProgram = null;
try
{
var gl = __context.gl;
var vertexShader = __createGLShader(vertexSource, gl.VERTEX_SHADER);
var fragmentShader = __createGLShader(fragmentSource, gl.FRAGMENT_SHADER);
program = gl.createProgram();
// Fix support for drivers that don't draw if attribute 0 is disabled
for (param in __paramFloat)
{
if (param.name.indexOf("Position") > -1 && StringTools.startsWith(param.name, "openfl_"))
{
gl.bindAttribLocation(program, 0, param.name);
break;
}
}
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0)
{
var messageBuf = new StringBuf();
messageBuf.add("Unable to initialize the shader program");
messageBuf.add("\n");
messageBuf.add(gl.getProgramInfoLog(program));
var message = messageBuf.toString();
Log.error(message);
}
}
catch (error:Dynamic)
{
Logs.traceColored([
Logs.logText('[Shader] ', BLUE),
Logs.logText('Failed to compile shader ${fileName}: ', RED),
Logs.logText(Std.string(error))
], TRACE);
}
return program;
return program;
}
var glRawFragmentSource:String;
var glRawVertexSource:String;
@:noCompletion override private function set_glFragmentSource(value:String):String
{
if(value == null)
value = ShaderTemplates.defaultFragmentSource;
glRawFragmentSource = value;
value = processImports(value, FRAGMENT_SHADER);
value = value.replace("#pragma header", ShaderTemplates.fragHeader).replace("#pragma body", ShaderTemplates.fragBody);
if (value != __glFragmentSource)
{
__glSourceDirty = true;
}
return __glFragmentSource = value;
}
@:noCompletion override private function set_glVertexSource(value:String):String
{
if(value == null)
value = ShaderTemplates.defaultVertexSource;
glRawVertexSource = value;
value = processImports(value, VERTEX_SHADER);
var useBackCompat:Bool = true;
for (regex in ShaderTemplates.vertBackCompatVarList) if (!regex.match(value)) {
useBackCompat = false;
break;
}
var header = useBackCompat ? ShaderTemplates.vertHeaderBackCompat : ShaderTemplates.vertHeader;
var body = useBackCompat ? ShaderTemplates.vertBodyBackCompat : ShaderTemplates.vertBody;
value = value.replace("#pragma header", header).replace("#pragma body", body);
if (value != __glVertexSource)
{
__glSourceDirty = true;
}
return __glVertexSource = value;
super.__initGL();
}
override function __updateGL():Void {
@@ -258,276 +174,14 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
super.__updateGL();
}
@:noCompletion private override function __initGL():Void
{
if (__glSourceDirty || __paramBool == null)
{
__glSourceDirty = false;
program = null;
__inputBitmapData = new Array();
__paramBool = new Array();
__paramFloat = new Array();
__paramInt = new Array();
__processGLData(glVertexSource, "attribute");
__processGLData(glVertexSource, "uniform");
__processGLData(glFragmentSource, "uniform");
}
if (__context != null && program == null)
{
var prefixBuf = new StringBuf();
prefixBuf.add('#version ${glslVer}\n');
prefixBuf.add(shaderPrefix);
var gl = __context.gl;
prefixBuf.add("#ifdef GL_ES\n");
if (precisionHint == FULL) {
prefixBuf.add("#ifdef GL_FRAGMENT_PRECISION_HIGH\n");
prefixBuf.add("precision highp float;\n");
prefixBuf.add("#else\n");
prefixBuf.add("precision mediump float;\n");
prefixBuf.add("#endif\n");
} else {
prefixBuf.add("precision lowp float;\n");
}
prefixBuf.add("#endif\n");
var prefix = prefixBuf.toString();
var vertex = prefix + vertexPrefix + glVertexSource;
var fragment = prefix + fragmentPrefix + glFragmentSource;
var id = vertex + fragment;
if (__context.__programs.exists(id))
{
program = __context.__programs.get(id);
}
else
{
program = __context.createProgram(GLSL);
program.__glProgram = __createGLProgram(vertex, fragment);
__context.__programs.set(id, program);
}
if (program != null)
{
glProgram = program.__glProgram;
for (input in __inputBitmapData) {
if (input.__isUniform) {
input.index = gl.getUniformLocation(glProgram, input.name);
} else {
input.index = gl.getAttribLocation(glProgram, input.name);
}
}
for (parameter in __paramBool) {
if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
} else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
for (parameter in __paramFloat) {
if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
} else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
for (parameter in __paramInt) {
if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
} else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
}
// initInstance(vertex, fragment); // btw make sure to disable the prefixes for ._isInstance
}
}
var __cancelNextProcessGLData:Bool = false;
@:noCompletion private override function __processGLData(source:String, storageType:String):Void
{
onProcessGLData.dispatch(source, storageType);
if (__cancelNextProcessGLData != (__cancelNextProcessGLData = false))
return;
var lastMatch = 0, position, regex, name, type;
if (storageType == "uniform")
{
regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/;
}
else
{
regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/;
}
while (regex.matchSub(source, lastMatch))
{
type = regex.matched(1);
name = regex.matched(2);
if (StringTools.startsWith(name, "gl_"))
{
continue;
}
var isUniform = (storageType == "uniform");
registerParameter(name, type, isUniform);
position = regex.matchedPos();
lastMatch = position.pos + position.len;
}
}
function registerParameter(name:String, type:String, isUniform:Bool):Void
{
if (StringTools.startsWith(type, "sampler"))
{
var input = new ShaderInput<BitmapData>();
input.name = name;
input.__isUniform = isUniform;
__inputBitmapData.push(input);
switch (name)
{
case "openfl_Texture":
__texture = input;
case "bitmap":
__bitmap = input;
default:
}
Reflect.setField(__data, name, input);
try{Reflect.setField(this, name, input);} catch(e) {}
}
else if (!Reflect.hasField(__data, name) || Reflect.field(__data, name) == null)
{
var parameterType:ShaderParameterType = switch (type)
{
case "bool": BOOL;
case "double", "float": FLOAT;
case "int", "uint": INT;
case "bvec2": BOOL2;
case "bvec3": BOOL3;
case "bvec4": BOOL4;
case "ivec2", "uvec2": INT2;
case "ivec3", "uvec3": INT3;
case "ivec4", "uvec4": INT4;
case "vec2", "dvec2": FLOAT2;
case "vec3", "dvec3": FLOAT3;
case "vec4", "dvec4": FLOAT4;
case "mat2", "mat2x2": MATRIX2X2;
case "mat2x3": MATRIX2X3;
case "mat2x4": MATRIX2X4;
case "mat3x2": MATRIX3X2;
case "mat3", "mat3x3": MATRIX3X3;
case "mat3x4": MATRIX3X4;
case "mat4x2": MATRIX4X2;
case "mat4x3": MATRIX4X3;
case "mat4", "mat4x4": MATRIX4X4;
default: null;
}
var length = switch (parameterType)
{
case BOOL2, INT2, FLOAT2: 2;
case BOOL3, INT3, FLOAT3: 3;
case BOOL4, INT4, FLOAT4, MATRIX2X2: 4;
case MATRIX3X3: 9;
case MATRIX4X4: 16;
default: 1;
}
var arrayLength = switch (parameterType)
{
case MATRIX2X2: 2;
case MATRIX3X3: 3;
case MATRIX4X4: 4;
default: 1;
}
switch (parameterType)
{
case BOOL, BOOL2, BOOL3, BOOL4:
var parameter = new ShaderParameter<Bool>();
parameter.name = name;
parameter.type = parameterType;
parameter.__arrayLength = arrayLength;
parameter.__isBool = true;
parameter.__isUniform = isUniform;
parameter.__length = length;
__paramBool.push(parameter);
if (name == "openfl_HasColorTransform")
{
__hasColorTransform = parameter;
}
Reflect.setField(__data, name, parameter);
try{Reflect.setField(this, name, parameter);} catch(e) {}
case INT, INT2, INT3, INT4:
var parameter = new ShaderParameter<Int>();
parameter.name = name;
parameter.type = parameterType;
parameter.__arrayLength = arrayLength;
parameter.__isInt = true;
parameter.__isUniform = isUniform;
parameter.__length = length;
__paramInt.push(parameter);
Reflect.setField(__data, name, parameter);
try{Reflect.setField(this, name, parameter);} catch(e) {}
default:
var parameter = new ShaderParameter<Float>();
parameter.name = name;
parameter.type = parameterType;
parameter.__arrayLength = arrayLength;
#if lime
if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(arrayLength * arrayLength);
#end
parameter.__isFloat = true;
parameter.__isUniform = isUniform;
parameter.__length = length;
__paramFloat.push(parameter);
if (StringTools.startsWith(name, "openfl_"))
{
switch (name)
{
case "openfl_Alpha": __alpha = parameter;
case "openfl_ColorMultiplier": __colorMultiplier = parameter;
case "openfl_ColorOffset": __colorOffset = parameter;
case "openfl_Matrix": __matrix = parameter;
case "openfl_Position": __position = parameter;
case "openfl_TextureCoord": __textureCoord = parameter;
case "openfl_TextureSize": __textureSize = parameter;
default:
}
}
Reflect.setField(__data, name, parameter);
try{Reflect.setField(this, name, parameter);} catch(e) {}
}
}
}
public function hget(name:String):Dynamic {
if (__instanceFields.contains(name) || __instanceFields.contains('get_${name}'))
return Reflect.getProperty(this, name);
if (!Reflect.hasField(data, name))
return null;
var field:Dynamic = Reflect.field(data, name);
if (__glSourceDirty || __data == null) __init();
if (thisHasField(name) || thisHasField('get_${name}')) return Reflect.getProperty(this, name);
else if (!Reflect.hasField(__data, name)) return null;
final field:Dynamic = Reflect.field(__data, name);
var cl:String = Type.getClassName(Type.getClass(field));
// little problem we are facing boys...
@@ -546,17 +200,19 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
}
public function hset(name:String, val:Dynamic):Dynamic {
if (__instanceFields.contains(name) || __instanceFields.contains('set_${name}')) {
if (__glSourceDirty || __data == null) __init();
if (thisHasField(name) || thisHasField('set_${name}')) {
Reflect.setProperty(this, name, val);
return val;
}
if (!Reflect.hasField(data, name)) {
Reflect.setField(data, name, val);
else if (!Reflect.hasField(__data, name)) {
// ??? huh
Reflect.setField(__data, name, val);
return val;
}
var field = Reflect.field(data, name);
var field = Reflect.field(__data, name);
var cl = Type.getClassName(Type.getClass(field));
var isNotNull = val != null;
// cant do "field is ShaderInput" for some reason
@@ -598,9 +254,133 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
return val;
}
override function __buildSourcePrefix(isFragment:Bool):String {
var result = super.__buildSourcePrefix(isFragment) + '\n$shaderPrefix';
return isFragment ? result + '\n$fragmentPrefix' : result + '\n$vertexPrefix';
}
override function set_glFragmentExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
if (value == null) value = __glFragmentExtensionsDefault;
if (value != __glFragmentExtensions) __glSourceDirty = true;
return __glFragmentExtensions = value;
}
override function set_glVertexExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
if (value == null) value = __glVertexExtensionsDefault;
if (value != __glVertexExtensions) __glSourceDirty = true;
return __glVertexExtensions = value;
}
override function set_glVersion(value:Null<String>):String {
if (value == null || value == "") value = Flags.DEFAULT_GLSL_VERSION;
if ((__glVersionRaw = value) != __glVersion) {
__glSourceDirty = true;
if (__glVertexSourceRaw != null) __glVertexSource = processGLSLText(__glVertexSourceRaw, value, false, __glVertexPragmas);
if (__glFragmentSourceRaw != null) __glFragmentSource = processGLSLText(__glFragmentSourceRaw, value, true, __glFragmentPragmas);
}
return __glVersion = value;
}
override function set_glFragmentSource(value:String):String {
if (value == null || value == "") value = __glFragmentSourceDefault;
if ((__glFragmentSourceRaw = value) != null) {
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
__glSourceDirty = true;
value = processGLSLText(value, __glVersion, true, __glFragmentPragmas);
}
if (value != __glFragmentSource) __glSourceDirty = true;
return __glFragmentSource = value;
}
override function set_glVertexSource(value:String):String {
if (value == null || value == "") value = __glVertexSourceDefault;
if ((__glVertexSourceRaw = value) != null) {
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
__glSourceDirty = true;
value = processGLSLText(value, __glVersion, false, __glVertexPragmas);
}
if (value != __glVertexSource) __glSourceDirty = true;
return __glVertexSource = value;
}
override function set_glFragmentPragmas(value:Map<String, String>):Map<String, String> {
if (value == null) value = __glFragmentPragmasDefault;
if (value != __glFragmentPragmas)
__glSourceDirty = true;
return __glFragmentPragmas = value;
}
override function set_glVertexPragmas(value:Map<String, String>):Map<String, String> {
if (value == null) value = __glVertexPragmasDefault;
if (value != __glVertexPragmas)
__glSourceDirty = true;
return __glVertexPragmas = value;
}
function registerParameter(name:String, type:String, isUniform:Bool):Void {
__registerParameter(name, Program3D.getParameterTypeFromGLString(type, 1), 1, -1, isUniform, false, null);
}
public function toString():String
return FlxStringUtil.getDebugString([for (field in Reflect.fields(data)) LabelValuePair.weak(field, Reflect.field(data, field))]);
}
class ShaderTemplates {
#if REGION /* Backward Compatibility */
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
attribute float alpha;
attribute vec4 colorMultiplier;
attribute vec4 colorOffset;
uniform bool hasColorTransform;";
public static final vertBody:String = "openfl_TextureCoordv = openfl_TextureCoord;
if (hasColorTransform) {
openfl_Alphav = openfl_Alpha * colorMultiplier.a;
if (openfl_HasColorTransform) {
openfl_ColorOffsetv = (openfl_ColorOffset / 255.0 * colorMultiplier) + (colorOffset / 255.0);
openfl_ColorMultiplierv = openfl_ColorMultiplier * vec4(colorMultiplier.rgb, 1.0);
}
else {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(colorMultiplier.rgb, 1.0);
}
}
else {
openfl_Alphav = openfl_Alpha * alpha;
if (openfl_HasColorTransform) {
openfl_ColorOffsetv = (openfl_ColorOffset + colorOffset) / 255.0;
openfl_ColorMultiplierv = openfl_ColorMultiplier;
}
else {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(1.0);
}
}";
public static final fragHeader:String = "varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
@@ -613,31 +393,19 @@ uniform sampler2D bitmap;
uniform bool hasTransform;
uniform bool hasColorTransform;
vec4 applyFlixelEffects(vec4 color) {
if(!hasTransform) {
return color;
}
vec4 apply_flixel_transform(vec4 color) {
if (!hasTransform) return color;
else if (color.a <= 0.0 || openfl_Alphav == 0.0) return vec4(0.0);
if(color.a == 0.0) {
return vec4(0.0, 0.0, 0.0, 0.0);
}
if(!hasColorTransform) {
return color * openfl_Alphav;
}
color.rgb = color.rgb / color.a;
color.rgb /= color.a;
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
if(color.a > 0.0) {
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
return vec4(0.0, 0.0, 0.0, 0.0);
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
#define applyFlixelEffects(color) apply_flixel_transform(color)
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
vec4 color = texture2D(bitmap, coord);
return applyFlixelEffects(color);
return apply_flixel_transform(texture2D(bitmap, coord));
}
uniform vec4 _camSize;
@@ -658,53 +426,17 @@ vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);";
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
if (gl_FragColor.a == 0.0) discard;";
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
attribute float alpha;
attribute vec4 colorMultiplier;
attribute vec4 colorOffset;
uniform bool hasColorTransform;";
public static final vertBody:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
}
openfl_Alphav = openfl_Alpha * alpha;
if(hasColorTransform) {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = colorMultiplier;
}
gl_Position = openfl_Matrix * openfl_Position;";
// TODO: make this ignore comments
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
@@ -719,7 +451,7 @@ uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;";
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
@@ -728,18 +460,7 @@ if(openfl_HasColorTransform) {
}
gl_Position = openfl_Matrix * openfl_Position;";
public static final defaultVertexSource:String = "#pragma header
void main(void) {
#pragma body
}";
public static final defaultFragmentSource:String = "#pragma header
void main(void) {
#pragma body
}";
#end
}
class ShaderTypeException extends Exception {
@@ -753,16 +474,4 @@ class ShaderTypeException extends Exception {
this.name = name;
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
}
}
class ShaderErrorPosition {
public var column:Int;
public var line:Int;
public var message:String;
public function new(line:String, column:String, message:String) {
this.line = Std.parseInt(line);
this.column = Std.parseInt(column);
this.message = message;
}
}
+13 -8
View File
@@ -11,6 +11,11 @@ import openfl.display.BlendMode;
import openfl.geom.ColorTransform;
import openfl.geom.Point;
import openfl.geom.Rectangle;
import openfl.display.TriangleCulling;
import openfl.display3D.Context3DWrapMode;
import openfl.display3D.Context3DCompareMode;
import openfl.filters.BitmapFilter;
import openfl.filters.ShaderFilter;
class FakeCamera extends FlxCamera {
public static final instance = new FakeCamera();
@@ -21,14 +26,14 @@ class FakeCamera extends FlxCamera {
visible = false;
}
override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader) { return null;}
override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) { return null;}
override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode, ?culling:TriangleCulling) { return null;}
override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) { return null;}
override function clearDrawStack() {}
override function render() {}
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {}
public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {}
public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData<Float>, indices:DrawData<Int>, uvtData:DrawData<Float>, ?colors:DrawData<Int>, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void {}
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {}
public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {}
public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData<Float>, indices:DrawData<Int>, uvtData:DrawData<Float>, ?colors:DrawData<Int>, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode, ?culling:TriangleCulling):Void {}
public override function update(elapsed:Float) {}
@@ -41,10 +46,10 @@ class FakeCallCamera extends FakeCamera {
public static final instance = new FakeCallCamera();
public var ignoreDraws:Bool = false;
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
}
override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
if (!ignoreDraws) onDraw(frame, pixels, matrix, transform, blend, smoothing, shader);
override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
if (!ignoreDraws) onDraw(frame, pixels, matrix, transform, blend, smoothing, shader, wrapMode, depthCompareMode);
}
}
+1 -1
View File
@@ -275,7 +275,7 @@ class Flags {
public static var DEFAULT_CHARACTER_GHOSTDISABLE_SOUND:String = "editors/character/ghostDisable";
public static var DEFAULT_CHARACTER_GHOSTENABLE_SOUND:String = "editors/character/ghostEnable";
public static var DEFAULT_GLSL_VERSION:String = "120";
public static var DEFAULT_GLSL_VERSION:String = openfl.display.Shader.getDefaultGLVersion();
@:also(funkin.backend.utils.HttpUtil.userAgent)
public static var USER_AGENT:String = 'request';
// -- End of Codename's Default Flags --
@@ -36,7 +36,7 @@ class GraphicCacheSprite extends FlxSprite {
if (graphic == null) return;
// make their useCount one time higher to prevent them from auto being cleared from cache
graphic.useCount++;
graphic.incrementUseCount();
graphic.destroyOnNoUse = false;
cachedGraphics.push(graphic);
nonRenderedCachedGraphics.push(graphic);
@@ -45,7 +45,7 @@ class GraphicCacheSprite extends FlxSprite {
public override function destroy() {
for(g in cachedGraphics) {
g.destroyOnNoUse = true;
g.useCount--;
g.decrementUseCount();
}
graphic = null;
super.destroy();
+1 -1
View File
@@ -115,7 +115,7 @@ final class Logs {
Sys.print(t.text);
}
NativeAPI.setConsoleColors();
Sys.print("\r\n");
Sys.println("\r");
__showing = false;
#elseif mobile
while(__showing) {
+2 -11
View File
@@ -58,9 +58,11 @@ class Main extends Sprite
// You can pretty much ignore everything from here on - your code should go in your states.
public static function preInit() {
#if sys
funkin.backend.utils.NativeAPI.registerAsDPICompatible();
funkin.backend.system.CommandLineHandler.parseCommandLine(Sys.args());
funkin.backend.system.Main.fixWorkingDirectory();
#end
}
public function new()
@@ -134,7 +136,6 @@ class Main extends Sprite
FlxG.scaleMode = scaleMode = new FunkinRatioScaleMode();
Conductor.init();
AudioSwitchFix.init();
EventManager.init();
FlxG.signals.focusGained.add(onFocus);
FlxG.signals.preStateSwitch.add(onStateSwitch);
@@ -206,16 +207,6 @@ class Main extends Sprite
// manual asset clearing since base openfl one does'nt clear lime one
// does'nt clear bitmaps since flixel fork does it auto
@:privateAccess {
// clear uint8 pools
for(length=>pool in openfl.display3D.utils.UInt8Buff._pools) {
for(b in pool.clear())
b.destroy();
}
openfl.display3D.utils.UInt8Buff._pools.clear();
}
MemoryUtil.clearMajor();
}
@@ -40,6 +40,7 @@ class MainState extends FlxState {
ControlsUtil.resetCustomControls();
FlxG.bitmap.reset();
FlxG.sound.destroy(true);
FlxG.sound.resetCache();
Paths.assetsTree.reset();
@@ -4,7 +4,9 @@ import lime.graphics.Image;
import lime.graphics.cairo.CairoImageSurface;
import openfl.display.BitmapData;
import openfl.geom.Rectangle;
import openfl.utils.BitmapDataUtil;
@:deprecated("Use openfl.utils.BitmapDataUtil.toHardware instead.")
class OptimizedBitmapData extends BitmapData {
@SuppressWarnings("checkstyle:Dynamic")
@:noCompletion private override function __fromImage(image:#if lime Image #else Dynamic #end):Void
@@ -29,34 +31,8 @@ class OptimizedBitmapData extends BitmapData {
__isValid = true;
readable = true;
if(FlxG.stage.context3D != null) {
lock();
getTexture(FlxG.stage.context3D);
getSurface();
readable = true;
this.image = null;
// @:privateAccess
// if (FlxG.bitmap.__doNotDelete)
// MemoryUtil.clearMinor();
}
BitmapDataUtil.toHardware(this);
}
#end
}
@SuppressWarnings("checkstyle:Dynamic")
@:dox(hide) public override function getSurface():#if lime CairoImageSurface #else Dynamic #end
{
#if lime
if (__surface == null)
{
__surface = CairoImageSurface.fromImage(image);
}
return __surface;
#else
return null;
#end
}
}
@@ -8,7 +8,12 @@ class RotatingSpriteGroup extends FlxSpriteGroup {
if (maxSize <= 0)
return super.recycle(ObjectClass, ObjectFactory, Force, Revive);
if (group.members.length < maxSize)
return group.recycleCreateObject(ObjectClass, ObjectFactory);
{
if (ObjectFactory != null) return add(ObjectFactory());
if (ObjectClass != null) return add(Type.createInstance(ObjectClass, []));
return null;
}
var spr = group.members.shift();
group.members.push(spr);
if (Revive)
@@ -58,6 +58,8 @@ class Macros {
final macroPath = 'funkin.backend.system.macros.Macros';
Compiler.addMetadata('@:build($macroPath.buildLimeAssetLibrary())', 'lime.utils.AssetLibrary');
Compiler.addMetadata('@:build($macroPath.buildLimeApplication())', 'lime.app.Application');
Compiler.addMetadata('@:build($macroPath.buildLimeWindow())', 'lime.ui.Window');
//Adds Compat for #if hscript blocks when you have hscript improved
if (Context.defined("hscript_improved") && !Context.defined("hscript")) {
@@ -72,5 +74,37 @@ class Macros {
return fields;
}
public static function buildLimeApplication():Array<Field> {
final fields:Array<Field> = Context.getBuildFields(), pos:Position = Context.currentPos();
for (f in fields) switch (f.kind) {
case FFun(func): switch (f.name) {
case "exec": switch (func.expr.expr) {
case EBlock(exprs): exprs.insert(1, macro funkin.backend.system.Main.preInit());
default:
}
}
default:
}
return fields;
}
public static function buildLimeWindow():Array<Field> {
final fields:Array<Field> = Context.getBuildFields(), pos:Position = Context.currentPos();
if (!Context.defined("DARK_MODE_WINDOW")) return fields;
for (f in fields) switch (f.kind) {
case FFun(func): switch (f.name) {
case "new": switch (func.expr.expr) {
case EBlock(exprs): exprs.push(macro funkin.backend.utils.NativeAPI.setDarkMode(title, true));
default:
}
}
default:
}
return fields;
}
}
#end
File diff suppressed because it is too large Load Diff
+1 -16
View File
@@ -13,12 +13,6 @@ import flixel.util.FlxColor;
* Some functions might not have effect on some platforms.
*/
class NativeAPI {
@:dox(hide) public static function registerAudio() {
#if windows
Windows.registerAudio();
#end
}
@:dox(hide) public static function registerAsDPICompatible() {
#if windows
Windows.registerAsDPICompatible();
@@ -185,16 +179,7 @@ class NativeAPI {
public static function setConsoleColors(foregroundColor:ConsoleColor = NONE, ?backgroundColor:ConsoleColor = NONE) {
if(Main.noTerminalColor) return;
#if (windows && !hl)
if(foregroundColor == NONE)
foregroundColor = LIGHTGRAY;
if(backgroundColor == NONE)
backgroundColor = BLACK;
var fg:Int = cast foregroundColor;
var bg:Int = cast backgroundColor;
Windows.setConsoleColors((bg * 16) + fg);
#elseif sys
#if sys
Sys.print("\x1b[0m");
if(foregroundColor != NONE)
Sys.print("\x1b[" + Std.int(consoleColorToANSI(foregroundColor)) + "m");
@@ -27,107 +27,10 @@ import funkin.backend.utils.NativeAPI.MessageBoxIcon;
#include <wingdi.h>
#include <shellapi.h>
#include <uxtheme.h>
#define SAFE_RELEASE(punk) \\
if ((punk) != NULL) \\
{ (punk)->Release(); (punk) = NULL; }
static long lastDefId = 0;
class AudioFixClient : public IMMNotificationClient {
LONG _cRef;
IMMDeviceEnumerator *_pEnumerator;
public:
AudioFixClient() :
_cRef(1),
_pEnumerator(NULL)
{
HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(void**)&_pEnumerator);
if (result == S_OK) {
_pEnumerator->RegisterEndpointNotificationCallback(this);
}
}
~AudioFixClient()
{
SAFE_RELEASE(_pEnumerator);
}
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef)
{
delete this;
}
return ulRef;
}
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid, VOID **ppvInterface)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId)
{
return S_OK;
};
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(
LPCWSTR pwstrDeviceId,
DWORD dwNewState)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(
LPCWSTR pwstrDeviceId,
const PROPERTYKEY key)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(
EDataFlow flow, ERole role,
LPCWSTR pwstrDeviceId)
{
::funkin::backend::_hx_system::Main_obj::audioDisconnected = true;
return S_OK;
};
};
AudioFixClient *curAudioFix;
')
@:dox(hide)
final class Windows {
public static var __audioChangeCallback:Void->Void = function() {
trace("test");
};
@:functionCode('
if (!curAudioFix) curAudioFix = new AudioFixClient();
')
public static function registerAudio() {
funkin.backend.system.Main.audioDisconnected = false;
}
@:functionCode('
int darkMode = enable ? 1 : 0;
+1 -1
View File
@@ -1082,7 +1082,7 @@ class PlayState extends MusicBeatState
if (notNull) PlayState.instance.gameAndCharsCall("onStageDestroy", [stage]);
scripts.call("destroy");
for (g in __cachedGraphics) g.useCount--;
for (g in __cachedGraphics) g.decrementUseCount();
@:privateAccess {
for (strumLine in strumLines.members) FlxG.sound.destroySound(strumLine.vocals);
if (FlxG.sound.music != inst) FlxG.sound.destroySound(inst);
+1
View File
@@ -228,6 +228,7 @@ class Options
applyKeybinds();
applyQuality();
flixel.sound.FlxSoundData.allowStreaming = streamedMusic;
FlxG.sound.defaultMusicGroup.volume = volumeMusic;
FlxG.autoPause = autoPause;
if (FlxG.updateFramerate < framerate) FlxG.drawFramerate = FlxG.updateFramerate = framerate;
+232 -47
View File
@@ -3,7 +3,6 @@ package openfl.utils;
#if !macro
import funkin.backend.system.Main;
import funkin.options.Options;
import funkin.backend.system.OptimizedBitmapData;
#end
import openfl.utils._internal.Log;
import openfl.display.BitmapData;
@@ -15,11 +14,11 @@ import openfl.media.Sound;
import openfl.text.Font;
#if lime
import lime.app.Promise;
import lime.media.AudioBuffer;
import lime.utils.AssetLibrary as LimeAssetLibrary;
import lime.utils.Assets as LimeAssets;
#end
#if lime_vorbis
import lime.media.AudioBuffer;
import lime.media.vorbis.VorbisFile;
#end
@@ -38,6 +37,11 @@ import lime.media.vorbis.VorbisFile;
preloader by extending the `NMEPreloader` class,
and specifying a custom preloader using <window preloader="" />
in the project file.
@see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html)
@see [Working with byte array assets](https://books.openfl.org/openfl-developers-guide/working-with-byte-arrays/working-with-byte-array-assets.html)
@see [Working with font assets](https://books.openfl.org/openfl-developers-guide/using-the-textfield-class/working-with-font-assets.html)
@see [Working with sound assets](https://books.openfl.org/openfl-developers-guide/working-with-sound/working-with-sound-assets.html)
**/
#if !openfl_debug
@:fileXml('tags="haxe,release"')
@@ -49,6 +53,8 @@ import lime.media.vorbis.VorbisFile;
@:access(openfl.utils.AssetLibrary)
class Assets
{
public static var allowCompressedTextures:Bool = false;
public static var cache:IAssetCache = new AssetCache();
@:noCompletion private static var dispatcher:EventDispatcher #if !macro = new EventDispatcher() #end;
@@ -75,11 +81,29 @@ class Assets
Returns whether a specific asset exists
@param id The ID or asset path for the asset
@param type The asset type to match, or null to match any type
@param allowCompressedTextures Whether to check for compressed texture formats (e.g., ASTC) when the asset is a PNG. Defaults to true.
@return Whether the requested asset ID and type exists
**/
public static function exists(id:String, type:AssetType = null):Bool
public static function exists(id:String, type:AssetType = null, allowCompressedTextures:Bool = true):Bool
{
#if lime
#if !flash
if (allowCompressedTextures)
{
if (id != null && haxe.io.Path.extension(id) == "png")
{
if (LimeAssets.exists(haxe.io.Path.withExtension(id, "astc"), BINARY))
{
return true;
}
}
else if (id != null && haxe.io.Path.extension(id) == "astc" && type != AssetType.BINARY)
{
type = AssetType.BINARY;
}
}
#end
return LimeAssets.exists(id, cast type);
#else
return false;
@@ -87,26 +111,74 @@ class Assets
}
/**
Gets an instance of an embedded bitmap
@usage var bitmap = new Bitmap (Assets.getBitmapData ("image.png"));
Gets an instance of an embedded bitmap.
```haxe
var bitmap = new Bitmap (Assets.getBitmapData ("image.png"));
```
_Note:_ This method may behave differently, depending on the target
platform. On targets that can quickly create new BitmapData instances
synchronously, every call to `Assets.getBitmapData()` with the same ID
will return a BitmapData instance with its own separate copy of the
underlying image data. However, on other targets where loading
BitmapData synchronously is unacceptably slow, or where BitmapData may
not be loaded synchronously at all (meaning that there is no choice but
to load it asynchronously), every call to `Assets.getBitmapData()` with
the same ID may return a BitmapData instance that shares the same
underlying image data each time.
With that in mind, modifying or disposing the contents of the BitmapData
returned by `Assets.getBitmapData()` may affect the results of future
calls to `Assets.getBitmapData()` on some targets. To access a
BitmapData instance that may be modified or disposed without affecting
future calls to `Assets.getBitmapData()`, call the BitmapData instance's
`clone()` method to manually create a copy.
@param id The ID or asset path for the bitmap
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@param pushToGPU Whenever the image should be immediately pushed to GPU.
@param allowCompressedTextures (Optional) Wether to allow compressed textures to be used to get this bitmap (Default: true)
@return A new BitmapData object
@see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html)
**/
public static function getBitmapData(id:String, useCache:Bool = true, pushToGPU:Bool = true):BitmapData
public static function getBitmapData(id:String, useCache:Bool = true, allowCompressedTextures:Bool = true):BitmapData
{
#if (lime && tools && !display)
if (useCache && cache.enabled && cache.hasBitmapData(id))
{
var bitmapData = cache.getBitmapData(id);
if (isValidBitmapData(bitmapData) && (pushToGPU || bitmapData.readable))
if (isValidBitmapData(bitmapData))
{
return bitmapData;
}
}
#if !flash
if ((allowCompressedTextures || haxe.io.Path.extension(id) == "astc") && openfl.Lib.current.stage.context3D.isASTCSupported())
{
final astcTexture:String = haxe.io.Path.withExtension(id, "astc");
if (LimeAssets.exists(astcTexture, BINARY))
{
var bitmapData = BitmapData.fromTexture(openfl.Lib.current.stage.context3D.createASTCTexture(LimeAssets.getBytes(astcTexture)), false);
if (useCache && cache.enabled)
{
cache.setBitmapData(id, bitmapData);
}
return bitmapData;
}
if (haxe.io.Path.extension(id) == "astc")
{
return null;
}
}
#end
var image = LimeAssets.getImage(id, false);
if (image != null)
@@ -114,13 +186,11 @@ class Assets
#if flash
var bitmapData = image.src;
#else
var bitmapData:BitmapData = null;
#if !macro if (pushToGPU && !Main.forceGPUOnlyBitmapsOff && Options.gpuOnlyBitmaps) {
bitmapData = new OptimizedBitmapData(0, 0, true, 0);
bitmapData.__fromImage(image);
} else #end {
bitmapData = BitmapData.fromImage(image);
}
var bitmapData = BitmapData.fromImage(image);
if (Assets.allowCompressedTextures && allowCompressedTextures && !Main.forceGPUOnlyBitmapsOff && Options.gpuOnlyBitmaps)
BitmapDataUtil.toHardware(bitmapData);
bitmapData.__asset = true;
#end
if (useCache && cache.enabled)
@@ -137,9 +207,15 @@ class Assets
/**
Gets an instance of an embedded binary asset
@usage var bytes = Assets.getBytes ("file.zip");
```haxe
var bytes = Assets.getBytes ("file.zip");
```
@param id The ID or asset path for the asset
@return A new ByteArray object
@see [Working with byte array assets](https://books.openfl.org/openfl-developers-guide/working-with-byte-arrays/working-with-byte-array-assets.html)
**/
public static function getBytes(id:String):ByteArray
{
@@ -152,10 +228,16 @@ class Assets
/**
Gets an instance of an embedded font
@usage var fontName = Assets.getFont ("font.ttf").fontName;
```haxe
var fontName = Assets.getFont ("font.ttf").fontName;
```
@param id The ID or asset path for the font
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return A new Font object
@see [Working with font assets](https://books.openfl.org/openfl-developers-guide/using-the-textfield-class/working-with-font-assets.html)
**/
public static function getFont(id:String, useCache:Bool = true):Font
{
@@ -199,7 +281,11 @@ class Assets
/**
Gets an instance of an included MovieClip
@usage var movieClip = Assets.getMovieClip ("library:BouncingBall");
```haxe
var movieClip = Assets.getMovieClip ("library:BouncingBall");
```
@param id The ID for the MovieClip
@return A new MovieClip object
**/
@@ -241,26 +327,31 @@ class Assets
return null;
}
public static function getMusic(id:String, useCache:Bool = true, staticFallback:Bool = true):Sound
public static function getMusic(id:String, useCache:Bool = true):Sound
{
if (useCache && staticFallback && cache.enabled && cache.hasSound(id)) {
var sound = cache.getSound(id);
if (isValidSound(sound)) return sound;
}
#if (lime_vorbis && lime > "7.9.0" && !macro)
if (Options.streamedMusic) {
#if (lime_funkin && lime_native)
var path = getPath(id);
var buffer = AudioBuffer.fromFile(path, true);
if (buffer != null) return Sound.fromAudioBuffer(buffer);
#elseif (lime_vorbis && lime > "7.9.0")
var path = getPath(id);
// TODO: What if it is a WAV or non-Vorbis file?
var vorbisFile = VorbisFile.fromFile(path);
if (vorbisFile != null) return Sound.fromAudioBuffer(AudioBuffer.fromVorbisFile(vorbisFile));
var buffer = AudioBuffer.fromVorbisFile(vorbisFile);
if (buffer != null) return Sound.fromAudioBuffer(buffer);
#end
}
#end
return if (staticFallback) getSound(id, useCache); else null;
return getSound(id, useCache);
}
/**
Gets the file path (if available) for an asset
@usage var path = Assets.getPath ("file.txt");
```haxe
var path = Assets.getPath ("file.txt");
```
@param id The ID or asset path for the asset
@return The path to the asset, or null if it does not exist
**/
@@ -275,10 +366,16 @@ class Assets
/**
Gets an instance of an embedded sound
@usage var sound = Assets.getSound ("sound.wav");
```haxe
var sound = Assets.getSound ("sound.wav");
```
@param id The ID or asset path for the sound
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return A new Sound object
@see [Working with sound assets](https://books.openfl.org/openfl-developers-guide/working-with-sound/working-with-sound-assets.html)
**/
public static function getSound(id:String, useCache:Bool = true):Sound
{
@@ -317,7 +414,11 @@ class Assets
/**
Gets an instance of an embedded text asset
@usage var text = Assets.getText ("text.txt");
```haxe
var text = Assets.getText ("text.txt");
```
@param id The ID or asset path for the asset
@return A new String object
**/
@@ -438,7 +539,8 @@ class Assets
return false;
}
#else
return (bitmapData != null && #if !lime_hybrid bitmapData.image != null #else bitmapData.__handle != null #end);
return (bitmapData != null
&& #if !lime_hybrid (bitmapData.image != null || bitmapData.__texture != null) #else bitmapData.__handle != null #end);
#end
#else
return true;
@@ -471,12 +573,18 @@ class Assets
/**
Loads an included bitmap asset asynchronously
@usage Assets.loadBitmapData ("image.png").onComplete (handleImage);
```haxe
Assets.loadBitmapData ("image.png").onComplete (handleImage);
```
@param id The ID or asset path for the asset
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return Returns a Future<BitmapData>
@see [Working with bitmap assets](https://books.openfl.org/openfl-developers-guide/working-with-bitmaps/working-with-bitmap-assets.html)
**/
public static function loadBitmapData(id:String, useCache:Null<Bool> = true):Future<BitmapData>
public static function loadBitmapData(id:String, useCache:Null<Bool> = true, allowCompressedTextures:Bool = true):Future<BitmapData>
{
if (useCache == null) useCache = true;
@@ -494,6 +602,47 @@ class Assets
}
}
#if !flash
if ((allowCompressedTextures || haxe.io.Path.extension(id) == "astc") && openfl.Lib.current.stage.context3D.isASTCSupported())
{
final astcTexture:String = haxe.io.Path.withExtension(id, "astc");
if (LimeAssets.exists(astcTexture, BINARY))
{
LimeAssets.loadBytes(astcTexture).onComplete(function(bytes)
{
if (bytes != null)
{
var bitmapData = BitmapData.fromTexture(openfl.Lib.current.stage.context3D.createASTCTexture(bytes), false);
if (Assets.allowCompressedTextures && allowCompressedTextures && !Main.forceGPUOnlyBitmapsOff && Options.gpuOnlyBitmaps)
BitmapDataUtil.toHardware(bitmapData);
bitmapData.__asset = true;
if (useCache && cache.enabled)
{
cache.setBitmapData(id, bitmapData);
}
promise.complete(bitmapData);
}
else
{
promise.error("[Assets] Could not load Image \"" + id + "\"");
}
}).onError(promise.error).onProgress(promise.progress);
return promise.future;
}
if (haxe.io.Path.extension(id) == "astc")
{
promise.error("[Assets] Could not load Image \"" + id + "\"");
return promise.future;
}
}
#end
LimeAssets.loadImage(id, false).onComplete(function(image)
{
if (image != null)
@@ -501,13 +650,11 @@ class Assets
#if flash
var bitmapData = image.src;
#else
var bitmapData:BitmapData = null;
#if !macro if (!Main.forceGPUOnlyBitmapsOff && Options.gpuOnlyBitmaps) {
bitmapData = new OptimizedBitmapData(0, 0, true, 0);
bitmapData.__fromImage(image);
} else #end {
bitmapData = BitmapData.fromImage(image);
}
var bitmapData = BitmapData.fromImage(image);
if (Assets.allowCompressedTextures && allowCompressedTextures && !Main.forceGPUOnlyBitmapsOff && Options.gpuOnlyBitmaps)
BitmapDataUtil.toHardware(bitmapData);
bitmapData.__asset = true;
#end
if (useCache && cache.enabled)
@@ -531,9 +678,15 @@ class Assets
/**
Loads an included byte asset asynchronously
@usage Assets.loadBytes ("file.zip").onComplete (handleBytes);
```haxe
Assets.loadBytes ("file.zip").onComplete (handleBytes);
```
@param id The ID or asset path for the asset
@return Returns a Future<ByteArray>
@see [Working with byte array assets](https://books.openfl.org/openfl-developers-guide/working-with-byte-arrays/working-with-byte-array-assets.html)
**/
public static function loadBytes(id:String):Future<ByteArray>
{
@@ -553,10 +706,16 @@ class Assets
/**
Loads an included font asset asynchronously
@usage Assets.loadFont ("font.ttf").onComplete (handleFont);
```haxe
Assets.loadFont ("font.ttf").onComplete (handleFont);
```
@param id The ID or asset path for the asset
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return Returns a Future<Font>
@see [Working with font assets](https://books.openfl.org/openfl-developers-guide/using-the-textfield-class/working-with-font-assets.html)
**/
public static function loadFont(id:String, useCache:Null<Bool> = true):Future<Font>
{
@@ -617,8 +776,16 @@ class Assets
}
else
{
// TODO: after Lime 8.2.0 is released, use conditional
// compilation to call LimeAssets.removeLibrary(name, false)
// since that is a new public API
@:privateAccess LimeAssets.libraries.remove(name);
_library = new AssetLibrary();
_library.__proxy = library;
// ERIC: Figure out what bug the change here was made to fix
// https://github.com/FunkinCrew/openfl/commit/7af97e4baff7371eba1f79959909ffca7971902e
// https://github.com/FunkinCrew/lime/commit/f195121ebec688b417e38ab115185c8d93c349d3
LimeAssets.registerLibrary(name, _library);
}
}
@@ -632,7 +799,11 @@ class Assets
/**
Loads an included music asset asynchronously
@usage Assets.loadMusic ("music.ogg").onComplete (handleMusic);
```haxe
Assets.loadMusic ("music.ogg").onComplete (handleMusic);
```
@param id The ID or asset path for the asset
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return Returns a Future<Sound>
@@ -682,7 +853,11 @@ class Assets
/**
Loads an included MovieClip asset asynchronously
@usage Assets.loadMovieClip ("library:BouncingBall").onComplete (handleMovieClip);
```haxe
Assets.loadMovieClip ("library:BouncingBall").onComplete (handleMovieClip);
```
@param id The ID for the asset
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return Returns a Future<MovieClip>
@@ -724,10 +899,16 @@ class Assets
/**
Loads an included sound asset asynchronously
@usage Assets.loadSound ("sound.wav").onComplete (handleSound);
```haxe
Assets.loadSound ("sound.wav").onComplete (handleSound);
```
@param id The ID or asset path for the asset
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return Returns a Future<Sound>
@see [Working with sound assets](https://books.openfl.org/openfl-developers-guide/working-with-sound/working-with-sound-assets.html)
**/
public static function loadSound(id:String, useCache:Null<Bool> = true):Future<Sound>
{
@@ -769,7 +950,11 @@ class Assets
/**
Loads an included text asset asynchronously
@usage Assets.loadText ("text.txt").onComplete (handleString);
```haxe
Assets.loadText ("text.txt").onComplete (handleString);
```
@param id The ID or asset path for the asset
@param useCache (Optional) Whether to allow use of the asset cache (Default: true)
@return Returns a Future<String>