mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-11-23 13:12:06 +00:00
all known bugs fixed and loaded maps work correctly now.
This commit is contained in:
@@ -159,7 +159,6 @@ namespace T6
|
|||||||
AUFT_NUM_FIELD_TYPES,
|
AUFT_NUM_FIELD_TYPES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct customMapVertex
|
struct customMapVertex
|
||||||
{
|
{
|
||||||
vec3_t pos;
|
vec3_t pos;
|
||||||
@@ -171,13 +170,27 @@ namespace T6
|
|||||||
unsigned int packedLmapCoord;
|
unsigned int packedLmapCoord;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CM_MATERIAL_TYPE
|
||||||
|
{
|
||||||
|
NO_COLOUR_OR_TEXTURE,
|
||||||
|
CM_MATERIAL_COLOUR,
|
||||||
|
CM_MATERIAL_TEXTURE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct customMapMaterial
|
||||||
|
{
|
||||||
|
CM_MATERIAL_TYPE materialType;
|
||||||
|
const char* materialName;
|
||||||
|
};
|
||||||
|
|
||||||
struct worldSurface
|
struct worldSurface
|
||||||
{
|
{
|
||||||
char flags;
|
char flags;
|
||||||
char lightmapIndex;
|
customMapMaterial material;
|
||||||
std::string materialName;
|
|
||||||
char primaryLightIndex;
|
//char lightmapIndex;
|
||||||
char reflectionProbeIndex;
|
//char primaryLightIndex;
|
||||||
|
//char reflectionProbeIndex;
|
||||||
|
|
||||||
int triCount;
|
int triCount;
|
||||||
int firstVertexIndex;
|
int firstVertexIndex;
|
||||||
@@ -196,12 +209,49 @@ namespace T6
|
|||||||
worldSurface* surfaces;
|
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
|
struct customMapInfo
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string bspName;
|
std::string bspName;
|
||||||
|
|
||||||
customMapGfx gfxInfo;
|
customMapGfx gfxInfo;
|
||||||
|
customMapGfx colInfo;
|
||||||
|
|
||||||
|
size_t modelCount;
|
||||||
|
customMapModel* models;
|
||||||
};
|
};
|
||||||
|
|
||||||
using AssetPhysPreset = Asset<ASSET_TYPE_PHYSPRESET, PhysPreset>;
|
using AssetPhysPreset = Asset<ASSET_TYPE_PHYSPRESET, PhysPreset>;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Precalculated, evenly sized BSPs are much more efficient and smaller compared to
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define MAX_AABB_SIZE 512 // maximum size an AABB tree can be before it becomes a node
|
#include "CustomMapConsts.h"
|
||||||
|
|
||||||
enum PlaneAxis
|
enum PlaneAxis
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,14 +10,37 @@
|
|||||||
// material flags determine the features of the surface
|
// material flags determine the features of the surface
|
||||||
// unsure which flag type changes what right now
|
// unsure which flag type changes what right now
|
||||||
// -1 results in: no running, water splashes all the time, low friction, slanted angles make you slide very fast
|
// -1 results in: no running, water splashes all the time, low friction, slanted angles make you slide very fast
|
||||||
// 1 results in: normal surface features, grenades work,
|
// 1 results in: normal surface features, grenades work, seems normal
|
||||||
#define MATERIAL_SURFACE_FLAGS 1
|
#define MATERIAL_SURFACE_FLAGS 1
|
||||||
#define MATERIAL_CONTENT_FLAGS 1
|
#define MATERIAL_CONTENT_FLAGS 1
|
||||||
|
|
||||||
// terrain flags: does not change the type of terrain or what features they have
|
// terrain/world flags: does not change the type of terrain or what features they have
|
||||||
// from testing, as long at it isn't 0 things will work correctly
|
// from testing, as long at it isn't 0 things will work correctly
|
||||||
#define LEAF_TERRAIN_CONTENTS 1 // match all flags
|
#define LEAF_TERRAIN_CONTENTS 1
|
||||||
#define WORLD_TERRAIN_CONTENTS 1 // match all flags
|
#define WORLD_TERRAIN_CONTENTS 1
|
||||||
|
|
||||||
// const std::string defaultMaterialName = "wpc/intro_wall_plaster_light_blue_01";
|
const std::string missingMaterialName = "custom/missing_material";
|
||||||
const std::string defaultMaterialName = "wpc/dig_plastic_blue";
|
const std::string colourOnlyMaterialName = "custom/colour_only_material";
|
||||||
|
const std::string templateMaterialName = "custom/material_template";
|
||||||
|
|
||||||
|
#define DEFAULT_SURFACE_LIGHT 1
|
||||||
|
#define DEFAULT_SURFACE_LIGHTMAP 0
|
||||||
|
#define DEFAULT_SURFACE_REFLECTION_PROBE 0
|
||||||
|
|
||||||
|
#define MAX_AABB_SIZE 512 // maximum size a BSP node can be before it becomes a leaf
|
||||||
|
|
||||||
|
// do not change
|
||||||
|
#define MAX_COL_VERTS (UINT16_MAX - 1) // max amount of verts a map can have
|
||||||
|
|
||||||
|
// do not change
|
||||||
|
#define DEFAULT_LIGHT_INDEX 0
|
||||||
|
#define SUN_LIGHT_INDEX 1
|
||||||
|
|
||||||
|
// do not change
|
||||||
|
#define SMODEL_FLAG_NO_SHADOW 1
|
||||||
|
#define SMODEL_FLAG_IS_LIT 2
|
||||||
|
|
||||||
|
#define DEFAULT_SMODEL_CULL_DIST 10000.0f
|
||||||
|
#define DEFAULT_SMODEL_FLAGS SMODEL_FLAG_NO_SHADOW
|
||||||
|
#define DEFAULT_SMODEL_LIGHT 1
|
||||||
|
#define DEFAULT_SMODEL_REFLECTION_PROBE 0
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BinarySpacePartitionTreePreCalc.h"
|
#include "BinarySpacePartitionTreePreCalc.h"
|
||||||
|
#include "TriangleSort.h"
|
||||||
#include "CustomMapConsts.h"
|
#include "CustomMapConsts.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "Utils/Pack.h"
|
#include "Utils/Pack.h"
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
@@ -68,6 +70,7 @@ private:
|
|||||||
GfxPackedWorldVertex* GfxVertex = &vertexBuffer[i];
|
GfxPackedWorldVertex* GfxVertex = &vertexBuffer[i];
|
||||||
|
|
||||||
GfxVertex->xyz = CMUtil::convertToBO2Coords(WorldVertex->pos);
|
GfxVertex->xyz = CMUtil::convertToBO2Coords(WorldVertex->pos);
|
||||||
|
//GfxVertex->xyz = WorldVertex->pos;
|
||||||
|
|
||||||
GfxVertex->binormalSign = WorldVertex->binormalSign;
|
GfxVertex->binormalSign = WorldVertex->binormalSign;
|
||||||
|
|
||||||
@@ -76,8 +79,10 @@ private:
|
|||||||
GfxVertex->texCoord.packed = pack32::Vec2PackTexCoordsUV(WorldVertex->texCoord);
|
GfxVertex->texCoord.packed = pack32::Vec2PackTexCoordsUV(WorldVertex->texCoord);
|
||||||
|
|
||||||
GfxVertex->normal.packed = pack32::Vec3PackUnitVecThirdBased(CMUtil::convertToBO2Coords(WorldVertex->normal).v);
|
GfxVertex->normal.packed = pack32::Vec3PackUnitVecThirdBased(CMUtil::convertToBO2Coords(WorldVertex->normal).v);
|
||||||
|
//GfxVertex->normal.packed = pack32::Vec3PackUnitVecThirdBased(WorldVertex->normal.v);
|
||||||
|
|
||||||
GfxVertex->tangent.packed = pack32::Vec3PackUnitVecThirdBased(CMUtil::convertToBO2Coords(WorldVertex->tangent).v);
|
GfxVertex->tangent.packed = pack32::Vec3PackUnitVecThirdBased(CMUtil::convertToBO2Coords(WorldVertex->tangent).v);
|
||||||
|
//GfxVertex->tangent.packed = pack32::Vec3PackUnitVecThirdBased(WorldVertex->tangent.v);
|
||||||
|
|
||||||
GfxVertex->lmapCoord.packed = WorldVertex->packedLmapCoord;
|
GfxVertex->lmapCoord.packed = WorldVertex->packedLmapCoord;
|
||||||
}
|
}
|
||||||
@@ -125,14 +130,14 @@ private:
|
|||||||
gfxWorld->surfaceCount = surfaceCount;
|
gfxWorld->surfaceCount = surfaceCount;
|
||||||
gfxWorld->dpvs.staticSurfaceCount = surfaceCount;
|
gfxWorld->dpvs.staticSurfaceCount = surfaceCount;
|
||||||
gfxWorld->dpvs.surfaces = new GfxSurface[surfaceCount];
|
gfxWorld->dpvs.surfaces = new GfxSurface[surfaceCount];
|
||||||
for (int i = 0; i < surfaceCount; i++)
|
for (unsigned int i = 0; i < surfaceCount; i++)
|
||||||
{
|
{
|
||||||
auto currSurface = &gfxWorld->dpvs.surfaces[i];
|
auto currSurface = &gfxWorld->dpvs.surfaces[i];
|
||||||
auto objSurface = &projInfo->gfxInfo.surfaces[i];
|
auto objSurface = &projInfo->gfxInfo.surfaces[i];
|
||||||
|
|
||||||
currSurface->lightmapIndex = objSurface->lightmapIndex;
|
currSurface->primaryLightIndex = DEFAULT_SURFACE_LIGHT;
|
||||||
currSurface->primaryLightIndex = objSurface->primaryLightIndex;
|
currSurface->lightmapIndex = DEFAULT_SURFACE_LIGHTMAP;
|
||||||
currSurface->reflectionProbeIndex = objSurface->reflectionProbeIndex;
|
currSurface->reflectionProbeIndex = DEFAULT_SURFACE_REFLECTION_PROBE;
|
||||||
currSurface->flags = objSurface->flags;
|
currSurface->flags = objSurface->flags;
|
||||||
|
|
||||||
currSurface->tris.triCount = objSurface->triCount;
|
currSurface->tris.triCount = objSurface->triCount;
|
||||||
@@ -141,12 +146,31 @@ private:
|
|||||||
currSurface->tris.vertexDataOffset0 = objSurface->firstVertexIndex * sizeof(GfxPackedWorldVertex);
|
currSurface->tris.vertexDataOffset0 = objSurface->firstVertexIndex * sizeof(GfxPackedWorldVertex);
|
||||||
currSurface->tris.vertexDataOffset1 = 0;
|
currSurface->tris.vertexDataOffset1 = 0;
|
||||||
|
|
||||||
auto* assetInfo = m_context.LoadDependency<AssetMaterial>(objSurface->materialName);
|
std::string surfMaterialName;
|
||||||
|
switch (objSurface->material.materialType)
|
||||||
|
{
|
||||||
|
case CM_MATERIAL_TEXTURE:
|
||||||
|
surfMaterialName = objSurface->material.materialName;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CM_MATERIAL_COLOUR:
|
||||||
|
case NO_COLOUR_OR_TEXTURE:
|
||||||
|
surfMaterialName = colourOnlyMaterialName;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_ASSERT(false);
|
||||||
|
}
|
||||||
|
auto* assetInfo = m_context.LoadDependency<AssetMaterial>(surfMaterialName);
|
||||||
if (assetInfo == NULL)
|
if (assetInfo == NULL)
|
||||||
{
|
{
|
||||||
printf("Warning: unable to load surface material %s, replacing with the default texture\n", objSurface->materialName.c_str());
|
assetInfo = m_context.LoadDependency<AssetMaterial>(missingMaterialName);
|
||||||
assetInfo = m_context.LoadDependency<AssetMaterial>(defaultMaterialName);
|
if (assetInfo == NULL)
|
||||||
_ASSERT(assetInfo != NULL);
|
{
|
||||||
|
printf("Error: unable to find the default texture!\n");
|
||||||
|
hasLinkFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currSurface->material = assetInfo->Asset();
|
currSurface->material = assetInfo->Asset();
|
||||||
|
|
||||||
@@ -159,7 +183,8 @@ private:
|
|||||||
currSurface->bounds[1].z = firstVert[0].xyz.z;
|
currSurface->bounds[1].z = firstVert[0].xyz.z;
|
||||||
for (int k = 0; k < currSurface->tris.triCount * 3; k++)
|
for (int k = 0; k < currSurface->tris.triCount * 3; k++)
|
||||||
{
|
{
|
||||||
CMUtil::calcNewBoundsWithPoint(&firstVert[k].xyz, &currSurface->bounds[0], &currSurface->bounds[1]);
|
uint16_t vertIndex = gfxWorld->draw.indices[currSurface->tris.baseIndex + k];
|
||||||
|
CMUtil::calcNewBoundsWithPoint(&firstVert[vertIndex].xyz, &currSurface->bounds[0], &currSurface->bounds[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unused values
|
// unused values
|
||||||
@@ -176,7 +201,7 @@ private:
|
|||||||
|
|
||||||
// doesn't seem to matter what order the sorted surfs go in
|
// doesn't seem to matter what order the sorted surfs go in
|
||||||
gfxWorld->dpvs.sortedSurfIndex = new uint16_t[surfaceCount];
|
gfxWorld->dpvs.sortedSurfIndex = new uint16_t[surfaceCount];
|
||||||
for (int i = 0; i < surfaceCount; i++)
|
for (unsigned int i = 0; i < surfaceCount; i++)
|
||||||
{
|
{
|
||||||
gfxWorld->dpvs.sortedSurfIndex[i] = i;
|
gfxWorld->dpvs.sortedSurfIndex[i] = i;
|
||||||
}
|
}
|
||||||
@@ -209,51 +234,38 @@ private:
|
|||||||
gfxWorld->dpvs.litTransSurfsEnd = surfaceCount;
|
gfxWorld->dpvs.litTransSurfsEnd = surfaceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SMODEL_FLAG_NO_SHADOW 1
|
void overwriteMapSModels(customMapInfo* projInfo, GfxWorld* gfxWorld)
|
||||||
#define SMODEL_FLAG_IS_LIT 2
|
|
||||||
|
|
||||||
void overwriteMapSModels(GfxWorld* gfxWorld)
|
|
||||||
{
|
{
|
||||||
unsigned int modelCount = 0;
|
unsigned int modelCount = projInfo->modelCount;
|
||||||
gfxWorld->dpvs.smodelCount = modelCount;
|
gfxWorld->dpvs.smodelCount = modelCount;
|
||||||
|
|
||||||
gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
|
gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
|
||||||
gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount];
|
gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount];
|
||||||
/*
|
|
||||||
for (unsigned int i = 0; i < modelCount; i++)
|
for (unsigned int i = 0; i < modelCount; i++)
|
||||||
{
|
{
|
||||||
auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i];
|
auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i];
|
||||||
auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
|
auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
|
||||||
json currModelJs = js["models"][i];
|
customMapModel* inModel = &projInfo->models[i];
|
||||||
|
|
||||||
// TODO: load custom xmodels
|
auto xModelAsset = m_context.LoadDependency<AssetXModel>(inModel->name);
|
||||||
std::string modelName = currModelJs["model"];
|
|
||||||
auto xModelAsset = findAsset(assetPool, ASSET_TYPE_XMODEL, modelName);
|
|
||||||
if (xModelAsset == NULL)
|
if (xModelAsset == NULL)
|
||||||
{
|
{
|
||||||
printf("Custom model (%s) not supported!\n", modelName.c_str());
|
printf("XModel %s not found!\n", inModel->name.c_str());
|
||||||
hasLinkFailed = true;
|
currModel->model = NULL;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
currModel->model = (XModel*)xModelAsset->m_ptr;
|
else
|
||||||
|
currModel->model = (XModel*)xModelAsset->Asset();
|
||||||
|
|
||||||
currModel->placement.origin.x = currModelJs["origin"]["x"];
|
currModel->placement.origin.x = inModel->origin.x;
|
||||||
currModel->placement.origin.y = currModelJs["origin"]["y"];
|
currModel->placement.origin.y = inModel->origin.y;
|
||||||
currModel->placement.origin.z = currModelJs["origin"]["z"];
|
currModel->placement.origin.z = inModel->origin.z;
|
||||||
currModel->placement.origin = CMUtil::convertToBO2Coords(currModel->placement.origin);
|
currModel->placement.origin = CMUtil::convertToBO2Coords(currModel->placement.origin);
|
||||||
currModel->placement.axis[0].x = currModelJs["forward"]["x"];
|
currModel->placement.scale = inModel->scale;
|
||||||
currModel->placement.axis[0].y = currModelJs["forward"]["y"];
|
|
||||||
currModel->placement.axis[0].z = currModelJs["forward"]["z"];
|
CMUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
|
||||||
currModel->placement.axis[1].x = currModelJs["right"]["x"];
|
|
||||||
currModel->placement.axis[1].y = currModelJs["right"]["y"];
|
|
||||||
currModel->placement.axis[1].z = currModelJs["right"]["z"];
|
|
||||||
currModel->placement.axis[2].x = currModelJs["up"]["x"];
|
|
||||||
currModel->placement.axis[2].y = currModelJs["up"]["y"];
|
|
||||||
currModel->placement.axis[2].z = currModelJs["up"]["z"];
|
|
||||||
currModel->placement.scale = currModelJs["scale"];
|
|
||||||
|
|
||||||
// mins and maxs are calculated in world space not local space
|
// mins and maxs are calculated in world space not local space
|
||||||
// TODO: mins and maxs are slightly different to what bo2 uses, which results in some wierd culling ingame
|
// TODO: this does not account for model rotation or scale
|
||||||
currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
|
currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
|
||||||
currModelInst->mins.y = currModel->model->mins.y + currModel->placement.origin.y;
|
currModelInst->mins.y = currModel->model->mins.y + currModel->placement.origin.y;
|
||||||
currModelInst->mins.z = currModel->model->mins.z + currModel->placement.origin.z;
|
currModelInst->mins.z = currModel->model->mins.z + currModel->placement.origin.z;
|
||||||
@@ -261,10 +273,10 @@ private:
|
|||||||
currModelInst->maxs.y = currModel->model->maxs.y + currModel->placement.origin.y;
|
currModelInst->maxs.y = currModel->model->maxs.y + currModel->placement.origin.y;
|
||||||
currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
|
currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
|
||||||
|
|
||||||
currModel->cullDist = currModelJs["cullDist"];
|
currModel->cullDist = DEFAULT_SMODEL_CULL_DIST;
|
||||||
currModel->flags = currModelJs["flags"];
|
currModel->flags = DEFAULT_SMODEL_FLAGS;
|
||||||
currModel->primaryLightIndex = (unsigned char)currModelJs["primaryLightIndex"];
|
currModel->primaryLightIndex = DEFAULT_SMODEL_LIGHT;
|
||||||
currModel->reflectionProbeIndex = (unsigned char)currModelJs["reflectionProbeIndex"];
|
currModel->reflectionProbeIndex = DEFAULT_SMODEL_REFLECTION_PROBE;
|
||||||
|
|
||||||
// unknown use / unused
|
// unknown use / unused
|
||||||
currModel->smid = i;
|
currModel->smid = i;
|
||||||
@@ -285,7 +297,7 @@ private:
|
|||||||
currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
|
currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
|
||||||
currModel->lmapVertexInfo[3].lmapVertexColors = NULL;
|
currModel->lmapVertexInfo[3].lmapVertexColors = NULL;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// all visdata is alligned by 128
|
// all visdata is alligned by 128
|
||||||
gfxWorld->dpvs.smodelVisDataCount = CMUtil::allignBy128(modelCount);
|
gfxWorld->dpvs.smodelVisDataCount = CMUtil::allignBy128(modelCount);
|
||||||
@@ -399,10 +411,10 @@ private:
|
|||||||
{
|
{
|
||||||
// there must be 2 or more lights, first is the default light and second is the sun
|
// there must be 2 or more lights, first is the default light and second is the sun
|
||||||
gfxWorld->primaryLightCount = 2;
|
gfxWorld->primaryLightCount = 2;
|
||||||
gfxWorld->sunPrimaryLightIndex = 1; // the sun is always index 1
|
gfxWorld->sunPrimaryLightIndex = SUN_LIGHT_INDEX; // the sun is always index 1
|
||||||
|
|
||||||
gfxWorld->shadowGeom = new GfxShadowGeometry[gfxWorld->primaryLightCount];
|
gfxWorld->shadowGeom = new GfxShadowGeometry[gfxWorld->primaryLightCount];
|
||||||
for (int i = 0; i < gfxWorld->primaryLightCount; i++)
|
for (unsigned int i = 0; i < gfxWorld->primaryLightCount; i++)
|
||||||
{
|
{
|
||||||
gfxWorld->shadowGeom[i].smodelCount = 0;
|
gfxWorld->shadowGeom[i].smodelCount = 0;
|
||||||
gfxWorld->shadowGeom[i].surfaceCount = 0;
|
gfxWorld->shadowGeom[i].surfaceCount = 0;
|
||||||
@@ -411,7 +423,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfxWorld->lightRegion = new GfxLightRegion[gfxWorld->primaryLightCount];
|
gfxWorld->lightRegion = new GfxLightRegion[gfxWorld->primaryLightCount];
|
||||||
for (int i = 0; i < gfxWorld->primaryLightCount; i++)
|
for (unsigned int i = 0; i < gfxWorld->primaryLightCount; i++)
|
||||||
{
|
{
|
||||||
gfxWorld->lightRegion[i].hullCount = 0;
|
gfxWorld->lightRegion[i].hullCount = 0;
|
||||||
gfxWorld->lightRegion[i].hulls = NULL;
|
gfxWorld->lightRegion[i].hulls = NULL;
|
||||||
@@ -440,7 +452,7 @@ private:
|
|||||||
|
|
||||||
gfxWorld->lightGrid.rowAxis = 0; // default value
|
gfxWorld->lightGrid.rowAxis = 0; // default value
|
||||||
gfxWorld->lightGrid.colAxis = 1; // default value
|
gfxWorld->lightGrid.colAxis = 1; // default value
|
||||||
gfxWorld->lightGrid.sunPrimaryLightIndex = 1; // the sun is always index 1
|
gfxWorld->lightGrid.sunPrimaryLightIndex = SUN_LIGHT_INDEX; // the sun is always index 1
|
||||||
gfxWorld->lightGrid.offset = 0.0f;
|
gfxWorld->lightGrid.offset = 0.0f;
|
||||||
|
|
||||||
// if rowDataStart's first value is -1, it will not look up any lightmap data
|
// if rowDataStart's first value is -1, it will not look up any lightmap data
|
||||||
@@ -518,9 +530,11 @@ private:
|
|||||||
// Nodes mnode_t.cellIndex indexes gfxWorld->cells
|
// Nodes mnode_t.cellIndex indexes gfxWorld->cells
|
||||||
// and (mnode_t.cellIndex - (world->dpvsPlanes.cellCount + 1) indexes world->dpvsPlanes.planes
|
// and (mnode_t.cellIndex - (world->dpvsPlanes.cellCount + 1) indexes world->dpvsPlanes.planes
|
||||||
gfxWorld->nodeCount = 1;
|
gfxWorld->nodeCount = 1;
|
||||||
gfxWorld->planeCount = 0;
|
|
||||||
gfxWorld->dpvsPlanes.nodes = new uint16_t[gfxWorld->nodeCount];
|
gfxWorld->dpvsPlanes.nodes = new uint16_t[gfxWorld->nodeCount];
|
||||||
gfxWorld->dpvsPlanes.nodes[0] = 1; // nodes reference cells by index + 1
|
gfxWorld->dpvsPlanes.nodes[0] = 1; // nodes reference cells by index + 1
|
||||||
|
|
||||||
|
// planes are overwritten by the clipmap loading code ingame
|
||||||
|
gfxWorld->planeCount = 0;
|
||||||
gfxWorld->dpvsPlanes.planes = NULL;
|
gfxWorld->dpvsPlanes.planes = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,10 +555,13 @@ private:
|
|||||||
|
|
||||||
void overwriteModels(GfxWorld* gfxWorld)
|
void overwriteModels(GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
|
// these models are the collision for the entities defined in the mapents asset
|
||||||
|
// used for triggers and stuff
|
||||||
|
|
||||||
gfxWorld->modelCount = 1;
|
gfxWorld->modelCount = 1;
|
||||||
gfxWorld->models = new GfxBrushModel[gfxWorld->modelCount];
|
gfxWorld->models = new GfxBrushModel[gfxWorld->modelCount];
|
||||||
|
|
||||||
// first model is the world model, the world json doesn't include it so its added here
|
// first model is always the world model
|
||||||
gfxWorld->models[0].startSurfIndex = 0;
|
gfxWorld->models[0].startSurfIndex = 0;
|
||||||
gfxWorld->models[0].surfaceCount = gfxWorld->surfaceCount;
|
gfxWorld->models[0].surfaceCount = gfxWorld->surfaceCount;
|
||||||
gfxWorld->models[0].bounds[0].x = gfxWorld->mins.x;
|
gfxWorld->models[0].bounds[0].x = gfxWorld->mins.x;
|
||||||
@@ -576,7 +593,7 @@ private:
|
|||||||
void updateSunData(GfxWorld* gfxWorld)
|
void updateSunData(GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
// default values taken from mp_dig
|
// default values taken from mp_dig
|
||||||
gfxWorld->sunParse.fogTransitionTime = 0.001;
|
gfxWorld->sunParse.fogTransitionTime = (float)0.001;
|
||||||
gfxWorld->sunParse.name[0] = 0x00;
|
gfxWorld->sunParse.name[0] = 0x00;
|
||||||
|
|
||||||
gfxWorld->sunParse.initWorldSun->control = 0;
|
gfxWorld->sunParse.initWorldSun->control = 0;
|
||||||
@@ -783,7 +800,7 @@ private:
|
|||||||
|
|
||||||
overwriteMapSurfaces(projInfo, gfxWorld);
|
overwriteMapSurfaces(projInfo, gfxWorld);
|
||||||
|
|
||||||
overwriteMapSModels(gfxWorld);
|
overwriteMapSModels(projInfo, gfxWorld);
|
||||||
|
|
||||||
overwriteLightmapData(gfxWorld);
|
overwriteLightmapData(gfxWorld);
|
||||||
|
|
||||||
@@ -813,6 +830,49 @@ private:
|
|||||||
m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld);
|
m_context.AddAsset<AssetGfxWorld>(gfxWorld->name, gfxWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addXModelsToCollision(customMapInfo* projInfo, clipMap_t* clipMap)
|
||||||
|
{
|
||||||
|
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(projInfo->bspName);
|
||||||
|
_ASSERT(gfxWorldAsset != NULL);
|
||||||
|
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
|
||||||
|
|
||||||
|
clipMap->numStaticModels = gfxWorld->dpvs.smodelCount;
|
||||||
|
clipMap->staticModelList = new cStaticModel_s[clipMap->numStaticModels];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < clipMap->numStaticModels; i++)
|
||||||
|
{
|
||||||
|
GfxStaticModelDrawInst* gfxModelDrawInst = &gfxWorld->dpvs.smodelDrawInsts[i];
|
||||||
|
GfxStaticModelInst* gfxModelInst = &gfxWorld->dpvs.smodelInsts[i];
|
||||||
|
cStaticModel_s* currModel = &clipMap->staticModelList[i];
|
||||||
|
|
||||||
|
memset(&currModel->writable, 0, sizeof(cStaticModelWritable));
|
||||||
|
currModel->xmodel = gfxModelDrawInst->model;
|
||||||
|
currModel->contents = gfxModelDrawInst->model->contents;
|
||||||
|
currModel->origin.x = gfxModelDrawInst->placement.origin.x;
|
||||||
|
currModel->origin.y = gfxModelDrawInst->placement.origin.y;
|
||||||
|
currModel->origin.z = gfxModelDrawInst->placement.origin.z;
|
||||||
|
|
||||||
|
// TODO: this does not account for model rotation or scale
|
||||||
|
currModel->absmin.x = gfxModelInst->mins.x;
|
||||||
|
currModel->absmin.y = gfxModelInst->mins.y;
|
||||||
|
currModel->absmin.z = gfxModelInst->mins.z;
|
||||||
|
currModel->absmax.x = gfxModelInst->maxs.x;
|
||||||
|
currModel->absmax.y = gfxModelInst->maxs.y;
|
||||||
|
currModel->absmax.z = gfxModelInst->maxs.z;
|
||||||
|
|
||||||
|
CMUtil::matrixTranspose3x3(gfxModelDrawInst->placement.axis, currModel->invScaledAxis);
|
||||||
|
currModel->invScaledAxis[0].x = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[0].x;
|
||||||
|
currModel->invScaledAxis[0].y = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[0].y;
|
||||||
|
currModel->invScaledAxis[0].z = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[0].z;
|
||||||
|
currModel->invScaledAxis[1].x = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[1].x;
|
||||||
|
currModel->invScaledAxis[1].y = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[1].y;
|
||||||
|
currModel->invScaledAxis[1].z = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[1].z;
|
||||||
|
currModel->invScaledAxis[2].x = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[2].x;
|
||||||
|
currModel->invScaledAxis[2].y = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[2].y;
|
||||||
|
currModel->invScaledAxis[2].z = (1.0f / gfxModelDrawInst->placement.scale) * currModel->invScaledAxis[2].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void aabbCalcOriginAndHalfSize(vec3_t* mins, vec3_t* maxs, vec3_t* out_origin, vec3_t* out_halfSize)
|
void aabbCalcOriginAndHalfSize(vec3_t* mins, vec3_t* maxs, vec3_t* out_origin, vec3_t* out_halfSize)
|
||||||
{
|
{
|
||||||
// Origin is the midpoint: (min + max) / 2
|
// Origin is the midpoint: (min + max) / 2
|
||||||
@@ -841,14 +901,6 @@ private:
|
|||||||
return (edgeBitMask & clipMap->triEdgeIsWalkable[(triIndex + edgeIndex + 2 * triIndex) >> 3]) != 0;
|
return (edgeBitMask & clipMap->triEdgeIsWalkable[(triIndex + edgeIndex + 2 * triIndex) >> 3]) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float distBetweenPoints(vec3_t p1, vec3_t p2)
|
|
||||||
{
|
|
||||||
float x = p2.x - p1.x;
|
|
||||||
float y = p2.y - p1.y;
|
|
||||||
float z = p2.z - p1.z;
|
|
||||||
return sqrtf((x * x) + (y * y) + (z * z));
|
|
||||||
}
|
|
||||||
|
|
||||||
void traverseBSPTreeForCounts(BSPTree* node, int* numPlanes, int* numNodes, int* numLeafs, int* numAABBTrees, int* maxObjsPerLeaf)
|
void traverseBSPTreeForCounts(BSPTree* node, int* numPlanes, int* numNodes, int* numLeafs, int* numAABBTrees, int* maxObjsPerLeaf)
|
||||||
{
|
{
|
||||||
if (node->isLeaf)
|
if (node->isLeaf)
|
||||||
@@ -920,7 +972,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create root AABB node
|
|
||||||
CollisionAabbTree* rootAABB = &clipMap->aabbTrees[firstAABBIndex];
|
CollisionAabbTree* rootAABB = &clipMap->aabbTrees[firstAABBIndex];
|
||||||
aabbCalcOriginAndHalfSize(&aabbMins, &aabbMaxs, &rootAABB->origin, &rootAABB->halfSize);
|
aabbCalcOriginAndHalfSize(&aabbMins, &aabbMaxs, &rootAABB->origin, &rootAABB->halfSize);
|
||||||
rootAABB->materialIndex = 0;
|
rootAABB->materialIndex = 0;
|
||||||
@@ -1015,7 +1066,7 @@ private:
|
|||||||
|
|
||||||
// converting OGL -> BO2 X coords doesn't change the x coords at all, so
|
// converting OGL -> BO2 X coords doesn't change the x coords at all, so
|
||||||
// the dist stays the same
|
// the dist stays the same
|
||||||
currPlane->dist = node->u.node->distance;
|
currPlane->dist = (float)node->u.node->distance;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1027,7 +1078,7 @@ private:
|
|||||||
|
|
||||||
// converting OGL -> BO2 Z coords negates the z coords and sets it to the y coord.
|
// converting OGL -> BO2 Z coords negates the z coords and sets it to the y coord.
|
||||||
// just negate it here as it is just the distance from the orgin along the axis
|
// just negate it here as it is just the distance from the orgin along the axis
|
||||||
currPlane->dist = -node->u.node->distance;
|
currPlane->dist = (float)(-node->u.node->distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool foundType = false;
|
bool foundType = false;
|
||||||
@@ -1127,6 +1178,118 @@ private:
|
|||||||
_ASSERT(clipMap->aabbTreeCount == currAABBCount);
|
_ASSERT(clipMap->aabbTreeCount == currAABBCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createPartitions(customMapInfo* projInfo, clipMap_t* clipMap)
|
||||||
|
{
|
||||||
|
int collisionVertexCount = projInfo->colInfo.vertexCount;
|
||||||
|
std::vector<vec3_t> collisionVertVec;
|
||||||
|
for (int i = 0; i < collisionVertexCount; i++)
|
||||||
|
{
|
||||||
|
collisionVertVec.push_back(CMUtil::convertToBO2Coords(projInfo->colInfo.vertices[i].pos));
|
||||||
|
//collisionVertVec.push_back(projInfo->colInfo.vertices[i].pos);
|
||||||
|
}
|
||||||
|
clipMap->vertCount = collisionVertexCount;
|
||||||
|
clipMap->verts = new vec3_t[collisionVertexCount];
|
||||||
|
memcpy(clipMap->verts, &collisionVertVec[0], sizeof(vec3_t) * collisionVertexCount);
|
||||||
|
|
||||||
|
// due to tris using uint16_t as the type for indexing the vert array,
|
||||||
|
// any vertex count over the uint16_t max means the vertices above it can't be indexed
|
||||||
|
if (collisionVertexCount > MAX_COL_VERTS)
|
||||||
|
{
|
||||||
|
printf("ERROR: collision vertex count %i exceeds the maximum number: %i!\n", collisionVertexCount, MAX_COL_VERTS);
|
||||||
|
hasLinkFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint16_t> triIndexVec;
|
||||||
|
for (int i = 0; i < projInfo->colInfo.surfaceCount; i++)
|
||||||
|
{
|
||||||
|
worldSurface* currSurface = &projInfo->colInfo.surfaces[i];
|
||||||
|
int triCount = currSurface->triCount;
|
||||||
|
|
||||||
|
for (int k = 0; k < triCount * 3; k += 3)
|
||||||
|
{
|
||||||
|
int firstIndex_Index = currSurface->firstIndex_Index;
|
||||||
|
int firstVertexIndex = currSurface->firstVertexIndex;
|
||||||
|
|
||||||
|
// gfx index bufer starts at 0 for each new mesh, while the clipmap index buffer indexes the entire
|
||||||
|
// clipmap verts buffer, so this code updates the indexes to follow that.
|
||||||
|
int triIndex0 = projInfo->colInfo.indices[firstIndex_Index + (k + 0)] + firstVertexIndex;
|
||||||
|
int triIndex1 = projInfo->colInfo.indices[firstIndex_Index + (k + 1)] + firstVertexIndex;
|
||||||
|
int triIndex2 = projInfo->colInfo.indices[firstIndex_Index + (k + 2)] + firstVertexIndex;
|
||||||
|
|
||||||
|
// triangle index ordering is opposite to blenders, so its converted here
|
||||||
|
triIndexVec.push_back(triIndex2);
|
||||||
|
triIndexVec.push_back(triIndex1);
|
||||||
|
triIndexVec.push_back(triIndex0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ASSERT(triIndexVec.size() % 3 == 0);
|
||||||
|
clipMap->triCount = triIndexVec.size() / 3;
|
||||||
|
clipMap->triIndices = (uint16_t(*)[3])(new uint16_t[triIndexVec.size()]);
|
||||||
|
memcpy(clipMap->triIndices, &triIndexVec[0], sizeof(uint16_t) * triIndexVec.size());
|
||||||
|
|
||||||
|
// partitions are made for each triangle, not one for each surface.
|
||||||
|
// one for each surface causes physics bugs, as the entire bounding box is considered solid instead of the surface itself (for some reason).
|
||||||
|
// so a partition is made for each triangle which removes the physics bugs but likely makes the game run slower
|
||||||
|
std::vector<CollisionPartition> partitionVec;
|
||||||
|
for (int i = 0; i < projInfo->colInfo.surfaceCount; i++)
|
||||||
|
{
|
||||||
|
int triCount = projInfo->colInfo.surfaces[i].triCount;
|
||||||
|
int firstTriIndex = projInfo->colInfo.surfaces[i].firstIndex_Index / 3;
|
||||||
|
for (int k = 0; k < triCount; k++)
|
||||||
|
{
|
||||||
|
CollisionPartition newPartition;
|
||||||
|
newPartition.nuinds = 0; // initialised later
|
||||||
|
newPartition.fuind = 0; // initialised later
|
||||||
|
newPartition.triCount = 1;
|
||||||
|
newPartition.firstTri = firstTriIndex;
|
||||||
|
firstTriIndex += 1;
|
||||||
|
|
||||||
|
partitionVec.push_back(newPartition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clipMap->partitionCount = partitionVec.size();
|
||||||
|
clipMap->partitions = new CollisionPartition[clipMap->partitionCount];
|
||||||
|
memcpy(clipMap->partitions, &partitionVec[0], sizeof(CollisionPartition) * clipMap->partitionCount);
|
||||||
|
|
||||||
|
int totalUindCount = 0;
|
||||||
|
std::vector<uint16_t> uindVec;
|
||||||
|
for (int i = 0; i < clipMap->partitionCount; i++)
|
||||||
|
{
|
||||||
|
CollisionPartition* currPartition = &clipMap->partitions[i];
|
||||||
|
std::vector<uint16_t> uniqueVertVec;
|
||||||
|
for (int k = 0; k < currPartition->triCount; k++)
|
||||||
|
{
|
||||||
|
uint16_t* tri = clipMap->triIndices[currPartition->firstTri + k];
|
||||||
|
for (int l = 0; l < 3; l++)
|
||||||
|
{
|
||||||
|
bool isVertexIndexUnique = true;
|
||||||
|
uint16_t vertIndex = tri[l];
|
||||||
|
|
||||||
|
for (size_t m = 0; m < uniqueVertVec.size(); m++)
|
||||||
|
{
|
||||||
|
if (uniqueVertVec[m] == vertIndex)
|
||||||
|
{
|
||||||
|
isVertexIndexUnique = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVertexIndexUnique)
|
||||||
|
uniqueVertVec.push_back(vertIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currPartition->fuind = totalUindCount;
|
||||||
|
currPartition->nuinds = (int)uniqueVertVec.size();
|
||||||
|
uindVec.insert(uindVec.end(), uniqueVertVec.begin(), uniqueVertVec.end());
|
||||||
|
totalUindCount += currPartition->nuinds;
|
||||||
|
}
|
||||||
|
clipMap->info.nuinds = totalUindCount;
|
||||||
|
clipMap->info.uinds = new uint16_t[totalUindCount];
|
||||||
|
memcpy(clipMap->info.uinds, &uindVec[0], sizeof(uint16_t) * totalUindCount);
|
||||||
|
}
|
||||||
|
|
||||||
void createClipMap(customMapInfo* projInfo)
|
void createClipMap(customMapInfo* projInfo)
|
||||||
{
|
{
|
||||||
clipMap_t* clipMap = new clipMap_t;
|
clipMap_t* clipMap = new clipMap_t;
|
||||||
@@ -1148,12 +1311,21 @@ private:
|
|||||||
clipMap->box_model.maxs.z = 0.0f;
|
clipMap->box_model.maxs.z = 0.0f;
|
||||||
clipMap->box_model.radius = 0.0f;
|
clipMap->box_model.radius = 0.0f;
|
||||||
clipMap->box_model.info = NULL;
|
clipMap->box_model.info = NULL;
|
||||||
clipMap->box_model.leaf.mins.x = 3.4028235e38;
|
|
||||||
clipMap->box_model.leaf.mins.y = 3.4028235e38;
|
// for some reason the maxs are negative, and mins are positive
|
||||||
clipMap->box_model.leaf.mins.z = 3.4028235e38;
|
// float box_mins = 3.4028235e38;
|
||||||
clipMap->box_model.leaf.maxs.x = -3.4028235e38; // for some reason the maxs are negative, and mins are positive
|
// float box_maxs = -3.4028235e38;
|
||||||
clipMap->box_model.leaf.maxs.y = -3.4028235e38;
|
// hack: the floats above can't be converted to 32 bit floats, and the game requires them to be exact
|
||||||
clipMap->box_model.leaf.maxs.z = -3.4028235e38;
|
// so we use the hex representation and set it using int pointers
|
||||||
|
unsigned int box_mins = 0x7F7FFFFF;
|
||||||
|
unsigned int box_maxs = 0xFF7FFFFF;
|
||||||
|
*((unsigned int*)&clipMap->box_model.leaf.mins.x) = box_mins;
|
||||||
|
*((unsigned int*)&clipMap->box_model.leaf.mins.y) = box_mins;
|
||||||
|
*((unsigned int*)&clipMap->box_model.leaf.mins.z) = box_mins;
|
||||||
|
*((unsigned int*)&clipMap->box_model.leaf.maxs.x) = box_maxs;
|
||||||
|
*((unsigned int*)&clipMap->box_model.leaf.maxs.y) = box_maxs;
|
||||||
|
*((unsigned int*)&clipMap->box_model.leaf.maxs.z) = box_maxs;
|
||||||
|
|
||||||
clipMap->box_model.leaf.brushContents = -1;
|
clipMap->box_model.leaf.brushContents = -1;
|
||||||
clipMap->box_model.leaf.terrainContents = 0;
|
clipMap->box_model.leaf.terrainContents = 0;
|
||||||
clipMap->box_model.leaf.cluster = 0;
|
clipMap->box_model.leaf.cluster = 0;
|
||||||
@@ -1250,6 +1422,11 @@ private:
|
|||||||
currDef->physConstraints[3] = 0x1FF;
|
currDef->physConstraints[3] = 0x1FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cmodels is the collision for mapents
|
||||||
|
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(projInfo->bspName);
|
||||||
|
_ASSERT(gfxWorldAsset != NULL);
|
||||||
|
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
|
||||||
|
_ASSERT(gfxWorld->modelCount == 1);
|
||||||
clipMap->numSubModels = 1;
|
clipMap->numSubModels = 1;
|
||||||
clipMap->cmodels = new cmodel_t[clipMap->numSubModels];
|
clipMap->cmodels = new cmodel_t[clipMap->numSubModels];
|
||||||
clipMap->cmodels[0].leaf.firstCollAabbIndex = 0;
|
clipMap->cmodels[0].leaf.firstCollAabbIndex = 0;
|
||||||
@@ -1265,166 +1442,38 @@ private:
|
|||||||
clipMap->cmodels[0].leaf.leafBrushNode = 0;
|
clipMap->cmodels[0].leaf.leafBrushNode = 0;
|
||||||
clipMap->cmodels[0].leaf.cluster = 0;
|
clipMap->cmodels[0].leaf.cluster = 0;
|
||||||
clipMap->cmodels[0].info = NULL;
|
clipMap->cmodels[0].info = NULL;
|
||||||
|
|
||||||
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(projInfo->bspName);
|
|
||||||
_ASSERT(gfxWorldAsset != NULL);
|
|
||||||
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
|
|
||||||
|
|
||||||
clipMap->cmodels[0].mins.x = gfxWorld->models[0].bounds[0].x;
|
clipMap->cmodels[0].mins.x = gfxWorld->models[0].bounds[0].x;
|
||||||
clipMap->cmodels[0].mins.y = gfxWorld->models[0].bounds[0].y;
|
clipMap->cmodels[0].mins.y = gfxWorld->models[0].bounds[0].y;
|
||||||
clipMap->cmodels[0].mins.z = gfxWorld->models[0].bounds[0].z;
|
clipMap->cmodels[0].mins.z = gfxWorld->models[0].bounds[0].z;
|
||||||
clipMap->cmodels[0].maxs.x = gfxWorld->models[0].bounds[1].x;
|
clipMap->cmodels[0].maxs.x = gfxWorld->models[0].bounds[1].x;
|
||||||
clipMap->cmodels[0].maxs.y = gfxWorld->models[0].bounds[1].y;
|
clipMap->cmodels[0].maxs.y = gfxWorld->models[0].bounds[1].y;
|
||||||
clipMap->cmodels[0].maxs.z = gfxWorld->models[0].bounds[1].z;
|
clipMap->cmodels[0].maxs.z = gfxWorld->models[0].bounds[1].z;
|
||||||
clipMap->cmodels[0].radius = distBetweenPoints(clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs) / 2;
|
clipMap->cmodels[0].radius = CMUtil::distBetweenPoints(clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs) / 2;
|
||||||
|
|
||||||
clipMap->numStaticModels = 0;
|
|
||||||
clipMap->staticModelList = NULL;
|
addXModelsToCollision(projInfo, clipMap);
|
||||||
|
|
||||||
clipMap->info.numMaterials = 1;
|
clipMap->info.numMaterials = 1;
|
||||||
clipMap->info.materials = new ClipMaterial[clipMap->info.numMaterials];
|
clipMap->info.materials = new ClipMaterial[clipMap->info.numMaterials];
|
||||||
clipMap->info.materials[0].name = _strdup(defaultMaterialName.c_str());
|
clipMap->info.materials[0].name = _strdup(missingMaterialName.c_str());
|
||||||
clipMap->info.materials[0].contentFlags = MATERIAL_CONTENT_FLAGS;
|
clipMap->info.materials[0].contentFlags = MATERIAL_CONTENT_FLAGS;
|
||||||
clipMap->info.materials[0].surfaceFlags = MATERIAL_SURFACE_FLAGS;
|
clipMap->info.materials[0].surfaceFlags = MATERIAL_SURFACE_FLAGS;
|
||||||
|
|
||||||
int collisionVertexCount = projInfo->gfxInfo.vertexCount;
|
|
||||||
vec3_t* convertedCollisionVerts = new vec3_t[collisionVertexCount];
|
|
||||||
for (int i = 0; i < collisionVertexCount; i++)
|
|
||||||
{
|
|
||||||
convertedCollisionVerts[i] = CMUtil::convertToBO2Coords(projInfo->gfxInfo.vertices[i].pos);
|
|
||||||
}
|
|
||||||
clipMap->vertCount = collisionVertexCount;
|
|
||||||
clipMap->verts = convertedCollisionVerts;
|
|
||||||
|
|
||||||
// due to tris using uint16_t as the type for indexing the vert array,
|
|
||||||
// any vertex count over the uint16_t max means the vertices above it can't be indexed
|
|
||||||
const int maxVerts = UINT16_MAX - 1;
|
|
||||||
if (collisionVertexCount > maxVerts)
|
|
||||||
{
|
|
||||||
printf("ERROR: collision vertex count %i exceeds the maximum number: %i!\n", collisionVertexCount, maxVerts);
|
|
||||||
hasLinkFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
clipMap->triCount = projInfo->gfxInfo.indexCount / 3;
|
|
||||||
clipMap->triIndices = (uint16_t(*)[3])(new uint16_t[projInfo->gfxInfo.indexCount]); // 3 indexes per tri
|
|
||||||
int triIndex = 0;
|
|
||||||
for (int i = 0; i < projInfo->gfxInfo.indexCount; i += 3)
|
|
||||||
{
|
|
||||||
clipMap->triIndices[triIndex][2] = projInfo->gfxInfo.indices[i + 0];
|
|
||||||
clipMap->triIndices[triIndex][1] = projInfo->gfxInfo.indices[i + 1];
|
|
||||||
clipMap->triIndices[triIndex][0] = projInfo->gfxInfo.indices[i + 2];
|
|
||||||
triIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int partitionCount = 0;
|
|
||||||
for (int i = 0; i < projInfo->gfxInfo.surfaceCount; i++)
|
|
||||||
{
|
|
||||||
int triCount = projInfo->gfxInfo.surfaces[i].triCount;
|
|
||||||
int subdividedSize = triCount / 16; // integer division used
|
|
||||||
partitionCount += subdividedSize;
|
|
||||||
|
|
||||||
// add another partition if the triangle count doesn't add up to a multiple of 16
|
|
||||||
if (triCount % 16 != 0)
|
|
||||||
partitionCount++;
|
|
||||||
}
|
|
||||||
clipMap->partitionCount = partitionCount;
|
|
||||||
clipMap->partitions = new CollisionPartition[clipMap->partitionCount];
|
|
||||||
|
|
||||||
int partitionIndex = 0;
|
|
||||||
for (int i = 0; i < projInfo->gfxInfo.surfaceCount; i++)
|
|
||||||
{
|
|
||||||
int triCount = projInfo->gfxInfo.surfaces[i].triCount;
|
|
||||||
int firstIndex = projInfo->gfxInfo.surfaces[i].firstIndex_Index;
|
|
||||||
int firstVertex = projInfo->gfxInfo.surfaces[i].firstVertexIndex;
|
|
||||||
int firstTri = firstIndex / 3;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// TODO: fixup tri indices does not fully work correctly, and leaves some gaps or removes faces.
|
|
||||||
// NEED TO FIX
|
|
||||||
// fixup the tri indices.
|
|
||||||
// GfxWorld calculates what vertex to render through vertexBuffer[indexBuffer[index] + firstVertex]
|
|
||||||
// while clipmap caclulates it through vertexBuffer[indexBuffer[index]]
|
|
||||||
// this loop fixes the index buffer by adding the firstVertex to each index
|
|
||||||
for (int k = 0; k < triCount; k++)
|
|
||||||
{
|
|
||||||
clipMap->triIndices[k + firstTri][0] += firstVertex;
|
|
||||||
clipMap->triIndices[k + firstTri][1] += firstVertex;
|
|
||||||
clipMap->triIndices[k + firstTri][2] += firstVertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (triCount > 0)
|
|
||||||
{
|
|
||||||
if (triCount > 16)
|
|
||||||
clipMap->partitions[partitionIndex].triCount = 16;
|
|
||||||
else
|
|
||||||
clipMap->partitions[partitionIndex].triCount = triCount;
|
|
||||||
|
|
||||||
clipMap->partitions[partitionIndex].firstTri = firstTri;
|
|
||||||
|
|
||||||
triCount -= 16;
|
|
||||||
firstIndex += 16 * 3;
|
|
||||||
partitionIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int uindCount = 0;
|
|
||||||
clipMap->info.uinds = new uint16_t[3 * 16 * clipMap->partitionCount]; // 3 vertexes per tri, and max 16 tris per partition
|
|
||||||
for (int i = 0; i < clipMap->partitionCount; i++)
|
|
||||||
{
|
|
||||||
auto currPartition = &clipMap->partitions[i];
|
|
||||||
|
|
||||||
int uniqueVertBufferCount = 0;
|
|
||||||
uint16_t uniqueVertBuffer[3 * 16]; // 3 vertexes per tri, and max 16 tris
|
|
||||||
|
|
||||||
for (int k = 0; k < currPartition->triCount; k++)
|
|
||||||
{
|
|
||||||
uint16_t* tri = clipMap->triIndices[currPartition->firstTri + k];
|
|
||||||
for (int l = 0; l < 3; l++)
|
|
||||||
{
|
|
||||||
bool isVertexIndexUnique = true;
|
|
||||||
uint16_t vertIndex = tri[l];
|
|
||||||
|
|
||||||
for (int m = 0; m < uniqueVertBufferCount; m++)
|
|
||||||
{
|
|
||||||
if (uniqueVertBuffer[m] == vertIndex)
|
|
||||||
{
|
|
||||||
isVertexIndexUnique = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVertexIndexUnique)
|
|
||||||
{
|
|
||||||
uniqueVertBuffer[uniqueVertBufferCount] = vertIndex;
|
|
||||||
uniqueVertBufferCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ASSERT(uniqueVertBufferCount <= 3 * 16);
|
|
||||||
|
|
||||||
currPartition->fuind = uindCount;
|
|
||||||
currPartition->nuinds = uniqueVertBufferCount;
|
|
||||||
memcpy(&clipMap->info.uinds[uindCount], uniqueVertBuffer, uniqueVertBufferCount * sizeof(uint16_t));
|
|
||||||
uindCount += uniqueVertBufferCount;
|
|
||||||
}
|
|
||||||
_ASSERT(uindCount < 3 * 16 * clipMap->partitionCount);
|
|
||||||
clipMap->info.nuinds = uindCount;
|
|
||||||
|
|
||||||
// set all edges to walkable (all walkable edge bits are set to 1, see isEdgeWalkable) until changing it is a possiblility
|
// set all edges to walkable (all walkable edge bits are set to 1, see isEdgeWalkable) until changing it is a possiblility
|
||||||
// might do weird stuff on walls
|
// might do weird stuff on walls, but from testing doesnt seem to do much
|
||||||
int walkableEdgeSize = (3 * clipMap->triCount + 31) / 32 * 4;
|
int walkableEdgeSize = (3 * clipMap->triCount + 31) / 32 * 4;
|
||||||
clipMap->triEdgeIsWalkable = new char[walkableEdgeSize];
|
clipMap->triEdgeIsWalkable = new char[walkableEdgeSize];
|
||||||
memset(clipMap->triEdgeIsWalkable, 0xFF, walkableEdgeSize * sizeof(char));
|
memset(clipMap->triEdgeIsWalkable, 1, walkableEdgeSize * sizeof(char));
|
||||||
|
|
||||||
// BSP creation must go last as it depends on unids, tris and verts already being populated
|
// clipmap BSP creation must go last as it depends on unids, tris and verts already being populated
|
||||||
// HACK:
|
// HACK:
|
||||||
// the BSP tree creation does not work when BO2's coordinate system is used for mins and maxs.
|
// the BSP tree creation does not work when BO2's coordinate system is used for mins and maxs.
|
||||||
// Workaround is to convert every BO2 coordinate to OGL's before it is added into the BSP tree,
|
// Workaround is to convert every BO2 coordinate to OGL's before it is added into the BSP tree,
|
||||||
// and then convert them back when it is being parsed into the clipmap. Requires some hacky
|
// and then convert them back when it is being parsed into the clipmap. Requires some hacky
|
||||||
// logic, check populateBSPTree_r and addAABBTreeFromLeaf
|
// logic, check populateBSPTree_r and addAABBTreeFromLeaf
|
||||||
|
|
||||||
|
createPartitions(projInfo, clipMap);
|
||||||
|
|
||||||
vec3_t* firstVert = &clipMap->verts[0];
|
vec3_t* firstVert = &clipMap->verts[0];
|
||||||
vec3_t clipMins;
|
vec3_t clipMins;
|
||||||
vec3_t clipMaxs;
|
vec3_t clipMaxs;
|
||||||
@@ -1436,13 +1485,16 @@ private:
|
|||||||
clipMaxs.z = firstVert->z;
|
clipMaxs.z = firstVert->z;
|
||||||
clipMins = CMUtil::convertFromBO2Coords(clipMins);
|
clipMins = CMUtil::convertFromBO2Coords(clipMins);
|
||||||
clipMaxs = CMUtil::convertFromBO2Coords(clipMaxs);
|
clipMaxs = CMUtil::convertFromBO2Coords(clipMaxs);
|
||||||
for (int i = 1; i < clipMap->vertCount; i++)
|
for (unsigned int i = 1; i < clipMap->vertCount; i++)
|
||||||
{
|
{
|
||||||
vec3_t vertCoord = CMUtil::convertFromBO2Coords(clipMap->verts[i]);
|
vec3_t vertCoord = CMUtil::convertFromBO2Coords(clipMap->verts[i]);
|
||||||
CMUtil::calcNewBoundsWithPoint(&vertCoord, &clipMins, &clipMaxs);
|
CMUtil::calcNewBoundsWithPoint(&vertCoord, &clipMins, &clipMaxs);
|
||||||
}
|
}
|
||||||
|
|
||||||
BSPTree* tree = new BSPTree(clipMins.x, clipMins.y, clipMins.z, clipMaxs.x, clipMaxs.y, clipMaxs.z, 0);
|
BSPTree* tree = new BSPTree(clipMins.x, clipMins.y, clipMins.z, clipMaxs.x, clipMaxs.y, clipMaxs.z, 0);
|
||||||
|
|
||||||
|
_ASSERT(!tree->isLeaf);
|
||||||
|
|
||||||
for (int i = 0; i < clipMap->partitionCount; i++)
|
for (int i = 0; i < clipMap->partitionCount; i++)
|
||||||
{
|
{
|
||||||
auto currPartition = &clipMap->partitions[i];
|
auto currPartition = &clipMap->partitions[i];
|
||||||
@@ -1489,20 +1541,20 @@ private:
|
|||||||
comWorld->primaryLightCount = 2;
|
comWorld->primaryLightCount = 2;
|
||||||
comWorld->primaryLights = new ComPrimaryLight[comWorld->primaryLightCount];
|
comWorld->primaryLights = new ComPrimaryLight[comWorld->primaryLightCount];
|
||||||
|
|
||||||
|
// default light is always empty
|
||||||
ComPrimaryLight* defaultLight = &comWorld->primaryLights[0];
|
ComPrimaryLight* defaultLight = &comWorld->primaryLights[0];
|
||||||
memset(defaultLight, 0, sizeof(ComPrimaryLight));
|
memset(defaultLight, 0, sizeof(ComPrimaryLight));
|
||||||
|
|
||||||
ComPrimaryLight* sunLight = &comWorld->primaryLights[1];
|
ComPrimaryLight* sunLight = &comWorld->primaryLights[1];
|
||||||
memset(sunLight, 0, sizeof(ComPrimaryLight));
|
memset(sunLight, 0, sizeof(ComPrimaryLight));
|
||||||
sunLight->type = 1;
|
sunLight->type = 1;
|
||||||
// Below are default values taken from mp_dig
|
sunLight->diffuseColor.r = 0.75f;
|
||||||
sunLight->diffuseColor.r = 1.0f;
|
sunLight->diffuseColor.g = 0.75f;
|
||||||
sunLight->diffuseColor.g = 1.0f;
|
sunLight->diffuseColor.b = 0.75f;
|
||||||
sunLight->diffuseColor.b = 1.0f;
|
sunLight->diffuseColor.a = 1.0f;
|
||||||
sunLight->diffuseColor.a = 0.0f;
|
sunLight->dir.x = 0.0f;
|
||||||
sunLight->dir.x = -0.2410777360200882;
|
sunLight->dir.y = 0.0f;
|
||||||
sunLight->dir.y = -0.8407384753227234;
|
sunLight->dir.z = 0.0f;
|
||||||
sunLight->dir.z = 0.48480960726737976;
|
|
||||||
|
|
||||||
m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld);
|
m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld);
|
||||||
}
|
}
|
||||||
@@ -1616,42 +1668,42 @@ private:
|
|||||||
|
|
||||||
void checkAndAddDefaultRequiredAssets(customMapInfo* projectInfo)
|
void checkAndAddDefaultRequiredAssets(customMapInfo* projectInfo)
|
||||||
{
|
{
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/mp_dig.gsc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/mod.gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/mp_dig_amb.gsc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/mod_amb.gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/mp_dig_fx.gsc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/mod_fx.gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/createfx/mp_dig_fx.gsc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/createfx/mod_fx.gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mp_dig.csc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mod.csc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mp_dig_amb.csc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mod_amb.csc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mp_dig_fx.csc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mod_fx.csc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/createfx/mp_dig_fx.csc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/createfx/mod_fx.csc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -22,21 +22,32 @@ namespace
|
|||||||
|
|
||||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||||
{
|
{
|
||||||
auto mapFile = m_search_path.Open("custom_map/map.obj");
|
auto mapGfxFile = m_search_path.Open("custom_map/map_gfx.fbx");
|
||||||
if (!mapFile.IsOpen())
|
if (!mapGfxFile.IsOpen())
|
||||||
return AssetCreationResult::NoAction();
|
return AssetCreationResult::NoAction();
|
||||||
|
|
||||||
|
printf("Loading map data...\n");
|
||||||
|
|
||||||
// create map info from the obj file
|
// create map info from the obj file
|
||||||
customMapInfo* mapInfo = CustomMapInfo::createCustomMapInfo(m_zone.m_name, m_search_path);
|
customMapInfo* mapInfo = CustomMapInfo::createCustomMapInfo(m_zone.m_name, m_search_path);
|
||||||
if (mapInfo == NULL)
|
if (mapInfo == NULL)
|
||||||
return AssetCreationResult::Failure();
|
return AssetCreationResult::Failure();
|
||||||
|
|
||||||
|
printf("Creating map from data...\n");
|
||||||
|
|
||||||
// linker will add all the assets needed
|
// linker will add all the assets needed
|
||||||
CustomMapLinker* linker = new CustomMapLinker(m_memory, m_search_path, m_zone, context);
|
CustomMapLinker* linker = new CustomMapLinker(m_memory, m_search_path, m_zone, context);
|
||||||
bool result = linker->linkCustomMap(mapInfo);
|
bool result = linker->linkCustomMap(mapInfo);
|
||||||
|
|
||||||
|
//auto gfxWorldAsset = context.LoadDependency<AssetFootstepTable>("default_1st_person");
|
||||||
|
//return AssetCreationResult::Success(gfxWorldAsset);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
return AssetCreationResult::NoAction();
|
{
|
||||||
|
auto gfxWorldAsset = context.LoadDependency<AssetGfxWorld>(mapInfo->bspName);
|
||||||
|
_ASSERT(gfxWorldAsset != NULL);
|
||||||
|
return AssetCreationResult::Success(gfxWorldAsset);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return AssetCreationResult::Failure();
|
return AssetCreationResult::Failure();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// OBJ_Loader.h - A Single Header OBJ Model Loader
|
// OBJ_Loader.h - A Single Header OBJ Model Loader
|
||||||
|
// modified to work better with OpenAssetTools
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@@ -17,6 +18,8 @@
|
|||||||
// Math.h - STD math Library
|
// Math.h - STD math Library
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
// Print progress to console while loading (large models)
|
// Print progress to console while loading (large models)
|
||||||
// #define OBJL_CONSOLE_OUTPUT
|
// #define OBJL_CONSOLE_OUTPUT
|
||||||
|
|
||||||
@@ -432,15 +435,11 @@ namespace objl
|
|||||||
//
|
//
|
||||||
// If the file is unable to be found
|
// If the file is unable to be found
|
||||||
// or unable to be loaded return false
|
// or unable to be loaded return false
|
||||||
bool LoadFile(std::string Path)
|
bool LoadFile(ISearchPath& searchPath, std::string fileName)
|
||||||
{
|
{
|
||||||
// If the file is not an .obj file return false
|
auto file = searchPath.Open(fileName);
|
||||||
if (Path.substr(Path.size() - 4, 4) != ".obj")
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::ifstream file(Path);
|
if (!file.IsOpen())
|
||||||
|
|
||||||
if (!file.is_open())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LoadedMeshes.clear();
|
LoadedMeshes.clear();
|
||||||
@@ -467,7 +466,7 @@ namespace objl
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string curline;
|
std::string curline;
|
||||||
while (std::getline(file, curline))
|
while (std::getline(*file.m_stream, curline))
|
||||||
{
|
{
|
||||||
#ifdef OBJL_CONSOLE_OUTPUT
|
#ifdef OBJL_CONSOLE_OUTPUT
|
||||||
if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1)
|
if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1)
|
||||||
@@ -642,13 +641,13 @@ namespace objl
|
|||||||
|
|
||||||
// Generate a path to the material file
|
// Generate a path to the material file
|
||||||
std::vector<std::string> temp;
|
std::vector<std::string> temp;
|
||||||
algorithm::split(Path, temp, "\\"); // update: use windows file seperators
|
algorithm::split(fileName, temp, "/"); // update: use windows file seperators
|
||||||
|
|
||||||
std::string pathtomat = "";
|
std::string pathtomat = "";
|
||||||
|
|
||||||
if (temp.size() != 1)
|
if (temp.size() != 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < temp.size() - 1; i++)
|
for (size_t i = 0; i < temp.size() - 1; i++)
|
||||||
{
|
{
|
||||||
pathtomat += temp[i] + "/";
|
pathtomat += temp[i] + "/";
|
||||||
}
|
}
|
||||||
@@ -661,7 +660,7 @@ namespace objl
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Load Materials
|
// Load Materials
|
||||||
LoadMaterials(pathtomat);
|
LoadMaterials(searchPath, pathtomat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,16 +680,14 @@ namespace objl
|
|||||||
LoadedMeshes.push_back(tempMesh);
|
LoadedMeshes.push_back(tempMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
// Set Materials for each Mesh
|
// Set Materials for each Mesh
|
||||||
for (int i = 0; i < MeshMatNames.size(); i++)
|
for (size_t i = 0; i < MeshMatNames.size(); i++)
|
||||||
{
|
{
|
||||||
std::string matname = MeshMatNames[i];
|
std::string matname = MeshMatNames[i];
|
||||||
|
|
||||||
// Find corresponding material name in loaded materials
|
// Find corresponding material name in loaded materials
|
||||||
// when found copy material variables into mesh material
|
// when found copy material variables into mesh material
|
||||||
for (int j = 0; j < LoadedMaterials.size(); j++)
|
for (size_t j = 0; j < LoadedMaterials.size(); j++)
|
||||||
{
|
{
|
||||||
if (LoadedMaterials[j].name == matname)
|
if (LoadedMaterials[j].name == matname)
|
||||||
{
|
{
|
||||||
@@ -941,7 +938,7 @@ namespace objl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If Vertex is not an interior vertex
|
// If Vertex is not an interior vertex
|
||||||
float angle = math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (180 / 3.14159265359);
|
float angle = math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (float)(180 / 3.14159265359);
|
||||||
if (angle <= 0 && angle >= 180)
|
if (angle <= 0 && angle >= 180)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -996,16 +993,12 @@ namespace objl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load Materials from .mtl file
|
// Load Materials from .mtl file
|
||||||
bool LoadMaterials(std::string path)
|
bool LoadMaterials(ISearchPath& searchPath, std::string fileName)
|
||||||
{
|
{
|
||||||
// If the file is not a material file return false
|
auto file = searchPath.Open(fileName);
|
||||||
if (path.substr(path.size() - 4, path.size()) != ".mtl")
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::ifstream file(path);
|
|
||||||
|
|
||||||
// If the file is not found return false
|
// If the file is not found return false
|
||||||
if (!file.is_open())
|
if (!file.IsOpen())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Material tempMaterial;
|
Material tempMaterial;
|
||||||
@@ -1014,7 +1007,7 @@ namespace objl
|
|||||||
|
|
||||||
// Go through each line looking for material variables
|
// Go through each line looking for material variables
|
||||||
std::string curline;
|
std::string curline;
|
||||||
while (std::getline(file, curline))
|
while (std::getline(*file.m_stream, curline))
|
||||||
{
|
{
|
||||||
// new material and material name
|
// new material and material name
|
||||||
if (algorithm::firstToken(curline) == "newmtl")
|
if (algorithm::firstToken(curline) == "newmtl")
|
||||||
|
|||||||
@@ -1,105 +1,413 @@
|
|||||||
#include "ProjectCreator.h"
|
#include "ProjectCreator.h"
|
||||||
|
|
||||||
#include "OBJ_Loader.h"
|
#include "fbx/ufbx.h"
|
||||||
|
|
||||||
void parseMesh(objl::Mesh* OBJMesh, worldSurface* meshSurface, customMapInfo* projInfo)
|
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)
|
||||||
{
|
{
|
||||||
int meshVertexCount = OBJMesh->Vertices.size();
|
if (node->attrib_type != UFBX_ELEMENT_MESH)
|
||||||
int meshIndexCount = OBJMesh->Indices.size();
|
|
||||||
int surfVertexStart = projInfo->gfxInfo.vertexCount;
|
|
||||||
int surfIndexStart = projInfo->gfxInfo.indexCount;
|
|
||||||
|
|
||||||
projInfo->gfxInfo.vertexCount += meshVertexCount;
|
|
||||||
projInfo->gfxInfo.indexCount += meshIndexCount;
|
|
||||||
|
|
||||||
projInfo->gfxInfo.vertices = (customMapVertex*)realloc(projInfo->gfxInfo.vertices, sizeof(customMapVertex) * projInfo->gfxInfo.vertexCount);
|
|
||||||
projInfo->gfxInfo.indices = (uint16_t*)realloc(projInfo->gfxInfo.indices, sizeof(uint16_t) * projInfo->gfxInfo.indexCount);
|
|
||||||
|
|
||||||
customMapVertex* surfVertices = &projInfo->gfxInfo.vertices[surfVertexStart];
|
|
||||||
uint16_t* surfIndices = &projInfo->gfxInfo.indices[surfIndexStart];
|
|
||||||
|
|
||||||
meshSurface->firstIndex_Index = surfIndexStart;
|
|
||||||
meshSurface->firstVertexIndex = surfVertexStart;
|
|
||||||
meshSurface->triCount = meshIndexCount / 3;
|
|
||||||
_ASSERT(meshIndexCount % 3 == 0);
|
|
||||||
|
|
||||||
for (int i = 0; i < meshIndexCount; i++)
|
|
||||||
{
|
{
|
||||||
_ASSERT(OBJMesh->Indices[i] < UINT16_MAX);
|
printf("ignoring non-mesh node \"%s\"\n", node->name.data);
|
||||||
surfIndices[i] = OBJMesh->Indices[i];
|
return false;
|
||||||
|
}
|
||||||
|
ufbx_mesh* mesh = node->mesh;
|
||||||
|
|
||||||
|
if (mesh->instances.count != 1)
|
||||||
|
printf("node %s has %i instances, only the 1st instace will be used.\n", node->name.data, mesh->instances.count);
|
||||||
|
|
||||||
|
if (mesh->num_triangles == 0)
|
||||||
|
{
|
||||||
|
printf("ignoring mesh %s: triangle count is 0.\n", node->name.data);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < meshVertexCount; i++)
|
if (mesh->num_indices % 3 != 0)
|
||||||
{
|
{
|
||||||
objl::Vertex* meshVertex = &OBJMesh->Vertices[i];
|
printf("ignoring mesh %s: it is not triangulated.\n", node->name.data);
|
||||||
customMapVertex* surfVertex = &surfVertices[i];
|
return false;
|
||||||
|
|
||||||
surfVertex->pos.x = meshVertex->Position.X;
|
|
||||||
surfVertex->pos.y = meshVertex->Position.Y;
|
|
||||||
surfVertex->pos.z = meshVertex->Position.Z;
|
|
||||||
|
|
||||||
surfVertex->color[0] = OBJMesh->MeshMaterial.Kd.X;
|
|
||||||
surfVertex->color[1] = OBJMesh->MeshMaterial.Kd.Y;
|
|
||||||
surfVertex->color[2] = OBJMesh->MeshMaterial.Kd.Z;
|
|
||||||
surfVertex->color[3] = 1.0f;
|
|
||||||
|
|
||||||
surfVertex->texCoord[0] = meshVertex->TextureCoordinate.X;
|
|
||||||
surfVertex->texCoord[1] = meshVertex->TextureCoordinate.Y;
|
|
||||||
|
|
||||||
surfVertex->normal.x = meshVertex->Normal.X;
|
|
||||||
surfVertex->normal.y = meshVertex->Normal.Y;
|
|
||||||
surfVertex->normal.z = meshVertex->Normal.Z;
|
|
||||||
|
|
||||||
// TODO: fix tangents, seems to work for now though
|
|
||||||
surfVertex->tangent.x = 1.0f;
|
|
||||||
surfVertex->tangent.y = 0.0f;
|
|
||||||
surfVertex->tangent.z = 0.0f;
|
|
||||||
|
|
||||||
surfVertex->packedLmapCoord = 0;
|
|
||||||
|
|
||||||
surfVertex->binormalSign = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t k = 0; k < mesh->num_indices; k++)
|
||||||
|
{
|
||||||
|
if (mesh->vertex_indices[k] > UINT16_MAX)
|
||||||
|
{
|
||||||
|
printf("ignoring mesh %s, it has more than %i indices.\n", node->name.data, UINT16_MAX);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ASSERT(mesh->vertex_position.unique_per_vertex == true);
|
||||||
|
_ASSERT(mesh->vertex_color.unique_per_vertex == false);
|
||||||
|
_ASSERT(mesh->vertex_uv.unique_per_vertex == false);
|
||||||
|
_ASSERT(mesh->vertex_normal.unique_per_vertex == false);
|
||||||
|
_ASSERT(mesh->vertex_tangent.unique_per_vertex == false);
|
||||||
|
|
||||||
|
if (mesh->vertex_tangent.exists == false)
|
||||||
|
hasTangentSpace = false;
|
||||||
|
|
||||||
|
// UFBX stores the transform data in units that are 100x larger than what blender uses, so this converts them back
|
||||||
|
ufbx_transform origTransform = node->local_transform;
|
||||||
|
origTransform.translation.x /= 100.0f;
|
||||||
|
origTransform.translation.y /= 100.0f;
|
||||||
|
origTransform.translation.z /= 100.0f;
|
||||||
|
origTransform.scale.x /= 100.0f;
|
||||||
|
origTransform.scale.y /= 100.0f;
|
||||||
|
origTransform.scale.z /= 100.0f;
|
||||||
|
ufbx_matrix meshMatrix = ufbx_transform_to_matrix(&origTransform);
|
||||||
|
|
||||||
|
CM_MATERIAL_TYPE meshMaterialType;
|
||||||
|
if (mesh->materials.count == 0)
|
||||||
|
{
|
||||||
|
if (!mesh->vertex_color.exists)
|
||||||
|
{
|
||||||
|
printf("mesh with no colour/texture data: %s\n", node->name.data);
|
||||||
|
meshMaterialType = NO_COLOUR_OR_TEXTURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("colour only mesh %s\n", node->name.data);
|
||||||
|
meshMaterialType = CM_MATERIAL_COLOUR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meshMaterialType = CM_MATERIAL_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FBX loading code modified from https://ufbx.github.io/elements/meshes/
|
||||||
|
// Seems like I have to use this exact way of loading, otherwise some values become incorrect
|
||||||
|
for (int i = 0; i < mesh->material_parts.count; i++)
|
||||||
|
{
|
||||||
|
ufbx_mesh_part* meshPart = &mesh->material_parts.data[i];
|
||||||
|
|
||||||
|
if (meshPart->num_faces == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
worldSurface surface;
|
||||||
|
surface.flags = 0;
|
||||||
|
surface.triCount = meshPart->num_triangles;
|
||||||
|
surface.firstVertexIndex = vertexVec.size();
|
||||||
|
surface.firstIndex_Index = indexVec.size();
|
||||||
|
|
||||||
|
surface.material.materialType = meshMaterialType;
|
||||||
|
switch (meshMaterialType)
|
||||||
|
{
|
||||||
|
case CM_MATERIAL_TEXTURE:
|
||||||
|
surface.material.materialName = _strdup(mesh->materials.data[i]->name.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CM_MATERIAL_COLOUR:
|
||||||
|
case NO_COLOUR_OR_TEXTURE:
|
||||||
|
surface.material.materialName = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t num_triangles = meshPart->num_triangles;
|
||||||
|
customMapVertex* vertices = (customMapVertex*)calloc(num_triangles * 3, sizeof(customMapVertex));
|
||||||
|
size_t num_vertices = 0;
|
||||||
|
|
||||||
|
// Reserve space for the maximum triangle indices.
|
||||||
|
size_t num_tri_indices = mesh->max_face_triangles * 3;
|
||||||
|
uint32_t* tri_indices = (uint32_t*)calloc(num_tri_indices, sizeof(uint32_t));
|
||||||
|
|
||||||
|
_ASSERT(meshPart->num_triangles == meshPart->num_faces);
|
||||||
|
for (size_t face_ix = 0; face_ix < meshPart->num_faces; face_ix++)
|
||||||
|
{
|
||||||
|
ufbx_face face = mesh->faces.data[meshPart->face_indices.data[face_ix]];
|
||||||
|
|
||||||
|
// Triangulate the face into `tri_indices[]`.
|
||||||
|
uint32_t num_tris = ufbx_triangulate_face(tri_indices, num_tri_indices, mesh, face);
|
||||||
|
|
||||||
|
// Iterate over each triangle corner contiguously.
|
||||||
|
for (size_t q = 0; q < num_tris * 3; q++)
|
||||||
|
{
|
||||||
|
uint32_t index = tri_indices[q];
|
||||||
|
|
||||||
|
customMapVertex* vertex = &vertices[num_vertices++];
|
||||||
|
|
||||||
|
ufbx_vec3 transformedPos = ufbx_transform_position(&meshMatrix, ufbx_get_vertex_vec3(&mesh->vertex_position, index));
|
||||||
|
vertex->pos.x = transformedPos.x;
|
||||||
|
vertex->pos.y = transformedPos.y;
|
||||||
|
vertex->pos.z = transformedPos.z;
|
||||||
|
|
||||||
|
// textured and missing materials are set to white
|
||||||
|
switch (meshMaterialType)
|
||||||
|
{
|
||||||
|
case CM_MATERIAL_TEXTURE:
|
||||||
|
case NO_COLOUR_OR_TEXTURE:
|
||||||
|
vertex->color[0] = 1.0f;
|
||||||
|
vertex->color[1] = 1.0f;
|
||||||
|
vertex->color[2] = 1.0f;
|
||||||
|
vertex->color[3] = 1.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CM_MATERIAL_COLOUR:
|
||||||
|
vertex->color[0] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).x;
|
||||||
|
vertex->color[1] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).y;
|
||||||
|
vertex->color[2] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).z;
|
||||||
|
vertex->color[3] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).w;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 1.0f - uv.v:
|
||||||
|
// https://gamedev.stackexchange.com/questions/92886/fbx-uv-coordinates-is-strange
|
||||||
|
vertex->texCoord[0] = (float)(ufbx_get_vertex_vec2(&mesh->vertex_uv, index).x);
|
||||||
|
vertex->texCoord[1] = (float)(1.0f - ufbx_get_vertex_vec2(&mesh->vertex_uv, index).y);
|
||||||
|
|
||||||
|
vertex->normal.x = ufbx_get_vertex_vec3(&mesh->vertex_normal, index).x;
|
||||||
|
vertex->normal.y = ufbx_get_vertex_vec3(&mesh->vertex_normal, index).y;
|
||||||
|
vertex->normal.z = ufbx_get_vertex_vec3(&mesh->vertex_normal, index).z;
|
||||||
|
|
||||||
|
if (mesh->vertex_tangent.exists)
|
||||||
|
{
|
||||||
|
vertex->tangent.x = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).x;
|
||||||
|
vertex->tangent.y = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).y;
|
||||||
|
vertex->tangent.z = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vertex->tangent.x = 0.0f;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ASSERT(num_vertices == num_triangles * 3);
|
||||||
|
|
||||||
|
// Generate the index buffer.
|
||||||
|
ufbx_vertex_stream streams[1] = {
|
||||||
|
{vertices, num_vertices, sizeof(customMapVertex)},
|
||||||
|
};
|
||||||
|
size_t num_indices = num_triangles * 3;
|
||||||
|
uint32_t* indices = (uint32_t*)calloc(num_indices, sizeof(uint32_t));
|
||||||
|
|
||||||
|
// This call will deduplicate vertices, modifying the arrays passed in `streams[]`,
|
||||||
|
// indices are written in `indices[]` and the number of unique vertices is returned.
|
||||||
|
num_vertices = ufbx_generate_indices(streams, 1, indices, num_indices, NULL, NULL);
|
||||||
|
_ASSERT(num_vertices != 0);
|
||||||
|
|
||||||
|
vertexVec.insert(vertexVec.end(), &vertices[0], &vertices[num_vertices]);
|
||||||
|
|
||||||
|
size_t currIndexVecSize = indexVec.size();
|
||||||
|
indexVec.resize(indexVec.size() + num_indices);
|
||||||
|
for (size_t m = 0; m < num_indices; m++)
|
||||||
|
{
|
||||||
|
indexVec[currIndexVecSize + m] = (uint16_t)indices[m];
|
||||||
|
}
|
||||||
|
|
||||||
|
surfaceVec.push_back(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadFBXModel(ufbx_node* node)
|
||||||
|
{
|
||||||
|
customMapModel model;
|
||||||
|
|
||||||
|
model.name = node->name.data;
|
||||||
|
|
||||||
|
ufbx_transform origTransform = node->local_transform;
|
||||||
|
origTransform.translation.x /= 100.0f;
|
||||||
|
origTransform.translation.y /= 100.0f;
|
||||||
|
origTransform.translation.z /= 100.0f;
|
||||||
|
origTransform.scale.x /= 100.0f;
|
||||||
|
origTransform.scale.y /= 100.0f;
|
||||||
|
origTransform.scale.z /= 100.0f;
|
||||||
|
ufbx_matrix meshMatrix = ufbx_transform_to_matrix(&origTransform);
|
||||||
|
|
||||||
|
model.origin.x = node->local_transform.translation.x / 100.0f;
|
||||||
|
model.origin.y = node->local_transform.translation.y / 100.0f;
|
||||||
|
model.origin.z = node->local_transform.translation.z / 100.0f;
|
||||||
|
model.rotation.x = node->euler_rotation.x;
|
||||||
|
model.rotation.y = node->euler_rotation.y;
|
||||||
|
model.rotation.z = node->euler_rotation.z;
|
||||||
|
model.scale = node->local_transform.scale.x / 100.0f;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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->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* CustomMapInfo::createCustomMapInfo(std::string& projectName, ISearchPath& searchPath)
|
customMapInfo* CustomMapInfo::createCustomMapInfo(std::string& projectName, ISearchPath& searchPath)
|
||||||
{
|
{
|
||||||
std::string objFilePath = searchPath.GetPath() + "custom_map/world.obj";
|
ufbx_scene* gfxScene;
|
||||||
|
ufbx_scene* colScene;
|
||||||
|
|
||||||
objl::Loader OBJloader;
|
std::string gfxFbxPath = "custom_map/map_gfx.fbx";
|
||||||
bool isLoaded = OBJloader.LoadFile(objFilePath);
|
auto gfxFile = searchPath.Open(gfxFbxPath);
|
||||||
if (!isLoaded)
|
if (!gfxFile.IsOpen())
|
||||||
{
|
{
|
||||||
printf("OBJLoader: unable to load obj file %s\n", objFilePath.c_str());
|
printf("Failed to open map gfx fbx file: %s\n", gfxFbxPath.c_str());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* gfxMapData = new char[gfxFile.m_length];
|
||||||
|
gfxFile.m_stream->seekg(0);
|
||||||
|
gfxFile.m_stream->read(gfxMapData, gfxFile.m_length);
|
||||||
|
|
||||||
|
ufbx_error error;
|
||||||
|
ufbx_load_opts opts;
|
||||||
|
opts.target_axes = ufbx_axes_right_handed_y_up;
|
||||||
|
opts.generate_missing_normals = true;
|
||||||
|
opts.allow_missing_vertex_position = false;
|
||||||
|
gfxScene = ufbx_load_memory(gfxMapData, gfxFile.m_length, NULL, &error);
|
||||||
|
if (!gfxScene)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to load map gfx fbx file: %s\n", error.description.data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string colFbxPath = "custom_map/map_col.fbx";
|
||||||
|
auto colFile = searchPath.Open(colFbxPath);
|
||||||
|
if (!colFile.IsOpen())
|
||||||
|
{
|
||||||
|
printf("Failed to open map collison fbx file: %s. map gfx will be used for collision instead.\n", colFbxPath.c_str());
|
||||||
|
colScene = gfxScene;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char* colMapData = new char[colFile.m_length];
|
||||||
|
colFile.m_stream->seekg(0);
|
||||||
|
colFile.m_stream->read(colMapData, colFile.m_length);
|
||||||
|
|
||||||
|
ufbx_error error;
|
||||||
|
ufbx_load_opts opts;
|
||||||
|
opts.target_axes = ufbx_axes_right_handed_y_up;
|
||||||
|
opts.generate_missing_normals = true;
|
||||||
|
opts.allow_missing_vertex_position = false;
|
||||||
|
colScene = ufbx_load_memory(colMapData, colFile.m_length, NULL, &error);
|
||||||
|
if (!colScene)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to load map collision fbx file: %s\n", error.description.data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
customMapInfo* projInfo = new customMapInfo;
|
customMapInfo* projInfo = new customMapInfo;
|
||||||
|
|
||||||
projInfo->name = projectName;
|
projInfo->name = projectName;
|
||||||
projInfo->bspName = "maps/mp/" + projectName + ".d3dbsp";
|
projInfo->bspName = "maps/mp/" + projectName + ".d3dbsp";
|
||||||
|
|
||||||
projInfo->gfxInfo.surfaceCount = OBJloader.LoadedMeshes.size();
|
parseGFXData(gfxScene, projInfo);
|
||||||
projInfo->gfxInfo.surfaces = new worldSurface[projInfo->gfxInfo.surfaceCount];
|
parseCollisionData(colScene, projInfo);
|
||||||
|
|
||||||
projInfo->gfxInfo.vertexCount = 0;
|
ufbx_free_scene(gfxScene);
|
||||||
projInfo->gfxInfo.indexCount = 0;
|
if (gfxScene != colScene)
|
||||||
projInfo->gfxInfo.vertices = (customMapVertex*)malloc(1);
|
ufbx_free_scene(colScene);
|
||||||
projInfo->gfxInfo.indices = (uint16_t*)malloc(1);
|
|
||||||
|
|
||||||
for (int i = 0; i < projInfo->gfxInfo.surfaceCount; i++)
|
|
||||||
{
|
|
||||||
objl::Mesh* currMesh = &OBJloader.LoadedMeshes[i];
|
|
||||||
worldSurface* currSurface = &projInfo->gfxInfo.surfaces[i];
|
|
||||||
|
|
||||||
currSurface->materialName = currMesh->MeshMaterial.name;
|
|
||||||
currSurface->reflectionProbeIndex = 0;
|
|
||||||
currSurface->primaryLightIndex = 0;
|
|
||||||
currSurface->lightmapIndex = 0;
|
|
||||||
currSurface->flags = 0;
|
|
||||||
|
|
||||||
parseMesh(currMesh, currSurface, projInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return projInfo;
|
return projInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
99
src/ObjLoading/Game/T6/CustomMap/TriangleSort.h
Normal file
99
src/ObjLoading/Game/T6/CustomMap/TriangleSort.h
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <queue>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "Util.h"
|
||||||
|
#include "CustomMapConsts.h"
|
||||||
|
|
||||||
|
using TriangleGroup = std::vector<unsigned int>; // Group of triangle indices
|
||||||
|
using AdjacencyList = std::vector<TriangleGroup>; // Triangle-to-triangle connections
|
||||||
|
|
||||||
|
class TriangleSort
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static void computeTriCentroid(vec3_t& result, std::vector<vec3_t>& vertices, uint16_t i0, uint16_t i1, uint16_t i2)
|
||||||
|
{
|
||||||
|
result.x = 0.0f;
|
||||||
|
result.y = 0.0f;
|
||||||
|
result.z = 0.0f;
|
||||||
|
|
||||||
|
result.x += vertices[i0].x;
|
||||||
|
result.y += vertices[i0].y;
|
||||||
|
result.z += vertices[i0].z;
|
||||||
|
result.x += vertices[i1].x;
|
||||||
|
result.y += vertices[i1].y;
|
||||||
|
result.z += vertices[i1].z;
|
||||||
|
result.x += vertices[i2].x;
|
||||||
|
result.y += vertices[i2].y;
|
||||||
|
result.z += vertices[i2].z;
|
||||||
|
|
||||||
|
result.x /= 3.0f;
|
||||||
|
result.y /= 3.0f;
|
||||||
|
result.z /= 3.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AdjacencyList buildAdjacencyList(const std::vector<uint16_t>& indices, std::vector<vec3_t>& vertices, int maxTrianglesPerGroup)
|
||||||
|
{
|
||||||
|
size_t numTriangles = indices.size() / 3;
|
||||||
|
AdjacencyList adjList(numTriangles);
|
||||||
|
|
||||||
|
std::vector<vec3_t> centroids;
|
||||||
|
for (size_t i = 0; i < numTriangles; i++)
|
||||||
|
{
|
||||||
|
vec3_t center;
|
||||||
|
computeTriCentroid(center, vertices, indices[i * 3], indices[i * 3 + 1], indices[i * 3 + 2]);
|
||||||
|
centroids.push_back(center);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> visited(numTriangles, false);
|
||||||
|
for (size_t i = 0; i < numTriangles; ++i)
|
||||||
|
{
|
||||||
|
_ASSERT(i < MAX_COL_VERTS);
|
||||||
|
|
||||||
|
if (visited[i] == true)
|
||||||
|
continue;
|
||||||
|
visited[i] = true;
|
||||||
|
|
||||||
|
// Store distances to other triangles
|
||||||
|
std::vector<std::pair<float, unsigned int>> distances;
|
||||||
|
for (size_t j = 0; j < numTriangles; ++j)
|
||||||
|
{
|
||||||
|
if (visited[j] == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (i != j)
|
||||||
|
{
|
||||||
|
float dist = CMUtil::distBetweenPoints(centroids[i], centroids[j]);
|
||||||
|
distances.emplace_back(dist, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by distance and take the closest maxNeighbors
|
||||||
|
std::sort(distances.begin(), distances.end());
|
||||||
|
for (size_t k = 0; k < std::min((size_t)maxTrianglesPerGroup, distances.size()); ++k)
|
||||||
|
{
|
||||||
|
unsigned int neighbour = distances[k].second;
|
||||||
|
adjList[i].push_back(neighbour);
|
||||||
|
visited[neighbour] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < visited.size(); i++)
|
||||||
|
{
|
||||||
|
if (visited[i] == false)
|
||||||
|
printf("WARN: missing triangle: %i\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return adjList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static AdjacencyList groupTriangles(std::vector<uint16_t>& indices, std::vector<vec3_t>& vertices, int maxTrianglesPerGroup)
|
||||||
|
{
|
||||||
|
return buildAdjacencyList(indices, vertices, maxTrianglesPerGroup);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "Game/T6/T6.h"
|
#include "Game/T6/T6.h"
|
||||||
using namespace T6;
|
using namespace T6;
|
||||||
@@ -73,4 +74,50 @@ public:
|
|||||||
{
|
{
|
||||||
return ((size + 127) & 0xFFFFFF80);
|
return ((size + 127) & 0xFFFFFF80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float distBetweenPoints(vec3_t p1, vec3_t p2)
|
||||||
|
{
|
||||||
|
float x = p2.x - p1.x;
|
||||||
|
float y = p2.y - p1.y;
|
||||||
|
float z = p2.z - p1.z;
|
||||||
|
return sqrtf((x * x) + (y * y) + (z * z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// angles are in euler degrees
|
||||||
|
static void convertAnglesToAxis(vec3_t* angles, vec3_t* axis)
|
||||||
|
{
|
||||||
|
float xRadians = angles->x * 0.017453292; // M_PI / 180.0f
|
||||||
|
float yRadians = angles->y * 0.017453292; // M_PI / 180.0f
|
||||||
|
float zRadians = angles->z * 0.017453292; // M_PI / 180.0f
|
||||||
|
|
||||||
|
float cosX = cos(xRadians);
|
||||||
|
float sinX = sin(xRadians);
|
||||||
|
float cosY = cos(yRadians);
|
||||||
|
float sinY = sin(yRadians);
|
||||||
|
float cosZ = cos(zRadians);
|
||||||
|
float sinZ = sin(zRadians);
|
||||||
|
|
||||||
|
axis[0].x = cosX * cosY;
|
||||||
|
axis[0].y = cosX * sinY;
|
||||||
|
axis[0].z = -sinX;
|
||||||
|
axis[1].x = (sinZ * sinX * cosY) - (cosZ * sinY);
|
||||||
|
axis[1].y = (sinZ * sinX * sinY) + (cosZ * cosY);
|
||||||
|
axis[1].z = sinZ * cosX;
|
||||||
|
axis[2].x = (cosZ * sinX * cosY) + (sinZ * sinY);
|
||||||
|
axis[2].y = (cosZ * sinX * sinY) - (sinZ * cosY);
|
||||||
|
axis[2].z = cosZ * cosX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void matrixTranspose3x3(const vec3_t* in, vec3_t* out)
|
||||||
|
{
|
||||||
|
out[0].x = in[0].x;
|
||||||
|
out[0].y = in[1].x;
|
||||||
|
out[0].z = in[2].x;
|
||||||
|
out[1].x = in[0].y;
|
||||||
|
out[1].y = in[1].y;
|
||||||
|
out[1].z = in[2].y;
|
||||||
|
out[2].x = in[0].z;
|
||||||
|
out[2].y = in[1].z;
|
||||||
|
out[2].z = in[2].z;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
33093
src/ObjLoading/Game/T6/CustomMap/fbx/ufbx.c
Normal file
33093
src/ObjLoading/Game/T6/CustomMap/fbx/ufbx.c
Normal file
File diff suppressed because it is too large
Load Diff
6062
src/ObjLoading/Game/T6/CustomMap/fbx/ufbx.h
Normal file
6062
src/ObjLoading/Game/T6/CustomMap/fbx/ufbx.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
|||||||
#include "Game/T6/CommonT6.h"
|
#include "Game/T6/CommonT6.h"
|
||||||
#include "Game/T6/T6.h"
|
#include "Game/T6/T6.h"
|
||||||
#include "Image/IwiLoader.h"
|
#include "Image/IwiLoader.h"
|
||||||
|
#include "Image/IwiTypes.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
@@ -25,7 +26,12 @@ namespace
|
|||||||
|
|
||||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||||
{
|
{
|
||||||
const auto fileName = std::format("images/{}.iwi", assetName);
|
auto fileName = std::format("images/{}.iwi", assetName);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fileName.size(); i++)
|
||||||
|
if (fileName[i] == '*')
|
||||||
|
fileName[i] = '_';
|
||||||
|
|
||||||
const auto file = m_search_path.Open(fileName);
|
const auto file = m_search_path.Open(fileName);
|
||||||
if (!file.IsOpen())
|
if (!file.IsOpen())
|
||||||
return AssetCreationResult::NoAction();
|
return AssetCreationResult::NoAction();
|
||||||
@@ -53,11 +59,47 @@ namespace
|
|||||||
image->height = static_cast<uint16_t>(texture->GetHeight());
|
image->height = static_cast<uint16_t>(texture->GetHeight());
|
||||||
image->depth = static_cast<uint16_t>(texture->GetDepth());
|
image->depth = static_cast<uint16_t>(texture->GetDepth());
|
||||||
|
|
||||||
image->streaming = 1;
|
if (texture->GetTextureType() == TextureType::T_2D)
|
||||||
image->streamedParts[0].levelCount = 1;
|
image->mapType = 3;
|
||||||
image->streamedParts[0].levelSize = static_cast<uint32_t>(fileSize);
|
else if (texture->GetTextureType() == TextureType::T_3D)
|
||||||
image->streamedParts[0].hash = dataHash & 0x1FFFFFFF;
|
image->mapType = 4;
|
||||||
image->streamedPartCount = 1;
|
else if (texture->GetTextureType() == TextureType::T_CUBE)
|
||||||
|
image->mapType = 5;
|
||||||
|
else
|
||||||
|
_ASSERT(false);
|
||||||
|
|
||||||
|
//image->streaming = 1;
|
||||||
|
//image->streamedParts[0].levelCount = 1;
|
||||||
|
//image->streamedParts[0].levelSize = static_cast<uint32_t>(fileSize);
|
||||||
|
//image->streamedParts[0].hash = dataHash & 0x1FFFFFFF;
|
||||||
|
//image->streamedPartCount = 1;
|
||||||
|
|
||||||
|
int mipMapCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
|
||||||
|
size_t textureSize = 0;
|
||||||
|
for (int previousMipLevel = 0; previousMipLevel < mipMapCount; previousMipLevel++)
|
||||||
|
{
|
||||||
|
textureSize += texture->GetSizeOfMipLevel(previousMipLevel) * texture->GetFaceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
image->streaming = 0;
|
||||||
|
image->texture.loadDef = (GfxImageLoadDef*)malloc(sizeof(GfxImageLoadDef) + textureSize);
|
||||||
|
memset(image->texture.loadDef, 0, sizeof(GfxImageLoadDef) + textureSize);
|
||||||
|
image->texture.loadDef->format = texture->GetFormat()->GetDxgiFormat();
|
||||||
|
image->texture.loadDef->levelCount = 1;
|
||||||
|
image->texture.loadDef->resourceSize = textureSize;
|
||||||
|
memcpy(image->texture.loadDef->data,
|
||||||
|
texture->GetBufferForMipLevel(0),
|
||||||
|
textureSize); // GetBufferForMipLevel(0) returns a pointer to the start of the image
|
||||||
|
|
||||||
|
image->texture.loadDef->flags = 0;
|
||||||
|
if (image->noPicmip)
|
||||||
|
image->texture.loadDef->flags |= iwi27::IMG_FLAG_NOMIPMAPS;
|
||||||
|
|
||||||
|
if (texture->GetTextureType() == TextureType::T_3D)
|
||||||
|
image->texture.loadDef->flags |= iwi27::IMG_FLAG_VOLMAP;
|
||||||
|
|
||||||
|
if (texture->GetTextureType() == TextureType::T_CUBE)
|
||||||
|
image->texture.loadDef->flags |= iwi27::IMG_FLAG_CUBEMAP;
|
||||||
|
|
||||||
return AssetCreationResult::Success(context.AddAsset<AssetImage>(assetName, image));
|
return AssetCreationResult::Success(context.AddAsset<AssetImage>(assetName, image));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ namespace
|
|||||||
printf("ERROR: Cant find pixel shader %s\n", psFileName.c_str());
|
printf("ERROR: Cant find pixel shader %s\n", psFileName.c_str());
|
||||||
return AssetCreationResult::Failure();
|
return AssetCreationResult::Failure();
|
||||||
}
|
}
|
||||||
currPass->pixelShader->prog.loadDef.programSize = psFile.m_length;
|
currPass->pixelShader->prog.loadDef.programSize = (unsigned int)psFile.m_length;
|
||||||
currPass->pixelShader->prog.loadDef.program = new char[psFile.m_length];
|
currPass->pixelShader->prog.loadDef.program = new char[(unsigned int)psFile.m_length];
|
||||||
psFile.m_stream->read(currPass->pixelShader->prog.loadDef.program, psFile.m_length);
|
psFile.m_stream->read(currPass->pixelShader->prog.loadDef.program, psFile.m_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +158,8 @@ namespace
|
|||||||
printf("ERROR: Cant find vertex shader %s\n", vsFileName.c_str());
|
printf("ERROR: Cant find vertex shader %s\n", vsFileName.c_str());
|
||||||
return AssetCreationResult::Failure();
|
return AssetCreationResult::Failure();
|
||||||
}
|
}
|
||||||
currPass->vertexShader->prog.loadDef.programSize = vsFile.m_length;
|
currPass->vertexShader->prog.loadDef.programSize = (unsigned int)vsFile.m_length;
|
||||||
currPass->vertexShader->prog.loadDef.program = new char[vsFile.m_length];
|
currPass->vertexShader->prog.loadDef.program = new char[(unsigned int)vsFile.m_length];
|
||||||
vsFile.m_stream->read(currPass->vertexShader->prog.loadDef.program, vsFile.m_length);
|
vsFile.m_stream->read(currPass->vertexShader->prog.loadDef.program, vsFile.m_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "Writing/Steps/StepWriteZoneContentToFile.h"
|
#include "Writing/Steps/StepWriteZoneContentToFile.h"
|
||||||
#include "Writing/Steps/StepWriteZoneContentToMemory.h"
|
#include "Writing/Steps/StepWriteZoneContentToMemory.h"
|
||||||
#include "Writing/Steps/StepWriteZoneHeader.h"
|
#include "Writing/Steps/StepWriteZoneHeader.h"
|
||||||
|
#include "Writing/Steps/StepWriteZoneRSA.h"
|
||||||
#include "Writing/Steps/StepWriteZoneSizes.h"
|
#include "Writing/Steps/StepWriteZoneSizes.h"
|
||||||
#include "Zone/XChunk/XChunkProcessorDeflate.h"
|
#include "Zone/XChunk/XChunkProcessorDeflate.h"
|
||||||
#include "Zone/XChunk/XChunkProcessorSalsa20Encryption.h"
|
#include "Zone/XChunk/XChunkProcessorSalsa20Encryption.h"
|
||||||
@@ -99,9 +100,9 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
|
|||||||
{
|
{
|
||||||
auto writer = std::make_unique<ZoneWriter>();
|
auto writer = std::make_unique<ZoneWriter>();
|
||||||
|
|
||||||
// TODO Support signed fastfiles
|
bool isSecure = true;
|
||||||
bool isSecure = false;
|
|
||||||
bool isEncrypted = true;
|
bool isEncrypted = true;
|
||||||
|
bool isOfficial = true;
|
||||||
|
|
||||||
SetupBlocks(*writer);
|
SetupBlocks(*writer);
|
||||||
|
|
||||||
@@ -111,7 +112,11 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
|
|||||||
writer->AddWritingStep(std::move(contentInMemory));
|
writer->AddWritingStep(std::move(contentInMemory));
|
||||||
|
|
||||||
// Write zone header
|
// Write zone header
|
||||||
writer->AddWritingStep(std::make_unique<StepWriteZoneHeader>(CreateHeaderForParams(isSecure, false, isEncrypted)));
|
writer->AddWritingStep(std::make_unique<StepWriteZoneHeader>(CreateHeaderForParams(isSecure, isOfficial, isEncrypted)));
|
||||||
|
|
||||||
|
// write RSA
|
||||||
|
if (isSecure)
|
||||||
|
writer->AddWritingStep(std::make_unique<StepWriteZoneRSA>(zone.m_name));
|
||||||
|
|
||||||
// Setup loading XChunks from the zone from this point on.
|
// Setup loading XChunks from the zone from this point on.
|
||||||
ICapturedDataProvider* dataToSignProvider;
|
ICapturedDataProvider* dataToSignProvider;
|
||||||
|
|||||||
35
src/ZoneWriting/Writing/Steps/StepWriteZoneRSA.cpp
Normal file
35
src/ZoneWriting/Writing/Steps/StepWriteZoneRSA.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "StepWriteZoneRSA.h"
|
||||||
|
|
||||||
|
#include "Game/T6/ZoneConstantsT6.h"
|
||||||
|
|
||||||
|
StepWriteZoneRSA::StepWriteZoneRSA(std::string zoneName)
|
||||||
|
: m_zoneName(zoneName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StepWriteZoneRSA::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream)
|
||||||
|
{
|
||||||
|
stream->Write(T6::ZoneConstants::MAGIC_AUTH_HEADER, strlen(T6::ZoneConstants::MAGIC_AUTH_HEADER));
|
||||||
|
|
||||||
|
uint32_t loadFlags = 0;
|
||||||
|
stream->Write(&loadFlags, sizeof(uint32_t));
|
||||||
|
|
||||||
|
char fileName[32];
|
||||||
|
memset(fileName, 0, 32);
|
||||||
|
strncpy(fileName, m_zoneName.c_str(), 31);
|
||||||
|
stream->Write(fileName, 32);
|
||||||
|
|
||||||
|
char data[256] = {0x75, 0xc2, 0xca, 0x61, 0x15, 0xef, 0xcb, 0xde, 0x42, 0xfc, 0xa8, 0xed, 0xb1, 0x77, 0x79, 0x93, 0x73, 0x28, 0x3e, 0x7f, 0xca,
|
||||||
|
0x76, 0x48, 0xc3, 0x21, 0x23, 0x86, 0xc3, 0x0f, 0xb6, 0xa6, 0xb5, 0xe9, 0xab, 0x40, 0x29, 0xb8, 0x3c, 0x03, 0xc4, 0xe0, 0x99, 0xed,
|
||||||
|
0xf2, 0x96, 0xd7, 0xb3, 0x95, 0x0d, 0x2e, 0xdd, 0xf0, 0x08, 0x6d, 0x5a, 0x95, 0x0b, 0x61, 0xd9, 0xde, 0xb4, 0x9d, 0x8a, 0x1b, 0x19,
|
||||||
|
0xa8, 0x88, 0xb4, 0x35, 0xe8, 0x25, 0x78, 0x21, 0x04, 0xbf, 0x36, 0x13, 0x9b, 0xf6, 0x10, 0x12, 0x8a, 0x08, 0x98, 0xf0, 0xb5, 0xdc,
|
||||||
|
0x8c, 0xd6, 0x37, 0x6d, 0x9a, 0xd8, 0xe4, 0x62, 0x5d, 0x02, 0xc1, 0xf6, 0xf1, 0xa1, 0x95, 0x93, 0x42, 0xee, 0xc2, 0x1a, 0xd9, 0xf0,
|
||||||
|
0x36, 0x36, 0x23, 0x50, 0x8b, 0x11, 0x90, 0x6a, 0xa1, 0x8d, 0xf6, 0xd0, 0xe4, 0xb5, 0x0f, 0xfd, 0x87, 0x2f, 0x46, 0xb9, 0x08, 0x3e,
|
||||||
|
0x38, 0xf9, 0x81, 0xaa, 0x39, 0x2b, 0xf7, 0x44, 0x44, 0x75, 0x0e, 0x8a, 0x09, 0x6c, 0x6f, 0x6e, 0xea, 0xd0, 0x32, 0x62, 0xfd, 0x98,
|
||||||
|
0x65, 0xb5, 0xbd, 0xc0, 0xae, 0x63, 0xf1, 0xe9, 0x24, 0x03, 0xfc, 0x34, 0xed, 0xb6, 0xbf, 0x0e, 0xd2, 0x56, 0x43, 0xea, 0xde, 0xff,
|
||||||
|
0x51, 0xa8, 0xb1, 0x93, 0x47, 0xe3, 0xc3, 0xee, 0xc2, 0xa3, 0x0a, 0x93, 0x14, 0x8f, 0x98, 0x7c, 0xaf, 0x2d, 0xa2, 0x2c, 0x71, 0x23,
|
||||||
|
0x60, 0x6a, 0x66, 0xd1, 0x6b, 0x55, 0xc0, 0x5d, 0x9b, 0xad, 0x18, 0xc5, 0xac, 0x2f, 0xa4, 0x00, 0xe8, 0xd0, 0xa6, 0xb4, 0x67, 0xa7,
|
||||||
|
0xbb, 0x7d, 0x4a, 0xbe, 0x02, 0xd0, 0xb6, 0xe0, 0xc6, 0xac, 0x1e, 0x59, 0x88, 0xcd, 0x26, 0x41, 0x73, 0x10, 0x65, 0x13, 0x79, 0x72,
|
||||||
|
0x5a, 0x26, 0x41, 0xe9, 0x89, 0x51, 0xc3, 0x79, 0x7d, 0x70, 0x3a, 0x5b, 0x94, 0x5d, 0xdd};
|
||||||
|
stream->Write(data, 256);
|
||||||
|
}
|
||||||
13
src/ZoneWriting/Writing/Steps/StepWriteZoneRSA.h
Normal file
13
src/ZoneWriting/Writing/Steps/StepWriteZoneRSA.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Writing/IWritingStep.h"
|
||||||
|
|
||||||
|
|
||||||
|
class StepWriteZoneRSA final : public IWritingStep
|
||||||
|
{
|
||||||
|
std::string m_zoneName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit StepWriteZoneRSA(std::string zoneName);
|
||||||
|
|
||||||
|
void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user