From a4546c530e74dff1e7daa47f9b067f16d0e57a59 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Fri, 9 Jan 2026 21:22:56 +1100 Subject: [PATCH 1/8] Initial commit for branch --- source/flx3d/FlxView3D.hx | 60 +++++-- source/flx3d/_internal/TextureView3D.hx | 215 ++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 13 deletions(-) create mode 100644 source/flx3d/_internal/TextureView3D.hx diff --git a/source/flx3d/FlxView3D.hx b/source/flx3d/FlxView3D.hx index 11137eed3f..be6bb18f30 100644 --- a/source/flx3d/FlxView3D.hx +++ b/source/flx3d/FlxView3D.hx @@ -1,6 +1,7 @@ package flx3d; #if THREE_D_SUPPORT +import flx3d._internal.TextureView3D; import away3d.containers.View3D; import away3d.library.assets.IAsset; import flixel.FlxG; @@ -18,12 +19,12 @@ import flixel.FlxSprite; class FlxView3D extends FlxSprite { #if THREE_D_SUPPORT - @:noCompletion private var bmp:BitmapData; + @:noCompletion private var bmp:BitmapData = null; /** * The Away3D View */ - public var view:View3D; + public var view:TextureView3D; /** * Set this flag to true to force the View3D to update during the `draw()` call. @@ -41,18 +42,43 @@ class FlxView3D extends FlxSprite public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) { super(x, y); - - view = new View3D(); + view = new TextureView3D(); + view.addCallback = function() { + trace("ADDED"); + bmp = view.bitmap; //new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0); + loadGraphic(bmp); + } view.visible = false; - - view.width = width == -1 ? FlxG.width : width; - view.height = height == -1 ? FlxG.height : height; + //view.width = width == -1 ? FlxG.width : width; + //view.height = height == -1 ? FlxG.height : height; + this.width = width == -1 ? FlxG.width : width; + this.height = height == -1 ? FlxG.height : height; view.backgroundAlpha = 0; FlxG.stage.addChildAt(view, 0); - bmp = new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0); - loadGraphic(bmp); + } + + override function resetHelpers():Void + { + resetFrameSize(); + //resetSizeFromFrame(); // commenting out this shit because it's causing issues + _flashRect2.x = 0; + _flashRect2.y = 0; + + if (graphic != null) + { + _flashRect2.width = graphic.width; + _flashRect2.height = graphic.height; + } + + centerOrigin(); + + if (FlxG.renderBlit) + { + dirty = true; + updateFramePixels(); + } } /** @@ -86,25 +112,33 @@ class FlxView3D extends FlxSprite } } - @:noCompletion override function draw() + override function update(elapsed:Float) { + if (bmp != view.bitmap) { + funkin.backend.system.Logs.warn("FlxView3D bitmaps do not match, correcting..."); + bmp = view.bitmap; + } + + } + + /*@:noCompletion override function draw() { super.draw(); - if (dirty3D) { + view.x = 0; view.visible = false; FlxG.stage.addChildAt(view, 0); var old = FlxG.game.filters; FlxG.game.filters = null; - view.renderer.queueSnapshot(bmp); + //view.renderer.queueSnapshot(bmp); view.render(); FlxG.game.filters = old; FlxG.stage.removeChild(view); } - } + }*/ @:noCompletion override function set_width(newWidth:Float):Float { diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx new file mode 100644 index 0000000000..250f5c34d5 --- /dev/null +++ b/source/flx3d/_internal/TextureView3D.hx @@ -0,0 +1,215 @@ +package flx3d._internal; + +import haxe.CallStack; +import flixel.FlxG; +import haxe.Exception; +import away3d.containers.View3D; +import away3d.containers.Scene3D; +import away3d.cameras.Camera3D; +import away3d.core.render.RendererBase; +import away3d.core.managers.Stage3DManager; +import away3d.core.managers.Stage3DProxy; +import openfl.display3D.textures.TextureBase; +import openfl.display3D.textures.RectangleTexture; +import openfl.display.BitmapData; +import openfl.events.Event; +import openfl.geom.Point; + +// TODO: error when disposing of Stage3DProxy. Possibly related to it using Flixel's stage? + +class TextureView3D extends View3D { + public var bitmap:BitmapData; + private var _framebuffer:TextureBase = null; + private var _initialised:Bool = false; + public var addCallback:() -> Void; + + /*private override function onAddedToStage(event:Event):Void + { + if (_addedToStage) + return; + super.onAddedToStage(event); + trace(_stage3DProxy); + _framebuffer = _stage3DProxy.context3D.createRectangleTexture(Std.int(width), Std.int(height), BGRA, true); + bitmap = BitmapData.fromTexture(_framebuffer); + if (addCallback != null) addCallback(); + }*/ + + public override function dispose() { + _stage3DProxy = null; + super.dispose(); + } + + private override function set_height(value:Float):Float { + //if (_height == value) return value; + trace("height", value); + trace("=====set_height CALLSTACK====="); + trace(CallStack.toString(CallStack.callStack())); + trace("=============================="); + super.set_height(value); + //trace("from: set_height"); + _createFramebuffer(); + return value; + } + private override function set_width(value:Float):Float { + //if (value > 2048) throw new Exception("breakpoint"); + //if (_width == value) return value; + trace("width", value); + trace("=====set_width CALLSTACK====="); + trace(CallStack.toString(CallStack.callStack())); + trace("============================="); + super.set_width(value); + //trace("from: set_width"); + _createFramebuffer(); + return value; + } + + public function new(scene:Scene3D = null, camera:Camera3D = null, renderer:RendererBase = null, forceSoftware:Bool = false, profile:String = "baseline", + contextIndex:Int = -1) { + super(scene, camera, renderer, forceSoftware, profile, contextIndex); + + _stage3DProxy = Stage3DManager.getInstance(FlxG.stage).getStage3DProxy(0); + addEventListener(Event.ENTER_FRAME, _tryCreateFramebuffer); + } + + public function createFramebuffer() { + /*if (!_initialised || width == 0 || height == 0) return; + trace(_width, _height); + _framebuffer = _stage3DProxy.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); + bitmap = BitmapData.fromTexture(_framebuffer); + addCallback();*/ + } + + private function _createFramebuffer() { + if (!_initialised || width == 0 || height == 0) return; + trace(_width, _height); + _framebuffer = _stage3DProxy.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); + bitmap = BitmapData.fromTexture(_framebuffer); + addCallback(); + } + + private function _tryCreateFramebuffer(event:Event) { + if (_initialised) return; + if (_stage3DProxy == null) return; + if (_stage3DProxy.context3D == null) return; + if (_width == 0 || _height == 0) return; + + _initialised = true; + trace("from: _tryCreateFramebuffer"); + _createFramebuffer(); + removeEventListener(Event.ENTER_FRAME, _tryCreateFramebuffer); + } + + /** + * Renders the view. + */ + public override function render():Void + { + Stage3DProxy.drawTriangleCount = 0; + + // if context3D has Disposed by the OS,don't render at this frame + if (stage3DProxy.context3D == null || !stage3DProxy.recoverFromDisposal()) { + _backBufferInvalid = true; + return; + } + + // reset or update render settings + if (_backBufferInvalid) + updateBackBuffer(); + + if (_shareContext && _layeredView) + stage3DProxy.clearDepthBuffer(); + + if (!_parentIsStage) { + var globalPos:Point = parent.localToGlobal(_localTLPos); + if (_globalPos.x != globalPos.x || _globalPos.y != globalPos.y) { + _globalPos = globalPos; + _globalPosDirty = true; + } + } + + if (_globalPosDirty) + updateGlobalPos(); + + updateTime(); + + updateViewSizeData(); + + _entityCollector.clear(); + + // collect stuff to render + _scene.traversePartitions(_entityCollector); + + // update picking + _mouse3DManager.updateCollider(this); + _touch3DManager.updateCollider(); + + if (_requireDepthRender) + renderSceneDepthToTexture(_entityCollector); + + // todo: perform depth prepass after light update and before final render + if (_depthPrepass) + renderDepthPrepass(_entityCollector); + + + @:privateAccess _renderer.clearOnRender = !_depthPrepass; + + if (_filter3DRenderer != null && _stage3DProxy.context3D != null) { + _renderer.render(_entityCollector, _filter3DRenderer.getMainInputTexture(_stage3DProxy), _rttBufferManager.renderToTextureRect); + _filter3DRenderer.render(_stage3DProxy, camera, _depthRender); + } else { + @:privateAccess _renderer.shareContext = _shareContext; + if (_shareContext) + _renderer.render(_entityCollector, _framebuffer, _scissorRect); + else + _renderer.render(_entityCollector, _framebuffer); + } + + if (!_shareContext) { + stage3DProxy.present(); + + // fire collected mouse events + _mouse3DManager.fireMouseEvents(); + _touch3DManager.fireTouchEvents(); + } + + // clean up data for this render + _entityCollector.cleanUp(); + + // register that a view has been rendered + stage3DProxy.bufferClear = false; + } + + private override function updateBackBuffer():Void { + // No reason trying to configure back buffer if there is no context available. + // Doing this anyway (and relying on _stage3DProxy to cache width/height for + // context does get available) means usesSoftwareRendering won't be reliable. + if (_stage3DProxy.context3D != null && !_shareContext) { + if (_globalWidth > 0 && _globalHeight > 0) { + // Backbuffers are limited to 2048x2048 in software mode and + // trying to configure the backbuffer to be bigger than that + // will throw an error. Capping the value is a graceful way of + // avoiding runtime exceptions for developers who are unable + // to test their Away3D implementation on screens that are + // large enough for this error to ever occur. + if (_stage3DProxy.usesSoftwareRendering) { + // Even though these checks where already made in the width + // and height setters, at that point we couldn't be sure that + // the context had even been retrieved and the software flag + // thus be reliable. Make checks again. + if (_globalWidth > 2048) + _globalWidth = 2048; + if (_globalHeight > 2048) + _globalHeight = 2048; + } + + _stage3DProxy.configureBackBuffer(Std.int(_globalWidth), Std.int(_globalHeight), _antiAlias, true); + _backBufferInvalid = false; + } else { + // no. fuck you. + /*var stageBR:Point = new Point(stage.x + stage.stageWidth, stage.y + stage.stageHeight); + width = parent != null ? parent.globalToLocal(stageBR).x - _localTLPos.x : stage.stageWidth; + height = parent != null ? parent.globalToLocal(stageBR).y - _localTLPos.y : stage.stageHeight;*/ + } + } + } +} \ No newline at end of file From f412b3c9df4a84f0a73b75ae992a06cb1a0c6959 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Fri, 9 Jan 2026 23:41:10 +1100 Subject: [PATCH 2/8] Almost done, just need to fix that weird bug where 2 views need to be present to render 3D --- source/flx3d/FlxView3D.hx | 59 ++++++++++------ source/flx3d/_internal/TextureView3D.hx | 93 ++++++++++--------------- 2 files changed, 75 insertions(+), 77 deletions(-) diff --git a/source/flx3d/FlxView3D.hx b/source/flx3d/FlxView3D.hx index be6bb18f30..f8fa03b9d9 100644 --- a/source/flx3d/FlxView3D.hx +++ b/source/flx3d/FlxView3D.hx @@ -15,6 +15,10 @@ import flixel.FlxSprite; * * @author lunarcleint * @see https://twitter.com/lunarcleint + * + * + * @author StrawberrySage + * @see https://twitter.com/StrawberrySage_ */ class FlxView3D extends FlxSprite { @@ -24,13 +28,16 @@ class FlxView3D extends FlxSprite /** * The Away3D View */ - public var view:TextureView3D; + public var view:View3D; + private var _textureView:TextureView3D; /** * Set this flag to true to force the View3D to update during the `draw()` call. */ public var dirty3D:Bool = true; + private var legacyRender:Bool = false; + /** * Creates a new instance of a View3D from Away3D and renders it as a FlxSprite * ! Call Flx3DUtil.is3DAvailable(); to make sure a 3D stage is usable @@ -41,18 +48,32 @@ class FlxView3D extends FlxSprite */ public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) { + // TODO: With new rendering, it seems to only work if 2 or more views are being rendered, hence why it only worked in Funkscop and nothing else. + legacyRender = false; + super(x, y); - view = new TextureView3D(); - view.addCallback = function() { - trace("ADDED"); - bmp = view.bitmap; //new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0); - loadGraphic(bmp); + var setInitialWidth:Bool = false; + if (legacyRender) { + view = new View3D(); + } + else { + _textureView = new TextureView3D(); + _textureView.addCallback = function() { + bmp = _textureView.bitmap; + loadGraphic(bmp); + } + + view = _textureView; } + view.visible = false; - //view.width = width == -1 ? FlxG.width : width; - //view.height = height == -1 ? FlxG.height : height; + this.width = width == -1 ? FlxG.width : width; this.height = height == -1 ? FlxG.height : height; + if (legacyRender) { + bmp = new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0); + loadGraphic(bmp); + } view.backgroundAlpha = 0; FlxG.stage.addChildAt(view, 0); @@ -61,8 +82,12 @@ class FlxView3D extends FlxSprite override function resetHelpers():Void { + if (legacyRender) { + super.resetHelpers(); + return; + } resetFrameSize(); - //resetSizeFromFrame(); // commenting out this shit because it's causing issues + //resetSizeFromFrame(); _flashRect2.x = 0; _flashRect2.y = 0; @@ -112,33 +137,25 @@ class FlxView3D extends FlxSprite } } - override function update(elapsed:Float) { - if (bmp != view.bitmap) { - funkin.backend.system.Logs.warn("FlxView3D bitmaps do not match, correcting..."); - bmp = view.bitmap; - } - - } - - /*@:noCompletion override function draw() + @:noCompletion override function draw() { super.draw(); if (dirty3D) { - view.x = 0; view.visible = false; FlxG.stage.addChildAt(view, 0); var old = FlxG.game.filters; FlxG.game.filters = null; - //view.renderer.queueSnapshot(bmp); + if (legacyRender) + view.renderer.queueSnapshot(bmp); view.render(); FlxG.game.filters = old; FlxG.stage.removeChild(view); } - }*/ + } @:noCompletion override function set_width(newWidth:Float):Float { diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx index 250f5c34d5..afe06c67c0 100644 --- a/source/flx3d/_internal/TextureView3D.hx +++ b/source/flx3d/_internal/TextureView3D.hx @@ -1,6 +1,5 @@ package flx3d._internal; -import haxe.CallStack; import flixel.FlxG; import haxe.Exception; import away3d.containers.View3D; @@ -11,54 +10,35 @@ import away3d.core.managers.Stage3DManager; import away3d.core.managers.Stage3DProxy; import openfl.display3D.textures.TextureBase; import openfl.display3D.textures.RectangleTexture; +import openfl.display3D.Context3D; import openfl.display.BitmapData; import openfl.events.Event; import openfl.geom.Point; -// TODO: error when disposing of Stage3DProxy. Possibly related to it using Flixel's stage? - class TextureView3D extends View3D { public var bitmap:BitmapData; private var _framebuffer:TextureBase = null; private var _initialised:Bool = false; public var addCallback:() -> Void; - /*private override function onAddedToStage(event:Event):Void - { - if (_addedToStage) - return; - super.onAddedToStage(event); - trace(_stage3DProxy); - _framebuffer = _stage3DProxy.context3D.createRectangleTexture(Std.int(width), Std.int(height), BGRA, true); - bitmap = BitmapData.fromTexture(_framebuffer); - if (addCallback != null) addCallback(); - }*/ - - public override function dispose() { + public override function dispose() @:privateAccess{ + /*_stage3DProxy._stage3DManager.removeStage3DProxy(_stage3DProxy); + _stage3DProxy._stage3DIndex = -1; + _stage3DProxy._stage3DManager = null; + _stage3DProxy._stage3D = null;*/ _stage3DProxy = null; super.dispose(); } private override function set_height(value:Float):Float { - //if (_height == value) return value; - trace("height", value); - trace("=====set_height CALLSTACK====="); - trace(CallStack.toString(CallStack.callStack())); - trace("=============================="); + if (_height == value) return value; super.set_height(value); - //trace("from: set_height"); _createFramebuffer(); return value; } private override function set_width(value:Float):Float { - //if (value > 2048) throw new Exception("breakpoint"); - //if (_width == value) return value; - trace("width", value); - trace("=====set_width CALLSTACK====="); - trace(CallStack.toString(CallStack.callStack())); - trace("============================="); + if (_width == value) return value; super.set_width(value); - //trace("from: set_width"); _createFramebuffer(); return value; } @@ -68,37 +48,17 @@ class TextureView3D extends View3D { super(scene, camera, renderer, forceSoftware, profile, contextIndex); _stage3DProxy = Stage3DManager.getInstance(FlxG.stage).getStage3DProxy(0); - addEventListener(Event.ENTER_FRAME, _tryCreateFramebuffer); - } - - public function createFramebuffer() { - /*if (!_initialised || width == 0 || height == 0) return; - trace(_width, _height); - _framebuffer = _stage3DProxy.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); - bitmap = BitmapData.fromTexture(_framebuffer); - addCallback();*/ + _initialised = true; + _createFramebuffer(); } private function _createFramebuffer() { - if (!_initialised || width == 0 || height == 0) return; - trace(_width, _height); - _framebuffer = _stage3DProxy.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); - bitmap = BitmapData.fromTexture(_framebuffer); + if (width == 0 || height == 0) return; + _framebuffer = FlxG.stage.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); + bitmap = BitmapDataCrashFix.fromTextureCrashFix(_framebuffer); addCallback(); } - private function _tryCreateFramebuffer(event:Event) { - if (_initialised) return; - if (_stage3DProxy == null) return; - if (_stage3DProxy.context3D == null) return; - if (_width == 0 || _height == 0) return; - - _initialised = true; - trace("from: _tryCreateFramebuffer"); - _createFramebuffer(); - removeEventListener(Event.ENTER_FRAME, _tryCreateFramebuffer); - } - /** * Renders the view. */ @@ -179,7 +139,9 @@ class TextureView3D extends View3D { stage3DProxy.bufferClear = false; } - private override function updateBackBuffer():Void { + // idk if i need this but i'll keep commented in case removing it breaks anything + + /*private override function updateBackBuffer():Void { // No reason trying to configure back buffer if there is no context available. // Doing this anyway (and relying on _stage3DProxy to cache width/height for // context does get available) means usesSoftwareRendering won't be reliable. @@ -205,11 +167,30 @@ class TextureView3D extends View3D { _stage3DProxy.configureBackBuffer(Std.int(_globalWidth), Std.int(_globalHeight), _antiAlias, true); _backBufferInvalid = false; } else { - // no. fuck you. /*var stageBR:Point = new Point(stage.x + stage.stageWidth, stage.y + stage.stageHeight); width = parent != null ? parent.globalToLocal(stageBR).x - _localTLPos.x : stage.stageWidth; - height = parent != null ? parent.globalToLocal(stageBR).y - _localTLPos.y : stage.stageHeight;*/ + height = parent != null ? parent.globalToLocal(stageBR).y - _localTLPos.y : stage.stageHeight;* / } } + }*/ +} + + +class BitmapDataCrashFix extends BitmapData { + public static function fromTextureCrashFix(texture:TextureBase):BitmapDataCrashFix + @:privateAccess { + if (texture == null) return null; + + var bitmapData = new BitmapDataCrashFix(texture.__width, texture.__height, true, 0); + bitmapData.readable = false; + bitmapData.__texture = texture; + bitmapData.__textureContext = texture.__textureContext; + bitmapData.image = null; + return bitmapData; + } + + @:dox(hide) public override function getTexture(context:Context3D):TextureBase + { + return __texture; } } \ No newline at end of file From 9961b0792786e856bef1da1c540ec2fec2950145 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Sat, 10 Jan 2026 00:04:50 +1100 Subject: [PATCH 3/8] Small optimisations --- source/flx3d/FlxView3D.hx | 19 +++++++++++-------- source/flx3d/_internal/TextureView3D.hx | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/source/flx3d/FlxView3D.hx b/source/flx3d/FlxView3D.hx index f8fa03b9d9..5d67a23664 100644 --- a/source/flx3d/FlxView3D.hx +++ b/source/flx3d/FlxView3D.hx @@ -139,22 +139,25 @@ class FlxView3D extends FlxSprite @:noCompletion override function draw() { - super.draw(); if (dirty3D) { - view.visible = false; - FlxG.stage.addChildAt(view, 0); + if (legacyRender) { + view.visible = false; + FlxG.stage.addChildAt(view, 0); - var old = FlxG.game.filters; - FlxG.game.filters = null; + var old = FlxG.game.filters; + FlxG.game.filters = null; - if (legacyRender) view.renderer.queueSnapshot(bmp); + } view.render(); - FlxG.game.filters = old; - FlxG.stage.removeChild(view); + if (legacyRender) { + FlxG.game.filters = old; + FlxG.stage.removeChild(view); + } } + super.draw(); } @:noCompletion override function set_width(newWidth:Float):Float diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx index afe06c67c0..8297d0dc9e 100644 --- a/source/flx3d/_internal/TextureView3D.hx +++ b/source/flx3d/_internal/TextureView3D.hx @@ -54,6 +54,7 @@ class TextureView3D extends View3D { private function _createFramebuffer() { if (width == 0 || height == 0) return; + if (_framebuffer != null) _framebuffer.dispose(); _framebuffer = FlxG.stage.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); bitmap = BitmapDataCrashFix.fromTextureCrashFix(_framebuffer); addCallback(); From 0b978bd4ab50ee274d2e55b1e85cca4730b2380a Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Sat, 10 Jan 2026 17:54:15 +1100 Subject: [PATCH 4/8] Added temporary fix for rendering with a single view --- source/flx3d/Flx3DCamera.hx | 83 ++++++++++++++--------- source/flx3d/Flx3DView.hx | 73 ++++++++++++-------- source/flx3d/FlxView3D.hx | 89 +++++++++++++------------ source/flx3d/_internal/TextureView3D.hx | 80 +++++++++++++--------- 4 files changed, 192 insertions(+), 133 deletions(-) diff --git a/source/flx3d/Flx3DCamera.hx b/source/flx3d/Flx3DCamera.hx index d4f76229e8..48089857b7 100644 --- a/source/flx3d/Flx3DCamera.hx +++ b/source/flx3d/Flx3DCamera.hx @@ -25,19 +25,25 @@ import flx3d.Flx3DUtil; import haxe.io.Path; import openfl.Assets; #end - import flixel.FlxCamera; -class Flx3DCamera extends FlxCamera { +class Flx3DCamera extends FlxCamera +{ #if THREE_D_SUPPORT private static var __3DIDS:Int = 0; public var view:View3D; var meshes:Array = []; - public function new(X:Int = 0, Y:Int = 0, Width:Int = 0, Height:Int = 0, DefaultZoom:Float = 1) { + + public function new(X:Int = 0, Y:Int = 0, Width:Int = 0, Height:Int = 0, DefaultZoom:Float = 1) + { if (!Flx3DUtil.is3DAvailable()) - throw "[Flx3DCamera] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + "."; + throw "[Flx3DCamera] 3D is not available on this platform. Stages in use: " + + Flx3DUtil.getTotal3D() + + ", Max stages allowed: " + + FlxG.stage.stage3Ds.length + + "."; super(X, Y, Width, Height, DefaultZoom); __cur3DStageID = __3DIDS++; @@ -49,7 +55,8 @@ class Flx3DCamera extends FlxCamera { FlxG.stage.addChild(view); } - public override function render() { + public override function render() + { super.render(); view.x = FlxG.game.x + FlxG.game.scaleX * (flashSprite.x + flashSprite.scaleX * (_scrollRect.x + _scrollRect.scaleX * (_scrollRect.scrollRect.x))); @@ -65,7 +72,8 @@ class Flx3DCamera extends FlxCamera { view.render(); } - public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) { + public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) + { var model = Assets.getBytes(assetPath); if (model == null) throw 'Model at ${assetPath} was not found.'; @@ -79,36 +87,43 @@ class Flx3DCamera extends FlxCamera { if (texturePath != null) material = new TextureMaterial(Cast.bitmapTexture(Assets.getBitmapData(texturePath, true, false)), smoothTexture); - return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) { + return loadData(model, context, switch (Path.extension(assetPath).toLowerCase()) + { case "dae": new DAEParser(); case "md2": new MD2Parser(); case "md5": new MD5MeshParser(); case "awd": new AWDParser(); - default: new OBJParser(); - }, (event:Asset3DEvent) -> { - if (event.asset != null && event.asset.assetType == Asset3DType.MESH) { - var mesh:Mesh = cast event.asset; - if (material != null) - mesh.material = material; - meshes.push(mesh); - } - callback(event); - }); + default: new OBJParser(); + }, (event:Asset3DEvent) -> + { + if (event.asset != null && event.asset.assetType == Asset3DType.MESH) + { + var mesh:Mesh = cast event.asset; + if (material != null) + mesh.material = material; + meshes.push(mesh); + } + callback(event); + }); } private var __cur3DStageID:Int; private var _loaders:Map = []; - private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken { + private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken + { var token:AssetLoaderToken; var lib:Asset3DLibraryBundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); token = lib.loadData(data, context, null, parser); - token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> { + token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> + { // ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232 - if (event.type == Asset3DEvent.ASSET_COMPLETE) { - var obj:ObjectContainer3D = switch (event.asset.assetType) { + if (event.type == Asset3DEvent.ASSET_COMPLETE) + { + var obj:ObjectContainer3D = switch (event.asset.assetType) + { case Asset3DType.LIGHT: expect(event.asset, LightBase); case Asset3DType.CONTAINER: expect(event.asset, ObjectContainer3D); case Asset3DType.MESH: expect(event.asset, Mesh); @@ -126,25 +141,29 @@ class Flx3DCamera extends FlxCamera { onAssetCallback(event); }); - token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> { + token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> + { trace("Loader Finished..."); }); - _loaders.set(lib,token); + _loaders.set(lib, token); return token; } - override function destroy() { + override function destroy() + { if (meshes != null) - for(mesh in meshes) + for (mesh in meshes) mesh.dispose(); var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); bundle.stopAllLoadingSessions(); @:privateAccess { - if (bundle._loadingSessions != null) { - for(load in bundle._loadingSessions) { + if (bundle._loadingSessions != null) + { + for (load in bundle._loadingSessions) + { load.dispose(); } } @@ -152,10 +171,12 @@ class Flx3DCamera extends FlxCamera { } FlxG.stage.removeChild(view); - try { + try + { view.dispose(); - } catch(e) { - + } + catch (e) + { } super.destroy(); @@ -164,4 +185,4 @@ class Flx3DCamera extends FlxCamera { public function addChild(c) view.scene.addChild(c); #end -} \ No newline at end of file +} diff --git a/source/flx3d/Flx3DView.hx b/source/flx3d/Flx3DView.hx index 59413e77db..9004d27af8 100644 --- a/source/flx3d/Flx3DView.hx +++ b/source/flx3d/Flx3DView.hx @@ -25,20 +25,27 @@ import away3d.utils.Utils.expect; #end // FlxView3D with helpers for easier updating -class Flx3DView extends FlxView3D { +class Flx3DView extends FlxView3D +{ #if THREE_D_SUPPORT private static var __3DIDS:Int = 0; var meshes:Array = []; - public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) { + + public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) + { if (!Flx3DUtil.is3DAvailable()) - throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getUsed3D() + ", Max stages allowed: " + Flx3DUtil.getTotal3D() + "."; + throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + + Flx3DUtil.getUsed3D() + + ", Max stages allowed: " + + Flx3DUtil.getTotal3D() + + "."; super(x, y, width, height); __cur3DStageID = __3DIDS++; } - public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) { - + public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) + { var model = Assets.getBytes(assetPath); if (model == null) throw 'Model at ${assetPath} was not found.'; @@ -52,37 +59,44 @@ class Flx3DView extends FlxView3D { if (texturePath != null) material = new TextureMaterial(Cast.bitmapTexture(Assets.getBitmapData(texturePath, true, false)), smoothTexture); - return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) { + return loadData(model, context, switch (Path.extension(assetPath).toLowerCase()) + { case "dae": new DAEParser(); case "md2": new MD2Parser(); case "md5": new MD5MeshParser(); case "awd": new AWDParser(); - default: new OBJParser(); - }, (event:Asset3DEvent) -> { - if (event.asset != null && event.asset.assetType == Asset3DType.MESH) { - var mesh:Mesh = cast event.asset; - if (material != null) - mesh.material = material; - meshes.push(mesh); - } - callback(event); - }); + default: new OBJParser(); + }, (event:Asset3DEvent) -> + { + if (event.asset != null && event.asset.assetType == Asset3DType.MESH) + { + var mesh:Mesh = cast event.asset; + if (material != null) + mesh.material = material; + meshes.push(mesh); + } + callback(event); + }); } private var __cur3DStageID:Int; private var _loaders:Map = []; - private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken { + private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken + { var token:AssetLoaderToken; var lib:Asset3DLibraryBundle; lib = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); token = lib.loadData(data, context, null, parser); - token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> { + token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> + { // ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232 - if (event.type == Asset3DEvent.ASSET_COMPLETE) { - var obj:ObjectContainer3D = switch (event.asset.assetType) { + if (event.type == Asset3DEvent.ASSET_COMPLETE) + { + var obj:ObjectContainer3D = switch (event.asset.assetType) + { case Asset3DType.LIGHT: expect(event.asset, LightBase); case Asset3DType.CONTAINER: expect(event.asset, ObjectContainer3D); case Asset3DType.MESH: expect(event.asset, Mesh); @@ -100,26 +114,29 @@ class Flx3DView extends FlxView3D { onAssetCallback(event); }); - token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> { + token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> + { trace("Loader Finished..."); - }); - _loaders.set(lib,token); + _loaders.set(lib, token); return token; } - override function destroy() { + override function destroy() + { if (meshes != null) - for(mesh in meshes) + for (mesh in meshes) mesh.dispose(); var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}'); bundle.stopAllLoadingSessions(); @:privateAccess { - if (bundle._loadingSessions != null) { - for(load in bundle._loadingSessions) { + if (bundle._loadingSessions != null) + { + for (load in bundle._loadingSessions) + { load.dispose(); } } @@ -132,4 +149,4 @@ class Flx3DView extends FlxView3D { public function addChild(c) view.scene.addChild(c); #end -} \ No newline at end of file +} diff --git a/source/flx3d/FlxView3D.hx b/source/flx3d/FlxView3D.hx index 5d67a23664..e7e23df694 100644 --- a/source/flx3d/FlxView3D.hx +++ b/source/flx3d/FlxView3D.hx @@ -24,20 +24,45 @@ class FlxView3D extends FlxSprite { #if THREE_D_SUPPORT @:noCompletion private var bmp:BitmapData = null; + private var _textureView:TextureView3D; + private var legacyRender:Bool = false; + + // With new rendering, it seems to only work if 2 or more views are being rendered. + // This workaround creates a second instance if there is only one view. + // "There is nothing more permanent than a temporary solution" + // -idk who said this i just wanted to quote it + private static var workaroundInstance:FlxView3D; + private static var createdWorkaround:Bool = false; + + private inline function createWorkaround() + { + if (!createdWorkaround && !legacyRender) + { + createdWorkaround = true; + workaroundInstance = new FlxView3D(0, 0, 1, 1); + FlxG.state.add(workaroundInstance); + } + } + + private inline function destroyWorkaround() + { + if (workaroundInstance == this) + { + workaroundInstance = null; + createdWorkaround = false; + } + } /** * The Away3D View */ public var view:View3D; - private var _textureView:TextureView3D; /** * Set this flag to true to force the View3D to update during the `draw()` call. */ public var dirty3D:Bool = true; - private var legacyRender:Bool = false; - /** * Creates a new instance of a View3D from Away3D and renders it as a FlxSprite * ! Call Flx3DUtil.is3DAvailable(); to make sure a 3D stage is usable @@ -48,29 +73,31 @@ class FlxView3D extends FlxSprite */ public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) { - // TODO: With new rendering, it seems to only work if 2 or more views are being rendered, hence why it only worked in Funkscop and nothing else. legacyRender = false; super(x, y); - var setInitialWidth:Bool = false; - if (legacyRender) { + if (legacyRender) + { view = new View3D(); } - else { + else + { _textureView = new TextureView3D(); - _textureView.addCallback = function() { - bmp = _textureView.bitmap; + _textureView.onUpdateBitmap = function(bitmap) + { + bmp = bitmap; loadGraphic(bmp); } view = _textureView; } - + view.visible = false; this.width = width == -1 ? FlxG.width : width; this.height = height == -1 ? FlxG.height : height; - if (legacyRender) { + if (legacyRender) + { bmp = new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0); loadGraphic(bmp); } @@ -78,32 +105,7 @@ class FlxView3D extends FlxSprite view.backgroundAlpha = 0; FlxG.stage.addChildAt(view, 0); - } - - override function resetHelpers():Void - { - if (legacyRender) { - super.resetHelpers(); - return; - } - resetFrameSize(); - //resetSizeFromFrame(); - _flashRect2.x = 0; - _flashRect2.y = 0; - - if (graphic != null) - { - _flashRect2.width = graphic.width; - _flashRect2.height = graphic.height; - } - - centerOrigin(); - - if (FlxG.renderBlit) - { - dirty = true; - updateFramePixels(); - } + createWorkaround(); } /** @@ -135,13 +137,16 @@ class FlxView3D extends FlxSprite view.dispose(); view = null; } + + destroyWorkaround(); } @:noCompletion override function draw() { if (dirty3D) { - if (legacyRender) { + if (legacyRender) + { view.visible = false; FlxG.stage.addChildAt(view, 0); @@ -149,13 +154,15 @@ class FlxView3D extends FlxSprite FlxG.game.filters = null; view.renderer.queueSnapshot(bmp); - } - view.render(); + view.render(); - if (legacyRender) { FlxG.game.filters = old; FlxG.stage.removeChild(view); } + else + { + view.render(); + } } super.draw(); } diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx index 8297d0dc9e..769171a396 100644 --- a/source/flx3d/_internal/TextureView3D.hx +++ b/source/flx3d/_internal/TextureView3D.hx @@ -15,60 +15,70 @@ import openfl.display.BitmapData; import openfl.events.Event; import openfl.geom.Point; -class TextureView3D extends View3D { +class TextureView3D extends View3D +{ public var bitmap:BitmapData; + private var _framebuffer:TextureBase = null; private var _initialised:Bool = false; - public var addCallback:() -> Void; - - public override function dispose() @:privateAccess{ - /*_stage3DProxy._stage3DManager.removeStage3DProxy(_stage3DProxy); - _stage3DProxy._stage3DIndex = -1; - _stage3DProxy._stage3DManager = null; - _stage3DProxy._stage3D = null;*/ + + public var onUpdateBitmap:(BitmapData) -> Void; + + public override function dispose() @:privateAccess { + // prevents the game from disposing flixel's stage3D/context3D _stage3DProxy = null; super.dispose(); } - private override function set_height(value:Float):Float { - if (_height == value) return value; + private override function set_height(value:Float):Float + { + if (_height == value) + return value; super.set_height(value); _createFramebuffer(); return value; } - private override function set_width(value:Float):Float { - if (_width == value) return value; + + private override function set_width(value:Float):Float + { + if (_width == value) + return value; super.set_width(value); _createFramebuffer(); return value; } public function new(scene:Scene3D = null, camera:Camera3D = null, renderer:RendererBase = null, forceSoftware:Bool = false, profile:String = "baseline", - contextIndex:Int = -1) { + contextIndex:Int = -1) + { super(scene, camera, renderer, forceSoftware, profile, contextIndex); - + _stage3DProxy = Stage3DManager.getInstance(FlxG.stage).getStage3DProxy(0); _initialised = true; _createFramebuffer(); } - private function _createFramebuffer() { - if (width == 0 || height == 0) return; - if (_framebuffer != null) _framebuffer.dispose(); + private function _createFramebuffer() + { + if (width == 0 || height == 0) + return; + if (_framebuffer != null) + _framebuffer.dispose(); _framebuffer = FlxG.stage.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true); bitmap = BitmapDataCrashFix.fromTextureCrashFix(_framebuffer); - addCallback(); + onUpdateBitmap(bitmap); } /** * Renders the view. */ - public override function render():Void + public override function render():Void { Stage3DProxy.drawTriangleCount = 0; // if context3D has Disposed by the OS,don't render at this frame - if (stage3DProxy.context3D == null || !stage3DProxy.recoverFromDisposal()) { + if (stage3DProxy.context3D == null || !stage3DProxy.recoverFromDisposal()) + { _backBufferInvalid = true; return; } @@ -80,9 +90,11 @@ class TextureView3D extends View3D { if (_shareContext && _layeredView) stage3DProxy.clearDepthBuffer(); - if (!_parentIsStage) { + if (!_parentIsStage) + { var globalPos:Point = parent.localToGlobal(_localTLPos); - if (_globalPos.x != globalPos.x || _globalPos.y != globalPos.y) { + if (_globalPos.x != globalPos.x || _globalPos.y != globalPos.y) + { _globalPos = globalPos; _globalPosDirty = true; } @@ -111,13 +123,15 @@ class TextureView3D extends View3D { if (_depthPrepass) renderDepthPrepass(_entityCollector); - @:privateAccess _renderer.clearOnRender = !_depthPrepass; - if (_filter3DRenderer != null && _stage3DProxy.context3D != null) { + if (_filter3DRenderer != null && _stage3DProxy.context3D != null) + { _renderer.render(_entityCollector, _filter3DRenderer.getMainInputTexture(_stage3DProxy), _rttBufferManager.renderToTextureRect); _filter3DRenderer.render(_stage3DProxy, camera, _depthRender); - } else { + } + else + { @:privateAccess _renderer.shareContext = _shareContext; if (_shareContext) _renderer.render(_entityCollector, _framebuffer, _scissorRect); @@ -125,7 +139,8 @@ class TextureView3D extends View3D { _renderer.render(_entityCollector, _framebuffer); } - if (!_shareContext) { + if (!_shareContext) + { stage3DProxy.present(); // fire collected mouse events @@ -141,7 +156,6 @@ class TextureView3D extends View3D { } // idk if i need this but i'll keep commented in case removing it breaks anything - /*private override function updateBackBuffer():Void { // No reason trying to configure back buffer if there is no context available. // Doing this anyway (and relying on _stage3DProxy to cache width/height for @@ -176,11 +190,11 @@ class TextureView3D extends View3D { }*/ } - -class BitmapDataCrashFix extends BitmapData { - public static function fromTextureCrashFix(texture:TextureBase):BitmapDataCrashFix - @:privateAccess { - if (texture == null) return null; +class BitmapDataCrashFix extends BitmapData +{ + public static function fromTextureCrashFix(texture:TextureBase):BitmapDataCrashFix @:privateAccess { + if (texture == null) + return null; var bitmapData = new BitmapDataCrashFix(texture.__width, texture.__height, true, 0); bitmapData.readable = false; @@ -194,4 +208,4 @@ class BitmapDataCrashFix extends BitmapData { { return __texture; } -} \ No newline at end of file +} From f5d508b1d663ae5fa3c7c740f8cdf008eb6bbc01 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Sat, 10 Jan 2026 17:59:24 +1100 Subject: [PATCH 5/8] removed myself from the authors --- source/flx3d/FlxView3D.hx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/flx3d/FlxView3D.hx b/source/flx3d/FlxView3D.hx index e7e23df694..b07b78e213 100644 --- a/source/flx3d/FlxView3D.hx +++ b/source/flx3d/FlxView3D.hx @@ -15,10 +15,6 @@ import flixel.FlxSprite; * * @author lunarcleint * @see https://twitter.com/lunarcleint - * - * - * @author StrawberrySage - * @see https://twitter.com/StrawberrySage_ */ class FlxView3D extends FlxSprite { From d699fde78b2e81302cbf82a31e23e31b9b27c713 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Sun, 11 Jan 2026 10:43:22 +1100 Subject: [PATCH 6/8] Removing it in fact did not break anything (removed commented out block of code) --- source/flx3d/_internal/TextureView3D.hx | 34 ------------------------- 1 file changed, 34 deletions(-) diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx index 769171a396..7e1c2b6a1a 100644 --- a/source/flx3d/_internal/TextureView3D.hx +++ b/source/flx3d/_internal/TextureView3D.hx @@ -154,40 +154,6 @@ class TextureView3D extends View3D // register that a view has been rendered stage3DProxy.bufferClear = false; } - - // idk if i need this but i'll keep commented in case removing it breaks anything - /*private override function updateBackBuffer():Void { - // No reason trying to configure back buffer if there is no context available. - // Doing this anyway (and relying on _stage3DProxy to cache width/height for - // context does get available) means usesSoftwareRendering won't be reliable. - if (_stage3DProxy.context3D != null && !_shareContext) { - if (_globalWidth > 0 && _globalHeight > 0) { - // Backbuffers are limited to 2048x2048 in software mode and - // trying to configure the backbuffer to be bigger than that - // will throw an error. Capping the value is a graceful way of - // avoiding runtime exceptions for developers who are unable - // to test their Away3D implementation on screens that are - // large enough for this error to ever occur. - if (_stage3DProxy.usesSoftwareRendering) { - // Even though these checks where already made in the width - // and height setters, at that point we couldn't be sure that - // the context had even been retrieved and the software flag - // thus be reliable. Make checks again. - if (_globalWidth > 2048) - _globalWidth = 2048; - if (_globalHeight > 2048) - _globalHeight = 2048; - } - - _stage3DProxy.configureBackBuffer(Std.int(_globalWidth), Std.int(_globalHeight), _antiAlias, true); - _backBufferInvalid = false; - } else { - /*var stageBR:Point = new Point(stage.x + stage.stageWidth, stage.y + stage.stageHeight); - width = parent != null ? parent.globalToLocal(stageBR).x - _localTLPos.x : stage.stageWidth; - height = parent != null ? parent.globalToLocal(stageBR).y - _localTLPos.y : stage.stageHeight;* / - } - } - }*/ } class BitmapDataCrashFix extends BitmapData From 2d24df304a5fcd3bbc5f9dd45a7e8cdd554f2a47 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Sun, 11 Jan 2026 10:54:58 +1100 Subject: [PATCH 7/8] Removed a useless variable and improved formatting on a comment --- source/flx3d/_internal/TextureView3D.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx index 7e1c2b6a1a..39df445958 100644 --- a/source/flx3d/_internal/TextureView3D.hx +++ b/source/flx3d/_internal/TextureView3D.hx @@ -20,12 +20,13 @@ class TextureView3D extends View3D public var bitmap:BitmapData; private var _framebuffer:TextureBase = null; - private var _initialised:Bool = false; public var onUpdateBitmap:(BitmapData) -> Void; + /** + * Prevents the enging from disposing Flixel's Stage3D/Context3D instance + */ public override function dispose() @:privateAccess { - // prevents the game from disposing flixel's stage3D/context3D _stage3DProxy = null; super.dispose(); } @@ -54,7 +55,6 @@ class TextureView3D extends View3D super(scene, camera, renderer, forceSoftware, profile, contextIndex); _stage3DProxy = Stage3DManager.getInstance(FlxG.stage).getStage3DProxy(0); - _initialised = true; _createFramebuffer(); } From 1a942437b2d4c32ffd76c5fc73bd75fe6cc0be23 Mon Sep 17 00:00:00 2001 From: kitzsh <110337474+kitzsh@users.noreply.github.com> Date: Sun, 11 Jan 2026 10:57:06 +1100 Subject: [PATCH 8/8] Aw dang it --- source/flx3d/_internal/TextureView3D.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx index 39df445958..efce9b9a4f 100644 --- a/source/flx3d/_internal/TextureView3D.hx +++ b/source/flx3d/_internal/TextureView3D.hx @@ -24,7 +24,7 @@ class TextureView3D extends View3D public var onUpdateBitmap:(BitmapData) -> Void; /** - * Prevents the enging from disposing Flixel's Stage3D/Context3D instance + * Prevents the engine from disposing Flixel's Stage3D/Context3D instance */ public override function dispose() @:privateAccess { _stage3DProxy = null;