1/*****************************************************************************/
2// Filter
3// Written by Michael Pfeiffer
4//
5// Filter.h
6//
7//
8// Copyright (c) 2003 Haiku Project
9//
10// Permission is hereby granted, free of charge, to any person obtaining a
11// copy of this software and associated documentation files (the "Software"),
12// to deal in the Software without restriction, including without limitation
13// the rights to use, copy, modify, merge, publish, distribute, sublicense,
14// and/or sell copies of the Software, and to permit persons to whom the
15// Software is furnished to do so, subject to the following conditions:
16//
17// The above copyright notice and this permission notice shall be included
18// in all copies or substantial portions of the Software.
19//
20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26// DEALINGS IN THE SOFTWARE.
27/*****************************************************************************/
28
29#ifndef _Filter_h
30#define _Filter_h
31
32#include <OS.h>
33#include <Bitmap.h>
34#include <Messenger.h>
35#include <StopWatch.h>
36
37#define TIME_FILTER 0
38
39class Filter;
40
41typedef int32 intType;
42typedef int64 long_fixed_point;
43typedef int32 fixed_point;
44
45// Could use shift operator instead of multiplication and division,
46// but compiler will optimize it for use anyway.
47#define to_fixed_point(number) static_cast<fixed_point>((number) * kFPPrecisionFactor)
48#define from_fixed_point(number) ((number) / kFPPrecisionFactor)
49#define to_float(number) from_fixed_point(static_cast<float>(number))
50
51#define int_value(number) ((number) & kFPInverseMask)
52#define tail_value(number) ((number) & kFPPrecisionMask)
53
54// Has to be called after muliplication of two fixed point values
55#define mult_correction(number) ((number) / kFPPrecisionFactor)
56
57const int32 kFPPrecision = 8; // (32-kFPPrecision).kFPPrecision
58const int32 kFPPrecisionFactor = (1 << kFPPrecision);
59const int32 kFPPrecisionMask = ((kFPPrecisionFactor)-1);
60const int32 kFPInverseMask = (~kFPPrecisionMask);
61const int32 kFPOne = to_fixed_point(1);
62
63// Used by class Filter
64class FilterThread {
65public:
66	FilterThread(Filter* filter, int32 i, int32 n,
67		bool runInCurrentThread = false);
68	~FilterThread();
69
70private:
71	status_t Run();
72	static status_t worker_thread(void* data);
73
74	Filter*	fFilter;
75	int32	fI;
76	int32	fN;
77};
78
79class Filter {
80public:
81	// The filter uses the input "image" as source image
82	// for an operation executed in Run() method which
83	// writes into the destination image, that can be
84	// retrieve using GetBitmap() method.
85	// GetBitmap() must be called either before Start(),
86	// or after Start() and IsRunning() returns false.
87	// To start the operation Start() method has to
88	// be called. The operation is executed in as many
89	// threads as GetMaxNumberOfThreads() returns.
90	// The implementation of GetMaxNumberOfThreads()
91	// can use CPUCount() to retrieve the number of
92	// active CPUs at the time the Filter was created.
93	// IsRunning() is true as long as there are any
94	// threads running.
95	// The operation is complete when IsRunning() is false
96	// and Stop() has not been called.
97	// To abort an operation Stop() method has to
98	// be called. Stop() has to be called after Start().
99	// When the operation is done Completed() is called.
100	// and only if it has not been aborted, then the listener
101	// receives a message with the specified "what" value.
102	Filter(BBitmap* image, BMessenger listener, uint32 what);
103	virtual ~Filter();
104
105	// The bitmap the filter writes into
106	BBitmap* GetBitmap();
107	// Removes the destination image from Filter (caller is new owner of image)
108	BBitmap* DetachBitmap();
109
110	// Starts one or more FilterThreads. Returns immediately if async is true.
111	// Either Wait() or Stop() has to be called if async is true!
112	void Start(bool async = true);
113	// Wait for completion of operation
114	void Wait();
115	// Has to be called after Start() (even if IsRunning() is false)
116	void Stop();
117	// Are there any running FilterThreads?
118	bool IsRunning() const;
119
120	// To be implemented by inherited class (methods are called in this order):
121	virtual BBitmap* CreateDestImage(BBitmap* srcImage) = 0;
122	// The number of processing units
123	virtual int32 GetNumberOfUnits() = 0;
124	// Should calculate part i of n of the image. i starts with zero
125	virtual void Run(int32 i, int32 n) = 0;
126	// Completed() is called when the last FilterThread has completed its work.
127	virtual void Completed();
128
129	// Used by FilterThread only!
130	void FilterThreadDone();
131	void FilterThreadInitFailed();
132
133	bool IsBitmapValid(BBitmap* bitmap) const;
134
135protected:
136	// Number of threads to be used to perform the operation
137	int32 NumberOfThreads();
138	BBitmap* GetSrcImage();
139	BBitmap* GetDestImage();
140
141private:
142	int32 NumberOfActiveCPUs() const;
143	// Returns the number of active CPUs
144	int32 CPUCount() const { return fCPUCount; }
145
146	BMessenger		fListener;
147	uint32			fWhat;
148	int32			fCPUCount; // the number of active CPUs
149	bool			fStarted; // has Start() been called?
150	sem_id			fWaitForThreads; // to exit
151	int32			fN; // the number of used filter threads
152	int32			fNumberOfThreads; // the current number of FilterThreads
153	volatile bool	fIsRunning; // FilterThreads should process data as long as it is true
154	BBitmap*		fSrcImage;
155	bool			fDestImageInitialized;
156	BBitmap*		fDestImage;
157#if TIME_FILTER
158	BStopWatch*		fStopWatch;
159#endif
160};
161
162// Scales and optionally dithers an image
163class Scaler : public Filter {
164public:
165	Scaler(BBitmap* image, BRect rect, BMessenger listener, uint32 what,
166		bool dither);
167	~Scaler();
168
169	BBitmap* CreateDestImage(BBitmap* srcImage);
170	int32 GetNumberOfUnits();
171	void Run(int32 i, int32 n);
172	void Completed();
173	bool Matches(BRect rect, bool dither) const;
174
175private:
176	void ScaleBilinear(int32 fromRow, int32 toRow);
177	void ScaleBilinearFP(int32 fromRow, int32 toRow);
178	inline void RowValues(float* sum, const uchar* srcData, intType srcW,
179					intType fromX, intType toX, const float a0X,
180					const float a1X, const int32 kBPP);
181	void DownScaleBilinear(int32 fromRow, int32 toRow);
182	static inline uchar Limit(intType value);
183	void Dither(int32 fromRow, int32 toRow);
184
185	BBitmap* fScaledImage;
186	BRect fRect;
187	bool fDither;
188};
189
190// Rotates, mirrors or inverts an image
191class ImageProcessor : public Filter {
192public:
193	enum operation {
194		kRotateClockwise,
195		kRotateCounterClockwise,
196		kFlipLeftToRight,
197		kFlipTopToBottom,
198		kInvert,
199		kNumberOfAffineTransformations = 4
200	};
201
202	ImageProcessor(enum operation op, BBitmap* image, BMessenger listener,
203		uint32 what);
204	BBitmap* CreateDestImage(BBitmap* srcImage);
205	int32 GetNumberOfUnits();
206	void Run(int32 i, int32 n);
207
208private:
209	int32 BytesPerPixel(color_space cs) const;
210	inline void CopyPixel(uchar* dest, int32 destX, int32 destY,
211					const uchar* src, int32 x, int32 y);
212	inline void InvertPixel(int32 x, int32 y, uchar* dest, const uchar* src);
213
214	enum operation fOp;
215	int32 fBPP;
216	int32 fWidth;
217	int32 fHeight;
218	int32 fSrcBPR;
219	int32 fDestBPR;
220};
221
222#endif
223