finish BuildNormals
This commit is contained in:
parent
be6cbc5692
commit
2d190ea30b
|
@ -35,6 +35,11 @@ def GetTmplOperOffset(sname: str, svars: tuple[str]) -> str:
|
|||
\t\t\t{sp.join(map(lambda x: f'case {x}: return {svars[x]};', range(len(svars))))}
|
||||
\t\t\tdefault: return {svars[0]};
|
||||
\t\t}}
|
||||
\t}}\tconst CKFLOAT& operator[](size_t i) const {{
|
||||
\t\tswitch (i) {{
|
||||
\t\t\t{sp.join(map(lambda x: f'case {x}: return {svars[x]};', range(len(svars))))}
|
||||
\t\t\tdefault: return {svars[0]};
|
||||
\t\t}}
|
||||
\t}}"""
|
||||
|
||||
def GetTmplOperAddMinus(sname: str, svars: tuple[str], oper: str) -> str:
|
||||
|
@ -58,6 +63,9 @@ def GetTmplOperMul(sname: str, svars: tuple[str]) -> str:
|
|||
\t}}
|
||||
\tfriend {sname} operator*(CKFLOAT lhs, const {sname}& rhs) {{
|
||||
\t\treturn {sname}({', '.join(map(lambda x: f'lhs * rhs.{x}', svars))});
|
||||
\t}}
|
||||
\tfriend CKFLOAT operator*(const {sname}& lhs, const {sname}& rhs) {{
|
||||
\t\treturn ({' + '.join(map(lambda x: f'lhs.{x} * rhs.{x}', svars))});
|
||||
\t}}"""
|
||||
|
||||
def GetTmplOperDiv(sname: str, svars: tuple[str]) -> str:
|
||||
|
@ -73,7 +81,6 @@ def GetTmplOperDiv(sname: str, svars: tuple[str]) -> str:
|
|||
\t}}"""
|
||||
|
||||
def GetTmplOperEqual(sname: str, svars: tuple[str]) -> str:
|
||||
sp: str = '\n\t\t'
|
||||
return f"""\tbool operator==(const {sname}& rhs) const {{
|
||||
\t\treturn ({' && '.join(map(lambda x: f'{x} == rhs.{x}', svars))});
|
||||
\t}}
|
||||
|
@ -81,6 +88,27 @@ def GetTmplOperEqual(sname: str, svars: tuple[str]) -> str:
|
|||
\t\treturn !(*this == rhs);
|
||||
\t}}"""
|
||||
|
||||
def GetTmplLength(sname: str, svars: tuple[str]) -> str:
|
||||
return f"""\tCKFLOAT SquaredLength() const {{
|
||||
\t\treturn ({' + '.join(map(lambda x: f'{x} * {x}', svars))});
|
||||
\t}}
|
||||
\tCKFLOAT Length() const {{
|
||||
\t\treturn std::sqrt(SquaredLength());
|
||||
\t}}"""
|
||||
|
||||
def GetTmplNormalize(sname: str, svars: tuple[str]) -> str:
|
||||
sp: str = '\n\t\t'
|
||||
return f"""\tvoid Normalized() {{
|
||||
\t\tCKFLOAT len = Length();
|
||||
\t\tif (len == 0.0f) return;
|
||||
\t\t{sp.join(map(lambda x: f'{x} /= len;', svars))}
|
||||
\t}}
|
||||
\t{sname} Normalize() const {{
|
||||
\t\tCKFLOAT len = Length();
|
||||
\t\tif (len == 0.0f) return {sname}();
|
||||
\t\treturn {sname}({', '.join(map(lambda x: f'{x} / len', svars))});
|
||||
\t}}"""
|
||||
|
||||
def GetTmplVector(sname: str, svars: tuple[str]) -> str:
|
||||
return f"""
|
||||
struct {sname} {{
|
||||
|
@ -94,6 +122,8 @@ struct {sname} {{
|
|||
{GetTmplOperMul(sname, svars)}
|
||||
{GetTmplOperDiv(sname, svars)}
|
||||
{GetTmplOperEqual(sname, svars)}
|
||||
{GetTmplLength(sname, svars)}
|
||||
{GetTmplNormalize(sname, svars)}
|
||||
}};
|
||||
"""
|
||||
|
||||
|
|
|
@ -226,6 +226,8 @@ namespace LibCmo::CK2::ObjImpls {
|
|||
return true;
|
||||
}
|
||||
|
||||
#pragma region Misc Section
|
||||
|
||||
void CKMesh::CleanMesh() {
|
||||
// clear material channel first
|
||||
SetMtlChannelCount(0);
|
||||
|
@ -236,9 +238,46 @@ namespace LibCmo::CK2::ObjImpls {
|
|||
SetLineCount(0);
|
||||
}
|
||||
|
||||
void CKMesh::BuildNormals() {}
|
||||
void CKMesh::BuildNormals() {
|
||||
if (m_FaceCount == 0 || m_VertexCount == 0) return;
|
||||
|
||||
void CKMesh::BuildFaceNormals() {}
|
||||
// build face normal first
|
||||
BuildFaceNormals();
|
||||
|
||||
// iterate all face and add face normal to each point's normal
|
||||
for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) {
|
||||
m_VertexNormal[m_FaceIndices[fid * 3]] += m_Faces[fid].m_Normal;
|
||||
m_VertexNormal[m_FaceIndices[fid * 3 + 1]] += m_Faces[fid].m_Normal;
|
||||
m_VertexNormal[m_FaceIndices[fid * 3 + 2]] += m_Faces[fid].m_Normal;
|
||||
}
|
||||
|
||||
// then normalize all vertex normal
|
||||
for (auto& nml : m_VertexNormal) {
|
||||
nml.Normalized();
|
||||
}
|
||||
}
|
||||
|
||||
void CKMesh::BuildFaceNormals() {
|
||||
if (m_FaceCount == 0 || m_VertexCount == 0) return;
|
||||
|
||||
// iertate all face to build face normal according to position data
|
||||
for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) {
|
||||
VxMath::VxVector3 *p0 = &m_VertexPosition[m_FaceIndices[fid * 3]];
|
||||
|
||||
VxMath::VxVector3 p0_p1 = m_VertexPosition[m_FaceIndices[fid * 3 + 1]] - *p0,
|
||||
p0_p2 = m_VertexPosition[m_FaceIndices[fid * 3 + 2]] - *p0;
|
||||
|
||||
// cross product to get normal
|
||||
// and normalize it
|
||||
VxMath::VxVector3 nml = VxMath::NSVxVector::CrossProduct(p0_p1, p0_p2);
|
||||
nml.Normalized();
|
||||
|
||||
// assign it
|
||||
m_Faces[fid].m_Normal = nml;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Vertex Section
|
||||
|
||||
|
|
|
@ -124,6 +124,33 @@ namespace LibCmo::VxMath {
|
|||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Patched
|
||||
|
||||
namespace NSVxVector {
|
||||
|
||||
float LibCmo::VxMath::NSVxVector::DotProduct(const VxVector2& lhs, const VxVector2& rhs) {
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
float LibCmo::VxMath::NSVxVector::DotProduct(const VxVector3& lhs, const VxVector3& rhs) {
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
float LibCmo::VxMath::NSVxVector::DotProduct(const VxVector4& lhs, const VxVector4& rhs) {
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
VxVector3 CrossProduct(const VxVector3& lhs, const VxVector3& rhs) {
|
||||
return VxVector3(
|
||||
lhs.y * rhs.z - lhs.z * rhs.y,
|
||||
lhs.z * rhs.x - lhs.x * rhs.z,
|
||||
lhs.x * rhs.y - lhs.y * rhs.x
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -83,5 +83,18 @@ namespace LibCmo::VxMath {
|
|||
*/
|
||||
void VxDoAlphaBlit(VxImageDescEx* dst_desc, const CKBYTE* AlphaValues);
|
||||
|
||||
|
||||
// ========== Patch Section ==========
|
||||
|
||||
namespace NSVxVector {
|
||||
|
||||
CKFLOAT DotProduct(const VxVector2& lhs, const VxVector2& rhs);
|
||||
CKFLOAT DotProduct(const VxVector3& lhs, const VxVector3& rhs);
|
||||
CKFLOAT DotProduct(const VxVector4& lhs, const VxVector4& rhs);
|
||||
|
||||
VxVector3 CrossProduct(const VxVector3& lhs, const VxVector3& rhs);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
* @brief The VxMath part of LibCmo.
|
||||
|
@ -35,6 +36,12 @@ namespace LibCmo::VxMath {
|
|||
case 1: return y;
|
||||
default: return x;
|
||||
}
|
||||
} const CKFLOAT& operator[](size_t i) const {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
default: return x;
|
||||
}
|
||||
}
|
||||
VxVector2& operator+=(const VxVector2& rhs) {
|
||||
x += rhs.x;
|
||||
|
@ -63,6 +70,9 @@ namespace LibCmo::VxMath {
|
|||
friend VxVector2 operator*(CKFLOAT lhs, const VxVector2& rhs) {
|
||||
return VxVector2(lhs * rhs.x, lhs * rhs.y);
|
||||
}
|
||||
friend CKFLOAT operator*(const VxVector2& lhs, const VxVector2& rhs) {
|
||||
return (lhs.x * rhs.x + lhs.y * rhs.y);
|
||||
}
|
||||
VxVector2& operator/=(CKFLOAT rhs) {
|
||||
if (rhs == 0.0f) return *this;
|
||||
x /= rhs;
|
||||
|
@ -79,6 +89,23 @@ namespace LibCmo::VxMath {
|
|||
bool operator!=(const VxVector2& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
CKFLOAT SquaredLength() const {
|
||||
return (x * x + y * y);
|
||||
}
|
||||
CKFLOAT Length() const {
|
||||
return std::sqrt(SquaredLength());
|
||||
}
|
||||
void Normalized() {
|
||||
CKFLOAT len = Length();
|
||||
if (len == 0.0f) return;
|
||||
x /= len;
|
||||
y /= len;
|
||||
}
|
||||
VxVector2 Normalize() const {
|
||||
CKFLOAT len = Length();
|
||||
if (len == 0.0f) return VxVector2();
|
||||
return VxVector2(x / len, y / len);
|
||||
}
|
||||
};
|
||||
|
||||
struct VxVector3 {
|
||||
|
@ -93,6 +120,13 @@ namespace LibCmo::VxMath {
|
|||
case 2: return z;
|
||||
default: return x;
|
||||
}
|
||||
} const CKFLOAT& operator[](size_t i) const {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
default: return x;
|
||||
}
|
||||
}
|
||||
VxVector3& operator+=(const VxVector3& rhs) {
|
||||
x += rhs.x;
|
||||
|
@ -124,6 +158,9 @@ namespace LibCmo::VxMath {
|
|||
friend VxVector3 operator*(CKFLOAT lhs, const VxVector3& rhs) {
|
||||
return VxVector3(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
|
||||
}
|
||||
friend CKFLOAT operator*(const VxVector3& lhs, const VxVector3& rhs) {
|
||||
return (lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z);
|
||||
}
|
||||
VxVector3& operator/=(CKFLOAT rhs) {
|
||||
if (rhs == 0.0f) return *this;
|
||||
x /= rhs;
|
||||
|
@ -141,6 +178,24 @@ namespace LibCmo::VxMath {
|
|||
bool operator!=(const VxVector3& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
CKFLOAT SquaredLength() const {
|
||||
return (x * x + y * y + z * z);
|
||||
}
|
||||
CKFLOAT Length() const {
|
||||
return std::sqrt(SquaredLength());
|
||||
}
|
||||
void Normalized() {
|
||||
CKFLOAT len = Length();
|
||||
if (len == 0.0f) return;
|
||||
x /= len;
|
||||
y /= len;
|
||||
z /= len;
|
||||
}
|
||||
VxVector3 Normalize() const {
|
||||
CKFLOAT len = Length();
|
||||
if (len == 0.0f) return VxVector3();
|
||||
return VxVector3(x / len, y / len, z / len);
|
||||
}
|
||||
};
|
||||
|
||||
struct VxVector4 {
|
||||
|
@ -156,6 +211,14 @@ namespace LibCmo::VxMath {
|
|||
case 3: return w;
|
||||
default: return x;
|
||||
}
|
||||
} const CKFLOAT& operator[](size_t i) const {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
case 3: return w;
|
||||
default: return x;
|
||||
}
|
||||
}
|
||||
VxVector4& operator+=(const VxVector4& rhs) {
|
||||
x += rhs.x;
|
||||
|
@ -190,6 +253,9 @@ namespace LibCmo::VxMath {
|
|||
friend VxVector4 operator*(CKFLOAT lhs, const VxVector4& rhs) {
|
||||
return VxVector4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
|
||||
}
|
||||
friend CKFLOAT operator*(const VxVector4& lhs, const VxVector4& rhs) {
|
||||
return (lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z + lhs.w * rhs.w);
|
||||
}
|
||||
VxVector4& operator/=(CKFLOAT rhs) {
|
||||
if (rhs == 0.0f) return *this;
|
||||
x /= rhs;
|
||||
|
@ -208,6 +274,25 @@ namespace LibCmo::VxMath {
|
|||
bool operator!=(const VxVector4& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
CKFLOAT SquaredLength() const {
|
||||
return (x * x + y * y + z * z + w * w);
|
||||
}
|
||||
CKFLOAT Length() const {
|
||||
return std::sqrt(SquaredLength());
|
||||
}
|
||||
void Normalized() {
|
||||
CKFLOAT len = Length();
|
||||
if (len == 0.0f) return;
|
||||
x /= len;
|
||||
y /= len;
|
||||
z /= len;
|
||||
w /= len;
|
||||
}
|
||||
VxVector4 Normalize() const {
|
||||
CKFLOAT len = Length();
|
||||
if (len == 0.0f) return VxVector4();
|
||||
return VxVector4(x / len, y / len, z / len, w / len);
|
||||
}
|
||||
};
|
||||
|
||||
struct VxQuaternion {
|
||||
|
@ -259,7 +344,7 @@ namespace LibCmo::VxMath {
|
|||
if (r > 1.0f) r = 1.0f;
|
||||
else if (r < 0.0f) r = 0.0f;
|
||||
if (g > 1.0f) g = 1.0f;
|
||||
else if (g < 0.0f) g= 0.0f;
|
||||
else if (g < 0.0f) g = 0.0f;
|
||||
if (b > 1.0f) b = 1.0f;
|
||||
else if (b < 0.0f) b = 0.0f;
|
||||
if (a > 1.0f) a = 1.0f;
|
||||
|
@ -309,8 +394,7 @@ namespace LibCmo::VxMath {
|
|||
public:
|
||||
VxStridedData(_Ty ptr, CKDWORD stride) :
|
||||
m_Ptr(reinterpret_cast<CKBYTE*>(m_Ptr)),
|
||||
m_Stride(stride)
|
||||
{}
|
||||
m_Stride(stride) {}
|
||||
~VxStridedData() {}
|
||||
|
||||
_Ty operator[](size_t idx) {
|
||||
|
@ -433,7 +517,7 @@ namespace LibCmo::VxMath {
|
|||
m_Width != 0u &&
|
||||
m_Height != 0u &&
|
||||
m_Image != nullptr
|
||||
);
|
||||
);
|
||||
}
|
||||
bool IsHWEqual(const VxImageDescEx& rhs) const {
|
||||
return (m_Width == rhs.m_Width && m_Height == rhs.m_Height);
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
# Tools
|
||||
|
||||
The developer need to know the loaded data whether is correct when testing LibCmo. So we create this folder and you can use Unvirt and the tools located in this folder to test the correction of loaded data.
|
||||
|
||||
Unvirt can show the data of each CKObject, such as Texture, Mesh and etc. For example, Unvirt can provide vertex's position, normal, UV, even the face's indices data for CKMesh. You can use tools to broswer memory to get them, but you couldn't evaluate them how they shape a mesh. This is the reason why this folder existed and in this README I will tell you how to debug the loaded data.
|
||||
|
||||
I suggest you to use HxD to broswer memory, but if you have other softwares, use it freely.
|
||||
|
||||
## CKTexture
|
||||
|
||||
* Install [PixelViewer](https://github.com/carina-studio/PixelViewer) first.
|
||||
* Change profile to `BGRA_8888` (actually is little-endian RGBA8888, but I think the developer of PixelViewer get confused).
|
||||
* The image resolution can be gotten from Uvirt. Set it in PixelViewer.
|
||||
* The image address also can be gotten from Unvirt. Save the memory image data to local file and open it by PixelViewer.
|
||||
|
||||
## CKMesh
|
||||
|
||||
* Have a executable Python.
|
||||
* Save VertexPosition, VertexNormal, VertexUV, FaceIndices data into file according to the given memory address by Unvirt.
|
||||
* Call `MeshConv.py`, set the argument properly, then you will get a converted Wavefront OBJ file.
|
||||
|
|
|
@ -123,32 +123,32 @@ namespace Unvirt::StructFormatter {
|
|||
|
||||
fputs("VertexPositions: ", stdout);
|
||||
PrintPointer(obj->GetVertexPositions());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3));
|
||||
fputs("VertexNormals: ", stdout);
|
||||
PrintPointer(obj->GetVertexNormals());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3));
|
||||
fputs("VertexUVs: ", stdout);
|
||||
PrintPointer(obj->GetVertexUVs());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector2));
|
||||
fputs("VertexColors: ", stdout);
|
||||
PrintPointer(obj->GetVertexColors());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD));
|
||||
fputs("VertexSpecularColors: ", stdout);
|
||||
PrintPointer(obj->GetVertexSpecularColors());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD));
|
||||
fputs("VertexWeights: ", stdout);
|
||||
PrintPointer(obj->GetVertexWeights());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKFLOAT));
|
||||
|
||||
fputs("Face:\n", stdout);
|
||||
fprintf(stdout, "Face Count: %" PRIuCKDWORD "\n", obj->GetFaceCount());
|
||||
|
||||
fputs("FaceIndices: ", stdout);
|
||||
PrintPointer(obj->GetFaceIndices());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetFaceCount() * 3 * CKSizeof(LibCmo::CKWORD));
|
||||
fputs("FaceMaterialSlotIndexs: ", stdout);
|
||||
PrintPointer(obj->GetFaceMaterialSlotIndexs());
|
||||
fputc('\n', stdout);
|
||||
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetFaceCount() * CKSizeof(LibCmo::CKWORD));
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user