void EndStroke() { if (eCurrentShape != Entity.Null) { DynamicMeshData dmd = EntityManager.GetComponentData <DynamicMeshData>(eCurrentShape); dmd.Dirty = true; dmd.UseDynamicGPUBuffer = false; EntityManager.SetComponentData(eCurrentShape, dmd); //EntityManager.RemoveComponent<GizmoNormalsAndTangents>(eCurrentShape); //EntityManager.RemoveComponent<GizmoObjectBoundingBox>(eCurrentShape); strokeStack.Add(eCurrentShape); } eCurrentShape = Entity.Null; drawList.Clear(); }
void AddMeshRendererComponents(Entity e, int nVertex, int nIndex, NativeArray <SimpleVertex> vertices) { MeshRenderer mr = EntityManager.GetComponentData <MeshRenderer>(e); mr.startIndex = 0; mr.indexCount = nIndex; EntityManager.SetComponentData(e, mr); DynamicMeshData dmd = EntityManager.GetComponentData <DynamicMeshData>(e); dmd.Dirty = true; dmd.NumIndices = nIndex; dmd.NumVertices = nVertex; MeshBounds mb = default; mb.Bounds = MeshHelper.ComputeBounds(vertices); EntityManager.SetComponentData <DynamicMeshData>(e, dmd); EntityManager.SetComponentData(e, mb); }
void ContinueStroke(float2 inputPos) { if (eCurrentShape == Entity.Null) { return; } float3 pos = s2w.InputPosToWorldSpacePos(inputPos, 4.0f); drawList.Add(pos); var resampleList = MeshHelper.ResampleCatmullRom(drawList, .075f, false, Allocator.TempJob); if (resampleList.Length >= 3) { // replace the existing CPU mesh, invalidate content var iBuffer = EntityManager.GetBuffer <DynamicIndex>(eCurrentShape); var vBuffer = EntityManager.GetBuffer <DynamicLitVertex>(eCurrentShape); const int nSegments = 9; int ni = MeshHelper.ExtrudedLineMeshRequiredIndices(resampleList.Length, nSegments); int nv = MeshHelper.ExtrudedLineMeshRequiredVertices(resampleList.Length, nSegments); if (ni <= iBuffer.Capacity && nv <= vBuffer.Capacity) { vBuffer.ResizeUninitialized(nv); iBuffer.ResizeUninitialized(ni); MeshHelper.SmoothCurve(resampleList); MeshHelper.SmoothCurve(resampleList); MeshHelper.FillExtrudedLineCircle( vBuffer.AsNativeArray().Reinterpret <DynamicLitVertex, LitVertex>(), iBuffer.AsNativeArray().Reinterpret <DynamicIndex, ushort>(), drawSize, drawSize, .5f, resampleList, nSegments, false); MeshHelper.SetAlbedoColor( vBuffer.AsNativeArray().Reinterpret <DynamicLitVertex, LitVertex>(), new float4(drawColor, 1)); DynamicMeshData dmd = EntityManager.GetComponentData <DynamicMeshData>(eCurrentShape); dmd.Dirty = true; dmd.NumIndices = iBuffer.Length; dmd.NumVertices = vBuffer.Length; MeshBounds mb; mb.Bounds = MeshHelper.ComputeBounds(vBuffer.AsNativeArray().Reinterpret <DynamicLitVertex, LitVertex>()); EntityManager.SetComponentData <DynamicMeshData>(eCurrentShape, dmd); EntityManager.SetComponentData(eCurrentShape, mb); EntityManager.SetComponentData <Translation>(eCurrentShape, new Translation { Value = new float3(0) }); EntityManager.SetComponentData <Rotation>(eCurrentShape, new Rotation { Value = quaternion.identity }); EntityManager.SetComponentData <LocalToWorld>(eCurrentShape, new LocalToWorld { Value = float4x4.identity }); // have to update the index count of the submesh var mr = EntityManager.GetComponentData <MeshRenderer>(eCurrentShape); mr.indexCount = dmd.NumIndices; mr.material = eCurrentMaterial; EntityManager.SetComponentData(eCurrentShape, mr); if (EntityManager.HasComponent <DemoSpinner>(eCurrentShape)) { EntityManager.RemoveComponent <DemoSpinner>(eCurrentShape); } } else { Debug.Log("Stroke is too long."); } } resampleList.Dispose(); }
void BeginStroke(float2 inputPos) { if (eCurrentShape != Entity.Null) { EndStroke(); } float3 pos = s2w.InputPosToWorldSpacePos(inputPos, 4.0f); // start a new shape eCurrentShape = EntityManager.CreateEntity(); EntityManager.AddBuffer <DynamicLitVertex>(eCurrentShape); EntityManager.AddBuffer <DynamicIndex>(eCurrentShape); var iBuffer = EntityManager.GetBuffer <DynamicIndex>(eCurrentShape); var vBuffer = EntityManager.GetBuffer <DynamicLitVertex>(eCurrentShape); int tess = 65; vBuffer.Capacity = 0x10000; vBuffer.ResizeUninitialized(tess * tess); iBuffer.Capacity = 0x60000; iBuffer.ResizeUninitialized((tess - 1) * (tess - 1) * 6); DynamicMeshData dmd = new DynamicMeshData { Dirty = true, IndexCapacity = iBuffer.Capacity, VertexCapacity = vBuffer.Capacity, NumIndices = iBuffer.Length, NumVertices = vBuffer.Length, UseDynamicGPUBuffer = true }; MeshBounds mb; MeshHelper.CreateSuperEllipsoid(new float3(drawSize * 2.0f), vBuffer.AsNativeArray().Reinterpret <DynamicLitVertex, LitVertex>(), iBuffer.AsNativeArray().Reinterpret <DynamicIndex, ushort>(), random.NextFloat(0.04f, 3.0f), random.NextFloat(0.04f, 3.0f), tess, tess, out mb.Bounds); // start with a dot.. box MeshHelper.SetAlbedoColor( vBuffer.AsNativeArray().Reinterpret <DynamicLitVertex, LitVertex>(), new float4(drawColor, 1)); EntityManager.AddComponentData <DynamicMeshData>(eCurrentShape, dmd); EntityManager.AddComponentData <MeshRenderer>(eCurrentShape, new MeshRenderer { mesh = eCurrentShape, material = eCurrentMaterial, startIndex = 0, indexCount = dmd.NumIndices // because mesh renderers can render only parts of a mesh (sub-mesh) we need to also update the count here }); EntityManager.AddComponentData(eCurrentShape, new LitMeshRenderer()); EntityManager.AddComponentData(eCurrentShape, mb); EntityManager.AddComponentData <Translation>(eCurrentShape, new Translation { Value = pos }); EntityManager.AddComponentData <Rotation>(eCurrentShape, new Rotation { Value = quaternion.identity }); EntityManager.AddComponentData <LocalToWorld>(eCurrentShape, new LocalToWorld { Value = float4x4.Translate(pos) }); EntityManager.AddComponentData(eCurrentShape, new DemoSpinner { spin = math.normalize(new quaternion(new float4(random.NextFloat3Direction(), 1))) }); //EntityManager.AddComponentData(eCurrentShape, new GizmoNormalsAndTangents { width = 2.0f, length = .1f }); //EntityManager.AddComponentData(eCurrentShape, new GizmoObjectBoundingBox { color = new float4(0,0,0,1), width=4.0f }); //EntityManager.AddComponentData(eCurrentShape, new GizmoBoundingSphere { subdiv=32, width=4.0f }); // start shaper drawList.Clear(); drawList.Add(pos); }
protected override unsafe void OnUpdate() { CompleteDependency(); // If someone is just creating text, we'll take care of the material and mesh // TODO -- we really need an efficient way to one-step transform an entity into // the shape that we need Entities .WithAll <TextRendererString>() .WithNone <MeshRenderer, DynamicMeshData>() .WithNone <MeshBounds, DynamicSimpleVertex, DynamicIndex>() .WithStructuralChanges() .ForEach((ref Entity entity, in TextRenderer font) => { // will fill in startIndex/indexCount later if (!EntityManager.HasComponent <MeshRenderer>(entity)) { EntityManager.AddComponentData(entity, new MeshRenderer { mesh = entity, material = font.FontMaterial, startIndex = 0, indexCount = 0 }); } // may as well, these are likely not there EntityManager.AddComponent <DynamicMeshData>(entity); EntityManager.AddComponent <MeshBounds>(entity); EntityManager.AddBuffer <DynamicSimpleVertex>(entity); EntityManager.AddBuffer <DynamicIndex>(entity); // for new things force the update EntityManager.AddComponent <TextRendererNeedsUpdate>(entity); }) .Run(); var textMaterialFromEntity = GetComponentDataFromEntity <BitmapFontMaterial>(); var textSDFMaterialFromEntity = GetComponentDataFromEntity <SDFFontMaterial>(); var dsvFromEntity = GetBufferFromEntity <DynamicSimpleVertex>(); var diFromEntity = GetBufferFromEntity <DynamicIndex>(); var srgbColors = GetSingleton <DisplayInfo>().colorSpace == ColorSpace.Gamma; // we're going to do fine-grained change tracking, because mesh generation is costly since it'll // cause a re-upload to graphics var ecb = new EntityCommandBuffer(Allocator.TempJob); Entities .WithAll <TextRendererNeedsUpdate>() .ForEach((Entity entity, ref MeshRenderer meshRenderer, ref TextRenderer fontRef, ref DynamicBuffer <TextRendererString> text) => { if (fontRef.FontMaterial == Entity.Null) { return; } //Console.WriteLine($"[{entity.Index}:{entity.Version}] match"); // TODO support static text meshes too. For our initial impl the mesh is always dynamic var meshEntity = meshRenderer.mesh; // This meshEntity will often be the same as the renderer entity (e.g. if setup was done // as above, next to TextRendererString component). But it doesn't need to be; there could be // a shared mesh. In that case though, this code will end up modifying every text string // that uses that mesh, which is probably not what's desired! // We also don't really need a dozen meshes for the identical string/font. All of this can // be significantly optimized. var vertexBuffer = dsvFromEntity[meshEntity]; var indexBuffer = diFromEntity[meshEntity]; var vertexColor = srgbColors ? Color.LinearToSRGB(fontRef.MeshColor.AsFloat4()) : fontRef.MeshColor.AsFloat4(); //string s = new String((char*)UnsafeUtility.AddressOf(ref text.ElementAt(0)), 0, text.Length); //Console.WriteLine($"[{entity.Index}:{entity.Version}] Generating mesh for {s}"); AABB bounds; BlobAssetReference <FontData> fontData; if (textMaterialFromEntity.HasComponent(fontRef.FontMaterial)) { var material = textMaterialFromEntity[fontRef.FontMaterial]; fontData = material.FontData; } else if (textSDFMaterialFromEntity.HasComponent(fontRef.FontMaterial)) { var material = textSDFMaterialFromEntity[fontRef.FontMaterial]; fontData = material.FontData; } else { throw new InvalidOperationException(); } TextLayout.LayoutString((char *)text.GetUnsafePtr(), text.Length, fontRef.Size, fontRef.HorizontalAlignment, vertexColor, ref fontData.Value, vertexBuffer, indexBuffer, out bounds); meshRenderer.startIndex = 0; meshRenderer.indexCount = indexBuffer.Length; var dmd = new DynamicMeshData { Dirty = true, IndexCapacity = indexBuffer.Capacity, VertexCapacity = vertexBuffer.Capacity, NumIndices = indexBuffer.Length, NumVertices = vertexBuffer.Length, UseDynamicGPUBuffer = true }; ecb.SetComponent(meshEntity, dmd); ecb.SetComponent(meshEntity, new MeshBounds { Bounds = bounds }); ecb.RemoveComponent <TextRendererNeedsUpdate>(entity); }) .Run(); ecb.Playback(EntityManager); ecb.Dispose(); }
void CreateSimpleRenderer(Entity eMesh, quaternion rot, float3 pos, float3 scale) { EntityManager.AddComponentData(eMesh, new MeshRenderer // renderer -> maps to shader to use { material = eMesh, mesh = eMesh, startIndex = 0, indexCount = 0 }); EntityManager.AddComponentData(eMesh, new LocalToWorld { Value = float4x4.identity }); EntityManager.AddComponentData(eMesh, new Translation { Value = pos }); EntityManager.AddComponentData(eMesh, new Rotation { Value = rot }); if (scale.x != scale.y || scale.y != scale.z) { EntityManager.AddComponentData(eMesh, new NonUniformScale { Value = scale }); } else if (scale.x != 1.0f) { EntityManager.AddComponentData(eMesh, new Scale { Value = scale.x }); } EntityManager.AddComponentData(eMesh, new WorldBounds()); EntityManager.AddBuffer <DynamicSimpleVertex>(eMesh); EntityManager.AddBuffer <DynamicIndex>(eMesh); var iBuffer = EntityManager.GetBuffer <DynamicIndex>(eMesh); var vBuffer = EntityManager.GetBuffer <DynamicSimpleVertex>(eMesh); vBuffer.Capacity = kMaxVertex; vBuffer.ResizeUninitialized(kMaxVertex); iBuffer.Capacity = kMaxIndex; iBuffer.ResizeUninitialized(kMaxIndex); DynamicMeshData dmd = new DynamicMeshData { Dirty = true, IndexCapacity = iBuffer.Capacity, VertexCapacity = vBuffer.Capacity, NumIndices = iBuffer.Length, NumVertices = vBuffer.Length, UseDynamicGPUBuffer = false }; EntityManager.AddComponentData <DynamicMeshData>(eMesh, dmd); }