/*****************************************************************************/// Filter// Written by Michael Pfeiffer//// Filter.h////// Copyright (c) 2003 Haiku Project//// Permission is hereby granted, free of charge, to any person obtaining a// copy of this software and associated documentation files (the "Software"),// to deal in the Software without restriction, including without limitation// the rights to use, copy, modify, merge, publish, distribute, sublicense,// and/or sell copies of the Software, and to permit persons to whom the// Software is furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included// in all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER// DEALINGS IN THE SOFTWARE./*****************************************************************************/#ifndef _Filter_h#define _Filter_h#include <OS.h>#include <Bitmap.h>#include <Messenger.h>#include <StopWatch.h>#define TIME_FILTER 0class Filter;typedef int32 intType;typedef int64 long_fixed_point;typedef int32 fixed_point;// Could use shift operator instead of multiplication and division,// but compiler will optimize it for use anyway.#define to_fixed_point(number) static_cast<fixed_point>((number) * kFPPrecisionFactor)#define from_fixed_point(number) ((number) / kFPPrecisionFactor)#define to_float(number) from_fixed_point(static_cast<float>(number))#define int_value(number) ((number) & kFPInverseMask)#define tail_value(number) ((number) & kFPPrecisionMask)// Has to be called after muliplication of two fixed point values#define mult_correction(number) ((number) / kFPPrecisionFactor)const int32 kFPPrecision = 8; // (32-kFPPrecision).kFPPrecisionconst int32 kFPPrecisionFactor = (1 << kFPPrecision);const int32 kFPPrecisionMask = ((kFPPrecisionFactor)-1);const int32 kFPInverseMask = (~kFPPrecisionMask);const int32 kFPOne = to_fixed_point(1);// Used by class Filterclass FilterThread {public:FilterThread(Filter* filter, int32 i, int32 n,bool runInCurrentThread = false);~FilterThread();private:status_t Run();static status_t worker_thread(void* data);Filter* fFilter;int32 fI;int32 fN;};class Filter {public:// The filter uses the input "image" as source image// for an operation executed in Run() method which// writes into the destination image, that can be// retrieve using GetBitmap() method.// GetBitmap() must be called either before Start(),// or after Start() and IsRunning() returns false.// To start the operation Start() method has to// be called. The operation is executed in as many// threads as GetMaxNumberOfThreads() returns.// The implementation of GetMaxNumberOfThreads()// can use CPUCount() to retrieve the number of// active CPUs at the time the Filter was created.// IsRunning() is true as long as there are any// threads running.// The operation is complete when IsRunning() is false// and Stop() has not been called.// To abort an operation Stop() method has to// be called. Stop() has to be called after Start().// When the operation is done Completed() is called.// and only if it has not been aborted, then the listener// receives a message with the specified "what" value.Filter(BBitmap* image, BMessenger listener, uint32 what);virtual ~Filter();// The bitmap the filter writes intoBBitmap* GetBitmap();// Removes the destination image from Filter (caller is new owner of image)BBitmap* DetachBitmap();// Starts one or more FilterThreads. Returns immediately if async is true.// Either Wait() or Stop() has to be called if async is true!void Start(bool async = true);// Wait for completion of operationvoid Wait();// Has to be called after Start() (even if IsRunning() is false)void Stop();// Are there any running FilterThreads?bool IsRunning() const;// To be implemented by inherited class (methods are called in this order):virtual BBitmap* CreateDestImage(BBitmap* srcImage) = 0;// The number of processing unitsvirtual int32 GetNumberOfUnits() = 0;// Should calculate part i of n of the image. i starts with zerovirtual void Run(int32 i, int32 n) = 0;// Completed() is called when the last FilterThread has completed its work.virtual void Completed();// Used by FilterThread only!void FilterThreadDone();void FilterThreadInitFailed();bool IsBitmapValid(BBitmap* bitmap) const;protected:// Number of threads to be used to perform the operationint32 NumberOfThreads();BBitmap* GetSrcImage();BBitmap* GetDestImage();private:int32 NumberOfActiveCPUs() const;// Returns the number of active CPUsint32 CPUCount() const { return fCPUCount; }BMessenger fListener;uint32 fWhat;int32 fCPUCount; // the number of active CPUsbool fStarted; // has Start() been called?sem_id fWaitForThreads; // to exitint32 fN; // the number of used filter threadsint32 fNumberOfThreads; // the current number of FilterThreadsvolatile bool fIsRunning; // FilterThreads should process data as long as it is trueBBitmap* fSrcImage;bool fDestImageInitialized;BBitmap* fDestImage;#if TIME_FILTERBStopWatch* fStopWatch;#endif};// Scales and optionally dithers an imageclass Scaler : public Filter {public:Scaler(BBitmap* image, BRect rect, BMessenger listener, uint32 what,bool dither);~Scaler();BBitmap* CreateDestImage(BBitmap* srcImage);int32 GetNumberOfUnits();void Run(int32 i, int32 n);void Completed();bool Matches(BRect rect, bool dither) const;private:void ScaleBilinear(int32 fromRow, int32 toRow);void ScaleBilinearFP(int32 fromRow, int32 toRow);inline void RowValues(float* sum, const uchar* srcData, intType srcW,intType fromX, intType toX, const float a0X,const float a1X, const int32 kBPP);void DownScaleBilinear(int32 fromRow, int32 toRow);static inline uchar Limit(intType value);void Dither(int32 fromRow, int32 toRow);BBitmap* fScaledImage;BRect fRect;bool fDither;};// Rotates, mirrors or inverts an imageclass ImageProcessor : public Filter {public:enum operation {kRotateClockwise,kRotateCounterClockwise,kFlipLeftToRight,kFlipTopToBottom,kInvert,kNumberOfAffineTransformations = 4};ImageProcessor(enum operation op, BBitmap* image, BMessenger listener,uint32 what);BBitmap* CreateDestImage(BBitmap* srcImage);int32 GetNumberOfUnits();void Run(int32 i, int32 n);private:int32 BytesPerPixel(color_space cs) const;inline void CopyPixel(uchar* dest, int32 destX, int32 destY,const uchar* src, int32 x, int32 y);inline void InvertPixel(int32 x, int32 y, uchar* dest, const uchar* src);enum operation fOp;int32 fBPP;int32 fWidth;int32 fHeight;int32 fSrcBPR;int32 fDestBPR;};#endif