Commits

Ross Light committed 9203d80

initial import

Comments (0)

Files changed (5)

+Hello, World!  I present a smattering of computer graphics boilerplate code.
+
+This software is released under an open-source MIT license.
+
+License
+=========
+
+Copyright (c) 2012 Ross Light.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+#!/usr/bin/env python3
+
+"""Blender script for extracting curve data"""
+
+import bpy
+from bpy_extras.io_utils import ExportHelper
+
+bl_info = {
+    'name': "animdata",
+    'description': "Export animation data from a file in a simple text file",
+    'author': "Ross Light",
+    'version': (0, 1),
+    'blender': (2, 64, 0),
+    'location': "File > Export",
+    'category': "Import-Export",
+}
+
+class ExportAnimData(bpy.types.Operator, ExportHelper):
+    bl_idname = "export_scene.animdata"
+    bl_label = "Export AnimData"
+
+    filename_ext = ".out"
+
+    def execute(self, context):
+        with open(self.filepath, 'w') as f:
+            for obj in context.scene.objects:
+                if obj.animation_data is None:
+                    continue
+                print("*", obj.name, file=f)
+                if obj.parent is not None:
+                    print("^", obj.name, file=f)
+                for curve in obj.animation_data.action.fcurves:
+                    print(">", curve.data_path, curve.array_index, file=f)
+                    for k in curve.keyframe_points:
+                        print("|", k.interpolation[0].upper(),
+                            k.co.x, k.co.y,
+                            k.handle_left.x, k.handle_left.y,
+                            k.handle_right.x, k.handle_right.y,
+                            file=f)
+        return {'FINISHED'}
+
+def menu_func(self, context):
+    self.layout.operator(ExportAnimData.bl_idname, text="AnimData (.out)")
+
+def register():
+    bpy.utils.register_module(__name__)
+    bpy.types.INFO_MT_file_export.append(menu_func)
+
+def unregister():
+    bpy.utils.unregister_module(__name__)
+    bpy.types.INFO_MT_file_export.remove(menu_func)
+
+if __name__ == "__main__":
+    register()
+#include <fstream>
+
+int vertexCount;
+GLuint ibo;
+GLuint positions, uvs, normals;
+
+void Initialize()
+{
+    // ...
+    
+    // open an OBJ file
+    std::ifstream modelFile("model.obj");
+    // parse the meshes from the file
+    Model model;
+    model.load(modelFile);
+    // create VBOs from the first mesh in the file.
+    // Any of the parameters can be NULL and the corresponding VBO won't be created.
+    vertexCount = model.meshes()[0].makeVBO(&ibo, &positions, &uvs, &normals);
+    // If you make IBO NULL, then the vertices will not be de-duped (you can use
+    // the simpler glDrawArrays, but it will probably be more video memory).
+    vertexCount = model.meshes()[0].makeVBO(NULL, &positions, &uvs, &normals);
+
+    // You can even get fancy and check against mesh names:
+    for (MeshVector::const_iterator iter = model.meshes().begin(); iter != model.meshes().end(); ++iter) {
+        if (iter->name() == "Ground") {
+            iter->makeVBO(/* ... */);
+        }
+    }
+
+    // ...
+}
+
+void Draw()
+{
+    // ...
+
+    glEnableVertexAttribArray(h_aPosition);
+    glBindBuffer(GL_ARRAY_BUFFER, positions);
+    glVertexAttribPointer(h_aPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+    glEnableVertexAttribArray(h_aUV);
+    glBindBuffer(GL_ARRAY_BUFFER, uvs);
+    glVertexAttribPointer(h_aUV, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+    glEnableVertexAttribArray(h_aNormal);
+    glBindBuffer(GL_ARRAY_BUFFER, normals);
+    glVertexAttribPointer(h_aNormal, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+    // If you used the IBO (generally a good idea):
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
+    glDrawElements(GL_TRIANGLES, vertexCount, GL_UNSIGNED_INT, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    // else:
+    glDrawArrays(GL_TRIANGLES, 0, vertexCount);
+
+    // ...
+}
+// mesh.cpp
+
+#include "mesh.h"
+
+#include <map>
+#include <sstream>
+
+namespace {
+
+template<class T>
+void fillBuffer(GLuint buf, std::vector<T> data)
+{
+    glBindBuffer(GL_ARRAY_BUFFER, buf);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(T)*data.size(), &data[0], GL_STATIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+} // namespace
+
+void Model::load(std::istream& is)
+{
+    Mesh* currMesh = NULL;
+
+    mMeshes.empty();
+    mVertices.empty();
+    mUVs.empty();
+    mNormals.empty();
+
+    while (is.good()) {
+        std::string line;
+        std::getline(is, line);
+        if (line.empty() || line[0] == '#') {
+            continue;
+        }
+        std::istringstream lineStream(line);
+
+        std::string cmd;
+        lineStream >> cmd;
+        if (cmd == "o") {
+            std::string name;
+            lineStream >> std::ws;
+            std::getline(lineStream, name);
+            Mesh mesh(*this, name);
+            mMeshes.push_back(mesh);
+            currMesh = &(*--mMeshes.end());
+        } else if (cmd == "v") {
+            float x, y, z;
+            lineStream >> x >> y >> z;
+            mVertices.push_back(glm::vec3(x, y, z));
+        } else if (cmd == "vt") {
+            float u, v;
+            lineStream >> u >> v;
+            mUVs.push_back(glm::vec2(u, v));
+        } else if (cmd == "vn") {
+            float x, y, z;
+            lineStream >> x >> y >> z;
+            mNormals.push_back(glm::vec3(x, y, z));
+        } else if (cmd == "f") {
+            if (currMesh == NULL) {
+                Mesh mesh(*this, "");
+                mMeshes.push_back(mesh);
+                currMesh = &(*--mMeshes.end());
+            }
+
+            Face face;
+            lineStream >> face.V[0] >> face.V[1] >> face.V[2];
+            currMesh->mFaces.push_back(face);
+
+            if (lineStream.good()) {
+                lineStream >> face.V[1];
+                currMesh->mFaces.push_back(face);
+            }
+        }
+    }
+}
+
+Mesh::Mesh(const Model& model, const std::string& name)
+    : mModel(&model)
+    , mName(name)
+{
+}
+
+typedef std::map<Face::Vertex, GLuint> VertexIndexMap;
+
+int Mesh::makeVBO(GLuint* indexHandle, GLuint* posHandle, GLuint* uvHandle, GLuint* normalHandle) const
+{
+    VertexIndexMap indexMap;
+    std::vector<GLuint> index;
+    std::vector<GLfloat> pos;
+    std::vector<GLfloat> uv;
+    std::vector<GLfloat> normal;
+    GLuint n = 0;
+
+    for (std::vector<Face>::const_iterator iter = mFaces.begin(); iter != mFaces.end(); ++iter) {
+        const Face& face = *iter;
+        for (int i = 0; i < 3; ++i) {
+            const Face::Vertex& v = face.V[i];
+            VertexIndexMap::const_iterator indexIter;
+
+            if (indexHandle != NULL && (indexIter = indexMap.find(v)) != indexMap.end()) {
+                index.push_back(indexIter->second);
+            } else {
+                pos.push_back(mModel->mVertices[v.mVertex-1].x);
+                pos.push_back(mModel->mVertices[v.mVertex-1].y);
+                pos.push_back(mModel->mVertices[v.mVertex-1].z);
+                if (v.mUV != 0) {
+                    uv.push_back(mModel->mUVs[v.mUV-1].x);
+                    uv.push_back(mModel->mUVs[v.mUV-1].y);
+                } else {
+                    uv.push_back(0.0f);
+                    uv.push_back(0.0f);
+                }
+                if (v.mNormal != 0) {
+                    normal.push_back(mModel->mNormals[v.mNormal-1].x);
+                    normal.push_back(mModel->mNormals[v.mNormal-1].y);
+                    normal.push_back(mModel->mNormals[v.mNormal-1].z);
+                } else {
+                    normal.push_back(0.0f);
+                    normal.push_back(0.0f);
+                    normal.push_back(0.0f);
+                }
+
+                if (indexHandle != NULL) {
+                    index.push_back(n);
+                    indexMap[v] = n;
+                    n++;
+                }
+            }
+        }
+    }
+
+    if (indexHandle != NULL) {
+        glGenBuffers(1, indexHandle);
+        fillBuffer(*indexHandle, index);
+    }
+    if (posHandle != NULL) {
+        glGenBuffers(1, posHandle);
+        fillBuffer(*posHandle, pos);
+    }
+    if (uvHandle != NULL) {
+        glGenBuffers(1, uvHandle);
+        fillBuffer(*uvHandle, uv);
+    }
+    if (normalHandle != NULL) {
+        glGenBuffers(1, normalHandle);
+        fillBuffer(*normalHandle, normal);
+    }
+
+    return mFaces.size() * 3;
+}
+
+std::istream& operator>>(std::istream& is, Face::Vertex& vert)
+{
+    vert.mVertex = 0;
+    vert.mUV = 0;
+    vert.mNormal = 0;
+
+    is >> vert.mVertex;
+    if (is.peek() != '/') {
+        return is;
+    }
+    is.ignore();
+
+    if (is.peek() != '/') {
+        is >> vert.mUV;
+    }
+    if (is.peek() != '/') {
+        return is;
+    }
+    is.ignore();
+
+    is >> vert.mNormal;
+
+    return is;
+}
+
+bool operator<(const Face::Vertex& a, const Face::Vertex& b)
+{
+    if (a.mVertex != b.mVertex) {
+        return a.mVertex < b.mVertex;
+    }
+    if (a.mUV != b.mUV) {
+        return a.mUV < b.mUV;
+    }
+    return a.mNormal < b.mNormal;
+}
+
+bool operator==(const Face::Vertex& a, const Face::Vertex& b)
+{
+    return a.mVertex == b.mVertex &&
+        a.mUV == b.mUV &&
+        a.mNormal == b.mNormal;
+}
+
+bool operator!=(const Face::Vertex& a, const Face::Vertex& b)
+{
+    return a.mVertex != b.mVertex ||
+        a.mUV != b.mUV ||
+        a.mNormal != b.mNormal;
+}
+// mesh.h
+
+#ifndef _MESH_H_
+#define _MESH_H_
+
+#include <string>
+#include <vector>
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#endif
+#ifdef __unix__
+#include <GL/gl.h>
+#endif
+#include "glm/glm.hpp"
+
+class Mesh;
+struct Face;
+
+typedef std::vector<Mesh> MeshVector;
+
+class Model
+{
+    friend class Mesh;
+public:
+    void load(std::istream& is);
+    const MeshVector& meshes() const { return mMeshes; }
+private:
+    MeshVector mMeshes;
+    std::vector<glm::vec3> mVertices;
+    std::vector<glm::vec2> mUVs;
+    std::vector<glm::vec3> mNormals;
+};
+
+class Mesh
+{
+    friend class Model;
+public:
+    const std::string& name() const { return mName; }
+    int makeVBO(GLuint* indexHandle, GLuint* posHandle, GLuint* uvHandle, GLuint* normalHandle) const;
+private:
+    Mesh(const Model& model, const std::string& name);
+
+    const Model* mModel;
+    std::string mName;
+    std::vector<Face> mFaces;
+};
+
+struct Face
+{
+    struct Vertex
+    {
+        int mVertex;
+        int mUV;
+        int mNormal;
+    };
+
+    Vertex V[3];
+};
+
+std::istream& operator>>(std::istream& is, Face::Vertex& vert);
+bool operator<(const Face::Vertex& a, const Face::Vertex& b);
+bool operator==(const Face::Vertex& a, const Face::Vertex& b);
+bool operator!=(const Face::Vertex& a, const Face::Vertex& b);
+
+#endif