I am trying to create a round brush with blurred edges in Processing through the following code. The circle shape is drawn pixel by pixel because in the actual version, I try to draw with pixels taken from the PGraphic pg.
PFont font;
PGraphics pg;
int X;
int Y;
int rad = 20;
void setup (){
size(800, 800, P2D);
background(0);
noStroke();
pg = createGraphics(800, 800, JAVA2D);
pg.beginDraw();
pg.fill(255);
pg.noStroke();
pg.textFont(font);
pg.textSize(400);
pg.pushMatrix();
pg.translate(width/2, height/2-140);
pg.textAlign(CENTER, CENTER);
pg.text("b", 0 , 0);
pg.popMatrix();
pg.endDraw();
}
void draw () {
image(pg,0,0);
}
void mousePressed(){
X = mouseX;
Y = mouseY;
}
void mouseDragged(){
for (int x=0; x<rad; x++) {
for (int y=0; y<rad; y++) {
float distance = sqrt(pow(x,2)+pow(y,2));
float alpha = 255-map(distance,0,rad,0,255);
if (sqrt(pow(x,2)+pow(y,2)) < rad){
pg.beginDraw();
pg.set(mouseX+x,mouseY+y,color(255,255,255, alpha));
pg.set(mouseX-x,mouseY+y,color(255,255,255, alpha));
pg.set(mouseX+x,mouseY-y,color(255,255,255, alpha));
pg.set(mouseX-x,mouseY-y,color(255,255,255, alpha));
pg.endDraw();
}
}
}
}
Create a function which draw a single dot to a PGraphics object:
void DrawPen(PGraphics pg, int cptX, int cptY, int r) {
pg.beginDraw();
for (int x = 0; x < r; ++x) {
for (int y = 0; y < r; ++y) {
float distance = sqrt(x*x + y*y);
float alpha = 255-map(distance,0,r,0,255);
if (distance < r) {
pg.set(cptX+x,cptY+y,color(255,255,255, alpha));
pg.set(cptX-x,cptY+y,color(255,255,255, alpha));
pg.set(cptX+x,cptY-y,color(255,255,255, alpha));
pg.set(cptX-x,cptY-y,color(255,255,255, alpha));
}
}
}
pg.endDraw();
}
Draw a dot to a separate PGraphics object in setup
PGraphics pg;
PGraphics pg_pen;
int rad = 20;
void setup (){
size(800, 800, P2D);
pg = createGraphics(800, 800, JAVA2D);
pg.beginDraw();
// [...]
pg.endDraw();
pg_pen = createGraphics(2*rad, 2*rad, JAVA2D);
DrawPen(pg_pen, rad, rad, rad);
}
When the mouse is dragged then blend the pg_pen to the common PGraphics object (pg) at the current mouse position:
void mouseDragged(){
pg.beginDraw();
pg.image(pg_pen, mouseX-rad, mouseY-rad);
pg.endDraw();
}
For the seek of completeness the draw function:
void draw () {
background(0);
image(pg,0,0);
}
[...] and tried to get the color from the white part to draw on the black part.
Add a color parameter to the DrawPen function and clear the pen PGraphics before drawing to it:
void DrawPen(PGraphics pg, int cptX, int cptY, int r, color c) {
pg.beginDraw();
pg.clear();
for (int x = 0; x < r; ++x) {
for (int y = 0; y < r; ++y) {
float distance = sqrt(x*x + y*y);
float alpha = 255-map(distance,0,r,0,255);
if (distance < r) {
color pc = color(red(c),green(c),blue(c), alpha);
pg.set(cptX+x,cptY+y,pc);
pg.set(cptX-x,cptY+y,pc);
pg.set(cptX+x,cptY-y,pc);
pg.set(cptX-x,cptY-y,pc);
}
}
}
pg.endDraw();
}
Get the color in the mouse pressed event call back and change the color of the pen:
void mousePressed() {
color c = pg.get(mouseX, mouseY);
println(c);
DrawPen(pg_pen, rad, rad, rad, c);
}
Note, the color is get from the pg object and not from the screen. If you want to get the color from the screen then it has to be (without .pg):
color c = get(mouseX, mouseY);
Further the color is changed any time when any mouse is pressed (pressed not dragged). Possibly you want to change the color when the right mouse button is pressed and paint when the left mouse button is pressed:
void mousePressed() {
if (mouseButton == RIGHT) {
color c = pg.get(mouseX, mouseY);
println(c);
DrawPen(pg_pen, rad, rad, rad, c);
}
}
add a "background(0);" before "image(pg,0,0);" in your drawing method, that way you reset the background every time, if you don't do that the program will keep drawing every frame images on top of each other's, which will make the low opacity pixel gain opacity slowly every frame until reaching 100%
void draw () {
background(0);
image(pg,0,0);
}
Edit:
After testing your code I noticed there was a problem with the way you were creating those circles, making it super slow to run (every frame you go through that double for loop to draw one circle ) and also gave that weird black edges problem, so here is what I did:
First I used your variable pg and drew one circle on it on the startup, Then I declared another PGraphics 'pg_all', where I drew one pg every call of the mousedrag method, I tested it on multiple backgrounds it seems like working fine, here is the final code, let me know if you didn't understand a part or want to do it differently:
PFont font;
PGraphics pg;
PGraphics pg_all;
int X;
int Y;
int rad = 20;
void setup (){
size(800, 800, P2D);
background(0);
noStroke();
pg_all = createGraphics(800, 800, JAVA2D);
pg_all.beginDraw();
pg_all.endDraw();
pg = createGraphics(800, 800, JAVA2D);
pg.beginDraw();
for (int x=0; x<rad; x++) {
for (int y=0; y<rad; y++) {
float distance = sqrt(pow(x,2)+pow(y,2));
float alpha = 255-map(distance,0,rad,0,255);
if (sqrt(pow(x,2)+pow(y,2)) < rad){
pg.beginDraw();
pg.set(20+x,20+y,color(255,255,255, alpha));
pg.set(20-x,20+y,color(255,255,255, alpha));
pg.set(20+x,20-y,color(255,255,255, alpha));
pg.set(20-x,20-y,color(255,255,255, alpha));
pg.endDraw();
}
}
}
pg.endDraw();
}
void draw () {
background(0);
image(pg_all,0,0);
}
void mouseDragged(){
X = mouseX;
Y = mouseY;
pg_all.beginDraw();
pg_all.image(pg,X-rad,Y-rad);
pg_all.endDraw();
}
Related
I am currently in the process of coding a kind of drawing tool in Processing. I want to be able to draw a black line with the mouse, but have it fade away again. For this I first thought of working with a black ellipse that fades from black to white. This ellipse is then linked to the mouse pointer via mouseX and mouseY. Because I want each drawn ellipse to fade from black to white individually (to create the effect that the line fades again), I thought of working with objects. This works so far, but the fading does not work yet.
I want the ellipse at the mouse pointer to always be black and then only change to white once the mouse pointer has been moved further or drawn further... just like a fade...
Should I use an ArrayList for this? And say that a new object should be drawn at the MouseX and MouseY position per frame? Do I need PVector for this?
This is what I came up for this so far:
float counter;
PGraphics pg;
Brush myBrush;
void setup() {
size(600, 600);
pg = createGraphics(width, height);
}
void draw() {
//background(255);
color from = color(0);
color to = color(255);
color faded = lerpColor(from, to, counter);
myBrush = new Brush(faded, mouseX, mouseY);
myBrush.display();
}
class Brush {
color tempC;
float xpos;
float ypos;
color c;
Brush(color tempC, float tempXpos, float tempYpos) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
}
void display() {
noStroke();
fill(c);
ellipse(xpos, ypos, 50, 50);
counter = counter + 0.01;
}
}
The issue you're struggling with here is that you can only know how to fade the line once the line has been drawn, but you draw it while the user move the mouse.
To deal with this issue, I would suggest to store every information needed to draw the line in an object, and update it as the user is drawing. As you guessed, you could totally use an ArrayList to achieve this.
I modified your code quite heavily to simplify my own life, and I commented the result so it would be easier for you to re-cast it into your own project on your own terms.
I used objects to keep everything tidy. The logic here goes as follow: The Canvas object contains the drawing. It's made of Line objects, which are themselves made of Dots.
Here's the commented code:
Canvas canvas;
void setup() {
size(600, 600);
canvas = new Canvas();
}
void draw() {
// instead of drawing only once, we're going to save every line the user draw in teh canvas object
background(255);
// the canvas object has to calculate stuff, then display itself
canvas.Update();
canvas.Display();
}
// setting up the mousePressed and mouseReleased events so the canvas object "knows"
void mousePressed() {
canvas.mouseDown = true;
}
void mouseReleased() {
canvas.mouseReleased = true;
canvas.mouseDown = false;
}
class Canvas {
boolean mouseDown;
boolean mouseReleased = true;
ArrayList<Line> lines = new ArrayList<Line>(); // every line will be stored in this list
Brush brush; // the brush object can be modified with different sizes or colors
Canvas() {
// here i use a default brush, but you can experiment different colors or sizes
brush = new Brush(color(0, 200, 0), color(0), color(255), 50);
}
void Update() {
brush.highlight = mouseDown; // so the user has visual feedback while drawing
if (mouseDown) {
if (mouseReleased) { // if this is a "new" line, add a line object to store it
lines.add(new Line(brush.colorFrom, brush.colorTo));
mouseReleased = false;
}
// add a dot at the mouse's current position, then update the fading
lines.get(lines.size()-1).Add(new Dot(mouseX, mouseY, brush.diameter, brush.colorFrom));
lines.get(lines.size()-1).ApplyFade();
}
}
void Display() {
// for every Line, draw every Dot... then don't forget to display the brush!
for (Line l : lines) {
for (Dot d : l.dots) {
d.Display();
}
}
brush.Display();
}
}
// A line is a bunch of dots and two colord (for the fade effect)
class Line {
ArrayList<Dot> dots = new ArrayList<Dot>();
color colorFrom, colorTo;
Line(color colorFrom, color colorTo) {
this.colorFrom = colorFrom;
this.colorTo = colorTo;
}
void Add(Dot d) {
dots.add(d);
}
// This method calculate how many dots there are in the line to better distribute the shades of the fade
void ApplyFade() {
for (int i=0; i<dots.size(); i++) {
Dot d = dots.get(i);
d.c = lerpColor(colorFrom, colorTo, (float) i/dots.size());
}
}
}
// a Dot has a size, a position and a color
class Dot {
float xpos;
float ypos;
float diameter;
color c;
Dot(float xpos, float ypos, float diameter, color c) {
this.xpos = xpos;
this.ypos = ypos;
this.diameter = diameter;
this.c = c;
}
void Display() {
noStroke();
fill(c);
ellipse(xpos, ypos, diameter, diameter);
}
}
// this class is overdesigned so in the future you can change the brush's characteristics like the fade'S colors or simply it's size
class Brush {
boolean highlight;
float diameter, xpos, ypos;
color circleColor, colorFrom, colorTo;
Brush(color circleColor, color colorFrom, color colorTo, float diameter) {
this.circleColor = circleColor;
this.colorFrom = colorFrom;
this.colorTo = colorTo;
this.diameter = diameter;
}
void Display() {
stroke(circleColor);
strokeWeight(5);
noFill();
ellipse(mouseX, mouseY, diameter, diameter);
if (highlight) { // if the mouse's button is down, give visual feedback about the brush
stroke(0);
strokeWeight(4);
ellipse(mouseX, mouseY, diameter, diameter);
stroke(255);
strokeWeight(3);
ellipse(mouseX, mouseY, diameter, diameter);
}
}
}
Hope this helps. I'll be around if you have questions about the code. Have fun!
Here is a version with an ArrayList and Object... The problem here is that all ellipse objects fade away at the same time... I would like to achieve that each ellipse is first drawn black and then after time X becomes white... Like a fingerprint on a sensor for example... A lot of pressure: black, little pressure (or no pressure): fade to white... Later on I want to draw everything on a PGraphics layer – therefore there is alyready this variable...
float counter;
PGraphics pg;
ArrayList<PVector> positionsList;
Brush myBrush;
void setup() {
size(600, 600);
positionsList = new ArrayList<PVector>();
pg = createGraphics(width, height);
}
void draw() {
background(255);
color from = color(0);
color to = color(255);
color faded = lerpColor(from, to, counter);
for (PVector p : positionsList) {
myBrush = new Brush(faded, p.x, p.y);
myBrush.display();
}
positionsList.add(new PVector(mouseX, mouseY));
counter = counter + 0.01;
}
class Brush {
color tempC;
float xpos;
float ypos;
color c;
Brush(color tempC, float tempXpos, float tempYpos) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
}
void display() {
noStroke();
fill(c);
ellipse(xpos, ypos, 50, 50);
}
}
I like working with Processing array functions but when I draw things using this function, I realize it's storing every single drawn shape in the memory, which is causing spikes in CPU. (Especially when it goes up to a few thousands)
How to bake the drawing then remove the array objects on mouserelease? I mean, can Processing behave those objects as a single image after every stroke then I'd clear the array using .remove(0) function?
Here's my code:
ArrayList <Drawing> drawings = new ArrayList <Drawing>();
void setup() {
size(400, 400);
background(255);
colorMode(HSB);
}
void draw() {
background(255);
for (int i=0;i<drawings.size();i++) {
drawings.get(i).display();
}
println(drawings.size());
}
void mouseDragged() {
drawings.add(new Drawing(mouseX, mouseY));
}
class Drawing {
float x, y, r;
color c;
Drawing(float ax, float ay) {
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255, 88);
}
void display() {
noStroke();
fill(c, 100);
ellipse(x,y, r, r);
}
}
If you want to store the objects into the ArrayList only while the mouse is pressed (drawing new objects) and just have all the old objects to be static on the background out of the ArrayList you can do something like this:
ArrayList<Drawing> drawings = new ArrayList();
boolean flag = false;
void setup()
{
size(400, 400);
background(255);
colorMode(HSB);
loadPixels();
}
void draw()
{
updatePixels();
if(flag)
{
for(Drawing drawing : drawings)
{
drawing.display();
}
}
println(drawings.size());
}
void mouseDragged()
{
flag = true;
Drawing drawing = new Drawing(mouseX, mouseY);
drawings.add(drawing);
}
void mouseReleased()
{
flag = false;
loadPixels();
drawings = new ArrayList();
}
class Drawing
{
float x, y, r;
color c;
Drawing(float ax, float ay)
{
x=ax;
y=ay;
r=random(2, 20);
c=color(random(100, 200), 255, 255, 88);
}
public void display()
{
noStroke();
fill(c, 100);
ellipse(x,y, r, r);
}
}
The function loadPixels() stores into the pixels[] array all the pixels of the screen, while updatePixels() draws the pixels in pixels[] on the canvas. This way you can just empty your ArrayList every time the mouse is released and, even though when the ArrayList gets some thousands of elements you still get some CPU spikes, when the mouse is not being dragged or the ArrayList has less than a couple thousands of elements it is less CPU consuming.
If you don't need to access the drawings objects later (say to change properties), you can simply cache the rendering onto a separate PGraphics layer:
PGraphics drawings;
void setup() {
size(400, 400);
colorMode(HSB);
drawings = createGraphics(width, height);
// use drawing commands between beginDraw() / endDraw() calls
drawings.beginDraw();
drawings.background(255);
drawings.colorMode(HSB);
drawings.noStroke();
drawings.endDraw();
}
void draw() {
background(255);
// PGraphics extends PImage so you can render it the same way
image(drawings, 0, 0);
println((int)frameRate);
}
void mouseDragged() {
drawRandomCircle(drawings, mouseX, mouseY);
}
void drawRandomCircle(PGraphics layer, float x, float y){
float diameter = random(2, 20);
layer.beginDraw();
layer.fill(color(random(100, 200), 255, 255, 88));
layer.ellipse(x, y, diameter, diameter);
layer.endDraw();
}
Otherwise you can make use of PShape:
PShape drawings;
void setup() {
size(400, 400, P2D);
smooth();
background(255);
colorMode(HSB);
// create a PShape group to append circles to later
drawings = createShape(GROUP);
}
void draw() {
background(255);
// render PShape
shape(drawings);
println(drawings.getChildCount() + " shapes at ~" + (int)frameRate + "fps");
}
void mouseDragged() {
drawings.addChild(addRandomCircle(mouseX, mouseY));
}
PShape addRandomCircle(float x, float y){
float diameter = random(2, 20);
// create an ellipse PShape with the desired dimensions, position, fill and (no)stroke
PShape circle = createShape(ELLIPSE, x, y, diameter, diameter);
circle.setFill(color(random(100, 200), 255, 255, 88));
circle.setStroke(false);
return circle;
}
As mentioned in my comment check out Processing > Examples > Demos > Performance > StaticParticlesRetained
If you need later access to each added circle/drawing you can iterate over the parent PShape:
// iterate though nested PShapes
for(int i = 0 ; i < drawings.getChildCount(); i++){
// access each PShape
PShape drawing = drawings.getChild(i);
// access PShape properties
println("drawings[" + i + "] has " + drawing.getVertexCount() + " vertices");
}
Should you need extra functionality (like a separate property to animate), you can always extend PShape: re-use what's already there add what you need on top:
PShape drawings;
void setup() {
size(400, 400, P2D);
smooth();
background(255);
colorMode(HSB);
// create a PShape group to append circles to later
drawings = createShape(GROUP);
}
void draw() {
background(255);
// use custom functionality
for(int i = 0 ; i < drawings.getChildCount(); i++){
// cast from PShape superclass to the custom Drawing subclass
Drawing drawing = (Drawing)drawings.getChild(i);
// use the custom functionality
drawing.update(i);
}
// render PShape
shape(drawings);
println(drawings.getChildCount() + " shapes at ~" + (int)frameRate + "fps");
}
void mouseDragged() {
drawings.addChild(new Drawing((PGraphicsOpenGL)g, mouseX, mouseY));
}
class Drawing extends PShapeOpenGL{
float x, y, diameter;
Drawing(PGraphicsOpenGL pg, float x, float y){
// call PShape super constructor setting this as a primitive (e.g. POINT, LINE, RECT, ELLIPSE, etc.)
super(pg, PShape.PRIMITIVE);
setKind(ELLIPSE);
diameter = random(2, 20);
// set (ellipse) shape parameters
setParams(new float[]{x, y, diameter, diameter});
// fill
setFill(color(random(100, 200), 255, 255, 88));
// disable stroke
setStroke(false);
// remember original position
this.x = x;
this.y = y;
}
// a custom functionality on top of PShape
void update(int index){
float offset = map(sin((frameCount + ((index+1) * 10)) * 0.025), -1.0, 1.0, -15, 15);
// reset transformations
this.resetMatrix();
// translate backwards
this.translate(-x, -y);
// translate back + the offset
this.translate(x + offset, y);
}
}
For the full list of functionalities see PShape javadocs
Starting with the simplest thing though. If you want to simply render many shapes without changing them later PGraphics will do the trick
I was steered over to this forum when I asked my lecturer for advice on a piece of code for a group project. The general idea is that there are two images on top of each other, the user can wipe the top image away to reveal the one underneath.
Using some other projects from this forum, I have managed to get the basics running, however I am struggling to get the code to the starting point once the user lets go of the mouse.
I would also appreciate any advice regarding how to convert this to using a touch screen. I have looked at the multitouch code within the processing app, however it does not allow me to add images to this, and if I try and use the computer software it does not seem to like the multitouch. Is there any way around this?
The code I currently have is below, I will be greatful so any advice or input- thanks in advance!
PImage img, front;
int xstart, ystart, xend, yend;
int ray;
void setup()
{
size(961, 534);
img = loadImage("back.jpg");
front = loadImage("front.jpg");
xstart = 0;
ystart = 0;
xend = img.width;
yend = img.height;
ray = 50;
}
void draw()
{
{
img.loadPixels();
front.loadPixels();
// loop over image pixels
for (int x = xstart; x < xend; x++)
{
for (int y = ystart; y < yend; y++ )
{
int loc = x + y*img.width;
float dd = dist(mouseX, mouseY, x, y);
// pixels distance less than ray
if (mousePressed && dd < 50)
{
// set equal pixel
front.pixels[loc] = img.pixels[loc];
}
else
{
if (!mousePressed)
{
// reset- this is what I have not been able to work as of yet
front.pixels[loc] = ;
}
}
}
}
img.updatePixels();
front.updatePixels();
// show front image
image(front, 0, 0);
}
}
I recommend to use a mask instead of changing the pixels of the image. Create an empty image and associated it as mask to the the image:
img = loadImage("back.jpg");
front = loadImage("front.jpg");
mask = createImage(img.width, img.height, RGB);
img.mask(mask);
If you now draw both images, then you can only "see" the front image:
image(front, 0, 0);
image(img, 0, 0);
Set the color of the mask (255, 255, 255) instead of changing the pixel of front:
mask.pixels[loc] = color(255, 255, 255);
and reapply the mask to the image
img.mask(mask);
When the mouse button is released, the pixels of the mask have to be changed back to (0, 0, 0) or simply create a new and empty mask:
mask = createImage(img.width, img.height, RGB);
See the example where I applied the suggestions to your original code:
PImage img, front, mask;
int xstart, ystart, xend, yend;
int ray;
void setup() {
size(961, 534);
img = loadImage("back.jpg");
front = loadImage("front.jpg");
mask = createImage(img.width, img.height, RGB);
img.mask(mask);
xstart = 0;
ystart = 0;
xend = img.width;
yend = img.height;
ray = 50;
}
void draw() {
img.loadPixels();
front.loadPixels();
// loop over image pixels
for (int x = xstart; x < xend; x++) {
for (int y = ystart; y < yend; y++ ) {
int loc = x + y*img.width;
float dd = dist(mouseX, mouseY, x, y);
if (mousePressed && dd < 50) {
mask.pixels[loc] = color(255, 255, 255);
}
else {
if (!mousePressed) {
//mask = createImage(img.width, img.height, RGB);
mask.pixels[loc] = color(0, 0, 0);
}
}
}
}
mask.updatePixels();
img.mask(mask);
// show front image
image(front, 0, 0);
image(img, 0, 0);
}
My problem is following:
I wrote a code and managed to display an image when i click on a rectangle (with the loadImage-fuction). The rectangle serves as a button that I want to replace with an image later.
But i actually don't just want an image to be displayed when the button is clicked. I want to call a code, to copy an image onto another:
public static int SQUARE_WIDTH = 30;
public static int SQUARE_HEIGHT = 30;
PImage img1,img2, img3;
void setup() {
size(670, 943);
img1 = loadImage("white.png");
img2 = loadImage("hase.jpg");
img3= loadImage("ohrring.jpg");
image(img1,0,0);
}
void draw() {
if(mousePressed)
copy(img2,
constrain(mouseX-SQUARE_WIDTH/2,0,width),
constrain(mouseY-SQUARE_HEIGHT/2,0,height),
SQUARE_WIDTH,SQUARE_HEIGHT,
constrain(mouseX-SQUARE_WIDTH/2,0,width),
constrain(mouseY-SQUARE_HEIGHT/2,0,height),
SQUARE_WIDTH,SQUARE_HEIGHT);
}
The copy-code doesn't simply copy an image, it uses the mouse as a brush! When you "draw" on an area, the image shows with the "strokes" of the brush pixel after pixel!
processing.org/reference/copy_.html
I happen to have huge problems when I want to combine this one with my main code:
int rectX, rectY;
int rectSize = 90;
boolean rectOver = false;
color rectHighlight;
color currentColor, baseColor;
color rectColor;
public static int SQUARE_WIDTH = 30;
public static int SQUARE_HEIGHT = 30;
PImage img1,img2, img3;
void setup() {
size(670, 943);
rectColor = color(0);
rectX = width/2-rectSize-10;
rectY = height/2-rectSize/2;
baseColor = color(102);
currentColor = baseColor;
img1 = loadImage("frida.jpg");
img2 = loadImage("hase.jpg");
img3 = loadImage("white.png");
background(img3);
}
void draw() {
update(mouseX, mouseY);
if (rectOver) {
fill(rectHighlight);
} else {
fill(rectColor);
}
stroke(255);
rect(rectX, rectY, rectSize, rectSize);
}
void update(int x, int y) {
if ( overRect(rectX, rectY, rectSize, rectSize) ) {
rectOver = true;
}else {
rectOver = false;
}
}
void mousePressed() {
if (rectOver) {
background(img2);
}
}
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}
Theoretically I got the tip to set a boolean in mousePressed() to do the copy-operation in draw(), and then to check this boolean in draw(): if set (true) it shall do the copy. But I'm unfortunately not the brightest star in the programming-sky , so could anybody show me what this part is supposed to look like? Of course, I'm open to other suggestions how to solve this problem!
Thank you!
I hope this is what you are looking for. If you want to copy an image you don't need to call a function to copy an image, you can simply invoke the = sign and the image will be copied.
In my example code buttonImage is the image on the button. Whenever you don't want an image on the button assign it the following way:
buttonImage = null;
If you want to have an image instead of the rectangle do the following:
buttonImage = yourImage;
buttonImage.resize(w, h); //fit it on the button.
I think this is what you want to achieve?
PImage buttonImage;
void setup()
{
}
void draw()
{
if(buttonImage == null ||Â buttonImage.width < 2) rect(x, y, w, h);
else image(buttonImage, x, y);
}
void mouseReleased()
{
if(mouseX > x && mouseX < x + w && mouseY > y && mouseY < y + h)
{
//copy any image onto the buttonImage
buttonImage = loadImage("newPath.png"); //update / overwrite image
buttonImage.resize(w, h); //fit it on the button
}
}
x and y are the position of the button, w and h are the width and the height of the button in my example.
EDIT:
Ok, so basically you want to have a white background and you want to scrap it using your tool so an image appears? I'm still not 100% sure of what you're asking, but if that is the case try this:
I used img.get() instead of img.copy(), because it has less parameters to deal with. I really hoped i understood this correctly, if not maybe link a video to something similar? I have a hard time understanding what you want.
The toolSelected integer is a counter to which tool you are using. Depending on its value, it is executing a different code.
My code:
PImage img1;
int toolSelected = 0; //Normal tool;
int widthOfBrush = 20; //Now you are drawing 20x20
int buttonX = 200;
int buttonY = 200;
int buttonW = 40;
int buttonH = 20;
void setup()
{
size(640, 480);
background(255);
img1 = loadImage("yourImg.png");
img1.resize(width, height); //Fit it on processing screen
}
void draw()
{
if(toolSelected == 0) {}//other tool
//Instead of using copy we will be using buttonImage.get(x, y, w, h) --> makes more sense
if(toolSelected == 1 && mousePressed)
{
float yourX = mouseX;
float yourY = mouseY;
yourX -= floor(widthOfBrush / 2);
yourY -= floor(widthOfBrush / 2);
//scale & copy:
PImage brushImage = img1.get((int)yourX, (int)yourY, widthOfBrush * (width / img1.width), widthOfBrush * (width / img1.width)); //Draw the image at your destination
image(brushImage, mouseX, mouseY);
}
stroke(0);
fill(255);
rect(buttonX, buttonY, buttonW, buttonH);
}
void mouseReleased()
{
if (mouseX > buttonX && mouseX < buttonX + buttonW && mouseY > buttonY && mouseY < buttonY + buttonH)
{
//copy any image onto the buttonImage
//buttonImage = loadImage("newPath.png"); //update / overwrite image
toolSelected = 1; //Our tool is the image brush now.
}
}
I am trying to do a theoretically simple effect. For example, I have two white circles bouncing around the window. When they intersect, I want the parts of the circle which are intersecting to be black while the rest of the circles remain white, like this:
Is there a way to do this?
So far I have this:
for(int i = 0; i < balls.length; i++)
{
balls[i].move();
for(int j = 0; j < balls.length; j++)
{
if(i != j && balls[i].intersect(balls[j]) && !changed[i] && !changed[j])
{
balls[j].swapColor();
changed[j] = true;
}
else
changed[j] = false;
}
balls[i].display();
}
but it turns the circles entirely to black when they intersect, whereas I only want the intersection itself to change.
edit:
I tried using blend() with two 200x200 pngs, magenta and red to better see the blending work. The blend() parameters don't seem to help with positioning the circles correctly, however.
void setup() {
size(300, 300);
background(255);
}
void draw() {
PImage img = loadImage("circle.png");
PImage img2 = loadImage("circle2.png");
img.blend(img2,0,0,200,200,10,10,200,200,DIFFERENCE);
image(img,0,0);
image(img2,50,50);
}
gives me this:
Here give this a try. It's the blend approach using two PGraphics, instead of PImages. A simple example. EDIT: There is a strange artifact in upper corner of base ellipse when they overlap though, don't now why... I'm looking for, If i find I'll post it here.
EDIT2: it seems to be related to the antialias, if you skip smooth() the artifact is gone...
PGraphics c;
PGraphics d;
void setup() {
size(300, 300);
background(255);
c = createGraphics(width, height, JAVA2D);
d = createGraphics(width, height, JAVA2D);
c.beginDraw();
c.smooth();
c.endDraw();
d.beginDraw();
d.smooth();
d.endDraw();
}
void draw() {
background(255);
c.beginDraw();
c.background(0, 0);
c.fill(255);
c.stroke(0);
c.ellipse(mouseX, mouseY, 30, 30);
c.endDraw();
d.beginDraw();
d.background(0, 0);
d.fill(255);
d.stroke(0);
d.ellipse(width/2, height/2, 30, 30);
d.endDraw();
d.blend(c, 0, 0, width, height, 0, 0, width, height, DIFFERENCE);
image(d, 0, 0);
}
Unfortunately I can't provide a runnable sample now, but for the visual effect you can use the blend() function (probably on the DIFFERENCE mode).
You can draw an ellipse into a PImage using createGraphics btw.
I thought of an amusing way to do this. Create a new sketch with the following code and move your mouse around within the canvas.
void setup() {
size(600,600);
}
void draw() {
background(0);
int c1x = width/2;
int c1y = height/2;
int c2x = mouseX;
int c2y = mouseY;
int d = 100;
boolean intersect = false;
if(dist(c1x, c1y, c2x, c2y) < d) intersect = true;
fill(255);
stroke(0);
ellipse(c1x, c1y, d, d);
ellipse(c2x, c2y, d, d);
noFill();
ellipse(c1x, c1y, d, d);
stroke(0, 0, 255);
line(c1x, c1y, c2x, c2y);
stroke(255, 0, 0);
if(intersect) stroke(0, 255, 0);
rectMode(CORNERS);
int mx = (c1x+c2x)/2;
int my = (c1y+c2y)/2;
int r = d/2;
rect(mx-r, my-r, mx+r, my+r);
if(intersect) {
for(int j = my-r; j <= my+r; j++) {
for(int i = mx-r; i <= mx+r; i++) {
if(dist(i, j, c1x, c1y) <= r && dist(i, j, c2x, c2y) <= r) {
stroke(0);
point(i, j);
}
}
}
}
}
This is a dirty mock-up showing the concept. I know the center points of the two circles. I imagine a square with a width and height equal to the diameter of the circles, and I center that square at the midpoint between the two circles. When the circles collide, I check each pixel within that square, and if the pixel is within both circles, I draw a point there.
I simplified by having the circles with identical diameter, but it's trivial to modify it for variable diameters.
Obviously you don't have to draw the green square and blue line, those are there just for reference.
they intersect if distance between their centers is smaller than sum of their radius
This would be dark ellipses with a white intersection and background and is quick and dirty but works.
with a white background:
background(255);
call something like this:
blendMode(SUBTRACT);
fill(0);
ball1.display();
fill(255);
ball2.display();
If you want to take a look at the math behind it check out this link. I think you also might be able to do this with a library like toxiclibs.geom.