initial commit
This commit is contained in:
commit
984d590b3f
20
MeshConverter.sln
Normal file
20
MeshConverter.sln
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
|
# Visual Studio 2010
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeshConverter", "MeshConverter\MeshConverter.vcxproj", "{AADE0387-ED8A-46E2-B2DA-FC521DF7CB9C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{AADE0387-ED8A-46E2-B2DA-FC521DF7CB9C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{AADE0387-ED8A-46E2-B2DA-FC521DF7CB9C}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{AADE0387-ED8A-46E2-B2DA-FC521DF7CB9C}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{AADE0387-ED8A-46E2-B2DA-FC521DF7CB9C}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
92
MeshConverter/MeshConverter.vcxproj
Normal file
92
MeshConverter/MeshConverter.vcxproj
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{AADE0387-ED8A-46E2-B2DA-FC521DF7CB9C}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>MeshConverter</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\assets\material.cpp" />
|
||||||
|
<ClCompile Include="src\main.cpp" />
|
||||||
|
<ClCompile Include="src\md2\md2.cpp" />
|
||||||
|
<ClCompile Include="src\obj\obj.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\assets\material.h" />
|
||||||
|
<ClInclude Include="src\geometry\vector2.h" />
|
||||||
|
<ClInclude Include="src\geometry\vector3.h" />
|
||||||
|
<ClInclude Include="src\md2\md2.h" />
|
||||||
|
<ClInclude Include="src\obj\obj.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
14
MeshConverter/src/assets/material.cpp
Normal file
14
MeshConverter/src/assets/material.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "material.h"
|
||||||
|
|
||||||
|
Material::Material(unsigned long ambient, unsigned long diffuse, unsigned long specular, unsigned long emission, std::string texture)
|
||||||
|
{
|
||||||
|
m_ambient = ambient;
|
||||||
|
m_diffuse = diffuse;
|
||||||
|
m_specular = specular;
|
||||||
|
m_emission = emission;
|
||||||
|
m_texture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material::~Material()
|
||||||
|
{
|
||||||
|
}
|
40
MeshConverter/src/assets/material.h
Normal file
40
MeshConverter/src/assets/material.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef __MATERIAL_H_INCLUDED__
|
||||||
|
#define __MATERIAL_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define RGB_32(r, g, b, a) ((b)|((g) << 8)|((r) << 16)|((a) << 24))
|
||||||
|
#define RGB_24(r, g, b) ((b)|((g) << 8)|((r) << 16))
|
||||||
|
#define RGB_32_f(r, g, b, a) RGB_32((int)((r) * 255), (int)((g) * 255), (int)((b) * 255), (int)((a) * 255))
|
||||||
|
#define RGB_24_f(r, g, b) RGB_24((int)((r) * 255), (int)((g) * 255), (int)((b) * 255))
|
||||||
|
|
||||||
|
class Material
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Material(unsigned long ambient = 0, unsigned long diffuse = 0, unsigned long specular = 0, unsigned long emission = 0, std::string texture = "");
|
||||||
|
virtual ~Material();
|
||||||
|
|
||||||
|
void SetAmbient(unsigned long ambient) { m_ambient = ambient; }
|
||||||
|
void SetDiffuse(unsigned long diffuse) { m_diffuse = diffuse; }
|
||||||
|
void SetSpecular(unsigned long specular) { m_specular = specular; }
|
||||||
|
void SetEmission(unsigned long emission) { m_emission = emission; }
|
||||||
|
void SetTexture(std::string texture) { m_texture = texture; }
|
||||||
|
unsigned long GetAmbient() { return m_ambient; }
|
||||||
|
unsigned long GetDiffuse() { return m_diffuse; }
|
||||||
|
unsigned long GetSpecular() { return m_specular; }
|
||||||
|
unsigned long GetEmission() { return m_emission; }
|
||||||
|
std::string GetTexture() { return m_texture; }
|
||||||
|
|
||||||
|
static void ApplyDefault();
|
||||||
|
static Material GetDefault();
|
||||||
|
void Apply();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned long m_ambient;
|
||||||
|
unsigned long m_diffuse;
|
||||||
|
unsigned long m_specular;
|
||||||
|
unsigned long m_emission;
|
||||||
|
std::string m_texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
11
MeshConverter/src/geometry/vector2.h
Normal file
11
MeshConverter/src/geometry/vector2.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef __VECTOR2_H_INCLUDED__
|
||||||
|
#define __VECTOR2_H_INCLUDED__
|
||||||
|
|
||||||
|
class Vector2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
319
MeshConverter/src/geometry/vector3.h
Normal file
319
MeshConverter/src/geometry/vector3.h
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
#ifndef __VECTOR3_H_INCLUDED__
|
||||||
|
#define __VECTOR3_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a 3D vector and provides common methods/operators
|
||||||
|
* for vector math
|
||||||
|
*/
|
||||||
|
class Vector3
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector3() {}
|
||||||
|
Vector3(float vx, float vy, float vz) { x = vx; y = vy; z = vz; }
|
||||||
|
Vector3(const float *v) { x = v[0]; y = v[1]; z = v[2]; }
|
||||||
|
~Vector3() {}
|
||||||
|
|
||||||
|
static Vector3 Cross(const Vector3 &a, const Vector3 &b);
|
||||||
|
static float Dot(const Vector3 &a, const Vector3 &b);
|
||||||
|
static Vector3 Normalize(const Vector3 &a);
|
||||||
|
static Vector3 SurfaceNormal(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3);
|
||||||
|
static float Magnitude(const Vector3 &a);
|
||||||
|
static float SquaredLength(const Vector3 &a);
|
||||||
|
static Vector3 SetLength(const Vector3 &v, float length);
|
||||||
|
static float Distance(const Vector3 &a, const Vector3 &b);
|
||||||
|
static bool IsPointInTriangle(const Vector3 &point, const Vector3 &pa, const Vector3 &pb, const Vector3 &pc);
|
||||||
|
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 operator-(const Vector3 &left);
|
||||||
|
Vector3 operator+(const Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 &operator+=(Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 operator-(const Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 &operator-=(Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 operator*(const Vector3 &left, float right);
|
||||||
|
Vector3 &operator*=(Vector3 &left, float right);
|
||||||
|
Vector3 operator/(const Vector3 &left, float right);
|
||||||
|
Vector3 &operator/=(Vector3 &left, float right);
|
||||||
|
Vector3 operator*(const Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 &operator*=(Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 operator/(const Vector3 &left, const Vector3 &right);
|
||||||
|
Vector3 &operator/=(Vector3 &left, const Vector3 &right);
|
||||||
|
|
||||||
|
#define ZERO_VECTOR Vector3(0.0f, 0.0f, 0.0f)
|
||||||
|
|
||||||
|
#define X_AXIS Vector3(1.0f, 0.0f, 0.0f)
|
||||||
|
#define Y_AXIS Vector3(0.0f, 1.0f, 0.0f)
|
||||||
|
#define Z_AXIS Vector3(0.0f, 0.0f, 1.0f)
|
||||||
|
|
||||||
|
#define UP_VECTOR Vector3(0.0f, 1.0f, 0.0f)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the cross product of 2 vectors.
|
||||||
|
* x = a.y * b.z - b.y * a.z
|
||||||
|
* y = a.z * b.x - b.z * a.x
|
||||||
|
* z = a.x * b.y - b.x * a.y
|
||||||
|
* @param a first vector
|
||||||
|
* @param b second vector
|
||||||
|
*
|
||||||
|
* @return Vector3 the cross product
|
||||||
|
*/
|
||||||
|
inline Vector3 Vector3::Cross(const Vector3 &a, const Vector3 &b)
|
||||||
|
{
|
||||||
|
return Vector3(
|
||||||
|
(a.y * b.z) - (b.y * a.z),
|
||||||
|
(a.z * b.x) - (b.z * a.x),
|
||||||
|
(a.x * b.y) - (b.x * a.y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the dot product of 2 vectors.
|
||||||
|
* dot = (a.x * b.x) + (a.y * b.y) + (a.z * b.z)
|
||||||
|
* @param a first vector
|
||||||
|
* @param b second vector
|
||||||
|
*
|
||||||
|
* @return float the dot product
|
||||||
|
*/
|
||||||
|
inline float Vector3::Dot(const Vector3 &a, const Vector3 &b)
|
||||||
|
{
|
||||||
|
return (a.x * b.x) +
|
||||||
|
(a.y * b.y) +
|
||||||
|
(a.z * b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a vector
|
||||||
|
* x = a.x / ||a||
|
||||||
|
* y = a.y / ||a||
|
||||||
|
* z = a.z / ||a||
|
||||||
|
* @param a vector to normalize
|
||||||
|
*
|
||||||
|
* @return Vector3 the normalized vector
|
||||||
|
*/
|
||||||
|
inline Vector3 Vector3::Normalize(const Vector3 &a)
|
||||||
|
{
|
||||||
|
float magnitudeSquared = (a.x * a.x) + (a.y * a.y) + (a.z * a.z);
|
||||||
|
if (magnitudeSquared > 0.0f)
|
||||||
|
{
|
||||||
|
float inverseMagnitude = 1.0f / sqrtf(magnitudeSquared);
|
||||||
|
return Vector3(
|
||||||
|
a.x * inverseMagnitude,
|
||||||
|
a.y * inverseMagnitude,
|
||||||
|
a.z * inverseMagnitude
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a normal vector for the given 3 vectors making up
|
||||||
|
* a triangle (counter-clockwise order)
|
||||||
|
* @param v1 first vertex
|
||||||
|
* @param v2 second vertex
|
||||||
|
* @param v3 third vertex
|
||||||
|
*
|
||||||
|
* @return Vector3 normal vector for the triangle
|
||||||
|
*/
|
||||||
|
inline Vector3 Vector3::SurfaceNormal(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
|
||||||
|
{
|
||||||
|
return Vector3::Normalize(Vector3::Cross(v2 - v1, v3 - v1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns magnitude of a vector.
|
||||||
|
* ||a|| = sqrt((a.x * a.x) + (a.y * a.y) + (a.z * a.z))
|
||||||
|
* @param a vector to calculate the magnitude of
|
||||||
|
*
|
||||||
|
* @return float vector magnitude
|
||||||
|
*/
|
||||||
|
inline float Vector3::Magnitude(const Vector3 &a)
|
||||||
|
{
|
||||||
|
return sqrtf(
|
||||||
|
(a.x * a.x) +
|
||||||
|
(a.y * a.y) +
|
||||||
|
(a.z * a.z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the squared length of a vector (the magnitude minus
|
||||||
|
* the sqrt call)
|
||||||
|
* @param a vector to calculate the squared length of
|
||||||
|
*
|
||||||
|
* @return float squared length of the vector
|
||||||
|
*/
|
||||||
|
inline float Vector3::SquaredLength(const Vector3 &a)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(a.x * a.x) +
|
||||||
|
(a.y * a.y) +
|
||||||
|
(a.z * a.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts a vector so that it's magnitude is equal to the given
|
||||||
|
* length
|
||||||
|
* @param v the original vector to be adjusted
|
||||||
|
* @param length desired vector magnitude
|
||||||
|
*
|
||||||
|
* @return Vector3 the resulting vector after it's length has
|
||||||
|
* been converted to the desired amount
|
||||||
|
*/
|
||||||
|
inline Vector3 Vector3::SetLength(const Vector3 &v, float length)
|
||||||
|
{
|
||||||
|
float magnitude = Vector3::Magnitude(v);
|
||||||
|
return v * (length / magnitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the distance between two points
|
||||||
|
* @param a the first point
|
||||||
|
* @param b the second point
|
||||||
|
*
|
||||||
|
* @return float the distance between both points
|
||||||
|
*/
|
||||||
|
inline float Vector3::Distance(const Vector3 &a, const Vector3 &b)
|
||||||
|
{
|
||||||
|
return sqrtf(
|
||||||
|
((b.x - a.x) * (b.x - a.x)) +
|
||||||
|
((b.y - a.y) * (b.y - a.y)) +
|
||||||
|
((b.z - a.z) * (b.z - a.z))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given point lies inside a triangle or not
|
||||||
|
* @param point point to test
|
||||||
|
* @param a first vector of the triangle
|
||||||
|
* @param b second vector of the triangle
|
||||||
|
* @param c third vector of the triangle
|
||||||
|
*
|
||||||
|
* @return BOOL TRUE if the point lies inside the triangle,
|
||||||
|
* FALSE if it doesn't
|
||||||
|
*/
|
||||||
|
inline bool Vector3::IsPointInTriangle(const Vector3 &point, const Vector3 &pa, const Vector3 &pb, const Vector3 &pc)
|
||||||
|
{
|
||||||
|
Vector3 edge1 = pb - pa;
|
||||||
|
Vector3 edge2 = pc - pa;
|
||||||
|
|
||||||
|
float a = Vector3::Dot(edge1, edge1);
|
||||||
|
float b = Vector3::Dot(edge1, edge2);
|
||||||
|
float c = Vector3::Dot(edge2, edge2);
|
||||||
|
float ac_bb = (a * c) - (b * b);
|
||||||
|
Vector3 vp(point.x - pa.x, point.y - pa.y, point.z - pa.z);
|
||||||
|
|
||||||
|
float d = Vector3::Dot(vp, edge1);
|
||||||
|
float e = Vector3::Dot(vp, edge2);
|
||||||
|
float x = (d * c) - (e * b);
|
||||||
|
float y = (e * a) - (d * b);
|
||||||
|
float z = x + y - ac_bb;
|
||||||
|
|
||||||
|
int result = (( ((unsigned int&) z)& ~(((unsigned int&) x)|((unsigned int&) y)) ) & 0x80000000);
|
||||||
|
if (result == 0)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
return (left.x == right.x && left.y == right.y && left.z == right.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator-(const Vector3 &left)
|
||||||
|
{
|
||||||
|
return Vector3(-left.x, -left.y, -left.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator+(const Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
return Vector3(left.x + right.x, left.y + right.y, left.z + right.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 &operator+=(Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
left.x += right.x;
|
||||||
|
left.y += right.y;
|
||||||
|
left.z += right.z;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator-(const Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
return Vector3(left.x - right.x, left.y - right.y, left.z - right.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 &operator-=(Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
left.x -= right.x;
|
||||||
|
left.y -= right.y;
|
||||||
|
left.z -= right.z;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator*(const Vector3 &left, float right)
|
||||||
|
{
|
||||||
|
return Vector3(left.x * right, left.y * right, left.z * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 &operator*=(Vector3 &left, float right)
|
||||||
|
{
|
||||||
|
left.x *= right;
|
||||||
|
left.y *= right;
|
||||||
|
left.z *= right;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator/(const Vector3 &left, float right)
|
||||||
|
{
|
||||||
|
return Vector3(left.x / right, left.y / right, left.z / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 &operator/=(Vector3 &left, float right)
|
||||||
|
{
|
||||||
|
left.x /= right;
|
||||||
|
left.y /= right;
|
||||||
|
left.z /= right;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator*(const Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
return Vector3(left.x * right.x, left.y * right.y, left.z * right.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 &operator*=(Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
left.x *= right.x;
|
||||||
|
left.y *= right.y;
|
||||||
|
left.z *= right.z;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 operator/(const Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
return Vector3(left.x / right.x, left.y / right.y, left.z / right.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3 &operator/=(Vector3 &left, const Vector3 &right)
|
||||||
|
{
|
||||||
|
left.x /= right.x;
|
||||||
|
left.y /= right.y;
|
||||||
|
left.z /= right.z;
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
77
MeshConverter/src/main.cpp
Normal file
77
MeshConverter/src/main.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include "md2/md2.h"
|
||||||
|
#include "obj/obj.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("MESH Converter\n");
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
printf("No input file specified.\n");
|
||||||
|
printf("Usage: meshconverter.exe [inputfile]\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string file = argv[1];
|
||||||
|
std::string extension;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
extension = file.substr(file.find_last_of('.'), std::string::npos);
|
||||||
|
for (int i = 0; i < extension.size(); ++i)
|
||||||
|
extension[i] = tolower(extension[i]);
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
extension = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string meshFile = "";
|
||||||
|
if (extension.length() > 0)
|
||||||
|
{
|
||||||
|
meshFile = file;
|
||||||
|
meshFile.erase(meshFile.find_last_of('.'), std::string::npos);
|
||||||
|
meshFile.append(".mesh");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension == ".obj")
|
||||||
|
{
|
||||||
|
Obj *obj = new Obj();
|
||||||
|
if (!obj->Load(file, "./"))
|
||||||
|
{
|
||||||
|
printf("Error loading OBJ file.\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!obj->ConvertToMesh(meshFile))
|
||||||
|
{
|
||||||
|
printf("Error converting OBJ to MESH.\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (extension == ".md2")
|
||||||
|
{
|
||||||
|
Md2 *md2 = new Md2();
|
||||||
|
if (!md2->Load(file))
|
||||||
|
{
|
||||||
|
printf("Error loading MD2 file.\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!md2->ConvertToMesh(meshFile))
|
||||||
|
{
|
||||||
|
printf("Error converting MD2 to MESH.\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Unrecognized file type.\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
244
MeshConverter/src/md2/md2.cpp
Normal file
244
MeshConverter/src/md2/md2.cpp
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
#include "md2.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
Md2::Md2()
|
||||||
|
{
|
||||||
|
m_numFrames = 0;
|
||||||
|
m_numPolys = 0;
|
||||||
|
m_numTexCoords = 0;
|
||||||
|
m_numVertices = 0;
|
||||||
|
m_numSkins = 0;
|
||||||
|
m_frames = NULL;
|
||||||
|
m_polys = NULL;
|
||||||
|
m_texCoords = NULL;
|
||||||
|
m_skins = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Md2::Release()
|
||||||
|
{
|
||||||
|
delete[] m_frames;
|
||||||
|
delete[] m_polys;
|
||||||
|
delete[] m_texCoords;
|
||||||
|
delete[] m_skins;
|
||||||
|
m_numFrames = 0;
|
||||||
|
m_numPolys = 0;
|
||||||
|
m_numTexCoords = 0;
|
||||||
|
m_numVertices = 0;
|
||||||
|
m_numSkins = 0;
|
||||||
|
m_frames = NULL;
|
||||||
|
m_polys = NULL;
|
||||||
|
m_texCoords = NULL;
|
||||||
|
m_skins = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Md2::Load(const std::string &file)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
unsigned char c;
|
||||||
|
unsigned short u, v, t;
|
||||||
|
float x, y, z;
|
||||||
|
Md2Header header;
|
||||||
|
Vector3 scale, translate;
|
||||||
|
|
||||||
|
fp = fopen(file.c_str(), "rb");
|
||||||
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Simple filetype verification
|
||||||
|
fread(&header.ident, 4, 1, fp);
|
||||||
|
if (header.ident[0] != 'I' || header.ident[1] != 'D' || header.ident[2] != 'P' || header.ident[3] != '2')
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fread(&header.version, 4, 1, fp);
|
||||||
|
if (header.version != 8)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release();
|
||||||
|
|
||||||
|
// Read rest of the MD2 header
|
||||||
|
fread(&header.skinWidth, 4, 1, fp);
|
||||||
|
fread(&header.skinHeight, 4, 1, fp);
|
||||||
|
fread(&header.frameSize, 4, 1, fp);
|
||||||
|
fread(&header.numSkins, 4, 1, fp);
|
||||||
|
fread(&header.numVertices, 4, 1, fp);
|
||||||
|
fread(&header.numTexCoords, 4, 1, fp);
|
||||||
|
fread(&header.numPolys, 4, 1, fp);
|
||||||
|
fread(&header.numGlCmds, 4, 1, fp);
|
||||||
|
fread(&header.numFrames, 4, 1, fp);
|
||||||
|
fread(&header.offsetSkins, 4, 1, fp);
|
||||||
|
fread(&header.offsetTexCoords, 4, 1, fp);
|
||||||
|
fread(&header.offsetPolys, 4, 1, fp);
|
||||||
|
fread(&header.offsetFrames, 4, 1, fp);
|
||||||
|
fread(&header.offsetGlCmds, 4, 1, fp);
|
||||||
|
fread(&header.offsetEnd, 4, 1, fp);
|
||||||
|
|
||||||
|
// Allocate memory
|
||||||
|
if (header.numSkins > 0)
|
||||||
|
{
|
||||||
|
m_skins = new std::string[header.numSkins];
|
||||||
|
//ASSERT(m_skins != NULL);
|
||||||
|
}
|
||||||
|
m_texCoords = new Vector2[header.numTexCoords];
|
||||||
|
m_polys = new Md2Polygon[header.numPolys];
|
||||||
|
m_frames = new Md2Frame[header.numFrames];
|
||||||
|
|
||||||
|
//ASSERT(m_texCoords != NULL);
|
||||||
|
//ASSERT(m_polys != NULL);
|
||||||
|
//ASSERT(m_frames != NULL);
|
||||||
|
|
||||||
|
// Save model properties
|
||||||
|
m_numFrames = header.numFrames;
|
||||||
|
m_numPolys = header.numPolys;
|
||||||
|
m_numSkins = header.numSkins;
|
||||||
|
m_numTexCoords = header.numTexCoords;
|
||||||
|
m_numVertices = header.numVertices;
|
||||||
|
|
||||||
|
// Read skin info
|
||||||
|
fseek(fp, header.offsetSkins, SEEK_SET);
|
||||||
|
for (int i = 0; i < header.numSkins; ++i)
|
||||||
|
{
|
||||||
|
// Not wasting the full 64 characters stored in the file here
|
||||||
|
for (int j = 0; j < MD2_SKIN_NAME_LENGTH; ++j)
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, fp);
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
fseek(fp, MD2_SKIN_NAME_LENGTH - j - 1, SEEK_CUR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_skins[i].append(1, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read texture coordinates
|
||||||
|
fseek(fp, header.offsetTexCoords, SEEK_SET);
|
||||||
|
for (int i = 0; i < header.numTexCoords; ++i)
|
||||||
|
{
|
||||||
|
fread(&u, 2, 1, fp);
|
||||||
|
fread(&v, 2, 1, fp);
|
||||||
|
m_texCoords[i].x = u / (float)header.skinWidth;
|
||||||
|
m_texCoords[i].y = v / (float)header.skinHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read polygons (this is all just indexes into m_texCoords and m_frames[].vertices)
|
||||||
|
fseek(fp, header.offsetPolys, SEEK_SET);
|
||||||
|
for (int i = 0; i < header.numPolys; ++i)
|
||||||
|
{
|
||||||
|
fread(&t, 2, 1, fp);
|
||||||
|
m_polys[i].vertex[0] = t;
|
||||||
|
fread(&t, 2, 1, fp);
|
||||||
|
m_polys[i].vertex[2] = t;
|
||||||
|
fread(&t, 2, 1, fp);
|
||||||
|
m_polys[i].vertex[1] = t;
|
||||||
|
|
||||||
|
// HACK: Not sure why some of these indexes are invalid? This seems to fix the problem
|
||||||
|
fread(&t, 2, 1, fp);
|
||||||
|
m_polys[i].texCoord[0] = (t == 65535 ? 0 : t);
|
||||||
|
fread(&t, 2, 1, fp);
|
||||||
|
m_polys[i].texCoord[2] = (t == 65535 ? 0 : t);
|
||||||
|
fread(&t, 2, 1, fp);
|
||||||
|
m_polys[i].texCoord[1] = (t == 65535 ? 0 : t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read frames
|
||||||
|
fseek(fp, header.offsetFrames, SEEK_SET);
|
||||||
|
for (int i = 0; i < header.numFrames; ++i)
|
||||||
|
{
|
||||||
|
// Allocate enough memory for this frame's vertex/normal indexes
|
||||||
|
m_frames[i].vertices = new Vector3[header.numVertices];
|
||||||
|
//m_frames[i].normals = new Vector3[header.numPolys];
|
||||||
|
m_frames[i].normals = new Vector3[header.numVertices];
|
||||||
|
//ASSERT(m_frames[i].vertices != NULL);
|
||||||
|
//ASSERT(m_frames[i].normals != NULL);
|
||||||
|
|
||||||
|
fread(&scale.x, 4, 1, fp);
|
||||||
|
fread(&scale.y, 4, 1, fp);
|
||||||
|
fread(&scale.z, 4, 1, fp);
|
||||||
|
|
||||||
|
fread(&translate.x, 4, 1, fp);
|
||||||
|
fread(&translate.y, 4, 1, fp);
|
||||||
|
fread(&translate.z, 4, 1, fp);
|
||||||
|
|
||||||
|
// Store the text name of the frame (we won't waste the full 16 characters
|
||||||
|
// reserved in the file here)
|
||||||
|
for (int j = 0; j < MD2_FRAME_NAME_LENGTH; ++j)
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, fp);
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
fseek(fp, MD2_FRAME_NAME_LENGTH - j - 1, SEEK_CUR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_frames[i].name += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read vertices, and decompress as we load them for performance when rendering
|
||||||
|
for (int j = 0; j < header.numVertices; ++j)
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, fp);
|
||||||
|
x = (float)c;
|
||||||
|
fread(&c, 1, 1, fp);
|
||||||
|
y = (float)c;
|
||||||
|
fread(&c, 1, 1, fp);
|
||||||
|
z = (float)c;
|
||||||
|
|
||||||
|
// Convert to OpenGL's coordinate system, otherwise models will need to be rotated to be drawn upright
|
||||||
|
m_frames[i].vertices[j].x = (x * scale.x) + translate.x;
|
||||||
|
m_frames[i].vertices[j].y = (z * scale.z) + translate.z;
|
||||||
|
m_frames[i].vertices[j].z = -1.0f * ((y * scale.y) + translate.y);
|
||||||
|
|
||||||
|
fread(&c, 1, 1, fp); // Dummy command to increment file pointer (we don't care about the normal index)
|
||||||
|
}
|
||||||
|
|
||||||
|
//m_frameMap[m_frames[i].name] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup and finishing touches.
|
||||||
|
// Vertex coordinates, as of now, are waaay out of range (most likely, unless the model is tiny).
|
||||||
|
// We could've scaled them down above while reading them in, but I noticed issues calculating normals
|
||||||
|
// when that was done (probably due to lacking precision). So, we calculate the normals using the
|
||||||
|
// un-touched coordinates (get the most accurate normal calc that way), then scale the vertex down.
|
||||||
|
for (int i = 0; i < header.numFrames; ++i)
|
||||||
|
{
|
||||||
|
// Calculate vertex normals
|
||||||
|
Vector3 sumNormal;
|
||||||
|
int sum;
|
||||||
|
for (int j = 0; j < header.numVertices; ++j)
|
||||||
|
{
|
||||||
|
sum = 0;
|
||||||
|
sumNormal = Vector3(0, 0, 0);
|
||||||
|
for (int k = 0; k < header.numPolys; ++k)
|
||||||
|
{
|
||||||
|
if (m_polys[k].vertex[0] == j || m_polys[k].vertex[1] == j || m_polys[k].vertex[2] == j)
|
||||||
|
{
|
||||||
|
++sum;
|
||||||
|
sumNormal += Vector3::SurfaceNormal(m_frames[i].vertices[m_polys[k].vertex[0]],
|
||||||
|
m_frames[i].vertices[m_polys[k].vertex[1]],
|
||||||
|
m_frames[i].vertices[m_polys[k].vertex[2]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_frames[i].normals[j] = sumNormal / (float)sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Done, now scale the vertices down
|
||||||
|
//for (int j = 0; j < header.numVertices; ++j)
|
||||||
|
//{
|
||||||
|
// m_frames[i].vertices[j] /= (float)(MD2_SCALE_FACTOR);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Md2::ConvertToMesh(const std::string &file)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
91
MeshConverter/src/md2/md2.h
Normal file
91
MeshConverter/src/md2/md2.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#ifndef __MD2_H_INCLUDED__
|
||||||
|
#define __MD2_H_INCLUDED__
|
||||||
|
|
||||||
|
#include "../geometry/vector3.h"
|
||||||
|
#include "../geometry/vector2.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define MD2_SKIN_NAME_LENGTH 64
|
||||||
|
#define MD2_FRAME_NAME_LENGTH 16
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char ident[4]; // Should be "IDP2"
|
||||||
|
int version; // Should be 8
|
||||||
|
int skinWidth; // Texture dimensions
|
||||||
|
int skinHeight;
|
||||||
|
int frameSize; // Size of a single frame in bytes
|
||||||
|
int numSkins;
|
||||||
|
int numVertices;
|
||||||
|
int numTexCoords;
|
||||||
|
int numPolys;
|
||||||
|
int numGlCmds;
|
||||||
|
int numFrames;
|
||||||
|
int offsetSkins;
|
||||||
|
int offsetTexCoords;
|
||||||
|
int offsetPolys;
|
||||||
|
int offsetFrames;
|
||||||
|
int offsetGlCmds;
|
||||||
|
int offsetEnd;
|
||||||
|
} Md2Header;
|
||||||
|
|
||||||
|
// Vertex and texcoord indices
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned short vertex[3];
|
||||||
|
unsigned short texCoord[3];
|
||||||
|
} Md2Polygon;
|
||||||
|
|
||||||
|
// For each keyframe, stores the vertices, normals, and the string name
|
||||||
|
typedef struct Md2Frame
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
Vector3 *vertices;
|
||||||
|
Vector3 *normals;
|
||||||
|
|
||||||
|
Md2Frame()
|
||||||
|
{
|
||||||
|
vertices = NULL;
|
||||||
|
normals = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Md2Frame()
|
||||||
|
{
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] normals;
|
||||||
|
}
|
||||||
|
} Md2Frame;
|
||||||
|
|
||||||
|
class Md2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Md2();
|
||||||
|
virtual ~Md2() { Release(); }
|
||||||
|
|
||||||
|
void Release();
|
||||||
|
bool Load(const std::string &file);
|
||||||
|
bool ConvertToMesh(const std::string &file);
|
||||||
|
|
||||||
|
int GetNumFrames() { return m_numFrames; }
|
||||||
|
int GetNumVertices() { return m_numVertices; }
|
||||||
|
int GetNumTexCoords() { return m_numTexCoords; }
|
||||||
|
int GetNumPolys() { return m_numPolys; }
|
||||||
|
int GetNumSkins() { return m_numSkins; }
|
||||||
|
Md2Frame* GetFrames() { return m_frames; }
|
||||||
|
Md2Polygon* GetPolygons() { return m_polys; }
|
||||||
|
Vector2* GetTexCoords() { return m_texCoords; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_numFrames;
|
||||||
|
int m_numVertices;
|
||||||
|
int m_numTexCoords;
|
||||||
|
int m_numPolys;
|
||||||
|
int m_numSkins;
|
||||||
|
Md2Frame *m_frames;
|
||||||
|
Md2Polygon *m_polys;
|
||||||
|
Vector2 *m_texCoords;
|
||||||
|
std::string *m_skins;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
496
MeshConverter/src/obj/obj.cpp
Normal file
496
MeshConverter/src/obj/obj.cpp
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
#include "obj.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
Obj::Obj()
|
||||||
|
{
|
||||||
|
m_vertices = NULL;
|
||||||
|
m_normals = NULL;
|
||||||
|
m_texCoords = NULL;
|
||||||
|
m_materials = NULL;
|
||||||
|
m_numVertices = 0;
|
||||||
|
m_numNormals = 0;
|
||||||
|
m_numTexCoords = 0;
|
||||||
|
m_numMaterials = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj::Release()
|
||||||
|
{
|
||||||
|
delete[] m_vertices;
|
||||||
|
delete[] m_normals;
|
||||||
|
delete[] m_texCoords;
|
||||||
|
delete[] m_materials;
|
||||||
|
m_vertices = NULL;
|
||||||
|
m_normals = NULL;
|
||||||
|
m_texCoords = NULL;
|
||||||
|
m_materials = NULL;
|
||||||
|
m_numVertices = 0;
|
||||||
|
m_numNormals = 0;
|
||||||
|
m_numTexCoords = 0;
|
||||||
|
m_numMaterials = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Obj::Load(const std::string &file, const std::string &texturePath)
|
||||||
|
{
|
||||||
|
std::ifstream input;
|
||||||
|
std::string line;
|
||||||
|
std::string op;
|
||||||
|
std::string path;
|
||||||
|
std::string tempName;
|
||||||
|
Vector3 vertex;
|
||||||
|
Vector3 normal;
|
||||||
|
ObjMaterial *currentMaterial = NULL;
|
||||||
|
int currentVertex = 0;
|
||||||
|
int currentNormal = 0;
|
||||||
|
int currentTexCoord = 0;
|
||||||
|
int numGroups = 0;
|
||||||
|
|
||||||
|
// Get pathname from filename given (if present)
|
||||||
|
// Need this as we assume any .mtl files specified are in the same path as this .obj file
|
||||||
|
if (file.find_last_of('/') != std::string::npos)
|
||||||
|
path = file.substr(0, file.find_last_of('/') + 1);
|
||||||
|
|
||||||
|
if (!FindAndLoadMaterials(path, texturePath, file))
|
||||||
|
return false;
|
||||||
|
if (!GetDataSizes(file))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
input.open(file.c_str());
|
||||||
|
if (input.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Extract name of model from the filename given (basically, chop off the extension and path)
|
||||||
|
//if (file.find_last_of('.') != std::string::npos)
|
||||||
|
// model->name = file.substr(path.length(), file.find_last_of('.') - path.length());
|
||||||
|
|
||||||
|
// Begin reading in model data
|
||||||
|
while (!input.eof())
|
||||||
|
{
|
||||||
|
if (numGroups > 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::getline(input, line, '\n');
|
||||||
|
|
||||||
|
op = line.substr(0, line.find(' '));
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
if (op == "#")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertex
|
||||||
|
else if (op == "v")
|
||||||
|
{
|
||||||
|
sscanf(line.c_str(), "v %f %f %f", &m_vertices[currentVertex].x, &m_vertices[currentVertex].y, &m_vertices[currentVertex].z);
|
||||||
|
++currentVertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture coordinate
|
||||||
|
else if (op == "vt")
|
||||||
|
{
|
||||||
|
sscanf(line.c_str(), "vt %f %f", &m_texCoords[currentTexCoord].x, &m_texCoords[currentTexCoord].y);
|
||||||
|
m_texCoords[currentTexCoord].x = -m_texCoords[currentTexCoord].y;
|
||||||
|
++currentTexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertex normal
|
||||||
|
else if (op == "vn")
|
||||||
|
{
|
||||||
|
sscanf(line.c_str(), "vn %f %f %f", &m_normals[currentNormal].x, &m_normals[currentNormal].y, &m_normals[currentNormal].z);
|
||||||
|
++currentNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Face definition
|
||||||
|
else if (op == "f")
|
||||||
|
{
|
||||||
|
ParseFaceDefinition(line, currentMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group name
|
||||||
|
else if (op == "g")
|
||||||
|
{
|
||||||
|
++numGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object name
|
||||||
|
else if (op == "o")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Material
|
||||||
|
else if (op == "usemtl")
|
||||||
|
{
|
||||||
|
tempName = line.substr(line.find(' ') + 1);
|
||||||
|
|
||||||
|
currentMaterial = NULL;
|
||||||
|
|
||||||
|
// Find the named material and set it as current
|
||||||
|
for (unsigned int i = 0; i < m_numMaterials; ++i)
|
||||||
|
{
|
||||||
|
if (m_materials[i].name == tempName)
|
||||||
|
{
|
||||||
|
currentMaterial = &m_materials[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ASSERT(currentMaterial != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Material file
|
||||||
|
else if (op == "mtllib")
|
||||||
|
{
|
||||||
|
// Already would have been loaded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj::ParseFaceDefinition(const std::string &faceDefinition, ObjMaterial *currentMaterial)
|
||||||
|
{
|
||||||
|
static int numFaceVertices = 0;
|
||||||
|
static OBJ_FACE_VERTEX_TYPE vertexType;
|
||||||
|
std::string def;
|
||||||
|
int pos;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
// Just get the vertex index part of the line (can be variable length, and we dont want the newline at the end)
|
||||||
|
pos = faceDefinition.find(' ') + 1;
|
||||||
|
def = faceDefinition.substr(pos);
|
||||||
|
|
||||||
|
// Few different face formats, and variable amount of vertices per face possible
|
||||||
|
|
||||||
|
// How many vertices are there in this face definition? (only calc this once)
|
||||||
|
// Also calc the vertex format
|
||||||
|
if (!numFaceVertices)
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
while (def.length() > 0 && def[def.length() - 1] == ' ')
|
||||||
|
def = def.substr(0, def.length() - 1);
|
||||||
|
//ASSERT(def.length() > 0);
|
||||||
|
|
||||||
|
while (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
++numFaceVertices;
|
||||||
|
pos = def.find(' ', pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tempVertex = def.substr(0, def.find(' '));
|
||||||
|
if (tempVertex.find("//") != std::string::npos)
|
||||||
|
vertexType = OBJ_VERTEX_NORMAL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
while (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
++n;
|
||||||
|
pos = tempVertex.find('/', pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 1)
|
||||||
|
vertexType = OBJ_VERTEX_TEXCOORD;
|
||||||
|
else
|
||||||
|
vertexType = OBJ_VERTEX_FULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse out vertices in this face
|
||||||
|
// We also store only triangles. Since OBJ file face definitions can have any number
|
||||||
|
// of vertices per face, we need to split it up into triangles here for easy rendering
|
||||||
|
// This is done as follows:
|
||||||
|
// - first 3 vertices = first triangle for face
|
||||||
|
// - for each additional 1 vertex, take the first vertex read for this face + the previously
|
||||||
|
// read vertex for this face and combine to make a new triangle
|
||||||
|
std::istringstream parser;
|
||||||
|
std::string currentVertex;
|
||||||
|
int thisVertex[3];
|
||||||
|
int firstVertex[3];
|
||||||
|
int lastReadVertex[3];
|
||||||
|
int thisTriangle[3][3];
|
||||||
|
ObjFace face;
|
||||||
|
|
||||||
|
memset(&firstVertex, 0, sizeof(int) * 3);
|
||||||
|
memset(&lastReadVertex, 0, sizeof(int) * 3);
|
||||||
|
memset(&thisTriangle, 0, sizeof(int) * (3 * 3));
|
||||||
|
parser.clear();
|
||||||
|
parser.str(def);
|
||||||
|
|
||||||
|
for (int i = 0; i < numFaceVertices; ++i)
|
||||||
|
{
|
||||||
|
// Get current vertex for this face
|
||||||
|
parser >> currentVertex;
|
||||||
|
|
||||||
|
// Add vertex/texcoord/normal indexes to the data arrays
|
||||||
|
// (OBJ file indexes are NOT zero based. We fix that here)
|
||||||
|
memset(&thisVertex, 0, sizeof(int) * 3);
|
||||||
|
switch (vertexType)
|
||||||
|
{
|
||||||
|
case OBJ_VERTEX_FULL: // v/vt/vn
|
||||||
|
sscanf(currentVertex.c_str(), "%d/%d/%d", &thisVertex[0], &thisVertex[1], &thisVertex[2]);
|
||||||
|
break;
|
||||||
|
case OBJ_VERTEX_NORMAL: // v//vn
|
||||||
|
sscanf(currentVertex.c_str(), "%d//%d", &thisVertex[0], &thisVertex[2]);
|
||||||
|
break;
|
||||||
|
case OBJ_VERTEX_TEXCOORD: // v/vt
|
||||||
|
sscanf(currentVertex.c_str(), "%d/%d", &thisVertex[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the first vertex read for a face
|
||||||
|
if (i == 0)
|
||||||
|
memcpy(&firstVertex, &thisVertex, sizeof(int) * 3);
|
||||||
|
|
||||||
|
// First 3 vertices simply form a triangle
|
||||||
|
if (i <= 2)
|
||||||
|
{
|
||||||
|
face.vertices[i] = thisVertex[0] - 1;
|
||||||
|
face.texcoords[i] = thisVertex[1] - 1;
|
||||||
|
face.normals[i] = thisVertex[2] - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the first triangle
|
||||||
|
if (i == 2)
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial != NULL);
|
||||||
|
currentMaterial->faces[currentMaterial->lastFaceIndex] = face;
|
||||||
|
++currentMaterial->lastFaceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine vertices to form additional triangles
|
||||||
|
if (i > 2)
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial != NULL);
|
||||||
|
face.vertices[0] = firstVertex[0] - 1; face.texcoords[0] = firstVertex[1] - 1; face.normals[0] = firstVertex[2] - 1;
|
||||||
|
face.vertices[1] = lastReadVertex[0] - 1; face.texcoords[1] = lastReadVertex[1] - 1; face.normals[1] = lastReadVertex[2] - 1;
|
||||||
|
face.vertices[2] = thisVertex[0] - 1; face.texcoords[2] = thisVertex[1] - 1; face.normals[2] = thisVertex[2] - 1;
|
||||||
|
currentMaterial->faces[currentMaterial->lastFaceIndex] = face;
|
||||||
|
++currentMaterial->lastFaceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save as "previously read vertex"
|
||||||
|
memcpy(&lastReadVertex, &thisVertex, sizeof(int) * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Obj::GetDataSizes(const std::string &file)
|
||||||
|
{
|
||||||
|
std::ifstream input;
|
||||||
|
std::string line;
|
||||||
|
std::string op;
|
||||||
|
int countVertices = 0;
|
||||||
|
int countNormals = 0;
|
||||||
|
int countTexCoords = 0;
|
||||||
|
int numGroups = 0;
|
||||||
|
std::string useMtlName;
|
||||||
|
ObjMaterial *currentMaterial;
|
||||||
|
|
||||||
|
input.open(file.c_str());
|
||||||
|
if (input.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (!input.eof())
|
||||||
|
{
|
||||||
|
if (numGroups > 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::getline(input, line, '\n');
|
||||||
|
|
||||||
|
op = line.substr(0, line.find(' '));
|
||||||
|
|
||||||
|
if (op == "g")
|
||||||
|
++numGroups;
|
||||||
|
else if (op == "v")
|
||||||
|
++countVertices;
|
||||||
|
else if (op == "vt")
|
||||||
|
++countTexCoords;
|
||||||
|
else if (op == "vn")
|
||||||
|
++countNormals;
|
||||||
|
else if (op == "f")
|
||||||
|
// TODO: count number of vertices per face definition, and adjust the ++ operation accordingly (i.e. for 4 vertices per face, needs to be "+= 2")
|
||||||
|
++currentMaterial->numFaces;
|
||||||
|
|
||||||
|
else if (op == "usemtl")
|
||||||
|
{
|
||||||
|
std::string useMtlName = line.substr(line.find(' ') + 1);
|
||||||
|
|
||||||
|
currentMaterial = NULL;
|
||||||
|
|
||||||
|
// Find the named material and set it as current
|
||||||
|
for (unsigned int i = 0; i < m_numMaterials; ++i)
|
||||||
|
{
|
||||||
|
if (m_materials[i].name == useMtlName)
|
||||||
|
{
|
||||||
|
currentMaterial = &m_materials[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ASSERT(currentMaterial != NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
|
||||||
|
m_numVertices = countVertices;
|
||||||
|
m_numTexCoords = countTexCoords;
|
||||||
|
m_numNormals = countNormals;
|
||||||
|
m_vertices = new Vector3[m_numVertices];
|
||||||
|
m_texCoords = new Vector2[m_numTexCoords];
|
||||||
|
m_normals = new Vector3[m_numNormals];
|
||||||
|
for (unsigned int i = 0; i < m_numMaterials; ++i)
|
||||||
|
{
|
||||||
|
m_materials[i].faces = new ObjFace[m_materials[i].numFaces];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Obj::LoadMaterialLibrary(const std::string &file, const std::string &texturePath)
|
||||||
|
{
|
||||||
|
std::ifstream input;
|
||||||
|
std::string line;
|
||||||
|
std::string op;
|
||||||
|
int currentMaterial = -1;
|
||||||
|
float r, g, b;
|
||||||
|
|
||||||
|
if (!CountDefinedMaterials(file))
|
||||||
|
return false;
|
||||||
|
m_materials = new ObjMaterial[m_numMaterials];
|
||||||
|
|
||||||
|
input.open(file.c_str());
|
||||||
|
if (input.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (!input.eof())
|
||||||
|
{
|
||||||
|
std::getline(input, line, '\n');
|
||||||
|
|
||||||
|
op = line.substr(0, line.find(' '));
|
||||||
|
|
||||||
|
// New material definition (possibility of multiple per .mtl file)
|
||||||
|
if (op == "newmtl")
|
||||||
|
{
|
||||||
|
++currentMaterial;
|
||||||
|
m_materials[currentMaterial].name = line.substr(op.length() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ambient color
|
||||||
|
else if (op == "Ka")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
sscanf(line.c_str(), "Ka %f %f %f", &r, &g, &b);
|
||||||
|
m_materials[currentMaterial].material->SetAmbient(RGB_24_f(r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diffuse color
|
||||||
|
else if (op == "Kd")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
sscanf(line.c_str(), "Kd %f %f %f", &r, &g, &b);
|
||||||
|
m_materials[currentMaterial].material->SetDiffuse(RGB_24_f(r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specular color
|
||||||
|
else if (op == "Ks")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
sscanf(line.c_str(), "Ks %f %f %f", &r, &g, &b);
|
||||||
|
m_materials[currentMaterial].material->SetSpecular(RGB_24_f(r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha value
|
||||||
|
else if (op == "d" || op == "Tr")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shininess
|
||||||
|
else if (op == "Ns")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Illumination model
|
||||||
|
else if (op == "illum")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture
|
||||||
|
else if (op == "map_Ka" || op == "map_Kd")
|
||||||
|
{
|
||||||
|
//ASSERT(currentMaterial >= 0);
|
||||||
|
m_materials[currentMaterial].material->SetTexture(texturePath + line.substr(op.length() + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Obj::CountDefinedMaterials(const std::string &file)
|
||||||
|
{
|
||||||
|
std::ifstream input;
|
||||||
|
std::string line;
|
||||||
|
std::string op;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
input.open(file.c_str());
|
||||||
|
if (input.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (!input.eof())
|
||||||
|
{
|
||||||
|
std::getline(input, line, '\n');
|
||||||
|
|
||||||
|
op = line.substr(0, line.find(' '));
|
||||||
|
if (op == "newmtl")
|
||||||
|
++m_numMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Obj::FindAndLoadMaterials(const std::string &materialPath, const std::string &texturePath, const std::string &file)
|
||||||
|
{
|
||||||
|
std::ifstream input;
|
||||||
|
std::string line;
|
||||||
|
std::string op;
|
||||||
|
|
||||||
|
input.open(file.c_str());
|
||||||
|
if (input.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (!input.eof())
|
||||||
|
{
|
||||||
|
std::getline(input, line, '\n');
|
||||||
|
|
||||||
|
op = line.substr(0, line.find(' '));
|
||||||
|
|
||||||
|
if (op == "mtllib")
|
||||||
|
{
|
||||||
|
LoadMaterialLibrary(materialPath + line.substr(line.find(' ') + 1), texturePath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Obj::ConvertToMesh(const std::string &file)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
84
MeshConverter/src/obj/obj.h
Normal file
84
MeshConverter/src/obj/obj.h
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#ifndef __OBJ_H_INCLUDED__
|
||||||
|
#define __OBJ_H_INCLUDED__
|
||||||
|
|
||||||
|
#include "../geometry/vector3.h"
|
||||||
|
#include "../geometry/vector2.h"
|
||||||
|
#include "../assets/material.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
typedef enum OBJ_FACE_VERTEX_TYPE
|
||||||
|
{
|
||||||
|
OBJ_VERTEX_TEXCOORD,
|
||||||
|
OBJ_VERTEX_NORMAL,
|
||||||
|
OBJ_VERTEX_FULL
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int vertices[3];
|
||||||
|
unsigned int texcoords[3];
|
||||||
|
unsigned int normals[3];
|
||||||
|
} ObjFace;
|
||||||
|
|
||||||
|
typedef struct ObjMaterial
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
Material *material;
|
||||||
|
ObjFace *faces;
|
||||||
|
unsigned int numFaces;
|
||||||
|
unsigned int lastFaceIndex;
|
||||||
|
|
||||||
|
ObjMaterial()
|
||||||
|
{
|
||||||
|
material = new Material();
|
||||||
|
faces = NULL;
|
||||||
|
numFaces = 0;
|
||||||
|
lastFaceIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ObjMaterial()
|
||||||
|
{
|
||||||
|
delete material;
|
||||||
|
delete[] faces;
|
||||||
|
}
|
||||||
|
} ObjMaterial;
|
||||||
|
|
||||||
|
class Obj
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Obj();
|
||||||
|
virtual ~Obj() { Release(); }
|
||||||
|
|
||||||
|
void Release();
|
||||||
|
bool Load(const std::string &file, const std::string &texturePath);
|
||||||
|
bool ConvertToMesh(const std::string &file);
|
||||||
|
|
||||||
|
int GetNumVertices() { return m_numVertices; }
|
||||||
|
int GetNumNormals() { return m_numNormals; }
|
||||||
|
int GetNumTexCoords() { return m_numTexCoords; }
|
||||||
|
int GetNumMaterials() { return m_numMaterials; }
|
||||||
|
Vector3* GetVertices() { return m_vertices; }
|
||||||
|
Vector3* GetNormals() { return m_normals; }
|
||||||
|
Vector2* GetTexCoords() { return m_texCoords; }
|
||||||
|
ObjMaterial* GetMaterials() { return m_materials; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool GetDataSizes(const std::string &file);
|
||||||
|
bool LoadMaterialLibrary(const std::string &file, const std::string &texturePath);
|
||||||
|
bool CountDefinedMaterials(const std::string &file);
|
||||||
|
bool FindAndLoadMaterials(const std::string &materialPath, const std::string &texturePath, const std::string &file);
|
||||||
|
void ParseFaceDefinition(const std::string &faceDefinition, ObjMaterial *currentMaterial);
|
||||||
|
|
||||||
|
Vector3 *m_vertices;
|
||||||
|
Vector3 *m_normals;
|
||||||
|
Vector2 *m_texCoords;
|
||||||
|
ObjMaterial *m_materials;
|
||||||
|
unsigned int m_numVertices;
|
||||||
|
unsigned int m_numNormals;
|
||||||
|
unsigned int m_numTexCoords;
|
||||||
|
unsigned int m_numMaterials;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Reference in a new issue