/// <summary> /// Cleans up the rendering view of the models. /// </summary> /// <param name="frustumCuller">The area where models can be viewed from the camera.</param> /// <param name="frustumCullMode">The mode of the culling.</param> public void FrustumCull(FrustumCulling frustumCuller, EnumFrustumCullMode frustumCullMode) { indicesGroupsCount = 0; int multiplier = (IntPtr.Size == 8) ? 2 : 1; RenderedTriangles = 0; AllocatedTris = 0; for (int i = 0; i < poolLocations.Count; i++) { ModelDataPoolLocation location = poolLocations[i]; int size = location.IndicesEnd - location.IndicesStart; if (location.IsVisible(frustumCullMode, frustumCuller)) { indicesStartsByte[indicesGroupsCount * multiplier] = location.IndicesStart * 4; // Offset in bytes, not ints indicesSizes[indicesGroupsCount] = size; RenderedTriangles += size / 3; indicesGroupsCount++; } AllocatedTris += size / 3; } }
/// <summary> /// Attempts to remove the model from the pool if the model exists. Will throw an invalid call or an InvalidOperationException if used improperly. /// </summary> /// <param name="location">The location of the model data.</param> public void RemoveLocation(ModelDataPoolLocation location) { if (location.PoolId != poolId) { throw new Exception("invalid call"); } if (!poolLocations.Remove(location)) { throw new InvalidOperationException("Tried to remove mesh that does not exist. This shouldn't happen"); } // Last location? if (poolLocations.Count == 0) { indicesPosition = 0; verticesPosition = 0; } else { // Location at the end of the buffer? if (location.IndicesEnd == indicesPosition && location.VerticesEnd == verticesPosition) { indicesPosition = poolLocations[poolLocations.Count - 1].IndicesEnd; verticesPosition = poolLocations[poolLocations.Count - 1].VerticesEnd; } } CalcFragmentation(); }
/// <summary> /// Attempts to add the new model. /// </summary> /// <param name="capi">The core client API</param> /// <param name="modeldata">The model to add</param> /// <param name="modelOrigin">The origin point of the model.</param> /// <param name="frustumCullSphere">The culling sphere.</param> /// <returns>The location of the model (and the data) in the pool.</returns> public ModelDataPoolLocation TryAdd(ICoreClientAPI capi, MeshData modeldata, Vec3i modelOrigin, Sphere frustumCullSphere) { if (poolLocations.Count >= MaxPartsPerPool) { return(null); } // Can't add a model data to far away from our baseposition, otherwise our floating point positions // become too inaccurate if (poolOrigin != null && modelOrigin.SquareDistanceTo(poolOrigin) > 5000 * 5000) { return(null); } if (CurrentFragmentation > 0.05f) { ModelDataPoolLocation location = TrySqueezeInbetween(capi, modeldata, modelOrigin, frustumCullSphere); if (location != null) { return(location); } } return(TryAppend(capi, modeldata, modelOrigin, frustumCullSphere)); }
ModelDataPoolLocation TryAppend(ICoreClientAPI capi, MeshData modeldata, Vec3i modelOrigin, Sphere frustumCullSphere) { if (modeldata.IndicesCount + indicesPosition >= IndicesPoolSize || modeldata.VerticesCount + verticesPosition >= VerticesPoolSize) { return(null); } ModelDataPoolLocation location = InsertAt(capi, modeldata, modelOrigin, frustumCullSphere, indicesPosition, verticesPosition, -1); indicesPosition += modeldata.IndicesCount; verticesPosition += modeldata.VerticesCount; return(location); }
ModelDataPoolLocation TrySqueezeInbetween(ICoreClientAPI capi, MeshData modeldata, Vec3i modelOrigin, Sphere frustumCullSphere) { int curVertexPos = 0; int curIndexPos = 0; for (int i = 0; i < poolLocations.Count; i++) { ModelDataPoolLocation location = poolLocations[i]; if (location.IndicesStart - curIndexPos > modeldata.IndicesCount && location.VerticesStart - curVertexPos > modeldata.VerticesCount) { return(InsertAt(capi, modeldata, modelOrigin, frustumCullSphere, curIndexPos, curVertexPos, i)); } curIndexPos = location.IndicesEnd + 1; curVertexPos = location.VerticesEnd + 1; } return(null); }
/// <summary> /// Adds a model to the mesh pool. /// </summary> /// <param name="modeldata">The model data</param> /// <param name="modelOrigin">The origin point of the Model</param> /// <param name="frustumCullSphere">The culling sphere.</param> /// <returns>The location identifier for the pooled model.</returns> public ModelDataPoolLocation AddModel(MeshData modeldata, Vec3i modelOrigin, Sphere frustumCullSphere) { ModelDataPoolLocation location = null; for (int i = 0; i < pools.Count; i++) { location = pools[i].TryAdd(capi, modeldata, modelOrigin, frustumCullSphere); if (location != null) { break; } } if (location == null) { int vertexSize = Math.Max(modeldata.VerticesCount + 1, defaultVertexPoolSize); int indexSize = Math.Max(modeldata.IndicesCount + 1, defaultIndexPoolSize); if (vertexSize > defaultIndexPoolSize) { capi.World.Logger.Warning("Chunk (or some other mesh source at origin: {0}) exceeds default geometric complexity maximum of {1} vertices and {2} indices. You must be loading some very complex objects (#v = {3}, #i = {4}). Adjusted Pool size accordingly.", modelOrigin, defaultVertexPoolSize, defaultIndexPoolSize, modeldata.VerticesCount, modeldata.IndicesCount); } MeshDataPool pool = MeshDataPool.AllocateNewPool(capi, vertexSize, indexSize, maxPartsPerPool, customFloats, customShorts, customBytes, customInts); pool.poolOrigin = modelOrigin; masterPool.AddModelDataPool(pool); pools.Add(pool); location = pool.TryAdd(capi, modeldata, modelOrigin, frustumCullSphere); } if (location == null) { capi.World.Logger.Fatal("Can't add modeldata (probably a tesselated chunk @{0}) to the model data pool list, it exceeds the size of a single empty pool of {1} vertices and {2} indices. You must be loading some very complex objects (#v = {3}, #i = {4}). Try increasing MaxVertexSize and MaxIndexSize. The whole chunk will be invisible.", modelOrigin, defaultVertexPoolSize, defaultIndexPoolSize, modeldata.VerticesCount, modeldata.IndicesCount); //location = new ModelDataPoolLocation() { frustumCullSphere = frustumCullSphere }; //pools[0].poolLocations.Add(location); } return(location); }
ModelDataPoolLocation InsertAt(ICoreClientAPI capi, MeshData modeldata, Vec3i modelOrigin, Sphere frustumCullSphere, int indexPosition, int vertexPosition, int listPosition) { // Shift the indices numbers accordingly for (int i = 0; i < modeldata.IndicesCount; i++) { modeldata.Indices[i] += vertexPosition; } // Relative offset to our pool origin if (poolOrigin != null) { int dx = modelOrigin.X - this.poolOrigin.X; int dy = modelOrigin.Y - this.poolOrigin.Y; int dz = modelOrigin.Z - this.poolOrigin.Z; for (int i = 0; i < modeldata.VerticesCount; i++) { modeldata.xyz[3 * i] += dx; modeldata.xyz[3 * i + 1] += dy; modeldata.xyz[3 * i + 2] += dz; } } // Shift position to the end of the used buffers memory modeldata.XyzOffset = vertexPosition * MeshData.XyzSize; modeldata.NormalsOffset = vertexPosition * MeshData.NormalSize; modeldata.RgbaOffset = vertexPosition * MeshData.RgbaSize; modeldata.Rgba2Offset = vertexPosition * MeshData.RgbaSize; modeldata.UvOffset = vertexPosition * MeshData.UvSize; modeldata.FlagsOffset = vertexPosition * MeshData.FlagsSize; modeldata.IndicesOffset = indexPosition * MeshData.IndexSize; if (modeldata.CustomFloats != null) { modeldata.CustomFloats.BaseOffset = vertexPosition * modeldata.CustomFloats.InterleaveStride; } if (modeldata.CustomBytes != null) { modeldata.CustomBytes.BaseOffset = vertexPosition * modeldata.CustomBytes.InterleaveStride; } if (modeldata.CustomInts != null) { modeldata.CustomInts.BaseOffset = vertexPosition * modeldata.CustomInts.InterleaveStride; } // Load into graphics card capi.Render.UpdateMesh(modelRef, modeldata); // Assign a location to it ModelDataPoolLocation poolLocation = new ModelDataPoolLocation() { IndicesStart = indexPosition, IndicesEnd = indexPosition + modeldata.IndicesCount, VerticesStart = vertexPosition, VerticesEnd = vertexPosition + modeldata.VerticesCount, PoolId = poolId, FrustumCullSphere = frustumCullSphere }; // Maintain correct ordering if (listPosition != -1) { poolLocations.Insert(listPosition, poolLocation); } else { poolLocations.Add(poolLocation); } CalcFragmentation(); return(poolLocation); }