Files
GTASource/game/debug/SceneGeometryCapture.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1496 lines
47 KiB
C++

// ==============================
// debug/SceneGeometryCapture.cpp
// (c) 2013 Rockstar
// ==============================
#if __BANK
#include "bank/bank.h"
#include "bank/bkmgr.h"
#include "file/asset.h"
#include "file/remote.h"
#include "file/stream.h"
#include "grcore/debugdraw.h"
#include "grcore/device.h"
#include "grcore/image.h"
#include "grcore/viewport.h"
#include "grmodel/model.h"
#include "grmodel/shader.h"
#include "grmodel/shadergroup.h"
#include "parser/manager.h"
#include "rmcore/lodgroup.h"
#include "spatialdata/aabb.h"
#include "spatialdata/sphere.h"
#include "string/stringutil.h"
#include "vector/geometry.h"
#include "vectormath/classes.h"
#include "fwdebug/picker.h"
#include "fwgeovis/geovis.h"
#include "fwscene/lod/LodTypes.h"
#include "fwscene/world/EntityContainer.h"
#include "camera/CamInterface.h"
#include "camera/debug/DebugDirector.h"
#include "camera/helpers/Frame.h"
#include "camera/viewports/ViewportManager.h"
#include "debug/AssetAnalysis/GeometryCollector.h" // for area code boxes
#include "debug/AssetAnalysis/StreamingIteratorManager.h" // for area code boxes
#include "debug/DebugGeometryUtil.h"
#include "debug/MarketingTools.h"
#include "debug/SceneGeometryCapture.h"
#include "modelinfo/BaseModelInfo.h"
#include "Objects/DummyObject.h"
#include "Objects/Object.h"
#include "Peds/Ped.h"
#include "Peds/PlayerInfo.h"
#include "physics/WorldProbe/WorldProbe.h"
#include "renderer/Renderer.h"
#include "scene/AnimatedBuilding.h"
#include "scene/Building.h"
#include "scene/Entity.h"
//#include "scene/EntityBatch.h"
#include "scene/EntityTypes.h"
#include "scene/LoadScene.h"
#include "scene/world/GameWorldHeightMap.h"
#include "vehicles/vehicle.h"
namespace rage { XPARAM(nopopups); }
#define SGC_DEFAULT_PATH "assets:"
#define SGC_DEFAULT_NAME "default"
#define SGC_DEFAULT_RADIUS 5.0f
#define SGC_DEFAULT_HEIGHT 0.0f
#define SGC_DEFAULT_COLOUR Color32(0,255,0,255)
#define SGC_MAX_SPHERES 2000
#define SGC_PRIVATE_RDR_STUFF (1 && RDR_VERSION) // TODO -- clean this up .. it might be useful for other people too
#define SGC_PANORAMA (1)
class CSceneGeometryCapture
{
public:
CSceneGeometryCapture() : m_panoramaPath(SGC_DEFAULT_PATH), m_geometryPath(SGC_DEFAULT_PATH) {}
class Sphere
{
public:
Sphere(const char* name = SGC_DEFAULT_NAME) : m_name(name), m_sphere(V_ZERO), m_height(SGC_DEFAULT_HEIGHT), m_colour(SGC_DEFAULT_COLOUR)
{
sysMemSet(m_areaCode, 0, sizeof(m_areaCode));
}
atString m_name;
char m_areaCode[4]; // rdr-specific
Vec4V m_sphere;
float m_height; // camera height
Color32 m_colour;
PAR_SIMPLE_PARSABLE;
};
atString m_panoramaPath;
atString m_geometryPath;
atArray<Sphere> m_spheres;
PAR_SIMPLE_PARSABLE;
};
#include "debug/SceneGeometryCapture_parser.h"
namespace SceneGeometryCapture {
static CSceneGeometryCapture* g = NULL;
static char g_metafilePath[128] = "assets:/capture.meta";
static bkCombo* g_selectedSphereCombo = NULL;
static char g_selectedSphereComboFilter[128] = "";
static atArray<int> g_selectedSphereComboList;
static int g_selectedSphereComboIndex = 0; // index into g_selectedSphereComboList
static char g_selectedSphereName[128] = SGC_DEFAULT_NAME;
static Vec3V g_selectedSphereCentre = Vec3V(V_ZERO);
static float g_selectedSphereRadius = SGC_DEFAULT_RADIUS;
static float g_selectedSphereHeight = SGC_DEFAULT_HEIGHT;
static Color32 g_selectedSphereColour = SGC_DEFAULT_COLOUR;
static int g_selectedSphereIndex = -1;
static bool g_warpToCameraHeight = false;
static float g_cameraHeightOffset = 10.0f;
static bool g_captureSelectedSphereOnly = false;
static int g_captureAutoListIndex = -1;
static int g_captureAutoSphereIndex = -1;
static int g_captureAutoStreamFrames = 0;
#if SGC_PANORAMA
static bool g_capturePanoramaEnabled = false;
static bool g_capturePanoramaShowFPS = true;
static Vec2V g_capturePanoramaShowFPSPos = Vec2V(32.0f, 100.0f);
static Color32 g_capturePanoramaShowFPSColour = Color32(255,255,255,255);
static bool g_capturePanoramaShowFPSBkgQuad = true;
static float g_capturePanoramaShowFPSScale = 6.0f;
static int g_capturePanoramaSteps = 12;
static int g_capturePanoramaFrameIndex = -1;
static int g_capturePanoramaAutoTimer = -1;
static int g_capturePanoramaAutoTimerDelay = 3;
static float g_capturePanoramaCameraFacing = 0.0f;
static char g_capturePanoramaPath[128] = SGC_DEFAULT_PATH;
#endif // SGC_PANORAMA
static char g_captureGeometryPath[128] = SGC_DEFAULT_PATH;
static u32 g_captureEntityLodFlags = LODTYPES_FLAG_HD | LODTYPES_FLAG_ORPHANHD;
static u32 g_captureEntityPoolFlags = ENTITY_TYPE_MASK_BUILDING | ENTITY_TYPE_MASK_ANIMATED_BUILDING | ENTITY_TYPE_MASK_OBJECT | ENTITY_TYPE_MASK_DUMMY_OBJECT | ENTITY_TYPE_MASK_MLO /*| ENTITY_TYPE_MASK_PED*/ | ENTITY_TYPE_MASK_VEHICLE;
static bool g_captureProps = true;
static bool g_captureTrees = true;
static bool g_captureAlpha = true;
static bool g_captureWater = true;
static bool g_captureDecals = false;
//static bool g_captureTerrain = true;
static u32 g_captureDrawableLodFlags = BIT(LOD_HIGH);
static bool g_captureClipToSpheres = true;
static bool g_captureVerbose = false;
static float g_drawOpacity = 1.0f;
static float g_drawDistanceMin = 400.0f;
static float g_drawDistanceMax = 500.0f;
static int MakeNameUnique(char* newName)
{
int index = -1;
if (g)
{
while (true)
{
bool bUnique = true;
for (int i = 0; i < g->m_spheres.GetCount(); i++)
{
if (stricmp(newName, g->m_spheres[i].m_name.c_str()) == 0)
{
if (index == -1)
{
index = i;
}
bUnique = false;
break;
}
}
if (!bUnique)
{
char* lastNonNumericChar = newName + strlen(newName) - 1;
while (lastNonNumericChar >= newName && isdigit(*lastNonNumericChar))
{
lastNonNumericChar--;
}
const int numeric = atoi(++lastNonNumericChar);
strcpy(lastNonNumericChar, atVarString("%d", numeric + 1).c_str());
}
else
{
break;
}
}
}
return index; // index of first sphere with name conflict, or -1 indicating no name conflict
}
static void UpdateCombo_cb();
static void UpdateSelectedSphere_cb()
{
if (g && g_selectedSphereIndex >= 0 && g_selectedSphereIndex < g->m_spheres.GetCount())
{
CSceneGeometryCapture::Sphere& sphere = g->m_spheres[g_selectedSphereIndex];
sphere.m_name = atString(g_selectedSphereName);
sphere.m_sphere = Vec4V(g_selectedSphereCentre, ScalarV(g_selectedSphereRadius));
sphere.m_height = g_selectedSphereHeight;
sphere.m_colour = g_selectedSphereColour;
}
}
static void UpdateSelectedSphereCameraHeight_cb()
{
if (g_warpToCameraHeight && camInterface::GetDebugDirector().IsFreeCamActive())
{
camFrame& cam = camInterface::GetDebugDirector().GetFreeCamFrameNonConst();
const Vec3V pos(g_selectedSphereCentre.GetXY(), ScalarV(g_selectedSphereHeight + g_cameraHeightOffset));
cam.SetPosition(RCC_VECTOR3(pos));
}
}
static void UpdateSelectedSphereCamera_cb()
{
UpdateSelectedSphereCameraHeight_cb();
UpdateSelectedSphere_cb();
}
static void UpdateSelectedSphereName_cb()
{
if (g && g_selectedSphereIndex >= 0 && g_selectedSphereIndex < g->m_spheres.GetCount())
{
CSceneGeometryCapture::Sphere& sphere = g->m_spheres[g_selectedSphereIndex];
char newName[128] = "";
strcpy(newName, g_selectedSphereName);
const int index = MakeNameUnique(newName);
sphere.m_name = atString(newName);
if (index >= 0)
{
Displayf("sphere name %s was used (index = %d), changing name to %s", g_selectedSphereName, index, newName);
strcpy(g_selectedSphereName, newName);
}
}
UpdateSelectedSphere_cb();
UpdateCombo_cb();
}
static void UpdateSelectedSphereIndex_cb()
{
if (g && g_selectedSphereIndex >= 0 && g->m_spheres.GetCount() > 0)
{
g_selectedSphereIndex = Min<int>(g_selectedSphereIndex, g->m_spheres.GetCount() - 1);
const CSceneGeometryCapture::Sphere& sphere = g->m_spheres[g_selectedSphereIndex];
strcpy(g_selectedSphereName, sphere.m_name.c_str() ? sphere.m_name.c_str() : SGC_DEFAULT_NAME);
g_selectedSphereCentre = sphere.m_sphere.GetXYZ();
g_selectedSphereRadius = sphere.m_sphere.GetWf();
g_selectedSphereHeight = sphere.m_height;
g_selectedSphereColour = sphere.m_colour;
}
else
{
strcpy(g_selectedSphereName, SGC_DEFAULT_NAME);
g_selectedSphereCentre = Vec3V(V_ZERO);
g_selectedSphereRadius = SGC_DEFAULT_RADIUS;
g_selectedSphereHeight = SGC_DEFAULT_HEIGHT;
g_selectedSphereColour = SGC_DEFAULT_COLOUR;
g_selectedSphereIndex = -1;
}
g_selectedSphereComboIndex = 0;
for (int i = 0; i < g_selectedSphereComboList.GetCount(); i++)
{
if (g_selectedSphereComboList[i] == g_selectedSphereIndex)
{
g_selectedSphereComboIndex = i;
break;
}
}
}
static void SelectedSphereSnapToGround_button()
{
if (g && g_selectedSphereIndex >= 0 && g->m_spheres.GetCount() > 0)
{
Vec3V vStart = g->m_spheres[g_selectedSphereIndex].m_sphere.GetXYZ();
Vec3V vEnd = vStart;
vStart.SetZf(+8000.0f);
vEnd.SetZf(-8000.0f);
WorldProbe::CShapeTestProbeDesc probeDesc;
WorldProbe::CShapeTestHitPoint probeHitPoint;
WorldProbe::CShapeTestResults probeResult(probeHitPoint);
probeDesc.SetResultsStructure(&probeResult);
probeDesc.SetStartAndEnd(RCC_VECTOR3(vStart), RCC_VECTOR3(vEnd));
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES);
if (WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc))
{
Displayf("probe hit pos=%f,%f,%f, normal=%f,%f,%f", VEC3V_ARGS(probeResult[0].GetHitPositionV()), VEC3V_ARGS(probeResult[0].GetHitNormalV()));
g_selectedSphereCentre = probeResult[0].GetHitPositionV();
g->m_spheres[g_selectedSphereIndex].m_sphere = Vec4V(g_selectedSphereCentre, ScalarV(g_selectedSphereRadius));
}
else
{
Displayf("probe failed");
}
}
}
#if SGC_PANORAMA
static void UpdateCameraFacing_cb()
{
if (camInterface::GetDebugDirector().IsFreeCamActive())
{
camFrame& cam = camInterface::GetDebugDirector().GetFreeCamFrameNonConst();
cam.SetWorldMatrixFromHeadingPitchAndRoll(DtoR*g_capturePanoramaCameraFacing, 0.0f, 0.0f);
}
}
#endif // SGC_PANORAMA
static void LoadMetafile_button()
{
if (ASSET.Exists(g_metafilePath, NULL))
{
bool bCreated = false;
if (g == NULL)
{
g = rage_new CSceneGeometryCapture();
bCreated = true;
}
if (PARSER.InitAndLoadObject(g_metafilePath, NULL, *g))
{
g_selectedSphereIndex = -1;
UpdateSelectedSphereIndex_cb();
UpdateCombo_cb();
Displayf("%s loaded (%d spheres)", g_metafilePath, g->m_spheres.GetCount());
// check that there are no duplicate names
for (int i = 0; i < g->m_spheres.GetCount(); i++)
{
for (int j = i + 1; j < g->m_spheres.GetCount(); j++)
{
if (stricmp(g->m_spheres[i].m_name.c_str(), g->m_spheres[j].m_name.c_str()) == 0)
{
const bool nopopups = PARAM_nopopups.Get();
PARAM_nopopups.Set(NULL);
char msg[512] = "";
sprintf(msg, "Name collisions found in %s - spheres %d and %d both have the name '%s' .. please fix meta file and reload", g_metafilePath, i, j, g->m_spheres[i].m_name.c_str());
fiRemoteShowMessageBox(msg, sysParam::GetProgramName(), MB_ICONERROR | MB_OK | MB_TOPMOST, IDOK);
PARAM_nopopups.Set(nopopups ? "" : NULL);
g->m_spheres.clear();
g_selectedSphereIndex = -1;
UpdateSelectedSphereIndex_cb();
UpdateCombo_cb();
delete g;
g = NULL;
break;
}
}
if (g == NULL)
{
break;
}
}
for (int i = 0; i < g->m_spheres.GetCount(); i++)
{
if (g->m_spheres[i].m_height == SGC_DEFAULT_HEIGHT)
{
g->m_spheres[i].m_height = g->m_spheres[i].m_sphere.GetZf();
}
}
if (g->m_panoramaPath.length() == 0) { g->m_panoramaPath = SGC_DEFAULT_PATH; }
if (g->m_geometryPath.length() == 0) { g->m_geometryPath = SGC_DEFAULT_PATH; }
#if SGC_PANORAMA
strcpy(g_capturePanoramaPath, g->m_panoramaPath.c_str());
#endif // SGC_PANORAMA
strcpy(g_captureGeometryPath, g->m_geometryPath.c_str());
}
else if (bCreated)
{
Displayf("%s failed to load", g_metafilePath);
delete g;
g = NULL;
}
}
else
{
Displayf("%s does not exist", g_metafilePath);
}
}
static void SaveMetafile_button()
{
if (g)
{
#if SGC_PANORAMA
g->m_panoramaPath = g_capturePanoramaPath;
#else
g->m_panoramaPath = "";
#endif
g->m_geometryPath = g_captureGeometryPath;
if (PARSER.SaveObject(g_metafilePath, NULL, g))
{
Displayf("%s saved (%d spheres)", g_metafilePath, g->m_spheres.GetCount());
}
else
{
Displayf("%s failed to load", g_metafilePath);
}
}
}
static void SelectedSphereCombo_cb()
{
if (g_selectedSphereComboIndex >= 0 && g_selectedSphereComboIndex < g_selectedSphereComboList.GetCount())
{
g_selectedSphereIndex = g_selectedSphereComboList[g_selectedSphereComboIndex];
UpdateSelectedSphereIndex_cb();
}
}
static void UpdateCombo_cb()
{
if (g)
{
int prevSelectedSphereIndex = -1;
if (g_selectedSphereComboIndex >= 0 && g_selectedSphereComboIndex < g_selectedSphereComboList.GetCount())
{
prevSelectedSphereIndex = g_selectedSphereComboList[g_selectedSphereComboIndex];
}
atArray<const char*> names;
char* emptyNameCopy = rage_new char[1];
strcpy(emptyNameCopy, "");
names.PushAndGrow(emptyNameCopy);
g_selectedSphereComboList.Reset();
g_selectedSphereComboList.PushAndGrow(-1);
for (int i = 0; i < g->m_spheres.GetCount(); i++)
{
if (g_selectedSphereComboFilter[0] == '\0' || stristr(g->m_spheres[i].m_name.c_str(), g_selectedSphereComboFilter))
{
char temp[256] = "";
sprintf(temp, "%d. %s", i, g->m_spheres[i].m_name.c_str());
char* nameCopy = rage_new char[strlen(temp) + 1];
strcpy(nameCopy, temp);
names.PushAndGrow(nameCopy);
g_selectedSphereComboList.PushAndGrow(i);
}
}
g_selectedSphereComboIndex = 0;
for (int i = 0; i < g_selectedSphereComboList.GetCount(); i++)
{
if (g_selectedSphereComboList[i] == prevSelectedSphereIndex)
{
g_selectedSphereComboIndex = i;
break;
}
}
g_selectedSphereCombo->UpdateCombo(NULL, &g_selectedSphereComboIndex, names.GetCount(), &names[0], SelectedSphereCombo_cb);
for (int i = 0; i < names.GetCount(); i++)
{
delete[] names[i];
}
}
}
static void WarpToSphere(int sphereIndex, float warpHeight, bool warpHeightIsRelative)
{
if (g && sphereIndex >= 0 && sphereIndex < g->m_spheres.GetCount())
{
const CSceneGeometryCapture::Sphere& sphere = g->m_spheres[sphereIndex];
CPed* pPlayerPed = FindPlayerPed();
if (pPlayerPed)
{
pPlayerPed->Teleport(VEC3V_TO_VECTOR3(sphere.m_sphere.GetXYZ()), 0.0f);
}
Mat34V camMtx;
if (g_warpToCameraHeight
#if SGC_PANORAMA
|| g_capturePanoramaEnabled
#endif // SGC_PANORAMA
)
{
const Vec3V camFront = Vec3V(V_Y_AXIS_WZERO);
const Vec3V camUp = Vec3V(V_Z_AXIS_WZERO);
const Vec3V camLeft = Vec3V(V_X_AXIS_WZERO);
const Vec3V camPos = Vec3V(sphere.m_sphere.GetXY(), ScalarV(sphere.m_height + g_cameraHeightOffset));
camMtx = Mat34V(camLeft, camFront, camUp, camPos);
}
else
{
const Vec3V camFront = -Vec3V(V_Z_AXIS_WZERO);
const Vec3V camUp = Vec3V(V_Y_AXIS_WZERO);
const Vec3V camLeft = Cross(camFront, camUp);
const Vec3V camPos = sphere.m_sphere.GetXYZ() + Vec3V(0.0f, 0.0f, warpHeight*(warpHeightIsRelative ? sphere.m_sphere.GetWf() : 1.0f));
camMtx = Mat34V(camLeft, camFront, camUp, camPos);
}
camInterface::GetDebugDirector().ActivateFreeCam();
camInterface::GetDebugDirector().GetFreeCamFrameNonConst().SetWorldMatrix(RCC_MATRIX34(camMtx), false); // set both orientation and position
}
}
static void WarpToSelectedSphere_button()
{
WarpToSphere(g_selectedSphereIndex, 1.6f, true);
}
static void WarpToAndSelectNext_button()
{
if (g && g_selectedSphereComboIndex < g_selectedSphereComboList.GetCount() - 1)
{
const int sphereIndex = g_selectedSphereComboList[++g_selectedSphereComboIndex];
if (sphereIndex >= 0 && sphereIndex < g->m_spheres.GetCount())
{
g_selectedSphereIndex = sphereIndex;
}
else
{
g_selectedSphereIndex = -1;
}
UpdateSelectedSphereIndex_cb();
WarpToSelectedSphere_button();
}
}
static void SelectClosestSphere_button()
{
if (g && g->m_spheres.GetCount() > 0)
{
const grcViewport* vp = gVpMan.GetCurrentGameGrcViewport();
const Vec3V camPos = vp->GetCameraPosition();
ScalarV distMin1(V_FLT_MAX); // distance to centre
ScalarV distMin2(V_FLT_MAX); // distance to surface
int index = -1;
for (int i = 0; i < g->m_spheres.GetCount(); i++)
{
const CSceneGeometryCapture::Sphere& sphere = g->m_spheres[i];
if (vp->IsSphereVisible(sphere.m_sphere))
{
const ScalarV dist1 = Mag(sphere.m_sphere.GetXYZ() - camPos);
const ScalarV dist2 = Max(ScalarV(V_ZERO), dist1 - sphere.m_sphere.GetW());
if (IsLessThanOrEqualAll(dist2, distMin2))
{
if (IsLessThanAll(dist2, distMin2) | IsLessThanAll(dist1, distMin1))
{
distMin1 = dist1;
distMin2 = dist2;
index = i;
}
}
}
}
if (index != -1)
{
g_selectedSphereIndex = index;
UpdateSelectedSphereIndex_cb();
}
else
{
Displayf("no spheres are visible");
}
}
}
// copied from RenderPhaseCascadeShadows.cpp (TODO -- move this function to GtaPicker)
static FASTRETURNCHECK(bool) _GetEntityApproxAABB(spdAABB& aabb, const CEntity* pEntity)
{
if (pEntity && !pEntity->GetIsRetainedByInteriorProxy())
{
fwBaseEntityContainer* pContainer = pEntity->GetOwnerEntityContainer();
if (pContainer)
{
const u32 index = pContainer->GetEntityDescIndex(pEntity);
if (index != fwBaseEntityContainer::INVALID_ENTITY_INDEX)
{
pContainer->GetApproxBoundingBox(index, aabb);
return true;
}
}
}
return false;
}
static Vec4V g_AddNewSphere(V_ZERO);
static char g_AddNewSphereName[128] = "";
static void AddNewSphere_button()
{
if (g == NULL)
{
g = rage_new CSceneGeometryCapture();
}
if (g->m_spheres.GetCount() >= SGC_MAX_SPHERES)
{
Displayf("too many spheres - max is %d", SGC_MAX_SPHERES);
return;
}
const char* name = SGC_DEFAULT_NAME;
Color32 colour = SGC_DEFAULT_COLOUR;
if (g_AddNewSphereName[0])
{
name = g_AddNewSphereName;
}
else if (g_selectedSphereIndex >= 0 && g_selectedSphereIndex < g->m_spheres.GetCount())
{
name = g->m_spheres[g_selectedSphereIndex].m_name.c_str();
colour = g->m_spheres[g_selectedSphereIndex].m_colour;
}
else
{
name = g_selectedSphereName;
colour = g_selectedSphereColour;
}
char newName[128] = "";
strcpy(newName, name);
MakeNameUnique(newName);
g->m_spheres.PushAndGrow(CSceneGeometryCapture::Sphere(newName));
g_selectedSphereIndex = g->m_spheres.GetCount() - 1;
CSceneGeometryCapture::Sphere& sphere = g->m_spheres[g_selectedSphereIndex];
if (IsZeroAll(g_AddNewSphere))
{
spdAABB aabb;
if (_GetEntityApproxAABB(aabb, (CEntity*)g_PickerManager.GetSelectedEntity()))
{
sphere.m_sphere = Vec4V(aabb.GetCenter(), Mag(aabb.GetExtent()));
}
else
{
sphere.m_sphere = Vec4V(gVpMan.GetCurrentGameGrcViewport()->GetCameraPosition(), ScalarV(SGC_DEFAULT_RADIUS));
}
}
else
{
sphere.m_sphere = g_AddNewSphere;
}
sphere.m_height = sphere.m_sphere.GetZf();
sphere.m_colour = colour;
UpdateSelectedSphereIndex_cb();
UpdateCombo_cb();
for (int i = 0; i < g_selectedSphereComboList.GetCount(); i++)
{
if (g_selectedSphereComboList[i] == g_selectedSphereIndex)
{
g_selectedSphereComboIndex = i;
break;
}
}
}
static void DeleteSelectedSphere_button()
{
if (g && g_selectedSphereIndex >= 0 && g_selectedSphereIndex < g->m_spheres.GetCount())
{
for (int i = g_selectedSphereIndex + 1; i < g->m_spheres.GetCount(); i++)
{
g->m_spheres[i - 1] = g->m_spheres[i];
}
g->m_spheres.Pop();
if (g_selectedSphereIndex >= g->m_spheres.GetCount())
{
g_selectedSphereIndex = -1;
}
UpdateSelectedSphereIndex_cb();
UpdateCombo_cb();
}
}
static void DeleteAllSpheres_button()
{
if (g)
{
const bool nopopups = PARAM_nopopups.Get();
PARAM_nopopups.Set(NULL);
const int result = fiRemoteShowMessageBox("Are you sure you want to delete all spheres?", sysParam::GetProgramName(), MB_ICONQUESTION | MB_OKCANCEL | MB_TOPMOST, IDCANCEL);
PARAM_nopopups.Set(nopopups ? "" : NULL);
if (result == IDOK)
{
const int numSpheres = g->m_spheres.GetCount();
g->m_spheres.clear();
g_selectedSphereIndex = -1;
UpdateSelectedSphereIndex_cb();
UpdateCombo_cb();
delete g;
g = NULL;
Displayf("%d spheres deleted", numSpheres);
}
else
{
Displayf("aborted");
}
}
}
#if SGC_PRIVATE_RDR_STUFF
static void AddAreaCodeSpheres_button()
{
class CAreaCodeBounds : public spdAABB
{
public:
char m_areaCode[4];
bool m_used;
};
atArray<CAreaCodeBounds> bounds;
char line[512] = "";
// load area bounds
{
fiStream* fp = fiStream::Open("assets:/non_final/rdr3_area_bounds.txt");
if (fp)
{
// e.g.: area 'lev' bounds = [3885.510742,-3909.626709,35.058342],[4099.395020,-3589.768311,107.753555], centre = 3992.452881,-3749.697510,71.405945, radius = 195.793564
while (fgetline(line, sizeof(line), fp))
{
const char* temp = strstr(line, "area '");
if (temp == NULL) continue;
temp += strlen("area '");
if (temp[3] != '\'') continue;
const char* areaCode = temp;
temp = strstr(temp, "bounds = [");
if (temp == NULL) continue;
const char* x0 = temp + strlen("bounds = [");
temp = strchr(x0, ','); if (temp == NULL) continue; const char* y0 = temp + 1;
temp = strchr(y0, ','); if (temp == NULL) continue; const char* z0 = temp + 1;
temp = strchr(z0, '['); if (temp == NULL) continue; const char* x1 = temp + 1;
temp = strchr(x1, ','); if (temp == NULL) continue; const char* y1 = temp + 1;
temp = strchr(y1, ','); if (temp == NULL) continue; const char* z1 = temp + 1;
CAreaCodeBounds ab;
memcpy(ab.m_areaCode, areaCode, 3);
ab.m_areaCode[3] = '\0';
const Vec3V bmin = Vec3V((float)atof(x0), (float)atof(y0), (float)atof(z0));
const Vec3V bmax = Vec3V((float)atof(x1), (float)atof(y1), (float)atof(z1));
ab.Set(bmin, bmax);
ab.m_used = false;
bounds.PushAndGrow(ab);
}
fp->Close();
}
}
// load area names
{
fiStream* fp = fiStream::Open("assets:/non_final/rdr3_area_names.txt");
if (fp)
{
// e.g.: area_01/adl - K08 - The Grizzlies (intro) - Adler Ranch
while (fgetline(line, sizeof(line), fp))
{
const char* temp = strchr(line, '/');
if (temp == NULL) continue;
temp++;
CAreaCodeBounds* ab = NULL;
if (isalpha(temp[0]) && isalpha(temp[1]) && isalpha(temp[2]) && temp[3] == ' ')
{
for (int i = 0; i < bounds.GetCount(); i++)
{
if (memcmp(bounds[i].m_areaCode, temp, 3) == 0)
{
ab = &bounds[i];
break;
}
}
}
else
{
continue;
}
temp = strstr(temp, " - "); // grid
if (temp == NULL) continue;
temp += strlen(" - ");
const int row = *(temp++);
if (row < 'F' || row > 'U') continue;
const int col = atoi(temp);
if (col < 2 || col > 18) continue;
temp = strstr(temp, " - "); // district name
if (temp == NULL) continue;
temp += strlen(" - ");
temp = strstr(temp, " - "); // area name
if (temp == NULL) continue;
temp += strlen(" - ");
char areaName[256] = "";
strcpy(areaName, temp);
for (char* s = areaName; *s; s++) { if (strchr("\\/:*?\"<>|", *s)) { *s = '_'; } }
float x = (float)gv::WORLD_BOUNDS_MIN_X + (float)gv::WORLD_TILE_SIZE*(1.0f + 2.0f*(float)(col - 2));
float y = (float)gv::WORLD_BOUNDS_MIN_Y + (float)gv::WORLD_TILE_SIZE*(1.0f + 2.0f*(float)('U' - row));
float z = CGameWorldHeightMap::GetMinHeightFromWorldHeightMap(x, y);
float r = 80.0f;
if (ab)
{
x = ab->GetCenter().GetXf();
y = ab->GetCenter().GetYf();
z = ab->GetCenter().GetZf();
r = Mag(ab->GetExtent()).Getf();
ab->m_used = true;
}
g_AddNewSphere = Vec4V(x, y, z, r);
strcpy(g_AddNewSphereName, areaName);
bool bUnique = true;
if (g)
{
for (int i = 0; i < g->m_spheres.GetCount(); i++)
{
if (IsEqualAll(g_AddNewSphere, g->m_spheres[i].m_sphere))
{
Displayf("skipping '%s' %sbecause it coincides with sphere %d", areaName, ab ? "" : "(no bounds) ", i);
bUnique = false; // don't add duplicate spheres - our area positions are quantised to tile grid, so not very accurate ..
break;
}
}
}
if (bUnique)
{
Displayf("adding '%s' %s@ %f,%f,%f (r=%f)", g_AddNewSphereName, ab ? "" : "(no bounds) ", VEC4V_ARGS(g_AddNewSphere));
AddNewSphere_button();
if (g && strcmp(g->m_spheres.Top().m_name.c_str(), g_AddNewSphereName) == 0)
{
if (ab)
{
strcpy(g->m_spheres.Top().m_areaCode, ab->m_areaCode);
}
else
{
g->m_spheres.Top().m_colour = Color32(255,0,0,255);
}
}
}
}
fp->Close();
}
}
for (int i = 0; i < bounds.GetCount(); i++)
{
if (!bounds[i].m_used)
{
g_AddNewSphere = Vec4V(bounds[i].GetCenter(), Mag(bounds[i].GetExtent()));
strcpy(g_AddNewSphereName, bounds[i].m_areaCode);
Displayf("adding '%s' @ %f,%f,%f (r=%f)", g_AddNewSphereName, VEC4V_ARGS(g_AddNewSphere));
AddNewSphere_button();
if (g && strcmp(g->m_spheres.Top().m_name.c_str(), g_AddNewSphereName) == 0)
{
strcpy(g->m_spheres.Top().m_areaCode, bounds[i].m_areaCode);
}
}
}
g_AddNewSphere = Vec4V(V_ZERO);
g_AddNewSphereName[0] = '\0';
g_selectedSphereComboIndex = 0;
}
#endif // SGC_PRIVATE_RDR_STUFF
CDumpGeometryToOBJ* g_obj = NULL;
static bool CaptureGeometryBegin()
{
return true;
}
static void CaptureGeometry(int sphereIndex)
{
if (!AssertVerify(g_obj == NULL))
{
delete g_obj;
}
g_obj = rage_new CDumpGeometryToOBJ(atVarString("%s/%s.obj", g_captureGeometryPath, g->m_spheres[sphereIndex].m_name.c_str()).c_str());
static spdSphere s_sphere;
static int s_sphereIndex = -1;
static int s_entityIndex = 0;
class p { public: static bool func(void* item, void*)
{
if (item)
{
const CEntity* pEntity = static_cast<CEntity*>(item);
const CBaseModelInfo* pModelInfo = pEntity->GetBaseModelInfo();
if (pModelInfo && (g_captureEntityLodFlags & BIT(pEntity->GetLodData().GetLodType())) != 0)
{
if (!g_captureProps && pModelInfo->GetIsProp())
{
return false;
}
if (!g_captureTrees && pModelInfo->GetIsTree())
{
return false;
}
//if (!g_captureTerrain && pModelInfo->GetIsTerrain())
//{
// return false;
//}
static int s_actualNumTriangles = 0;
static int s_numTrianglesConsidered = 0;
if (pEntity->GetIsTypePed())
{
// TODO -- see CutSceneManager::CaptureSceneToObj for how to capture ped geometry
}
// else if (pEntity->GetIsTypeInstanceList() || pEntity->GetIsTypeGrassInstanceList())
// {
// // TODO
// }
else
{
spdAABB aabb;
pEntity->GetAABB(aabb);
if (aabb.IntersectsSphere(s_sphere))
{
class AddTrianglesForEntity_geometry { public: static bool func(const grmModel& model, const grmGeometry&, const grmShader& shader, const grmShaderGroup& shaderGroup, int lodIndex, void*)
{
if (g_captureDrawableLodFlags & BIT(lodIndex))
{
if (!g_captureAlpha && false) // TODO -- use CRenderer::RB_ALPHA, not shader name
{
return false;
}
if (!g_captureWater && strstr(shader.GetName(), "water")) // TODO -- use CRenderer::RB_WATER, not shader name
{
return false;
}
if (!g_captureDecals && strstr(shader.GetName(), "decal")) // TODO -- use CRenderer::RB_DECAL, not shader name
{
return false;
}
const u32 mask = CRenderer::GetSubBucketMask(model.ComputeBucketMask(shaderGroup));
if (mask & CRenderer::GenerateSubBucketMask(CRenderer::RB_MODEL_DEFAULT))
{
return true;
}
}
return false;
}};
class AddTrianglesForEntity_triangle { public: static void func(Vec3V_In v0, Vec3V_In v1, Vec3V_In v2, int, int, int, void*)
{
if (g_captureClipToSpheres)
{
const Vec3V verts[3] = {v0, v1, v2};
const Vec3V faceNormal = NormalizeSafe(Cross(v1 - v0, v2 - v0), Vec3V(V_ZERO), Vec3V(V_FLT_SMALL_4));
if (IsZeroAll(faceNormal)) // if the triangle is nearly degenerate, just test the bounding box ..
{
if (!spdAABB(Min(v0, v1, v2), Max(v0, v1, v2)).IntersectsSphere(s_sphere))
{
return;
}
}
else if (!geomSpheres::TestSphereToTriangle(s_sphere.GetV4(), verts, faceNormal)) // .. otherwise do the proper sphere-triangle test
{
return;
}
}
g_obj->AddTriangle(v0, v1, v2);
s_actualNumTriangles++;
}};
g_obj->GroupBegin(atVarString("%s_%04d", pEntity->GetModelName(), s_entityIndex++).c_str());
s_actualNumTriangles = 0;
s_numTrianglesConsidered = GeometryUtil::AddTrianglesForEntity(pEntity, -1, AddTrianglesForEntity_geometry::func, AddTrianglesForEntity_triangle::func);
g_obj->GroupEnd();
}
}
if (g_captureVerbose)
{
Displayf("sphere %d added %d out of %d triangles for %s at %f,%f,%f", s_sphereIndex, s_actualNumTriangles, s_numTrianglesConsidered, pEntity->GetModelName(), VEC3V_ARGS(pEntity->GetTransform().GetPosition()));
}
}
}
return true;
}};
s_sphere = spdSphere(g->m_spheres[sphereIndex].m_sphere);
s_sphereIndex = sphereIndex;
s_entityIndex = 0;
// add origin group
g_obj->GroupBegin("origin");
g_obj->AddTriangle(s_sphere.GetCenter(), s_sphere.GetCenter(), s_sphere.GetCenter());
g_obj->GroupEnd();
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_BUILDING ) { CBuilding ::GetPool()->ForAll(p::func, NULL); }
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_ANIMATED_BUILDING ) { CAnimatedBuilding::GetPool()->ForAll(p::func, NULL); }
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_OBJECT ) { CObject ::GetPool()->ForAll(p::func, NULL); }
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_DUMMY_OBJECT ) { CDummyObject ::GetPool()->ForAll(p::func, NULL); }
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_MLO ) { CInteriorInst ::GetPool()->ForAll(p::func, NULL); }
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_PED ) { CPed ::GetPool()->ForAll(p::func, NULL); }
if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_VEHICLE ) { CVehicle ::GetPool()->ForAll(p::func, NULL); }
// if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_INSTANCE_LIST ) { CEntityBatch ::GetPool()->ForAll(p::func, NULL); }
// if (g_captureEntityPoolFlags & ENTITY_TYPE_MASK_GRASS_INSTANCE_LIST) { CGrassBatch ::GetPool()->ForAll(p::func, NULL); }
}
static void CaptureGeometryEnd()
{
if (AssertVerify(g_obj))
{
g_obj->Close();
g_obj = NULL;
}
}
static void CaptureGeometrySelectedSphere_button()
{
if (g && g_selectedSphereIndex >= 0 && g_selectedSphereIndex < g->m_spheres.GetCount())
{
if (CaptureGeometryBegin())
{
CaptureGeometry(g_selectedSphereIndex);
CaptureGeometryEnd();
}
}
}
template <bool bSelectedSphereOnly> static void CaptureGeometryStart_button()
{
if (bSelectedSphereOnly && !g_capturePanoramaEnabled)
{
CaptureGeometrySelectedSphere_button();
return;
}
if (g && g_captureAutoListIndex == -1)
{
g_captureSelectedSphereOnly = bSelectedSphereOnly;
g_captureAutoListIndex = 1;
g_captureAutoSphereIndex = -1;
g_captureAutoStreamFrames = 0;
#if SGC_PANORAMA
g_capturePanoramaFrameIndex = -1;
g_capturePanoramaAutoTimer = -1;
#endif // SGC_PANORAMA
Displayf("starting auto capture ...");
if (g_capturePanoramaEnabled)
{
CMarketingTools::WidgetHudHideAll();
}
camInterface::GetDebugDirector().ActivateFreeCam();
fwTimer::StartUserPause();
}
}
static void CaptureGeometryStop_button()
{
if (g && g_captureAutoListIndex != -1)
{
g_captureAutoListIndex = -1;
g_captureAutoSphereIndex = -1;
g_captureAutoStreamFrames = 0;
#if SGC_PANORAMA
g_capturePanoramaFrameIndex = -1;
g_capturePanoramaAutoTimer = -1;
#endif // SGC_PANORAMA
Displayf("auto capture stopped.");
if (g_capturePanoramaEnabled)
{
CMarketingTools::WidgetHudShowAll();
}
g_LoadScene.Stop();
}
}
static void CaptureGeometryUpdate()
{
if (g && g_captureAutoListIndex >= 0)
{
if (g_captureSelectedSphereOnly)
{
while (g_captureAutoListIndex < g_selectedSphereComboList.GetCount())
{
if (g_selectedSphereComboList[g_captureAutoListIndex] != g_selectedSphereIndex)
{
g_captureAutoListIndex++;
}
else
{
break;
}
}
}
if (g_captureAutoListIndex < g_selectedSphereComboList.GetCount())
{
#if SGC_PANORAMA
if (g_capturePanoramaFrameIndex >= 0) // capturing panoramic frame
{
if (!g_LoadScene.IsLoaded())
{
// wait for streaming ..
}
else if (g_capturePanoramaAutoTimer > 0)
{
g_capturePanoramaAutoTimer--; // wait for rendering ..
}
else
{
grcImage* pScreenImage = GRCDEVICE.CaptureScreenShot(NULL);
if (AssertVerify(pScreenImage))
{
pScreenImage->SavePNG(atVarString("%s/%s_%03d.png", g_capturePanoramaPath, g->m_spheres[g_captureAutoSphereIndex].m_name.c_str(), g_capturePanoramaFrameIndex).c_str(), 0.0f);
pScreenImage->Release();
}
g_capturePanoramaFrameIndex++;
if (g_capturePanoramaFrameIndex < g_capturePanoramaSteps)
{
g_capturePanoramaCameraFacing = (360.0f/(float)g_capturePanoramaSteps)*(float)g_capturePanoramaFrameIndex;
UpdateCameraFacing_cb();
Displayf("starting panoramic frame %d", g_capturePanoramaFrameIndex);
const Vec3V camPos = +gVpMan.GetCurrentGameGrcViewport()->GetCameraMtx().GetCol3();
const Vec3V camDir = -gVpMan.GetCurrentGameGrcViewport()->GetCameraMtx().GetCol2();
g_LoadScene.Start(camPos, camDir, 16000.0f, true, 0, CLoadScene::LOADSCENE_OWNER_DEBUG);
g_capturePanoramaAutoTimer = g_capturePanoramaAutoTimerDelay;
}
else
{
Displayf("panorama captured.");
g_capturePanoramaFrameIndex = -1; // done capturing panoramic frames .. next update we'll advance the sphere
g_LoadScene.Stop();
g_captureAutoListIndex++;
g_captureAutoSphereIndex = -1;
}
}
}
else
#endif // SGC_PANORAMA
if (g_captureAutoStreamFrames == 0) // warp to next sphere
{
g_captureAutoSphereIndex = g_selectedSphereComboList[g_captureAutoListIndex];
if (!AssertVerify(g_captureAutoSphereIndex >= 0 && g_captureAutoSphereIndex < g->m_spheres.GetCount()))
{
// something happened, maybe the combo list changed?
Displayf("sphere index %d is out of range - should be [0..%d], auto capture stopped", g_captureAutoSphereIndex, g->m_spheres.GetCount() - 1);
g_captureAutoListIndex = -1;
g_captureAutoSphereIndex = -1;
return;
}
const Vec4V sphere = g->m_spheres[g_captureAutoSphereIndex].m_sphere;
WarpToSphere(g_captureAutoSphereIndex, 25.0f, false);
g_LoadScene.Start(sphere.GetXYZ(), Vec3V(V_ZERO), sphere.GetWf(), false, 0, CLoadScene::LOADSCENE_OWNER_DEBUG);
g_captureAutoStreamFrames = 1;
Displayf("teleported to sphere %d '%s' at %f,%f,%f (r=%f)", g_captureAutoSphereIndex, g->m_spheres[g_captureAutoSphereIndex].m_name.c_str(), VEC4V_ARGS(sphere));
}
else if (g_LoadScene.IsLoaded()) // warp is complete .. capture geometry
{
if (CaptureGeometryBegin())
{
CaptureGeometry(g_captureAutoSphereIndex);
CaptureGeometryEnd();
}
Displayf("captured sphere %d '%s' (streamed in %d frames)", g_captureAutoSphereIndex, g->m_spheres[g_captureAutoSphereIndex].m_name.c_str(), g_captureAutoStreamFrames);
g_captureAutoStreamFrames = 0;
#if SGC_PANORAMA
if (g_capturePanoramaEnabled)
{
g_capturePanoramaFrameIndex = 0;
g_capturePanoramaCameraFacing = 0.0f;
UpdateCameraFacing_cb();
Displayf("starting panoramic frame %d", g_capturePanoramaFrameIndex);
const Vec3V camPos = +gVpMan.GetCurrentGameGrcViewport()->GetCameraMtx().GetCol3();
const Vec3V camDir = -gVpMan.GetCurrentGameGrcViewport()->GetCameraMtx().GetCol2();
g_LoadScene.Start(camPos, camDir, 16000.0f, true, 0, CLoadScene::LOADSCENE_OWNER_DEBUG);
g_capturePanoramaAutoTimer = g_capturePanoramaAutoTimerDelay;
}
else
#endif // SGC_PANORAMA
{
g_LoadScene.Stop();
g_captureAutoListIndex++;
g_captureAutoSphereIndex = -1;
}
}
else
{
g_captureAutoStreamFrames++;
}
}
else
{
CaptureGeometryStop_button();
}
}
}
} // namespace SceneGeometryCapture
// ================================================================================================
//PARAM(SceneGeometryCapture,"");
void SceneGeometryCapture::AddWidgets()
{
//if (PARAM_SceneGeometryCapture.Get())
{
bkBank& bk = BANKMGR.CreateBank("Scene Geometry Capture");
bk.AddText("Metafile Path", &g_metafilePath[0], sizeof(g_metafilePath), false);
bk.AddButton("Load Metafile", LoadMetafile_button);
bk.AddButton("Save Metafile", SaveMetafile_button);
#if SGC_PANORAMA
bk.AddToggle("Capture Panorama Enabled", &g_capturePanoramaEnabled);
bk.AddToggle("Capture Panorama Show FPS", &g_capturePanoramaShowFPS);
bk.AddVector(" -- fps text position", &g_capturePanoramaShowFPSPos, 0.0f, 2000.0f, 1.0f);
bk.AddColor (" -- fps text colour", &g_capturePanoramaShowFPSColour);
bk.AddToggle(" -- fps background quad", &g_capturePanoramaShowFPSBkgQuad);
bk.AddSlider(" -- fps text scale", &g_capturePanoramaShowFPSScale, 1.0f, 16.0f, 1.0f/32.0f);
bk.AddSlider("Capture Panorama Steps", &g_capturePanoramaSteps, 1, 64, 1);
bk.AddSlider("Capture Panorama Delay", &g_capturePanoramaAutoTimerDelay, 0, 10, 1);
bk.AddSlider("Capture Panorama Facing", &g_capturePanoramaCameraFacing, 0.0f, 360.0f, 30.0f, UpdateCameraFacing_cb);
bk.AddText("Capture Panorama Path", &g_capturePanoramaPath[0], sizeof(g_capturePanoramaPath), false);
#endif // SGC_PANORAMA
bk.AddText("Capture Geometry Path", &g_captureGeometryPath[0], sizeof(g_captureGeometryPath), false);
bk.AddButton("Capture Geometry Start", CaptureGeometryStart_button<false>);
bk.AddButton("Capture Geometry Stop", CaptureGeometryStop_button);
bk.AddButton("Capture Geometry (selected sphere only)", CaptureGeometryStart_button<true>);//CaptureGeometrySelectedSphere_button);
bk.AddTitle("");
const char* strings[] = {""};
g_selectedSphereComboList.PushAndGrow(-1);
bk.AddText("Filter", &g_selectedSphereComboFilter[0], sizeof(g_selectedSphereComboFilter), false, UpdateCombo_cb);
g_selectedSphereCombo = bk.AddCombo("Selected Sphere", &g_selectedSphereComboIndex, NELEM(strings), strings, SelectedSphereCombo_cb);
bk.AddText("Selected Sphere Name", &g_selectedSphereName[0], sizeof(g_selectedSphereName), false, UpdateSelectedSphereName_cb);
bk.AddVector("Selected Sphere Centre", &g_selectedSphereCentre, -16000.0f, 16000.0f, 1.0f/32.0f, UpdateSelectedSphereCamera_cb);
bk.AddSlider("Selected Sphere Radius", &g_selectedSphereRadius, 0.0f, 64.0f, 1.0f/32.0f, UpdateSelectedSphere_cb);
bk.AddSlider("Selected Sphere Height", &g_selectedSphereHeight, (float)gv::WORLD_BOUNDS_MIN_Z, (float)gv::WORLD_BOUNDS_MAX_Z, 1.0f/32.0f, UpdateSelectedSphereCamera_cb);
bk.AddButton("Selected Sphere Snap to Ground", SelectedSphereSnapToGround_button);
bk.AddColor("Selected Sphere Colour", &g_selectedSphereColour, UpdateSelectedSphere_cb);
bk.AddSlider("Selected Sphere Index", &g_selectedSphereIndex, -1, SGC_MAX_SPHERES - 1, 1, UpdateSelectedSphereIndex_cb);
bk.AddTitle("");
bk.AddToggle("Warp to Camera Height", &g_warpToCameraHeight, UpdateSelectedSphereCameraHeight_cb);
bk.AddSlider("Camera Height Offset", &g_cameraHeightOffset, -100.0f, 100.0f, 1.0f/32.0f, UpdateSelectedSphereCameraHeight_cb);
bk.AddButton("Warp to Selected Sphere", WarpToSelectedSphere_button);
bk.AddButton("Warp to and Select Next", WarpToAndSelectNext_button);
bk.AddButton("Select Closest Sphere", SelectClosestSphere_button);
bk.AddButton("Add New Sphere", AddNewSphere_button);
bk.AddButton("Delete Selected Sphere", DeleteSelectedSphere_button);
bk.AddButton("Delete All Spheres", DeleteAllSpheres_button);
#if SGC_PRIVATE_RDR_STUFF
bk.AddTitle("");
bk.AddButton("*** Start Area Codes", CStreamingIteratorManager::StartAreaCodeBoundsCollection);
bk.AddButton("*** Add Area Codes", AddAreaCodeSpheres_button);
#endif // SGC_PRIVATE_RDR_STUFF
bk.AddTitle("");
bk.AddToggle("Capture Entity Type - Buildings", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_BUILDING);
bk.AddToggle("Capture Entity Type - Animated Buildings", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_ANIMATED_BUILDING);
bk.AddToggle("Capture Entity Type - Objects", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_OBJECT);
bk.AddToggle("Capture Entity Type - Dummy Objects", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_DUMMY_OBJECT);
bk.AddToggle("Capture Entity Type - MLO Interiors", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_MLO);
bk.AddToggle("Capture Entity Type - Peds", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_PED);
bk.AddToggle("Capture Entity Type - Vehicles", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_VEHICLE);
// bk.AddToggle("Capture Entity Type - Instances", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_INSTANCE_LIST);
// bk.AddToggle("Capture Entity Type - Grass Instances", &g_captureEntityPoolFlags, ENTITY_TYPE_MASK_GRASS_INSTANCE_LIST);
bk.AddSeparator("");
bk.AddToggle("Capture Entity Lod - HD", &g_captureEntityLodFlags, LODTYPES_FLAG_HD);
bk.AddToggle("Capture Entity Lod - ORPHANHD", &g_captureEntityLodFlags, LODTYPES_FLAG_ORPHANHD);
bk.AddToggle("Capture Entity Lod - LOD", &g_captureEntityLodFlags, LODTYPES_FLAG_LOD);
bk.AddToggle("Capture Entity Lod - SLOD1", &g_captureEntityLodFlags, LODTYPES_FLAG_SLOD1);
bk.AddToggle("Capture Entity Lod - SLOD2", &g_captureEntityLodFlags, LODTYPES_FLAG_SLOD2);
bk.AddToggle("Capture Entity Lod - SLOD3", &g_captureEntityLodFlags, LODTYPES_FLAG_SLOD3);
bk.AddToggle("Capture Entity Lod - SLOD4", &g_captureEntityLodFlags, LODTYPES_FLAG_SLOD4);
bk.AddSeparator("");
bk.AddToggle("Capture Drawable Lod - HIGH", &g_captureDrawableLodFlags, BIT(LOD_HIGH));
bk.AddToggle("Capture Drawable Lod - MED", &g_captureDrawableLodFlags, BIT(LOD_MED));
bk.AddToggle("Capture Drawable Lod - LOW", &g_captureDrawableLodFlags, BIT(LOD_LOW));
bk.AddToggle("Capture Drawable Lod - VLOW", &g_captureDrawableLodFlags, BIT(LOD_VLOW));
bk.AddSeparator("");
bk.AddToggle("Capture Props", &g_captureProps);
bk.AddToggle("Capture Trees", &g_captureTrees);
bk.AddToggle("Capture Alpha", &g_captureAlpha);
bk.AddToggle("Capture Water", &g_captureWater);
bk.AddToggle("Capture Decals", &g_captureDecals);
// bk.AddToggle("Capture Terrain", &g_captureTerrain);
bk.AddSeparator("");
bk.AddToggle("Capture Only Triangles Within Sphere", &g_captureClipToSpheres);
bk.AddToggle("Capture Verbose", &g_captureVerbose);
bk.AddTitle("");
bk.AddSlider("Draw Opacity", &g_drawOpacity, 0.0f, 1.0f, 1.0f/32.0f);
bk.AddSlider("Draw Dist Min", &g_drawDistanceMin, 0.0f, 16000.0f, 1.0f/8.0f);
bk.AddSlider("Draw Dist Max", &g_drawDistanceMax, 0.0f, 16000.0f, 1.0f/8.0f);
}
}
void SceneGeometryCapture::Update()
{
#if SGC_PANORAMA
if (g_capturePanoramaEnabled && g_capturePanoramaShowFPS && g_capturePanoramaShowFPSColour.GetAlpha() > 0)
{
grcDebugDraw::Text(Vector2(g_capturePanoramaShowFPSPos.GetXf(), g_capturePanoramaShowFPSPos.GetYf()), DD_ePCS_Pixels, g_capturePanoramaShowFPSColour, atVarString("FPS = %f", 1.0f/Max<float>(0.001f, fwTimer::GetSystemTimeStep())).c_str(), g_capturePanoramaShowFPSBkgQuad, g_capturePanoramaShowFPSScale, g_capturePanoramaShowFPSScale);
}
#endif // SGC_PANORAMA
CaptureGeometryUpdate();
if (g && g_drawOpacity > 0.0f)
{
#if SGC_PANORAMA
if (g_capturePanoramaEnabled)
{
return;
}
#endif // SGC_PANORAMA
const grcViewport* vp = gVpMan.GetCurrentGameGrcViewport();
const Vec3V camPos = vp->GetCameraPosition();
const Vec3V camDir = -vp->GetCameraMtx().GetCol2();
for (int i = 1; i < g_selectedSphereComboList.GetCount(); i++)
{
const int sphereIndex = g_selectedSphereComboList[i];
if (sphereIndex >= 0 && sphereIndex < g->m_spheres.GetCount())
{
const CSceneGeometryCapture::Sphere& sphere = g->m_spheres[sphereIndex];
const float dist = Max(ScalarV(V_ZERO), Mag(sphere.m_sphere.GetXYZ() - camPos) - sphere.m_sphere.GetW()).Getf();
if ((dist < g_drawDistanceMax || sphereIndex == g_selectedSphereIndex) && vp->IsSphereVisible(sphere.m_sphere))
{
float opacity = g_drawOpacity;
if (dist > g_drawDistanceMin && g_drawDistanceMin < g_drawDistanceMax && sphereIndex != g_selectedSphereIndex)
{
opacity *= (dist - g_drawDistanceMax)/(g_drawDistanceMin - g_drawDistanceMax);
}
if (sphereIndex != g_selectedSphereIndex)
{
opacity *= 0.5f;
}
Color32 colour = sphere.m_colour;
colour.SetAlpha((u8)(0.5f + (float)colour.GetAlpha()*opacity));
grcDebugDraw::Sphere(sphere.m_sphere.GetXYZ(), sphere.m_sphere.GetWf(), colour, false, 1, 16, true);
if (Dot(sphere.m_sphere.GetXYZ() - camPos, camDir).Getf() > 0.1f)
{
const Vec3V centre = sphere.m_sphere.GetXYZ();
// cross
grcDebugDraw::Line(centre - Vec3V(V_X_AXIS_WZERO), centre + Vec3V(V_X_AXIS_WZERO), Color32(255,0,0,255));
grcDebugDraw::Line(centre - Vec3V(V_Y_AXIS_WZERO), centre + Vec3V(V_Y_AXIS_WZERO), Color32(0,255,0,255));
grcDebugDraw::Line(centre, centre + Vec3V(V_Z_AXIS_WZERO), Color32(0,0,255,255));
// text
grcDebugDraw::Text(centre, colour, 0, 0, atVarString("%d. %s", sphereIndex, sphere.m_name.c_str()).c_str(), true);
}
#if RDR_VERSION
if (sphereIndex == g_selectedSphereIndex && sphere.m_areaCode[0])
{
const u32 key = ((u32)sphere.m_areaCode[0]) | (((u32)sphere.m_areaCode[1])<<8) | (((u32)sphere.m_areaCode[2])<<16);
const int numBoxes = GeomCollector::GetAreaCodeNumBoxes(key);
for (int k = 0; k < numBoxes; k++)
{
const spdAABB& box = GeomCollector::GetAreaCodeBox(key, k);
Color32 boxColour(255,255,255,255);
switch (box.GetUserInt1())
{
case 1: boxColour = Color32( 0,255, 0,255); break; // same area code from both archetype and mapdata paths (expected case)
case 2: boxColour = Color32( 0,255,255,255); break; // area code from mapdata path, no code in archetype path
case 3: boxColour = Color32(255, 0,255,255); break; // area code from archetype path, no code in mapdata path
case 4: boxColour = Color32(255,255, 0,255); break; // area code from mapdata path, different code in archetype path
case 5: boxColour = Color32(255, 0, 0,255); break; // area code from archetype path, different code in mapdata path
}
grcDebugDraw::BoxAxisAligned(box.GetMin(), box.GetMax(), boxColour, false);
grcDebugDraw::Line(sphere.m_sphere.GetXYZ(), box.GetCenter(), boxColour, boxColour); // hack for me to more easily spot crap under the map ..
}
}
#endif // RDR_VERSION
}
}
}
}
}
bool SceneGeometryCapture::IsCapturingPanorama()
{
#if SGC_PANORAMA
return g_capturePanoramaEnabled;
#else
return false;
#endif
}
bool SceneGeometryCapture::ShouldSkipEntity(const CEntity* pEntity)
{
#if SGC_PANORAMA
if (Unlikely(g_capturePanoramaEnabled))
{
if (pEntity && pEntity->GetIsTypePed())
{
return true;
}
}
#else
(void)pEntity;
#endif
return false;
}
#endif // __BANK