MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
imagelayer.cpp
1 //© Copyright 2010 - 2012 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _uiimagelayer_cpp
41 #define _uiimagelayer_cpp
42 
43 #include "UI/imagelayer.h"
44 #include "UI/quadrenderable.h"
45 #include "UI/screen.h"
46 
47 namespace Mezzanine
48 {
49  namespace UI
50  {
52  RenderLayer(ParentRenderable),
53  LayerSprite(NULL),
54  BorderWidth(0)
55  {
56  this->FillColours[0] = ColourValue::White();
57  this->FillColours[1] = ColourValue::White();
58  this->FillColours[2] = ColourValue::White();
59  this->FillColours[3] = ColourValue::White();
60  this->BorderColours[0] = ColourValue::Black();
61  this->BorderColours[1] = ColourValue::Black();
62  this->BorderColours[2] = ColourValue::Black();
63  this->BorderColours[3] = ColourValue::Black();
64  }
65 
67  { }
68 
69  void ImageLayer::RedrawImpl(bool Force)
70  {
71  // Get the Texel Offsets
72  Real TexelOffsetX = this->Parent->GetScreen()->GetTexelOffsetX();
73  Real TexelOffsetY = this->Parent->GetScreen()->GetTexelOffsetY();
74 
75  // Get the parent rect and apply the scaling
76  Rect ActDims = this->GetAreaRect();
77 
78  // Apply the texel offsets
79  Vector2 TopLeft, TopRight, BottomLeft, BottomRight;
80  TopLeft.X = ActDims.Position.X + TexelOffsetX; TopLeft.Y = ActDims.Position.Y + TexelOffsetY;
81  TopRight.X = (ActDims.Position.X + ActDims.Size.X) + TexelOffsetX; TopRight.Y = ActDims.Position.Y + TexelOffsetY;
82  BottomLeft.X = ActDims.Position.X + TexelOffsetX; BottomLeft.Y = (ActDims.Position.Y + ActDims.Size.Y) + TexelOffsetY;
83  BottomRight.X = (ActDims.Position.X + ActDims.Size.X) + TexelOffsetX; BottomRight.Y = (ActDims.Position.Y + ActDims.Size.Y) + TexelOffsetY;
84 
85  // Border and rotation
86  if(0.0 != this->BorderWidth)
87  {
88  Vector2 OuterTopLeft = TopLeft, OuterTopRight = TopRight, OuterBottomLeft = BottomLeft, OuterBottomRight = BottomRight;
89  OuterTopLeft.X -= BorderWidth; OuterTopLeft.Y -= BorderWidth;
90  OuterTopRight.X += BorderWidth; OuterTopRight.Y -= BorderWidth;
91  OuterBottomLeft.X -= BorderWidth; OuterBottomLeft.Y += BorderWidth;
92  OuterBottomRight.X += BorderWidth; OuterBottomRight.Y += BorderWidth;
93 
94  this->RotationTransform(TopLeft,TopRight,BottomLeft,BottomRight);
95  this->RotationTransform(OuterTopLeft,OuterTopRight,OuterBottomLeft,OuterBottomRight);
96  this->DrawBorder(TopLeft,TopRight,BottomLeft,BottomRight,
97  OuterTopLeft,OuterTopRight,OuterBottomLeft,OuterBottomRight);
98  }else{
99  this->RotationTransform(TopLeft,TopRight,BottomLeft,BottomRight);
100  }
101  // Fill
102  this->DrawFill(TopLeft,TopRight,BottomLeft,BottomRight);
103  }
104 
105  void ImageLayer::DrawBorder(const Vector2& TopLeft, const Vector2& TopRight, const Vector2& BottomLeft, const Vector2& BottomRight,
106  const Vector2& OuterTopLeft, const Vector2& OuterTopRight, const Vector2& OuterBottomLeft, const Vector2& OuterBottomRight)
107  {
109 
110  // North
111  if( 0 != this->BorderColours[UI::Border_North].AlphaChannel )
112  {
113  this->PushTriangle(TopLeft, OuterTopRight, OuterTopLeft, WP, this->BorderColours[UI::Border_North], this->PriAtlas);
114  this->PushTriangle(TopLeft, TopRight, OuterTopRight, WP, this->BorderColours[UI::Border_North], this->PriAtlas);
115  }
116 
117  // East
118  if( 0 != this->BorderColours[UI::Border_East].AlphaChannel )
119  {
120  this->PushTriangle(BottomRight, OuterTopRight, TopRight, WP, this->BorderColours[UI::Border_East], this->PriAtlas);
121  this->PushTriangle(BottomRight, OuterBottomRight, OuterTopRight, WP, this->BorderColours[UI::Border_East], this->PriAtlas);
122  }
123 
124  // South
125  if( 0 != this->BorderColours[UI::Border_South].AlphaChannel )
126  {
127  this->PushTriangle(OuterBottomLeft, BottomRight, BottomLeft, WP, this->BorderColours[UI::Border_South], this->PriAtlas);
128  this->PushTriangle(OuterBottomLeft, OuterBottomRight, BottomRight, WP, this->BorderColours[UI::Border_South], this->PriAtlas);
129  }
130 
131  // West
132  if( 0 != this->BorderColours[UI::Border_West].AlphaChannel )
133  {
134  this->PushTriangle(OuterBottomLeft, TopLeft, OuterTopLeft, WP, BorderColours[UI::Border_West], this->PriAtlas);
135  this->PushTriangle(OuterBottomLeft, BottomLeft, TopLeft, WP, BorderColours[UI::Border_West], this->PriAtlas);
136  }
137  }
138 
139  void ImageLayer::DrawFill(const Vector2& TopLeft, const Vector2& TopRight, const Vector2& BottomLeft, const Vector2& BottomRight)
140  {
141  if(!this->IsCompletelyTransparent())
142  {
143  Vector2 UVs[4];
144  if( this->LayerSprite == NULL ) {
145  UVs[UI::QC_TopLeft] = UVs[UI::QC_TopRight] = UVs[UI::QC_BottomRight] = UVs[UI::QC_BottomLeft] = this->Parent->GetScreen()->GetWhitePixel(this->PriAtlas);
146  }else{
147  UVs[UI::QC_TopLeft] = this->LayerSprite->GetRelativeAtlasCoords(UI::QC_TopLeft);
148  UVs[UI::QC_TopRight] = this->LayerSprite->GetRelativeAtlasCoords(UI::QC_TopRight);
149  UVs[UI::QC_BottomRight] = this->LayerSprite->GetRelativeAtlasCoords(UI::QC_BottomRight);
150  UVs[UI::QC_BottomLeft] = this->LayerSprite->GetRelativeAtlasCoords(UI::QC_BottomLeft);
151  }
152 
153  // Triangle A
154  this->PushVertex(BottomLeft.X, BottomLeft.Y, UVs[UI::QC_BottomLeft], this->FillColours[UI::QC_BottomLeft], this->PriAtlas); // Left/Bottom 3
155  this->PushVertex(TopRight.X, TopRight.Y, UVs[UI::QC_TopRight], this->FillColours[UI::QC_TopRight], this->PriAtlas); // Right/Top 1
156  this->PushVertex(TopLeft.X, TopLeft.Y, UVs[UI::QC_TopLeft], this->FillColours[UI::QC_TopLeft], this->PriAtlas); // Left/Top 0
157 
158  // Triangle B
159  this->PushVertex(BottomLeft.X, BottomLeft.Y, UVs[UI::QC_BottomLeft], this->FillColours[UI::QC_BottomLeft], this->PriAtlas); // Left/Bottom 3
160  this->PushVertex(BottomRight.X, BottomRight.Y, UVs[UI::QC_BottomRight], this->FillColours[UI::QC_BottomRight], this->PriAtlas); // Right/Bottom 2
161  this->PushVertex(TopRight.X, TopRight.Y, UVs[UI::QC_TopRight], this->FillColours[UI::QC_TopRight], this->PriAtlas); // Right/Top 1
162  }
163  }
164 
165  ///////////////////////////////////////////////////////////////////////////////
166  // Utility
167 
169  {
170  return RenderLayer::RLT_Image;
171  }
172 
173  ///////////////////////////////////////////////////////////////////////////////
174  // Fill Methods
175 
176  void ImageLayer::SetColour(const ColourValue& Colour)
177  {
178  this->FillColours[0] = Colour;
179  this->FillColours[1] = Colour;
180  this->FillColours[2] = Colour;
181  this->FillColours[3] = Colour;
182  this->_MarkDirty();
183  }
184 
185  void ImageLayer::SetColour(const UI::QuadCorner Corner, const ColourValue& Colour)
186  {
187  this->FillColours[Corner] = Colour;
188  this->_MarkDirty();
189  }
190 
192  {
193  /*if(PSprite == NULL)
194  {
195  this->PriAtlas = this->Parent->GetScreen()->GetPrimaryAtlas();
196  UVs[0] = UVs[1] = UVs[2] = UVs[3] = Parent->GetScreen()->GetWhitePixel(PriAtlas);
197  this->_MarkDirty();
198  }else{
199  this->PriAtlas = PSprite->GetAtlasName();
200  Real TexelOffsetX = Parent->GetScreen()->GetTexelOffsetX();
201  Real TexelOffsetY = Parent->GetScreen()->GetTexelOffsetY();
202  if(TexelOffsetX) TexelOffsetX /= PSprite->Atlas->GetTextureSize();
203  if(TexelOffsetY) TexelOffsetY /= PSprite->Atlas->GetTextureSize();
204  UVs[0].X = UVs[3].X = PSprite->GetUVLeft();// - TexelOffsetX;
205  UVs[0].Y = UVs[1].Y = PSprite->GetUVTop();// + TexelOffsetY;
206  UVs[1].X = UVs[2].X = PSprite->GetUVRight();// - TexelOffsetX;
207  UVs[2].Y = UVs[3].Y = PSprite->GetUVBottom();// + TexelOffsetY;
208  this->_MarkDirty();
209  }//*/
210  this->PriAtlas = ( PSprite == NULL ? this->Parent->GetScreen()->GetPrimaryAtlas() : PSprite->GetAtlasName() );
211  this->LayerSprite = PSprite;
212  this->_MarkDirty();
213  }
214 
215  void ImageLayer::SetSprite(const String& SpriteName)
216  {
217  Sprite* PSprite = this->Parent->GetScreen()->GetSprite(SpriteName,PriAtlas);
218  this->SetSprite(PSprite);
219  }
220 
221  void ImageLayer::SetSprite(const String& SpriteName, const String& Atlas)
222  {
223  Sprite* PSprite = this->Parent->GetScreen()->GetSprite(SpriteName,Atlas);
224  this->SetSprite(PSprite);
225  }
226 
227  void ImageLayer::SetGradient(const UI::Gradient Grad, const ColourValue& ColourA, const ColourValue& ColourB)
228  {
229  switch(Grad)
230  {
231  case UI::Gradient_NorthSouth:
232  {
233  this->FillColours[0] = ColourA;
234  this->FillColours[1] = ColourA;
235  this->FillColours[2] = ColourB;
236  this->FillColours[3] = ColourB;
237  }
238  case UI::Gradient_WestEast:
239  {
240  this->FillColours[0] = ColourA;
241  this->FillColours[3] = ColourA;
242  this->FillColours[1] = ColourB;
243  this->FillColours[2] = ColourB;
244  }
245  case UI::Gradient_Diagonal_1:
246  {
247  ColourValue Average;
248  Average.RedChannel = (ColourA.RedChannel + ColourB.RedChannel) * 0.5f;
249  Average.GreenChannel = (ColourA.GreenChannel + ColourB.GreenChannel) * 0.5f;
250  Average.BlueChannel = (ColourA.BlueChannel + ColourB.BlueChannel) * 0.5f;
251  Average.AlphaChannel = (ColourA.AlphaChannel + ColourB.AlphaChannel) * 0.5f;
252  this->FillColours[0] = ColourA;
253  this->FillColours[1] = Average;
254  this->FillColours[2] = ColourB;
255  this->FillColours[3] = Average;
256  }
257  case UI::Gradient_Diagonal_2:
258  {
259  ColourValue Average;
260  Average.RedChannel = (ColourA.RedChannel + ColourB.RedChannel) * 0.5f;
261  Average.GreenChannel = (ColourA.GreenChannel + ColourB.GreenChannel) * 0.5f;
262  Average.BlueChannel = (ColourA.BlueChannel + ColourB.BlueChannel) * 0.5f;
263  Average.AlphaChannel = (ColourA.AlphaChannel + ColourB.AlphaChannel) * 0.5f;
264  this->FillColours[0] = Average;
265  this->FillColours[1] = ColourA;
266  this->FillColours[2] = Average;
267  this->FillColours[3] = ColourB;
268  }
269  }
270  this->_MarkDirty();
271  }
272 
274  {
275  return this->FillColours[Corner];
276  }
277 
279  {
280  return ( 0 == this->FillColours[UI::QC_TopLeft].AlphaChannel &&
281  0 == this->FillColours[UI::QC_TopRight].AlphaChannel &&
282  0 == this->FillColours[UI::QC_BottomLeft].AlphaChannel &&
283  0 == this->FillColours[UI::QC_BottomRight].AlphaChannel );
284  }
285 
286  ///////////////////////////////////////////////////////////////////////////////
287  // Border Methods
288 
290  {
291  this->BorderWidth = Width;
292  this->_MarkDirty();
293  }
294 
296  {
297  this->BorderColours[0] = Colour;
298  this->BorderColours[1] = Colour;
299  this->BorderColours[2] = Colour;
300  this->BorderColours[3] = Colour;
301  this->_MarkDirty();
302  }
303 
304  void ImageLayer::SetBorderColour(const UI::Border Side, const ColourValue& Colour)
305  {
306  this->BorderColours[Side] = Colour;
307  this->_MarkDirty();
308  }
309 
310  void ImageLayer::SetBorder(const Real Width, const ColourValue& Colour)
311  {
312  this->SetBorderWidth(Width);
313  this->SetBorderColour(Colour);
314  }
315 
316  void ImageLayer::SetBorder(const Real Width, const ColourValue& North, const ColourValue& South, const ColourValue& East, const ColourValue& West)
317  {
318  this->SetBorderWidth(Width);
319  this->BorderColours[UI::Border_North] = North;
320  this->BorderColours[UI::Border_South] = South;
321  this->BorderColours[UI::Border_East] = East;
322  this->BorderColours[UI::Border_West] = West;
323  }
324 
326  {
327  this->SetBorderWidth(0.0);
329  }
330 
332  {
333  return this->BorderWidth;
334  }
335 
337  {
338  return this->BorderColours[Side];
339  }
340 
341  ///////////////////////////////////////////////////////////////////////////////
342  // Serialization
343 
345  {
347  XML::Node PropertiesNode = SelfRoot.AppendChild( ImageLayer::GetSerializableName() + "Properties" );
348 
349  if( PropertiesNode.AppendAttribute("Version").SetValue("1") &&
350  PropertiesNode.AppendAttribute("BorderWidth").SetValue(this->BorderWidth) &&
351  PropertiesNode.AppendAttribute("SpriteName").SetValue( this->LayerSprite ? this->LayerSprite->Name : "" ) )
352  {
353  XML::Node ScaleNode = PropertiesNode.AppendChild("Scale");
354  this->Scale.ProtoSerialize(ScaleNode);
355 
356  XML::Node FillColoursNode = PropertiesNode.AppendChild("FillColours");
357 
358  XML::Node TopLeftFillNode = FillColoursNode.AppendChild("TopLeft");
359  this->FillColours[UI::QC_TopLeft].ProtoSerialize(TopLeftFillNode);
360 
361  XML::Node TopRightFillNode = FillColoursNode.AppendChild("TopRight");
362  this->FillColours[UI::QC_TopRight].ProtoSerialize(TopRightFillNode);
363 
364  XML::Node BottomLeftFillNode = FillColoursNode.AppendChild("BottomLeft");
365  this->FillColours[UI::QC_BottomLeft].ProtoSerialize(BottomLeftFillNode);
366 
367  XML::Node BottomRightFillNode = FillColoursNode.AppendChild("BottomRight");
368  this->FillColours[UI::QC_BottomRight].ProtoSerialize(BottomRightFillNode);
369 
370  XML::Node BorderColoursNode = PropertiesNode.AppendChild("BorderColours");
371 
372  XML::Node TopLeftBorderNode = BorderColoursNode.AppendChild("TopLeft");
373  this->BorderColours[UI::QC_TopLeft].ProtoSerialize(TopLeftBorderNode);
374 
375  XML::Node TopRightBorderNode = FillColoursNode.AppendChild("TopRight");
376  this->BorderColours[UI::QC_TopRight].ProtoSerialize(TopRightBorderNode);
377 
378  XML::Node BottomLeftBorderNode = FillColoursNode.AppendChild("BottomLeft");
379  this->BorderColours[UI::QC_BottomLeft].ProtoSerialize(BottomLeftBorderNode);
380 
381  XML::Node BottomRightBorderNode = FillColoursNode.AppendChild("BottomRight");
382  this->BorderColours[UI::QC_BottomRight].ProtoSerialize(BottomRightBorderNode);
383 
384  return;
385  }else{
386  SerializeError("Create XML Attribute Values",ImageLayer::GetSerializableName() + "Properties",true);
387  }
388  }
389 
391  {
393  XML::Attribute CurrAttrib;
394  XML::Node PropertiesNode = SelfRoot.GetChild( ImageLayer::GetSerializableName() + "Properties" );
395 
396  if( !PropertiesNode.Empty() ) {
397  if(PropertiesNode.GetAttribute("Version").AsInt() == 1) {
398  CurrAttrib = PropertiesNode.GetAttribute("BorderWidth");
399  if( !CurrAttrib.Empty() )
400  this->BorderWidth = CurrAttrib.AsReal();
401 
402  CurrAttrib = PropertiesNode.GetAttribute("SpriteName");
403  if( !CurrAttrib.Empty() )
404  this->SetSprite( CurrAttrib.AsString() );
405 
406  XML::Node ScaleNode = PropertiesNode.GetChild("Scale").GetFirstChild();
407  if( !ScaleNode.Empty() )
408  this->Scale.ProtoDeSerialize(ScaleNode);
409 
410  XML::Node FillColoursNode = PropertiesNode.GetChild("FillColours");
411  XML::Node TopLeftFillNode = PropertiesNode.GetChild("TopLeft").GetFirstChild();
412  if( !TopLeftFillNode.Empty() )
413  this->FillColours[UI::QC_TopLeft].ProtoDeSerialize(TopLeftFillNode);
414 
415  XML::Node TopRightFillNode = PropertiesNode.GetChild("TopRight").GetFirstChild();
416  if( !TopRightFillNode.Empty() )
417  this->FillColours[UI::QC_TopRight].ProtoDeSerialize(TopRightFillNode);
418 
419  XML::Node BottomLeftFillNode = PropertiesNode.GetChild("BottomLeft").GetFirstChild();
420  if( !BottomLeftFillNode.Empty() )
421  this->FillColours[UI::QC_BottomLeft].ProtoDeSerialize(BottomLeftFillNode);
422 
423  XML::Node BottomRightFillNode = PropertiesNode.GetChild("BottomRight").GetFirstChild();
424  if( !BottomRightFillNode.Empty() )
425  this->FillColours[UI::QC_BottomRight].ProtoDeSerialize(BottomRightFillNode);
426 
427  XML::Node BorderColoursNode = PropertiesNode.GetChild("BorderColours");
428  XML::Node TopLeftBorderNode = PropertiesNode.GetChild("TopLeft").GetFirstChild();
429  if( !TopLeftBorderNode.Empty() )
430  this->BorderColours[UI::QC_TopLeft].ProtoDeSerialize(TopLeftBorderNode);
431 
432  XML::Node TopRightBorderNode = PropertiesNode.GetChild("TopRight").GetFirstChild();
433  if( !TopRightBorderNode.Empty() )
434  this->BorderColours[UI::QC_TopRight].ProtoDeSerialize(TopRightBorderNode);
435 
436  XML::Node BottomLeftBorderNode = PropertiesNode.GetChild("BottomLeft").GetFirstChild();
437  if( !BottomLeftBorderNode.Empty() )
438  this->BorderColours[UI::QC_BottomLeft].ProtoDeSerialize(BottomLeftBorderNode);
439 
440  XML::Node BottomRightBorderNode = PropertiesNode.GetChild("BottomRight").GetFirstChild();
441  if( !BottomRightBorderNode.Empty() )
442  this->BorderColours[UI::QC_BottomRight].ProtoDeSerialize(BottomRightBorderNode);
443  }else{
444  MEZZ_EXCEPTION(Exception::INVALID_VERSION_EXCEPTION,"Incompatible XML Version for " + (ImageLayer::GetSerializableName() + "Properties") + ": Not Version 1.");
445  }
446  }else{
447  MEZZ_EXCEPTION(Exception::II_IDENTITY_NOT_FOUND_EXCEPTION,ImageLayer::GetSerializableName() + "Properties" + " was not found in the provided XML node, which was expected.");
448  }
449  }
450 
452  {
454  }
455 
457  {
458  return "ImageLayer";
459  }
460  }//UI
461 }//Mezzanine
462 
463 #endif