2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-11-22 21:02:07 +00:00

WIP: Updating code to follow laupentin's code review.

Done:
- Moved custom map structures to their own objcommon header file
- Updated GfxLightGridRow struct
- Reverted shader_bin file path
- Renamed Project Creator to BSP Creator
- Removed model loading from BSP creator
- Cleaned up BSP Creator and updated the names of structs
WIP:
- Update BSP calculation code to be more readable and use unique/shared ptrs
This commit is contained in:
LJW-Dev
2025-10-20 18:04:03 +08:00
parent 15918506c3
commit e19a3a142a
10 changed files with 165 additions and 339 deletions

View File

@@ -159,100 +159,6 @@ namespace T6
AUFT_NUM_FIELD_TYPES,
};
struct customMapVertex
{
vec3_t pos;
float binormalSign;
float color[4];
float texCoord[2];
vec3_t normal;
vec3_t tangent;
unsigned int packedLmapCoord;
};
enum CM_MATERIAL_TYPE
{
CM_MATERIAL_COLOUR,
CM_MATERIAL_TEXTURE,
CM_MATERIAL_EMPTY
};
struct customMapMaterial
{
CM_MATERIAL_TYPE materialType;
const char* materialName;
};
struct worldSurface
{
customMapMaterial material;
//char lightmapIndex;
//char primaryLightIndex;
//char reflectionProbeIndex;
int triCount;
int firstVertexIndex;
int firstIndex_Index;
};
struct customMapGfx
{
int vertexCount;
customMapVertex* vertices;
int indexCount;
uint16_t* indices;
int surfaceCount;
worldSurface* surfaces;
};
struct customMapColVertex
{
vec3_t pos;
};
struct collisionSurface
{
int triCount;
int firstVertexIndex;
int firstIndex_Index;
};
struct customMapCol
{
int vertexCount;
customMapColVertex* vertices;
int indexCount;
uint16_t* indices;
int surfaceCount;
collisionSurface* surfaces;
};
struct customMapModel
{
std::string name;
vec3_t origin;
vec3_t rotation; // euler rotation in degrees
float scale;
};
struct customMapInfo
{
std::string name;
std::string bspName;
customMapGfx gfxInfo;
customMapGfx colInfo;
size_t modelCount;
customMapModel* models;
};
using AssetPhysPreset = Asset<ASSET_TYPE_PHYSPRESET, PhysPreset>;
using AssetPhysConstraints = Asset<ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints>;
using AssetDestructibleDef = Asset<ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef>;

View File

@@ -1278,30 +1278,16 @@ namespace T6
typedef tdef_align32(4) char aligned_byte_pointer;
typedef tdef_align32(4) GfxCompressedLightGridCoeffs GfxCompressedLightGridCoeffs_align4;
struct GfxLightGridUnk
{
char unknown1;
char unknown2;
char unknown3;
char unknown4;
char unknown5;
char unknown6;
char unknown7;
char unknown8;
};
struct GfxLightGridRow
{
unsigned __int16 colStart;
unsigned __int16 colCount;
unsigned __int16 zStart;
unsigned __int16 zCount;
uint16_t colStart;
uint16_t colCount;
uint16_t zStart;
uint16_t zCount;
unsigned int firstEntry;
GfxLightGridUnk unk;
char lookupTable[1]; // The lookup table has a variable length
};
struct GfxLightGrid
{
unsigned int sunPrimaryLightIndex;

View File

@@ -0,0 +1,53 @@
#pragma once
#include <vector>
#include <string>
#include "Game/T6/T6.h"
using namespace T6;
struct CustomMapVertex
{
vec3_t pos;
vec4_t color;
vec2_t texCoord;
vec3_t normal;
vec3_t tangent;
};
enum CustomMapMaterialType
{
MATERIAL_TYPE_COLOUR,
MATERIAL_TYPE_TEXTURE,
MATERIAL_TYPE_EMPTY
};
struct CustomMapMaterial
{
CustomMapMaterialType materialType;
std::string materialName;
};
struct CustomMapSurface
{
CustomMapMaterial material;
int triCount;
int indexOfFirstVertex;
int indexOfFirstIndex;
};
struct CustomMapWorld
{
std::vector<CustomMapSurface> surfaces;
std::vector<CustomMapVertex> vertices;
std::vector<uint16_t> indices;
};
struct CustomMapBSP
{
std::string name;
std::string bspName;
CustomMapWorld gfxWorld;
CustomMapWorld colWorld;
};

View File

@@ -6,11 +6,11 @@ namespace shader
{
std::string GetFileNameForPixelShaderAssetName(const std::string& assetName)
{
return std::format("techniquesets/shader_bin/ps_{}.cso", assetName);
return std::format("shader_bin/ps_{}.cso", assetName);
}
std::string GetFileNameForVertexShaderAssetName(const std::string& assetName)
{
return std::format("techniquesets/shader_bin/vs_{}.cso", assetName);
return std::format("shader_bin/vs_{}.cso", assetName);
}
} // namespace shader

View File

@@ -1,14 +1,14 @@
#include "ProjectCreator.h"
#include "BSPCreator.h"
#include "fbx/ufbx.h"
#include "Game/T6/T6.h"
using namespace T6;
std::vector<customMapVertex> vertexVec;
std::vector<uint16_t> indexVec;
std::vector<worldSurface> surfaceVec;
std::vector<customMapModel> modelVec;
bool hasTangentSpace = true;
bool loadFBXMesh(ufbx_node* node)
bool addFBXMeshToWorld(ufbx_node* node,
std::vector<CustomMapSurface>& surfaceVec,
std::vector<CustomMapVertex>& vertexVec,
std::vector<uint16_t>& indexVec,
bool& hasTangentSpace)
{
if (node->attrib_type != UFBX_ELEMENT_MESH)
{
@@ -65,15 +65,15 @@ bool loadFBXMesh(ufbx_node* node)
if (meshPart->num_faces == 0)
continue;
worldSurface surface;
CustomMapSurface surface;
surface.triCount = meshPart->num_triangles;
surface.firstVertexIndex = vertexVec.size();
surface.firstIndex_Index = indexVec.size();
surface.indexOfFirstVertex = vertexVec.size();
surface.indexOfFirstIndex = indexVec.size();
CM_MATERIAL_TYPE meshMaterialType;
CustomMapMaterialType meshMaterialType;
if (mesh->materials.count == 0)
{
meshMaterialType = CM_MATERIAL_EMPTY;
meshMaterialType = MATERIAL_TYPE_EMPTY;
}
//else if (mesh->materials.data[i]->textures.count != 0)
//{
@@ -87,13 +87,13 @@ bool loadFBXMesh(ufbx_node* node)
//}
else
{
meshMaterialType = CM_MATERIAL_TEXTURE;
meshMaterialType = MATERIAL_TYPE_TEXTURE;
surface.material.materialName = _strdup(mesh->materials.data[i]->name.data);
}
surface.material.materialType = meshMaterialType;
size_t num_triangles = meshPart->num_triangles;
customMapVertex* vertices = (customMapVertex*)calloc(num_triangles * 3, sizeof(customMapVertex));
CustomMapVertex* vertices = (CustomMapVertex*)calloc(num_triangles * 3, sizeof(CustomMapVertex));
size_t num_vertices = 0;
// Reserve space for the maximum triangle indices.
@@ -113,7 +113,7 @@ bool loadFBXMesh(ufbx_node* node)
{
uint32_t index = tri_indices[q];
customMapVertex* vertex = &vertices[num_vertices++];
CustomMapVertex* vertex = &vertices[num_vertices++];
//ufbx_vec3 pos = ufbx_get_vertex_vec3(&mesh->vertex_position, index);
//vertex->pos.x = static_cast<float>(pos.x);
@@ -128,21 +128,21 @@ bool loadFBXMesh(ufbx_node* node)
switch (meshMaterialType)
{
case CM_MATERIAL_TEXTURE:
case CM_MATERIAL_EMPTY:
vertex->color[0] = 1.0f;
vertex->color[1] = 1.0f;
vertex->color[2] = 1.0f;
vertex->color[3] = 1.0f;
case MATERIAL_TYPE_TEXTURE:
case MATERIAL_TYPE_EMPTY:
vertex->color.x = 1.0f;
vertex->color.y = 1.0f;
vertex->color.z = 1.0f;
vertex->color.w = 1.0f;
break;
case CM_MATERIAL_COLOUR:
case MATERIAL_TYPE_COLOUR:
{
float factor = static_cast<float>(mesh->materials.data[i]->fbx.diffuse_factor.value_real);
ufbx_vec4 diffuse = mesh->materials.data[i]->fbx.diffuse_color.value_vec4;
vertex->color[0] = static_cast<float>(diffuse.x * factor);
vertex->color[1] = static_cast<float>(diffuse.y * factor);
vertex->color[2] = static_cast<float>(diffuse.z * factor);
vertex->color[3] = static_cast<float>(diffuse.w * factor);
vertex->color.x = static_cast<float>(diffuse.x * factor);
vertex->color.y = static_cast<float>(diffuse.y * factor);
vertex->color.z = static_cast<float>(diffuse.z * factor);
vertex->color.w = static_cast<float>(diffuse.w * factor);
break;
}
@@ -155,8 +155,8 @@ bool loadFBXMesh(ufbx_node* node)
// 1.0f - uv.y reason:
// https://gamedev.stackexchange.com/questions/92886/fbx-uv-coordinates-is-strange
ufbx_vec2 uv = ufbx_get_vertex_vec2(&mesh->vertex_uv, index);
vertex->texCoord[0] = (float)(uv.x);
vertex->texCoord[1] = (float)(1.0f - uv.y);
vertex->texCoord.x = (float)(uv.x);
vertex->texCoord.y = (float)(1.0f - uv.y);
ufbx_vec3 normal = ufbx_get_vertex_vec3(&mesh->vertex_normal, index);
vertex->normal.x = static_cast<float>(normal.x);
@@ -176,11 +176,6 @@ bool loadFBXMesh(ufbx_node* node)
vertex->tangent.y = 0.0f;
vertex->tangent.z = 0.0f;
}
vertex->packedLmapCoord = 0;
// possibly bitangent, unsure what the sign part means though
vertex->binormalSign = 0.0f;
}
}
@@ -188,7 +183,7 @@ bool loadFBXMesh(ufbx_node* node)
// Generate the index buffer.
ufbx_vertex_stream streams[1] = {
{vertices, num_vertices, sizeof(customMapVertex)},
{vertices, num_vertices, sizeof(CustomMapVertex)},
};
size_t num_indices = num_triangles * 3;
uint32_t* indices = (uint32_t*)calloc(num_indices, sizeof(uint32_t));
@@ -213,120 +208,32 @@ bool loadFBXMesh(ufbx_node* node)
return true;
}
bool loadFBXModel(ufbx_node* node)
void loadWorldData(ufbx_scene* scene, CustomMapBSP* bsp, bool isGfxData)
{
customMapModel model;
model.name = node->name.data;
model.origin.x = static_cast<float>(node->local_transform.translation.x);
model.origin.y = static_cast<float>(node->local_transform.translation.y);
model.origin.z = static_cast<float>(node->local_transform.translation.z);
model.rotation.x = static_cast<float>(node->euler_rotation.x);
model.rotation.y = static_cast<float>(node->euler_rotation.y);
model.rotation.z = static_cast<float>(node->euler_rotation.z);
model.scale = static_cast<float>(node->local_transform.scale.x);
if (model.scale == 0.0f)
{
printf("WARN: Ignoring model %s: has a scale of 0!\n", node->name.data);
return false;
}
if (node->local_transform.scale.x != node->local_transform.scale.y || node->local_transform.scale.x != node->local_transform.scale.z)
printf("WARNING: model %s uses non-uniform scaling! Only the X axis will be used for the scale value.\n", node->name.data);
modelVec.push_back(model);
return true;
}
void parseGFXData(ufbx_scene* scene, customMapInfo* projInfo)
{
vertexVec.clear();
indexVec.clear();
surfaceVec.clear();
modelVec.clear();
hasTangentSpace = true;
bool hasTangentSpace = true;
for (size_t i = 0; i < scene->nodes.count; i++)
{
ufbx_node* node = scene->nodes.data[i];
switch (node->attrib_type)
if (node->attrib_type == UFBX_ELEMENT_MESH)
{
if (isGfxData)
addFBXMeshToWorld(node, bsp->gfxWorld.surfaces, bsp->gfxWorld.vertices, bsp->gfxWorld.indices, hasTangentSpace);
else
addFBXMeshToWorld(node, bsp->colWorld.surfaces, bsp->colWorld.vertices, bsp->colWorld.indices, hasTangentSpace);
}
else
{
case UFBX_ELEMENT_MESH:
loadFBXMesh(node);
break;
case UFBX_ELEMENT_EMPTY:
// loadFBXModel(node);
break;
default:
//printf("ignoring node type %i: %s\n", node->attrib_type, node->name.data);
break;
}
}
projInfo->gfxInfo.surfaceCount = surfaceVec.size();
projInfo->gfxInfo.vertexCount = vertexVec.size();
projInfo->gfxInfo.indexCount = indexVec.size();
projInfo->modelCount = modelVec.size();
projInfo->gfxInfo.surfaces = new worldSurface[surfaceVec.size()];
projInfo->gfxInfo.vertices = new customMapVertex[vertexVec.size()];
projInfo->gfxInfo.indices = new uint16_t[indexVec.size()];
projInfo->models = new customMapModel[modelVec.size()];
memcpy(projInfo->gfxInfo.surfaces, &surfaceVec[0], surfaceVec.size() * sizeof(worldSurface));
memcpy(projInfo->gfxInfo.vertices, &vertexVec[0], vertexVec.size() * sizeof(customMapVertex));
memcpy(projInfo->gfxInfo.indices, &indexVec[0], indexVec.size() * sizeof(uint16_t));
// memcpy(projInfo->models, &modelVec[0], modelVec.size() * sizeof(customMapModel));
if (hasTangentSpace == false)
printf("warning: one or more meshes have no tangent space. Be sure to select the tangent space box when exporting the FBX from blender.\n");
}
void parseCollisionData(ufbx_scene* scene, customMapInfo* projInfo)
{
// hack: cbf changing the code for collision data, so just load collision dada as if it was gfx data
vertexVec.clear();
indexVec.clear();
surfaceVec.clear();
modelVec.clear();
hasTangentSpace = true;
for (size_t i = 0; i < scene->nodes.count; i++)
{
ufbx_node* node = scene->nodes.data[i];
switch (node->attrib_type)
{
case UFBX_ELEMENT_MESH:
loadFBXMesh(node);
break;
case UFBX_ELEMENT_EMPTY:
// loadFBXModel(node);
break;
default:
//printf("ignoring node type %i: %s\n", node->attrib_type, node->name.data);
break;
}
}
projInfo->colInfo.surfaceCount = surfaceVec.size();
projInfo->colInfo.vertexCount = vertexVec.size();
projInfo->colInfo.indexCount = indexVec.size();
projInfo->modelCount = modelVec.size();
projInfo->colInfo.surfaces = new worldSurface[surfaceVec.size()];
projInfo->colInfo.vertices = new customMapVertex[vertexVec.size()];
projInfo->colInfo.indices = new uint16_t[indexVec.size()];
projInfo->models = new customMapModel[modelVec.size()];
memcpy(projInfo->colInfo.surfaces, &surfaceVec[0], surfaceVec.size() * sizeof(worldSurface));
memcpy(projInfo->colInfo.vertices, &vertexVec[0], vertexVec.size() * sizeof(customMapVertex));
memcpy(projInfo->colInfo.indices, &indexVec[0], indexVec.size() * sizeof(uint16_t));
// memcpy(projInfo->models, &modelVec[0], modelVec.size() * sizeof(customMapModel));
if (hasTangentSpace == false)
printf("warning: one or more meshes have no tangent space. Be sure to select the tangent space box when exporting the FBX from blender.\n");
}
customMapInfo* ProjectCreator::createCustomMapInfo(std::string& projectName, ISearchPath& searchPath)
CustomMapBSP* BSPCreator::createCustomMapBSP(std::string& mapName, ISearchPath& searchPath)
{
ufbx_scene* gfxScene;
ufbx_scene* colScene;
@@ -379,13 +286,13 @@ customMapInfo* ProjectCreator::createCustomMapInfo(std::string& projectName, ISe
}
}
customMapInfo* projInfo = new customMapInfo;
CustomMapBSP* projInfo = new CustomMapBSP;
projInfo->name = projectName;
projInfo->bspName = "maps/mp/" + projectName + ".d3dbsp";
projInfo->name = mapName;
projInfo->bspName = "maps/mp/" + mapName + ".d3dbsp";
parseGFXData(gfxScene, projInfo);
parseCollisionData(colScene, projInfo);
loadWorldData(gfxScene, projInfo, true);
loadWorldData(colScene, projInfo, false);
ufbx_free_scene(gfxScene);
if (gfxScene != colScene)

View File

@@ -0,0 +1,10 @@
#pragma once
#include "Game/T6/Maps/CustomMaps.h"
#include "SearchPath/ISearchPath.h"
class BSPCreator
{
public:
static CustomMapBSP* createCustomMapBSP(std::string& mapName, ISearchPath& searchPath);
};

View File

@@ -1,22 +1,12 @@
#pragma once
/*
Heavily modified version of https://github.com/sudeshnapal12/Space-Partitioning-Algorithms BSP implementation
Credit to sudeshnapal12
BSP leaf sizes are precalculated, evenly sized BSPs are much more efficient and smaller compared to dynamically creating them
*/
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
#include <memory>
#define MAX_AABB_SIZE 512 // maximum size a BSP node can be before it becomes a leaf
#include "Game/T6/T6.h"
using namespace T6;
constexpr int MAX_NODE_SIZE = 512; // maximum size a BSP node can be before it becomes a leaf
enum PlaneAxis
{
@@ -28,56 +18,50 @@ enum PlaneAxis
class Object
{
public:
double low[3];
double high[3];
vec3_t min;
vec3_t max;
// custom data
int partitionIndex; // index of the partition the object is based on (custom)
int partitionIndex; // index of the partition the object is contained in
Object(double min_x, double min_y, double min_z, double max_x, double max_y, double max_z, int partition_Index)
Object(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax, int objPartitionIndex)
{
low[0] = min_x;
low[1] = min_y, low[2] = min_z;
high[0] = max_x;
high[1] = max_y;
high[2] = max_z;
partitionIndex = partition_Index;
min.x = xMin;
min.y = yMin;
min.z = zMin;
max.x = xMax;
max.y = yMax;
max.z = zMax;
partitionIndex = objPartitionIndex;
}
};
union u_BSPNode;
union u_BSPNode
{
BSPLeaf* leaf;
BSPNode* node;
};
class BSPTree;
class BSPLeaf
{
private:
std::vector<Object*> objectList;
std::vector<std::unique_ptr<Object>> objectList;
public:
BSPLeaf()
void addObject(std::unique_ptr<Object> object)
{
objectList = std::vector<Object*>();
objectList.push_back(std::move(object));
}
~BSPLeaf()
std::unique_ptr<Object> getObject(int index)
{
objectList.clear();
}
void addToList(Object* object)
{
objectList.push_back(object);
return std::move(objectList.at(index));
}
int getObjectCount()
{
return objectList.size();
}
Object* getObject(int index)
{
return objectList.at(index);
}
};
enum objectPlaneSide
@@ -106,25 +90,23 @@ public:
objectPlaneSide objectIsInfront(Object* object)
{
double minCoord, maxCoord;
float minCoord, maxCoord;
// Select the relevant coordinate based on the plane's axis
switch (axis)
if (axis == AXIS_X)
{
case AXIS_X:
minCoord = object->low[0];
maxCoord = object->high[0];
break;
case AXIS_Y:
minCoord = object->low[1];
maxCoord = object->high[1];
break;
case AXIS_Z:
minCoord = object->low[2];
maxCoord = object->high[2];
break;
default:
_ASSERT(false); // this should never be executed
minCoord = object->min.x;
maxCoord = object->max.x;
}
else if (axis == AXIS_Y)
{
minCoord = object->min.y;
maxCoord = object->max.y;
}
else // axis == AXIS_Z
{
minCoord = object->min.z;
maxCoord = object->max.z;
}
// Compare with the plane's distance
@@ -143,12 +125,6 @@ public:
}
};
union u_BSPNode
{
BSPLeaf* leaf;
BSPNode* node;
};
class BSPTree
{
public:
@@ -178,7 +154,7 @@ public:
BSPTree* back;
double halfLength;
if (high[0] - low[0] > MAX_AABB_SIZE)
if (high[0] - low[0] > MAX_NODE_SIZE)
{
// split along the x axis
halfLength = (low[0] + high[0]) * 0.5f;
@@ -188,7 +164,7 @@ public:
isLeaf = false;
u.node = new BSPNode(front, back, AXIS_X, halfLength);
}
else if (high[2] - low[2] > MAX_AABB_SIZE)
else if (high[2] - low[2] > MAX_NODE_SIZE)
{
// split along the z axis
halfLength = (low[2] + high[2]) * 0.5f;

View File

@@ -1,5 +1,7 @@
#include "Game/T6/Maps/CustomMaps.h"
#include "LoaderCustomMapT6.h"
#include "ProjectCreator.h"
#include "BSPCreator.h"
#include "CustomMapLinker.h"
#include "Game/T6/T6.h"
@@ -27,18 +29,16 @@ namespace
if (!mapGfxFile.IsOpen())
return AssetCreationResult::NoAction();
// create map info from the fbx file
customMapInfo* mapInfo = ProjectCreator::createCustomMapInfo(m_zone.m_name, m_search_path);
if (mapInfo == NULL)
CustomMapBSP* mapBSP = BSPCreator::createCustomMapBSP(m_zone.m_name, m_search_path);
if (mapBSP == NULL)
return AssetCreationResult::Failure();
// linker will add all the assets needed
CustomMapLinker* linker = new CustomMapLinker(m_memory, m_search_path, m_zone, context);
bool result = linker->linkCustomMap(mapInfo);
bool result = linker->linkCustomMap(mapBSP);
if (result)
{
auto gfxWorldAsset = context.LoadDependency<AssetGfxWorld>(mapInfo->bspName);
auto gfxWorldAsset = context.LoadDependency<AssetGfxWorld>(mapBSP->bspName);
_ASSERT(gfxWorldAsset != NULL);
return AssetCreationResult::Success(gfxWorldAsset);
}

View File

@@ -1,12 +0,0 @@
#pragma once
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include "Game/T6/T6.h"
using namespace T6;
class ProjectCreator
{
public:
static customMapInfo* createCustomMapInfo(std::string& projectName, ISearchPath& searchPath);
};