mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-25 11:52:40 +01:00
commit
c7d77084c2
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "external/microprofile/microprofile"]
|
[submodule "external/microprofile/microprofile"]
|
||||||
path = external/microprofile/microprofile
|
path = external/microprofile/microprofile
|
||||||
url = https://github.com/jonasmr/microprofile.git
|
url = https://github.com/jonasmr/microprofile.git
|
||||||
|
[submodule "imgui"]
|
||||||
|
path = external/imgui/imgui
|
||||||
|
url = https://github.com/ocornut/imgui.git
|
||||||
|
2
external/CMakeLists.txt
vendored
2
external/CMakeLists.txt
vendored
@ -1,3 +1,5 @@
|
|||||||
if(ENABLE_PROFILING)
|
if(ENABLE_PROFILING)
|
||||||
add_subdirectory(microprofile)
|
add_subdirectory(microprofile)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(imgui)
|
||||||
|
63
external/imgui/CMakeLists.txt
vendored
Normal file
63
external/imgui/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
add_library(imgui EXCLUDE_FROM_ALL
|
||||||
|
rw_imconfig.h
|
||||||
|
imgui/imgui.h
|
||||||
|
imgui/imgui.cpp
|
||||||
|
imgui/imgui_demo.cpp
|
||||||
|
imgui/imgui_draw.cpp
|
||||||
|
imgui/imgui_internal.h
|
||||||
|
imgui/imgui_widgets.cpp
|
||||||
|
imgui/imstb_rectpack.h
|
||||||
|
imgui/imstb_textedit.h
|
||||||
|
imgui/imstb_truetype.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(imgui SYSTEM
|
||||||
|
PUBLIC
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/imgui"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(imgui
|
||||||
|
PUBLIC
|
||||||
|
IMGUI_USER_CONFIG="${CMAKE_CURRENT_SOURCE_DIR}/rw_imconfig.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(imgui
|
||||||
|
PUBLIC
|
||||||
|
openrw::checks
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(imgui::core ALIAS imgui)
|
||||||
|
|
||||||
|
openrw_target_apply_options(
|
||||||
|
TARGET imgui
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(imgui_sdl_gl3 EXCLUDE_FROM_ALL
|
||||||
|
imgui/examples/imgui_impl_opengl3.h
|
||||||
|
imgui/examples/imgui_impl_opengl3.cpp
|
||||||
|
imgui/examples/imgui_impl_sdl.h
|
||||||
|
imgui/examples/imgui_impl_sdl.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(imgui_sdl_gl3 SYSTEM
|
||||||
|
PUBLIC
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/imgui/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(imgui_sdl_gl3
|
||||||
|
PUBLIC
|
||||||
|
imgui::core
|
||||||
|
SDL2::SDL2
|
||||||
|
)
|
||||||
|
|
||||||
|
# FIXME: extract gl loader to target + add property to get header
|
||||||
|
target_compile_definitions(imgui_sdl_gl3
|
||||||
|
PRIVATE
|
||||||
|
"IMGUI_IMPL_OPENGL_LOADER_CUSTOM=\"${OpenRW_SOURCE_DIR}/rwcore/gl/gl_core_3_3.h\""
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(imgui::sdl_gl3 ALIAS imgui_sdl_gl3)
|
||||||
|
|
||||||
|
openrw_target_apply_options(
|
||||||
|
TARGET imgui_sdl_gl3
|
||||||
|
)
|
1
external/imgui/imgui
vendored
Submodule
1
external/imgui/imgui
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 801645d35092c8da0eeabe71d7c1997c47aa3648
|
9
external/imgui/rw_imconfig.h
vendored
Normal file
9
external/imgui/rw_imconfig.h
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef RW_IMCONFIG_H
|
||||||
|
#define RW_IMCONFIG_H
|
||||||
|
|
||||||
|
// Disable imgui assertions when not in debug mode
|
||||||
|
#ifndef RW_DEBUG
|
||||||
|
#define IM_ASSERT(MSG) //FIXME(madebr): remove comment
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RW_IMCONFIG_H
|
@ -19,7 +19,7 @@ public:
|
|||||||
, rotation(rot) {
|
, rotation(rot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 getView() {
|
glm::mat4 getView() const {
|
||||||
auto up = rotation * glm::vec3(0.f, 0.f, 1.f);
|
auto up = rotation * glm::vec3(0.f, 0.f, 1.f);
|
||||||
return glm::lookAt(position,
|
return glm::lookAt(position,
|
||||||
position + rotation * glm::vec3(1.f, 0.f, 0.f), up);
|
position + rotation * glm::vec3(1.f, 0.f, 0.f), up);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
glm::mat4 ViewFrustum::projection() {
|
glm::mat4 ViewFrustum::projection() const {
|
||||||
return glm::perspective(fov / aspectRatio, aspectRatio, near, far);
|
return glm::perspective(fov / aspectRatio, aspectRatio, near, far);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
: near(near), far(far), fov(fov), aspectRatio(aspect) {
|
: near(near), far(far), fov(fov), aspectRatio(aspect) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 projection();
|
glm::mat4 projection() const;
|
||||||
|
|
||||||
void update(const glm::mat4& proj);
|
void update(const glm::mat4& proj);
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ add_library(librwgame STATIC
|
|||||||
GameWindow.hpp
|
GameWindow.hpp
|
||||||
GameWindow.cpp
|
GameWindow.cpp
|
||||||
|
|
||||||
|
RWImGui.cpp
|
||||||
|
RWImGui.hpp
|
||||||
|
|
||||||
HUDDrawer.hpp
|
HUDDrawer.hpp
|
||||||
HUDDrawer.cpp
|
HUDDrawer.cpp
|
||||||
MenuSystem.hpp
|
MenuSystem.hpp
|
||||||
@ -68,6 +71,16 @@ target_link_libraries(librwgame
|
|||||||
SDL2::SDL2
|
SDL2::SDL2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(librwgame
|
||||||
|
PUBLIC
|
||||||
|
RW_IMGUI
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(librwgame
|
||||||
|
PUBLIC
|
||||||
|
imgui::sdl_gl3
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(rwgame
|
add_executable(rwgame
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,7 @@ GameBase::GameBase(Logger &inlog, const std::optional<RWArgConfigLayer> &args) :
|
|||||||
bool fullscreen = config.fullscreen();
|
bool fullscreen = config.fullscreen();
|
||||||
size_t w = config.width(), h = config.height();
|
size_t w = config.width(), h = config.height();
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
|
||||||
throw std::runtime_error("Failed to initialize SDL2!");
|
throw std::runtime_error("Failed to initialize SDL2!");
|
||||||
|
|
||||||
window.create(kWindowTitle + " [" + kBuildStr + "]", w, h, fullscreen);
|
window.create(kWindowTitle + " [" + kBuildStr + "]", w, h, fullscreen);
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
class GameWindow {
|
class GameWindow {
|
||||||
SDL_Window* window = nullptr;
|
SDL_Window* window = nullptr;
|
||||||
@ -30,6 +31,10 @@ public:
|
|||||||
bool isOpen() const {
|
bool isOpen() const {
|
||||||
return !!window;
|
return !!window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<SDL_Window *, SDL_GLContext> getSDLContext() {
|
||||||
|
return std::make_tuple(window, glcontext);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
|
#include "RWImGui.hpp"
|
||||||
#include "GameInput.hpp"
|
#include "GameInput.hpp"
|
||||||
#include "State.hpp"
|
#include "State.hpp"
|
||||||
#include "StateManager.hpp"
|
#include "StateManager.hpp"
|
||||||
@ -28,7 +29,6 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable : 4305 5033)
|
#pragma warning(disable : 4305 5033)
|
||||||
@ -54,7 +54,8 @@ constexpr float kMaxPhysicsSubSteps = 2;
|
|||||||
RWGame::RWGame(Logger& log, const std::optional<RWArgConfigLayer> &args)
|
RWGame::RWGame(Logger& log, const std::optional<RWArgConfigLayer> &args)
|
||||||
: GameBase(log, args)
|
: GameBase(log, args)
|
||||||
, data(&log, config.gamedataPath())
|
, data(&log, config.gamedataPath())
|
||||||
, renderer(&log, &data) {
|
, renderer(&log, &data)
|
||||||
|
, imgui(*this) {
|
||||||
RW_PROFILE_THREAD("Main");
|
RW_PROFILE_THREAD("Main");
|
||||||
RW_TIMELINE_ENTER("Startup", MP_YELLOW);
|
RW_TIMELINE_ENTER("Startup", MP_YELLOW);
|
||||||
|
|
||||||
@ -76,6 +77,8 @@ RWGame::RWGame(Logger& log, const std::optional<RWArgConfigLayer> &args)
|
|||||||
config.gamedataPath());
|
config.gamedataPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui.init();
|
||||||
|
|
||||||
data.load();
|
data.load();
|
||||||
|
|
||||||
for (const auto& [specialModel, fileName, name] : kSpecialModels) {
|
for (const auto& [specialModel, fileName, name] : kSpecialModels) {
|
||||||
@ -480,6 +483,9 @@ bool RWGame::updateInput() {
|
|||||||
RW_PROFILE_SCOPE(__func__);
|
RW_PROFILE_SCOPE(__func__);
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
|
if (imgui.processEvent(event)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
return false;
|
return false;
|
||||||
@ -628,10 +634,12 @@ void RWGame::tickObjects(float dt) const {
|
|||||||
|
|
||||||
void RWGame::render(float alpha, float time) {
|
void RWGame::render(float alpha, float time) {
|
||||||
RW_PROFILE_SCOPEC(__func__, MP_CORNFLOWERBLUE);
|
RW_PROFILE_SCOPEC(__func__, MP_CORNFLOWERBLUE);
|
||||||
|
RW_UNUSED(time);
|
||||||
|
|
||||||
lastDraws = getRenderer().getRenderer().getDrawCount();
|
lastDraws = getRenderer().getRenderer().getDrawCount();
|
||||||
|
|
||||||
getRenderer().getRenderer().swap();
|
getRenderer().getRenderer().swap();
|
||||||
|
imgui.startFrame();
|
||||||
|
|
||||||
// Update the camera
|
// Update the camera
|
||||||
if (!stateManager.states.empty()) {
|
if (!stateManager.states.empty()) {
|
||||||
@ -661,7 +669,7 @@ void RWGame::render(float alpha, float time) {
|
|||||||
|
|
||||||
renderer.getRenderer().popDebugGroup();
|
renderer.getRenderer().popDebugGroup();
|
||||||
|
|
||||||
renderDebugView(time, viewCam);
|
renderDebugView();
|
||||||
|
|
||||||
if (!world->isPaused()) hudDrawer.drawOnScreenText(world.get(), renderer);
|
if (!world->isPaused()) hudDrawer.drawOnScreenText(world.get(), renderer);
|
||||||
|
|
||||||
@ -669,98 +677,26 @@ void RWGame::render(float alpha, float time) {
|
|||||||
RW_PROFILE_SCOPE("state");
|
RW_PROFILE_SCOPE("state");
|
||||||
stateManager.draw(renderer);
|
stateManager.draw(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui.endFrame(viewCam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RWGame::renderDebugView(float time, ViewCamera &viewCam) {
|
void RWGame::renderDebugView() {
|
||||||
RW_PROFILE_SCOPE(__func__);
|
RW_PROFILE_SCOPE(__func__);
|
||||||
switch (debugview_) {
|
switch (debugview_) {
|
||||||
case DebugViewMode::General:
|
|
||||||
renderDebugStats(time);
|
|
||||||
break;
|
|
||||||
case DebugViewMode::Physics:
|
case DebugViewMode::Physics:
|
||||||
world->dynamicsWorld->debugDrawWorld();
|
world->dynamicsWorld->debugDrawWorld();
|
||||||
debug.flush(renderer);
|
debug.flush(renderer);
|
||||||
break;
|
break;
|
||||||
case DebugViewMode::Navigation:
|
case DebugViewMode::Navigation:
|
||||||
renderDebugPaths(time);
|
renderDebugPaths();
|
||||||
break;
|
|
||||||
case DebugViewMode::Objects:
|
|
||||||
renderDebugObjects(time, viewCam);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RWGame::renderDebugStats(float time) {
|
void RWGame::renderDebugPaths() {
|
||||||
// Turn time into milliseconds
|
|
||||||
float time_ms = time * 1000.f;
|
|
||||||
constexpr size_t average_every_frame = 15;
|
|
||||||
static float times[average_every_frame];
|
|
||||||
static size_t times_index = 0;
|
|
||||||
static float time_average = 0;
|
|
||||||
times[times_index++] = time_ms;
|
|
||||||
if (times_index >= average_every_frame) {
|
|
||||||
times_index = 0;
|
|
||||||
time_average = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < average_every_frame; ++i) {
|
|
||||||
time_average += times[i];
|
|
||||||
}
|
|
||||||
time_average /= average_every_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "FPS: " << (1000.f / time_average) << " (" << time_average << "ms)\n"
|
|
||||||
<< "Frame: " << time_ms << "ms\n"
|
|
||||||
<< "Draws/Culls/Textures/Buffers: " << lastDraws << "/"
|
|
||||||
<< renderer.getCulledCount() << "/"
|
|
||||||
<< renderer.getRenderer().getTextureCount() << "/"
|
|
||||||
<< renderer.getRenderer().getBufferCount() << "\n"
|
|
||||||
<< "Timescale: " << world->state->basic.timeScale;
|
|
||||||
|
|
||||||
TextRenderer::TextInfo ti;
|
|
||||||
ti.font = FONT_ARIAL;
|
|
||||||
ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
|
|
||||||
ti.screenPosition = glm::vec2(10.f, 10.f);
|
|
||||||
ti.size = 15.f;
|
|
||||||
ti.baseColour = glm::u8vec3(255);
|
|
||||||
renderer.text.renderText(ti);
|
|
||||||
|
|
||||||
/*while( engine->log.size() > 0 && engine->log.front().time + 10.f <
|
|
||||||
engine->gameTime ) {
|
|
||||||
engine->log.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
ti.screenPosition = glm::vec2( 10.f, 500.f );
|
|
||||||
ti.size = 15.f;
|
|
||||||
for(auto it = engine->log.begin(); it != engine->log.end(); ++it) {
|
|
||||||
ti.text = it->message;
|
|
||||||
switch(it->type) {
|
|
||||||
case GameWorld::LogEntry::Error:
|
|
||||||
ti.baseColour = glm::vec3(1.f, 0.f, 0.f);
|
|
||||||
break;
|
|
||||||
case GameWorld::LogEntry::Warning:
|
|
||||||
ti.baseColour = glm::vec3(1.f, 1.f, 0.f);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ti.baseColour = glm::vec3(1.f, 1.f, 1.f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolate the color
|
|
||||||
// c.a = (engine->gameTime - it->time > 5.f) ? 255 - (((engine->gameTime
|
|
||||||
- it->time) - 5.f)/5.f) * 255 : 255;
|
|
||||||
// text.setColor(c);
|
|
||||||
|
|
||||||
engine->renderer.text.renderText(ti);
|
|
||||||
ti.screenPosition.y -= ti.size;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void RWGame::renderDebugPaths(float time) {
|
|
||||||
RW_UNUSED(time);
|
|
||||||
|
|
||||||
btVector3 roadColour(1.f, 0.f, 0.f);
|
btVector3 roadColour(1.f, 0.f, 0.f);
|
||||||
btVector3 pedColour(0.f, 0.f, 1.f);
|
btVector3 pedColour(0.f, 0.f, 1.f);
|
||||||
|
|
||||||
@ -864,74 +800,6 @@ void RWGame::renderDebugPaths(float time) {
|
|||||||
debug.flush(renderer);
|
debug.flush(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RWGame::renderDebugObjects(float time, ViewCamera& camera) {
|
|
||||||
RW_UNUSED(time);
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
ss << "Models: " << data.modelinfo.size() << "\n"
|
|
||||||
<< "Dynamic Objects:\n"
|
|
||||||
<< " Vehicles: " << world->vehiclePool.objects.size() << "\n"
|
|
||||||
<< " Peds: " << world->pedestrianPool.objects.size() << "\n";
|
|
||||||
|
|
||||||
TextRenderer::TextInfo ti;
|
|
||||||
ti.font = FONT_ARIAL;
|
|
||||||
ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
|
|
||||||
ti.screenPosition = glm::vec2(10.f, 10.f);
|
|
||||||
ti.size = 15.f;
|
|
||||||
ti.baseColour = glm::u8vec3(255);
|
|
||||||
renderer.text.renderText(ti);
|
|
||||||
|
|
||||||
// Render worldspace overlay for nearby objects
|
|
||||||
constexpr float kNearbyDistance = 25.f;
|
|
||||||
const auto& view = camera.position;
|
|
||||||
const auto& model = camera.getView();
|
|
||||||
const auto& proj = camera.frustum.projection();
|
|
||||||
const auto& size = getWindow().getSize();
|
|
||||||
glm::vec4 viewport(0.f, 0.f, size.x, size.y);
|
|
||||||
auto isnearby = [&](GameObject* o) {
|
|
||||||
return glm::distance2(o->getPosition(), view) <
|
|
||||||
kNearbyDistance * kNearbyDistance;
|
|
||||||
};
|
|
||||||
auto showdata = [&](GameObject* o, std::stringstream& ss) {
|
|
||||||
auto screen = glm::project(o->getPosition(), model, proj, viewport);
|
|
||||||
if (screen.z >= 1.f) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
|
|
||||||
screen.y = viewport.w - screen.y;
|
|
||||||
ti.screenPosition = glm::vec2(screen);
|
|
||||||
ti.size = 10.f;
|
|
||||||
renderer.text.renderText(ti);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto& p : world->vehiclePool.objects) {
|
|
||||||
if (!isnearby(p.second.get())) continue;
|
|
||||||
auto v = static_cast<VehicleObject*>(p.second.get());
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << v->getVehicle()->vehiclename_ << "\n"
|
|
||||||
<< (v->isFlipped() ? "Flipped" : "Upright") << "\n"
|
|
||||||
<< (v->isStopped() ? "Stopped" : "Moving") << "\n"
|
|
||||||
<< v->getVelocity() << "m/s\n";
|
|
||||||
|
|
||||||
showdata(v, ss);
|
|
||||||
}
|
|
||||||
for (auto& p : world->pedestrianPool.objects) {
|
|
||||||
if (!isnearby(p.second.get())) continue;
|
|
||||||
auto c = static_cast<CharacterObject*>(p.second.get());
|
|
||||||
const auto& state = c->getCurrentState();
|
|
||||||
auto act = c->controller->getCurrentActivity();
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Health: " << state.health << " (" << state.armour << ")\n"
|
|
||||||
<< (c->isAlive() ? "Alive" : "Dead") << "\n"
|
|
||||||
<< "Activity: " << (act ? act->name() : "Idle") << "\n";
|
|
||||||
|
|
||||||
showdata(c, ss);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "GameBase.hpp"
|
#include "GameBase.hpp"
|
||||||
#include "HUDDrawer.hpp"
|
#include "HUDDrawer.hpp"
|
||||||
|
#include "RWConfig.hpp"
|
||||||
|
#include "RWImGui.hpp"
|
||||||
#include "StateManager.hpp"
|
#include "StateManager.hpp"
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
|
|
||||||
@ -20,8 +22,19 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
class RWGame final : public GameBase {
|
class RWGame final : public GameBase {
|
||||||
|
public:
|
||||||
|
enum class DebugViewMode {
|
||||||
|
Disabled,
|
||||||
|
General,
|
||||||
|
Physics,
|
||||||
|
Navigation,
|
||||||
|
Objects
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
GameData data;
|
GameData data;
|
||||||
GameRenderer renderer;
|
GameRenderer renderer;
|
||||||
|
RWImGui imgui;
|
||||||
DebugDraw debug;
|
DebugDraw debug;
|
||||||
GameState state;
|
GameState state;
|
||||||
HUDDrawer hudDrawer{};
|
HUDDrawer hudDrawer{};
|
||||||
@ -37,14 +50,6 @@ class RWGame final : public GameBase {
|
|||||||
bool inFocus = true;
|
bool inFocus = true;
|
||||||
ViewCamera currentCam;
|
ViewCamera currentCam;
|
||||||
|
|
||||||
enum class DebugViewMode {
|
|
||||||
Disabled,
|
|
||||||
General,
|
|
||||||
Physics,
|
|
||||||
Navigation,
|
|
||||||
Objects
|
|
||||||
};
|
|
||||||
|
|
||||||
DebugViewMode debugview_ = DebugViewMode::Disabled;
|
DebugViewMode debugview_ = DebugViewMode::Disabled;
|
||||||
int lastDraws{0}; /// Number of draws issued for the last frame.
|
int lastDraws{0}; /// Number of draws issued for the last frame.
|
||||||
|
|
||||||
@ -89,6 +94,10 @@ public:
|
|||||||
return hudDrawer;
|
return hudDrawer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DebugViewMode getDebugViewMode() const {
|
||||||
|
return debugview_;
|
||||||
|
}
|
||||||
|
|
||||||
bool hitWorldRay(glm::vec3& hit, glm::vec3& normal,
|
bool hitWorldRay(glm::vec3& hit, glm::vec3& normal,
|
||||||
GameObject** object = nullptr);
|
GameObject** object = nullptr);
|
||||||
|
|
||||||
@ -109,9 +118,7 @@ private:
|
|||||||
void tick(float dt);
|
void tick(float dt);
|
||||||
void render(float alpha, float dt);
|
void render(float alpha, float dt);
|
||||||
|
|
||||||
void renderDebugStats(float time);
|
void renderDebugPaths();
|
||||||
void renderDebugPaths(float time);
|
|
||||||
void renderDebugObjects(float time, ViewCamera& camera);
|
|
||||||
|
|
||||||
void handleCheatInput(char symbol);
|
void handleCheatInput(char symbol);
|
||||||
|
|
||||||
@ -121,7 +128,7 @@ private:
|
|||||||
|
|
||||||
float tickWorld(const float deltaTime, float accumulatedTime);
|
float tickWorld(const float deltaTime, float accumulatedTime);
|
||||||
|
|
||||||
void renderDebugView(float time, ViewCamera &viewCam);
|
void renderDebugView();
|
||||||
|
|
||||||
void tickObjects(float dt) const;
|
void tickObjects(float dt) const;
|
||||||
};
|
};
|
||||||
|
204
rwgame/RWImGui.cpp
Normal file
204
rwgame/RWImGui.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
#include "RWImGui.hpp"
|
||||||
|
|
||||||
|
#include <ai/CharacterController.hpp>
|
||||||
|
#include <objects/CharacterObject.hpp>
|
||||||
|
#include <objects/VehicleObject.hpp>
|
||||||
|
|
||||||
|
#include "RWGame.hpp"
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_impl_sdl.h>
|
||||||
|
#include <imgui_impl_opengl3.h>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <gl/gl_core_3_3.h>
|
||||||
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void WindowDebugStats(RWGame& game) {
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
auto time_ms = 1000.0f / io.Framerate;
|
||||||
|
constexpr size_t average_every_frame = 240;
|
||||||
|
static float times[average_every_frame];
|
||||||
|
static size_t times_index = 0;
|
||||||
|
static double time_average = 0, time_min = 0, time_max = 0;
|
||||||
|
times[times_index++] = time_ms;
|
||||||
|
if (times_index >= average_every_frame) {
|
||||||
|
times_index = 0;
|
||||||
|
time_average = 0;
|
||||||
|
time_min = std::numeric_limits<double>::max();
|
||||||
|
time_max = std::numeric_limits<double>::lowest();
|
||||||
|
|
||||||
|
for (double time : times) {
|
||||||
|
time_average += time;
|
||||||
|
time_min = std::min(time, time_min);
|
||||||
|
time_max = std::max(time, time_max);
|
||||||
|
}
|
||||||
|
time_average /= average_every_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& world = game.getWorld();
|
||||||
|
auto& renderer = game.getRenderer();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos({20.f, 20.f});
|
||||||
|
ImGui::Begin("Engine Information", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoInputs);
|
||||||
|
ImGui::Text("%.3f ms/frame (%.1f FPS)\n%.3f / %.3f / %.3f ms",
|
||||||
|
static_cast<double>(1000.0f / io.Framerate),
|
||||||
|
static_cast<double>(io.Framerate), time_average, time_min,
|
||||||
|
time_max);
|
||||||
|
ImGui::Text("Timescale %.2f",
|
||||||
|
static_cast<double>(world->state->basic.timeScale));
|
||||||
|
ImGui::Text("%i Drawn %lu Culled", renderer.getRenderer().getDrawCount(),
|
||||||
|
renderer.getCulledCount());
|
||||||
|
ImGui::Text("%i Textures %i Buffers",
|
||||||
|
renderer.getRenderer().getTextureCount(),
|
||||||
|
renderer.getRenderer().getBufferCount());
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowDebugObjects(RWGame& game, const ViewCamera& camera) {
|
||||||
|
auto& data = game.getGameData();
|
||||||
|
auto world = game.getWorld();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos({20.f, 20.f});
|
||||||
|
ImGui::Begin("Object Information", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoInputs);
|
||||||
|
ImGui::Text("%lu Models", data.modelinfo.size());
|
||||||
|
ImGui::Text("Dynamic Objects\n %lu Vehicles\n %lu Peds",
|
||||||
|
world->vehiclePool.objects.size(),
|
||||||
|
world->pedestrianPool.objects.size());
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
// Render worldspace overlay for nearby objects
|
||||||
|
constexpr float kNearbyDistance = 25.f;
|
||||||
|
const auto& view = camera.position;
|
||||||
|
const auto& model = camera.getView();
|
||||||
|
const auto& proj = camera.frustum.projection();
|
||||||
|
const auto& size = game.getWindow().getSize();
|
||||||
|
glm::vec4 viewport(0.f, 0.f, size.x, size.y);
|
||||||
|
auto isnearby = [&](GameObject* o) {
|
||||||
|
return glm::distance2(o->getPosition(), view) <
|
||||||
|
kNearbyDistance * kNearbyDistance;
|
||||||
|
};
|
||||||
|
auto showdata = [&](GameObject* o, std::stringstream& ss) {
|
||||||
|
auto screen = glm::project(o->getPosition(), model, proj, viewport);
|
||||||
|
if (screen.z >= 1.f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ImGui::SetNextWindowPos({screen.x, viewport.w - screen.y}, 0,
|
||||||
|
{0.5f, 0.5f});
|
||||||
|
ImGui::Begin(
|
||||||
|
std::to_string(reinterpret_cast<uintptr_t>(o)).c_str(), nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |
|
||||||
|
ImGuiWindowFlags_NoInputs);
|
||||||
|
ImGui::Text("%s", ss.str().c_str());
|
||||||
|
ImGui::End();
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto& p : world->vehiclePool.objects) {
|
||||||
|
if (!isnearby(p.second.get())) continue;
|
||||||
|
auto v = static_cast<VehicleObject*>(p.second.get());
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << v->getVehicle()->vehiclename_ << "\n"
|
||||||
|
<< (v->isFlipped() ? "Flipped" : "Upright") << "\n"
|
||||||
|
<< (v->isStopped() ? "Stopped" : "Moving") << "\n"
|
||||||
|
<< v->getVelocity() << "m/s\n";
|
||||||
|
|
||||||
|
showdata(v, ss);
|
||||||
|
}
|
||||||
|
for (auto& p : world->pedestrianPool.objects) {
|
||||||
|
if (!isnearby(p.second.get())) continue;
|
||||||
|
auto c = static_cast<CharacterObject*>(p.second.get());
|
||||||
|
const auto& state = c->getCurrentState();
|
||||||
|
auto act = c->controller->getCurrentActivity();
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Health: " << state.health << " (" << state.armour << ")\n"
|
||||||
|
<< (c->isAlive() ? "Alive" : "Dead") << "\n"
|
||||||
|
<< "Activity: " << (act ? act->name() : "Idle") << "\n";
|
||||||
|
|
||||||
|
showdata(c, ss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
RWImGui::RWImGui(RWGame &game)
|
||||||
|
: _game(game) {
|
||||||
|
}
|
||||||
|
|
||||||
|
RWImGui::~RWImGui() {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWImGui::init() {
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
_context = ImGui::CreateContext();
|
||||||
|
|
||||||
|
auto [window, context] = _game.getWindow().getSDLContext();
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_InitForOpenGL(window, context);
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 150");
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWImGui::destroy() {
|
||||||
|
if (!_context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ImGui::SetCurrentContext(_context);
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
ImGui_ImplSDL2_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
_context = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RWImGui::processEvent(SDL_Event& event) {
|
||||||
|
if (!_context) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ImGui::SetCurrentContext(_context);
|
||||||
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
return io.WantCaptureMouse || io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWImGui::startFrame() {
|
||||||
|
if (!_context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ImGui::SetCurrentContext(_context);
|
||||||
|
|
||||||
|
auto [window, sdl_glcontext] = _game.getWindow().getSDLContext();
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplSDL2_NewFrame(window);
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWImGui::endFrame(const ViewCamera& camera) {
|
||||||
|
switch (_game.getDebugViewMode()) {
|
||||||
|
case RWGame::DebugViewMode::General:
|
||||||
|
WindowDebugStats(_game);
|
||||||
|
break;
|
||||||
|
case RWGame::DebugViewMode::Objects:
|
||||||
|
WindowDebugObjects(_game, camera);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool show_demo_window = false;
|
||||||
|
if (show_demo_window) {
|
||||||
|
ImGui::ShowDemoWindow(&show_demo_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
}
|
23
rwgame/RWImGui.hpp
Normal file
23
rwgame/RWImGui.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef RWGAME_RWIMGUI_HPP
|
||||||
|
#define RWGAME_RWIMGUI_HPP
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
class RWGame;
|
||||||
|
struct ImGuiContext;
|
||||||
|
class ViewCamera;
|
||||||
|
|
||||||
|
class RWImGui {
|
||||||
|
RWGame &_game;
|
||||||
|
ImGuiContext *_context = nullptr;
|
||||||
|
public:
|
||||||
|
RWImGui(RWGame &game);
|
||||||
|
~RWImGui();
|
||||||
|
void init();
|
||||||
|
void destroy();
|
||||||
|
bool processEvent(SDL_Event &event);
|
||||||
|
void startFrame();
|
||||||
|
void endFrame(const ViewCamera &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RWGAME_RWIMGUI_HPP
|
@ -17,10 +17,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
constexpr float kDebugEntryHeight = 14.f;
|
#include <imgui.h>
|
||||||
constexpr float kDebugEntryHeightMissions = 12.f;
|
|
||||||
constexpr int kDebugFont = 2;
|
|
||||||
const glm::vec2 kDebugMenuOffset = glm::vec2(10.f, 50.f);
|
|
||||||
|
|
||||||
static void jumpCharacter(RWGame* game, CharacterObject* player,
|
static void jumpCharacter(RWGame* game, CharacterObject* player,
|
||||||
const glm::vec3& target, bool ground = true) {
|
const glm::vec3& target, bool ground = true) {
|
||||||
@ -38,126 +35,133 @@ static void jumpCharacter(RWGame* game, CharacterObject* player,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu DebugState::createDebugMenu() {
|
void DebugState::drawDebugMenu() {
|
||||||
CharacterObject* player = nullptr;
|
CharacterObject* player = nullptr;
|
||||||
if (game->getWorld()->getPlayer()) {
|
if (game->getWorld()->getPlayer()) {
|
||||||
player = game->getWorld()->getPlayer()->getCharacter();
|
player = game->getWorld()->getPlayer()->getCharacter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu menu{
|
ImGui::Begin("Debug Tools");
|
||||||
{{"Jump to Debug Camera",
|
|
||||||
[=] {
|
|
||||||
jumpCharacter(game, player,
|
|
||||||
_debugCam.position +
|
|
||||||
_debugCam.rotation * glm::vec3(3.f, 0.f, 0.f),
|
|
||||||
false);
|
|
||||||
}},
|
|
||||||
{"-Map", [=] { setNextMenu(createMapMenu()); }},
|
|
||||||
{"-Vehicles", [=] { setNextMenu(createVehicleMenu()); }},
|
|
||||||
{"-AI", [=] { setNextMenu(createAIMenu()); }},
|
|
||||||
{"-Weapons", [=] { setNextMenu(createWeaponMenu()); }},
|
|
||||||
{"-Weather", [=] { setNextMenu(createWeatherMenu()); }},
|
|
||||||
{"-Missions", [=] { setNextMenu(createMissionsMenu()); }},
|
|
||||||
{"Set Super Jump", [=] { player->setJumpSpeed(20.f); }},
|
|
||||||
{"Set Normal Jump",
|
|
||||||
[=] { player->setJumpSpeed(CharacterObject::DefaultJumpSpeed); }},
|
|
||||||
{"Full Health", [=] { player->getCurrentState().health = 100.f; }},
|
|
||||||
{"Full Armour", [=] { player->getCurrentState().armour = 100.f; }},
|
|
||||||
{"Cull Here",
|
|
||||||
[=] { game->getRenderer().setCullOverride(true, _debugCam); }}},
|
|
||||||
kDebugMenuOffset,
|
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeight};
|
|
||||||
|
|
||||||
// Optional block if the player is in a vehicle
|
if (player && ImGui::BeginMenu("Game")) {
|
||||||
auto cv = player->getCurrentVehicle();
|
if (ImGui::MenuItem("Set Super Jump")) {
|
||||||
if (cv) {
|
player->setJumpSpeed(20.f);
|
||||||
menu.lambda("Flip vehicle", [=] {
|
}
|
||||||
cv->setRotation(cv->getRotation() *
|
if (ImGui::MenuItem("Set Normal Jump")) {
|
||||||
glm::quat(glm::vec3(0.f, glm::pi<float>(), 0.f)));
|
player->setJumpSpeed(CharacterObject::DefaultJumpSpeed);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Full Health")) {
|
||||||
|
player->getCurrentState().health = 100.f;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Full Armour")) {
|
||||||
|
player->getCurrentState().armour = 100.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional block if the player is in a vehicle
|
||||||
|
if (auto cv = player->getCurrentVehicle(); cv) {
|
||||||
|
if (ImGui::MenuItem("Flip Vehicle")) {
|
||||||
|
cv->setRotation(
|
||||||
|
cv->getRotation() *
|
||||||
|
glm::quat(glm::vec3(0.f, glm::pi<float>(), 0.f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Cull Here")) {
|
||||||
|
game->getRenderer().setCullOverride(true, _debugCam);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
if (ImGui::BeginMenu("Map")) {
|
||||||
|
drawMapMenu();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Vehicle")) {
|
||||||
|
drawVehicleMenu();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("AI")) {
|
||||||
|
drawAIMenu();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Weapons")) {
|
||||||
|
drawWeaponMenu();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Weather")) {
|
||||||
|
drawWeatherMenu();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Missions")) {
|
||||||
|
drawMissionsMenu();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu DebugState::createMapMenu() {
|
void DebugState::drawMapMenu() {
|
||||||
CharacterObject* player = nullptr;
|
CharacterObject* player = nullptr;
|
||||||
if (game->getWorld()->getPlayer()) {
|
if (game->getWorld()->getPlayer()) {
|
||||||
player = game->getWorld()->getPlayer()->getCharacter();
|
player = game->getWorld()->getPlayer()->getCharacter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu menu{
|
if (ImGui::MenuItem("Jump to Debug Camera")) {
|
||||||
{{"Back", [=] { setNextMenu(createDebugMenu()); }},
|
jumpCharacter(
|
||||||
{"Jump to Docks",
|
game, player,
|
||||||
[=] {
|
_debugCam.position + _debugCam.rotation * glm::vec3(3.f, 0.f, 0.f),
|
||||||
jumpCharacter(game, player, glm::vec3(1390.f, -837.f, 100.f));
|
false);
|
||||||
}},
|
}
|
||||||
{"Jump to Garage",
|
|
||||||
[=] { jumpCharacter(game, player, glm::vec3(270.f, -605.f, 40.f)); }},
|
|
||||||
{"Jump to Airport",
|
|
||||||
[=] {
|
|
||||||
jumpCharacter(game, player, glm::vec3(-950.f, -980.f, 12.f));
|
|
||||||
}},
|
|
||||||
{"Jump to Hideout",
|
|
||||||
[=] {
|
|
||||||
jumpCharacter(game, player, glm::vec3(875.0, -309.0, 100.0));
|
|
||||||
}},
|
|
||||||
{"Jump to Luigi's",
|
|
||||||
[=] {
|
|
||||||
jumpCharacter(game, player, glm::vec3(902.75, -425.56, 100.0));
|
|
||||||
}},
|
|
||||||
{"Jump to Hospital",
|
|
||||||
[=] {
|
|
||||||
jumpCharacter(game, player, glm::vec3(1123.77, -569.15, 100.0));
|
|
||||||
}},
|
|
||||||
{"Unsolid garage doors",
|
|
||||||
[=] {
|
|
||||||
static constexpr std::array<char const*, 33> garageDoorModels{
|
|
||||||
{"8ballsuburbandoor", "amcogaragedoor",
|
|
||||||
"bankjobdoor", "bombdoor",
|
|
||||||
"crushercrush", "crushertop",
|
|
||||||
"door2_garage", "door3_garage",
|
|
||||||
"door4_garage", "door_bombshop",
|
|
||||||
"door_col_compnd_01", "door_col_compnd_02",
|
|
||||||
"door_col_compnd_03", "door_col_compnd_04",
|
|
||||||
"door_col_compnd_05", "door_jmsgrage",
|
|
||||||
"door_sfehousegrge", "double_garage_dr",
|
|
||||||
"impex_door", "impexpsubgrgdoor",
|
|
||||||
"ind_plyrwoor", "ind_slidedoor",
|
|
||||||
"jamesgrge_kb", "leveldoor2",
|
|
||||||
"oddjgaragdoor", "plysve_gragedoor",
|
|
||||||
"SalvGarage", "shedgaragedoor",
|
|
||||||
"Sub_sprayshopdoor", "towergaragedoor1",
|
|
||||||
"towergaragedoor2", "towergaragedoor3",
|
|
||||||
"vheistlocdoor"}};
|
|
||||||
|
|
||||||
auto gw = game->getWorld();
|
const std::vector<std::tuple<const char*, glm::vec3>> kInterestingPlaces{
|
||||||
for (auto& [id, instancePtr] : gw->instancePool.objects) {
|
{"Docks", {1390.f, -837.f, 100.f}},
|
||||||
auto obj = static_cast<InstanceObject*>(instancePtr.get());
|
{"Garage", {270.f, -605.f, 40.f}},
|
||||||
if (std::find(garageDoorModels.begin(),
|
{"Airport", {-950.f, -980.f, 12.f}},
|
||||||
garageDoorModels.end(),
|
{"Hideout", {875.0, -309.0, 100.0}},
|
||||||
obj->getModelInfo<BaseModelInfo>()->name) !=
|
{"Luigi's", {902.75, -425.56, 100.0}},
|
||||||
garageDoorModels.end()) {
|
{"Hospital", {1123.77, -569.15, 100.0}},
|
||||||
obj->setSolid(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}},
|
|
||||||
kDebugMenuOffset,
|
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeight};
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
Menu DebugState::createVehicleMenu() {
|
|
||||||
Menu menu{
|
|
||||||
{{"Back", [=] { setNextMenu(createDebugMenu()); }}},
|
|
||||||
kDebugMenuOffset,
|
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeight,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (const auto& [name, pos] : kInterestingPlaces) {
|
||||||
|
if (ImGui::MenuItem((std::string("Jump to ") + name).c_str())) {
|
||||||
|
jumpCharacter(game, player, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Unsolid Garage Doors")) {
|
||||||
|
static constexpr std::array<char const*, 33> garageDoorModels{
|
||||||
|
{"8ballsuburbandoor", "amcogaragedoor", "bankjobdoor",
|
||||||
|
"bombdoor", "crushercrush", "crushertop",
|
||||||
|
"door2_garage", "door3_garage", "door4_garage",
|
||||||
|
"door_bombshop", "door_col_compnd_01", "door_col_compnd_02",
|
||||||
|
"door_col_compnd_03", "door_col_compnd_04", "door_col_compnd_05",
|
||||||
|
"door_jmsgrage", "door_sfehousegrge", "double_garage_dr",
|
||||||
|
"impex_door", "impexpsubgrgdoor", "ind_plyrwoor",
|
||||||
|
"ind_slidedoor", "jamesgrge_kb", "leveldoor2",
|
||||||
|
"oddjgaragdoor", "plysve_gragedoor", "SalvGarage",
|
||||||
|
"shedgaragedoor", "Sub_sprayshopdoor", "towergaragedoor1",
|
||||||
|
"towergaragedoor2", "towergaragedoor3", "vheistlocdoor"}};
|
||||||
|
|
||||||
|
auto gw = game->getWorld();
|
||||||
|
for (auto& [id, instancePtr] : gw->instancePool.objects) {
|
||||||
|
auto obj = static_cast<InstanceObject*>(instancePtr.get());
|
||||||
|
if (std::find(garageDoorModels.begin(), garageDoorModels.end(),
|
||||||
|
obj->getModelInfo<BaseModelInfo>()->name) !=
|
||||||
|
garageDoorModels.end()) {
|
||||||
|
obj->setSolid(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugState::drawVehicleMenu() {
|
||||||
static constexpr std::array<std::tuple<char const*, unsigned int>, 19>
|
static constexpr std::array<std::tuple<char const*, unsigned int>, 19>
|
||||||
kVehicleTypes{{{"Landstalker", 90},
|
kVehicleTypes{{{"Landstalker", 90},
|
||||||
{"Taxi", 110},
|
{"Taxi", 110},
|
||||||
@ -180,18 +184,13 @@ Menu DebugState::createVehicleMenu() {
|
|||||||
{"Infernus", 101}}};
|
{"Infernus", 101}}};
|
||||||
|
|
||||||
for (const auto& [name, id] : kVehicleTypes) {
|
for (const auto& [name, id] : kVehicleTypes) {
|
||||||
menu.lambda(name, [this, id = id] { spawnVehicle(id); });
|
if (ImGui::MenuItem(name)) {
|
||||||
|
spawnVehicle(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu DebugState::createAIMenu() {
|
void DebugState::drawAIMenu() {
|
||||||
Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}},
|
|
||||||
kDebugMenuOffset,
|
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeight};
|
|
||||||
|
|
||||||
static constexpr std::array<std::tuple<char const*, unsigned int>, 6>
|
static constexpr std::array<std::tuple<char const*, unsigned int>, 6>
|
||||||
kPedTypes{{
|
kPedTypes{{
|
||||||
{"Triad", 12},
|
{"Triad", 12},
|
||||||
@ -203,10 +202,12 @@ Menu DebugState::createAIMenu() {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
for (const auto& [name, id] : kPedTypes) {
|
for (const auto& [name, id] : kPedTypes) {
|
||||||
menu.lambda(name, [this, id = id] { spawnFollower(id); });
|
if (ImGui::MenuItem(name)) {
|
||||||
|
spawnFollower(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.lambda("Kill All Peds", [=] {
|
if (ImGui::MenuItem("Kill All Peds")) {
|
||||||
for (auto& [id, pedestrianPtr] :
|
for (auto& [id, pedestrianPtr] :
|
||||||
game->getWorld()->pedestrianPool.objects) {
|
game->getWorld()->pedestrianPool.objects) {
|
||||||
if (pedestrianPtr->getLifetime() == GameObject::PlayerLifetime) {
|
if (pedestrianPtr->getLifetime() == GameObject::PlayerLifetime) {
|
||||||
@ -220,47 +221,31 @@ Menu DebugState::createAIMenu() {
|
|||||||
0.f
|
0.f
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu DebugState::createWeaponMenu() {
|
void DebugState::drawWeaponMenu() {
|
||||||
Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}},
|
|
||||||
kDebugMenuOffset,
|
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeight};
|
|
||||||
|
|
||||||
for (int i = 1; i < kMaxInventorySlots; ++i) {
|
for (int i = 1; i < kMaxInventorySlots; ++i) {
|
||||||
auto& name = getWorld()->data->weaponData[i].name;
|
auto& name = getWorld()->data->weaponData[i].name;
|
||||||
menu.lambda(name, [=] { giveItem(i); });
|
if (ImGui::MenuItem(name.c_str())) {
|
||||||
|
giveItem(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu DebugState::createWeatherMenu() {
|
void DebugState::drawWeatherMenu() {
|
||||||
Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}},
|
static constexpr std::array<char const*, 4> w{
|
||||||
kDebugMenuOffset,
|
{"Sunny", "Cloudy", "Rainy", "Foggy"}};
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeight};
|
|
||||||
|
|
||||||
static constexpr std::array<char const*, 4> w{{"Sunny", "Cloudy", "Rainy", "Foggy"}};
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < w.size(); ++i) {
|
for (std::size_t i = 0; i < w.size(); ++i) {
|
||||||
menu.lambda(w[i],
|
if (ImGui::MenuItem(w[i])) {
|
||||||
[=] { game->getWorld()->state->basic.nextWeather = static_cast<std::uint16_t>(i); });
|
game->getWorld()->state->basic.nextWeather =
|
||||||
|
static_cast<std::uint16_t>(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu DebugState::createMissionsMenu() {
|
void DebugState::drawMissionsMenu() {
|
||||||
Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}},
|
|
||||||
kDebugMenuOffset,
|
|
||||||
kDebugFont,
|
|
||||||
kDebugEntryHeightMissions};
|
|
||||||
|
|
||||||
static constexpr std::array<char const*, 80> w{{
|
static constexpr std::array<char const*, 80> w{{
|
||||||
"Intro Movie",
|
"Intro Movie",
|
||||||
"Hospital Info Scene",
|
"Hospital Info Scene",
|
||||||
@ -345,7 +330,7 @@ Menu DebugState::createMissionsMenu() {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
for (std::size_t i = 0; i < w.size(); ++i) {
|
for (std::size_t i = 0; i < w.size(); ++i) {
|
||||||
menu.lambda(w[i], [=] {
|
if (ImGui::MenuItem(w[i])) {
|
||||||
ScriptMachine* vm = game->getScriptVM();
|
ScriptMachine* vm = game->getScriptVM();
|
||||||
|
|
||||||
if (vm) {
|
if (vm) {
|
||||||
@ -367,16 +352,12 @@ Menu DebugState::createMissionsMenu() {
|
|||||||
|
|
||||||
vm->startThread(offsets[i], true);
|
vm->startThread(offsets[i], true);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugState::DebugState(RWGame* game, const glm::vec3& vp, const glm::quat& vd)
|
DebugState::DebugState(RWGame* game, const glm::vec3& vp, const glm::quat& vd)
|
||||||
: State(game), _invertedY(game->getConfig().invertY()) {
|
: State(game), _invertedY(game->getConfig().invertY()) {
|
||||||
this->setNextMenu(createDebugMenu());
|
|
||||||
|
|
||||||
_debugCam.position = vp;
|
_debugCam.position = vp;
|
||||||
_debugCam.rotation = vd;
|
_debugCam.rotation = vd;
|
||||||
}
|
}
|
||||||
@ -400,19 +381,18 @@ void DebugState::tick(float dt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugState::draw(GameRenderer& r) {
|
void DebugState::draw(GameRenderer& r) {
|
||||||
// Draw useful information like camera position.
|
ImGui::SetNextWindowPos({20.f, 20.f});
|
||||||
std::stringstream ss;
|
ImGui::Begin("Debug Info", nullptr,
|
||||||
ss << "Camera Position: " << glm::to_string(_debugCam.position) << "\n";
|
ImGuiWindowFlags_NoDecoration |
|
||||||
auto zone = getWorld()->data->findZoneAt(_debugCam.position);
|
ImGuiWindowFlags_NoSavedSettings |
|
||||||
ss << (zone ? zone->name : "No Zone") << "\n";
|
ImGuiWindowFlags_NoInputs);
|
||||||
|
|
||||||
TextRenderer::TextInfo ti;
|
ImGui::Text("Camera: %s", glm::to_string(_debugCam.position).c_str());
|
||||||
ti.font = FONT_ARIAL;
|
auto zone = getWorld()->data->findZoneAt(_debugCam.position);
|
||||||
ti.text = GameStringUtil::fromString(ss.str(), ti.font);
|
ImGui::Text("Zone: %s", zone ? zone->name.c_str() : "No Zone");
|
||||||
ti.screenPosition = glm::vec2(10.f, 10.f);
|
ImGui::End();
|
||||||
ti.size = 15.f;
|
|
||||||
ti.baseColour = glm::u8vec3(255);
|
drawDebugMenu();
|
||||||
r.text.renderText(ti);
|
|
||||||
|
|
||||||
State::draw(r);
|
State::draw(r);
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,13 @@ class DebugState final : public State {
|
|||||||
bool _sonicMode = false;
|
bool _sonicMode = false;
|
||||||
bool _invertedY;
|
bool _invertedY;
|
||||||
|
|
||||||
Menu createDebugMenu();
|
void drawDebugMenu();
|
||||||
Menu createMapMenu();
|
void drawMapMenu();
|
||||||
Menu createVehicleMenu();
|
void drawVehicleMenu();
|
||||||
Menu createAIMenu();
|
void drawAIMenu();
|
||||||
Menu createWeaponMenu();
|
void drawWeaponMenu();
|
||||||
Menu createWeatherMenu();
|
void drawWeatherMenu();
|
||||||
Menu createMissionsMenu();
|
void drawMissionsMenu();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DebugState(RWGame* game, const glm::vec3& vp = {},
|
DebugState(RWGame* game, const glm::vec3& vp = {},
|
||||||
|
@ -28,15 +28,13 @@ void LoadingState::handleEvent(const SDL_Event& e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LoadingState::draw(GameRenderer& r) {
|
void LoadingState::draw(GameRenderer& r) {
|
||||||
static auto kLoadingString =
|
|
||||||
GameStringUtil::fromString("Loading...", FONT_ARIAL);
|
|
||||||
// Display some manner of loading screen.
|
// Display some manner of loading screen.
|
||||||
TextRenderer::TextInfo ti;
|
TextRenderer::TextInfo ti;
|
||||||
ti.text = kLoadingString;
|
ti.text = GameStringUtil::fromString("Loading...", FONT_ARIAL);
|
||||||
auto size = r.getRenderer().getViewport();
|
auto size = r.getRenderer().getViewport();
|
||||||
ti.size = 25.f;
|
ti.size = 25.f;
|
||||||
ti.screenPosition = glm::vec2(50.f, size.y - ti.size - 50.f);
|
ti.screenPosition = glm::vec2(50.f, size.y - ti.size - 50.f);
|
||||||
ti.font = FONT_PRICEDOWN;
|
ti.font = FONT_ARIAL;
|
||||||
ti.baseColour = glm::u8vec3(255);
|
ti.baseColour = glm::u8vec3(255);
|
||||||
r.text.renderText(ti);
|
r.text.renderText(ti);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ set(TESTS
|
|||||||
Text
|
Text
|
||||||
TrafficDirector
|
TrafficDirector
|
||||||
Vehicle
|
Vehicle
|
||||||
|
ViewCamera
|
||||||
VisualFX
|
VisualFX
|
||||||
Weapon
|
Weapon
|
||||||
World
|
World
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
#include "test_Globals.hpp"
|
#include "test_Globals.hpp"
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& stream, const glm::vec3& v) {
|
std::ostream& operator<<(std::ostream& stream, const glm::vec3& v) {
|
||||||
stream << v.x << " " << v.y << " " << v.z;
|
stream << glm::to_string(v);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,12 @@ struct print_log_value<glm::vec3> {
|
|||||||
s << glm::to_string(v);
|
s << glm::to_string(v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
template <>
|
||||||
|
struct print_log_value<glm::vec4> {
|
||||||
|
void operator()(std::ostream& s, glm::vec4 const& v) {
|
||||||
|
s << glm::to_string(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
BOOST_NS_MAGIC_CLOSING
|
BOOST_NS_MAGIC_CLOSING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
tests/test_ViewCamera.cpp
Normal file
26
tests/test_ViewCamera.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include "test_Globals.hpp"
|
||||||
|
#include <render/ViewCamera.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct CameraFixture {
|
||||||
|
ViewCamera camera_ {
|
||||||
|
{1.f, 2.f, 3.f}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(ViewCameraTests)
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(test_creation, CameraFixture) {
|
||||||
|
BOOST_CHECK_EQUAL(camera_.position, glm::vec3(1.f, 2.f, 3.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(test_view_matrix, CameraFixture) {
|
||||||
|
const auto& view = camera_.getView();
|
||||||
|
BOOST_CHECK_EQUAL(view[3], glm::vec4(2.f, -3.f, 1.f, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user