Spinning Topp Logo BlackTopp Studios
inc
convolutionmodifier.cpp
1 // © Copyright 2010 - 2016 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 /*
41  -----------------------------------------------------------------------------
42  This source file is part of ogre-procedural
43 
44  For the latest info, see http://code.google.com/p/ogre-procedural/
45 
46  Copyright (c) 2010-2013 Michael Broutin
47 
48  Permission is hereby granted, free of charge, to any person obtaining a copy
49  of this software and associated documentation files (the "Software"), to deal
50  in the Software without restriction, including without limitation the rights
51  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52  copies of the Software, and to permit persons to whom the Software is
53  furnished to do so, subject to the following conditions:
54 
55  The above copyright notice and this permission notice shall be included in
56  all copies or substantial portions of the Software.
57 
58  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64  THE SOFTWARE.
65  -----------------------------------------------------------------------------
66  */
67 #ifndef _graphicsproceduralconvolutionmodifier_cpp
68 #define _graphicsproceduralconvolutionmodifier_cpp
69 
70 #include "Graphics/Procedural/Texture/convolutionmodifier.h"
71 
72 #include <cstring>
73 
74 namespace Mezzanine
75 {
76  namespace Graphics
77  {
78  namespace Procedural
79  {
81  KernelData(NULL),
82  Divisor(1.0),
83  KernelSize(3),
84  Threshold(128),
85  CalculateEdgeDivisor(true),
86  IncludeAlphaChannel(false)
87  {
88  Integer Mid = 2;
89  if( ( this->KernelSize % 2 ) == 0 ) {
90  Mid = this->KernelSize / 2;
91  }else{
92  Mid = ( ( this->KernelSize - 1 ) / 2 ) + 1;
93  }
94  Whole SquaredSize = this->KernelSize * this->KernelSize;
95  this->KernelData = new Real[ SquaredSize ];
96  memset(this->KernelData,0,SquaredSize * sizeof(Real));
97  this->KernelData[ this->KernelSize * Mid + Mid ] = 1.0;
98  }
99 
101  {
102  if( this->KernelData != NULL ) {
103  delete[] this->KernelData;
104  }
105  }
106 
107  ///////////////////////////////////////////////////////////////////////////////
108  // Utility
109 
111  {
112  Whole TargetWidth = Buffer.GetWidth();
113  Whole TargetHeight = Buffer.GetHeight();
114  Integer Radius = static_cast<Integer>( this->KernelSize ) >> 1;
115  TextureBuffer TempBuffer( Buffer );
116 
117  for( Whole Y = 0 ; Y < TargetHeight ; ++Y )
118  {
119  for( Whole X = 0 ; X < TargetWidth ; ++X )
120  {
121  Integer Red = 0;
122  Integer Green = 0;
123  Integer Blue = 0;
124  Integer Alpha = 0;
125  Integer Div = 0;
126  Integer ProcessedKernelSize = 0;
127 
128  for( UInt8 i = 0 ; i < this->KernelSize ; ++i )
129  {
130  Integer iRad = i - Radius;
131  Integer YPos = static_cast<Integer>(Y) + iRad;
132 
133  if( YPos < 0 )
134  continue;
135  if( YPos >= static_cast<Integer>( TargetHeight ) )
136  break;
137 
138  for( UInt8 j = 0 ; j < this->KernelSize ; ++j )
139  {
140  Integer jRad = j - Radius;
141  Integer XPos = static_cast<Integer>(X) + jRad;
142 
143  if( XPos < 0 )
144  continue;
145  if( XPos < static_cast<Integer>( TargetWidth ) ) {
146  Real KernelVal = this->KernelData[ i * this->KernelSize + j ];
147  ColourValue Pixel = Buffer.GetPixel(XPos,YPos);
148  Div += static_cast<Integer>( KernelVal );
149  KernelVal *= 255.0;
150  Red += static_cast<Integer>( KernelVal * Pixel.RedChannel );
151  Green += static_cast<Integer>( KernelVal * Pixel.GreenChannel );
152  Blue += static_cast<Integer>( KernelVal * Pixel.BlueChannel );
153  Alpha += static_cast<Integer>( KernelVal * Pixel.AlphaChannel );
154 
155  ProcessedKernelSize++;
156  }
157  }
158  }
159 
160  if( ProcessedKernelSize == ( this->KernelSize * this->KernelSize ) ) {
161  Div = static_cast<Integer>( this->Divisor );
162  }else{
163  if( !this->CalculateEdgeDivisor ) {
164  Div = static_cast<Integer>( this->Divisor );
165  }
166  }
167 
168  if( Div != 0 ) {
169  Red /= Div;
170  Green /= Div;
171  Blue /= Div;
172  Alpha /= Div;
173  }
174  Red += ( static_cast<Integer>( this->Threshold ) - 128 );
175  Green += ( static_cast<Integer>( this->Threshold ) - 128 );
176  Blue += ( static_cast<Integer>( this->Threshold ) - 128 );
177  if( this->IncludeAlphaChannel ) {
178  Alpha += ( static_cast<Integer>( this->Threshold ) - 128 );
179  }else{
180  Alpha = static_cast<Integer>( Buffer.GetAlphaByte(X,Y) );
181  }
182 
183  /// @todo The X and Y here was originally swapped when I transposed the code from Ogre Procedural. It didn't seem right so I changed it. Who is wronger?
184  TempBuffer.SetPixelByte( X, Y,
185  static_cast<UInt8>( (Red > 255) ? 255 : ( (Red < 0) ? 0 : Red ) ),
186  static_cast<UInt8>( (Green > 255) ? 255 : ( (Green < 0) ? 0 : Green ) ),
187  static_cast<UInt8>( (Blue > 255) ? 255 : ( (Blue < 0) ? 0 : Blue ) ),
188  static_cast<UInt8>( (Alpha > 255) ? 255 : ( (Alpha < 0) ? 0 : Alpha ) ) );
189  }
190  }
191 
192  Buffer.SetData(TempBuffer);
193  }
194 
196  { return "ConvolutionModifier"; }
197 
198  ///////////////////////////////////////////////////////////////////////////////
199  // Configuration
200 
202  {
203  if( Size < 3 || Size % 2 == 0 ) {
204  return *this;
205  }
206  delete[] this->KernelData;
207  this->KernelSize = Size;
208  this->KernelData = new Real[this->KernelSize * this->KernelSize];
209  for( Integer Y = 0 ; Y < this->KernelSize ; ++Y )
210  {
211  for( Integer X = 0 ; X < this->KernelSize ; ++X )
212  {
213  this->KernelData[ Y * this->KernelSize + X ] = Data[ Y * this->KernelSize + X ];
214  }
215  }
216  this->CalculateDivisor();
217  return *this;
218  }
219 
221  {
222  if( Size < 3 || Size % 2 == 0 ) {
223  return *this;
224  }
225  delete[] this->KernelData;
226  this->KernelSize = Size;
227  this->KernelData = new Real[ this->KernelSize * this->KernelSize ];
228  for( Integer Y = 0 ; Y < this->KernelSize ; ++Y )
229  {
230  for( Integer X = 0 ; X < this->KernelSize ; ++X )
231  {
232  this->KernelData[ Y * this->KernelSize + X ] = static_cast<Real>( Data[ Y * this->KernelSize + X ] );
233  }
234  }
235  this->CalculateDivisor();
236  return *this;
237  }
238 
240  {
241  delete[] this->KernelData;
242  this->KernelSize = 3;
243  this->KernelData = new Real[ this->KernelSize * this->KernelSize ];
244  for( Integer Y = 0 ; Y < this->KernelSize ; ++Y )
245  {
246  for( Integer X = 0 ; X < this->KernelSize ; ++X )
247  {
248  this->KernelData[ Y * this->KernelSize + X ] = Data[Y][X];
249  }
250  }
251  this->CalculateDivisor();
252  return *this;
253  }
254 
256  { this->Divisor = Div; return *this; }
257 
259  { this->Threshold = Thresh; return *this; }
260 
262  { this->CalculateEdgeDivisor = CalculateEdge; return *this; }
263 
265  { this->IncludeAlphaChannel = IncludeAlpha; return *this; }
266 
268  {
269  this->Divisor = 0.0;
270  for( Integer Y = 0 ; Y < this->KernelSize ; ++Y )
271  {
272  for( Integer X = 0 ; X < this->KernelSize ; ++X )
273  {
274  this->Divisor += this->KernelData[ Y * this->KernelSize + X ];
275  }
276  }
277  if( this->Divisor == 0.0 ) {
278  this->Divisor = 1.0;
279  }
280 
281  return *this;
282  }
283  }//Procedural
284  }//Graphics
285 }//Mezzanine
286 
287 #endif
ColourChannelType & GetPixel(const Whole X, const Whole Y, const UInt16 Component)
Gets access to the pixel at the specified position in this buffer. the X or Y location go beyond the ...
This is a 3x3 Matrix class used for representing rotations and scaling in an object.
Definition: matrix3x3.h:62
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
void SetPixelByte(const Whole X, const Whole Y, const ColourChannelType Red, const ColourChannelType Green, const ColourChannelType Blue, const ColourChannelType Alpha=255)
Set colour of a specified pixel using a 0-255 range. the X or Y location go beyond the set size of th...
Whole GetWidth() const
Get the pixel width of this texture.
int Integer
A datatype used to represent any integer close to.
Definition: datatypes.h:154
ConvolutionModifier & SetThreshold(const UInt8 Thresh)
Sets a threshold that will force the colours of each pixel further to white or black.
uint8_t UInt8
An 8-bit unsigned integer.
Definition: datatypes.h:118
This is a simple class for holding 4 reals representing the colour any give object or lightsource can...
Definition: colourvalue.h:64
ColourChannelType GetAlphaByte(const Whole X, const Whole Y) const
Gets the alpha colour value of a specified pixel. the X or Y location go beyond the set size of this ...
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
ConvolutionModifier & SetCalculateEdgeDivisor(const Boole CalculateEdge)
Sets if a custom divisor should be use or one automatically generated during pixel processing...
Boole IncludeAlphaChannel
Whether or not the Alpha channel is to be processed with the rest of the pixel.
Real GreenChannel
Value from 0.0 to 1.0 representing the amount of green present in the colour. 1.0 if very green...
Definition: colourvalue.h:73
Real Divisor
The custom value to divide the pixel result by.
Real AlphaChannel
Value from 0.0 to 1.0 representing the transparency of the colours. 1.0 is opaque and 0...
Definition: colourvalue.h:79
virtual void Modify(TextureBuffer &Buffer)
Alters the generated pixels in a TextureBuffer.
Boole CalculateEdgeDivisor
Whether or not a dynamic divisor from pixel processing is to be used or the explicitly set divisor...
ConvolutionModifier & SetIncludeAlphaChannel(const Boole IncludeAlpha)
Sets if the alpha channel of each pixel should be processed.
ConvolutionModifier & SetDivisor(const Real Div)
Sets a custom divisor that will be applied to the result of the pixel to help keep the value within a...
Real * KernelData
The matricy to use for per-pixel processing.
A convenience buffer that stores pixel colour values of a texture to be generated.
Definition: texturebuffer.h:86
ConvolutionModifier & CalculateDivisor()
Automatically generates a sane divisor for pixel processing.
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
A modifier that will calculate each pixel in an image to be a weighed sum of itself and it's neighbor...
Whole GetHeight() const
Get the pixel height of this texture.
Real BlueChannel
Value from 0.0 to 1.0 representing the amount of blue present in the colour. 1.0 if very blue...
Definition: colourvalue.h:76
virtual String GetName() const
Gets the name of this modifier.
Real RedChannel
Value from 0.0 to 1.0 representing the amount of red present in the colour. 1.0 if very red...
Definition: colourvalue.h:70
ConvolutionModifier & SetKernel(const UInt8 Size, Real *Data)
Sets the matrix that determines how each pixel neighbor is to be weighed when processing each pixel...
UInt8 Threshold
A value over 128 will force a colour closer to White, lower will force a colour closer to black...
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
void SetData(const TextureBuffer &Other)
Copies image data from another buffer into this buffer.