#include "DDImage/Attribute.h" #include "DDImage/GeometryList.h" #include "DDImage/GeoReader.h" #include "DDImage/GeoReaderDescription.h" #include "DDImage/Triangle.h" #include "DDImage/Vector3.h" #include #include #include using namespace DD::Image; namespace my3d { // If you wish to include custom knobs in your 3d reader, you also need to implement a // GeoReaderFormat for your reader. Below is a simple example of how to achieve this. class my3dReaderFormat : public GeoReaderFormat { friend class my3dReader; private: // The following variable receives values from the reader-specific knob bool _readOnEachFrame; public: my3dReaderFormat(); virtual ~my3dReaderFormat() {}; static GeoReaderFormat* buildformat(ReadGeo* iop); // GeoReaderFormat virtual void knobs(Knob_Callback c); virtual void extraKnobs(Knob_Callback c); virtual void append(Hash& hash); //~GeoReaderFormat }; class my3dReader : public GeoReader { public: my3dReader(ReadGeo* readNode); // DD::Image::GeoReader virtual int knob_changed(Knob* k); virtual void append(Hash& newHash); virtual void get_geometry_hash(Hash* geo_hash); virtual void _validate(const bool for_real); virtual void geometry_engine(Scene& scene, GeometryList& out); // DD::Image::GeoReader static GeoReader* Build(ReadGeo* readNode, int fd, const unsigned char* buf, int bufSize); static bool Test(int fd, const unsigned char* buf, int bufSize); static GeoReader::Description description; private: // Used to store a pointer to the read node ReadGeo* _pReadGeo; }; // // my3dReaderFormat methods // my3dReaderFormat::my3dReaderFormat() : _readOnEachFrame(false) { } void my3dReaderFormat::knobs(Knob_Callback f) { // This places knobs in the format specific area of the main tab Bool_knob(f, &_readOnEachFrame, "read_on_each_frame", "read on each frame"); Tooltip(f, "Activate this to read the objects on each frame. This should be activated for animated objects."); } void my3dReaderFormat::extraKnobs(Knob_Callback f) { // This places knobs after all other knobs // (For example, the "SceneGraph" tab knob and sceneView knob in the abcReader) } void my3dReaderFormat::append(Hash& new_hash) { new_hash.append(_readOnEachFrame); } /*! Build the my3d file interface */ /*static*/ GeoReaderFormat* my3dReaderFormat::buildformat(ReadGeo* iop) { return new my3dReaderFormat(); } // // my3dReader methods // my3dReader::my3dReader(ReadGeo* readNode) : GeoReader(readNode) , _pReadGeo(readNode) { } int my3dReader::knob_changed(Knob* k) { // Perform tasks based on knob_changed events from the base ReadGeo class or the associated GeoReaderFormat return true; } void my3dReader::append(Hash& newHash) { // Append any local variables to the hash in order to invalidate the op when they change. // Get the read_on_each_frame knob from the reader format Knob* myKnob = _pReadGeo->knob("read_on_each_frame"); newHash.append(myKnob->get_value()); } void my3dReader::get_geometry_hash(Hash* geo_hash) { // Use this function to invalidate different aspects of the geometry. e.g. // geo_hash[Group_Primitives].append(myLocalVariable1); // geo_hash[Group_Matrix].append(myLocalVariable2); } void my3dReader::_validate(const bool for_real) { // Use this to do any pre-render setup code. } void my3dReader::geometry_engine(Scene& scene, GeometryList& out) { const unsigned int kMaxLineLen = 4096; // Open the file std::ifstream in(filename()); // Skip over the header. in.ignore(kMaxLineLen, '\n'); int obj = 0; out.add_object(obj); PointList* points = out.writable_points(obj); Attribute* normals = out.writable_attribute(obj, Group_Primitives, kNormalAttrName, NORMAL_ATTRIB); Attribute* texCoords = out.writable_attribute(obj, Group_Points, kUVAttrName, VECTOR4_ATTRIB); Vector3 pos, normal; Vector4 uv(0, 0, 0, 1); float size; int n = 0; while (in.good()) { in >> size >> pos.x >> pos.y >> pos.z >> normal.x >> normal.y >> normal.z >> uv.x >> uv.y; in.ignore(kMaxLineLen, '\n'); // skip any trailing characters. out.add_primitive(obj, new Triangle(n * 3, n * 3 + 1, n * 3 + 2)); Vector3 v1 = normal.cross(Vector3(1, 0, 0)); Vector3 v2 = v1.cross(normal); v1.normalize(); v2.normalize(); points->push_back(pos); points->push_back(pos + (v1 * size)); points->push_back(pos + (v2 * size)); normals->add(1); normals->normal(n) = normal; texCoords->add(3); texCoords->vector4(n * 3) = uv; texCoords->vector4(n * 3 + 1) = uv + Vector4(size, 0, 0, 0); texCoords->vector4(n * 3 + 2) = uv + Vector4(0, size, 0, 0); ++n; } } // // my3dReader static methods // GeoReader* my3dReader::Build(ReadGeo* readNode, int fd, const unsigned char* buf, int bufSize) { return new my3dReader(readNode); } bool my3dReader::Test(int fd, const unsigned char* buf, int bufSize) { const char* kHeader = "{my3d}"; const size_t kHeaderLen = strlen(kHeader); // Check that the buffer starts with our header. return (bufSize >= (int)kHeaderLen && strncmp(kHeader, (const char*)buf, kHeaderLen) == 0); } // // my3dReader static variables // // if your reader implements a GeoReaderFormat, use this implementation of description: /*! Build the my3d file interface */ static GeoReader* build(ReadGeo* op, int fd, const unsigned char* b, int n) { return new my3dReader(op); } GeoReader::Description my3dReader::description("my3d\0", build, my3dReaderFormat::buildformat, my3dReader::Test); // Otherwise, use this implementation // GeoReader::Description my3dReader::description("my3d\0", my3dReader::Build, my3dReader::Test); } // namespace my3d