diff --git a/src/apps/mandelbrot/FractalEngine.cpp b/src/apps/mandelbrot/FractalEngine.cpp index c20b2511df..f1d2bbc904 100644 --- a/src/apps/mandelbrot/FractalEngine.cpp +++ b/src/apps/mandelbrot/FractalEngine.cpp @@ -91,6 +91,9 @@ void FractalEngine::MessageReceived(BMessage* msg) case MSG_SET_ITERATIONS: fIterations = msg->GetUInt16("iterations", 0); break; + case MSG_SET_SUBSAMPLING: + fSubsampling = msg->GetUInt8("subsampling", 1); + break; case MSG_RESIZE: { TRACE("Got MSG_RESIZE threads rendering\n"); @@ -251,19 +254,38 @@ void FractalEngine::RenderPixel(uint32 x, uint32 y) double real = (x * fSize + fLocationX) - (fWidth / 2 * fSize); double imaginary = (y * -(fSize) + fLocationY) - (fHeight / 2 * -(fSize)); - int32 iterToEscape = (this->*fDoSet)(real, imaginary); - uint16 loc = 0; - if (iterToEscape == -1) - // Didn't escape. - loc = 999; - else - loc = 998 - (iterToEscape % 999); + double subsampleDelta = fSize / fSubsampling; + uint16 nSamples = fSubsampling * fSubsampling; + + int16 totalR = 0; + int16 totalG = 0; + int16 totalB = 0; + for (uint8 subX = 0; subX < fSubsampling; subX++) { + for (uint8 subY = 0; subY < fSubsampling; subY++) { + double sampleReal = real + subX * subsampleDelta; + double sampleImaginary = imaginary + subY * subsampleDelta; + + int32 sampleIterToEscape = (this->*fDoSet)(sampleReal, sampleImaginary); + + uint16 sampleLoc = 0; + if (sampleIterToEscape == -1) + // Didn't escape. + sampleLoc = 999; + else + sampleLoc = 998 - (sampleIterToEscape % 999); + sampleLoc *= 3; + + totalR += fColorset[sampleLoc + 0]; + totalG += fColorset[sampleLoc + 1]; + totalB += fColorset[sampleLoc + 2]; + } + } + uint32 offsetBase = fWidth * y * 3 + x * 3; - loc *= 3; - fRenderBuffer[offsetBase + 2] = fColorset[loc + 0]; // fRenderBuffer is BGR - fRenderBuffer[offsetBase + 1] = fColorset[loc + 1]; - fRenderBuffer[offsetBase + 0] = fColorset[loc + 2]; + fRenderBuffer[offsetBase + 2] = totalR / nSamples; // fRenderBuffer is BGR + fRenderBuffer[offsetBase + 1] = totalG / nSamples; + fRenderBuffer[offsetBase + 0] = totalB / nSamples; } diff --git a/src/apps/mandelbrot/FractalEngine.h b/src/apps/mandelbrot/FractalEngine.h index 8411a1d3fa..9918071055 100644 --- a/src/apps/mandelbrot/FractalEngine.h +++ b/src/apps/mandelbrot/FractalEngine.h @@ -25,6 +25,7 @@ public: MSG_CHANGE_SET = 'Frct', MSG_SET_PALETTE, MSG_SET_ITERATIONS, + MSG_SET_SUBSAMPLING, MSG_RESIZE, MSG_BUFFER_CREATED, MSG_RENDER, @@ -45,6 +46,9 @@ private: uint8* fRenderBuffer; uint32 fRenderBufferLen; + uint8 fSubsampling = 2; + // 1 disables subsampling. + BMessenger fMessenger; uint8 fThreadCount; diff --git a/src/apps/mandelbrot/Mandelbrot.cpp b/src/apps/mandelbrot/Mandelbrot.cpp index 7735d7901d..fe8a30cfc1 100644 --- a/src/apps/mandelbrot/Mandelbrot.cpp +++ b/src/apps/mandelbrot/Mandelbrot.cpp @@ -358,7 +358,12 @@ public: MSG_ITER_4096, MSG_ITER_8192, MSG_ITER_12288, - MSG_ITER_16384 + MSG_ITER_16384, + + MSG_SUBSAMPLING_1, + MSG_SUBSAMPLING_2, + MSG_SUBSAMPLING_3, + MSG_SUBSAMPLING_4 }; MandelbrotWindow(BRect frame); ~MandelbrotWindow() {} @@ -381,6 +386,7 @@ MandelbrotWindow::MandelbrotWindow(BRect frame) BMenu* setMenu; BMenu* paletteMenu; BMenu* iterMenu; + BMenu* subsamplingMenu; BLayoutBuilder::Menu<>(menuBar) .AddMenu(B_TRANSLATE("File")) .AddItem(B_TRANSLATE("About"), B_ABOUT_REQUESTED) @@ -417,6 +423,13 @@ MandelbrotWindow::MandelbrotWindow(BRect frame) .AddItem("12288", MSG_ITER_12288) .AddItem("16384", MSG_ITER_16384) .End() + .AddMenu(B_TRANSLATE("Subsampling")) + .GetMenu(subsamplingMenu) + .AddItem(B_TRANSLATE("1 (none)"), MSG_SUBSAMPLING_1) + .AddItem("4", MSG_SUBSAMPLING_2) + .AddItem("9", MSG_SUBSAMPLING_3) + .AddItem("16", MSG_SUBSAMPLING_4) + .End() .End(); setMenu->SetRadioMode(true); setMenu->FindItem(MSG_MANDELBROT_SET)->SetMarked(true); @@ -424,6 +437,8 @@ MandelbrotWindow::MandelbrotWindow(BRect frame) paletteMenu->FindItem(MSG_ROYAL_PALETTE)->SetMarked(true); iterMenu->SetRadioMode(true); iterMenu->FindItem(MSG_ITER_1024)->SetMarked(true); + subsamplingMenu->SetRadioMode(true); + subsamplingMenu->FindItem(MSG_SUBSAMPLING_2)->SetMarked(true); BLayoutBuilder::Group<>(this, B_VERTICAL, 0) .SetInsets(0) @@ -458,6 +473,14 @@ MandelbrotWindow::MandelbrotWindow(BRect frame) fFractalView->RedrawFractal(); \ break; \ } +#define HANDLE_SUBSAMPLING(uiwhat, id) \ + case uiwhat: { \ + BMessage msg(FractalEngine::MSG_SET_SUBSAMPLING); \ + msg.AddUInt8("subsampling", id); \ + fFractalView->fFractalEngine->PostMessage(&msg); \ + fFractalView->RedrawFractal(); \ + break; \ + } void MandelbrotWindow::MessageReceived(BMessage* msg) { @@ -487,6 +510,11 @@ MandelbrotWindow::MessageReceived(BMessage* msg) HANDLE_ITER(MSG_ITER_12288, 12288) HANDLE_ITER(MSG_ITER_16384, 16384) + HANDLE_SUBSAMPLING(MSG_SUBSAMPLING_1, 1) + HANDLE_SUBSAMPLING(MSG_SUBSAMPLING_2, 2) + HANDLE_SUBSAMPLING(MSG_SUBSAMPLING_3, 3) + HANDLE_SUBSAMPLING(MSG_SUBSAMPLING_4, 4) + case B_ABOUT_REQUESTED: { BAboutWindow* wind = new BAboutWindow("Mandelbrot", "application/x-vnd.Haiku-Mandelbrot"); @@ -510,6 +538,7 @@ MandelbrotWindow::MessageReceived(BMessage* msg) #undef HANDLE_SET #undef HANDLE_PALETTE #undef HANDLE_ITER +#undef HANDLE_SUBSAMPLING bool