async threading for map progress, etc. no cancelling yet
This commit is contained in:
parent
539c722666
commit
caa7418375
|
|
@ -79,6 +79,12 @@ void close()
|
|||
}
|
||||
|
||||
static std::mutex print_mutex;
|
||||
static print_callback_t active_print_callback;
|
||||
|
||||
void set_print_callback(print_callback_t cb)
|
||||
{
|
||||
active_print_callback = cb;
|
||||
}
|
||||
|
||||
void print(flag logflag, const char *str)
|
||||
{
|
||||
|
|
@ -86,6 +92,12 @@ void print(flag logflag, const char *str)
|
|||
return;
|
||||
}
|
||||
|
||||
if (active_print_callback)
|
||||
{
|
||||
active_print_callback(logflag, str);
|
||||
return;
|
||||
}
|
||||
|
||||
fmt::text_style style;
|
||||
|
||||
if (enable_color_codes) {
|
||||
|
|
@ -157,6 +169,13 @@ void assert_(bool success, const char *expr, const char *file, int line)
|
|||
}
|
||||
}
|
||||
|
||||
static percent_callback_t active_percent_callback;
|
||||
|
||||
void set_percent_callback(percent_callback_t cb)
|
||||
{
|
||||
active_percent_callback = cb;
|
||||
}
|
||||
|
||||
void percent(uint64_t count, uint64_t max, bool displayElapsed)
|
||||
{
|
||||
bool expected = false;
|
||||
|
|
@ -188,9 +207,17 @@ void percent(uint64_t count, uint64_t max, bool displayElapsed)
|
|||
is_timing = false;
|
||||
if (displayElapsed) {
|
||||
if (max == indeterminate) {
|
||||
print(flag::PERCENT, "[done] time elapsed: {:.3}\n", elapsed);
|
||||
if (active_percent_callback) {
|
||||
active_percent_callback(std::nullopt, elapsed);
|
||||
} else {
|
||||
print(flag::PERCENT, "[done] time elapsed: {:.3}\n", elapsed);
|
||||
}
|
||||
} else {
|
||||
print(flag::PERCENT, "[100%] time elapsed: {:.3}\n", elapsed);
|
||||
if (active_percent_callback) {
|
||||
active_percent_callback(100u, elapsed);
|
||||
} else {
|
||||
print(flag::PERCENT, "[100%] time elapsed: {:.3}\n", elapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_count = -1;
|
||||
|
|
@ -198,7 +225,11 @@ void percent(uint64_t count, uint64_t max, bool displayElapsed)
|
|||
if (max != indeterminate) {
|
||||
uint32_t pct = static_cast<uint32_t>((static_cast<float>(count) / max) * 100);
|
||||
if (last_count != pct) {
|
||||
print(flag::PERCENT, "[{:>3}%]\r", pct);
|
||||
if (active_percent_callback) {
|
||||
active_percent_callback(pct, std::nullopt);
|
||||
} else {
|
||||
print(flag::PERCENT, "[{:>3}%]\r", pct);
|
||||
}
|
||||
last_count = pct;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -206,8 +237,12 @@ void percent(uint64_t count, uint64_t max, bool displayElapsed)
|
|||
|
||||
if (t - last_indeterminate_time > std::chrono::milliseconds(100)) {
|
||||
constexpr const char *spinners[] = {". ", " . ", " . ", " ."};
|
||||
last_count = (last_count + 1) >= std::size(spinners) ? 0 : (last_count + 1);
|
||||
print(flag::PERCENT, "[{}]\r", spinners[last_count]);
|
||||
if (active_percent_callback) {
|
||||
active_percent_callback(std::nullopt, std::nullopt);
|
||||
} else {
|
||||
last_count = (last_count + 1) >= std::size(spinners) ? 0 : (last_count + 1);
|
||||
print(flag::PERCENT, "[{}]\r", spinners[last_count]);
|
||||
}
|
||||
last_indeterminate_time = t;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@
|
|||
#include <list>
|
||||
#include <cmath> // for log10
|
||||
#include <stdexcept> // for std::runtime_error
|
||||
#include <functional> // for std::function
|
||||
#include <optional> // for std::optional
|
||||
#include <fmt/core.h>
|
||||
#include <common/bitflags.hh>
|
||||
#include <common/fs.hh>
|
||||
#include <common/cmdlib.hh>
|
||||
|
||||
// forward declaration
|
||||
namespace settings
|
||||
|
|
@ -89,6 +92,11 @@ inline void print(const char *formt, const Args &...args)
|
|||
print(flag::DEFAULT, fmt::format(fmt::runtime(formt), std::forward<const Args &>(args)...).c_str());
|
||||
}
|
||||
|
||||
// set print callback
|
||||
using print_callback_t = std::function<void(flag logflag, const char *str)>;
|
||||
|
||||
void set_print_callback(print_callback_t cb);
|
||||
|
||||
void header(const char *name);
|
||||
|
||||
// TODO: C++20 source_location
|
||||
|
|
@ -102,6 +110,11 @@ void header(const char *name);
|
|||
|
||||
void assert_(bool success, const char *expr, const char *file, int line);
|
||||
|
||||
// set percent callback
|
||||
using percent_callback_t = std::function<void(std::optional<uint32_t> percent, std::optional<duration> elapsed)>;
|
||||
|
||||
void set_percent_callback(percent_callback_t cb);
|
||||
|
||||
// Display a percent timer. This also keeps track of how long the
|
||||
// current task is taking to execute. Note that only one of these
|
||||
// can be active at a time. Once `count` == `max`, the progress
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@ enum class visapprox_t
|
|||
enum class emissivequality_t
|
||||
{
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -222,23 +222,27 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
|
|||
// Get face normal and midpoint...
|
||||
qvec3d facenormal = faceplane.normal;
|
||||
qvec3d facemidpoint = winding.center() + facenormal; // Lift 1 unit
|
||||
|
||||
vector<qvec3f> points;
|
||||
|
||||
if (light_options.emissivequality.value() == emissivequality_t::LOW) {
|
||||
vector<qvec3f> points{facemidpoint};
|
||||
if (light_options.emissivequality.value() == emissivequality_t::LOW ||
|
||||
light_options.emissivequality.value() == emissivequality_t::MEDIUM) {
|
||||
points = {facemidpoint};
|
||||
|
||||
for (auto &style : emitcolors) {
|
||||
MakeBounceLight(
|
||||
bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
||||
if (light_options.emissivequality.value() == emissivequality_t::MEDIUM) {
|
||||
|
||||
for (auto &pt : winding) {
|
||||
points.push_back(pt + faceplane.normal);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vector<qvec3f> points;
|
||||
winding.dice(cfg.bouncelightsubdivision.value(),
|
||||
[&points, &faceplane](winding_t &w) { points.push_back(w.center() + faceplane.normal); });
|
||||
}
|
||||
|
||||
for (auto &style : emitcolors) {
|
||||
MakeBounceLight(
|
||||
bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
||||
}
|
||||
for (auto &style : emitcolors) {
|
||||
MakeBounceLight(
|
||||
bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -300,8 +300,8 @@ light_settings::light_settings()
|
|||
this, "lightmap_scale", 0, &experimental_group, "force change lightmap scale; vanilla engines only allow 16"},
|
||||
extra{
|
||||
this, {"extra", "extra4"}, 1, &performance_group, "supersampling; 2x2 (extra) or 4x4 (extra4) respectively"},
|
||||
emissivequality{this, "emissivequality", emissivequality_t::LOW, { { "LOW", emissivequality_t::LOW }, { "HIGH", emissivequality_t::HIGH } }, &performance_group,
|
||||
"low = one point in the center of the face, high = spread points out for antialiasing"},
|
||||
emissivequality{this, "emissivequality", emissivequality_t::LOW, { { "LOW", emissivequality_t::LOW }, { "MEDIUM", emissivequality_t::MEDIUM }, { "HIGH", emissivequality_t::HIGH } }, &performance_group,
|
||||
"low = one point in the center of the face, med = center + all verts, high = spread points out for antialiasing"},
|
||||
visapprox{this, "visapprox", visapprox_t::AUTO,
|
||||
{{"auto", visapprox_t::AUTO}, {"none", visapprox_t::NONE}, {"vis", visapprox_t::VIS},
|
||||
{"rays", visapprox_t::RAYS}},
|
||||
|
|
|
|||
|
|
@ -123,10 +123,32 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
|
|||
// Dice winding...
|
||||
l->points_before_culling = 0;
|
||||
|
||||
if (light_options.emissivequality.value() == emissivequality_t::LOW) {
|
||||
if (light_options.emissivequality.value() == emissivequality_t::LOW ||
|
||||
light_options.emissivequality.value() == emissivequality_t::MEDIUM) {
|
||||
l->points = { l->pos };
|
||||
l->points_before_culling++;
|
||||
total_surflight_points++;
|
||||
|
||||
if (light_options.emissivequality.value() == emissivequality_t::MEDIUM) {
|
||||
|
||||
for (auto &pt : winding) {
|
||||
l->points_before_culling++;
|
||||
auto point = pt + l->surfnormal;
|
||||
auto diff = qv::normalize(l->pos - pt);
|
||||
|
||||
point += diff;
|
||||
|
||||
// optimization - cull surface lights in the void
|
||||
// also try to move them if they're slightly inside a wall
|
||||
auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f);
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
l->points.push_back(fixed_point);
|
||||
total_surflight_points++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
winding.dice(cfg.surflightsubdivision.value(), [&](winding_t &w) {
|
||||
++l->points_before_culling;
|
||||
|
|
|
|||
|
|
@ -40,17 +40,21 @@ See file, 'COPYING', for details.
|
|||
#include <QTimer>
|
||||
#include <QScrollArea>
|
||||
#include <QSpinBox>
|
||||
#include <QScrollBar>
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QStatusBar>
|
||||
#include <QStringList>
|
||||
#include <QThread>
|
||||
#include <QApplication>
|
||||
|
||||
#include <common/bspfile.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
#include <vis/vis.hh>
|
||||
#include <light/light.hh>
|
||||
#include <common/bspinfo.hh>
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
#include "glview.h"
|
||||
|
||||
|
|
@ -95,6 +99,23 @@ static QStringList GetRecents()
|
|||
return recents;
|
||||
}
|
||||
|
||||
// ETLogWidget
|
||||
ETLogWidget::ETLogWidget(QWidget *parent) :
|
||||
QTabWidget(parent)
|
||||
{
|
||||
for (size_t i = 0; i < std::size(logTabNames); i++) {
|
||||
m_textEdits[i] = new QTextEdit();
|
||||
|
||||
auto *formLayout = new QFormLayout();
|
||||
auto *form = new QWidget();
|
||||
formLayout->addRow(m_textEdits[i]);
|
||||
form->setLayout(formLayout);
|
||||
setTabText(i, logTabNames[i]);
|
||||
addTab(form, logTabNames[i]);
|
||||
formLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// MainWindow
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
|
|
@ -223,16 +244,74 @@ void MainWindow::createPropertiesSidebar()
|
|||
m_fileReloadTimer->connect(m_fileReloadTimer.get(), &QTimer::timeout, this, &MainWindow::fileReloadTimerExpired);
|
||||
}
|
||||
|
||||
void MainWindow::logWidgetSetText(ETLogTab tab, const std::string &str)
|
||||
{
|
||||
m_outputLogWidget->setTabText((int32_t) tab, str.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::lightpreview_percent_callback(std::optional<uint32_t> percent, std::optional<duration> elapsed)
|
||||
{
|
||||
int32_t tabIndex = (int32_t) m_activeLogTab;
|
||||
|
||||
if (elapsed.has_value()) {
|
||||
lightpreview_log_callback(logging::flag::PROGRESS, fmt::format("finished in: {:.3}\n", elapsed.value()).c_str());
|
||||
QMetaObject::invokeMethod(this, std::bind(&MainWindow::logWidgetSetText, this, m_activeLogTab, ETLogWidget::logTabNames[tabIndex]));
|
||||
} else {
|
||||
if (percent.has_value()) {
|
||||
QMetaObject::invokeMethod(this, std::bind(&MainWindow::logWidgetSetText, this, m_activeLogTab, fmt::format("{} [{:>3}%]", ETLogWidget::logTabNames[tabIndex], percent.value())));
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this, std::bind(&MainWindow::logWidgetSetText, this, m_activeLogTab, fmt::format("{} (...)", ETLogWidget::logTabNames[tabIndex])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::lightpreview_log_callback(logging::flag flags, const char *str)
|
||||
{
|
||||
if (bitflags(flags) & logging::flag::PERCENT)
|
||||
return;
|
||||
|
||||
if (QApplication::instance()->thread() != QThread::currentThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, std::bind([this, flags](const std::string &s) -> void
|
||||
{
|
||||
lightpreview_log_callback(flags, s.c_str());
|
||||
}, std::string(str)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto *textEdit = m_outputLogWidget->textEdit(m_activeLogTab);
|
||||
const bool atBottom = textEdit->verticalScrollBar()->value() == textEdit->verticalScrollBar()->maximum();
|
||||
QTextDocument* doc = textEdit->document();
|
||||
QTextCursor cursor(doc);
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
cursor.beginEditBlock();
|
||||
cursor.insertBlock();
|
||||
cursor.insertHtml(QString::asprintf("%s\n", str));
|
||||
cursor.endEditBlock();
|
||||
|
||||
//scroll scrollarea to bottom if it was at bottom when we started
|
||||
//(we don't want to force scrolling to bottom if user is looking at a
|
||||
//higher position)
|
||||
if (atBottom) {
|
||||
QScrollBar* bar = textEdit->verticalScrollBar();
|
||||
bar->setValue(bar->maximum());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::createOutputLog()
|
||||
{
|
||||
QDockWidget *dock = new QDockWidget(tr("Output Log"), this);
|
||||
QDockWidget *dock = new QDockWidget(tr("Tool Logs"), this);
|
||||
|
||||
m_outputTextEdit = new QTextEdit();
|
||||
m_outputLogWidget = new ETLogWidget();
|
||||
|
||||
// finish dock widget setup
|
||||
dock->setWidget(m_outputTextEdit);
|
||||
dock->setWidget(m_outputLogWidget);
|
||||
|
||||
addDockWidget(Qt::BottomDockWidgetArea, dock);
|
||||
viewMenu->addAction(dock->toggleViewAction());
|
||||
|
||||
logging::set_print_callback(std::bind(&MainWindow::lightpreview_log_callback, this, std::placeholders::_1, std::placeholders::_2));
|
||||
logging::set_percent_callback(std::bind(&MainWindow::lightpreview_percent_callback, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void MainWindow::createStatusBar()
|
||||
|
|
@ -386,9 +465,13 @@ std::filesystem::path MakeFSPath(const QString &string)
|
|||
return std::filesystem::path{string.toStdU16String()};
|
||||
}
|
||||
|
||||
static bspdata_t QbspVisLight_Common(const std::filesystem::path &name, std::vector<std::string> extra_qbsp_args,
|
||||
bspdata_t MainWindow::QbspVisLight_Common(const std::filesystem::path &name, std::vector<std::string> extra_qbsp_args,
|
||||
std::vector<std::string> extra_vis_args, std::vector<std::string> extra_light_args, bool run_vis)
|
||||
{
|
||||
auto resetActiveTabText = [&]() {
|
||||
QMetaObject::invokeMethod(this, std::bind(&MainWindow::logWidgetSetText, this, m_activeLogTab, ETLogWidget::logTabNames[(int32_t) m_activeLogTab]));
|
||||
};
|
||||
|
||||
auto bsp_path = name;
|
||||
bsp_path.replace_extension(".bsp");
|
||||
|
||||
|
|
@ -401,12 +484,16 @@ static bspdata_t QbspVisLight_Common(const std::filesystem::path &name, std::vec
|
|||
args.push_back(name.string());
|
||||
|
||||
// run qbsp
|
||||
m_activeLogTab = ETLogTab::TAB_BSP;
|
||||
|
||||
InitQBSP(args);
|
||||
ProcessFile();
|
||||
|
||||
resetActiveTabText();
|
||||
|
||||
// run vis
|
||||
if (run_vis) {
|
||||
m_activeLogTab = ETLogTab::TAB_VIS;
|
||||
std::vector<std::string> vis_args{
|
||||
"", // the exe path, which we're ignoring in this case
|
||||
};
|
||||
|
|
@ -417,8 +504,11 @@ static bspdata_t QbspVisLight_Common(const std::filesystem::path &name, std::vec
|
|||
vis_main(vis_args);
|
||||
}
|
||||
|
||||
resetActiveTabText();
|
||||
|
||||
// run light
|
||||
{
|
||||
m_activeLogTab = ETLogTab::TAB_LIGHT;
|
||||
std::vector<std::string> light_args{
|
||||
"", // the exe path, which we're ignoring in this case
|
||||
};
|
||||
|
|
@ -430,6 +520,10 @@ static bspdata_t QbspVisLight_Common(const std::filesystem::path &name, std::vec
|
|||
light_main(light_args);
|
||||
}
|
||||
|
||||
resetActiveTabText();
|
||||
|
||||
m_activeLogTab = ETLogTab::TAB_LIGHTPREVIEW;
|
||||
|
||||
// serialize obj
|
||||
{
|
||||
bspdata_t bspdata;
|
||||
|
|
@ -515,30 +609,12 @@ private:
|
|||
GLView *glView;
|
||||
};
|
||||
|
||||
void MainWindow::loadFileInternal(const QString &file, bool is_reload)
|
||||
int MainWindow::compileMap(const QString &file, bool is_reload)
|
||||
{
|
||||
qDebug() << "loadFileInternal " << file;
|
||||
|
||||
// just in case
|
||||
m_fileReloadTimer->stop();
|
||||
|
||||
// persist settings
|
||||
QSettings s;
|
||||
s.setValue("qbsp_options", qbsp_options->text());
|
||||
s.setValue("vis_enabled", vis_checkbox->isChecked());
|
||||
s.setValue("vis_options", vis_options->text());
|
||||
s.setValue("light_options", light_options->text());
|
||||
s.setValue("nearest", nearest->isChecked());
|
||||
|
||||
// update title bar
|
||||
setWindowFilePath(file);
|
||||
setWindowTitle(QFileInfo(file).fileName() + " - lightpreview");
|
||||
|
||||
fs::path fs_path = MakeFSPath(file);
|
||||
|
||||
m_bspdata = {};
|
||||
|
||||
settings::common_settings render_settings;
|
||||
render_settings.reset();
|
||||
|
||||
try {
|
||||
if (fs_path.extension().compare(".bsp") == 0) {
|
||||
|
|
@ -576,13 +652,22 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload)
|
|||
m_bspdata.loadversion->game->init_filesystem(file.toStdString(), settings);
|
||||
}
|
||||
} catch (const settings::parse_exception &p) {
|
||||
m_outputTextEdit->append(QString::fromUtf8(p.what()) + QString::fromLatin1("\n"));
|
||||
return;
|
||||
auto *textEdit = m_outputLogWidget->textEdit(m_activeLogTab);
|
||||
textEdit->append(QString::fromUtf8(p.what()) + QString::fromLatin1("\n"));
|
||||
m_activeLogTab = ETLogTab::TAB_LIGHTPREVIEW;
|
||||
return 1;
|
||||
} catch (const settings::quit_after_help_exception &p) {
|
||||
m_outputTextEdit->append(QString::fromUtf8(p.what()) + QString::fromLatin1("\n"));
|
||||
return;
|
||||
auto *textEdit = m_outputLogWidget->textEdit(m_activeLogTab);
|
||||
textEdit->append(QString::fromUtf8(p.what()) + QString::fromLatin1("\n"));
|
||||
m_activeLogTab = ETLogTab::TAB_LIGHTPREVIEW;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MainWindow::compileThreadExited()
|
||||
{
|
||||
const auto &bsp = std::get<mbsp_t>(m_bspdata.bsp);
|
||||
|
||||
auto ents = EntData_Parse(bsp);
|
||||
|
|
@ -590,9 +675,9 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload)
|
|||
// build lightmap atlas
|
||||
auto atlas = build_lightmap_atlas(bsp, m_bspdata.bspx.entries, false, bspx_decoupled_lm->isChecked());
|
||||
|
||||
glView->renderBSP(file, bsp, m_bspdata.bspx.entries, ents, atlas, render_settings, bspx_normals->isChecked());
|
||||
glView->renderBSP(m_mapFile, bsp, m_bspdata.bspx.entries, ents, atlas, render_settings, bspx_normals->isChecked());
|
||||
|
||||
if (!is_reload && !glView->getKeepOrigin()) {
|
||||
if (!m_fileWasReload && !glView->getKeepOrigin()) {
|
||||
for (auto &ent : ents) {
|
||||
if (ent.get("classname") == "info_player_start") {
|
||||
qvec3d origin;
|
||||
|
|
@ -624,6 +709,42 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload)
|
|||
auto *style = new QLightStyleSlider(style_entry.first, glView);
|
||||
lightstyles->addWidget(style);
|
||||
}
|
||||
|
||||
delete m_compileThread;
|
||||
m_compileThread = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::loadFileInternal(const QString &file, bool is_reload)
|
||||
{
|
||||
// TODO
|
||||
if (m_compileThread)
|
||||
return;
|
||||
|
||||
qDebug() << "loadFileInternal " << file;
|
||||
|
||||
// just in case
|
||||
m_fileReloadTimer->stop();
|
||||
m_fileWasReload = is_reload;
|
||||
|
||||
// persist settings
|
||||
QSettings s;
|
||||
s.setValue("qbsp_options", qbsp_options->text());
|
||||
s.setValue("vis_enabled", vis_checkbox->isChecked());
|
||||
s.setValue("vis_options", vis_options->text());
|
||||
s.setValue("light_options", light_options->text());
|
||||
s.setValue("nearest", nearest->isChecked());
|
||||
|
||||
// update title bar
|
||||
setWindowFilePath(file);
|
||||
setWindowTitle(QFileInfo(file).fileName() + " - lightpreview");
|
||||
|
||||
for (auto &edit : m_outputLogWidget->textEdits()) {
|
||||
edit->clear();
|
||||
}
|
||||
|
||||
m_compileThread = QThread::create(std::bind(&MainWindow::compileMap, this, file, is_reload));
|
||||
connect(m_compileThread, &QThread::finished, this, &MainWindow::compileThreadExited);
|
||||
m_compileThread->start();
|
||||
}
|
||||
|
||||
void MainWindow::displayCameraPositionInfo()
|
||||
|
|
|
|||
|
|
@ -31,6 +31,40 @@ class QCheckBox;
|
|||
class QStringList;
|
||||
class QTextEdit;
|
||||
|
||||
enum class ETLogTab
|
||||
{
|
||||
TAB_LIGHTPREVIEW,
|
||||
TAB_BSP,
|
||||
TAB_VIS,
|
||||
TAB_LIGHT,
|
||||
|
||||
TAB_TOTAL
|
||||
};
|
||||
|
||||
class ETLogWidget : public QTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static constexpr const char *logTabNames[(size_t) ETLogTab::TAB_TOTAL] = {
|
||||
"lightpreview",
|
||||
"bsp",
|
||||
"vis",
|
||||
"light"
|
||||
};
|
||||
|
||||
explicit ETLogWidget(QWidget *parent = nullptr);
|
||||
~ETLogWidget() { }
|
||||
|
||||
QTextEdit *textEdit(ETLogTab i) { return m_textEdits[(size_t) i]; }
|
||||
const QTextEdit *textEdit(ETLogTab i) const { return m_textEdits[(size_t) i]; }
|
||||
|
||||
auto &textEdits() { return m_textEdits; }
|
||||
|
||||
private:
|
||||
std::array<QTextEdit *, std::size(logTabNames)> m_textEdits;
|
||||
};
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -38,9 +72,13 @@ class MainWindow : public QMainWindow
|
|||
private:
|
||||
QFileSystemWatcher *m_watcher = nullptr;
|
||||
std::unique_ptr<QTimer> m_fileReloadTimer;
|
||||
bool m_fileWasReload = false;
|
||||
QString m_mapFile;
|
||||
bspdata_t m_bspdata;
|
||||
settings::common_settings render_settings;
|
||||
qint64 m_fileSize = -1;
|
||||
ETLogTab m_activeLogTab = ETLogTab::TAB_LIGHTPREVIEW;
|
||||
QThread *m_compileThread = nullptr;
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
|
|
@ -49,12 +87,19 @@ public:
|
|||
private:
|
||||
void createPropertiesSidebar();
|
||||
void createOutputLog();
|
||||
void lightpreview_log_callback(logging::flag flags, const char *str);
|
||||
void lightpreview_percent_callback(std::optional<uint32_t> percent, std::optional<duration> elapsed);
|
||||
void logWidgetSetText(ETLogTab tab, const std::string &str);
|
||||
void createStatusBar();
|
||||
void updateRecentsSubmenu(const QStringList &recents);
|
||||
void setupMenu();
|
||||
void fileOpen();
|
||||
void takeScreenshot();
|
||||
void fileReloadTimerExpired();
|
||||
int compileMap(const QString &file, bool is_reload);
|
||||
void compileThreadExited();
|
||||
bspdata_t QbspVisLight_Common(const fs::path &name, std::vector<std::string> extra_qbsp_args,
|
||||
std::vector<std::string> extra_vis_args, std::vector<std::string> extra_light_args, bool run_vis);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
|
|
@ -83,5 +128,5 @@ private:
|
|||
QMenu *viewMenu = nullptr;
|
||||
QMenu *openRecentMenu = nullptr;
|
||||
|
||||
QTextEdit *m_outputTextEdit = nullptr;
|
||||
ETLogWidget *m_outputLogWidget = nullptr;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue