Cells/Worley noise discussion continued...

70 views
Skip to first unread message

Ognen

unread,
Oct 11, 2021, 5:24:14 PM10/11/21
to FilterMeister Mailing List (FMML)
Hello,

I have trouble understanding how the getArray () function works, especially how it performs math for the int x and int y arguments of the function. As far as I could understand, the values of those arguments represent the coordinates from which to take the value of their intersection and show it on the screen. However do not understand the given results using the Info() function.

This is the excerpt of Kohan's code where I am stuck:

tempx = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 0) and
tempy = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 1)

Especially what this math represents:

x*gridwidth)/X + j and
x*gridwidth)/X + j

My assumption is that in the math in the loop represents the coordinates around given pixel from the previous one where putArray() writes them into the memory of the array.

Neither way I do not have a clue how this works. May I get a detailed explanation on this topic please?

Thanks,
Ognen

P.S. As a reminder, I have started a new thread for the same topic because in the previous one I am not allowed to post messages anymore, they are deleted immediately after I post. Somewhere I have read that this is problem related to Google Groups itself.

Here is the Kohan's code for reference:

%fml

//////////////////////////////////////////////////////////////////////
//
// Fast Worley Noise 1.02 - 27 September 2021
// by Kohan "SyneRyder" Ikin
// https://www.namesuppressed.com
//
// Written for FilterMeister: http://www.filtermeister.com
//
// This code is copyright free: released into public domain.
//
// Version History
//
// 1.00 2021.09.24 First version
// 1.01 2021.09.26 Implement a grid of points for fast lookup
// 1.02 2021.09.27 Add 16-bit Grayscale / RGB support
//
// Credits
//
// Inspired by The Coding Train's "Coding In The Cabana Episode 4
// Worley Noise" video: https://www.youtube.com/watch?v=4066MndcyCk
// Prompted by FilterMeister Mailing List discussion by Ognen Genc
// and Paul Simeons.
//
//////////////////////////////////////////////////////////////////////

// Plugin specific details
Title: "Fast Worley Noise"
Copyright: "Public Domain"
Filename: "fastworley.8bf"
Version: "1.02"
Description: "Generates Worley noise textures"

// General Author details
Author: "Kohan Ikin"
Category: "Textures"
Organization: "namesuppressed"
URL: "https://www.namesuppressed.com/"
About: "Version !V (!x-bit)"

// Dialog definitions
Dialog: Text = "!T by !O"

// Supported Modes
SupportedModes: RGBMode, RGB48Mode, GrayScaleMode, Gray16Mode



/*******************************************************************
Global Variables (mostly constants)
*******************************************************************/

// Controls (values < 250)
const int CTL_DOTS = 0;
const int CTL_MAXDISTANCE = 1;
const int CTL_INVERT = 2;
const int CTL_TIMERDISPLAY = 5;

// Arrays
const int ARRAY_RANDOMPOINTS = 1;



/*******************************************************************
Control Definitions
*******************************************************************/

ctl[CTL_DOTS]: STANDARD, Text="Dots", Val=200, Range=(1, 500)
ctl[CTL_MAXDISTANCE]: STANDARD, Text="Distance", Val=50, Range=(1, 300)
ctl[CTL_INVERT]: CHECKBOX, Text="Invert"
ctl[CTL_TIMERDISPLAY]: STATICTEXT, Text="please wait..."



/*******************************************************************
Filter Start Handler (one-off processing)
*******************************************************************/

OnFilterStart: {

// Seed the random number generator with current clock time
srand(clock());

// Due to an FM bug that causes X & Y & scaleFactor to not be
// correctly initialized in OnFilterStart, especially on first
// invocation of a compiled plugin, allocating the random point
// array has been moved into the ForEveryTile handler.

return true;
}



/*******************************************************************
ForEveryTile Handler
*******************************************************************/

ForEveryTile: {

// Store the values from the user controls in variables, might save a
// little time compared to retrieving them every pixel in main loop
int maxdist = getCtlVal(CTL_MAXDISTANCE) / scaleFactor;
int numdots = getCtlVal(CTL_DOTS);
bool invert = getCtlVal(CTL_INVERT);

int val;
int red, green, blue;
int bright, dark;
int i, j, tempx, tempy, dist;
int smallestdistance;


// Set the maximum white value depending on if we're 8-bit or 16-bit
int MAXWHITE = 255; // Assume 8-bit by default
if (imageMode == RGB48Mode || imageMode == Gray16Mode) {
MAXWHITE = 32768;
}

// We want to divide the image into a grid of approximately as many
// squares as the user has asked for, and we'll put a dot randomly
// somewhere in each grid square. We decide the size of the grid
// using a square root:
// eg sqrt(200) = 14 when rounded down. 14x14 = 196, almost 200.
// This gives the wrong number of dots for small values:
// eg sqrt(3) = 1 when rounded down, and 1 dot is not 3 dots..
// So you might want to rewrite this to use the proper Worley noise
// algorithm for smaller numbers of dots (eg less than 9)
int gridwidth = sqrt((double)numdots);

// Allocate gridwidth x gridwidth x 2 array of random 32-bit xy points
// Note the 4 here means 4-bytes, ie 32-bit.
// Usually we do this allocation in OnFilterStart, but a bug in
// FM means that X & Y are not correctly initialized in OnFilterStart,
// and aren't valid until ForEveryTile. We shouldn't actually do this
// allocation for every tile of a tilable filter....
allocArray(ARRAY_RANDOMPOINTS, gridwidth, gridwidth, 2, 4);

// Do this for every cell in our grid
for (j = 0; j < gridwidth; j++) {
for (i = 0; i < gridwidth; i++) {

// Generate a random x & y co-ord value within current cell
// Use modulo % to limit co-ords to maximum pixelwidth of cell
tempx = rand() % X/gridwidth;
tempy = rand() % Y/gridwidth;

// Then store the random co-ords in our array
putArray(ARRAY_RANDOMPOINTS, i, j, 0, tempx + i*X/gridwidth);
putArray(ARRAY_RANDOMPOINTS, i, j, 1, tempy + j*Y/gridwidth);
}
}

// Timing how long the algorithm takes. Record start time here:
int timerstart = clock();

// For every pixel in the canvas / preview area...
for (y = y_start; y < y_end; y++) {
for (x = x_start; x < x_end; x++) {

// Initialize values
smallestdistance = maxdist;

// The nearest random point has to be somewhere in the 3x3 grid of
// grid cells around our current cell. This way we only need to
// check the distance to 9 of the random dots, and not the
// distance to every dot, which saves a LOT of processing time if
// you have 500 dots in the image.
for (j = -1; j < 2; j++) {
for (i = -1; i < 2; i++) {

// Get the next xy random co-ordinate to check
tempx = getArray(ARRAY_RANDOMPOINTS,
(int)((x*gridwidth)/X + j),
(int)((y*gridwidth)/Y + i), 0);
tempy = getArray(ARRAY_RANDOMPOINTS,
(int)((x*gridwidth)/X + j),
(int)((y*gridwidth)/Y + i), 1);

// Calculate the distance from current xy pixel to the
// selected random point. Calculating the distance is the main
// point of the Worley Noise algorithm.
dist = sqrt((double)
((x - tempx) * (x - tempx) +
(y - tempy) * (y - tempy))); // euclidean

// Is this measured distance the smallest so far?
// If so, remember it.
if (dist < smallestdistance) {
smallestdistance = dist;
}

}
}


// Usual Worley noise is the distance to the closest point
val = (int)(MAXWHITE * ((float)(maxdist -
smallestdistance)/maxdist));

// If user has chosen to invert, then flip the value here
if (invert) {
val = MAXWHITE - val;
}

// For greyscale, just set the first "color" channel value
pset(x, y, 0, val);

// If it's an RGB Image, set for green and blue too
if (imageMode == RGBMode || RGB48Mode) {
pset(x, y, 1, val);
pset(x, y, 2, val);
}
}

// Update the progress bar after every row of pixels is done
updateProgress(y - y_start, y_end - y_start);
}

// Stop our timer (record the end time & calculate difference)
// and show the time calculation to the user on a text control
int timerend = clock();
sprintf(str9, "Time = %d", timerend - timerstart);
setCtlText(CTL_TIMERDISPLAY, str9);

return true;
}



/*******************************************************************
OnFilterEnd Handler (cleanup)
*******************************************************************/

OnFilterEnd: {
// Free the memory allocated to hold the random points
// to prevent any memory leaks
freeArray(ARRAY_RANDOMPOINTS);
return true;
}

%%EOF


Kohan Ikin

unread,
Oct 12, 2021, 10:33:44 AM10/12/21
to FilterMeister Mailing List (FMML)
Hi Ognen,

> I have trouble understanding how the getArray () function works,
> especially how it performs math for the int x and int y arguments...

I might be misunderstanding the question, but getArray doesn't perform
any maths on the arguments. The C language calculates the math in those
lines first, then passes the result of the math as an argument. I think
you understand that, but I wasn't sure from the way you've asked.

getArray & putArray should be straightforward if you're familiar with
arrays. getArray gets a value from an element/cell in an array, and
putArray puts/stores a value in a specific element/cell of an array.



> Especially what this math represents:
>
> (x*gridwidth)/X + j and
> (x*gridwidth)/X + j

It's working out which cell of the grid / element of the array to get a
stored value from.

Maybe think of the math above as:

gridwidth * (x / X) + j

x / X is like a percentage of how far the current x pixel is across the
x axis. So if x = 25 and X = 100, x/X is 0.25 and you're a quarter of
the way across. If the grid is 10 cells wide, then multiplying 10 * 0.25
gives you 2.5, which gets rounded to 2 as an integer. So, if j=0,
getArray will be getting the value from array cell 2 in this case.

The j variable loops from -1 to +1 in the code, so the loop will
eventually use getArray to get values from cell 1 (j = -1), cell 2 (j =
0), and cell 3 (j = +1). That's the cells on either side of cell 2.


Beyond that, I don't think I can really explain it more than I've
already documented in the code. Maybe take a look at The Book Of Shaders
on Worley Noise again, the grid diagrams on that page might help
visualize how Worley Noise with the grid works:

https://thebookofshaders.com/12/

- Kohan

--
kohan ikin
founder & chief developer for namesuppressed
http://kohanikin.com - http://namesuppressed.com - @syneryder

Ognen

unread,
Oct 16, 2021, 5:41:21 PM10/16/21
to FilterMeister Mailing List (FMML)
Hello Kohan,

As I had a brain fart last time posting my question, you have successfully answered a half of the mystery of how arrays are functioning in FM and not by your fault of course.
In your explanation you have answered for the x coordinate, but what about the y coordinate? Let's say if 2 is for x and y, i.e. j=0 and i=0, which cell is then taken?

Thanks,
Ognen

Kohan Ikin

unread,
Oct 17, 2021, 3:50:39 PM10/17/21
to FilterMeister Mailing List (FMML)
Hi Ognen,

> In your explanation you have answered for the x coordinate, but what
> about the y coordinate? Let's say if 2 is for x and y, i.e. j=0 and i=0,
> which cell is then taken?

The math is the same - you can see the "x" co-ord of the array is
(x*gridwidth)/X + j, and for the "y" co-ord of the array the math was
(y*gridwidth)/Y + i, so you'd solve them similarly. It's really just
plugging in the numbers as you go through each step of the for loops.

I realize there's something you're not understanding that seems
intuitive to me, but I'm not sure what that part is. If it's
understanding arrays in general, that would be better explained by a
programming tutorial.

Ognen

unread,
Oct 18, 2021, 7:21:49 PM10/18/21
to FilterMeister Mailing List (FMML)
Hello Kohan,

I know that your time is more valuable than explaining things here and I respect every choice you make for which I will agree.

Let's say that:
allocArray(ARRAY_RANDOMPOINTS, gridwidth, gridwidth, 2, 4)
is two blocks of sqared gridwidth, which means 3D array. The variable gridwidth=sqrt(9)

Below you will find that we have 9 by 9 pixels canvas with maximum of the random point of the 15 bit image where:
tempx = 32768 % 9/3 = 2 and
tempy = 32768 % 9/3 = 2

In the loop:

putArray(ARRAY_RANDOMPOINTS, i, j, 0, tempx + i*X/gridwidth)
If, for example, i(x)=0 and j(y)=1 which represent the coordinates of the cell in the first block(z=0) that is the second from top, and where 'tempx + i*X/gridwidth' represents the x coordinate in that cell which is 2.

putArray(ARRAY_RANDOMPOINTS, i, j, 1, tempy + j*Y/gridwidth)
In the second, i(x)=0 and j(y)=1 which represent the coordinates of the cell in the second block(z=1), and where 'tempy + j*Y/gridwidth' represents the y coordinate in that cell which is 5.

That means the pixel will be drawn at the coordinates x=2 and y=5 in the canvas. Did I miss something here? Because in the Command Reference book it states it is the value of the xy coordinates in the cell and not a xy coordinate.

Now in the next loop, which gets the values from the 8 neighbor cells around the original:

tempx = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 0) and
tempy = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 1)

What values are stored in the tempx and tempy variables respectively if x=0, y=0, j=-1 and i=-1?
I get the value 2 for both, the tempx and tempy which is the first most  iteration. Does it mean that if j=0 and i=0, getArray() in this assumes it as the center cell in the whole canvas to get the value from the xy coordinates from the top left cell? Or what am I missing here?

Thanks,
Ognen

Ognen

unread,
Oct 20, 2021, 6:58:34 PM10/20/21
to FilterMeister Mailing List (FMML)
> What values are stored in the tempx and tempy variables respectively if x=0, y=0, j=-1 and i=-1?
> I get the value 2 for both, the tempx and tempy which is the first most  iteration. Does it mean that if j=0 and i=0, getArray() in this assumes it as the center cell in the whole canvas to get the value from the xy coordinates from the top left cell? Or what am I missing here?

The simple question in all this matter is if in the first loop in the first most iteration:

putArray(ARRAY_RANDOMPOINTS, i, j, 0, tempx + i*X/gridwidth) gives 2 as a final result and
putArray(ARRAY_RANDOMPOINTS, i, j, 1, tempy + j*Y/gridwidth) also gives 2 as a final result,

that means these numbers are stored somewhere in the computer's memory until getArray() function finds them, right?

In the second loop in the matter of the first iteration where x=0, y=0, i=-1 and j=-1, that means:

getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 0) when replacing variables with numbers we get -1 and in
getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 1) also we get -1,

which means that we get the information from xy coordinate from the first and also from the second block of the array where -1 for both, x and y, means to get the information from one field to the left and one field up. I get value of 2, why?

I do not get the logic because I think there is lack of information here. I know how to work with multidimensional array data, but in this case I am so confused.

Kohan Ikin

unread,
Oct 21, 2021, 6:06:28 AM10/21/21
to FilterMeister Mailing List (FMML)
Hi Ognen,

Many thanks for the steps & working out the math, I really appreciate
it! It helps me see the exact points where there is confusion.


> Below you will find that we have 9 by 9 pixels canvas...
> with maximum of the random point of the 15 bit image where:
> tempx = 32768 % 9/3 = 2 and
> tempy = 32768 % 9/3 = 2

Ahh! The maximum random value from rand() isn't related to 15-bit /
16-bit images. It's just a coincidence that RAND_MAX is usually 32767 in
the C language. RAND_MAX is in the Windows SDK, so it's set by Microsoft:

https://docs.microsoft.com/en-us/cpp/c-runtime-library/rand-max?view=msvc-160


As to the other questions, I think the confusion is related to how I've
written my code in that first loop. So I've tried rewriting that first
loop to be clearer, and replacing rand() with the FilterMeister-only
rnd() function which might be easier to understand. This code also
includes the 'double' fix that makes the result smoother too.
Unfortunately Google Groups deletes the code indentation, making the
code harder to understand, but see if this version helps.




%fml

//////////////////////////////////////////////////////////////////////
//
// Fast Worley Noise 1.05 - 20 October 2021
// by Kohan "SyneRyder" Ikin
// https://www.namesuppressed.com
//
// Written for FilterMeister: http://www.filtermeister.com
//
// This code is copyright free: released into public domain.
//
// Version History
//
// 1.00 2021.09.24 First version
// 1.01 2021.09.26 Implement a grid of points for fast lookup
// 1.02 2021.09.27 Add 16-bit Grayscale / RGB support
// 1.03 2021.09.29 Smooth output by using doubles in distance
// 1.04 2021.10.09 Make alpha channels opaque
// 1.05 2021.10.20 Make dot positioning loop easier to understand
//
// Credits
//
// Inspired by The Coding Train's "Coding In The Cabana Episode 4
// Worley Noise" video: https://www.youtube.com/watch?v=4066MndcyCk
// Prompted by FilterMeister Mailing List discussion by Ognen Genc
// and Paul Simeons.
//
//////////////////////////////////////////////////////////////////////

// Plugin specific details
Title: "Fast Worley Noise"
Copyright: "Public Domain"
Filename: "fastworley.8bf"
Version: "1.05"
int i, j, tempx, tempy;
double dist, smallestdistance;


// Set the maximum white value depending on if we're 8-bit or 16-bit
int MAXWHITE = 255; // Assume 8-bit by default
if (imageMode == RGB48Mode || imageMode == Gray16Mode) {
MAXWHITE = 32768;
}

// We want to divide the image into a grid of approximately as many
// squares as the user has asked for, and we'll put a dot randomly
// somewhere in each grid square. We decide the size of the grid
// using a square root:
// eg sqrt(200) = 14 when rounded down. 14x14 = 196, almost 200.
// This gives the wrong number of dots for small values:
// eg sqrt(3) = 1 when rounded down, and 1 dot is not 3 dots..
// So you might want to rewrite this to use the proper Worley noise
// algorithm for smaller numbers of dots (eg less than 9)
int gridwidth = sqrt((double)numdots);
int gridheight = gridwidth;

// Allocate gridwidth x gridheight x 2 array of random 32-bit xy points
// Note the 4 here means 4-bytes, ie 32-bit.
// Usually we do this allocation in OnFilterStart, but a bug in
// FM means that X & Y are not correctly initialized in OnFilterStart,
// and aren't valid until ForEveryTile. We shouldn't actually do this
// allocation for every tile of a tilable filter....
allocArray(ARRAY_RANDOMPOINTS, gridwidth, gridheight, 2, 4);

// Calculate the pixel width, height, bounds of each cell in our grid
int cellpixelwidth = X/gridwidth;
int cellpixelheight = Y/gridheight;

// Declare variables that will be used in loop
int leftmostcellpixel, topmostcellpixel;
int rightmostcellpixel, bottommostcellpixel;

// Do this for every cell in our square array grid
for (j = 0; j < gridheight; j++) {
for (i = 0; i < gridwidth; i++) {

// Calculate pixel bounds of current cell
topmostcellpixel = j*cellpixelheight;
leftmostcellpixel = i*cellpixelwidth;
bottommostcellpixel = topmostcellpixel + cellpixelheight;
rightmostcellpixel = leftmostcellpixel + cellpixelwidth;

// Generate a random x & y co-ord value within current cell
tempx = rnd(leftmostcellpixel, rightmostcellpixel);
tempy = rnd(topmostcellpixel, bottommostcellpixel);

// Then store these random co-ords into our array
putArray(ARRAY_RANDOMPOINTS, i, j, 0, tempx);
putArray(ARRAY_RANDOMPOINTS, i, j, 1, tempy);
}
}

// Timing how long the algorithm takes. Record start time here:
int timerstart = clock();

// For every pixel in the canvas / preview area...
for (y = y_start; y < y_end; y++) {
for (x = x_start; x < x_end; x++) {

// Initialize values
smallestdistance = maxdist;

// The nearest random point has to be somewhere in the 3x3 grid of
// grid cells around our current cell. This way we only need to
// check the distance to 9 of the random dots, and not the
// distance to every dot, which saves a LOT of processing time if
// you have 500 dots in the image.
for (j = -1; j < 2; j++) {
for (i = -1; i < 2; i++) {

// Get the next xy random co-ordinate to check
tempx = getArray(ARRAY_RANDOMPOINTS,
(int)((x*gridwidth)/X + j),
(int)((y*gridwidth)/Y + i), 0);
tempy = getArray(ARRAY_RANDOMPOINTS,
(int)((x*gridheight)/X + j),
(int)((y*gridheight)/Y + i), 1);

// Calculate the distance from current xy pixel to the
// selected random point. Calculating the distance is the main
// point of the Worley Noise algorithm.
dist = sqrt((double)
((x - tempx) * (x - tempx) +
(y - tempy) * (y - tempy))); // euclidean

// Is this measured distance the smallest so far?
// If so, remember it.
if (dist < smallestdistance) {
smallestdistance = dist;
}

}
}


// Usual Worley noise is the distance to the closest point
val = (int)(MAXWHITE * (maxdist - smallestdistance)
/ maxdist);

// If user has chosen to invert, then flip the value here
if (invert) {
val = MAXWHITE - val;
}

// For greyscale, just set the first "color" channel value
pset(x, y, 0, val);
if (imageMode == GrayScaleMode || imageMode == Gray16Mode) {
// Don't forget to fill the alpha channel
if (planes > 1) pset(x, y, 1, MAXWHITE);
}

// If it's an RGB Image, set for green and blue too
if (imageMode == RGBMode || imageMode == RGB48Mode) {
pset(x, y, 1, val);
pset(x, y, 2, val);
// And don't forget to fill alpha channel
if (planes > 3) pset(x, y, 3, MAXWHITE);
}

}

// Update the progress bar after every row of pixels is done
updateProgress(y - y_start, y_end - y_start);
}

// Stop our timer (record the end time & calculate difference)
// and show the time calculation to the user on a text control
int timerend = clock();
sprintf(str9, "Time = %d", timerend - timerstart);
setCtlText(CTL_TIMERDISPLAY, str9);

return true;
}



/*******************************************************************
OnFilterEnd Handler (cleanup)
*******************************************************************/

OnFilterEnd: {
// Free the memory allocated to hold the random points
// to prevent any memory leaks
freeArray(ARRAY_RANDOMPOINTS);
return true;
}

%%EOF



--
kohan ikin
founder & chief developer for namesuppressed
https://kohanikin.com - https://www.namesuppressed.com

Kohan Ikin

unread,
Oct 21, 2021, 6:34:17 AM10/21/21
to filter...@googlegroups.com
Ognen wrote on 21/10/2021 6:58 AM:
> The simple question in all this matter is if in the first loop in the
> first most iteration:
>
> putArray(ARRAY_RANDOMPOINTS, i, j, 0, tempx + i*X/gridwidth) gives 2 as
> a final result and
> putArray(ARRAY_RANDOMPOINTS, i, j, 1, tempy + j*Y/gridwidth) also gives
> 2 as a final result,
>
> that means these numbers are stored somewhere in the computer's memory
> until getArray() function finds them, right?

Yes, the numbers are stored in memory (an array is a block of memory).
It puts the value into the array, hence putArray. You could also write
it as:

int value = tempx + i*X/gridwidth;
putArray(ARRAY_RANDOMPOINTS, i, j, 0, value);

So 'value' is stored in the ARRAY_RANDOMPOINTS, in the array location
i,j,0. In another language like Pascal, you might write:

array_randompoints[i,j,0] := value;

I apologize if I'm explaining something simple that you already
understand, I would assume that you do. I keep focusing on it because if
it's not clear how putArray & getArray work, none of the rest of the
code will make sense. putArray isn't drawing anything on the pixel
canvas, it just stores a value in a memory location.


(I'm not sure which other programming languages you're familiar with, I
think you mentioned you were coming from Javascript & had some C
experience?)

- Kohan
--
kohan ikin
founder & chief developer for namesuppressed

Ognen

unread,
Oct 24, 2021, 7:03:11 PM10/24/21
to FilterMeister Mailing List (FMML)
Hello Kohan,

First, thank you for your time making a modification to the code although I did understand the math behind all the algorithm with the first example. It was my bad in explaining problems so one can understand and provide appropriate solution to the problem. So, my apologies to you for taking your precious time in making effort explaining my bad requests.

Just to get to the point, I made my last peak at the monitor tonight and found the solution to my problem that bothered me all the time. I didn't know that negative array indexes always return 1-1 equivalence, thus in getArray() for x=-1 and y=-1 that equals to 0 finds the first cell in the array. I have to admit, my experience in negative array indexes was equal to nothing until now, so I guess I am not talking nonsense on the matter of arrays in FM too.

Another question is, I was implementing sine distribution to the final values of the calculated distances by using the sin() function that gave me successful results in the 8bit mode, but was unsuccessful in the 16bit mode. Does this mean that sin() function is supported only by 8bit mode? If so, my only alternative in calculating trigonometric functions will be by using Taylor series calculations. Any thoughts on this?

P.S. My domestic language is not English and again, my apologies when writing potential garbage that comes out of my keyboard.

paul simoens

unread,
Oct 25, 2021, 5:01:43 PM10/25/21
to filter...@googlegroups.com

Hi Ognen,

use
allocArrayPad, instead of allocArray. It works completely similar but adds before and after extra coordinates for memory.
Syntax allocArrayPad( 0, X, Y, Z, byte size, padding).
E.g. with allocArrayPad( 0, 200, 200, 3, 2, 3) you can go from x = -3 till x =202.
By the way (and again) it’s all in the FilterMeisterWiki…


sin( ) is an obsolete function from the early days of FilterMeister.
Use

fsin( a), fcos( b), ftan( c),

asin( a), acos( b), atan( c), etc.

These return float variables with an internal 14 digits precision and in radians format. 2 *PI ==full cercle…

Because at the end pixels must be integers, I use aside floats an integer avatar for the end result.
Be aware that an integer will not directly be recongnised as float. E.g.
float fA0;

int iA0;


Important to know:

fA0 =25; will give 0.0
fA0 =25 +0.0; or 2fA0 =5 *1.0 will give 25.0  (each mix or calculation with an float, transforms an integer to float).

 

 

iA0 =fA0 =asin( 1.0) *90.0 /M_PI_2;

fA0 will give float 90.0 and iA0 int 90

You probabely miss the UserGuide pdf? For the convenience I add it as attachement.


I’m actually still in the middle of a transformation of my kitchen and therefore the promise of an extended and more worked out explanation of the most important basics of making filters in FM moves more forward in time. Meanwhile I made nonetheless a more efficient working Worley Noise filter, but I won’t publish it before I could fully document it. It’s an interesting topic of how to approach a task and translate it to the most compact math.


Hopes this helps you further away.

Greetings,
Paul

--
You received this message because you are subscribed to the Google Groups "FilterMeister Mailing List (FMML)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to filtermeiste...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/filtermeister/c637433e-12c8-48f1-bf0f-0457010b7431n%40googlegroups.com.

02-UserGuide.pdf

Kohan Ikin

unread,
Oct 26, 2021, 4:30:08 AM10/26/21
to filter...@googlegroups.com
paul simoens wrote on 26/10/2021 5:01 AM:
> use allocArrayPad, instead of allocArray. It works completely similar
> but adds before and after extra coordinates for memory.

That's my mistake, my code was taking advantage of how getArray
internally caps the x & y values within the array bounds if edgeMode ==
0. I don't actually need the extra padding, just the edge case behavior.
I should have handled those edge & corner cases in my own code instead
of relying on the underlying framework.

I've just checked the FM source and the behavior of getArray changes
depending on the value of edgeMode. That isn't documented in the Wiki
yet. So it looks like I have some new tasks on my To Do list!

(20 years later and I'm still learning how FM works!)


> sin( ) is an obsolete function from the early days of FilterMeister.
> Use
> fsin( a), fcos( b), ftan( c),
> asin( a), acos( b), atan( c), etc.

Eek, you're right! Just checked and the Wiki / Command Reference hasn't
properly documented this either yet (though it is in the User Guide).
sin, cos & tan aren't the C Runtime versions, they're the integer
versions compatible with Adobe's Filter Factory. That's frustrating for
anyone who likes keeping their code C compatible :/

Many thanks for pointing this out! It adds to my to-do list, but it's
important that the Command Reference should explain this.


> Meanwhile I made nonetheless a more efficient working Worley Noise
> filter, but I won’t publish it before I could fully document it.

I can empathize - I've been tracking my time & I can see that adequately
documenting & explaining code can sometimes take 5 - 10x as long as
actually writing the code! But good documentation certainly makes things
much more useful.

Ognen

unread,
Nov 20, 2021, 11:17:39 AM11/20/21
to FilterMeister Mailing List (FMML)
Hello,
Thank you Paul for the info about allocArrayPad I will consider doing some experiments with it.

I also came to another question here, is it possible to make channel transparent in the 16 bit Grey mode, and if possible how?

paul simoens

unread,
Nov 21, 2021, 3:51:35 PM11/21/21
to filter...@googlegroups.com

Hi Ognen,

Of coarse you can – a piece of cake! It’s just a matter of channel number. In rgb you have the channels 0, 1 and 2. The alpha channel for transparency is nr 3. In the case of 16-bit, 32768 is completely opaque, 0 is completely transparent.

Note:
1. You must first transform the image into layer mode. A flattened image cannot have transparency.
2. As long as the alpha channel contains no zeros, you can fully turn back transparency to full opaqueness. The imageparts were zeros were set are defenitely lost (unless you apply a CTRL+Z).

 

About my promises about a faster code for Worley Noise and further explanations, I’m still working on it. Actually my time is split between renovation works in my appartment (to come to an intermediate break) and FM. Also, I’ll approach this as a cae study that will go beyond the filter effect only. I see this as a first step to refurbish and promote the potentials of FM, it really merits, together with its low threshold for stepping in.

 

Awaiting this, I’m finishing a FM tool that will make it much more comfortable to follow up all kind of coding by means of an extensive info panel. A while ago I spoke about a basic structure, as part of different interschangeable versions – this will be one of it. I’ll hope to send this tomorrow - or at least one of next days.


Best Greetings,
Paul

 

 

Van: filter...@googlegroups.com [mailto:filter...@googlegroups.com] Namens Ognen
Verzonden: zaterdag 20 november 2021 17:18
Aan: FilterMeister Mailing List (FMML)
Onderwerp: Re: [FMML2] Cells/Worley noise discussion continued...

 

Hello,

--

You received this message because you are subscribed to the Google Groups "FilterMeister Mailing List (FMML)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to filtermeiste...@googlegroups.com.

Ognen

unread,
Nov 21, 2021, 9:23:53 PM11/21/21
to FilterMeister Mailing List (FMML)
Hello Paul,
Thank you for the information but I am still confused how to make the channel opacity in Grayscale mode, whether it be in 8 or 16 bit mode in this in the context of creating a texture.

paul simoens

unread,
Nov 22, 2021, 8:55:33 AM11/22/21
to filter...@googlegroups.com

Hi Ognen,

A quick answer inbetween:
In Grayscale mode you have only 1 channel with Z-plane number 0. If your image is set into a layer, you obtain the availability of an extra Alpha channel with Z-plane number 1.

In RGB mode the channel numbers are 0, 1 and 2. If it is set into a layer, the extra Alpha channel will take Z-plane number 3.

8 or 16-bit has nothing to do with the Z-planes.

A complete filterbase is almost finished that will help you better distinguish these concepts and follow up your own coding.



Kind Regards,
Paul

Ognen

unread,
Nov 22, 2021, 9:04:05 AM11/22/21
to FilterMeister Mailing List (FMML)
Thank you Paul,
I can't wait to see the filterbase you are preparing :))

Ognen

unread,
Dec 1, 2021, 7:47:11 AM12/1/21
to FilterMeister Mailing List (FMML)
Hi,

I'm really confused what am I doing wrong so help would be appreciated as actually this modification outputs wrong results:
pset( x, y, 0, abs( val - pget( x - 2, y, 0 ) ) );

According to the code sample from Kohan in the first message, in continuation I want to subtract two identical images from each other, same as the subtract blend mode in PS.
Instead, if distance >1, it outputs vertical black and white stripes blended with the val result (I'm working in 16-bit Greyscale mode). If distance is set to 1, dots are placed in a row equally distanced from each other beginning almost from the middle of the screen, and as there are many rows, each row is placed random on the screen.

I am using the abs() to always return positive number because as I know, negative numbers are always considered as zeroes.

Thanks,
Ognen

paul simoens

unread,
Dec 1, 2021, 10:19:56 AM12/1/21
to filter...@googlegroups.com

Hi Ognen,

You make it
unnecessary very complicated. Subtracting something identical will per definition result in zero... So think again about the effect you want to obtain!

1.  ‘val’ is a non existing code in FM. Rval, Gval, Bval and Aval exists and are used to retrieve the respective channel values from a pixel. This works only in 8-bit! Btw, how could you get ‘val’ passed through the compiler?...


2.  Pixels are always positive integers. So retrieving pixels don’t need to be transformed first to abs values, because nothing will change, except increase of processing time.

 

3.  Interesting to know: pget( x, y, 0) retrieves pixels from the image buffer and is zoom setting sensitive! src( x, y, 0) gets the pixel values from the image itself. src works faster. Theoretical disadvantage is that with src the image is handled as a single file and demands thus more ram, but today that’s mostly not an issue anymore (for normal sized images).

What you want to obtain will thus look something like this:
pset( x, y, 0, src( x, y, 0) –src( x -2, y, 0));

This will indeed often result in negative values truncated to zero. Therefore a ‘carrier’ is necessary, such as a middle value of 16384, similar to a high pass filter.



Paul

Ognen

unread,
Dec 1, 2021, 2:21:25 PM12/1/21
to FilterMeister Mailing List (FMML)
Hi Paul,

Thank you for your response, very good point about using the abs() in the matter of optimization and for the high pass filter idea.


> 1.  ‘val’ is a non existing code in FM. Rval, Gval, Bval and Aval exists and are used to retrieve the respective channel values from a pixel. This works only in 8-bit! Btw, how could you get ‘val’ passed through the compiler?...

Actually, val is a user defined integer variable with subsequently other user defined variables such as in the sample code that Kohan posted:

// Usual Worley noise is the distance to the closest point
val = (int)(MAXWHITE * ((float)(maxdist - smallestdistance)/maxdist));

> What you want to obtain will thus look something like this:
> pset( x, y, 0, src( x, y, 0) –src( x -2, y, 0));

This works with already loaded image, but, according to the code provided by Kohan(please read the first post with the sample code), when the image is generated in the buffer before it is applied on the screen, I am aware  we have to use pget() to make changes in the buffer, i.e. in the output buffer before it is actually applied. So when doing the same with(now without using abs) pset( x, y, 0, val - pget( x - 2, y, 0 ) ), as I stated in my last message I get strange results.

On Wednesday, December 1, 2021 at 4:19:56 PM UTC+1 paul simoens wrote:

Hi Ognen,

You make it
unnecessary very complicated. Subtracting something identical will per definition result in zero... So think again about the effect you want to obtain!



1.  ‘val’ is a non existing code in FM. Rval, Gval, Bval and Aval exists and are used to retrieve the respective channel values from a pixel. This works only in 8-bit! Btw, how could you get ‘val’ passed through the compiler?...

Kohan Ikin

unread,
Dec 2, 2021, 4:40:07 AM12/2/21
to FilterMeister Mailing List (FMML)
Ognen wrote on 2/12/2021 3:21 AM:
> So when doing the same with(now without using abs) pset( x, y, 0, val -
> pget( x - 2, y, 0 ) ), as I stated in my last message I get strange
> results.

The problem is that you're reading pixels that you've already modified.
pset changes pixels in the output buffer, pget gets pixels from the
output buffer.

So if you have something like pget(x-2, y, 0), you're reading from an x
pixel 2 to the left. But in the typical left-to-right for loop, you've
already modified that pixel value with pset 2 for-loop iterations ago.
So that x-2 pixel no longer has the original picture value. Remember to
think pixel-by-pixel, each step of the for loop.

If you change it to x+2, so it's looking at pixels you haven't changed
yet, it will work.

Ognen

unread,
Dec 2, 2021, 4:34:16 PM12/2/21
to FilterMeister Mailing List (FMML)
Hi Kohan,

> Remember to think pixel-by-pixel, each step of the for loop.
Thank you for the remainder, I need more practice to get used to it although it is not that hard to get it.

> If you change it to x+2, so it's looking at pixels you haven't changed yet, it will work.
I have tried that too, but nothing is changed, that is why I am so confused.

Any suggestions?

Kohan Ikin

unread,
Dec 3, 2021, 4:38:16 AM12/3/21
to FilterMeister Mailing List (FMML)
Ognen wrote on 3/12/2021 5:34 AM:
>> If you change it to x+2, so it's looking at pixels you haven't
>> changed yet, it will work.
> I have tried that too, but nothing is changed, that is why I am so
> confused.

Works fine here, if I comment out the original line in the original code
and put your line with +2 instead of -2, I get a blend with the original
image, and none of the strange lines. But only with greyscale images,
you'll need more code changes than this to work with RGB:


// For greyscale, just set the first "color" channel value
//pset(x, y, 0, val);
pset( x, y, 0, val - pget( x + 2, y, 0 ) );



(If instead of that line, you made your blend code part of the
calculation of "val", then you wouldn't need to make changes for RGB mode.)

As for how to solve the x - 2 cases, there's all kinds of ways. You
could create a whole new buffer copy of the image, and look at the x-2
pixel value in that buffer instead of in the output buffer. But that
would be a waste of memory if you only ever look at the last two pixels,
so maybe you just cache / memorize the last two pixel values.

Ognen

unread,
Dec 3, 2021, 8:09:20 AM12/3/21
to FilterMeister Mailing List (FMML)

> Works fine here
If I use src() with already loaded image:
pset(x,y,0,src(x,y,0)-src(x-5,y,0));
I get the wanted result, as in the attached image you will see.
With pset( x, y, 0, val - pget( x + 2, y, 0 ) );
The result is as if I would use only pset(x,y,0,val)
I think I realize that with x+2, pget() takes 2 pixels forward that are empty, i.e. 0 value so this means that val is subtracted from 0 which results in original image.
How would I move pixels instead like with the src() function?

subtracted_worely.png

paul simoens

unread,
Dec 3, 2021, 9:37:27 AM12/3/21
to filter...@googlegroups.com

Waw, an unexpected and impressive effect – well done !
Congratulations for your persistance of not giving up !

 


Best Greetings,
Paul



 

Van: filter...@googlegroups.com [mailto:filter...@googlegroups.com] Namens Ognen
Verzonden: vrijdag 3 december 2021 14:09
Aan: FilterMeister Mailing List (FMML)
Onderwerp: Re: [FMML2] Cells/Worley noise discussion continued...

 

 

> Works fine here

--

You received this message because you are subscribed to the Google Groups "FilterMeister Mailing List (FMML)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to filtermeiste...@googlegroups.com.

Ognen

unread,
Dec 4, 2021, 4:54:41 PM12/4/21
to FilterMeister Mailing List (FMML)

Hi Paul,

> Waw, an unexpected and impressive effect – well done !
> Congratulations for your persistance of not giving up !

Thank you for your motivational words! :))
Somehow, I feel hooked to learning graphics programming although I have ZERO experience in that field. I hope that FilterMeister will rise like Phoenix once again and will contribute to saving Photoshop from, at the moment, finding itself in a state of a certain doom.

Anyway, I am still trying to find a way how to move pixels around, experimenting with pset(), tset(), pget(), tget() and similar, and must admit, there must be more explanation on these functions.

Ognen

unread,
Dec 4, 2021, 5:33:14 PM12/4/21
to FilterMeister Mailing List (FMML)
I am also confused on how actually variables store values when there is need that they should act as an array holders as this isn't an ordinary int some_variable[] array holder. Does it mean that in a for loop the variable automatically allocates the array values in the memory and then retrieves them with calling it just in a for loop?

for example in this excerpt:

for (j = -1; j < 2; j++) {
    for (i = -1; i < 2; i++) {
        tempx = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 0);
        tempy = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 1);
       
        dist = sqrt((double)((x - tempx) * (x - tempx) + (y - tempy) * (y - tempy)));

        if (dist < smallestdistance) {
            smallestdistance = dist;
        }
    }
}

does it mean that the tempx, tempy and dist variables will allocate 9 separate values in the memory where later those variables will be used to retrieve each value in FIFO order but only in a for loop?

I really need an explanation on this as this looks the unconvetnional way of storing values in a variable, or there is something that I miss in C language?

paul simoens

unread,
Dec 5, 2021, 10:03:22 AM12/5/21
to filter...@googlegroups.com

An Array allows you to store variables in a grid. It’s just a grid - just like a notebook with squared paper you put notes in. That grid is not aware from which variable which value came from. The only way to know the origin from a value is to know what coordinate stood for that particular variable.

Personally, I recommend to use shorter names for variables, with a hint to understand for what they stand for. That permits a more comfortable reading of the coding and is less confusing. But that’s a personal view.

 

Forget ‘tsets and tgets’, they are obsolete remnants from the historical build-up of FilterMeister. In a modern approach, I should ban all code that doesn’t permit internal 16-bit math, even if the output will be 8-bit. The resolution grid of 16-bit (which is in fact 15-bit +1) allows to manipulate values with almost no danger of overlap. Thus maintaining the original information as long as possible. 8-bit is an end product with too little margin for editing.

 


Regards,
Paul

Ognen

unread,
Dec 5, 2021, 1:13:26 PM12/5/21
to FilterMeister Mailing List (FMML)
Thank you Paul, but I am afraid you did not understand my question clearly.
I will try to explain it through an example. Let's say in C we initialize an array with 4 values:

int my_array[] = {5, 7, 2, 4};

and then loop it:

for( int i = 0; i < 4; i++ ) {
        printf("%d"my_array[i]);
}

We clearly see that an array my_array[] has been initialized with values allocated somewhere in the memory, then when looping them, on each new iteration the values are retreived from my_array array in the FIFO order.
I know that in FM using brackets are not supported, and does it mean that FM is programmed in such a way to store values in the variable which automatically becomes an array, especially when it is found in a loop like in the case with the dist variable in my last question?
I hope I have cleared things up so the question becomes more clear?

paul simoens

unread,
Dec 5, 2021, 3:11:15 PM12/5/21
to filter...@googlegroups.com

Hi Ognen,

I’m not familiar with specific C-code. FilterMeister code is inspired on C, but it’s not fully exchangeable with it. So the question looks irrelevant to me. Perhaps somebody else could pick in?

Ognen

unread,
Dec 5, 2021, 5:13:54 PM12/5/21
to FilterMeister Mailing List (FMML)
Hi Paul,

Thank you and please accept my apology.

Kohan Ikin

unread,
Dec 6, 2021, 2:21:39 PM12/6/21
to FilterMeister Mailing List (FMML)
Ognen wrote:
> I am also confused on how actually variables store values when there is
> need that they should act as an array holders as this isn't an ordinary
> int some_variable[] array holder....

getArray doesn't return a pointer to an array. It returns a single
element from an array. Again, it's all documented in the wiki:

http://www.filtermeister.com/wiki/index.php?page=getArray

- Kohan

--
kohan ikin
founder & chief developer for namesuppressed

Ognen

unread,
Dec 6, 2021, 4:12:37 PM12/6/21
to FilterMeister Mailing List (FMML)
Hi Kohan,

> getArray doesn't return a pointer to an array.

I am not speaking about getArray(). Please let me be direct with my question. In the loop:

for (j = -1; j < 2; j++) {
    for (i = -1; i < 2; i++) {
        tempx = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 0);
        tempy = getArray(ARRAY_RANDOMPOINTS, (int)((x*gridwidth)/X + j), (int)((y*gridwidth)/Y + i), 1);
       
        dist = sqrt((double)((x - tempx) * (x - tempx) + (y - tempy) * (y - tempy)));

        if (dist < smallestdistance) {
            smallestdistance = dist;
        }
    }
}

the variables tempx, tempy and dist for example, are taking 9 different values before exiting the main loop, do they store these values somewhere in the memory becoming an arrays or is it something else that I should know?

Kohan Ikin

unread,
Dec 6, 2021, 11:39:47 PM12/6/21
to FilterMeister Mailing List (FMML)
Ognen wrote on 7/12/2021 5:12 AM:
> the variables tempx, tempy and dist for example, are taking 9 different
> values before exiting the main loop, do they store these values
> somewhere in the memory becoming an arrays or is it something else that
> I should know?

It's just a normal for-loop, and the variables are all integers. They're
defined as integers at the top of ForEveryTile. They don't become arrays.

- Kohan

--
kohan ikin
founder & chief developer for namesuppressed

Ognen

unread,
Dec 7, 2021, 8:29:05 AM12/7/21
to FilterMeister Mailing List (FMML)
Please excuse me if I am becoming a nagger and boring but,

let's say on each iteration in the for loop, a new calculated value is stored in the variable dist. I am not sure if those values are overwritten on each new iterations in the variable dist, because in every programming language that I know of, on loop exit the last value is stored in the variable unless that variable is an initialized array or some calculation is performed like for example with the addition assignment (my_variable += 2) that will store the total value of all the summed values in the iteration?

Also, if smallestdistance = dist if dist < smallestdistance, then smallest distance stores some values that are unrelated from the variable dist, neither the first, neither the second nor the last value.

Let's say if maxdist = 7, and dist = 2.368, then, by the programming language logic, the last value from dist should be stored in smallestdistance upon exit from the for loop and continue its calculation further in the code which is not the case.

Again, how FilterMeister copes with storing new different values on each iteration in the variable dist and what is actually stored in the variable smallestdistance upon exiting the loop, i.e. which values are taken from dist from inside the iteration?

I am not sure, maybe this will become more clear what I am trying to ask actually.

Thank you,
Ognen

Kohan Ikin

unread,
Dec 7, 2021, 10:41:38 AM12/7/21
to FilterMeister Mailing List (FMML)
Ognen wrote on 7/12/2021 9:29 PM:
> I am not sure if those values are overwritten on each new iterations
> in the variable dist...
Yes, they are being overwritten.


> Let's say if maxdist = 7, and dist = 2.368, then, by the programming
> language logic, the last value from dist should be stored in
> smallestdistance upon exit from the for loop....

Only if that value of dist is smaller than the value that was already in
smallestdistance. That part of the code again, with my original code
comments added back in:

// Is this measured distance the smallest so far?
// If so, remember it.
if (dist < smallestdistance) {
smallestdistance = dist;
}


I really don't know what else I can say. I don't want to be unkind or
unhelpful, but I've also now spent more than 25 hours answering Worley
Noise related questions. That's a lot of free consulting time, I need to
bow out at this point. If I haven't been able to explain it well enough
in that amount of time, perhaps someone else is better at explaining it
than I have been.

Ognen

unread,
Dec 7, 2021, 11:21:23 AM12/7/21
to FilterMeister Mailing List (FMML)
> I don't want to be unkind or unhelpful,
You  are very kind and very helpful. I understood many things related to FM thanks to you.

> but I've also now spent more than 25 hours answering Worley Noise related questions.
Please accept my apologies for making you think I want to solve math problems related to graphics.
I will bring a clear statement that all I want is to get to know the FilterMeister language from a closer perspective, because it really is to some extent an unconventional language. I am using your excellent worley noise algorithm code as an example for pointing out some ambiguities about programming with this language that is C like, but not exactly C. Your code is a great example on how to start programming something useful.

At the other hand please do not feel forced to answer to my questions and again, my sincere apologies for making you think that I am using you for completing my goals for free. I am just trying to understand FM as much as possible that I found it interesting, nothing more and nothing less.

Sincere,
Ognen

Roberto

unread,
Dec 7, 2021, 3:21:18 PM12/7/21
to filter...@googlegroups.com
Hi Kohan,

"I really don't know what else I can say" seemed unnecessary with just having answered Ognen's questions very clearly :-P

Wow, that's a graceful saying: "to bow out"! Never heard of it but it instantly triggered my imagination as you in a fancy musketeer outfit humble bowing deeply while taking your hat off :-)))) ... kinda like this :-P

I can relate to Ognen's situation: at first he got educative multi-subject code to play with. Excited to know how it works he goes through the code trying to understand it with the help of the inlined comments. Running into less intuitive parts he puts his teeth in it to understand it in detail. In the process trying to master the details the 'overall comments' somehow dissapear to the background and the overall context gets a bit lost of the "sub-problem".
I remember when I intended to learn FM I did want to understand -in detail- the lines of the code looping through the rows and columns of pixels instead of just memorizing thatr "standard part of code".
Understanding the basics always pays off in the long run multiple times.

The getArray lines are indeed a bit overwelming but even when understood in detail it all makes only sense in the context of the goal: splitting up the image in smaller blocks of pixels each containing a point at random location and check the shortest distance of the block edges to the point. An array is re-used for this purpose and even within a single block being processed the variable for "distance" may be overwritten multiple times.

I love to read how Ognen is putting his teeth into this matter. Those are the ones who come up with great stuff eventually :-P
Keep up the great work, Ognen! ;-)

Roberto


Op Tue, 07 Dec 2021 16:41:28 +0100 schreef Kohan Ikin <koha...@namesuppressed.com>:
--
Gemaakt met Opera's e-mailprogramma: http://www.opera.com/mail/

Ognen

unread,
Dec 7, 2021, 4:06:09 PM12/7/21
to FilterMeister Mailing List (FMML)
Hi Roberto,

> Understanding the basics always pays off in the long run multiple time.
Totally agree on this. We have to get to know the bottom so will understand how deep it is which means if we don't know the basics, every new problem has to be solved by someone else who already knows how deep the bottom is.

>  I love to read how Ognen is putting his teeth into this matter. Those are the ones who come up with great stuff eventually :-P
Again, all credits go to Kohan who took his precious time to offer help. I am one of those who are just trying to understand how FM works, that's all.
Thank you anyway for the motivational words Robert.

Regards,
Ognen
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages