Exemplo n.º 1
0
/**
 * @brief Set the position of the point that is being dragged.
 *        Calling this function will also automatically set m_dragging to true,
 *        which applyDragValue() have to be called to m_dragging.
 * @param the time(x position) of the point being dragged
 * @param the value(y position) of the point being dragged
 * @param true to snip x position
 * @return
 */
MidiTime AutomationPattern::setDragValue( const MidiTime & time,
						const float value,
						const bool quantPos,
						const bool controlKey )
{
	if( m_dragging == false )
	{
		MidiTime newTime = quantPos  ?
				Note::quantized( time, quantization() ) :
							time;
		this->removeValue( newTime );
		m_oldTimeMap = m_timeMap;
		m_dragging = true;
	}

	//Restore to the state before it the point were being dragged
	m_timeMap = m_oldTimeMap;

	for( timeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); ++it )
	{
		generateTangents( it, 3 );
	}

	return this->putValue( time, value, quantPos, controlKey );

}
Exemplo n.º 2
0
void AutomationPattern::flipY( int min, int max )
{
	timeMap tempMap = m_timeMap;
	timeMap::ConstIterator iterate = m_timeMap.lowerBound(0);
	float tempValue = 0;

	int numPoints = 0;

	for( int i = 0; ( iterate + i + 1 ) != m_timeMap.end() && ( iterate + i ) != m_timeMap.end() ; i++)
	{
		numPoints++;
	}

	for( int i = 0; i <= numPoints; i++ )
	{

		if ( min < 0 )
		{
			tempValue = valueAt( ( iterate + i ).key() ) * -1;
			putValue( MidiTime( (iterate + i).key() ) , tempValue, false);
		}
		else
		{
			tempValue = max - valueAt( ( iterate + i ).key() );
			putValue( MidiTime( (iterate + i).key() ) , tempValue, false);
		}
	}

	generateTangents();
	emit dataChanged();
}
Exemplo n.º 3
0
/**
 * @brief Set the position of the point that is being draged.
 *        Calling this function will also automatically set m_dragging to true,
 *        which applyDragValue() have to be called to m_dragging.
 * @param the time(x position) of the point being dragged
 * @param the value(y position) of the point being dragged
 * @param true to snip x position
 * @return
 */
MidiTime AutomationPattern::setDragValue( const MidiTime & _time, const float _value,
					   const bool _quant_pos )
{
	if( m_dragging == false )
	{
		MidiTime newTime = _quant_pos && engine::automationEditor() ?
			note::quantized( _time,
				engine::automationEditor()->quantization() ) :
			_time;
		this->removeValue( newTime );
		m_oldTimeMap = m_timeMap;
		m_dragging = true;
	}

	//Restore to the state before it the point were being dragged
	m_timeMap = m_oldTimeMap;

	for( timeMap::const_iterator it = m_timeMap.begin(); it != m_timeMap.end(); it++ )
	{
		generateTangents(it, 3);
	}

	return this->putValue( _time, _value, _quant_pos );

}
Exemplo n.º 4
0
MidiTime AutomationPattern::putValue( const MidiTime & _time,
							const float _value,
							const bool _quant_pos )
{
	cleanObjects();

	MidiTime newTime = _quant_pos && engine::automationEditor() ?
		note::quantized( _time,
			engine::automationEditor()->quantization() ) :
		_time;

	m_timeMap[newTime] = _value;
	timeMap::const_iterator it = m_timeMap.find( newTime );
	if( it != m_timeMap.begin() )
	{
		it--;
	}
	generateTangents(it, 3);

	// we need to maximize our length in case we're part of a hidden
	// automation track as the user can't resize this pattern
	if( getTrack() && getTrack()->type() == track::HiddenAutomationTrack )
	{
		changeLength( length() );
	}

	emit dataChanged();

	return newTime;
}
Exemplo n.º 5
0
void AutomationPattern::removeValue( const MidiTime & _time,
									 const bool _quant_pos )
{
	cleanObjects();

	MidiTime newTime = _quant_pos && engine::automationEditor() ?
		note::quantized( _time,
			engine::automationEditor()->quantization() ) :
		_time;

	m_timeMap.remove( newTime );
	m_tangents.remove( newTime );
	timeMap::const_iterator it = m_timeMap.lowerBound( newTime );
	if( it != m_timeMap.begin() )
	{
		it--;
	}
	generateTangents(it, 3);

	if( getTrack() &&
		getTrack()->type() == track::HiddenAutomationTrack )
	{
		changeLength( length() );
	}

	emit dataChanged();
}
Exemplo n.º 6
0
Entity::Entity(string name, string fileName){
    this->name = name;
    this->fileName = fileName;

    vertices = NULL;
    indices = NULL;
    normals = NULL;

    vboVertices = NULL;
    vboIndices = NULL;
    vboNormals = NULL;

    shaderProgram = NULL ;
    vertexShader = NULL ;
    fragmentShader = NULL ;

    textureCoordinates = NULL;
    tangents = NULL;

    readMeshXml();
    readMaterial();
    generateTangents();

    createVBOs();

    transformation.setToIdentity() ;

    live = true;
}
Exemplo n.º 7
0
void AutomationPattern::loadSettings( const QDomElement & _this )
{
	clear();

	movePosition( _this.attribute( "pos" ).toInt() );
	setName( _this.attribute( "name" ) );
	setProgressionType( static_cast<ProgressionTypes>( _this.attribute(
							"prog" ).toInt() ) );
	setTension( _this.attribute( "tens" ) );
	setMuted(_this.attribute( "mute", QString::number( false ) ).toInt() );

	for( QDomNode node = _this.firstChild(); !node.isNull();
						node = node.nextSibling() )
	{
		QDomElement element = node.toElement();
		if( element.isNull()  )
		{
			continue;
		}
		if( element.tagName() == "time" )
		{
			m_timeMap[element.attribute( "pos" ).toInt()]
				= element.attribute( "value" ).toFloat();
		}
		else if( element.tagName() == "object" )
		{
			m_idsToResolve << element.attribute( "id" ).toInt();
		}
	}

	int len = _this.attribute( "len" ).toInt();
	if( len <= 0 )
	{
		// TODO: Handle with an upgrade method
		updateLength();
	}
	else
	{
		changeLength( len );
	}
	generateTangents();
}
Exemplo n.º 8
0
void AutomationPattern::removeValue( const MidiTime & time )
{
	cleanObjects();

	m_timeMap.remove( time );
	m_tangents.remove( time );
	timeMap::const_iterator it = m_timeMap.lowerBound( time );
	if( it != m_timeMap.begin() )
	{
		--it;
	}
	generateTangents(it, 3);

	if( getTrack() && getTrack()->type() == Track::HiddenAutomationTrack )
	{
		updateLength();
	}

	emit dataChanged();
}
Exemplo n.º 9
0
MidiTime AutomationPattern::putValue( const MidiTime & time,
					const float value,
					const bool quantPos,
					const bool ignoreSurroundingPoints )
{
	cleanObjects();

	MidiTime newTime = quantPos ?
				Note::quantized( time, quantization() ) :
				time;

	m_timeMap[ newTime ] = value;
	timeMap::const_iterator it = m_timeMap.find( newTime );

	// Remove control points that are covered by the new points
	// quantization value. Control Key to override
	if( ! ignoreSurroundingPoints )
	{
		for( int i = newTime + 1; i < newTime + quantization(); ++i )
		{
			AutomationPattern::removeValue( i );
		}
	}
	if( it != m_timeMap.begin() )
	{
		--it;
	}
	generateTangents( it, 3 );

	// we need to maximize our length in case we're part of a hidden
	// automation track as the user can't resize this pattern
	if( getTrack() && getTrack()->type() == Track::HiddenAutomationTrack )
	{
		updateLength();
	}

	emit dataChanged();

	return newTime;
}
Exemplo n.º 10
0
			void DrawVBOMesh::loadOBJ(Geometry::MeshDataStructPtr obj)
			{
				m_objInfo = obj;
				Geometry::MeshDataStruct& refObjInfo = *m_objInfo;
				std::vector< vrGLMVec3 > & points = refObjInfo.points;
				std::vector< vrGLMVec3 > & normals = refObjInfo.normals;
				std::vector< vrGLMVec2 > & texCoords = refObjInfo.texCoords;
				std::vector<vrInt>& faces = refObjInfo.faces;

				if (normals.size() == 0) {
					generateAveragedNormals(points, normals, faces);
				}

				std::vector< vrGLMVec4 > tangents;
				if (genTang && texCoords.size() > 0) {
					generateTangents(points, normals, faces, texCoords, tangents);
				}

				if (reCenterMesh) {
					center(points);
				}

				storeVBO(points, normals, texCoords, tangents, faces);
			}
Exemplo n.º 11
0
void AutomationPattern::flipX( int length )
{
	timeMap tempMap;

	timeMap::ConstIterator iterate = m_timeMap.lowerBound(0);
	float tempValue = 0;
	int numPoints = 0;

	for( int i = 0; ( iterate + i + 1 ) != m_timeMap.end() && ( iterate + i ) != m_timeMap.end() ; i++)
	{
		numPoints++;
	}

	float realLength = ( iterate + numPoints ).key();

	if ( length != -1 && length != realLength)
	{
		if ( realLength < length )
		{
			tempValue = valueAt( ( iterate + numPoints ).key() );
			putValue( MidiTime( length ) , tempValue, false);
			numPoints++;
			for( int i = 0; i <= numPoints; i++ )
			{
				tempValue = valueAt( ( iterate + i ).key() );
				MidiTime newTime = MidiTime( length - ( iterate + i ).key() );
				tempMap[newTime] = tempValue;
			}
		}
		else
		{
			for( int i = 0; i <= numPoints; i++ )
			{
				tempValue = valueAt( ( iterate + i ).key() );
				MidiTime newTime;

				if ( ( iterate + i ).key() <= length )
				{
					newTime = MidiTime( length - ( iterate + i ).key() );
				}
				else
				{
					newTime = MidiTime( ( iterate + i ).key() );
				}
				tempMap[newTime] = tempValue;
			}
		}
	}
	else
	{
		for( int i = 0; i <= numPoints; i++ )
		{
			tempValue = valueAt( ( iterate + i ).key() );
			cleanObjects();
			MidiTime newTime = MidiTime( realLength - ( iterate + i ).key() );
			tempMap[newTime] = tempValue;
		}
	}

	m_timeMap.clear();

	m_timeMap = tempMap;

	generateTangents();
	emit dataChanged();
}
Exemplo n.º 12
0
Cone::Cone(std::string name, int id, int tesselation, float3 color,
           float radius, float height) :
    Primitive(0, name, id, tesselation, color),
    radius_(radius),
    height_(height)
{

    hasVBO_[NORMALS] = true;
    hasVBO_[COLORS] = true;
    hasVBO_[TEXCOORDS] = true;

    int steps = 6 + tesselation_ * tesselation_;
    for (int i = 0; i < steps; i++) {
        double phi_left = 2 * M_PI * i / static_cast<double>(steps);
        double phi_right = 2 * M_PI * (i + 1) / static_cast<double>(steps);

        // cap
        float3 position0 = float3(radius_ * sin(phi_left), 0, radius_ * cos(phi_left));
        float3 position1 = float3(radius_ * sin(phi_right), 0, radius_ * cos(phi_right));
        float3 position2 = float3(0, 0, 0);

        vertexPositions_.push_back(position0);
        vertexPositions_.push_back(position1);
        vertexPositions_.push_back(position2);

        vertexNormals_.push_back(float3(0, -1, 0));
        vertexNormals_.push_back(float3(0, -1, 0));
        vertexNormals_.push_back(float3(0, -1, 0));

        float3 texCoord0 = float3(position0.x_ / 2 + 0.5, position0.z_ / 2 + 0.5, 0.0f);
        float3 texCoord1 = float3(position1.x_ / 2 + 0.5, position1.z_ / 2 + 0.5, 0.0f);
        float3 texCoord2 = float3(position2.x_ / 2 + 0.5, position2.z_ / 2 + 0.5, 0.0f);

        vertexTextureCoordinates_.push_back(texCoord0);
        vertexTextureCoordinates_.push_back(texCoord1);
        vertexTextureCoordinates_.push_back(texCoord2);



        // body

        position0 = float3(radius_ * sin(phi_left), 0, radius_ * cos(phi_left));
        position1 = float3(radius_ * sin(phi_right), 0, radius_ * cos(phi_right));
        position2 = float3(0, height_, 0);

        vertexPositions_.push_back(position0);
        vertexPositions_.push_back(position1);
        vertexPositions_.push_back(position2);



        float degree = atan(height_ / radius_);
        float3 normal0 = float3(cos(degree) * 0 + (1 - cos(degree)) * radius_ * sin(phi_left),
                                cos(degree) * 1 + (1 - cos(degree)) * 0,
                                cos(degree) * 0 + (1 - cos(degree)) * radius_ * cos(phi_left));
        vertexNormals_.push_back(normal0);

        float3 normal1 = float3(cos(degree) * 0 + (1 - cos(degree)) * radius_ * sin(phi_right),
                                cos(degree) * 1 + (1 - cos(degree)) * 0,
                                cos(degree) * 0 + (1 - cos(degree)) * radius_ * cos(phi_right));
        vertexNormals_.push_back(normal1);

        float3 normal2 = float3(cos(degree) * 0 + (1 - cos(degree)) * (radius_ * sin(phi_left) + radius_ * sin(phi_right)) / 2,
                                cos(degree) * 1 + (1 - cos(degree)) * 0,
                                cos(degree) * 0 + (1 - cos(degree)) * (radius_ * cos(phi_left) + radius_ * cos(phi_right)) / 2);

        //normal2 = float3(0, 1, 0);
        vertexNormals_.push_back(normal2);


        vertexTextureCoordinates_.push_back(float3(i / (float) steps, 0, 0));
        vertexTextureCoordinates_.push_back(float3((i + 1) / (float) steps, 0, 0));
        vertexTextureCoordinates_.push_back(float3(((i + 0.5) / (float) steps) , 1, 0));


    }


    // set indices list
    for (uint i = 0; i < vertexPositions_.size(); i++) {
        indicesList_.push_back(i);
    }

    float coneColor[3] = {1, 1, 0};
    for (uint i = 0; i < vertexPositions_.size(); i++) {
        vertexColors_.push_back(float3(coneColor));
    }


    generateTangents(3);
}
bool ModelOBJ::import(const char *pszFilename, bool rebuildNormals)
{
    FILE *pFile = fopen(pszFilename, "r");

    if (!pFile)
        return false;

    // Extract the directory the OBJ file is in from the file name.
    // This directory path will be used to load the OBJ's associated MTL file.

    m_directoryPath.clear();

    std::string filename = pszFilename;
    std::string::size_type offset = filename.find_last_of('\\');

    if (offset != std::string::npos)
    {
        m_directoryPath = filename.substr(0, ++offset);
    }
    else
    {
        offset = filename.find_last_of('/');

        if (offset != std::string::npos)
            m_directoryPath = filename.substr(0, ++offset);
    }

    // Import the OBJ file.

    importGeometryFirstPass(pFile);
    rewind(pFile);
    importGeometrySecondPass(pFile);
    fclose(pFile);

    // Perform post import tasks.

    buildMeshes();
    bounds(m_center, m_width, m_height, m_length, m_radius);

    // Build vertex normals if required.

    if (rebuildNormals)
    {
        generateNormals();
    }
    else
    {
        if (!hasNormals())
            generateNormals();
    }

    // Build tangents is required.

    for (int i = 0; i < m_numberOfMaterials; ++i)
    {
        if (!m_materials[i].bumpMapFilename.empty())
        {
            generateTangents();
            break;
        }
    }

    return true;
}
Exemplo n.º 14
0
void init()
{
	GLfloat skyboxVertices[] = {
        // Positions          
        -1.0f, 1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f, 1.0f, -1.0f,
        -1.0f, 1.0f, -1.0f,

        -1.0f, -1.0f, 1.0f,
        -1.0f, -1.0f, -1.0f,
        -1.0f, 1.0f, -1.0f,
        -1.0f, 1.0f, -1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, -1.0f, 1.0f,

        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,

        -1.0f, -1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, -1.0f, 1.0f,
        -1.0f, -1.0f, 1.0f,

        -1.0f, 1.0f, -1.0f,
        1.0f, 1.0f, -1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, -1.0f,

        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f, 1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f, 1.0f,
        1.0f, -1.0f, 1.0f
    };  

	planet = tetrahedron(5);
	object = ObjLoadModel("include/obj/torus.obj");

	vec3 tangent[planet.vertexNumber];
	vec3 bitangent[planet.vertexNumber];
	*tangent = *generateTangents(planet.vertexNumber, planet.points, tangent, bitangent);
	
	vec3 vna[planet.vertexNumber];
	*vna = *generateSmoothNormals(planet.vertexNumber, vna, planet.points, planet.normals);
	
	createShader(&skyboxShader, "src/shaders/skybox.vert",
		"src/shaders/skybox.frag");
	createShader(&sunShader, "src/shaders/sun.vert",
		"src/shaders/sun.frag");
	createShader(&planetShader, "src/shaders/planet.vert",
		"src/shaders/planet.frag");
		
	createShader(&atmosphereShader, "src/shaders/atmosphere.vert",
		"src/shaders/atmosphere.frag");
    
    
    glGenFramebuffers(1, &hdrFBO);
    glGenTextures(1, &colorBuffer);
    glBindTexture(GL_TEXTURE_2D, colorBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, WIDTH, HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    glGenRenderbuffers(1, &rboDepth);
    glBindRenderbuffer(GL_RENDERBUFFER, rboDepth);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, WIDTH, HEIGHT);
    
    glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        printf("Framebuffer not complete!\n");
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

	glGenVertexArrays(1, &planetVAO);
	glBindVertexArray(planetVAO);
	glGenBuffers(1, &planetVBO);
	glBindBuffer(GL_ARRAY_BUFFER, planetVBO);
	glBufferData(GL_ARRAY_BUFFER, planet.size + planet.nsize, NULL, GL_STATIC_DRAW);
	glBufferSubData(GL_ARRAY_BUFFER, 0, planet.size, planet.points);
	glBufferSubData(GL_ARRAY_BUFFER, planet.size, planet.nsize, vna);
	
	glBufferSubData(GL_ARRAY_BUFFER, planet.size+planet.nsize, sizeof(tangent), tangent);
	glBufferSubData(GL_ARRAY_BUFFER, planet.size+planet.nsize+sizeof(tangent), sizeof(tangent), tangent);
	
	vPosition = glGetAttribLocation(planetShader, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(0));	
    vNormal = glGetAttribLocation(planetShader, "vNormal");
    glEnableVertexAttribArray(vNormal);
    glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(planet.size));
    
    vTangent = glGetAttribLocation(planetShader, "vTangent");
    glEnableVertexAttribArray(vTangent);
    glVertexAttribPointer(vTangent, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(planet.size+planet.nsize));
    
    vBitangent = glGetAttribLocation(planetShader, "vBitangent");
    glEnableVertexAttribArray(vBitangent);
    glVertexAttribPointer(vBitangent, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(planet.size+planet.nsize+sizeof(tangent)));
    
	glBindVertexArray(0);
	
	glGenVertexArrays(1, &skyboxVAO);
	glBindVertexArray(skyboxVAO);
    glGenBuffers(1, &skyboxVBO);
    glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), skyboxVertices, GL_STATIC_DRAW);
    vPosition = glGetAttribLocation(skyboxShader, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glBindVertexArray(0);
    
    glGenVertexArrays(1, &objectVAO);
	glBindVertexArray(objectVAO);
	glGenBuffers(1, &objectVBO);
	glBindBuffer(GL_ARRAY_BUFFER, objectVBO);
	glBufferData(GL_ARRAY_BUFFER, object.size + object.nsize, NULL, GL_STATIC_DRAW);
	glBufferSubData(GL_ARRAY_BUFFER, 0, object.size, object.points);
	glBufferSubData(GL_ARRAY_BUFFER, object.size, object.nsize, object.normals);
	vPosition = glGetAttribLocation(sunShader, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(0));	
    
    vNormal = glGetAttribLocation(sunShader, "vNormal");
    glEnableVertexAttribArray(vNormal);
    glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(object.size));
	glBindVertexArray(0);
	
	glGenVertexArrays(1, &atmosphereVAO);
	glBindVertexArray(atmosphereVAO);
	glGenBuffers(1, &atmosphereVBO);
	glBindBuffer(GL_ARRAY_BUFFER, atmosphereVBO);
	glBufferData(GL_ARRAY_BUFFER, planet.size + planet.nsize, NULL, GL_STATIC_DRAW);
	glBufferSubData(GL_ARRAY_BUFFER, 0, planet.size, planet.points);
	glBufferSubData(GL_ARRAY_BUFFER, planet.size, planet.nsize, planet.normals);
	vPosition = glGetAttribLocation(atmosphereShader, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(0));	
    
    vNormal = glGetAttribLocation(atmosphereShader, "vNormal");
    glEnableVertexAttribArray(vNormal);
    glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), BUFFER_OFFSET(planet.size));
	glBindVertexArray(0);
	
    glEnable(GL_DEPTH_TEST);
}
Exemplo n.º 15
0
void AutomationPattern::generateTangents()
{
	generateTangents(m_timeMap.begin(), m_timeMap.size());
}
Exemplo n.º 16
0
bool ObjLoader::load(::QIODevice *ioDev, const QString &subMesh)
{
    Q_CHECK_PTR(ioDev);
    if (!ioDev->isOpen()) {
        qCWarning(Render::Io) << "iodevice" << ioDev << "not open for reading";
        return false;
    }

    int faceCount = 0;

    // Parse faces taking into account each vertex in a face can index different indices
    // for the positions, normals and texture coords;
    // Generate unique vertices (in OpenGL parlance) and output to m_points, m_texCoords,
    // m_normals and calculate mapping from faces to unique indices
    QVector<QVector3D> positions;
    QVector<QVector3D> normals;
    QVector<QVector2D> texCoords;
    QHash<FaceIndices, unsigned int> faceIndexMap;
    QVector<FaceIndices> faceIndexVector;

    bool skipping = false;
    int positionsOffset = 0;
    int normalsOffset = 0;
    int texCoordsOffset = 0;

    QRegExp subMeshMatch(subMesh);
    if (!subMeshMatch.isValid())
        subMeshMatch.setPattern(QString(QStringLiteral("^(%1)$")).arg(subMesh));
    Q_ASSERT(subMeshMatch.isValid());

    QTextStream stream(ioDev);
    while (!stream.atEnd()) {
        QString line = stream.readLine();
        line = line.simplified();

        if (line.length() > 0 && line.at(0) != QChar::fromLatin1('#')) {
            const QVector<QStringRef> tokens = line.splitRef(QChar::fromLatin1(' '));

            if (tokens.first() == QStringLiteral("v")) {
                if (tokens.size() < 4) {
                    qCWarning(Render::Io) << "Unsupported number of components in vertex";
                } else {
                    if (!skipping) {
                        float x = tokens.at(1).toFloat();
                        float y = tokens.at(2).toFloat();
                        float z = tokens.at(3).toFloat();
                        positions.append(QVector3D( x, y, z ));
                    } else {
                        positionsOffset++;
                    }
                }
            } else if (tokens.first() == QStringLiteral("vt") && m_loadTextureCoords) {
                if (tokens.size() < 3) {
                    qCWarning(Render::Io) << "Unsupported number of components in texture coordinate";
                } else {
                    if (!skipping) {
                        // Process texture coordinate
                        float s = tokens.at(1).toFloat();
                        float t = tokens.at(2).toFloat();
                        //FlipUVs
                        t = 1.0f - t;
                        texCoords.append(QVector2D( s, t ));
                    } else {
                        texCoordsOffset++;
                    }
                }
            } else if (tokens.first() == QStringLiteral("vn")) {
                if (tokens.size() < 4) {
                    qCWarning(Render::Io) << "Unsupported number of components in vertex normal";
                } else {
                    if (!skipping) {
                        float x = tokens.at(1).toFloat();
                        float y = tokens.at(2).toFloat();
                        float z = tokens.at(3).toFloat();
                        normals.append(QVector3D( x, y, z ));
                    } else {
                        normalsOffset++;
                    }
                }
            } else if (!skipping && tokens.first() == QStringLiteral("f")) {
                // Process face
                ++faceCount;

                int faceVertices = tokens.size() - 1;

                QVector<FaceIndices> face;
                face.reserve(faceVertices);

                for (int i = 0; i < faceVertices; i++) {
                    FaceIndices faceIndices;
                    const QVector<QStringRef> indices = tokens.at(i + 1).split(QChar::fromLatin1('/'));
                    switch (indices.size()) {
                    case 3:
                        faceIndices.normalIndex = indices.at(2).toInt() - 1 - normalsOffset;  // fall through
                    case 2:
                        faceIndices.texCoordIndex = indices.at(1).toInt() - 1 - texCoordsOffset; // fall through
                    case 1:
                        faceIndices.positionIndex = indices.at(0).toInt() - 1 - positionsOffset;
                        break;
                    default:
                        qCWarning(Render::Io) << "Unsupported number of indices in face element";
                    }

                    face.append(faceIndices);
                }

                // If number of edges in face is greater than 3,
                // decompose into triangles as a triangle fan.
                FaceIndices v0 = face[0];
                FaceIndices v1 = face[1];
                FaceIndices v2 = face[2];

                // First face
                addFaceVertex(v0, faceIndexVector, faceIndexMap);
                addFaceVertex(v1, faceIndexVector, faceIndexMap);
                addFaceVertex(v2, faceIndexVector, faceIndexMap);

                for ( int i = 3; i < face.size(); ++i ) {
                    v1 = v2;
                    v2 = face[i];
                    addFaceVertex(v0, faceIndexVector, faceIndexMap);
                    addFaceVertex(v1, faceIndexVector, faceIndexMap);
                    addFaceVertex(v2, faceIndexVector, faceIndexMap);
                }

                // end of face
            } else if (tokens.first() == QStringLiteral("o")) {
                if (tokens.size() < 2) {
                    qCWarning(Render::Io) << "Missing submesh name";
                } else {
                    if (!subMesh.isEmpty() ) {
                        QString objName = tokens.at(1).toString();
                        skipping = subMeshMatch.indexIn(objName) < 0;
                    }
                }
            }
        } // end of input line
    } // while (!stream.atEnd())

    updateIndices(positions, normals, texCoords, faceIndexMap, faceIndexVector);

    if (m_normals.isEmpty())
        generateAveragedNormals(m_points, m_normals, m_indices);

    if (m_generateTangents && !m_texCoords.isEmpty())
        generateTangents(m_points, m_normals, m_indices, m_texCoords, m_tangents);

    if (m_centerMesh)
        center(m_points);

    qCDebug(Render::Io) << "Loaded mesh:";
    qCDebug(Render::Io) << " " << m_points.size() << "points";
    qCDebug(Render::Io) << " " << faceCount << "faces";
    qCDebug(Render::Io) << " " << m_indices.size() / 3 << "triangles.";
    qCDebug(Render::Io) << " " << m_normals.size() << "normals";
    qCDebug(Render::Io) << " " << m_tangents.size() << "tangents ";
    qCDebug(Render::Io) << " " << m_texCoords.size() << "texture coordinates.";

    return true;
}
Exemplo n.º 17
0
bool xmlMeshLoad(const char * filename, void * data)
{
    MLOG_DEBUG("xmlMeshLoad " << filename?filename:"NULL");
	
	MLevel * level = MEngine::getInstance()->getLevel();

	// read document
	TiXmlDocument doc(filename);
	if(! doc.LoadFile())
	{
	    MLOG_WARNING("TiXmlDocument load failed : " << doc.ErrorDesc() << " line " << doc.ErrorRow());
	    return false;
	}

	TiXmlHandle hDoc(&doc);
	TiXmlElement * pRootNode;
	TiXmlHandle hRoot(0);

	// Maratis
	pRootNode = hDoc.FirstChildElement().Element();
	if(! pRootNode)
	{
	    MLOG_WARNING("Cannot find any root node");
	    return false;
	}

	if(strcmp(pRootNode->Value(), "Maratis") != 0)
	{
	    MLOG_WARNING("Cannot find Maratis root node");
	    return false;
	}

	hRoot = TiXmlHandle(pRootNode);


	// Mesh
	TiXmlElement * pMeshNode = pRootNode->FirstChildElement("Mesh");
	if(! pMeshNode)
	{
	    MLOG_WARNING("Cannot find a Mesh node");
	    return false;
	}

	// create new mesh
	MMesh * mesh = (MMesh *)data;
	mesh->clear();

	char path[256];
	char meshRep[256];
	char vertShadPath[256];
	char fragShadPath[256];

	// mesh rep
	getRepertory(meshRep, filename);

	// animation
	if(! loadAnim(pMeshNode, meshRep, mesh))
	{
		// load external anim file (depracated)
		char animFilename[256];
		strcpy(animFilename, filename);
		strcpy(animFilename + strlen(animFilename) - 4, "anim");
		loadAnimFile(mesh, animFilename, meshRep);
	}

	// Textures
	TiXmlElement * texturesNode = pMeshNode->FirstChildElement("Textures");
	if(texturesNode)
	{
	    MLOG_DEBUG("entering Textures node");
		
		unsigned int numTextures = 0;
		texturesNode->QueryUIntAttribute("num", &numTextures);
		mesh->allocTextures(numTextures);

		// Texture
		TiXmlElement * textureNode = texturesNode->FirstChildElement("Texture");
		for(textureNode; textureNode; textureNode=textureNode->NextSiblingElement("Texture"))
		{
			const char * file = NULL;
			bool mipmap = true;

			// image
			TiXmlElement * imageNode = textureNode->FirstChildElement("image");
			if(imageNode)
			{
				int value = 1;
				file = imageNode->Attribute("filename");
				imageNode->QueryIntAttribute("mipmap", &value);
				mipmap = (value == 1);
			}

			if(! file)
			{
				mesh->addNewTexture(NULL);
				continue;
			}

			// load texture
			getGlobalFilename(path, meshRep, file);

			MTextureRef * texRef = level->loadTexture(path, mipmap);
			MTexture * texture = mesh->addNewTexture(texRef);

			// tile
			TiXmlElement * tileNode = textureNode->FirstChildElement("tile");
			if(tileNode)
			{
				const char * uTile = tileNode->Attribute("u");
				const char * vTile = tileNode->Attribute("v");
				if(uTile){
					if(strcmp(uTile, "clamp") == 0)
						texture->setUWrapMode(M_WRAP_CLAMP);
					else
						texture->setUWrapMode(M_WRAP_REPEAT);
				}
				if(vTile){
					if(strcmp(vTile, "clamp") == 0)
						texture->setVWrapMode(M_WRAP_CLAMP);
					else
						texture->setVWrapMode(M_WRAP_REPEAT);
				}
			}

			// translate
			TiXmlElement * translateNode = textureNode->FirstChildElement("translate");
			if(translateNode)
			{
				MVector2 translate = texture->getTexTranslate();
				translateNode->QueryFloatAttribute("x", &translate.x);
				translateNode->QueryFloatAttribute("y", &translate.y);
				texture->setTexTranslate(translate);
			}

			// scale
			TiXmlElement * scaleNode = textureNode->FirstChildElement("scale");
			if(scaleNode)
			{
				MVector2 scale = texture->getTexScale();
				scaleNode->QueryFloatAttribute("x", &scale.x);
				scaleNode->QueryFloatAttribute("y", &scale.y);
				texture->setTexScale(scale);
			}

			// rotate
			TiXmlElement * rotateNode = textureNode->FirstChildElement("rotate");
			if(rotateNode)
			{
				float angle = 0;
				rotateNode->QueryFloatAttribute("angle", &angle);
				texture->setTexRotate(angle);
			}
		}
	}


	// Materials
	TiXmlElement * materialsNode = pMeshNode->FirstChildElement("Materials");
	if(materialsNode)
	{
	    MLOG_DEBUG("entering Materials node");
		
		unsigned int numMaterials = 0;
		materialsNode->QueryUIntAttribute("num", &numMaterials);
		mesh->allocMaterials(numMaterials);

		// Material
		TiXmlElement * materialNode = materialsNode->FirstChildElement("Material");
		for(materialNode; materialNode; materialNode=materialNode->NextSiblingElement("Material"))
		{
			MMaterial * material = mesh->addNewMaterial();

			int type = 0;
			materialNode->QueryIntAttribute("type", &type);
			material->setType(type);

			float opacity=1, shininess=0, customValue=0;
			MVector3 diffuseColor;
			MVector3 specularColor;
			MVector3 emitColor;
			MVector3 customColor;

			// blend
			int blendType = 0;
			TiXmlElement * blendNode = materialNode->FirstChildElement("blend");
			if(blendNode)
				blendNode->QueryIntAttribute("type", &blendType);

			switch(blendType)
			{
			case 2:
				material->setBlendMode(M_BLENDING_ALPHA);
				break;
			case 3:
				material->setBlendMode(M_BLENDING_ADD);
				break;
			case 4:
				material->setBlendMode(M_BLENDING_PRODUCT);
				break;
			}

			// opacity
			TiXmlElement * opacityNode = materialNode->FirstChildElement("opacity");
			if(opacityNode)
				opacityNode->QueryFloatAttribute("value", &opacity);

			// shininess
			TiXmlElement * shininessNode = materialNode->FirstChildElement("shininess");
			if(shininessNode)
				shininessNode->QueryFloatAttribute("value", &shininess);

			// customValue
			TiXmlElement * customValueNode = materialNode->FirstChildElement("customValue");
			if(customValueNode)
				customValueNode->QueryFloatAttribute("value", &customValue);

			material->setOpacity(opacity);
			material->setShininess(shininess);
			material->setCustomValue(customValue);

			// diffuseColor
			TiXmlElement * diffuseColorNode = materialNode->FirstChildElement("diffuseColor");
			if(diffuseColorNode){
				diffuseColorNode->QueryFloatAttribute("r", &diffuseColor.x);
				diffuseColorNode->QueryFloatAttribute("g", &diffuseColor.y);
				diffuseColorNode->QueryFloatAttribute("b", &diffuseColor.z);
				material->setDiffuse(diffuseColor);
			}

			// specularColor
			TiXmlElement * specularColorNode = materialNode->FirstChildElement("specularColor");
			if(specularColorNode){
				specularColorNode->QueryFloatAttribute("r", &specularColor.x);
				specularColorNode->QueryFloatAttribute("g", &specularColor.y);
				specularColorNode->QueryFloatAttribute("b", &specularColor.z);
				material->setSpecular(specularColor);
			}

			// emitColor
			TiXmlElement * emitColorNode = materialNode->FirstChildElement("emitColor");
			if(emitColorNode){
				emitColorNode->QueryFloatAttribute("r", &emitColor.x);
				emitColorNode->QueryFloatAttribute("g", &emitColor.y);
				emitColorNode->QueryFloatAttribute("b", &emitColor.z);
				material->setEmit(emitColor);
			}

			// customColor
			TiXmlElement * customColorNode = materialNode->FirstChildElement("customColor");
			if(customColorNode){
				customColorNode->QueryFloatAttribute("r", &customColor.x);
				customColorNode->QueryFloatAttribute("g", &customColor.y);
				customColorNode->QueryFloatAttribute("b", &customColor.z);
				material->setCustomColor(customColor);
			}

			// TexturesPass
			TiXmlElement * texturesPassNode = materialNode->FirstChildElement("TexturesPass");
			if(texturesPassNode)
			{
				unsigned int numTexturesPass = 0;
				texturesPassNode->QueryUIntAttribute("num", &numTexturesPass);
				material->allocTexturesPass(numTexturesPass);

				// texturePass
				TiXmlElement * texturePassNode = texturesPassNode->FirstChildElement("texturePass");
				for(texturePassNode; texturePassNode; texturePassNode=texturePassNode->NextSiblingElement("texturePass"))
				{
					int textureId = -1;
					unsigned int mapChannel = 0;

					const char * mode = texturePassNode->Attribute("mode");
					texturePassNode->QueryIntAttribute("texture", &textureId);

					if(textureId < 0)
					{
						material->addTexturePass(NULL, M_TEX_COMBINE_MODULATE, 0);
						continue;
					}

					texturePassNode->QueryUIntAttribute("mapChannel", &mapChannel);

					// combine mode
					M_TEX_COMBINE_MODES texCombine = M_TEX_COMBINE_MODULATE;

					if(strcmp(mode, "modulate") == 0)
						texCombine = M_TEX_COMBINE_MODULATE;
					else if(strcmp(mode, "replace") == 0)
						texCombine = M_TEX_COMBINE_REPLACE;
					else if(strcmp(mode, "alpha") == 0)
						texCombine = M_TEX_COMBINE_ALPHA;
					else if(strcmp(mode, "dot") == 0)
						texCombine = M_TEX_COMBINE_DOT;
					else if(strcmp(mode, "add") == 0)
						texCombine = M_TEX_COMBINE_ADD;
					else if(strcmp(mode, "sub") == 0)
						texCombine = M_TEX_COMBINE_SUB;

					// add texture pass
					material->addTexturePass(mesh->getTexture(textureId), texCombine, mapChannel);
				}
			}

			// FX
			{
				// vertexShader
				const char * vertShadFile = NULL;
				TiXmlElement * vertexShaderNode = materialNode->FirstChildElement("vertexShader");
				if(vertexShaderNode){
					vertShadFile = vertexShaderNode->Attribute("file");
				}

				// fragmentShader
				const char * fragShadFile = NULL;
				TiXmlElement * fragmentShaderNode = materialNode->FirstChildElement("fragmentShader");
				if(fragmentShaderNode){
					fragShadFile = fragmentShaderNode->Attribute("file");
				}

				// create FX
				if(vertShadFile && fragShadFile)
				{
					getGlobalFilename(vertShadPath, meshRep, vertShadFile);
					getGlobalFilename(fragShadPath, meshRep, fragShadFile);

					MShaderRef * vertShad = level->loadShader(vertShadPath, M_SHADER_VERTEX);
					MShaderRef * pixShad = level->loadShader(fragShadPath, M_SHADER_PIXEL);
					if(vertShad && pixShad)
					{
						MFXRef * FXRef = level->createFX(vertShad, pixShad);
						material->setFXRef(FXRef);
					}
				}
			}

			// ZFX (optional optim)
			{
				// ZVertexShader
				const char * vertShadFile = NULL;
				TiXmlElement * vertexShaderNode = materialNode->FirstChildElement("ZVertexShader");
				if(vertexShaderNode){
					vertShadFile = vertexShaderNode->Attribute("file");
				}

				// ZFragmentShader
				const char * fragShadFile = NULL;
				TiXmlElement * fragmentShaderNode = materialNode->FirstChildElement("ZFragmentShader");
				if(fragmentShaderNode){
					fragShadFile = fragmentShaderNode->Attribute("file");
				}

				// create ZFX
				if(vertShadFile && fragShadFile)
				{
					getGlobalFilename(vertShadPath, meshRep, vertShadFile);
					getGlobalFilename(fragShadPath, meshRep, fragShadFile);

					MShaderRef * vertShad = level->loadShader(vertShadPath, M_SHADER_VERTEX);
					MShaderRef * pixShad = level->loadShader(fragShadPath, M_SHADER_PIXEL);
					if(vertShad && pixShad)
					{
						MFXRef * ZFXRef = level->createFX(vertShad, pixShad);
						material->setZFXRef(ZFXRef);
					}
				}
			}
		}
	}


	// Bones
	TiXmlElement * bonesNode = pMeshNode->FirstChildElement("Bones");
	if(bonesNode)
	{
	    MLOG_DEBUG("entering Bones node");
		
		MArmature * armature = mesh->createArmature();

		unsigned int b, numBones = 0;
		bonesNode->QueryUIntAttribute("num", &numBones);
		armature->allocBones(numBones);

		// add bones
		for(b=0; b<numBones; b++)
			armature->addNewBone();
		b = 0;

		// Bone
		TiXmlElement * boneNode = bonesNode->FirstChildElement("Bone");
		for(boneNode; boneNode; boneNode=boneNode->NextSiblingElement("Bone"))
		{
			if(b >= armature->getBonesNumber())
				break;

			MOBone * bone = armature->getBone(b);

			const char * name = boneNode->Attribute("name");
			if(name)
				bone->setName(name);

			// parent
			TiXmlElement * parentNode = boneNode->FirstChildElement("parent");
			if(parentNode){
				unsigned int boneId = 0;
				parentNode->QueryUIntAttribute("id", &boneId);
				bone->linkTo(armature->getBone(boneId));
			}

			// position
			TiXmlElement * positionNode = boneNode->FirstChildElement("position");
			if(positionNode){
				MVector3 position;
				positionNode->QueryFloatAttribute("x", &position.x);
				positionNode->QueryFloatAttribute("y", &position.y);
				positionNode->QueryFloatAttribute("z", &position.z);
				bone->setPosition(position);
			}

			// rotation
			TiXmlElement * rotationNode = boneNode->FirstChildElement("rotation");
			if(rotationNode){

				MVector3 euler;
				rotationNode->QueryFloatAttribute("x", &euler.x);
				rotationNode->QueryFloatAttribute("y", &euler.y);
				rotationNode->QueryFloatAttribute("z", &euler.z);
				bone->setEulerRotation(euler);
			}

			// scale
			TiXmlElement * scaleNode = boneNode->FirstChildElement("scale");
			if(scaleNode){
				MVector3 scale;
				scaleNode->QueryFloatAttribute("x", &scale.x);
				scaleNode->QueryFloatAttribute("y", &scale.y);
				scaleNode->QueryFloatAttribute("z", &scale.z);
				bone->setScale(scale);
			}

			b++;
		}

		// construct bones inverse pose matrix
		armature->constructBonesInversePoseMatrix();
	}


	// SubMeshs
	TiXmlElement * subMeshsNode = pMeshNode->FirstChildElement("SubMeshs");
	if(! subMeshsNode)
		return true;

	unsigned int numSubMeshs = 0;
	subMeshsNode->QueryUIntAttribute("num", &numSubMeshs);
	if(numSubMeshs == 0)
		return true;

	// alloc subMeshs
	MSubMesh * subMeshs = mesh->allocSubMeshs(numSubMeshs);

	// BoundingBox
	TiXmlElement * boundingBoxNode = pMeshNode->FirstChildElement("BoundingBox");
	if(boundingBoxNode)
	{
		MVector3 * min = &mesh->getBoundingBox()->min;
		MVector3 * max = &mesh->getBoundingBox()->max;

		boundingBoxNode->QueryFloatAttribute("minx", &min->x);
		boundingBoxNode->QueryFloatAttribute("miny", &min->y);
		boundingBoxNode->QueryFloatAttribute("minz", &min->z);

		boundingBoxNode->QueryFloatAttribute("maxx", &max->x);
		boundingBoxNode->QueryFloatAttribute("maxy", &max->y);
		boundingBoxNode->QueryFloatAttribute("maxz", &max->z);
	}

	// SubMesh
	TiXmlElement * SubMeshNode = subMeshsNode->FirstChildElement("SubMesh");
	for(SubMeshNode; SubMeshNode; SubMeshNode=SubMeshNode->NextSiblingElement("SubMesh"))
	{
		MSubMesh * subMesh = subMeshs;

		// BoundingBox
		boundingBoxNode = SubMeshNode->FirstChildElement("BoundingBox");
		if(boundingBoxNode)
		{
			MVector3 * min = &subMesh->getBoundingBox()->min;
			MVector3 * max = &subMesh->getBoundingBox()->max;

			boundingBoxNode->QueryFloatAttribute("minx", &min->x);
			boundingBoxNode->QueryFloatAttribute("miny", &min->y);
			boundingBoxNode->QueryFloatAttribute("minz", &min->z);

			boundingBoxNode->QueryFloatAttribute("maxx", &max->x);
			boundingBoxNode->QueryFloatAttribute("maxy", &max->y);
			boundingBoxNode->QueryFloatAttribute("maxz", &max->z);
		}

		// Vertices
		TiXmlElement * verticesNode = SubMeshNode->FirstChildElement("Vertices");
		if(verticesNode)
		{
			unsigned int numVertices = 0;
			verticesNode->QueryUIntAttribute("num", &numVertices);
			MVector3 * vertices = subMesh->allocVertices(numVertices);

			// vertex
			TiXmlElement * vertexNode = verticesNode->FirstChildElement("vertex");
			for(vertexNode; vertexNode; vertexNode=vertexNode->NextSiblingElement("vertex"))
			{
				vertexNode->QueryFloatAttribute("x", &vertices->x);
				vertexNode->QueryFloatAttribute("y", &vertices->y);
				vertexNode->QueryFloatAttribute("z", &vertices->z);
				vertices++;
			}
		}

		// Normals
		TiXmlElement * normalsNode = SubMeshNode->FirstChildElement("Normals");
		if(normalsNode)
		{
			unsigned int numNormals = 0;
			normalsNode->QueryUIntAttribute("num", &numNormals);
			MVector3 * normals = subMesh->allocNormals(numNormals);

			// normal
			TiXmlElement * normalNode = normalsNode->FirstChildElement("normal");
			for(normalNode; normalNode; normalNode=normalNode->NextSiblingElement("normal"))
			{
				normalNode->QueryFloatAttribute("x", &normals->x);
				normalNode->QueryFloatAttribute("y", &normals->y);
				normalNode->QueryFloatAttribute("z", &normals->z);
				normals->normalize();
				normals++;
			}
		}

		// Tangents
		TiXmlElement * tangentsNode = SubMeshNode->FirstChildElement("Tangents");
		if(tangentsNode)
		{
			unsigned int numTangents = 0;
			tangentsNode->QueryUIntAttribute("num", &numTangents);
			MVector3 * tangents = subMesh->allocTangents(numTangents);

			// tangent
			TiXmlElement * tangentNode = tangentsNode->FirstChildElement("tangent");
			for(tangentNode; tangentNode; tangentNode=tangentNode->NextSiblingElement("tangent"))
			{
				tangentNode->QueryFloatAttribute("x", &tangents->x);
				tangentNode->QueryFloatAttribute("y", &tangents->y);
				tangentNode->QueryFloatAttribute("z", &tangents->z);
				tangents->normalize();
				tangents++;
			}
		}

		// TexCoords
		TiXmlElement * texCoordsNode = SubMeshNode->FirstChildElement("TexCoords");
		if(texCoordsNode)
		{
			// num
			unsigned int numTexCoords = 0;
			texCoordsNode->QueryUIntAttribute("num", &numTexCoords);
			MVector2 * texCoords = subMesh->allocTexCoords(numTexCoords);

			// mapChannels
			unsigned int numVertices = subMesh->getVerticesSize();
			const char * mapChannelsData = texCoordsNode->Attribute("mapChannels");

			// read channels
			if(mapChannelsData)
			{
				char str[256];
				strcpy(str, mapChannelsData);
				char * pch;

				unsigned int offset = 0;
				pch = strtok(str, " ");
				while(pch != NULL)
				{
					unsigned int channel = 0;
					sscanf(pch, "%d", &channel);

					subMesh->setMapChannelOffset(channel, offset);

					pch = strtok(NULL, " ");
					offset += numVertices;
				}
			}
			// create default channels
			else if((numVertices > 0) && (numTexCoords > numVertices))
			{
				unsigned int numChannels = numTexCoords / numVertices;
				for(unsigned int c=0; c<numChannels; c++)
					subMesh->setMapChannelOffset(c, numVertices*c);
			}

			// texCoord
			TiXmlElement * texCoordNode = texCoordsNode->FirstChildElement("texCoord");
			for(texCoordNode; texCoordNode; texCoordNode=texCoordNode->NextSiblingElement("texCoord"))
			{
				texCoordNode->QueryFloatAttribute("x", &texCoords->x);
				texCoordNode->QueryFloatAttribute("y", &texCoords->y);
				texCoords++;
			}
		}

		// Colors
		TiXmlElement * colorsNode = SubMeshNode->FirstChildElement("Colors");
		if(colorsNode)
		{
			unsigned int numColors = 0;
			colorsNode->QueryUIntAttribute("num", &numColors);
			MColor * colors = subMesh->allocColors(numColors);

			// color
			TiXmlElement * colorNode = colorsNode->FirstChildElement("color");
			for(colorNode; colorNode; colorNode=colorNode->NextSiblingElement("color"))
			{
				float x = 1, y = 1, z = 1, w = 1;
				colorNode->QueryFloatAttribute("x", &x);
				colorNode->QueryFloatAttribute("y", &y);
				colorNode->QueryFloatAttribute("z", &z);
				colorNode->QueryFloatAttribute("w", &w);

				colors->r = (unsigned char)x*255;
				colors->g = (unsigned char)y*255;
				colors->b = (unsigned char)z*255;
				colors->a = (unsigned char)w*255;;

				colors++;
			}
		}

		// Indices
		TiXmlElement * indicesNode = SubMeshNode->FirstChildElement("Indices");
		if(indicesNode)
		{
			M_TYPES indicesType;
			unsigned int vSize = subMesh->getVerticesSize();

			if(vSize < 65536){
				indicesType = M_USHORT;
			}
			else{
				indicesType = M_UINT;
			}

			unsigned int numIndices = 0;
			indicesNode->QueryUIntAttribute("num", &numIndices);
			subMesh->allocIndices(numIndices, indicesType);

			// indices
			TiXmlElement * indexNode = indicesNode->FirstChildElement("index");
			switch(indicesType)
			{
			case M_USHORT:
				{
					unsigned short * indices = (unsigned short *)subMesh->getIndices();
					for(indexNode; indexNode; indexNode=indexNode->NextSiblingElement("index"))
					{
						unsigned int id;
						indexNode->QueryUIntAttribute("value", &id);
						*indices = (unsigned short)id;
						indices++;
					}
				}
				break;
			case M_UINT:
				{
					unsigned int * indices = (unsigned int *)subMesh->getIndices();
					for(indexNode; indexNode; indexNode=indexNode->NextSiblingElement("index"))
					{
						indexNode->QueryUIntAttribute("value", indices);
						indices++;
					}
				}
				break;
			}
		}

		// Skins
		TiXmlElement * skinsNode = SubMeshNode->FirstChildElement("Skins");
		if(skinsNode)
		{
			MSkinData * skinData = subMesh->createSkinData();

			unsigned int numSkins = 0;
			skinsNode->QueryUIntAttribute("num", &numSkins);
			MSkinPoint * skinPoints = skinData->allocPoints(numSkins);

			// skin
			TiXmlElement * skinNode = skinsNode->FirstChildElement("skin");
			for(skinNode; skinNode; skinNode=skinNode->NextSiblingElement("skin"))
			{
				unsigned int vertexId = 0;
				unsigned int numBones = 0;

				skinNode->QueryUIntAttribute("vertex", &vertexId);
				skinNode->QueryUIntAttribute("numBones", &numBones);

				if(numBones > 0)
				{
					skinPoints->setVertexId(vertexId);
					skinPoints->allocateBonesLinks(numBones);

					unsigned short * bonesIds = skinPoints->getBonesIds();
					float * bonesWeights = skinPoints->getBonesWeights();

					TiXmlElement * boneNode = skinNode->FirstChildElement("bone");
					for(boneNode; boneNode; boneNode=boneNode->NextSiblingElement("bone"))
					{
						unsigned int id;
						boneNode->QueryUIntAttribute("id", &id);
						boneNode->QueryFloatAttribute("weight", bonesWeights);

						*bonesIds = id;

						bonesIds++;
						bonesWeights++;
					}
				}

				skinPoints++;
			}
		}

		// Displays
		TiXmlElement * displaysNode = SubMeshNode->FirstChildElement("Displays");
		if(displaysNode)
		{
			unsigned int numDisplays = 0;
			displaysNode->QueryUIntAttribute("num", &numDisplays);
			subMesh->allocDisplays(numDisplays);

			// display
			TiXmlElement * displayNode = displaysNode->FirstChildElement("display");
			for(displayNode; displayNode; displayNode=displayNode->NextSiblingElement("display"))
			{
				unsigned int begin, size, material, cullFace = 0;

				displayNode->QueryUIntAttribute("begin", &begin);
				displayNode->QueryUIntAttribute("size", &size);
				displayNode->QueryUIntAttribute("material", &material);
				displayNode->QueryUIntAttribute("cullFace", &cullFace);

				// create display
				MDisplay * display = subMesh->addNewDisplay(M_PRIMITIVE_TRIANGLES, begin, size);

				// set material
				if(material < mesh->getMaterialsNumber())
					display->setMaterial(mesh->getMaterial(material));

				// set cull mode
				M_CULL_MODES cullMode = M_CULL_BACK;
				if(cullFace == 1)
					cullMode = M_CULL_FRONT;
				else if(cullFace == 2)
					cullMode = M_CULL_NONE;
				display->setCullMode(cullMode);
			}
		}

		// generate tangents if needed
		if(! subMesh->getTangents())
			generateTangents(subMesh);


		subMeshs++;
	}

    MLOG_DEBUG("xmlMeshLoad success: "<<numSubMeshs<<" submeshs found");
	
	return true;
}