goat3d
changeset 75:76dea247f75c
in progress
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 08 May 2014 00:50:16 +0300 |
parents | ab66cdabf6f2 |
children | 9785847d52d4 |
files | goatview/src/goatview.cc goatview/src/goatview.h goatview/src/main.cc src/aabox.cc src/aabox.h src/goat3d_impl.h src/goat3d_readxml.cc src/mesh.h src/node.cc src/node.h src/object.h src/scene.cc |
diffstat | 12 files changed, 327 insertions(+), 8 deletions(-) [+] |
line diff
1.1 --- a/goatview/src/goatview.cc Tue May 06 13:26:52 2014 +0300 1.2 +++ b/goatview/src/goatview.cc Thu May 08 00:50:16 2014 +0300 1.3 @@ -1,7 +1,13 @@ 1.4 +#include <GL/glu.h> 1.5 #include "goatview.h" 1.6 #include "goat3d.h" 1.7 1.8 goat3d *scene; 1.9 +QSettings *settings; 1.10 + 1.11 +static long anim_time; 1.12 +static float cam_theta, cam_phi, cam_dist = 8; 1.13 + 1.14 1.15 GoatView::GoatView() 1.16 { 1.17 @@ -12,12 +18,20 @@ 1.18 statusBar(); 1.19 1.20 setWindowTitle("GoatView"); 1.21 + resize(settings->value("main/size", QSize(1024, 768)).toSize()); 1.22 + move(settings->value("main/pos", QPoint(100, 100)).toPoint()); 1.23 } 1.24 1.25 GoatView::~GoatView() 1.26 { 1.27 } 1.28 1.29 +void GoatView::closeEvent(QCloseEvent *ev) 1.30 +{ 1.31 + settings->setValue("main/size", size()); 1.32 + settings->setValue("main/pos", pos()); 1.33 +} 1.34 + 1.35 bool GoatView::make_menu() 1.36 { 1.37 QMenu *menu_file = menuBar()->addMenu("&File"); 1.38 @@ -120,15 +134,79 @@ 1.39 1.40 void GoatViewport::initializeGL() 1.41 { 1.42 + glClearColor(0.1, 0.1, 0.1, 1); 1.43 } 1.44 1.45 void GoatViewport::resizeGL(int xsz, int ysz) 1.46 { 1.47 glViewport(0, 0, xsz, ysz); 1.48 + glMatrixMode(GL_PROJECTION); 1.49 + glLoadIdentity(); 1.50 + gluPerspective(60.0, (float)xsz / (float)ysz, 0.5, 5000.0); 1.51 } 1.52 1.53 +static void draw_node(goat3d_node *node); 1.54 + 1.55 void GoatViewport::paintGL() 1.56 { 1.57 - glClearColor(1, 0, 0, 1); 1.58 - glClear(GL_COLOR_BUFFER_BIT); 1.59 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.60 + 1.61 + glMatrixMode(GL_MODELVIEW); 1.62 + glLoadIdentity(); 1.63 + glTranslatef(0, 0, -cam_dist); 1.64 + glRotatef(cam_phi, 1, 0, 0); 1.65 + glRotatef(cam_theta, 0, 1, 0); 1.66 + 1.67 + if(scene) { 1.68 + int node_count = goat3d_get_node_count(scene); 1.69 + for(int i=0; i<node_count; i++) { 1.70 + goat3d_node *node = goat3d_get_node(scene, i); 1.71 + draw_node(node); 1.72 + } 1.73 + } 1.74 } 1.75 + 1.76 +static void draw_node(goat3d_node *node) 1.77 +{ 1.78 + float xform[16]; 1.79 + goat3d_get_node_matrix(node, xform, anim_time); 1.80 + glMultMatrixf(xform); 1.81 + 1.82 + if(goat3d_get_node_type(node) == GOAT3D_NODE_MESH) { 1.83 + goat3d_mesh *mesh = (goat3d_mesh*)goat3d_get_node_object(node); 1.84 + 1.85 + int num_faces = goat3d_get_mesh_face_count(mesh); 1.86 + int num_verts = goat3d_get_mesh_attrib_count(mesh, GOAT3D_MESH_ATTR_VERTEX); 1.87 + 1.88 + glEnableClientState(GL_VERTEX_ARRAY); 1.89 + glVertexPointer(3, GL_FLOAT, 0, goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX)); 1.90 + 1.91 + float *data; 1.92 + if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL))) { 1.93 + glEnableClientState(GL_NORMAL_ARRAY); 1.94 + glNormalPointer(GL_FLOAT, 0, data); 1.95 + } 1.96 + if((data = (float*)goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD))) { 1.97 + glEnableClientState(GL_TEXTURE_COORD_ARRAY); 1.98 + glTexCoordPointer(2, GL_FLOAT, 0, data); 1.99 + } 1.100 + 1.101 + int *indices; 1.102 + if((indices = goat3d_get_mesh_faces(mesh))) { 1.103 + glDrawElements(GL_TRIANGLES, num_faces * 3, GL_UNSIGNED_INT, indices); 1.104 + } else { 1.105 + glDrawArrays(GL_TRIANGLES, 0, num_verts * 3); 1.106 + } 1.107 + 1.108 + glDisableClientState(GL_VERTEX_ARRAY); 1.109 + glDisableClientState(GL_NORMAL_ARRAY); 1.110 + glDisableClientState(GL_TEXTURE_COORD_ARRAY); 1.111 + } 1.112 + 1.113 + int num_child = goat3d_get_node_child_count(node); 1.114 + for(int i=0; i<num_child; i++) { 1.115 + draw_node(goat3d_get_node_child(node, i)); 1.116 + } 1.117 +} 1.118 + 1.119 +
2.1 --- a/goatview/src/goatview.h Tue May 06 13:26:52 2014 +0300 2.2 +++ b/goatview/src/goatview.h Thu May 08 00:50:16 2014 +0300 2.3 @@ -1,15 +1,18 @@ 2.4 #ifndef GOATVIEW_H_ 2.5 #define GOATVIEW_H_ 2.6 2.7 +#include <QtCore/QtCore> 2.8 #include <QtWidgets/QtWidgets> 2.9 #include <QtOpenGL/QGLWidget> 2.10 #include "goat3d.h" 2.11 2.12 extern goat3d *scene; 2.13 +extern QSettings *settings; 2.14 2.15 class GoatView : public QMainWindow { 2.16 Q_OBJECT 2.17 private: 2.18 + void closeEvent(QCloseEvent *ev); 2.19 bool make_menu(); 2.20 bool make_dock(); 2.21 bool make_center();
3.1 --- a/goatview/src/main.cc Tue May 06 13:26:52 2014 +0300 3.2 +++ b/goatview/src/main.cc Thu May 08 00:50:16 2014 +0300 3.3 @@ -1,9 +1,47 @@ 3.4 #include <QtWidgets/QtWidgets> 3.5 +#include <QtCore/QtCore> 3.6 #include "goatview.h" 3.7 3.8 int main(int argc, char **argv) 3.9 { 3.10 QApplication app(argc, argv); 3.11 + app.setOrganizationName("Mutant Stargoat"); 3.12 + app.setOrganizationDomain("mutantstargoat.com"); 3.13 + app.setApplicationName("GoatView"); 3.14 + settings = new QSettings; 3.15 + 3.16 + QCommandLineParser argparse; 3.17 + argparse.addHelpOption(); 3.18 + 3.19 + argparse.addPositionalArgument("scene", "scene file to open"); 3.20 + argparse.addOption(QCommandLineOption("a", "add animation file")); 3.21 + argparse.process(app); 3.22 + 3.23 + const QStringList &args = argparse.positionalArguments(); 3.24 + if(!args.isEmpty()) { 3.25 + if(args.count() > 1) { 3.26 + fprintf(stderr, "please specify at most one scene file to open\n"); 3.27 + return 1; 3.28 + } 3.29 + std::string fname = args.at(0).toStdString(); 3.30 + printf("loading scene file: %s ...\n", fname.c_str()); 3.31 + if(!(scene = goat3d_create()) || goat3d_load(scene, fname.c_str())) { 3.32 + fprintf(stderr, "failed to load scene: %s\n", fname.c_str()); 3.33 + return 1; 3.34 + } 3.35 + } 3.36 + 3.37 + const QStringList &anims = argparse.values("a"); 3.38 + QStringList::const_iterator it = anims.begin(); 3.39 + while(it != anims.end()) { 3.40 + std::string fname = it++->toStdString(); 3.41 + printf("loading animation file: %s ...\n", fname.c_str()); 3.42 + 3.43 + if(goat3d_load_anim(scene, fname.c_str()) == -1) { 3.44 + fprintf(stderr, "failed to load animation: %s\n", fname.c_str()); 3.45 + return 1; 3.46 + } 3.47 + } 3.48 3.49 GoatView gview; 3.50 gview.show();
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/aabox.cc Thu May 08 00:50:16 2014 +0300 4.3 @@ -0,0 +1,27 @@ 4.4 +#include <float.h> 4.5 +#include <algorithm> 4.6 +#include "aabox.h" 4.7 + 4.8 +using namespace g3dimpl; 4.9 + 4.10 +AABox::AABox() 4.11 + : bmin(FLT_MAX, FLT_MAX, FLT_MAX), bmax(-FLT_MAX, -FLT_MAX, -FLT_MAX) 4.12 +{ 4.13 +} 4.14 + 4.15 +AABox::AABox(const Vector3 &b0, const Vector3 &b1) 4.16 + : bmin(b0), bmax(b1) 4.17 +{ 4.18 +} 4.19 + 4.20 +AABox g3dimpl::aabox_union(const AABox &a, const AABox &b) 4.21 +{ 4.22 + Vector3 bmin, bmax; 4.23 + 4.24 + for(int i=0; i<3; i++) { 4.25 + bmin[i] = std::min(a.bmin[i], b.bmin[i]); 4.26 + bmax[i] = std::max(a.bmax[i], b.bmax[i]); 4.27 + } 4.28 + 4.29 + return AABox(bmin, bmax); 4.30 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/aabox.h Thu May 08 00:50:16 2014 +0300 5.3 @@ -0,0 +1,20 @@ 5.4 +#ifndef AABOX_H_ 5.5 +#define AABOX_H_ 5.6 + 5.7 +#include <vmath/vmath.h> 5.8 + 5.9 +namespace g3dimpl { 5.10 + 5.11 +class AABox { 5.12 +public: 5.13 + Vector3 bmin, bmax; 5.14 + 5.15 + AABox(); 5.16 + AABox(const Vector3 &b0, const Vector3 &b1); 5.17 +}; 5.18 + 5.19 +AABox aabox_union(const AABox &a, const AABox &b); 5.20 + 5.21 +} 5.22 + 5.23 +#endif // AABOX_H_
6.1 --- a/src/goat3d_impl.h Tue May 06 13:26:52 2014 +0300 6.2 +++ b/src/goat3d_impl.h Thu May 08 00:50:16 2014 +0300 6.3 @@ -26,6 +26,7 @@ 6.4 #include "camera.h" 6.5 #include "material.h" 6.6 #include "node.h" 6.7 +#include "aabox.h" 6.8 6.9 namespace g3dimpl { 6.10 class Scene; 6.11 @@ -65,6 +66,9 @@ 6.12 std::vector<Camera*> cameras; 6.13 std::vector<Node*> nodes; 6.14 6.15 + mutable AABox bbox; 6.16 + mutable bool bbox_valid; 6.17 + 6.18 public: 6.19 goat3d *goat; 6.20 6.21 @@ -104,6 +108,8 @@ 6.22 Node *get_node(const char *name) const; 6.23 int get_node_count() const; 6.24 6.25 + const AABox &get_bounds() const; 6.26 + 6.27 bool load(goat3d_io *io); 6.28 bool save(goat3d_io *io) const; 6.29
7.1 --- a/src/goat3d_readxml.cc Tue May 06 13:26:52 2014 +0300 7.2 +++ b/src/goat3d_readxml.cc Thu May 08 00:50:16 2014 +0300 7.3 @@ -16,6 +16,8 @@ 7.4 along with this program. If not, see <http://www.gnu.org/licenses/>. 7.5 */ 7.6 #include <stdio.h> 7.7 +#include <map> 7.8 +#include <string> 7.9 #include "goat3d.h" 7.10 #include "goat3d_impl.h" 7.11 #include "tinyxml2.h" 7.12 @@ -27,7 +29,8 @@ 7.13 static Material *read_material(Scene *scn, XMLElement *xml_mtl); 7.14 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr); 7.15 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh); 7.16 -static std::string get_name(XMLElement *node, int idx); 7.17 +static Node *read_node(Scene *scn, XMLElement *xml_node, std::map<Node*, std::string> &linkmap); 7.18 +static std::string get_name(XMLElement *node, int idx, const char *def_prefix); 7.19 7.20 bool Scene::loadxml(goat3d_io *io) 7.21 { 7.22 @@ -79,6 +82,29 @@ 7.23 elem = elem->NextSiblingElement("mesh"); 7.24 } 7.25 7.26 + // get all nodes 7.27 + std::map<Node*, std::string> linkmap; 7.28 + 7.29 + elem = root->FirstChildElement("node"); 7.30 + while(elem) { 7.31 + Node *node = read_node(this, elem, linkmap); 7.32 + if(node) { 7.33 + add_node(node); 7.34 + } 7.35 + elem = elem->NextSiblingElement("node"); 7.36 + } 7.37 + 7.38 + // link up all the nodes in the hierarchy 7.39 + for(size_t i=0; i<nodes.size(); i++) { 7.40 + std::string parent_name = linkmap[nodes[i]]; 7.41 + if(!parent_name.empty()) { 7.42 + Node *parent = get_node(parent_name.c_str()); 7.43 + if(parent) { 7.44 + parent->add_child(nodes[i]); 7.45 + } 7.46 + } 7.47 + } 7.48 + 7.49 delete [] buf; 7.50 return true; 7.51 } 7.52 @@ -130,7 +156,7 @@ 7.53 static Material *read_material(Scene *scn, XMLElement *xml_mtl) 7.54 { 7.55 Material *mtl = new Material; 7.56 - mtl->name = get_name(xml_mtl, scn->get_material_count()); 7.57 + mtl->name = get_name(xml_mtl, scn->get_material_count(), "material"); 7.58 7.59 // get all the material attributes in turn 7.60 XMLElement *elem = xml_mtl->FirstChildElement("attr"); 7.61 @@ -188,7 +214,7 @@ 7.62 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh) 7.63 { 7.64 Mesh *mesh = new Mesh; 7.65 - mesh->name = get_name(xml_mesh, scn->get_mesh_count()); 7.66 + mesh->name = get_name(xml_mesh, scn->get_mesh_count(), "mesh"); 7.67 7.68 XMLElement *elem; 7.69 if((elem = xml_mesh->FirstChildElement("material"))) { 7.70 @@ -226,7 +252,74 @@ 7.71 return mesh; 7.72 } 7.73 7.74 -static std::string get_name(XMLElement *node, int idx) 7.75 +static Node *read_node(Scene *scn, XMLElement *xml_node, std::map<Node*, std::string> &linkmap) 7.76 +{ 7.77 + Node *node = new Node; 7.78 + node->set_name(get_name(xml_node, scn->get_node_count(), "node").c_str()); 7.79 + 7.80 + XMLElement *elem; 7.81 + if((elem = xml_node->FirstChildElement("parent"))) { 7.82 + const char *pname = elem->Attribute("string"); 7.83 + if(pname) { 7.84 + linkmap[node] = pname; 7.85 + } 7.86 + } 7.87 + 7.88 + if((elem = xml_node->FirstChildElement("mesh"))) { 7.89 + Mesh *mesh = scn->get_mesh(elem->Attribute("string")); 7.90 + if(mesh) { 7.91 + node->set_object(mesh); 7.92 + } 7.93 + } else if((elem = xml_node->FirstChildElement("light"))) { 7.94 + Light *lt = scn->get_light(elem->Attribute("string")); 7.95 + if(lt) { 7.96 + node->set_object(lt); 7.97 + } 7.98 + } else if((elem = xml_node->FirstChildElement("camera"))) { 7.99 + Camera *cam = scn->get_camera(elem->Attribute("string")); 7.100 + if(cam) { 7.101 + node->set_object(cam); 7.102 + } 7.103 + } 7.104 + 7.105 + float vec[4]; 7.106 + if((elem = xml_node->FirstChildElement("pos"))) { 7.107 + const char *val = elem->Attribute("float3"); 7.108 + if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) { 7.109 + node->set_position(Vector3(val[0], val[1], val[2])); 7.110 + } else { 7.111 + logmsg(LOG_ERROR, "node %s: invalid position tag\n", node->get_name()); 7.112 + } 7.113 + } 7.114 + if((elem = xml_node->FirstChildElement("rot"))) { 7.115 + const char *val = elem->Attribute("float4"); 7.116 + if(val && sscanf(val, "%f %f %f %f", vec, vec + 1, vec + 2, vec + 3) == 4) { 7.117 + node->set_rotation(Quaternion(vec[3], Vector3(vec[0], vec[1], vec[2]))); 7.118 + } else { 7.119 + logmsg(LOG_ERROR, "node %s: invalid rotation tag\n", node->get_name()); 7.120 + } 7.121 + } 7.122 + if((elem = xml_node->FirstChildElement("scale"))) { 7.123 + const char *val = elem->Attribute("float3"); 7.124 + if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) { 7.125 + node->set_scaling(Vector3(vec[0], vec[1], vec[2])); 7.126 + } else { 7.127 + logmsg(LOG_ERROR, "node %s: invalid scaling tag\n", node->get_name()); 7.128 + } 7.129 + } 7.130 + if((elem = xml_node->FirstChildElement("pivot"))) { 7.131 + const char *val = elem->Attribute("float3"); 7.132 + if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) { 7.133 + node->set_pivot(Vector3(vec[0], vec[1], vec[2])); 7.134 + } else { 7.135 + logmsg(LOG_ERROR, "node %s: invalid pivot tag\n", node->get_name()); 7.136 + } 7.137 + } 7.138 + 7.139 + return node; 7.140 +} 7.141 + 7.142 +static std::string get_name(XMLElement *node, int idx, const char *def_prefix) 7.143 { 7.144 char buf[64]; 7.145 const char *name = 0; 7.146 @@ -237,7 +330,7 @@ 7.147 } 7.148 7.149 if(!name) { 7.150 - sprintf(buf, "mesh%04d", idx); 7.151 + sprintf(buf, "%s%04d", def_prefix, idx); 7.152 name = buf; 7.153 } 7.154
8.1 --- a/src/mesh.h Tue May 06 13:26:52 2014 +0300 8.2 +++ b/src/mesh.h Thu May 08 00:50:16 2014 +0300 8.3 @@ -60,6 +60,8 @@ 8.4 void set_material(Material *mat); 8.5 Material *get_material(); 8.6 const Material *get_material() const; 8.7 + 8.8 + AABox get_bounds() const; 8.9 }; 8.10 8.11 } // namespace g3dimpl
9.1 --- a/src/node.cc Tue May 06 13:26:52 2014 +0300 9.2 +++ b/src/node.cc Thu May 08 00:50:16 2014 +0300 9.3 @@ -24,15 +24,18 @@ 9.4 Node::Node() 9.5 { 9.6 obj = 0; 9.7 + bbox_valid = false; 9.8 } 9.9 9.10 void Node::set_object(Object *obj) 9.11 { 9.12 this->obj = obj; 9.13 + bbox_valid = false; 9.14 } 9.15 9.16 Object *Node::get_object() 9.17 { 9.18 + bbox_valid = false; 9.19 return obj; 9.20 } 9.21 9.22 @@ -41,6 +44,20 @@ 9.23 return obj; 9.24 } 9.25 9.26 +const AABox &Node::get_bounds() const 9.27 +{ 9.28 + if(!bbox_valid) { 9.29 + bbox = obj ? obj->get_bounds() : AABox(); 9.30 + 9.31 + for(int i=0; i<get_children_count(); i++) { 9.32 + bbox = aabox_union(bbox, ((Node*)get_child(i))->get_bounds()); 9.33 + } 9.34 + bbox_valid = true; 9.35 + } 9.36 + 9.37 + return bbox; 9.38 +} 9.39 + 9.40 void g3dimpl::delete_node_tree(Node *n) 9.41 { 9.42 if(!n) return;
10.1 --- a/src/node.h Tue May 06 13:26:52 2014 +0300 10.2 +++ b/src/node.h Thu May 08 00:50:16 2014 +0300 10.3 @@ -20,6 +20,7 @@ 10.4 10.5 #include "xform_node.h" 10.6 #include "object.h" 10.7 +#include "aabox.h" 10.8 10.9 namespace g3dimpl { 10.10 10.11 @@ -27,12 +28,17 @@ 10.12 private: 10.13 Object *obj; 10.14 10.15 + mutable AABox bbox; 10.16 + mutable bool bbox_valid; 10.17 + 10.18 public: 10.19 Node(); 10.20 10.21 void set_object(Object *obj); 10.22 Object *get_object(); 10.23 const Object *get_object() const; 10.24 + 10.25 + const AABox &get_bounds() const; 10.26 }; 10.27 10.28 void delete_node_tree(Node *n);
11.1 --- a/src/object.h Tue May 06 13:26:52 2014 +0300 11.2 +++ b/src/object.h Thu May 08 00:50:16 2014 +0300 11.3 @@ -20,6 +20,9 @@ 11.4 11.5 #include <string> 11.6 #include <vmath/vmath.h> 11.7 +#include "aabox.h" 11.8 + 11.9 +namespace g3dimpl { 11.10 11.11 class Object { 11.12 public: 11.13 @@ -27,8 +30,14 @@ 11.14 11.15 Vector3 pos; 11.16 Quaternion rot; 11.17 + Vector3 scale; 11.18 11.19 - virtual ~Object() {}; 11.20 + Object() : scale(1, 1, 1) {} 11.21 + virtual ~Object() {} 11.22 + 11.23 + virtual AABox get_bounds(const Matrix4x4 &xform) const { return AABox(); } 11.24 }; 11.25 11.26 +} 11.27 + 11.28 #endif // OBJECT_H_
12.1 --- a/src/scene.cc Tue May 06 13:26:52 2014 +0300 12.2 +++ b/src/scene.cc Thu May 08 00:50:16 2014 +0300 12.3 @@ -26,6 +26,7 @@ 12.4 : name("unnamed"), ambient(0.05, 0.05, 0.05) 12.5 { 12.6 goat = 0; 12.7 + bbox_valid = false; 12.8 } 12.9 12.10 Scene::~Scene() 12.11 @@ -61,6 +62,7 @@ 12.12 nodes.clear(); 12.13 12.14 name = "unnamed"; 12.15 + bbox_valid = false; 12.16 } 12.17 12.18 void Scene::set_name(const char *name) 12.19 @@ -222,6 +224,24 @@ 12.20 return (int)nodes.size(); 12.21 } 12.22 12.23 +const AABox &Scene::get_bounds() const 12.24 +{ 12.25 + if(!bbox_valid) { 12.26 + bbox = AABox(); 12.27 + 12.28 + for(size_t i=0; i<nodes.size(); i++) { 12.29 + if(nodes[i]->get_parent()) { 12.30 + continue; 12.31 + } 12.32 + 12.33 + bbox = aabox_union(bbox, nodes[i]->get_bounds()); 12.34 + } 12.35 + bbox_valid = true; 12.36 + } 12.37 + 12.38 + return bbox; 12.39 +} 12.40 + 12.41 // Scene::load is defined in goat3d_read.cc 12.42 // Scene::loadxml is defined in goat3d_readxml.cc 12.43 // Scene::save is defined in goat3d_write.cc