Advertisement
MrMusAddict

Erosion Simulator in Processing IDE

Sep 4th, 2022
1,152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 16.13 KB | None | 0 0
  1. import peasy.*;
  2.  
  3. float tileSize = 5;
  4. int worldWidth;
  5. int worldLength;
  6. float waterInCloud;
  7. boolean raining;
  8.  
  9. ArrayList<Tile> tiles;
  10.  
  11. PeasyCam cam;
  12.  
  13. long bNoise;
  14. long pNoise;
  15. long sNoise;
  16. long tNoise;
  17. long oNoise;
  18.  
  19.  
  20.  
  21. void setup() {
  22.   fullScreen(P3D);
  23.   initUI();
  24.   generate();
  25.  
  26.   float cameraZ = ((height/2.0) / tan(PI*60.0/360.0));
  27.   perspective(PI/3.0, (width/1.0)/(height/1.0), 0.1, cameraZ*10.0);
  28.  
  29.   cam = new PeasyCam(this, 500);
  30.   cam.lookAt(worldWidth*tileSize/2.0, 0, worldLength*tileSize/2.0);
  31.   cam.setDistance(1000);
  32.   cam.setMinimumDistance(-100);
  33.   cam.setRotations(cam.getRotations()[0], 0, 0);
  34.  
  35.   worldWidth = 100;
  36.   worldLength = 10;
  37. }
  38.  
  39. void draw() {
  40.   translate(width/2 - ((worldWidth*tileSize)/2.0), height/2 +((worldLength*tileSize)/2.0), 0);
  41.   translate(0, ((worldLength*tileSize)/2.0), 0);
  42.   cam.setRotations(cam.getRotations()[0], cam.getRotations()[1], cam.getRotations()[2]);
  43.  
  44.   if (!raining) {
  45.     if (waterInCloud >= worldWidth*worldLength*6) {
  46.       raining = true;
  47.     }
  48.   }
  49.   for (Tile t : tiles) {
  50.     t.move();
  51.   }
  52.   background(200);
  53.   lights();
  54.   for (Tile t : tiles) {
  55.     t.show();
  56.   }
  57.   for (Tile t : tiles) {
  58.     t.calculate();
  59.   }
  60.  
  61.   cam.setActive(true);
  62.   showUI();
  63.   dragging = false;
  64. }
  65.  
  66. void generate() {
  67.   worldWidth = int(wWidth.value);
  68.   worldLength = int(wDepth.value);
  69.   rainfallRate = new Slider(0.01, wWidth.value*wDepth.value*6, wWidth.value*wDepth.value*6/500.0, width/4.0, height/40.0, width/4.0, height/40.0*38.0, true, "Rainfall Rate", false);
  70.  
  71.   bNoise = int(random(1000000));
  72.   pNoise = int(random(1000000));
  73.   sNoise = int(random(1000000));
  74.   tNoise = int(random(1000000));
  75.   oNoise = int(random(1000000));
  76.  
  77.   waterInCloud = worldWidth*worldLength*8;
  78.  
  79.   tiles = new ArrayList<Tile>();
  80.  
  81.   for (int i = 0; i < worldWidth; i++) {
  82.     for (int j = 0; j < worldLength; j++) {
  83.       noiseSeed(bNoise);
  84.       float bn = noise(i/20.0, j/20.0)*200*tileSize/2.0;
  85.       noiseSeed(pNoise);
  86.       float pn = noise(i/10.0, j/10.0)*50*tileSize/3.0;
  87.       noiseSeed(sNoise);
  88.       float sn = noise(i/5.0, j/5.0)*25*tileSize/4.0;
  89.       noiseSeed(tNoise);
  90.       float tn = noise(i/2.5, j/2.5)*12.5*tileSize/5.0;
  91.       noiseSeed(oNoise);
  92.       float on = noise(i/1.25, j/1.25)*6.25*tileSize/6.0;
  93.  
  94.       tiles.add(new Tile(i, j, bn, pn, sn, tn, on));
  95.     }
  96.   }
  97. }
  98. boolean toggle = false;
  99. boolean dragging;
  100.  
  101. float angleX = 0;
  102. float angleY = 0;
  103.  
  104. void keyPressed() {
  105.   if (key == 'w' || key == 'W') {
  106.     toggle = !toggle;
  107.   }
  108.   if (keyCode == ENTER) {
  109.     generate();
  110.   }
  111. }
  112.  
  113. void mouseDragged() {
  114.   dragging = true;
  115. }
  116. Tile getLowestWaterNeighbor(Tile t) {
  117.   Tile temp = t;
  118.   float minHeight = 100000;
  119.  
  120.   for (Tile ts : tiles) {
  121.     if ((ts.x == t.x-1 && ts.y == t.y)
  122.       || (ts.x == t.x+1 && ts.y == t.y)
  123.       || (ts.x == t.x && ts.y == t.y-1)
  124.       || (ts.x == t.x && ts.y == t.y+1)
  125.       || (ts.x == t.x && ts.y == t.y)) {
  126.       if (ts.totalHeightWithWater() < minHeight) {
  127.         minHeight = ts.totalHeightWithWater();
  128.         temp = ts;
  129.       }
  130.     }
  131.   }
  132.  
  133.   return temp;
  134. }
  135.  
  136. Tile getLowestLandNeighbor(Tile t) {
  137.   Tile temp = null;
  138.   float minHeight = 100000;
  139.  
  140.   for (Tile ts : tiles) {
  141.     if (ts.x >= t.x-1 && ts.x <= t.x+1 && ts.y >= t.y-1 && ts.y <= t.y+1) {
  142.       if (ts.totalHeightWithOutWater() < minHeight) {
  143.         minHeight = ts.totalHeightWithOutWater();
  144.         temp = ts;
  145.       }
  146.     }
  147.   }
  148.  
  149.   return temp;
  150. }
  151.  
  152. float log10(float x) {
  153.   return (log(x) / log(10));
  154. }
  155. class Tile {
  156.   int x;
  157.   int y;
  158.  
  159.   float sBedrock;
  160.   float sParentrock;
  161.   float sSubsoil;
  162.   float sTopsoil;
  163.   float sOrganic;
  164.  
  165.   float tBedrock;
  166.   float tParentrock;
  167.   float tSubsoil;
  168.   float tTopsoil;
  169.   float tOrganic;
  170.  
  171.   float bedrock;
  172.   float parentrock;
  173.   float subsoil;
  174.   float topsoil;
  175.   float organic;
  176.   float water;
  177.  
  178.   float waterToAdd;
  179.   float waterToSubtract;
  180.   float organicToAdd;
  181.   float organicToSubtract;
  182.   float topsoilToAdd;
  183.   float topsoilToSubtract;
  184.   float subsoilToAdd;
  185.   float subsoilToSubtract;
  186.   float parentrockToAdd;
  187.   float parentrockToSubtract;
  188.  
  189.   Tile(int x_, int y_, float b_, float p_, float s_, float t_, float o_) {
  190.     x=x_;
  191.     y=y_;
  192.     sBedrock = b_;
  193.     sParentrock = p_;
  194.     sSubsoil = s_;
  195.     sTopsoil = t_;
  196.     sOrganic = o_;
  197.     bedrock = b_;
  198.     parentrock = p_;
  199.     subsoil = s_;
  200.     topsoil = t_;
  201.     organic = o_;
  202.     water = 0;
  203.   }
  204.  
  205.   void show() {
  206.     float cumulativeTranslation = 0;
  207.     noStroke();
  208.  
  209.  
  210.  
  211.  
  212.  
  213.     translate(x*tileSize, 0, y*tileSize);
  214.     translate(0, -bedrock/2, 0);
  215.     cumulativeTranslation += -bedrock/2;
  216.  
  217.     if (bedrock > 0) {
  218.       fill(80, 80, 80);
  219.       box(tileSize, bedrock, tileSize);
  220.     }
  221.  
  222.  
  223.     translate(0, -bedrock/2-parentrock/2, 0);
  224.     cumulativeTranslation += -bedrock/2-parentrock/2;
  225.     if (parentrock > 0) {
  226.       fill(120, 120, 120);
  227.       box(tileSize, parentrock, tileSize);
  228.     }
  229.  
  230.  
  231.     translate(0, -parentrock/2-subsoil/2, 0);
  232.     cumulativeTranslation += -parentrock/2-subsoil/2;
  233.     if (subsoil > 0) {
  234.       fill(172, 107, 83);
  235.       box(tileSize, subsoil, tileSize);
  236.     }
  237.  
  238.  
  239.     translate(0, -subsoil/2-topsoil/2, 0);
  240.     cumulativeTranslation += -subsoil/2-topsoil/2;
  241.     if (topsoil > 0) {
  242.       fill(118, 96, 83);
  243.       box(tileSize, topsoil, tileSize);
  244.     }
  245.  
  246.  
  247.     translate(0, -topsoil/2-organic/2, 0);
  248.     cumulativeTranslation += -topsoil/2-organic/2;
  249.     if (organic > 0) {
  250.       fill(108, 147, 92);
  251.       box(tileSize, organic, tileSize);
  252.     }
  253.  
  254.  
  255.     translate(0, -organic/2-water/2, 0);
  256.     cumulativeTranslation += -organic/2-water/2;
  257.     if (water > 0) {
  258.       fill(100, 200, 255, 100);
  259.       box(tileSize, -water, tileSize);
  260.     }
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.     translate(x*-tileSize, -cumulativeTranslation, y*-tileSize);
  268.   }
  269.  
  270.   float totalHeightWithWater() {
  271.     return  bedrock + parentrock + subsoil + topsoil + organic + water;
  272.   }
  273.   float totalHeightWithOutWater() {
  274.     return  bedrock + parentrock + subsoil + topsoil + organic;
  275.   }
  276.  
  277.   void calculate() {
  278.     //if (!center) {
  279.     //  if (toggle) {
  280.     //    if (intermittent) {
  281.     //      if (frameCount % 100 < 25) {
  282.     //        if (random(worldWidth*worldLength) < worldWidth*worldLength/5.0) {
  283.     //          water += 1;
  284.     //        }
  285.     //      }
  286.     //    } else {
  287.     //      if (random(worldWidth*worldLength) < worldWidth*worldLength/5.0) {
  288.     //        water += 1;
  289.     //      }
  290.     //    }
  291.     //  }
  292.     //} else {
  293.     //  if (x == worldWidth/2 && y == worldLength/2) {
  294.     //    water += 5;
  295.     //  }
  296.     //}
  297.  
  298.     if (toggle) {
  299.       if (raining) {
  300.         if (random(worldWidth*worldLength) < worldWidth*worldLength/100.0) {
  301.           float deduct = min(waterInCloud, rainfallRate.value);
  302.           water += deduct;
  303.           waterInCloud -= deduct;
  304.           if (waterInCloud == 0) {
  305.             raining = false;
  306.           }
  307.         }
  308.       }
  309.     }
  310.  
  311.  
  312.     Tile temp = getLowestWaterNeighbor(this);
  313.  
  314.     float movingWater = min(5, water, (totalHeightWithWater()-temp.totalHeightWithWater())/2.0);
  315.     temp.waterToAdd += movingWater;
  316.     waterToSubtract -= movingWater;
  317.  
  318.     if (temp.totalHeightWithOutWater() < totalHeightWithOutWater()) {
  319.       float movingLand = min(movingWater, (totalHeightWithOutWater()-temp.totalHeightWithOutWater())/2.0);
  320.  
  321.       float oVal = constrain(4*erosionRate.value, 0, 4);
  322.       float tVal = constrain(2*erosionRate.value, 0, 4);
  323.       float sVal = constrain(1*erosionRate.value, 0, 4);
  324.       float pVal = constrain(0.5*erosionRate.value, 0, 4);
  325.  
  326.       float movingOrganic = min(oVal, organic, movingLand/(5/oVal));
  327.       movingLand = max(movingLand - movingOrganic*(5/oVal), 0);
  328.       temp.organicToAdd += movingOrganic;
  329.       organicToSubtract -= movingOrganic;
  330.  
  331.       float movingTopSoil = min(tVal, topsoil, movingLand/(5/tVal));
  332.       movingLand = max(movingLand - movingTopSoil*(5/tVal), 0);
  333.       temp.topsoilToAdd += movingTopSoil;
  334.       topsoilToSubtract -= movingTopSoil;
  335.  
  336.       float movingSubSoil = min(sVal, subsoil, movingLand/(5/sVal));
  337.       movingLand = max(movingLand - movingSubSoil*(5/sVal), 0);
  338.       temp.subsoilToAdd += movingSubSoil;
  339.       subsoilToSubtract -= movingSubSoil;
  340.  
  341.       float movingParentRock = min(pVal, parentrock, movingLand/(5/pVal));
  342.       movingLand = max(movingLand - movingParentRock*(5/pVal), 0);
  343.       temp.parentrockToAdd += movingParentRock;
  344.       parentrockToSubtract -= movingParentRock;
  345.     }
  346.   }
  347.  
  348.   void move() {
  349.     water += waterToAdd + waterToSubtract;
  350.     float evaporate = min(water, evaporationRate.value);
  351.     water -= evaporate;
  352.     waterInCloud += evaporate;
  353.  
  354.     organic += organicToAdd + organicToSubtract;
  355.     topsoil += topsoilToAdd + topsoilToSubtract;
  356.     subsoil += subsoilToAdd + subsoilToSubtract;
  357.     parentrock += parentrockToAdd + parentrockToSubtract;
  358.  
  359.  
  360.     waterToAdd = 0;
  361.     waterToSubtract = 0;
  362.     organicToAdd = 0;
  363.     organicToSubtract = 0;
  364.     topsoilToAdd = 0;
  365.     topsoilToSubtract = 0;
  366.     subsoilToAdd = 0;
  367.     subsoilToSubtract = 0;
  368.     parentrockToAdd = 0;
  369.     parentrockToSubtract = 0;
  370.  
  371.     if (water == 0) {
  372.       adjustLayerDry();
  373.     } else {
  374.       adjustLayerWet();
  375.     }
  376.   }
  377.  
  378.   void adjustLayerDry() {
  379.     float cTotal = parentrock + subsoil + topsoil + organic;
  380.  
  381.     if (cTotal > 0) {
  382.       float oTotal = sParentrock + sSubsoil + sTopsoil + sOrganic;
  383.       //float tbP = sBedrock / oTotal;
  384.       float tpP = sParentrock / oTotal;
  385.       float tsP = sSubsoil / oTotal;
  386.       float ttP = sTopsoil / oTotal;
  387.       float toP = sOrganic / oTotal;
  388.  
  389.  
  390.  
  391.       //float cB = (bedrock / (totalHeightWithOutWater()-bedrock));
  392.       float cP = parentrock / cTotal;
  393.       float cS = subsoil / cTotal;
  394.       float cT = topsoil / cTotal;
  395.       float cO = organic / cTotal;
  396.  
  397.       //bedrock = (cB + (tbP-cB) * 0.01) * (totalHeightWithOutWater()-bedrock);
  398.       parentrock = (cP + (tpP-cP) * 0.001) * cTotal;
  399.       subsoil = (cS + (tsP-cS) * 0.001) * cTotal;
  400.       topsoil = (cT + (ttP-cT) * 0.001) * cTotal;
  401.       organic = (cO + (toP-cO) * 0.001) * cTotal;
  402.     }
  403.   }
  404.   void adjustLayerWet() {
  405.     float cTotal = parentrock + subsoil + topsoil + organic;
  406.  
  407.     if (cTotal > 0) {
  408.       float oTotal = sParentrock + sSubsoil + sTopsoil;
  409.       //float tbP = sBedrock / oTotal;
  410.       float tpP = sParentrock / oTotal;
  411.       float tsP = sSubsoil / oTotal;
  412.       float ttP = sTopsoil / oTotal;
  413.       float toP = 0;
  414.  
  415.  
  416.  
  417.       //float cB = (bedrock / (totalHeightWithOutWater()-bedrock));
  418.       float cP = parentrock / cTotal;
  419.       float cS = subsoil / cTotal;
  420.       float cT = topsoil / cTotal;
  421.       float cO = organic / cTotal;
  422.  
  423.       //bedrock = (cB + (tbP-cB) * 0.01) * (totalHeightWithOutWater()-bedrock);
  424.       parentrock = (cP + (tpP-cP) * 0.001) * cTotal;
  425.       subsoil = (cS + (tsP-cS) * 0.001) * cTotal;
  426.       topsoil = (cT + (ttP-cT) * 0.001) * cTotal;
  427.       organic = (cO + (toP-cO) * 0.001) * cTotal;
  428.     }
  429.   }
  430. }
  431. Slider rainfallRate;
  432. Slider evaporationRate;
  433. Slider erosionRate;
  434. Slider wWidth;
  435. Slider wDepth;
  436.  
  437. class Slider {
  438.   float minValue;
  439.   float maxValue;
  440.   float value;
  441.   float w;
  442.   float h;
  443.   float innerW;
  444.   PVector pos;
  445.   boolean log;
  446.   SliderKnob sk;
  447.   String name;
  448.   boolean round;
  449.   color col;
  450.  
  451.   Slider(float miV, float maV, float cV, float w_, float h_, float x, float y, boolean log_, String s, boolean round_) {
  452.     round = round_;
  453.  
  454.     minValue = min(miV, maV);
  455.     maxValue = max(miV, maV);
  456.     value = constrain(cV, min(minValue, maxValue), max(minValue, maxValue));
  457.     println(value);
  458.     w = w_;
  459.     h = h_;
  460.     pos = new PVector(x, y);
  461.     log = log_;
  462.  
  463.     innerW = w - h;
  464.  
  465.     float skX = 0;
  466.  
  467.     if (log) {
  468.       skX = (log(1+abs(value-minValue)) / log(1+abs(maxValue-minValue)))*w + pos.x - w/2.0-(w-innerW)/2;
  469.     } else {
  470.       skX = ((value-minValue) / (maxValue-minValue))*(w-h) + pos.x - innerW/2.0;
  471.     }
  472.  
  473.     sk = new SliderKnob(skX, pos.y, h);
  474.  
  475.     name = s;
  476.  
  477.     col  = color(0);
  478.   }
  479.  
  480.   void show() {
  481.     if (mouseOver()) cam.setActive(false);
  482.     listenDrag();
  483.     noFill();
  484.     stroke(0);
  485.     strokeWeight(2);
  486.     rect(pos.x, pos.y, w, h);
  487.     fill(0);
  488.  
  489.     noStroke();
  490.     rect(pos.x, pos.y, w-h, h/2.0);
  491.  
  492.     stroke(col);
  493.     fill(col);
  494.     textAlign(LEFT, CENTER);
  495.     textSize(h);
  496.     String valueString;
  497.  
  498.     if (round) {
  499.       valueString = "" + int(value);
  500.     } else {
  501.       valueString = "" + round(value*1000)/1000.0;
  502.     }
  503.  
  504.     text(name + ": " + valueString, pos.x - innerW / 2.0, pos.y - h*1.5);
  505.  
  506.     sk.show();
  507.   }
  508.  
  509.   void listenDrag() {
  510.     if (dragging && mouseOver()) {
  511.       sk.pos.x = constrain(mouseX, pos.x - innerW/2.0, pos.x + innerW/2.0);
  512.       value = newValue();
  513.     }
  514.   }
  515.  
  516.   float newValue() {
  517.     if (log) {
  518.       float xMin = pos.x-innerW/2.0;
  519.       float xMax = pos.x+innerW/2.0;
  520.       float xDiff = xMax - xMin;
  521.       float screenXPerc = (sk.pos.x-xMin)/(xMax-xMin);
  522.       float logMin = log10(minValue + 1);
  523.       float logMax = log10(maxValue + 1);
  524.       float logDiff = logMax - logMin;
  525.       float logCurrent = logDiff * screenXPerc;
  526.       float finalLog = logMin + logCurrent;
  527.  
  528.       if (round) {
  529.         return round(pow(10, finalLog)-1);
  530.       } else {
  531.         return pow(10, finalLog)-1;
  532.       }
  533.     } else {
  534.       float perc = (sk.pos.x - (pos.x-innerW/2.0))/innerW;
  535.       if (round) {
  536.         return round((maxValue - minValue)*perc + minValue);
  537.       } else {
  538.         return (maxValue - minValue)*perc + minValue;
  539.       }
  540.     }
  541.   }
  542.  
  543.   boolean mouseOver() {
  544.     return (mouseX > pos.x - w/2.0) && (mouseX < pos.x + w/2.0) && (mouseY > pos.y - h/2.0) && (mouseY < pos.y + h/2.0);
  545.   }
  546. }
  547.  
  548. class SliderKnob {
  549.   PVector pos;
  550.   float r;
  551.  
  552.   SliderKnob(float x, float y, float r_) {
  553.     pos = new PVector(x, y);
  554.     r = r_;
  555.   }
  556.  
  557.   void show() {
  558.     fill(127);
  559.     stroke(0);
  560.     strokeWeight(2);
  561.     ellipse(pos.x, pos.y, r, r);
  562.   }
  563. }
  564.  
  565. void initUI() {
  566.   rectMode(CENTER);
  567.   wWidth = new Slider(1, 400, 100, width/8.0, height/40.0, width/12.0, height/40.0*32.0, true, "World Width", true);
  568.   wDepth = new Slider(1, 100, 10, width/8.0, height/40.0, width/12.0, height/40.0*35.0, true, "World Depth", true);
  569.   rainfallRate = new Slider(0.01, wWidth.value*wDepth.value*6, wWidth.value*wDepth.value*6/500.0, width/4.0, height/40.0, width/4.0, height/40.0*38.0, true, "Rainfall Rate", false);
  570.   evaporationRate = new Slider(0.001, 5, 0.2, width/4.0, height/40.0, width/2.0, height/40.0*38.0, true, "Evaporation Rate", false);
  571.   erosionRate = new Slider(0.001, 4, 0.5, width/4.0, height/40.0, width/4.0*3.0, height/40.0*38.0, true, "Erosion Rate", false);
  572. }
  573.  
  574. void showUI() {
  575.   cam.beginHUD();
  576.   float minWH = min(width, height);
  577.   float maxRVal = minWH*0.13;
  578.   float maxArea = worldWidth*worldLength*6;
  579.   float maxR = sqrt(maxArea/PI);
  580.   float currentR = sqrt(waterInCloud/PI);
  581.   float currentRVal = maxRVal / maxR * currentR;
  582.  
  583.   fill(255);
  584.   noStroke();
  585.   ellipse(width*0.9, height*0.1, currentRVal, currentRVal);
  586.  
  587.  
  588.   stroke(0);
  589.   strokeWeight(minWH/500.0);
  590.   noFill();
  591.   ellipse(width*0.9, height*0.1, maxRVal*1.05, maxRVal*1.05);
  592.  
  593.   rainfallRate.show();
  594.   evaporationRate.show();
  595.   erosionRate.show();
  596.  
  597.   if (wWidth.value * wDepth.value > 20000) {
  598.     wWidth.col = color(120, 0, 120);
  599.     wDepth.col = color(120, 0, 120);
  600.   } else if (wWidth.value * wDepth.value > 10000) {
  601.     wWidth.col = color(220, 25, 25);
  602.     wDepth.col = color(220, 25, 25);
  603.   } else if ((wWidth.value * wDepth.value > 4000)) {
  604.     wWidth.col = color(170, 170, 50);
  605.     wDepth.col = color(170, 170, 50);
  606.   } else {
  607.     wWidth.col = color(50, 150, 50);
  608.     wDepth.col = color(50, 150, 50);
  609.   }
  610.   wWidth.show();
  611.   wDepth.show();
  612.  
  613.   fill(255, 127);
  614.   stroke(0);
  615.   rectMode(CENTER);
  616.   rect(width/12.0, height/2, width/7, height/3);
  617.   fill(0);
  618.   textAlign(CENTER, CENTER);
  619.   textSize(width/60);
  620.   text("Controls", width/12.0, height/8*3);
  621.   text("W: Toggle Rain", width/12.0, height/8*3+height/20);
  622.   text("Enter: Regenerate", width/12.0, height/8*3+height/20*2);
  623.   text("LMB + Drag: Rotate", width/12.0, height/8*3+height/20*3);
  624.   text("MMB + Drag: Pan", width/12.0, height/8*3+height/20*4);
  625.   text("Scroll: Zoom", width/12.0, height/8*3+height/20*5);
  626.  
  627.   cam.endHUD();
  628. }
  629.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement