#define BOOST_FILESYSTEM_NO_LIB #define BOOST_SYSTEM_NO_LIB #include #include #include #include #include #include #include #include #include #include #include #if defined(__OSX__) #include #else #include #endif #include "converter.h" typedef std::map StringMap; enum ESourceType { EPosition = 0, ENormal = 1, EUV = 2, EVertexColors = 3, ELast }; struct Vec4 { Float x, y, z, w; inline Vec4(Float x=0, Float y=0, Float z=0, Float w=0) : x(x), y(y), z(z), w(w) { } inline Float operator[](int i) const { return (&x)[i]; } inline Float &operator[](int i) { return (&x)[i]; } inline Point toPoint() const { return Point(x, y, z); } inline Normal toNormal() const { return Normal(x, y, z); } inline Point2 toPoint2() const { return Point2(x, y); } }; struct VertexData { size_t nSources; bool hasNormals; bool hasUVs; GLdouble *glPos; std::vector data; std::vector typeToOffset; std::vector typeToOffsetInStream; VertexData() : glPos(NULL) { } virtual ~VertexData() { for (size_t i=0; i tess_data; size_t tess_nSources; VertexData *fetchVertexData(Transform transform, std::ostream &os, const domInputLocal_Array &vertInputs, const domInputLocalOffset_Array &inputs) { VertexData *result = new VertexData(); result->hasNormals = false; result->hasUVs = false; result->nSources = inputs.getCount(); result->data.resize(result->nSources); for (size_t i=0; inSources; ++i) result->data[i] = NULL; result->typeToOffset.resize(ELast); result->typeToOffsetInStream.resize(ELast); for (int i=0; itypeToOffset[i] = result->typeToOffsetInStream[i] = -1; int vertInputIndex = 0; for (size_t i=0; igetOffset(), offset = offsetInStream; daeURI &sourceRef = inputs[i]->getSource(); sourceRef.resolveElement(); domSource *source = daeSafeCast(sourceRef.getElement()); std::string semantic = inputs[i]->getSemantic(); if (semantic == "VERTEX") { sourceRef = vertInputs[vertInputIndex]->getSource(); sourceRef.resolveElement(); source = daeSafeCast(sourceRef.getElement()); semantic = vertInputs[vertInputIndex]->getSemantic(); if (vertInputIndex > 0) { offset = result->data.size(); result->data.push_back(NULL); } if (++vertInputIndex < (int) vertInputs.getCount()) --i; } domListOfFloats &floatArray = source->getFloat_array()->getValue(); domSource::domTechnique_common *techniqueCommon = source->getTechnique_common(); if (!techniqueCommon) SLog(EError, "Data source does not have a tag!"); domAccessor *accessor = techniqueCommon->getAccessor(); if (!accessor) SLog(EError, "Data source does not have a tag!"); int nParams = (int) accessor->getParam_array().getCount(), stride = (int) accessor->getStride(), size = (int) accessor->getCount(); SAssert(nParams <= 4); Vec4 *target = new Vec4[size]; for (int j=0; jdata[offset] = target; if (semantic == "POSITION") { SAssert(accessor->getStride() == 3); SAssert(result->typeToOffset[EPosition] == -1); result->typeToOffset[EPosition] = offset; result->typeToOffsetInStream[EPosition] = offsetInStream; result->glPos = new GLdouble[3*size]; for (int k=0; k<3*size; ++k) result->glPos[k] = floatArray[k]; } else if (semantic == "NORMAL") { SAssert(accessor->getStride() == 3); SAssert(result->typeToOffset[ENormal] == -1); result->hasNormals = true; result->typeToOffset[ENormal] = offset; result->typeToOffsetInStream[ENormal] = offsetInStream; } else if (semantic == "TEXCOORD") { SAssert(accessor->getStride() == 2 || accessor->getStride() == 3); if (result->typeToOffset[EUV] == -1) { result->hasUVs = true; result->typeToOffset[EUV] = offset; result->typeToOffsetInStream[EUV] = offsetInStream; } else { SLog(EWarn, "Found multiple sets of texture coordinates - ignoring!"); } } else if (semantic == "COLOR") { SLog(EWarn, "Found per-vertex colors - ignoring. Please bake into a texture " "(Lighting/shading -> Batch Bake in Maya)"); result->typeToOffset[EVertexColors] = offset; result->typeToOffsetInStream[EVertexColors] = offsetInStream; } else { SLog(EError, "Encountered an unknown source semantic: %s", semantic.c_str()); } } SAssert(result->typeToOffset[EPosition] != -1); return result; } /// For using vertices as keys in an associative structure struct vertex_key_order : public std::binary_function { public: bool operator()(const Vertex &v1, const Vertex &v2) const { if (v1.v.x < v2.v.x) return true; else if (v1.v.x > v2.v.x) return false; if (v1.v.y < v2.v.y) return true; else if (v1.v.y > v2.v.y) return false; if (v1.v.z < v2.v.z) return true; else if (v1.v.z > v2.v.z) return false; if (v1.n.x < v2.n.x) return true; else if (v1.n.x > v2.n.x) return false; if (v1.n.y < v2.n.y) return true; else if (v1.n.y > v2.n.y) return false; if (v1.n.z < v2.n.z) return true; else if (v1.n.z > v2.n.z) return false; if (v1.uv.x < v2.uv.x) return true; else if (v1.uv.x > v2.uv.x) return false; if (v1.uv.y < v2.uv.y) return true; else if (v1.uv.y > v2.uv.y) return false; return false; } }; void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::string matID, Transform transform, std::ostream &os, VertexData *vData, const std::string &meshesDirectory) { std::vector vertexBuffer; std::vector triangles; std::map vertexMap; size_t numMerged = 0, triangleIdx = 0; Triangle triangle; id += formatString("_%i", geomIndex); for (size_t i=0; itypeToOffsetInStream[EPosition]]; vertex.v = vData->data[vData->typeToOffset[EPosition]][posRef].toPoint(); if (vData->typeToOffset[ENormal] != -1) { domUint normalRef = tess_data[i+vData->typeToOffsetInStream[ENormal]]; vertex.n = vData->data[vData->typeToOffset[ENormal]][normalRef].toNormal(); } if (vData->typeToOffset[EUV] != -1) { domUint uvRef = tess_data[i+vData->typeToOffsetInStream[EUV]]; vertex.uv = vData->data[vData->typeToOffset[EUV]][uvRef].toPoint2(); } int key = -1; if (vertexMap.find(vertex) != vertexMap.end()) { key = vertexMap[vertex]; numMerged++; } else { key = (int) vertexBuffer.size(); vertexMap[vertex] = (int) key; vertexBuffer.push_back(vertex); } triangle.idx[triangleIdx++] = key; if (triangleIdx == 3) { triangles.push_back(triangle); triangleIdx = 0; } } SAssert(triangleIdx == 0); SLog(EInfo, "%s: Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT " vertices (merged " SIZE_T_FMT " vertices).", id.c_str(), triangles.size(), vertexBuffer.size(), numMerged); ref mesh = new TriMesh(triangles.size(), vertexBuffer.size()); std::copy(triangles.begin(), triangles.end(), mesh->getTriangles()); std::copy(vertexBuffer.begin(), vertexBuffer.end(), mesh->getVertexBuffer()); mesh->calculateTangentSpaceBasis(vData->typeToOffset[ENormal]!=-1, vData->typeToOffset[EUV]!=-1); std::string filename = meshesDirectory + id + std::string(".serialized"); ref stream = new FileStream(filename, FileStream::ETruncReadWrite); stream->setByteOrder(Stream::ENetworkByteOrder); mesh->serialize(stream); stream->close(); std::ostringstream matrix; for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) matrix << transform.getMatrix()->m[i][j] << " "; std::string matrixValues = matrix.str(); os << "\t" << endl; os << "\t\t" << endl; if (!transform.isIdentity()) { os << "\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t" << endl; } if (matID != "") os << "\t\t" << endl; os << "\t" << endl << endl; } void loadGeometry(std::string prefixName, Transform transform, std::ostream &os, domGeometry &geom, StringMap &matLookupTable, const std::string &meshesDir) { std::string identifier; if (geom.getId() != NULL) { identifier = geom.getId(); } else { if (geom.getName() != NULL) { identifier = geom.getName(); } else { static int unnamedCtr = 0; identifier = formatString("unnamedGeom_%i", unnamedCtr++); } } SLog(EInfo, "Converting geometry \"%s\" (instantiated by %s)..", identifier.c_str(), prefixName.c_str()); domMesh *mesh = geom.getMesh().cast(); if (!mesh) SLog(EError, "Invalid geometry type encountered (must be a )!"); const domInputLocal_Array &vertInputs = mesh->getVertices()->getInput_array(); int geomIndex = 0; domTriangles_Array &trianglesArray = mesh->getTriangles_array(); for (size_t i=0; igetInput_array(); VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); domListOfUInts &indices = triangles->getP()->getValue(); tess_data.clear(); tess_nSources = data->nSources; for (size_t j=0; jgetMaterial() == NULL || matLookupTable.find(triangles->getMaterial()) == matLookupTable.end()) SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); else matID = matLookupTable[triangles->getMaterial()]; writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, meshesDir); delete data; ++geomIndex; } domPolygons_Array &polygonsArray = mesh->getPolygons_array(); for (size_t i=0; igetInput_array(); VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); domP_Array &indexArray = polygons->getP_array(); int posOffset = data->typeToOffset[EPosition]; tess_data.clear(); tess_nSources = data->nSources; for (size_t j=0; jgetValue(); domUint *temp = new domUint[indices.getCount()]; for (size_t l = 0; lnSources) gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp)); gluTessEndContour(tess); gluTessEndPolygon(tess); delete[] temp; } std::string matID; if (polygons->getMaterial() == NULL || matLookupTable.find(polygons->getMaterial()) == matLookupTable.end()) SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); else matID = matLookupTable[polygons->getMaterial()]; writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, meshesDir); delete data; ++geomIndex; } domPolylist_Array &polylistArray = mesh->getPolylist_array(); for (size_t i=0; igetInput_array(); VertexData *data = fetchVertexData(transform, os, vertInputs, inputs); domListOfUInts &vcount = polylist->getVcount()->getValue(); domListOfUInts &indexArray = polylist->getP()->getValue(); int posOffset = data->typeToOffset[EPosition], indexOffset = 0; tess_data.clear(); tess_nSources = data->nSources; for (size_t j=0; jnSources]; for (size_t l = 0; lnSources; ++l) temp[l] = indexArray.get(indexOffset++); gluTessBeginPolygon(tess, NULL); gluTessBeginContour(tess); for (size_t k=0; kglPos[temp[k*data->nSources+posOffset]*3], (GLvoid *) (temp + k*data->nSources)); gluTessEndContour(tess); gluTessEndPolygon(tess); delete[] temp; } std::string matID; if (polylist->getMaterial() == NULL || matLookupTable.find(polylist->getMaterial()) == matLookupTable.end()) SLog(EWarn, "Referenced material could not be found, substituting a lambertian BRDF."); else matID = polylist->getMaterial(); writeGeometry(prefixName, identifier, geomIndex, matID, transform, os, data, meshesDir); delete data; ++geomIndex; } } void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const std::string &name, StringMap &idToTexture, domCommon_color_or_texture_type *value, bool handleRefs) { if (!value) return; domCommon_color_or_texture_type_complexType::domColor* color = value->getColor().cast(); domCommon_color_or_texture_type_complexType::domTexture* texture = value->getTexture().cast(); if (color && !handleRefs) { domFloat4 &colValue = color->getValue(); if (cvt->m_srgb) os << "\t\t" << endl; } else if (texture && handleRefs) { if (idToTexture.find(texture->getTexture()) == idToTexture.end()) { SLog(EError, "Could not find referenced texture \"%s\"", texture->getTexture()); } else { os << "\t\tgetTexture()] << "\"/>" << endl; } } } void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const std::string &name, StringMap &, domCommon_float_or_param_type *value, bool handleRef) { if (!value) return; domCommon_float_or_param_type::domFloat *floatValue = value->getFloat(); if (!handleRef && floatValue) { os << "\t\tgetValue() << "\"/>" << endl; } } void loadMaterial(GeometryConverter *cvt, std::ostream &os, domMaterial &mat, StringMap &_idToTexture) { std::string identifier; if (mat.getId() != NULL) { identifier = mat.getId(); } else { if (mat.getName() != NULL) { identifier = mat.getName(); } else { static int unnamedCtr = 0; identifier = formatString("unnamedMat_%i", unnamedCtr++); } } StringMap idToTexture = _idToTexture; daeURI &effRef = mat.getInstance_effect()->getUrl(); effRef.resolveElement(); domEffect *effect = daeSafeCast(effRef.getElement()); if (!effect) SLog(EError, "Referenced effect not found!"); domProfile_COMMON *commonProfile = daeSafeCast (effect->getDescendant("profile_COMMON")); if (!commonProfile) SLog(EError, "Common effect profile not found!"); /* The following supports a subset of the curious ColladaFX output produced by the Blender COLLADA exporter */ daeTArray > &newParamArray = commonProfile->getNewparam_array(); for (size_t i=0; igetSurface(); domFx_sampler2D_common *sampler2D = newParam->getSampler2D(); if (surface) { SAssert(surface->getType() == FX_SURFACE_TYPE_ENUM_2D); daeTArray > &initFromArray = surface->getFx_surface_init_common()->getInit_from_array(); SAssert(initFromArray.getCount() == 1); std::string id = initFromArray[0]->getValue().getID(); if (idToTexture.find(id) == idToTexture.end()) SLog(EError, "Referenced bitmap '%s' not found!", id.c_str()); idToTexture[newParam->getSid()] = idToTexture[id]; } if (sampler2D) { std::string id = sampler2D->getSource()->getValue(); if (idToTexture.find(id) == idToTexture.end()) SLog(EError, "Referenced surface '%s' not found!", id.c_str()); idToTexture[newParam->getSid()] = idToTexture[id]; } } domProfile_COMMON::domTechnique *technique = commonProfile->getTechnique(); if (!technique) SLog(EError, "The technique element is missing!"); domProfile_COMMON::domTechnique::domPhong* phong = technique->getPhong(); domProfile_COMMON::domTechnique::domBlinn* blinn = technique->getBlinn(); domProfile_COMMON::domTechnique::domLambert* lambert = technique->getLambert(); domProfile_COMMON::domTechnique::domConstant* constant = technique->getConstant(); if (phong) { domCommon_color_or_texture_type* diffuse = phong->getDiffuse(); domCommon_color_or_texture_type* specular = phong->getSpecular(); domCommon_float_or_param_type* shininess = phong->getShininess(); bool isDiffuse = false; if (specular->getColor().cast()) { domFloat4 &colValue = specular->getColor()->getValue(); if (colValue.get(0) == colValue.get(1) && colValue.get(1) == colValue.get(2) && colValue.get(2) == 0) isDiffuse = true; } if (isDiffuse) { os << "\t" << endl; loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false); loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true); os << "\t" << endl << endl; } else { os << "\t" << endl; os << "\t\t" << endl; os << "\t\t" << endl; loadMaterialParam(cvt, os, "diffuseColor", idToTexture, diffuse, false); loadMaterialParam(cvt, os, "specularColor", idToTexture, specular, false); loadMaterialParam(cvt, os, "exponent", idToTexture, shininess, false); loadMaterialParam(cvt, os, "diffuseColor", idToTexture, diffuse, true); loadMaterialParam(cvt, os, "specularColor", idToTexture, specular, true); loadMaterialParam(cvt, os, "exponent", idToTexture, shininess, true); os << "\t" << endl << endl; } } else if (lambert) { domCommon_color_or_texture_type* diffuse = lambert->getDiffuse(); os << "\t" << endl; loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false); loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true); os << "\t" << endl << endl; } else if (blinn) { SLog(EWarn, "\"%s\": Encountered a \"blinn\" COLLADA material, which is currently " "unsupported in Mitsuba -- replacing it using a Phong material.", identifier.c_str()); domCommon_color_or_texture_type* diffuse = blinn->getDiffuse(); domCommon_color_or_texture_type* specular = blinn->getSpecular(); domCommon_float_or_param_type* shininess = blinn->getShininess(); bool isDiffuse = false; if (specular->getColor().cast()) { domFloat4 &colValue = specular->getColor()->getValue(); if (colValue.get(0) == colValue.get(1) && colValue.get(1) == colValue.get(2) && colValue.get(2) == 0) isDiffuse = true; } if (isDiffuse) { os << "\t" << endl; loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false); loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true); os << "\t" << endl << endl; } else { os << "\t" << endl; os << "\t\t" << endl; os << "\t\t" << endl; loadMaterialParam(cvt, os, "diffuseColor", idToTexture, diffuse, false); loadMaterialParam(cvt, os, "specularColor", idToTexture, specular, false); loadMaterialParam(cvt, os, "exponent", idToTexture, shininess, false); loadMaterialParam(cvt, os, "diffuseColor", idToTexture, diffuse, true); loadMaterialParam(cvt, os, "specularColor", idToTexture, specular, true); loadMaterialParam(cvt, os, "exponent", idToTexture, shininess, true); os << "\t" << endl << endl; } } else if (constant) { SLog(EWarn, "\"%s\": Encountered a \"constant\" COLLADA material, which is currently " "unsupported in Mitsuba -- replacing it using a Lambertian material.", identifier.c_str()); os << "\t" << endl << endl; } else { SLog(EError, "Material type not supported! (must be Lambertian/Phong/Blinn/Constant)"); } } void loadLight(Transform transform, std::ostream &os, domLight &light) { std::string identifier; if (light.getId() != NULL) { identifier = light.getId(); } else { if (light.getName() != NULL) { identifier = light.getName(); } else { static int unnamedCtr = 0; identifier = formatString("unnamedLight_%i", unnamedCtr++); } } SLog(EInfo, "Converting light \"%s\" ..", identifier.c_str()); char *end_ptr = NULL; // Lights in Mitsuba point along the positive Z axis (COLLADA: neg. Z) transform = transform * Transform::scale(Vector(1, 1, -1)); Point pos = transform(Point(0, 0, 0)); Vector target = transform(Point(0, 0, 1)); Float intensity = 1; const domTechnique_Array &techniques = light.getTechnique_array(); for (size_t i=0; igetChild("intensity"); if (intensityElement && intensityElement->hasCharData()) { std::string charData = intensityElement->getCharData(); intensity = (Float) strtod(charData.c_str(), &end_ptr); if (*end_ptr != '\0') SLog(EError, "Could not parse the light intensity!"); } } domLight::domTechnique_common::domPoint *point = light.getTechnique_common()->getPoint().cast(); if (point) { bool notQuadratic = false; if (point->getConstant_attenuation() && point->getConstant_attenuation()->getValue() != 1) notQuadratic = true; if (point->getLinear_attenuation() && point->getLinear_attenuation()->getValue() != 0) notQuadratic = true; if (point->getQuadratic_attenuation() && point->getQuadratic_attenuation()->getValue() != 1) notQuadratic = true; if (notQuadratic) SLog(EWarn, "Point light \"%s\" is not a quadratic light! Treating it as one -- expect problems.", identifier.c_str()); domFloat3 &color = point->getColor()->getValue(); os << "\t" << endl; os << "\t\t" << endl << endl; os << "\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t" << endl; os << "\t" << endl << endl; } domLight::domTechnique_common::domDirectional *directional = light.getTechnique_common()->getDirectional().cast(); if (directional) { domFloat3 &color = directional->getColor()->getValue(); os << "\t" << endl; os << "\t\t" << endl << endl; os << "\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t" << endl << endl; os << "\t" << endl << endl; } domLight::domTechnique_common::domSpot *spot = light.getTechnique_common()->getSpot().cast(); if (spot) { bool notQuadratic = false; if (spot->getConstant_attenuation() && spot->getConstant_attenuation()->getValue() != 1) notQuadratic = true; if (spot->getLinear_attenuation() && spot->getLinear_attenuation()->getValue() != 0) notQuadratic = true; if (spot->getQuadratic_attenuation() && spot->getQuadratic_attenuation()->getValue() != 1) notQuadratic = true; if (notQuadratic) SLog(EWarn, "Spot light \"%s\" is not a quadratic light! Treating it as one -- expect problems.", identifier.c_str()); domFloat3 &color = spot->getColor()->getValue(); Float falloffAngle = 180.0f; if (spot->getFalloff_angle()) falloffAngle = (Float) spot->getFalloff_angle()->getValue(); os << "\t" << endl; os << "\t\t" << endl; os << "\t\t" << endl << endl; os << "\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t" << endl; os << "\t" << endl << endl; } domLight::domTechnique_common::domAmbient *ambient = light.getTechnique_common()->getAmbient().cast(); if (ambient) { domFloat3 &color = ambient->getColor()->getValue(); os << "\t" << endl; os << "\t\t" << endl; os << "\t" << endl << endl; } if (!point && !spot && !ambient && !directional) SLog(EWarn, "Encountered an unknown light type!"); } void loadImage(GeometryConverter *cvt, std::ostream &os, const std::string &textureDir, domImage &image, StringMap &idToTexture, StringMap &fileToId) { std::string identifier; if (image.getId() != NULL) { identifier = image.getId(); } else { if (image.getName() != NULL) { identifier = image.getName(); } else { static int unnamedCtr = 0; identifier = formatString("unnamedTexture_%i", unnamedCtr++); } } SLog(EInfo, "Converting texture \"%s\" ..", identifier.c_str()); std::string filename = cdom::uriToFilePath(image.getInit_from()->getValue().str()); if (fileToId.find(filename) != fileToId.end()) { idToTexture[identifier] = fileToId[filename]; return; } idToTexture[identifier] = identifier; fileToId[filename] = identifier; boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native); std::string targetPath = textureDir + path.leaf(); if (endsWith(filename, ".rgb")) SLog(EWarn, "Maya RGB images must be converted to PNG, EXR or JPEG! The 'imgcvt' " "utility found in the Maya binary directory can be used to do this."); if (!FileStream::exists(targetPath)) { ref fRes = FileResolver::getInstance(); std::string resolved = fRes->resolve(path.leaf()); if (!FileStream::exists(filename)) { if (!FileStream::exists(resolved)) { SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), resolved.c_str()); filename = cvt->locateResource(filename); if (filename == "") SLog(EError, "Unable to locate a resource -- aborting conversion."); } else { filename = resolved; } } ref input = new FileStream(filename, FileStream::EReadOnly); ref output = new FileStream(targetPath, FileStream::ETruncReadWrite); input->copyTo(output); input->close(); output->close(); } os << "\t" << endl; os << "\t\t" << endl; os << "\t" << endl << endl; } void loadCamera(GeometryConverter *cvt, Transform transform, std::ostream &os, domCamera &camera) { std::string identifier; if (camera.getId() != NULL) { identifier = camera.getId(); } else { if (camera.getName() != NULL) { identifier = camera.getName(); } else { static int unnamedCtr = 0; identifier = formatString("unnamedCamera_%i", unnamedCtr++); } } SLog(EInfo, "Converting camera \"%s\" ..", identifier.c_str()); Float aspect = 1.0f; int xres=768; // Cameras in Mitsuba point along the positive Z axis (COLLADA: neg. Z) transform = transform * Transform::scale(Vector(1,1,-1)); std::ostringstream matrix; for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) matrix << transform.getMatrix()->m[i][j] << " "; std::string matrixValues = matrix.str(); domCamera::domOptics::domTechnique_common::domOrthographic* ortho = camera.getOptics()-> getTechnique_common()->getOrthographic().cast(); if (ortho) { if (ortho->getAspect_ratio().cast() != 0) aspect = (Float) ortho->getAspect_ratio()->getValue(); if (cvt->m_xres != -1) { xres = cvt->m_xres; aspect = (Float) cvt->m_xres / (Float) cvt->m_yres; } os << "\t" << endl; } domCamera::domOptics::domTechnique_common::domPerspective* persp = camera.getOptics()-> getTechnique_common()->getPerspective().cast(); if (persp) { if (cvt->m_xres != -1) { xres = cvt->m_xres; aspect = (Float) cvt->m_xres / (Float) cvt->m_yres; } else { if (persp->getAspect_ratio().cast() != 0) { aspect = (Float) persp->getAspect_ratio()->getValue(); if (std::abs(aspect-0.1) < Epsilon) { SLog(EWarn, "Found the suspicious aspect ratio \"0.1\", which is likely due to a bug in Blender 2.5" " - setting to 1.0. Please use the \"-r\" parameter to override the resolution."); aspect = 1.0f; } } } os << "\t" << endl; if (persp->getXfov().cast()) { Float xFov = (Float) persp->getXfov()->getValue(); if (std::abs(xFov-1.0f) < Epsilon && cvt->m_fov == -1) { SLog(EWarn, "Found the suspicious field of view value \"1.0\", which is likely due to a bug in Blender 2.5" " - setting to 45deg. Please use the \"-f\" parameter to override this."); xFov = 45.0f; } Float yFov = radToDeg(2 * std::atan(std::tan(degToRad(xFov)/2) / aspect)); if (cvt->m_fov != -1) xFov = yFov = cvt->m_fov; if (aspect <= 1.0f) os << "\t\t" << endl; else os << "\t\t" << endl; } else if (persp->getYfov().cast()) { Float yFov = (Float) persp->getYfov()->getValue(); if (std::abs(yFov-1.0) < Epsilon && cvt->m_fov == -1) { SLog(EWarn, "Found the suspicious field of view value \"1.0\", which is likely due to a bug in Blender 2.5" " - setting to 45deg. Please use the \"-f\" parameter to override this."); yFov = 45.0f; } Float xFov = radToDeg(2 * std::atan(std::tan(degToRad(yFov)/2) * aspect)); if (cvt->m_fov != -1) xFov = yFov = cvt->m_fov; if (aspect > 1.0f) os << "\t\t" << endl; else os << "\t\t" << endl; } os << "\t\tgetZnear()->getValue() << "\"/>" << endl; os << "\t\tgetZfar()->getValue() << "\"/>" << endl; os << "\t\tm_mapSmallerSide ? "true" : "false") << "\"/>" << endl; } os << endl; os << "\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t" << endl << endl; os << "\t\t" << endl; os << "\t\t\tm_samplesPerPixel << "\"/>" << endl; os << "\t\t" << endl << endl; os << "\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t\t" << endl; os << "\t\t" << endl; os << "\t" << endl << endl; } void loadNode(GeometryConverter *cvt, Transform transform, std::ostream &os, domNode &node, std::string prefixName, const std::string &meshesDir) { std::string identifier; if (node.getId() != NULL) { identifier = node.getId(); } else { if (node.getName() != NULL) { identifier = node.getName(); } else { static int unnamedCtr = 0; identifier = formatString("unnamedNode_%i", unnamedCtr); } } SLog(EInfo, "Converting node \"%s\" ..", identifier.c_str()); daeTArray > children = node.getChildren(); /* Parse transformations */ for (size_t i=0; itypeID() == domRotate::ID()) { /* Skip rotations labeled as "post-rotationY". Maya exports these with some cameras, which introduces an incorrect 90 degree rotation unless ignored */ if (element->hasAttribute("sid") && element->getAttribute("sid") == "post-rotationY") continue; daeTArray value = daeSafeCast(element)->getValue(); transform = transform * Transform::rotate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), (Float) value.get(3)); } else if (element->typeID() == domTranslate::ID()) { daeTArray value = daeSafeCast(element)->getValue(); transform = transform * Transform::translate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2))); } else if (element->typeID() == domScale::ID()) { daeTArray value = daeSafeCast(element)->getValue(); transform = transform * Transform::scale(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2))); } else if (element->typeID() == domLookat::ID()) { daeTArray value = daeSafeCast(element)->getValue(); transform = transform * Transform::lookAt( Point((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), Point((Float) value.get(3), (Float) value.get(4), (Float) value.get(5)), Vector((Float) value.get(6), (Float) value.get(7), (Float) value.get(8)) ); } else if (element->typeID() == domMatrix::ID()) { daeTArray value = daeSafeCast(element)->getValue(); ref matrix = new Matrix4x4( (Float) value.get(0), (Float) value.get(1), (Float) value.get(2), (Float) value.get(3), (Float) value.get(4), (Float) value.get(5), (Float) value.get(6), (Float) value.get(7), (Float) value.get(8), (Float) value.get(9), (Float) value.get(10), (Float) value.get(11), (Float) value.get(12), (Float) value.get(13), (Float) value.get(14), (Float) value.get(15) ); transform = transform * Transform(matrix); } } /* Iterate over all geometry references */ domInstance_geometry_Array &instanceGeometries = node.getInstance_geometry_array(); for (size_t i=0; i(inst->getUrl().getElement()); domBind_material *bmat = inst->getBind_material(); StringMap matLookupTable; if (bmat) { domBind_material::domTechnique_common *technique = bmat->getTechnique_common(); if (!technique) SLog(EError, "bind_material does not contain a element!"); domInstance_material_Array &instMaterials = technique->getInstance_material_array(); for (size_t i=0; igetTarget(); matRef.resolveElement(); domMaterial *material = daeSafeCast(matRef.getElement()); matLookupTable[instMat->getSymbol()] = material->getId(); } } else { SLog(EWarn, "instance_geometry does not contain a element!"); } if (!geom) SLog(EError, "Could not find a referenced geometry object!"); loadGeometry(prefixName, transform, os, *geom, matLookupTable, meshesDir); } /* Iterate over all light references */ domInstance_light_Array &instanceLights = node.getInstance_light_array(); for (size_t i=0; i(inst->getUrl().getElement()); if (!light) SLog(EError, "Could not find a referenced light!"); loadLight(transform, os, *light); } /* Iterate over all camera references */ domInstance_camera_Array &instanceCameras = node.getInstance_camera_array(); for (size_t i=0; i(inst->getUrl().getElement()); if (camera == NULL) SLog(EError, "Could not find a referenced camera!"); loadCamera(cvt, transform, os, *camera); } /* Recursively iterate through sub-nodes */ domNode_Array &nodes = node.getNode_array(); for (size_t i=0; i elements */ domInstance_node_Array &instanceNodes = node.getInstance_node_array(); for (size_t i=0; i(instanceNodes[i]->getUrl().getElement()); if (!node) SLog(EError, "Could not find a referenced node!"); loadNode(cvt, transform, os, *node, prefixName + std::string("/") + identifier, meshesDir); } } #ifndef WIN32 #define __stdcall #endif GLvoid __stdcall tessBegin(GLenum type) { SAssert(type == GL_TRIANGLES); } GLvoid __stdcall tessVertex(void *data) { const domUint *raw = (domUint *) data; for (size_t i=0; iresolveAbsolute(inputFile); #else std::string path = inputFile; #endif DAE *dae = new DAE(); SLog(EInfo, "Loading \"%s\" ..", path.c_str()); if (dae->load(path.c_str()) != DAE_OK) SLog(EError, "Could not load \"%s\"!", path.c_str()); domCOLLADA *document = dae->getDom(path.c_str()); domVisual_scene *visualScene = daeSafeCast (document->getDescendant("visual_scene")); if (!visualScene) SLog(EError, "Could not find a visual_scene!"); /* Configure the GLU tesselator */ tess = gluNewTess(); if (!tess) SLog(EError, "Could not allocate a GLU tesselator!"); gluTessCallback(tess, GLU_TESS_VERTEX, reinterpret_cast(&tessVertex)); gluTessCallback(tess, GLU_TESS_BEGIN, reinterpret_cast(&tessBegin)); gluTessCallback(tess, GLU_TESS_END, reinterpret_cast(&tessEnd)); gluTessCallback(tess, GLU_TESS_ERROR, reinterpret_cast(&tessError)); gluTessCallback(tess, GLU_TESS_COMBINE, reinterpret_cast(&tessCombine)); gluTessCallback(tess, GLU_TESS_EDGE_FLAG, reinterpret_cast(&tessEdgeFlag)); domNode_Array &nodes = visualScene->getNode_array(); os << "" << endl << endl; os << "" << endl << endl; os << "" << endl; os << "\t" << endl << endl; StringMap idToTexture, fileToId; domLibrary_images_Array &libraryImages = document->getLibrary_images_array(); for (size_t i=0; igetImage_array(); for (size_t j=0; jgetLibrary_materials_array(); for (size_t i=0; igetMaterial_array(); for (size_t j=0; j" << endl; gluDeleteTess(tess); delete dae; }