void LineSegmentCollection::UpdateGPUVertexData()
{
   if (defaultGPUVertexData != nullptr)
   {
      std::size_t numLineSegments = lineSegments.size();

      std::size_t numVertices = numLineSegments * 2;

      defaultGPUVertexData->Bind();
      defaultGPUVertexData->Buffer(numVertices, GL_STATIC_DRAW);

      if (numVertices > 0)
      {
         std::vector<GPUVertexDataStorage> vertData(numVertices);

         for (std::size_t lineSegmentIndex = 0, vertDataIndex = 0; lineSegmentIndex < numLineSegments; ++lineSegmentIndex)
         {
            for (std::size_t linePointIndex = 0; linePointIndex < 2; ++linePointIndex)
            {
               const FVector3& point = (linePointIndex == 0) ? lineSegments[lineSegmentIndex].segment.P1 : lineSegments[lineSegmentIndex].segment.P2;

               vertData[vertDataIndex].position[0] = static_cast<float>( point.x );
               vertData[vertDataIndex].position[1] = static_cast<float>( point.y );
               vertData[vertDataIndex].position[2] = static_cast<float>( point.z );

               const Color& color = lineSegments[lineSegmentIndex].color;

               vertData[vertDataIndex].color[0] = color.r;
               vertData[vertDataIndex].color[1] = color.g;
               vertData[vertDataIndex].color[2] = color.b;
               vertData[vertDataIndex].color[3] = color.a;

               ++vertDataIndex;
            }
         }

         defaultGPUVertexData->BufferSub(0, numVertices, vertData.data());
      }

      defaultGPUVertexData->transferInfo.sendPositions = true;
      defaultGPUVertexData->transferInfo.sendColors = true;
      defaultGPUVertexData->transferInfo.sendNormals = false;
      defaultGPUVertexData->transferInfo.sendTexCoords = false;

      defaultGPUVertexData->drawMode = GL_LINES;
   }
}
void ModelLoader::CreateVertexBuffer( Vertex::VERTEX_TYPE type ) {
	aiMesh* mesh = scene->mMeshes[0];
	UINT count = mesh->mNumVertices;
	aiVector3D* vertices = mesh->mVertices;
	/*  The switch case looks like duplicated code.  It is not.	 vertData is a different type in each and SetVertices() is a template. */
	switch( type ) {
	case Vertex::BASIC_32:
	{
		std::vector<Vertex::Basic32> vertData( count );
		aiVector3D* normals = mesh->mNormals;
		aiVector3D* texCoords = mesh->mTextureCoords[0];
		for( UINT i = 0; i<count; ++i ) {
			UpdateExtents( vertices[i].x, vertices[i].y, vertices[i].z );
			vertData[i].Pos = XMFLOAT3( vertices[i].x, vertices[i].y, vertices[i].z );
			vertData[i].Normal = XMFLOAT3( normals[i].x, normals[i].y, normals[i].z );
			vertData[i].Tex = XMFLOAT2( texCoords[i].x, texCoords[i].y );
		}
		SetVertices( device, count, vertData.data() );
		break;
	}
	case Vertex::POS_NORMAL_TEX_TAN:
	{
		aiVector3D* normals = mesh->mNormals;
		aiVector3D* texCoords = mesh->mTextureCoords[0];
		aiVector3D* tangents = mesh->mTangents;
		std::vector<Vertex::PosNormalTexTan> vertData( count );
		for( UINT i = 0; i<count; ++i ) {
			UpdateExtents( vertices[i].x, vertices[i].y, vertices[i].z );
			vertData[i].Pos = XMFLOAT3( vertices[i].x, vertices[i].y, vertices[i].z );
			vertData[i].Normal = XMFLOAT3( normals[i].x, normals[i].y, normals[i].z );
			vertData[i].Tex = XMFLOAT2( texCoords[i].x, texCoords[i].y );
			vertData[i].TangentU = XMFLOAT4( tangents[i].x, tangents[i].y, tangents[i].z, 0.f );
		}
		SetVertices( device, count, vertData.data() );
		break;
	}
	case Vertex::POS_NORMAL_TEX_TAN_SKINNED:
	{
		aiVector3D* normals = mesh->mNormals;
		aiVector3D* texCoords = mesh->mTextureCoords[0];
		aiVector3D* tangents = mesh->mTangents;
		std::vector<Vertex::PosNormalTexTanSkinned> vertData( count );
		for( UINT i = 0; i<count; ++i ) {
			UpdateExtents( vertices[i].x, vertices[i].y, vertices[i].z );
			vertData[i].Pos = XMFLOAT3( vertices[i].x, vertices[i].y, vertices[i].z );
			vertData[i].Normal = XMFLOAT3( normals[i].x, normals[i].y, normals[i].z );
			vertData[i].Tex = XMFLOAT2( texCoords[i].x, texCoords[i].y );
			vertData[i].TangentU = XMFLOAT4( tangents[i].x, tangents[i].y, tangents[i].z, 0.f );
		}

		// Bone Data
		std::multimap<int, BoneWeight> vertexBoneWeight;
		for( unsigned int boneIndex = 0; boneIndex<mesh->mNumBones; ++boneIndex ) {
			auto bone = mesh->mBones[boneIndex];
			for( int i = 0; i<bone->mNumWeights; ++i ) {
				auto boneWeight = BoneWeight( boneIndex, bone->mWeights[i].mWeight );
				vertexBoneWeight.insert( std::pair<int, BoneWeight>( bone->mWeights[i].mVertexId, boneWeight ) );
			}
		}
		for( UINT i = 0; i<count; ++i ) {
			BYTE boneIndices[4] = { 0, 0, 0, 0 };
			float weights[4] = { 0, 0, 0, 0 };
			int j = 0;
			auto itlow = vertexBoneWeight.lower_bound( i );
			auto itup = vertexBoneWeight.upper_bound( i );
			assert( itlow!=itup ); // every vertex should have some influence
			for( auto it = itlow; it!=itup; ++it ) {
				if( j>3 ) {
					assert( false ); // only 4 boes should influence one vertex
					break;
				}
				boneIndices[j] = it->second.boneIndex;
				weights[j] = it->second.weight;
				++j;
			}
			vertData[i].BoneIndicies[0] = boneIndices[0];
			vertData[i].BoneIndicies[1] = boneIndices[1];
			vertData[i].BoneIndicies[2] = boneIndices[2];
			vertData[i].BoneIndicies[3] = boneIndices[3];
			vertData[i].Weights = XMFLOAT4( weights );
		}

		SetVertices( device, count, vertData.data() );
		break;
	}
	}
}
        void EntityLinkDecorator::render(Vbo& vbo, RenderContext& context) {
            if (context.viewOptions().linkDisplayMode() == View::ViewOptions::LinkDisplayNone)
                return;

            const Model::EntityList& entities = map().entities();
            if (entities.empty())
                return;

            SetVboState activateVbo(vbo, Vbo::VboActive);
            
            if (m_doRebuild) {
                delete m_vertexArray;
                m_vertexArray = NULL;
                m_doRebuild = false;

                // for keeping track of which entities have already been visited by the link-gathering algorithm - should this be part of each entity instead ?
                Model::EntitySet visitedEntities;

                Vec4f::List vertsLocal; // links directly connected to a selected entity
                Vec4f::List vertsContext; // links not directly connected, but in the same context
                Vec4f::List vertsUnrelated; // links not related to the current selection

                Model::EntityList::const_iterator it, end;

                // first pass, outputs local or local+context links
                for (it = entities.begin(), end = entities.end(); it != end; ++it) {
                    Model::Entity& entity = **it;

                    if (entity.selected()) {
                        if (context.viewOptions().linkDisplayMode() == View::ViewOptions::LinkDisplayLocal) {
                            gatherLinksLocal(vertsLocal, context, entity);
                        } else {
                            gatherLinks(vertsLocal, vertsContext, context, entity, visitedEntities);
                        }
                    }
                }

                // second pass, only used in "display all" mode, outputs target links of entities the first pass didn't visit
                if (context.viewOptions().linkDisplayMode() == View::ViewOptions::LinkDisplayAll) {
                    Model::EntitySet::const_iterator vIt;
                    for (it = entities.begin(), end = entities.end(); it != end; ++it) {
                        Model::Entity& entity = **it;
                        vIt = visitedEntities.lower_bound( &entity );

                        if( *vIt != &entity )
                            gatherLinksUnrelated(vertsUnrelated, context, entity);
                    }
                }

                unsigned int vertexCount = static_cast<unsigned int>(vertsLocal.size() + vertsContext.size() + vertsUnrelated.size());
                if (vertexCount == 0)
                    return;
                
                //FIXME : doesn't need to be a color4f at the moment
                m_vertexArray = new VertexArray(vbo, GL_LINES, vertexCount, Attribute::position3f(), Attribute::color4f(), 0);
                
                SetVboState mapVbo(vbo, Vbo::VboMapped);

                // draw order : unrelated -> context -> local
                // vertData.y sets the type of link for the shader ( 0 = unrelated, 0.5 = context, 1.0 = local )
                Vec4f vertData(1.0f);

                vertData.y = 0.0f;
                for (int i = 0; i != vertsUnrelated.size(); ++i ) {
                    vertData.x = vertsUnrelated[i].w;
                    m_vertexArray->addAttribute(Vec3f(vertsUnrelated[i].x, vertsUnrelated[i].y, vertsUnrelated[i].z));
                    m_vertexArray->addAttribute(vertData);
                }
                vertData.y = 0.5f;
                for (int i = 0; i != vertsContext.size(); ++i) {
                    vertData.x = vertsContext[i].w;
                    m_vertexArray->addAttribute(Vec3f(vertsContext[i].x, vertsContext[i].y, vertsContext[i].z));
                    m_vertexArray->addAttribute(vertData);
                }
                vertData.y = 1.0f;
                for (int i = 0; i != vertsLocal.size(); ++i) {
                    vertData.x = vertsLocal[i].w;
                    m_vertexArray->addAttribute(Vec3f(vertsLocal[i].x, vertsLocal[i].y, vertsLocal[i].z));
                    m_vertexArray->addAttribute(vertData);
                }

                m_valid = true;
            }

            if (!m_valid || m_vertexArray == NULL)
                return;

            ActivateShader shader(context.shaderManager(), Shaders::EntityLinkShader );
            shader.currentShader().setUniformVariable("CameraPosition", context.camera().position());
            //shader.currentShader().setUniformVariable("Color", m_color); // unused at the moment, make color view-prefs for the different types of links ?
            shader.currentShader().setUniformVariable("Occluded", 1.0f);

            // render the "occluded" portion without depth-test
            glLineWidth(2.0f);
            glDepthMask(GL_FALSE);
            glDisable(GL_DEPTH_TEST);

            m_vertexArray->render();

            shader.currentShader().setUniformVariable("Occluded", 0.0f);
            glEnable(GL_DEPTH_TEST);

            m_vertexArray->render();

            glDepthMask(GL_TRUE);
            glLineWidth(1.0f);
        }