/*============================================================================= D3DTexturesStreaming.cpp : Direct3D9 vertex/index buffers management. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Honitch Andrey =============================================================================*/ #include "RenderPCH.h" #include "DriverD3D9.h" //=============================================================================== #ifdef _DEBUG TArray gDVB; #endif //=============================================================================== void *CVertexBuffer::GetStream(int nStream, int *nOffs) { if (m_VS[nStream].m_pPool) { if (nOffs) *nOffs = m_VS[nStream].m_nBufOffset; return m_VS[nStream].m_pPool->m_pVB; } else { if (nOffs) *nOffs = 0; return m_VS[nStream].m_VertBuf.m_pPtr; } } void CD3D9Renderer::DrawDynVB(int nOffs, int Pool, int nVerts) { PROFILE_FRAME(Draw_IndexMesh); if (!m_SceneRecurseCount) { iLog->Log("Error: CD3D9Renderer::DrawDynVB without BeginScene\n"); return; } if (CV_d3d9_forcesoftware) return; if (!nVerts) return; if (m_bDeviceLost) return; HRESULT h; struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *pDst = (struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *)GetVBPtr3D(nVerts, nOffs); //assert(pDst); if (!pDst) return; if (m_TempDynVB) { cryMemcpy(pDst, m_TempDynVB, nVerts*sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); SAFE_DELETE_ARRAY(m_TempDynVB); } else cryMemcpy(pDst, m_DynVB, nVerts*sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); m_pVB3D[0]->Unlock(); // Bind our vertex as the first data stream of our device h = m_pd3dDevice->SetStreamSource(0, m_pVB3D[0], 0, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); EF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB_TEX2F); // Render the two triangles from the data stream h = m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, nOffs, nVerts/3); } void CD3D9Renderer::DrawDynVB(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *pBuf, ushort *pInds, int nVerts, int nInds, int nPrimType) { PROFILE_FRAME(Draw_IndexMesh); if (!pBuf) return; if (!m_SceneRecurseCount) { iLog->Log("Error: CD3D9Renderer::DrawDynVB without BeginScene\n"); return; } if (CV_d3d9_forcesoftware) return; if (!nVerts || !nInds) return; if (FAILED(m_pd3dDevice->TestCooperativeLevel())) return; HRESULT h; int nOffs, nIOffs; struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *pDst = (struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *)GetVBPtr3D(nVerts, nOffs); assert(pDst); if (!pDst) return; ushort *pDstInds = NULL; if (pInds) pDstInds = GetIBPtr(nInds, nIOffs); cryMemcpy(pDst, pBuf, nVerts*sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); if (pDstInds) cryMemcpy(pDstInds, pInds, nInds*sizeof(short)); m_pVB3D[0]->Unlock(); if (pDstInds) m_pIB->Unlock(); // Bind our vertex as the first data stream of our device h = m_pd3dDevice->SetStreamSource(0, m_pVB3D[0], 0, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); EF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB_TEX2F); // Render triangles from the data stream if (pDstInds) { h = m_pd3dDevice->SetIndices((IDirect3DIndexBuffer9 *)m_pIB); h = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, nOffs, 0, nVerts, nIOffs, nInds/3); } else { h = m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, nOffs, nVerts/3); } } //=============================================================================== void CD3D9Renderer::CreateIndexBuffer(SVertexStream *dest,const void *src,int indexcount) { WaitForDevice(); if (dest->m_VertBuf.m_pPtr) { IDirect3DIndexBuffer9 *pIndBuf = (IDirect3DIndexBuffer9 *)dest->m_VertBuf.m_pPtr; #ifdef _DEBUG sRemoveVB(pIndBuf, dest); #endif SAFE_RELEASE(pIndBuf); } dest->m_nItems = 0; if (indexcount) { IDirect3DIndexBuffer9 *ibuf=NULL; int size = indexcount*sizeof(ushort); int flags = D3DUSAGE_WRITEONLY; D3DPOOL Pool = D3DPOOL_MANAGED; if (dest->m_bDynamic) { flags |= D3DUSAGE_DYNAMIC; Pool = D3DPOOL_DEFAULT; } HRESULT hReturn = m_pd3dDevice->CreateIndexBuffer(size, flags, D3DFMT_INDEX16, Pool, &ibuf, NULL); #ifdef _DEBUG sAddVB(ibuf, dest, NULL, "Index buf"); #endif if (FAILED(hReturn)) { iLog->Log("Failed to create index buffer\n"); return; } dest->m_VertBuf.m_pPtr = ibuf; dest->m_nItems = indexcount; } if (src && indexcount) UpdateIndexBuffer(dest, src, indexcount, true); } void CD3D9Renderer::UpdateIndexBuffer(SVertexStream *dest,const void *src,int indexcount, bool bUnLock) { PROFILE_FRAME(Mesh_UpdateIBuffers); if (m_bDeviceLost) return; HRESULT hReturn; IDirect3DIndexBuffer9 *ibuf; if (src && indexcount) { if (dest->m_nItems < indexcount) { if (dest->m_nItems) ReleaseIndexBuffer(dest); CreateIndexBuffer(dest, NULL, indexcount); } ushort *dst; ibuf = (IDirect3DIndexBuffer9 *)dest->m_VertBuf.m_pPtr; { PROFILE_FRAME(Mesh_UpdateIBuffersLock); hReturn = ibuf->Lock(0, 0, (void **) &dst, dest->m_bDynamic ? D3DLOCK_DISCARD : 0); } int size = indexcount*sizeof(ushort); { PROFILE_FRAME(Mesh_UpdateIBuffersCopy); cryMemcpy(dst, src, size); } dest->m_VData = dst; //hReturn = m_pd3dDevice->TestCooperativeLevel(); if (bUnLock) { hReturn = ibuf->Unlock(); dest->m_bLocked = false; } else dest->m_bLocked = true; } else if (dest->m_VertBuf.m_pPtr) { if (bUnLock && dest->m_bLocked) { ibuf = (IDirect3DIndexBuffer9 *)dest->m_VertBuf.m_pPtr; hReturn = ibuf->Unlock(); dest->m_bLocked = false; } else if (!bUnLock && !dest->m_bLocked) { PROFILE_FRAME(Mesh_UpdateIBuffersLock); ibuf = (IDirect3DIndexBuffer9 *)dest->m_VertBuf.m_pPtr; ushort *dst; hReturn = ibuf->Lock(0, 0, (void **) &dst, dest->m_bDynamic ? D3DLOCK_DISCARD : 0); dest->m_bLocked = true; dest->m_VData = dst; } } } void CD3D9Renderer::ReleaseIndexBuffer(SVertexStream *dest) { IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9 *)dest->m_VertBuf.m_pPtr; #ifdef _DEBUG if (ibuf) sRemoveVB(ibuf, dest); #endif SAFE_RELEASE(ibuf); dest->Reset(); } void *CD3D9Renderer::GetDynVBPtr(int nVerts, int &nOffs, int Pool) { void *vBuf = NULL; nOffs = 0; switch(Pool) { case 0: default: if (nVerts <= 2048) { SAFE_DELETE_ARRAY(m_TempDynVB); return m_DynVB; } else { m_TempDynVB = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F [nVerts]; return m_TempDynVB; } break; case 1: case 2: vBuf = GetVBPtr3D(nVerts, nOffs, Pool); break; } return vBuf; } #ifdef _DEBUG static char *szDescBuf[] = { "Base Mesh", "Mesh Tangents", "Mesh LM", }; #endif bool CD3D9Renderer::AllocateVBChunk(int bytes_count, TVertPool *Ptr, SVertexStream *pVB, const char *szSource) { assert(bytes_count); int best_i = -1; int min_size = 10000000; // find best chunk for(int i=0; im_alloc_info.Count(); i++) { if(!Ptr->m_alloc_info[i].busy) { if(Ptr->m_alloc_info[i].bytes_num >= bytes_count) { if(Ptr->m_alloc_info[i].bytes_num < min_size) { best_i = i; min_size = Ptr->m_alloc_info[i].bytes_num; } } } } if(best_i>=0) { // use best free chunk Ptr->m_alloc_info[best_i].busy = true; Ptr->m_alloc_info[best_i].szSource = szSource; int bytes_free = Ptr->m_alloc_info[best_i].bytes_num - bytes_count; if(bytes_free>0) { // modify reused shunk Ptr->m_alloc_info[best_i].bytes_num = bytes_count; // insert another free shunk alloc_info_struct new_shunk; new_shunk.bytes_num = bytes_free; new_shunk.ptr = Ptr->m_alloc_info[best_i].ptr + Ptr->m_alloc_info[best_i].bytes_num; new_shunk.busy = false; if(best_i < Ptr->m_alloc_info.Count()-1) // if not last Ptr->m_alloc_info.InsertBefore(new_shunk, best_i+1); else Ptr->m_alloc_info.Add(new_shunk); } pVB->m_nBufOffset = Ptr->m_alloc_info[best_i].ptr; pVB->m_pPool = (SVertPool *)Ptr; return true; } int res_ptr = 0; int piplevel = Ptr->m_alloc_info.Count() ? (Ptr->m_alloc_info.Last().ptr - Ptr->m_alloc_info[0].ptr) + Ptr->m_alloc_info.Last().bytes_num : 0; if(piplevel + bytes_count + 100 >= Ptr->m_nBufSize) { return false; } else { res_ptr = piplevel; } // register new chunk alloc_info_struct ai; ai.ptr = res_ptr; ai.szSource = szSource; ai.bytes_num = bytes_count; ai.busy = true; Ptr->m_alloc_info.Add(ai); pVB->m_nBufOffset = res_ptr; pVB->m_pPool = (SVertPool *)Ptr; return true; } bool CD3D9Renderer::ReleaseVBChunk(TVertPool *Ptr, SVertexStream *pVB) { int p = pVB->m_nBufOffset; for(int i=0; im_alloc_info.Count(); i++) { if(Ptr->m_alloc_info[i].ptr == p) { Ptr->m_alloc_info[i].busy = false; // delete info about last unused shunks while(Ptr->m_alloc_info.Count() && Ptr->m_alloc_info.Last().busy == false) Ptr->m_alloc_info.Delete(Ptr->m_alloc_info.Count()-1); // merge unused shunks for(int s=0; sm_alloc_info.Count()-1; s++) { assert(Ptr->m_alloc_info[s].ptr < Ptr->m_alloc_info[s+1].ptr); if(Ptr->m_alloc_info[s].busy == false) { if(Ptr->m_alloc_info[s+1].busy == false) { Ptr->m_alloc_info[s].bytes_num += Ptr->m_alloc_info[s+1].bytes_num; Ptr->m_alloc_info.Delete(s+1); s--; } } } return Ptr->m_alloc_info.Count() ? false : true; } } iLog->Log("Error: CD3D9Renderer::ReleaseVBChunk::ReleasePointer: pointer not found"); return false; } void CD3D9Renderer::AllocVBInPool(int size, int nVFormat, SVertexStream *pVB) { CD3D9Renderer *rd = gcpRendD3D; assert(nVFormat>=0 && nVFormatNext) { if (AllocateVBChunk(size, Ptr, pVB, NULL)) break; } if (!Ptr) { Ptr = new TVertPool; Ptr->m_nBufSize = VBsize; Ptr->m_pVB = NULL; Ptr->Next = sVertPools; Ptr->PrevLink = &sVertPools; if (sVertPools) { assert(sVertPools->PrevLink == &sVertPools); sVertPools->PrevLink = &Ptr->Next; } sVertPools = Ptr; AllocateVBChunk(size, Ptr, pVB, NULL); } if (!Ptr->m_pVB) rd->m_pd3dDevice->CreateVertexBuffer(VBsize, Flags, fvf, Pool, &Ptr->m_pVB, NULL); } void CD3D9Renderer::CreateBuffer(int size, int vertexformat, CVertexBuffer *buf, int Type, const char *szSource) { PROFILE_FRAME(Mesh_CreateVBuffers); WaitForDevice(); if (CV_d3d9_vbpools && size < CV_d3d9_vbpoolsize && !buf->m_bDynamic) { AllocVBInPool(size, vertexformat, &buf->m_VS[Type]); return; } IDirect3DVertexBuffer9 *vptr = NULL; int fvf = m_RP.m_D3DFixedPipeline[Type][vertexformat].m_Handle; int Flags = D3DUSAGE_WRITEONLY; D3DPOOL Pool = D3DPOOL_MANAGED; if (buf->m_bDynamic) { Flags |= D3DUSAGE_DYNAMIC; Pool = D3DPOOL_DEFAULT; } HRESULT hReturn = m_pd3dDevice->CreateVertexBuffer(size, Flags, fvf, Pool, &vptr, NULL); if (FAILED(hReturn)) return; buf->m_VS[Type].m_bDynamic = buf->m_bDynamic; #ifdef _DEBUG sAddVB(vptr, &buf->m_VS[Type], buf, szDescBuf[Type]); #endif void *dst; buf->m_VS[Type].m_VertBuf.m_pPtr = vptr; hReturn = vptr->Lock(0, 0, (void **) &dst, buf->m_bDynamic ? D3DLOCK_NOOVERWRITE : 0); buf->m_VS[Type].m_VData = dst; hReturn = vptr->Unlock(); m_CurVertBufferSize += size; } CVertexBuffer *CD3D9Renderer::CreateBuffer(int vertexcount,int vertexformat, const char *szSource, bool bDynamic) { PROFILE_FRAME(Mesh_CreateVBuffers); WaitForDevice(); IDirect3DVertexBuffer9 *vptr = NULL; int fvf = m_RP.m_D3DFixedPipeline[0][vertexformat].m_Handle; int Flags = D3DUSAGE_WRITEONLY; D3DPOOL Pool = D3DPOOL_MANAGED; if (bDynamic) { Flags |= D3DUSAGE_DYNAMIC; Pool = D3DPOOL_DEFAULT; } int size = m_VertexSize[vertexformat]*vertexcount; if (size+m_CurVertBufferSize > m_MaxVertBufferSize) { CLeafBuffer *pLB = CLeafBuffer::m_Root.m_Prev; while (size+m_CurVertBufferSize > m_MaxVertBufferSize) { if (pLB == &CLeafBuffer::m_Root) iConsole->Exit("Error: Pipeline buffer overflow. Current geometry cannot fit in video memory (%s)", gRenDev->GetStatusText(eRS_VidBuffer)); CLeafBuffer *Next = pLB->m_Prev; pLB->Unload(); pLB = Next; } } m_CurVertBufferSize += m_VertexSize[vertexformat]*vertexcount; CVertexBuffer *newbuf = new CVertexBuffer; newbuf->m_bDynamic = bDynamic; newbuf->m_VS[VSF_GENERAL].m_bDynamic = bDynamic; newbuf->m_VS[VSF_GENERAL].m_bLocked = false; newbuf->m_fence=0; newbuf->m_NumVerts = vertexcount; newbuf->m_vertexformat = vertexformat; if (CV_d3d9_vbpools && m_VertexSize[vertexformat]*vertexcount < CV_d3d9_vbpoolsize && !newbuf->m_bDynamic) { AllocVBInPool(size, vertexformat, &newbuf->m_VS[VSF_GENERAL]); return newbuf; } HRESULT hReturn = m_pd3dDevice->CreateVertexBuffer(m_VertexSize[vertexformat]*vertexcount, Flags, fvf, Pool, &vptr, NULL); if (FAILED(hReturn)) return (NULL); newbuf->m_VS[VSF_GENERAL].m_VertBuf.m_pPtr = vptr; #ifdef _DEBUG sAddVB(vptr, &newbuf->m_VS[VSF_GENERAL], newbuf, szDescBuf[VSF_GENERAL]); #endif return(newbuf); } /////////////////////////////////////////// void CD3D9Renderer::UpdateBuffer(CVertexBuffer *dest, const void *src, int vertexcount, bool bUnLock, int offs, int Type) { PROFILE_FRAME(Mesh_UpdateVBuffers); if (m_bDeviceLost) return; VOID *pVertices; HRESULT hr = 0; IDirect3DVertexBuffer9 *tvert; int size; int nOffs = 0; if (!src) { if (!Type) { tvert=(IDirect3DVertexBuffer9 *)dest->GetStream(VSF_GENERAL, &nOffs); size = m_VertexSize[dest->m_vertexformat]; if (bUnLock) { // video buffer update if (dest->m_VS[VSF_GENERAL].m_bLocked) { dest->m_VS[VSF_GENERAL].m_bLocked = false; hr = tvert->Unlock(); } } else { // video buffer update if (!dest->m_VS[VSF_GENERAL].m_bLocked) { PROFILE_FRAME(Mesh_UpdateVBuffersLock); dest->m_VS[VSF_GENERAL].m_bLocked = true; hr=tvert->Lock(0, 0, (void **) &pVertices, dest->m_bDynamic ? D3DLOCK_DISCARD : 0); byte *pData = (byte *)pVertices; dest->m_VS[VSF_GENERAL].m_VData = &pData[nOffs]; } } } else { for (int i=0; iGetStream(i, &nOffs); if (!tvert) continue; if (!((1<m_VS[i].m_bLocked) { dest->m_VS[i].m_bLocked = false; hr = tvert->Unlock(); } } else { if (!dest->m_VS[i].m_bLocked) { PROFILE_FRAME(Mesh_UpdateVBuffersLock); dest->m_VS[i].m_bLocked = true; hr=tvert->Lock(0, 0, (void **) &pVertices, dest->m_bDynamic ? D3DLOCK_DISCARD : 0); byte *pData = (byte *)pVertices; dest->m_VS[VSF_GENERAL].m_VData = &pData[nOffs]; } } } } return; } if (Type == VSF_GENERAL) { if (dest->m_VS[VSF_GENERAL].m_pPool) { tvert = dest->m_VS[VSF_GENERAL].m_pPool->m_pVB; nOffs = dest->m_VS[VSF_GENERAL].m_nBufOffset; } else tvert = (IDirect3DVertexBuffer9 *)dest->m_VS[VSF_GENERAL].m_VertBuf.m_pPtr; size = m_VertexSize[dest->m_vertexformat]; } else if (Type == VSF_TANGENTS) { if (dest->m_VS[VSF_TANGENTS].m_pPool) { tvert = dest->m_VS[VSF_TANGENTS].m_pPool->m_pVB; nOffs = dest->m_VS[VSF_TANGENTS].m_nBufOffset; } else tvert = (IDirect3DVertexBuffer9 *)dest->m_VS[VSF_TANGENTS].m_VertBuf.m_pPtr; size = sizeof(SPipTangents); } if (!tvert) // system buffer update { PROFILE_FRAME(Mesh_UpdateVBuffersCopy); if (dest->m_bFenceSet) cryMemcpy(dest->m_VS[Type].m_VData, src, size*vertexcount); else if (Type == VSF_GENERAL && dest->m_VS[VSF_GENERAL].m_VData) cryMemcpy(dest->m_VS[VSF_GENERAL].m_VData, src, size*vertexcount); return; } // video buffer update if (!dest->m_VS[Type].m_bLocked) { PROFILE_FRAME(Mesh_UpdateVBuffersLock); dest->m_VS[Type].m_bLocked = true; hr=tvert->Lock(nOffs, size*vertexcount, (void **) &pVertices, dest->m_bDynamic ? D3DLOCK_DISCARD : 0); assert(!hr); dest->m_VS[Type].m_VData = pVertices; } if (SUCCEEDED(hr) && src) { PROFILE_FRAME(Mesh_UpdateVBuffersCopy); cryMemcpy(dest->m_VS[Type].m_VData, src, size*vertexcount); tvert->Unlock(); dest->m_VS[Type].m_bLocked = false; m_RP.m_PS.m_MeshUpdateBytes += size*vertexcount; } else if (dest->m_VS[Type].m_bLocked && bUnLock) { tvert->Unlock(); dest->m_VS[Type].m_bLocked = false; } } void CD3D9Renderer::UnlockBuffer(CVertexBuffer *buf, int Type) { if (!buf->m_VS[Type].m_bLocked) return; if (m_bDeviceLost) return; if (buf->m_bFenceSet) { UnlockVB3D(Type+1); buf->m_VS[Type].m_bLocked = false; return; } IDirect3DVertexBuffer9 *tvert; tvert = (IDirect3DVertexBuffer9 *)buf->GetStream(Type, NULL); HRESULT hr = tvert->Unlock(); buf->m_VS[Type].m_bLocked = false; } /////////////////////////////////////////// void CD3D9Renderer::ReleaseBuffer(CVertexBuffer *bufptr) { if (bufptr) { m_CurVertBufferSize -= m_VertexSize[bufptr->m_vertexformat]*bufptr->m_NumVerts; if (bufptr->m_VS[VSF_TANGENTS].m_VertBuf.m_pPtr) m_CurVertBufferSize -= sizeof(SPipTangents)*bufptr->m_NumVerts; IDirect3DVertexBuffer9 *vtemp; if (bufptr->m_VS[VSF_GENERAL].m_pPool) { TVertPool *pPool = (TVertPool *)bufptr->m_VS[VSF_GENERAL].m_pPool; if (ReleaseVBChunk(pPool, &bufptr->m_VS[VSF_GENERAL])) { IDirect3DVertexBuffer9 *vtemp = pPool->m_pVB; SAFE_RELEASE(vtemp); pPool->Unlink(); delete pPool; } } else { vtemp = (IDirect3DVertexBuffer9 *)bufptr->m_VS[VSF_GENERAL].m_VertBuf.m_pPtr; #ifdef _DEBUG if (vtemp) sRemoveVB(vtemp, &bufptr->m_VS[VSF_GENERAL]); #endif SAFE_RELEASE(vtemp); bufptr->m_VS[VSF_GENERAL].m_VertBuf.m_pPtr = NULL; } if (bufptr->m_VS[VSF_TANGENTS].m_pPool) { TVertPool *pPool = (TVertPool *)bufptr->m_VS[VSF_TANGENTS].m_pPool; if (ReleaseVBChunk(pPool, &bufptr->m_VS[VSF_TANGENTS])) { IDirect3DVertexBuffer9 *vtemp = pPool->m_pVB; SAFE_RELEASE(vtemp); pPool->Unlink(); delete pPool; } } else { vtemp = (IDirect3DVertexBuffer9 *)bufptr->m_VS[VSF_TANGENTS].m_VertBuf.m_pPtr; #ifdef _DEBUG if (vtemp) sRemoveVB(vtemp, &bufptr->m_VS[VSF_TANGENTS]); #endif SAFE_RELEASE(vtemp); bufptr->m_VS[VSF_TANGENTS].m_VertBuf.m_pPtr = NULL; } delete bufptr; } } #include "../Common/NvTriStrip/NVTriStrip.h" /////////////////////////////////////////// void CD3D9Renderer::DrawBuffer(CVertexBuffer *src,SVertexStream *indicies,int numindices,int offsindex,int prmode,int vert_start,int vert_stop, CMatInfo *mi) { if (m_bDeviceLost) return; if (CV_d3d9_forcesoftware) return; if (!m_SceneRecurseCount) { iLog->Log("ERROR: CD3D9Renderer::DrawBuffer before BeginScene"); return; } if (!indicies->m_VertBuf.m_pPtr || !src) return; PROFILE_FRAME(Draw_IndexMesh); int size = numindices * sizeof(short); if (src->m_VS[VSF_GENERAL].m_bLocked) { IDirect3DVertexBuffer9 *tvert = (IDirect3DVertexBuffer9 *)src->m_VS[VSF_GENERAL].m_VertBuf.m_pPtr; tvert->Unlock(); src->m_VS[VSF_GENERAL].m_bLocked = false; } IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9 *)indicies->m_VertBuf.m_pPtr; HRESULT h = EF_SetVertexDeclaration(0, src->m_vertexformat); int nOffs; IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)src->GetStream(VSF_GENERAL, &nOffs); h = m_pd3dDevice->SetStreamSource( 0, pBuf, nOffs, m_VertexSize[src->m_vertexformat]); h = m_pd3dDevice->SetIndices(ibuf); int NumVerts = src->m_NumVerts; if (vert_stop) NumVerts = vert_stop; switch(prmode) { case R_PRIMV_TRIANGLES: h = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,NumVerts,offsindex,numindices/3); m_nPolygons+=numindices/3; break; case R_PRIMV_TRIANGLE_STRIP: h = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,0,NumVerts,offsindex,numindices-2); m_nPolygons+=numindices-2; break; case R_PRIMV_MULTI_GROUPS: { if (mi) { int offs = mi->nFirstIndexId; int nGroups = mi->m_dwNumSections; SPrimitiveGroup *gr = mi->m_pPrimitiveGroups; if (gr) { for (int i=0; itype) { case PT_STRIP: if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, mi->nNumVerts, g->offsIndex+offs, g->numIndices - 2))) { Error("CD3D9Renderer::DrawBuffer: DrawIndexedPrimitive error", h); return; } m_nPolygons += (g->numIndices - 2); break; case PT_LIST: if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mi->nNumVerts, g->offsIndex+offs, g->numIndices / 3))) { Error("CD3D9Renderer::DrawBuffer: DrawIndexedPrimitive error", h); return; } m_nPolygons += (g->numIndices / 3); break; case PT_FAN: if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, 0, 0, mi->nNumVerts, g->offsIndex+offs, g->numIndices - 2))) { Error("CD3D9Renderer::DrawBuffer: DrawIndexedPrimitive error", h); return; } m_nPolygons += (g->numIndices - 2); break; } } } } } break; } }