-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support to compile ftgrays/ftraster/gpac-evg
preparing for new renderer implementation
- Loading branch information
Showing
6 changed files
with
293 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"C_Cpp.default.defines": [ "STANDALONE_", | ||
"FALL_THROUGH=((void)0)", "FT_BEGIN_HEADER" ], | ||
"C_Cpp.default.includePath": [ "src/evg", "src/raster" ] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,79 @@ | ||
|
||
fn main() { // https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html | ||
// https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html | ||
fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
//println!("cargo:rerun-if-changed=build.rs"); // XXX: prevent re-run indead | ||
// By default, cargo always re-run the build script if any file within the package | ||
// is changed, and no any rerun-if instruction is emitted. | ||
println!("cargo:rerun-if-changed=src/"); | ||
|
||
println!("cargo:rerun-if-changed=.git/index"); | ||
let output = std::process::Command::new("git") | ||
.args(["rev-parse", "--short", "HEAD"]).output().unwrap(); | ||
println!("cargo:rustc-env=BUILD_GIT_HASH={}", String::from_utf8(output.stdout).unwrap()); | ||
.args(["rev-parse", "--short", "HEAD"]).output()?; | ||
println!("cargo:rustc-env=BUILD_GIT_HASH={}", String::from_utf8(output.stdout)?); | ||
|
||
println!("cargo:rustc-env=BUILD_TIMESTAMP={}", | ||
chrono::Local::now().format("%H:%M:%S%z %Y-%m-%d")); | ||
|
||
//println!("cargo:rerun-if-changed=build.rs"); // XXX: prevent re-run indead | ||
#[cfg(feature = "cc")] { use std::path::PathBuf; | ||
#[derive(Debug)] struct DoctestComment; | ||
impl bindgen::callbacks::ParseCallbacks for DoctestComment { | ||
fn process_comment(&self, comment: &str) -> Option<String> { | ||
Some(format!("````c,ignore\n{comment}\n````")) // FIXME: | ||
} | ||
} | ||
|
||
let module = "ftgrays"; | ||
cc::Build::new().flag("-std=c17").flag("-pedantic") | ||
.define("FALL_THROUGH", "((void)0)").file("src/raster/ftgrays.c") | ||
.opt_level(3).define("NDEBUG", None).file("src/raster/ftraster.c") | ||
.files(glob::glob("src/raster/stroke/*.c")?.filter_map(Result::ok)) | ||
.flag("-Wno-unused-variable")//.flag("-Wno-unused-function") | ||
.define("STANDALONE_", None).compile(module); | ||
|
||
// The bindgen::Builder is the main entry point to bindgen, | ||
// and lets you build up options for the resulting bindings. | ||
bindgen::Builder::default() //.header("src/raster/ftimage.h") | ||
.clang_arg("-DSTANDALONE_").header("src/raster/ftgrays.h") | ||
.clang_arg("-DFT_BEGIN_HEADER=").clang_arg("-DFT_END_HEADER=") | ||
.clang_arg("-DFT_STATIC_BYTE_CAST(type,var)=(type)(unsigned char)(var)") | ||
.allowlist_item("FT_OUTLINE_.*|FT_RASTER_FLAG_.*|FT_CURVE_TAG.*") | ||
.layout_tests(false).derive_copy(false).allowlist_var("ft_standard_raster") | ||
.allowlist_var("ft_grays_raster").allowlist_type("FT_Outline|FT_Pixel_Mode") | ||
.default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true }) | ||
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed) | ||
.parse_callbacks(Box::new(DoctestComment)).generate_comments(false) // XXX: | ||
// Tell cargo to invalidate the built crate whenever any of the | ||
// included header files changed. | ||
.parse_callbacks(Box::new(bindgen::CargoCallbacks)).generate()? | ||
.write_to_file(PathBuf::from(std::env::var("OUT_DIR")?).join(format!("{module}.rs")))?; | ||
|
||
/* ln -s /path/to/freetype2/{include/freetype/ftimage.h,src/smooth/ftgrays.[ch],\ | ||
src/raster/ft{misc.h,raster.c}} src/raster/ | ||
* ln -s /path/to/freetype2/src/{raster/ftmisc.h,base/ft{stroke,trigon}.c} src/raster/stroke/ | ||
* ln -s /path/to/freetype2/include/freetype/ft{stroke,trigon,image}.h src/raster/stroke/ | ||
* ln -s /path/to/gpac/src/evg/{ftgrays.c,rast_soft.h,stencil.c,surface.c,\ | ||
raster_{argb,rgb,565,yuv}.c},raster3d.c src/evg/ | ||
* ln -s /path/to/gpac/src/utils/{path2d{,_stroke},math,alloc,color,error}.c src/evg/ | ||
* ln -s /path/gpac/include/gpac/{evg,setup,constants,maths,color,path2d,\ | ||
tools,thread}.h src/evg/gpac/ | ||
* touch src/evg/gpac/{Remotery,config_file,configuration,main,module,version}.h | ||
*/ | ||
let module = "gpac_evg"; | ||
cc::Build::new().flag("-std=c17").flag("-Isrc/evg").define("GPAC_FIXED_POINT", None) | ||
.flag("-Wno-unused-parameter").define("GPAC_DISABLE_THREADS", None) | ||
.flag("-Wno-pointer-sign").define("GPAC_DISABLE_LOG", None) | ||
.files(glob::glob("src/evg/*.c")?.filter_map(Result::ok)) | ||
.opt_level(3).define("NDEBUG", None).compile(module); | ||
|
||
bindgen::Builder::default().header("src/evg/gpac/evg.h").clang_arg("-Isrc/evg") | ||
.default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true }) | ||
.clang_arg("-DGPAC_DISABLE_THREADS").allowlist_function("gf_evg_s.*") | ||
//.allowlist_item("GF_LINE_.*") | ||
.clang_arg("-DGPAC_FIXED_POINT").allowlist_function("gf_path_.*") | ||
.layout_tests(false).derive_copy(false).new_type_alias("Fixed") | ||
.parse_callbacks(Box::new(bindgen::CargoCallbacks)).generate()? | ||
.write_to_file(PathBuf::from(std::env::var("OUT_DIR")?).join(format!("{module}.rs")))?; | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
|
||
#[cfg(feature = "cc")] | ||
#[test] fn raster_evg() -> Result<(), Box<dyn std::error::Error>> { | ||
use intvg::gpac_evg::*; | ||
|
||
// /*#[macro_export] */macro_rules! dbg_ne { ($($v:expr),*) => () } | ||
macro_rules! dbg_ne { ($v:expr,$g:expr) => { if $v != $g { dbg!($v); } } } | ||
|
||
let (width, height) = (1024_i32, 512_i32); | ||
//let mut bbox = GF_IRect { x: 0, y: 0, width, height }; | ||
let mut pixels = vec![0u8; (width * height * 4) as usize]; | ||
|
||
unsafe { | ||
let surf = gf_evg_surface_new(Bool::GF_FALSE); | ||
let _err = gf_evg_surface_attach_to_buffer(surf, pixels.as_mut_ptr(), | ||
width as u32, height as u32, 4, width << 2, GF_PixelFormat::GF_PIXEL_RGBA); | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
//let _err = gf_evg_surface_clear(surf, &mut bbox, 0xFF000000); | ||
//dbg_ne!(_err, GF_Err::GF_OK); | ||
|
||
let path = gf_path_new(); // to build path and stencil | ||
|
||
//gf_path_add_move_to_vec(path, pt); | ||
//gf_path_add_line_to_vec(path, pt); | ||
//gf_path_add_cubic_to_vec(path, c1, c2, pt); | ||
//gf_path_add_quadratic_to_vec(path, cp, pt); | ||
//gf_path_add_svg_arc_to(path, end_x, end_y, r_x, r_y, x_rotation, large_arc, sweep); | ||
|
||
//let _err = gf_path_close(path); dbg_ne!(_err, GF_Err::GF_OK); | ||
|
||
let (rw, rh) = ((width >> 1).into(), (height >> 1).into()); | ||
//gf_path_add_arc_to(path, end_x, end_y, fa_x, fa_y, fb_x, fb_y, cw); | ||
//gf_path_add_arc(path, radius, start_angle, end_angle, close_type); | ||
//gf_path_add_ellipse(path, cx, cy, a_axis, b_axis); | ||
gf_path_add_rect_center(path, rw, rh, rw, rh); | ||
//gf_path_add_bezier(path, pts, nb_pts); | ||
|
||
let stencil = gf_evg_stencil_new(GF_StencilType::GF_STENCIL_SOLID); | ||
|
||
let _err = gf_evg_stencil_set_brush_color(stencil, 0xFF0000FF); | ||
//let _err = gf_evg_stencil_set_linear_gradient(stencil, start_x, start_y, end_x, end_y); | ||
//let _err = gf_evg_stencil_set_radial_gradient(stencil, | ||
// cx, cy, fx, fy, x_radius, y_radius); // GF_STENCIL_(LINEAR/RADIAL)_GRADIENT | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
|
||
//let _err = gf_evg_stencil_set_gradient_interpolation(stencil, pos, col, count); | ||
//let _err = gf_evg_stencil_set_gradient_mode(stencil, | ||
// GF_GradientMode::GF_GRADIENT_MODE_PAD); | ||
//let _err = gf_evg_stencil_set_alpha(stencil, alpha); | ||
|
||
let _err = gf_evg_surface_set_path(surf, path); | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
let _err = gf_evg_surface_fill(surf, stencil); | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
|
||
let pen = GF_PenSettings { | ||
width: 10.into(), cap: 1, join: 1, align: 0, dash: 0, | ||
// GF_LINE_(CAP/JOIN)_ROUND, GF_PATH_LINE_CENTER, GF_DASH_STYLE_PLAIN | ||
dash_offset: 0.into(), dash_set: core::ptr::null_mut(), | ||
path_length: 0.into(), miterLimit: 0.into(), | ||
}; | ||
let gpol = gf_path_get_outline(path, pen); // XXX: why not closed? | ||
|
||
let _err = gf_evg_stencil_set_brush_color(stencil, 0xAA00FF00); | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
|
||
let _err = gf_evg_surface_set_path(surf, gpol); | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
let _err = gf_evg_surface_fill(surf, stencil); | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
|
||
gf_path_del(gpol); | ||
gf_path_del(path); | ||
gf_evg_surface_delete(surf); | ||
gf_evg_stencil_delete(stencil); | ||
} | ||
|
||
fn write_png(data: &[u8], w: u32, h: u32, path: &str) | ||
-> Result<(), Box<dyn std::error::Error>> { | ||
let bufw = std::io::BufWriter::new( | ||
std::fs::File::create(std::path::Path::new(path))?); | ||
let mut encoder = png::Encoder::new(bufw, w, h); | ||
encoder.set_color(png::ColorType::Rgba); | ||
encoder.set_depth(png::BitDepth::Eight); | ||
encoder.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2)); | ||
// png::ScaledFloat::from_scaled(45455) // 1.0 / 2.2 scaled by 100000 | ||
//let source_chromaticities = png::SourceChromaticities::new( // unscaled instantiation | ||
// (0.31270, 0.32900), (0.64000, 0.33000), (0.30000, 0.60000), (0.15000, 0.06000)); | ||
//encoder.set_source_chromaticities(source_chromaticities); | ||
encoder.write_header()?.write_image_data(data)?; Ok(()) | ||
} | ||
|
||
let path = concat!("target", "/image.png"); //env!("OUT_DIR") | ||
write_png(&pixels, width as u32, height as u32, path)?; Ok(()) | ||
} | ||
|
||
#[cfg(feature = "cc")] | ||
#[test] fn raster_ftgrays() -> Result<(), Box<dyn std::error::Error>> { | ||
use core::{ptr::null_mut, ffi::c_void}; use intvg::ftgrays::*; | ||
|
||
let mut points = vec![ // FTDemo_Icon @freetype2/demo/src/ftcommon.c | ||
( 4, 8).into(), ( 4,10).into(), ( 8,12).into(), ( 8,52).into(), ( 4,54).into(), | ||
( 4,56).into(), (60,56).into(), (60,44).into(), (58,44).into(), (56,52).into(), | ||
(44,52).into(), (44,12).into(), (48,10).into(), (48, 8).into(), (32, 8).into(), | ||
(32,10).into(), (36,12).into(), (36,52).into(), (16,52).into(), (16,36).into(), | ||
(24,36).into(), (26,40).into(), (28,40).into(), (28,28).into(), (26,28).into(), | ||
(24,32).into(), (16,32).into(), (16,12).into(), (20,10).into(), (20, 8).into(), ]; | ||
let mut tags = vec![FT_CURVE_TAG_ON as i8; points.len()]; | ||
let mut contours = vec![29]; | ||
|
||
let mut bitmap = FT_Bitmap { | ||
rows: 0, width: 0, pitch: 0, buffer: null_mut(), // FIXME: | ||
|
||
pixel_mode: FT_Pixel_Mode::FT_PIXEL_MODE_LCD as u8, // FT_PIXEL_MODE_BGRA | ||
// https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#enums | ||
// Not used currently, or only used with FT_PIXEL_MODE_GRAY | ||
palette_mode: 0, palette: null_mut(), num_grays: 0, | ||
}; | ||
|
||
#[allow(unused)] | ||
unsafe extern "C" fn span_func(y: i32, count: i32, // TODO: solid/linear/radial/stroke | ||
spans: *const FT_Span, user: *mut c_void) { // The gray span drawing callback. | ||
let bitmap = user as *mut FT_Bitmap; assert!(0 < count); | ||
|
||
for span in core::slice::from_raw_parts(spans, count as usize) { | ||
for x in span.x..span.len as i16 { | ||
// TODO: handle pixel at (x, y) with span.coverage (alpha) | ||
} | ||
} | ||
} | ||
|
||
let outline = FT_Outline { | ||
n_points: points.len() as i16, points: points.as_mut_ptr(), tags: tags.as_mut_ptr(), | ||
n_contours: contours.len() as i16, contours: contours.as_mut_ptr(), | ||
flags: FT_OUTLINE_NONE, // XXX: FT_OUTLINE_IGNORE_DROPOUTS | ||
}; assert!(tags.len() == points.len()); | ||
|
||
let mut params = FT_Raster_Params { | ||
source: &outline as *const _ as *const c_void, | ||
user: &mut bitmap as *mut _ as *mut c_void, gray_spans: Some(span_func), | ||
|
||
// ftgrays.c: `ft_grays_raster` are typoed as `ft_gray_raster` in some comments. | ||
// ftimage.h: FT_Pos can be typed as `signed int` rather than `long`? // XXX: | ||
clip_box: FT_BBox { xMin: 0, yMin: 0, xMax: 0, yMax: 0 }, // FT_RASTER_FLAG_CLIP | ||
flags: FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT, | ||
black_spans: None, bit_test: None, bit_set: None, // Unused | ||
target: null_mut(), // &bitmap, unused in direct mode | ||
}; let mut raster = null_mut(); | ||
|
||
unsafe { // use of extern static (ft_grays_raster/ft_standard_raster) is unsafe | ||
let _ = ft_grays_raster.raster_new.unwrap()(null_mut(), &mut raster); | ||
//if res != 0 { panic!("raster_new failed: {}", res); } | ||
//ft_grays_raster.raster_reset.unwrap()(raster, null_mut(), 0); | ||
//ft_grays_raster.raster_set_mode.unwrap()(raster, 0, null_mut()); | ||
|
||
let res = ft_grays_raster.raster_render.unwrap()(raster, &mut params); | ||
if res != 0 { panic!("raster_render failed: {res}"); } | ||
//ft_grays_raster.raster_done.unwrap()(raster); | ||
} | ||
|
||
Ok(()) | ||
} |