Mandelbrot: Scrap the old app, initial workings of a new one.

Based upon a HTML5 fractal engine by @kerwizzy (relicensed as MIT and copyright
assigned to Haiku, Inc. with permission from the author). Hacky and a mess,
but it works, and has the potentiality to be much nicer than the previous
Mandelbrot app.

Already supports rendering & zooming in, but has hacks all over the place.
This commit is contained in:
Augustin Cavalier 2016-05-15 17:42:35 -04:00
parent c8cfaef631
commit 86370d7b02
9 changed files with 2364 additions and 875 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,372 @@
/*
* Copyright 2016, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Augustin Cavalier <waddlesplash>
* kerwizzy
*/
#include "FractalEngine.h"
#include <SupportDefs.h>
#include <math.h>
#include "Colorsets.h"
#define colors Colorset_Royal
double zReal_end = 0;
double zImaginary_end = 0;
double juliaC_a = 0;
double juliaC_b = 1;
uint8 r = 0;
uint8 g = 0;
uint8 b = 0;
uint8 logChecked = 0;
uint8 smoothChecked = 0;
uint8 gEscapeHorizon = 4; // set to 64 when doing smooth colors
int32 gIterations = 1024;
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 renderPixel_default(double real, double imaginary)
{
int32 iterToEscape = (*inSet)(real, imaginary);
uint16 loc = 0;
if (iterToEscape == -1) {
// Didn't escape.
loc = 999;
} else {
loc = 998 - (iterToEscape % 999);
}
r = colors[loc * 3 + 0];
g = colors[loc * 3 + 1];
b = colors[loc * 3 + 2];
}
void renderPixel_smooth(double real, double imaginary)
{
int32 outColor = (*inSet)(real, imaginary);
int8 mapperDiff_r = 0;
int8 mapperDiff_g = 0;
int8 mapperDiff_b = 0;
int16 mapperLoc = 0;
double dist = sqrt(zReal_end * zReal_end + zImaginary_end * zImaginary_end);
double ratio = (1 - (log(log(dist))) / log(2));
if (sqrt(real * real + imaginary * imaginary) > 8) {
// Make the colors >8 be flat.
ratio = -1.0821509904820257;
outColor = 1;
}
if (outColor == -1) {
r = colors[999 * 3];
g = colors[999 * 3 + 1];
b = colors[999 * 3 + 2];
return;
}
outColor = 998 - (outColor % 999);
mapperLoc = outColor * 3;
mapperDiff_r = colors[mapperLoc + 0] - colors[mapperLoc + 0 + 3];
mapperDiff_g = colors[mapperLoc + 1] - colors[mapperLoc + 1 + 3];
mapperDiff_b = colors[mapperLoc + 2] - colors[mapperLoc + 2 + 3];
r = mapperDiff_r * ratio + colors[mapperLoc + 0];
g = mapperDiff_g * ratio + colors[mapperLoc + 1];
b = mapperDiff_b * ratio + colors[mapperLoc + 2];
}
int32 inSet_mandelbrot(double real, double imaginary)
{
double zReal = 0;
double zImaginary = 0;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
double zRealSq = zReal * zReal;
double zImaginarySq = zImaginary * zImaginary;
double nzReal = (zRealSq + (-1 * (zImaginarySq)));
zImaginary = 2 * (zReal * zImaginary);
zReal = nzReal;
zReal += real;
zImaginary += imaginary;
if ((zRealSq) + (zImaginarySq) >
escapeHorizon) { // If it is outside the 2 unit circle...
zReal_end = zReal;
zImaginary_end = zImaginary;
return i; // stop it from running longer
}
}
return -1;
}
int32 inSet_burningShip(double real, double imaginary)
{
double zReal = 0;
double zImaginary = 0;
// It looks "upside down" otherwise.
imaginary = -imaginary;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
zReal = fabs(zReal);
zImaginary = fabs(zImaginary);
double zRealSq = zReal * zReal;
double zImaginarySq = zImaginary * zImaginary;
double nzReal = (zRealSq + (-1 * (zImaginarySq)));
zImaginary = 2 * (zReal * zImaginary);
zReal = nzReal;
zReal += real;
zImaginary += imaginary;
// If it is outside the 2 unit circle...
if ((zRealSq) + (zImaginarySq) > escapeHorizon) {
zReal_end = zReal;
zImaginary_end = zImaginary;
return i; // stop it from running longer
}
}
return -1;
}
int32 inSet_tricornMandelbrot(double real, double imaginary)
{
double zReal = 0;
double zImaginary = 0;
real = -real;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
double znRe = zImaginary * -1;
zImaginary = zReal * -1;
zReal = znRe; // Swap the real and complex parts each time.
double zRealSq = zReal * zReal;
double zImaginarySq = zImaginary * zImaginary;
double nzReal = (zRealSq + (-1 * (zImaginarySq)));
zImaginary = 2 * (zReal * zImaginary);
zReal = nzReal;
zReal += real;
zImaginary += imaginary;
// If it is outside the 2 unit circle...
if ((zRealSq) + (zImaginarySq) > escapeHorizon) {
zReal_end = zReal;
zImaginary_end = zImaginary;
return i; // stop it from running longer
}
}
return -1;
}
int32 inSet_julia(double real, double imaginary)
{
double zReal = real;
double zImaginary = imaginary;
double muRe = juliaC_a;
double muIm = juliaC_b;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
double zRealSq = zReal * zReal;
double zImaginarySq = zImaginary * zImaginary;
double nzReal = (zRealSq + (-1 * (zImaginarySq)));
zImaginary = 2 * (zReal * zImaginary);
zReal = nzReal;
zReal += muRe;
zImaginary += muIm;
// If it is outside the 2 unit circle...
if ((zRealSq) + (zImaginarySq) > escapeHorizon) {
zReal_end = zReal;
zImaginary_end = zImaginary;
return i; // stop it from running longer
}
}
return -1;
}
int32 inSet_mandelbrot_orbitTrap(double real, double imaginary)
{
double zReal = 0;
double zImaginary = 0;
double closest = 10000000;
double distance = 0;
double lineDist = 0;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
double zRealSq = zReal * zReal;
double zImaginarySq = zImaginary * zImaginary;
double nzReal = (zRealSq + (-1 * (zImaginarySq)));
zImaginary = 2 * (zReal * zImaginary);
zReal = nzReal;
zReal += real;
zImaginary += imaginary;
distance = sqrt((zRealSq) + (zImaginarySq));
lineDist = fabs((zReal) + (zImaginary));
// If it is closer than ever before...
if (lineDist < closest)
closest = lineDist;
if (distance > escapeHorizon) {
zReal_end = zReal;
zImaginary_end = zImaginary;
return floor(4 * log(4 / closest));
}
}
return floor(4 * log(4 / closest));
}
int32 inSet_multibrot_3(double real, double imaginary)
{
double zReal = 0;
double zImaginary = 0;
int32 iterations = gIterations;
uint8 escapeHorizon = gEscapeHorizon;
int32 i = 0;
for (i = 0; i < iterations; i++) {
double zRealSq = zReal * zReal;
double zImaginarySq = zImaginary * zImaginary;
double nzReal = (zRealSq * zReal - 3 * zReal * (zImaginarySq));
zImaginary = 3 * ((zRealSq)*zImaginary) - (zImaginarySq * zImaginary);
zReal = nzReal;
zReal += real;
zImaginary += imaginary;
// If it is outside the 2 unit circle...
if ((zRealSq) + (zImaginarySq) > escapeHorizon) {
zReal_end = zReal;
zImaginary_end = zImaginary;
return i; // stop it from running longer
}
}
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) \
buf[width * y * 3 + x * 3 + 0] = r; \
buf[width * y * 3 + x * 3 + 1] = g; \
buf[width * y * 3 + x * 3 + 2] = b;
BBitmap* FractalEngine(uint32 width, uint32 height, double locationX,
double locationY, double size)
{
uint16 halfcWidth = width / 2;
uint16 halfcHeight = height / 2;
uint32 bufLen = width * height * 3;
uint8* buf = new uint8[bufLen];
renderPixel = renderPixel_default;
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);
}
}
BBitmap* ret = new BBitmap(BRect(0, 0, width - 1 , height - 1), 0, B_RGB24);
ret->ImportBits(buf, bufLen, width * 3, 0, B_RGB24_BIG);
return ret;
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2016, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Augustin Cavalier <waddlesplash>
* kerwizzy
*/
#ifndef FRACTALENGINE_H
#define FRACTALENGINE_H
#include <SupportDefs.h>
#include <Bitmap.h>
BBitmap* FractalEngine(uint32 width, uint32 height, double locationX,
double locationY, double size);
#endif /* FRACTALENGINE_H */

View File

@ -1,11 +1,12 @@
SubDir HAIKU_TOP src apps mandelbrot ;
SetSubDirSupportedPlatformsBeOSCompatible ;
AddSubDirSupportedPlatforms libbe_test ;
SubDirC++Flags -Wno-error ;
Application Mandelbrot :
Mandelbrot.cpp
tsb.cpp
FractalEngine.cpp
: be [ TargetLibsupc++ ] localestub
: Mandelbrot.rdef
;

View File

@ -1,31 +0,0 @@
----------------------
Be Sample Code License
----------------------
Copyright 1991-1999, Be Incorporated.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,215 +1,185 @@
/*
Copyright 1993-1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
* Copyright 2016, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Augustin Cavalier <waddlesplash>
*/
#include "tsb.h"
#include <Debug.h>
#include <Alert.h>
#include <Application.h>
#include <Bitmap.h>
#include <Catalog.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <OS.h>
#include <Roster.h>
#include <ScrollView.h>
#include <LayoutBuilder.h>
#include <View.h>
#include <Window.h>
#include <math.h>
#include <stdio.h>
#include "FractalEngine.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Mandelbrot"
#define B_TRANSLATION_CONTEXT "MandelbrotWindow"
/* Those are the menu item id's of the main window */
#define P1 0x60
#define P2 0x61
#define P3 0x62
#define P4 0x63
// #pragma mark - FractalView
class TMainWindow : public BWindow {
public:
TMainWindow(BRect bound, const char* name, window_type type,
long flags);
virtual ~TMainWindow();
virtual void MessageReceived(BMessage* message);
virtual void FrameResized(float width, float height);
virtual bool QuitRequested();
class FractalView : public BView {
public:
FractalView();
~FractalView();
void UpdateScrollBars();
virtual void AttachedToWindow();
virtual void FrameResized(float, float)
{ RedrawFractal(); }
virtual void MouseDown(BPoint where);
virtual void Draw(BRect updateRect);
private:
TShowBit* fView;
private:
BBitmap* fBitmap;
double fLocationX;
double fLocationY;
double fSize;
void RedrawFractal();
};
TMainWindow::TMainWindow(BRect bound, const char* name, window_type type,
long flags)
: BWindow(bound, name, type, flags)
FractalView::FractalView()
:
BView(NULL, B_WILL_DRAW),
fBitmap(NULL),
fLocationX(0),
fLocationY(0),
fSize(0.005)
{
BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 1000, 15), "MB");
BMenuItem* item;
BMenu* menu;
menu = new BMenu(B_TRANSLATE("File"));
menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
new BMessage(B_QUIT_REQUESTED), 'Q'));
menuBar->AddItem(menu);
menu = new BMenu(B_TRANSLATE("Palette"));
menu->AddItem(new BMenuItem(B_TRANSLATE("Palette 1"), new BMessage(P1)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Palette 2"), new BMessage(P2)));
menu->AddItem(item = new BMenuItem(B_TRANSLATE("Palette 3"),
new BMessage(P3)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Palette 4"), new BMessage(P4)));
menuBar->AddItem(menu);
item->SetMarked(true);
menu->SetRadioMode(true);
menu = new BMenu(B_TRANSLATE("Iterations"));
menu->AddItem(new BMenuItem("128", new BMessage(128)));
menu->AddItem(item = new BMenuItem("256", new BMessage(256)));
menu->AddItem(new BMenuItem("384", new BMessage(384)));
menu->AddItem(new BMenuItem("512", new BMessage(512)));
menu->AddItem(new BMenuItem("768", new BMessage(768)));
menu->AddItem(new BMenuItem("1024", new BMessage(1024)));
menu->AddItem(new BMenuItem("2048", new BMessage(2048)));
menu->AddItem(new BMenuItem("4096", new BMessage(4096)));
menu->AddItem(new BMenuItem("8192", new BMessage(8192)));
menuBar->AddItem(menu);
item->SetMarked(true);
menu->SetRadioMode(true);
AddChild(menuBar);
float barHeight = menuBar->Bounds().Height();
fView = new TShowBit(BRect(0, barHeight + 1, 188 - B_V_SCROLL_BAR_WIDTH,
188 - B_H_SCROLL_BAR_HEIGHT), B_FOLLOW_ALL, B_WILL_DRAW);
BScrollView *scrollView = new BScrollView("scroll view", fView,
B_FOLLOW_ALL, B_WILL_DRAW, true, true, B_NO_BORDER);
AddChild(scrollView);
SetSizeLimits(80, size_x + 13, 80 + 20, size_y + barHeight + 1 + 13);
ResizeTo(size_x + 13, size_y + barHeight + 1 + 13);
SetPulseRate(150000);
UpdateScrollBars();
}
TMainWindow::~TMainWindow()
FractalView::~FractalView()
{
delete fBitmap;
}
void FractalView::AttachedToWindow()
{
//RedrawFractal();
}
void FractalView::MouseDown(BPoint where)
{
BRect frame = Frame();
fLocationX = ((where.x - frame.Width() / 2) * fSize + fLocationX);
fLocationY = ((where.y - frame.Height() / 2) * -fSize + fLocationY);
fSize /= 2;
RedrawFractal();
}
void FractalView::RedrawFractal()
{
delete fBitmap;
fBitmap = FractalEngine(Frame().Width(), Frame().Height(), fLocationX,
fLocationY, fSize);
Invalidate();
}
void FractalView::Draw(BRect updateRect)
{
DrawBitmap(fBitmap, updateRect, updateRect);
}
// #pragma mark - MandelbrotWindow
class MandelbrotWindow : public BWindow
{
public:
MandelbrotWindow(BRect frame);
~MandelbrotWindow() {}
virtual void MessageReceived(BMessage* msg);
virtual bool QuitRequested();
private:
FractalView* fFractalView;
};
MandelbrotWindow::MandelbrotWindow(BRect frame)
:
BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Mandelbrot"), B_TITLED_WINDOW_LOOK,
B_NORMAL_WINDOW_FEEL, 0L),
fFractalView(new FractalView)
{
BMenuBar* menuBar = new BMenuBar("MenuBar");
BLayoutBuilder::Menu<>(menuBar)
.AddMenu(B_TRANSLATE("File"))
.AddItem(B_TRANSLATE("Quit"), B_QUIT_REQUESTED, 'Q')
.End()
.End();
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(0)
.Add(menuBar)
.Add(fFractalView)
.End();
}
void
TMainWindow::UpdateScrollBars()
MandelbrotWindow::MessageReceived(BMessage* msg)
{
BScrollView* scrollview;
BScrollBar* scrollbar;
BRect visible_extent;
BRect total_extent;
BRect bound;
BRect my_bounds;
long max;
Lock();
if ((scrollview = (BScrollView*)FindView("scroll view"))) {
bound.Set(0, 0, size_x, size_y);
my_bounds = Bounds();
visible_extent = bound & my_bounds;
total_extent = bound | my_bounds;
scrollbar = scrollview->ScrollBar(B_HORIZONTAL);
max = (long) (bound.Width() - my_bounds.Width());
if (max < 0)
max = 0;
scrollbar->SetRange(0, max);
scrollbar->SetProportion(visible_extent.Width() / total_extent.Width());
scrollbar = scrollview->ScrollBar(B_VERTICAL);
max = (long) (bound.Height() - my_bounds.Height());
if (max < 0)
max = 0;
scrollbar->SetRange(0, max);
scrollbar->SetProportion(visible_extent.Height() / total_extent.Height());
switch (msg->what) {
default:
BWindow::MessageReceived(msg);
break;
}
Unlock();
}
void
TMainWindow::FrameResized(float, float)
{
UpdateScrollBars();
}
bool
TMainWindow::QuitRequested()
MandelbrotWindow::QuitRequested()
{
if (fView->busy) {
fView->exit_now = true;
PostMessage(B_QUIT_REQUESTED);
return false;
if (BWindow::QuitRequested()) {
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
return false;
}
// #pragma mark - MandelbrotApp
class MandelbrotApp : public BApplication
{
public:
MandelbrotApp()
: BApplication("application/x-vnd.Haiku-Mandelbrot") {}
void ReadyToRun();
bool QuitRequested() { return true; }
};
void
TMainWindow::MessageReceived(BMessage* message)
MandelbrotApp::ReadyToRun()
{
switch (message->what) {
case P1:
case P2:
case P3:
case P4:
fView->set_palette(message->what - P1);
break;
case 128:
case 256:
case 384:
case 512:
case 768:
case 1024:
case 2048:
case 4096:
case 8192:
fView->set_iter(message->what);
break;
default:
BWindow::MessageReceived(message);
break;
}
MandelbrotWindow* wind = new MandelbrotWindow(BRect(0, 0, 640, 480));
wind->CenterOnScreen();
wind->Show();
}
// #pragma mark -
int
main(int, char**)
main(int argc, char* argv[])
{
BApplication* app = new BApplication("application/x-vnd.Haiku-Mandelbrot");
BWindow* window = new TMainWindow(BRect(100, 100, 288, 288),
B_TRANSLATE_SYSTEM_NAME("Mandelbrot"), B_DOCUMENT_WINDOW,
B_WILL_ACCEPT_FIRST_CLICK);
window->Show();
app->Run();
delete app;
MandelbrotApp().Run();
return 0;
}

View File

@ -1,3 +1,18 @@
resource app_signature "application/x-vnd.Haiku-Mandelbrot";
resource app_name_catalog_entry "x-vnd.Haiku-Mandelbrot:System name:Mandelbrot";
resource app_flags B_MULTIPLE_LAUNCH;
resource app_version {
major = 1,
middle = 0,
minor = 0,
variety = B_APPV_DEVELOPMENT,
internal = 0,
short_info = "Mandelbrot",
long_info = "Mandelbrot"
};
resource vector_icon {
$"6E6369660C04006B0500020006023B4FDF3A26DEBE07943F1FB649C6A13E02F4"
@ -23,10 +38,3 @@ resource vector_icon {
$"000A030107000A040108000A050109000A0701041001178100040A010104000A"
$"09010A000A09010C000A0A010D000A0A010B00"
};
resource app_signature "application/x-vnd.Haiku-Mandelbrot";
resource app_name_catalog_entry "x-vnd.Haiku-Mandelbrot:System name:Mandelbrot";
resource app_flags B_MULTIPLE_LAUNCH;

View File

@ -1,609 +0,0 @@
//******************************************************************************
//
// File: tsb.cpp
//
//******************************************************************************
/*
Copyright 1993-1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#include <Debug.h>
#include <Window.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <OS.h>
#include <Screen.h>
#include "tsb.h"
#ifndef _INTERFACE_DEFS_H
#include <InterfaceDefs.h>
#endif
/*------------------------------------------------------------*/
static TShowBit *tsbb;
static long niter = 256;
static uchar palette[256];
void TShowBit::MouseDown(BPoint where)
{
if (!this->Window()->IsActive()) {
this->Window()->Activate(TRUE);
this->Window()->UpdateIfNeeded();
}
if (busy)
return;
if ((modifiers() & B_SHIFT_KEY) == 0) {
change_selection(where.x, where.y);
if ((selection.bottom - selection.top) < 4)
return;
}
redraw_mand();
}
void
TShowBit::MessageReceived(BMessage* message)
{
switch(message->what) {
case B_MOUSE_WHEEL_CHANGED:
{
//float factor = 1;
float change = message->FindFloat("be:wheel_delta_y");
BPoint where;
GetMouse(&where, 0, 0);
selection = Bounds();
if (change < 0) {
// zoom in
selection.top = (where.y + selection.top) / 2;
selection.bottom = (where.y + selection.bottom) / 2;
selection.left = (where.x + selection.left) / 2;
selection.right = (where.x + selection.right) / 2;
} else {
// zoom out
selection.top = - where.y + selection.top * 2;
selection.bottom = - where.y + selection.bottom * 2;
selection.left = - where.x + selection.left * 2;
selection.right = - where.x + selection.right * 2;
}
redraw_mand();
break;
}
default:
BView::MessageReceived(message);
}
}
void TShowBit::redraw_mand()
{
double px0;
double py0;
double scale0;
if (modifiers() & B_SHIFT_KEY) {
px -= (scale / 2.0);
py -= (scale / 2.0);
scale *= 2.0;
} else {
px0 = px + (scale * (selection.left / (1.0*size_x)));
py0 = py + (scale * (selection.top / (1.0*size_x)));
scale0 = scale * ((selection.bottom-selection.top) / (1.0*size_x));
px = px0; py = py0; scale = scale0;
}
selection.Set(-1000, -1000, -1000, -1000);
mand(px, py, scale, scale);
}
/*------------------------------------------------------------*/
void TShowBit::set_iter(long it)
{
if (it != iter) {
iter = it;
niter = it;
selection.Set(-1000, -1000, -1000, -1000);
mand(px, py, scale, scale);
}
}
/*------------------------------------------------------------*/
void TShowBit::set_palette(long code)
{
rgb_color c = {0, 0, 0, 255};
long i;
BScreen screen( Window() );
if (code == 0) {
for (i = 0; i < 256; i++)
palette[i] = (i >> 1) & 0x1f;
}
if (code == 1) {
for (i = 0; i < 256; i++) {
c.red = i * 4;
c.green = i * 7;
c.blue = 256-(i - i * 5);
palette[i] = screen.IndexForColor(c);
}
}
if (code == 2) {
for (i = 0; i < 256; i++) {
c.red = (i * 7);
c.green = i/2;
c.blue = 256-(i * 3);
palette[i] = screen.IndexForColor(c);
}
}
if (code == 3) {
for (i = 0; i < 256; i++) {
c.red = 256-(i * 6);
c.green = (i * 7);
c.blue = 0;
palette[i] = screen.IndexForColor(c);
}
}
mand(px, py, scale, scale);
}
/*------------------------------------------------------------*/
TShowBit::TShowBit(BRect r, uint32 resizeMask, uint32 flags) :
BView(r, "", resizeMask, flags | B_WILL_DRAW | B_PULSE_NEEDED)
{
BRect bitmap_r;
char *bits;
busy = FALSE;
exit_now = FALSE;
tsbb = this;
bitmap_r.Set(0, 0, size_x - 1, size_y - 1);
selection.Set(-1000, -1000, -1000, -1000);
iter = 256;
the_bitmap = new BBitmap(bitmap_r, B_COLOR_8_BIT);
bits = (char *)the_bitmap->Bits();
memset(bits, 0x00, size_x*size_y);
px = -2.5;
py = -2.0;
scale = 4.0;
set_palette(2);
}
/*------------------------------------------------------------*/
TShowBit::~TShowBit()
{
delete the_bitmap;
}
/*------------------------------------------------------------*/
void TShowBit::Draw(BRect update_rect)
{
DrawBitmap(the_bitmap, BPoint(0, 0));
}
/*------------------------------------------------------------*/
int iterate_double(double a, double b)
{
double x;
double y;
double xsq;
double ysq;
int i = 0, iter = niter;
x = 0.0;
y = 0.0;
while (i < iter) {
xsq = x * x;
ysq = y * y;
y = (2.0 * x * y) + b;
i++;
x = a + (xsq - ysq);
if ((xsq + ysq) > 4.0)
return(i);
}
return(i);
}
/*------------------------------------------------------------*/
//extern "C" int iterate(float a, float b);
/*------------------------------------------------------------*/
int iterate_float(float a, float b)
{
float x;
float y;
float xsq;
float ysq;
long i;
int iter = niter;
x = 0.0;
y = 0.0;
i = 0;
while (i < iter) {
xsq = x * x;
ysq = y * y;
y = (2.0f * x * y) + b;
i++;
x = a + (xsq - ysq);
if ((xsq + ysq) > 4.0f)
return(i);
}
return(i);
}
/*------------------------------------------------------------*/
double vvx;
double vvy;
double ssx;
char t1_done;
char t2_done;
/*------------------------------------------------------------*/
int32 __calc1(void *arg)
{
tsbb->manda(vvx, vvy, ssx, ssx);
return B_NO_ERROR;
}
/*------------------------------------------------------------*/
int32 __calc2(void *arg)
{
tsbb->mandb(vvx, vvy, ssx, ssx);
return B_NO_ERROR;
}
/*------------------------------------------------------------*/
uchar tmp[256];
uchar pc[32][32];
uchar tmp1[256];
/*------------------------------------------------------------*/
void TShowBit::mand(double vx, double vy, double sx, double sy)
{
vvx = vx; vvy = vy; ssx = sx;
t1_done = 0; t2_done = 0;
precompute(vx, vy, sx, sy);
resume_thread(spawn_thread(__calc1, "calc1", B_NORMAL_PRIORITY, NULL));
resume_thread(spawn_thread(__calc2, "calc2", B_NORMAL_PRIORITY, NULL));
busy = TRUE;
}
/*------------------------------------------------------------*/
void TShowBit::Pulse()
{
// PRINT(("pulsing (%d)\n", busy));
if (busy) {
Draw(BRect(0,0,0,0));
if (t1_done && t2_done) {
busy = FALSE;
exit_now = FALSE;
}
}
}
/*------------------------------------------------------------*/
void TShowBit::precompute(double vx, double vy, double sx, double sy)
{
long x, y;
double cx, cy;
double scale = sx;
sx = sx / (32.0);
sy = sy / (32.0);
cy = vy;
for (y = 0; y < 32; y++) {
cy += sy;
cx = vx;
if (scale < 0.000025 || niter != 256) {
for (x = 0; x < 32; x++) {
cx += sx;
pc[x][y] = iterate_double(cx, cy);
}
}
else
for (x = 0; x < 32; x++) {
cx += sx;
pc[x][y] = iterate_float(cx, cy);
}
}
}
/*------------------------------------------------------------*/
void TShowBit::mandb(double vx, double vy, double sx, double sy)
{
long x, y;
long bx;
double cx, cy;
int v;
uchar *bits = (uchar *)the_bitmap->Bits();
uchar *b0;
long y12;
long x12;
double scale = sx;
sx = sx / (size_x * 1.0);
sy = sy / (size_y * 1.0);
cy = vy;
cy += sy;
sy *= 2.0;
for (y = 1; y < size_y; y+=2) {
y12 = y / 12;
cy += sy;
cx = vx;
b0 = bits + (y * size_x);
for (bx = 0; bx < size_x; bx += 12) {
x12 = (bx+6) / 12;
v = pc[x12][y12];
if (exit_now)
goto done;
if (v == pc[x12+1][y12] &&
v == pc[x12][y12+1] &&
v == pc[x12-1][y12] &&
v == pc[x12][y12-1] &&
v == pc[x12-2][y12]) {
for (x = bx; x < (bx+12); x++) {
cx += sx;
*b0++ = palette[v & 0xff];
}
}
else {
if (scale < 0.000025 || niter != 256) {
for (x = bx; x < (bx+12); x++) {
cx += sx;
v = iterate_double(cx, cy);
*b0++ = palette[v & 0xff];
}
}
else
for (x = bx; x < (bx+12); x++) {
cx += sx;
v = iterate_float(cx, cy);
*b0++ = palette[v & 0xff];
}
}
}
}
done:
t2_done = 1;
}
/*------------------------------------------------------------*/
void TShowBit::manda(double vx, double vy, double sx, double sy)
{
long x, y;
long bx;
double cx, cy;
int v;
uchar *bits = (uchar *)the_bitmap->Bits();
uchar *b0;
long y12;
long x12;
double scale = sx;
sx = sx / (size_x * 1.0);
sy = sy / (size_y * 1.0);
cy = vy;
sy *= 2.0;
for (y = 0; y < size_y; y+=2) {
y12 = y / 12;
cy += sy;
cx = vx;
b0 = bits + (y * size_x);
for (bx = 0; bx < size_x; bx += 12) {
x12 = (bx+6) / 12;
v = pc[x12][y12];
if (exit_now)
goto done;
if (v == pc[x12+1][y12] &&
v == pc[x12][y12+1] &&
v == pc[x12-1][y12] &&
v == pc[x12][y12-1] &&
v == pc[x12-2][y12]) {
for (x = bx; x < (bx+12); x++) {
cx += sx;
*b0++ = palette[v & 0xff];
}
}
else {
if (scale < 0.000025 || niter != 256) {
for (x = bx; x < (bx+12); x++) {
cx += sx;
v = iterate_double(cx, cy);
*b0++ = palette[v & 0xff];
}
}
else
for (x = bx; x < (bx+12); x++) {
cx += sx;
v = iterate_float(cx, cy);
*b0++ = palette[v & 0xff];
}
}
}
}
done:
t1_done = 1;
}
/*------------------------------------------------------------*/
long TShowBit::limit_v(long v)
{
if (v > (size_y - 1))
v = (size_y - 1);
if (v < 0)
v = 0;
return(v);
}
/*------------------------------------------------------------*/
long TShowBit::limit_h(long v)
{
if (v > (size_x - 1))
v = size_x - 1;
if (v < 0)
v = 0;
return(v);
}
/*------------------------------------------------------------*/
BRect TShowBit::sort_rect(BRect *aRect)
{
BRect tmp_rect;
long tmp;
tmp_rect = *aRect;
if (tmp_rect.bottom < tmp_rect.top) {
tmp = (long)tmp_rect.top;
tmp_rect.top = tmp_rect.bottom;
tmp_rect.bottom = tmp;
}
if (tmp_rect.left > tmp_rect.right) {
tmp = (long) tmp_rect.right;
tmp_rect.right = tmp_rect.left;
tmp_rect.left = tmp;
}
tmp_rect.top = limit_v(tmp_rect.top);
tmp_rect.left = limit_h(tmp_rect.left);
tmp_rect.bottom = limit_v(tmp_rect.bottom);
tmp_rect.right = limit_h(tmp_rect.right);
return(tmp_rect);
}
/*------------------------------------------------------------*/
void TShowBit::clip(long *h, long *v)
{
if (*h > (size_x - 1))
*h = (size_x - 1);
if (*h < 0)
*h = 0;
if (*v > (size_y - 1))
*v = size_y - 1;
if (*v < 0)
*v = 0;
}
/*------------------------------------------------------------*/
char TShowBit::has_selection()
{
if (((selection.bottom - selection.top) + (selection.right - selection.left)) < 5)
return 0;
else
return 1;
}
void TShowBit::change_selection(long h, long v)
{
uint32 buttons;
long h0;
long v0;
BRect new_select;
BRect old_select;
BRect tmp_rect;
long max;
long width, height;
clip(&h, &v);
new_select.top = v;
new_select.left = h;
old_select = selection;
SetDrawingMode(B_OP_INVERT);
do {
BPoint where;
GetMouse(&where, &buttons);
h0 = (long) where.x;
v0 = (long) where.y;
width = h0 - h;
height = v0 - v;
max = std::max(std::abs(height), std::abs(width));
v0 = (v0 > v) ? (v + max) : (v - max);
h0 = (h0 > h) ? (h + max) : (h - max);
clip(&h0, &v0);
new_select.right = h0;
new_select.bottom = v0;
if ((old_select.top != new_select.top)
|| (old_select.bottom != new_select.bottom)
|| (old_select.right != new_select.right)
|| (old_select.left != new_select.left)) {
tmp_rect = sort_rect(&new_select);
StrokeRect(tmp_rect);
tmp_rect = sort_rect(&old_select);
StrokeRect(tmp_rect);
old_select = new_select;
Flush();
}
snooze(20000);
} while (buttons);
selection = sort_rect(&new_select);
if (!has_selection()) {
StrokeRect(selection);
selection.Set(-1000, -1000, -1000, -1000);
}
SetDrawingMode(B_OP_COPY);
}

View File

@ -1,59 +0,0 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _VIEW_H
#include <View.h>
#endif
#ifndef _BITMAP_H
#include <Bitmap.h>
#endif
#include <math.h>
#ifndef TSB
#define TSB
/*------------------------------------------------------------*/
#define size_x 384
#define size_y 384
/*------------------------------------------------------------*/
class TShowBit : public BView {
public:
BBitmap *the_bitmap;
bool busy;
bool exit_now;
BRect selection;
double px;
double py;
double scale;
long iter;
TShowBit(BRect r, uint32 resizeMask, uint32 flags);
virtual ~TShowBit();
virtual void Draw(BRect);
virtual void MouseDown(BPoint where);
void MessageReceived(BMessage* message);
virtual void Pulse();
void mand(double vx, double vy, double sx, double sy);
long limit_v(long v);
long limit_h(long h);
BRect sort_rect(BRect *aRect);
void clip(long *h, long *v);
void change_selection(long h, long v);
char has_selection();
void redraw_mand();
void mandb(double vx, double vy, double sx, double sy);
void manda(double vx, double vy, double sx, double sy);
void set_palette(long code);
void set_iter(long i);
void precompute(double vx, double vy, double sx, double sy);
};
/*------------------------------------------------------------*/
#endif