goat3d

annotate goatview/src/goatview.cc @ 82:70b7c41a4f17

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 11 May 2014 22:04:54 +0300
parents c5e997e8fd62
children 57e745dd13c2
rev   line source
nuclear@78 1 #include <stdio.h>
nuclear@82 2 #include "opengl.h"
nuclear@76 3 #include <QtOpenGL/QtOpenGL>
nuclear@76 4 #include <vmath/vmath.h>
nuclear@73 5 #include "goatview.h"
nuclear@74 6 #include "goat3d.h"
nuclear@74 7
nuclear@82 8 static void update_tree(QTreeWidget *tree);
nuclear@82 9 static void add_tree(QTreeWidget *tree, goat3d_node *node, QTreeWidgetItem *parent);
nuclear@82 10
nuclear@78 11 static void draw_node(goat3d_node *node);
nuclear@82 12 static void draw_mesh(goat3d_mesh *mesh);
nuclear@78 13
nuclear@74 14 goat3d *scene;
nuclear@75 15
nuclear@75 16 static long anim_time;
nuclear@75 17 static float cam_theta, cam_phi, cam_dist = 8;
nuclear@76 18 static float fov = 60.0;
nuclear@82 19 static bool use_nodes = true;
nuclear@75 20
nuclear@82 21
nuclear@82 22 GoatView::GoatView()
nuclear@82 23 {
nuclear@82 24 glview = 0;
nuclear@82 25
nuclear@82 26 make_menu();
nuclear@82 27 make_dock();
nuclear@82 28 make_center();
nuclear@82 29
nuclear@82 30 statusBar();
nuclear@82 31
nuclear@82 32 setWindowTitle("GoatView");
nuclear@82 33
nuclear@82 34 QSettings *settings = new QSettings;
nuclear@82 35 resize(settings->value("main/size", QSize(1024, 768)).toSize());
nuclear@82 36 move(settings->value("main/pos", QPoint(100, 100)).toPoint());
nuclear@82 37 delete settings;
nuclear@82 38 }
nuclear@82 39
nuclear@82 40 GoatView::~GoatView()
nuclear@82 41 {
nuclear@82 42 }
nuclear@82 43
nuclear@82 44 bool GoatView::load_scene(const char *fname)
nuclear@76 45 {
nuclear@76 46 if(scene) {
nuclear@76 47 goat3d_free(scene);
nuclear@76 48 }
nuclear@76 49 if(!(scene = goat3d_create()) || goat3d_load(scene, fname) == -1) {
nuclear@76 50 return false;
nuclear@76 51 }
nuclear@76 52
nuclear@76 53 float bmin[3], bmax[3];
nuclear@82 54 if(goat3d_get_bounds(scene, bmin, bmax) != -1) {
nuclear@82 55 float bsize = (Vector3(bmax[0], bmax[1], bmax[2]) - Vector3(bmin[0], bmin[1], bmin[2])).length();
nuclear@82 56 cam_dist = bsize / tan(DEG_TO_RAD(fov) / 2.0) + bsize;
nuclear@82 57 printf("bounds size: %f, cam_dist: %f\n", bsize, cam_dist);
nuclear@82 58 }
nuclear@76 59
nuclear@82 60 update_tree(scntree);
nuclear@76 61 return true;
nuclear@76 62 }
nuclear@73 63
nuclear@75 64 void GoatView::closeEvent(QCloseEvent *ev)
nuclear@75 65 {
nuclear@82 66 QSettings *settings = new QSettings;
nuclear@75 67 settings->setValue("main/size", size());
nuclear@75 68 settings->setValue("main/pos", pos());
nuclear@82 69 delete settings;
nuclear@75 70 }
nuclear@75 71
nuclear@73 72 bool GoatView::make_menu()
nuclear@73 73 {
nuclear@82 74 // file menu
nuclear@73 75 QMenu *menu_file = menuBar()->addMenu("&File");
nuclear@73 76
nuclear@73 77 QAction *act_open_sce = new QAction("&Open Scene", this);
nuclear@73 78 act_open_sce->setShortcuts(QKeySequence::Open);
nuclear@73 79 connect(act_open_sce, &QAction::triggered, this, &GoatView::open_scene);
nuclear@73 80 menu_file->addAction(act_open_sce);
nuclear@73 81
nuclear@73 82 QAction *act_open_anm = new QAction("Open &Animation", this);
nuclear@73 83 connect(act_open_anm, &QAction::triggered, this, &GoatView::open_anim);
nuclear@73 84 menu_file->addAction(act_open_anm);
nuclear@73 85
nuclear@73 86 QAction *act_quit = new QAction("&Quit", this);
nuclear@73 87 act_quit->setShortcuts(QKeySequence::Quit);
nuclear@73 88 connect(act_quit, &QAction::triggered, [&](){qApp->quit();});
nuclear@73 89 menu_file->addAction(act_quit);
nuclear@82 90
nuclear@82 91 // view menu
nuclear@82 92 QMenu *menu_view = menuBar()->addMenu("&View");
nuclear@82 93
nuclear@82 94 QAction *act_use_nodes = new QAction("use nodes", this);
nuclear@82 95 act_use_nodes->setCheckable(true);
nuclear@82 96 act_use_nodes->setChecked(use_nodes);
nuclear@82 97 connect(act_use_nodes, &QAction::triggered, this, [&](){use_nodes = !use_nodes; glview->updateGL();});
nuclear@82 98 menu_view->addAction(act_use_nodes);
nuclear@73 99 return true;
nuclear@73 100 }
nuclear@73 101
nuclear@73 102 bool GoatView::make_dock()
nuclear@73 103 {
nuclear@73 104 // ---- side-dock ----
nuclear@73 105 QWidget *dock_cont = new QWidget;
nuclear@73 106 QVBoxLayout *dock_vbox = new QVBoxLayout;
nuclear@73 107 dock_cont->setLayout(dock_vbox);
nuclear@73 108
nuclear@73 109 QDockWidget *dock = new QDockWidget("Scene graph", this);
nuclear@73 110 dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
nuclear@73 111 dock->setWidget(dock_cont);
nuclear@73 112 addDockWidget(Qt::LeftDockWidgetArea, dock);
nuclear@73 113
nuclear@82 114 // make the tree view widget
nuclear@82 115 scntree = new QTreeWidget;
nuclear@82 116 scntree->setColumnCount(1);
nuclear@82 117 QStringList hdrstr;
nuclear@82 118 hdrstr << "Node";// << "Type";
nuclear@82 119 scntree->setHeaderItem(new QTreeWidgetItem((QTreeWidget*)0, hdrstr));
nuclear@82 120 scntree->setAlternatingRowColors(true);
nuclear@82 121 dock_vbox->addWidget(scntree);
nuclear@82 122
nuclear@82 123 update_tree(scntree);
nuclear@82 124
nuclear@82 125 // misc
nuclear@82 126 QPushButton *bn_quit = new QPushButton("quit");
nuclear@82 127 dock_vbox->addWidget(bn_quit);
nuclear@82 128 connect(bn_quit, &QPushButton::clicked, [&](){qApp->quit();});
nuclear@82 129
nuclear@73 130 // ---- bottom dock ----
nuclear@73 131 dock_cont = new QWidget;
nuclear@73 132 QHBoxLayout *dock_hbox = new QHBoxLayout;
nuclear@73 133 dock_cont->setLayout(dock_hbox);
nuclear@73 134
nuclear@73 135 QSlider *slider_time = new QSlider(Qt::Orientation::Horizontal);
nuclear@73 136 slider_time->setDisabled(true);
nuclear@73 137 dock_hbox->addWidget(slider_time);
nuclear@73 138
nuclear@73 139 dock = new QDockWidget("Animation", this);
nuclear@73 140 dock->setAllowedAreas(Qt::BottomDockWidgetArea);
nuclear@73 141 dock->setWidget(dock_cont);
nuclear@73 142 addDockWidget(Qt::BottomDockWidgetArea, dock);
nuclear@73 143
nuclear@73 144 return true;
nuclear@73 145 }
nuclear@73 146
nuclear@73 147 bool GoatView::make_center()
nuclear@73 148 {
nuclear@82 149 glview = new GoatViewport(this);
nuclear@82 150 setCentralWidget(glview);
nuclear@73 151 return true;
nuclear@73 152 }
nuclear@73 153
nuclear@73 154 void GoatView::open_scene()
nuclear@73 155 {
nuclear@74 156 std::string fname = QFileDialog::getOpenFileName(this, "Open scene file", "",
nuclear@74 157 "Goat3D Scene (*.goatsce);;All Files (*)").toStdString();
nuclear@74 158 if(fname.empty()) {
nuclear@74 159 statusBar()->showMessage("Abort: No file selected!");
nuclear@74 160 return;
nuclear@74 161 }
nuclear@74 162
nuclear@74 163 statusBar()->showMessage("opening scene file");
nuclear@76 164 if(!load_scene(fname.c_str())) {
nuclear@74 165 statusBar()->showMessage("failed to load scene file");
nuclear@74 166 }
nuclear@73 167 }
nuclear@73 168
nuclear@73 169 void GoatView::open_anim()
nuclear@73 170 {
nuclear@73 171 statusBar()->showMessage("opening animation...");
nuclear@73 172 }
nuclear@73 173
nuclear@82 174 static void update_tree(QTreeWidget *tree)
nuclear@82 175 {
nuclear@82 176 if(!scene) return;
nuclear@82 177
nuclear@82 178 int num_nodes = goat3d_get_node_count(scene);
nuclear@82 179 for(int i=0; i<num_nodes; i++) {
nuclear@82 180 goat3d_node *node = goat3d_get_node(scene, i);
nuclear@82 181 if(goat3d_get_node_parent(node)) {
nuclear@82 182 continue;
nuclear@82 183 }
nuclear@82 184
nuclear@82 185 // only add the root nodes, the rest will be added recursively by them
nuclear@82 186 add_tree(tree, node, 0);
nuclear@82 187 }
nuclear@82 188 tree->expandAll();
nuclear@82 189 }
nuclear@82 190
nuclear@82 191 static void add_tree(QTreeWidget *tree, goat3d_node *node, QTreeWidgetItem *parent)
nuclear@82 192 {
nuclear@82 193 //char icon_name[64];
nuclear@82 194 //sprintf(icon_name, ":/icons/icons/icon_%s.png", node->get_type());
nuclear@82 195
nuclear@82 196 QStringList row;
nuclear@82 197 row << goat3d_get_node_name(node) << "M";
nuclear@82 198 QTreeWidgetItem *item = new QTreeWidgetItem(parent, row);
nuclear@82 199 //item->setIcon(0, QIcon(icon_name));
nuclear@82 200 tree->addTopLevelItem(item);
nuclear@82 201
nuclear@82 202 int num_children = goat3d_get_node_child_count(node);
nuclear@82 203 for(int i=0; i<num_children; i++) {
nuclear@82 204 add_tree(tree, goat3d_get_node_child(node, i), item);
nuclear@82 205 }
nuclear@82 206 }
nuclear@82 207
nuclear@82 208
nuclear@73 209
nuclear@73 210 // ---- OpenGL viewport ----
nuclear@82 211 GoatViewport::GoatViewport(QWidget *main_win)
nuclear@73 212 : QGLWidget(QGLFormat(QGL::DepthBuffer))
nuclear@73 213 {
nuclear@82 214 this->main_win = main_win;
nuclear@82 215 initialized = false;
nuclear@73 216 }
nuclear@73 217
nuclear@73 218 GoatViewport::~GoatViewport()
nuclear@73 219 {
nuclear@73 220 }
nuclear@73 221
nuclear@73 222 QSize GoatViewport::sizeHint() const
nuclear@73 223 {
nuclear@73 224 return QSize(800, 600);
nuclear@73 225 }
nuclear@73 226
nuclear@82 227 #define CRITICAL(error, detail) \
nuclear@82 228 do { \
nuclear@82 229 fprintf(stderr, "%s: %s\n", error, detail); \
nuclear@82 230 QMessageBox::critical(main_win, error, detail); \
nuclear@82 231 abort(); \
nuclear@82 232 } while(0)
nuclear@82 233
nuclear@73 234 void GoatViewport::initializeGL()
nuclear@73 235 {
nuclear@82 236 if(initialized) return;
nuclear@82 237 initialized = true;
nuclear@82 238
nuclear@79 239 init_opengl();
nuclear@79 240
nuclear@82 241 if(!GLEW_ARB_transpose_matrix) {
nuclear@82 242 CRITICAL("OpenGL initialization failed", "ARB_transpose_matrix extension not found!");
nuclear@82 243 }
nuclear@82 244
nuclear@79 245 glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
nuclear@78 246
nuclear@78 247 glEnable(GL_DEPTH_TEST);
nuclear@78 248 glEnable(GL_CULL_FACE);
nuclear@73 249 }
nuclear@73 250
nuclear@73 251 void GoatViewport::resizeGL(int xsz, int ysz)
nuclear@73 252 {
nuclear@73 253 glViewport(0, 0, xsz, ysz);
nuclear@75 254 glMatrixMode(GL_PROJECTION);
nuclear@75 255 glLoadIdentity();
nuclear@75 256 gluPerspective(60.0, (float)xsz / (float)ysz, 0.5, 5000.0);
nuclear@73 257 }
nuclear@73 258
nuclear@73 259 void GoatViewport::paintGL()
nuclear@73 260 {
nuclear@75 261 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@75 262
nuclear@75 263 glMatrixMode(GL_MODELVIEW);
nuclear@75 264 glLoadIdentity();
nuclear@75 265 glTranslatef(0, 0, -cam_dist);
nuclear@75 266 glRotatef(cam_phi, 1, 0, 0);
nuclear@75 267 glRotatef(cam_theta, 0, 1, 0);
nuclear@75 268
nuclear@82 269 if(!scene) return;
nuclear@82 270
nuclear@82 271 if(use_nodes) {
nuclear@75 272 int node_count = goat3d_get_node_count(scene);
nuclear@75 273 for(int i=0; i<node_count; i++) {
nuclear@75 274 goat3d_node *node = goat3d_get_node(scene, i);
nuclear@82 275 draw_node(node); // only draw root nodes, the rest will be drawn recursively
nuclear@82 276 }
nuclear@82 277 } else {
nuclear@82 278 int mesh_count = goat3d_get_mesh_count(scene);
nuclear@82 279 for(int i=0; i<mesh_count; i++) {
nuclear@82 280 goat3d_mesh *mesh = goat3d_get_mesh(scene, i);
nuclear@82 281 draw_mesh(mesh);
nuclear@75 282 }
nuclear@75 283 }
nuclear@73 284 }
nuclear@75 285
nuclear@82 286 #ifndef GLEW_ARB_transpose_matrix
nuclear@82 287 #error "GLEW_ARB_transpose_matrix undefined?"
nuclear@82 288 #endif
nuclear@82 289
nuclear@75 290 static void draw_node(goat3d_node *node)
nuclear@75 291 {
nuclear@75 292 float xform[16];
nuclear@75 293 goat3d_get_node_matrix(node, xform, anim_time);
nuclear@78 294
nuclear@78 295 glPushMatrix();
nuclear@82 296 glMultTransposeMatrixf(xform);
nuclear@75 297
nuclear@75 298 if(goat3d_get_node_type(node) == GOAT3D_NODE_MESH) {
nuclear@75 299 goat3d_mesh *mesh = (goat3d_mesh*)goat3d_get_node_object(node);
nuclear@75 300
nuclear@82 301 draw_mesh(mesh);
nuclear@75 302 }
nuclear@75 303
nuclear@80 304 /*int num_child = goat3d_get_node_child_count(node);
nuclear@75 305 for(int i=0; i<num_child; i++) {
nuclear@75 306 draw_node(goat3d_get_node_child(node, i));
nuclear@80 307 }*/
nuclear@78 308
nuclear@78 309 glPopMatrix();
nuclear@78 310 }
nuclear@78 311
nuclear@82 312 static void draw_mesh(goat3d_mesh *mesh)
nuclear@82 313 {
nuclear@82 314 int num_faces = goat3d_get_mesh_face_count(mesh);
nuclear@82 315 int num_verts = goat3d_get_mesh_attrib_count(mesh, GOAT3D_MESH_ATTR_VERTEX);
nuclear@82 316
nuclear@82 317 glEnableClientState(GL_VERTEX_ARRAY);
nuclear@82 318 glVertexPointer(3, GL_FLOAT, 0, goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX));
nuclear@82 319
nuclear@82 320 float *data;
nuclear@82 321 if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL))) {
nuclear@82 322 glEnableClientState(GL_NORMAL_ARRAY);
nuclear@82 323 glNormalPointer(GL_FLOAT, 0, data);
nuclear@82 324 }
nuclear@82 325 if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD))) {
nuclear@82 326 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
nuclear@82 327 glTexCoordPointer(2, GL_FLOAT, 0, data);
nuclear@82 328 }
nuclear@82 329
nuclear@82 330 int *indices;
nuclear@82 331 if((indices = goat3d_get_mesh_faces(mesh))) {
nuclear@82 332 glDrawElements(GL_TRIANGLES, num_faces * 3, GL_UNSIGNED_INT, indices);
nuclear@82 333 } else {
nuclear@82 334 glDrawArrays(GL_TRIANGLES, 0, num_verts * 3);
nuclear@82 335 }
nuclear@82 336
nuclear@82 337 glDisableClientState(GL_VERTEX_ARRAY);
nuclear@82 338 glDisableClientState(GL_NORMAL_ARRAY);
nuclear@82 339 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
nuclear@82 340 }
nuclear@82 341
nuclear@78 342
nuclear@78 343 static float prev_x, prev_y;
nuclear@78 344 void GoatViewport::mousePressEvent(QMouseEvent *ev)
nuclear@78 345 {
nuclear@78 346 prev_x = ev->x();
nuclear@78 347 prev_y = ev->y();
nuclear@78 348 }
nuclear@78 349
nuclear@78 350 void GoatViewport::mouseMoveEvent(QMouseEvent *ev)
nuclear@78 351 {
nuclear@78 352 int dx = ev->x() - prev_x;
nuclear@78 353 int dy = ev->y() - prev_y;
nuclear@80 354 prev_x = ev->x();
nuclear@80 355 prev_y = ev->y();
nuclear@78 356
nuclear@78 357 if(!dx && !dy) return;
nuclear@78 358
nuclear@78 359 if(ev->buttons() & Qt::LeftButton) {
nuclear@78 360 cam_theta += dx * 0.5;
nuclear@78 361 cam_phi += dy * 0.5;
nuclear@78 362
nuclear@78 363 if(cam_phi < -90) cam_phi = -90;
nuclear@78 364 if(cam_phi > 90) cam_phi = 90;
nuclear@78 365 }
nuclear@78 366 if(ev->buttons() & Qt::RightButton) {
nuclear@78 367 cam_dist += dy * 0.1;
nuclear@78 368
nuclear@78 369 if(cam_dist < 0.0) cam_dist = 0.0;
nuclear@78 370 }
nuclear@78 371 updateGL();
nuclear@78 372 }