goat3d

changeset 82:70b7c41a4f17

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 11 May 2014 22:04:54 +0300
parents 7458b8568463
children 57e745dd13c2
files goatview/Makefile goatview/src/goatview.cc goatview/src/goatview.h goatview/src/main.cc goatview/src/opengl.h src/aabox.cc src/aabox.h src/goat3d.cc src/goat3d.h src/goat3d_writexml.cc
diffstat 10 files changed, 208 insertions(+), 80 deletions(-) [+]
line diff
     1.1 --- a/goatview/Makefile	Thu May 08 23:05:29 2014 +0300
     1.2 +++ b/goatview/Makefile	Sun May 11 22:04:54 2014 +0300
     1.3 @@ -10,7 +10,7 @@
     1.4  
     1.5  goat_root = ..
     1.6  
     1.7 -CFLAGS = -pedantic -Wall -g $(pic) -I$(goat_root)/src $(qtinc)
     1.8 +CFLAGS = -Wall -Wno-cpp -g $(pic) -I$(goat_root)/src $(qtinc)
     1.9  CXXFLAGS = -std=c++11 $(CFLAGS)
    1.10  LDFLAGS = $(libgoat) $(libgl) $(qtlib) -lvmath
    1.11  MOC = moc
     2.1 --- a/goatview/src/goatview.cc	Thu May 08 23:05:29 2014 +0300
     2.2 +++ b/goatview/src/goatview.cc	Sun May 11 22:04:54 2014 +0300
     2.3 @@ -1,20 +1,47 @@
     2.4  #include <stdio.h>
     2.5 +#include "opengl.h"
     2.6  #include <QtOpenGL/QtOpenGL>
     2.7 -#include "opengl.h"
     2.8  #include <vmath/vmath.h>
     2.9  #include "goatview.h"
    2.10  #include "goat3d.h"
    2.11  
    2.12 +static void update_tree(QTreeWidget *tree);
    2.13 +static void add_tree(QTreeWidget *tree, goat3d_node *node, QTreeWidgetItem *parent);
    2.14 +
    2.15  static void draw_node(goat3d_node *node);
    2.16 +static void draw_mesh(goat3d_mesh *mesh);
    2.17  
    2.18  goat3d *scene;
    2.19 -QSettings *settings;
    2.20  
    2.21  static long anim_time;
    2.22  static float cam_theta, cam_phi, cam_dist = 8;
    2.23  static float fov = 60.0;
    2.24 +static bool use_nodes = true;
    2.25  
    2.26 -bool load_scene(const char *fname)
    2.27 +
    2.28 +GoatView::GoatView()
    2.29 +{
    2.30 +	glview = 0;
    2.31 +
    2.32 +	make_menu();
    2.33 +	make_dock();
    2.34 +	make_center();
    2.35 +
    2.36 +	statusBar();
    2.37 +
    2.38 +	setWindowTitle("GoatView");
    2.39 +
    2.40 +	QSettings *settings = new QSettings;
    2.41 +	resize(settings->value("main/size", QSize(1024, 768)).toSize());
    2.42 +	move(settings->value("main/pos", QPoint(100, 100)).toPoint());
    2.43 +	delete settings;
    2.44 +}
    2.45 +
    2.46 +GoatView::~GoatView()
    2.47 +{
    2.48 +}
    2.49 +
    2.50 +bool GoatView::load_scene(const char *fname)
    2.51  {
    2.52  	if(scene) {
    2.53  		goat3d_free(scene);
    2.54 @@ -24,39 +51,27 @@
    2.55  	}
    2.56  
    2.57  	float bmin[3], bmax[3];
    2.58 -	goat3d_get_bounds(scene, bmin, bmax);
    2.59 -	float bsize = (Vector3(bmax[0], bmax[1], bmax[2]) - Vector3(bmin[0], bmin[1], bmin[2])).length();
    2.60 -	cam_dist = bsize / tan(DEG_TO_RAD(fov) / 2.0) + bsize;
    2.61 +	if(goat3d_get_bounds(scene, bmin, bmax) != -1) {
    2.62 +		float bsize = (Vector3(bmax[0], bmax[1], bmax[2]) - Vector3(bmin[0], bmin[1], bmin[2])).length();
    2.63 +		cam_dist = bsize / tan(DEG_TO_RAD(fov) / 2.0) + bsize;
    2.64 +		printf("bounds size: %f, cam_dist: %f\n", bsize, cam_dist);
    2.65 +	}
    2.66  
    2.67 -	printf("bounds size: %f, cam_dist: %f\n", bsize, cam_dist);
    2.68 +	update_tree(scntree);
    2.69  	return true;
    2.70  }
    2.71  
    2.72 -GoatView::GoatView()
    2.73 -{
    2.74 -	make_menu();
    2.75 -	make_dock();
    2.76 -	make_center();
    2.77 -
    2.78 -	statusBar();
    2.79 -
    2.80 -	setWindowTitle("GoatView");
    2.81 -	resize(settings->value("main/size", QSize(1024, 768)).toSize());
    2.82 -	move(settings->value("main/pos", QPoint(100, 100)).toPoint());
    2.83 -}
    2.84 -
    2.85 -GoatView::~GoatView()
    2.86 -{
    2.87 -}
    2.88 -
    2.89  void GoatView::closeEvent(QCloseEvent *ev)
    2.90  {
    2.91 +	QSettings *settings = new QSettings;
    2.92  	settings->setValue("main/size", size());
    2.93  	settings->setValue("main/pos", pos());
    2.94 +	delete settings;
    2.95  }
    2.96  
    2.97  bool GoatView::make_menu()
    2.98  {
    2.99 +	// file menu
   2.100  	QMenu *menu_file = menuBar()->addMenu("&File");
   2.101  
   2.102  	QAction *act_open_sce = new QAction("&Open Scene", this);
   2.103 @@ -72,6 +87,15 @@
   2.104  	act_quit->setShortcuts(QKeySequence::Quit);
   2.105  	connect(act_quit, &QAction::triggered, [&](){qApp->quit();});
   2.106  	menu_file->addAction(act_quit);
   2.107 +
   2.108 +	// view menu
   2.109 +	QMenu *menu_view = menuBar()->addMenu("&View");
   2.110 +
   2.111 +	QAction *act_use_nodes = new QAction("use nodes", this);
   2.112 +	act_use_nodes->setCheckable(true);
   2.113 +	act_use_nodes->setChecked(use_nodes);
   2.114 +	connect(act_use_nodes, &QAction::triggered, this, [&](){use_nodes = !use_nodes; glview->updateGL();});
   2.115 +	menu_view->addAction(act_use_nodes);
   2.116  	return true;
   2.117  }
   2.118  
   2.119 @@ -82,15 +106,27 @@
   2.120  	QVBoxLayout *dock_vbox = new QVBoxLayout;
   2.121  	dock_cont->setLayout(dock_vbox);
   2.122  
   2.123 -	QPushButton *bn_quit = new QPushButton("quit");
   2.124 -	dock_vbox->addWidget(bn_quit);
   2.125 -	connect(bn_quit, &QPushButton::clicked, [&](){qApp->quit();});
   2.126 -
   2.127  	QDockWidget *dock = new QDockWidget("Scene graph", this);
   2.128  	dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
   2.129  	dock->setWidget(dock_cont);
   2.130  	addDockWidget(Qt::LeftDockWidgetArea, dock);
   2.131  
   2.132 +	// make the tree view widget
   2.133 +	scntree = new QTreeWidget;
   2.134 +	scntree->setColumnCount(1);
   2.135 +	QStringList hdrstr;
   2.136 +	hdrstr << "Node";// << "Type";
   2.137 +	scntree->setHeaderItem(new QTreeWidgetItem((QTreeWidget*)0, hdrstr));
   2.138 +	scntree->setAlternatingRowColors(true);
   2.139 +	dock_vbox->addWidget(scntree);
   2.140 +
   2.141 +	update_tree(scntree);
   2.142 +
   2.143 +	// misc
   2.144 +	QPushButton *bn_quit = new QPushButton("quit");
   2.145 +	dock_vbox->addWidget(bn_quit);
   2.146 +	connect(bn_quit, &QPushButton::clicked, [&](){qApp->quit();});
   2.147 +
   2.148  	// ---- bottom dock ----
   2.149  	dock_cont = new QWidget;
   2.150  	QHBoxLayout *dock_hbox = new QHBoxLayout;
   2.151 @@ -110,8 +146,8 @@
   2.152  
   2.153  bool GoatView::make_center()
   2.154  {
   2.155 -	GoatViewport *vport = new GoatViewport;
   2.156 -	setCentralWidget(vport);
   2.157 +	glview = new GoatViewport(this);
   2.158 +	setCentralWidget(glview);
   2.159  	return true;
   2.160  }
   2.161  
   2.162 @@ -135,11 +171,48 @@
   2.163  	statusBar()->showMessage("opening animation...");
   2.164  }
   2.165  
   2.166 +static void update_tree(QTreeWidget *tree)
   2.167 +{
   2.168 +	if(!scene) return;
   2.169 +
   2.170 +	int num_nodes = goat3d_get_node_count(scene);
   2.171 +	for(int i=0; i<num_nodes; i++) {
   2.172 +		goat3d_node *node = goat3d_get_node(scene, i);
   2.173 +		if(goat3d_get_node_parent(node)) {
   2.174 +			continue;
   2.175 +		}
   2.176 +
   2.177 +		// only add the root nodes, the rest will be added recursively by them
   2.178 +		add_tree(tree, node, 0);
   2.179 +	}
   2.180 +	tree->expandAll();
   2.181 +}
   2.182 +
   2.183 +static void add_tree(QTreeWidget *tree, goat3d_node *node, QTreeWidgetItem *parent)
   2.184 +{
   2.185 +	//char icon_name[64];
   2.186 +	//sprintf(icon_name, ":/icons/icons/icon_%s.png", node->get_type());
   2.187 +
   2.188 +	QStringList row;
   2.189 +	row << goat3d_get_node_name(node) << "M";
   2.190 +	QTreeWidgetItem *item = new QTreeWidgetItem(parent, row);
   2.191 +	//item->setIcon(0, QIcon(icon_name));
   2.192 +	tree->addTopLevelItem(item);
   2.193 +
   2.194 +	int num_children = goat3d_get_node_child_count(node);
   2.195 +	for(int i=0; i<num_children; i++) {
   2.196 +		add_tree(tree, goat3d_get_node_child(node, i), item);
   2.197 +	}
   2.198 +}
   2.199 +
   2.200 +
   2.201  
   2.202  // ---- OpenGL viewport ----
   2.203 -GoatViewport::GoatViewport()
   2.204 +GoatViewport::GoatViewport(QWidget *main_win)
   2.205  	: QGLWidget(QGLFormat(QGL::DepthBuffer))
   2.206  {
   2.207 +	this->main_win = main_win;
   2.208 +	initialized = false;
   2.209  }
   2.210  
   2.211  GoatViewport::~GoatViewport()
   2.212 @@ -151,10 +224,24 @@
   2.213  	return QSize(800, 600);
   2.214  }
   2.215  
   2.216 +#define CRITICAL(error, detail)	\
   2.217 +	do { \
   2.218 +		fprintf(stderr, "%s: %s\n", error, detail); \
   2.219 +		QMessageBox::critical(main_win, error, detail); \
   2.220 +		abort(); \
   2.221 +	} while(0)
   2.222 +
   2.223  void GoatViewport::initializeGL()
   2.224  {
   2.225 +	if(initialized) return;
   2.226 +	initialized = true;
   2.227 +
   2.228  	init_opengl();
   2.229  
   2.230 +	if(!GLEW_ARB_transpose_matrix) {
   2.231 +		CRITICAL("OpenGL initialization failed", "ARB_transpose_matrix extension not found!");
   2.232 +	}
   2.233 +
   2.234  	glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
   2.235  
   2.236  	glEnable(GL_DEPTH_TEST);
   2.237 @@ -179,61 +266,39 @@
   2.238  	glRotatef(cam_phi, 1, 0, 0);
   2.239  	glRotatef(cam_theta, 0, 1, 0);
   2.240  
   2.241 -	if(scene) {
   2.242 +	if(!scene) return;
   2.243 +
   2.244 +	if(use_nodes) {
   2.245  		int node_count = goat3d_get_node_count(scene);
   2.246  		for(int i=0; i<node_count; i++) {
   2.247  			goat3d_node *node = goat3d_get_node(scene, i);
   2.248 -			//if(!goat3d_get_node_parent(node)) {
   2.249 -				draw_node(node);	// only draw root nodes, the rest will be drawn recursively
   2.250 -			//}
   2.251 +			draw_node(node);	// only draw root nodes, the rest will be drawn recursively
   2.252 +		}
   2.253 +	} else {
   2.254 +		int mesh_count = goat3d_get_mesh_count(scene);
   2.255 +		for(int i=0; i<mesh_count; i++) {
   2.256 +			goat3d_mesh *mesh = goat3d_get_mesh(scene, i);
   2.257 +			draw_mesh(mesh);
   2.258  		}
   2.259  	}
   2.260  }
   2.261  
   2.262 +#ifndef GLEW_ARB_transpose_matrix
   2.263 +#error "GLEW_ARB_transpose_matrix undefined?"
   2.264 +#endif
   2.265 +
   2.266  static void draw_node(goat3d_node *node)
   2.267  {
   2.268  	float xform[16];
   2.269  	goat3d_get_node_matrix(node, xform, anim_time);
   2.270 -	for(int i=0; i<4; i++) {
   2.271 -		for(int j=0; j<i; j++) {
   2.272 -			float tmp = xform[i * 4 + j];
   2.273 -			xform[i * 4 + j] = xform[j * 4 + i];
   2.274 -			xform[j * 4 + i] = tmp;
   2.275 -		}
   2.276 -	}
   2.277  
   2.278  	glPushMatrix();
   2.279 -	glMultMatrixf(xform);
   2.280 +	glMultTransposeMatrixf(xform);
   2.281  
   2.282  	if(goat3d_get_node_type(node) == GOAT3D_NODE_MESH) {
   2.283  		goat3d_mesh *mesh = (goat3d_mesh*)goat3d_get_node_object(node);
   2.284  
   2.285 -		int num_faces = goat3d_get_mesh_face_count(mesh);
   2.286 -		int num_verts = goat3d_get_mesh_attrib_count(mesh, GOAT3D_MESH_ATTR_VERTEX);
   2.287 -
   2.288 -		glEnableClientState(GL_VERTEX_ARRAY);
   2.289 -		glVertexPointer(3, GL_FLOAT, 0, goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX));
   2.290 -
   2.291 -		float *data;
   2.292 -		if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL))) {
   2.293 -			glEnableClientState(GL_NORMAL_ARRAY);
   2.294 -			glNormalPointer(GL_FLOAT, 0, data);
   2.295 -		}
   2.296 -		if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD))) {
   2.297 -			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   2.298 -			glTexCoordPointer(2, GL_FLOAT, 0, data);
   2.299 -		}
   2.300 -
   2.301 -		int *indices;
   2.302 -		if((indices = goat3d_get_mesh_faces(mesh))) {
   2.303 -			glDrawElements(GL_TRIANGLES, num_faces * 3, GL_UNSIGNED_INT, indices);
   2.304 -		} else {
   2.305 -			glDrawArrays(GL_TRIANGLES, 0, num_verts * 3);
   2.306 -		}
   2.307 -
   2.308 -		glDisableClientState(GL_VERTEX_ARRAY);
   2.309 -		glDisableClientState(GL_NORMAL_ARRAY);
   2.310 -		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   2.311 +		draw_mesh(mesh);
   2.312  	}
   2.313  
   2.314  	/*int num_child = goat3d_get_node_child_count(node);
   2.315 @@ -244,6 +309,36 @@
   2.316  	glPopMatrix();
   2.317  }
   2.318  
   2.319 +static void draw_mesh(goat3d_mesh *mesh)
   2.320 +{
   2.321 +	int num_faces = goat3d_get_mesh_face_count(mesh);
   2.322 +	int num_verts = goat3d_get_mesh_attrib_count(mesh, GOAT3D_MESH_ATTR_VERTEX);
   2.323 +
   2.324 +	glEnableClientState(GL_VERTEX_ARRAY);
   2.325 +	glVertexPointer(3, GL_FLOAT, 0, goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX));
   2.326 +
   2.327 +	float *data;
   2.328 +	if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL))) {
   2.329 +		glEnableClientState(GL_NORMAL_ARRAY);
   2.330 +		glNormalPointer(GL_FLOAT, 0, data);
   2.331 +	}
   2.332 +	if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD))) {
   2.333 +		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   2.334 +		glTexCoordPointer(2, GL_FLOAT, 0, data);
   2.335 +	}
   2.336 +
   2.337 +	int *indices;
   2.338 +	if((indices = goat3d_get_mesh_faces(mesh))) {
   2.339 +		glDrawElements(GL_TRIANGLES, num_faces * 3, GL_UNSIGNED_INT, indices);
   2.340 +	} else {
   2.341 +		glDrawArrays(GL_TRIANGLES, 0, num_verts * 3);
   2.342 +	}
   2.343 +
   2.344 +	glDisableClientState(GL_VERTEX_ARRAY);
   2.345 +	glDisableClientState(GL_NORMAL_ARRAY);
   2.346 +	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   2.347 +}
   2.348 +
   2.349  
   2.350  static float prev_x, prev_y;
   2.351  void GoatViewport::mousePressEvent(QMouseEvent *ev)
     3.1 --- a/goatview/src/goatview.h	Thu May 08 23:05:29 2014 +0300
     3.2 +++ b/goatview/src/goatview.h	Sun May 11 22:04:54 2014 +0300
     3.3 @@ -7,13 +7,16 @@
     3.4  #include "goat3d.h"
     3.5  
     3.6  extern goat3d *scene;
     3.7 -extern QSettings *settings;
     3.8  
     3.9 -bool load_scene(const char *fname);
    3.10 +class GoatViewport;
    3.11  
    3.12  class GoatView : public QMainWindow {
    3.13  	Q_OBJECT
    3.14  private:
    3.15 +	GoatViewport *glview;
    3.16 +	QStandardItemModel *sgmodel;	// scene graph model
    3.17 +	QTreeWidget *scntree;
    3.18 +
    3.19  	void closeEvent(QCloseEvent *ev);
    3.20  	bool make_menu();
    3.21  	bool make_dock();
    3.22 @@ -26,12 +29,19 @@
    3.23  public:
    3.24  	GoatView();
    3.25  	~GoatView();
    3.26 +
    3.27 +	bool load_scene(const char *fname);
    3.28  };
    3.29  
    3.30  class GoatViewport : public QGLWidget {
    3.31 +private:
    3.32  	Q_OBJECT
    3.33 +
    3.34 +	QWidget *main_win;
    3.35 +	bool initialized;
    3.36 +
    3.37  public:
    3.38 -	GoatViewport();
    3.39 +	GoatViewport(QWidget *main_win);
    3.40  	~GoatViewport();
    3.41  
    3.42  	QSize sizeHint() const;
     4.1 --- a/goatview/src/main.cc	Thu May 08 23:05:29 2014 +0300
     4.2 +++ b/goatview/src/main.cc	Sun May 11 22:04:54 2014 +0300
     4.3 @@ -8,7 +8,8 @@
     4.4  	app.setOrganizationName("Mutant Stargoat");
     4.5  	app.setOrganizationDomain("mutantstargoat.com");
     4.6  	app.setApplicationName("GoatView");
     4.7 -	settings = new QSettings;
     4.8 +
     4.9 +	GoatView gview;
    4.10  
    4.11  	QCommandLineParser argparse;
    4.12  	argparse.addHelpOption();
    4.13 @@ -25,7 +26,7 @@
    4.14  		}
    4.15  		std::string fname = args.at(0).toStdString();
    4.16  		printf("loading scene file: %s ...\n", fname.c_str());
    4.17 -		if(!load_scene(fname.c_str())) {
    4.18 +		if(!gview.load_scene(fname.c_str())) {
    4.19  			fprintf(stderr, "failed to load scene: %s\n", fname.c_str());
    4.20  			return 1;
    4.21  		}
    4.22 @@ -43,7 +44,6 @@
    4.23  		}
    4.24  	}
    4.25  
    4.26 -	GoatView gview;
    4.27  	gview.show();
    4.28  
    4.29  	return app.exec();
     5.1 --- a/goatview/src/opengl.h	Thu May 08 23:05:29 2014 +0300
     5.2 +++ b/goatview/src/opengl.h	Sun May 11 22:04:54 2014 +0300
     5.3 @@ -2,6 +2,7 @@
     5.4  #define OPENGL_H_
     5.5  
     5.6  #include <GL/glew.h>
     5.7 +#define QT_NO_OPENGL_ES_2
     5.8  
     5.9  #ifdef WIN32
    5.10  #include <windows.h>
    5.11 @@ -25,4 +26,4 @@
    5.12  }
    5.13  #endif
    5.14  
    5.15 -#endif	/* OPENGL_G_ */
    5.16 +#endif	/* OPENGL_H_ */
     6.1 --- a/src/aabox.cc	Thu May 08 23:05:29 2014 +0300
     6.2 +++ b/src/aabox.cc	Sun May 11 22:04:54 2014 +0300
     6.3 @@ -14,6 +14,16 @@
     6.4  {
     6.5  }
     6.6  
     6.7 +bool AABox::operator ==(const AABox &rhs) const
     6.8 +{
     6.9 +	return bmin == rhs.bmin && bmax == rhs.bmax;
    6.10 +}
    6.11 +
    6.12 +bool AABox::operator !=(const AABox &rhs) const
    6.13 +{
    6.14 +	return !(*this == rhs);
    6.15 +}
    6.16 +
    6.17  AABox g3dimpl::aabox_union(const AABox &a, const AABox &b)
    6.18  {
    6.19  	Vector3 bmin, bmax;
     7.1 --- a/src/aabox.h	Thu May 08 23:05:29 2014 +0300
     7.2 +++ b/src/aabox.h	Sun May 11 22:04:54 2014 +0300
     7.3 @@ -11,6 +11,9 @@
     7.4  
     7.5  	AABox();
     7.6  	AABox(const Vector3 &b0, const Vector3 &b1);
     7.7 +
     7.8 +	bool operator ==(const AABox &rhs) const;
     7.9 +	bool operator !=(const AABox &rhs) const;
    7.10  };
    7.11  
    7.12  AABox aabox_union(const AABox &a, const AABox &b);
     8.1 --- a/src/goat3d.cc	Thu May 08 23:05:29 2014 +0300
     8.2 +++ b/src/goat3d.cc	Sun May 11 22:04:54 2014 +0300
     8.3 @@ -253,13 +253,18 @@
     8.4  	return &g->scn->get_ambient().x;
     8.5  }
     8.6  
     8.7 -GOAT3DAPI void goat3d_get_bounds(const struct goat3d *g, float *bmin, float *bmax)
     8.8 +GOAT3DAPI int goat3d_get_bounds(const struct goat3d *g, float *bmin, float *bmax)
     8.9  {
    8.10  	AABox bbox = g->scn->get_bounds();
    8.11 +	if(bbox == AABox()) {
    8.12 +		return -1;
    8.13 +	}
    8.14 +
    8.15  	for(int i=0; i<3; i++) {
    8.16  		bmin[i] = bbox.bmin[i];
    8.17  		bmax[i] = bbox.bmax[i];
    8.18  	}
    8.19 +	return 0;
    8.20  }
    8.21  
    8.22  // ---- materials ----
    8.23 @@ -926,7 +931,7 @@
    8.24  
    8.25  GOAT3DAPI void goat3d_get_node_matrix(const struct goat3d_node *node, float *matrix, long tmsec)
    8.26  {
    8.27 -	node->get_xform(tmsec, (Matrix4x4*)matrix);
    8.28 +	node->get_node_xform(tmsec, (Matrix4x4*)matrix);
    8.29  }
    8.30  
    8.31  
     9.1 --- a/src/goat3d.h	Thu May 08 23:05:29 2014 +0300
     9.2 +++ b/src/goat3d.h	Sun May 11 22:04:54 2014 +0300
     9.3 @@ -123,7 +123,7 @@
     9.4  GOAT3DAPI void goat3d_set_ambient3f(struct goat3d *g, float ar, float ag, float ab);
     9.5  GOAT3DAPI const float *goat3d_get_ambient(const struct goat3d *g);
     9.6  
     9.7 -GOAT3DAPI void goat3d_get_bounds(const struct goat3d *g, float *bmin, float *bmax);
     9.8 +GOAT3DAPI int goat3d_get_bounds(const struct goat3d *g, float *bmin, float *bmax);
     9.9  
    9.10  /* materials */
    9.11  GOAT3DAPI void goat3d_add_mtl(struct goat3d *g, struct goat3d_material *mtl);
    10.1 --- a/src/goat3d_writexml.cc	Thu May 08 23:05:29 2014 +0300
    10.2 +++ b/src/goat3d_writexml.cc	Sun May 11 22:04:54 2014 +0300
    10.3 @@ -33,6 +33,8 @@
    10.4  
    10.5  bool Scene::savexml(goat3d_io *io) const
    10.6  {
    10.7 +	xmlout(io, 0, "<!-- vi:set filetype=xml: -->\n");
    10.8 +	xmlout(io, 0, "<!-- Goat3D XML scene description -->\n");
    10.9  	xmlout(io, 0, "<scene>\n");
   10.10  
   10.11  	// write environment stuff
   10.12 @@ -62,6 +64,8 @@
   10.13  
   10.14  bool Scene::save_anim_xml(goat3d_io *io) const
   10.15  {
   10.16 +	xmlout(io, 0, "<!-- vi:set filetype=xml: -->\n");
   10.17 +	xmlout(io, 0, "<!-- Goat3D XML animation -->\n");
   10.18  	xmlout(io, 0, "<anim>\n");
   10.19  
   10.20  	if(!nodes.empty()) {