2014-02-10 13:41:05 +01:00
|
|
|
#include "ViewerWidget.hpp"
|
2016-04-16 15:06:02 +02:00
|
|
|
#include <data/Model.hpp>
|
2015-04-13 02:48:29 +02:00
|
|
|
#include <render/GameRenderer.hpp>
|
|
|
|
#include <render/OpenGLRenderer.hpp>
|
2014-02-11 14:40:56 +01:00
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
2014-02-11 16:45:45 +01:00
|
|
|
#include <QMouseEvent>
|
2015-04-27 03:09:56 +02:00
|
|
|
#include <objects/GameObject.hpp>
|
2014-03-01 12:19:33 +01:00
|
|
|
#include <engine/Animator.hpp>
|
2016-04-16 16:05:36 +02:00
|
|
|
#include <data/Skeleton.hpp>
|
2014-06-10 01:46:48 +02:00
|
|
|
#include <QFileDialog>
|
|
|
|
#include <algorithm>
|
2014-09-19 17:06:09 +02:00
|
|
|
|
2014-06-10 02:32:29 +02:00
|
|
|
#include <objects/InstanceObject.hpp>
|
2014-09-19 17:06:09 +02:00
|
|
|
#include <objects/CharacterObject.hpp>
|
|
|
|
#include <objects/VehicleObject.hpp>
|
|
|
|
|
2014-02-10 13:41:05 +01:00
|
|
|
|
2016-08-08 06:30:11 +02:00
|
|
|
ViewerWidget::ViewerWidget(QGLFormat g, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
|
|
|
|
: QGLWidget(g, parent, shareWidget, f)
|
2016-05-16 01:06:51 +02:00
|
|
|
, gworld(nullptr)
|
|
|
|
, activeModel(nullptr)
|
|
|
|
, selectedFrame(nullptr)
|
|
|
|
, dummyObject(nullptr)
|
|
|
|
, currentObjectID(0)
|
|
|
|
, _lastModel(nullptr)
|
|
|
|
, canimation(nullptr)
|
|
|
|
, viewDistance(1.f)
|
|
|
|
, dragging(false)
|
|
|
|
, moveFast(false)
|
|
|
|
, _frameWidgetDraw(nullptr)
|
|
|
|
, _frameWidgetGeom(nullptr)
|
2014-02-11 06:46:29 +01:00
|
|
|
{
|
2016-05-16 01:06:51 +02:00
|
|
|
setFocusPolicy(Qt::StrongFocus);
|
2014-02-11 06:46:29 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 21:26:04 +02:00
|
|
|
struct WidgetVertex {
|
|
|
|
float x, y, z;
|
|
|
|
static const AttributeList vertex_attributes() {
|
|
|
|
return {
|
2015-04-13 03:09:14 +02:00
|
|
|
{ATRS_Position, 3, sizeof(WidgetVertex), 0ul}
|
2014-06-10 21:26:04 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<WidgetVertex> widgetVerts = {
|
2015-04-13 03:09:14 +02:00
|
|
|
{-.5f, 0.f, 0.f},
|
|
|
|
{ .5f, 0.f, 0.f},
|
|
|
|
{ 0.f,-.5f, 0.f},
|
|
|
|
{ 0.f, .5f, 0.f},
|
|
|
|
{ 0.f, 0.f,-.5f},
|
|
|
|
{ 0.f, 0.f, .5f}
|
2014-06-10 21:26:04 +02:00
|
|
|
};
|
|
|
|
|
2014-02-10 13:41:05 +01:00
|
|
|
void ViewerWidget::initializeGL()
|
|
|
|
{
|
2014-02-10 18:22:07 +01:00
|
|
|
QGLWidget::initializeGL();
|
2016-08-08 17:02:54 +02:00
|
|
|
timer.setInterval(25);
|
2014-02-10 18:22:07 +01:00
|
|
|
connect(&timer, SIGNAL(timeout()), SLOT(updateGL()));
|
|
|
|
timer.start();
|
2014-06-10 21:26:04 +02:00
|
|
|
|
|
|
|
_frameWidgetDraw = new DrawBuffer;
|
|
|
|
_frameWidgetDraw->setFaceType(GL_LINES);
|
|
|
|
_frameWidgetGeom = new GeometryBuffer;
|
|
|
|
_frameWidgetGeom->uploadVertices(widgetVerts);
|
|
|
|
_frameWidgetDraw->addGeometry(_frameWidgetGeom);
|
2015-04-13 03:09:14 +02:00
|
|
|
|
|
|
|
glGenTextures(1, &whiteTex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, whiteTex);
|
|
|
|
GLuint tex = 0xFFFFFFFF;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &tex);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
2014-02-10 13:41:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewerWidget::resizeGL(int w, int h)
|
|
|
|
{
|
2014-02-10 18:22:07 +01:00
|
|
|
QGLWidget::resizeGL(w, h);
|
2014-02-11 06:46:29 +01:00
|
|
|
glViewport(0, 0, w, h);
|
2014-02-10 13:41:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewerWidget::paintGL()
|
|
|
|
{
|
|
|
|
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
|
2014-02-11 14:40:56 +01:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
|
|
|
glViewport(0, 0, width(), height());
|
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
if( world() == nullptr ) return;
|
2014-06-08 02:58:49 +02:00
|
|
|
|
2015-04-13 02:48:29 +02:00
|
|
|
auto& r = *renderer;
|
|
|
|
|
|
|
|
r.setViewport(width(), height());
|
2014-03-01 12:19:33 +01:00
|
|
|
|
2016-04-16 16:05:36 +02:00
|
|
|
if(dummyObject && dummyObject->animator && dummyObject->skeleton) {
|
2014-03-01 12:19:33 +01:00
|
|
|
dummyObject->animator->tick(1.f/60.f);
|
2016-04-16 16:05:36 +02:00
|
|
|
dummyObject->skeleton->interpolate(1.f);
|
2014-03-01 12:19:33 +01:00
|
|
|
}
|
2014-02-11 14:40:56 +01:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
gworld->_work->update();
|
2014-06-10 17:47:44 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
r.getRenderer()->invalidate();
|
2014-09-19 01:10:05 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
2015-04-13 02:48:29 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
glm::mat4 m(1.f);
|
2014-06-10 17:47:44 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
r.getRenderer()->useProgram(r.worldProg);
|
2014-09-19 01:10:05 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
ViewCamera vc;
|
2014-02-10 18:22:07 +01:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
float viewFov = glm::radians(45.f);
|
2014-08-12 22:15:26 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
vc.frustum.far = 500.f;
|
|
|
|
vc.frustum.near = 0.1f;
|
|
|
|
vc.frustum.fov = viewFov;
|
|
|
|
vc.frustum.aspectRatio = width()/(height()*1.f);
|
2014-09-21 17:20:30 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
Model* model = activeModel;
|
|
|
|
if( model != _lastModel ) {
|
|
|
|
_lastModel = model;
|
|
|
|
emit modelChanged(_lastModel);
|
|
|
|
}
|
2014-08-12 22:15:26 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
glm::vec3 eye(sin(viewAngles.x) * cos(viewAngles.y), cos(viewAngles.x) * cos(viewAngles.y), sin(viewAngles.y));
|
|
|
|
|
|
|
|
if( model )
|
|
|
|
{
|
2014-08-12 22:15:26 +02:00
|
|
|
glm::mat4 proj = vc.frustum.projection();
|
2014-02-11 16:45:45 +01:00
|
|
|
glm::mat4 view = glm::lookAt(eye * viewDistance, glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f));
|
2014-06-17 22:46:54 +02:00
|
|
|
|
2014-09-21 17:20:30 +02:00
|
|
|
r.getRenderer()->setSceneParameters({ proj, view, glm::vec4(0.15f), glm::vec4(0.7f), glm::vec4(1.f), glm::vec4(0.f), 90.f, vc.frustum.far });
|
2014-06-17 22:46:54 +02:00
|
|
|
|
2014-09-19 01:10:05 +02:00
|
|
|
r.getRenderer()->invalidate();
|
|
|
|
|
2015-04-13 02:48:29 +02:00
|
|
|
r.setupRender();
|
2014-06-10 21:26:04 +02:00
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
r.renderModel(model, m, dummyObject);
|
|
|
|
|
|
|
|
drawFrameWidget(model->frames[model->rootFrameIdx]);
|
2015-04-13 02:48:29 +02:00
|
|
|
r.renderPostProcess();
|
2014-02-10 18:22:07 +01:00
|
|
|
}
|
2016-05-16 01:06:51 +02:00
|
|
|
else if (world()->allObjects.size() > 0)
|
|
|
|
{
|
|
|
|
vc.frustum.fov = glm::radians(90.f);
|
|
|
|
vc.frustum.far = 1000.f;
|
|
|
|
vc.position = viewPosition;
|
|
|
|
vc.rotation = glm::angleAxis(glm::half_pi<float>() + viewAngles.x, glm::vec3(0.f, 0.f, 1.f))
|
|
|
|
* glm::angleAxis(viewAngles.y, glm::vec3(0.f, 1.f, 0.f));
|
|
|
|
r.renderWorld(world(), vc, 0.f);
|
|
|
|
}
|
2014-02-10 13:41:05 +01:00
|
|
|
}
|
2014-02-10 18:22:07 +01:00
|
|
|
|
2014-06-10 21:26:04 +02:00
|
|
|
void ViewerWidget::drawFrameWidget(ModelFrame* f, const glm::mat4& m)
|
|
|
|
{
|
|
|
|
auto thisM = m * f->getTransform();
|
2015-04-13 02:48:29 +02:00
|
|
|
if(f->getGeometries().size() == 0)
|
|
|
|
{
|
|
|
|
Renderer::DrawParameters dp;
|
|
|
|
dp.count = _frameWidgetGeom->getCount();
|
|
|
|
dp.start = 0;
|
|
|
|
dp.ambient = 1.f;
|
|
|
|
dp.diffuse = 1.f;
|
2015-04-13 03:09:14 +02:00
|
|
|
if( f == selectedFrame )
|
|
|
|
{
|
|
|
|
dp.colour = {255, 255, 0, 255};
|
|
|
|
// Sorry!
|
|
|
|
glLineWidth(10.f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dp.colour = {255, 255, 255, 255};
|
|
|
|
glLineWidth(1.f);
|
|
|
|
}
|
|
|
|
dp.textures = { whiteTex };
|
2015-04-13 02:48:29 +02:00
|
|
|
renderer->getRenderer()->drawArrays(thisM, _frameWidgetDraw, dp);
|
2014-06-10 21:26:04 +02:00
|
|
|
}
|
2015-04-13 02:48:29 +02:00
|
|
|
|
2014-06-10 21:26:04 +02:00
|
|
|
for(auto c : f->getChildren()) {
|
|
|
|
drawFrameWidget(c, thisM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-11 06:46:29 +01:00
|
|
|
GameWorld* ViewerWidget::world()
|
|
|
|
{
|
|
|
|
return gworld;
|
|
|
|
}
|
|
|
|
|
2015-04-14 02:06:50 +02:00
|
|
|
void ViewerWidget::showObject(qint16 item)
|
2014-02-11 06:46:29 +01:00
|
|
|
{
|
2014-06-10 01:46:48 +02:00
|
|
|
currentObjectID = item;
|
2014-06-10 02:32:29 +02:00
|
|
|
|
|
|
|
if( dummyObject ) gworld->destroyObject( dummyObject );
|
|
|
|
|
2015-04-24 19:09:21 +02:00
|
|
|
auto def = world()->data->objectTypes[item];
|
2014-09-19 17:06:09 +02:00
|
|
|
|
|
|
|
if( def )
|
|
|
|
{
|
|
|
|
if(def->class_type == ObjectData::class_id)
|
|
|
|
{
|
|
|
|
dummyObject = gworld->createInstance(item, {});
|
|
|
|
}
|
|
|
|
else if(def->class_type == CharacterData::class_id)
|
|
|
|
{
|
|
|
|
dummyObject = gworld->createPedestrian(item, {});
|
|
|
|
}
|
|
|
|
else if(def->class_type == VehicleData::class_id)
|
|
|
|
{
|
|
|
|
dummyObject = gworld->createVehicle(item, {});
|
|
|
|
}
|
2016-04-16 15:06:02 +02:00
|
|
|
RW_CHECK(dummyObject != nullptr, "Dummy Object is null");
|
|
|
|
if (dummyObject != nullptr) {
|
|
|
|
activeModel = dummyObject->model->resource;
|
|
|
|
}
|
2014-09-19 17:06:09 +02:00
|
|
|
}
|
2014-02-11 06:46:29 +01:00
|
|
|
}
|
2014-02-11 16:45:45 +01:00
|
|
|
|
2015-04-13 02:48:29 +02:00
|
|
|
void ViewerWidget::showModel(Model* model)
|
|
|
|
{
|
|
|
|
if( dummyObject ) gworld->destroyObject( dummyObject );
|
|
|
|
dummyObject = nullptr;
|
|
|
|
activeModel = model;
|
|
|
|
}
|
|
|
|
|
2015-04-13 03:09:14 +02:00
|
|
|
void ViewerWidget::selectFrame(ModelFrame* frame)
|
|
|
|
{
|
|
|
|
selectedFrame = frame;
|
|
|
|
}
|
2015-04-13 02:48:29 +02:00
|
|
|
|
2014-06-10 01:46:48 +02:00
|
|
|
void ViewerWidget::exportModel()
|
|
|
|
{
|
|
|
|
QString toSv = QFileDialog::getSaveFileName(this,
|
|
|
|
"Export Model",
|
|
|
|
QDir::homePath(),
|
|
|
|
"Model (*.DFF)");
|
|
|
|
|
|
|
|
if( toSv.size() == 0 ) return;
|
|
|
|
|
2014-09-17 04:13:02 +02:00
|
|
|
#if 0
|
2014-06-10 01:46:48 +02:00
|
|
|
auto it = world()->objectTypes.find(currentObjectID);
|
|
|
|
if( it != world()->objectTypes.end() ) {
|
2015-04-18 02:11:17 +02:00
|
|
|
for( auto& archive : world()->data.archives ) {
|
2014-06-10 01:46:48 +02:00
|
|
|
for(size_t i = 0; i < archive.second.getAssetCount(); ++i) {
|
|
|
|
auto& assetI = archive.second.getAssetInfoByIndex(i);
|
|
|
|
std::string q(assetI.name);
|
|
|
|
std::transform(q.begin(), q.end(), q.begin(), ::tolower);
|
|
|
|
if( q.find(it->second->modelName) != q.npos ) {
|
|
|
|
archive.second.saveAsset(q, toSv.toStdString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-17 04:13:02 +02:00
|
|
|
#endif
|
2014-06-10 01:46:48 +02:00
|
|
|
}
|
|
|
|
|
2014-09-19 01:10:05 +02:00
|
|
|
void ViewerWidget::dataLoaded(GameWorld *world)
|
2014-02-12 07:42:07 +01:00
|
|
|
{
|
2014-09-19 01:10:05 +02:00
|
|
|
gworld = world;
|
2014-02-12 07:42:07 +01:00
|
|
|
}
|
|
|
|
|
2015-04-13 02:48:29 +02:00
|
|
|
void ViewerWidget::setRenderer(GameRenderer *render)
|
|
|
|
{
|
|
|
|
renderer = render;
|
|
|
|
}
|
|
|
|
|
2016-05-16 01:06:51 +02:00
|
|
|
void ViewerWidget::keyPressEvent(QKeyEvent* e)
|
|
|
|
{
|
|
|
|
if (e->key() == Qt::Key_Shift)
|
|
|
|
moveFast = true;
|
|
|
|
|
|
|
|
glm::vec3 movement;
|
|
|
|
if (e->key() == Qt::Key_W)
|
|
|
|
movement.y += moveFast ? 10.f : 1.f;
|
|
|
|
if (e->key() == Qt::Key_S)
|
|
|
|
movement.y -= moveFast ? 10.f : 1.f;
|
|
|
|
if (e->key() == Qt::Key_A)
|
|
|
|
movement.x -= moveFast ? 10.f : 1.f;
|
|
|
|
if (e->key() == Qt::Key_D)
|
|
|
|
movement.x += moveFast? 10.f : 1.f;
|
|
|
|
|
|
|
|
if (movement.length() > 0.f)
|
|
|
|
{
|
|
|
|
movement = (glm::angleAxis(viewAngles.x, glm::vec3(0.f, 0.f, 1.f))
|
|
|
|
* glm::angleAxis(viewAngles.y, glm::vec3(-1.f, 0.f, 0.f))) * movement;
|
|
|
|
viewPosition += movement;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewerWidget::keyReleaseEvent(QKeyEvent* e)
|
|
|
|
{
|
|
|
|
if (e->key() == Qt::Key_Shift)
|
|
|
|
moveFast = false;
|
|
|
|
}
|
|
|
|
|
2014-09-19 01:10:05 +02:00
|
|
|
Model* ViewerWidget::currentModel() const
|
2014-02-12 07:42:07 +01:00
|
|
|
{
|
2015-04-13 02:48:29 +02:00
|
|
|
return activeModel;
|
2014-02-12 07:42:07 +01:00
|
|
|
}
|
|
|
|
|
2015-04-14 02:06:50 +02:00
|
|
|
GameObject* ViewerWidget::currentObject() const
|
|
|
|
{
|
|
|
|
return dummyObject;
|
|
|
|
}
|
|
|
|
|
2014-02-11 16:45:45 +01:00
|
|
|
void ViewerWidget::mousePressEvent(QMouseEvent* e)
|
|
|
|
{
|
|
|
|
dragging = true;
|
|
|
|
dstart = e->localPos();
|
|
|
|
dastart = viewAngles;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewerWidget::mouseReleaseEvent(QMouseEvent*)
|
|
|
|
{
|
|
|
|
dragging = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewerWidget::mouseMoveEvent(QMouseEvent* e)
|
|
|
|
{
|
|
|
|
if(dragging) {
|
|
|
|
auto d = e->localPos() - dstart;
|
|
|
|
viewAngles = dastart + glm::vec2(d.x(), d.y()) * 0.01f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewerWidget::wheelEvent(QWheelEvent* e)
|
|
|
|
{
|
2014-05-27 01:08:14 +02:00
|
|
|
viewDistance = qMax(viewDistance - e->angleDelta().y() / 240.f, 0.5f);
|
2014-02-11 16:45:45 +01:00
|
|
|
}
|
|
|
|
|