Merge branch 'brushbsp' of https://github.com/ericwa/ericw-tools into brushbsp

This commit is contained in:
Jonathan 2023-06-12 01:59:20 -04:00
commit ac50f17e9b
7 changed files with 175 additions and 58 deletions

View File

@ -20,6 +20,7 @@
#include <common/entdata.h>
#include <sstream>
#include <cstdlib> // atoi()
#include <common/bsputils.hh>
#include <common/parser.hh>
@ -50,32 +51,24 @@ const std::string &entdict_t::get(const std::string_view &key) const
vec_t entdict_t::get_float(const std::string_view &key) const
{
auto s = get(key);
const std::string &s = get(key);
if (s.empty()) {
return 0;
}
try {
return std::stod(s);
} catch (std::exception &) {
return 0.0;
}
return atof(s.data());
}
int32_t entdict_t::get_int(const std::string_view &key) const
{
auto s = get(key);
const std::string &s = get(key);
if (s.empty()) {
return 0;
}
try {
return std::stoi(s);
} catch (std::exception &) {
return 0;
}
return atoi(s.data());
}
int32_t entdict_t::get_vector(const std::string_view &key, qvec3d &vec) const

View File

@ -551,6 +551,20 @@ void GLView::setLightStyleIntensity(int style_id, int intensity)
update();
}
void GLView::setMagFilter(QOpenGLTexture::Filter filter)
{
m_filter = filter;
if (placeholder_texture)
placeholder_texture->setMagnificationFilter(m_filter);
for (auto &dc : m_drawcalls) {
dc.texture->setMagnificationFilter(m_filter);
}
update();
}
void GLView::takeScreenshot(QString destPath, int w, int h)
{
// update aspect ratio
@ -632,7 +646,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
placeholder_texture->setSize(64, 64);
placeholder_texture->setFormat(QOpenGLTexture::TextureFormat::RGBA8_UNorm);
placeholder_texture->setAutoMipMapGenerationEnabled(true);
placeholder_texture->setMagnificationFilter(QOpenGLTexture::Linear);
placeholder_texture->setMagnificationFilter(m_filter);
placeholder_texture->setMinificationFilter(QOpenGLTexture::Linear);
placeholder_texture->allocateStorage();
@ -752,19 +766,20 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
skybox_texture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::TargetCubeMap);
{
QImage up_img;
{
auto up = img::load_texture(fmt::format("env/{}up", skybox), false, bsp.loadversion->game, settings, true);
up_img = QImage((const uchar *) std::get<0>(up)->pixels.data(), std::get<0>(up)->width, std::get<0>(up)->height, QImage::Format_RGB32);
auto up =
img::load_texture(fmt::format("env/{}up", skybox), false, bsp.loadversion->game, settings, true);
up_img = QImage((const uchar *)std::get<0>(up)->pixels.data(), std::get<0>(up)->width,
std::get<0>(up)->height, QImage::Format_RGB32);
up_img = std::move(up_img.transformed(QTransform().rotate(-90.0)).mirrored(false, true));
}
skybox_texture->setSize(up_img.width(), up_img.height());
skybox_texture->setFormat(QOpenGLTexture::TextureFormat::RGBA8_UNorm);
skybox_texture->setAutoMipMapGenerationEnabled(true);
skybox_texture->setMagnificationFilter(QOpenGLTexture::Linear);
skybox_texture->setMagnificationFilter(m_filter);
skybox_texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
skybox_texture->setMaximumAnisotropy(16);
skybox_texture->allocateStorage();
@ -777,8 +792,10 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
{
QImage down_img;
{
auto down = img::load_texture(fmt::format("env/{}dn", skybox), false, bsp.loadversion->game, settings, true);
down_img = QImage((const uchar *) std::get<0>(down)->pixels.data(), std::get<0>(down)->width, std::get<0>(down)->height, QImage::Format_RGB32);
auto down =
img::load_texture(fmt::format("env/{}dn", skybox), false, bsp.loadversion->game, settings, true);
down_img = QImage((const uchar *)std::get<0>(down)->pixels.data(), std::get<0>(down)->width,
std::get<0>(down)->height, QImage::Format_RGB32);
down_img = std::move(down_img.transformed(QTransform().rotate(90.0)).mirrored(true, false));
}
@ -788,8 +805,10 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
{
QImage left_img;
{
auto left = img::load_texture(fmt::format("env/{}lf", skybox), false, bsp.loadversion->game, settings, true);
left_img = QImage((const uchar *) std::get<0>(left)->pixels.data(), std::get<0>(left)->width, std::get<0>(left)->height, QImage::Format_RGB32);
auto left =
img::load_texture(fmt::format("env/{}lf", skybox), false, bsp.loadversion->game, settings, true);
left_img = QImage((const uchar *)std::get<0>(left)->pixels.data(), std::get<0>(left)->width,
std::get<0>(left)->height, QImage::Format_RGB32);
left_img = std::move(left_img.transformed(QTransform().rotate(-90.0)).mirrored(true, false));
}
skybox_texture->setData(0, 0, QOpenGLTexture::CubeMapNegativeX, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
@ -798,8 +817,10 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
{
QImage right_img;
{
auto right = img::load_texture(fmt::format("env/{}rt", skybox), false, bsp.loadversion->game, settings, true);
right_img = QImage((const uchar *) std::get<0>(right)->pixels.data(), std::get<0>(right)->width, std::get<0>(right)->height, QImage::Format_RGB32);
auto right =
img::load_texture(fmt::format("env/{}rt", skybox), false, bsp.loadversion->game, settings, true);
right_img = QImage((const uchar *)std::get<0>(right)->pixels.data(), std::get<0>(right)->width,
std::get<0>(right)->height, QImage::Format_RGB32);
right_img = std::move(right_img.transformed(QTransform().rotate(90.0)).mirrored(true, false));
}
skybox_texture->setData(0, 0, QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
@ -808,8 +829,10 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
{
QImage front_img;
{
auto front = img::load_texture(fmt::format("env/{}ft", skybox), false, bsp.loadversion->game, settings, true);
front_img = QImage((const uchar *) std::get<0>(front)->pixels.data(), std::get<0>(front)->width, std::get<0>(front)->height, QImage::Format_RGB32);
auto front =
img::load_texture(fmt::format("env/{}ft", skybox), false, bsp.loadversion->game, settings, true);
front_img = QImage((const uchar *)std::get<0>(front)->pixels.data(), std::get<0>(front)->width,
std::get<0>(front)->height, QImage::Format_RGB32);
front_img = std::move(front_img.mirrored(true, false));
}
skybox_texture->setData(0, 0, QOpenGLTexture::CubeMapNegativeY, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
@ -818,8 +841,10 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
{
QImage back_img;
{
auto back = img::load_texture(fmt::format("env/{}bk", skybox), false, bsp.loadversion->game, settings, true);
back_img = QImage((const uchar *) std::get<0>(back)->pixels.data(), std::get<0>(back)->width, std::get<0>(back)->height, QImage::Format_RGB32);
auto back =
img::load_texture(fmt::format("env/{}bk", skybox), false, bsp.loadversion->game, settings, true);
back_img = QImage((const uchar *)std::get<0>(back)->pixels.data(), std::get<0>(back)->width,
std::get<0>(back)->height, QImage::Format_RGB32);
back_img = std::move(back_img.transformed(QTransform().rotate(-180.0)).mirrored(true, false));
}
skybox_texture->setData(0, 0, QOpenGLTexture::CubeMapPositiveY, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
@ -925,7 +950,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries
qtexture->setMaximumAnisotropy(16);
qtexture->setAutoMipMapGenerationEnabled(true);
qtexture->setMagnificationFilter(QOpenGLTexture::Linear);
qtexture->setMagnificationFilter(m_filter);
qtexture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
}

View File

@ -82,6 +82,7 @@ private:
bool m_showTris = false;
bool m_drawFlat = false;
bool m_keepOrigin = false;
QOpenGLTexture::Filter m_filter = QOpenGLTexture::Linear;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
@ -157,6 +158,7 @@ public:
void setKeepOrigin(bool keeporigin);
// intensity = 0 to 200
void setLightStyleIntensity(int style_id, int intensity);
void setMagFilter(QOpenGLTexture::Filter filter);
const bool &getKeepOrigin() const { return m_keepOrigin; }
void takeScreenshot(QString destPath, int w, int h);

View File

@ -151,6 +151,8 @@ void MainWindow::createPropertiesSidebar()
auto *keepposition = new QCheckBox(tr("Keep Camera Pos"));
nearest = new QCheckBox(tr("Nearest Filter"));
formLayout->addRow(tr("qbsp"), qbsp_options);
formLayout->addRow(vis_checkbox, vis_options);
formLayout->addRow(tr("light"), light_options);
@ -158,6 +160,7 @@ void MainWindow::createPropertiesSidebar()
formLayout->addRow(rendermode_group);
formLayout->addRow(showtris);
formLayout->addRow(keepposition);
formLayout->addRow(nearest);
lightstyles = new QVBoxLayout();
@ -187,6 +190,10 @@ void MainWindow::createPropertiesSidebar()
vis_checkbox->setChecked(s.value("vis_enabled").toBool());
vis_options->setText(s.value("vis_options").toString());
light_options->setText(s.value("light_options").toString());
nearest->setChecked(s.value("nearest").toBool());
if (nearest->isChecked()) {
glView->setMagFilter(QOpenGLTexture::Nearest);
}
// setup event handlers
@ -197,6 +204,8 @@ void MainWindow::createPropertiesSidebar()
connect(showtris, &QAbstractButton::toggled, this, [=](bool checked) { glView->setShowTris(checked); });
connect(drawflat, &QAbstractButton::toggled, this, [=](bool checked) { glView->setDrawFlat(checked); });
connect(keepposition, &QAbstractButton::toggled, this, [=](bool checked) { glView->setKeepOrigin(checked); });
connect(nearest, &QAbstractButton::toggled, this,
[=](bool checked) { glView->setMagFilter(checked ? QOpenGLTexture::Nearest : QOpenGLTexture::Linear); });
connect(glView, &GLView::cameraMoved, this, &MainWindow::displayCameraPositionInfo);
// set up load timer
@ -210,10 +219,10 @@ void MainWindow::createOutputLog()
{
QDockWidget *dock = new QDockWidget(tr("Output Log"), this);
auto *textEdit = new QTextEdit();
m_outputTextEdit = new QTextEdit();
// finish dock widget setup
dock->setWidget(textEdit);
dock->setWidget(m_outputTextEdit);
addDockWidget(Qt::BottomDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
}
@ -511,6 +520,7 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload)
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);
@ -522,39 +532,47 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload)
settings::common_settings render_settings;
if (fs_path.extension().compare(".bsp") == 0) {
try {
if (fs_path.extension().compare(".bsp") == 0) {
LoadBSPFile(fs_path, &m_bspdata);
LoadBSPFile(fs_path, &m_bspdata);
auto opts = ParseArgs(light_options);
auto opts = ParseArgs(light_options);
std::vector<const char *> argPtrs;
std::vector<const char *> argPtrs;
argPtrs.push_back("");
argPtrs.push_back("");
for (const std::string &arg : opts) {
argPtrs.push_back(arg.data());
for (const std::string &arg : opts) {
argPtrs.push_back(arg.data());
}
render_settings.preinitialize(argPtrs.size(), argPtrs.data());
render_settings.initialize(argPtrs.size() - 1, argPtrs.data() + 1);
render_settings.postinitialize(argPtrs.size(), argPtrs.data());
m_bspdata.version->game->init_filesystem(fs_path, render_settings);
ConvertBSPFormat(&m_bspdata, &bspver_generic);
} else {
m_bspdata = QbspVisLight_Common(fs_path, ParseArgs(qbsp_options), ParseArgs(vis_options),
ParseArgs(light_options), vis_checkbox->isChecked());
// FIXME: move to a lightpreview_settings
settings::common_settings settings;
// FIXME: copy the -path args from light
settings.paths.copy_from(::light_options.paths);
m_bspdata.loadversion->game->init_filesystem(file.toStdString(), settings);
}
render_settings.preinitialize(argPtrs.size(), argPtrs.data());
render_settings.initialize(argPtrs.size() - 1, argPtrs.data() + 1);
render_settings.postinitialize(argPtrs.size(), argPtrs.data());
m_bspdata.version->game->init_filesystem(fs_path, render_settings);
ConvertBSPFormat(&m_bspdata, &bspver_generic);
} else {
m_bspdata = QbspVisLight_Common(fs_path, ParseArgs(qbsp_options), ParseArgs(vis_options),
ParseArgs(light_options), vis_checkbox->isChecked());
// FIXME: move to a lightpreview_settings
settings::common_settings settings;
// FIXME: copy the -path args from light
settings.paths.copy_from(::light_options.paths);
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;
} catch (const settings::quit_after_help_exception &p) {
m_outputTextEdit->append(QString::fromUtf8(p.what()) + QString::fromLatin1("\n"));
return;
}
const auto &bsp = std::get<mbsp_t>(m_bspdata.bsp);

View File

@ -29,6 +29,7 @@ class QFileSystemWatcher;
class QLineEdit;
class QCheckBox;
class QStringList;
class QTextEdit;
class MainWindow : public QMainWindow
{
@ -70,6 +71,7 @@ private:
GLView *glView = nullptr;
QCheckBox *vis_checkbox = nullptr;
QCheckBox *nearest = nullptr;
QLineEdit *qbsp_options = nullptr;
QLineEdit *vis_options = nullptr;
@ -78,4 +80,6 @@ private:
QMenu *viewMenu = nullptr;
QMenu *openRecentMenu = nullptr;
QTextEdit *m_outputTextEdit = nullptr;
};

View File

@ -0,0 +1,69 @@
// Game: Quake
// Format: Valve
// entity 0
{
"classname" "worldspawn"
"wad" "deprecated/free_wad.wad"
"_tb_def" "builtin:Quake.fgd"
"_bounce" "1"
"_minlight" "100"
// brush 0
{
( -256 -128 -16 ) ( -256 -127 -16 ) ( -256 -128 -15 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
( -256 -208 -16 ) ( -256 -208 -15 ) ( -255 -208 -16 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( -256 -128 -16 ) ( -255 -128 -16 ) ( -256 -127 -16 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 288 272 0 ) ( 288 273 0 ) ( 289 272 0 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 288 272 0 ) ( 289 272 0 ) ( 288 272 1 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 288 272 0 ) ( 288 272 1 ) ( 288 273 0 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
}
// brush 1
{
( -256 -128 240 ) ( -256 -127 240 ) ( -256 -128 241 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
( -256 -208 240 ) ( -256 -208 241 ) ( -255 -208 240 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( -256 -128 240 ) ( -255 -128 240 ) ( -256 -127 240 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 288 272 256 ) ( 288 273 256 ) ( 289 272 256 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 288 272 256 ) ( 289 272 256 ) ( 288 272 257 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 288 272 256 ) ( 288 272 257 ) ( 288 273 256 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
}
// brush 2
{
( -272 -128 224 ) ( -272 -127 224 ) ( -272 -128 225 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
( -272 -208 224 ) ( -272 -208 225 ) ( -271 -208 224 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( -272 -128 0 ) ( -271 -128 0 ) ( -272 -127 0 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 272 272 240 ) ( 272 273 240 ) ( 273 272 240 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 272 272 240 ) ( 273 272 240 ) ( 272 272 241 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( -256 272 240 ) ( -256 272 241 ) ( -256 273 240 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
}
// brush 3
{
( 288 -128 224 ) ( 288 -127 224 ) ( 288 -128 225 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
( 288 -208 224 ) ( 288 -208 225 ) ( 289 -208 224 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 288 -128 0 ) ( 289 -128 0 ) ( 288 -127 0 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 832 272 240 ) ( 832 273 240 ) ( 833 272 240 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 832 272 240 ) ( 833 272 240 ) ( 832 272 241 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 304 272 240 ) ( 304 272 241 ) ( 304 273 240 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
}
// brush 4
{
( -256 -144 224 ) ( -256 -143 224 ) ( -256 -144 225 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
( 256 -224 224 ) ( 256 -224 225 ) ( 257 -224 224 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 256 -144 0 ) ( 257 -144 0 ) ( 256 -143 0 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 800 256 240 ) ( 800 257 240 ) ( 801 256 240 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 800 -208 240 ) ( 801 -208 240 ) ( 800 -208 241 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 288 256 240 ) ( 288 256 241 ) ( 288 257 240 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
}
// brush 5
{
( -256 256 0 ) ( -256 257 0 ) ( -256 256 1 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
( -272 256 0 ) ( -272 256 1 ) ( -271 256 0 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( -272 256 0 ) ( -271 256 0 ) ( -272 257 0 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 288 272 240 ) ( 288 273 240 ) ( 289 272 240 ) bolt3 [ 1 0 0 -32 ] [ 0 -1 0 -32 ] 0 1 1
( 288 272 16 ) ( 289 272 16 ) ( 288 272 17 ) bolt3 [ 1 0 0 -32 ] [ 0 0 -1 16 ] 0 1 1
( 288 272 16 ) ( 288 272 17 ) ( 288 273 16 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 16 ] 0 1 1
}
}
// entity 1
{
"classname" "info_player_start"
"origin" "-132 0 108"
}

View File

@ -787,4 +787,10 @@ TEST_CASE("q2_light_divzero")
INFO("should not have a black spot in the center of the light face");
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {255, 127, 63}, {-992, 0, -480}, {0, 0, -1}, nullptr, &bspx);
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {255, 127, 63}, {-984, 8, -480}, {0, 0, -1}, nullptr, &bspx);
}
}
TEST_CASE("minlight doesn't bounce")
{
auto [bsp, bspx, lit] = QbspVisLight_Q1("q1_minlight_nobounce.map", {"-lit"});
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {50, 50, 50}, {0, 0, 0}, {0, 0, 1}, &lit);
}