diff --git a/commandline/commands/Update.hx b/commandline/commands/Update.hx
index c354aca8..d43c3620 100644
--- a/commandline/commands/Update.hx
+++ b/commandline/commands/Update.hx
@@ -64,8 +64,7 @@ class Update {
break;
} else if (curHaxeVer[i] > requiredHaxeVer[i]) {
prettyPrint("!! WARNING !!"
- + "\nHaxeFlixel has incompability issues with the latest version of Haxe, 4.3.0 and above, due to macros."
- + "\nProceeding will cause compilation issues related to macros (ex: cannot access flash package in macro)");
+ + "\nUsing Haxe 4.3.0 and above is currently not recommended due to lack of testing.");
Sys.println('');
Sys.println('We recommend downgrading back to 4.2.5.');
break;
@@ -75,14 +74,36 @@ class Update {
}
public static function prettyPrint(text:String) {
+ var lines = text.split("\n");
+ var length = -1;
+ for(line in lines)
+ if(line.length > length)
+ length = line.length;
var header = "══════";
- for(i in 0...(text.length-(text.lastIndexOf("\n")+1)))
+ for(i in 0...length)
header += "═";
Sys.println("");
Sys.println('╔$header╗');
- Sys.println('║ $text ║');
+ for(line in lines) {
+ Sys.println('║ ${centerText(line, length)} ║');
+ }
Sys.println('╚$header╝');
}
+
+
+ public static function centerText(text:String, width:Int):String {
+ var centerOffset = (width - text.length) / 2;
+ var left = repeat(' ', Math.floor(centerOffset));
+ var right = repeat(' ', Math.ceil(centerOffset));
+ return left + text + right;
+ }
+
+ public static inline function repeat(ch:String, amt:Int) {
+ var str = "";
+ for(i in 0...amt)
+ str += ch;
+ return str;
+ }
}
typedef Library = {
diff --git a/project.xml b/project.xml
index 42c962e6..5d17fa17 100644
--- a/project.xml
+++ b/project.xml
@@ -96,17 +96,9 @@
-
-
-
-
-
-
-
-
@@ -144,9 +136,6 @@
-
-
-
@@ -190,10 +179,10 @@
-
+
diff --git a/source/away3d/extrusions/PathExtrude.hx b/source/away3d/extrusions/PathExtrude.hx
new file mode 100644
index 00000000..2666c1ba
--- /dev/null
+++ b/source/away3d/extrusions/PathExtrude.hx
@@ -0,0 +1,1372 @@
+package away3d.extrusions;
+
+import away3d.bounds.BoundingVolumeBase;
+import away3d.core.base.Geometry;
+import away3d.core.base.SubGeometry;
+import away3d.core.base.SubMesh;
+import away3d.core.base.data.UV;
+import away3d.core.base.data.Vertex;
+import away3d.core.math.Vector3DUtils;
+import away3d.entities.Mesh;
+import away3d.extrusions.data.SubGeometryList;
+import away3d.materials.MaterialBase;
+import away3d.paths.IPath;
+import away3d.paths.IPathSegment;
+import away3d.tools.helpers.MeshHelper;
+
+import openfl.errors.Error;
+import openfl.geom.Matrix3D;
+import openfl.geom.Vector3D;
+import openfl.Vector;
+
+class PathExtrude extends Mesh
+{
+ public var upAxis(get, set):Vector3D;
+ public var centerMesh(get, set):Bool;
+ public var distributeU(get, set):Bool;
+ public var path(get, set):IPath;
+ public var profile(get, set):Vector;
+ public var scales(get, set):Vector;
+ public var rotations(get, set):Vector;
+ public var materials(get, set):Vector;
+ public var subdivision(get, set):Int;
+ public var coverAll(get, set):Bool;
+ public var distribute(get, set):Bool;
+ public var smoothSurface(get, set):Bool;
+ public var coverSegment(get, set):Bool;
+ public var mapFit(get, set):Bool;
+ public var flip(get, set):Bool;
+ public var closePath(get, set):Bool;
+ public var aligntoPath(get, never):Bool;
+ public var alignToPath(never, set):Bool;
+ public var smoothScale(get, set):Bool;
+ public var keepExtremes(get, set):Bool;
+ public var startProfile(get, never):Vector;
+ public var endProfile(get, never):Vector;
+
+ private var _varr:Vector;
+ private var _doubles:Vector = new Vector();
+ private var _upAxis:Vector3D = new Vector3D(0, 1, 0);
+ private var _trans:Matrix3D = new Matrix3D();
+
+ private static inline var LIMIT:Int = 196605;
+ private static inline var MAXRAD:Float = 1.2;
+ private var _path:IPath;
+ private var _profile:Vector;
+ private var _centerMesh:Bool;
+ private var _scales:Vector;
+ private var _rotations:Vector;
+ private var _materials:Vector;
+ private var _activeMaterial:MaterialBase;
+ private var _subdivision:Int;
+ private var _coverAll:Bool;
+ private var _coverSegment:Bool;
+ private var _flip:Bool;
+ private var _mapFit:Bool;
+ private var _closePath:Bool;
+ private var _alignToPath:Bool;
+ private var _smoothScale:Bool;
+ private var _smoothSurface:Bool;
+ private var _isClosedProfile:Bool;
+ private var _maxIndProfile:Int;
+ private var _matIndex:Int = 0;
+ private var _segv:Float;
+ private var _geomDirty:Bool = true;
+ private var _subGeometry:SubGeometry;
+ private var _MaterialsSubGeometries:Vector = new Vector();
+ private var _uva:UV;
+ private var _uvb:UV;
+ private var _uvc:UV;
+ private var _uvd:UV;
+ private var _uvs:Vector;
+ private var _vertices:Vector;
+ private var _indices:Vector;
+ private var _normals:Vector;
+ private var _normalTmp:Vector3D;
+ private var _normal0:Vector3D;
+ private var _normal1:Vector3D;
+ private var _normal2:Vector3D;
+ private var _keepExtremes:Bool;
+ private var _distribute:Bool;
+ private var _distributeU:Bool;
+ private var _distributedU:Vector;
+ private var _startPoints:Vector;
+ private var _endPoints:Vector;
+
+ /**
+ * Creates a new PathExtrude
+ *
+ * @param material [optional] MaterialBase. The PathExtrude (Mesh) material. Optional in constructor, material must be set before PathExtrude object is rendered. Required for the class to work.
+ * @param path [optional] Path. Defines the Path object representing path to extrude along. Required for the class to work.
+ * @param profile [optional] Vector.<Vector3D>. Defines an Vector.<Vector3D> of Vector3D objects representing the profile information to be projected along the Path object. Required for the class to work.
+ * @param subdivision [optional] uint. Howmany steps between each PathSegment. If the path holds curves, the higher this value, the higher the curve fidelity. Default and minimum is 2;
+ * @param coverall [optional] Boolean. Defines the uv mapping, when true a unique material is stretched along the entire path/shape. Default is true.
+ * @param coverSegment [optional] Boolean. Defines the uv mapping, when true and coverall is false a unique material is stretched along one PathSegment. Default is false.
+ * @param alignToPath [optional] Boolean. If the profile must follow the path or keep its original orientation.
+ * @param centerMesh [optional] Boolean. If the geometry needs to be recentered in its own object space. If the position after generation is set to 0,0,0, the object would be centered in worldspace. Default is false.
+ * @param mapFit [optional] Boolean. The UV mapping is percentually spreaded over the width of the path, making texture looking nicer and edits for applications such as a race track, road, more easy. Affects the uv's u values and set distributeU to false. Default is false.
+ * @param flip [optional] Boolean. If the faces must be reversed depending on Vector3D's orientation. Default is false.
+ * @param closePath [optional] Boolean. If the last PathSegment entered must be welded back to first one. Executed in a straight manner, its recommanded to pass the first entry to the Path again, as last entry if curves are involved.
+ * @param materials [optional] Vector.<MaterialBase>. An optional Vector.<MaterialBase> of different materials that can be alternated along the path if coverAll is false.
+ * @param scales [optional] An optional Vector.<Vector3D> of Vector3D objects that defines a series of scales to be set on each PathSegment.
+ * @param smoothScale [optional] Boolean. Defines if the scale must be interpolated between values or keep their full aspect on each PathSegment.
+ * @param rotations [optional] An optional Vector.<Vector3D> of Vector3D objects that defines a series of rotations to be set on each PathSegment.
+ * @param smoothSurface [optional] An optional Boolean. Defines if the surface of the mesh must be smoothed or not. Default is true.
+ * @param distribute [optional] Boolean. If the mesh subdivision is evenly spreaded over the entire mesh. Depending on path definition, segments are possibly not having the same amount of subdivision.
+ * @param distributeU [optional] Boolean. If the mesh uv' u value is procentually spreaded over the entire mesh surface. Prevents the source map to be stretched. Default is true.
+ * @param keepExtremes [optional] Boolean. If the the first and last profile coordinates must be kept accessible, in order to feed classes such as DelaunayMesh. Default is false;
+ */
+ public function new(material:MaterialBase = null, path:IPath = null, profile:Vector = null, subdivision:Int = 2, coverAll:Bool = true, coverSegment:Bool = false, alignToPath:Bool = true, centerMesh:Bool = false, mapFit:Bool = false, flip:Bool = false, closePath:Bool = false, materials:Vector = null, scales:Vector = null, smoothScale:Bool = true, rotations:Vector = null, smoothSurface:Bool = true, distribute:Bool = false, distributeU:Bool = true, keepExtremes:Bool = false)
+ {
+ var geom:Geometry = new Geometry();
+ _subGeometry = new SubGeometry();
+ super(geom, material);
+
+ _activeMaterial = this.material;
+ _path = path;
+ this.profile = profile;
+ this.subdivision = subdivision;
+ _coverSegment = coverSegment;
+ _coverAll = (_coverSegment)? false : coverAll;
+ _alignToPath = alignToPath;
+ _centerMesh = centerMesh;
+ _mapFit = mapFit;
+ _flip = flip;
+ _closePath = closePath;
+ _materials = (materials != null)? materials : new Vector();
+ _scales = scales;
+ _smoothScale = smoothScale;
+ _rotations = rotations;
+ _smoothSurface = smoothSurface;
+ _distributeU = distributeU;
+ _keepExtremes = keepExtremes;
+ }
+
+ private function get_upAxis():Vector3D
+ {
+ return _upAxis;
+ }
+
+ private function set_upAxis(value:Vector3D):Vector3D
+ {
+ _upAxis = value;
+ return value;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ override private function get_bounds():BoundingVolumeBase
+ {
+ if (_geomDirty)
+ buildExtrude();
+
+ return super.bounds;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ override private function get_geometry():Geometry
+ {
+ if (_geomDirty)
+ buildExtrude();
+
+ return super.geometry;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ override private function get_subMeshes():Vector
+ {
+ if (_geomDirty)
+ buildExtrude();
+
+ return super.subMeshes;
+ }
+
+ /**
+ * Defines whether the mesh is recentered of not after generation
+ */
+ private function get_centerMesh():Bool
+ {
+ return _centerMesh;
+ }
+
+ private function set_centerMesh(val:Bool):Bool
+ {
+ if (_centerMesh == val)
+ return val;
+
+ _centerMesh = val;
+
+ if (_centerMesh && this.geometry.subGeometries.length > 0)
+ MeshHelper.recenter(this);
+ else
+ invalidateGeometry();
+ return val;
+ }
+
+ /**
+ * Defines the uv's u values are spreaded procentually over the entire surface to prevent the maps to be stretched.
+ */
+ private function get_distributeU():Bool
+ {
+ return _distributeU;
+ }
+
+ private function set_distributeU(val:Bool):Bool
+ {
+ if (_distributeU == val)
+ return val;
+
+ _distributeU = val;
+
+ if (val && _mapFit)
+ _mapFit = false;
+ if (!val && _distributedU != null)
+ _distributedU = null;
+
+ invalidateGeometry();
+ return val;
+ }
+
+ /**
+ * Invalidates the geometry, causing it to be rebuillded when requested.
+ */
+ private function invalidateGeometry():Void
+ {
+ _geomDirty = true;
+ invalidateBounds();
+ }
+
+ /**
+ * Defines the Path object representing path to extrude along. Required.
+ */
+ private function get_path():IPath
+ {
+ return _path;
+ }
+
+ private function set_path(val:IPath):IPath
+ {
+ _path = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines a Vector.<Vector3D> of Vector3D objects representing the profile information to be projected along the Path object. Required.
+ */
+ private function get_profile():Vector
+ {
+ return _profile;
+ }
+
+ private function set_profile(val:Vector):Vector
+ {
+ _profile = val;
+
+ if (_profile != null)
+ _isClosedProfile = (_profile[0].x == _profile[_profile.length - 1].x && _profile[0].y == _profile[_profile.length - 1].y && _profile[0].z == _profile[_profile.length - 1].z);
+
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * An optional Vector.<Vector3D> of Vector3D objects that defines a series of scales to be set on each PathSegment.
+ */
+ private function get_scales():Vector
+ {
+ return _scales;
+ }
+
+ private function set_scales(val:Vector):Vector
+ {
+ _scales = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * An optional Vector.<Vector3D> of Vector3D objects that defines a series of rotations to be set on each PathSegment.
+ */
+ private function get_rotations():Vector
+ {
+ return _rotations;
+ }
+
+ private function set_rotations(val:Vector):Vector
+ {
+ _rotations = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * An optional Vector.<MaterialBase>. It defines a series of materials to be set on each PathSegment if coverAll is set to false.
+ */
+ private function get_materials():Vector
+ {
+ return _materials;
+ }
+
+ private function set_materials(val:Vector):Vector
+ {
+ if (val == null)
+ return val;
+ _materials = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines the subdivisions created in the mesh for each PathSegment. Defaults to 2, minimum 2.
+ */
+ private function get_subdivision():Int
+ {
+ return _subdivision;
+ }
+
+ private function set_subdivision(val:Int):Int
+ {
+ val = (val < 2)? 2 : val;
+
+ if (_subdivision == val)
+ return val;
+
+ _subdivision = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the texture(s) should be stretched to cover the entire mesh or per step between segments. Defaults to true.
+ */
+ private function get_coverAll():Bool
+ {
+ return _coverAll;
+ }
+
+ private function set_coverAll(val:Bool):Bool
+ {
+ if (_coverAll == val)
+ return val;
+
+ _coverAll = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the mesh subdivision is spread evenly over the entire geometry. Possibly resulting in uneven subdivision per segments.
+ * Uv mapping is less distorted on complex shapes once applied. Depending on Path length, extra construct time might be significant.
+ * Defaults to false.
+ */
+ private function get_distribute():Bool
+ {
+ return _distribute;
+ }
+
+ private function set_distribute(val:Bool):Bool
+ {
+ if (_distribute == val)
+ return val;
+
+ _distribute = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the surface of the mesh must be smoothed or not.
+ */
+ private function get_smoothSurface():Bool
+ {
+ return _smoothSurface;
+ }
+
+ private function set_smoothSurface(val:Bool):Bool
+ {
+ if (_smoothSurface == val)
+ return val;
+
+ _smoothSurface = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the texture(s) should applied per segment. Default false.
+ */
+ private function set_coverSegment(b:Bool):Bool
+ {
+ _coverSegment = b;
+ return b;
+ }
+
+ private function get_coverSegment():Bool
+ {
+ return _coverSegment;
+ }
+
+ /**
+ * Defines if the texture(s) should be projected on the geometry evenly spreaded over the source bitmapdata or using distance/percent. Default is false.
+ * The mapping considers first and last profile points are the most distant from each other. Most left and most right on the map.
+ * Note that it is NOT suitable for most cases. It is helpfull for roads definition, usually seen from above with simple profile. It prevents then distorts and eases map designs.
+ */
+ private function get_mapFit():Bool
+ {
+ return _mapFit;
+ }
+
+ private function set_mapFit(val:Bool):Bool
+ {
+ if (_mapFit == val)
+ return val;
+
+ if (val && _distributeU)
+ _distributeU = false;
+
+ _mapFit = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the generated faces should be inversed. Default false.
+ */
+ private function get_flip():Bool
+ {
+ return _flip;
+ }
+
+ private function set_flip(val:Bool):Bool
+ {
+ if (_flip == val)
+ return val;
+
+ _flip = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the last PathSegment should join the first one and close the loop. Defaults to false.
+ */
+ private function get_closePath():Bool
+ {
+ return _closePath;
+ }
+
+ private function set_closePath(val:Bool):Bool
+ {
+ if (_closePath == val)
+ return val;
+
+ _closePath = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the array of profile points should be orientated on path or not. Default true. Note that Path object's worldaxis property might need to be changed. default = 0,1,0.
+ *
+ * @see #profile
+ */
+ private function get_aligntoPath():Bool
+ {
+ return _alignToPath;
+ }
+
+ private function set_alignToPath(val:Bool):Bool
+ {
+ if (_alignToPath == val)
+ return val;
+
+ _alignToPath = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if a scaling of a PathSegment defined from the scales array of Vector3D objects should affect the whole PathSegment evenly or be smoothly interpolated from previous PathSegment scale. Defaults to true.
+ */
+ private function get_smoothScale():Bool
+ {
+ return _smoothScale;
+ }
+
+ private function set_smoothScale(val:Bool):Bool
+ {
+ if (_smoothScale == val)
+ return val;
+
+ _smoothScale = val;
+ _geomDirty = true;
+ return val;
+ }
+
+ /**
+ * Defines if the first and last transformed vector3d's of the profile are kept.
+ * For instance to be able to pass these coordinates to DelaunayMesh class, to close the extrude, if it was a tube.
+ * @see getStartProfile
+ * @see getEndProfile
+ */
+ private function get_keepExtremes():Bool
+ {
+ return _keepExtremes;
+ }
+
+ private function set_keepExtremes(b:Bool):Bool
+ {
+ _keepExtremes = b;
+ return b;
+ }
+
+ /**
+ * returns a vector of vector3d's representing the transformed profile coordinates at the start of the extrude shape
+ * null if "keepExtremes" is false or if the extrusion has not been builded yet.
+ */
+ private function get_startProfile():Vector
+ {
+ if (_path == null || _startPoints == null)
+ return null;
+
+ return _startPoints;
+ }
+
+ /**
+ * returns a vector of vector3d's representing the transformed profile coordinates at the end of the extrude shape
+ * null if "keepExtremes" is false or if the extrusion has not been builded yet.
+ */
+ private function get_endProfile():Vector
+ {
+ if (_path == null || _endPoints == null)
+ return null;
+
+ return _endPoints;
+ }
+
+ private function orientateAt(target:Vector3D, position:Vector3D):Void
+ {
+ var xAxis:Vector3D;
+ var yAxis:Vector3D;
+ var zAxis:Vector3D = target.subtract(position);
+
+ zAxis.normalize();
+
+ if (zAxis.length > 0.1) {
+ xAxis = _upAxis.crossProduct(zAxis);
+ xAxis.normalize();
+
+ yAxis = xAxis.crossProduct(zAxis);
+ yAxis.normalize();
+
+ var rawData:Vector = _trans.rawData;
+
+ rawData[0] = xAxis.x;
+ rawData[1] = xAxis.y;
+ rawData[2] = xAxis.z;
+
+ rawData[4] = -yAxis.x;
+ rawData[5] = -yAxis.y;
+ rawData[6] = -yAxis.z;
+
+ rawData[8] = zAxis.x;
+ rawData[9] = zAxis.y;
+ rawData[10] = zAxis.z;
+
+ _trans.rawData = rawData;
+ }
+ }
+
+ private function generate(points:Vector>, offsetV:Int = 0, closedata:Bool = false):Void
+ {
+ var uvlength:Int = (points.length - 1) + offsetV;
+ var offset:Int;
+
+ for (i in 0...points.length - 1) {
+ _varr = new Vector();
+ offset = (closedata)? i + uvlength : i;
+
+ extrudePoints(points[i], points[i + 1], (1/uvlength)*offset, uvlength, offset/(_subdivision - 1));
+
+ if (i == 0 && _isClosedProfile)
+ _doubles = _varr.concat();
+ }
+ _varr = _doubles = null;
+ }
+
+ private function extrudePoints(points1:Vector, points2:Vector, vscale:Float, indexv:Int, indexp:Float):Void
+ {
+ var i:Int;
+ var j:Int;
+
+ var stepx:Float;
+ var stepy:Float;
+ var stepz:Float;
+
+ var va:Vertex;
+ var vb:Vertex;
+ var vc:Vertex;
+ var vd:Vertex;
+
+ var u1:Float;
+ var u2:Float;
+ var index:Int = 0;
+
+ var v1:Float = 0;
+ var v2:Float = 0;
+
+ var countloop:Int = points1.length;
+
+ var mat:MaterialBase;
+
+ var dist:Float = 0;
+ var tdist:Float;
+ var bleft:Vector3D = null;
+ var bu:Float = 0;
+ var bincu:Float = 0;
+
+ if (_mapFit) {
+ for (i in 0...countloop) {
+ for (j in 0...countloop) {
+ if (i != j) {
+ tdist = Vector3D.distance(points1[i], points1[j]);
+ if (tdist > dist) {
+ dist = tdist;
+ bleft = points1[i];
+ }
+ }
+ }
+ }
+
+ } else {
+ bincu = 1/(countloop - 1);
+ }
+
+ function getDouble(x:Float, y:Float, z:Float):Vertex
+ {
+ for (i in 0..._doubles.length) {
+ if (_doubles[i].x == x && _doubles[i].y == y && _doubles[i].z == z) {
+ return _doubles[i];
+ }
+ }
+ return new Vertex(x, y, z);
+ }
+
+ for (i in 0...countloop) {
+ stepx = points2[i].x - points1[i].x;
+ stepy = points2[i].y - points1[i].y;
+ stepz = points2[i].z - points1[i].z;
+
+ for (j in 0...2) {
+ if (_isClosedProfile && _doubles.length > 0)
+ _varr.push(getDouble(points1[i].x + (stepx*j), points1[i].y + (stepy*j), points1[i].z + (stepz*j)));
+ else
+ _varr.push(new Vertex(points1[i].x + (stepx*j), points1[i].y + (stepy*j), points1[i].z + (stepz*j)));
+ }
+ }
+
+ var floored:Int = (_coverSegment) ? Std.int(indexp) : 0;
+
+ if (_materials != null && _materials.length > 0) {
+
+ if (_coverSegment && indexp - floored == 0)
+ _matIndex = (_matIndex + 1 > _materials.length - 1)? 0 : _matIndex + 1;
+ else if (!coverAll && !_coverSegment)
+ _matIndex = (_matIndex + 1 > _materials.length - 1)? 0 : _matIndex + 1;
+ }
+
+ mat = (_coverAll || _materials == null || _materials.length == 0)? this.material : _materials[_matIndex];
+
+ var covSub:Bool = _coverAll && _subdivision > 1;
+ var cosegSub:Bool = _coverSegment && _subdivision > 1;
+
+ for (i in 0...countloop) {
+
+ if (_distributeU) {
+ u1 = _distributedU[i];
+ u2 = _distributedU[i + 1];
+ } else if (_mapFit) {
+ u1 = 1 - Vector3D.distance(points1[i], bleft)/dist;
+ u2 = 1 - Vector3D.distance(points1[i + 1], bleft)/dist;
+ } else {
+ u1 = 1 - bu;
+ bu += bincu;
+ u2 = 1 - bu;
+ }
+
+ v1 = ((covSub)) ? vscale : (((cosegSub)) ? indexp - floored : 0);
+ v2 = ((covSub)) ? vscale + (1 / indexv) : (((cosegSub)) ? v1 + _segv : 1);
+
+ _uva.u = u1;
+ _uva.v = v1;
+ _uvb.u = u1;
+ _uvb.v = v2;
+ _uvc.u = u2;
+ _uvc.v = v2;
+ _uvd.u = u2;
+ _uvd.v = v1;
+
+ va = _varr[index];
+ vb = _varr[index + 1];
+ vc = _varr[index + 3];
+ vd = _varr[index + 2];
+
+ if (_flip) {
+ addFace(vb, va, vc, _uvb, _uva, _uvc, mat);
+ addFace(vc, va, vd, _uvc, _uva, _uvd, mat);
+
+ } else {
+ addFace(va, vb, vc, _uva, _uvb, _uvc, mat);
+ addFace(va, vc, vd, _uva, _uvc, _uvd, mat);
+ }
+
+ if (_mapFit)
+ u1 = u2;
+
+ index += 2;
+ }
+ }
+
+ private function initHolders():Void
+ {
+ if (_uva == null) {
+ _uva = new UV(0, 0);
+ _uvb = new UV(0, 0);
+ _uvc = new UV(0, 0);
+ _uvd = new UV(0, 0);
+ _normal0 = new Vector3D(0.0, 0.0, 0.0);
+ _normal1 = new Vector3D(0.0, 0.0, 0.0);
+ _normal2 = new Vector3D(0.0, 0.0, 0.0);
+ _normalTmp = new Vector3D(0.0, 0.0, 0.0);
+ }
+
+ if (_materials != null && _materials.length > 0) {
+ var sglist:SubGeometryList = new SubGeometryList();
+ _MaterialsSubGeometries.push(sglist);
+ sglist.subGeometry = new SubGeometry();
+ _subGeometry = sglist.subGeometry;
+
+ sglist.uvs = _uvs = new Vector();
+ sglist.vertices = _vertices = new Vector();
+ if (_smoothSurface)
+ sglist.normals = _normals = new Vector();
+ sglist.indices = _indices = new Vector();
+ sglist.material = this.material;
+ if (sglist.material.name == null)
+ sglist.material.name = "baseMaterial";
+
+ _matIndex = _materials.length;
+
+ } else {
+ _uvs = new Vector();
+ _vertices = new Vector();
+ _indices = new Vector();
+ if (_smoothSurface)
+ _normals = new Vector()
+ else
+ _subGeometry.autoDeriveVertexNormals = true;
+ _subGeometry.autoDeriveVertexTangents = true;
+ }
+ }
+
+ private function getSubGeometryListFromMaterial(mat:MaterialBase):SubGeometryList
+ {
+ var sglist:SubGeometryList = null;
+
+ for (i in 0..._MaterialsSubGeometries.length) {
+ if (_MaterialsSubGeometries[i].material == mat) {
+ sglist = _MaterialsSubGeometries[i];
+ break;
+ }
+ }
+
+ if (sglist == null) {
+ sglist = new SubGeometryList();
+ _MaterialsSubGeometries.push(sglist);
+ sglist.subGeometry = new SubGeometry();
+ sglist.uvs = new Vector();
+ sglist.vertices = new Vector();
+ sglist.indices = new Vector();
+ sglist.material = mat;
+ if (_smoothSurface)
+ sglist.normals = new Vector();
+ }
+
+ return sglist;
+ }
+
+ private function calcNormal(v0:Vertex, v1:Vertex, v2:Vertex):Void
+ {
+ var dx1:Float = v2.x - v0.x;
+ var dy1:Float = v2.y - v0.y;
+ var dz1:Float = v2.z - v0.z;
+ var dx2:Float = v1.x - v0.x;
+ var dy2:Float = v1.y - v0.y;
+ var dz2:Float = v1.z - v0.z;
+
+ var cx:Float = dz1 * dy2 - dy1 * dz2;
+ var cy:Float = dx1 * dz2 - dz1 * dx2;
+ var cz:Float = dy1 * dx2 - dx1 * dy2;
+ var d:Float = 1/Math.sqrt(cx * cx + cy * cy + cz * cz);
+
+ _normal0.x = _normal1.x = _normal2.x = cx*d;
+ _normal0.y = _normal1.y = _normal2.y = cy*d;
+ _normal0.z = _normal1.z = _normal2.z = cz*d;
+ }
+
+ private function addFace(v0:Vertex, v1:Vertex, v2:Vertex, uv0:UV, uv1:UV, uv2:UV, mat:MaterialBase):Void
+ {
+ var subGeom:SubGeometry;
+ var uvs:Vector;
+ var vertices:Vector;
+ var normals:Vector;
+ var indices:Vector;
+ var sglist:SubGeometryList;
+ var startMat:Bool = false;
+
+ if (_activeMaterial != mat && _materials != null && _materials.length > 0) {
+ _activeMaterial = mat;
+ sglist = getSubGeometryListFromMaterial(mat);
+ _subGeometry = subGeom = sglist.subGeometry;
+ _uvs = uvs = sglist.uvs;
+ _vertices = vertices = sglist.vertices;
+ _indices = indices = sglist.indices;
+ _normals = normals = sglist.normals;
+ startMat = true;
+
+ } else {
+ subGeom = _subGeometry;
+ uvs = _uvs;
+ vertices = _vertices;
+ indices = _indices;
+ normals = _normals;
+ }
+
+ if (vertices.length + 9 > LIMIT) {
+ subGeom.updateVertexData(vertices);
+ subGeom.updateIndexData(indices);
+ subGeom.updateUVData(uvs);
+ if (_smoothSurface)
+ subGeom.updateVertexNormalData(normals);
+
+ this.geometry.addSubGeometry(subGeom);
+ this.subMeshes[this.subMeshes.length - 1].material = mat;
+
+ subGeom = new SubGeometry();
+ subGeom.autoDeriveVertexTangents = true;
+ if (!_smoothSurface)
+ subGeom.autoDeriveVertexNormals = true;
+
+ if (_MaterialsSubGeometries != null && _MaterialsSubGeometries.length > 1) {
+
+ sglist = getSubGeometryListFromMaterial(mat);
+ sglist.subGeometry = _subGeometry = subGeom;
+ sglist.uvs = _uvs = uvs = new Vector();
+ sglist.vertices = _vertices = vertices = new Vector();
+ sglist.indices = _indices = indices = new Vector();
+ if (_smoothSurface)
+ sglist.normals = _normals = normals = new Vector();
+
+ } else {
+
+ _subGeometry = subGeom;
+ uvs = _uvs = new Vector();
+ vertices = _vertices = new Vector();
+ indices = _indices = new Vector();
+ normals = _normals = new Vector();
+ }
+ }
+
+ var bv0:Bool = false;
+ var bv1:Bool = false;
+ var bv2:Bool = false;
+
+ var ind0:Int = 0;
+ var ind1:Int = 0;
+ var ind2:Int = 0;
+
+ if (_smoothSurface && !startMat) {
+ var uvind:Int;
+ var uvindV:Int;
+ var vind:Int;
+ var vindy:Int;
+ var vindz:Int;
+ var ind:Int;
+ var indlength:Int = indices.length;
+ calcNormal(v0, v1, v2);
+ var ab:Float;
+
+ if (indlength > 0) {
+ var back:Float = indlength - _maxIndProfile;
+ var limitBack:Int = ((back < 0)) ? 0 : Std.int(back);
+
+ var i:Int = indlength - 1;
+ while (i > limitBack) {
+ ind = indices[i];
+ vind = ind*3;
+ vindy = vind + 1;
+ vindz = vind + 2;
+ uvind = ind*2;
+ uvindV = uvind + 1;
+
+ if (bv0 && bv1 && bv2)
+ break;
+
+ if (!bv0 && vertices[vind] == v0.x && vertices[vindy] == v0.y && vertices[vindz] == v0.z) {
+
+ _normalTmp.x = normals[vind];
+ _normalTmp.y = normals[vindy];
+ _normalTmp.z = normals[vindz];
+ ab = Vector3D.angleBetween(_normalTmp, _normal0);
+
+ if (ab < MAXRAD) {
+ _normal0.x = (_normalTmp.x + _normal0.x)*.5;
+ _normal0.y = (_normalTmp.y + _normal0.y)*.5;
+ _normal0.z = (_normalTmp.z + _normal0.z)*.5;
+
+ if (_coverAll || uvs[uvind] == uv0.u && uvs[uvindV] == uv0.v) {
+ bv0 = true;
+ ind0 = ind;
+ --i;
+ continue;
+ }
+ }
+ }
+
+ if (!bv1 && vertices[vind] == v1.x && vertices[vindy] == v1.y && vertices[vindz] == v1.z) {
+
+ _normalTmp.x = normals[vind];
+ _normalTmp.y = normals[vindy];
+ _normalTmp.z = normals[vindz];
+ ab = Vector3D.angleBetween(_normalTmp, _normal1);
+
+ if (ab < MAXRAD) {
+ _normal1.x = (_normalTmp.x + _normal1.x)*.5;
+ _normal1.y = (_normalTmp.y + _normal1.y)*.5;
+ _normal1.z = (_normalTmp.z + _normal1.z)*.5;
+
+ if (_coverAll || uvs[uvind] == uv1.u && uvs[uvindV] == uv1.v) {
+ bv1 = true;
+ ind1 = ind;
+ --i;
+ continue;
+ }
+ }
+ }
+
+ if (!bv2 && vertices[vind] == v2.x && vertices[vindy] == v2.y && vertices[vindz] == v2.z) {
+
+ _normalTmp.x = normals[vind];
+ _normalTmp.y = normals[vindy];
+ _normalTmp.z = normals[vindz];
+ ab = Vector3D.angleBetween(_normalTmp, _normal2);
+
+ if (ab < MAXRAD) {
+ _normal2.x = (_normalTmp.x + _normal2.x)*.5;
+ _normal2.y = (_normalTmp.y + _normal2.y)*.5;
+ _normal2.z = (_normalTmp.z + _normal2.z)*.5;
+
+ if (_coverAll || uvs[uvind] == uv2.u && uvs[uvindV] == uv2.v) {
+ bv2 = true;
+ ind2 = ind;
+ --i;
+ continue;
+ }
+ }
+
+ }
+ --i;
+ }
+ }
+ }
+
+ if (!bv0) {
+ ind0 = Std.int(vertices.length / 3);
+ vertices.push(v0.x);
+ vertices.push(v0.y);
+ vertices.push(v0.z);
+ uvs.push(uv0.u);
+ uvs.push(uv0.v);
+ if (_smoothSurface) {
+ normals.push(_normal0.x);
+ normals.push(_normal0.y);
+ normals.push(_normal0.z);
+ }
+ }
+
+ if (!bv1) {
+ ind1 = Std.int(vertices.length / 3);
+ vertices.push(v1.x);
+ vertices.push(v1.y);
+ vertices.push(v1.z);
+ uvs.push(uv1.u);
+ uvs.push(uv1.v);
+ if (_smoothSurface) {
+ normals.push(_normal1.x);
+ normals.push(_normal1.y);
+ normals.push(_normal1.z);
+ }
+ }
+
+ if (!bv2) {
+ ind2 = Std.int(vertices.length / 3);
+ vertices.push(v2.x);
+ vertices.push(v2.y);
+ vertices.push(v2.z);
+ uvs.push(uv2.u);
+ uvs.push(uv2.v);
+ if (_smoothSurface) {
+ normals.push(_normal2.x);
+ normals.push(_normal2.y);
+ normals.push(_normal2.z);
+ }
+ }
+
+ indices.push(ind0);
+ indices.push(ind1);
+ indices.push(ind2);
+ }
+
+ private function distributeVectors():Vector>
+ {
+ var segs:Vector> = _path.getPointsOnCurvePerSegment(_subdivision);
+ var nSegs:Vector> = new Vector>();
+
+ var seg:Vector;
+ var j:Int = 0;
+ var estLength:Float = 0;
+ var vCount:Int = 0;
+
+ var v:Vector3D;
+ var tmpV:Vector3D = new Vector3D();
+ var prevV:Vector3D = null;
+
+ for (i in 0...segs.length) {
+ seg = segs[i];
+ for (j in 0..._subdivision) {
+ if (prevV != null)
+ estLength += Vector3D.distance(prevV, seg[j]);
+ prevV = seg[j];
+ vCount++;
+ }
+ }
+ var step:Float = estLength/vCount;
+ var tPrecision:Float = 0.001;
+ var t:Float = 0;
+ var ps:IPathSegment;
+
+ var tmpVDist:Float = 0;
+ var diff:Float = 0;
+ var ignore:Bool;
+
+ for (i in 0...segs.length) {
+ ps = _path.getSegmentAt(i);
+ ignore = false;
+ t = diff;
+ seg = new Vector();
+
+ while (t < 1) {
+
+ if (segs.length == 0) {
+ v = segs[i][0];
+ seg.push(v);
+ prevV = v;
+ continue;
+ }
+
+ tmpVDist = 0;
+ while (tmpVDist < step) {
+ t += tPrecision;
+ if (t > 1 && i < segs.length - 1) {
+ ignore = true;
+ break;
+ } else {
+ tmpV = ps.getPointOnSegment(t, tmpV);
+ tmpVDist = Vector3D.distance(prevV, tmpV);
+ }
+ }
+
+ diff = 1 - t;
+ if (!ignore) {
+ v = new Vector3D(tmpV.x, tmpV.y, tmpV.z);
+ prevV = v;
+ seg.push(v);
+ }
+ }
+
+ nSegs.push(seg);
+ }
+
+ segs = null;
+
+ return nSegs;
+ }
+
+ private function generateUlist():Void
+ {
+ _distributedU = Vector.ofArray(cast [0]);
+ var tdist:Float = 0;
+ var dist:Float = 0;
+ var tmpDists:Vector = new Vector();
+ for (i in 0..._profile.length - 1) {
+ tmpDists[i] = Vector3D.distance(_profile[i], _profile[i + 1]);
+ tdist += tmpDists[i];
+ }
+ for (i in 1..._profile.length) {
+ _distributedU[i] = (tmpDists[i - 1] + dist)/tdist;
+ dist += tmpDists[i - 1];
+ }
+
+ tmpDists = null;
+ }
+
+ private function buildExtrude():Void
+ {
+ if (_path == null || _path.numSegments == 0 || _profile == null || _profile.length < 2)
+ throw new Error("PathExtrude error: invalid Path or profile with unsufficient data");
+
+ _geomDirty = false;
+ initHolders();
+
+ _maxIndProfile = _profile.length*9;
+
+ var vSegPts:Vector> = null;
+
+ if (_distribute)
+ vSegPts = distributeVectors();
+ else
+ vSegPts = _path.getPointsOnCurvePerSegment(_subdivision);
+
+ if (_distributeU)
+ generateUlist();
+
+ var vPtsList:Vector = new Vector();
+ var vSegResults:Vector> = new Vector>();
+ var atmp:Vector = null;
+ var tmppt:Vector3D = new Vector3D(0, 0, 0);
+
+ var i:Int = 0;
+ var j:Int = 0;
+ var k:Int = 0;
+
+ var nextpt:Vector3D = null;
+ if (_coverSegment)
+ _segv = 1 / (_subdivision - 1);
+
+ var lastP:Vector = null;
+ if (_closePath)
+ lastP = new Vector();
+
+ var rescale:Bool = (_scales != null);
+ var lastscale:Vector3D = null;
+ if (rescale)
+ lastscale = ((_scales[0] == null)) ? new Vector3D(1, 1, 1) : _scales[0];
+
+ var rotate:Bool = (_rotations != null);
+
+ var lastrotate:Vector3D = null;
+ var nextrotate:Vector3D = null;
+ var rotation:Vector = null ;
+ var tweenrot:Vector3D = null;
+ var nextscale:Vector3D = null;
+ var vScales:Vector = null;
+
+ if (rotate && _rotations.length > 0) {
+ lastrotate = _rotations[0];
+ rotation = new Vector();
+ }
+
+ if (_smoothScale && rescale) {
+ nextscale = new Vector3D(1, 1, 1);
+ vScales = Vector.ofArray(cast [lastscale]);
+ if (_scales.length != _path.numSegments + 2) {
+ var lastScl:Vector3D = _scales[_scales.length - 1];
+ while (_scales.length != _path.numSegments + 2)
+ _scales.push(lastScl);
+ }
+ }
+
+ var tmploop:Int = _profile.length;
+ for (i in 0...vSegPts.length) {
+ if (rotate) {
+ lastrotate = ((_rotations[i] == null)) ? lastrotate : _rotations[i];
+ nextrotate = ((_rotations[i + 1] == null)) ? lastrotate : _rotations[i + 1];
+ rotation = Vector.ofArray(cast [lastrotate]);
+ rotation = rotation.concat(Vector3DUtils.subdivide(lastrotate, nextrotate, _subdivision));
+ }
+
+ if (rescale)
+ lastscale = ((_scales[i] == null)) ? lastscale : _scales[i];
+
+ if (_smoothScale && rescale) {
+ nextscale = ((_scales[i + 1] == null)) ? ((_scales[i] == null)) ? lastscale : _scales[i] : _scales[i + 1];
+ vScales = vScales.concat(Vector3DUtils.subdivide(lastscale, nextscale, _subdivision));
+ }
+
+ for (j in 0...vSegPts[i].length) {
+
+ atmp = new Vector();
+ atmp = atmp.concat(_profile);
+ vPtsList = new Vector();
+
+ if (rotate)
+ tweenrot = rotation[j];
+
+ if (_alignToPath) {
+ _trans = new Matrix3D();
+ if (i == vSegPts.length - 1 && j == vSegPts[i].length - 1) {
+
+ if (_closePath) {
+ nextpt = vSegPts[0][0];
+ orientateAt(nextpt, vSegPts[i][j]);
+ } else {
+ nextpt = vSegPts[i][j - 1];
+ orientateAt(vSegPts[i][j], nextpt);
+ }
+
+ } else {
+ nextpt = ((j < vSegPts[i].length - 1)) ? vSegPts[i][j + 1] : vSegPts[i + 1][0];
+ orientateAt(nextpt, vSegPts[i][j]);
+ }
+
+ }
+
+ for (k in 0...tmploop) {
+
+ if (rescale && !_smoothScale) {
+ atmp[k].x *= lastscale.x;
+ atmp[k].y *= lastscale.y;
+ atmp[k].z *= lastscale.z;
+ }
+
+ if (_alignToPath) {
+ tmppt = new Vector3D();
+
+ tmppt.x = atmp[k].x * _trans.rawData[0] + atmp[k].y * _trans.rawData[4] + atmp[k].z * _trans.rawData[8] + _trans.rawData[12];
+ tmppt.y = atmp[k].x * _trans.rawData[1] + atmp[k].y * _trans.rawData[5] + atmp[k].z * _trans.rawData[9] + _trans.rawData[13];
+ tmppt.z = atmp[k].x * _trans.rawData[2] + atmp[k].y * _trans.rawData[6] + atmp[k].z * _trans.rawData[10] + _trans.rawData[14];
+
+ if (rotate)
+ tmppt = Vector3DUtils.rotatePoint(tmppt, tweenrot);
+
+ tmppt.x += vSegPts[i][j].x;
+ tmppt.y += vSegPts[i][j].y;
+ tmppt.z += vSegPts[i][j].z;
+
+ } else
+ tmppt = new Vector3D(atmp[k].x + vSegPts[i][j].x, atmp[k].y + vSegPts[i][j].y, atmp[k].z + vSegPts[i][j].z);
+
+ vPtsList.push(tmppt);
+ }
+
+ if (_closePath && i == vSegPts.length - 1 && j == vSegPts[i].length - 1)
+ break;
+
+ if (_closePath)
+ lastP = vPtsList;
+
+ vSegResults.push(vPtsList);
+
+ }
+ }
+
+ if (rescale && _smoothScale) {
+ for (i in 0...vScales.length) {
+ for (j in 0...vSegResults[i].length) {
+ vSegResults[i][j].x *= vScales[i].x;
+ vSegResults[i][j].y *= vScales[i].y;
+ vSegResults[i][j].z *= vScales[i].z;
+ }
+ }
+ vScales = null;
+ }
+
+ if (rotate)
+ rotation = null;
+
+ if (_closePath) {
+ var stepx:Float;
+ var stepy:Float;
+ var stepz:Float;
+ var c:Vector;
+ var c2:Vector> = new Vector>();
+
+ for (i in 1..._subdivision + 1) {
+ c = new Vector();
+ for (j in 0...lastP.length) {
+ stepx = (vSegResults[0][j].x - lastP[j].x) / _subdivision;
+ stepy = (vSegResults[0][j].y - lastP[j].y) / _subdivision;
+ stepz = (vSegResults[0][j].z - lastP[j].z) / _subdivision;
+ c.push(new Vector3D(lastP[j].x + (stepx * i), lastP[j].y + (stepy * i), lastP[j].z + (stepz * i)));
+ }
+ c2.push(c);
+ }
+
+ c2[0] = lastP;
+ generate(c2, (_coverAll)? vSegResults.length : 0, _coverAll);
+ c = null;
+ c2 = null;
+ }
+
+ if (_keepExtremes) {
+ _startPoints = new Vector();
+ _endPoints = new Vector();
+ var offsetEnd:Int = vSegResults.length - 1;
+
+ for (i in 0...tmploop) {
+ _startPoints[i] = vSegResults[0][i];
+ _endPoints[i] = vSegResults[offsetEnd][i];
+ }
+
+ } else if (_startPoints != null) {
+
+ for (i in 0...tmploop)
+ _startPoints[i] = _endPoints[i] = null;
+ _startPoints = _endPoints = null;
+ }
+
+ generate(vSegResults, (_closePath && _coverAll)? 1 : 0, (_closePath && !_coverAll));
+
+ vSegPts = null;
+ _varr = null;
+
+ if (_MaterialsSubGeometries != null && _MaterialsSubGeometries.length > 0) {
+ var sglist:SubGeometryList;
+ var sg:SubGeometry;
+ for (i in 0..._MaterialsSubGeometries.length) {
+ sglist = _MaterialsSubGeometries[i];
+ sg = sglist.subGeometry;
+ if (sg != null && sglist.vertices.length > 0) {
+ this.geometry.addSubGeometry(sg);
+ this.subMeshes[this.subMeshes.length - 1].material = sglist.material;
+ sg.updateVertexData(sglist.vertices);
+ sg.updateIndexData(sglist.indices);
+ sg.updateUVData(sglist.uvs);
+
+ if (_smoothSurface)
+ sg.updateVertexNormalData(sglist.normals);
+ }
+ }
+
+ } else {
+
+ _subGeometry.updateVertexData(_vertices);
+ _subGeometry.updateIndexData(_indices);
+ _subGeometry.updateUVData(_uvs);
+
+ if (_smoothSurface)
+ _subGeometry.updateVertexNormalData(_normals);
+
+ this.geometry.addSubGeometry(_subGeometry);
+ }
+
+ if (_centerMesh)
+ MeshHelper.recenter(this);
+ }
+}
\ No newline at end of file
diff --git a/source/away3d/materials/methods/LightMapMethod.hx b/source/away3d/materials/methods/LightMapMethod.hx
new file mode 100644
index 00000000..4ac81fb6
--- /dev/null
+++ b/source/away3d/materials/methods/LightMapMethod.hx
@@ -0,0 +1,127 @@
+package away3d.materials.methods;
+
+import away3d.core.managers.Stage3DProxy;
+import away3d.materials.compilation.ShaderRegisterCache;
+import away3d.materials.compilation.ShaderRegisterElement;
+import away3d.textures.Texture2DBase;
+
+import openfl.display.BlendMode;
+import openfl.errors.Error;
+
+/**
+ * LightMapMethod provides a method that allows applying a light map texture to the calculated pixel colour.
+ * It is different from LightMapDiffuseMethod in that the latter only modulates the diffuse shading value rather
+ * than the whole pixel colour.
+ */
+class LightMapMethod extends EffectMethodBase
+{
+ public var blendMode(get, set):BlendMode;
+ public var texture(get, set):Texture2DBase;
+
+ /**
+ * Indicates the light map should be multiplied with the calculated shading result.
+ */
+ public static inline var MULTIPLY:BlendMode = BlendMode.MULTIPLY;
+
+ /**
+ * Indicates the light map should be added into the calculated shading result.
+ */
+ public static var ADD:BlendMode = BlendMode.ADD;
+
+ private var _texture:Texture2DBase;
+
+ private var _blendMode:BlendMode;
+ private var _useSecondaryUV:Bool;
+
+ /**
+ * Creates a new LightMapMethod object.
+ * @param texture The texture containing the light map.
+ * @param blendMode The blend mode with which the light map should be applied to the lighting result.
+ * @param useSecondaryUV Indicates whether the secondary UV set should be used to map the light map.
+ */
+ public function new(texture:Texture2DBase, blendMode:BlendMode = MULTIPLY, useSecondaryUV:Bool = false)
+ {
+ super();
+ _useSecondaryUV = useSecondaryUV;
+ _texture = texture;
+ this.blendMode = blendMode;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ override private function initVO(vo:MethodVO):Void
+ {
+ vo.needsUV = !_useSecondaryUV;
+ vo.needsSecondaryUV = _useSecondaryUV;
+ }
+
+ /**
+ * The blend mode with which the light map should be applied to the lighting result.
+ *
+ * @see LightMapMethod.ADD
+ * @see LightMapMethod.MULTIPLY
+ */
+ private function get_blendMode():BlendMode
+ {
+ return _blendMode;
+ }
+
+ private function set_blendMode(value:BlendMode):BlendMode
+ {
+ if (value != ADD && value != MULTIPLY)
+ throw new Error("Unknown blendmode!");
+ if (_blendMode == value)
+ return value;
+ _blendMode = value;
+ invalidateShaderProgram();
+ return value;
+ }
+
+ /**
+ * The texture containing the light map.
+ */
+ private function get_texture():Texture2DBase
+ {
+ return _texture;
+ }
+
+ private function set_texture(value:Texture2DBase):Texture2DBase
+ {
+ if (value.hasMipMaps != _texture.hasMipMaps || value.format != _texture.format)
+ invalidateShaderProgram();
+ _texture = value;
+ return value;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ override private function activate(vo:MethodVO, stage3DProxy:Stage3DProxy):Void
+ {
+ stage3DProxy._context3D.setTextureAt(vo.texturesIndex, _texture.getTextureForStage3D(stage3DProxy));
+ super.activate(vo, stage3DProxy);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ override private function getFragmentCode(vo:MethodVO, regCache:ShaderRegisterCache, targetReg:ShaderRegisterElement):String
+ {
+ var code:String;
+ var lightMapReg:ShaderRegisterElement = regCache.getFreeTextureReg();
+ var temp:ShaderRegisterElement = regCache.getFreeFragmentVectorTemp();
+ vo.texturesIndex = lightMapReg.index;
+
+ code = getTex2DSampleCode(vo, temp, lightMapReg, _texture, _useSecondaryUV? _sharedRegisters.secondaryUVVarying : _sharedRegisters.uvVarying);
+
+ switch (_blendMode) {
+ case BlendMode.MULTIPLY:
+ code += "mul " + targetReg + ", " + targetReg + ", " + temp + "\n";
+ case BlendMode.ADD:
+ code += "add " + targetReg + ", " + targetReg + ", " + temp + "\n";
+ default:
+ }
+ return code;
+ }
+}
\ No newline at end of file
diff --git a/source/funkin/backend/FunkinSprite.hx b/source/funkin/backend/FunkinSprite.hx
index 53e87114..ec8183ce 100644
--- a/source/funkin/backend/FunkinSprite.hx
+++ b/source/funkin/backend/FunkinSprite.hx
@@ -13,8 +13,7 @@ import flixel.math.FlxRect;
import flixel.math.FlxPoint;
import funkin.backend.system.interfaces.IBeatReceiver;
-@:enum
-abstract XMLAnimType(Int)
+enum abstract XMLAnimType(Int)
{
var NONE = 0;
var BEAT = 1;
diff --git a/source/funkin/backend/MusicBeatState.hx b/source/funkin/backend/MusicBeatState.hx
index c89728a9..35b684e5 100644
--- a/source/funkin/backend/MusicBeatState.hx
+++ b/source/funkin/backend/MusicBeatState.hx
@@ -1,6 +1,5 @@
package funkin.backend;
-import flixel.addons.transition.FlxTransitionableState;
import funkin.backend.system.framerate.Framerate;
import funkin.backend.system.GraphicCacheSprite;
import funkin.backend.system.Controls;
diff --git a/source/funkin/backend/MusicBeatSubstate.hx b/source/funkin/backend/MusicBeatSubstate.hx
index d8940afc..e2bbb312 100644
--- a/source/funkin/backend/MusicBeatSubstate.hx
+++ b/source/funkin/backend/MusicBeatSubstate.hx
@@ -6,7 +6,6 @@ import funkin.backend.scripting.Script;
import funkin.backend.scripting.ScriptPack;
import funkin.backend.scripting.DummyScript;
import funkin.backend.system.interfaces.IBeatReceiver;
-import funkin.backend.system.Conductor.BPMChangeEvent;
import funkin.backend.system.Conductor;
import funkin.backend.system.Controls;
import funkin.options.PlayerSettings;
diff --git a/source/funkin/backend/assets/ModdableAssetsFolder.hx b/source/funkin/backend/assets/ModdableAssetsFolder.hx
index 0da7ed5f..c9ca2e16 100644
--- a/source/funkin/backend/assets/ModdableAssetsFolder.hx
+++ b/source/funkin/backend/assets/ModdableAssetsFolder.hx
@@ -15,7 +15,7 @@ class ModdableAssetsFolder extends ModsFolderLibrary {
return super.exists(id, type);
}
- public override function getAsset(id:String, type:String) {
+ public override function getAsset(id:String, type:String):Dynamic {
if (!id.startsWith("assets/")) {
var possibleReplacement = getAsset('assets/$id', type);
if (possibleReplacement != null)
diff --git a/source/funkin/backend/scripting/HScript.hx b/source/funkin/backend/scripting/HScript.hx
index be108c5f..37aaaa95 100644
--- a/source/funkin/backend/scripting/HScript.hx
+++ b/source/funkin/backend/scripting/HScript.hx
@@ -45,7 +45,9 @@ class HScript extends Script {
this.trace(v);
}));
+ #if GLOBAL_SCRIPT
funkin.backend.scripting.GlobalScript.call("onScriptCreated", [this, "hscript"]);
+ #end
loadFromString(code);
}
diff --git a/source/funkin/backend/scripting/events/PlayAnimEvent.hx b/source/funkin/backend/scripting/events/PlayAnimEvent.hx
index 7d5499ba..ca88c408 100644
--- a/source/funkin/backend/scripting/events/PlayAnimEvent.hx
+++ b/source/funkin/backend/scripting/events/PlayAnimEvent.hx
@@ -30,8 +30,7 @@ final class PlayAnimEvent extends CancellableEvent {
/**
Contains all contexts possible for `PlayAnimEvent`.
**/
-@:enum
-abstract PlayAnimContext(String) {
+enum abstract PlayAnimContext(String) {
/**
No context was given for the animation.
The character won't dance until the animation is finished
diff --git a/source/funkin/backend/system/Conductor.hx b/source/funkin/backend/system/Conductor.hx
index 696db005..8db60b36 100644
--- a/source/funkin/backend/system/Conductor.hx
+++ b/source/funkin/backend/system/Conductor.hx
@@ -1,17 +1,10 @@
package funkin.backend.system;
-import funkin.backend.chart.Chart;
import funkin.backend.chart.ChartData;
-import openfl.Lib;
import flixel.FlxState;
import funkin.backend.system.interfaces.IBeatReceiver;
import flixel.util.FlxSignal.FlxTypedSignal;
-/**
- * ...
- * @author
- */
-
typedef BPMChangeEvent =
{
var stepTime:Float;
diff --git a/source/funkin/backend/system/ErrorCode.hx b/source/funkin/backend/system/ErrorCode.hx
index 9959df82..c1121c0e 100644
--- a/source/funkin/backend/system/ErrorCode.hx
+++ b/source/funkin/backend/system/ErrorCode.hx
@@ -1,7 +1,6 @@
package funkin.backend.system;
-@:enum
-abstract ErrorCode(Int) {
+enum abstract ErrorCode(Int) {
var OK = 0;
var FAILED = 1;
var MISSING_PROPERTY = 2;
diff --git a/source/funkin/backend/system/Main.hx b/source/funkin/backend/system/Main.hx
index d715103e..87bd26d8 100644
--- a/source/funkin/backend/system/Main.hx
+++ b/source/funkin/backend/system/Main.hx
@@ -4,26 +4,17 @@ import funkin.editors.SaveWarning;
import funkin.backend.assets.AssetsLibraryList;
import funkin.backend.system.framerate.SystemInfo;
import openfl.utils.AssetLibrary;
-import openfl.utils.AssetCache;
import openfl.text.TextFormat;
import flixel.system.ui.FlxSoundTray;
-import funkin.backend.utils.NativeAPI;
-import funkin.menus.BetaWarningState;
-import funkin.menus.TitleState;
-import flixel.FlxGame;
-import flixel.FlxState;
import openfl.Assets;
import openfl.Lib;
-import openfl.display.FPS;
import openfl.display.Sprite;
-import openfl.events.Event;
import flixel.graphics.FlxGraphic;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
import flixel.addons.transition.TransitionData;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
-import lime.app.Application;
import funkin.backend.system.modules.*;
#if ALLOW_MULTITHREADING
@@ -78,7 +69,6 @@ class Main extends Sprite
#if (!mobile && !web)
addChild(framerateSprite = new funkin.backend.system.framerate.Framerate());
- framerateSprite.scaleX = framerateSprite.scaleY = stage.window.scale;
SystemInfo.init();
#end
}
diff --git a/source/funkin/backend/system/github/GitHubUser.hx b/source/funkin/backend/system/github/GitHubUser.hx
index 4f817891..e0dc15bc 100644
--- a/source/funkin/backend/system/github/GitHubUser.hx
+++ b/source/funkin/backend/system/github/GitHubUser.hx
@@ -125,8 +125,7 @@ typedef GitHubUser = {
var updated_at:String;
}
-@:enum
-abstract GitHubUserType(String) {
+enum abstract GitHubUserType(String) {
var USER = "User";
var ORGANIZATION = "Organization";
}
\ No newline at end of file
diff --git a/source/funkin/backend/system/macros/DefinesMacro.hx b/source/funkin/backend/system/macros/DefinesMacro.hx
index b7a8b96e..da257223 100644
--- a/source/funkin/backend/system/macros/DefinesMacro.hx
+++ b/source/funkin/backend/system/macros/DefinesMacro.hx
@@ -1,9 +1,7 @@
package funkin.backend.system.macros;
#if macro
-import sys.io.Process;
import haxe.macro.Context;
-import haxe.macro.Compiler;
import haxe.macro.Expr;
#end
diff --git a/source/funkin/backend/system/macros/EventMacro.hx b/source/funkin/backend/system/macros/EventMacro.hx
index 3a0f72dc..810ff1fd 100644
--- a/source/funkin/backend/system/macros/EventMacro.hx
+++ b/source/funkin/backend/system/macros/EventMacro.hx
@@ -1,6 +1,9 @@
package funkin.backend.system.macros;
#if macro
+import haxe.macro.Context;
+import haxe.macro.Expr;
+
/**
* Macro that generates all additional fields, making events much easier to code in.
* It adds the `recycle` function, which allows you to "reset" an event's values.
@@ -19,7 +22,6 @@ class EventMacro {
if (f.name == "recycle")
return fields;
-
// gets all fields
var values:Array = [];
var hiddenValues:Array = [];
@@ -48,8 +50,8 @@ class EventMacro {
// add recycle option
var func:Function = {
args: [for(a in values) {
- value: a.expr,
- type: a.type,
+ value: a.expr,
+ type: a.type,
opt: false,
name: a.name
}],
@@ -87,7 +89,7 @@ class EventMacro {
})
});
}
-
+
// add a "set this" expr to reset each private/hidden variables
for(v in hiddenValues) {
var name = v.name;
diff --git a/source/funkin/backend/system/macros/FunkinSaveMacro.hx b/source/funkin/backend/system/macros/FunkinSaveMacro.hx
index f1c2207d..11632991 100644
--- a/source/funkin/backend/system/macros/FunkinSaveMacro.hx
+++ b/source/funkin/backend/system/macros/FunkinSaveMacro.hx
@@ -1,6 +1,9 @@
package funkin.backend.system.macros;
#if macro
+import haxe.macro.Context;
+import haxe.macro.Expr;
+
/**
* Macro that automatically generates flush and load functions.
*/
@@ -13,7 +16,6 @@ class FunkinSaveMacro {
* @return Array
*/
public static function build(saveFieldName:String = "save", saveFuncName:String = "flush", loadFuncName:String = "load"):Array {
-
var fields:Array = Context.getBuildFields();
var fieldNames:Array = [];
diff --git a/source/funkin/backend/system/macros/HashLinkFixer.hx b/source/funkin/backend/system/macros/HashLinkFixer.hx
index 6c1b396f..046929e8 100644
--- a/source/funkin/backend/system/macros/HashLinkFixer.hx
+++ b/source/funkin/backend/system/macros/HashLinkFixer.hx
@@ -1,17 +1,8 @@
package funkin.backend.system.macros;
#if macro
-import haxe.macro.Type.ClassType;
-import Type.ValueType;
-import haxe.macro.Expr.Function;
import haxe.macro.Expr;
-import haxe.macro.Type.MetaAccess;
-import haxe.macro.Type.FieldKind;
-import haxe.macro.Type.ClassField;
-import haxe.macro.Type.VarAccess;
import haxe.macro.*;
-import Sys;
-import haxe.io.Path;
using StringTools;
using haxe.macro.PositionTools;
@@ -30,12 +21,12 @@ class HashLinkFixer {
public static function init() {
#if !display
- #if HL
- for(apply in applyOn) {
- compile(apply);
+ if(Context.defined("hl")) {
+ for(apply in applyOn) {
+ compile(apply);
+ }
}
#end
- #end
}
public static function compile(name:String) {
diff --git a/source/funkin/backend/system/macros/ScriptsMacro.hx b/source/funkin/backend/system/macros/Macros.hx
similarity index 63%
rename from source/funkin/backend/system/macros/ScriptsMacro.hx
rename to source/funkin/backend/system/macros/Macros.hx
index 0014af3d..9183e4a4 100644
--- a/source/funkin/backend/system/macros/ScriptsMacro.hx
+++ b/source/funkin/backend/system/macros/Macros.hx
@@ -1,14 +1,13 @@
package funkin.backend.system.macros;
#if macro
-import haxe.macro.Context;
-import haxe.macro.Compiler;
+import haxe.macro.*;
import haxe.macro.Expr;
/**
* Macros containing additional help functions to expand HScript capabilities.
*/
-class ScriptsMacro {
+class Macros {
public static function addAdditionalClasses() {
for(inc in [
// FLIXEL
@@ -27,19 +26,25 @@ class ScriptsMacro {
])
Compiler.include(inc);
- for(inc in [#if SYS "sys", "openfl.net", "funkin.backend.system.net" #end]) {
- #if !HL
- Compiler.include(inc);
- #else
- // TODO: Hashlink
- //Compiler.include(inc, ["sys.net.UdpSocket", "openfl.net.DatagramSocket"]); // fixes FATAL ERROR : Failed to load function std@socket_set_broadcast
- #end
+ var isHl = Context.defined("hl");
+
+ if(Context.defined("sys")) {
+ for(inc in ["sys", "openfl.net", "funkin.backend.system.net"]) {
+ if(!isHl)
+ Compiler.include(inc);
+ else {
+ // TODO: Hashlink
+ //Compiler.include(inc, ["sys.net.UdpSocket", "openfl.net.DatagramSocket"]); // fixes FATAL ERROR : Failed to load function std@socket_set_broadcast
+ }
+ }
}
- Compiler.include("funkin", #if !UPDATE_CHECKING ['funkin.backend.system.updating'] #end);
+ Compiler.include("funkin", [#if !UPDATE_CHECKING 'funkin.backend.system.updating' #end]);
+ }
- #if HL HashLinkFixer.init(); #end
- // Todo rewrite this to use if(Context.defined(""))
+ public static function initMacros() {
+ if(Context.defined("hl"))
+ HashLinkFixer.init();
}
}
#end
\ No newline at end of file
diff --git a/source/funkin/backend/system/macros/NewHaxeWarning.hx b/source/funkin/backend/system/macros/NewHaxeWarning.hx
index 88a00e9a..ee467955 100644
--- a/source/funkin/backend/system/macros/NewHaxeWarning.hx
+++ b/source/funkin/backend/system/macros/NewHaxeWarning.hx
@@ -6,7 +6,7 @@ class NewHaxeWarning {
#if (haxe >= "4.3.0")
Sys.println("====================");
Sys.println("[ WARNING ]");
- Sys.println("Compiling with Haxe 4.3.0 or above CAN and WILL end up in compilation errors due to changes in macros.");
+ Sys.println("Compiling with Haxe 4.3.0 isnt fully recommended yet, but it does work.");
Sys.println("We recommend building the project using Haxe 4.2.5.");
Sys.println("You can download it here -> https://haxe.org/download/version/4.2.5/");
Sys.println("====================");
diff --git a/source/funkin/backend/system/macros/OptionsMacro.hx b/source/funkin/backend/system/macros/OptionsMacro.hx
index b3503f5d..ae54eb66 100644
--- a/source/funkin/backend/system/macros/OptionsMacro.hx
+++ b/source/funkin/backend/system/macros/OptionsMacro.hx
@@ -1,8 +1,10 @@
package funkin.backend.system.macros;
#if macro
-using StringTools;
+import haxe.macro.Context;
+import haxe.macro.Expr;
+using StringTools;
/**
* Macro used in the options class to add getters for the SOLO keybinds.
diff --git a/source/funkin/backend/system/macros/Utils.hx b/source/funkin/backend/system/macros/Utils.hx
index f55797d2..df25030c 100644
--- a/source/funkin/backend/system/macros/Utils.hx
+++ b/source/funkin/backend/system/macros/Utils.hx
@@ -1,7 +1,8 @@
package funkin.backend.system.macros;
#if macro
-import haxe.macro.Expr.ExprDef;
+import haxe.macro.Context;
+import haxe.macro.Expr;
#end
class Utils {
diff --git a/source/funkin/backend/system/macros/import.hx b/source/funkin/backend/system/macros/import.hx
deleted file mode 100644
index 670edbee..00000000
--- a/source/funkin/backend/system/macros/import.hx
+++ /dev/null
@@ -1,4 +0,0 @@
-#if macro
-import haxe.macro.*;
-import haxe.macro.Expr;
-#end
\ No newline at end of file
diff --git a/source/funkin/backend/system/updating/AsyncUpdater.hx b/source/funkin/backend/system/updating/AsyncUpdater.hx
index ce119a5a..52b59766 100644
--- a/source/funkin/backend/system/updating/AsyncUpdater.hx
+++ b/source/funkin/backend/system/updating/AsyncUpdater.hx
@@ -185,8 +185,7 @@ class UpdaterProgress {
public function new() {}
}
-@:enum
-abstract UpdaterStep(Int) {
+enum abstract UpdaterStep(Int) {
var PREPARING = 0;
var DOWNLOADING_ASSETS = 1;
var DOWNLOADING_EXECUTABLE = 2;
diff --git a/source/funkin/backend/utils/AudioAnalyzer.hx b/source/funkin/backend/utils/AudioAnalyzer.hx
index 235f227f..b5208fa3 100644
--- a/source/funkin/backend/utils/AudioAnalyzer.hx
+++ b/source/funkin/backend/utils/AudioAnalyzer.hx
@@ -15,9 +15,9 @@ class AudioAnalyzer {
__peakByte = Math.pow(2, buffer.bitsPerSample-1)-1;
- __timeMulti = 1 / (1 / buffer.sampleRate);
- __timeMulti *= buffer.bitsPerSample;
- __timeMulti -= __timeMulti % buffer.bitsPerSample;
+ __timeMulti = 1 / (1 / buffer.sampleRate);
+ __timeMulti *= buffer.bitsPerSample;
+ __timeMulti -= __timeMulti % buffer.bitsPerSample;
}
public function analyze(startPos:Float, endPos:Float):Float {
@@ -25,16 +25,16 @@ class AudioAnalyzer {
var bytesEndPos:Int = Math.floor(endPos * __timeMulti / 4000 / buffer.bitsPerSample) * buffer.bitsPerSample;
bytesStartPos -= bytesStartPos % buffer.bitsPerSample;
- bytesEndPos -= bytesEndPos % buffer.bitsPerSample;
+ bytesEndPos -= bytesEndPos % buffer.bitsPerSample;
var maxByte:Int = 0;
for(i in 0...Math.floor((bytesEndPos - bytesStartPos) / buffer.bitsPerSample)) {
- var byte:Int = buffer.data.buffer.get(bytesStartPos + (i * buffer.bitsPerSample))
+ var byte:Int = buffer.data.buffer.get(bytesStartPos + (i * buffer.bitsPerSample))
| (buffer.data.buffer.get(bytesStartPos + (i * buffer.bitsPerSample) + 1) << 8);
if (byte > 256 * 128) byte -= 256 * 256;
if (maxByte < byte) maxByte = byte;
}
-
- return maxByte/__peakByte;
+
+ return maxByte/__peakByte;
}
}
\ No newline at end of file
diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx
index 67d0b4c0..261e85f7 100644
--- a/source/funkin/backend/utils/CoolUtil.hx
+++ b/source/funkin/backend/utils/CoolUtil.hx
@@ -1,7 +1,6 @@
package funkin.backend.utils;
import flixel.text.FlxText;
-import openfl.text.TextFormatAlign;
import funkin.backend.utils.XMLUtil.TextFormat;
import flixel.tweens.FlxTween;
import flixel.system.frontEnds.SoundFrontEnd;
@@ -9,7 +8,6 @@ import flixel.sound.FlxSound;
import funkin.backend.system.Conductor;
import flixel.sound.FlxSoundGroup;
import haxe.Json;
-import funkin.menus.StoryMenuState.WeekData;
import haxe.io.Path;
import haxe.xml.Access;
import flixel.input.keyboard.FlxKey;
@@ -17,10 +15,7 @@ import lime.utils.Assets;
import flixel.animation.FlxAnimation;
import flixel.util.FlxColor;
import flixel.util.FlxAxes;
-import flixel.graphics.frames.FlxFrame;
-import flixel.graphics.frames.FlxFramesCollection;
import openfl.geom.ColorTransform;
-import funkin.backend.chart.Chart;
import haxe.CallStack;
using StringTools;
diff --git a/source/funkin/backend/utils/NativeAPI.hx b/source/funkin/backend/utils/NativeAPI.hx
index 061021bc..a651645e 100644
--- a/source/funkin/backend/utils/NativeAPI.hx
+++ b/source/funkin/backend/utils/NativeAPI.hx
@@ -3,8 +3,8 @@ package funkin.backend.utils;
import funkin.backend.utils.native.*;
/**
- * Class for Windows-only functions, such as transparent windows, message boxes, and more.
- * Does not have any effect on other platforms.
+ * Class for functions that talk to a lower level than haxe, such as message boxes, and more.
+ * Some functions might not have effect on some platforms.
*/
class NativeAPI {
@:dox(hide) public static function registerAudio() {
diff --git a/source/funkin/backend/utils/native/Windows.hx b/source/funkin/backend/utils/native/Windows.hx
index 1efb4d33..07312d8d 100644
--- a/source/funkin/backend/utils/native/Windows.hx
+++ b/source/funkin/backend/utils/native/Windows.hx
@@ -1,7 +1,7 @@
package funkin.backend.utils.native;
-import funkin.backend.utils.NativeAPI.MessageBoxIcon;
#if windows
+import funkin.backend.utils.NativeAPI.MessageBoxIcon;
@:buildXml('
@@ -12,7 +12,7 @@ import funkin.backend.utils.NativeAPI.MessageBoxIcon;
')
-// majority is taken from microsofts doc
+// majority is taken from microsofts doc
@:cppFileCode('
#include "mmdeviceapi.h"
#include "combaseapi.h"
@@ -36,7 +36,7 @@ static long lastDefId = 0;
class AudioFixClient : public IMMNotificationClient {
LONG _cRef;
IMMDeviceEnumerator *_pEnumerator;
-
+
public:
AudioFixClient() :
_cRef(1),
@@ -153,9 +153,9 @@ class Windows {
public static function allocConsole() {
}
-
+
@:functionCode('
- HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(console, color);
')
public static function setConsoleColors(color:Int) {
@@ -175,7 +175,7 @@ class Windows {
MessageBox(GetActiveWindow(), message, caption, icon | MB_SETFOREGROUND);
')
public static function showMessageBox(caption:String, message:String, icon:MessageBoxIcon = MSG_WARNING) {
-
+
}
@:functionCode('
diff --git a/source/funkin/editors/EditorPicker.hx b/source/funkin/editors/EditorPicker.hx
index 1ddbd508..7056305f 100644
--- a/source/funkin/editors/EditorPicker.hx
+++ b/source/funkin/editors/EditorPicker.hx
@@ -1,6 +1,5 @@
package funkin.editors;
-import flixel.addons.transition.FlxTransitionableState;
import flixel.math.FlxPoint;
import flixel.effects.FlxFlicker;
diff --git a/source/funkin/editors/SaveSubstate.hx b/source/funkin/editors/SaveSubstate.hx
index aed0c120..6250050a 100644
--- a/source/funkin/editors/SaveSubstate.hx
+++ b/source/funkin/editors/SaveSubstate.hx
@@ -5,9 +5,6 @@ import sys.io.File;
#end
import haxe.io.Path;
import lime.ui.FileDialog;
-import openfl.net.FileReference;
-import openfl.events.Event;
-import openfl.events.IOErrorEvent;
class SaveSubstate extends MusicBeatSubstate {
public var saveOptions:Map;
diff --git a/source/funkin/editors/character/CharacterEditor.hx b/source/funkin/editors/character/CharacterEditor.hx
index 24166263..25c2d33b 100644
--- a/source/funkin/editors/character/CharacterEditor.hx
+++ b/source/funkin/editors/character/CharacterEditor.hx
@@ -5,9 +5,7 @@ import haxe.xml.Printer;
import haxe.xml.Access;
import funkin.backend.utils.XMLUtil.AnimData;
import flixel.math.FlxPoint;
-import flixel.animation.FlxAnimation;
import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
-import flixel.input.keyboard.FlxKey;
import funkin.game.Character;
class CharacterEditor extends UIState {
diff --git a/source/funkin/editors/charter/ChartCreationScreen.hx b/source/funkin/editors/charter/ChartCreationScreen.hx
index 46a68488..c89835f9 100644
--- a/source/funkin/editors/charter/ChartCreationScreen.hx
+++ b/source/funkin/editors/charter/ChartCreationScreen.hx
@@ -3,7 +3,6 @@ package funkin.editors.charter;
import flixel.text.FlxText.FlxTextFormat;
import flixel.text.FlxText.FlxTextFormatMarkerPair;
import funkin.backend.shaders.CustomShader;
-import flixel.math.FlxRect;
import funkin.game.Character;
import funkin.game.Stage;
import funkin.game.HealthIcon;
diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx
index 083634c6..38023cfc 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -1,7 +1,5 @@
package funkin.editors.charter;
-import openfl.geom.Rectangle;
-import flixel.util.FlxSpriteUtil;
import funkin.editors.ui.UIContextMenu.UIContextMenuOptionSpr;
import funkin.editors.ui.UITopMenu.UITopMenuButton;
import funkin.editors.charter.CharterStrumline;
@@ -10,20 +8,14 @@ import funkin.backend.system.framerate.Framerate;
import haxe.Json;
import flixel.input.keyboard.FlxKey;
import flixel.sound.FlxSound;
-import flixel.util.FlxSort;
import flixel.math.FlxPoint;
import funkin.editors.charter.CharterBackdropGroup.CharterBackdropDummy;
import funkin.backend.system.Conductor;
import funkin.backend.chart.*;
import funkin.backend.chart.ChartData;
-import openfl.display.BitmapData;
-import flixel.util.FlxColor;
import flixel.addons.display.FlxBackdrop;
import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
import funkin.editors.ui.UIState;
-import openfl.net.FileReference;
-
-using flixel.util.FlxColor;
class Charter extends UIState {
public static var __song:String;
@@ -59,7 +51,7 @@ class Charter extends UIState {
public var addEventSpr:CharterEventAdd;
public var gridBackdropDummy:CharterBackdropDummy;
- public var noteHoverer:CharterNote;
+ public var noteHoverer:CharterNoteHoverer;
public var strumlineInfoBG:FlxSprite;
public var strumlineAddButton:CharterStrumlineButton;
@@ -549,7 +541,6 @@ class Charter extends UIState {
for(e in eventsGroup.members)
e.refreshEventIcons();
-
buildNoteTypesUI();
refreshBPMSensitive();
@@ -580,47 +571,45 @@ class Charter extends UIState {
* NOTE AND CHARTER GRID LOGIC HERE
*/
#if REGION
- var gridActionType:CharterGridActionType = NONE;
- var dragStartPos:FlxPoint = new FlxPoint();
- var selectionDragging:Bool = false;
+ public var gridActionType:CharterGridActionType = NONE;
+ public var dragStartPos:FlxPoint = new FlxPoint();
+ public var mousePos:FlxPoint = new FlxPoint();
+ public var selectionDragging:Bool = false;
+
+ public function updateSelectionLogic() {
+ function select(s:ICharterSelectable) {
+ if (FlxG.keys.pressed.CONTROL) selection.push(s);
+ else if (FlxG.keys.pressed.SHIFT) selection.remove(s);
+ else selection = [s];
+ }
- public function updateNoteLogic(elapsed:Float) {
for (group in [notesGroup, eventsGroup]) {
- cast(group, FlxTypedGroup).forEach(function(n) {
- n.selected = false;
- if (n.hovered && gridActionType == NONE) {
- if (FlxG.mouse.justReleased) {
- if (FlxG.keys.pressed.CONTROL)
- selection.push(cast n);
- else if (FlxG.keys.pressed.SHIFT)
- selection.remove(cast n);
- else
- selection = [cast n];
- }
-
- if (FlxG.mouse.justReleasedRight) {
- var mousePos = FlxG.mouse.getScreenPosition(uiCamera);
- if (!selection.contains(cast n))
- selection = [cast n];
- closeCurrentContextMenu();
- openContextMenu(topMenu[1].childs, null, mousePos.x, mousePos.y);
- mousePos.put();
- }
+ cast(group, FlxTypedGroup).forEach(function(s) {
+ s.selected = false;
+ if (gridActionType == NONE) {
+ if (s is CharterNote) {
+ var n:CharterNote = cast s;
+ if ((n.hovered || n.sustainDraggable) && FlxG.mouse.justReleased) select(cast s);
+ } else if (FlxG.mouse.justReleased && s.hovered) select(cast s);
}
});
}
selection = __fixSelection(selection);
for(s in selection) s.selected = true;
+ }
+
+ public function updateNoteLogic(elapsed:Float) {
+ updateSelectionLogic();
/**
* NOTE DRAG HANDLING
*/
- var mousePos = FlxG.mouse.getWorldPosition(charterCamera);
+ mousePos = FlxG.mouse.getWorldPosition(charterCamera);
if (!gridBackdropDummy.hoveredByChild && !FlxG.mouse.pressed)
gridActionType = NONE;
selectionBox.visible = false;
switch(gridActionType) {
- case BOX:
+ case BOX_SELECTION:
if (gridBackdropDummy.hoveredByChild) {
selectionBox.visible = true;
if (FlxG.mouse.pressed) {
@@ -655,7 +644,7 @@ class Charter extends UIState {
// do nothing, locked
if (!FlxG.mouse.pressed)
gridActionType = NONE;
- case DRAG:
+ case NOTE_DRAG:
selectionDragging = FlxG.mouse.pressed;
if (selectionDragging) {
gridBackdrops.draggingObj = null;
@@ -718,7 +707,7 @@ class Charter extends UIState {
if (gridBackdropDummy.hovered) {
// AUTO DETECT
if (FlxG.mouse.pressed && (Math.abs(mousePos.x - dragStartPos.x) > 20 || Math.abs(mousePos.y - dragStartPos.y) > 20))
- gridActionType = BOX;
+ gridActionType = BOX_SELECTION;
var id = Math.floor(mousePos.x / 40);
var mouseOnGrid = id >= 0 && id < 4 * gridBackdrops.strumlinesAmount && mousePos.y >= 0;
@@ -739,14 +728,21 @@ class Charter extends UIState {
}
}
} else if (gridBackdropDummy.hoveredByChild) {
- if (FlxG.mouse.pressed && (Math.abs(mousePos.x - dragStartPos.x) > 5 || Math.abs(mousePos.y - dragStartPos.y) > 5)) {
+ if (FlxG.mouse.pressed) {
var noteHovered:Bool = false;
- for(n in selection)
- if (n.hovered) {
- noteHovered = true;
- break;
- }
- gridActionType = noteHovered ? DRAG : INVALID_DRAG;
+ for(n in selection) if (n.hovered) {noteHovered = true; break;}
+
+ var noteSusDrag:Bool = false;
+ for(s in selection) {
+ if (!(s is CharterNote)) continue;
+ var n:CharterNote = cast s;
+ if (n.sustainDraggable) {noteSusDrag = true; break;}
+ }
+
+ if ((Math.abs(mousePos.x - dragStartPos.x) > (noteSusDrag ? 1 : 5) || Math.abs(mousePos.y - dragStartPos.y) > (noteSusDrag ? 1 : 5))) {
+ if (noteHovered) gridActionType = noteHovered ? NOTE_DRAG : INVALID_DRAG;
+ if (noteSusDrag) gridActionType = SUSTAIN_DRAG;
+ }
}
}
@@ -756,6 +752,35 @@ class Charter extends UIState {
openContextMenu(topMenu[1].childs, null, mousePos.x, mousePos.y);
mousePos.put();
}
+ case SUSTAIN_DRAG:
+ selectionDragging = FlxG.mouse.pressed;
+ if (selectionDragging) {
+ currentCursor = BUTTON;
+ selection.loop(function (n:CharterNote) {
+ var change:Float = Math.max((mousePos.y-(FlxG.keys.pressed.SHIFT ? dragStartPos.y : quantStep(dragStartPos.y))) / 40, -n.susLength);
+ n.tempSusLength = change;
+
+ if (!FlxG.keys.pressed.SHIFT)
+ n.tempSusLength -= (n.susLength + change) - quantStepRounded(n.susLength + change, change > 0 ? 0.35 : 0.65);
+ @:privateAccess n.__susInstaLerp = FlxG.keys.pressed.SHIFT;
+ });
+ } else {
+ var undoChanges:Array = [];
+ selection.loop(function (n:CharterNote) {
+ var oldSusLen:Float = n.susLength;
+
+ n.susLength += n.tempSusLength;
+ n.tempSusLength = 0;
+
+ @:privateAccess n.__susInstaLerp = false;
+ n.updatePos(n.step, n.id, n.susLength, n.type);
+ undoChanges.push({before: oldSusLen, after: n.susLength, note: n});
+ });
+ undos.addToUndo(CEditSustains(undoChanges));
+
+ gridActionType = NONE;
+ currentCursor = ARROW;
+ }
}
addEventSpr.selectable = !selectionBox.visible;
@@ -769,6 +794,8 @@ class Charter extends UIState {
if (event != null) addEventSpr.updateEdit(event);
else addEventSpr.updatePos(FlxG.keys.pressed.SHIFT ? ((mousePos.y) / 40) : quantStepRounded(mousePos.y/40));
} else addEventSpr.sprAlpha = lerp(addEventSpr.sprAlpha, 0, 0.25);
+
+ noteHoverer.showHoverer = Charter.instance.gridBackdropDummy.hovered;
}
public function quantStep(step:Float):Float {
@@ -1475,7 +1502,7 @@ class Charter extends UIState {
if (s is CharterNote) {
var n:CharterNote = cast s;
var old:Float = n.susLength;
- n.updatePos(n.step, n.id, Math.max(n.susLength + change, 0));
+ n.updatePos(n.step, n.id, Math.max(n.susLength + change, 0), n.type);
undoChanges.push({before: old, after: n.susLength, note: n});
}
@@ -1783,9 +1810,10 @@ interface ICharterSelectable {
enum abstract CharterGridActionType(Int) {
var NONE = 0;
- var BOX = 1;
- var DRAG = 2;
+ var BOX_SELECTION = 1;
+ var NOTE_DRAG = 2;
var INVALID_DRAG = 3;
+ var SUSTAIN_DRAG = 4;
}
typedef PlaytestInfo = {
diff --git a/source/funkin/editors/charter/CharterBackdropGroup.hx b/source/funkin/editors/charter/CharterBackdropGroup.hx
index 7e69b7e9..f99571ab 100644
--- a/source/funkin/editors/charter/CharterBackdropGroup.hx
+++ b/source/funkin/editors/charter/CharterBackdropGroup.hx
@@ -1,6 +1,5 @@
package funkin.editors.charter;
-import flixel.util.FlxPool;
import flixel.graphics.FlxGraphic;
import funkin.backend.system.Conductor;
import openfl.geom.Rectangle;
diff --git a/source/funkin/editors/charter/CharterNote.hx b/source/funkin/editors/charter/CharterNote.hx
index 0a9af564..1ea7804d 100644
--- a/source/funkin/editors/charter/CharterNote.hx
+++ b/source/funkin/editors/charter/CharterNote.hx
@@ -9,6 +9,9 @@ import flixel.util.FlxColor;
class CharterNote extends UISprite implements ICharterSelectable {
var angleTween:FlxTween;
+ var __doAnim:Bool = false;
+ var __animSpeed:Float = 1;
+ var __susInstaLerp:Bool = false;
private static var colors:Array = [
0xFFC24B99,
@@ -17,10 +20,11 @@ class CharterNote extends UISprite implements ICharterSelectable {
0xFFF9393F
];
- public var sustainSpr:FlxSprite;
+ public var sustainSpr:UISprite;
+ public var tempSusLength:Float = 0;
+ public var sustainDraggable:Bool = false;
+
public var typeText:UIText;
- var __doAnim:Bool = false;
- var __animSpeed:Float = 1;
public var selected:Bool = false;
public var draggable:Bool = true;
@@ -34,15 +38,15 @@ class CharterNote extends UISprite implements ICharterSelectable {
animation.play("note");
this.setUnstretchedGraphicSize(40, 40, false);
- cursor = BUTTON;
- moves = false;
-
- sustainSpr = new FlxSprite(10, 40);
- sustainSpr.makeGraphic(1, 1, -1);
+ sustainSpr = new UISprite(10, 20);
+ sustainSpr.makeSolid(1, 1, -1);
+ sustainSpr.scale.set(10, 0);
members.push(sustainSpr);
typeText = new UIText(x, y, 0, Std.string(type));
- //typeText.borderSize = 1.5;
+
+ cursor = sustainSpr.cursor = BUTTON;
+ moves = false;
}
public override function updateButtonHandler() {
@@ -82,12 +86,6 @@ class CharterNote extends UISprite implements ICharterSelectable {
y = step * 40;
- sustainSpr.scale.set(10, (40 * susLength) + (height/2));
- sustainSpr.updateHitbox();
- sustainSpr.exists = susLength != 0;
- sustainSpr.alpha = alpha;
- sustainSpr.follow(this, 15, 20);
-
if (angleTween != null) angleTween.cancel();
var destAngle = switch(animation.curAnim.curFrame = (id % 4)) {
@@ -134,8 +132,18 @@ class CharterNote extends UISprite implements ICharterSelectable {
var __passed:Bool = false;
public override function update(elapsed:Float) {
super.update(elapsed);
- if (sustainSpr.exists)
- sustainSpr.follow(this, 15, 20);
+
+ var sprLength:Float = (40 * (susLength+tempSusLength)) + ((susLength+tempSusLength) != 0 ? (height/2) : 0);
+ sustainSpr.scale.set(10, __susInstaLerp ? sprLength : CoolUtil.fpsLerp(sustainSpr.scale.y, sprLength, 1/2));
+ sustainSpr.updateHitbox();
+ sustainSpr.follow(this, 15, 20);
+
+ sustainDraggable = false;
+ if (!hovered && susLength != 0) {
+ UIState.state.updateSpriteRect(sustainSpr);
+ sustainDraggable = UIState.state.isOverlapping(sustainSpr, @:privateAccess sustainSpr.__rect);
+ }
+
if (typeText.exists)
typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
diff --git a/source/funkin/editors/charter/CharterNoteHoverer.hx b/source/funkin/editors/charter/CharterNoteHoverer.hx
index e3648daf..46997a9b 100644
--- a/source/funkin/editors/charter/CharterNoteHoverer.hx
+++ b/source/funkin/editors/charter/CharterNoteHoverer.hx
@@ -1,6 +1,8 @@
package funkin.editors.charter;
class CharterNoteHoverer extends CharterNote {
+ public var showHoverer:Bool = false;
+
public function new() {
super();
@@ -15,7 +17,7 @@ class CharterNoteHoverer extends CharterNote {
switch (Charter.instance.gridActionType) {
case NONE:
var inBoundsY:Bool = (__mousePos.y > 0 && __mousePos.y < (Charter.instance.__endStep)*40);
- if (__mousePos.x > 0 && __mousePos.x < Charter.instance.gridBackdrops.strumlinesAmount * 160 && inBoundsY) {
+ if ((__mousePos.x > 0 && __mousePos.x < Charter.instance.gridBackdrops.strumlinesAmount * 160 && inBoundsY) && showHoverer) {
step = FlxMath.bound(FlxG.keys.pressed.SHIFT ? ((__mousePos.y-20) / 40) : Charter.instance.quantStep(__mousePos.y/40), 0, Charter.instance.__endStep-1);
id = Math.floor(__mousePos.x / 40); y = step * 40; x = id * 40; visible = true; sustainSpr.visible = typeText.visible = false;
angle = switch(animation.curAnim.curFrame = (id % 4)) {
@@ -27,7 +29,7 @@ class CharterNoteHoverer extends CharterNote {
};
} else
visible = false;
- case DRAG:
+ case NOTE_DRAG:
visible = sustainSpr.visible = typeText.visible = true; __doAnim = false;
default:
visible = sustainSpr.visible = typeText.visible = false; __doAnim = false;
@@ -38,8 +40,8 @@ class CharterNoteHoverer extends CharterNote {
switch (Charter.instance.gridActionType) {
case NONE:
super.draw();
- case DRAG:
- if (Charter.instance.gridActionType == DRAG) {
+ case NOTE_DRAG:
+ if (Charter.instance.gridActionType == NOTE_DRAG) {
var verticalChange:Float = (__mousePos.y - Charter.instance.dragStartPos.y) / 40;
var horizontalChange:Int = CoolUtil.floorInt((__mousePos.x - (Std.int(Charter.instance.dragStartPos.x / 40) * 40)) / 40);
diff --git a/source/funkin/editors/charter/CharterSelection.hx b/source/funkin/editors/charter/CharterSelection.hx
index 7835603a..ba1acdc4 100644
--- a/source/funkin/editors/charter/CharterSelection.hx
+++ b/source/funkin/editors/charter/CharterSelection.hx
@@ -3,11 +3,9 @@ package funkin.editors.charter;
import funkin.backend.chart.ChartData;
import funkin.backend.chart.ChartData.ChartMetaData;
import haxe.Json;
-import funkin.backend.assets.ModsFolder;
import funkin.editors.charter.SongCreationScreen.SongCreationData;
import funkin.options.type.NewOption;
import funkin.backend.system.framerate.Framerate;
-import flixel.util.FlxColor;
import funkin.menus.FreeplayState.FreeplaySonglist;
import funkin.editors.EditorTreeMenu;
import funkin.options.*;
diff --git a/source/funkin/editors/charter/CharterStrumLineGroup.hx b/source/funkin/editors/charter/CharterStrumLineGroup.hx
index 3018300c..a342c779 100644
--- a/source/funkin/editors/charter/CharterStrumLineGroup.hx
+++ b/source/funkin/editors/charter/CharterStrumLineGroup.hx
@@ -1,6 +1,5 @@
package funkin.editors.charter;
-import funkin.backend.chart.ChartData.ChartStrumLine;
import funkin.backend.chart.EventsData;
import flixel.util.FlxSort;
diff --git a/source/funkin/editors/charter/CharterStrumline.hx b/source/funkin/editors/charter/CharterStrumline.hx
index 185e4a04..bee6e7a3 100644
--- a/source/funkin/editors/charter/CharterStrumline.hx
+++ b/source/funkin/editors/charter/CharterStrumline.hx
@@ -1,9 +1,7 @@
package funkin.editors.charter;
import flixel.group.FlxSpriteGroup;
-import funkin.backend.chart.EventsData;
import funkin.game.Character;
-import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
import funkin.editors.ui.UITopMenu.UITopMenuButton;
import funkin.game.HealthIcon;
import funkin.backend.chart.ChartData.ChartStrumLine;
diff --git a/source/funkin/editors/charter/SongCreationScreen.hx b/source/funkin/editors/charter/SongCreationScreen.hx
index 0a6da065..fdd9cf1e 100644
--- a/source/funkin/editors/charter/SongCreationScreen.hx
+++ b/source/funkin/editors/charter/SongCreationScreen.hx
@@ -3,7 +3,7 @@ package funkin.editors.charter;
import flixel.text.FlxText.FlxTextFormat;
import flixel.text.FlxText.FlxTextFormatMarkerPair;
import flixel.group.FlxGroup;
-import funkin.backend.chart.ChartData;
+import funkin.backend.chart.ChartData.ChartMetaData;
import haxe.io.Bytes;
typedef SongCreationData = {
diff --git a/source/funkin/editors/import.hx b/source/funkin/editors/import.hx
index b15a4507..75250a63 100644
--- a/source/funkin/editors/import.hx
+++ b/source/funkin/editors/import.hx
@@ -1,6 +1,8 @@
+#if !macro
package funkin.editors;
import funkin.editors.ui.*;
import flixel.math.FlxPoint;
-using funkin.editors.ui.UIUtil;
\ No newline at end of file
+using funkin.editors.ui.UIUtil;
+#end
\ No newline at end of file
diff --git a/source/funkin/editors/ui/UIAudioPlayer.hx b/source/funkin/editors/ui/UIAudioPlayer.hx
index daf6b3b2..ad1ba457 100644
--- a/source/funkin/editors/ui/UIAudioPlayer.hx
+++ b/source/funkin/editors/ui/UIAudioPlayer.hx
@@ -3,7 +3,6 @@ package funkin.editors.ui;
import flixel.math.FlxRect;
import flixel.util.FlxColor;
import flixel.ui.FlxBar;
-import openfl.geom.Rectangle;
import flixel.sound.FlxSound;
import haxe.io.Bytes;
import lime.media.AudioBuffer;
diff --git a/source/funkin/editors/ui/UIAutoCompleteTextBox.hx b/source/funkin/editors/ui/UIAutoCompleteTextBox.hx
index 6b5d31b3..938a2384 100644
--- a/source/funkin/editors/ui/UIAutoCompleteTextBox.hx
+++ b/source/funkin/editors/ui/UIAutoCompleteTextBox.hx
@@ -1,10 +1,7 @@
package funkin.editors.ui;
-import flixel.math.FlxPoint;
import lime.ui.KeyModifier;
import lime.ui.KeyCode;
-import openfl.desktop.Clipboard;
-import openfl.geom.Rectangle;
class UIAutoCompleteTextBox extends UITextBox {
public var suggestionText:UIText;
diff --git a/source/funkin/editors/ui/UIButton.hx b/source/funkin/editors/ui/UIButton.hx
index f3e67821..c5522c5c 100644
--- a/source/funkin/editors/ui/UIButton.hx
+++ b/source/funkin/editors/ui/UIButton.hx
@@ -1,7 +1,5 @@
package funkin.editors.ui;
-import flixel.graphics.frames.FlxFrame;
-
class UIButton extends UISliceSprite {
public var callback:Void->Void = null;
public var field:UIText;
diff --git a/source/funkin/editors/ui/UIButtonList.hx b/source/funkin/editors/ui/UIButtonList.hx
index af27be84..59d88971 100644
--- a/source/funkin/editors/ui/UIButtonList.hx
+++ b/source/funkin/editors/ui/UIButtonList.hx
@@ -1,10 +1,7 @@
package funkin.editors.ui;
import flixel.FlxCamera;
-import flixel.group.FlxGroup;
-import flixel.util.FlxColor;
import flixel.math.FlxPoint;
-import funkin.game.Character;
import flixel.util.FlxSort;
import flixel.math.FlxMath;
diff --git a/source/funkin/editors/ui/UICheckbox.hx b/source/funkin/editors/ui/UICheckbox.hx
index 8a0b1a55..a5bcdef3 100644
--- a/source/funkin/editors/ui/UICheckbox.hx
+++ b/source/funkin/editors/ui/UICheckbox.hx
@@ -1,7 +1,5 @@
package funkin.editors.ui;
-import funkin.backend.FunkinText;
-
class UICheckbox extends UISprite {
public var checked:Bool = false;
public var onChecked:Bool->Void = null;
diff --git a/source/funkin/editors/ui/UIState.hx b/source/funkin/editors/ui/UIState.hx
index b43e605e..3e33004e 100644
--- a/source/funkin/editors/ui/UIState.hx
+++ b/source/funkin/editors/ui/UIState.hx
@@ -2,7 +2,6 @@ package funkin.editors.ui;
import lime.ui.KeyModifier;
import lime.ui.KeyCode;
-import openfl.events.KeyboardEvent;
import funkin.backend.system.framerate.Framerate;
import funkin.editors.ui.UIContextMenu.UIContextMenuCallback;
import openfl.ui.Mouse;
diff --git a/source/funkin/game/GameOverSubstate.hx b/source/funkin/game/GameOverSubstate.hx
index c7d6c44e..3d119f02 100644
--- a/source/funkin/game/GameOverSubstate.hx
+++ b/source/funkin/game/GameOverSubstate.hx
@@ -4,10 +4,7 @@ import funkin.editors.charter.Charter;
import funkin.backend.scripting.events.GameOverCreationEvent;
import funkin.backend.scripting.events.CancellableEvent;
import funkin.backend.scripting.Script;
-import flixel.addons.transition.FlxTransitionableState;
import flixel.sound.FlxSound;
-import flixel.FlxSubState;
-import flixel.math.FlxPoint;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import funkin.menus.StoryMenuState;
diff --git a/source/funkin/game/HudCamera.hx b/source/funkin/game/HudCamera.hx
index c0b6c48e..accd5f30 100644
--- a/source/funkin/game/HudCamera.hx
+++ b/source/funkin/game/HudCamera.hx
@@ -1,31 +1,7 @@
package funkin.game;
-
-import lime.app.Application;
-import flixel.graphics.tile.FlxGraphicsShader;
-import openfl.display.Bitmap;
-import openfl.display.BitmapData;
-import openfl.display.DisplayObject;
-import openfl.display.Graphics;
-import openfl.display.Sprite;
-import openfl.geom.ColorTransform;
-import openfl.geom.Point;
-import openfl.geom.Rectangle;
-import flixel.graphics.FlxGraphic;
-import flixel.graphics.frames.FlxFrame;
-import flixel.graphics.tile.FlxDrawBaseItem;
-import flixel.graphics.tile.FlxDrawTrianglesItem;
import flixel.math.FlxMatrix;
import flixel.math.FlxPoint;
-import flixel.math.FlxRect;
-import flixel.system.FlxAssets.FlxShader;
-import flixel.util.FlxAxes;
-import flixel.util.FlxColor;
-import flixel.util.FlxSpriteUtil;
-import openfl.display.BlendMode;
-import openfl.filters.BitmapFilter;
-import openfl.filters.ShaderFilter;
-import openfl.Vector;
class HudCamera extends FlxCamera {
public var downscroll:Bool = false;
diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx
index e72d62ec..b8baf48e 100644
--- a/source/funkin/game/Note.hx
+++ b/source/funkin/game/Note.hx
@@ -1,11 +1,8 @@
package funkin.game;
-import funkin.backend.chart.Chart;
import funkin.backend.chart.ChartData;
-import flixel.graphics.frames.FlxAtlasFrames;
-import flixel.util.FlxColor;
-import flixel.math.FlxRect;
import flixel.math.FlxPoint;
+import flixel.math.FlxRect;
import funkin.backend.system.Conductor;
import funkin.backend.scripting.events.*;
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index 575c612c..c567b3c5 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -2,7 +2,6 @@ package funkin.game;
import funkin.editors.charter.CharterSelection;
import flixel.FlxState;
-import funkin.editors.EditorTreeMenu;
import funkin.editors.SaveWarning;
import funkin.backend.chart.EventsData;
import funkin.backend.system.RotatingSpriteGroup;
@@ -15,11 +14,9 @@ import funkin.game.SplashHandler;
import funkin.backend.scripting.DummyScript;
import funkin.menus.StoryMenuState.WeekData;
import funkin.backend.FunkinText;
-import flixel.group.FlxSpriteGroup;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.ScriptPack;
import flixel.FlxSubState;
-import flixel.addons.transition.FlxTransitionableState;
import flixel.math.FlxPoint;
import flixel.sound.FlxSound;
import flixel.text.FlxText;
@@ -762,7 +759,7 @@ class PlayState extends MusicBeatState
SaveWarning.warningFunc = saveWarn;
SaveWarning.saveFunc = () -> {
@:privateAccess Chart.save('${Paths.getAssetsRoot()}/songs/${Charter.__song.toLowerCase()}',
- PlayState.SONG, Charter.__diff.toLowerCase(), {saveMetaInChart: false});
+ PlayState.SONG, Charter.__diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: true});
}
}
}
diff --git a/source/funkin/game/Stage.hx b/source/funkin/game/Stage.hx
index 4f645a4b..af36d445 100644
--- a/source/funkin/game/Stage.hx
+++ b/source/funkin/game/Stage.hx
@@ -3,7 +3,6 @@ package funkin.game;
import funkin.backend.scripting.events.StageXMLEvent;
import funkin.backend.scripting.events.StageNodeEvent;
import flixel.math.FlxPoint;
-import funkin.backend.MusicBeatGroup;
import flixel.FlxState;
import haxe.xml.Access;
import funkin.backend.system.interfaces.IBeatReceiver;
diff --git a/source/funkin/menus/BetaWarningState.hx b/source/funkin/menus/BetaWarningState.hx
index 78813ac0..08d60f39 100644
--- a/source/funkin/menus/BetaWarningState.hx
+++ b/source/funkin/menus/BetaWarningState.hx
@@ -1,6 +1,5 @@
package funkin.menus;
-import flixel.addons.transition.FlxTransitionableState;
import flixel.util.FlxColor;
import flixel.text.FlxText;
import funkin.backend.FunkinText;
diff --git a/source/funkin/menus/FreeplayState.hx b/source/funkin/menus/FreeplayState.hx
index b2531268..f88b8d99 100644
--- a/source/funkin/menus/FreeplayState.hx
+++ b/source/funkin/menus/FreeplayState.hx
@@ -1,17 +1,14 @@
package funkin.menus;
import funkin.backend.chart.Chart;
-import funkin.backend.chart.ChartData;
+import funkin.backend.chart.ChartData.ChartMetaData;
import haxe.io.Path;
import openfl.text.TextField;
-import flixel.FlxState;
-import flixel.addons.display.FlxGridOverlay;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import lime.utils.Assets;
import funkin.game.HealthIcon;
import funkin.savedata.FunkinSave;
-import haxe.Json;
import funkin.backend.scripting.events.*;
using StringTools;
@@ -411,17 +408,14 @@ class FreeplayState extends MusicBeatState
var event = event("onUpdateOptionsAlpha", EventManager.get(FreeplayAlphaUpdateEvent).recycle(0.6, 0.45, 1, 1, 0.25));
if (event.cancelled) return;
- var bullShit:Int = 0;
-
for (i in 0...iconArray.length)
iconArray[i].alpha = lerp(iconArray[i].alpha, #if PRELOAD_ALL songInstPlaying ? event.idlePlayingAlpha : #end event.idleAlpha, event.lerp);
iconArray[curSelected].alpha = #if PRELOAD_ALL songInstPlaying ? event.selectedPlayingAlpha : #end event.selectedAlpha;
- for (item in grpSongs.members)
+ for (i=>item in grpSongs.members)
{
- item.targetY = bullShit - curSelected;
- bullShit++;
+ item.targetY = i - curSelected;
item.alpha = lerp(item.alpha, #if PRELOAD_ALL songInstPlaying ? event.idlePlayingAlpha : #end event.idleAlpha, event.lerp);
diff --git a/source/funkin/menus/GitarooPause.hx b/source/funkin/menus/GitarooPause.hx
index bc782121..a8448b4e 100644
--- a/source/funkin/menus/GitarooPause.hx
+++ b/source/funkin/menus/GitarooPause.hx
@@ -1,7 +1,6 @@
package funkin.menus;
import funkin.editors.charter.Charter;
-import flixel.graphics.frames.FlxAtlasFrames;
class GitarooPause extends MusicBeatState
{
diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx
index ea6a71b9..2c5c7101 100644
--- a/source/funkin/menus/MainMenuState.hx
+++ b/source/funkin/menus/MainMenuState.hx
@@ -4,9 +4,7 @@ import haxe.Json;
import funkin.backend.FunkinText;
import funkin.menus.credits.CreditsMain;
import flixel.FlxState;
-import flixel.addons.transition.FlxTransitionableState;
import flixel.effects.FlxFlicker;
-import flixel.graphics.frames.FlxAtlasFrames;
import flixel.text.FlxText;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx
index 2fe5e85a..b0c34bf9 100644
--- a/source/funkin/menus/PauseSubState.hx
+++ b/source/funkin/menus/PauseSubState.hx
@@ -6,9 +6,6 @@ import funkin.options.OptionsMenu;
import funkin.backend.scripting.events.PauseCreationEvent;
import funkin.backend.scripting.events.NameEvent;
import funkin.backend.scripting.Script;
-import flixel.FlxSubState;
-import flixel.addons.transition.FlxTransitionableState;
-import flixel.input.keyboard.FlxKey;
import flixel.sound.FlxSound;
import flixel.text.FlxText;
import flixel.tweens.FlxTween;
@@ -194,12 +191,9 @@ class PauseSubState extends MusicBeatSubstate
curSelected = event.value;
- var bullShit:Int = 0;
-
- for (item in grpMenuShit.members)
+ for (i=>item in grpMenuShit.members)
{
- item.targetY = bullShit - curSelected;
- bullShit++;
+ item.targetY = i - curSelected;
if (item.targetY == 0)
item.alpha = 1;
diff --git a/source/funkin/menus/StoryMenuState.hx b/source/funkin/menus/StoryMenuState.hx
index 705758e0..0f8dd1d5 100644
--- a/source/funkin/menus/StoryMenuState.hx
+++ b/source/funkin/menus/StoryMenuState.hx
@@ -5,7 +5,6 @@ import haxe.io.Path;
import funkin.backend.scripting.events.*;
import flixel.util.FlxTimer;
import flixel.math.FlxPoint;
-import flixel.graphics.frames.FlxFramesCollection;
import flixel.tweens.FlxTween;
import flixel.util.FlxColor;
import funkin.backend.FunkinText;
@@ -37,7 +36,7 @@ class StoryMenuState extends MusicBeatState {
public var weekSprites:FlxTypedGroup