Move the FractalEngine to its own thread.

This commit is contained in:
Augustin Cavalier 2016-05-27 20:40:04 -04:00
parent bdf389fde5
commit 9daf130b6d
3 changed files with 201 additions and 107 deletions

View File

@ -8,11 +8,69 @@
*/ */
#include "FractalEngine.h" #include "FractalEngine.h"
#include <SupportDefs.h> #include <algorithm>
#include <math.h> #include <math.h>
#include <Bitmap.h>
#include "Colorsets.h" #include "Colorsets.h"
#define colors Colorset_Royal
FractalEngine::FractalEngine(BHandler* parent, BLooper* looper)
:
BLooper("FractalEngine"),
fMessenger(parent, looper),
fBitmapStandby(NULL),
fBitmapDisplay(NULL),
fWidth(0), fHeight(0),
fRenderBuffer(NULL),
fRenderBufferLen(0),
fColorset(Colorset_Royal)
{
fRenderPixel = &FractalEngine::RenderPixelDefault;
fDoSet = &FractalEngine::DoSet_Mandelbrot;
}
FractalEngine::~FractalEngine()
{
}
void FractalEngine::MessageReceived(BMessage* msg)
{
switch (msg->what) {
case MSG_RESIZE: {
delete fBitmapStandby;
// We don't delete the "display" bitmap; the viewer now owns it
delete fRenderBuffer;
fWidth = msg->GetUInt16("width", 320);
fHeight = msg->GetUInt16("height", 240);
BRect rect(0, 0, fWidth - 1, fHeight - 1);
fBitmapStandby = new BBitmap(rect, B_RGB24);
fBitmapDisplay = new BBitmap(rect, B_RGB24);
fRenderBufferLen = fWidth * fHeight * 3;
fRenderBuffer = new uint8[fRenderBufferLen];
break;
}
case MSG_RENDER: {
// Render to "standby" bitmap
Render(msg->GetDouble("locationX", 0), msg->GetDouble("locationY", 0),
msg->GetDouble("size", 0.005));
BMessage message(MSG_RENDER_COMPLETE);
message.AddPointer("bitmap", (const void*)fBitmapStandby);
fMessenger.SendMessage(&message);
std::swap(fBitmapStandby, fBitmapDisplay);
break;
}
default:
BLooper::MessageReceived(msg);
break;
}
}
double zReal_end = 0; double zReal_end = 0;
double zImaginary_end = 0; double zImaginary_end = 0;
@ -33,18 +91,10 @@ int32 gIterations = 1024;
double gPower = 0; double gPower = 0;
void renderPixel_smooth(double real, double imaginary);
void renderPixel_default(double real, double imaginary);
int32 (*inSet)(double real, double imaginary);
int32 inSet_mandelbrot(double real, double imaginary);
int32 inSet_burningShip(double real, double imaginary);
int32 inSet_tricornMandelbrot(double real, double imaginary);
void (*renderPixel)(double real, double imaginary); void FractalEngine::RenderPixelDefault(double real, double imaginary)
void renderPixel_default(double real, double imaginary)
{ {
int32 iterToEscape = (*inSet)(real, imaginary); int32 iterToEscape = (this->*fDoSet)(real, imaginary);
uint16 loc = 0; uint16 loc = 0;
if (iterToEscape == -1) { if (iterToEscape == -1) {
// Didn't escape. // Didn't escape.
@ -53,14 +103,15 @@ void renderPixel_default(double real, double imaginary)
loc = 998 - (iterToEscape % 999); loc = 998 - (iterToEscape % 999);
} }
r = colors[loc * 3 + 0]; r = fColorset[loc * 3 + 0];
g = colors[loc * 3 + 1]; g = fColorset[loc * 3 + 1];
b = colors[loc * 3 + 2]; b = fColorset[loc * 3 + 2];
} }
void renderPixel_smooth(double real, double imaginary)
void FractalEngine::RenderPixelSmooth(double real, double imaginary)
{ {
int32 outColor = (*inSet)(real, imaginary); int32 outColor = (this->*fDoSet)(real, imaginary);
int8 mapperDiff_r = 0; int8 mapperDiff_r = 0;
int8 mapperDiff_g = 0; int8 mapperDiff_g = 0;
int8 mapperDiff_b = 0; int8 mapperDiff_b = 0;
@ -77,25 +128,26 @@ void renderPixel_smooth(double real, double imaginary)
} }
if (outColor == -1) { if (outColor == -1) {
r = colors[999 * 3]; r = fColorset[999 * 3];
g = colors[999 * 3 + 1]; g = fColorset[999 * 3 + 1];
b = colors[999 * 3 + 2]; b = fColorset[999 * 3 + 2];
return; return;
} }
outColor = 998 - (outColor % 999); outColor = 998 - (outColor % 999);
mapperLoc = outColor * 3; mapperLoc = outColor * 3;
mapperDiff_r = colors[mapperLoc + 0] - colors[mapperLoc + 0 + 3]; mapperDiff_r = fColorset[mapperLoc + 0] - fColorset[mapperLoc + 0 + 3];
mapperDiff_g = colors[mapperLoc + 1] - colors[mapperLoc + 1 + 3]; mapperDiff_g = fColorset[mapperLoc + 1] - fColorset[mapperLoc + 1 + 3];
mapperDiff_b = colors[mapperLoc + 2] - colors[mapperLoc + 2 + 3]; mapperDiff_b = fColorset[mapperLoc + 2] - fColorset[mapperLoc + 2 + 3];
r = mapperDiff_r * ratio + colors[mapperLoc + 0]; r = mapperDiff_r * ratio + fColorset[mapperLoc + 0];
g = mapperDiff_g * ratio + colors[mapperLoc + 1]; g = mapperDiff_g * ratio + fColorset[mapperLoc + 1];
b = mapperDiff_b * ratio + colors[mapperLoc + 2]; b = mapperDiff_b * ratio + fColorset[mapperLoc + 2];
} }
int32 inSet_mandelbrot(double real, double imaginary)
int32 FractalEngine::DoSet_Mandelbrot(double real, double imaginary)
{ {
double zReal = 0; double zReal = 0;
double zImaginary = 0; double zImaginary = 0;
@ -126,7 +178,8 @@ int32 inSet_mandelbrot(double real, double imaginary)
return -1; return -1;
} }
int32 inSet_burningShip(double real, double imaginary)
int32 FractalEngine::DoSet_BurningShip(double real, double imaginary)
{ {
double zReal = 0; double zReal = 0;
double zImaginary = 0; double zImaginary = 0;
@ -163,7 +216,8 @@ int32 inSet_burningShip(double real, double imaginary)
return -1; return -1;
} }
int32 inSet_tricornMandelbrot(double real, double imaginary)
int32 FractalEngine::DoSet_Tricorn(double real, double imaginary)
{ {
double zReal = 0; double zReal = 0;
double zImaginary = 0; double zImaginary = 0;
@ -200,7 +254,8 @@ int32 inSet_tricornMandelbrot(double real, double imaginary)
return -1; return -1;
} }
int32 inSet_julia(double real, double imaginary)
int32 FractalEngine::DoSet_Julia(double real, double imaginary)
{ {
double zReal = real; double zReal = real;
double zImaginary = imaginary; double zImaginary = imaginary;
@ -234,7 +289,7 @@ int32 inSet_julia(double real, double imaginary)
return -1; return -1;
} }
int32 inSet_mandelbrot_orbitTrap(double real, double imaginary) int32 FractalEngine::DoSet_OrbitTrap(double real, double imaginary)
{ {
double zReal = 0; double zReal = 0;
double zImaginary = 0; double zImaginary = 0;
@ -274,7 +329,7 @@ int32 inSet_mandelbrot_orbitTrap(double real, double imaginary)
return floor(4 * log(4 / closest)); return floor(4 * log(4 / closest));
} }
int32 inSet_multibrot_3(double real, double imaginary) int32 FractalEngine::DoSet_Multibrot(double real, double imaginary)
{ {
double zReal = 0; double zReal = 0;
double zImaginary = 0; double zImaginary = 0;
@ -305,68 +360,24 @@ int32 inSet_multibrot_3(double real, double imaginary)
return -1; return -1;
} }
int32 inSet_fractional(double real, double imaginary)
{
double zReal = 0;
double zImaginary = 0;
double r = 0;
double t = 0;
double power = gPower;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
r = sqrt(zReal * zReal + zImaginary * zImaginary);
r = pow(r, power);
t = atan2(zImaginary, zReal) * power;
double nzReal = r * cos(t);
zImaginary = r * sin(t);
zReal = nzReal;
zReal += real;
zImaginary += imaginary;
// If it is outside the 2 unit circle...
if ((zReal * zReal) + (zImaginary * zImaginary) > escapeHorizon) {
zReal_end = zReal;
zImaginary_end = zImaginary;
return i; // stop it from running longer
}
}
return -1;
}
#define buf_SetPixel(x, y, r, g, b) \ #define buf_SetPixel(x, y, r, g, b) \
buf[width * y * 3 + x * 3 + 0] = r; \ fRenderBuffer[fWidth * y * 3 + x * 3 + 0] = r; \
buf[width * y * 3 + x * 3 + 1] = g; \ fRenderBuffer[fWidth * y * 3 + x * 3 + 1] = g; \
buf[width * y * 3 + x * 3 + 2] = b; fRenderBuffer[fWidth * y * 3 + x * 3 + 2] = b;
BBitmap* FractalEngine(uint32 width, uint32 height, double locationX, void FractalEngine::Render(double locationX, double locationY, double size)
double locationY, double size)
{ {
uint16 halfcWidth = width / 2; uint16 halfWidth = fWidth / 2;
uint16 halfcHeight = height / 2; uint16 halfHeight = fHeight / 2;
uint32 bufLen = width * height * 3; for (uint32 x = 0; x < fWidth; x++) {
uint8* buf = new uint8[bufLen]; for (uint32 y = 0; y < fHeight; y++) {
(this->*fRenderPixel)((x * size + locationX) - (halfWidth * size),
renderPixel = renderPixel_default; (y * -size + locationY) - (halfHeight * -size));
inSet = inSet_mandelbrot;
for (uint32 x = 0; x < width; x++) {
for (uint32 y = 0; y < height; y++) {
(*renderPixel)((x * size + locationX) - (halfcWidth * size),
(y * -size + locationY) - (halfcHeight * -size));
buf_SetPixel(x, y, r, g, b); buf_SetPixel(x, y, r, g, b);
} }
} }
BBitmap* ret = new BBitmap(BRect(0, 0, width - 1 , height - 1), 0, B_RGB24); fBitmapStandby->ImportBits(fRenderBuffer, fRenderBufferLen, fWidth * 3,
ret->ImportBits(buf, bufLen, width * 3, 0, B_RGB24_BIG); 0, B_RGB24_BIG);
return ret;
} }

View File

@ -10,11 +10,49 @@
#define FRACTALENGINE_H #define FRACTALENGINE_H
#include <SupportDefs.h> #include <SupportDefs.h>
#include <Bitmap.h> #include <Looper.h>
#include <Messenger.h>
class BBitmap;
BBitmap* FractalEngine(uint32 width, uint32 height, double locationX, class FractalEngine : public BLooper {
double locationY, double size); public:
enum {
MSG_RESIZE = 'Frct',
MSG_RENDER,
MSG_RENDER_COMPLETE,
};
FractalEngine(BHandler* parent, BLooper* looper);
~FractalEngine();
virtual void MessageReceived(BMessage* msg);
private:
BMessenger fMessenger;
BBitmap* fBitmapStandby;
BBitmap* fBitmapDisplay;
uint16 fWidth;
uint16 fHeight;
uint8* fRenderBuffer;
uint32 fRenderBufferLen;
const uint8* fColorset;
int32 (FractalEngine::*fDoSet)(double real, double imaginary);
void (FractalEngine::*fRenderPixel)(double real, double imaginary);
void Render(double locationX, double locationY, double size);
void RenderPixelSmooth(double real, double imaginary);
void RenderPixelDefault(double real, double imaginary);
int32 DoSet_Mandelbrot(double real, double imaginary);
int32 DoSet_BurningShip(double real, double imaginary);
int32 DoSet_Tricorn(double real, double imaginary);
int32 DoSet_Julia(double real, double imaginary);
int32 DoSet_OrbitTrap(double real, double imaginary);
int32 DoSet_Multibrot(double real, double imaginary);
};
#endif /* FRACTALENGINE_H */ #endif /* FRACTALENGINE_H */

View File

@ -29,36 +29,65 @@ public:
FractalView(); FractalView();
~FractalView(); ~FractalView();
virtual void FrameResized(float, float) virtual void AttachedToWindow();
{ RedrawFractal(); } virtual void FrameResized(float width, float height);
virtual void MouseDown(BPoint where); virtual void MouseDown(BPoint where);
virtual void MessageReceived(BMessage* msg);
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
private: private:
BBitmap* fBitmap; FractalEngine* fFractalEngine;
bool fOwnBitmap;
BBitmap* fDisplayBitmap;
double fLocationX; double fLocationX;
double fLocationY; double fLocationY;
double fSize; double fSize;
void RedrawFractal(uint16 width = 0, uint16 height = 0); void RedrawFractal();
}; };
FractalView::FractalView() FractalView::FractalView()
: :
BView(NULL, B_WILL_DRAW), BView(NULL, B_WILL_DRAW),
fBitmap(NULL), fFractalEngine(NULL),
fOwnBitmap(false),
fDisplayBitmap(NULL),
fLocationX(0), fLocationX(0),
fLocationY(0), fLocationY(0),
fSize(0.005) fSize(0.005)
{ {
RedrawFractal(641, 462);
} }
FractalView::~FractalView() FractalView::~FractalView()
{ {
delete fBitmap; if (fOwnBitmap)
delete fDisplayBitmap;
}
void FractalView::AttachedToWindow()
{
fFractalEngine = new FractalEngine(this, Window());
fFractalEngine->Run();
BMessage msg(FractalEngine::MSG_RESIZE);
msg.AddUInt16("width", 641);
msg.AddUInt16("height", 462);
fFractalEngine->PostMessage(&msg);
RedrawFractal();
}
void FractalView::FrameResized(float width, float height)
{
BMessage msg(FractalEngine::MSG_RESIZE);
msg.AddUInt16("width", (uint16)width);
msg.AddUInt16("height", (uint16)height);
fFractalEngine->PostMessage(&msg);
// The renderer will create new bitmaps, so we own the bitmap now
fOwnBitmap = true;
RedrawFractal();
} }
@ -78,21 +107,37 @@ void FractalView::MouseDown(BPoint where)
} }
void FractalView::RedrawFractal(uint16 width, uint16 height) void FractalView::MessageReceived(BMessage* msg)
{ {
delete fBitmap; switch (msg->what) {
if (width == 0) case FractalEngine::MSG_RENDER_COMPLETE:
width = (uint16)Frame().Width(); if (fOwnBitmap)
if (height == 0) delete fDisplayBitmap;
height = (uint16)Frame().Height(); fDisplayBitmap = NULL; // In case the following line fails
fBitmap = FractalEngine(width, height, fLocationX, fLocationY, fSize); msg->FindPointer("bitmap", (void**)&fDisplayBitmap);
Invalidate(); Invalidate();
break;
default:
BView::MessageReceived(msg);
break;
}
}
void FractalView::RedrawFractal()
{
BMessage message(FractalEngine::MSG_RENDER);
message.AddDouble("locationX", fLocationX);
message.AddDouble("locationY", fLocationY);
message.AddDouble("size", fSize);
fFractalEngine->PostMessage(&message);
} }
void FractalView::Draw(BRect updateRect) void FractalView::Draw(BRect updateRect)
{ {
DrawBitmap(fBitmap, updateRect, updateRect); DrawBitmap(fDisplayBitmap, updateRect, updateRect);
} }