void CGraphics_Threaded::FlushVertices()
{
	if(m_NumVertices == 0)
		return;

	int NumVerts = m_NumVertices;
	m_NumVertices = 0;

	CCommandBuffer::SCommand_Render Cmd;
	Cmd.m_State = m_State;

	if(m_Drawing == DRAWING_QUADS)
	{
		Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_QUADS;
		Cmd.m_PrimCount = NumVerts/4;
	}
	else if(m_Drawing == DRAWING_LINES)
	{
		Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_LINES;
		Cmd.m_PrimCount = NumVerts/2;
	}
	else
		return;

	Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts);
	if(Cmd.m_pVertices == 0x0)
	{
		// kick command buffer and try again
		KickCommandBuffer();

		Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts);
		if(Cmd.m_pVertices == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}
	}

	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();
		
		Cmd.m_pVertices = (CCommandBuffer::SVertex *)m_pCommandBuffer->AllocData(sizeof(CCommandBuffer::SVertex)*NumVerts);
		if(Cmd.m_pVertices == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for render command");
			return;
		}
	}

	mem_copy(Cmd.m_pVertices, m_aVertices, sizeof(CCommandBuffer::SVertex)*NumVerts);
}
int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes)
{
	if(g_Config.m_GfxDisplayAllModes)
	{
		int Count = sizeof(g_aFakeModes)/sizeof(CVideoMode);
		mem_copy(pModes, g_aFakeModes, sizeof(g_aFakeModes));
		if(MaxModes < Count)
			Count = MaxModes;
		return Count;
	}

	// add videomodes command
	CImageInfo Image;
	mem_zero(&Image, sizeof(Image));

	int NumModes = 0;
	CCommandBuffer::SCommand_VideoModes Cmd;
	Cmd.m_pModes = pModes;
	Cmd.m_MaxModes = MaxModes;
	Cmd.m_pNumModes = &NumModes;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the buffer and wait for the result and return it
	KickCommandBuffer();
	WaitForIdle();
	return NumModes;
}
void CGraphics_Threaded::ScreenshotDirect(const char *pFilename)
{
	// add swap command
	CImageInfo Image;
	mem_zero(&Image, sizeof(Image));

	CCommandBuffer::SCommand_Screenshot Cmd;
	Cmd.m_pImage = &Image;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the buffer and wait for the result
	KickCommandBuffer();
	WaitForIdle();

	if(Image.m_pData)
	{
		// find filename
		char aWholePath[1024];
		png_t Png; // ignore_convention

		IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE, aWholePath, sizeof(aWholePath));
		if(File)
			io_close(File);

		// save png
		char aBuf[256];
		str_format(aBuf, sizeof(aBuf), "saved screenshot to '%s'", aWholePath);
		m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf);
		png_open_file_write(&Png, aWholePath); // ignore_convention
		png_set_data(&Png, Image.m_Width, Image.m_Height, 8, PNG_TRUECOLOR, (unsigned char *)Image.m_pData); // ignore_convention
		png_close_file(&Png); // ignore_convention

		mem_free(Image.m_pData);
	}
}
Example #4
0
int CGraphics_Threaded::LoadTextureRawSub(int TextureID, int x, int y, int Width, int Height, int Format, const void *pData)
{
	CCommandBuffer::SCommand_Texture_Update Cmd;
	Cmd.m_Slot = TextureID;
	Cmd.m_X = x;
	Cmd.m_Y = y;
	Cmd.m_Width = Width;
	Cmd.m_Height = Height;
	Cmd.m_Format = ImageFormatToTexFormat(Format);

	// calculate memory usage
	int MemSize = Width*Height*ImageFormatToPixelSize(Format);

	// copy texture data
	void *pTmpData = mem_alloc(MemSize, sizeof(void*));
	mem_copy(pTmpData, pData, MemSize);
	Cmd.m_pData = pTmpData;
	
	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();
		m_pCommandBuffer->AddCommand(Cmd);
	}		
	return 0;
}
bool CGraphics_Threaded::SetVSync(bool State)
{
	// add vsnc command
	bool RetOk = 0;
	CCommandBuffer::SCommand_VSync Cmd;
	Cmd.m_VSync = State ? 1 : 0;
	Cmd.m_pRetOk = &RetOk;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the command buffer
	KickCommandBuffer();
	WaitForIdle();
	return RetOk;
}
Example #6
0
void CGraphics_Threaded::Swap()
{
	// TODO: screenshot support
	if(m_DoScreenshot)
	{
		ScreenshotDirect(m_aScreenshotName);
		m_DoScreenshot = false;
	}

	// add swap command
	CCommandBuffer::SCommand_Swap Cmd;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the command buffer
	KickCommandBuffer();
}
Example #7
0
int CGraphics_Threaded::LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags)
{
	// don't waste memory on texture if we are stress testing
#ifdef CONF_DEBUG
	if(g_Config.m_DbgStress)
		return m_InvalidTexture;
#endif

	// grab texture
	int Tex = m_FirstFreeTexture;
	m_FirstFreeTexture = m_aTextureIndices[Tex];
	m_aTextureIndices[Tex] = -1;

	CCommandBuffer::SCommand_Texture_Create Cmd;
	Cmd.m_Slot = Tex;
	Cmd.m_Width = Width;
	Cmd.m_Height = Height;
	Cmd.m_PixelSize = ImageFormatToPixelSize(Format);
	Cmd.m_Format = ImageFormatToTexFormat(Format);
	Cmd.m_StoreFormat = ImageFormatToTexFormat(StoreFormat);

	// flags
	Cmd.m_Flags = 0;
	if(Flags&IGraphics::TEXLOAD_NOMIPMAPS)
		Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NOMIPMAPS;
	if(g_Config.m_GfxTextureCompression)
		Cmd.m_Flags |= CCommandBuffer::TEXFLAG_COMPRESSED;
	if(g_Config.m_GfxTextureQuality || Flags&TEXLOAD_NORESAMPLE)
		Cmd.m_Flags |= CCommandBuffer::TEXFLAG_QUALITY;

	// copy texture data
	int MemSize = Width*Height*Cmd.m_PixelSize;
	void *pTmpData = mem_alloc(MemSize, sizeof(void*));
	mem_copy(pTmpData, pData, MemSize);
	Cmd.m_pData = pTmpData;

	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();
		m_pCommandBuffer->AddCommand(Cmd);
	}

	return Tex;
}
void CGraphics_Threaded::Swap()
{
	// TODO: screenshot support
	if(m_DoScreenshot)
	{
		if(WindowActive())
			ScreenshotDirect(m_aScreenshotName);
		m_DoScreenshot = false;
	}

	// add swap command
	CCommandBuffer::SCommand_Swap Cmd;
	Cmd.m_Finish = g_Config.m_GfxFinish;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the command buffer
	KickCommandBuffer();
}
void CGraphics_Threaded::ReadBackbuffer(unsigned char **ppPixels, int x, int y, int w, int h)
{
	if(!ppPixels)
		return;

	// add swap command
	CImageInfo Image;
	mem_zero(&Image, sizeof(Image));

	CCommandBuffer::SCommand_Screenshot Cmd;
	Cmd.m_pImage = &Image;
	Cmd.m_X = x; Cmd.m_Y = y;
	Cmd.m_W = w; Cmd.m_H = h;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the buffer and wait for the result
	KickCommandBuffer();
	WaitForIdle();

	*ppPixels = (unsigned char *)Image.m_pData; // take ownership!
}
Example #10
0
void CGraphics_Threaded::DrawBorderTile(int VisualObjectIDX, float *pColor, char *pOffset, float *Offset, float *Dir, int JumpIndex, unsigned int DrawNum)
{
	if(DrawNum == 0) return;
	// Draw a border tile a lot of times
	CCommandBuffer::SCommand_RenderBorderTile Cmd;
	Cmd.m_State = m_State;
	Cmd.m_DrawNum = DrawNum;
	Cmd.m_VisualObjectIDX = m_VertexArrayIndices[VisualObjectIDX];
	mem_copy(&Cmd.m_Color, pColor, sizeof(Cmd.m_Color));
	float ScreenZoomRatio = ScreenWidth() / (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x);
	//the number of pixels we would skip in the fragment shader -- basically the LOD
	float LODFactor = (64.f / (32.f * ScreenZoomRatio));
	//log2 gives us the amount of halving the texture for mipmapping
	int LOD = (int)log2f(LODFactor);
	if(LOD > 5) LOD = 5;
	if(LOD < 0) LOD = 0;
	Cmd.m_LOD = LOD;

	Cmd.m_pIndicesOffset = pOffset;
	Cmd.m_JumpIndex = JumpIndex;
	
	Cmd.m_Offset[0] = Offset[0];
	Cmd.m_Offset[1] = Offset[1];
	Cmd.m_Dir[0] = Dir[0];
	Cmd.m_Dir[1] = Dir[1];

	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for render command");
			return;
		}
	}
}
Example #11
0
void CGraphics_Threaded::Resize(int w, int h)
{
	if(m_ScreenWidth == w && m_ScreenHeight == h)
		return;

	if(h > 4*w/5)
		h = 4*w/5;
	if(w > 21*h/9)
		w = 21*h/9;

	m_ScreenWidth = w;
	m_ScreenHeight = h;

	CCommandBuffer::SCommand_Resize Cmd;
	Cmd.m_Width = w;
	Cmd.m_Height = h;
	m_pCommandBuffer->AddCommand(Cmd);

	// kick the command buffer
	KickCommandBuffer();
	WaitForIdle();
}
Example #12
0
void CGraphics_Threaded::DestroyVisual(int VisualObjectIDX)
{
	if (VisualObjectIDX == -1) return;
	CCommandBuffer::SCommand_DestroyVisual Cmd;
	Cmd.m_VisualObjectIDX = m_VertexArrayIndices[VisualObjectIDX];
	
	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for destroy all visuals command");
			return;
		}
	}
	
	//also clear the vert array index
	m_VertexArrayIndices[VisualObjectIDX] = m_FirstFreeVertexArrayIndex;
	m_FirstFreeVertexArrayIndex = VisualObjectIDX;
}
Example #13
0
void CGraphics_Threaded::DrawVisualObject(int VisualObjectIDX, float *pColor, char** pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffet)
{
	if(NumIndicesOffet == 0) return;
	
	//add the VertexArrays and draw
	CCommandBuffer::SCommand_RenderVertexArray Cmd;
	Cmd.m_State = m_State;
	Cmd.m_IndicesDrawNum = NumIndicesOffet;
	Cmd.m_VisualObjectIDX = m_VertexArrayIndices[VisualObjectIDX];
	mem_copy(&Cmd.m_Color, pColor, sizeof(Cmd.m_Color));
	float ScreenZoomRatio = ScreenWidth() / (m_State.m_ScreenBR.x - m_State.m_ScreenTL.x);
	//the number of pixels we would skip in the fragment shader -- basically the LOD
	float LODFactor = (64.f / (32.f * ScreenZoomRatio));
	//log2 gives us the amount of halving the texture for mipmapping
	int LOD = (int)log2f(LODFactor);
	//5 because log2(1024/(2^5)) is 5 -- 2^5 = 32 which would mean 2 pixels per tile index
	if(LOD > 5) LOD = 5;
	if(LOD < 0) LOD = 0;
	Cmd.m_LOD = LOD;

	void *Data = m_pCommandBuffer->AllocData((sizeof(char*) + sizeof(unsigned int))*NumIndicesOffet);
	if(Data == 0x0)
	{
		// kick command buffer and try again
		KickCommandBuffer();
	
		void *Data = m_pCommandBuffer->AllocData((sizeof(char*) + sizeof(unsigned int))*NumIndicesOffet);
		if(Data == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}
	}
	Cmd.m_pIndicesOffsets = (char**)Data;
	Cmd.m_pDrawCount = (unsigned int*)(((char*)Data) + (sizeof(char*)*NumIndicesOffet));
	
	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();

		Data = m_pCommandBuffer->AllocData((sizeof(char*) + sizeof(unsigned int))*NumIndicesOffet);
		if(Data == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}
		Cmd.m_pIndicesOffsets = (char**)Data;
		Cmd.m_pDrawCount = (unsigned int*)(((char*)Data) + (sizeof(char*)*NumIndicesOffet));

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for render command");
			return;
		}
	}

	
	mem_copy(Cmd.m_pIndicesOffsets, pOffsets, sizeof(char*)*NumIndicesOffet);
	mem_copy(Cmd.m_pDrawCount, IndicedVertexDrawNum, sizeof(unsigned int)*NumIndicesOffet);
	
	//todo max indices group check!!
}
Example #14
0
void CGraphics_Threaded::FlushVertices()
{
	if(m_NumVertices == 0)
		return;
	
	size_t VertSize = 0;
	if(!m_UseOpenGL3_3) VertSize = sizeof(CCommandBuffer::SVertexOld);
	else VertSize = sizeof(CCommandBuffer::SVertex);

	int NumVerts = m_NumVertices;
	m_NumVertices = 0;

	CCommandBuffer::SCommand_Render Cmd;
	Cmd.m_State = m_State;

	if(m_Drawing == DRAWING_QUADS)
	{
		if(g_Config.m_GfxQuadAsTriangle && !m_UseOpenGL3_3)
		{
			Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_TRIANGLES;
			Cmd.m_PrimCount = NumVerts/3;
		}
		else
		{
			Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_QUADS;
			Cmd.m_PrimCount = NumVerts/4;
		}
	}
	else if(m_Drawing == DRAWING_LINES)
	{
		Cmd.m_PrimType = CCommandBuffer::PRIMTYPE_LINES;
		Cmd.m_PrimCount = NumVerts/2;
	}
	else
		return;

	Cmd.m_pVertices = (CCommandBuffer::SVertexBase *)m_pCommandBuffer->AllocData(VertSize*NumVerts);
	if(Cmd.m_pVertices == 0x0)
	{
		// kick command buffer and try again
		KickCommandBuffer();

		Cmd.m_pVertices = (CCommandBuffer::SVertexBase *)m_pCommandBuffer->AllocData(VertSize*NumVerts);
		if(Cmd.m_pVertices == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}
	}

	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();

		Cmd.m_pVertices = (CCommandBuffer::SVertexBase *)m_pCommandBuffer->AllocData(VertSize*NumVerts);
		if(Cmd.m_pVertices == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for render command");
			return;
		}
	}

	mem_copy(Cmd.m_pVertices, m_pVertices, VertSize*NumVerts);
}
Example #15
0
void CGraphics_Threaded::AppendAllVertices(float *pVertices, unsigned char *pTexCoords, int NumTiles, int VisualObjectIDX)
{
	//the size of the cmd data buffer is 2MB -- we create 4 vertices of each 2 floats plus 2 shorts(2*unsigned char each) if TexCoordinates are used
	char AddTexture = (pTexCoords == NULL ? 0 : 1);
	int AddTextureSize = (pTexCoords == NULL ? 0 : (sizeof(unsigned char) * 2 * 2 * 4));
	
	int MaxTileNumUpload = (1024*1024*2) / (sizeof(float) * 4 * 2 + AddTextureSize);
	
	int RealTileNum = NumTiles;
	if(NumTiles > MaxTileNumUpload) RealTileNum = MaxTileNumUpload;

	CCommandBuffer::SCommand_AppendVertexBufferObject Cmd;
	int NumVerts = (Cmd.m_NumVertices = RealTileNum * 4 * 2); //number of vertices to upload -- same value for texcoords(if used)
	Cmd.m_VisualObjectIDX = VisualObjectIDX;

	Cmd.m_Elements = m_pCommandBuffer->AllocData(RealTileNum * (sizeof(float) * 4 * 2 + AddTextureSize));
	if(Cmd.m_Elements == 0x0)
	{
		// kick command buffer and try again
		KickCommandBuffer();

		Cmd.m_Elements = m_pCommandBuffer->AllocData(RealTileNum * (sizeof(float) * 4 * 2 + AddTextureSize));
		if(Cmd.m_Elements == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}
	}

	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();
		
		Cmd.m_Elements = m_pCommandBuffer->AllocData(RealTileNum * (sizeof(float) * 4 * 2 + AddTextureSize));
		if(Cmd.m_Elements == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return;
		}

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for create vertex buffer command");
			return;
		}
	}
	
	mem_copy_special(Cmd.m_Elements, pVertices, sizeof(float) * 2, RealTileNum * 4, (AddTexture) * sizeof(unsigned char) * 2 * 2);
	
	if(pTexCoords)
	{
		mem_copy_special(((char*)Cmd.m_Elements) + sizeof(float) * 2, pTexCoords, sizeof(unsigned char) * 2 * 2, RealTileNum * 4, (AddTexture) * sizeof(float) * 2);
	}
	
	if(NumTiles > RealTileNum)
	{
		pVertices += NumVerts;
		if(pTexCoords) pTexCoords += NumVerts*2;
		AppendAllVertices(pVertices, pTexCoords, NumTiles - RealTileNum, VisualObjectIDX);
	}
}
Example #16
0
int CGraphics_Threaded::CreateVisualObjects(float *pVertices, unsigned char *pTexCoords, int NumTiles, unsigned int NumIndicesRequired)
{
	if(!pVertices) return -1;
	
	//first create an index
	int index = -1;
	if(m_FirstFreeVertexArrayIndex == -1)
	{
		index = m_VertexArrayIndices.size();
		m_VertexArrayIndices.push_back(index);
	}
	else
	{
		index = m_FirstFreeVertexArrayIndex;
		m_FirstFreeVertexArrayIndex = m_VertexArrayIndices[index];
		m_VertexArrayIndices[index] = index;
	}
	
	//upload the vertex buffer first
	//the size of the cmd data buffer is 2MB -- we create 4 vertices of each 2 floats plus 2 shorts(2*unsigned char each) if TexCoordinates are used
	char AddTexture = (pTexCoords == NULL ? 0 : 1);
	int AddTextureSize = (pTexCoords == NULL ? 0 : (sizeof(unsigned char) * 2 * 2 * 4));
	
	int MaxTileNumUpload = (1024*1024*2) / (sizeof(float) * 4 * 2 + AddTextureSize);
	
	int RealTileNum = NumTiles;
	if(NumTiles > MaxTileNumUpload) RealTileNum = MaxTileNumUpload;

	CCommandBuffer::SCommand_CreateVertexBufferObject Cmd;
	Cmd.m_IsTextured = pTexCoords != NULL;
	Cmd.m_VisualObjectIDX = index;
	int NumVerts = (Cmd.m_NumVertices = RealTileNum * 4 * 2); //number of vertices to upload -- same value for texcoords(if used)
	
	Cmd.m_Elements = m_pCommandBuffer->AllocData(RealTileNum * (sizeof(float) * 4 * 2 + AddTextureSize));
	if(Cmd.m_Elements == 0x0)
	{
		// kick command buffer and try again
		KickCommandBuffer();

		Cmd.m_Elements = m_pCommandBuffer->AllocData(RealTileNum * (sizeof(float) * 4 * 2 + AddTextureSize));
		if(Cmd.m_Elements == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return -1;
		}
	}

	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(Cmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();
		
		Cmd.m_Elements = m_pCommandBuffer->AllocData(RealTileNum * (sizeof(float) * 4 * 2 + AddTextureSize));
		if(Cmd.m_Elements == 0x0)
		{
			dbg_msg("graphics", "failed to allocate data for vertices");
			return -1;
		}

		if(!m_pCommandBuffer->AddCommand(Cmd))
		{
			dbg_msg("graphics", "failed to allocate memory for create vertex buffer command");
			return -1;
		}
	}
	
	mem_copy_special(Cmd.m_Elements, pVertices, sizeof(float) * 2, RealTileNum * 4, (AddTexture) * sizeof(unsigned char) * 2 * 2);
	
	if(pTexCoords)
	{
		mem_copy_special(((char*)Cmd.m_Elements) + sizeof(float) * 2, pTexCoords, sizeof(unsigned char) * 2 * 2, RealTileNum * 4, (AddTexture) * sizeof(float) * 2);
	}
		
	if(NumTiles > MaxTileNumUpload)
	{
		pVertices += NumVerts;
		if(pTexCoords) pTexCoords += NumVerts*2;
		AppendAllVertices(pVertices, pTexCoords, NumTiles - MaxTileNumUpload, index);
	}
		
	CCommandBuffer::SCommand_CreateVertexArrayObject VertArrayCmd;
	VertArrayCmd.m_VisualObjectIDX = index;
	VertArrayCmd.m_RequiredIndicesCount = NumIndicesRequired;
	// check if we have enough free memory in the commandbuffer
	if(!m_pCommandBuffer->AddCommand(VertArrayCmd))
	{
		// kick command buffer and try again
		KickCommandBuffer();
		
		if(!m_pCommandBuffer->AddCommand(VertArrayCmd))
		{
			dbg_msg("graphics", "failed to allocate memory for create vertex array command");
			return -1;
		}
	}
	
	//make sure we uploaded everything
	KickCommandBuffer();
	
	return index;
}