expose lit mode interface in CKMesh.

- provide lit mode and wrap mode getter and setter in CKMesh.
- add lost flags setter in CKMesh.
- show lit mode and wrap mode data in Unvirt.
- add interface for lit mode in BMap, because some old Ballance map use lit mode to light objects.
- expose a raw c callback when creating bmap to allow user decide how the log output by themselves.
- change python bindings for BMap interface changes.
This commit is contained in:
yyc12345 2023-11-15 21:47:58 +08:00
parent c55e334ead
commit d8b7ace53d
14 changed files with 173 additions and 8 deletions

View File

@ -98,13 +98,14 @@ bool BMFile_Load(
BMPARAM_IN(LibCmo::CKSTRING, file_name),
BMPARAM_IN(LibCmo::CKSTRING, temp_folder),
BMPARAM_IN(LibCmo::CKSTRING, texture_folder),
BMPARAM_IN(BMap::NakedOutputCallback, raw_callback),
BMPARAM_IN(LibCmo::CKDWORD, encoding_count),
BMPARAM_IN(LibCmo::CKSTRING*, encodings),
BMPARAM_OUT(BMap::BMFile*, out_file)) {
if (!CheckInited()) return false;
// create a now one and try to load data.
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, encoding_count, encodings, true));
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, raw_callback, encoding_count, encodings, true));
if (file->IsInitError()) return false;
if (!file->Load(file_name)) return false;
@ -117,13 +118,14 @@ bool BMFile_Load(
bool BMFile_Create(
BMPARAM_IN(LibCmo::CKSTRING, temp_folder),
BMPARAM_IN(LibCmo::CKSTRING, texture_folder),
BMPARAM_IN(BMap::NakedOutputCallback, raw_callback),
BMPARAM_IN(LibCmo::CKDWORD, encoding_count),
BMPARAM_IN(LibCmo::CKSTRING*, encodings),
BMPARAM_OUT(BMap::BMFile*, out_file)) {
if (!CheckInited()) return false;
// create a now one
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, encoding_count, encodings, false));
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, raw_callback, encoding_count, encodings, false));
if (file->IsInitError()) return false;
// add into list and return if success
@ -719,6 +721,21 @@ bool BMMaterial_SetZFunc(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::
#pragma region CKMesh
LIBCMO_EXPORT bool BMMesh_GetLitMode(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VXMESH_LITMODE, out_mode)) {
auto obj = CheckCKMesh(bmfile, objid);
if (obj == nullptr) return false;
BMPARAM_OUT_ASSIGN(out_mode, obj->GetLitMode());
return true;
}
LIBCMO_EXPORT bool BMMesh_SetLitMode(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::VxMath::VXMESH_LITMODE, mode)) {
auto obj = CheckCKMesh(bmfile, objid);
if (obj == nullptr) return false;
obj->SetLitMode(mode);
return true;
}
bool BMMesh_GetVertexCount(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::CKDWORD, out_count)) {
auto obj = CheckCKMesh(bmfile, objid);
if (obj == nullptr) return false;

View File

@ -74,6 +74,7 @@ LIBCMO_EXPORT bool BMFile_Load(
BMPARAM_IN(LibCmo::CKSTRING, file_name),
BMPARAM_IN(LibCmo::CKSTRING, temp_folder),
BMPARAM_IN(LibCmo::CKSTRING, texture_folder),
BMPARAM_IN(BMap::NakedOutputCallback, raw_callback),
BMPARAM_IN(LibCmo::CKDWORD, encoding_count),
BMPARAM_IN(LibCmo::CKSTRING*, encodings),
BMPARAM_OUT(BMap::BMFile*, out_file)
@ -81,6 +82,7 @@ LIBCMO_EXPORT bool BMFile_Load(
LIBCMO_EXPORT bool BMFile_Create(
BMPARAM_IN(LibCmo::CKSTRING, temp_folder),
BMPARAM_IN(LibCmo::CKSTRING, texture_folder),
BMPARAM_IN(BMap::NakedOutputCallback, raw_callback),
BMPARAM_IN(LibCmo::CKDWORD, encoding_count),
BMPARAM_IN(LibCmo::CKSTRING*, encodings),
BMPARAM_OUT(BMap::BMFile*, out_file)
@ -219,6 +221,9 @@ LIBCMO_EXPORT bool BMMaterial_SetZFunc(BMPARAM_OBJECT_DECL(bmfile, objid), BMPAR
#pragma region CKMesh
LIBCMO_EXPORT bool BMMesh_GetLitMode(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VXMESH_LITMODE, out_mode));
LIBCMO_EXPORT bool BMMesh_SetLitMode(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::VxMath::VXMESH_LITMODE, mode));
LIBCMO_EXPORT bool BMMesh_GetVertexCount(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::CKDWORD, out_count));
LIBCMO_EXPORT bool BMMesh_SetVertexCount(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::CKDWORD, count));
LIBCMO_EXPORT bool BMMesh_GetVertexPositions(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VxVector3*, out_mem));

View File

@ -231,13 +231,23 @@ namespace BMap {
#pragma region BMfile
BMFile::BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_loader) :
BMFile::BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, NakedOutputCallback raw_callback, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_loader) :
m_IsInitError(false), m_IsLoader(is_loader), m_HasLoaded(false), m_HasSaved(false), m_Context(nullptr) {
m_Context = new LibCmo::CK2::CKContext();
// binding callback with lambda wrapper.
// check whether callback is nullptr.
m_IsInitError = m_IsInitError || (raw_callback == nullptr);
if (raw_callback != nullptr) {
m_Context->SetOutputCallback([raw_callback](LibCmo::CKSTRING strl) -> void {
raw_callback(strl);
});
}
// set temp folder and texture folder
auto pm = m_Context->GetPathManager();
m_IsInitError = m_IsInitError || !pm->AddPath(texture_folder);
m_IsInitError = m_IsInitError || !pm->SetTempFolder(temp_folder);
// set encoding
LibCmo::XContainer::XArray<LibCmo::XContainer::XString> cache;
for (LibCmo::CKDWORD i = 0; i < encoding_count; ++i) {

View File

@ -8,9 +8,11 @@
namespace BMap {
using NakedOutputCallback = void(*)(LibCmo::CKSTRING);
class BMFile {
public:
BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_reader);
BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, NakedOutputCallback raw_callback, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_reader);
~BMFile();
LIBCMO_DISABLE_COPY_MOVE(BMFile);

View File

@ -32,6 +32,8 @@ 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),
@ -104,19 +106,21 @@ BMDispose = _create_bmap_func('BMDispose', [])
# @param file_name[in] Type: LibCmo::CKSTRING.
# @param temp_folder[in] Type: LibCmo::CKSTRING.
# @param texture_folder[in] Type: LibCmo::CKSTRING.
# @param raw_callback[in] Type: BMap::NakedOutputCallback.
# @param encoding_count[in] Type: LibCmo::CKDWORD.
# @param encodings[in] Type: LibCmo::CKSTRING*.
# @param out_file[out] Type: BMap::BMFile*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_Load = _create_bmap_func('BMFile_Load', [bm_CKSTRING, bm_CKSTRING, bm_CKSTRING, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp])
BMFile_Load = _create_bmap_func('BMFile_Load', [bm_CKSTRING, bm_CKSTRING, bm_CKSTRING, bm_callback, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp])
## BMFile_Create
# @param temp_folder[in] Type: LibCmo::CKSTRING.
# @param texture_folder[in] Type: LibCmo::CKSTRING.
# @param raw_callback[in] Type: BMap::NakedOutputCallback.
# @param encoding_count[in] Type: LibCmo::CKDWORD.
# @param encodings[in] Type: LibCmo::CKSTRING*.
# @param out_file[out] Type: BMap::BMFile*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_Create = _create_bmap_func('BMFile_Create', [bm_CKSTRING, bm_CKSTRING, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp])
BMFile_Create = _create_bmap_func('BMFile_Create', [bm_CKSTRING, bm_CKSTRING, bm_callback, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp])
## BMFile_Save
# @param map_file[in] Type: BMap::BMFile*.
# @param file_name[in] Type: LibCmo::CKSTRING.
@ -635,6 +639,18 @@ BMMaterial_GetZFunc = _create_bmap_func('BMMaterial_GetZFunc', [bm_void_p, bm_CK
# @param val[in] Type: LibCmo::VxMath::VXCMPFUNC.
# @return True if no error, otherwise False.
BMMaterial_SetZFunc = _create_bmap_func('BMMaterial_SetZFunc', [bm_void_p, bm_CKID, bm_enum])
## BMMesh_GetLitMode
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.
# @param out_mode[out] Type: LibCmo::VxMath::VXMESH_LITMODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetLitMode = _create_bmap_func('BMMesh_GetLitMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMesh_SetLitMode
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.
# @param mode[in] Type: LibCmo::VxMath::VXMESH_LITMODE.
# @return True if no error, otherwise False.
BMMesh_SetLitMode = _create_bmap_func('BMMesh_SetLitMode', [bm_void_p, bm_CKID, bm_enum])
## BMMesh_GetVertexCount
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.

View File

@ -7,6 +7,17 @@ g_InvalidPtr: bmap.bm_void_p = bmap.bm_void_p(0)
g_InvalidCKID: int = 0
g_BMapEncoding: str = "utf-8"
def python_callback(strl: bytes):
"""
The Python type callback for BMFile.
Simply add a prefix when output.
Need a convertion before passing to BMFile.
"""
# the passing value is bytes, not bmap.bm_CKSTRING.
# i think Python do a auto convertion here.
if strl is not None:
print(f'[PyBMap] {strl.decode(g_BMapEncoding)}')
class _AbstractPointer():
__mRawPointer: int
@ -398,6 +409,16 @@ class BMMaterial(BMObject):
bmap.BMMaterial_SetZFunc(self._get_pointer(), self._get_ckid(), data)
class BMMesh(BMObject):
def get_lit_mode(self) -> virtools_types.VXMESH_LITMODE:
mode: bmap.bm_enum = bmap.bm_enum()
bmap.BMMesh_GetLitMode(self._get_pointer(), self._get_ckid(), ctypes.byref(mode))
return virtools_types.VXMESH_LITMODE(mode.value)
def set_lit_mode(self, mode: virtools_types.VXMESH_LITMODE) -> None:
mode: bmap.bm_enum = bmap.bm_enum(mode.value)
bmap.BMMesh_SetLitMode(self._get_pointer(), self._get_ckid(), mode)
def get_vertex_count(self) -> int:
count: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
bmap.BMMesh_GetVertexCount(self._get_pointer(), self._get_ckid(), ctypes.byref(count))
@ -569,6 +590,7 @@ class BMFileReader(_AbstractPointer):
file_name: bmap.bm_CKSTRING = bmap.bm_CKSTRING(file_name_.encode(g_BMapEncoding))
temp_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(temp_folder_.encode(g_BMapEncoding))
texture_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(texture_folder_.encode(g_BMapEncoding))
raw_callback: bmap.bm_callback = bmap.bm_callback(python_callback)
encoding_count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(len(encodings_))
encodings: ctypes.Array = (bmap.bm_CKSTRING * len(encodings_))(
*(strl.encode(g_BMapEncoding) for strl in encodings_)
@ -576,7 +598,8 @@ class BMFileReader(_AbstractPointer):
out_file: bmap.bm_void_p = bmap.bm_void_p()
# exec
bmap.BMFile_Load(
file_name, temp_folder, texture_folder, encoding_count, encodings,
file_name, temp_folder, texture_folder, raw_callback,
encoding_count, encodings,
ctypes.byref(out_file)
)
# init self
@ -666,6 +689,7 @@ class BMFileWriter(_AbstractPointer):
# create param
temp_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(temp_folder_.encode(g_BMapEncoding))
texture_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(texture_folder_.encode(g_BMapEncoding))
raw_callback: bmap.bm_callback = bmap.bm_callback(python_callback)
encoding_count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(len(encodings_))
encodings: ctypes.Array = (bmap.bm_CKSTRING * len(encodings_))(
*(strl.encode(g_BMapEncoding) for strl in encodings_)
@ -673,7 +697,8 @@ class BMFileWriter(_AbstractPointer):
out_file: bmap.bm_void_p = bmap.bm_void_p()
# exec
bmap.BMFile_Create(
temp_folder, texture_folder, encoding_count, encodings,
temp_folder, texture_folder, raw_callback,
encoding_count, encodings,
ctypes.byref(out_file)
)
# init self

View File

@ -304,3 +304,15 @@ class VXCMPFUNC(enum.IntEnum):
VXCMP_NOTEQUAL = 6 ##< Accept if value if different than current value.
VXCMP_GREATEREQUAL = 7 ##< Accept if value if greater or equal current value.
VXCMP_ALWAYS = 8 ##< Always accept the test.
class VXMESH_LITMODE(enum.IntEnum):
"""!
{filename:VXMESH_LITMODE}
Summary: Mesh lighting options
Remarks:
+ The VXMESH_LITMODE is used by CKMesh::SetLitMode to specify how lighting is done.
See Also: CKMaterial,CKMesh
"""
VX_PRELITMESH = 0 ##< Lighting use color information store with vertices
VX_LITMESH = 1 ##< Lighting is done by renderer using normals and face material information.

View File

@ -19,6 +19,7 @@ public class PythonWriter {
cache.put("CKFLOAT", "CKFLOAT");
cache.put("CKBYTE", "CKBYTE");
cache.put("CK_ID", "CKID");
cache.put("NakedOutputCallback", "callback");
cache.put("BMFile", "void");
cache.put("BMMeshTransition", "void");
cache.put("VxVector3", "VxVector3");
@ -34,6 +35,7 @@ public class PythonWriter {
cache.put("VXFILL_MODE", "enum");
cache.put("VXSHADE_MODE", "enum");
cache.put("VXCMPFUNC", "enum");
cache.put("VXMESH_LITMODE", "enum");
return Collections.unmodifiableMap(cache);
}

View File

@ -32,6 +32,8 @@ 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),

View File

@ -433,6 +433,64 @@ namespace LibCmo::CK2::ObjImpls {
return m_Flags;
}
void CKMesh::SetMeshFlags(VxMath::VXMESH_FLAGS flags) {
// set value
m_Flags = flags;
// sync visibility to CKObject layer.
if (EnumsHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_VISIBLE)) {
EnumsHelper::Add(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
} else {
EnumsHelper::Rm(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
}
}
VxMath::VXMESH_LITMODE CKMesh::GetLitMode() const {
if (EnumsHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PRELITMODE)) {
return VxMath::VXMESH_LITMODE::VX_PRELITMESH;
} else {
return VxMath::VXMESH_LITMODE::VX_LITMESH;
}
}
void CKMesh::SetLitMode(VxMath::VXMESH_LITMODE mode) {
switch (mode) {
case VxMath::VXMESH_LITMODE::VX_PRELITMESH:
EnumsHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PRELITMODE);
break;
case VxMath::VXMESH_LITMODE::VX_LITMESH:
EnumsHelper::Rm(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PRELITMODE);
break;
}
}
VxMath::VXTEXTURE_WRAPMODE CKMesh::GetWrapMode() const {
VxMath::VXTEXTURE_WRAPMODE ret = VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_NONE;
if (EnumsHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPU)) {
EnumsHelper::Add(ret, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_U);
}
if (EnumsHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPV)) {
EnumsHelper::Add(ret, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_V);
}
return ret;
}
void CKMesh::SetWrapMode(VxMath::VXTEXTURE_WRAPMODE mode) {
if (EnumsHelper::Has(mode, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_U)) {
EnumsHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPU);
} else {
EnumsHelper::Rm(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPU);
}
if (EnumsHelper::Has(mode, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_V)) {
EnumsHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPV);
} else {
EnumsHelper::Rm(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPV);
}
}
CKMesh::VertexSaveFlags CKMesh::GenerateSaveFlags() {
// set to initial status
VertexSaveFlags saveflags = EnumsHelper::Merge({

View File

@ -38,6 +38,11 @@ namespace LibCmo::CK2::ObjImpls {
public:
void CleanMesh();
VxMath::VXMESH_FLAGS GetMeshFlags() const;
void SetMeshFlags(VxMath::VXMESH_FLAGS flags);
VxMath::VXMESH_LITMODE GetLitMode() const;
void SetLitMode(VxMath::VXMESH_LITMODE mode);
VxMath::VXTEXTURE_WRAPMODE GetWrapMode() const;
void SetWrapMode(VxMath::VXTEXTURE_WRAPMODE mode);
protected:
VertexSaveFlags GenerateSaveFlags();
void BuildNormals();

View File

@ -511,6 +511,10 @@ namespace Unvirt::AccessibleValue {
{ LibCmo::VxMath::VXMESH_FLAGS::VXMESH_BWEIGHTS_CHANGED, {"VXMESH_BWEIGHTS_CHANGED"} },
{ LibCmo::VxMath::VXMESH_FLAGS::VXMESH_ALLFLAGS, {"VXMESH_ALLFLAGS"} },
};
const GeneralReflectionArray<LibCmo::VxMath::VXMESH_LITMODE> VXMESH_LITMODE {
{ LibCmo::VxMath::VXMESH_LITMODE::VX_PRELITMESH, {"VX_PRELITMESH"} },
{ LibCmo::VxMath::VXMESH_LITMODE::VX_LITMESH, {"VX_LITMESH"} },
};
const GeneralReflectionArray<LibCmo::VxMath::VXTEXTURE_WRAPMODE> VXTEXTURE_WRAPMODE {
{ LibCmo::VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_NONE, {"VXTEXTUREWRAP_NONE"} },
{ LibCmo::VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_U, {"VXTEXTUREWRAP_U"} },

View File

@ -96,6 +96,7 @@ namespace Unvirt {
extern const GeneralReflectionArray<LibCmo::VxMath::VX_EFFECT> VX_EFFECT;
extern const GeneralReflectionArray<LibCmo::VxMath::VX_MOVEABLE_FLAGS> VX_MOVEABLE_FLAGS;
extern const GeneralReflectionArray<LibCmo::VxMath::VXMESH_FLAGS> VXMESH_FLAGS;
extern const GeneralReflectionArray<LibCmo::VxMath::VXMESH_LITMODE> VXMESH_LITMODE;
extern const GeneralReflectionArray<LibCmo::VxMath::VXTEXTURE_WRAPMODE> VXTEXTURE_WRAPMODE;
}

View File

@ -316,6 +316,12 @@ namespace Unvirt::StructFormatter {
fputs("Mesh Flags:\n", stdout);
fputs(AccessibleValue::GetFlagEnumName(obj->GetMeshFlags(), AccessibleValue::EnumDesc::VXMESH_FLAGS, "\n").c_str(), stdout);
fputc('\n', stdout);
fputs("Lit Mode: ", stdout);
fputs(AccessibleValue::GetEnumName(obj->GetLitMode(), AccessibleValue::EnumDesc::VXMESH_LITMODE).c_str(), stdout);
fputc('\n', stdout);
fputs("Wrap Mode: ", stdout);
fputs(AccessibleValue::GetEnumName(obj->GetWrapMode(), AccessibleValue::EnumDesc::VXTEXTURE_WRAPMODE).c_str(), stdout);
fputc('\n', stdout);
// vertex data
fputs("== Vertex ==\n", stdout);