mirror of
https://github.com/rwengine/openrw.git
synced 2024-10-06 09:07:19 +02:00
Merge pull request #621 from danhedron/feat/use_microprofile
Use microprofile for profiling
This commit is contained in:
commit
52dbe78b4a
@ -43,6 +43,7 @@ install:
|
|||||||
- for /f %%i in ('git rev-parse HEAD') do set COMMIT_HASH=%%i
|
- for /f %%i in ('git rev-parse HEAD') do set COMMIT_HASH=%%i
|
||||||
- echo APPVEYOR_REPO_COMMIT=%APPVEYOR_REPO_COMMIT%, COMMIT_HASH=%COMMIT_HASH%
|
- echo APPVEYOR_REPO_COMMIT=%APPVEYOR_REPO_COMMIT%, COMMIT_HASH=%COMMIT_HASH%
|
||||||
- if NOT "%APPVEYOR_REPO_COMMIT%" == "%COMMIT_HASH%" echo "Appveyor git hash does not match git checkout hash"
|
- if NOT "%APPVEYOR_REPO_COMMIT%" == "%COMMIT_HASH%" echo "Appveyor git hash does not match git checkout hash"
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- ctest -VV -S "%APPVEYOR_BUILD_FOLDER%/cmake/ctest/script_ci.ctest"
|
- ctest -VV -S "%APPVEYOR_BUILD_FOLDER%/cmake/ctest/script_ci.ctest"
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "external/microprofile/microprofile"]
|
||||||
|
path = external/microprofile/microprofile
|
||||||
|
url = https://github.com/jonasmr/microprofile.git
|
@ -65,6 +65,8 @@ endif()
|
|||||||
# Create a rw_interface TARGET that holds all compiler options
|
# Create a rw_interface TARGET that holds all compiler options
|
||||||
include("${PROJECT_SOURCE_DIR}/cmake_configure.cmake")
|
include("${PROJECT_SOURCE_DIR}/cmake_configure.cmake")
|
||||||
|
|
||||||
|
add_subdirectory(external)
|
||||||
|
|
||||||
add_subdirectory(rwcore)
|
add_subdirectory(rwcore)
|
||||||
add_subdirectory(rwengine)
|
add_subdirectory(rwengine)
|
||||||
add_subdirectory(rwgame)
|
add_subdirectory(rwgame)
|
||||||
|
@ -169,6 +169,7 @@ set(_CONFIGURE_OPTIONS
|
|||||||
"-DCMAKE_BUILD_TYPE=${_CMAKE_BUILD_TYPE}"
|
"-DCMAKE_BUILD_TYPE=${_CMAKE_BUILD_TYPE}"
|
||||||
"-DENABLE_SANITIZERS=${ENABLE_SANITIZERS}"
|
"-DENABLE_SANITIZERS=${ENABLE_SANITIZERS}"
|
||||||
"-DUSE_CONAN=${USE_CONAN}"
|
"-DUSE_CONAN=${USE_CONAN}"
|
||||||
|
"-DENABLE_PROFILING=TRUE"
|
||||||
)
|
)
|
||||||
|
|
||||||
message(STATUS "Configuring...")
|
message(STATUS "Configuring...")
|
||||||
|
3
external/CMakeLists.txt
vendored
Normal file
3
external/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
if(ENABLE_PROFILING)
|
||||||
|
add_subdirectory(microprofile)
|
||||||
|
endif()
|
23
external/microprofile/CMakeLists.txt
vendored
Normal file
23
external/microprofile/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
add_library(microprofile STATIC
|
||||||
|
microprofile/microprofile.h
|
||||||
|
microprofile/microprofile_html.h
|
||||||
|
microprofile/microprofile.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(microprofile
|
||||||
|
PUBLIC
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/microprofile"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(microprofile
|
||||||
|
PUBLIC
|
||||||
|
MICROPROFILE_GPU_TIMERS=0
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
target_link_libraries(microprofile
|
||||||
|
PUBLIC
|
||||||
|
Threads::Threads
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(microprofile::microprofile ALIAS microprofile)
|
1
external/microprofile/microprofile
vendored
Submodule
1
external/microprofile/microprofile
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b49ae80262b206a579808dc3e442f0d8aafe81e9
|
@ -151,6 +151,13 @@ target_link_libraries(rwengine
|
|||||||
OpenAL::OpenAL
|
OpenAL::OpenAL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (ENABLE_PROFILING)
|
||||||
|
target_link_libraries(rwengine
|
||||||
|
PUBLIC
|
||||||
|
microprofile::microprofile
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(rwengine
|
target_include_directories(rwengine
|
||||||
PUBLIC
|
PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
@ -2,73 +2,24 @@
|
|||||||
#define _RWENGINE_PROFILER_HPP_
|
#define _RWENGINE_PROFILER_HPP_
|
||||||
|
|
||||||
#ifdef RW_PROFILER
|
#ifdef RW_PROFILER
|
||||||
#include <chrono>
|
#include <microprofile.h>
|
||||||
#include <cstdint>
|
#define RW_PROFILE_THREAD(name) MicroProfileOnThreadCreate(name)
|
||||||
#include <stack>
|
#define RW_PROFILE_FRAME_BOUNDARY() MicroProfileFlip(nullptr)
|
||||||
#include <string>
|
#define RW_PROFILE_SCOPE(label) MICROPROFILE_SCOPEI("Default", label, MP_YELLOW)
|
||||||
#include <vector>
|
#define RW_PROFILE_SCOPEC(label, colour) MICROPROFILE_SCOPEI("Default", label, colour)
|
||||||
#define time_unit std::chrono::microseconds
|
#define RW_PROFILE_COUNTER_ADD(name, qty) MICROPROFILE_COUNTER_ADD(name, qty)
|
||||||
|
#define RW_PROFILE_COUNTER_SET(name, qty) MICROPROFILE_COUNTER_SET(name, qty)
|
||||||
#include <rw/debug.hpp>
|
#define RW_TIMELINE_ENTER(name, color) MICROPROFILE_TIMELINE_ENTER_STATIC(color, name)
|
||||||
|
#define RW_TIMELINE_LEAVE(name) MICROPROFILE_TIMELINE_LEAVE_STATIC(name)
|
||||||
namespace perf {
|
|
||||||
|
|
||||||
struct ProfileEntry {
|
|
||||||
std::string label;
|
|
||||||
int64_t start;
|
|
||||||
int64_t end;
|
|
||||||
std::vector<ProfileEntry> childProfiles;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Profiler {
|
|
||||||
ProfileEntry frame;
|
|
||||||
std::chrono::high_resolution_clock::time_point frameBegin;
|
|
||||||
std::stack<ProfileEntry> currentStack;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static Profiler& get() {
|
|
||||||
static Profiler profile;
|
|
||||||
return profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProfileEntry& getFrame() const {
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void startFrame() {
|
|
||||||
frameBegin = std::chrono::high_resolution_clock::now();
|
|
||||||
frame = {"Frame", 0, 0, {}};
|
|
||||||
}
|
|
||||||
|
|
||||||
void beginEvent(const std::string& label) {
|
|
||||||
auto now = std::chrono::duration_cast<time_unit>(
|
|
||||||
std::chrono::high_resolution_clock::now() - frameBegin);
|
|
||||||
currentStack.push({label, now.count(), 0, {}});
|
|
||||||
}
|
|
||||||
|
|
||||||
void endEvent() {
|
|
||||||
auto now = std::chrono::duration_cast<time_unit>(
|
|
||||||
std::chrono::high_resolution_clock::now() - frameBegin);
|
|
||||||
RW_CHECK(currentStack.size() > 0, "Perf stack is empty");
|
|
||||||
currentStack.top().end = now.count();
|
|
||||||
if (currentStack.size() == 1) {
|
|
||||||
frame.childProfiles.push_back(currentStack.top());
|
|
||||||
currentStack.pop();
|
|
||||||
} else {
|
|
||||||
auto tmp = currentStack.top();
|
|
||||||
currentStack.pop();
|
|
||||||
currentStack.top().childProfiles.push_back(std::move(tmp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#define RW_PROFILE_FRAME_BOUNDARY() perf::Profiler::get().startFrame();
|
|
||||||
#define RW_PROFILE_BEGIN(label) perf::Profiler::get().beginEvent(label);
|
|
||||||
#define RW_PROFILE_END() perf::Profiler::get().endEvent();
|
|
||||||
#else
|
#else
|
||||||
#define RW_PROFILE_FRAME_BOUNDARY()
|
#define RW_PROFILE_THREAD(name) do {} while (0)
|
||||||
#define RW_PROFILE_BEGIN(label)
|
#define RW_PROFILE_FRAME_BOUNDARY() do {} while (0)
|
||||||
#define RW_PROFILE_END()
|
#define RW_PROFILE_SCOPE(label) do {} while (0)
|
||||||
|
#define RW_PROFILE_SCOPEC(label, colour) do {} while (0)
|
||||||
|
#define RW_PROFILE_COUNTER_ADD(name, qty) do {} while (0)
|
||||||
|
#define RW_PROFILE_COUNTER_SET(name, qty) do {} while (0)
|
||||||
|
#define RW_TIMELINE_ENTER(name, color) do {} while (0)
|
||||||
|
#define RW_TIMELINE_LEAVE(name) do {} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <rw/types.hpp>
|
#include <rw/types.hpp>
|
||||||
|
|
||||||
#include "core/Logger.hpp"
|
#include "core/Logger.hpp"
|
||||||
|
#include "core/Profiler.hpp"
|
||||||
#include "engine/GameState.hpp"
|
#include "engine/GameState.hpp"
|
||||||
#include "engine/GameWorld.hpp"
|
#include "engine/GameWorld.hpp"
|
||||||
#include "loaders/LoaderCOL.hpp"
|
#include "loaders/LoaderCOL.hpp"
|
||||||
@ -349,6 +350,7 @@ void GameData::loadWater(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameData::loadTXD(const std::string& name) {
|
void GameData::loadTXD(const std::string& name) {
|
||||||
|
RW_PROFILE_COUNTER_ADD("loadTXD", 1);
|
||||||
auto slot = name;
|
auto slot = name;
|
||||||
auto ext = name.find(".txd");
|
auto ext = name.find(".txd");
|
||||||
if (ext != std::string::npos) {
|
if (ext != std::string::npos) {
|
||||||
@ -368,6 +370,7 @@ void GameData::loadTXD(const std::string& name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextureArchive GameData::loadTextureArchive(const std::string& name) {
|
TextureArchive GameData::loadTextureArchive(const std::string& name) {
|
||||||
|
RW_PROFILE_COUNTER_ADD("loadTextureArchive", 1);
|
||||||
/// @todo refactor loadTXD to use correct file locations
|
/// @todo refactor loadTXD to use correct file locations
|
||||||
auto file = index.openFile(name);
|
auto file = index.openFile(name);
|
||||||
if (!file.data) {
|
if (!file.data) {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <data/Clump.hpp>
|
#include <data/Clump.hpp>
|
||||||
|
|
||||||
|
#include "core/Profiler.hpp"
|
||||||
#include "core/Logger.hpp"
|
#include "core/Logger.hpp"
|
||||||
|
|
||||||
#include "engine/GameData.hpp"
|
#include "engine/GameData.hpp"
|
||||||
@ -653,6 +654,7 @@ void handleInstanceResponse(InstanceObject* instance, const btManifoldPoint& mp,
|
|||||||
|
|
||||||
bool GameWorld::ContactProcessedCallback(btManifoldPoint& mp, void* body0,
|
bool GameWorld::ContactProcessedCallback(btManifoldPoint& mp, void* body0,
|
||||||
void* body1) {
|
void* body1) {
|
||||||
|
RW_PROFILE_SCOPEC(__func__, MP_GOLDENROD1);
|
||||||
auto obA = static_cast<btCollisionObject*>(body0);
|
auto obA = static_cast<btCollisionObject*>(body0);
|
||||||
auto obB = static_cast<btCollisionObject*>(body1);
|
auto obB = static_cast<btCollisionObject*>(body1);
|
||||||
|
|
||||||
@ -689,18 +691,24 @@ bool GameWorld::ContactProcessedCallback(btManifoldPoint& mp, void* body0,
|
|||||||
|
|
||||||
void GameWorld::PhysicsTickCallback(btDynamicsWorld* physWorld,
|
void GameWorld::PhysicsTickCallback(btDynamicsWorld* physWorld,
|
||||||
btScalar timeStep) {
|
btScalar timeStep) {
|
||||||
|
RW_PROFILE_SCOPEC(__func__, MP_CYAN);
|
||||||
GameWorld* world = static_cast<GameWorld*>(physWorld->getWorldUserInfo());
|
GameWorld* world = static_cast<GameWorld*>(physWorld->getWorldUserInfo());
|
||||||
|
|
||||||
|
RW_PROFILE_COUNTER_SET("physicsTick/vehiclePool", world->vehiclePool.objects.size());
|
||||||
for (auto& p : world->vehiclePool.objects) {
|
for (auto& p : world->vehiclePool.objects) {
|
||||||
|
RW_PROFILE_SCOPEC("VehicleObject", MP_THISTLE1);
|
||||||
VehicleObject* object = static_cast<VehicleObject*>(p.second);
|
VehicleObject* object = static_cast<VehicleObject*>(p.second);
|
||||||
object->tickPhysics(timeStep);
|
object->tickPhysics(timeStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RW_PROFILE_COUNTER_SET("physicsTick/pedestrianPool", world->pedestrianPool.objects.size());
|
||||||
for (auto& p : world->pedestrianPool.objects) {
|
for (auto& p : world->pedestrianPool.objects) {
|
||||||
|
RW_PROFILE_SCOPEC("CharacterObject", MP_THISTLE1);
|
||||||
CharacterObject* object = static_cast<CharacterObject*>(p.second);
|
CharacterObject* object = static_cast<CharacterObject*>(p.second);
|
||||||
object->tickPhysics(timeStep);
|
object->tickPhysics(timeStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RW_PROFILE_COUNTER_SET("physicsTick/instancePool", world->instancePool.objects.size());
|
||||||
for (auto& p : world->instancePool.objects) {
|
for (auto& p : world->instancePool.objects) {
|
||||||
InstanceObject* object = static_cast<InstanceObject*>(p.second);
|
InstanceObject* object = static_cast<InstanceObject*>(p.second);
|
||||||
object->tickPhysics(timeStep);
|
object->tickPhysics(timeStep);
|
||||||
|
@ -247,94 +247,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera,
|
|||||||
|
|
||||||
culled = 0;
|
culled = 0;
|
||||||
|
|
||||||
renderer->useProgram(worldProg.get());
|
renderObjects(world);
|
||||||
|
|
||||||
//===============================================================
|
|
||||||
// Render List Construction
|
|
||||||
//---------------------------------------------------------------
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("RenderList");
|
|
||||||
|
|
||||||
// This is sequential at the moment, it should be easy to make it
|
|
||||||
// run in parallel with a good threading system.
|
|
||||||
RenderList renderList;
|
|
||||||
// Naive optimisation, assume 50% hitrate
|
|
||||||
renderList.reserve(world->allObjects.size() * 0.5f);
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Build");
|
|
||||||
|
|
||||||
ObjectRenderer objectRenderer(_renderWorld,
|
|
||||||
(cullOverride ? cullingCamera : _camera),
|
|
||||||
_renderAlpha, getMissingTexture());
|
|
||||||
|
|
||||||
// World Objects
|
|
||||||
for (auto object : world->allObjects) {
|
|
||||||
objectRenderer.buildRenderList(object, renderList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Area indicators
|
|
||||||
auto sphereModel = getSpecialModel(ZoneCylinderA);
|
|
||||||
for (auto& i : world->getAreaIndicators()) {
|
|
||||||
glm::mat4 m(1.f);
|
|
||||||
m = glm::translate(m, i.position);
|
|
||||||
m = glm::scale(
|
|
||||||
m, glm::vec3(i.radius +
|
|
||||||
0.15f * glm::sin(_renderWorld->getGameTime() * 5.f)));
|
|
||||||
|
|
||||||
objectRenderer.renderClump(sphereModel.get(), m, nullptr, renderList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render arrows above anything that isn't radar only (or hidden)
|
|
||||||
auto arrowModel = getSpecialModel(Arrow);
|
|
||||||
for (auto& blip : world->state->radarBlips) {
|
|
||||||
auto dm = blip.second.display;
|
|
||||||
if (dm == BlipData::Hide || dm == BlipData::RadarOnly) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 model{1.0f};
|
|
||||||
|
|
||||||
if (blip.second.target > 0) {
|
|
||||||
auto object = world->getBlipTarget(blip.second);
|
|
||||||
if (object) {
|
|
||||||
model = object->getTimeAdjustedTransform(_renderAlpha);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
model = glm::translate(model, blip.second.coord);
|
|
||||||
}
|
|
||||||
|
|
||||||
float a = world->getGameTime() * glm::pi<float>();
|
|
||||||
model = glm::translate(model,
|
|
||||||
glm::vec3(0.f, 0.f, 2.5f + glm::sin(a) * 0.5f));
|
|
||||||
model = glm::rotate(model, a, glm::vec3(0.f, 0.f, 1.f));
|
|
||||||
model = glm::scale(model, glm::vec3(1.5f, 1.5f, 1.5f));
|
|
||||||
objectRenderer.renderClump(arrowModel.get(), model, nullptr, renderList);
|
|
||||||
}
|
|
||||||
|
|
||||||
RW_PROFILE_END();
|
|
||||||
culled += objectRenderer.culled;
|
|
||||||
renderer->pushDebugGroup("Objects");
|
|
||||||
renderer->pushDebugGroup("RenderList");
|
|
||||||
// Also parallelizable
|
|
||||||
RW_PROFILE_BEGIN("Sort");
|
|
||||||
// Earlier position in the array means earlier object's rendering
|
|
||||||
// Transparent objects should be sorted and rendered after opaque
|
|
||||||
std::sort(renderList.begin(), renderList.end(),
|
|
||||||
[](const Renderer::RenderInstruction& a,
|
|
||||||
const Renderer::RenderInstruction& b) {
|
|
||||||
if (a.drawInfo.blendMode==BlendMode::BLEND_NONE && b.drawInfo.blendMode!=BlendMode::BLEND_NONE) return true;
|
|
||||||
if (a.drawInfo.blendMode!=BlendMode::BLEND_NONE && b.drawInfo.blendMode==BlendMode::BLEND_NONE) return false;
|
|
||||||
return (a.sortKey > b.sortKey);
|
|
||||||
});
|
|
||||||
RW_PROFILE_END();
|
|
||||||
RW_PROFILE_BEGIN("Draw");
|
|
||||||
renderer->drawBatched(renderList);
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
renderer->popDebugGroup();
|
|
||||||
profObjects = renderer->popDebugGroup();
|
|
||||||
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
renderer->pushDebugGroup("Water");
|
renderer->pushDebugGroup("Water");
|
||||||
|
|
||||||
@ -392,6 +305,94 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera,
|
|||||||
renderPostProcess();
|
renderPostProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameRenderer::renderObjects(const GameWorld *world) {
|
||||||
|
RW_PROFILE_SCOPE(__func__);
|
||||||
|
|
||||||
|
renderer->useProgram(worldProg.get());
|
||||||
|
RenderList renderList = createObjectRenderList(world);
|
||||||
|
|
||||||
|
renderer->pushDebugGroup("Objects");
|
||||||
|
renderer->pushDebugGroup("RenderList");
|
||||||
|
renderer->drawBatched(renderList);
|
||||||
|
|
||||||
|
renderer->popDebugGroup();
|
||||||
|
profObjects = renderer->popDebugGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderList GameRenderer::createObjectRenderList(const GameWorld *world) {
|
||||||
|
RW_PROFILE_SCOPE(__func__);
|
||||||
|
// This is sequential at the moment, it should be easy to make it
|
||||||
|
// run in parallel with a good threading system.
|
||||||
|
RenderList renderList;
|
||||||
|
// Naive optimisation, assume 50% hitrate
|
||||||
|
renderList.reserve(world->allObjects.size() * 0.5f);
|
||||||
|
|
||||||
|
ObjectRenderer objectRenderer(_renderWorld,
|
||||||
|
(cullOverride ? cullingCamera : _camera),
|
||||||
|
_renderAlpha, getMissingTexture());
|
||||||
|
|
||||||
|
// World Objects
|
||||||
|
for (auto object : world->allObjects) {
|
||||||
|
objectRenderer.buildRenderList(object, renderList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Area indicators
|
||||||
|
auto sphereModel = getSpecialModel(ZoneCylinderA);
|
||||||
|
for (auto &i : world->getAreaIndicators()) {
|
||||||
|
glm::mat4 m(1.f);
|
||||||
|
m = translate(m, i.position);
|
||||||
|
m = scale(
|
||||||
|
m, glm::vec3(i.radius +
|
||||||
|
0.15f * sin(_renderWorld->getGameTime() * 5.f)));
|
||||||
|
|
||||||
|
objectRenderer.renderClump(sphereModel.get(), m, nullptr, renderList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render arrows above anything that isn't radar only (or hidden)
|
||||||
|
auto arrowModel = getSpecialModel(Arrow);
|
||||||
|
for (auto &blip : world->state->radarBlips) {
|
||||||
|
auto dm = blip.second.display;
|
||||||
|
if (dm == BlipData::Hide || dm == BlipData::RadarOnly) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 model{1.0f};
|
||||||
|
|
||||||
|
if (blip.second.target > 0) {
|
||||||
|
auto object = world->getBlipTarget(blip.second);
|
||||||
|
if (object) {
|
||||||
|
model = object->getTimeAdjustedTransform(_renderAlpha);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
model = translate(model, blip.second.coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
float a = world->getGameTime() * glm::pi<float>();
|
||||||
|
model = translate(model,
|
||||||
|
glm::vec3(0.f, 0.f, 2.5f + sin(a) * 0.5f));
|
||||||
|
model = rotate(model, a, glm::vec3(0.f, 0.f, 1.f));
|
||||||
|
model = scale(model, glm::vec3(1.5f, 1.5f, 1.5f));
|
||||||
|
objectRenderer.renderClump(arrowModel.get(), model, nullptr, renderList);
|
||||||
|
}
|
||||||
|
culled += objectRenderer.culled;
|
||||||
|
|
||||||
|
RW_PROFILE_SCOPE("sortRenderList");
|
||||||
|
// Also parallelizable
|
||||||
|
// Earlier position in the array means earlier object's rendering
|
||||||
|
// Transparent objects should be sorted and rendered after opaque
|
||||||
|
sort(renderList.begin(), renderList.end(),
|
||||||
|
[](const Renderer::RenderInstruction &a,
|
||||||
|
const Renderer::RenderInstruction &b) {
|
||||||
|
if (a.drawInfo.blendMode == BlendMode::BLEND_NONE && b.drawInfo.blendMode != BlendMode::BLEND_NONE)
|
||||||
|
return true;
|
||||||
|
if (a.drawInfo.blendMode != BlendMode::BLEND_NONE && b.drawInfo.blendMode == BlendMode::BLEND_NONE)
|
||||||
|
return false;
|
||||||
|
return (a.sortKey > b.sortKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
return renderList;
|
||||||
|
}
|
||||||
|
|
||||||
void GameRenderer::renderSplash(GameWorld* world, GLuint splashTexName, glm::u16vec3 fc) {
|
void GameRenderer::renderSplash(GameWorld* world, GLuint splashTexName, glm::u16vec3 fc) {
|
||||||
float fadeTimer = world->getGameTime() - world->state->fadeStart;
|
float fadeTimer = world->getGameTime() - world->state->fadeStart;
|
||||||
|
|
||||||
|
@ -172,6 +172,10 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void drawRect(const glm::vec4& colour, TextureData* texture, glm::vec4& extents);
|
void drawRect(const glm::vec4& colour, TextureData* texture, glm::vec4& extents);
|
||||||
|
|
||||||
|
void renderObjects(const GameWorld *world);
|
||||||
|
|
||||||
|
RenderList createObjectRenderList(const GameWorld *world);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include <core/Profiler.hpp>
|
||||||
#include <gl/DrawBuffer.hpp>
|
#include <gl/DrawBuffer.hpp>
|
||||||
#include <rw/debug.hpp>
|
#include <rw/debug.hpp>
|
||||||
|
|
||||||
@ -123,7 +124,7 @@ void OpenGLRenderer::useDrawBuffer(DrawBuffer* dbuff) {
|
|||||||
glBindVertexArray(dbuff->getVAOName());
|
glBindVertexArray(dbuff->getVAOName());
|
||||||
currentDbuff = dbuff;
|
currentDbuff = dbuff;
|
||||||
bufferCounter++;
|
bufferCounter++;
|
||||||
#ifdef RW_PROFILER
|
#ifdef RW_GRAPHICS_STATS
|
||||||
if (currentDebugDepth > 0) {
|
if (currentDebugDepth > 0) {
|
||||||
profileInfo[currentDebugDepth - 1].buffers++;
|
profileInfo[currentDebugDepth - 1].buffers++;
|
||||||
}
|
}
|
||||||
@ -140,7 +141,7 @@ void OpenGLRenderer::useTexture(GLuint unit, GLuint tex) {
|
|||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
currentTextures[unit] = tex;
|
currentTextures[unit] = tex;
|
||||||
textureCounter++;
|
textureCounter++;
|
||||||
#ifdef RW_PROFILER
|
#ifdef RW_GRAPHICS_STATS
|
||||||
if (currentDebugDepth > 0) {
|
if (currentDebugDepth > 0) {
|
||||||
profileInfo[currentDebugDepth - 1].textures++;
|
profileInfo[currentDebugDepth - 1].textures++;
|
||||||
}
|
}
|
||||||
@ -286,7 +287,7 @@ void OpenGLRenderer::setDrawState(const glm::mat4& model, DrawBuffer* draw,
|
|||||||
uploadUBO(UBOObject, objectData);
|
uploadUBO(UBOObject, objectData);
|
||||||
|
|
||||||
drawCounter++;
|
drawCounter++;
|
||||||
#ifdef RW_PROFILER
|
#ifdef RW_GRAPHICS_STATS
|
||||||
if (currentDebugDepth > 0) {
|
if (currentDebugDepth > 0) {
|
||||||
profileInfo[currentDebugDepth - 1].draws++;
|
profileInfo[currentDebugDepth - 1].draws++;
|
||||||
profileInfo[currentDebugDepth - 1].primitives += p.count;
|
profileInfo[currentDebugDepth - 1].primitives += p.count;
|
||||||
@ -310,6 +311,7 @@ void OpenGLRenderer::drawArrays(const glm::mat4& model, DrawBuffer* draw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::drawBatched(const RenderList& list) {
|
void OpenGLRenderer::drawBatched(const RenderList& list) {
|
||||||
|
RW_PROFILE_SCOPE(__func__);
|
||||||
#if 0 // Needs shader changes
|
#if 0 // Needs shader changes
|
||||||
// Determine how many batches we need to process the entire list
|
// Determine how many batches we need to process the entire list
|
||||||
auto entries = list.size();
|
auto entries = list.size();
|
||||||
@ -416,7 +418,7 @@ void OpenGLRenderer::uploadUBOEntry(Buffer &buffer, const void *data, size_t siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::pushDebugGroup(const std::string& title) {
|
void OpenGLRenderer::pushDebugGroup(const std::string& title) {
|
||||||
#ifdef RW_PROFILER
|
#ifdef RW_GRAPHICS_STATS
|
||||||
if (ogl_ext_KHR_debug) {
|
if (ogl_ext_KHR_debug) {
|
||||||
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, title.c_str());
|
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, title.c_str());
|
||||||
ProfileInfo& prof = profileInfo[currentDebugDepth];
|
ProfileInfo& prof = profileInfo[currentDebugDepth];
|
||||||
@ -435,7 +437,7 @@ void OpenGLRenderer::pushDebugGroup(const std::string& title) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Renderer::ProfileInfo& OpenGLRenderer::popDebugGroup() {
|
const Renderer::ProfileInfo& OpenGLRenderer::popDebugGroup() {
|
||||||
#ifdef RW_PROFILER
|
#ifdef RW_GRAPHICS_STATS
|
||||||
if (ogl_ext_KHR_debug) {
|
if (ogl_ext_KHR_debug) {
|
||||||
glPopDebugGroup();
|
glPopDebugGroup();
|
||||||
currentDebugDepth--;
|
currentDebugDepth--;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "ai/PlayerController.hpp"
|
#include "ai/PlayerController.hpp"
|
||||||
#include "core/Logger.hpp"
|
#include "core/Logger.hpp"
|
||||||
|
#include "core/Profiler.hpp"
|
||||||
#include "engine/GameState.hpp"
|
#include "engine/GameState.hpp"
|
||||||
#include "engine/GameWorld.hpp"
|
#include "engine/GameWorld.hpp"
|
||||||
#include "script/SCMFile.hpp"
|
#include "script/SCMFile.hpp"
|
||||||
@ -226,6 +227,7 @@ SCMByte* ScriptMachine::getGlobals() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScriptMachine::execute(float dt) {
|
void ScriptMachine::execute(float dt) {
|
||||||
|
RW_PROFILE_SCOPEC(__func__, MP_ORANGERED);
|
||||||
int ms = dt * 1000.f;
|
int ms = dt * 1000.f;
|
||||||
for (auto t = _activeThreads.begin(); t != _activeThreads.end(); ++t) {
|
for (auto t = _activeThreads.begin(); t != _activeThreads.end(); ++t) {
|
||||||
auto& thread = *t;
|
auto& thread = *t;
|
||||||
|
@ -45,6 +45,9 @@ RWGame::RWGame(Logger& log, int argc, char* argv[])
|
|||||||
: GameBase(log, argc, argv)
|
: GameBase(log, argc, argv)
|
||||||
, data(&log, config.getGameDataPath())
|
, data(&log, config.getGameDataPath())
|
||||||
, renderer(&log, &data) {
|
, renderer(&log, &data) {
|
||||||
|
RW_PROFILE_THREAD("Main");
|
||||||
|
RW_TIMELINE_ENTER("Startup", MP_YELLOW);
|
||||||
|
|
||||||
bool newgame = options.count("newgame");
|
bool newgame = options.count("newgame");
|
||||||
bool test = options.count("test");
|
bool test = options.count("test");
|
||||||
std::string startSave(
|
std::string startSave(
|
||||||
@ -106,6 +109,7 @@ RWGame::RWGame(Logger& log, int argc, char* argv[])
|
|||||||
});
|
});
|
||||||
|
|
||||||
log.info("Game", "Started");
|
log.info("Game", "Started");
|
||||||
|
RW_TIMELINE_LEAVE("Startup");
|
||||||
}
|
}
|
||||||
|
|
||||||
RWGame::~RWGame() {
|
RWGame::~RWGame() {
|
||||||
@ -365,46 +369,9 @@ int RWGame::run() {
|
|||||||
bool running = true;
|
bool running = true;
|
||||||
while (StateManager::currentState() && running) {
|
while (StateManager::currentState() && running) {
|
||||||
RW_PROFILE_FRAME_BOUNDARY();
|
RW_PROFILE_FRAME_BOUNDARY();
|
||||||
|
RW_PROFILE_SCOPE("Main Loop");
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Input");
|
running = updateInput();
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_PollEvent(&event)) {
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_QUIT:
|
|
||||||
running = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
|
||||||
switch (event.window.event) {
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
|
||||||
inFocus = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
|
||||||
inFocus = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
globalKeyEvent(event);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_MOUSEMOTION:
|
|
||||||
event.motion.xrel *= MOUSE_SENSITIVITY_SCALE;
|
|
||||||
event.motion.yrel *= MOUSE_SENSITIVITY_SCALE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameInput::updateGameInputState(&getState()->input[0], event);
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("State");
|
|
||||||
if (StateManager::currentState()) {
|
|
||||||
StateManager::currentState()->handleEvent(event);
|
|
||||||
}
|
|
||||||
RW_PROFILE_END()
|
|
||||||
}
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
auto currentFrame = chrono::steady_clock::now();
|
auto currentFrame = chrono::steady_clock::now();
|
||||||
auto frameTime =
|
auto frameTime =
|
||||||
@ -419,48 +386,10 @@ int RWGame::run() {
|
|||||||
frameTime = 0.1f;
|
frameTime = 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto deltaTimeWithTimeScale =
|
accumulatedTime = tickWorld(deltaTime, accumulatedTime);
|
||||||
deltaTime * world->state->basic.timeScale;
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Update");
|
|
||||||
while (accumulatedTime >= deltaTime) {
|
|
||||||
if (!StateManager::currentState()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("physics");
|
|
||||||
world->dynamicsWorld->stepSimulation(
|
|
||||||
deltaTimeWithTimeScale, kMaxPhysicsSubSteps, deltaTime);
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("state");
|
|
||||||
StateManager::get().tick(deltaTimeWithTimeScale);
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("engine");
|
|
||||||
tick(deltaTimeWithTimeScale);
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
getState()->swapInputState();
|
|
||||||
|
|
||||||
accumulatedTime -= deltaTime;
|
|
||||||
}
|
|
||||||
RW_PROFILE_END();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Render");
|
|
||||||
RW_PROFILE_BEGIN("engine");
|
|
||||||
render(1, frameTime);
|
render(1, frameTime);
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("state");
|
|
||||||
if (StateManager::currentState()) {
|
|
||||||
StateManager::get().draw(&renderer);
|
|
||||||
}
|
|
||||||
RW_PROFILE_END();
|
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
renderProfile();
|
|
||||||
|
|
||||||
getWindow().swap();
|
getWindow().swap();
|
||||||
|
|
||||||
@ -475,7 +404,75 @@ int RWGame::run() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float RWGame::tickWorld(const float deltaTime, float accumulatedTime) {
|
||||||
|
RW_PROFILE_SCOPEC(__func__, MP_GREEN);
|
||||||
|
auto deltaTimeWithTimeScale =
|
||||||
|
deltaTime * world->state->basic.timeScale;
|
||||||
|
|
||||||
|
while (accumulatedTime >= deltaTime) {
|
||||||
|
if (!StateManager::currentState()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RW_PROFILE_SCOPEC("stepSimulation", MP_DARKORANGE1);
|
||||||
|
world->dynamicsWorld->stepSimulation(
|
||||||
|
deltaTimeWithTimeScale, kMaxPhysicsSubSteps, deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
StateManager::get().tick(deltaTimeWithTimeScale);
|
||||||
|
|
||||||
|
tick(deltaTimeWithTimeScale);
|
||||||
|
|
||||||
|
getState()->swapInputState();
|
||||||
|
|
||||||
|
accumulatedTime -= deltaTime;
|
||||||
|
}
|
||||||
|
return accumulatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RWGame::updateInput() {
|
||||||
|
RW_PROFILE_SCOPE(__func__);
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_QUIT:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
switch (event.window.event) {
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
|
inFocus = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||||
|
inFocus = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
globalKeyEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
event.motion.xrel *= MOUSE_SENSITIVITY_SCALE;
|
||||||
|
event.motion.yrel *= MOUSE_SENSITIVITY_SCALE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameInput::updateGameInputState(&getState()->input[0], event);
|
||||||
|
|
||||||
|
if (StateManager::currentState()) {
|
||||||
|
RW_PROFILE_SCOPE("State");
|
||||||
|
StateManager::currentState()->handleEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void RWGame::tick(float dt) {
|
void RWGame::tick(float dt) {
|
||||||
|
RW_PROFILE_SCOPE(__func__);
|
||||||
State* currState = StateManager::get().states.back().get();
|
State* currState = StateManager::get().states.back().get();
|
||||||
|
|
||||||
static float clockAccumulator = 0.f;
|
static float clockAccumulator = 0.f;
|
||||||
@ -527,22 +524,7 @@ void RWGame::tick(float dt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
world->updateEffects();
|
tickObjects(dt);
|
||||||
|
|
||||||
for (auto& object : world->allObjects) {
|
|
||||||
object->_updateLastTransform();
|
|
||||||
object->tick(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& g : world->garages) {
|
|
||||||
g->tick(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& p : world->payphones) {
|
|
||||||
p->tick(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
world->destroyQueuedObjects();
|
|
||||||
|
|
||||||
state.text.tick(dt);
|
state.text.tick(dt);
|
||||||
|
|
||||||
@ -570,7 +552,39 @@ void RWGame::tick(float dt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RWGame::tickObjects(float dt) const {
|
||||||
|
RW_PROFILE_SCOPEC(__func__, MP_MAGENTA1);
|
||||||
|
world->updateEffects();
|
||||||
|
|
||||||
|
{
|
||||||
|
RW_PROFILE_SCOPEC("allObjects", MP_HOTPINK1);
|
||||||
|
RW_PROFILE_COUNTER_SET("tickObjects/allObjects", world->allObjects.size());
|
||||||
|
for (auto &object : world->allObjects) {
|
||||||
|
object->_updateLastTransform();
|
||||||
|
object->tick(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RW_PROFILE_SCOPEC("garages", MP_HOTPINK2);
|
||||||
|
for (auto &g : world->garages) {
|
||||||
|
g->tick(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
RW_PROFILE_SCOPEC("payphones", MP_HOTPINK3);
|
||||||
|
for (auto &p : world->payphones) {
|
||||||
|
p->tick(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
world->destroyQueuedObjects();
|
||||||
|
}
|
||||||
|
|
||||||
void RWGame::render(float alpha, float time) {
|
void RWGame::render(float alpha, float time) {
|
||||||
|
RW_PROFILE_SCOPEC(__func__, MP_CORNFLOWERBLUE);
|
||||||
|
|
||||||
lastDraws = getRenderer().getRenderer()->getDrawCount();
|
lastDraws = getRenderer().getRenderer()->getDrawCount();
|
||||||
|
|
||||||
getRenderer().getRenderer()->swap();
|
getRenderer().getRenderer()->swap();
|
||||||
@ -599,13 +613,22 @@ void RWGame::render(float alpha, float time) {
|
|||||||
|
|
||||||
renderer.getRenderer()->pushDebugGroup("World");
|
renderer.getRenderer()->pushDebugGroup("World");
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("world");
|
|
||||||
renderer.renderWorld(world.get(), viewCam, alpha);
|
renderer.renderWorld(world.get(), viewCam, alpha);
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
renderer.getRenderer()->popDebugGroup();
|
renderer.getRenderer()->popDebugGroup();
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("debug");
|
renderDebugView(time, viewCam);
|
||||||
|
|
||||||
|
if (!world->isPaused()) drawOnScreenText(world.get(), &renderer);
|
||||||
|
|
||||||
|
if (StateManager::currentState()) {
|
||||||
|
RW_PROFILE_SCOPE("state");
|
||||||
|
StateManager::get().draw(&renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGame::renderDebugView(float time, ViewCamera &viewCam) {
|
||||||
|
RW_PROFILE_SCOPE(__func__);
|
||||||
switch (debugview_) {
|
switch (debugview_) {
|
||||||
case DebugViewMode::General:
|
case DebugViewMode::General:
|
||||||
renderDebugStats(time);
|
renderDebugStats(time);
|
||||||
@ -623,9 +646,6 @@ void RWGame::render(float alpha, float time) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
RW_PROFILE_END();
|
|
||||||
|
|
||||||
if (!world->isPaused()) drawOnScreenText(world.get(), &renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RWGame::renderDebugStats(float time) {
|
void RWGame::renderDebugStats(float time) {
|
||||||
@ -836,55 +856,6 @@ void RWGame::renderDebugObjects(float time, ViewCamera& camera) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RWGame::renderProfile() {
|
|
||||||
#ifdef RW_PROFILER
|
|
||||||
auto& frame = perf::Profiler::get().getFrame();
|
|
||||||
constexpr float upperlimit = 30000.f;
|
|
||||||
constexpr float lineHeight = 15.f;
|
|
||||||
static std::vector<glm::vec4> perf_colours;
|
|
||||||
if (perf_colours.size() == 0) {
|
|
||||||
float c = 8.f;
|
|
||||||
for (int r = 0; r < c; ++r) {
|
|
||||||
for (int g = 0; g < c; ++g) {
|
|
||||||
for (int b = 0; b < c; ++b) {
|
|
||||||
perf_colours.emplace_back(r / c, g / c, b / c, 1.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float xscale = renderer.getRenderer()->getViewport().x / upperlimit;
|
|
||||||
TextRenderer::TextInfo ti;
|
|
||||||
ti.align = TextRenderer::TextInfo::TextAlignment::Left;
|
|
||||||
ti.font = FONT_ARIAL;
|
|
||||||
ti.size = lineHeight - 2.f;
|
|
||||||
ti.baseColour = glm::u8vec3(255);
|
|
||||||
std::function<void(const perf::ProfileEntry&, int)> renderEntry =
|
|
||||||
[&](const perf::ProfileEntry& entry, int depth) {
|
|
||||||
int g = 0;
|
|
||||||
for (auto& event : entry.childProfiles) {
|
|
||||||
auto duration = event.end - event.start;
|
|
||||||
float y = 60.f + (depth * (lineHeight + 5.f));
|
|
||||||
renderer.drawColour(
|
|
||||||
perf_colours[(std::hash<std::string>()(entry.label) *
|
|
||||||
(g++)) %
|
|
||||||
perf_colours.size()],
|
|
||||||
{xscale * event.start, y, xscale * duration, lineHeight});
|
|
||||||
ti.screenPosition.x = xscale * (event.start);
|
|
||||||
ti.screenPosition.y = y + 2.f;
|
|
||||||
ti.text = GameStringUtil::fromString(
|
|
||||||
event.label + " " + std::to_string(duration) + " us ", ti.font);
|
|
||||||
renderer.text.renderText(ti);
|
|
||||||
renderEntry(event, depth + 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
renderEntry(frame, 0);
|
|
||||||
ti.screenPosition = glm::vec2(xscale * (16000), 40.f);
|
|
||||||
ti.text = GameStringUtil::fromString(".16 ms", ti.font);
|
|
||||||
renderer.text.renderText(ti);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void RWGame::globalKeyEvent(const SDL_Event& event) {
|
void RWGame::globalKeyEvent(const SDL_Event& event) {
|
||||||
const auto toggle_debug = [&](DebugViewMode m) {
|
const auto toggle_debug = [&](DebugViewMode m) {
|
||||||
debugview_ = debugview_ == m ? DebugViewMode::Disabled : m;
|
debugview_ = debugview_ == m ? DebugViewMode::Disabled : m;
|
||||||
|
@ -128,11 +128,18 @@ private:
|
|||||||
void renderDebugStats(float time);
|
void renderDebugStats(float time);
|
||||||
void renderDebugPaths(float time);
|
void renderDebugPaths(float time);
|
||||||
void renderDebugObjects(float time, ViewCamera& camera);
|
void renderDebugObjects(float time, ViewCamera& camera);
|
||||||
void renderProfile();
|
|
||||||
|
|
||||||
void handleCheatInput(char symbol);
|
void handleCheatInput(char symbol);
|
||||||
|
|
||||||
void globalKeyEvent(const SDL_Event& event);
|
void globalKeyEvent(const SDL_Event& event);
|
||||||
|
|
||||||
|
bool updateInput();
|
||||||
|
|
||||||
|
float tickWorld(const float deltaTime, float accumulatedTime);
|
||||||
|
|
||||||
|
void renderDebugView(float time, ViewCamera &viewCam);
|
||||||
|
|
||||||
|
void tickObjects(float dt) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user