#JavaFX Fluid Simulation

1 messages Β· Page 3 of 1

grand garnet
#

where does this Platform.runLater() go?

steep elbow
#

render is just a for loop

#

you put this code here

grand garnet
#

ahh

steep elbow
#

I have no idea what PixelStream is

#

but get rid of that and just pass an array

boreal socket
#

I could squish it down to one single class for the simulation loop

#

non threaded

#

its 200 MB ram usage

#

missing the improvements to Fluid.java

grand garnet
boreal socket
#

but its like the only way you would do it

#

what is he expecting?

grand garnet
#

lots

#

shall i find another one of those wacky emails 😭

boreal socket
#

bruh tell him he has no idea and shouldnt be a teacher cat_thumbs_up

#

jk

#

but this makes no sense

#

and I wont continue to help

#

this is the best solution for this

#

other stuff makes no sense

grand garnet
#

Hmm

#

i might try sending him another email then 😭

boreal socket
#

might want to check/refer to this:
#today-i-teach message

#

nvm

#

it is missing AnimationTimer NootLikeThis

#

literally made for this purpose

#

literally

grand garnet
#

ooooh

#

ok will have a look rn

boreal socket
#

the nice thing is that the handle method is still called on the FX Thread

#

so you can do UI stuff

grand garnet
#

separate to updating?

boreal socket
#

wdym

grand garnet
#

nvmm

#

i get it now lmao

boreal socket
#

lol

grand garnet
#

I will finalise this with my teacher

#

if he says no i guess i gotta just do the more convoluted way

boreal socket
#

it would be so giga cringe

#

because it makes no sense

#

its like creating your own arraylist instead of using the provided one by the standard library

grand garnet
#

he likes it when you make the stuff yourself and don't rely on too much other stuff

grand garnet
#

i mean it was a linked list but same idea i guess

#

i'm gonna have to make my own deque as well when it comes to storing recordings

boreal socket
#

this is a fluid simulation, you are creating it using javafx and so you should be allowed to use the features provided by javafx
the focus should be on the simulation itself

#

such a bad way of teaching ngl

#

its really important that you know your libraries

#

using them efficiently is important for good code quality

grand garnet
#

@steep elbow is it fine if i do use an interface as a parameter because i can't just pass the density array by itself as there is the fluid.index() method which i would require for setting pixels but idk if i should pass in the whole fluid

grand garnet
#

it's a fluid simulation for a computer science project not a physics project

#

they care more about the computational methods you use

boreal socket
#

yeah but still

grand garnet
#

e.g. concurrent programming

boreal socket
#

but its not like that you use concurrency even if its worse

#

thats not how it works in reality

grand garnet
#

i should've just done a graph visualiser everyuthing would've been so ez and i would've gotten all the marks quickly

boreal socket
#

wdym?

grand garnet
#

you can choose your project

boreal socket
#

ah ok

grand garnet
#

normally people do something easy like a small game or booking system with some cool database stuff

boreal socket
#

but for a graph visualiser you would also need to do all stuff your own because of that teacher lmao

grand garnet
#

i asked my teacher for recommendations and he said a fluid simulation

grand garnet
boreal socket
#

which is a cool project and pretty nice and easy to implement using javafx

#

if you know and are allowed to at least use the standard lib lol

grand garnet
#

yeahh

#

people get marked down so much for using drag and drops and just anythingn that saves them a lot of time 😭

#

because then they won't be doing much work and the project would be easy for them

boreal socket
#

that teacher never went into industry

#

has no idea how reality works

#

whatever

grand garnet
#

he wrote code for CERN apparently

#

I shall ask him tho dw

boreal socket
#

he should at least read what AnimationTimer is about before just saying
yeah nah, do it yourself 🀑

#

and if he says no, ask him if you are allowed to use Platform.runlater

#

if he also says no just tell him that its not possible to finish this then

#

you would need either one

#

big trap

grand garnet
#

ok sure

#

also

#

how do i do it so that when i press the close button, my program fully stops?

#

i think the introduction of a new thread fully ruined it

boreal socket
#

make it a daemon thread

#

or instead handle the close button properly

#

so it shut downs the thread properly

grand garnet
#

okayy

#

got it daemon

boreal socket
#

also normally you shouldnt use Thread directly

#

instead use stuff like Executor services and stuff

grand garnet
#

never heard of that 😭

#

how do i clone a whole class?

#

is it possible?

boreal socket
#

wdym clone?

#

like clone an instance?

grand garnet
#

like you know how I can clone a whole array?

#

yeahhh

boreal socket
#

maybe make smth like a copy constructor

#

but depends on the context

grand garnet
#

ala said to use this Platform.runLater(() -> render(density.clone()));

#

but

#

the problem is

#

i can't just pass in the density

#

because i need the fluids methods to actually correspond a location in the density to a pixel

boreal socket
#

Tbh I wouldn’t continue this until your teacher answered or use the provided code by me temporarily to work on other stuff

grand garnet
#

hmm

#

ok i shall just wait for him to answer then

#

i'm still going to try edit this one myself though because he will most likely disagree with what you said

#

i did exactly this

#

but it just shows a plain canvas

#

within the mouse adapter

#
    public int index(int i, int j) {
        if (i < 0) {
            i = 0;
        }
        if (i > 300 + 1) {
            i = 300 + 1;
        }
        if (j < 0) {
            j = 0;
        }
        if (j > 300 + 1) {
            j = 300 + 1;
        }
        return (i + j * (300 + 2));
    }

    @Override
    public void render(double[] dens) {
        GraphicsContext gc = canvas.getGraphicsContext2D();

        for (int y = 0; y <  canvas.getHeight() ; y += 3) {
            for (int x = 0; x < canvas.getWidth(); x += 3) {
                double num = dens[index(x / 3, y / 3)];
                byte pixelValue = (byte) ((num > 255) ? 255 : num);
                int color = pixelValue & 0xFF;
                gc.setFill(Color.grayRgb(color));
                gc.fillRect(x, y, 3, 3);
            }
        }
    }```
cedar tigerBOT
# grand garnet ```java public int index(int i, int j) { if (i < 0) { i ...

Detected code, here are some useful tools:

Formatted code
public int index(int i, int j) {
  if (i < 0) {
    i = 0;
  }
  if (i > 300 + 1) {
    i = 300 + 1;
  }
  if (j < 0) {
    j = 0;
  }
  if (j > 300 + 1) {
    j = 300 + 1;
  }
  return (i + j * (300 + 2));
}
@Override
public void render(double [] dens) {
  GraphicsContext gc = canvas.getGraphicsContext2D();
  for (int y = 0; y < canvas.getHeight(); y += 3) {
    for (int x = 0; x < canvas.getWidth(); x += 3) {
      double num = dens[index(x / 3, y / 3) ] ;
      byte pixelValue = (byte ) ((num > 255) ? 255 : num);
      int color = pixelValue & 0xFF;
      gc.setFill(Color.grayRgb(color));
      gc.fillRect(x, y, 3, 3);
    }
  }
}
grand garnet
#

the render handler method

#
    public void render() {
        Platform.runLater(() -> mouseAdapter.render(fluid.dens.clone()));
    }```
dense hare
#

whats the new issue?

#

im assuming you guys solved the memory issue

steep elbow
steep elbow
steep elbow
cedar tigerBOT
#

@grand garnet

Your question has been closed due to inactivity.

If it was not resolved yet, feel free to just post a message below
to reopen it, or create a new thread.

Note that usually the reason for nobody calling back is that your
question may have been not well asked and hence no one felt confident
enough answering.

When you reopen the thread, try to use your time to improve the quality
of the question by elaborating, providing details, context, all relevant code
snippets, any errors you are getting, concrete examples and perhaps also some
screenshots. Share your attempt, explain the expected results and compare
them to the current results.

Also try to make the information easily accessible by sharing code
or assignment descriptions directly on Discord, not behind a link or
PDF-file; provide some guidance for long code snippets and ensure
the code is well formatted and has syntax highlighting. Kindly read through
https://stackoverflow.com/help/how-to-ask for more.

With enough info, someone knows the answer for sure πŸ‘

grand garnet
#

hihiiiii

#

gonna start at 4 today

grand garnet
grand garnet
boreal socket
#

You got a response?

grand garnet
#

@steep elbow for the time being, i just copied the index function again into the class that needs it

#

like this:

#

however, whenever i start it up it just shows this

#

whenever I don't use run later, it works

steep elbow
# grand garnet

place a brakpoint and see if this method is getting called

grand garnet
#

that's the red circle thingy right?

steep elbow
#

yes

grand garnet
#

shows this

steep elbow
#

wait

#

you have to clone before

#

@grand garnet

grand garnet
#

outside the argument?

steep elbow
#

clone the array before the runlater

#

and then pass the copy

grand garnet
#

ok sure

#

why does that need to happen though?

steep elbow
#

otherwise copying is kinda useless

#

you want to copy so you don't have concurrency problems

grand garnet
#

oh

#

so this yeah?

        double[] arrayToPass = fluid.dens.clone();
        Platform.runLater(() -> mouseAdapter.render(arrayToPass));```
steep elbow
#

yes

grand garnet
#

still the same thing

#

hmm

#

breakpoint again?

steep elbow
#

does it work?

grand garnet
#

nope

steep elbow
#

hmm

#

wait

#

why is the array only filled with 0

grand garnet
#

i mean starting density of the fluid is 0

#

it's normal to be that

#

lemem check with the awt one just to confirm

steep elbow
#

like is full white 0 ?

grand garnet
#

nope

#

that's what i was saying

#

if i remove the runLater

#

it renders

#

but then freezes

#

after like 5 seconds

steep elbow
#

you need runLater

#

show the full TestSimulationController

grand garnet
#

could it be to do with my main simulation thread?

steep elbow
#

why are coords an array instead of two ints

#

and you will have to debug this

#

try to see why it doesn't display on the canvas

#

also what is Color.grayRgb

#

i don't see such a method

grand garnet
grand garnet
steep elbow
grand garnet
grand garnet
#

ok after like 10 seconds it turns fully black

#

this takes very long apparently

#

this as well

steep elbow
grand garnet
# grand garnet

I shouldn't have to change this for now because it works completely fine in awt so i know jfx is the problem

grand garnet
steep elbow
#

there is no way a setter would take 18s

grand garnet
steep elbow
grand garnet
#

how do i check?~

steep elbow
grand garnet
#

i think i went off it i can't find how long 😭

#

lemme redo

#

oh wait

#

i found it

#

45 seconds

steep elbow
#

huh

grand garnet
#

this right?

#

ok so it seems to be accessing the rendering method on time

#

it's just not actually rendering it

#

hey @boreal socket how do i check the memory usage?

boreal socket
#

On the default profiler window on the top right

#

By default it shows CPU time

#

But you can change it to Memory

#

Not at home

#

Can’t show it

grand garnet
#

yep crazyy

#

ala i don't think this is normal 😭

steep elbow
#

what

grand garnet
#

18GB

#

from setFill

steep elbow
#

wtf

#

what if you comment it

grand garnet
#

AHHHHHHHHHHHHHH

steep elbow
grand garnet
#

YES

#

BRUH 😭

steep elbow
#

what

boreal socket
#

So my solution works zuccwater

steep elbow
#

how

#

then use a buffer

grand garnet
#

I do not know 😭

grand garnet
#

teacher will kill me off πŸ’€

boreal socket
#

Yeah the good solution

#

I can transform it using threading later

grand garnet
#

okayy

#

im going to look into buffering though

steep elbow
#

just use a buffer

#

and use I think setPixels

grand garnet
#

i used a buffer in awt iirc

#

yes i did

#
public synchronized void render(DataProvider pixelStream) {
        BufferedImage imageContainer = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_BYTE_GRAY);
        byte[] buffer = ((DataBufferByte) imageContainer.getRaster()
                .getDataBuffer()).getData();

        for (int y = 0; y < imageContainer.getHeight(); y++) {
            for (int x = 0; x < imageContainer.getWidth(); x++) {
                buffer[y * IMAGE_WIDTH + x] = pixelStream.provideData(x, y);
            }
        }

        this.buffer = imageContainer;
        repaint();
    }
}```
cedar tigerBOT
boreal socket
grand garnet
#

what's the equivalent of a BufferedImage in jfx?

#

like what shoudl i serach up for if i wanna start using a bfufer in jfx

steep elbow
#

PixelWriter p = gc.getPixelWriter();
p.setPixels(0, 0, W, H, pixelFormat, buffer, 0, W);

grand garnet
#

ohhh

#

ok

dense hare
grand garnet
#

does this rendering make sense?

#
@Override
    public void render(double[] dens) {
        PixelWriter pixelWriter = canvas.getGraphicsContext2D()
                .getPixelWriter();

        for (int y = 0; y <  canvas.getHeight() ; y += 3) {
            for (int x = 0; x < canvas.getWidth(); x += 3) {
                double num = dens[index(x / 3, y / 3)];
                byte pixelValue = (byte) ((num > 255) ? 255 : num);
                int color = pixelValue & 0xFF;
                
                for (int i = x; i < 3; i++) {
                    for (int j = y; j < 3; j++) {
                        pixelWriter.setColor(x+i, y+j, Color.grayRgb(color));
                    }
                }
                
            }
        }
    }```
grand garnet
#

unless it's very necessary

grand garnet
#

😭

#

i am bugging

steep elbow
#

but no, that's not a buffer

grand garnet
grand garnet
steep elbow
grand garnet
steep elbow
#

dens is 302*302 right

#

so 302*302*8 bytes

#

so 729632

#

so if fps = 30

grand garnet
#

yep

steep elbow
#

21888960 bytes per second

#

so 20Mb per second

grand garnet
#

21mb a second

steep elbow
#

yea

grand garnet
#

😭

steep elbow
#

so how do you even get 35Gb lol

grand garnet
#

I am running it on a quantum computer

#

my qbits travel at the speed of light

#

ok im quite unsure on what to assign into my buffer

#

i have this so far

#
@Override
    public void render(double[] dens) {
        PixelWriter pixelWriter = canvas.getGraphicsContext2D()
                .getPixelWriter();
        int[] buffer = new int[900 * 900];
        for (int y = 0; y <  canvas.getHeight() ; y += 3) {
            for (int x = 0; x < canvas.getWidth(); x += 3) {
                double num = dens[index(x / 3, y / 3)];
                byte pixelValue = (byte) ((num > 255) ? 255 : num);
                int color = pixelValue & 0xFF;
                buffer[y*900 + x] = ;
            }
        }
    }```
cedar tigerBOT
# grand garnet ```java @Override public void render(double[] dens) { PixelWriter pi...

Detected code, here are some useful tools:

Formatted code
@Override
public void render(double [] dens) {
  PixelWriter pixelWriter = canvas.getGraphicsContext2D().getPixelWriter();
  int [] buffer = new int [900 * 900] ;
  for (int y = 0; y < canvas.getHeight(); y += 3) {
    for (int x = 0; x < canvas.getWidth(); x += 3) {
      double num = dens[index(x / 3, y / 3) ] ;
      byte pixelValue = (byte ) ((num > 255) ? 255 : num);
      int color = pixelValue & 0xFF;
      buffer[y * 900 + x]  = ;
    }
  }
}
steep elbow
grand garnet
#

hmm

#

so the RGB values i assign to them?

steep elbow
#

yes

grand garnet
#

thing is

#

I am using Color.grayRgb(color) to get the value

#

but that is of type Color and not int

steep elbow
#

isn't pixelValue already the grey color ?

#

@grand garnet

grand garnet
#

that's just the value for grayscale no?

#

it only worked in awt because my image was of type BufferedImage.TYPE_BYTE_GRAY

#

wot

steep elbow
grand garnet
#

yeah i realised

#

i just did the pixelFormat as PixelFormat.getByteBgraInstance()

#

which i assume is to do with GRAY

boreal socket
#

assuming is not a good idea

grand garnet
#

😭

#

okkk i'll search up the docs

boreal socket
#

Returns a WritablePixelFormat instance describing a pixel layout with the pixels stored in adjacent bytes with the non-premultiplied components stored in order of increasing index: blue, green, red, alpha.

steep elbow
#

gra probably means gradient

grand garnet
#

hmm

#

which one should I be using?

#

i am clueless when it comes to jfx 😭

boreal socket
#

just use animation timer geniusidea

grand garnet
#

teacher gonna kill me fr 😭

steep elbow
boreal socket
#

not this what you are talking about, but the simulation in general

#

its the correct way in the first place

steep elbow
#

and I have no idea why javafx struggles so much here
i never had this problem

grand garnet
#

why deos it say this 😭

boreal socket
#

because it takes an byte[] instead of int[]

grand garnet
boreal socket
#

because you are using PixelFormat<ByteBuffer> and not PixelFormat<IntBuffer>

grand garnet
#

What the fok

grand garnet
#

ok

#

big problem

boreal socket
#

πŸ‘€

grand garnet
#

even if i change my method to

#

it still throws an OutOfMemoryError

#

somehwere it is saving everything

#

wut

boreal socket
#

πŸ’€

steep elbow
steep elbow
boreal socket
#

I think its correct

steep elbow
#

show your logic loop

steep elbow
boreal socket
#

because you clone like 30 times a second

steep elbow
#

20mb per second

boreal socket
#

and that profiler showing all the ram used while running the profiler

#

and not at one time

#

but its still way toooooo much

steep elbow
#

6gb would take 300s

#

so there is no way

boreal socket
#

anyways my solution works zoomeyes

steep elbow
#

and since he is doing a lot of copies everywhere else

#

then this single copy can't be the problem

grand garnet
steep elbow
#

no

#

what is calling everything

#

the main loop

boreal socket
#

aka the run overrided method

grand garnet
#
@Override
    public void run() {
        double deltaTimeSeconds = 1.0 / TPS;
        double lastFrameTime = nanosToSeconds(System.nanoTime());
        double secondsToConsume = 0.0;

        while (simulationThread != null) {
            double currentFrameTime = nanosToSeconds(System.nanoTime());
            double lastFrameNeeded = currentFrameTime - lastFrameTime;
            lastFrameTime = currentFrameTime;

            secondsToConsume += lastFrameNeeded;
            while (secondsToConsume >= deltaTimeSeconds) {
                update(deltaTimeSeconds);
                secondsToConsume -= deltaTimeSeconds;
            }

            render();

            double currentFPS = 1.0 / lastFrameNeeded;
            if (currentFPS > FPS) {
                double targetSecondsPerFrame = 1.0 / FPS;
                double secondsToWaste = Math.abs(targetSecondsPerFrame - lastFrameNeeded) / 1000000;
                try {
                    TimeUnit.SECONDS.sleep(secondsToMillis(secondsToWaste));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }```
cedar tigerBOT
boreal socket
#

works fine as well

grand garnet
#

what's the main difference?

boreal socket
#

between which? between both my solution? or between my and yours?

grand garnet
#

mine and yours

boreal socket
#

can you share your full current state of your application pls

#

like update the branch

grand garnet
#

sure

boreal socket
grand garnet
#

fairs

grand garnet
#

it's rlly broken rn

boreal socket
#

why you got such a weird rendering method?

grand garnet
#

it's broken

#

dw bout it 😭

boreal socket
#

fix it

grand garnet
#

I am gonna use yours 😭

#

but im trying to understand it first

#
  private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor(r -> {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
    });``` 

What does this do?
#

like the Daemon

boreal socket
#

do you know what an executor is in the first place?

grand garnet
#

never heard of it

boreal socket
#

the newer and better way of submitting Runnable tasks

#

instead of using:

Thread thread = new Thread(runnable);
thread.start();

you are using an executor

#

which will handle stuff for you etc

#

and uses stuff like Future

#

a daemon thread is basically a thread which wont stop your whole application from terminating

#

currently with your solution, you already noticed, if you click the close button the actual application continues running

#

because the thread is non daemon

#

and thus the application waits until all non daemon threads finished executing

boreal socket
#

which gives you the ability to change the creation of the thread

#

and thus make it daemon

grand garnet
#

thread factory 😭

boreal socket
#

whats wrong with it

grand garnet
#

it sounds funny

#

like i can just imagine like a factory

#

where they are making threads

boreal socket
#

yeah actually pretty good name for it

#

makes it self explanatory

#

you get a Runnable and need to create a thread for it

#

but you most likely want to change the usage of the executor in the controller later on

#

so that you store the future created by the initialize method

#

and properly stop the runnable if someone switches scenes

grand garnet
#

what exactly is future?

boreal socket
#

A Future represents the result of an asynchronous computation

#

thats returned by using EXECUTOR.submit

#

and then when switching the scene you should also stop the runnable

#

so the simulation actually stops

grand garnet
#

does it work for you 😭

#

it doesn't for me

grand garnet
boreal socket
grand garnet
#

like it doesn't respond to mouse inputs or anything

boreal socket
#

works fine for me

#

maybe update the branch

#

so I can check

grand garnet
#

done

#

also

#

is there a way I can make it so that I can change FPS?

boreal socket
#

you can update it yeah

#

just need to update the run method

#

but thats usually not recommended anyways

#

ok depends

#

but yea

grand garnet
#

oh

#

but like

#

what if i wanna run at 30fps on one system

#

and 60 on another

boreal socket
#

then you need to implement it

grand garnet
#

Hmm ok

#

updated branch btw

boreal socket
#

bruh I am so confused

#

its literally the same I used

grand garnet
#

yep 😭

#

does it not work for you?

boreal socket
#

bruh wtf

#

this is giga cursed

grand garnet
#

I think my project just hates me

#

u sure ur running the right project and everything?

boreal socket
#

im on master2

grand garnet
#

nah i mean as in your one

#

the one that works 😭

boreal socket
#

the thing that got overwritten now πŸ’€

#

but it just consisted of the code shared in the gist

#

I found the problem

#
    protected Fluid() {
        this.WIDTH = 100;
        this.HEIGHT = 100;
#

these need to be 300 and 300

grand garnet
#

isn't that image height though

#

hmm

#

logic error

#

lemme try rq

boreal socket
#

the thing is you got smth like cell size

#

and I ignored that

#

and work with 1 pixel = 1 cell

grand garnet
#

OMG

#

it works

#

ok

#

i can fix that tmrw

#

bro

#

ILY MAN

boreal socket
#

lmao

grand garnet
#

actually a life saviour

#

i think i should be fine with the rest because no more concurrency problem πŸ’ͺ

#

lemme try a much bigger size and check if it lags

#

oh it's not too laggy

#

roughly 30fps

boreal socket
#

yeah but your Fluid.java is weird anyways

grand garnet
#

yeah im gonna optimise it after finishing the prototype

boreal socket
#

needs some improvements

grand garnet
#

i should be able to fix it all within 4 hours tmrw

#

btw

#

you good at math?

boreal socket
#

kinda

#

depends

grand garnet
#

(not gonna ask for math help dw)

grand garnet
#

very fun

boreal socket
#

ke

grand garnet
#

what's a kek

#

😭

boreal socket
#

have fun

grand garnet
#

LMAO

grand garnet
boreal socket
#

nah

cedar tigerBOT
#

@grand garnet

Your question has been closed due to inactivity.

If it was not resolved yet, feel free to just post a message below
to reopen it, or create a new thread.

Note that usually the reason for nobody calling back is that your
question may have been not well asked and hence no one felt confident
enough answering.

When you reopen the thread, try to use your time to improve the quality
of the question by elaborating, providing details, context, all relevant code
snippets, any errors you are getting, concrete examples and perhaps also some
screenshots. Share your attempt, explain the expected results and compare
them to the current results.

Also try to make the information easily accessible by sharing code
or assignment descriptions directly on Discord, not behind a link or
PDF-file; provide some guidance for long code snippets and ensure
the code is well formatted and has syntax highlighting. Kindly read through
https://stackoverflow.com/help/how-to-ask for more.

With enough info, someone knows the answer for sure πŸ‘

grand garnet
#

.

boreal socket
#

πŸ‘€

grand garnet
#

my simulation stopped working 😭

boreal socket
#

πŸ’€

grand garnet
#

I didn't even change much

#

I just tried making the cell length a variable

boreal socket
#

much

grand garnet
#

before I just kept dividing by 3

#

but i just changed it to CELL_LENGTH

#

and it started lagging

boreal socket
#

Can’t check right now

grand garnet
#

ok no worries

#

roughly what time would you be able to?

boreal socket
#

Now

#

@grand garnet

grand garnet
#

YOOO

#

ok

#

so lemme update master2 rq

#

done!

#

idk why it isn't working

#

did the branch update for you?

boreal socket
#

yea

#

the problem is the width (BoxFluid) vs width (window, visual) probably

#

like yesterday

#

but idk why

boreal socket
#

what?

boreal socket
#

this was the problem yesterday as well

#

idk how to fix it so you can have it separate

#

looking in some minutes

boreal socket
#

yeah idk

#

it must be some calculation issue

#

not really interested in checking all the calculations

#
double num = fluid.dens[fluid.index(x / 5, y / 5)];

this already confuses me

grand garnet
grand garnet
boreal socket
#

yeah I noticed

#

but why are you not using the variable?

grand garnet
#

oh i was checking if the variable was the problem

#

that's why i changed it to 5

#

my baddd

boreal socket
#

all good

grand garnet
#

i've just been staring at this fro 30 mins

boreal socket
#

try using a debugger πŸ€·β€β™‚οΈ

grand garnet
#

I don't get how i would here 😭

grand garnet
#

bruh

#

I'm gonna cry

boreal socket
#

the x, y logic is wrong no?

grand garnet
#

how?

grizzled inlet
#

what the 164 gb with fire mean?

grand garnet
#

storage it uses over the time it is run

boreal socket
#

also in this case I would use setPixels instead of creating a new double nested for loop

#
writer.setPixels(x * CELL_LENGTH, y * CELL_LENGTH, CELL_LENGTH, CELL_LENGTH, ...);
#

not sure about the PixelFormat

#

ingame right now

#

but you would want a pixel format/reader that only uses the one color

grand garnet
#

thing is

#

if i remove the runLater

#

it runs but just freezes

#

but if i don't remove runLater it doesnt run at all

boreal socket
#

try making CELL_LENGTH = 1

#

it will probably work in that case

grand garnet
#

withhout the runLater it works but then crashes straigth away 😭

boreal socket
#

you need the runLater

grand garnet
#

hmm

#

but then why does it run fine without it but just crash after a couple sends

#

i don't think the fluid class is the problem

#

i think it's the concurrency

boreal socket
#

I think its your logic

grand garnet
boreal socket
#

your logic seems to be crashing your application

#

idk

#

its just guessing

grand garnet
#

i meann I was only running for like 10 seconds

boreal socket
#

yeah but this profiling just leads to guessing

grand garnet
#

umm

#

i just randomly started it up

#

and now it's working

#

😭

#

like it didn't crash at all

#

ok when i change the cell length now it bugs

boreal socket
#

yeah exactly

grand garnet
#

ok

#

lemem try debug with a different cell length

#

but before i do so imma push onto master2

grand garnet
#

shitty thing seems to break whenever i change cell size 😭

#

im doing a wrong calculation somewhere

#

has to be

boreal socket
#

yeah exactly

grand garnet
#

i want to kms

#

I can't find it

#

because surely rendering a 24x24 fluid is a lot easier than rendering a 120x120 fluid

#

you know whta

#

imma go on my laptop

#

and check

#

fresh mind

grand garnet
#

how do i load master2 from git onto intelliJ

#

idk why iut does this when cell length = 5

boreal socket
#

try to find it out

grand garnet
#

im trying 😭

#

i've been jus trying random tests

#

but idk why it increases storage when i increase cell length

#

it should technically decrease

#

ok so it does paint a cell correctly

#

it paints the edge colors correctly according to cell length as well

boreal socket
#

the problem will be in the Fluid.java anyways

grand garnet
#

don't think so because the density is updated accordingly

boreal socket
#

but it already crashes with a different CELL_LENGTH even without updating the rendering

#

and it was only used in Fluid.java

grand garnet
#

it does update the rendering once lmao

#

didn't i show you?

boreal socket
#

what?

#

it doesnt work

#

lol

#

thats the point

grand garnet
#

most the time it doesn't

boreal socket
#

yeah so it doesnt work

grand garnet
#

but if you touch it like luckily

#

you can get somethin glike this

#

i did that

#

and then it froze

boreal socket
#

yeah so it doesnt work

grand garnet
#

oh

#

nooo

#

ok

#

i think i am getting confused

#

so

#

my problem is

#

this num

#

is correct

#

i believe

#

but it's just the writer.setColor which is bugging

#

like if i do this

#

it will output changing values

#

i.e. it wouldn't output 0 indefinitely

#

it's just that it's not rendering

#

so the calculations within Fluid.java are fine

#

it's just the way it's being rendered i believe

#

System.out.println("Writing value to coord: \n" + (x * CELL_LENGTH + i) + "\n" + (y * CELL_LENGTH + j) + "\n" + Color.grayRgb(color));

boreal socket
#

but the code worked before introducing CELL_LENGTH

#

so its probably not the concurrency making the issue

grand garnet
#

hmm

#

if i do this

#

it outputs stuff like this

#

which means that color is defo being given in

#

just not being displayed

#

πŸ€”

grand garnet
boreal socket
#

I highly doubt that

#

why would it?

grand garnet
# grand garnet

because the fluid class is clearly giving colors to be written to the canvas at a given pixel

#

if the run later is taken away as well, it will display some sort of image but will ofc crash because it has no runLater

boreal socket
#

trying to remove the runLater is the first problem

grand garnet
#

hmm

#

ok lemme try CELL_LENGTH = 2

boreal socket
#

maybe its your mouseAdapter?

grand garnet
#

that's what i was thinking maybe

boreal socket
#

it mostly likely is

#

because you dont transform the coords

grand garnet
#

I do though?

boreal socket
#

I dont see it

#

where are you using cell_length?

grand garnet
#
    this.x = (x / cellLength);
    this.y = (y / cellLength);
boreal socket
#

ah ok didnt see it

#

but will it work here then:

    private void addSourcesFromUI(Fluid fluid) {
        synchronized (fluid) {
            mouseAdapter.consumeSources(fluidInput -> {
                fluid.u[fluid.index(fluidInput.x, fluidInput.y)] += fluidInput.forceX;
                fluid.v[fluid.index(fluidInput.x, fluidInput.y)] += fluidInput.forceY;
                fluid.u[fluid.index(fluidInput.x + 1, fluidInput.y)] += fluidInput.forceX;
                fluid.v[fluid.index(fluidInput.x + 1, fluidInput.y)] += fluidInput.forceY;
                fluid.u[fluid.index(fluidInput.x - 1, fluidInput.y)] += fluidInput.forceX;
                fluid.v[fluid.index(fluidInput.x - 1, fluidInput.y)] += fluidInput.forceY;
                fluid.u[fluid.index(fluidInput.x, fluidInput.y + 1)] += fluidInput.forceX;
                fluid.v[fluid.index(fluidInput.x, fluidInput.y + 1)] += fluidInput.forceY;
                fluid.u[fluid.index(fluidInput.x, fluidInput.y - 1)] += fluidInput.forceX;
                fluid.v[fluid.index(fluidInput.x, fluidInput.y - 1)] += fluidInput.forceY;
                fluid.dens[fluid.index(fluidInput.x, fluidInput.y)] += fluidInput.density;
            });
        }
    }
#

I kinda doubt that

grand garnet
#

i mean

#

it works on the awt one

#

so it should on jfx

boreal socket
#

its easily said but is it even the same code? no

#

so it doesnt make sense

grand garnet
#

hmm

#

ok let's try see

boreal socket
#

but idk

#

I cant tell you where the issue is

grand garnet
#

hmm

#

yep mouse inputs are fine

#

just checked whether these match the sizes

#

it works

#

so i click pixel at (599,599) on screen

#

and it adds to (299,299) on fluid

#
PixelWriter writer = canvas.getGraphicsContext2D()
                        .getPixelWriter();

                for (int y = 0; y < fluid.HEIGHT; y++) {
                    for (int x = 0; x < fluid.WIDTH; x++) {
                        double num = fluid.dens[fluid.index(x, y)];
                        int color = (byte) (num > 255 ? 255 : num) & 0xFF;
                        for (int i = 0; i < CELL_LENGTH; i++) {
                            for (int j = 0; j < CELL_LENGTH; j++) {
                                writer.setColor((x * CELL_LENGTH + i), (y * CELL_LENGTH + j), Color.grayRgb(color));
                            }
                        }
                    }
                }
            });````
cedar tigerBOT
# grand garnet ```java PixelWriter writer = canvas.getGraphicsContext2D() ...

Detected code, here are some useful tools:

Formatted code
PixelWriter writer = canvas.getGraphicsContext2D().getPixelWriter();
for (int y = 0; y < fluid.HEIGHT; y++) {
  for (int x = 0; x < fluid.WIDTH; x++) {
    double num = fluid.dens[fluid.index(x, y) ] ;
    int color = (byte ) (num > 255 ? 255 : num) & 0xFF;
    for (int i = 0; i < CELL_LENGTH; i++) {
      for (int j = 0; j < CELL_LENGTH; j++) {
        writer.setColor((x * CELL_LENGTH + i), (y * CELL_LENGTH + j), Color.grayRgb(color));
      }
    }
  }
}
}
);
grand garnet
#

problem is defo here

#

OKay

#

cell length = 1, time = 25 secs

#

ran smoothly

#

okay not bad for 25 seconds

#

now

#

cell length = 2, time = 26 secs

#

did not run smoothly

#

only saw 2 frames out of 1000+

#

as you can see, the fluid calculation times are roughly the same but the writing takes a lot longer

steep elbow
#

use a buffer or squid solution

grand garnet
#

and writing takes up more GB

steep elbow
#

and don't make the fps as fast as the tps

grand garnet
grand garnet
steep elbow
grand garnet
steep elbow
#

and don't make the fps as fast as the tps

grand garnet
#

yeah ok

grand garnet
#

and that's if my current deltaTime is less than the max delta time?

steep elbow
#

you always have time

#

sicne you do a copy

#

wait

#

you don't

#

then it's wrong

#

you are not copying the array

#

also didn't you said you were using squid solution ?

#

then why are you using runlater ?

boreal socket
#

I shared two solutions

#

one with animation timer

#

and one threaded

#

both works

#

check pins

#

but he changed some stuff and now it doesnt work

grand garnet
#

im lost now

#
@Override
    public void run() {
        Fluid fluid = new BoxFluid(IMAGE_WIDTH / CELL_LENGTH, IMAGE_HEIGHT / CELL_LENGTH, CELL_LENGTH, 2, 2, 4);

        long current = System.nanoTime();
        while (true) {
            long l = System.nanoTime();
            double deltaMillis = (l - current) / 1_000_000_000.0;
            fluid.step(deltaMillis);

            Platform.runLater(() -> {
                addSourcesFromUI(fluid);
                PixelWriter writer = canvas.getGraphicsContext2D()
                        .getPixelWriter();

                for (int y = 0; y < fluid.HEIGHT; y++) {
                    for (int x = 0; x < fluid.WIDTH; x++) {
                        double num = fluid.dens[fluid.index(x, y)];
                        int color = (byte) (num > 255 ? 255 : num) & 0xFF;
                        for (int i = 0; i < CELL_LENGTH; i++) {
                            for (int j = 0; j < CELL_LENGTH; j++) {
                                writer.setColor((x * CELL_LENGTH + i), (y * CELL_LENGTH + j), Color.grayRgb(color));
                            }
                        }
                    }
                }
            });

            current = l;
        }
    }```
cedar tigerBOT
grand garnet
#

what's the usual way to make this into a loop where I limit the TPS and can vary the FPS?

steep elbow
#

and not eonly that

grand garnet
#

zabu showed me one a long time ago for a fractal algorithm and that's the one i use in awt 😭

steep elbow
#

but you shouldn't share fluid to the code in runlater

#

you can only work with code that won't be modified

grand garnet
#

oh

#

so i should be using that clone stuff ok

grand garnet
#

time for the buffering stuff

#

thing is

#

i have a duplicated code fragment becuase I can't make a specific class in the fluid static

#

it's this method java public int index(int i, int j) { if (i < 0) { i = 0; } if (i > FLUID_WIDTH + 1) { i = FLUID_WIDTH + 1; } if (j < 0) { j = 0; } if (j > FLUID_HEIGHT + 1) { j = FLUID_HEIGHT + 1; } return (i + j * (FLUID_WIDTH + 2)); }

cedar tigerBOT
grand garnet
#

im not sure if i should leave it duplicated or what 😭

cedar tigerBOT
#

@grand garnet

Your question has been closed due to inactivity.

If it was not resolved yet, feel free to just post a message below
to reopen it, or create a new thread.

Note that usually the reason for nobody calling back is that your
question may have been not well asked and hence no one felt confident
enough answering.

When you reopen the thread, try to use your time to improve the quality
of the question by elaborating, providing details, context, all relevant code
snippets, any errors you are getting, concrete examples and perhaps also some
screenshots. Share your attempt, explain the expected results and compare
them to the current results.

Also try to make the information easily accessible by sharing code
or assignment descriptions directly on Discord, not behind a link or
PDF-file; provide some guidance for long code snippets and ensure
the code is well formatted and has syntax highlighting. Kindly read through
https://stackoverflow.com/help/how-to-ask for more.

With enough info, someone knows the answer for sure πŸ‘

grand garnet
#

.

grand garnet
#

@steep elbow I'm quite unsure on what to put for the parameters here

#

writer.setPixels(0,0,IMAGE_WIDTH, IMAGE_HEIGHT, ..., buffer, 0, IMAGE_WIDTH);

#

I checked docs and saw something about PixelFormat but I was quite unsure on what one to use

#

ok i think i did it but it doeswn't seem to be rendering

#
public void render(double[] dens) {
        int[] buffer = new int[IMAGE_HEIGHT * IMAGE_WIDTH];
        int bufferIndex = 0;

        for (int y = 0; y < FLUID_HEIGHT; y++) {
            for (int x = 0; x < FLUID_WIDTH; x++) {
                double num = dens[index(x, y)];
                int color = (int) (num > 255 ? 255 : num) & 0xFF;
                int rgb = (color << 16) | (color << 8) | color;
                for (int i = 0; i < CELL_LENGTH; i++) {
                    for (int j = 0; j < CELL_LENGTH; j++) {
                        buffer[bufferIndex++] = rgb;
                    }
                }
            }
        }

        PixelWriter writer = canvas.getGraphicsContext2D()
                .getPixelWriter();
        writer.setPixels(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, PixelFormat.getIntArgbInstance(), buffer, 0, IMAGE_WIDTH);

    }
cedar tigerBOT
grand garnet
#

ok this sounds weird

#

i fixed everything using the buffer

#

like it works

#

I still haven't done the variable FPS yet

#

but my program renders better without runLater than with it lmao

grand garnet
#

any idea on how i can implement a varaible delta time loop?

dense hare
dense hare
boreal socket
#

and its something you wouldnt want in javafx

#

instead you would use AnimationTimer which automatically runs handle on the fx thread

boreal socket
cedar tigerBOT
#

@grand garnet

Your question has been closed due to inactivity.

If it was not resolved yet, feel free to just post a message below
to reopen it, or create a new thread.

Note that usually the reason for nobody calling back is that your
question may have been not well asked and hence no one felt confident
enough answering.

When you reopen the thread, try to use your time to improve the quality
of the question by elaborating, providing details, context, all relevant code
snippets, any errors you are getting, concrete examples and perhaps also some
screenshots. Share your attempt, explain the expected results and compare
them to the current results.

Also try to make the information easily accessible by sharing code
or assignment descriptions directly on Discord, not behind a link or
PDF-file; provide some guidance for long code snippets and ensure
the code is well formatted and has syntax highlighting. Kindly read through
https://stackoverflow.com/help/how-to-ask for more.

With enough info, someone knows the answer for sure πŸ‘

grand garnet
#

How can i stop like a thread?

steep elbow
grand garnet
#

well one thing

#

i have this:

viscositySlider.valueProperty()
                .addListener((obs, oldVal, newVal) -> {
                    viscosity = ExtraMath.roundToTwoDecimalPlaces(viscositySlider.getValue());
                    viscosityLabel.setText("Viscosity: " + viscosity);
                    simulation.setViscosity(viscosity);
                });
        flowspeedSlider.valueProperty()
                .addListener((obs, oldVal, newVal) -> {
                    flowspeed = ExtraMath.roundToTwoDecimalPlaces(flowspeedSlider.getValue());
                    flowspeedLabel.setText("Flow Speed: " + flowspeed);
                    simulation.setDiffusionRate(flowspeed);
                });```
#

and once i start the simulation, I want to stop this listening from happening

#

idk how to do that

#

and then with this:

@FXML
    private void onStartSimulationClick() {
        if (!simulationStarted) {
            viscositySlider = new Slider();
            flowspeedSlider = new Slider();
            EXECUTOR.submit(simulation);
            startSimulationButton.setText("Pause Simulation");
            simulationStarted = true;
        } else {
            Fluid fluid = simulation.getFluid();
            EXECUTOR.shutdown();
            createListeners();
            startSimulationButton.setText("Start Simulation");
        }
    }```
cedar tigerBOT
grand garnet
#

I don't think Executor.shutdown() stops the thread from running (stops the simulation)

boreal socket
#

store the Future

#

created by EXECUTOR.submit

grand garnet
#

wait what

grand garnet
#

idk how to do that lmoa

#

theres no method

boreal socket
#

call removeListener

boreal socket
grand garnet
#

I just did this intead:

viscositySlider = new Slider();
            flowspeedSlider = new Slider();```
boreal socket
#

just checked

boreal socket
#

store that in a field variable

boreal socket
#

no

grand garnet
#

oh

#

😭

boreal socket
#

so that you can later use that variable

#

these are the methods of Future<?>

#

just use the cancel method to stop the runnable

grand garnet
#

why is it red

boreal socket
#

because it needs arguments

#

you need to store the instance you gave it before

steep elbow
#

@grand garnet just toggle the variable which is in your while condition

boreal socket
#

so that you can pass it again to remove it

boreal socket
#

makes more sense in this context ig peepo_think

grand garnet
#

but what if i want to carry on the simulation

boreal socket
#

wdym

grand garnet
#

like if i stop the while loop

#

what if i want to carry it on

boreal socket
#

ah you want a pause mechanism?

#

you need both anyways

#

but you would need to create some pause mechanism yourself

#

in the runnable class

#

you have two different scenarios:

  • stop the simulation -> Future#cancel
  • pause the simulation -> exit the loop, therefore the runnable exits, but keep the stored state of Fluid.java, then resubmit once you want to continue
#

you can exit the loop by creating some boolean state that you change in your controller

#

simple as that

grand garnet
#

ahhh

#

yeahh

#

i get that

grand garnet
boreal socket
#

you dont need that if you do the suggestion by ala

#

you dont need to remove the listener if you just disable the sliding

#

which even makes more sense here

#

because the user shouldnt be able to change the settings if they have no effects while the simulation runs

grand garnet
boreal socket
#

isnt it in the same scene? therefore in the same controller?

#

I am not here to guess

#

give more context

grand garnet
#

yeah but the runnable isn't in the controller

boreal socket
#

wut
why would you need the runnable

#

you control all that through the controller

grand garnet
#

yeah

boreal socket
#

the runnable is getting started inside the controller as well

#

why would the runnable need to know about the slider in the first place?

grand garnet
#

i don't want the slider to interfere with the runnable

boreal socket
#

exactly

grand garnet
#

which is why i need to stop the sliding mechanism when the runnable is about to start and start the sliding when it has stopped

boreal socket
#

then I have one question

grand garnet
#

yea

boreal socket
#
@FXML
    private void onStartSimulationClick() {
        if (!simulationStarted) {
            viscositySlider = new Slider();
            flowspeedSlider = new Slider();
            EXECUTOR.submit(simulation);
            startSimulationButton.setText("Pause Simulation");
            simulationStarted = true;
        } else {
            Fluid fluid = simulation.getFluid();
            EXECUTOR.shutdown();
            createListeners();
            startSimulationButton.setText("Start Simulation");
        }
    }

you create the slider at the same time someone starts the simulation, wouldnt they need to exist before?
and also you can easily disable them here in this method

grand garnet
#

you create the slider at the same time someone starts the simulation, wouldnt they need to exist before?
I don't want that i just thought it would remove the listening lol

boreal socket
#

lol

#

but yeah

#

you can easily manage the slider in that method

grand garnet
#

yeahh

boreal socket
#

it also manages when the runnable starts and pauses

grand garnet
#

looks kinda cool

boreal socket
#

yea

grand garnet
#

I think i am going to remove flowlines though

boreal socket
#

your simulation

#

your choice

grand garnet
#

yeahh

#

it would be a bit too long

boreal socket
#

but it seems like you got a check button for it though

grand garnet
#

yep

#

how do i store the listener so i can remove it?

boreal socket
#

you dont need to

grand garnet
#

oh

boreal socket
#

just do ala's suggestion

#

disable it

#

if the simulation is running

boreal socket
#

and enable it again if it gets paused

#

yes

grand garnet
#

ohh so i would change this:

private void createListeners() {
        viscositySlider.valueProperty()
                .addListener((obs, oldVal, newVal) -> {
                    viscosity = ExtraMath.roundToTwoDecimalPlaces(viscositySlider.getValue());
                    viscosityLabel.setText("Viscosity: " + viscosity);
                    simulation.setViscosity(viscosity);
                });
        flowspeedSlider.valueProperty()
                .addListener((obs, oldVal, newVal) -> {
                    flowspeed = ExtraMath.roundToTwoDecimalPlaces(flowspeedSlider.getValue());
                    flowspeedLabel.setText("Flow Speed: " + flowspeed);
                    simulation.setDiffusionRate(flowspeed);
                });
    }```

into this:

```java
private void createListeners() {
        viscositySlider.valueProperty()
                .addListener((obs, oldVal, newVal) -> {
                    if (viscosityListening) {
                        viscosity = ExtraMath.roundToTwoDecimalPlaces(viscositySlider.getValue());
                        viscosityLabel.setText("Viscosity: " + viscosity);
                        simulation.setViscosity(viscosity);
                    }
                });
        flowspeedSlider.valueProperty()
                .addListener((obs, oldVal, newVal) -> {
                    if (flowspeedListening) {
                        flowspeed = ExtraMath.roundToTwoDecimalPlaces(flowspeedSlider.getValue());
                        flowspeedLabel.setText("Flow Speed: " + flowspeed);
                        simulation.setDiffusionRate(flowspeed);
                    }
                });
    }```
cedar tigerBOT
boreal socket
#

no

#

you keep your old listener

#

and just disable the slider itself

#

there is a method for that

#

you can disable some node in javafx

#

it will still be there

#

but it cant be used

#

in this case the user cant slide while its disabled

grand garnet
#

I can't find it 😭

boreal socket
#

i can

#

lol

grand garnet
#

is it blockIncrementProperty?

boreal socket
#

setDisabled

grand garnet
#

ohhh

boreal socket
#

nvm

#

its setDisable

#

they both have different use cases

grand garnet
#

yeahh

#

got that

boreal socket
#

both exist actually

boreal socket
#

so you wont be able to use it anyways

cedar tigerBOT
#

@grand garnet

Your question has been closed due to inactivity.

If it was not resolved yet, feel free to just post a message below
to reopen it, or create a new thread.

Note that usually the reason for nobody calling back is that your
question may have been not well asked and hence no one felt confident
enough answering.

When you reopen the thread, try to use your time to improve the quality
of the question by elaborating, providing details, context, all relevant code
snippets, any errors you are getting, concrete examples and perhaps also some
screenshots. Share your attempt, explain the expected results and compare
them to the current results.

Also try to make the information easily accessible by sharing code
or assignment descriptions directly on Discord, not behind a link or
PDF-file; provide some guidance for long code snippets and ensure
the code is well formatted and has syntax highlighting. Kindly read through
https://stackoverflow.com/help/how-to-ask for more.

With enough info, someone knows the answer for sure πŸ‘

grand garnet
#

if anyone wants to see how the project is doing you can always check master3

#

it's not bad

#

quite a few bugs but i'll fix them soon

boreal socket
#

you should give your branches better names

#

not master, master2, master3

grand garnet
#

yeah i couldn't be bothered about it lol

#

im a very lazy guy

boreal socket
#

I could give you a code review of your current state if you want

grand garnet
#

hmm

#

sure 😭

#

if you can, is it possible if you can ping me once you finish all the feedback and stuff?

#

i don't wanna get too distracted that's why

boreal socket
#

yeah all good

#

going to take a while anyways

#

ok so I should ignore bugs right?

#

because after pausing the simulation I cant restart it

#

Code Review

#

/resources

  • dont just put everything inside it, structure it, one extra folder for fxml files, one folder for css
grand garnet
boreal socket
#

com.fluidity.program.utilities

  • might name the package just util, but thats just minor

CircularLinkedList.java

  • remove unused imports
  • use varargs for constructor instead of array

ExtraMath.java

  • remove unused imports
  • might come up with a better class name
  • add private constructor for static helper classes

FileHandler.java

  • make logger final
  • writeLine() is supposed to append right? in that case its missing the OpenOption for that

LinkedListNode.java

  • why final in the constructor parameters?

Queue.java

  • empty class? probably work in progress ig
dense hare
boreal socket
#

com.fluidity.program.ui

ProgramState.java

  • pls give this enum finally a better name LUL
  • use javadocs instead of normal comments

MouseListener.java

  • why does this interface defines the consumeSources method? it doesnt fit imo, its not common to all MouseListener

Manager.java

  • use javadocs instead of normal comments
  • why final for the constructor parameter?
  • might make the title a static constant?
  • why window.show() being used in the loadScene?

GraphicsHandler.java

  • dont use Integer[], always prefer primitive
  • make the fpsValues, cellSizeValues, iterationsValues static constants instead
  • also why is this called GraphicsHandler? isnt it related to the settings instead?

FluidUIAction.java

  • as said before, instead of having a single enum value for primary and secondary just combine them into one enum? might be a bad idea based on context
  • give the IllegalArgumentException a custom exception message
boreal socket
#

com.fluidity.program.ui.controllers

  • might rename package to controller instead

MainMenuController.java

  • its overriding the initialize method, but its empty, do that in the Controller abstract class instead

ExitController.java

  • its overriding the initialize method, but its empty, do that in the Controller abstract class instead

AboutController.java

  • its overriding the initialize method, but its empty, do that in the Controller abstract class instead

RecordingsController.java

  • its overriding the initialize method, but its empty, do that in the Controller abstract class instead

SettingsController.java

  • rearrange the fields, statics first
  • make graphicsHandler private
  • the constant configPath is not used in Fluidity.java, why?
  • use appropriate class for primaryButtonColor/secondaryButtonColor, dont use String for it
  • instead of keyBindMap/buttonMap create a custom utility class for configuration that stores all that stuff, also use java.util.Properties as said before
  • I dont like that there is a switch in the try - catch in loadConfigurations

SimulationController.java

  • canvasX, why the X in the name?
  • some fields are not used at all
  • might create some simulation logic class for handling all the properties of the simulation (viscosity, sourceQueue, ...), doing this will remove a lot of fields
  • previousCoords should not be an int[] array, instead use some Point class or smth which actually represents whats getting stored

TestSimulationController.java

  • skipping this, seems to get deleted later anyways
#

com.fluidity.program.simulation

SimulationThreaded.java

  • check naming convention for the fields and constructor parameter
  • your run method needs a revamp, dont use Thread.sleep here, your logic for the fps/tps stuff is bad and would do it differently
  • index is a duplicate method
  • render can get some benefits

FluidInput.java

  • why not using records?

com.fluidity.program.simulation.fluid

Fluid.java

  • I wont check the full calculation and stuff, but:
  • fix naming convention
  • for nested loop start with height loop first
  • try to fix the memory "issues" here, I doubt you always need to create multiple double arrays each step

BoxFluid.java

  • fix naming convention
  • implement setBarriers

TunnelFluid.java

  • fix naming convention
  • implement setBarriers
#

@grand garnet

grand garnet
#

yess tysmm

grand garnet
cedar tigerBOT
#

The naming convention in Java is as follows:

Classes:
PascalCase. Example: GoldMiner, FoodDestroyer, DispenserBuilder

Methods / Fields / Variables:
camelCase. Example: foodAmount, integerValue, goodBoyAsADog

Packages:
All lowercase. Preferably the domain name backwards. Example: "google.com" ==> com.google, "ialistannen.me" ==> me.ialistannen
Followed by the project name. Example: Project "Builder" ==> com.google.builder

Constants/Enum entries:
UPPER_SNAKE_CASE. Where words are separated by underscores. Example: RED_DOG, I_AM_THE_BEST, CONQUER_WORLD

cedar tigerBOT
#

@grand garnet

Your question has been closed due to inactivity.

If it was not resolved yet, feel free to just post a message below
to reopen it, or create a new thread.

Note that usually the reason for nobody calling back is that your
question may have been not well asked and hence no one felt confident
enough answering.

When you reopen the thread, try to use your time to improve the quality
of the question by elaborating, providing details, context, all relevant code
snippets, any errors you are getting, concrete examples and perhaps also some
screenshots. Share your attempt, explain the expected results and compare
them to the current results.

Also try to make the information easily accessible by sharing code
or assignment descriptions directly on Discord, not behind a link or
PDF-file; provide some guidance for long code snippets and ensure
the code is well formatted and has syntax highlighting. Kindly read through
https://stackoverflow.com/help/how-to-ask for more.

With enough info, someone knows the answer for sure πŸ‘

grand garnet
#

.

#

Looking good

#

need to make sure the pause button actually pauses the simulation rather than ending it fully 😭

boreal socket
grand garnet
#

it's very cool cos the different pieces of the simulation i made are coming together

grand garnet
#

i don't want to look through your review yet because i don't wanna get distracted

boreal socket
grand garnet
#

yeah

boreal socket
#

you remember the Future<?> stuff I talked about before?

grand garnet
#

to do with the executor thing?

boreal socket
#

yea

#

which is starting your simulation

grand garnet
#

yeah

boreal socket
#

ok which exact point is starting your simulation? do you know?

grand garnet
#

hmm this right?

#

EXECUTOR.submit(simulation);

boreal socket
grand garnet
#

yay

boreal socket
#

do you know what that method returns

grand garnet
#

a boolean?

boreal socket
#

no

#

look it up

grand garnet
#

oooh

boreal socket
#

this is your Future<?> which stores and represents the current state of this task (runnable) submitted in that line

#

store it in a field

#

so you can later refer to it again

grand garnet
#

ooh ok

#

what is the generic

#

<?>

boreal socket
#

thats a generic wildcard

#

its used to refer to an unknown type

#

you dont need it here anyways

grand garnet
#

ahh

#

similar to wildcards in databases oooo

boreal socket
#

you use just a Runnable which means that you dont have some "result"

#

other scenarios might have some result that get available after the task is finished

#

like some computation

#

but you dont have that

grand garnet
#

oh

#

so i store the future

boreal socket
#

yeah

grand garnet
#

and whenever i need to return to it

#

i do Future.submit()?

boreal socket
#

no

#

if you want to pause the simulation you actually use Future#cancel

#

and if you want to start/restart the simulation you just call submit again, which creates a new future which you again store

#

if you keep the same SimulationThreaded instance its going to have the same state and continue at the point it stopped
as long as you dont change the internal Fluid instance

grand garnet
#

yeah ok that's fine then

grand garnet
#

it's not rlly pausing lmao

#

it carries on simulating

grand garnet
boreal socket
#

why would you want that?

grand garnet
#

like if i want to change the viscosity of the fluid after pausing it

boreal socket
boreal socket
#

just update the existing one

grand garnet
#

yeah i am

#

ohh

#

i thought u mean just updating the current instance

grand garnet
boreal socket
#

share the code

grand garnet
#
    private void startSimulation() {
        viscositySlider.setDisable(true);
        diffusionRateSlider.setDisable(true);
        simulationFuture = EXECUTOR.submit(simulation);
        startSimulationButton.setText("Pause Simulation");
        simulationStarted = true;
    }

    private void endSimulation() {
        viscositySlider.setDisable(false);
        diffusionRateSlider.setDisable(false);
        simulationFuture.cancel(true);
        createListeners();
        startSimulationButton.setText("Start Simulation");
    }```