mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-30 06:12:22 -06:00
examples: A simple Mandelbrot fractal viewer, using SIMD extensions
Examples/Mandelbrot: Cosmetics examples/Mandelbrot: fix.
This commit is contained in:
parent
d7b55c68be
commit
5bc6810ea1
5 changed files with 237 additions and 0 deletions
31
examples/Mandelbrot/Mandelbrot.h
Normal file
31
examples/Mandelbrot/Mandelbrot.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _Mandelbrot_Mandelbrot_h
|
||||
#define _Mandelbrot_Mandelbrot_h
|
||||
|
||||
// Run this example in release mode (-O3)
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#define LAYOUTFILE <Mandelbrot/Mandelbrot.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
class Mandelbrot : public WithMainLayout<TopWindow> {
|
||||
public:
|
||||
Mandelbrot();
|
||||
void Reset();
|
||||
void LeftDown(Point pt, dword keyflags) override;
|
||||
void LeftUp(Point pt, dword keyflags) override;
|
||||
void MouseMove(Point pt, dword keyflags) override;
|
||||
void MouseWheel(Point pt, int zdelta, dword keyflags) override;
|
||||
|
||||
private:
|
||||
Image DrawScalar(int itermax);
|
||||
Image DrawSIMD(int itermax);
|
||||
void Update();
|
||||
Rectf crect = { -2.0f, -1.5f, 1.0f, 1.5f };
|
||||
bool rendering = false;
|
||||
Point panpos = { -1, -1 };
|
||||
};
|
||||
|
||||
#endif
|
||||
9
examples/Mandelbrot/Mandelbrot.lay
Normal file
9
examples/Mandelbrot/Mandelbrot.lay
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
LAYOUT(MainLayout, 584, 372)
|
||||
ITEM(Upp::ImageCtrl, view, HSizePosZ(4, 4).VSizePosZ(4, 60))
|
||||
ITEM(Upp::Button, render, SetLabel(t_("Reset")).RightPosZ(4, 148).BottomPosZ(5, 23))
|
||||
ITEM(Upp::Option, simd, SetLabel(t_("Use SIMD")).LeftPosZ(264, 164).BottomPosZ(8, 16))
|
||||
ITEM(Upp::StaticText, timing, SetAlign(Upp::ALIGN_CENTER).SetFrame(Upp::ThinInsetFrame()).HSizePosZ(4, 4).BottomPosZ(37, 19))
|
||||
ITEM(Upp::DropList, maxiter, LeftPosZ(96, 160).BottomPosZ(6, 19))
|
||||
ITEM(Upp::Label, dv___5, SetLabel(t_("Max. iterations")).LeftPosZ(4, 88).BottomPosZ(8, 16))
|
||||
END_LAYOUT
|
||||
|
||||
13
examples/Mandelbrot/Mandelbrot.upp
Normal file
13
examples/Mandelbrot/Mandelbrot.upp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
description "A simple Mandelbrot fractal viewer, using SIMD extensions when available\377";
|
||||
|
||||
uses
|
||||
CtrlLib;
|
||||
|
||||
file
|
||||
Mandelbrot.h,
|
||||
main.cpp,
|
||||
Mandelbrot.lay;
|
||||
|
||||
mainconfig
|
||||
"" = "GUI";
|
||||
|
||||
9
examples/Mandelbrot/SIMDDemo.lay
Normal file
9
examples/Mandelbrot/SIMDDemo.lay
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
LAYOUT(SIMDDemoLayout, 584, 372)
|
||||
ITEM(Upp::ImageCtrl, view, HSizePosZ(4, 4).VSizePosZ(4, 60))
|
||||
ITEM(Upp::Button, render, SetLabel(t_("Reset")).RightPosZ(4, 148).BottomPosZ(5, 23))
|
||||
ITEM(Upp::Option, simd, SetLabel(t_("Use SIMD")).LeftPosZ(264, 164).BottomPosZ(8, 16))
|
||||
ITEM(Upp::StaticText, timing, SetAlign(Upp::ALIGN_CENTER).SetFrame(Upp::ThinInsetFrame()).HSizePosZ(4, 4).BottomPosZ(37, 19))
|
||||
ITEM(Upp::DropList, maxiter, LeftPosZ(96, 160).BottomPosZ(6, 19))
|
||||
ITEM(Upp::Label, dv___5, SetLabel(t_("Max. iterations")).LeftPosZ(4, 88).BottomPosZ(8, 16))
|
||||
END_LAYOUT
|
||||
|
||||
175
examples/Mandelbrot/main.cpp
Normal file
175
examples/Mandelbrot/main.cpp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
#include "Mandelbrot.h"
|
||||
|
||||
// Run this example in release mode (-O3)
|
||||
|
||||
force_inline RGBA GetFractalColor(int iter, int maxiter)
|
||||
{
|
||||
float hue = (float) iter / maxiter;
|
||||
float val = (iter < maxiter) ? 1.0f : 0.0f;
|
||||
return HsvColorf(hue, 1.0f, val);
|
||||
}
|
||||
|
||||
Mandelbrot::Mandelbrot()
|
||||
{
|
||||
CtrlLayout(*this, "Mandelbrot Viewer");
|
||||
#ifndef CPU_SIMD
|
||||
simd.Hide();
|
||||
#endif
|
||||
for(int i : { 250, 500, 1000 })
|
||||
maxiter.Add(i);
|
||||
maxiter.SetIndex(1);
|
||||
auto cb = [this] { Update(); };
|
||||
render << [this] { Reset(); Update(); };
|
||||
maxiter << cb;
|
||||
simd << cb;
|
||||
render.WhenAction();
|
||||
view.IgnoreMouse();
|
||||
}
|
||||
|
||||
void Mandelbrot::Reset()
|
||||
{
|
||||
rendering = true;
|
||||
crect = { -2.0f, -1.5f, 1.0f, 1.5f };
|
||||
maxiter.SetIndex(1);
|
||||
simd = true;
|
||||
rendering = false;
|
||||
}
|
||||
|
||||
void Mandelbrot::Update()
|
||||
{
|
||||
if(rendering)
|
||||
return;
|
||||
|
||||
rendering = true;
|
||||
TimeStop ts;
|
||||
Image img = ~simd ? DrawSIMD(~maxiter) : DrawScalar(~maxiter);
|
||||
timing.SetText(Format("Generated in %02.0f milliseconds...", ts.Elapsed() / 1000.0));
|
||||
view.SetImage(img);
|
||||
rendering = false;
|
||||
}
|
||||
|
||||
Image Mandelbrot::DrawScalar(int itermax)
|
||||
{
|
||||
const Size sz = view.GetSize();
|
||||
const float dx = crect.GetWidth() / sz.cx;
|
||||
const float dy = crect.GetHeight() / sz.cy;
|
||||
ImageBuffer ib(sz);
|
||||
RGBA* pix = ib;
|
||||
|
||||
for(int py = 0; py < sz.cy; py++) {
|
||||
const float cy = crect.top + py * dy;
|
||||
for(int px = 0; px < sz.cx; px++) {
|
||||
float cx = crect.left + px * dx;
|
||||
float zx = 0.0f, zy = 0.0f;
|
||||
int iter = 0;
|
||||
for(int k = 0; k < itermax; k++) {
|
||||
float zx2 = zx * zx;
|
||||
float zy2 = zy * zy;
|
||||
if(zx2 + zy2 >= 4.0f)
|
||||
break;
|
||||
float zxy = zx * zy;
|
||||
zx = zx2 - zy2 + cx;
|
||||
zy = zxy + zxy + cy;
|
||||
iter++;
|
||||
}
|
||||
pix[py * sz.cx + px] = GetFractalColor(iter, itermax);
|
||||
}
|
||||
ProcessEvents();
|
||||
}
|
||||
|
||||
return ib;
|
||||
}
|
||||
|
||||
Image Mandelbrot::DrawSIMD(int itermax)
|
||||
{
|
||||
#ifdef CPU_SIMD
|
||||
const Size sz = view.GetSize();
|
||||
const float dx = crect.GetWidth() / sz.cx;
|
||||
const float dy = crect.GetHeight() / sz.cy;
|
||||
ImageBuffer ib(sz);
|
||||
RGBA* pix = ib;
|
||||
const int block = 4;
|
||||
|
||||
const float offsets[block] = { 0.0f, dx, 2.0f * dx, 3.0f * dx };
|
||||
f32x4 xoffsets; xoffsets.Load(offsets);
|
||||
|
||||
for(int py = 0; py < sz.cy; py++) {
|
||||
f32x4 cy4 = f32all(crect.top + py * dy);
|
||||
for(int px = 0; px < sz.cx; px += block) {
|
||||
f32x4 cx4 = f32all(crect.left + px * dx) + xoffsets;
|
||||
f32x4 zx = f32all(0.0f), zy = f32all(0.0f);
|
||||
i32x4 iter = i32all(0);
|
||||
for(int k = 0; k < itermax; k++) {
|
||||
f32x4 zx2 = zx * zx;
|
||||
f32x4 zy2 = zy * zy;
|
||||
f32x4 mag2 = zx2 + zy2;
|
||||
f32x4 mask = mag2 < f32all(4.0f);
|
||||
if(!AnyTrue(mask))
|
||||
break;
|
||||
f32x4 zxy = zx * zy;
|
||||
zx = zx2 - zy2 + cx4;
|
||||
zy = zxy + zxy + cy4;
|
||||
iter = IncrementIf(iter, mask);
|
||||
}
|
||||
alignas(16) int tmp[block];
|
||||
iter.Store(tmp);
|
||||
for(int i = 0; i < block; i++) {
|
||||
if(px + i >= sz.cx) break;
|
||||
pix[py * sz.cx + px + i] = GetFractalColor(tmp[i], itermax);
|
||||
}
|
||||
}
|
||||
ProcessEvents();
|
||||
}
|
||||
|
||||
return ib;
|
||||
#else
|
||||
return DrawScalar(itermax);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mandelbrot::LeftDown(Point pt, dword keyflags)
|
||||
{
|
||||
if(!rendering) {
|
||||
panpos = pt;
|
||||
SetCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void Mandelbrot::LeftUp(Point pt, dword keyflags)
|
||||
{
|
||||
if(panpos.x != -1) {
|
||||
panpos = Point(-1, -1);
|
||||
ReleaseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void Mandelbrot::MouseMove(Point pt, dword keyflags)
|
||||
{
|
||||
if(rendering || panpos.x == -1)
|
||||
return;
|
||||
|
||||
const Size sz = view.GetSize();
|
||||
const Sizef csz = crect.GetSize();
|
||||
const double dx = (double)(pt.x - panpos.x) / sz.cx * csz.cx;
|
||||
const double dy = (double)(pt.y - panpos.y) / sz.cy * csz.cy;
|
||||
crect.Offset((float) -dx, (float) -dy);
|
||||
panpos = pt;
|
||||
Update();
|
||||
}
|
||||
|
||||
void Mandelbrot::MouseWheel(Point pt, int zdelta, dword keyflags)
|
||||
{
|
||||
if(rendering)
|
||||
return;
|
||||
|
||||
const Size sz = view.GetSize();
|
||||
const double scale = (zdelta > 0) ? 0.8 : 1.25;
|
||||
const Sizef csz = crect.GetSize();
|
||||
crect = Rectf(crect.TopLeft() + (Pointf(pt) / Sizef(sz)) * csz * (1.0 - scale), csz * scale);
|
||||
Update();
|
||||
}
|
||||
|
||||
GUI_APP_MAIN
|
||||
{
|
||||
Mandelbrot().Run();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue