From 57a06513c8148a069c0de69e556819e75eb0834e Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Tue, 17 May 2011 00:36:08 -0400 Subject: [PATCH] Initial Git commit --- GradientDesigner.ec | 337 +++++++++ LICENSE | 28 + fractals.ec | 1482 ++++++++++++++++++++++++++++++++++++++++ fractals.epj | 38 ++ samples/MOI.frc | 42 ++ samples/colorful.frc | 70 ++ samples/coolSpiral.frc | 42 ++ samples/deep.frc | 46 ++ samples/hot.frc | 50 ++ samples/hot2.frc | 50 ++ samples/oldColors.frc | 66 ++ samples/purplishmandelbrot.frc | 38 ++ samples/seaHorseValley.frc | 50 ++ samples/star.frc | 16 + samples/sunnySpiral.frc | 46 ++ samples/woah.frc | 50 ++ 16 files changed, 2451 insertions(+) create mode 100644 GradientDesigner.ec create mode 100644 LICENSE create mode 100644 fractals.ec create mode 100644 fractals.epj create mode 100644 samples/MOI.frc create mode 100644 samples/colorful.frc create mode 100644 samples/coolSpiral.frc create mode 100644 samples/deep.frc create mode 100644 samples/hot.frc create mode 100644 samples/hot2.frc create mode 100644 samples/oldColors.frc create mode 100644 samples/purplishmandelbrot.frc create mode 100644 samples/seaHorseValley.frc create mode 100644 samples/star.frc create mode 100644 samples/sunnySpiral.frc create mode 100644 samples/woah.frc diff --git a/GradientDesigner.ec b/GradientDesigner.ec new file mode 100644 index 0000000..baec4d0 --- /dev/null +++ b/GradientDesigner.ec @@ -0,0 +1,337 @@ +#ifdef ECERE_STATIC +import static "ecere" +#else +import "ecere" +#endif + +/* +static ColorKey defaultKeys[] = +{ + { navy, 0.0f }, + { green, 0.1f }, + { yellow, 0.2f }, + { orange, 0.3f }, + { red, 0.4f }, + { purple, 0.5f }, + { ivory, 0.6f }, + { tomato, 0.7f }, + { white, 0.8f }, + { powderBlue, 0.9f }, + { black, 1 } +}; +*/ +/* +static ColorKey defaultKeys[] = +{ + { navy, 0.0f }, + { Color { 146, 237, 237 }, 0.2f }, + { white, 0.3f }, + { lightYellow, 0.5f }, + { Color { 255, 100, 0 }, 0.8f }, + { navy, 0.99f }, + { black, 1 } +}; +*/ +static ColorKey defaultKeys[] = +{ + { navy, 0.0f }, + { Color { 146, 213, 237 }, 0.198606268f }, + { white, 0.3f }, + { Color { 255, 255, 124 }, 0.444250882f }, + { Color { 255, 100, 0 }, 0.634146333f }, + { navy, 1 } +}; + +class ArrayColorKeys : OldArray +{ + type = class(ColorKey); + ColorKey * _; +}; + +class ColorGradient +{ + ArrayColorKeys keys { }; + float smoothness; + smoothness = 1; + + ColorGradient() + { + keys.size = sizeof(defaultKeys) / sizeof(ColorKey); + memcpy(keys._, defaultKeys, sizeof(ColorKey) * keys.size); + } +} + +define handleWidth = 15; + +static uint CompareKeys(ColorKey a, ColorKey b) +{ + if(a.percent > b.percent) return 1; + else if(a.percent < b.percent) return -1; + else return 0; +} + +class KeyHandle : Window +{ + size = { handleWidth, 20 }; + borderStyle = deep; + + bool sliding; + float percent; + int startPos, startX; + + bool OnLeftButtonDown(int x, int y, Modifiers mods) + { + GradientDesigner designer = (GradientDesigner)master; + sliding = true; + startPos = position.x; + startX = x; + + Capture(); + + return true; + } + + bool OnMouseMove(int x, int y, Modifiers mods) + { + if(sliding) + { + GradientDesigner designer = (GradientDesigner)master; + int c; + ColorKey * key; + + for(c = 0; c < designer.gradient.keys.size; c++) + { + key = &designer.gradient.keys._[c]; + if(key->percent == percent && key->color == background) + break; + } + + x -= startX; + x += startPos; + x -= designer.preview.position.x; + x += handleWidth / 2; + key->percent = (float) x / (float) designer.preview.size.w; + + x = Max(x, 0); + x = Min(x, designer.preview.size.w); + percent = (float) x / (float) designer.preview.size.w; + + position.x = (percent * designer.preview.size.w) + designer.preview.position.x - handleWidth/2; + startPos = position.x; + + qsort(designer.gradient.keys._, designer.gradient.keys.size, sizeof(ColorKey), CompareKeys); + + for(c = 0; c < designer.gradient.keys.size; c++) + { + key = &designer.gradient.keys._[c]; + if(key->percent < 0) key->percent = 0; + else if(key->percent > 1) key->percent = 1; + } + + designer.Update(null); + designer.NotifyUpdate(designer.master); + } + return true; + } + + bool OnLeftDoubleClick(int x, int y, Modifiers mods) + { + ColorPicker colorPicker { master = this }; + colorPicker.color = background; + incref colorPicker; + if(colorPicker.Modal() == ok) + { + GradientDesigner designer = (GradientDesigner)master; + int c; + ColorKey * key; + + for(c = 0; c < designer.gradient.keys.size; c++) + { + key = &designer.gradient.keys._[c]; + if(key->percent == percent && key->color == background) + break; + } + background = colorPicker.color; + key->color = background; + designer.Update(null); + designer.NotifyUpdate(designer.master); + } + delete colorPicker; + return false; + } + + bool OnKeyDown(Key key, unichar ch) + { + if(key == del) + { + GradientDesigner designer = (GradientDesigner)master; + ColorKey * key; + int c; + + for(c = 0; c < designer.gradient.keys.size; c++) + { + key = &designer.gradient.keys._[c]; + if(key->percent == percent && key->color == background) + break; + } + *key = designer.gradient.keys._[designer.gradient.keys.size-1]; + designer.gradient.keys.size--; + qsort(designer.gradient.keys._, designer.gradient.keys.size, sizeof(ColorKey), CompareKeys); + Destroy(0); + + designer.Update(null); + designer.NotifyUpdate(designer.master); + return false; + } + return true; + } + + bool OnLeftButtonUp(int x, int y, Modifiers mods) + { + if(sliding) + { + ReleaseCapture(); + sliding = false; + } + return true; + } + + void OnRedraw(Surface surface) + { + if(active) + { + if(background.r > 128 || background.g > 128) + surface.SetForeground(darkGray); + else + surface.SetForeground(white); + + surface.Rectangle(0,0,clientSize.w-1, clientSize.h-1); + surface.Rectangle(1,1,clientSize.w-2, clientSize.h-2); + } + } + + bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct) + { + Update(null); + return true; + } +} + +class GradientDesigner : Window +{ + text = "Gradient Designer"; + borderStyle = fixed; + size = { 600, 300 }; + tabCycle = true; + + ColorGradient gradient { }; + Window preview + { + this, anchor = { left = 10, right = 10, top = 75, bottom = 75 }; + borderStyle = deep; + + void OnRedraw(Surface surface) + { + ColorGradient gradient = ((GradientDesigner)master).gradient; + surface.Gradient(gradient.keys._, gradient.keys.size, gradient.smoothness, horizontal, 0,0, clientSize.w-1, clientSize.h-1); + } + }; + + void OnRedraw(Surface surface) + { + int c; + + for(c = 0; c < gradient.keys.size; c++) + { + ColorKey * key = gradient.keys._ + c; + int x = key->percent * preview.size.w + preview.position.x; + surface.SetForeground(black); + surface.DrawLine(x - 6, preview.position.y - 10, x, preview.position.y); + surface.DrawLine(x + 6, preview.position.y - 10, x, preview.position.y); + surface.SetForeground(gray); + surface.DrawLine(x - 5, preview.position.y - 10, x, preview.position.y - 1); + surface.DrawLine(x + 5, preview.position.y - 10, x, preview.position.y - 1); + } + } + ScrollBar smoothness + { + this, borderStyle = deep, clientSize = { 124, 18 }, position = { 16, 240 }, range = 100; + text = "Smoothness"; + + void NotifyScrolling(ScrollBar scrollBar, ScrollBarAction action, int position, Key key) + { + gradient.smoothness = position / 100.0f; + Update(null); + NotifyUpdate(master); + } + }; + Label lblSmoothness { this, labeledWindow = smoothness, position = { 16, 220 } }; + + void UpdateHandles() + { + Window window, next; + int c; + + smoothness.thumbPosition = (int)gradient.smoothness * 100; + for(window = firstChild; window; window = next) + { + next = window.next; + if(window._class == class(KeyHandle)) + { + window.Destroy(0); + } + } + for(c = 0; c < gradient.keys.size; c++) + { + ColorKey * key = gradient.keys._ + c; + KeyHandle handle { this, percent = key->percent, position = { key->percent * preview.size.w + preview.position.x - handleWidth/2, preview.position.y - 30 }, background = key->color }; + handle.Create(); + } + } + + bool OnCreate() + { + UpdateHandles(); + return true; + } + ColorPicker picker { master = this, autoCreate = false, color = white }; + + bool OnLeftButtonDown(int x, int y, Modifiers mods) + { + if(x >= preview.position.x && x < preview.position.x + preview.size.w && y < preview.position.y && y > preview.position.y - 30) + { + if(picker.Modal() == ok) + { + ColorKey * key; + int c; + KeyHandle handle; + + gradient.keys.size++; + key = gradient.keys._ + gradient.keys.size - 1; + x -= preview.position.x; + x = Max(Min(x, preview.size.w), 0); + key->percent = (float) x / (float) preview.size.w; + key->color = picker.color; + + handle = KeyHandle { this, percent = key->percent, position = { key->percent * preview.size.w + preview.position.x - handleWidth/2, preview.position.y - 30 }, background = key->color }; + handle.Create(); + + qsort(gradient.keys._, gradient.keys.size, sizeof(ColorKey), CompareKeys); + + for(c = 0; c < gradient.keys.size; c++) + { + key = &gradient.keys._[c]; + if(key->percent == handle.percent && key->color == handle.background) + break; + } + key->color = picker.color; + handle.background = picker.color; + Update(null); + NotifyUpdate(master); + } + } + return true; + } + + virtual void Window::NotifyUpdate(); +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..61b4682 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ + Copyright (c) 1996-2007, Jerome Jacovella-St-Louis + Copyright (c) 2005-2007, Ecere Corporation + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + * Neither the name of Ecere Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS 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. diff --git a/fractals.ec b/fractals.ec new file mode 100644 index 0000000..6bb9477 --- /dev/null +++ b/fractals.ec @@ -0,0 +1,1482 @@ +#ifdef ECERE_STATIC +import static "ecere" +#else +import "ecere" +#endif + +import "GradientDesigner" + +define app = (GuiApplication)__thisModule; +define gradient = fractalsDesigner.gradientDesigner.gradient; + +struct Complex +{ + double a, b; +}; + +class Buffer +{ + float * pixels; + Complex * z; + int width, height; + + void Allocate(int w, int h) + { + width = w; + height = h; + pixels = renew pixels float[w * h]; + z = renew z Complex[w * h]; + FillBytes(pixels, 0, w * h * sizeof(float)); + FillBytes(z, 0, w * h * sizeof(Complex)); // renew0 crashes + } + void Free() + { + delete pixels; + delete z; + } +} + +class ParallelFractalRenderThread : Thread +{ + FractalRenderThread thread; + int yStart, yEnd; + int depth; + Semaphore go { }; + Semaphore done { }; + bool terminate; + int minY, maxY; + + void Render(int ns, int ne, int start, int end) + { + int x, y; + int w = thread.buffer.width; + int h = thread.buffer.height; + Complex C, C0, d; + double delta; + float * buffer = thread.buffer.pixels; + Complex * bufferZ = thread.buffer.z; + int bufferPos; + int power = thread.exponent; + bool julia = thread.isJulia; + double logOf2 = log(2); + double log2logOf2 = log(2*logOf2); + double logPower = log(power); + int n = ns; + + if(w > h) + { + d.a = thread.range; + d.b = thread.range * h / w; + } + else + { + d.b = thread.range; + d.a = thread.range * w / h; + } + + C0.a = thread.center.a - d.a/2; + C0.b = thread.center.b - d.b/2; + delta = d.a / w; + + if(julia) + C = thread.juliaPoint; + else + { + C = C0; + C.b += start * d.b / h; + } + + minY = MAXINT; + maxY = MAXINT; + for( y = start; y <=end && !terminate; y++) + { + float * buf; + bool got = false; + bufferPos = y * w; + buf = buffer + bufferPos; + for( x = 0; x < w/* && !terminate*/; x++) + { + /*int n; + for(n = ns; n<=ne; n++) + {*/ + if(*buf >= n) + { + int c; + double zm; + Complex Z, oldZ; + + if(n == 0 && julia) + Z = Complex { x * delta + C0.a, y * delta + C0.b }; + else + Z = bufferZ[bufferPos]; + + oldZ = Z; + for(c = 1; c=0 numThreads; t--) + { + if(threads[t].maxY != MAXINT) { max = threads[t].maxY; break; } + } + for(t = 0; t < numThreads; t++) + { + int yEnd; + if(t == numThreads - 1) + yEnd = max; + else + yEnd = yStart + (max + 1 - yStart) / numThreads - 1; + threads[t].yStart = yStart; + threads[t].yEnd = yEnd; + yStart = yEnd + 1; + }*/ + + if(!terminate) + { + if(!(c%25) && c == maxDepth) + fractal.UpdateDepth((depth < c) ? depth : (c+1), c+1); + else + { + depth = (depth < c) ? depth : (c+1); + //fractal.params.depthScroll.range = maxDepth; + //fractal.params.depthLabel.SetText("%d / %d", depth, fractal.params.depthScroll.range-1); + } + } + maxDepth = c + 1; + app.Unlock(); + } + for(t = 0; t < numThreads; t++) + { + threads[t].terminate = true; + threads[t].go.Release(); + threads[t].Wait(); + } + app.Lock(); + if(!terminate) + fractal.UpdateDepth(Min(depth, iterations), maxDepth); + app.Unlock(); + return 0; + } +} + +static define numColors = 30000; +static ColorAlpha palette[numColors]; + +class Fractal : Window +{ + borderStyle = sizable; + size = Size { 408, 428 }; + hasHorzScroll = true; + hasVertScroll = true; + isActiveClient = true; + hasMaximize = true; + hasMinimize = true; + + FractalParams params; + FractalRenderThread thread; + + Point mouse0, mouse1; + + void UpdateDepth(int d, int max) + { + params.depthScroll.range = max+1; + params.depthScroll.thumbPosition = d; + } + + void Reset() + { + if(thread.isJulia) + { + thread.range = 3; + thread.center = Complex { 0, 0 }; + } + else + { + thread.range = 3; + if(thread.exponent == 2) + thread.center = { -0.75, 0 }; + else + thread.center = { 0, 0 }; + } + params.UpdateControls(); + Render(true); + } + + Size imageSize { 400, 400 }; + scrollArea = imageSize; + Bitmap image {}; + + bool selecting; + + bool OnLeftButtonDown(int x, int y, Modifiers mods) + { + if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h) + { + x -= Max((clientSize.w - imageSize.w) / 2, 0); + y -= Max((clientSize.h - imageSize.h) / 2, 0); + x += scroll.x; + y += scroll.y; + if(x >= 0 && y >= 0 && x < imageSize.w && y < imageSize.h) + { + mouse0 = mouse1 = Point { x, y }; + Update(null); + Capture(); + selecting = true; + } + } + return true; + } + + bool OnLeftButtonUp(int x, int y, Modifiers mods) + { + if(selecting) + { + Complex C0, d, point; + int w = image.width; + int h = image.height; + int dx = Abs(mouse1.x - mouse0.x); + int dy = Abs(mouse1.y - mouse0.y); + + if(w > h) + { + d.a = thread.range; + d.b = thread.range * h / w; + } + else + { + d.b = thread.range; + d.a = thread.range * w / h; + } + + C0.a = thread.center.a - d.a/2; + C0.b = thread.center.b - d.b/2; + point = Complex { (mouse0.x + mouse1.x) / 2.0 * d.a / w + C0.a, (mouse0.y + mouse1.y) / 2.0 * d.b / h + C0.b }; + + if(Abs(x - mouse0.x) > 5 && Abs(y - mouse0.y) > 5) + { + thread.center = point; + + if(dx > dy) + thread.range = d.a * dx / w; + else + thread.range = d.b * dy / h; + + Render(true); + params.UpdateControls(); + } + else if(!thread.isJulia) + { + FractalsDesigner designer = (FractalsDesigner) master; + + // Click for Julia + designer.julia.thread.juliaPoint = point; + designer.paramsJulia.UpdateControls(); + designer.julia.Render(true); + } + ReleaseCapture(); + selecting = false; + Update(null); + } + return true; + } + + bool OnRightButtonUp(int x, int y, Modifiers mods) + { + Complex C0, d, point; + int w = image.width; + int h = image.height; + + x -= Max((clientSize.w - imageSize.w) / 2, 0); + y -= Max((clientSize.h - imageSize.h) / 2, 0); + x += scroll.x; + y += scroll.y; + + if(w > h) + { + d.a = thread.range; + d.b = thread.range * h / w; + } + else + { + d.b = thread.range; + d.a = thread.range * w / h; + } + + C0.a = thread.center.a - d.a/2; + C0.b = thread.center.b - d.b/2; + + point = Complex { x * d.a / w + C0.a, y * d.b / h + C0.b }; + + thread.range *= 1.5; + thread.center = point; + + Render(true); + params.UpdateControls(); + + ReleaseCapture(); + selecting = false; + Update(null); + return true; + } + + bool OnMouseMove(int x, int y, Modifiers mods) + { + if(selecting) + { + x -= Max((clientSize.w - imageSize.w) / 2, 0); + y -= Max((clientSize.h - imageSize.h) / 2, 0); + x += scroll.x; + y += scroll.y; + + mouse1 = Point { x, y }; + Update(null); + } + else + { + if(mods.ctrl) + params.depthScroll.thumbPosition = + (int)((double)x / (double)clientSize.w * (double)(params.depthScroll.range - 1)); + if(mods.shift) + params.loop.thumbPosition = (int)((double)y / (double)clientSize.h * 512); + } + return true; + } + + void ComputeImage() + { + if(this && image.picture) + { + int w = image.width, h = image.height; + int x, y; + float * cbuffer; + int max; + int depth; + ColorAlpha * picture = (ColorAlpha *)image.picture; + + thread.mutex.Wait(); + + cbuffer = thread.buffer.pixels; + depth = thread.depth + 1; + + //max = depth-1; + max = numColors-1; + + for(y = 0; y= depth-1) + { + *(picture++) = thread.useBlack ? black : palette[numColors - 1]; + } + else + { + int index; + if(thread.doLoop) + index = Min((int)(i * thread.numScales), ((int)(thread.maxLoops * numColors)) - 1) % numColors; + else + index = Min((int)(i * thread.numScales), numColors - 1); + if(index < 0) index = 0; + *(picture++) = palette[index]; + } + } + } + thread.mutex.Release(); + } + } + + void OnRedraw(Surface surface) + { + JuliaFractal julia = ((FractalsDesigner)master).julia; + int x = Max((clientSize.w - imageSize.w) / 2, 0); + int y = Max((clientSize.h - imageSize.h) / 2, 0); + int w = imageSize.w; + int h = imageSize.h; + surface.Blit(image, x, y, scroll.x, scroll.y, image.width, image.height); + surface.SetForeground(lime); + if(selecting) + surface.Rectangle(x+mouse0.x - scroll.x, y+mouse0.y - scroll.y, x+mouse1.x - scroll.x, y+mouse1.y - scroll.y); + if(!thread.isJulia && julia) + { + Complex juliaPoint = julia.thread.juliaPoint; + Complex C0, d; + int w = image.width; + int h = image.height; + if(w > h) + { + d.a = thread.range; + d.b = thread.range * h / w; + } + else + { + d.b = thread.range; + d.a = thread.range * w / h; + } + C0.a = thread.center.a - d.a/2; + C0.b = thread.center.b - d.b/2; + + x += (int)((juliaPoint.a - C0.a) * w / d.a ) - scroll.x; + y += (int)((juliaPoint.b - C0.b) * h / d.b ) - scroll.y; + + surface.DrawLine(x - 5, y, x + 5, y); + surface.DrawLine(x, y - 5, x, y + 5); + } + } + + void ResetDepth() + { + thread.terminate = true; + app.Unlock(); + thread.Wait(); + app.Lock(); + image.Free(); + thread.depth = 0; + thread.maxDepth = 0; + } + + void Render(bool resetDepth) + { + thread.terminate = true; + app.Unlock(); + thread.Wait(); + app.Lock(); + + if(resetDepth) + { + int width = imageSize.w; + int height = imageSize.h; + thread.buffer.Allocate(width, height); + image.Free(); + image.Allocate(null, width, height, 0, pixelFormat888, false); + thread.depth = 0; + thread.maxDepth = 0; + } + thread.terminate = false; + thread.Create(); + } + + bool OnCreate() + { + Render(true); + params.UpdateControls(); + return true; + } + + void OnDestroy() + { + thread.terminate = true; + app.Unlock(); + thread.Wait(); + app.Lock(); + } + + void OnScroll(ScrollBarAction action, int position, Key key) + { + Update(null); + } + + OnHScroll = OnScroll; + OnVScroll = OnScroll; + + menu = Menu { }; + Menu fileMenu { parent = menu, "File", f }; + + MenuItem exportItem + { + fileMenu, "Export Image...", e, ctrlE; + + bool NotifySelect(MenuItem selection, Modifiers mods) + { + bool result = false; + FileDialog exportDialog = ((FractalsDesigner)master).exportDialog; + exportDialog.SetText("Export %s image", text); + if(exportDialog.Modal()) + { + char * ext = exportDialog.types[exportDialog.fileType].typeExtension; + if(!ext) + { + char extension[MAX_EXTENSION]; + GetExtension(exportDialog.filePath, extension); + if(!extension[0]) + { + ext = "jpg"; + ChangeExtension(exportDialog.filePath, ext, exportDialog.filePath); + } + } + image.Save(exportDialog.filePath, ext, (void *) bool::true); + } + return true; + } + }; + + MenuItem exportItemFiltered + { + fileMenu, "Export Image (filtered half)...", f; + + bool NotifySelect(MenuItem selection, Modifiers mods) + { + bool result = false; + FileDialog exportDialog = ((FractalsDesigner)master).exportDialog; + exportDialog.SetText("Export %s image", text); + if(exportDialog.Modal()) + { + char * ext = exportDialog.types[exportDialog.fileType].typeExtension; + Bitmap filtered { }; + if(!ext) + { + char extension[MAX_EXTENSION]; + GetExtension(exportDialog.filePath, extension); + if(!extension[0]) + { + ext = "jpg"; + ChangeExtension(exportDialog.filePath, ext, exportDialog.filePath); + } + } + if(filtered.Allocate(null, image.width/2, image.height/2, 0, pixelFormat888, false)) + { + Surface surface = filtered.GetSurface(0,0,null); + surface.Filter(image, 0,0,0,0, filtered.width, filtered.height, image.width, image.height); + filtered.Save(exportDialog.filePath, ext, (void *) bool::true); + delete surface; + } + delete filtered; + } + return true; + } + }; +} + +class MandelbrotFractal : Fractal +{ + text = "Mandelbrot"; + FractalRenderThread mandelbrotThread { fractal = this, center = { -0.75, 0 }, range = 3 /*, range = 0.049179316033124996, center = { -0.7623287774189061, -0.1281808432395703 }*/ }; + + thread = mandelbrotThread; +} + +class JuliaFractal : Fractal +{ + text = "Julia"; + FractalRenderThread juliaThread { fractal = this, isJulia = true, range = 3 }; + thread = juliaThread; +} + +class FractalParams : Window +{ + text = "Mandelbrot Parameters"; + background = activeBorder; + borderStyle = fixed; + tabCycle = true; + stayOnTop = true; + size = Size { 206, 506 }; + + Fractal fractal; + + Label { labeledWindow = width, parent = this, position = Point { 16, 8 } }; + Label { labeledWindow = height, parent = this, position = Point { 104, 8 } }; + EditBox width + { + parent = this, text = "Width", position = Point { 16, 32 }; + + bool NotifyModified(EditBox editBox) + { + fractal.imageSize.w = atoi(editBox.contents); + fractal.scrollArea = fractal.imageSize; + fractal.clientSize = fractal.imageSize; + fractal.Render(true); + return true; + } + }; + EditBox height + { + parent = this, text = "Height", position = Point { 104, 32 }; + + bool NotifyModified(EditBox editBox) + { + fractal.imageSize.h = atoi(editBox.contents); + fractal.scrollArea = fractal.imageSize; + fractal.clientSize = fractal.imageSize; + fractal.Render(true); + return true; + } + }; + EditBox exponent + { + parent = this, text = "Exponent", position = Point { 16, 88 }; + + bool NotifyModified(EditBox editBox) + { + FractalsDesigner master = (FractalsDesigner)this.master; + + master.mandelbrot.thread.exponent = master.julia.thread.exponent = atoi(editBox.contents); + + master.paramsJulia.UpdateControls(); + master.julia.Render(true); + + master.paramsMandelbrot.UpdateControls(); + master.mandelbrot.Render(true); + return true; + } + }; + EditBox iterations + { + parent = this, text = "Iterations", position = Point { 104, 88 }; + + bool NotifyModified(EditBox editBox) + { + fractal.thread.mutex.Wait(); + fractal.thread.iterations = atoi(editBox.contents); + fractal.thread.depth = fractal.thread.iterations; + fractal.thread.mutex.Release(); + fractal.Render(false); + return true; + } + }; + ScrollBar depthScroll + { + parent = this, text = "scrollBar1", size = Size { 172, 16 }, position = Point { 16, 120 }; + + void NotifyScrolling(ScrollBar scrollBar, ScrollBarAction action, int position, Key key) + { + if(fractal) + { + fractal.thread.depth = position; + if(action != setRange) + { + fractal.ComputeImage(); + fractal.Update(null); + UpdateDisplay(); + } + depthLabel.SetText("%d / %d", fractal.thread.depth, scrollBar.range-1); + } + } + }; + EditBox centerX + { + parent = this, text = "X", size = Size { 166, 19 }, position = Point { 16, 192 }; + + bool NotifyModified(EditBox editBox) + { + fractal.thread.center.a = strtod(editBox.contents, null); + fractal.Render(true); + return true; + } + }; + EditBox centerY + { + parent = this, text = "Y", size = Size { 166, 19 }, position = Point { 16, 240 }; + + bool NotifyModified(EditBox editBox) + { + fractal.thread.center.b = strtod(editBox.contents, null); + fractal.Render(true); + return true; + } + }; + EditBox rangeEdit + { + parent = this, text = "Range", size = Size { 166, 19 }, position = Point { 16, 296 }; + + bool NotifyModified(EditBox editBox) + { + fractal.thread.range = strtod(editBox.contents, null); + fractal.Render(true); + return true; + } + }; + Button reset + { + parent = this, text = "Reset", size = Size { 170, 21 }, position = Point { 16, 328 }; + + bool NotifyClicked(Button button, int x, int y, Modifiers mods) + { + fractal.Reset(); + return true; + } + }; + Label depthLabel { parent = this, anchor = Anchor { top = 152, right = 16 } }; + Label label1 { labeledWindow = exponent, parent = this, position = Point { 16, 64 } }; + Label label2 { labeledWindow = iterations, parent = this, position = Point { 104, 64 } }; + Label label4 { labeledWindow = rangeEdit, parent = this, position = Point { 16, 272 } }; + Label label5 { labeledWindow = centerY, parent = this, position = Point { 16, 224 } }; + Label label3 { labeledWindow = centerX, parent = this, position = Point { 16, 176 } }; + + ScrollBar loop + { + this, borderStyle = deep, clientSize = { 124, 18 }, position = { 10, 376 }, range = 5000; + text = "Period"; + + void NotifyScrolling(ScrollBar scrollBar, ScrollBarAction action, int position, Key key) + { + if(fractal) + { + position = Max(position, 1); + fractal.thread.loop = position; + fractal.thread.numScales = numColors / position; + + loopEdit.Clear(); + loopEdit.SetContents("%d", fractal.thread.loop); + + fractal.ComputeImage(); + fractal.Update(null); + UpdateDisplay(); + } + } + }; + Label lblLoop { this, labeledWindow = loop, position = { 10, 356 } }; + EditBox loopEdit + { + this, position = { 60, 356 }, size = { 80, 20 }; + + bool OnKeyHit(Key key, unichar ch) + { + if((SmartKey)key == enter) { Deactivate(); Activate(); } + return EditBox::OnKeyHit(key, ch); + } + + bool NotifyModified(EditBox editBox) + { + int value = atoi(editBox.contents); + if(value != loop.thumbPosition) + loop.thumbPosition = value; + return true; + } + }; + Button loopCheck + { + this, checked = true, isCheckbox = true, position = { 110, 406 }, text = "Loop"; + + bool NotifyClicked(Button button, int x, int y, Modifiers mods) + { + fractal.thread.doLoop = button.checked; + fractal.ComputeImage(); + fractal.Update(null); + UpdateDisplay(); + return true; + } + }; + Button useBlack + { + this, checked = true, isCheckbox = true, position = { 10, 406 }, text = "Black"; + + bool NotifyClicked(Button button, int x, int y, Modifiers mods) + { + fractal.thread.useBlack = button.checked; + fractal.ComputeImage(); + fractal.Update(null); + UpdateDisplay(); + return true; + } + }; + + ScrollBar maxLoop + { + this, borderStyle = deep, clientSize = { 124, 18 }, position = { 10, 450 }, range = 5000; + text = "Max Loops"; + + void NotifyScrolling(ScrollBar scrollBar, ScrollBarAction action, int position, Key key) + { + if(fractal) + { + fractal.thread.maxLoops = position; + maxLoopEdit.Clear(); + maxLoopEdit.SetContents("%.0f", fractal.thread.maxLoops); + fractal.ComputeImage(); + fractal.Update(null); + UpdateDisplay(); + } + } + }; + Label lblMaxLoop { this, labeledWindow = maxLoop, position = { 10, 430 } }; + EditBox maxLoopEdit + { + this, position = { 70, 430 }, size = { 70, 20 }; + + bool OnKeyHit(Key key, unichar ch) + { + if((SmartKey)key == enter) { Deactivate(); Activate(); } + return EditBox::OnKeyHit(key, ch); + } + + bool NotifyModified(EditBox editBox) + { + float value = atof(editBox.contents); + //if(value != maxLoop.thumbPosition) + { + //thumbPosition = value; + fractal.thread.maxLoops = value; + fractal.ComputeImage(); + fractal.Update(null); + UpdateDisplay(); + } + return true; + } + }; + + virtual void UpdateControls() + { + float maxLoops = fractal.thread.maxLoops; + + exponent.SetContents("%d", fractal.thread.exponent); + iterations.SetContents("%d", fractal.thread.iterations); + centerX.SetContents("%.20f", fractal.thread.center.a); + centerY.SetContents("%.20f", fractal.thread.center.b); + rangeEdit.SetContents("%.20f", fractal.thread.range); + width.SetContents("%d", fractal.imageSize.w); + height.SetContents("%d", fractal.imageSize.h); + + loop.thumbPosition = (int)fractal.thread.loop; + loopEdit.Clear(); loopEdit.SetContents("%d", fractal.thread.loop); + maxLoop.thumbPosition = (int)fractal.thread.maxLoops; + fractal.thread.maxLoops = maxLoops; + maxLoopEdit.Clear(); maxLoopEdit.SetContents("%f", fractal.thread.maxLoops); + useBlack.checked = fractal.thread.useBlack; + loopCheck.checked = fractal.thread.doLoop; + } + + bool OnCreate() + { + width.Activate(); + return true; + } +} + +class FractalParamsJulia : FractalParams +{ + text = "Julia Parameters"; + size = Size { 206, 610 }; + + EditBox juliaX + { + parent = this, text = "Xj", size = Size { 166, 19 }, position = Point { 16, 504 }; + + bool NotifyModified(EditBox editBox) + { + fractal.Render(true); + fractal.thread.juliaPoint.a = strtod(editBox.contents, null); + return true; + } + }; + EditBox juliaY + { + parent = this, text = "Yj", size = Size { 166, 19 }, position = Point { 16, 552 }; + + bool NotifyModified(EditBox editBox) + { + fractal.Render(true); + fractal.thread.juliaPoint.b = strtod(editBox.contents, null); + return true; + } + }; + Label label7 { labeledWindow = juliaY, parent = this, position = Point { 16, 528 } }; + Label label6 { labeledWindow = juliaX, parent = this, position = Point { 16, 480 } }; + + void UpdateControls() + { + FractalParams::UpdateControls(); + juliaX.SetContents("%.20f", fractal.thread.juliaPoint.a); + juliaY.SetContents("%.20f", fractal.thread.juliaPoint.b); + } +} + +static FileFilter fractalFilters[] = +{ + { "ECERE Fractal Files (*.frc)", "frc" }, + { "All files", null } +}; +static FileType fractalTypes[] = +{ + { "ECERE Fractal", "frc", always }, +}; + +static FileFilter imageFilters[] = +{ + { + "Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", + "jpg, jpeg, bmp, pcx, png, gif" + }, + { "All files", null } +}; +static FileType imageTypes[] = +{ + { "Based on extension", null, always }, + { "JPG Image", "jpg", always }, + { "BMP Image", "bmp", always }, + { "PCX Image", "pcx", always }, + { "PNG Image", "png", always }, + { "GIF Image", "gif", always } +}; + +#define FRC_RECOGNITION { 'e', 'F', 'R', 'C', 11, 12, 3, 0 } +static byte frcRecognition[] = FRC_RECOGNITION; + +class FractalsDesigner : Window +{ + text = "Ecere Fractals Explorer"; + background = dimGray; + borderStyle = sizable; + hasMaximize = true; + hasMinimize = true; + hasClose = true; + hasMenuBar = true; + menu = Menu { }; + size = Size { 1000, 600 }; + state = maximized; + isDocument = true; + hasHorzScroll = true; + hasVertScroll = true; + + Menu fileMenu { menu, "File", f }; + MandelbrotFractal mandelbrot { this, position = Point { 10, 10 }, params = paramsMandelbrot }; + FractalParams paramsMandelbrot { this, anchor = Anchor { right = 260, top = 10 }, fractal = mandelbrot }; + JuliaFractal julia { this, position = Point { 420, 10 }, params = paramsJulia }; + FractalParamsJulia paramsJulia { this, anchor = Anchor { right = 10, top = 10 }, fractal = julia }; + GradientDesigner gradientDesigner + { + this, anchor = { left = 10, bottom = 10 }, stayOnTop = true; + void NotifyUpdate() + { + PaletteGradient(palette, numColors, gradient.keys._, gradient.keys.size, gradient.smoothness); + + mandelbrot.ComputeImage(); + julia.ComputeImage(); + mandelbrot.Update(null); + julia.Update(null); + UpdateDisplay(); + } + }; + bool LoadFractals(char * fileName) + { + File f = FileOpen(fileName, read); + if(f) + { + static byte frcRead[8]; + mandelbrot.ResetDepth(); + julia.ResetDepth(); + + // First attempt to treat this as an archive file + if(f.Read(frcRead, sizeof(frcRead), 1) == 1 && + !strncmp(frcRead, frcRecognition, sizeof(frcRecognition))) + { + TempFile bufferZ; + + mandelbrot.thread.terminate = true; + julia.thread.terminate = true; + app.Unlock(); + mandelbrot.thread.Wait(); + julia.thread.Wait(); + app.Lock(); + + // New binary format + f.Get(mandelbrot.imageSize); + f.Get(mandelbrot.thread.exponent); + f.Get(mandelbrot.thread.iterations); + f.Get(mandelbrot.thread.center); + f.Get(mandelbrot.thread.range); + f.Get(mandelbrot.thread.depth); + f.Get(mandelbrot.thread.maxDepth); + f.Get(bufferZ); + mandelbrot.thread.buffer.Allocate(mandelbrot.imageSize.w, mandelbrot.imageSize.h); + if(bufferZ) + { + bufferZ.Read(mandelbrot.thread.buffer.z, sizeof(Complex), mandelbrot.thread.buffer.width * mandelbrot.thread.buffer.height); + bufferZ.Read(mandelbrot.thread.buffer.pixels, sizeof(float), mandelbrot.thread.buffer.width * mandelbrot.thread.buffer.height); + } + delete bufferZ; + + f.Get(julia.imageSize); + f.Get(julia.thread.exponent); + f.Get(julia.thread.iterations); + f.Get(julia.thread.center); + f.Get(julia.thread.range); + f.Get(julia.thread.depth); + f.Get(julia.thread.maxDepth); + //julia.thread.iterations = julia.thread.maxDepth; + f.Get(bufferZ); + julia.thread.buffer.Allocate(julia.imageSize.w, julia.imageSize.h); + if(bufferZ) + { + bufferZ.Read(julia.thread.buffer.z, sizeof(Complex), julia.thread.buffer.width * julia.thread.buffer.height); + bufferZ.Read(julia.thread.buffer.pixels, sizeof(float), julia.thread.buffer.width * julia.thread.buffer.height); + } + delete bufferZ; + + f.Get(julia.thread.juliaPoint); + + f.Get(gradient.smoothness); + { + int size; + f.Get(size); + if(size) + { + gradient.keys.size = size; + f.Read(gradient.keys._, sizeof(ColorKey), gradient.keys.size); + } + } + { + int loop = 0; + f.Get(loop); + if(loop) + { + mandelbrot.thread.loop = loop; + f.Get(mandelbrot.thread.maxLoops); + if(mandelbrot.thread.maxLoops < 0.00001) mandelbrot.thread.maxLoops = 4999; + f.Get(mandelbrot.thread.useBlack); + f.Get(mandelbrot.thread.doLoop); + } + loop = 0; + f.Get(loop); + if(loop) + { + julia.thread.loop = loop; + f.Get(julia.thread.maxLoops); + if(julia.thread.maxLoops < 0.00001) julia.thread.maxLoops = 4999; + f.Get(julia.thread.useBlack); + f.Get(julia.thread.doLoop); + } + else + { + julia.thread.loop = mandelbrot.thread.loop; + julia.thread.maxLoops = mandelbrot.thread.maxLoops; + julia.thread.useBlack = mandelbrot.thread.useBlack; + julia.thread.doLoop = mandelbrot.thread.doLoop; + } + } + + gradientDesigner.UpdateHandles(); + + mandelbrot.clientSize = mandelbrot.imageSize; + julia.clientSize = julia.imageSize; + + mandelbrot.params.UpdateControls(); + julia.params.UpdateControls(); + + mandelbrot.image.Free(); + mandelbrot.image.Allocate(null, mandelbrot.imageSize.w, mandelbrot.imageSize.h, 0, pixelFormat888, false); + mandelbrot.ComputeImage(); + + julia.image.Free(); + julia.image.Allocate(null, julia.imageSize.w, julia.imageSize.h, 0, pixelFormat888, false); + julia.ComputeImage(); + + julia.thread.terminate = false; + julia.thread.Create(); + + mandelbrot.thread.terminate = false; + mandelbrot.thread.Create(); + } + else + { + // Old ASCII Format + f.Seek(0, start); + + mandelbrot.imageSize.w = f.GetValue(); + mandelbrot.imageSize.h = f.GetValue(); + mandelbrot.thread.exponent = f.GetValue(); + mandelbrot.thread.iterations = f.GetValue(); + mandelbrot.thread.center.a = f.GetDouble(); + mandelbrot.thread.center.b = f.GetDouble(); + mandelbrot.thread.range = f.GetDouble(); + + julia.imageSize.w = f.GetValue(); + julia.imageSize.h = f.GetValue(); + julia.thread.exponent = f.GetValue(); + julia.thread.iterations = f.GetValue(); + julia.thread.center.a = f.GetDouble(); + julia.thread.center.b = f.GetDouble(); + julia.thread.range = f.GetDouble(); + + julia.thread.juliaPoint.a = f.GetDouble(); + julia.thread.juliaPoint.b = f.GetDouble(); + + { + int size = f.GetValue(); + if(size) + { + int c; + gradient.keys.size = size; + for(c = 0; c < gradient.keys.size; c++) + { + gradient.keys._[c].percent = f.GetFloat(); + gradient.keys._[c].color.a = 255; + gradient.keys._[c].color.color.r = (byte)f.GetValue(); + gradient.keys._[c].color.color.g = (byte)f.GetValue(); + gradient.keys._[c].color.color.b = (byte)f.GetValue(); + } + gradient.smoothness = f.GetFloat(); + { + int loop = 0; + loop = f.GetValue(); + if(loop) + { + mandelbrot.thread.loop = loop; + mandelbrot.thread.maxLoops = f.GetFloat(); + mandelbrot.thread.useBlack = f.GetValue(); + mandelbrot.thread.doLoop = f.GetValue(); + } + loop = f.GetValue(); + if(loop) + { + julia.thread.loop = loop; + julia.thread.maxLoops = f.GetFloat(); + julia.thread.useBlack = f.GetValue(); + julia.thread.doLoop = f.GetValue(); + } + else + { + julia.thread.loop = mandelbrot.thread.loop; + julia.thread.maxLoops = mandelbrot.thread.maxLoops; + julia.thread.useBlack = mandelbrot.thread.useBlack; + julia.thread.doLoop = mandelbrot.thread.doLoop; + } + } + } + } + + gradientDesigner.UpdateHandles(); + + paramsJulia.UpdateControls(); + paramsMandelbrot.UpdateControls(); + + julia.scrollArea = julia.imageSize; + julia.clientSize = julia.imageSize; + + mandelbrot.scrollArea = mandelbrot.imageSize; + mandelbrot.clientSize = mandelbrot.imageSize; + + julia.Render(true); + mandelbrot.Render(true); + } + delete f; + + this.fileName = fileName; + return true; + } + return false; + } + MenuItem openItem + { + fileMenu, "Open", o, ctrlO; + + bool NotifySelect(MenuItem selection, Modifiers mods) + { + if(openDialog.Modal() == ok) + { + if(LoadFractals(openDialog.filePath)) + { + } + } + return true; + } + }; + MenuDivider { fileMenu }; + MenuPlacement { fileMenu, "Export Image...", e }; + MenuPlacement { fileMenu, "Export Image (filtered half)...", f }; + MenuDivider { fileMenu }; + MenuItem saveItemData + { + fileMenu, "Save (with data)"; + bool NotifySelect(MenuItem selection, Modifiers mods) + { + return MenuFileSave(selection, mods); + } + }; + MenuItem saveItemAsData + { + fileMenu, "Save As (with data)..."; + + bool NotifySelect(MenuItem selection, Modifiers mods) + { + return MenuFileSaveAs(selection, mods); + } + }; + MenuDivider { fileMenu }; + MenuItem saveItem + { + fileMenu, "Save", s, ctrlS; + + bool NotifySelect(MenuItem selection, Modifiers mods) + { + saveASCII = true; + MenuFileSave(selection, mods); + saveASCII = false; + return true; + } + }; + MenuItem saveItemAs + { + fileMenu, "Save As...", a; + + bool NotifySelect(MenuItem selection, Modifiers mods) + { + saveASCII = true; + MenuFileSaveAs(selection, mods); + saveASCII = false; + return true; + } + }; + MenuDivider { fileMenu }; + MenuItem exitItem { fileMenu, "Exit", x, altF4, NotifySelect = MenuFileExit }; + + FileDialog exportDialog + { + master = this, type = save, + filters = imageFilters, sizeFilters = sizeof(imageFilters), + types = imageTypes, sizeTypes = sizeof(imageTypes) + }; + FileDialog mySaveDialog + { + master = this, type = save, text = "Save Fractals Settings...", + types = fractalTypes, sizeTypes = sizeof(fractalTypes), filters = fractalFilters, sizeFilters = sizeof(fractalFilters) + }; + + FileDialog openDialog + { + master = this, type = open, text = "Load Fractals Settings...", + types = fractalTypes, sizeTypes = sizeof(fractalTypes), filters = fractalFilters, sizeFilters = sizeof(fractalFilters) + }; + bool saveASCII; + + saveDialog = mySaveDialog; + + bool OnSaveFile(char * fileName) + { + File f = FileOpen(fileName, write); + if(f) + { + if(!saveASCII) + { + TempFile bufferZ { }; + f.Write(frcRecognition, sizeof(frcRecognition), 1); + f.Put(mandelbrot.imageSize); + f.Put(mandelbrot.thread.exponent); + f.Put(mandelbrot.thread.iterations); + f.Put(mandelbrot.thread.center); + f.Put(mandelbrot.thread.range); + f.Put(mandelbrot.thread.depth); + f.Put(mandelbrot.thread.maxDepth); + + bufferZ.Write(mandelbrot.thread.buffer.z, sizeof(Complex), mandelbrot.thread.buffer.width * mandelbrot.thread.buffer.height); + bufferZ.Write(mandelbrot.thread.buffer.pixels, sizeof(float), mandelbrot.thread.buffer.width * mandelbrot.thread.buffer.height); + f.Put(bufferZ); + bufferZ.Truncate(0); + bufferZ.Seek(0, start); + + f.Put(julia.imageSize); + f.Put(julia.thread.exponent); + f.Put(julia.thread.iterations); + f.Put(julia.thread.center); + f.Put(julia.thread.range); + f.Put(julia.thread.depth); + f.Put(julia.thread.maxDepth); + + bufferZ.Write(julia.thread.buffer.z, sizeof(Complex), julia.thread.buffer.width * julia.thread.buffer.height); + bufferZ.Write(julia.thread.buffer.pixels, sizeof(float), julia.thread.buffer.width * julia.thread.buffer.height); + f.Put(bufferZ); + + f.Put(julia.thread.juliaPoint); + + f.Put(gradient.smoothness); + { int size = gradient.keys.size; f.Put(size); } + f.Write(gradient.keys._, sizeof(ColorKey), gradient.keys.size); + + f.Put(mandelbrot.thread.loop); + f.Put(mandelbrot.thread.maxLoops); + f.Put(mandelbrot.thread.useBlack); + f.Put(mandelbrot.thread.doLoop); + + f.Put(julia.thread.loop); + f.Put(julia.thread.maxLoops); + f.Put(julia.thread.useBlack); + f.Put(julia.thread.doLoop); + + delete bufferZ; + } + else + { + int c; + f.Printf("%d\n", mandelbrot.imageSize.w); + f.Printf("%d\n", mandelbrot.imageSize.h); + f.Printf("%d\n", mandelbrot.thread.exponent); + f.Printf("%d\n", mandelbrot.thread.iterations); + f.Printf("%.20f\n", mandelbrot.thread.center.a); + f.Printf("%.20f\n", mandelbrot.thread.center.b); + f.Printf("%.20f\n", mandelbrot.thread.range); + + f.Printf("%d\n", julia.imageSize.w); + f.Printf("%d\n", julia.imageSize.h); + f.Printf("%d\n", julia.thread.exponent); + f.Printf("%d\n", julia.thread.iterations); + f.Printf("%.20f\n", julia.thread.center.a); + f.Printf("%.20f\n", julia.thread.center.b); + f.Printf("%.20f\n", julia.thread.range); + + f.Printf("%.20f\n", julia.thread.juliaPoint.a); + f.Printf("%.20f\n", julia.thread.juliaPoint.b); + + f.Printf("%d\n", gradient.keys.size); + for(c = 0; c < gradient.keys.size; c++) + { + f.Printf("%.20f\n", gradient.keys._[c].percent); + f.Printf("%d\n", gradient.keys._[c].color.color.r); + f.Printf("%d\n", gradient.keys._[c].color.color.g); + f.Printf("%d\n", gradient.keys._[c].color.color.b); + } + f.Printf("%.20f\n", gradient.smoothness); + + f.Printf("%d\n", mandelbrot.thread.loop); + f.Printf("%.20f\n", mandelbrot.thread.maxLoops); + f.Printf("%d\n", mandelbrot.thread.useBlack); + f.Printf("%d\n", mandelbrot.thread.doLoop); + + f.Printf("%d\n", julia.thread.loop); + f.Printf("%.20f\n", julia.thread.maxLoops); + f.Printf("%d\n", julia.thread.useBlack); + f.Printf("%d\n", julia.thread.doLoop); + } + delete f; + } + return true; + } + + bool OnPostCreate() + { + if(app.argc > 1) + LoadFractals(app.argv[1]); + mandelbrot.Activate(); + return true; + } +} + +FractalsDesigner fractalsDesigner { }; diff --git a/fractals.epj b/fractals.epj new file mode 100644 index 0000000..2a56ec3 --- /dev/null +++ b/fractals.epj @@ -0,0 +1,38 @@ +{ + "Version" : 0.2, + "ModuleName" : "fractals", + "Options" : { + "MemoryGuard" : false, + "Profile" : false, + "StrictNameSpaces" : false, + "TargetType" : "Executable", + "TargetFileName" : "fractals", + "Libraries" : [ + "ecere" + ], + "Console" : false, + "Compress" : false + }, + "Configurations" : [ + { + "Name" : "Debug", + "Options" : { + "Debug" : true + } + }, + { + "Name" : "Release", + "Options" : { + "Optimization" : "Speed" + } + } + ], + "Files" : [ + "fractals.ec", + "GradientDesigner.ec" + ], + "ResourcesPath" : "", + "Resources" : [ + + ] +} \ No newline at end of file diff --git a/samples/MOI.frc b/samples/MOI.frc new file mode 100644 index 0000000..17efb63 --- /dev/null +++ b/samples/MOI.frc @@ -0,0 +1,42 @@ +400 +400 +2 +1000 +0.26809175612074615000 +0.00290833390405489810 +0.04324445480531056300 +800 +800 +2 +5000 +0.17555712890625000000 +-0.33306621093750000000 +0.01337402343750000000 +0.28528142690585712000 +0.01469244783850202700 +4 +0.00000000000000000000 +255 +0 +0 +0.31010451912879944000 +255 +255 +255 +0.63588851690292358000 +242 +104 +226 +1.00000000000000000000 +255 +0 +0 +0.98999994993209839000 +76 +4999.00000000000000000000 +1 +1 +9 +4999.00000000000000000000 +1 +1 diff --git a/samples/colorful.frc b/samples/colorful.frc new file mode 100644 index 0000000..b5a3e93 --- /dev/null +++ b/samples/colorful.frc @@ -0,0 +1,70 @@ +400 +400 +4 +100 +0.00000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +400 +400 +4 +1000 +0.00000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +0.63000000000000000000 +-0.36749999999999999000 +11 +0.00000000000000000000 +0 +0 +128 +0.10000000149011612000 +0 +128 +0 +0.20000000298023224000 +255 +255 +0 +0.30000001192092896000 +255 +165 +0 +0.40000000596046448000 +255 +0 +0 +0.50000000000000000000 +128 +0 +128 +0.60000002384185791000 +255 +255 +240 +0.69999992847442627000 +255 +99 +71 +0.80000001192092896000 +255 +255 +255 +0.89999991655349731000 +176 +224 +230 +1.00000000000000000000 +0 +0 +0 +0.00000000000000000000 +100 +4999.00000000000000000000 +1 +1 +100 +4999.00000000000000000000 +1 +1 diff --git a/samples/coolSpiral.frc b/samples/coolSpiral.frc new file mode 100644 index 0000000..fef7c89 --- /dev/null +++ b/samples/coolSpiral.frc @@ -0,0 +1,42 @@ +400 +400 +2 +100 +0.00000000000000000000 +0.00000000000000000000 +2.50000000000000000000 +400 +400 +2 +150 +-0.19867734611034393000 +-0.00888702273368835450 +0.48599210381507874000 +0.37799999117851257000 +-0.30700001120567322000 +5 +0.00000000000000000000 +0 +0 +128 +0.18641115725040436000 +0 +0 +0 +0.37804871797561646000 +1 +97 +104 +0.52787452936172485000 +255 +255 +240 +1.00000000000000000000 +0 +0 +0 +0.00000000000000000000 +150 +4999.00000000000000000000 +0 +0 diff --git a/samples/deep.frc b/samples/deep.frc new file mode 100644 index 0000000..92dfb43 --- /dev/null +++ b/samples/deep.frc @@ -0,0 +1,46 @@ +800 +800 +2 +1500 +0.36926081705566405000 +-0.09344808499511718400 +0.00145261168945312520 +400 +400 +2 +2000 +0.00000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +-0.69374499999999995000 +-0.29999999999999999000 +6 +0.00000000000000000000 +0 +0 +128 +0.19860625267028809000 +146 +213 +237 +0.30000001192092896000 +255 +255 +255 +0.44425091147422791000 +255 +255 +124 +0.63414639234542847000 +255 +100 +0 +1.00000000000000000000 +0 +0 +128 +0.00000000000000000000 +147 +4999.00000000000000000000 +1 +1 diff --git a/samples/hot.frc b/samples/hot.frc new file mode 100644 index 0000000..d7787eb --- /dev/null +++ b/samples/hot.frc @@ -0,0 +1,50 @@ +400 +400 +2 +1000 +-0.89643740653991699000 +0.25743749737739563000 +0.13822497427463531000 +400 +400 +2 +1000 +0.00309374998323619370 +-0.00024999998277053237 +0.16912500560283661000 +-0.74538516998291016000 +0.11303885281085968000 +6 +0.00000000000000000000 +255 +255 +255 +0.16027875244617462000 +0 +24 +25 +0.50871080160140991000 +77 +0 +0 +0.76306629180908203000 +217 +162 +0 +0.82926815748214722000 +222 +212 +136 +1.00000000000000000000 +0 +0 +0 +0.00000000000000000000 +60 +4999.00000000000000000000 +1 +0 +180 +4999.00000000000000000000 +1 +0 diff --git a/samples/hot2.frc b/samples/hot2.frc new file mode 100644 index 0000000..6fb4303 --- /dev/null +++ b/samples/hot2.frc @@ -0,0 +1,50 @@ +400 +400 +2 +1000 +-0.89643728733062744000 +0.25743749737739563000 +0.13822494447231293000 +800 +400 +2 +1000 +0.00309374998323619370 +-0.00024999998277053237 +0.40000000596046448000 +-0.74538516998291016000 +0.11303885281085968000 +6 +0.00000000000000000000 +255 +255 +255 +0.16027875244617462000 +0 +24 +25 +0.50871080160140991000 +77 +0 +0 +0.76306641101837158000 +217 +162 +0 +0.82926815748214722000 +222 +212 +136 +1.00000000000000000000 +0 +0 +0 +0.00000000000000000000 +60 +4999.00000000000000000000 +1 +0 +180 +4999.00000000000000000000 +1 +1 diff --git a/samples/oldColors.frc b/samples/oldColors.frc new file mode 100644 index 0000000..d1644d8 --- /dev/null +++ b/samples/oldColors.frc @@ -0,0 +1,66 @@ +400 +400 +2 +100 +-0.75000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +400 +400 +2 +100 +0.00000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +0.37799999117851257000 +-0.30700001120567322000 +11 +0.00000000000000000000 +0 +0 +128 +0.10000000149011612000 +0 +128 +0 +0.20000000298023224000 +255 +255 +0 +0.30000001192092896000 +255 +165 +0 +0.40000000596046448000 +255 +0 +0 +0.50000000000000000000 +128 +0 +128 +0.60000002384185791000 +255 +255 +240 +0.69999998807907104000 +255 +99 +71 +0.80000001192092896000 +255 +255 +255 +0.89999997615814209000 +176 +224 +230 +1.00000000000000000000 +0 +0 +0 +0.98999994993209839000 +100 +4999.00000000000000000000 +1 +1 diff --git a/samples/purplishmandelbrot.frc b/samples/purplishmandelbrot.frc new file mode 100644 index 0000000..dbaf868 --- /dev/null +++ b/samples/purplishmandelbrot.frc @@ -0,0 +1,38 @@ +2800 +2200 +2 +600 +-0.75000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +400 +400 +2 +100 +0.00000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +0.37799999117851257000 +-0.30700001120567322000 +3 +0.00000000000000000000 +0 +0 +0 +0.23344947397708893000 +43 +43 +122 +1.00000000000000000000 +255 +255 +255 +0.98999994993209839000 +100 +4999.00000000000000000000 +1 +0 +100 +4999.00000000000000000000 +1 +1 diff --git a/samples/seaHorseValley.frc b/samples/seaHorseValley.frc new file mode 100644 index 0000000..4a14824 --- /dev/null +++ b/samples/seaHorseValley.frc @@ -0,0 +1,50 @@ +400 +400 +2 +1000 +-0.76232877741890614000 +-0.12818084323957030000 +0.04917931603312499600 +400 +400 +2 +1000 +0.00000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +-0.72689534770911413000 +0.18888712904384594000 +6 +0.00000000000000000000 +0 +0 +128 +0.19860626757144928000 +146 +213 +237 +0.30000001192092896000 +255 +255 +255 +0.44425088167190552000 +255 +255 +124 +0.63414633274078369000 +255 +100 +0 +1.00000000000000000000 +0 +0 +128 +0.00000000000000000000 +100 +4999.00000000000000000000 +1 +1 +100 +4999.00000000000000000000 +1 +1 diff --git a/samples/star.frc b/samples/star.frc new file mode 100644 index 0000000..4c6c0c5 --- /dev/null +++ b/samples/star.frc @@ -0,0 +1,16 @@ +400 +400 +5 +500 +-0.69424901779316717000 +-0.29999612278567511000 +0.00168594977911376950 +800 +800 +5 +2000 +0.00000000000000000000 +0.02812500000000000100 +0.99375000000000002000 +-0.69374499999999995000 +-0.29999999999999999000 diff --git a/samples/sunnySpiral.frc b/samples/sunnySpiral.frc new file mode 100644 index 0000000..132601f --- /dev/null +++ b/samples/sunnySpiral.frc @@ -0,0 +1,46 @@ +400 +400 +2 +1000 +-0.75000000000000000000 +0.00000000000000000000 +3.00000000000000000000 +400 +400 +2 +1000 +-0.19685624539852142000 +0.50236874818801880000 +0.58953744173049927000 +0.37799999117851257000 +-0.30700001120567322000 +6 +0.00000000000000000000 +0 +0 +128 +0.19860625267028809000 +146 +213 +237 +0.30000001192092896000 +255 +255 +255 +0.44425091147422791000 +255 +255 +124 +0.63414639234542847000 +255 +100 +0 +1.00000000000000000000 +0 +0 +128 +0.00000000000000000000 +100 +1.50000000000000000000 +1 +1 diff --git a/samples/woah.frc b/samples/woah.frc new file mode 100644 index 0000000..ee81b02 --- /dev/null +++ b/samples/woah.frc @@ -0,0 +1,50 @@ +400 +400 +2 +100 +-0.04506194218993187000 +-0.98681175708770752000 +0.00000000143657574725 +3840 +2400 +2 +26993 +0.00953226536512374880 +-0.02591441385447979000 +0.04704407602548599200 +-0.04506194218993187000 +-0.98681175708770752000 +6 +0.00000000000000000000 +0 +0 +128 +0.19860625267028809000 +146 +213 +237 +0.30000001192092896000 +255 +255 +255 +0.44425091147422791000 +255 +255 +124 +0.63414639234542847000 +255 +100 +0 +1.00000000000000000000 +0 +0 +128 +0.00000000000000000000 +263 +4999.00000000000000000000 +1 +1 +127 +4999.00000000000000000000 +1 +1 -- 1.8.3.1