void CMeshConverter::OptimiseGraphicsObject(void) { int i; int j; ID3DXMesh* pXMesh; CGraphicsPrimitive* pcPrimitive; CVertexBufferExtended* psVertexBuffer; void* pvDestIndexBuffer; void* pvDestVertexBuffer; void* pvSrcIndexBuffer; void* pvSrcVertexBuffer; int iVertSize; DWORD* pvAdjacency; int iPrimitiveStart; int iOldVertSize; int iNumIndices; int iOldVertexBufferIndex; int iNumTriangles; void* pvDestBaseIndexBuffer; SIndexBuffer* psIndexBuffer; DWORD iMeshOptions; mpcGraphicsObject->SortPrimitives(); mpcGraphicsObject->Lock(); psIndexBuffer = mpcGraphicsObject->GetIndexBuffer(); iVertSize = 0; iNumIndices = 0; iOldVertexBufferIndex = 0; iNumTriangles = 0; iOldVertSize = 0; iMeshOptions = D3DXMESH_SYSTEMMEM; SetFlag((int*)&iMeshOptions, D3DXMESH_32BIT, psIndexBuffer->iIndexSize == 4); for (i = 0; i < mpcGraphicsObject->GetNumPrimitives(); i++) { pcPrimitive = mpcGraphicsObject->GetPrimitive(i); psVertexBuffer = mpcGraphicsObject->GetVertexBufferForIndex(pcPrimitive->miVertexBufferIndex); if (iOldVertSize != psVertexBuffer->iVertexSize) { if (iNumIndices != 0) { gcD3D.CreateMesh(iNumTriangles, iNumIndices, iMeshOptions, psVertexBuffer->iVertexFormat, &pXMesh); iVertSize = pXMesh->GetNumBytesPerVertex(); pXMesh->LockIndexBuffer(D3DLOCK_NO_DIRTY_UPDATE, &pvDestBaseIndexBuffer); pXMesh->LockVertexBuffer(D3DLOCK_NO_DIRTY_UPDATE, &pvDestVertexBuffer); psVertexBuffer = mpcGraphicsObject->GetVertexBufferForIndex(iOldVertexBufferIndex); pvSrcVertexBuffer = psVertexBuffer->pvLockedBuffer; if (iVertSize != psVertexBuffer->iVertexSize) { gcLogger.Error("D3DX vertex size differs from expected size"); break; } memcpy(pvDestVertexBuffer, pvSrcVertexBuffer, psVertexBuffer->iVertexSize * psVertexBuffer->iNumVerticies); pvDestIndexBuffer = pvDestBaseIndexBuffer; for (j = iPrimitiveStart; j < i; j++) { pcPrimitive = mpcGraphicsObject->GetPrimitive(j); pvSrcIndexBuffer = RemapSinglePointer(psIndexBuffer->pvLockedBuffer, 2 * pcPrimitive->miStartIndex); memcpy(pvDestIndexBuffer, pvSrcIndexBuffer, psIndexBuffer->iIndexSize * pcPrimitive->miNumVertices); pvDestIndexBuffer = RemapSinglePointer(pvDestIndexBuffer, pcPrimitive->miNumVertices); } pvAdjacency = (DWORD*)malloc(pcPrimitive->miNumPrimitives * 3 * sizeof(DWORD)); pXMesh->GenerateAdjacency(0.0f, pvAdjacency); pXMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_DONOTSPLIT, pvAdjacency, NULL, NULL, NULL); free(pvAdjacency); pvDestIndexBuffer = pvDestBaseIndexBuffer; for (j = iPrimitiveStart; j < i; j++) { pcPrimitive = mpcGraphicsObject->GetPrimitive(j); pvSrcIndexBuffer = RemapSinglePointer(psIndexBuffer->pvLockedBuffer, 2 * pcPrimitive->miStartIndex); memcpy(pvSrcIndexBuffer, pvDestIndexBuffer, psIndexBuffer->iIndexSize * pcPrimitive->miNumVertices); pvDestIndexBuffer = RemapSinglePointer(pvDestIndexBuffer, pcPrimitive->miNumVertices); } memcpy(pvSrcVertexBuffer, pvDestVertexBuffer, psVertexBuffer->iVertexSize * psVertexBuffer->iNumVerticies); pXMesh->UnlockIndexBuffer(); pXMesh->UnlockVertexBuffer(); pXMesh->Release(); } iPrimitiveStart = i; iNumIndices = 0; iOldVertexBufferIndex = pcPrimitive->miVertexBufferIndex; } else { iNumIndices += pcPrimitive->miNumVertices; iNumTriangles += pcPrimitive->miNumPrimitives; if (iOldVertexBufferIndex != pcPrimitive->miVertexBufferIndex) { gcUserError.Set("Primitive vertex buffer index is F****D!"); break; } } } mpcGraphicsObject->Unlock(); }
void LODManager::Render(IDirect3DDevice9 *D3DDevice) { const char *meshpath = (lod == GRID_FARNEAR ? "landscape\\lod\\farnear\\" : (lod == GRID_FARFAR ? "landscape\\lod\\farfar\\" : "landscape\\lod\\farinf\\")); const char *textpath = (lod == GRID_FARNEAR ? "landscapelod\\generated\\farnear\\" : (lod == GRID_FARFAR ? "landscapelod\\generated\\farfar\\" : "landscapelod\\generated\\farinf\\")); int nativeminx = (GRID_SIZE * 32) + (Constants.Coordinates.x - GridDistantCount.Get()); int nativeminy = (GRID_SIZE * 32) + (Constants.Coordinates.y - GridDistantCount.Get()); int nativemaxx = (GRID_SIZE * 32) + (Constants.Coordinates.x + GridDistantCount.Get()); int nativemaxy = (GRID_SIZE * 32) + (Constants.Coordinates.y + GridDistantCount.Get()); /* y-axis has flipped rounding */ nativeminx = (nativeminx / 32) - GRID_SIZE; nativeminy = (nativeminy / 32) - GRID_SIZE + 0; nativemaxx = (nativemaxx / 32) - GRID_SIZE; nativemaxy = (nativemaxy / 32) - GRID_SIZE + 0; int gridx = Constants.Coordinates.x / 32; int gridy = Constants.Coordinates.y / 32; for (int x = (gridx - extend); x <= (gridx + extend); x++) for (int y = (gridy - extend); y <= (gridy + extend); y++) { /* TODO: try radius, seems it's not a box */ /* leave out Oblivion's native tiles */ if ((x >= nativeminx) && (x <= nativemaxx) && (y >= nativeminy) && (y <= nativemaxy)) continue; /* leave out other LOD's inner tiles */ if ((abs(gridx - x) <= inner) && (abs(gridy - y) <= inner)) continue; /* where are we? */ const float TileOffset[4] = {x * TILE_DIM, y * TILE_DIM, 0, 0}; /* filter outside-array coordinates */ if (((GRID_OFFSET + y) >= 0) && ((GRID_OFFSET + y) < GRID_SIZE) && ((GRID_OFFSET + x) >= 0) && ((GRID_OFFSET + x) < GRID_SIZE)) { /* never seen, never attempted */ if (MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) { /* TODO: 32 means 32x32 cells, in theory that can be different as well */ char buf[256]; sprintf(buf, "%02d.%02d.%02d.32", WorldSpace, x * 32, y * 32); char pth[256]; strcpy(pth, meshpath); strcat(pth, buf); strcat(pth, ".x"); /* no textures without mesh, but we can render texture-free */ if ((MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = MeshManager::GetSingleton()->LoadPrivateMesh(pth, MR_REGULAR)) != -1) { if (ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) { strcpy(pth, textpath); strcat(pth, buf); strcat(pth, ".dds"); ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->LoadPrivateTexture(pth, TR_PLANAR); } if (NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) { strcpy(pth, textpath); strcat(pth, buf); strcat(pth, "_fn.dds"); NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->LoadPrivateTexture(pth, TR_PLANAR); } /* put the addresses */ ManagedMeshRecord *mesh = Meshes [lod][GRID_OFFSET + y][GRID_OFFSET + x] = MeshManager::GetSingleton()->GetMesh (MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]); ManagedTextureRecord *colr = Colors [lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->GetTexture(ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]); ManagedTextureRecord *norm = Normals[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->GetTexture(NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]); /* failure to load all resources */ if (!mesh || !colr || !norm) { if (mesh) mesh->Release(); if (colr) colr->Release(); if (norm) norm->Release(); MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1; ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1; NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1; continue; } #if defined(OBGE_GAMMACORRECTION) /* remember DeGamma for this kind of texture */ static const bool PotDeGamma = true; colr->GetTexture()->SetPrivateData(GammaGUID, &PotDeGamma, sizeof(PotDeGamma), 0); #endif } } /* get the addresses */ ManagedMeshRecord *mesh = Meshes [lod][GRID_OFFSET + y][GRID_OFFSET + x]; ManagedTextureRecord *colr = Colors [lod][GRID_OFFSET + y][GRID_OFFSET + x]; ManagedTextureRecord *norm = Normals[lod][GRID_OFFSET + y][GRID_OFFSET + x]; ID3DXMesh *m; if (mesh && (m = (ID3DXMesh *)mesh->GetMesh())) { #if 0 DWORD FVF = m->GetFVF(); DWORD size = m->GetNumBytesPerVertex(); DWORD numf = m->GetNumFaces(); DWORD numv = m->GetNumVertices(); IDirect3DIndexBuffer9 *pIB; m->GetIndexBuffer(&pIB); IDirect3DVertexBuffer9 *pVB; m->GetVertexBuffer(&pVB); D3DDevice->SetStreamSource(0, pVB, 0, size); D3DDevice->SetFVF(FVF); D3DDevice->SetTexture(0, colr->GetTexture()); D3DDevice->SetTexture(1, norm->GetTexture()); D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numv, 0, numf); #endif D3DDevice->SetTexture(0, colr ? colr->GetTexture() : NULL); D3DDevice->SetTexture(1, norm ? norm->GetTexture() : NULL); D3DDevice->SetVertexShader(vShader[lod]); D3DDevice->SetPixelShader (pShader[lod]); D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1); m->DrawSubset(0); } } /* water-planes */ D3DDevice->SetVertexShader(vShaderW); D3DDevice->SetPixelShader (pShaderW); D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1); D3DDevice->SetStreamSource(0, WaterVertex, 0, sizeof(WaterTile)); D3DDevice->SetFVF(WATERTILEFORMAT); D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } const float TileOffset[4] = {0, 0, 0, 1}; /* infini-plane */ D3DDevice->SetVertexShader(vShaderW); D3DDevice->SetPixelShader (pShaderW); D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1); D3DDevice->SetStreamSource(0, InfiniteVertex, 0, sizeof(WaterTile)); D3DDevice->SetFVF(WATERTILEFORMAT); D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); }
void Scene::LoadFromXFile(string file, IDirect3DDevice9 *device) { assert(device); ID3DXBuffer *material = nullptr; DWORD num_material = 0; ID3DXMesh *mesh = nullptr; HRESULT res = D3DXLoadMeshFromX(file.c_str(), // pFilename D3DXMESH_DYNAMIC, // Options device, // pD3DDevice nullptr, // ppAdjacency &material, // ppMaterials nullptr, // ppEffectInstances &num_material, // pNumMaterials &mesh); // ppMesh if (FAILED(res)) { Logger::GtLogError("load mesh from X file failed:%s", file.c_str()); return; } assert(num_material == 1); D3DXMATERIAL *mat = static_cast<D3DXMATERIAL *>(material->GetBufferPointer()); material_.ambient.r = mat->MatD3D.Ambient.r; material_.ambient.g = mat->MatD3D.Ambient.g; material_.ambient.b = mat->MatD3D.Ambient.b; material_.ambient.a = mat->MatD3D.Ambient.a; material_.diffuse.r = mat->MatD3D.Diffuse.r; material_.diffuse.g = mat->MatD3D.Diffuse.g; material_.diffuse.b = mat->MatD3D.Diffuse.b; material_.diffuse.a = mat->MatD3D.Diffuse.a; material_.specular.r = mat->MatD3D.Specular.r; material_.specular.g = mat->MatD3D.Specular.g; material_.specular.b = mat->MatD3D.Specular.b; material_.specular.a = mat->MatD3D.Specular.a; material_.emissive.r = mat->MatD3D.Emissive.r; material_.emissive.g = mat->MatD3D.Emissive.g; material_.emissive.b = mat->MatD3D.Emissive.b; material_.emissive.a = mat->MatD3D.Emissive.a; material_.power = mat->MatD3D.Power; bool ret = texture_.Load(mat->pTextureFilename, device); assert(ret); material->Release(); DWORD num_vertex = mesh->GetNumVertices(); IDirect3DVertexBuffer9 *vertex_buffer = nullptr; res = mesh->GetVertexBuffer(&vertex_buffer); assert(SUCCEEDED(res)); uint8 *vertex_data = nullptr; res = vertex_buffer->Lock(0, 0, reinterpret_cast<void **>(&vertex_data), D3DLOCK_READONLY); assert(SUCCEEDED(res)); D3DVERTEXELEMENT9 vertex_elements[MAX_FVF_DECL_SIZE] = {0}; res = mesh->GetDeclaration(vertex_elements); assert(SUCCEEDED(res)); int offset_pos = 0; int offset_nor = 0; int offset_tex = 0; int vertex_size = mesh->GetNumBytesPerVertex(); for (int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { if (vertex_elements[i].Type == D3DDECLTYPE_UNUSED) break; if (vertex_elements[i].Usage == D3DDECLUSAGE_POSITION) { offset_pos = vertex_elements[i].Offset; } if (vertex_elements[i].Usage == D3DDECLUSAGE_NORMAL) { offset_nor = vertex_elements[i].Offset; } if (vertex_elements[i].Usage == D3DDECLUSAGE_TEXCOORD) { offset_tex = vertex_elements[i].Offset; } } Primitive verteies(num_vertex, nullptr, nullptr); for (int i = 0; i < num_vertex; ++i) { verteies.positions[i] = *reinterpret_cast<Vector3 *>(vertex_data + vertex_size * i + offset_pos); verteies.positions[i].Display(); verteies.normals[i] = *reinterpret_cast<Vector3 *>(vertex_data + vertex_size * i + offset_nor); verteies.normals[i].Display(); verteies.uvs[i] = *reinterpret_cast<Vector2 *>(vertex_data + vertex_size * i + offset_tex); verteies.uvs[i].Display(); } primitive_ = verteies; vertex_buffer->Unlock(); vertex_buffer->Release(); }