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); } }
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; }
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(); }
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! }
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; } } }
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(); }
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; }
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!! }
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); }
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); } }
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; }