void WriterNodeVisitor::createListTriangle(osg::Geometry * geo, ListTriangle & listTriangles, bool & texcoords, unsigned int & drawable_n) { const osg::Array * basevecs = geo->getVertexArray(); if (!basevecs || basevecs->getNumElements()==0) return; // Texture coords const osg::Array * basetexvecs = geo->getNumTexCoordArrays()>=1 ? geo->getTexCoordArray(0) : NULL; if (basetexvecs) { unsigned int nb = basetexvecs->getNumElements(); if (nb != geo->getVertexArray()->getNumElements()) { OSG_NOTIFY(osg::FATAL) << "There are more/less texture coords than vertices (corrupted geometry)" << std::endl; _succeeded = false; return; } texcoords = true; } int material = processStateSet(_currentStateSet.get()); for(unsigned int i = 0; i < geo->getNumPrimitiveSets(); ++i) //Fill the Triangle List { osg::PrimitiveSet* ps = geo->getPrimitiveSet(i); PrimitiveIndexWriter pif(geo, listTriangles, drawable_n, material); ps->accept(pif); } }
bool osg::isGLExtensionOrVersionSupported(unsigned int contextID, const char *extension, float requiredGLVersion) { ExtensionSet& extensionSet = s_glExtensionSetList[contextID]; std::string& rendererString = s_glRendererList[contextID]; // first check to see if GL version number of recent enough. bool result = requiredGLVersion <= osg::getGLVersionNumber(); if (!result) { // if not already set up, initialize all the per graphic context values. if (!s_glInitializedList[contextID]) { s_glInitializedList[contextID] = 1; // set up the renderer const GLubyte* renderer = glGetString(GL_RENDERER); rendererString = renderer ? (const char*)renderer : ""; // get the extension list from OpenGL. GLint numExt = 0; #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) if( osg::getGLVersionNumber() >= 3.0 ) { // OpenGL 3.0 adds the concept of indexed strings and // deprecates calls to glGetString( GL_EXTENSIONS ), which // will now generate GL_INVALID_ENUM. // Get extensions using new indexed string interface. typedef const GLubyte * GL_APIENTRY PFNGLGETSTRINGIPROC( GLenum, GLuint ); PFNGLGETSTRINGIPROC* glGetStringi = 0; setGLExtensionFuncPtr( glGetStringi, "glGetStringi"); if( glGetStringi != NULL ) { # ifndef GL_NUM_EXTENSIONS # define GL_NUM_EXTENSIONS 0x821D # endif glGetIntegerv( GL_NUM_EXTENSIONS, &numExt ); int idx; for( idx=0; idx<numExt; idx++ ) { extensionSet.insert( std::string( (char*)( glGetStringi( GL_EXTENSIONS, idx ) ) ) ); } } else { OSG_WARN << "isGLExtensionOrVersionSupported: Can't obtain glGetStringi function pointer." << std::endl; } } #endif // No extensions found so far, so try with glGetString if (numExt == 0) { // Get extensions using GL1/2 interface. const char* extensions = (const char*)glGetString(GL_EXTENSIONS); if (extensions==NULL) return false; // insert the ' ' delimiated extensions words into the extensionSet. const char *startOfWord = extensions; const char *endOfWord; while ((endOfWord = strchr(startOfWord,' '))!=NULL) { extensionSet.insert(std::string(startOfWord,endOfWord)); startOfWord = endOfWord+1; } if (*startOfWord!=0) extensionSet.insert(std::string(startOfWord)); } #if defined(WIN32) && (defined(OSG_GL1_AVAILABLE) || defined(OSG_GL2_AVAILABLE) || defined(OSG_GL3_AVAILABLE)) // add WGL extensions to the list typedef const char* WINAPI WGLGETEXTENSIONSSTRINGARB(HDC); WGLGETEXTENSIONSSTRINGARB* wglGetExtensionsStringARB = 0; setGLExtensionFuncPtr(wglGetExtensionsStringARB, "wglGetExtensionsStringARB"); typedef const char* WINAPI WGLGETEXTENSIONSSTRINGEXT(); WGLGETEXTENSIONSSTRINGEXT* wglGetExtensionsStringEXT = 0; setGLExtensionFuncPtr(wglGetExtensionsStringEXT, "wglGetExtensionsStringEXT"); const char* wglextensions = 0; if (wglGetExtensionsStringARB) { HDC dc = wglGetCurrentDC(); wglextensions = wglGetExtensionsStringARB(dc); } else if (wglGetExtensionsStringEXT) { wglextensions = wglGetExtensionsStringEXT(); } if (wglextensions) { const char* startOfWord = wglextensions; const char* endOfWord; while ((endOfWord = strchr(startOfWord, ' '))) { extensionSet.insert(std::string(startOfWord, endOfWord)); startOfWord = endOfWord+1; } if (*startOfWord != 0) extensionSet.insert(std::string(startOfWord)); } #endif OSG_NOTIFY(INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<<std::endl; for(ExtensionSet::iterator itr=extensionSet.begin(); itr!=extensionSet.end(); ++itr) { OSG_NOTIFY(INFO)<<" "<<*itr<<std::endl; } } // true if extension found in extensionSet. result = extensionSet.find(extension)!=extensionSet.end(); }
void Lwo2Layer::notify(NotifySeverity severity) { OSG_NOTIFY(severity) << "Current layer: " << _number << endl; OSG_NOTIFY(severity) << " flags \t" << _flags << endl; OSG_NOTIFY(severity) << " pivot \t" << _pivot << endl; OSG_NOTIFY(severity) << " name: \t'" << _name.c_str() << "'" << endl; OSG_NOTIFY(severity) << " parent:\t" << _parent << endl; // points OSG_NOTIFY(severity) << " points:\t" << _points.size() << endl; OSG_NOTIFY(severity) << "\tcoord\t\t\t\ttexcoord" << endl; OSG_NOTIFY(severity) << "\t=====\t\t\t\t========" << endl; IteratorPoint itr; for (itr = _points.begin(); itr != _points.end(); itr++) { OSG_NOTIFY(severity) << " \t" << (*itr).coord << "\t\t" << (*itr).texcoord << endl; } // polygons OSG_NOTIFY(severity) << " polygons:\t" << _polygons.size() << endl; OSG_NOTIFY(severity) << "\tcoord\t\t\t\ttexcoord" << endl; OSG_NOTIFY(severity) << "\t=====\t\t\t\t========" << endl; IteratorPolygonsList polygon_iterator; int polygon_index = 0; for (polygon_iterator = _polygons.begin(); polygon_iterator != _polygons.end(); polygon_iterator++, polygon_index++) { OSG_NOTIFY(severity) << " \t" << polygon_index << " ("<< (*polygon_iterator).size() << " vertexes" << "):" << endl; for (itr = (*polygon_iterator).begin(); itr != (*polygon_iterator).end(); itr++) { OSG_NOTIFY(severity) << " \t" << (*itr).coord << "\t\t" << (*itr).texcoord << endl; } OSG_NOTIFY(severity) << endl; } // polygons tags OSG_NOTIFY(severity) << " polygons tags:\t" << _polygons_tag.size() << endl; IteratorShort short_itr; for (short_itr = _polygons_tag.begin(); short_itr != _polygons_tag.end(); short_itr++) { OSG_NOTIFY(severity) << "\t" << (*short_itr) << endl; } }
WindowCaptureCallback::ContextData::ContextData(osg::GraphicsContext* gc, Mode mode, GLenum readBuffer) : _gc(gc), _index(_gc->getState()->getContextID()), _mode(mode), _readBuffer(readBuffer), _pixelFormat(GL_RGBA), _type(GL_UNSIGNED_BYTE), _width(0), _height(0), _currentImageIndex(0), _currentPboIndex(0), _reportTimingFrequency(100), _numTimeValuesRecorded(0), _timeForReadPixels(0.0), _timeForMemCpy(0.0), _timeForCaptureOperation(0.0), _timeForFullCopy(0.0), _timeForFullCopyAndOperation(0.0), _previousFrameTick(0) { _previousFrameTick = osg::Timer::instance()->tick(); osg::NotifySeverity level = osg::INFO; if (gc->getTraits()) { if (gc->getTraits()->alpha) { OSG_NOTIFY(level)<<"ScreenCaptureHandler: Selected GL_RGBA read back format"<<std::endl; _pixelFormat = GL_RGBA; } else { OSG_NOTIFY(level)<<"ScreenCaptureHandler: Selected GL_RGB read back format"<<std::endl; _pixelFormat = GL_RGB; } } getSize(gc, _width, _height); //OSG_NOTICE<<"Window size "<<_width<<", "<<_height<<std::endl; // single buffered image _imageBuffer.push_back(new osg::Image); // double buffer PBO. switch(_mode) { case(READ_PIXELS): OSG_NOTIFY(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, without PixelBufferObject."<<std::endl; break; case(SINGLE_PBO): OSG_NOTIFY(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, with a single PixelBufferObject."<<std::endl; _pboBuffer.push_back(0); break; case(DOUBLE_PBO): OSG_NOTIFY(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, with a double buffer PixelBufferObject."<<std::endl; _pboBuffer.push_back(0); _pboBuffer.push_back(0); break; case(TRIPLE_PBO): OSG_NOTIFY(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, with a triple buffer PixelBufferObject."<<std::endl; _pboBuffer.push_back(0); _pboBuffer.push_back(0); _pboBuffer.push_back(0); break; default: break; } }
void WriterNodeVisitor::buildFaces(osg::Geode & geo, const osg::Matrix & mat, ListTriangle & listTriangles, bool texcoords) { unsigned int nbTrianglesRemaining = listTriangles.size(); unsigned int nbVerticesRemaining = calcVertices(geo); // May set _succeded to false if (!succeeded()) return; std::string name( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), true, "geo") ); if (!succeeded()) return; Lib3dsMesh *mesh = lib3ds_mesh_new( name.c_str() ); if (!mesh) { OSG_NOTIFY(osg::FATAL) << "Allocation error" << std::endl; _succeeded = false; return; } //copyOsgMatrixToLib3dsMatrix(mesh->matrix, mat); lib3ds_mesh_resize_faces (mesh, osg::minimum(nbTrianglesRemaining, MAX_FACES)); lib3ds_mesh_resize_vertices(mesh, osg::minimum(nbVerticesRemaining, MAX_VERTICES), texcoords ? 0 : 1, 0); // Not mandatory but will allocate once a big block // Test if the mesh will be split and needs sorting if (nbVerticesRemaining >= MAX_VERTICES || nbTrianglesRemaining >= MAX_FACES) { OSG_INFO << "Sorting elements..." << std::endl; WriterCompareTriangle cmp(geo, nbVerticesRemaining); std::sort(listTriangles.begin(), listTriangles.end(), cmp); } MapIndices index_vert; unsigned int numFace = 0; // Current face index for (ListTriangle::iterator it = listTriangles.begin(); it != listTriangles.end(); ++it) //Go through the triangle list to define meshs { // Test if the mesh will be full after adding a face if (index_vert.size()+3 >= MAX_VERTICES || numFace+1 >= MAX_FACES) { // Finnish mesh lib3ds_mesh_resize_faces (mesh, numFace); //lib3ds_mesh_resize_vertices() will be called in buildMesh() buildMesh(geo, mat, index_vert, texcoords, mesh); // May set _succeded to false if (!succeeded()) { lib3ds_mesh_free(mesh); return; } // "Reset" values and start over a new mesh index_vert.clear(); nbTrianglesRemaining -= numFace; numFace = 0; // We can't call a thing like "nbVerticesRemaining -= ...;" because points may be used multiple times. // [Sukender: An optimisation here would take too much time I think.] mesh = lib3ds_mesh_new( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), true, "geo").c_str()); if (!mesh) { OSG_NOTIFY(osg::FATAL) << "Allocation error" << std::endl; _succeeded = false; return; } lib3ds_mesh_resize_faces (mesh, osg::minimum(nbTrianglesRemaining, MAX_FACES)); lib3ds_mesh_resize_vertices(mesh, osg::minimum(nbVerticesRemaining, MAX_VERTICES), texcoords ? 0 : 1, 0); // Not mandatory but will allocate once a big block } Lib3dsFace & face = mesh->faces[numFace++]; face.index[0] = getMeshIndexForGeometryIndex(index_vert, it->first.t1, it->second); face.index[1] = getMeshIndexForGeometryIndex(index_vert, it->first.t2, it->second); face.index[2] = getMeshIndexForGeometryIndex(index_vert, it->first.t3, it->second); face.material = it->first.material; } buildMesh(geo, mat, index_vert, texcoords, mesh); // May set _succeded to false if (!succeeded()) { lib3ds_mesh_free(mesh); return; } }
void WriterNodeVisitor::buildMesh(osg::Geode & geo, const osg::Matrix & mat, MapIndices & index_vert, bool texcoords, Lib3dsMesh * mesh) { OSG_DEBUG << "Building Mesh" << std::endl; assert(mesh); // Write points assert(index_vert.size() <= MAX_VERTICES); lib3ds_mesh_resize_vertices(mesh, index_vert.size(), texcoords ? 1 : 0, 0); for(MapIndices::iterator it = index_vert.begin(); it != index_vert.end();++it) { osg::Geometry *g = geo.getDrawable( it->first.second )->asGeometry(); const osg::Array * basevecs = g->getVertexArray(); assert(basevecs); if (!basevecs || basevecs->getNumElements()==0) continue; if (basevecs->getType() == osg::Array::Vec3ArrayType) { const osg::Vec3Array & vecs= *static_cast<const osg::Vec3Array *>(basevecs); copyOsgVectorToLib3dsVector(mesh->vertices[it->second], vecs[it->first.first]*mat); } else if (basevecs->getType() == osg::Array::Vec3dArrayType) { // Handle double presision vertices by converting them to float with a warning OSG_NOTICE << "3DS format only supports single precision vertices. Converting double precision to single." << std::endl; const osg::Vec3dArray & vecs= *static_cast<const osg::Vec3dArray *>(basevecs); copyOsgVectorToLib3dsVector(mesh->vertices[it->second], vecs[it->first.first]*mat); } else { OSG_NOTIFY(osg::FATAL) << "Vertex array is not Vec3 or Vec3d. Not implemented" << std::endl; _succeeded = false; return; } } // Write texture coords (Texture 0 only) if (texcoords) { for(MapIndices::iterator it = index_vert.begin(); it != index_vert.end(); ++it) { osg::Geometry *g = geo.getDrawable( it->first.second )->asGeometry(); const osg::Array * texarray = g->getNumTexCoordArrays()>=1 ? g->getTexCoordArray(0) : NULL; if (!texarray || texarray->getNumElements()==0) continue; if (g->getTexCoordArray(0)->getType() != osg::Array::Vec2ArrayType) { OSG_NOTIFY(osg::FATAL) << "Texture coords array is not Vec2. Not implemented" << std::endl; _succeeded = false; return; } const osg::Vec2Array & vecs= *static_cast<const osg::Vec2Array *>(texarray); mesh->texcos[it->second][0] = vecs[it->first.first][0]; mesh->texcos[it->second][1] = vecs[it->first.first][1]; } } lib3ds_file_insert_mesh(_file3ds, mesh, _lastMeshIndex); ++_lastMeshIndex; Lib3dsMeshInstanceNode * node3ds = lib3ds_node_new_mesh_instance(mesh, mesh->name, NULL, NULL, NULL); lib3ds_file_append_node(_file3ds, reinterpret_cast<Lib3dsNode*>(node3ds), reinterpret_cast<Lib3dsNode*>(_cur3dsNode)); }
std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, bool isNodeName, const std::string & _defaultPrefix, int currentPrefixLen) { //const unsigned int MAX_LENGTH = maxNameLen(_extendedFilePaths); const unsigned int MAX_PREFIX_LENGTH = _extendedFilePaths ? 52 : 6; // Arbitrarily defined for short names, kept enough room for displaying UINT_MAX (10 characters) for long names. assert(_defaultPrefix.length()<=4); // Default prefix is too long (implementation error) const std::string defaultPrefix(_defaultPrefix.empty() ? "_" : _defaultPrefix); if (currentPrefixLen<0) currentPrefixLen = osg::maximum(_defaultPrefix.length(), _defaultValue.length()); currentPrefixLen = osg::clampBelow(currentPrefixLen, static_cast<int>(MAX_PREFIX_LENGTH)); // Tests if default name is valid and unique NameMap & nameMap = isNodeName ? _nodeNameMap : _imageNameMap; PrefixMap & prefixMap = isNodeName ? _nodePrefixMap : _imagePrefixMap; // Handling of paths is simple. Algorithm: // - For short names, subdirectories are simply forbidden. Use the simple file name. // - Else, the whole (relative) path must simply be <64 chars. // After this, begin enumeration. std::string parentPath, filename, ext, namePrefix; unsigned int max_val = 0; // TODO Move the two parts of this giant if/else into two separate functions for better readability. if (_extendedFilePaths) { // Tests if default name is valid and unique if (is3DSName(_defaultValue, _extendedFilePaths, isNodeName)) { std::pair<NameMap::iterator, bool> insertion( nameMap.insert(_defaultValue) ); if (insertion.second) return _defaultValue; // Return if element is newly inserted in the map (else there is a naming collision) } // Simply separate name and last extension filename = osgDB::getNameLessExtension(osgDB::getSimpleFileName(_defaultValue)); if (!isNodeName) { ext = osgDB::getFileExtensionIncludingDot(_defaultValue); if (ext == ".") ext = ""; } // Compute parent path // Pre-condition: paths are supposed to be relative. // If full path is too long (>MAX_PREFIX_LENGTH), cut path to let enough space for simple file name. // Do not cut in the middle of a name, but at path separators. parentPath = osgDB::getFilePath(_defaultValue); if (_defaultValue.length() >MAX_PREFIX_LENGTH) // Not parentPath but _defaultValue! { // Nodes names: keep last directories (used only for the root name, generally named after the full file path) // Images names: keep first directories (for images) if (isNodeName) std::reverse(parentPath.begin(), parentPath.end()); unsigned lenToDelete(filename.length() + ext.length() + 1); lenToDelete = osg::clampBelow(lenToDelete, MAX_PREFIX_LENGTH); parentPath = truncateFilenameBytes(parentPath, MAX_PREFIX_LENGTH - lenToDelete); // +1 for the path separator std::string::size_type separator = parentPath.find_last_of("/\\"); if (separator != std::string::npos) parentPath = parentPath.substr(0, separator); if (isNodeName) std::reverse(parentPath.begin(), parentPath.end()); } // Assert "MAX_PREFIX_LENGTH - parent path length - extension length -1" is >=0 and truncate name to this length to get our new prefix. assert(parentPath.length() + ext.length() <= MAX_PREFIX_LENGTH); const unsigned int len = MAX_PREFIX_LENGTH - (parentPath.length() + ext.length() +1); namePrefix = truncateFilenameBytes(filename, len); if (namePrefix.empty()) namePrefix = defaultPrefix; // Truncate the filename to get our new prefix namePrefix = truncateFilenameBytes(filename, currentPrefixLen); // Enough space has been reserved for UINT_MAX values max_val = UINT_MAX; } else { // Get last extension, and make filename have no extension filename = osgDB::getNameLessAllExtensions(osgDB::getSimpleFileName(_defaultValue)); if (!isNodeName) { ext = truncateFilenameBytes(osgDB::getFileExtensionIncludingDot(_defaultValue), 4); // 4 chars = dot + 3 chars if (ext == ".") ext = ""; } // Tests if STRIPPED default name is valid and unique const std::string strippedName( filename + ext ); if (is3DSName(strippedName, _extendedFilePaths, isNodeName)) { std::pair<NameMap::iterator, bool> insertion( nameMap.insert(strippedName) ); if (insertion.second) return strippedName; // Return if element is newly inserted in the map (else there is a naming collision) } namePrefix = filename; if (namePrefix.empty()) namePrefix = defaultPrefix; // Truncate the filename to get our new prefix namePrefix = truncateFilenameBytes(namePrefix, currentPrefixLen); // Compute the maximum enumeration value max_val = static_cast<unsigned int>(pow(10., 8. - namePrefix.length())) -1; } assert(namePrefix.size() <= MAX_PREFIX_LENGTH); // Find the current enumeration value (searchStart) unsigned int searchStart(0); PrefixMap::iterator pairPrefix( prefixMap.find(namePrefix) ); if (pairPrefix != prefixMap.end()) { searchStart = pairPrefix->second; } else { // Check if truncated name is ok const std::string res( osgDB::concatPaths(parentPath, namePrefix + ext) ); if (nameMap.find(res) == nameMap.end()) { prefixMap.insert(std::pair<std::string, unsigned int>(namePrefix, 0)); nameMap.insert(res); return res; } } // Search for a free value for(unsigned int i = searchStart; i <= max_val; ++i) { std::stringstream ss; ss << namePrefix << i; const std::string res( osgDB::concatPaths(parentPath, ss.str() + ext) ); if (nameMap.find(res) == nameMap.end()) { if (pairPrefix != prefixMap.end()) { pairPrefix->second = i + 1; } else { prefixMap.insert(std::pair<std::string, unsigned int>(namePrefix, i + 1)); } nameMap.insert(res); return res; } } // Failed finding a name // Try with a shorter prefix if possible if (currentPrefixLen>1) return getUniqueName(_defaultValue, isNodeName, defaultPrefix, currentPrefixLen-1); // Try with default prefix if not arleady done if (defaultPrefix != std::string("_")) return getUniqueName(_defaultValue, isNodeName, "_", 1); // No more names OSG_NOTIFY(osg::FATAL) << "No more names available!" << std::endl; _succeeded = false; return "ERROR"; }