diff --git a/.gitignore b/.gitignore index 6aa106405a..ba7432bda8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ +/mikktspace-sys/target/ **/*.rs.bk Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 14ae2a507a..8802dbc6e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,5 @@ name = "mikktspace" version = "0.1.0" authors = ["Benjamin Wasty "] -[dev-dependencies] -mikktspace-sys = { path = "./mikktspace-sys" } - [dependencies] +mikktspace-sys = { path = "./mikktspace-sys" } diff --git a/mikktspace-sys/Cargo.toml b/mikktspace-sys/Cargo.toml index 717102a12f..8b54f66d56 100644 --- a/mikktspace-sys/Cargo.toml +++ b/mikktspace-sys/Cargo.toml @@ -2,5 +2,9 @@ name = "mikktspace-sys" version = "0.1.0" authors = ["alteous "] +build = "build.rs" + +[build-dependencies] +cmake = "0.1" [dependencies] diff --git a/mikktspace-sys/build.rs b/mikktspace-sys/build.rs new file mode 100644 index 0000000000..155a9ed067 --- /dev/null +++ b/mikktspace-sys/build.rs @@ -0,0 +1,9 @@ + +extern crate cmake; + +fn main() { + let dst = cmake::build("libmikktspace"); + println!("cargo:rustc-link-search=native={}", dst.display()); + println!("cargo:rustc-link-lib=static=mikktspace"); +} + diff --git a/reference/CMakeLists.txt b/mikktspace-sys/libmikktspace/CMakeLists.txt similarity index 80% rename from reference/CMakeLists.txt rename to mikktspace-sys/libmikktspace/CMakeLists.txt index 7b57c07fb6..376409d8c8 100644 --- a/reference/CMakeLists.txt +++ b/mikktspace-sys/libmikktspace/CMakeLists.txt @@ -7,4 +7,5 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c11") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_DEBUG} -ggdb -DDEBUG") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_RELEASE} -O2") set(SOURCES mikktspace.h mikktspace.c) -add_library(mikktspace SHARED ${SOURCES}) +add_library(mikktspace STATIC ${SOURCES}) +install(TARGETS mikktspace ARCHIVE DESTINATION ".") diff --git a/mikktspace-sys/libmikktspace/libmikktspace.a.REMOVED.git-id b/mikktspace-sys/libmikktspace/libmikktspace.a.REMOVED.git-id new file mode 100644 index 0000000000..1ebb68ee37 --- /dev/null +++ b/mikktspace-sys/libmikktspace/libmikktspace.a.REMOVED.git-id @@ -0,0 +1 @@ +e52ce628fdfe770b52733629d6c2ba6ae871c323 \ No newline at end of file diff --git a/reference/mikktspace.c b/mikktspace-sys/libmikktspace/mikktspace.c similarity index 100% rename from reference/mikktspace.c rename to mikktspace-sys/libmikktspace/mikktspace.c diff --git a/reference/mikktspace.h b/mikktspace-sys/libmikktspace/mikktspace.h similarity index 100% rename from reference/mikktspace.h rename to mikktspace-sys/libmikktspace/mikktspace.h diff --git a/mikktspace-sys/src/ffi.rs b/mikktspace-sys/src/ffi.rs new file mode 100644 index 0000000000..b4e8fe9e72 --- /dev/null +++ b/mikktspace-sys/src/ffi.rs @@ -0,0 +1,136 @@ + +#![allow(bad_style)] + +use std::os::raw::*; + +#[allow(dead_code)] +pub type tbool = c_int; + +#[allow(dead_code)] +const TFALSE: tbool = 0; + +#[allow(dead_code)] +const TTRUE: tbool = 1; + +#[repr(C)] +pub struct SMikkTSpaceInterface { + /// Returns the number of faces (triangles/quads) on the mesh to be processed. + pub m_getNumFaces: extern "C" fn(pContext: *const SMikkTSpaceContext) -> c_int, + + /// Returns the number of vertices on face number iFace + /// iFace is a number in the range {0, 1, ..., getNumFaces()-1} + pub m_getNumVerticesOfFace: extern "C" fn( + pContext: *const SMikkTSpaceContext, + iFace: c_int, + ) -> c_int, + + /// Returns the position of the referenced face of vertex number + /// iVert, in the range {0,1,2} for triangles, and {0,1,2,3} for quads. + pub m_getPosition: extern "C" fn( + pContext: *const SMikkTSpaceContext, + fvPosOut: *mut c_float, + iFace: c_int, + iVert: c_int, + ), + + /// Returns the normal of the referenced face of vertex number + /// iVert, in the range {0,1,2} for triangles, and {0,1,2,3} for quads. + pub m_getNormal: extern "C" fn( + pContext: *const SMikkTSpaceContext, + fvNormOut: *mut c_float, + iFace: c_int, + iVert: c_int, + ), + + /// Returns the texcoord of the referenced face of vertex number + /// iVert, in the range {0,1,2} for triangles, and {0,1,2,3} for quads. + pub m_getTexCoord: extern "C" fn( + pContext: *const SMikkTSpaceContext, + fvTexcOut: *mut c_float, + iFace: c_int, + iVert: c_int, + ), + + /// either (or both) of the two setTSpace callbacks can be set. + /// The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + /// This function is used to return the tangent and fSign to the application. + /// fvTangent is a unit length vector. + /// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + /// bitangent = fSign * cross(vN, tangent); + /// Note that the results are returned unindexed. It is possible to generate a new index list + /// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + /// DO NOT! use an already existing index list. + pub m_setTSpaceBasic: extern "C" fn( + pContext: *const SMikkTSpaceContext, + fvTangent: *const c_float, + fSign: *const c_float, + iFace: c_int, + iVert: c_int, + ), + + /// This function is used to return tangent space results to the application. + /// fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + /// true magnitudes which can be used for relief mapping effects. + /// fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + /// However, both are perpendicular to the vertex normal. + /// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + /// fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + /// bitangent = fSign * cross(vN, tangent); + /// Note that the results are returned unindexed. It is possible to generate a new index list + /// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + /// DO NOT! use an already existing index list. + pub m_setTSpace: extern "C" fn( + pContext: *const SMikkTSpaceContext, + fvTangent: *const c_float, + fvBiTangent: *const c_float, + fMagS: *const c_float, + fMagT: *const c_float, + bIsOrientationPreserving: tbool, + iFace: c_int, + iVert: c_int, + ), +} + +/// these are both thread safe! +/// Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +pub type genTangSpaceDefault = extern "system" fn( + pContext: *const SMikkTSpaceContext, +) -> tbool; + +pub type genTangSpace = extern "system" fn( + pContext: *const SMikkTSpaceContext, + fAngularThreshold: c_float, +) -> tbool; + +/// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +/// normal map sampler must use the exact inverse of the pixel shader transformation. +/// The most efficient transformation we can possibly do in the pixel shader is +/// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +/// pixel shader (fast transform out) +/// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +/// where vNt is the tangent space normal. The normal map sampler must likewise use the +/// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +/// sampler does (exact inverse of pixel shader): +/// float3 row0 = cross(vB, vN); +/// float3 row1 = cross(vN, vT); +/// float3 row2 = cross(vT, vB); +/// float fSign = dot(vT, row0)<0 ? -1 : 1; +/// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +/// where vNout is the sampled normal in some chosen 3D space. +/// +/// Should you choose to reconstruct the bitangent in the pixel shader instead +/// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +/// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +/// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +/// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +/// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +/// However, this must be used both by the sampler and your tools/rendering pipeline. + +#[repr(C)] +pub struct SMikkTSpaceContext { + /// initialized with callback functions + pub m_pInterface: *const SMikkTSpaceInterface, + /// pointer to client side mesh data etc. (passed as the first parameter with every interface call) + pub m_pUserData: *const c_void, +} diff --git a/mikktspace-sys/src/lib.rs b/mikktspace-sys/src/lib.rs index cdfbe1aa56..f0644a98e5 100644 --- a/mikktspace-sys/src/lib.rs +++ b/mikktspace-sys/src/lib.rs @@ -1,3 +1,126 @@ + +mod ffi; + +use std::os::raw::*; +use std::mem; + +const INTERFACE: ffi::SMikkTSpaceInterface = ffi::SMikkTSpaceInterface { + m_getNumFaces: faces, + m_getNumVerticesOfFace: vertices, + m_getPosition: position, + m_getNormal: normal, + m_getTexCoord: tex_coord, + m_setTSpaceBasic: set_tspace_basic, + m_setTSpace: set_tspace, +}; + +pub struct Context { + faces: i32, +} + +/// Returns the number of faces (triangles/quads) on the mesh to be processed. +#[no_mangle] +extern "C" fn faces(pContext: *const ffi::SMikkTSpaceContext) -> c_int { + unsafe { + let m: *const Context = mem::transmute(pContext); + (*m).faces as c_int + } +} + +/// Returns the number of vertices on face number iFace +/// iFace is a number in the range {0, 1, ..., getNumFaces()-1} +#[no_mangle] +extern "C" fn vertices( + pContext: *const ffi::SMikkTSpaceContext, + iFace: c_int, +) -> c_int { + unsafe { + let _: *const Context = mem::transmute(pContext); + unimplemented!() + } +} + +/// Returns the position of the referenced face of vertex number +/// iVert, in the range {0,1,2} for triangles, and {0,1,2,3} for quads. +#[no_mangle] +extern "C" fn position( + pContext: *const ffi::SMikkTSpaceContext, + fvPosOut: *mut c_float, + iFace: c_int, + iVert: c_int, +) { + unsafe { + let _: *const Context = mem::transmute(pContext); + } +} + +/// Returns the normal of the referenced face of vertex number +/// iVert, in the range {0,1,2} for triangles, and {0,1,2,3} for quads. +#[no_mangle] +extern "C" fn normal( + pContext: *const ffi::SMikkTSpaceContext, + fvPosOut: *mut c_float, + iFace: c_int, + iVert: c_int, +) { + unsafe { + let _: *const Context = mem::transmute(pContext); + } +} + +/// Returns the texcoord of the referenced face of vertex number +/// iVert, in the range {0,1,2} for triangles, and {0,1,2,3} for quads. +#[no_mangle] +extern "C" fn tex_coord( + pContext: *const ffi::SMikkTSpaceContext, + fvTexcOut: *mut c_float, + iFace: c_int, + iVert: c_int, +) { + unsafe { + let _: *const Context = mem::transmute(pContext); + } +} + +/// Returns the tangent and its sign to the application. +#[no_mangle] +extern "C" fn set_tspace_basic( + pContext: *const ffi::SMikkTSpaceContext, + fvTangent: *const c_float, + fSign: *const c_float, + iFace: c_int, + iVert: c_int, +) { + unsafe { + let _: *const Context = mem::transmute(pContext); + } +} + +/// Returns tangent space results to the application. +#[no_mangle] +extern "C" fn set_tspace( + pContext: *const ffi::SMikkTSpaceContext, + fvTangent: *const c_float, + fvBiTangent: *const c_float, + fMagS: *const c_float, + fMagT: *const c_float, + bIsOrientationPreserving: ffi::tbool, + iFace: c_int, + iVert: c_int, +) { + unsafe { + let _: *const Context = mem::transmute(pContext); + } +} + +impl Context { + pub fn new() -> Self { + Context { + faces: 3, + } + } +} + #[cfg(test)] mod tests { #[test]