-
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
7 changed files
with
617 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"; // "ftgrays_bindings"; | ||
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"; // "evg_bindings"; | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
/**************************************************************** | ||
* $ID: gpac_evg.rs Tue 24 Oct 2023 15:58:07+0800 * | ||
* * | ||
* Maintainer: 范美辉 (MeiHui FAN) <[email protected]> * | ||
* Copyright (c) 2023 M.H.Fan, All rights reserved. * | ||
****************************************************************/ | ||
|
||
#![allow(non_snake_case)] #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] | ||
#![allow(clippy::approx_constant)] #![allow(clippy::useless_transmute)] | ||
|
||
//#[macro_export] macro_rules! dbg_ne { ($($v:expr),*) => () } | ||
#[macro_export] macro_rules! dbg_ne { ($v:expr, $g:expr) => { if $v != $g { dbg!($v); } } } | ||
|
||
/* TODO: https://github.com/sammycage/plutovg | ||
https://github.com/kiba/SDL_svg/blob/master/ftgrays.c | ||
https://github.com/Samsung/rlottie/tree/master/src/vector/freetype | ||
https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/src/smooth/ftgrays.c | ||
https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/src/raster/ftraster.c */ | ||
|
||
pub mod ftgrays { include!(concat!(env!("OUT_DIR"), "/ftgrays.rs")); | ||
impl From<(FT_Pos, FT_Pos)> for FT_Vector { | ||
fn from(v: (FT_Pos, FT_Pos)) -> Self { Self { x: v.0, y: v.1 } } | ||
} | ||
} | ||
|
||
//pub mod gpac_evg { // https://github.com/gpac/gpac/tree/master/src/evg/ | ||
include!(concat!(env!("OUT_DIR"), "/gpac_evg.rs")); // evg_bindings.rs | ||
|
||
impl From<i32> for Fixed { #[inline] fn from(v: i32) -> Self { Self(v << 16) } } | ||
impl From<Fixed> for i32 { #[inline] fn from(v: Fixed) -> Self { (v.0 + (1 << 15)) >> 16 } } | ||
impl From<f32> for Fixed { // 16.16 fixed-point, or 26.6? | ||
#[inline] fn from(v: f32) -> Self { Self((v * (1 << 16) as f32) as i32) } | ||
} | ||
impl From<Fixed> for f32 { #[inline] fn from(v: Fixed) -> Self { v.0 as f32 / (1 << 16) as f32 } } | ||
|
||
impl From<bool> for Bool { | ||
fn from(value: bool) -> Self { if value { Bool::GF_TRUE } else { Bool::GF_FALSE } } | ||
} | ||
|
||
impl Copy for Fixed {} | ||
impl Copy for GF_Point2D {} | ||
impl Copy for GF_PenSettings {} | ||
impl Clone for Fixed { #[inline] fn clone(&self) -> Self { *self } } | ||
impl Clone for GF_Point2D { #[inline] fn clone(&self) -> Self { *self } } | ||
impl Clone for GF_PenSettings { #[inline] fn clone(&self) -> Self { *self } } | ||
|
||
impl Default for GF_PenSettings { | ||
fn default() -> Self { Self { | ||
width: 0.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(), | ||
} } | ||
} | ||
|
||
pub struct VGPath(*mut GF_Path); | ||
impl Drop for VGPath { fn drop(&mut self) { unsafe { gf_path_del(self.0) } } } | ||
impl VGPath { #[allow(clippy::new_without_default)] // to build path and stencil | ||
#[inline] pub fn new() -> Self { Self(unsafe { gf_path_new() }) } | ||
|
||
#[inline] pub fn move_to(&self, pt: GF_Point2D) { | ||
let _err = unsafe { gf_path_add_move_to_vec(self.0, &pt as *const _ as *mut _) }; | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn line_to(&self, pt: GF_Point2D) { | ||
let _err = unsafe { gf_path_add_line_to_vec(self.0, &pt as *const _ as *mut _) }; | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn cubic_to(&self, c1: GF_Point2D, c2: GF_Point2D, pt: GF_Point2D) { | ||
let _err = unsafe { gf_path_add_cubic_to_vec(self.0, | ||
&c1 as *const _ as *mut _, &c2 as *const _ as *mut _, &pt as *const _ as *mut _) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn quad_to(&self, cp: GF_Point2D, pt: GF_Point2D) { | ||
let _err = unsafe { gf_path_add_quadratic_to_vec(self.0, | ||
&cp as *const _ as *mut _, &pt as *const _ as *mut _) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn svg_arc_to(&self, radius: GF_Point2D, | ||
rotation: Fixed, large: bool, sweep: bool, pt: GF_Point2D) { | ||
let _err = unsafe { gf_path_add_svg_arc_to(self.0, pt.x, pt.y, | ||
radius.x, radius.y, rotation, large.into(), sweep.into()) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn add_rect(&self, rect: GF_Rect) { | ||
let _err = unsafe { | ||
gf_path_add_rect(self.0, rect.x, rect.y, rect.width, rect.height) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
//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_bezier(path, pts, nb_pts); | ||
|
||
#[inline] pub fn reset(&self) { unsafe { gf_path_reset(self.0) }; } | ||
|
||
#[allow(clippy::len_without_is_empty)] #[inline] pub fn len(&self) -> u32 { | ||
if let Some(path) = unsafe { self.0.as_ref() } { path.n_points } else { 0 } | ||
} | ||
pub fn last_point(&self) -> Option<GF_Point2D> { | ||
let cnt = self.len(); if cnt < 1 { None } else { | ||
Some(unsafe { *(*self.0).points.offset(cnt as isize - 1) }) | ||
} | ||
} | ||
|
||
pub fn print_out(&self) { | ||
unsafe { let path = &*self.0; | ||
for n in 0..path.n_points { let n = n as isize; | ||
let pt = &*path.points.offset(n); | ||
eprintln!("{}-({:?}, {:?})", *path.tags.offset(n), //pt.x, pt.y); | ||
<f32>::from(pt.x), <f32>::from(pt.y)); | ||
} | ||
} | ||
} | ||
|
||
#[inline] pub fn close(&self) { // XXX: fix and simplify difference judgement in path2d.c | ||
let _err = unsafe { gf_path_close(self.0) }; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
} | ||
|
||
pub struct Stencil(*mut GF_EVGStencil); | ||
impl Drop for Stencil { fn drop(&mut self) { unsafe { gf_evg_stencil_delete(self.0) } } } | ||
impl Stencil { | ||
#[inline] pub fn new(t: GF_StencilType) -> Self { unsafe { Self(gf_evg_stencil_new(t)) } } | ||
|
||
#[inline] pub fn set_color(&self, color: GF_Color) { | ||
let _err = unsafe { gf_evg_stencil_set_brush_color(self.0, color) }; | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn set_linear(&self, start: GF_Point2D, end: GF_Point2D) { | ||
let _err = unsafe { | ||
gf_evg_stencil_set_linear_gradient(self.0, start.x, start.y, end.x, end.y) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn set_radial(&self, | ||
center: GF_Point2D, focal: GF_Point2D, radius: GF_Point2D) { | ||
let _err = unsafe { gf_evg_stencil_set_radial_gradient(self.0, | ||
center.x, center.y, focal.x, focal.y, radius.x, radius.y) }; | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
#[inline] pub fn push_interpolation(&self, pos: Fixed, col: GF_Color) { | ||
let _err = unsafe { | ||
gf_evg_stencil_push_gradient_interpolation(self.0, pos, col) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
/* #[inline] pub fn set_interpolation(&self, pos: &[Fixed], col: &[GF_Color], cnt: u32) { | ||
let _err = unsafe { gf_evg_stencil_set_gradient_interpolation(self.0, | ||
pos.as_mut_ptr(), col.as_mut_ptr(), cnt) }; dbg_ne!(_err, GF_Err::GF_OK); | ||
} */ | ||
|
||
//let _err = gf_evg_stencil_set_gradient_mode(sten, GF_GradientMode::GF_GRADIENT_MODE_PAD); | ||
//let _err = gf_evg_stencil_set_alpha(sten, alpha); | ||
|
||
#[inline] pub fn set_matrix(&self, mat: &GF_Matrix2D) { | ||
let _err = unsafe { | ||
gf_evg_stencil_set_matrix(self.0, mat as *const _ as *mut _) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
} | ||
|
||
pub struct Surface(*mut GF_EVGSurface); | ||
impl Drop for Surface { fn drop(&mut self) { unsafe { gf_evg_surface_delete(self.0) } } } | ||
impl Surface { | ||
#[inline] pub fn new(pixm: &mut Pixmap) -> Self { | ||
let surf = unsafe { Self(gf_evg_surface_new(Bool::GF_FALSE)) }; | ||
let _err = unsafe { gf_evg_surface_attach_to_buffer(surf.0, | ||
pixm.data.as_mut_ptr(), pixm.width, pixm.height, 4, (pixm.width << 2) as i32, | ||
GF_PixelFormat::GF_PIXEL_RGBA) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); surf | ||
//let _err = unsafe { gf_evg_surface_clear(surf, &mut bbox, 0xFF000000) }; | ||
} | ||
|
||
#[inline] pub fn fill_path(&self, path: &VGPath, sten: &Stencil) { | ||
let _err = unsafe { gf_evg_surface_set_path(self.0, path.0) }; | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
let _err = unsafe { gf_evg_surface_fill(self.0, sten.0) }; | ||
dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
|
||
/** ``` | ||
use intvg::gpac_evg::*; | ||
let mut pixm = Pixmap::new(1024, 512); | ||
let mut pens = GF_PenSettings::default(); | ||
let sten = Stencil::new(GF_StencilType::GF_STENCIL_SOLID); | ||
let (surf, path) = (Surface::new(&mut pixm), VGPath::new()); | ||
path.add_rect(GF_Rect { x: (pixm.width as i32 >> 2) .into(), | ||
y: (pixm.height as i32 - (pixm.height as i32 >> 2)).into(), | ||
width: (pixm.width as i32 >> 1).into(), height: (pixm.height as i32 >> 1).into() }); | ||
// RUSTDOCFLAGS="-Z unstable-options --nocapture" cargo +nightly test #--doc | ||
/* path.move_to(GF_Point2D { x: rect.x, y: rect.y }); | ||
path.line_to(GF_Point2D { x: Fixed(rect.x.0 + rect.width.0), y: rect.y }); | ||
path.line_to(GF_Point2D { x: Fixed(rect.x.0 + rect.width.0), | ||
y: Fixed(rect.y.0 - rect.height.0) }); | ||
path.line_to(GF_Point2D { x: rect.x, y: Fixed(rect.y.0 - rect.height.0) }); | ||
path.line_to(GF_Point2D { x: rect.x, y: rect.y }); path.print_out(); | ||
path.close(); */ | ||
sten.set_color(0xFF0000FF); surf.fill_path(&path, &sten); | ||
sten.set_color(0xAA00FF00); pens.width = 10.into(); | ||
surf.stroke_path(&path, &sten, &pens); | ||
pixm.save_png(concat!("target", "/stroke.png")).unwrap(); //env!("OUT_DIR") | ||
``` */ | ||
|
||
#[inline] pub fn stroke_path(&self, path: &VGPath, sten: &Stencil, pens: &GF_PenSettings) { | ||
let path = VGPath(unsafe { gf_path_get_outline(path.0, *pens) }); | ||
self.fill_path(&path, sten); | ||
} | ||
|
||
#[inline] pub fn set_matrix(&self, mat: &GF_Matrix2D) { | ||
let _err = unsafe { | ||
gf_evg_surface_set_matrix(self.0, mat as *const _ as *mut _) | ||
}; dbg_ne!(_err, GF_Err::GF_OK); | ||
} | ||
} | ||
|
||
pub struct Pixmap { pub data: Vec<u8>, pub width: u32, pub height: u32, } | ||
|
||
impl Pixmap { | ||
pub fn new(width: u32, height: u32) -> Self { | ||
Self { width, height, data: vec![0; (width * height * 4) as usize] } | ||
} | ||
|
||
pub fn save_png(&self, path: &str) -> Result<(), png::EncodingError> { | ||
let bufw = std::io::BufWriter::new( | ||
std::fs::File::create(std::path::Path::new(path))?); | ||
let mut encoder = png::Encoder::new(bufw, self.width, self.height); | ||
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 instant | ||
// (0.3127, 0.3290), (0.6400, 0.3300), (0.3000, 0.6000), (0.1500, 0.0600)); | ||
//encoder.set_source_chromaticities(source_chromaticities); | ||
encoder.write_header()?.write_image_data(&self.data)?; 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
Oops, something went wrong.