MetaCore/tools/PandaCubeDemo.cpp
2026-03-19 18:01:50 +08:00

223 lines
7.3 KiB
C++

#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <string_view>
#include <cmath>
#if METACORE_HAS_PANDA3D
#include <graphicsWindow.h>
#include <keyboardButton.h>
#include <lineSegs.h>
#include <load_prc_file.h>
#include <luse.h>
#include <nodePath.h>
#include <pandaFramework.h>
#include <transformState.h>
#include <windowProperties.h>
#include <filename.h>
#include <windows.h>
#endif
namespace {
void log_step(const std::string& message) {
std::cout << "[PandaCubeDemo] " << message << std::endl;
}
#if METACORE_HAS_PANDA3D
void configure_runtime_environment() {
const auto panda_bin = std::filesystem::path(METACORE_PANDA3D_ROOT_PATH) / "bin";
const auto panda_etc = std::filesystem::path(METACORE_PANDA3D_ROOT_PATH) / "etc";
if (std::filesystem::exists(panda_bin)) {
SetDllDirectoryW(panda_bin.wstring().c_str());
log_step("DLL search path set to " + panda_bin.string());
const std::wstring existing_path = [&]() {
const DWORD required = GetEnvironmentVariableW(L"PATH", nullptr, 0);
if (required == 0) {
return std::wstring{};
}
std::wstring buffer(required, L'\0');
GetEnvironmentVariableW(L"PATH", buffer.data(), required);
if (!buffer.empty() && buffer.back() == L'\0') {
buffer.pop_back();
}
return buffer;
}();
const std::wstring new_path = panda_bin.wstring() + L";" + existing_path;
SetEnvironmentVariableW(L"PATH", new_path.c_str());
log_step("PATH prefixed with Panda bin");
}
if (std::filesystem::exists(panda_etc)) {
SetEnvironmentVariableW(L"PANDA_PRC_DIR", panda_etc.wstring().c_str());
log_step("PANDA_PRC_DIR set to " + panda_etc.string());
}
wchar_t exe_path_buffer[MAX_PATH];
const DWORD path_length = GetModuleFileNameW(nullptr, exe_path_buffer, MAX_PATH);
if (path_length > 0 && path_length < MAX_PATH) {
std::filesystem::path exe_path(exe_path_buffer);
std::filesystem::current_path(exe_path.parent_path());
log_step("Working directory set to " + exe_path.parent_path().string());
}
}
void configure_local_prc() {
wchar_t exe_path_buffer[MAX_PATH];
const DWORD path_length = GetModuleFileNameW(nullptr, exe_path_buffer, MAX_PATH);
if (path_length == 0 || path_length >= MAX_PATH) {
return;
}
const std::filesystem::path exe_dir = std::filesystem::path(exe_path_buffer).parent_path();
const std::filesystem::path prc_path = exe_dir / "PandaCubeDemo.prc";
const std::filesystem::path panda_bin = std::filesystem::path(METACORE_PANDA3D_ROOT_PATH) / "bin";
const std::string panda_bin_forward = panda_bin.generic_string();
std::ofstream prc_file(prc_path, std::ios::trunc);
prc_file
<< "plugin-path " << panda_bin_forward << "\n"
<< "load-display pandagl\n"
<< "aux-display p3tinydisplay\n"
<< "window-type onscreen\n"
<< "win-size 1280 720\n"
<< "sync-video #f\n"
<< "audio-library-name null\n";
prc_file.close();
log_step("Local PRC written to " + prc_path.string());
load_prc_file(Filename::from_os_specific(prc_path.string()));
log_step("Local PRC loaded");
}
NodePath create_colored_cube(const NodePath& parent) {
LineSegs segments("demo-cube");
segments.set_thickness(2.5F);
segments.set_color(0.85F, 0.9F, 1.0F, 1.0F);
const LPoint3f corners[] = {
{-0.5F, -0.5F, -0.5F},
{0.5F, -0.5F, -0.5F},
{0.5F, 0.5F, -0.5F},
{-0.5F, 0.5F, -0.5F},
{-0.5F, -0.5F, 0.5F},
{0.5F, -0.5F, 0.5F},
{0.5F, 0.5F, 0.5F},
{-0.5F, 0.5F, 0.5F},
};
const int edges[][2] = {
{0, 1}, {1, 2}, {2, 3}, {3, 0},
{4, 5}, {5, 6}, {6, 7}, {7, 4},
{0, 4}, {1, 5}, {2, 6}, {3, 7},
};
for (const auto& edge : edges) {
segments.move_to(corners[edge[0]]);
segments.draw_to(corners[edge[1]]);
}
return parent.attach_new_node(segments.create());
}
float movement_axis(const SHORT positive_key, const SHORT negative_key) {
const float positive = (GetAsyncKeyState(positive_key) & 0x8000) != 0 ? 1.0F : 0.0F;
const float negative = (GetAsyncKeyState(negative_key) & 0x8000) != 0 ? 1.0F : 0.0F;
return positive - negative;
}
#endif
} // namespace
int main() {
#if METACORE_HAS_PANDA3D
log_step("Starting Panda3D C++ cube demo.");
configure_runtime_environment();
configure_local_prc();
PandaFramework framework;
log_step("Calling open_framework()");
framework.open_framework();
log_step("open_framework() succeeded");
framework.set_window_title("Panda3D Cube Demo");
WindowProperties props;
props.set_title("Panda3D Cube Demo");
props.set_size(1280, 720);
log_step("Calling open_window()");
WindowFramework* window = framework.open_window(props, 0);
if (window == nullptr) {
log_step("open_window() returned null");
framework.close_framework();
return 2;
}
log_step("open_window() succeeded");
if (GraphicsWindow* graphics_window = window->get_graphics_window(); graphics_window != nullptr) {
graphics_window->set_clear_color(LColor(0.06F, 0.07F, 0.10F, 1.0F));
}
NodePath render_root = window->get_render();
NodePath cube = create_colored_cube(render_root);
cube.set_scale(1.5F);
NodePath camera = window->get_camera_group();
float camera_x = 0.0F;
float camera_y = -8.0F;
float camera_z = 2.0F;
float heading = 0.0F;
float pitch = -10.0F;
log_step("Controls: WASD move, RF up/down, arrow keys look, Esc closes.");
while (window->get_graphics_window() != nullptr && !window->get_graphics_window()->is_closed()) {
if ((GetAsyncKeyState(VK_ESCAPE) & 0x8000) != 0) {
break;
}
const float move_speed = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0) ? 0.18F : 0.08F;
const float turn_speed = 1.2F;
heading += movement_axis(VK_RIGHT, VK_LEFT) * turn_speed;
pitch += movement_axis(VK_UP, VK_DOWN) * turn_speed;
if (pitch > 89.0F) {
pitch = 89.0F;
}
if (pitch < -89.0F) {
pitch = -89.0F;
}
const float heading_radians = heading * 3.1415926535F / 180.0F;
const float forward_x = std::sin(heading_radians);
const float forward_y = std::cos(heading_radians);
const float right_x = std::cos(heading_radians);
const float right_y = -std::sin(heading_radians);
const float forward_axis = movement_axis('W', 'S');
const float strafe_axis = movement_axis('D', 'A');
const float vertical_axis = movement_axis('R', 'F');
camera_x += forward_x * forward_axis * move_speed;
camera_y += forward_y * forward_axis * move_speed;
camera_x += right_x * strafe_axis * move_speed;
camera_y += right_y * strafe_axis * move_speed;
camera_z += vertical_axis * move_speed;
camera.set_pos(camera_x, camera_y, camera_z);
camera.set_hpr(heading, pitch, 0.0F);
cube.set_h(cube.get_h() + 0.2F);
framework.do_frame(nullptr);
}
framework.close_window(window);
framework.close_framework();
log_step("Demo closed cleanly.");
return 0;
#else
log_step("Panda3D support is not enabled in this build.");
return 1;
#endif
}