nuclear@78: #include nuclear@76: #include nuclear@79: #include "opengl.h" nuclear@76: #include nuclear@73: #include "goatview.h" nuclear@74: #include "goat3d.h" nuclear@74: nuclear@78: static void draw_node(goat3d_node *node); nuclear@78: nuclear@74: goat3d *scene; nuclear@75: QSettings *settings; nuclear@75: nuclear@75: static long anim_time; nuclear@75: static float cam_theta, cam_phi, cam_dist = 8; nuclear@76: static float fov = 60.0; nuclear@75: nuclear@76: bool load_scene(const char *fname) nuclear@76: { nuclear@76: if(scene) { nuclear@76: goat3d_free(scene); nuclear@76: } nuclear@76: if(!(scene = goat3d_create()) || goat3d_load(scene, fname) == -1) { nuclear@76: return false; nuclear@76: } nuclear@76: nuclear@76: float bmin[3], bmax[3]; nuclear@76: goat3d_get_bounds(scene, bmin, bmax); nuclear@76: float bsize = (Vector3(bmax[0], bmax[1], bmax[2]) - Vector3(bmin[0], bmin[1], bmin[2])).length(); nuclear@76: cam_dist = bsize / tan(DEG_TO_RAD(fov) / 2.0) + bsize; nuclear@76: nuclear@76: printf("bounds size: %f, cam_dist: %f\n", bsize, cam_dist); nuclear@76: return true; nuclear@76: } nuclear@73: nuclear@73: GoatView::GoatView() nuclear@73: { nuclear@73: make_menu(); nuclear@73: make_dock(); nuclear@73: make_center(); nuclear@73: nuclear@73: statusBar(); nuclear@73: nuclear@73: setWindowTitle("GoatView"); nuclear@75: resize(settings->value("main/size", QSize(1024, 768)).toSize()); nuclear@75: move(settings->value("main/pos", QPoint(100, 100)).toPoint()); nuclear@73: } nuclear@73: nuclear@73: GoatView::~GoatView() nuclear@73: { nuclear@73: } nuclear@73: nuclear@75: void GoatView::closeEvent(QCloseEvent *ev) nuclear@75: { nuclear@75: settings->setValue("main/size", size()); nuclear@75: settings->setValue("main/pos", pos()); nuclear@75: } nuclear@75: nuclear@73: bool GoatView::make_menu() nuclear@73: { nuclear@73: QMenu *menu_file = menuBar()->addMenu("&File"); nuclear@73: nuclear@73: QAction *act_open_sce = new QAction("&Open Scene", this); nuclear@73: act_open_sce->setShortcuts(QKeySequence::Open); nuclear@73: connect(act_open_sce, &QAction::triggered, this, &GoatView::open_scene); nuclear@73: menu_file->addAction(act_open_sce); nuclear@73: nuclear@73: QAction *act_open_anm = new QAction("Open &Animation", this); nuclear@73: connect(act_open_anm, &QAction::triggered, this, &GoatView::open_anim); nuclear@73: menu_file->addAction(act_open_anm); nuclear@73: nuclear@73: QAction *act_quit = new QAction("&Quit", this); nuclear@73: act_quit->setShortcuts(QKeySequence::Quit); nuclear@73: connect(act_quit, &QAction::triggered, [&](){qApp->quit();}); nuclear@73: menu_file->addAction(act_quit); nuclear@73: return true; nuclear@73: } nuclear@73: nuclear@73: bool GoatView::make_dock() nuclear@73: { nuclear@73: // ---- side-dock ---- nuclear@73: QWidget *dock_cont = new QWidget; nuclear@73: QVBoxLayout *dock_vbox = new QVBoxLayout; nuclear@73: dock_cont->setLayout(dock_vbox); nuclear@73: nuclear@73: QPushButton *bn_quit = new QPushButton("quit"); nuclear@73: dock_vbox->addWidget(bn_quit); nuclear@73: connect(bn_quit, &QPushButton::clicked, [&](){qApp->quit();}); nuclear@73: nuclear@73: QDockWidget *dock = new QDockWidget("Scene graph", this); nuclear@73: dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); nuclear@73: dock->setWidget(dock_cont); nuclear@73: addDockWidget(Qt::LeftDockWidgetArea, dock); nuclear@73: nuclear@73: // ---- bottom dock ---- nuclear@73: dock_cont = new QWidget; nuclear@73: QHBoxLayout *dock_hbox = new QHBoxLayout; nuclear@73: dock_cont->setLayout(dock_hbox); nuclear@73: nuclear@73: QSlider *slider_time = new QSlider(Qt::Orientation::Horizontal); nuclear@73: slider_time->setDisabled(true); nuclear@73: dock_hbox->addWidget(slider_time); nuclear@73: nuclear@73: dock = new QDockWidget("Animation", this); nuclear@73: dock->setAllowedAreas(Qt::BottomDockWidgetArea); nuclear@73: dock->setWidget(dock_cont); nuclear@73: addDockWidget(Qt::BottomDockWidgetArea, dock); nuclear@73: nuclear@73: return true; nuclear@73: } nuclear@73: nuclear@73: bool GoatView::make_center() nuclear@73: { nuclear@73: GoatViewport *vport = new GoatViewport; nuclear@73: setCentralWidget(vport); nuclear@73: return true; nuclear@73: } nuclear@73: nuclear@73: void GoatView::open_scene() nuclear@73: { nuclear@74: std::string fname = QFileDialog::getOpenFileName(this, "Open scene file", "", nuclear@74: "Goat3D Scene (*.goatsce);;All Files (*)").toStdString(); nuclear@74: if(fname.empty()) { nuclear@74: statusBar()->showMessage("Abort: No file selected!"); nuclear@74: return; nuclear@74: } nuclear@74: nuclear@74: statusBar()->showMessage("opening scene file"); nuclear@76: if(!load_scene(fname.c_str())) { nuclear@74: statusBar()->showMessage("failed to load scene file"); nuclear@74: } nuclear@73: } nuclear@73: nuclear@73: void GoatView::open_anim() nuclear@73: { nuclear@73: statusBar()->showMessage("opening animation..."); nuclear@73: } nuclear@73: nuclear@73: nuclear@73: // ---- OpenGL viewport ---- nuclear@73: GoatViewport::GoatViewport() nuclear@73: : QGLWidget(QGLFormat(QGL::DepthBuffer)) nuclear@73: { nuclear@73: } nuclear@73: nuclear@73: GoatViewport::~GoatViewport() nuclear@73: { nuclear@73: } nuclear@73: nuclear@73: QSize GoatViewport::sizeHint() const nuclear@73: { nuclear@73: return QSize(800, 600); nuclear@73: } nuclear@73: nuclear@73: void GoatViewport::initializeGL() nuclear@73: { nuclear@79: init_opengl(); nuclear@79: nuclear@79: glClearColor(0.1f, 0.1f, 0.1f, 1.0f); nuclear@78: nuclear@78: glEnable(GL_DEPTH_TEST); nuclear@78: glEnable(GL_CULL_FACE); nuclear@73: } nuclear@73: nuclear@73: void GoatViewport::resizeGL(int xsz, int ysz) nuclear@73: { nuclear@73: glViewport(0, 0, xsz, ysz); nuclear@75: glMatrixMode(GL_PROJECTION); nuclear@75: glLoadIdentity(); nuclear@75: gluPerspective(60.0, (float)xsz / (float)ysz, 0.5, 5000.0); nuclear@73: } nuclear@73: nuclear@73: void GoatViewport::paintGL() nuclear@73: { nuclear@75: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@75: nuclear@75: glMatrixMode(GL_MODELVIEW); nuclear@75: glLoadIdentity(); nuclear@75: glTranslatef(0, 0, -cam_dist); nuclear@75: glRotatef(cam_phi, 1, 0, 0); nuclear@75: glRotatef(cam_theta, 0, 1, 0); nuclear@75: nuclear@75: if(scene) { nuclear@75: int node_count = goat3d_get_node_count(scene); nuclear@75: for(int i=0; ix(); nuclear@78: prev_y = ev->y(); nuclear@78: } nuclear@78: nuclear@78: void GoatViewport::mouseMoveEvent(QMouseEvent *ev) nuclear@78: { nuclear@78: int dx = ev->x() - prev_x; nuclear@78: int dy = ev->y() - prev_y; nuclear@78: nuclear@78: if(!dx && !dy) return; nuclear@78: nuclear@78: if(ev->buttons() & Qt::LeftButton) { nuclear@78: cam_theta += dx * 0.5; nuclear@78: cam_phi += dy * 0.5; nuclear@78: nuclear@78: if(cam_phi < -90) cam_phi = -90; nuclear@78: if(cam_phi > 90) cam_phi = 90; nuclear@78: } nuclear@78: if(ev->buttons() & Qt::RightButton) { nuclear@78: cam_dist += dy * 0.1; nuclear@78: nuclear@78: if(cam_dist < 0.0) cam_dist = 0.0; nuclear@78: } nuclear@78: updateGL(); nuclear@78: }