fix: update BMap bindings

- send message in console if PyBMap fail to load native dynamic library. this is good for user experience.
- remove snippet from BMap bindings generator. We now insert generated code manually.
- fix C sharp code generation issue in BMap bidnings generator.
- add some content for BMapSharp.
This commit is contained in:
yyc12345 2024-09-21 16:50:53 +08:00
parent 8ef1c6e30a
commit 7c88b3614a
9 changed files with 1170 additions and 148 deletions

File diff suppressed because it is too large Load Diff

View File

@ -10,4 +10,14 @@
<Company>BearKidsTeam</Company> <Company>BearKidsTeam</Company>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="$([System.OperatingSystem]::IsWindows())">
<DefineConstants>BMAP_OS_WINDOWS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([System.OperatingSystem]::IsLinux()) Or $([System.OperatingSystem]::IsFreeBSD())">
<DefineConstants>BMAP_OS_LINUX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([System.OperatingSystem]::IsMacOS())">
<DefineConstants>BMAP_OS_MACOS</DefineConstants>
</PropertyGroup>
</Project> </Project>

View File

@ -1,6 +1,6 @@
using System; using System;
namespace BMapSharp { namespace BMapSharp.BMapWrapper {

View File

@ -1,7 +1,103 @@
using System; using System;
using System.Runtime.InteropServices;
using System.Numerics;
namespace BMapSharp { namespace BMapSharp.VirtoolsTypes {
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct VxVector2 {
[MarshalAs(UnmanagedType.R4)]
public float X;
[MarshalAs(UnmanagedType.R4)]
public float Y;
public VxVector2(float _x = 0.0f, float _y = 0.0f) {
this.X = _x;
this.Y = _y;
}
public VxVector2(Vector2 vec) {
this.FromManaged(vec);
}
public void FromManaged(Vector2 vec) {
this.X = vec.X;
this.Y = vec.Y;
}
public Vector2 ToManaged() {
return new Vector2(this.X, this.Y);
}
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct VxVector3 {
[MarshalAs(UnmanagedType.R4)]
public float X;
[MarshalAs(UnmanagedType.R4)]
public float Y;
[MarshalAs(UnmanagedType.R4)]
public float Z;
public VxVector3(float _x = 0.0f, float _y = 0.0f, float _z = 0.0f) {
this.X = _x;
this.Y = _y;
this.Z = _z;
}
public VxVector3(Vector3 vec) {
this.FromManaged(vec);
}
public void FromManaged(Vector3 vec) {
this.X = vec.X;
this.Y = vec.Y;
this.Z = vec.Z;
}
public Vector3 ToManaged() {
return new Vector3(this.X, this.Y, this.Z);
}
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct VxColor {
[MarshalAs(UnmanagedType.R4)]
public float A;
[MarshalAs(UnmanagedType.R4)]
public float R;
[MarshalAs(UnmanagedType.R4)]
public float G;
[MarshalAs(UnmanagedType.R4)]
public float B;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct VxVector4 {
[MarshalAs(UnmanagedType.R4)]
public float X;
[MarshalAs(UnmanagedType.R4)]
public float Y;
[MarshalAs(UnmanagedType.R4)]
public float Z;
[MarshalAs(UnmanagedType.R4)]
public float W;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct VxMatrix {
public VxVector4 x;
public VxVector4 y;
public VxVector4 z;
public VxVector4 w;
}
public struct CKFaceIndices {
[MarshalAs(UnmanagedType.U4)]
public uint I1;
[MarshalAs(UnmanagedType.U4)]
public uint I2;
[MarshalAs(UnmanagedType.U4)]
public uint I3;
public CKFaceIndices(uint i1 = 0u, uint i2 = 0u, uint i3 = 0u) {
this.I1 = i1;
this.I2 = i2;
this.I3 = i3;
}
}
} }

View File

@ -78,12 +78,13 @@ elif sys.platform.startswith('darwin'):
else: else:
_g_BMapLibName = "BMap.bin" _g_BMapLibName = "BMap.bin"
_g_BMapLibPath: str = os.path.join(os.path.dirname(__file__), _g_BMapLibName)
_g_BMapModule: ctypes.CDLL | None = None _g_BMapModule: ctypes.CDLL | None = None
try: try:
_g_BMapModule = ctypes.cdll.LoadLibrary( _g_BMapModule = ctypes.cdll.LoadLibrary(_g_BMapLibPath)
os.path.join(os.path.dirname(__file__), _g_BMapLibName)
)
except: except:
print(f'Fail to load native BMap dynamic library file "{_g_BMapLibPath}".')
_g_BMapModule = None _g_BMapModule = None
def is_bmap_available() -> bool: def is_bmap_available() -> bool:
@ -107,6 +108,8 @@ def _create_bmap_func(fct_name: str, fct_params: list[typing.Any]) -> typing.Cal
#region Function Defines #region Function Defines
##### GENERATED FUNCTIONS BEGIN #####
## BMInit ## BMInit
# @return True if no error, otherwise False. # @return True if no error, otherwise False.
BMInit = _create_bmap_func('BMInit', []) BMInit = _create_bmap_func('BMInit', [])
@ -781,5 +784,6 @@ BM3dObject_GetVisibility = _create_bmap_func('BM3dObject_GetVisibility', [bm_voi
# @return True if no error, otherwise False. # @return True if no error, otherwise False.
BM3dObject_SetVisibility = _create_bmap_func('BM3dObject_SetVisibility', [bm_void_p, bm_CKID, bm_bool]) BM3dObject_SetVisibility = _create_bmap_func('BM3dObject_SetVisibility', [bm_void_p, bm_CKID, bm_bool])
#endregion ##### GENERATED FUNCTIONS END #####
#endregion

View File

@ -52,7 +52,7 @@ public class CSharpWriter {
ret.mCsType = "string"; ret.mCsType = "string";
break; break;
case 1: case 1:
ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMashaler)"; ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler)";
ret.mCsType = "string[]"; ret.mCsType = "string[]";
break; break;
} }
@ -212,10 +212,6 @@ public class CSharpWriter {
IndentHelper helper = new IndentHelper(writer); IndentHelper helper = new IndentHelper(writer);
// write function decls // write function decls
helper.puts("");
helper.puts("#region Function Defines");
helper.puts("");
for (ExpFctDecl fctdecl : data) { for (ExpFctDecl fctdecl : data) {
// write annotation // write annotation
// summary (just plain function name) // summary (just plain function name)
@ -253,7 +249,7 @@ public class CSharpWriter {
// push MarshalAsAttribute // push MarshalAsAttribute
sb.append("MarshalAs("); sb.append("MarshalAs(");
sb.append(interop_type.mMarshalAs); sb.append(interop_type.mMarshalAs);
sb.append(") "); sb.append(")] ");
// push out keyword if parameter is out parameter // push out keyword if parameter is out parameter
if (!paramdecl.mIsInput) { if (!paramdecl.mIsInput) {
sb.append("out "); sb.append("out ");
@ -271,10 +267,6 @@ public class CSharpWriter {
cs_param_list.stream().collect(Collectors.joining(", "))); cs_param_list.stream().collect(Collectors.joining(", ")));
} }
helper.puts("");
helper.puts("#endregion");
helper.puts("");
writer.close(); writer.close();
} }

View File

@ -1,28 +1,28 @@
import java.io.FileInputStream; //import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStreamReader; //import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
public class CommonHelper { public class CommonHelper {
public static InputStreamReader openReader(String filename) throws Exception { // public static InputStreamReader openReader(String filename) throws Exception {
FileInputStream fs = new FileInputStream(filename); // FileInputStream fs = new FileInputStream(filename);
return new InputStreamReader(fs, StandardCharsets.UTF_8); // return new InputStreamReader(fs, StandardCharsets.UTF_8);
} // }
public static OutputStreamWriter openWriter(String filename) throws Exception { public static OutputStreamWriter openWriter(String filename) throws Exception {
FileOutputStream fs = new FileOutputStream(filename); FileOutputStream fs = new FileOutputStream(filename);
return new OutputStreamWriter(fs, StandardCharsets.UTF_8); return new OutputStreamWriter(fs, StandardCharsets.UTF_8);
} }
public static void writeSnippet(OutputStreamWriter writer, String snippet_path) throws Exception { // public static void writeSnippet(OutputStreamWriter writer, String snippet_path) throws Exception {
// open snippet // // open snippet
InputStreamReader reader = openReader(snippet_path); // InputStreamReader reader = openReader(snippet_path);
// write into writer // // write into writer
reader.transferTo(writer); // reader.transferTo(writer);
reader.close(); // reader.close();
} // }
public static String getDoxygenInOutStr(boolean isInput) { public static String getDoxygenInOutStr(boolean isInput) {
return isInput ? "in" : "out"; return isInput ? "in" : "out";

View File

@ -69,15 +69,7 @@ public class PythonWriter {
OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.py"); OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.py");
IndentHelper helper = new IndentHelper(writer); IndentHelper helper = new IndentHelper(writer);
// write snippet
CommonHelper.writeSnippet(writer, "snippets/header.py");
// write function decls // write function decls
helper.puts("");
helper.puts("#region Function Defines");
helper.puts("");
for (ExpFctDecl fctdecl : data) { for (ExpFctDecl fctdecl : data) {
// write annotation // write annotation
// function name // function name
@ -97,10 +89,6 @@ public class PythonWriter {
.stream().map(value -> pythonTypeGetter(value)).collect(Collectors.joining(", "))); .stream().map(value -> pythonTypeGetter(value)).collect(Collectors.joining(", ")));
} }
helper.puts("");
helper.puts("#endregion");
helper.puts("");
writer.close(); writer.close();
} }

View File

@ -1,106 +0,0 @@
import ctypes, os, sys, typing
#region Type Defines
class BMapException(Exception):
"""
The exception thrown by BMap bindings.
"""
pass
bm_CKSTRING = ctypes.c_char_p
bm_CKSTRING_p = ctypes.POINTER(bm_CKSTRING)
bm_CKDWORD = ctypes.c_uint32
bm_CKDWORD_p = ctypes.POINTER(bm_CKDWORD)
bm_CKDWORD_pp = ctypes.POINTER(bm_CKDWORD_p)
bm_CKWORD = ctypes.c_uint16
bm_CKWORD_p = ctypes.POINTER(bm_CKWORD)
bm_CKWORD_pp = ctypes.POINTER(bm_CKWORD_p)
bm_CKID = ctypes.c_uint32
bm_CKID_p = ctypes.POINTER(bm_CKID)
bm_CKID_pp = ctypes.POINTER(bm_CKID_p)
bm_CKFLOAT = ctypes.c_float
bm_CKFLOAT_p = ctypes.POINTER(bm_CKFLOAT)
bm_CKINT = ctypes.c_int32
bm_CKBYTE = ctypes.c_uint8
bm_CKBYTE_p = ctypes.POINTER(bm_CKBYTE)
bm_enum = bm_CKDWORD
bm_enum_p = ctypes.POINTER(bm_enum)
bm_bool = ctypes.c_bool
bm_bool_p = ctypes.POINTER(bm_bool)
bm_void_p = ctypes.c_void_p
bm_void_pp = ctypes.POINTER(ctypes.c_void_p)
bm_callback = ctypes.CFUNCTYPE(None, bm_CKSTRING)
class bm_VxVector2(ctypes.Structure):
_fields_ = [
('x', bm_CKFLOAT),
('y', bm_CKFLOAT),
]
bm_VxVector2_p = ctypes.POINTER(bm_VxVector2)
bm_VxVector2_pp = ctypes.POINTER(bm_VxVector2_p)
class bm_VxVector3(ctypes.Structure):
_fields_ = [
('x', bm_CKFLOAT),
('y', bm_CKFLOAT),
('z', bm_CKFLOAT),
]
bm_VxVector3_p = ctypes.POINTER(bm_VxVector3)
bm_VxVector3_pp = ctypes.POINTER(bm_VxVector3_p)
class bm_VxColor(ctypes.Structure):
_fields_ = [
('r', bm_CKFLOAT),
('g', bm_CKFLOAT),
('b', bm_CKFLOAT),
('a', bm_CKFLOAT),
]
bm_VxColor_p = ctypes.POINTER(bm_VxColor)
class bm_VxMatrix(ctypes.Structure):
_fields_ = list(
(f'i{idx}', bm_CKFLOAT) for idx in range(16)
)
bm_VxMatrix_p = ctypes.POINTER(bm_VxMatrix)
#endregion
#region BMap Loader
_g_BMapLibName: str
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
_g_BMapLibName = "BMap.dll"
elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):
_g_BMapLibName = "BMap.so"
elif sys.platform.startswith('darwin'):
_g_BMapLibName = "BMap.dylib"
else:
_g_BMapLibName = "BMap.bin"
_g_BMapModule: ctypes.CDLL | None = None
try:
_g_BMapModule = ctypes.cdll.LoadLibrary(
os.path.join(os.path.dirname(__file__), _g_BMapLibName)
)
except:
_g_BMapModule = None
def is_bmap_available() -> bool:
return _g_BMapModule is not None
def _bmap_error_check(result: bool, func, args):
if not result:
raise BMapException("BMap operation failed.")
return result
def _create_bmap_func(fct_name: str, fct_params: list[typing.Any]) -> typing.Callable[..., bm_bool]:
if _g_BMapModule is None: return None
cache: typing.Callable[..., bm_bool] = getattr(_g_BMapModule, fct_name)
cache.argtypes = fct_params
cache.restype = bm_bool
cache.errcheck = _bmap_error_check
return cache
#endregion