# HG changeset patch # User John Tsiombikas # Date 1399499416 -10800 # Node ID 76dea247f75cef29930c4053d3ba083ae443f813 # Parent ab66cdabf6f2cdf4acfcb88858a3019a99784699 in progress diff -r ab66cdabf6f2 -r 76dea247f75c goatview/src/goatview.cc --- a/goatview/src/goatview.cc Tue May 06 13:26:52 2014 +0300 +++ b/goatview/src/goatview.cc Thu May 08 00:50:16 2014 +0300 @@ -1,7 +1,13 @@ +#include #include "goatview.h" #include "goat3d.h" goat3d *scene; +QSettings *settings; + +static long anim_time; +static float cam_theta, cam_phi, cam_dist = 8; + GoatView::GoatView() { @@ -12,12 +18,20 @@ statusBar(); setWindowTitle("GoatView"); + resize(settings->value("main/size", QSize(1024, 768)).toSize()); + move(settings->value("main/pos", QPoint(100, 100)).toPoint()); } GoatView::~GoatView() { } +void GoatView::closeEvent(QCloseEvent *ev) +{ + settings->setValue("main/size", size()); + settings->setValue("main/pos", pos()); +} + bool GoatView::make_menu() { QMenu *menu_file = menuBar()->addMenu("&File"); @@ -120,15 +134,79 @@ void GoatViewport::initializeGL() { + glClearColor(0.1, 0.1, 0.1, 1); } void GoatViewport::resizeGL(int xsz, int ysz) { glViewport(0, 0, xsz, ysz); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, (float)xsz / (float)ysz, 0.5, 5000.0); } +static void draw_node(goat3d_node *node); + void GoatViewport::paintGL() { - glClearColor(1, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -cam_dist); + glRotatef(cam_phi, 1, 0, 0); + glRotatef(cam_theta, 0, 1, 0); + + if(scene) { + int node_count = goat3d_get_node_count(scene); + for(int i=0; i #include #include #include "goat3d.h" extern goat3d *scene; +extern QSettings *settings; class GoatView : public QMainWindow { Q_OBJECT private: + void closeEvent(QCloseEvent *ev); bool make_menu(); bool make_dock(); bool make_center(); diff -r ab66cdabf6f2 -r 76dea247f75c goatview/src/main.cc --- a/goatview/src/main.cc Tue May 06 13:26:52 2014 +0300 +++ b/goatview/src/main.cc Thu May 08 00:50:16 2014 +0300 @@ -1,9 +1,47 @@ #include +#include #include "goatview.h" int main(int argc, char **argv) { QApplication app(argc, argv); + app.setOrganizationName("Mutant Stargoat"); + app.setOrganizationDomain("mutantstargoat.com"); + app.setApplicationName("GoatView"); + settings = new QSettings; + + QCommandLineParser argparse; + argparse.addHelpOption(); + + argparse.addPositionalArgument("scene", "scene file to open"); + argparse.addOption(QCommandLineOption("a", "add animation file")); + argparse.process(app); + + const QStringList &args = argparse.positionalArguments(); + if(!args.isEmpty()) { + if(args.count() > 1) { + fprintf(stderr, "please specify at most one scene file to open\n"); + return 1; + } + std::string fname = args.at(0).toStdString(); + printf("loading scene file: %s ...\n", fname.c_str()); + if(!(scene = goat3d_create()) || goat3d_load(scene, fname.c_str())) { + fprintf(stderr, "failed to load scene: %s\n", fname.c_str()); + return 1; + } + } + + const QStringList &anims = argparse.values("a"); + QStringList::const_iterator it = anims.begin(); + while(it != anims.end()) { + std::string fname = it++->toStdString(); + printf("loading animation file: %s ...\n", fname.c_str()); + + if(goat3d_load_anim(scene, fname.c_str()) == -1) { + fprintf(stderr, "failed to load animation: %s\n", fname.c_str()); + return 1; + } + } GoatView gview; gview.show(); diff -r ab66cdabf6f2 -r 76dea247f75c src/aabox.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aabox.cc Thu May 08 00:50:16 2014 +0300 @@ -0,0 +1,27 @@ +#include +#include +#include "aabox.h" + +using namespace g3dimpl; + +AABox::AABox() + : bmin(FLT_MAX, FLT_MAX, FLT_MAX), bmax(-FLT_MAX, -FLT_MAX, -FLT_MAX) +{ +} + +AABox::AABox(const Vector3 &b0, const Vector3 &b1) + : bmin(b0), bmax(b1) +{ +} + +AABox g3dimpl::aabox_union(const AABox &a, const AABox &b) +{ + Vector3 bmin, bmax; + + for(int i=0; i<3; i++) { + bmin[i] = std::min(a.bmin[i], b.bmin[i]); + bmax[i] = std::max(a.bmax[i], b.bmax[i]); + } + + return AABox(bmin, bmax); +} diff -r ab66cdabf6f2 -r 76dea247f75c src/aabox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/aabox.h Thu May 08 00:50:16 2014 +0300 @@ -0,0 +1,20 @@ +#ifndef AABOX_H_ +#define AABOX_H_ + +#include + +namespace g3dimpl { + +class AABox { +public: + Vector3 bmin, bmax; + + AABox(); + AABox(const Vector3 &b0, const Vector3 &b1); +}; + +AABox aabox_union(const AABox &a, const AABox &b); + +} + +#endif // AABOX_H_ diff -r ab66cdabf6f2 -r 76dea247f75c src/goat3d_impl.h --- a/src/goat3d_impl.h Tue May 06 13:26:52 2014 +0300 +++ b/src/goat3d_impl.h Thu May 08 00:50:16 2014 +0300 @@ -26,6 +26,7 @@ #include "camera.h" #include "material.h" #include "node.h" +#include "aabox.h" namespace g3dimpl { class Scene; @@ -65,6 +66,9 @@ std::vector cameras; std::vector nodes; + mutable AABox bbox; + mutable bool bbox_valid; + public: goat3d *goat; @@ -104,6 +108,8 @@ Node *get_node(const char *name) const; int get_node_count() const; + const AABox &get_bounds() const; + bool load(goat3d_io *io); bool save(goat3d_io *io) const; diff -r ab66cdabf6f2 -r 76dea247f75c src/goat3d_readxml.cc --- a/src/goat3d_readxml.cc Tue May 06 13:26:52 2014 +0300 +++ b/src/goat3d_readxml.cc Thu May 08 00:50:16 2014 +0300 @@ -16,6 +16,8 @@ along with this program. If not, see . */ #include +#include +#include #include "goat3d.h" #include "goat3d_impl.h" #include "tinyxml2.h" @@ -27,7 +29,8 @@ static Material *read_material(Scene *scn, XMLElement *xml_mtl); static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr); static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh); -static std::string get_name(XMLElement *node, int idx); +static Node *read_node(Scene *scn, XMLElement *xml_node, std::map &linkmap); +static std::string get_name(XMLElement *node, int idx, const char *def_prefix); bool Scene::loadxml(goat3d_io *io) { @@ -79,6 +82,29 @@ elem = elem->NextSiblingElement("mesh"); } + // get all nodes + std::map linkmap; + + elem = root->FirstChildElement("node"); + while(elem) { + Node *node = read_node(this, elem, linkmap); + if(node) { + add_node(node); + } + elem = elem->NextSiblingElement("node"); + } + + // link up all the nodes in the hierarchy + for(size_t i=0; iadd_child(nodes[i]); + } + } + } + delete [] buf; return true; } @@ -130,7 +156,7 @@ static Material *read_material(Scene *scn, XMLElement *xml_mtl) { Material *mtl = new Material; - mtl->name = get_name(xml_mtl, scn->get_material_count()); + mtl->name = get_name(xml_mtl, scn->get_material_count(), "material"); // get all the material attributes in turn XMLElement *elem = xml_mtl->FirstChildElement("attr"); @@ -188,7 +214,7 @@ static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh) { Mesh *mesh = new Mesh; - mesh->name = get_name(xml_mesh, scn->get_mesh_count()); + mesh->name = get_name(xml_mesh, scn->get_mesh_count(), "mesh"); XMLElement *elem; if((elem = xml_mesh->FirstChildElement("material"))) { @@ -226,7 +252,74 @@ return mesh; } -static std::string get_name(XMLElement *node, int idx) +static Node *read_node(Scene *scn, XMLElement *xml_node, std::map &linkmap) +{ + Node *node = new Node; + node->set_name(get_name(xml_node, scn->get_node_count(), "node").c_str()); + + XMLElement *elem; + if((elem = xml_node->FirstChildElement("parent"))) { + const char *pname = elem->Attribute("string"); + if(pname) { + linkmap[node] = pname; + } + } + + if((elem = xml_node->FirstChildElement("mesh"))) { + Mesh *mesh = scn->get_mesh(elem->Attribute("string")); + if(mesh) { + node->set_object(mesh); + } + } else if((elem = xml_node->FirstChildElement("light"))) { + Light *lt = scn->get_light(elem->Attribute("string")); + if(lt) { + node->set_object(lt); + } + } else if((elem = xml_node->FirstChildElement("camera"))) { + Camera *cam = scn->get_camera(elem->Attribute("string")); + if(cam) { + node->set_object(cam); + } + } + + float vec[4]; + if((elem = xml_node->FirstChildElement("pos"))) { + const char *val = elem->Attribute("float3"); + if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) { + node->set_position(Vector3(val[0], val[1], val[2])); + } else { + logmsg(LOG_ERROR, "node %s: invalid position tag\n", node->get_name()); + } + } + if((elem = xml_node->FirstChildElement("rot"))) { + const char *val = elem->Attribute("float4"); + if(val && sscanf(val, "%f %f %f %f", vec, vec + 1, vec + 2, vec + 3) == 4) { + node->set_rotation(Quaternion(vec[3], Vector3(vec[0], vec[1], vec[2]))); + } else { + logmsg(LOG_ERROR, "node %s: invalid rotation tag\n", node->get_name()); + } + } + if((elem = xml_node->FirstChildElement("scale"))) { + const char *val = elem->Attribute("float3"); + if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) { + node->set_scaling(Vector3(vec[0], vec[1], vec[2])); + } else { + logmsg(LOG_ERROR, "node %s: invalid scaling tag\n", node->get_name()); + } + } + if((elem = xml_node->FirstChildElement("pivot"))) { + const char *val = elem->Attribute("float3"); + if(val && sscanf(val, "%f %f %f", vec, vec + 1, vec + 2) == 3) { + node->set_pivot(Vector3(vec[0], vec[1], vec[2])); + } else { + logmsg(LOG_ERROR, "node %s: invalid pivot tag\n", node->get_name()); + } + } + + return node; +} + +static std::string get_name(XMLElement *node, int idx, const char *def_prefix) { char buf[64]; const char *name = 0; @@ -237,7 +330,7 @@ } if(!name) { - sprintf(buf, "mesh%04d", idx); + sprintf(buf, "%s%04d", def_prefix, idx); name = buf; } diff -r ab66cdabf6f2 -r 76dea247f75c src/mesh.h --- a/src/mesh.h Tue May 06 13:26:52 2014 +0300 +++ b/src/mesh.h Thu May 08 00:50:16 2014 +0300 @@ -60,6 +60,8 @@ void set_material(Material *mat); Material *get_material(); const Material *get_material() const; + + AABox get_bounds() const; }; } // namespace g3dimpl diff -r ab66cdabf6f2 -r 76dea247f75c src/node.cc --- a/src/node.cc Tue May 06 13:26:52 2014 +0300 +++ b/src/node.cc Thu May 08 00:50:16 2014 +0300 @@ -24,15 +24,18 @@ Node::Node() { obj = 0; + bbox_valid = false; } void Node::set_object(Object *obj) { this->obj = obj; + bbox_valid = false; } Object *Node::get_object() { + bbox_valid = false; return obj; } @@ -41,6 +44,20 @@ return obj; } +const AABox &Node::get_bounds() const +{ + if(!bbox_valid) { + bbox = obj ? obj->get_bounds() : AABox(); + + for(int i=0; iget_bounds()); + } + bbox_valid = true; + } + + return bbox; +} + void g3dimpl::delete_node_tree(Node *n) { if(!n) return; diff -r ab66cdabf6f2 -r 76dea247f75c src/node.h --- a/src/node.h Tue May 06 13:26:52 2014 +0300 +++ b/src/node.h Thu May 08 00:50:16 2014 +0300 @@ -20,6 +20,7 @@ #include "xform_node.h" #include "object.h" +#include "aabox.h" namespace g3dimpl { @@ -27,12 +28,17 @@ private: Object *obj; + mutable AABox bbox; + mutable bool bbox_valid; + public: Node(); void set_object(Object *obj); Object *get_object(); const Object *get_object() const; + + const AABox &get_bounds() const; }; void delete_node_tree(Node *n); diff -r ab66cdabf6f2 -r 76dea247f75c src/object.h --- a/src/object.h Tue May 06 13:26:52 2014 +0300 +++ b/src/object.h Thu May 08 00:50:16 2014 +0300 @@ -20,6 +20,9 @@ #include #include +#include "aabox.h" + +namespace g3dimpl { class Object { public: @@ -27,8 +30,14 @@ Vector3 pos; Quaternion rot; + Vector3 scale; - virtual ~Object() {}; + Object() : scale(1, 1, 1) {} + virtual ~Object() {} + + virtual AABox get_bounds(const Matrix4x4 &xform) const { return AABox(); } }; +} + #endif // OBJECT_H_ diff -r ab66cdabf6f2 -r 76dea247f75c src/scene.cc --- a/src/scene.cc Tue May 06 13:26:52 2014 +0300 +++ b/src/scene.cc Thu May 08 00:50:16 2014 +0300 @@ -26,6 +26,7 @@ : name("unnamed"), ambient(0.05, 0.05, 0.05) { goat = 0; + bbox_valid = false; } Scene::~Scene() @@ -61,6 +62,7 @@ nodes.clear(); name = "unnamed"; + bbox_valid = false; } void Scene::set_name(const char *name) @@ -222,6 +224,24 @@ return (int)nodes.size(); } +const AABox &Scene::get_bounds() const +{ + if(!bbox_valid) { + bbox = AABox(); + + for(size_t i=0; iget_parent()) { + continue; + } + + bbox = aabox_union(bbox, nodes[i]->get_bounds()); + } + bbox_valid = true; + } + + return bbox; +} + // Scene::load is defined in goat3d_read.cc // Scene::loadxml is defined in goat3d_readxml.cc // Scene::save is defined in goat3d_write.cc