UnityMol  0.9.6-875
UnityMol viewer / In developement
SpriteManager.cs
Go to the documentation of this file.
1 
66 //-----------------------------------------------------------------
67 // SpriteManager v0.633 (8-02-2009)
68 // Copyright 2009 Brady Wright and Above and Beyond Software
69 // All rights reserved
70 //-----------------------------------------------------------------
71 // A class to allow the drawing of multiple "quads" as part of a
72 // single aggregated mesh so as to achieve multiple, independently
73 // moving objects using a single draw call.
74 //-----------------------------------------------------------------
75 
76 
77 using UnityEngine;
78 using System.Collections;
79 
80 //-----------------------------------------------------------------
81 // Describes a UV animation
82 //-----------------------------------------------------------------
83 // NOTE: Currently, you should assign at least two frames to an
84 // animation, or else you can expect problems!
85 //-----------------------------------------------------------------
86 public class UVAnimation
87 {
88  protected Vector2[] frames; // Array of UV coordinates (for quads) defining the frames of an animation
89 
90  // Animation state vars:
91  protected int curFrame = 0; // The current frame
92  protected int stepDir = 1; // The direction we're currently playing the animation (1=forwards (default), -1=backwards)
93  protected int numLoops = 0; // Number of times we've looped since last animation
94 
95  public string name; // The name of the
96  public int loopCycles = 0; // How many times to loop the animation (-1 loop infinitely)
97  public bool loopReverse = false; // Reverse the play direction when the end of the animation is reached? (if true, a loop iteration isn't counted until we return to the beginning)
98  public float framerate; // The rate in frames per second at which to play the animation
99 
100 
101  // Resets all the animation state vars to ready the object
102  // for playing anew:
103  public void Reset()
104  {
105  curFrame = 0;
106  stepDir = 1;
107  numLoops = 0;
108  }
109 
110  // Sets the stepDir to -1 and sets the current frame to the end
111  // so that the animation plays in reverse
112  public void PlayInReverse()
113  {
114  stepDir = -1;
115  curFrame = frames.Length - 1;
116  }
117 
118  // Stores the UV of the next frame in 'uv', returns false if
119  // we've reached the end of the animation (this will never
120  // happen if it is set to loop infinitely)
121  public bool GetNextFrame(ref Vector2 uv)
122  {
123  // See if we can advance to the next frame:
124  if((curFrame + stepDir) >= frames.Length || (curFrame + stepDir) < 0)
125  {
126  // See if we need to loop (if we're reversing, we don't loop until we get back to the beginning):
127  if( stepDir>0 && loopReverse )
128  {
129  stepDir = -1; // Reverse playback direction
130  curFrame += stepDir;
131 
132  uv = frames[curFrame];
133  }else
134  {
135  // See if we can loop:
136  if (numLoops + 1 > loopCycles && loopCycles != -1)
137  return false;
138  else
139  { // Loop the animation:
140  ++numLoops;
141 
142  if (loopReverse)
143  {
144  stepDir *= -1;
145  curFrame += stepDir;
146  }
147  else
148  curFrame = 0;
149 
150  uv = frames[curFrame];
151  }
152  }
153  }else
154  {
155  curFrame += stepDir;
156  uv = frames[curFrame];
157  }
158 
159  return true;
160  }
161 
162  // Constructs an array of UV coordinates based upon the info
163  // supplied.
164  //
165  // start - The UV of the lower-left corner of the first
166  // cell
167  // cellSize - width and height, in UV space, of each cell
168  // cols - Number of columns in the grid
169  // rows - Number of rows in the grid
170  // totalCells- Total number of cells in the grid (left-to-right,
171  // top-to-bottom ordering is assumed, just like reading
172  // English).
173  // fps - Framerate (frames per second)
174  public Vector2[] BuildUVAnim(Vector2 start, Vector2 cellSize, int cols, int rows, int totalCells, float fps)
175  {
176  int cellCount = 0;
177 
178  frames = new Vector2[totalCells];
179  framerate = fps;
180 
181  frames[0] = start;
182 
183  for(int row=0; row < rows; ++row)
184  {
185  for(int col=0; col<cols && cellCount < totalCells; ++col)
186  {
187  frames[cellCount].x = start.x + cellSize.x * ((float)col);
188  frames[cellCount].y = start.y - cellSize.y * ((float)row);
189 
190  ++cellCount;
191  }
192  }
193 
194  return frames;
195  }
196 
197  // Assigns the specified array of UV coordinates to the
198  // animation, replacing its current contents
199  public void SetAnim(Vector2[] anim)
200  {
201  frames = anim;
202  }
203 
204  // Appends the specified array of UV coordinates to the
205  // existing animation
206  public void AppendAnim(Vector2[] anim)
207  {
208  Vector2[] tempFrames = frames;
209 
210  frames = new Vector2[frames.Length + anim.Length];
211  tempFrames.CopyTo(frames, 0);
212  anim.CopyTo(frames, tempFrames.Length);
213  }
214 }
215 
216 
217 
218 
219 //-----------------------------------------------------------------
220 // Holds a single mesh object which is composed of an arbitrary
221 // number of quads that all use the same material, allowing
222 // multiple, independently moving objects to be drawn on-screen
223 // while using only a single draw call.
224 //-----------------------------------------------------------------
225 public class SpriteManager : MonoBehaviour
226 {
227  // In which plane should we create the sprites?
228  public enum SPRITE_PLANE
229  {
230  XY,
231  XZ,
232  YZ
233  };
234 
235  // Which way to wind polygons?
236  public enum WINDING_ORDER
237  {
238  CCW, // Counter-clockwise
239  CW // Clockwise
240  };
241 
242  public Material material; // The material to use for the sprites
243  public int allocBlockSize; // How many sprites to allocate space for at a time. ex: if set to 10, 10 new sprite blocks will be allocated at a time. Once all of these are used, 10 more will be allocated, and so on...
244  public SPRITE_PLANE plane; // The plane in which to create the sprites
245  public WINDING_ORDER winding=WINDING_ORDER.CCW; // Which way to wind polygons
246  public bool autoUpdateBounds = false; // Automatically recalculate the bounds of the mesh when vertices change?
247 
248  protected ArrayList availableBlocks = new ArrayList(); // Array of references to sprites which are currently not in use
249  protected bool vertsChanged = false; // Have changes been made to the vertices of the mesh since the last frame?
250  protected bool uvsChanged = false; // Have changes been made to the UVs of the mesh since the last frame?
251  protected bool colorsChanged = false; // Have the colors changed?
252  protected bool vertCountChanged = false;// Has the number of vertices changed?
253  protected bool updateBounds = false; // Update the mesh bounds?
254  protected Sprite[] sprites; // Array of all sprites (the offset of the vertices corresponding to each sprite should be found simply by taking the sprite's index * 4 (4 verts per sprite).
255  protected ArrayList activeBlocks = new ArrayList(); // Array of references to all the currently active (non-empty) sprites
256  protected ArrayList activeBillboards = new ArrayList(); // Array of references to all the *active* sprites which are to be rendered as billboards
257  protected ArrayList playingAnimations = new ArrayList();// Array of references to all the sprites that are currently playing animation
258  protected ArrayList spriteDrawOrder = new ArrayList(); // Array of indices of sprite objects stored in the order they are to be drawn (corresponding to the position of their vertex indices in the triIndices list) Allows us to keep track of where a given Sprite is in the drawing order (triIndices)
259  protected SpriteDrawLayerComparer drawOrderComparer = new SpriteDrawLayerComparer(); // Used to sort our draw order array
260  protected float boundUpdateInterval; // Interval, in seconds, to update the mesh bounds
261 
262  protected MeshFilter meshFilter;
263  protected MeshRenderer meshRenderer;
264  protected Mesh mesh; // Reference to our mesh (contained in the MeshFilter)
265 
266  protected Vector3[] vertices; // The vertices of our mesh
267  protected int[] triIndices; // Indices into the vertex array
268  protected Vector2[] UVs; // UV coordinates
269  protected Color[] colors; // Color values
270  //protected Vector3[] normals; // Normals
271 
272  // Working vars:
273  protected int i;
274  protected Sprite tempSprite = null;
275  protected float animTimeElapsed;
276 
277  //--------------------------------------------------------------
278  // Utility functions:
279  //--------------------------------------------------------------
280 
281  // Converts pixel-space values to UV-space scalar values
282  // according to the currently assigned material.
283  // NOTE: This is for converting widths and heights-not
284  // coordinates (which have reversed Y-coordinates).
285  // For coordinates, use PixelCoordToUVCoord()!
286  public Vector2 PixelSpaceToUVSpace(Vector2 xy)
287  {
288  Texture t = material.GetTexture("_MainTex");
289 
290  if(t)
291  return new Vector2(xy.x / ((float)t.width), xy.y / ((float)t.height));
292  else
293  return new Vector2(1.0f,1.0f);
294 
295  // return new Vector2(xy.x / ((float)t.width), xy.y / ((float)t.height));
296 
297  }
298 
299  // Converts pixel-space values to UV-space scalar values
300  // according to the currently assigned material.
301  // NOTE: This is for converting widths and heights-not
302  // coordinates (which have reversed Y-coordinates).
303  // For coordinates, use PixelCoordToUVCoord()!
304  public Vector2 PixelSpaceToUVSpace(int x, int y)
305  {
306  return PixelSpaceToUVSpace(new Vector2((float)x, (float)y));
307  }
308 
309  // Converts pixel coordinates to UV coordinates according to
310  // the currently assigned material.
311  // NOTE: This is for converting coordinates and will reverse
312  // the Y component accordingly. For converting widths and
313  // heights, use PixelSpaceToUVSpace()!
314  public Vector2 PixelCoordToUVCoord(Vector2 xy)
315  {
316  Vector2 p = PixelSpaceToUVSpace(xy);
317  p.y = 1.0f - p.y;
318  return p;
319  }
320 
321  // Converts pixel coordinates to UV coordinates according to
322  // the currently assigned material.
323  // NOTE: This is for converting coordinates and will reverse
324  // the Y component accordingly. For converting widths and
325  // heights, use PixelSpaceToUVSpace()!
326  public Vector2 PixelCoordToUVCoord(int x, int y)
327  {
328  return PixelCoordToUVCoord(new Vector2((float)x, (float)y));
329  }
330 
331  //--------------------------------------------------------------
332  // End utility functions
333  //--------------------------------------------------------------
334 
335  void Awake()
336  {
337  gameObject.AddComponent<MeshFilter>();
338  gameObject.AddComponent<MeshRenderer>();
339 
340  meshFilter = (MeshFilter)GetComponent(typeof(MeshFilter));
341  meshRenderer = (MeshRenderer)GetComponent(typeof(MeshRenderer));
342 
343  meshRenderer.GetComponent<Renderer>().material = material;
344  mesh = meshFilter.mesh;
345 
346  // Create our first batch of sprites:
347  EnlargeArrays(allocBlockSize);
348 
349  // Move the object to the origin so the objects drawn will not
350  // be offset from the objects they are intended to represent.
351  transform.position = Vector3.zero;
352  transform.rotation = Quaternion.identity;
353  }
354 
355  // Allocates initial arrays
356  protected void InitArrays()
357  {
358  sprites = new Sprite[1];
359  sprites[0] = new Sprite();
360  vertices = new Vector3[4];
361  UVs = new Vector2[4];
362  colors = new Color[4];
363  triIndices = new int[6];
364  }
365 
366  // Enlarges the sprite array by the specified count and also resizes
367  // the UV and vertex arrays by the necessary corresponding amount.
368  // Returns the index of the first newly allocated element
369  // (ex: if the sprite array was already 10 elements long and is
370  // enlarged by 10 elements resulting in a total length of 20,
371  // EnlargeArrays() will return 10, indicating that element 10 is the
372  // first of the newly allocated elements.)
373  protected int EnlargeArrays(int count)
374  {
375  int firstNewElement;
376 
377  if (sprites == null)
378  {
379  InitArrays();
380  firstNewElement = 0;
381  count = count - 1; // Allocate one less since InitArrays already allocated one sprite for us
382  }
383  else
384  firstNewElement = sprites.Length;
385 
386  // Resize sprite array:
387  Sprite[] tempSprites = sprites;
388  sprites = new Sprite[sprites.Length + count];
389  tempSprites.CopyTo(sprites, 0);
390 
391  // Vertices:
392  Vector3[] tempVerts = vertices;
393  vertices = new Vector3[vertices.Length + count*4];
394  tempVerts.CopyTo(vertices, 0);
395 
396  // UVs:
397  Vector2[] tempUVs = UVs;
398  UVs = new Vector2[UVs.Length + count*4];
399  tempUVs.CopyTo(UVs, 0);
400 
401  // Colors:
402  Color[] tempColors = colors;
403  colors = new Color[colors.Length + count * 4];
404  tempColors.CopyTo(colors, 0);
405 
406  // Triangle indices:
407  int[] tempTris = triIndices;
408  triIndices = new int[triIndices.Length + count*6];
409  tempTris.CopyTo(triIndices, 0);
410 
411  // Inform existing sprites of the new vertex and UV buffers:
412  for (int i = 0; i < firstNewElement; ++i)
413  {
414  sprites[i].SetBuffers(vertices, UVs);
415  }
416 
417  // Setup the newly-added sprites and Add them to the list of available
418  // sprite blocks. Also initialize the triangle indices while we're at it:
419  for (int i = firstNewElement; i < sprites.Length; ++i)
420  {
421  // Create and setup sprite:
422 
423  sprites[i] = new Sprite();
424  sprites[i].index = i;
425  sprites[i].manager = this;
426 
427  sprites[i].SetBuffers(vertices, UVs);
428 
429  // Setup indices of the sprite's vertices in the vertex buffer:
430  sprites[i].mv1 = i * 4 + 0;
431  sprites[i].mv2 = i * 4 + 1;
432  sprites[i].mv3 = i * 4 + 2;
433  sprites[i].mv4 = i * 4 + 3;
434 
435  // Setup the indices of the sprite's UV entries in the UV buffer:
436  sprites[i].uv1 = i * 4 + 0;
437  sprites[i].uv2 = i * 4 + 1;
438  sprites[i].uv3 = i * 4 + 2;
439  sprites[i].uv4 = i * 4 + 3;
440 
441  // Setup the indices to the color values:
442  sprites[i].cv1 = i * 4 + 0;
443  sprites[i].cv2 = i * 4 + 1;
444  sprites[i].cv3 = i * 4 + 2;
445  sprites[i].cv4 = i * 4 + 3;
446 
447  // Setup the default color:
448  sprites[i].SetColor(Color.white);
449 
450  // Add as an available sprite:
451  availableBlocks.Add(sprites[i]);
452 
453  // Init triangle indices:
454  if(winding == WINDING_ORDER.CCW)
455  { // Counter-clockwise winding
456  triIndices[i * 6 + 0] = i * 4 + 0; // 0_ 2 0 ___ 3
457  triIndices[i * 6 + 1] = i * 4 + 1; // | / Verts: | /|
458  triIndices[i * 6 + 2] = i * 4 + 3; // 1|/ 1|/__|2
459 
460  triIndices[i * 6 + 3] = i * 4 + 3; // 3
461  triIndices[i * 6 + 4] = i * 4 + 1; // /|
462  triIndices[i * 6 + 5] = i * 4 + 2; // 4/_|5
463  }
464  else
465  { // Clockwise winding
466  triIndices[i * 6 + 0] = i * 4 + 0; // 0_ 1 0 ___ 3
467  triIndices[i * 6 + 1] = i * 4 + 3; // | / Verts: | /|
468  triIndices[i * 6 + 2] = i * 4 + 1; // 2|/ 1|/__|2
469 
470  triIndices[i * 6 + 3] = i * 4 + 3; // 3
471  triIndices[i * 6 + 4] = i * 4 + 2; // /|
472  triIndices[i * 6 + 5] = i * 4 + 1; // 5/_|4
473  }
474 
475  // Add the index of this sprite to the draw order list
476  spriteDrawOrder.Add(sprites[i]);
477  }
478 
479  vertsChanged = true;
480  uvsChanged = true;
481  colorsChanged = true;
482  vertCountChanged = true;
483 
484  return firstNewElement;
485  }
486 
487  // Adds a sprite to the manager at the location and rotation of the client
488  // GameObject and with its transform. Returns a reference to the new sprite
489  // Width and height are in world space units
490  // leftPixelX and bottomPixelY- the bottom-left position of the desired portion of the texture, in pixels
491  // pixelWidth and pixelHeight - the dimensions of the desired portion of the texture, in pixels
492  public Sprite AddSprite(GameObject client, float width, float height, int leftPixelX, int bottomPixelY, int pixelWidth, int pixelHeight, bool billboarded)
493  {
494  return AddSprite(client, width, height, PixelCoordToUVCoord(leftPixelX, bottomPixelY), PixelSpaceToUVSpace(pixelWidth, pixelHeight), billboarded);
495  }
496 
497  // Adds a sprite to the manager at the location and rotation of the client
498  // GameObject and with its transform. Returns a reference to the new sprite
499  // Width and height are in world space units
500  // lowerLeftUV - the UV coordinate for the upper-left corner
501  // UVDimensions - the distance from lowerLeftUV to place the other UV coords
502  public Sprite AddSprite(GameObject client, float width, float height, Vector2 lowerLeftUV, Vector2 UVDimensions, bool billboarded)
503  {
504  int spriteIndex;
505 
506  // Get an available sprite:
507  if (availableBlocks.Count < 1)
508  EnlargeArrays(allocBlockSize); // If we're out of available sprites, allocate some more:
509 
510  // Use a sprite from the list of available blocks:
511  spriteIndex = ((Sprite)availableBlocks[0]).index;
512  availableBlocks.RemoveAt(0); // Now that we're using this one, remove it from the available list
513 
514  // Assign the new sprite:
515  Sprite newSprite = sprites[spriteIndex];
516  newSprite.client = client;
517  newSprite.lowerLeftUV = lowerLeftUV;
518  newSprite.uvDimensions = UVDimensions;
519 
520  switch(plane)
521  {
522  case SPRITE_PLANE.XY:
523  newSprite.SetSizeXY(width, height);
524  break;
525  case SPRITE_PLANE.XZ:
526  newSprite.SetSizeXZ(width, height);
527  break;
528  case SPRITE_PLANE.YZ:
529  newSprite.SetSizeYZ(width, height);
530  break;
531  default:
532  newSprite.SetSizeXY(width, height);
533  break;
534  }
535 
536  // Save this to an active list now that it is in-use:
537  if(billboarded)
538  {
539  newSprite.billboarded = true;
540  activeBillboards.Add(newSprite);
541  }
542  else
543  activeBlocks.Add(newSprite);
544 
545  // Transform the sprite:
546  newSprite.Transform();
547 
548  // Setup the UVs:
549  UVs[newSprite.uv1] = lowerLeftUV + Vector2.up * UVDimensions.y; // Upper-left
550  UVs[newSprite.uv2] = lowerLeftUV; // Lower-left
551  UVs[newSprite.uv3] = lowerLeftUV + Vector2.right * UVDimensions.x;// Lower-right
552  UVs[newSprite.uv4] = lowerLeftUV + UVDimensions; // Upper-right
553 
554  // Set our flags:
555  vertsChanged = true;
556  uvsChanged = true;
557 
558  return newSprite;
559  }
560 
561  public void SetBillboarded(Sprite sprite)
562  {
563  // Make sure the sprite isn't in the active list
564  // or else it'll get handled twice:
565  activeBlocks.Remove(sprite);
566  activeBillboards.Add(sprite);
567  }
568 
569  public void RemoveSprite(Sprite sprite)
570  {
571  sprite.SetSizeXY(0,0);
572  sprite.v1 = Vector3.zero;
573  sprite.v2 = Vector3.zero;
574  sprite.v3 = Vector3.zero;
575  sprite.v4 = Vector3.zero;
576 
577  vertices[sprite.mv1] = sprite.v1;
578  vertices[sprite.mv2] = sprite.v2;
579  vertices[sprite.mv3] = sprite.v3;
580  vertices[sprite.mv4] = sprite.v4;
581 
582  // Remove the sprite from the billboarded list
583  // since that list should only contain active
584  // sprites:
585  if (sprite.billboarded)
586  activeBillboards.Remove(sprite);
587  else
588  activeBlocks.Remove(sprite);
589 
590  // Clean the sprite's settings:
591  sprite.Clear();
592 
593  availableBlocks.Add(sprite);
594 
595  vertsChanged = true;
596  }
597 
598  public void HideSprite(Sprite sprite)
599  {
600  // Remove the sprite from the billboarded list
601  // since that list should only contain sprites
602  // we intend to transform:
603  if (sprite.billboarded)
604  activeBillboards.Remove(sprite);
605  else
606  activeBlocks.Remove(sprite);
607 
608  sprite.m_hidden___DoNotAccessExternally = true;
609 
610  vertices[sprite.mv1] = Vector3.zero;
611  vertices[sprite.mv2] = Vector3.zero;
612  vertices[sprite.mv3] = Vector3.zero;
613  vertices[sprite.mv4] = Vector3.zero;
614 
615  vertsChanged = true;
616  }
617 
618  public void ShowSprite(Sprite sprite)
619  {
620  // Only show the sprite if it has a client:
621  if(sprite.client == null)
622  return;
623 
625  return;
626 
627  sprite.m_hidden___DoNotAccessExternally = false;
628 
629  // Update the vertices:
630  sprite.Transform();
631 
632  if (sprite.billboarded)
633  activeBillboards.Add(sprite);
634  else
635  activeBlocks.Add(sprite);
636 
637  vertsChanged = true;
638  }
639 
640  // Moves the specified sprite to the end of the drawing order
641  public void MoveToFront(Sprite s)
642  {
643  int[] indices = new int[6];
644  int offset = spriteDrawOrder.IndexOf(s) * 6;
645 
646  if (offset < 0)
647  return;
648 
649  // Save our indices:
650  indices[0] = triIndices[offset];
651  indices[1] = triIndices[offset + 1];
652  indices[2] = triIndices[offset + 2];
653  indices[3] = triIndices[offset + 3];
654  indices[4] = triIndices[offset + 4];
655  indices[5] = triIndices[offset + 5];
656 
657  // Shift all indices from here forward down 6 slots (each sprite occupies 6 index slots):
658  for (int i = offset; i < triIndices.Length - 6; i += 6)
659  {
660  triIndices[i] = triIndices[i+6];
661  triIndices[i+1] = triIndices[i+7];
662  triIndices[i+2] = triIndices[i+8];
663  triIndices[i+3] = triIndices[i+9];
664  triIndices[i+4] = triIndices[i+10];
665  triIndices[i+5] = triIndices[i+11];
666 
667  spriteDrawOrder[i / 6] = spriteDrawOrder[i / 6 + 1];
668  }
669 
670  // Place our desired index value at the end:
671  triIndices[triIndices.Length - 6] = indices[0];
672  triIndices[triIndices.Length - 5] = indices[1];
673  triIndices[triIndices.Length - 4] = indices[2];
674  triIndices[triIndices.Length - 3] = indices[3];
675  triIndices[triIndices.Length - 2] = indices[4];
676  triIndices[triIndices.Length - 1] = indices[5];
677 
678  // Update the sprite's index offset:
679  spriteDrawOrder[spriteDrawOrder.Count - 1] = s.index;
680 
681  vertCountChanged = true;
682  }
683 
684  // Moves the specified sprite to the start of the drawing order
685  public void MoveToBack(Sprite s)
686  {
687  int[] indices = new int[6];
688  int offset = spriteDrawOrder.IndexOf(s) * 6;
689 
690  if (offset < 0)
691  return;
692 
693  // Save our indices:
694  indices[0] = triIndices[offset];
695  indices[1] = triIndices[offset + 1];
696  indices[2] = triIndices[offset + 2];
697  indices[3] = triIndices[offset + 3];
698  indices[4] = triIndices[offset + 4];
699  indices[5] = triIndices[offset + 5];
700 
701  // Shift all indices from here back up 6 slots (each sprite occupies 6 index slots):
702  for(int i=offset; i>5; i-=6)
703  {
704  triIndices[i] = triIndices[i-6];
705  triIndices[i+1] = triIndices[i-5];
706  triIndices[i+2] = triIndices[i-4];
707  triIndices[i+3] = triIndices[i-3];
708  triIndices[i+4] = triIndices[i-2];
709  triIndices[i+5] = triIndices[i-1];
710 
711  spriteDrawOrder[i / 6] = spriteDrawOrder[i / 6 - 1];
712  }
713 
714  // Place our desired index value at the beginning:
715  triIndices[0] = indices[0];
716  triIndices[1] = indices[1];
717  triIndices[2] = indices[2];
718  triIndices[3] = indices[3];
719  triIndices[4] = indices[4];
720  triIndices[5] = indices[5];
721 
722  // Update the sprite's index offset:
723  spriteDrawOrder[0] = s.index;
724 
725  vertCountChanged = true;
726  }
727 
728  // Moves the first sprite in front of the second sprite by
729  // placing it later in the draw order. If the sprite is already
730  // in front of the reference sprite, nothing is changed:
731  public void MoveInfrontOf(Sprite toMove, Sprite reference)
732  {
733  int[] indices = new int[6];
734  int offset = spriteDrawOrder.IndexOf(toMove) * 6;
735  int refOffset = spriteDrawOrder.IndexOf(reference) * 6;
736 
737  if (offset < 0)
738  return;
739 
740  // Check to see if the sprite is already in front:
741  if(offset > refOffset)
742  return;
743 
744  // Save our indices:
745  indices[0] = triIndices[offset];
746  indices[1] = triIndices[offset + 1];
747  indices[2] = triIndices[offset + 2];
748  indices[3] = triIndices[offset + 3];
749  indices[4] = triIndices[offset + 4];
750  indices[5] = triIndices[offset + 5];
751 
752  // Shift all indices from here to the reference sprite down 6 slots (each sprite occupies 6 index slots):
753  for (int i = offset; i < refOffset; i += 6)
754  {
755  triIndices[i] = triIndices[i+6];
756  triIndices[i+1] = triIndices[i+7];
757  triIndices[i+2] = triIndices[i+8];
758  triIndices[i+3] = triIndices[i+9];
759  triIndices[i+4] = triIndices[i+10];
760  triIndices[i+5] = triIndices[i+11];
761 
762  spriteDrawOrder[i / 6] = spriteDrawOrder[i / 6 + 1];
763  }
764 
765  // Place our desired index value at the destination:
766  triIndices[refOffset] = indices[0];
767  triIndices[refOffset+1] = indices[1];
768  triIndices[refOffset+2] = indices[2];
769  triIndices[refOffset+3] = indices[3];
770  triIndices[refOffset+4] = indices[4];
771  triIndices[refOffset+5] = indices[5];
772 
773  // Update the sprite's index offset:
774  spriteDrawOrder[refOffset/6] = toMove.index;
775 
776  vertCountChanged = true;
777  }
778 
779  // Moves the first sprite behind the second sprite by
780  // placing it earlier in the draw order. If the sprite
781  // is already behind, nothing is done:
782  public void MoveBehind(Sprite toMove, Sprite reference)
783  {
784  int[] indices = new int[6];
785  int offset = spriteDrawOrder.IndexOf(toMove) * 6;
786  int refOffset = spriteDrawOrder.IndexOf(reference) * 6;
787 
788  if (offset < 0)
789  return;
790 
791  // Check to see if the sprite is already behind:
792  if(offset < refOffset)
793  return;
794 
795  // Save our indices:
796  indices[0] = triIndices[offset];
797  indices[1] = triIndices[offset + 1];
798  indices[2] = triIndices[offset + 2];
799  indices[3] = triIndices[offset + 3];
800  indices[4] = triIndices[offset + 4];
801  indices[5] = triIndices[offset + 5];
802 
803  // Shift all indices from here to the reference sprite up 6 slots (each sprite occupies 6 index slots):
804  for (int i = offset; i > refOffset; i -= 6)
805  {
806  triIndices[i] = triIndices[i-6];
807  triIndices[i+1] = triIndices[i-5];
808  triIndices[i+2] = triIndices[i-4];
809  triIndices[i+3] = triIndices[i-3];
810  triIndices[i+4] = triIndices[i-2];
811  triIndices[i+5] = triIndices[i-1];
812 
813  spriteDrawOrder[i / 6] = spriteDrawOrder[i / 6 - 1];
814  }
815 
816  // Place our desired index value at the destination:
817  triIndices[refOffset] = indices[0];
818  triIndices[refOffset+1] = indices[1];
819  triIndices[refOffset+2] = indices[2];
820  triIndices[refOffset+3] = indices[3];
821  triIndices[refOffset+4] = indices[4];
822  triIndices[refOffset+5] = indices[5];
823 
824  // Update the sprite's index offset:
825  spriteDrawOrder[refOffset/6] = toMove.index;
826 
827  vertCountChanged = true;
828  }
829 
830  // Rebuilds the drawing order based upon the drawing order buffer
831  public void SortDrawingOrder()
832  {
833  Sprite s;
834 
835  spriteDrawOrder.Sort(drawOrderComparer);
836 
837  // Now reconstitute the triIndices in the order we want:
838  if (winding == WINDING_ORDER.CCW)
839  {
840  for (int i = 0; i < spriteDrawOrder.Count; ++i)
841  {
842  s = (Sprite) spriteDrawOrder[i];
843 
844  // Counter-clockwise winding
845  triIndices[i * 6 + 0] = s.mv1; // 0_ 2 1 ___ 4
846  triIndices[i * 6 + 1] = s.mv2; // | / Verts: | /|
847  triIndices[i * 6 + 2] = s.mv4; // 1|/ 2|/__|3
848 
849  triIndices[i * 6 + 3] = s.mv4; // 3
850  triIndices[i * 6 + 4] = s.mv2; // /|
851  triIndices[i * 6 + 5] = s.mv3; // 4/_|5
852  }
853  }
854  else
855  {
856  for (int i = 0; i < spriteDrawOrder.Count; ++i)
857  {
858  s = (Sprite)spriteDrawOrder[i];
859 
860  // Clockwise winding
861  triIndices[i * 6 + 0] = s.mv1; // 0_ 1 1 ___ 4
862  triIndices[i * 6 + 1] = s.mv2; // | / Verts: | /|
863  triIndices[i * 6 + 2] = s.mv4; // 2|/ 2|/__|3
864 
865  triIndices[i * 6 + 3] = s.mv4; // 3
866  triIndices[i * 6 + 4] = s.mv2; // /|
867  triIndices[i * 6 + 5] = s.mv3; // 5/_|4
868  }
869  }
870 
871  vertCountChanged = true;
872  }
873 
874  public void AnimateSprite(Sprite s)
875  {
876  // Add this sprite to our playingAnimation list:
877  playingAnimations.Add(s);
878  }
879 
880  public void StopAnimation(Sprite s)
881  {
882  playingAnimations.Remove(s);
883  }
884 
885  public Sprite GetSprite(int i)
886  {
887  if (i < sprites.Length)
888  return sprites[i];
889  else
890  return null;
891  }
892 
893  // Updates the vertices of a sprite based on the transform
894  // of its client GameObject
895  public void Transform(Sprite sprite)
896  {
897  sprite.Transform();
898 
899  vertsChanged = true;
900  }
901 
902  // Updates the vertices of a sprite such that it is oriented
903  // more or less toward the camera
904  public void TransformBillboarded(Sprite sprite)
905  {
906  Vector3 pos = sprite.clientTransform.position;
907  Transform t = Camera.main.transform;
908 
909  vertices[sprite.mv1] = pos + t.TransformDirection(sprite.v1);
910  vertices[sprite.mv2] = pos + t.TransformDirection(sprite.v2);
911  vertices[sprite.mv3] = pos + t.TransformDirection(sprite.v3);
912  vertices[sprite.mv4] = pos + t.TransformDirection(sprite.v4);
913 
914  vertsChanged = true;
915  }
916 
917  // Informs the SpriteManager that some vertices have changed position
918  // and the mesh needs to be reconstructed accordingly
919  public void UpdatePositions()
920  {
921  vertsChanged = true;
922  }
923 
924  // Updates the UVs of the specified sprite and copies the new values
925  // into the mesh object.
926  public void UpdateUV(Sprite sprite)
927  {
928  UVs[sprite.uv1] = sprite.lowerLeftUV + Vector2.up * sprite.uvDimensions.y; // Upper-left
929  UVs[sprite.uv2] = sprite.lowerLeftUV; // Lower-left
930  UVs[sprite.uv3] = sprite.lowerLeftUV + Vector2.right * sprite.uvDimensions.x;// Lower-right
931  UVs[sprite.uv4] = sprite.lowerLeftUV + sprite.uvDimensions; // Upper-right
932 
933  uvsChanged = true;
934  }
935 
936  // Updates the color values of the specified sprite and copies the
937  // new values into the mesh object.
938  public void UpdateColors(Sprite sprite)
939  {
940  colors[sprite.cv1] = sprite.color;
941  colors[sprite.cv2] = sprite.color;
942  colors[sprite.cv3] = sprite.color;
943  colors[sprite.cv4] = sprite.color;
944 
945  colorsChanged = true;
946  }
947 
948  // Instructs the manager to recalculate the bounds of the mesh
949  public void UpdateBounds()
950  {
951  updateBounds = true;
952  }
953 
954  // Schedules a recalculation of the mesh bounds to occur at a
955  // regular interval (given in seconds):
956  public void ScheduleBoundsUpdate(float seconds)
957  {
958  boundUpdateInterval = seconds;
959  InvokeRepeating("UpdateBounds", seconds, seconds);
960  }
961 
962  // Cancels any previously scheduled bounds recalculations:
963  public void CancelBoundsUpdate()
964  {
965  CancelInvoke("UpdateBounds");
966  }
967 
968  // Use this for initialization
969  void Start ()
970  {
971 
972  }
973 
974  // LateUpdate is called once per frame
975  virtual public void LateUpdate ()
976  {
977  // See if we have any active animations:
978  if(playingAnimations.Count > 0)
979  {
980  animTimeElapsed = Time.deltaTime;
981 
982  for(i=0; i<playingAnimations.Count; ++i)
983  {
984  tempSprite = (Sprite)playingAnimations[i];
985 
986  // Step the animation, and if it has finished
987  // playing, remove it from the playing list:
988  if (!tempSprite.StepAnim(animTimeElapsed))
989  playingAnimations.Remove(tempSprite);
990  }
991 
992  uvsChanged = true;
993  }
994 
995  // Were changes made to the mesh since last time?
996  if (vertCountChanged)
997  {
998  vertCountChanged = false;
999  colorsChanged = false;
1000  vertsChanged = false;
1001  uvsChanged = false;
1002  updateBounds = false;
1003 
1004  mesh.Clear();
1005  mesh.vertices = vertices;
1006  mesh.uv = UVs;
1007  mesh.colors = colors;
1008  //mesh.normals = normals;
1009  mesh.triangles = triIndices;
1010  }
1011  else
1012  {
1013  if (vertsChanged)
1014  {
1015  vertsChanged = false;
1016 
1017  if (autoUpdateBounds)
1018  updateBounds = true;
1019 
1020  mesh.vertices = vertices;
1021  }
1022 
1023  if (updateBounds)
1024  {
1025  mesh.RecalculateBounds();
1026  updateBounds = false;
1027  }
1028 
1029  if (colorsChanged)
1030  {
1031  colorsChanged = false;
1032 
1033  mesh.colors = colors;
1034  }
1035 
1036  if (uvsChanged)
1037  {
1038  uvsChanged = false;
1039  mesh.uv = UVs;
1040  }
1041  }
1042  }
1043 }
1044 
float framerate
bool loopReverse
Vector2[] UVs
GameObject client
Definition: Sprite.cs:160
Vector2 PixelSpaceToUVSpace(Vector2 xy)
void UpdateColors(Sprite sprite)
int mv1
Definition: Sprite.cs:109
void Transform()
Definition: Sprite.cs:302
void AnimateSprite(Sprite s)
void Transform(Sprite sprite)
Sprite GetSprite(int i)
Vector2 PixelCoordToUVCoord(Vector2 xy)
Vector2 lowerLeftUV
Definition: Sprite.cs:173
Sprite AddSprite(GameObject client, float width, float height, int leftPixelX, int bottomPixelY, int pixelWidth, int pixelHeight, bool billboarded)
SPRITE_PLANE plane
float animTimeElapsed
Vector2[] frames
int cv1
Definition: Sprite.cs:119
void PlayInReverse()
bool StepAnim(float time)
Definition: Sprite.cs:351
void SetSizeXZ(float width, float height)
Definition: Sprite.cs:268
int cv4
Definition: Sprite.cs:122
bool m_hidden___DoNotAccessExternally
Definition: Sprite.cs:92
Color color
Definition: Sprite.cs:99
void MoveBehind(Sprite toMove, Sprite reference)
void TransformBillboarded(Sprite sprite)
void MoveInfrontOf(Sprite toMove, Sprite reference)
Vector2[] BuildUVAnim(Vector2 start, Vector2 cellSize, int cols, int rows, int totalCells, float fps)
int uv4
Definition: Sprite.cs:117
int uv3
Definition: Sprite.cs:116
Vector3 v3
Definition: Sprite.cs:106
MeshFilter meshFilter
Vector2 PixelSpaceToUVSpace(int x, int y)
void UpdateBounds()
void Clear()
Definition: Sprite.cs:229
int mv2
Definition: Sprite.cs:110
Vector3 v4
Definition: Sprite.cs:107
void StopAnimation(Sprite s)
void ScheduleBoundsUpdate(float seconds)
void SortDrawingOrder()
int uv2
Definition: Sprite.cs:115
bool billboarded
Definition: Sprite.cs:203
void MoveToFront(Sprite s)
Vector3[] vertices
void UpdatePositions()
Vector2 PixelCoordToUVCoord(int x, int y)
int cv2
Definition: Sprite.cs:120
int index
Definition: Sprite.cs:101
int mv3
Definition: Sprite.cs:111
void MoveToBack(Sprite s)
virtual void LateUpdate()
float boundUpdateInterval
Definition: Sprite.cs:83
void ShowSprite(Sprite sprite)
void HideSprite(Sprite sprite)
Sprite[] sprites
void SetColor(Color c)
Definition: Sprite.cs:328
Transform clientTransform
Definition: Sprite.cs:97
Material material
void SetBuffers(Vector3[] v, Vector2[] uv)
Definition: Sprite.cs:294
void SetSizeXY(float width, float height)
Definition: Sprite.cs:255
void SetAnim(Vector2[] anim)
void AppendAnim(Vector2[] anim)
MeshRenderer meshRenderer
void UpdateUV(Sprite sprite)
void SetSizeYZ(float width, float height)
Definition: Sprite.cs:281
Sprite AddSprite(GameObject client, float width, float height, Vector2 lowerLeftUV, Vector2 UVDimensions, bool billboarded)
Vector3 v2
Definition: Sprite.cs:105
int uv1
Definition: Sprite.cs:114
Vector2 uvDimensions
Definition: Sprite.cs:183
int cv3
Definition: Sprite.cs:121
Vector3 v1
Definition: Sprite.cs:104
void SetBillboarded(Sprite sprite)
int mv4
Definition: Sprite.cs:112
bool GetNextFrame(ref Vector2 uv)
int EnlargeArrays(int count)
void RemoveSprite(Sprite sprite)
SpriteManager manager
Definition: Sprite.cs:154
void CancelBoundsUpdate()