Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions core/src/avm2/globals/flash/display3D/Context3D.as
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,19 @@ package flash.display3D {
return 2048;
}

public function setStencilReferenceValue(referenceValue:uint, readMask:uint = 255, writeMask:uint = 255):void {
stub_method("flash.display3D.Context3D", "setStencilReferenceValue");
}
public native function setStencilReferenceValue(referenceValue:uint, readMask:uint = 255, writeMask:uint = 255):void;

public native function setSamplerStateAt(sampler:int, wrap:String, filter:String, mipfilter:String):void;

public native function setRenderToTexture(texture:TextureBase, enableDepthAndStencil:Boolean = false, antiAlias:int = 0, surfaceSelector:int = 0, colorOutputIndex:int = 0):void;

public function setStencilActions(
public native function setStencilActions(
triangleFace:String = "frontAndBack",
compareMode:String = "always",
actionOnBothPass:String = "keep",
actionOnDepthFail:String = "keep",
actionOnDepthPassStencilFail:String = "keep"
):void {
stub_method("flash.display3D.Context3D", "setStencilActions");
}
):void;

public native function dispose(recreate:Boolean = true):void;
}
Expand Down
196 changes: 118 additions & 78 deletions core/src/avm2/globals/flash/display3D/context_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ use crate::avm2::TObject as _;
use crate::avm2::Value;
use crate::avm2_stub_method;
use ruffle_macros::istr;
use ruffle_render::backend::Context3DWrapMode;
use ruffle_render::backend::{
BufferUsage, Context3DBlendFactor, Context3DCompareMode, Context3DTextureFormat,
Context3DTriangleFace, Context3DVertexBufferFormat, ProgramType,
};
use ruffle_render::backend::{BufferUsage, Context3DTriangleFace};
use ruffle_render::backend::{Context3DProfile, Context3DTextureFilter};
use swf::{Rectangle, Twips};

Expand Down Expand Up @@ -166,25 +162,18 @@ pub fn set_vertex_buffer_at<'gc>(

let buffer = if let Some(buffer) = buffer {
// Note - we only check the format string if the buffer is non-null
let format = args.get_string(activation, 3)?;

let format = if &*format == b"float4" {
Context3DVertexBufferFormat::Float4
} else if &*format == b"float3" {
Context3DVertexBufferFormat::Float3
} else if &*format == b"float2" {
Context3DVertexBufferFormat::Float2
} else if &*format == b"float1" {
Context3DVertexBufferFormat::Float1
} else if &*format == b"bytes4" {
Context3DVertexBufferFormat::Bytes4
} else {
return Err(Error::avm_error(argument_error(
let format = args.get_string(activation, 3)?.parse().map_err(|_| {
let argument_error = argument_error(
activation,
"Error #2008: Parameter vertexStreamFormat must be one of the accepted values.",
2008,
)?));
};
);

match argument_error {
Ok(value) => Error::avm_error(value),
Err(err) => err,
}
})?;

Some((buffer.as_vertex_buffer().unwrap(), format))
} else {
Expand Down Expand Up @@ -293,18 +282,10 @@ pub fn set_culling<'gc>(
if let Some(context) = this.as_context_3d() {
let culling = args.get_string(activation, 0)?;

let culling = if &*culling == b"none" {
Context3DTriangleFace::None
} else if &*culling == b"back" {
Context3DTriangleFace::Back
} else if &*culling == b"front" {
Context3DTriangleFace::Front
} else if &*culling == b"frontAndBack" {
Context3DTriangleFace::FrontAndBack
} else {
tracing::error!("Unknown culling {:?}", culling);
Context3DTriangleFace::None
};
let culling = culling
.parse()
.inspect_err(|_| tracing::error!("Unknown culling {:?}", culling))
.unwrap_or(Context3DTriangleFace::None);

context.set_culling(culling);
}
Expand All @@ -320,14 +301,9 @@ pub fn set_program_constants_from_matrix<'gc>(

if let Some(context) = this.as_context_3d() {
let program_type = args.get_string(activation, 0)?;

let is_vertex = if &*program_type == b"vertex" {
ProgramType::Vertex
} else if &*program_type == b"fragment" {
ProgramType::Fragment
} else {
panic!("Unknown program type {program_type:?}");
};
let program_type = program_type
.parse()
.unwrap_or_else(|_| panic!("Unknown program type {program_type:?}"));

let first_register = args.get_u32(activation, 1)?;

Expand Down Expand Up @@ -363,7 +339,7 @@ pub fn set_program_constants_from_matrix<'gc>(
.map(|val| val.as_f64() as f32)
.collect::<Vec<f32>>();

context.set_program_constants_from_matrix(is_vertex, first_register, matrix_raw_data);
context.set_program_constants_from_matrix(program_type, first_register, matrix_raw_data);
}
Ok(Value::Undefined)
}
Expand All @@ -377,14 +353,9 @@ pub fn set_program_constants_from_vector<'gc>(

if let Some(context) = this.as_context_3d() {
let program_type = args.get_string(activation, 0)?;

let program_type = if &*program_type == b"vertex" {
ProgramType::Vertex
} else if &*program_type == b"fragment" {
ProgramType::Fragment
} else {
panic!("Unknown program type {program_type:?}");
};
let program_type = program_type
.parse()
.unwrap_or_else(|_| panic!("Unknown program type {program_type:?}"));

let first_register = args.get_u32(activation, 1)?;

Expand Down Expand Up @@ -444,11 +415,12 @@ pub fn create_texture<'gc>(
// This is a native method, so all of the arguments have been checked and coerced for us
let width = args.get_i32(activation, 0)? as u32;
let height = args.get_i32(activation, 1)? as u32;
let format = args.get_string_non_null(activation, 2, "textureFormat")?;
let format = args
.get_string_non_null(activation, 2, "textureFormat")?
.parse()
.map_err(|_| make_error_2008(activation, "textureFormat"))?;
let optimize_for_render_to_texture = args.get_bool(3);
let streaming_levels = args.get_i32(activation, 4)? as u32;
let format = Context3DTextureFormat::from_wstr(&format)
.ok_or_else(|| make_error_2008(activation, "textureFormat"))?;

let class = activation.avm2().classes().texture;

Expand Down Expand Up @@ -476,10 +448,11 @@ pub fn create_rectangle_texture<'gc>(
// This is a native method, so all of the arguments have been checked and coerced for us
let width = args.get_i32(activation, 0)? as u32;
let height = args.get_i32(activation, 1)? as u32;
let format = args.get_string_non_null(activation, 2, "textureFormat")?;
let format = args
.get_string_non_null(activation, 2, "textureFormat")?
.parse()
.map_err(|_| make_error_2008(activation, "textureFormat"))?;
let optimize_for_render_to_texture = args.get_bool(3);
let format = Context3DTextureFormat::from_wstr(&format)
.ok_or_else(|| make_error_2008(activation, "textureFormat"))?;

let class = activation.avm2().classes().rectangletexture;

Expand All @@ -506,11 +479,12 @@ pub fn create_cube_texture<'gc>(
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let size = args.get_i32(activation, 0)? as u32;
let format = args.get_string_non_null(activation, 1, "textureFormat")?;
let format = args
.get_string_non_null(activation, 1, "textureFormat")?
.parse()
.map_err(|_| make_error_2008(activation, "textureFormat"))?;
let optimize_for_render_to_texture = args.get_bool(2);
let streaming_levels = args.get_i32(activation, 3)? as u32;
let format = Context3DTextureFormat::from_wstr(&format)
.ok_or_else(|| make_error_2008(activation, "textureFormat"))?;

return context.create_cube_texture(
size,
Expand Down Expand Up @@ -582,9 +556,10 @@ pub fn set_depth_test<'gc>(
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let depth_mask = args.get_bool(0);
let pass_compare_mode = args.get_string_non_null(activation, 1, "passCompareMode")?;
let pass_compare_mode = Context3DCompareMode::from_wstr(&pass_compare_mode)
.ok_or_else(|| make_error_2008(activation, "passCompareMode"))?;
let pass_compare_mode = args
.get_string_non_null(activation, 1, "passCompareMode")?
.parse()
.map_err(|_| make_error_2008(activation, "passCompareMode"))?;

context.set_depth_test(depth_mask, pass_compare_mode);
}
Expand All @@ -600,14 +575,14 @@ pub fn set_blend_factors<'gc>(

if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let source_factor = args.get_string_non_null(activation, 0, "sourceFactor")?;
let destination_factor = args.get_string_non_null(activation, 1, "destinationFactor")?;

let source_factor = Context3DBlendFactor::from_wstr(&source_factor)
.ok_or_else(|| make_error_2008(activation, "sourceFactor"))?;

let destination_factor = Context3DBlendFactor::from_wstr(&destination_factor)
.ok_or_else(|| make_error_2008(activation, "destinationFactor"))?;
let source_factor = args
.get_string_non_null(activation, 0, "sourceFactor")?
.parse()
.map_err(|_| make_error_2008(activation, "sourceFactor"))?;
let destination_factor = args
.get_string_non_null(activation, 1, "destinationFactor")?
.parse()
.map_err(|_| make_error_2008(activation, "destinationFactor"))?;

context.set_blend_factors(source_factor, destination_factor);
}
Expand Down Expand Up @@ -686,6 +661,53 @@ pub fn set_render_to_texture<'gc>(
Ok(Value::Undefined)
}

pub fn set_stencil_actions<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

if let Some(context) = this.as_context_3d() {
let triangle_face = args.get_string(activation, 0)?;

let triangle_face = triangle_face
.parse()
.inspect_err(|_| tracing::error!("Unknown triangle_face {:?}", triangle_face))
.unwrap_or(Context3DTriangleFace::None);

let compare_mode = args
.get_string_non_null(activation, 1, "compareMode")?
.parse()
.map_err(|_| make_error_2008(activation, "compareMode"))?;

let on_both_pass = args
.get_string_non_null(activation, 2, "actionOnBothPass")?
.parse()
.map_err(|_| make_error_2008(activation, "actionOnBothPass"))?;

let on_depth_fail = args
.get_string_non_null(activation, 3, "actionOnDepthFail")?
.parse()
.map_err(|_| make_error_2008(activation, "actionOnDepthFail"))?;

let on_depth_pass_stencil_fail = args
.get_string_non_null(activation, 4, "actionOnDepthPassStencilFail")?
.parse()
.map_err(|_| make_error_2008(activation, "actionOnDepthPassStencilFail"))?;

context.set_stencil_actions(
triangle_face,
compare_mode,
on_both_pass,
on_depth_fail,
on_depth_pass_stencil_fail,
);
}

Ok(Value::Undefined)
}

pub fn set_render_to_back_buffer<'gc>(
_activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
Expand All @@ -698,6 +720,24 @@ pub fn set_render_to_back_buffer<'gc>(
Ok(Value::Undefined)
}

pub fn set_stencil_reference_value<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

if let Some(context) = this.as_context_3d() {
let reference_value = args.get_u32(activation, 0)?;
let read_mask = args.get_u32(activation, 1)?;
let write_mask = args.get_u32(activation, 2)?;

context.set_stencil_reference_value(reference_value, read_mask, write_mask);
}

Ok(Value::Undefined)
}

pub fn set_sampler_state_at<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
Expand All @@ -708,16 +748,16 @@ pub fn set_sampler_state_at<'gc>(
if let Some(context) = this.as_context_3d() {
// This is a native method, so all of the arguments have been checked and coerced for us
let sampler = args[0].as_i32() as u32;
let wrap = args[1].coerce_to_string(activation)?;
let filter = args[2].coerce_to_string(activation)?;
let wrap = args[1]
.coerce_to_string(activation)?
.parse()
.map_err(|_| make_error_2008(activation, "wrap"))?;
let filter = args[2]
.coerce_to_string(activation)?
.parse()
.map_err(|_| make_error_2008(activation, "filter"))?;
let mip_filter = args[3].coerce_to_string(activation)?;

let wrap = Context3DWrapMode::from_wstr(&wrap)
.ok_or_else(|| make_error_2008(activation, "wrap"))?;

let filter = Context3DTextureFilter::from_wstr(&filter)
.ok_or_else(|| make_error_2008(activation, "filter"))?;

if matches!(
filter,
Context3DTextureFilter::Anisotropic2X
Expand Down
38 changes: 36 additions & 2 deletions core/src/avm2/object/context3d_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::utils::HasPrefixField;
use gc_arena::{Collect, Gc, GcCell, GcWeak};
use ruffle_render::backend::{
BufferUsage, Context3D, Context3DBlendFactor, Context3DCommand, Context3DCompareMode,
Context3DTextureFormat, Context3DTriangleFace, Context3DVertexBufferFormat, ProgramType,
Texture,
Context3DStencilAction, Context3DTextureFormat, Context3DTriangleFace,
Context3DVertexBufferFormat, ProgramType, Texture,
};
use ruffle_render::commands::CommandHandler;
use std::cell::Cell;
Expand Down Expand Up @@ -476,6 +476,40 @@ impl<'gc> Context3DObject<'gc> {
ctx.process_command(Context3DCommand::SetScissorRectangle { rect })
});
}

pub(crate) fn set_stencil_actions(
&self,
triangle_face: Context3DTriangleFace,
compare_mode: Context3DCompareMode,
on_both_pass: Context3DStencilAction,
on_depth_fail: Context3DStencilAction,
on_depth_pass_stencil_fail: Context3DStencilAction,
) {
self.with_context_3d(|ctx| {
ctx.process_command(Context3DCommand::SetStencilActions {
triangle_face,
compare_mode,
on_both_pass,
on_depth_fail,
on_depth_pass_stencil_fail,
})
});
}

pub(crate) fn set_stencil_reference_value(
&self,
reference_value: u32,
read_mask: u32,
write_mask: u32,
) {
self.with_context_3d(|ctx| {
ctx.process_command(Context3DCommand::SetStencilReferenceValue {
reference_value,
read_mask,
write_mask,
})
});
}
}

#[derive(Collect, HasPrefixField)]
Expand Down
Loading
Loading