COpenGLGrassRenderer::COpenGLGrassRenderer(COpenGLRenderDevice *pRenderDevice)
	:	m_pRenderDevice(pRenderDevice), m_GrassTextureID(0),
		m_vDefaultGrassSize(0.5f, 1.0f, 0.0f),
		m_nGrassClusterVBOID(0), m_nGrassClusterIndexVBOID(0), m_nGrassClusterVAOID(0),
		m_GrassClusterInstanceVBID(0)
{
	m_GrassClusterInstanceArray.ensureStorageAllocated(INIT_GRASSCLUSTERINSTANCE_NUM);

	// Local Grass Cluster Vertex and Index
	/*
	0			1
	|-----------|
	| 			|
	|			|
	|			|
	|-----------|
	3			2
	*/
	uint16 grassIndex[6*3] = { 0, 2, 1, 0, 3, 2,	4, 6, 5, 4, 7, 6,	8, 10, 9, 8, 11, 10 };

	SGPVertex_GRASS grassLocalVertex[4*3];
	Vector3D OffsetVector(m_vDefaultGrassSize.x, 0, 0);
	Matrix4x4 RotMat;

	for( int i=-1; i<=1; i++ )
	{
		RotMat.RotationY( i * 60.0f * pi_over_180 );
		OffsetVector.RotateWith(RotMat);

		if( i == 0 )
			OffsetVector.Set(m_vDefaultGrassSize.x, 0, 0);

		grassLocalVertex[(i+1)*4 + 0].x = -OffsetVector.x;
		grassLocalVertex[(i+1)*4 + 0].y = -OffsetVector.y;
		grassLocalVertex[(i+1)*4 + 0].z = -OffsetVector.z;
		grassLocalVertex[(i+1)*4 + 0].tu = 0; grassLocalVertex[(i+1)*4 + 0].tv = 0;
		grassLocalVertex[(i+1)*4 + 1].x =  OffsetVector.x;
		grassLocalVertex[(i+1)*4 + 1].y =  OffsetVector.y;
		grassLocalVertex[(i+1)*4 + 1].z =  OffsetVector.z;
		grassLocalVertex[(i+1)*4 + 1].tu = 1; grassLocalVertex[(i+1)*4 + 1].tv = 0;
		grassLocalVertex[(i+1)*4 + 2].x =  OffsetVector.x;
		grassLocalVertex[(i+1)*4 + 2].y =  OffsetVector.y;
		grassLocalVertex[(i+1)*4 + 2].z =  OffsetVector.z;
		grassLocalVertex[(i+1)*4 + 2].tu = 1; grassLocalVertex[(i+1)*4 + 2].tv = 1;
		grassLocalVertex[(i+1)*4 + 3].x = -OffsetVector.x;
		grassLocalVertex[(i+1)*4 + 3].y = -OffsetVector.y;
		grassLocalVertex[(i+1)*4 + 3].z = -OffsetVector.z;
		grassLocalVertex[(i+1)*4 + 3].tu = 0; grassLocalVertex[(i+1)*4 + 3].tv = 1;
	}

	GLsizei nStride = sizeof(SGPVertex_GRASS);

	// create one GrassCluster VAO and VBO
	m_pRenderDevice->extGlGenVertexArray(1, &m_nGrassClusterVAOID);
	m_pRenderDevice->extGlBindVertexArray(m_nGrassClusterVAOID);

	m_pRenderDevice->extGlGenBuffers(1, &m_nGrassClusterVBOID);
	m_pRenderDevice->extGlBindBuffer(GL_ARRAY_BUFFER, m_nGrassClusterVBOID);
	m_pRenderDevice->extGlBufferData(GL_ARRAY_BUFFER, 4*3*nStride, grassLocalVertex, GL_STATIC_DRAW);

	m_pRenderDevice->extGlEnableVertexAttribArray(0);
	m_pRenderDevice->extGlVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(0));
	m_pRenderDevice->extGlEnableVertexAttribArray(1);
	m_pRenderDevice->extGlVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(3*sizeof(float)));

	// Instance VertexBuffer
	nStride = sizeof(SGPVertex_GRASS_Cluster);
	m_pRenderDevice->extGlGenBuffers(1, &m_GrassClusterInstanceVBID);
	m_pRenderDevice->extGlBindBuffer(GL_ARRAY_BUFFER, m_GrassClusterInstanceVBID);
	m_pRenderDevice->extGlBufferData(GL_ARRAY_BUFFER, INIT_GRASSCLUSTERINSTANCE_NUM * nStride, NULL, GL_STREAM_DRAW);
    m_pRenderDevice->extGlEnableVertexAttribArray(2);
    m_pRenderDevice->extGlVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(0));
    m_pRenderDevice->extGlVertexAttribDivisor(2, 1);
    m_pRenderDevice->extGlEnableVertexAttribArray(3);
    m_pRenderDevice->extGlVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, nStride, (GLvoid *)BUFFER_OFFSET(4*sizeof(float)));
    m_pRenderDevice->extGlVertexAttribDivisor(3, 1);
    m_pRenderDevice->extGlEnableVertexAttribArray(4);
    m_pRenderDevice->extGlVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(4*sizeof(float)+4*sizeof(uint8)));
    m_pRenderDevice->extGlVertexAttribDivisor(4, 1);
    m_pRenderDevice->extGlEnableVertexAttribArray(5);
    m_pRenderDevice->extGlVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(8*sizeof(float)+4*sizeof(uint8)));
    m_pRenderDevice->extGlVertexAttribDivisor(5, 1);


	m_pRenderDevice->extGlGenBuffers(1, &m_nGrassClusterIndexVBOID);
	m_pRenderDevice->extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nGrassClusterIndexVBOID);
	m_pRenderDevice->extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*3*sizeof(uint16), grassIndex, GL_STATIC_DRAW);
	
	m_pRenderDevice->extGlBindVertexArray(0);
}
COpenGLES2GrassRenderer::COpenGLES2GrassRenderer(COpenGLES2RenderDevice *pRenderDevice)
	:	m_pRenderDevice(pRenderDevice), m_GrassTextureID(0),
		m_vDefaultGrassSize(0.5f, 1.0f, 0.0f),
		m_nGrassClusterVBOID(0), m_nGrassClusterIndexVBOID(0), m_nGrassClusterVAOID(0)
{
	m_GrassClusterInstanceArray.ensureStorageAllocated(INIT_GRASSCLUSTERINSTANCE_NUM);
	
	// Local Grass Cluster Vertex and Index
	/*
	0			1
	|-----------|
	| 			|
	|			|
	|			|
	|-----------|
	3			2
	*/
	uint16 grassIndex[6*3] = { 0, 2, 1, 0, 3, 2,	4, 6, 5, 4, 7, 6,	8, 10, 9, 8, 11, 10 };



	Vector3D OffsetVector(m_vDefaultGrassSize.x, 0, 0);
	Matrix4x4 RotMat;

	for( int i=-1; i<=1; i++ )
	{
		RotMat.RotationY( i * 60.0f * pi_over_180 );
		OffsetVector.RotateWith(RotMat);

		if( i == 0 )
			OffsetVector.Set(m_vDefaultGrassSize.x, 0, 0);

		m_grassVertex[(i+1)*4 + 0].x = -OffsetVector.x;
		m_grassVertex[(i+1)*4 + 0].y = -OffsetVector.y;
		m_grassVertex[(i+1)*4 + 0].z = -OffsetVector.z;
		m_grassVertex[(i+1)*4 + 0].tu = 0; m_grassVertex[(i+1)*4 + 0].tv = 0;
		m_grassVertex[(i+1)*4 + 1].x =  OffsetVector.x;
		m_grassVertex[(i+1)*4 + 1].y =  OffsetVector.y;
		m_grassVertex[(i+1)*4 + 1].z =  OffsetVector.z;
		m_grassVertex[(i+1)*4 + 1].tu = 1; m_grassVertex[(i+1)*4 + 1].tv = 0;
		m_grassVertex[(i+1)*4 + 2].x =  OffsetVector.x;
		m_grassVertex[(i+1)*4 + 2].y =  OffsetVector.y;
		m_grassVertex[(i+1)*4 + 2].z =  OffsetVector.z;
		m_grassVertex[(i+1)*4 + 2].tu = 1; m_grassVertex[(i+1)*4 + 2].tv = 1;
		m_grassVertex[(i+1)*4 + 3].x = -OffsetVector.x;
		m_grassVertex[(i+1)*4 + 3].y = -OffsetVector.y;
		m_grassVertex[(i+1)*4 + 3].z = -OffsetVector.z;
		m_grassVertex[(i+1)*4 + 3].tu = 0; m_grassVertex[(i+1)*4 + 3].tv = 1;
	}

	GLsizei nStride = sizeof(SGPVertex_GRASS_GLES2);


	// create one GrassCluster VAO and VBO
	m_pRenderDevice->extGlGenVertexArray(1, &m_nGrassClusterVAOID);
	m_pRenderDevice->extGlBindVertexArray(m_nGrassClusterVAOID);

	glGenBuffers(1, &m_nGrassClusterVBOID);
	glBindBuffer(GL_ARRAY_BUFFER, m_nGrassClusterVBOID);
	glBufferData(GL_ARRAY_BUFFER, INIT_GRASSCLUSTERINSTANCE_NUM*4*3*nStride, NULL, GL_STREAM_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(0));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(4*sizeof(float)));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(8*sizeof(float)));
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, nStride, (GLvoid *)BUFFER_OFFSET(12*sizeof(float)));


	glGenBuffers(1, &m_nGrassClusterIndexVBOID);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nGrassClusterIndexVBOID);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, INIT_GRASSCLUSTERINSTANCE_NUM*6*3*sizeof(uint16), NULL, GL_STATIC_DRAW);
	
	uint16* pGrassIndex = (uint16*)m_pRenderDevice->extGlMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
	for( uint16 j=0; j<INIT_GRASSCLUSTERINSTANCE_NUM; j++ )
	{
		for( int k=0; k<6*3; k++ )
			pGrassIndex[ j*(6*3) + k ] = grassIndex[k] + j*(4*3);
	}
	m_pRenderDevice->extGlUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);

	m_pRenderDevice->extGlBindVertexArray(0);
}