Skip to content

Commit

Permalink
Suport uploading ATFTextureData::CompressedRawAlpha
Browse files Browse the repository at this point in the history
Fortunately, this is very simple - we can just take
the DXT5 data and upload it directly to the wgpu texture.
  • Loading branch information
Aaron1011 authored and Dinnerbone committed Nov 10, 2023
1 parent 2cb1efc commit 7110be9
Show file tree
Hide file tree
Showing 15 changed files with 209 additions and 2 deletions.
22 changes: 22 additions & 0 deletions core/src/avm2/globals/flash/display3D/textures/atf_jpegxr.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::avm2::bytearray::ByteArrayStorage;
use crate::avm2::object::TextureObject;
use crate::avm2::Activation;
use crate::avm2::Error;
use crate::avm2::Object;
use crate::avm2::TObject;
use crate::avm2_stub_method;
use ruffle_render::atf::ATFTexture;
use ruffle_render::atf::ATFTextureData;
use std::io::Cursor;
Expand All @@ -12,6 +14,7 @@ use std::io::Read;
use std::io::Seek;

pub fn do_compressed_upload<'gc>(
activation: &mut Activation<'_, 'gc>,
texture: TextureObject<'gc>,
data: Object<'gc>,
byte_array_offset: usize,
Expand Down Expand Up @@ -142,6 +145,25 @@ pub fn do_compressed_upload<'gc>(

reconstructed_dxt
}
ATFTextureData::CompressedRawAlpha {
dxt5,
pvrtc: _,
etc1: _,
etc2: _,
} => {
// DXT5 seems to be the most widely supported, so let's use that for now.
// TODO - fallback to other formats if DXT5 data isn't present
// (or if we're on Android/iOS).
if dxt5.is_empty() {
avm2_stub_method!(
activation,
"flash.display3D.textures.Texture",
"uploadCompressedTextureFromByteArray",
"with empty DXT5 data in CompressedRawAlpha"
);
}
dxt5.clone()
}
ATFTextureData::Unknown(_) => {
return Err(format!("Unsupported ATF format: {:?}", atf_texture.format).into())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::avm2::object::TextureObject;
use crate::avm2::Activation;
use crate::avm2::Error;
use crate::avm2::Object;

pub fn do_compressed_upload<'gc>(
_: &mut Activation<'_, 'gc>,
_: TextureObject<'gc>,
_: Object<'gc>,
_: usize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub fn upload_compressed_texture_from_byte_array<'gc>(
return Ok(Value::Undefined);
}

do_compressed_upload(texture, data, byte_array_offset, true)?;
do_compressed_upload(activation, texture, data, byte_array_offset, true)?;
Ok(Value::Undefined)
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/flash/display3D/textures/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn upload_compressed_texture_from_byte_array_internal<'gc>(
return Ok(Value::Undefined);
}

do_compressed_upload(texture, data, byte_array_offset, false)?;
do_compressed_upload(activation, texture, data, byte_array_offset, false)?;

Ok(Value::Undefined)
}
Expand Down
30 changes: 30 additions & 0 deletions render/src/atf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ pub enum ATFTextureData {
jpegxr_bgr: Vec<u8>,
dxt5_rgb_compressed: Vec<u8>,
},
CompressedRawAlpha {
dxt5: Vec<u8>,
pvrtc: Vec<u8>,
etc1: Vec<u8>,
etc2: Vec<u8>,
},
}

#[derive(FromPrimitive, Debug)]
Expand Down Expand Up @@ -134,6 +140,30 @@ impl ATFTexture {
dxt5_rgb_compressed,
});
}
ATFFormat::RawCompressedAlpha => {
let dxt5_len = read_len(bytes)? as usize;
let mut dxt5 = vec![0; dxt5_len];
bytes.read_exact(&mut dxt5)?;

let pvrtc_len = read_len(bytes)? as usize;
let mut pvrtc = vec![0; pvrtc_len];
bytes.read_exact(&mut pvrtc)?;

let etc1_len = read_len(bytes)? as usize;
let mut etc1 = vec![0; etc1_len];
bytes.read_exact(&mut etc1)?;

let etc2_len = read_len(bytes)? as usize;
let mut etc2 = vec![0; etc2_len];
bytes.read_exact(&mut etc2)?;

face_mip_data[face].push(ATFTextureData::CompressedRawAlpha {
dxt5,
pvrtc,
etc1,
etc2,
});
}
_ => {
// All of the formats consist of a number of (u32_length, data[u32_length]) records.
// For now, we just combine them into a single buffer to allow parsing to succeed.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package {
import com.adobe.utils.AGALMiniAssembler;

import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DCompareMode;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DStencilAction;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.Context3DTextureFilter;
import flash.display3D.Context3DWrapMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.utils.Timer;
import flash.display.MovieClip;
import flash.display.Stage;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.utils.ByteArray;

// Based on example from https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display3D/Context3D.html#setStencilActions
public class Test extends MovieClip {
public const viewWidth:Number = 500;
public const viewHeight:Number = 500;

private var stage3D:Stage3D;
private var renderContext:Context3D;
private var indexList:IndexBuffer3D;
private var vertexes:VertexBuffer3D;

private const VERTEX_SHADER:String =
"add op, va0, vc0 \n" + // copy position to output, adding offset
"mov v0, va1"; // copy uv to varying variable v0

private const FRAGMENT_SHADER:String =
"tex oc, v0, fs0 <2d,clamp,linear,mipnone,dxt5>";

private var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler(false);
private var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler(false);
private var programPair:Program3D;

[Embed(source = "ruffle_logo.atf", mimeType = "application/octet-stream")]
public var RUFFLE_LOGO: Class;

[Embed(source = "circle.atf", mimeType = "application/octet-stream")]
public var CIRCLE_ATF: Class;

public function Test() {
stage3D = this.stage.stage3Ds[0];

// Add event listener before requesting the context
stage3D.addEventListener(Event.CONTEXT3D_CREATE, contextCreated);
stage3D.requestContext3D(Context3DRenderMode.AUTO, "standard");

// Compile shaders
vertexAssembly.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER, 2);
fragmentAssembly.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER, 2);
}

// Note, context3DCreate event can happen at any time, such as when the hardware resources are taken by another process
private function contextCreated(event:Event):void {
renderContext = Stage3D(event.target).context3D;

renderContext.enableErrorChecking = true; // Can slow rendering - only turn on when developing/testing
renderContext.configureBackBuffer(viewWidth, viewHeight, 4, true);

// Create vertex index list for the triangles
var triangles:Vector.<uint> = Vector.<uint>([0, 1, 2, 0, 2, 3]);
indexList = renderContext.createIndexBuffer(triangles.length);
indexList.uploadFromVector(triangles, 0, triangles.length);

// Create vertexes
const dataPerVertex:int = 5;
var vertexData:Vector.<Number> = Vector.<Number>(
[
// x, y, z u, v
0, 0, 0, 0, 1,
0.5, 0, 0, 1, 1,
0.5, 0.5, 0, 1, 0,
0, 0.5, 0, 0, 0
]);
vertexes = renderContext.createVertexBuffer(vertexData.length / dataPerVertex, dataPerVertex);
vertexes.uploadFromVector(vertexData, 0, vertexData.length / dataPerVertex);

// Identify vertex data inputs for vertex program
renderContext.setVertexBufferAt(0, vertexes, 0, Context3DVertexBufferFormat.FLOAT_3); // va0 is position
renderContext.setVertexBufferAt(1, vertexes, 3, Context3DVertexBufferFormat.FLOAT_2); // va1 is texture uv coords

var logo: ByteArray = new RUFFLE_LOGO();
var logoAtfTexture = renderContext.createTexture(512, 512, Context3DTextureFormat.COMPRESSED_ALPHA , false);
logoAtfTexture.uploadCompressedTextureFromByteArray(logo, 0);

renderContext.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
// Upload programs to render context
programPair = renderContext.createProgram();
programPair.upload(vertexAssembly.agalcode, fragmentAssembly.agalcode);
renderContext.setProgram(programPair);

var circleATF: ByteArray = new CIRCLE_ATF();
var atfTexture = renderContext.createTexture(512, 512, Context3DTextureFormat.COMPRESSED_ALPHA , false);
atfTexture.uploadCompressedTextureFromByteArray(circleATF, 0);


// Clear, setting stencil to 0
renderContext.clear(.3, .3, .3, 1, 1, 0);


renderContext.setTextureAt(0, logoAtfTexture);
renderContext.setProgramConstantsFromVector("vertex", 0, Vector.<Number>([-0.7, 0.5, 0.0, 0.0]));
renderContext.drawTriangles(indexList, 0, 2);

renderContext.setTextureAt(0, atfTexture);
renderContext.setProgramConstantsFromVector("vertex", 0, Vector.<Number>([0.0, 0.5, 0.0, 0.0]));
renderContext.drawTriangles(indexList, 0, 2);


renderContext.present();

// this.addChild(new Bitmap(redGreen));
}
}
}
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
num_frames = 1

[image_comparisons.output]
tolerance = 2
max_outliers = 66

[player_options]
with_renderer = { optional = false, sample_count = 1 }

[required_features]
jpegxr = true

# Textures were generated with:
# png2atf.exe -i ruffle_logo.png -c d -o ruffle_logo.atf
# png2atf.exe -i circle.png -c d -o circle.atf

0 comments on commit 7110be9

Please sign in to comment.