Upstream tarball 20080304
[amule.git] / src / BarShader.cpp
blobdb72391cb5a1b77ea1be87890c09960b84790a66
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <wx/dc.h>
27 #include "Color.h" // Needed for RGB
29 #include "BarShader.h" // Interface declarations.
31 const double Pi = 3.14159265358979323846264338328;
33 #define HALF(X) (((X) + 1) / 2)
34 #define DEFAULT_DEPTH 10
37 CBarShader::CBarShader(uint32 height, uint32 width)
38 : m_Width( width ),
39 m_Height( height ),
40 m_FileSize( 1 ),
41 m_Modifiers( NULL ),
42 m_used3dlevel( DEFAULT_DEPTH )
44 Fill( 0 );
48 CBarShader::~CBarShader()
50 if ( m_Modifiers ) {
51 delete[] m_Modifiers;
56 void CBarShader::Reset()
58 m_spanlist.clear();
59 Fill(0);
63 void CBarShader::SetFileSize(uint64 fileSize)
65 m_FileSize = fileSize;
66 Reset();
70 void CBarShader::SetHeight( int height )
72 if( m_Height != height ) {
73 m_Height = height;
75 // Reset the modifers
76 if ( m_Modifiers ) {
77 delete[] m_Modifiers;
78 m_Modifiers = NULL;
84 void CBarShader::Set3dDepth( int depth )
86 if ( depth < 1 ) {
87 depth = 1;
88 } else if ( depth > 5 ) {
89 depth = 5;
92 if ( m_used3dlevel != depth ) {
93 m_used3dlevel = depth;
95 // Reset the modifers
96 if ( m_Modifiers ) {
97 delete[] m_Modifiers;
98 m_Modifiers = NULL;
104 void CBarShader::BuildModifiers()
106 if ( m_Modifiers ) {
107 delete[] m_Modifiers;
110 int depth = (7-m_used3dlevel);
111 int count = HALF(m_Height);
112 double piOverDepth = Pi/depth;
113 double base = piOverDepth * ((depth / 2.0) - 1);
114 double increment = piOverDepth / (count - 1);
116 m_Modifiers = new double[count];
117 for (int i = 0; i < count; i++)
118 m_Modifiers[i] = (double)(sin(base + i * increment));
122 void CBarShader::FillRange(uint64 start, uint64 end, const uint32 color)
124 // Sanity check
125 wxASSERT( start <= end );
127 if ( start >= m_FileSize ) {
128 return;
131 if ( end >= m_FileSize ) {
132 end = m_FileSize - 1;
135 m_spanlist.insert( start, end, color );
139 void CBarShader::Fill(uint32 color)
141 m_spanlist.clear();
142 m_spanlist.insert( 0, m_FileSize - 1, color );
146 void CBarShader::Draw( wxDC* dc, int iLeft, int iTop, bool bFlat )
148 wxASSERT( dc );
150 // Check if there's anything to do ...
151 if ( m_spanlist.empty() ) {
152 return;
156 // Do we need to rebuild the modifiers?
157 if ( !bFlat && !m_Modifiers ) {
158 BuildModifiers();
161 wxRect rectSpan;
162 rectSpan.x = iLeft;
163 rectSpan.y = iTop;
164 rectSpan.height = m_Height;
165 rectSpan.width = 0;
167 dc->SetPen(*wxTRANSPARENT_PEN);
169 // This modifier is multipled with sizes to allow for better handling of small ranges
170 const uint64 MOD = 1000;
171 // This is the number of bits each pixel should contain.
172 const uint64 bitsPerPixel = (m_FileSize * MOD) / (uint64)m_Width;
174 // The initial values for partial pixel drawing
175 uint64 curPixel = 0;
176 uint64 curRed = 0;
177 uint64 curGreen = 0;
178 uint64 curBlue = 0;
180 // Initialize to the first range
181 SpanList::iterator it = m_spanlist.begin();
182 uint64 size = (uint64)( it.keyEnd() - it.keyStart() + 1 ) * MOD;
183 uint32 color = *it++;
185 // Loop until everything has been drawn
186 while ( size || curPixel ) {
187 if ( !size && it != m_spanlist.end() ) {
188 // Fetch the next range and increment the iterator
189 size = (uint64)( it.keyEnd() - it.keyStart() + 1 ) * MOD;
190 color = *it++;
191 } else if ( curPixel || size < bitsPerPixel ) {
192 // This block is responsible for drawing ranges that are too small
193 // to fill a single pixel. To overcome this problem, we gather the
194 // sum of ranges until we have enough to draw a single pixel. The
195 // color of this pixel will be the sum of the colors of the ranges
196 // within the single pixel, each weighted after its relative size.
198 // See how much we can take from the current range
199 uint64 curDiff = std::min( size, bitsPerPixel - curPixel );
201 // Increment the current size of the partial pixel
202 curPixel += curDiff;
204 // Add the color of the current range times the ammount of the current
205 // range that was added to the partial pixel. The result will be divided
206 // by the length of the partial pixel to get the average.
207 curRed += curDiff * GetRValue( color );
208 curGreen += curDiff * GetGValue( color );
209 curBlue += curDiff * GetBValue( color );
211 // If we have a complete pixel, or if we have run out of usable ranges,
212 // then draw the partial pixel. Note that size is modified below this
213 // check, so that it only triggers when size was 0 to begin with.
214 if ( curPixel == bitsPerPixel || !size ) {
215 // Draw a single line containing the average of the smaller parts
216 uint32 col = RGB( (uint32)(curRed / curPixel),
217 (uint32)(curGreen / curPixel),
218 (uint32)(curBlue / curPixel) );
220 // Reset the partial-pixel
221 curPixel = curRed = curGreen = curBlue = 0;
223 // Increment the position on the device-context
224 rectSpan.x += rectSpan.width;
225 rectSpan.width = 1;
227 // Draw the line
228 FillRect(dc, rectSpan, col, bFlat);
231 // Decrement size
232 size -= curDiff;
233 } else {
234 // We are dealing with a range that is large enough to draw by itself.
235 // We will draw as many complete pixels as we can, and allow the rest
236 // to be absorbed by the partial pixel.
237 rectSpan.x += rectSpan.width;
238 rectSpan.width = size / bitsPerPixel;
240 // Unused size will be used by the partial-pixel drawing code.
241 size = size % bitsPerPixel;
243 // Draw the range
244 FillRect(dc, rectSpan, color, bFlat);
250 void CBarShader::FillRect(wxDC *dc, const wxRect& rectSpan, uint32 color, bool bFlat)
252 wxASSERT( dc );
254 if( bFlat || !color ) {
255 wxBrush brush( WxColourFromCr(color), wxSOLID );
256 dc->SetBrush( brush );
257 dc->DrawRectangle( rectSpan );
258 } else {
259 int x1 = rectSpan.x;
260 int x2 = rectSpan.x + rectSpan.width;
261 int y1 = rectSpan.y;
262 int y2 = rectSpan.GetBottom();
264 int Max = HALF(m_Height);
265 for (int i = 0; i < Max; i++) {
266 int cRed = std::min( 255, (int)(GetRValue(color) * m_Modifiers[i] + .5f) );
267 int cGreen = std::min( 255, (int)(GetGValue(color) * m_Modifiers[i] + .5f) );
268 int cBlue = std::min( 255, (int)(GetBValue(color) * m_Modifiers[i] + .5f) );
270 wxPen pen( wxColour( cRed, cGreen, cBlue ), 1, wxSOLID );
271 dc->SetPen( pen );
273 // Draw top row
274 dc->DrawLine( x1, y1 + i, x2, y1 + i );
276 // Draw bottom row
277 dc->DrawLine( x1, y2 - i, x2, y2 - i );
281 dc->SetBrush(wxNullBrush);
283 // File_checked_for_headers