public void CallBeginOperation(AtlasEntity entity, int id) { Entity = entity; Id = id; Begin(entity, id); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { if (arguments.Count < 1) { Chat.SendLocalMessage("Voice Chat", Function.Call <float>(Hash.NETWORK_GET_TALKER_PROXIMITY).ToString(CultureInfo.InvariantCulture), Color.FromArgb(0, 0, 255)); return; } float range; try { range = float.Parse(arguments.ElementAt(0)); } catch (Exception) { range = 0f; } Function.Call(Hash.NETWORK_CLEAR_VOICE_CHANNEL); Function.Call(Hash.NETWORK_SET_TALKER_PROXIMITY, range); Chat.SendLocalMessage("Voice Chat", $"Ă„ndrade voicechat proximity till {range}", Color.FromArgb(0, 0, 255)); }
public async void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { try { if (arguments.Count <= 0) { return; } var model = new Model(API.GetHashKey(arguments.ElementAt(0))); if (!model.IsValid || !model.IsVehicle) { return; } var position = entity.Position; var vehicle = await World.CreateVehicle(model, position.AsVector(), position.Heading); entity.Task.WarpIntoVehicle(vehicle, VehicleSeat.Driver); } catch (Exception) { // Ignored } }
protected override void Begin(AtlasEntity entity, int id) { if (!API.NetworkGetEntityIsNetworked(id)) { API.NetworkRegisterEntityAsNetworked(id); } }
public static AtlasEntity GetEntity(int id) { var entity = new AtlasEntity(API.NetworkGetEntityFromNetworkId(id)); entity.InstallModule("Network", new EntityNetworkModule()); return(entity); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { var position = entity.Position; var title = arguments.Count > 1 ? string.Join(" ", arguments.Skip(1)) : "Position"; var log = $"[Developer] {title}: new Position({position.X}f, {position.Y}f, {position.Z}f, {position.Heading}f)"; Logger.Info(log); }
public async void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { if (arguments.Count < 2) { return; } await entity.Task.PlayAnimation(arguments[0], arguments[1], 8f, -8f, -1, AnimationFlags.None, 0); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { API.ClearPedTasksImmediately(entity.Id); API.ClearPedSecondaryTask(entity.Id); API.SetNuiFocus(false, false); World.GetAllProps().Where(self => self.IsAttachedTo(Entity.FromHandle(entity.Id))).ToList() .ForEach(self => self.Detach()); Chat.SendGlobalMessage("Reload", "Laddade om karaktären!", Color.FromArgb(255, 0, 0)); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { if (arguments.Count < 2) { Chat.SendLocalMessage(Title, Usage, Color.FromArgb(255, 0, 0)); return; } int balance; try { balance = Convert.ToInt32(arguments.ElementAt(1)); } catch (FormatException) { Chat.SendLocalMessage(Title, InvalidAmount, Color.FromArgb(255, 0, 0)); return; } switch (arguments.ElementAt(0).ToUpper()) { case "ADD": player.Character.Cash += balance; Chat.SendLocalMessage(Title, $"{CorrectedCash}{player.Character.Cash})", Color.FromArgb(255, 0, 0)); break; case "SET": player.Character.Cash = balance; Chat.SendLocalMessage(Title, $"{CorrectedCash}{player.Character.Cash})", Color.FromArgb(255, 0, 0)); break; case "REMOVE": player.Character.Cash -= balance; Chat.SendLocalMessage(Title, $"{CorrectedCash}{player.Character.Cash})", Color.FromArgb(255, 0, 0)); break; default: Chat.SendLocalMessage(Title, $"{NotFoundSubcommand}{arguments.ElementAt(0)}", Color.FromArgb(255, 0, 0)); break; } }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { var manager = ActionMessageManager.GetModule(); manager.Messages.Add(new ActionMessageManager.ActionMessage { Seed = Seed.Generate(), Sender = API.GetPlayerServerId(API.PlayerId()), Message = string.Join(" ", arguments) }); manager.Commit(); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { if (arguments.Count < 1) { Chat.SendLocalMessage(Title, Usage, Color.FromArgb(255, 0, 0)); return; } switch (arguments.ElementAt(0).ToUpper()) { case "SET": if (arguments.Count < 3) { Chat.SendLocalMessage(Title, Usage, Color.FromArgb(255, 0, 0)); return; } var jobName = arguments[1]; var jobRole = 0; try { jobRole = int.Parse(arguments[2]); } catch (Exception) { // Ignored } Enum.TryParse <Employment>(jobName, true, out var job); var character = Cache.Character; character.Metadata.Employment = job; character.Metadata.EmploymentRole = jobRole; Chat.SendLocalMessage(Title, $"Anställde {character.Fullname} hos {job.ToString()} - {jobRole}", Color.FromArgb(255, 0, 0)); break; default: Chat.SendLocalMessage(Title, $"Kunde inte hitta kommando: {arguments.ElementAt(0)}", Color.FromArgb(255, 0, 0)); break; } }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { var vehicle = entity.Vehicle; if (vehicle == null) { return; } vehicle.Wash(); vehicle.Repair(); vehicle.PlaceOnGround(); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { StyleManager.GetModule().OpenStyleChange(Cache.Character.Style, "General", 0, (type) => { if (type != 0) { return; } Logger.Info($"[Developer] {JsonConvert.SerializeObject(player.Character.Style)}"); }, "All"); }
public async void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { var waypoint = World.GetWaypointBlip(); if (waypoint == null) { return; } var position = waypoint.Position; position.Z = World.GetGroundHeight(position) + 1; await player.Entity.Teleport(position.ToPosition()); }
/// <summary>Removes a texture from the atlas.</summary> /// <param name="texture">The texture to remove.</param> public void Remove(AtlasEntity texture) { if (texture == null) { return; } AtlasLocation location = Get(texture.GetAtlasID()); if (location == null) { return; } // Make the location available: location.Deselect(); }
public AtlasLocation RequireImage(AtlasEntity image) { // Get the image from the global atlas stack. AtlasLocation location = AtlasStacks.Graphics.RequireImage(image); if (location == null) { // It's separate from the atlas. Too big to fit/ not worth being on an atlas. Isolate(); } else { location.UsageCount++; Include(); } return(location); }
/// <summary>Optimizes the atlas by removing all 'holes' (removed images) from the atlas. /// It reconstructs the whole atlas (only when there are actually holes), so this method should be considered expensive. /// This is only ever called when we fail to add something to the atlas; Theres no performace issues of a non-optimized atlas. /// Instead it just simply has very fragmented space available.</summary> public bool Optimize() { if (!CanOptimize) { // It'll do as it is. return(false); } // Make sure it's not called again: CanOptimize = false; OptimizeRequested = false; Dictionary <int, AtlasLocation> allImages = Stack.ActiveImages; // Clear the textures and add in the starting empty location. Reset(); // Next up, add them all back in, and that's it! // The optimizing comes from them trying to fit in the smallest possible gap they can when added. foreach (KeyValuePair <int, AtlasLocation> kvp in allImages) { AtlasLocation location = kvp.Value; if (location.Atlas == this) { AtlasEntity image = location.Image; int entityID = image.GetAtlasID(); int width; int height; image.GetDimensionsOnAtlas(out width, out height); Add(image, entityID, width, height); } } return(true); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { if (arguments.Count < 1) { return; } var argument = arguments[0]; foreach (var item in Items) { if (item.Key != argument.ToLower()) { continue; } ItemHelper.Give(InventoryManager.GetModule().GetContainer("pockets_inventory"), (InventoryItem)Activator.CreateInstance(item.Value)); Chat.SendLocalMessage("Föremål", $"Gav dig x1 utav `{item.Key}`...", Color.FromArgb(0, 255, 0)); break; } }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { if (arguments.Count < 1) { Chat.SendLocalMessage("Session", $"{Session.LastSession}", Color.FromArgb(0, 0, 255)); return; } int id; try { id = int.Parse(arguments.ElementAt(0)); } catch (Exception) { id = 0; } Session.Join(id); Chat.SendLocalMessage("Session", $"Anslöt till session #{id}", Color.FromArgb(0, 0, 255)); }
/// <summary>This texture has selected this location to fit into. This adds it to the atlas.</summary> /// <param name="texture">The texture that wants to go here.</param> /// <param name="width">The width of the texture in pixels.</param> /// <param name="height">The height of the texture in pixels.</param> public void Select(AtlasEntity image, int width, int height, int spacing) { // The given texture wants to go in this location. // Width and height are given for dynamic textures - textures who's pixels are actually written straight to the atlas. Empty = false; int spacedWidth = width + spacing; int spacedHeight = height + spacing; // Remove from empty queue: if (EmptyBefore == null) { Atlas.FirstEmpty = EmptyAfter; } else { EmptyBefore.EmptyAfter = EmptyAfter; } if (EmptyAfter == null) { Atlas.LastEmpty = EmptyBefore; } else { EmptyAfter.EmptyBefore = EmptyBefore; } int entityID = image.GetAtlasID(); if (AtlasID == entityID) { // This is a restore - we don't need to do anything else. return; } Image = image; AtlasID = entityID; // If it's not a perfect fit, generate new atlas locations to the right and above of this one. if (Atlas.Mode == AtlasingMode.SmallestSpace) { if (Width > spacedWidth) { // The textures a little thin. // Generate a new area to the right of this one (NB: 0,0 is bottom left) AtlasLocation newRight = new AtlasLocation(Atlas, X + spacedWidth, Y, Width - spacedWidth, height); // Immediately mark this as empty: newRight.AddToEmptySet(); } if (Height > spacedHeight) { // The textures a little short. // Generate a new area above this one (NB: 0,0 is bottom left) AtlasLocation newTop = new AtlasLocation(Atlas, X, Y + spacedHeight, Width, Height - spacedHeight); // Immediately mark this as empty: newTop.AddToEmptySet(); } } else { int maxX = X + spacedWidth; if (Atlas.ColumnProgress < maxX) { Atlas.ColumnProgress = maxX; } if (Height > spacedHeight) { // The textures a little short. // Generate a new area above this one (NB: 0,0 is bottom left) AtlasLocation newTop = new AtlasLocation(Atlas, X, Y + spacedHeight, Width, Height - spacedHeight); // Immediately mark this as empty: newTop.AddToEmptySet(); } } // Set the new size of this location for UV baking: Width = width; Height = height; Spacing = spacing; // Update the UV's: BakeUV(); // Make sure the area is up to date: Area = spacedWidth * spacedHeight; // Write it in: Flush(); }
//--------------------------------------
/// <summary>This texture has selected this location to fit into. This adds it to the atlas.</summary> /// <param name="texture">The texture that wants to go here.</param> /// <param name="width">The width of the texture in pixels.</param> /// <param name="height">The height of the texture in pixels.</param> public void Select(AtlasEntity image,int width,int height,int spacing){ // The given texture wants to go in this location. // Width and height are given for dynamic textures - textures who's pixels are actually written straight to the atlas. Empty=false; int spacedWidth=width+spacing; int spacedHeight=height+spacing; // Remove from empty queue: if(EmptyBefore==null){ Atlas.FirstEmpty=EmptyAfter; }else{ EmptyBefore.EmptyAfter=EmptyAfter; } if(EmptyAfter==null){ Atlas.LastEmpty=EmptyBefore; }else{ EmptyAfter.EmptyBefore=EmptyBefore; } int entityID=image.GetAtlasID(); if(AtlasID==entityID){ // This is a restore - we don't need to do anything else. return; } Image=image; AtlasID=entityID; // If it's not a perfect fit, generate new atlas locations to the right and above of this one. if(Atlas.Mode==AtlasingMode.SmallestSpace){ if(Width>spacedWidth){ // The textures a little thin. // Generate a new area to the right of this one (NB: 0,0 is bottom left) AtlasLocation newRight=new AtlasLocation(Atlas,X+spacedWidth,Y,Width-spacedWidth,height); // Immediately mark this as empty: newRight.AddToEmptySet(); } if(Height>spacedHeight){ // The textures a little short. // Generate a new area above this one (NB: 0,0 is bottom left) AtlasLocation newTop=new AtlasLocation(Atlas,X,Y+spacedHeight,Width,Height-spacedHeight); // Immediately mark this as empty: newTop.AddToEmptySet(); } }else{ int maxX=X+spacedWidth; if(Atlas.ColumnProgress < maxX){ Atlas.ColumnProgress=maxX; } if(Height>spacedHeight){ // The textures a little short. // Generate a new area above this one (NB: 0,0 is bottom left) AtlasLocation newTop=new AtlasLocation(Atlas,X,Y+spacedHeight,Width,Height-spacedHeight); // Immediately mark this as empty: newTop.AddToEmptySet(); } } // Set the new size of this location for UV baking: Width=width; Height=height; Spacing=spacing; // Update the UV's: BakeUV(); // Make sure the area is up to date: Area=spacedWidth*spacedHeight; // Write it in: Flush(); }
/// <summary>Require the given image on any atlas. Note that this may reject the requirement if the image is too big and isn't worthwhile on an atlas.</summary> public AtlasLocation RequireImage(AtlasEntity image) { int entityID = image.GetAtlasID(); AtlasLocation result; if (ActiveImages.TryGetValue(entityID, out result)) { // Most calls fall through here. return(result); } int width; int height; image.GetDimensionsOnAtlas(out width, out height); if (width > InitialSize || height > InitialSize) { // Won't fit or is unsuitable for atlasing anyway. return(null); } if (Last == null) { Create(); } else { // Fast check - was this texture recently removed from any atlas? // We might have the chance of restoring it. // Their added at the back of the empty queue, so naturally, start at the end of the empty set // and go back until we hit one with a null texture. TextureAtlas currentAtlas = Last; while (currentAtlas != null) { AtlasLocation currentE = currentAtlas.LastEmpty; while (currentE != null) { if (currentE.Image == null) { // Nope! Shame. break; } else if (currentE.AtlasID == entityID) { // Ace! Time to bring it back from the dead. currentE.Select(image, width, height, Spacing); ActiveImages[entityID] = currentE; return(currentE); } currentE = currentE.EmptyBefore; } currentAtlas = currentAtlas.Previous; } } // Push to top of stack: result = Last.Add(image, entityID, width, height); if (result != null) { return(result); } // Non-fitter - try fitting in lower stack frames: TextureAtlas current = Last.Previous; while (current != null) { result = current.Add(image, entityID, width, height); if (result != null) { return(result); } current = current.Previous; } // Still not fitting! Create a new stack frame: Create(); return(Last.Add(image, entityID, width, height)); }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { Chat.SendGlobalMessage(player.Character.Fullname, string.Join(" ", arguments), Color.FromArgb(50, 50, 255)); }
/// <summary>Require the given image on any atlas. Note that this may reject the requirement if the image is too big and isn't worthwhile on an atlas.</summary> public AtlasLocation RequireImage(AtlasEntity image){ int entityID=image.GetAtlasID(); AtlasLocation result; if(ActiveImages.TryGetValue(entityID,out result)){ // Most calls fall through here. return result; } int width; int height; image.GetDimensionsOnAtlas(out width,out height); if(width>InitialSize || height>InitialSize){ // Won't fit or is unsuitable for atlasing anyway. return null; } if(Last==null){ Create(); }else{ // Fast check - was this texture recently removed from any atlas? // We might have the chance of restoring it. // Their added at the back of the empty queue, so naturally, start at the end of the empty set // and go back until we hit one with a null texture. TextureAtlas currentAtlas=Last; while(currentAtlas!=null){ AtlasLocation currentE=currentAtlas.LastEmpty; while(currentE!=null){ if(currentE.Image==null){ // Nope! Shame. break; }else if(currentE.AtlasID==entityID){ // Ace! Time to bring it back from the dead. currentE.Select(image,width,height,Spacing); ActiveImages[entityID]=currentE; return currentE; } currentE=currentE.EmptyBefore; } currentAtlas=currentAtlas.Previous; } } // Push to top of stack: result=Last.Add(image,entityID,width,height); if(result!=null){ return result; } // Non-fitter - try fitting in lower stack frames: TextureAtlas current=Last.Previous; while(current!=null){ result=current.Add(image,entityID,width,height); if(result!=null){ return result; } current=current.Previous; } // Still not fitting! Create a new stack frame: Create(); return Last.Add(image,entityID,width,height); }
public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null) { if (md.Vertices.Count == 0 || feature == null || feature.Points.Count < 1) { return; } if (tile != null) { _scale = tile.TileScale; } //facade texture to decorate this building _currentFacade = _options.atlasInfo.Textures[UnityEngine.Random.Range(0, _options.atlasInfo.Textures.Count)]; //rect is a struct so we're caching this _currentTextureRect = _currentFacade.TextureRect; //this can be moved to initialize or in an if clause if you're sure all your tiles will be same level/scale _singleFloorHeight = (tile.TileScale * _currentFacade.FloorHeight) / _currentFacade.MidFloorCount; _scaledFirstFloorHeight = tile.TileScale * _currentFacade.FirstFloorHeight; _scaledTopFloorHeight = tile.TileScale * _currentFacade.TopFloorHeight; _scaledPreferredWallLength = tile.TileScale * _currentFacade.PreferredEdgeSectionLength; _scaledFloorHeight = _scaledPreferredWallLength * _currentFacade.WallToFloorRatio; _singleColumnLength = _scaledPreferredWallLength / _currentFacade.ColumnCount; //read or force height float maxHeight = 1, minHeight = 0; //query height and push polygon up to create roof //can we do this vice versa and create roof at last? QueryHeight(feature, md, tile, out maxHeight, out minHeight); maxHeight = maxHeight * _options.extrusionScaleFactor * _scale; minHeight = minHeight * _options.extrusionScaleFactor * _scale; height = (maxHeight - minHeight); //we cann GenerateRoofMesh even if extrusion type is sidewall-only //it pushes the vertices to building height, then we clear top polygon triangles //to remove roof. GenerateRoofMesh(md, minHeight, maxHeight); if (_options.extrusionGeometryType == ExtrusionGeometryType.SideOnly) { md.Triangles[0].Clear(); } if (_options.extrusionGeometryType != ExtrusionGeometryType.RoofOnly) { //limiting section heights, first floor gets priority, then we draw top floor, then mid if we still have space finalFirstHeight = Mathf.Min(height, _scaledFirstFloorHeight); finalTopHeight = (height - finalFirstHeight) < _scaledTopFloorHeight ? 0 : _scaledTopFloorHeight; finalMidHeight = Mathf.Max(0, height - (finalFirstHeight + finalTopHeight)); wallTriangles = new List <int>(); //cuts long edges into smaller ones using PreferredEdgeSectionLength currentWallLength = 0; start = Constants.Math.Vector3Zero; wallSegmentDirection = Constants.Math.Vector3Zero; finalLeftOverRowHeight = 0f; if (finalMidHeight > 0) { finalLeftOverRowHeight = finalMidHeight; finalLeftOverRowHeight = finalLeftOverRowHeight % _singleFloorHeight; finalMidHeight -= finalLeftOverRowHeight; } else { finalLeftOverRowHeight = finalTopHeight; } for (int i = 0; i < md.Edges.Count; i += 2) { var v1 = md.Vertices[md.Edges[i]]; var v2 = md.Vertices[md.Edges[i + 1]]; wallDirection = v2 - v1; currentWallLength = Vector3.Distance(v1, v2); _leftOverColumnLength = currentWallLength % _singleColumnLength; start = v1; wallSegmentDirection = (v2 - v1).normalized; //half of leftover column (if _centerSegments ofc) at the begining if (_centerSegments && currentWallLength > _singleColumnLength) { //save left,right vertices and wall length wallSegmentFirstVertex = start; wallSegmentLength = (_leftOverColumnLength / 2); start += wallSegmentDirection * wallSegmentLength; wallSegmentSecondVertex = start; _leftOverColumnLength = _leftOverColumnLength / 2; CreateWall(md); } while (currentWallLength > _singleColumnLength) { wallSegmentFirstVertex = start; //columns fitting wall / max column we have in texture var stepRatio = (float)Math.Min(_currentFacade.ColumnCount, Math.Floor(currentWallLength / _singleColumnLength)) / _currentFacade.ColumnCount; wallSegmentLength = stepRatio * _scaledPreferredWallLength; start += wallSegmentDirection * wallSegmentLength; wallSegmentSecondVertex = start; currentWallLength -= (stepRatio * _scaledPreferredWallLength); CreateWall(md); } //left over column at the end if (_leftOverColumnLength > 0) { wallSegmentFirstVertex = start; wallSegmentSecondVertex = v2; wallSegmentLength = _leftOverColumnLength; CreateWall(md); } } //this first loop is for columns if (_separateSubmesh) { md.Triangles.Add(wallTriangles); } else { md.Triangles.Capacity = md.Triangles.Count + wallTriangles.Count; md.Triangles[0].AddRange(wallTriangles); } } }
/// <summary>Adds the given texture to the atlas if it's not already on it, /// taking up a set amount of space on the atlas.</summary> /// <param name="texture">The texture to add.</param> /// <param name="width">The x amount of space to take up on the atlas.</param> /// <param name="height">The y amount of space to take up on the atlas.</param> /// <returns>The location of the texture on the atlas.</returns> internal AtlasLocation Add(AtlasEntity texture,int entityID,int width,int height){ // Pad width/height: int spacedWidth=width+RawSpacing; int spacedHeight=height+RawSpacing; // Look for a spot to park this texture in the set of empty blocks. // The aim is to make it fit in the smallest empty block possible to save space. // This is done with a 'fitFactor' - this is simply the difference between the blocks area and the textures area. // We want this value to be as small as possible. int fitFactor=0; AtlasLocation currentAccepted=null; int area=spacedWidth*spacedHeight; AtlasLocation currentEmpty=FirstEmpty; while(currentEmpty!=null){ int factor=currentEmpty.FitFactor(spacedWidth,spacedHeight,area); if(factor==0){ // Perfect fit - break right now; can't beat that! currentAccepted=currentEmpty; break; }else if(factor!=-1){ // We can possibly fit here - is it the current smallest? if(currentAccepted==null||factor<fitFactor){ // Yep! select it. fitFactor=factor; currentAccepted=currentEmpty; } } currentEmpty=currentEmpty.EmptyAfter; } if(Mode==AtlasingMode.Columns && currentAccepted==null){ // Is there any more column space? int max=ColumnProgress + spacedWidth; if(max<=Dimension){ // Yep! Create a location using the remaining space: currentAccepted=new AtlasLocation(this,ColumnProgress,0,Dimension-ColumnProgress,Dimension); // As it's a new location, it's empty by default: // (Note that it must be in the empty set, otherwise Select will throw the empty set entirely) currentAccepted.AddToEmptySet(); } } if(currentAccepted==null){ // No space in this atlas to fit it in. Stop there. if(CanOptimize){ // Request an optimise: OptimizeRequested=true; Stack.OptimizeRequested=true; } return null; } Stack.ActiveImages[entityID]=currentAccepted; // And burn in the texture to the location (nb: it internally also writes the pixels to the atlas). currentAccepted.Select(texture,width,height,RawSpacing); return currentAccepted; }
public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null) { if (Criteria != null && Criteria.Count > 0) { foreach (var criterion in Criteria) { if (criterion.ShouldReplaceFeature(feature)) { return; } } } var _counter = feature.Points.Count; var subset = new List <List <Vector3> >(_counter); Data flatData = null; List <int> result = null; var currentIndex = 0; int vertCount = 0, polygonVertexCount = 0; List <int> triList = null; List <Vector3> sub = null; for (int i = 0; i < _counter; i++) { sub = feature.Points[i]; //earcut is built to handle one polygon with multiple holes //point data can contain multiple polygons though, so we're handling them separately here vertCount = md.Vertices.Count; if (IsClockwise(sub) && vertCount > 0) { flatData = EarcutLibrary.Flatten(subset); result = EarcutLibrary.Earcut(flatData.Vertices, flatData.Holes, flatData.Dim); polygonVertexCount = result.Count; if (triList == null) { triList = new List <int>(polygonVertexCount); } else { triList.Capacity = triList.Count + polygonVertexCount; } for (int j = 0; j < polygonVertexCount; j++) { triList.Add(result[j] + currentIndex); } currentIndex = vertCount; subset.Clear(); } subset.Add(sub); polygonVertexCount = sub.Count; md.Vertices.Capacity = md.Vertices.Count + polygonVertexCount; md.Normals.Capacity = md.Normals.Count + polygonVertexCount; md.Edges.Capacity = md.Edges.Count + polygonVertexCount * 2; var _size = md.TileRect.Size; for (int j = 0; j < polygonVertexCount; j++) { md.Edges.Add(vertCount + ((j + 1) % polygonVertexCount)); md.Edges.Add(vertCount + j); md.Vertices.Add(sub[j]); md.Tangents.Add(Constants.Math.Vector3Forward); md.Normals.Add(Constants.Math.Vector3Up); if (_options.style == StyleTypes.Satellite) { var fromBottomLeft = new Vector2( (float)(((sub[j].x + md.PositionInTile.x) / tile.TileScale + _size.x / 2) / _size.x), (float)(((sub[j].z + md.PositionInTile.z) / tile.TileScale + _size.x / 2) / _size.x)); md.UV[0].Add(fromBottomLeft); } else if (_options.texturingType == UvMapType.Tiled) { md.UV[0].Add(new Vector2(sub[j].x, sub[j].z)); } } } flatData = EarcutLibrary.Flatten(subset); result = EarcutLibrary.Earcut(flatData.Vertices, flatData.Holes, flatData.Dim); polygonVertexCount = result.Count; if (_options.texturingType == UvMapType.Atlas || _options.texturingType == UvMapType.AtlasWithColorPalette) { _currentFacade = _options.atlasInfo.Roofs[UnityEngine.Random.Range(0, _options.atlasInfo.Roofs.Count)]; minx = float.MaxValue; miny = float.MaxValue; maxx = float.MinValue; maxy = float.MinValue; _textureUvCoordinates = new Vector2[md.Vertices.Count]; _textureDirection = Quaternion.FromToRotation((md.Vertices[0] - md.Vertices[1]), Mapbox.Unity.Constants.Math.Vector3Right); _textureUvCoordinates[0] = new Vector2(0, 0); _firstVert = md.Vertices[0]; for (int i = 1; i < md.Vertices.Count; i++) { _vert = md.Vertices[i]; _vertexRelativePos = _vert - _firstVert; _vertexRelativePos = _textureDirection * _vertexRelativePos; _textureUvCoordinates[i] = new Vector2(_vertexRelativePos.x, _vertexRelativePos.z); if (_vertexRelativePos.x < minx) { minx = _vertexRelativePos.x; } if (_vertexRelativePos.x > maxx) { maxx = _vertexRelativePos.x; } if (_vertexRelativePos.z < miny) { miny = _vertexRelativePos.z; } if (_vertexRelativePos.z > maxy) { maxy = _vertexRelativePos.z; } } var width = maxx - minx; var height = maxy - miny; for (int i = 0; i < md.Vertices.Count; i++) { md.UV[0].Add(new Vector2( (((_textureUvCoordinates[i].x - minx) / width) * _currentFacade.TextureRect.width) + _currentFacade.TextureRect.x, (((_textureUvCoordinates[i].y - miny) / height) * _currentFacade.TextureRect.height) + _currentFacade.TextureRect.y)); } } if (triList == null) { triList = new List <int>(polygonVertexCount); } else { triList.Capacity = triList.Count + polygonVertexCount; } for (int i = 0; i < polygonVertexCount; i++) { triList.Add(result[i] + currentIndex); } md.Triangles.Add(triList); }
private void DrawAtlasEntityData(List <AtlasEntity> aeList) { for (int i = 0; i < aeList.Count; i++) { AtlasEntity ae = aeList[i]; Rect baseRect = ae.TextureRect; float topRatio = ae.TopSectionRatio * baseRect.height; float bottomRatio = ae.BottomSectionRatio * baseRect.height; float middleRatio = baseRect.height - (topRatio + bottomRatio); Rect groundFloorRect = new Rect(baseRect.x, baseRect.y, baseRect.width, bottomRatio); Rect topFloorRect = new Rect(baseRect.x, baseRect.y + baseRect.height - topRatio, baseRect.width, topRatio); PixelRect basePixelRect = ConvertUVRectToPixelRect(baseRect); PixelRect groundFloorPixelRect = ConvertUVRectToPixelRect(groundFloorRect); PixelRect topFloorPixelRect = ConvertUVRectToPixelRect(topFloorRect); Color color = m_colors[_drawCount]; Color colorLight = (color + Color.white) / 2; Color colorDark = (color + Color.black) / 2; DrawRect(basePixelRect, color); DrawRect(groundFloorPixelRect, colorLight); DrawRect(topFloorPixelRect, colorDark); DrawDebugCross(groundFloorPixelRect); DrawDebugCross(topFloorPixelRect); int numColumns = (int)ae.ColumnCount; int numMidFloors = ae.MidFloorCount; float colWidth = baseRect.width / numColumns; float floorHeight = middleRatio / numMidFloors; float midFloorBase = baseRect.y + bottomRatio; float mrgn = _cellRatioMargin; float halfMrgn = mrgn / 2; for (int j = 0; j < numMidFloors; j++) { float floorStart = midFloorBase + (floorHeight * j); for (int k = 0; k < numColumns; k++) { float columnStart = baseRect.x + (colWidth * k); Rect cellRect = new Rect(columnStart + halfMrgn, floorStart + halfMrgn, colWidth - mrgn, floorHeight - mrgn); PixelRect cellPixelRect = ConvertUVRectToPixelRect(cellRect); DrawRect(cellPixelRect, Color.white); DrawDebugCross(cellPixelRect); } } DrawCornerWatermarks(groundFloorPixelRect); DrawCornerWatermarks(topFloorPixelRect); _drawCount++; } }
public void On(AtlasPlayer player, AtlasEntity entity, List <string> arguments) { entity.Vehicle?.Delete(); }
public override void Run(CustomFeatureUnity feature, ref MeshDataStruct md) { var counter = feature.Points.Count; var subset = new List <List <Vector3> >(counter); Assets.Mapbox.Unity.MeshGeneration.Modifiers.MeshModifiers.Data flatData; List <int> result; var currentIndex = 0; var polygonVertexCount = 0; NativeList <int> triList = default; for (var i = 0; i < counter; i++) { var sub = feature.Points[i]; // ear cut is built to handle one polygon with multiple holes //point data can contain multiple polygons though, so we're handling them separately here var vertCount = md.Vertices.Length; if (IsClockwise(sub) && vertCount > 0) { flatData = Assets.Mapbox.Unity.MeshGeneration.Modifiers.MeshModifiers.EarcutLibrary.Flatten(subset); result = Assets.Mapbox.Unity.MeshGeneration.Modifiers.MeshModifiers.EarcutLibrary.Earcut(flatData.Vertices, flatData.Holes, flatData.Dim); polygonVertexCount = result.Count; if (!triList.IsCreated) { triList = new NativeList <int>(polygonVertexCount, Allocator.TempJob); } else { triList.Capacity = triList.Length + polygonVertexCount; } for (var j = 0; j < polygonVertexCount; j++) { triList.Add(result[j] + currentIndex); } currentIndex = vertCount; subset.Clear(); } subset.Add(sub); polygonVertexCount = sub.Count; md.Vertices.Capacity = md.Vertices.Length + polygonVertexCount; md.Normals.Capacity = md.Normals.Length + polygonVertexCount; md.Edges.Capacity = md.Edges.Length + polygonVertexCount * 2; for (var j = 0; j < polygonVertexCount; j++) { md.Edges.Add(vertCount + ((j + 1) % polygonVertexCount)); md.Edges.Add(vertCount + j); md.Vertices.Add(sub[j]); md.Normals.Add(Vector3.up); if (_options.texturingType != UvMapType.Tiled) { continue; } md.UV.Add(new Vector2(sub[j].x, sub[j].z)); } } flatData = Assets.Mapbox.Unity.MeshGeneration.Modifiers.MeshModifiers.EarcutLibrary.Flatten(subset); result = Assets.Mapbox.Unity.MeshGeneration.Modifiers.MeshModifiers.EarcutLibrary.Earcut(flatData.Vertices, flatData.Holes, flatData.Dim); polygonVertexCount = result.Count; if (_options.texturingType == UvMapType.Atlas || _options.texturingType == UvMapType.AtlasWithColorPalette) { _currentFacade = _options.atlasInfo.Roofs[UnityEngine.Random.Range(0, _options.atlasInfo.Roofs.Count)]; var minx = float.MaxValue; var miny = float.MaxValue; var maxx = float.MinValue; var maxy = float.MinValue; var textureUvCoordinates = new Vector2[md.Vertices.Length]; var textureDirection = Quaternion.FromToRotation(md.Vertices[0] - md.Vertices[1], Vector3.right); textureUvCoordinates[0] = new Vector2(0, 0); for (var i = 1; i < md.Vertices.Length; i++) { var vert = md.Vertices[i]; var vertexRelativePos = textureDirection * (vert - md.Vertices[0]); textureUvCoordinates[i] = new Vector2(vertexRelativePos.x, vertexRelativePos.z); if (vertexRelativePos.x < minx) { minx = vertexRelativePos.x; } if (vertexRelativePos.x > maxx) { maxx = vertexRelativePos.x; } if (vertexRelativePos.z < miny) { miny = vertexRelativePos.z; } if (vertexRelativePos.z > maxy) { maxy = vertexRelativePos.z; } } var width = maxx - minx; var height = maxy - miny; for (var i = 0; i < md.Vertices.Length; i++) { md.UV.Add(new Vector2( (((textureUvCoordinates[i].x - minx) / width) * _currentFacade.TextureRect.width) + _currentFacade.TextureRect.x, (((textureUvCoordinates[i].y - miny) / height) * _currentFacade.TextureRect.height) + _currentFacade.TextureRect.y)); } } if (!triList.IsCreated) { triList = new NativeList <int>(polygonVertexCount, Allocator.TempJob); } else { triList.Capacity = triList.Length + polygonVertexCount; } for (var i = 0; i < polygonVertexCount; i++) { triList.Add(result[i] + currentIndex); } md.Triangles.AddRange(triList); triList.Dispose(); }
public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null) { _uv.Clear(); _mdVertexCount = md.Vertices.Count; _size = md.TileRect.Size; if (_options.texturingType != UvMapType.Atlas && _options.texturingType != UvMapType.AtlasWithColorPalette) { for (int i = 0; i < _mdVertexCount; i++) { _vert = md.Vertices[i]; if (_options.texturingType == UvMapType.Tiled) { _uv.Add(new Vector2(_vert.x, _vert.z)); } else if (_options.texturingType == UvMapType.Satellite) { var fromBottomLeft = new Vector2((float)(((_vert.x + md.PositionInTile.x) / tile.TileScale + _size.x / 2) / _size.x), (float)(((_vert.z + md.PositionInTile.z) / tile.TileScale + _size.x / 2) / _size.x)); _uv.Add(fromBottomLeft); } } } else if (_options.texturingType == UvMapType.Atlas || _options.texturingType == UvMapType.AtlasWithColorPalette) { _currentFacade = _options.atlasInfo.Roofs[UnityEngine.Random.Range(0, _options.atlasInfo.Roofs.Count)]; float minx = float.MaxValue, miny = float.MaxValue, maxx = float.MinValue, maxy = float.MinValue; _textureUvCoordinates = new Vector2[_mdVertexCount]; _textureDirection = Quaternion.FromToRotation((md.Vertices[_mdVertexCount - 2] - md.Vertices[0]), Mapbox.Unity.Constants.Math.Vector3Right); _textureUvCoordinates[0] = new Vector2(0, 0); _firstVert = md.Vertices[0]; for (int i = 1; i < _mdVertexCount; i++) { _vert = md.Vertices[i]; _vertexRelativePos = _vert - _firstVert; _vertexRelativePos = _textureDirection * _vertexRelativePos; _textureUvCoordinates[i] = new Vector2(_vertexRelativePos.x, _vertexRelativePos.z); if (_vertexRelativePos.x < minx) { minx = _vertexRelativePos.x; } if (_vertexRelativePos.x > maxx) { maxx = _vertexRelativePos.x; } if (_vertexRelativePos.z < miny) { miny = _vertexRelativePos.z; } if (_vertexRelativePos.z > maxy) { maxy = _vertexRelativePos.z; } } var width = maxx - minx; var height = maxy - minx; for (int i = 0; i < _mdVertexCount; i++) { //var nx = _textureUvCoordinates[i].x - minx; //first point isn't always the min //var ny = _textureUvCoordinates[i].y - miny; //var xx = (nx / (maxx - minx)) * _currentFacade.TextureRect.width + _currentFacade.TextureRect.x; //var yy = (ny / (maxy - miny)) * _currentFacade.TextureRect.height + _currentFacade.TextureRect.y; _uv.Add(new Vector2( (((_textureUvCoordinates[i].x - minx) / width) * _currentFacade.TextureRect.width) + _currentFacade.TextureRect.x, (((_textureUvCoordinates[i].y - miny) / height) * _currentFacade.TextureRect.height) + _currentFacade.TextureRect.y)); } } md.UV[0].AddRange(_uv); }
/// <summary>Adds the given texture to the atlas if it's not already on it, /// taking up a set amount of space on the atlas.</summary> /// <param name="texture">The texture to add.</param> /// <param name="width">The x amount of space to take up on the atlas.</param> /// <param name="height">The y amount of space to take up on the atlas.</param> /// <returns>The location of the texture on the atlas.</returns> internal AtlasLocation Add(AtlasEntity texture, int entityID, int width, int height) { // Pad width/height: int spacedWidth = width + RawSpacing; int spacedHeight = height + RawSpacing; // Look for a spot to park this texture in the set of empty blocks. // The aim is to make it fit in the smallest empty block possible to save space. // This is done with a 'fitFactor' - this is simply the difference between the blocks area and the textures area. // We want this value to be as small as possible. AtlasLocation currentAccepted = null; int area = spacedWidth * spacedHeight; if (Mode == AtlasingMode.Columns) { // Space in this column? int max = ColumnProgressY + spacedHeight; if (max <= Dimension) { // Yep! Create a location here: currentAccepted = new AtlasLocation(this, ColumnProgressX, ColumnProgressY, spacedWidth, spacedHeight); // Move it: ColumnProgressY += spacedHeight; if (spacedWidth > ColumnWidth) { // Update width: ColumnWidth = spacedWidth; } // As it's a new location, it's empty by default: // (Note that it must be in the empty set, otherwise Select will throw the empty set entirely) currentAccepted.AddToEmptySet(); } else { // Space to generate a new column? max = ColumnProgressX + ColumnWidth + spacedWidth; if (max <= Dimension) { // Set Y: ColumnProgressY = spacedHeight; // Move X: ColumnProgressX += ColumnWidth; // Yep! Create a location here: currentAccepted = new AtlasLocation(this, ColumnProgressX, 0, spacedWidth, spacedHeight); // Reset width: ColumnWidth = spacedWidth; // As it's a new location, it's empty by default: // (Note that it must be in the empty set, otherwise Select will throw the empty set entirely) currentAccepted.AddToEmptySet(); } // Otherwise, the atlas is practically full. // We're gonna just reject the add (by falling below), and state that it can be optimised. // This triggers another atlas to get created and this one will // be optimised at some point in the near future. } } else { int fitFactor = 0; AtlasLocation currentEmpty = FirstEmpty; while (currentEmpty != null) { int factor = currentEmpty.FitFactor(spacedWidth, spacedHeight, area); if (factor == 0) { // Perfect fit - break right now; can't beat that! currentAccepted = currentEmpty; break; } else if (factor != -1) { // We can possibly fit here - is it the current smallest? if (currentAccepted == null || factor < fitFactor) { // Yep! select it. fitFactor = factor; currentAccepted = currentEmpty; } } currentEmpty = currentEmpty.EmptyAfter; } } if (currentAccepted == null) { // No space in this atlas to fit it in. Stop there. if (CanOptimize) { // Request an optimise: OptimizeRequested = true; Stack.OptimizeRequested = true; } return(null); } Stack.ActiveImages[entityID] = currentAccepted; // And burn in the texture to the location (nb: it internally also writes the pixels to the atlas). currentAccepted.Select(texture, width, height, RawSpacing); return(currentAccepted); }
public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null) { if (md.Vertices.Count == 0 || feature == null || feature.Points.Count < 1) { return; } if (tile != null) { _scale = tile.TileScale; } _currentFacade = _options.atlasInfo.Textures[UnityEngine.Random.Range(0, _options.atlasInfo.Textures.Count)]; //rect is a struct so we're caching this _currentTextureRect = _currentFacade.TextureRect; //this can be moved to initialize or in an if clause if you're sure all your tiles will be same level/scale _scaledFloorHeight = tile.TileScale * _currentFacade.FloorHeight; _scaledFirstFloorHeight = tile.TileScale * _currentFacade.FirstFloorHeight; _scaledTopFloorHeight = tile.TileScale * _currentFacade.TopFloorHeight; //read or force height float maxHeight = 1, minHeight = 0; QueryHeight(feature, md, tile, out maxHeight, out minHeight); maxHeight = maxHeight * _options.extrusionScaleFactor * _scale; minHeight = minHeight * _options.extrusionScaleFactor * _scale; height = (maxHeight - minHeight); GenerateRoofMesh(md, minHeight, maxHeight); if (_options.extrusionGeometryType != ExtrusionGeometryType.RoofOnly) { edgeList.Clear(); //cuts long edges into smaller ones using PreferredEdgeSectionLength CalculateEdgeList(md, tile, _currentFacade.PreferredEdgeSectionLength); //limiting section heights, first floor gets priority, then we draw top floor, then mid if we still have space firstHeight = Mathf.Min(height, _scaledFirstFloorHeight); topHeight = Mathf.Min(height - firstHeight, _scaledTopFloorHeight); midHeight = Mathf.Max(0, height - (firstHeight + topHeight)); //we're merging small mid sections to top and small top sections to first floor to avoid really short/compressed floors //I think we need this but I'm not sure about implementation. I feel like mid height should be shared by top&bottom for example. if (midHeight < _scaledFloorHeight / (_currentFacade.MidFloorCount * 2)) { topHeight += midHeight; _scaledTopFloorHeight += midHeight; midHeight = 0; } if (topHeight < _scaledTopFloorHeight * 0.66f) //0.66 here is just a random number for acceptable stretching { firstHeight += topHeight; topHeight = 0; } floorCount = (int)(midHeight / _scaledFloorHeight) + 1; scaledFloorHeight = midHeight / floorCount; wallTriangles = new List <int>(); //this first loop is for columns for (int i = 0; i < edgeList.Count - 1; i += 2) { v1 = edgeList[i]; v2 = edgeList[i + 1]; ind = md.Vertices.Count; wallDirection = (v2 - v1); d = wallDirection.magnitude; //this part minimizes stretching for narrow columns //if texture has 3 columns, 33% (of preferred edge length) wide walls will get 1 window. //0-33% gets 1 window, 33-66 gets 2, 66-100 gets all three //we're not wrapping/repeating texture as it won't work with atlases columnScaleRatio = Math.Min(1, d / (_currentFacade.PreferredEdgeSectionLength * tile.TileScale)); rightOfEdgeUv = _currentTextureRect.xMin + _currentTextureRect.size.x * Math.Min(1, ((float)(Math.Floor(columnScaleRatio * _currentFacade.ColumnCount) + 1) / _currentFacade.ColumnCount)); bottomOfTopUv = _currentTextureRect.yMax - (_currentTextureRect.size.y * _currentFacade.TopSectionRatio); //not doing that scaling thing for y axis and floors yet topOfBottomUv = _currentTextureRect.yMin + (_currentTextureRect.size.y * _currentFacade.BottomSectionRatio); // * (Mathf.Max(1, (float)Math.Floor(tby * textureSection.TopSectionFloorCount)) / textureSection.TopSectionFloorCount); wallNormal = new Vector3(-(v1.z - v2.z), 0, (v1.x - v2.x)).normalized; currentY1 = v1.y; currentY2 = v2.y; floorScaleRatio = Math.Min(1, midHeight / _scaledFloorHeight); var midSecHeight = (_currentTextureRect.height * (1 - _currentFacade.TopSectionRatio - _currentFacade.BottomSectionRatio)); var midFittedHeight = midSecHeight * Math.Min(1, ((float)(Math.Floor(floorScaleRatio * _currentFacade.MidFloorCount) + 1) / _currentFacade.MidFloorCount)); // midHeight < _scaledFloorHeight * 0.66 ? 0.5f : 0.125f; bottomOfMidUv = (_currentTextureRect.yMax - (_currentTextureRect.height * _currentFacade.TopSectionRatio)) - midFittedHeight; topOfMidUv = _currentTextureRect.yMax - (_currentTextureRect.height * _currentFacade.TopSectionRatio); TopFloor(md); MidFloors(md); FirstFloor(md, height); } if (_separateSubmesh) { md.Triangles.Add(wallTriangles); } else { md.Triangles.Capacity = md.Triangles.Count + wallTriangles.Count; md.Triangles[0].AddRange(wallTriangles); } } }
/// <summary>Removes a texture from the atlas.</summary> /// <param name="texture">The texture to remove.</param> public void Remove(AtlasEntity texture){ if(texture==null){ return; } AtlasLocation location=Get(texture.GetAtlasID()); if(location==null){ return; } // Make the location available: location.Deselect(); }