We are about to switch to a new forum software. Until then we have removed the registration on this forum.
So. New forum. First post. Frustrated.
I don't claim to write clean code, but I try to make it readable. I started programming somewhere in the 80s, in BASIC, then in C, C++, whatever. I love global variables, I can do Object Oriented. I was looking for a way to program in Java directly on Android, with the result being an APK. So I came to Processing. Hm. I would have made APDE as some kind of dual-mode tool chain, where one mode is the basic "Go and write processing" and the other mode as "programm natively, use P as import, do your own main without overriding", but that's just me and outside the scope of what I'm trying to do here.
First I went ahead and grabbed me android's sensors just to see if I could. I made my own sensor class, grabbed temperature from the battery manager, made another class (batman), registered some callbacks, put them on screen, added a background. Worked.
I started grabbing touch input as mouse input, worked just fine. Wanted to text() on a PGraphics to help debug. Easy-peasy. Make a PGraphics, text in, display it by image(..), clear() it, text in, display, clear, rinse, repeat. Huh. What's that? the text overwrites and overwrites and overwrites (I was grabbing touch position, fingerdown, fingerup, worked like a charm.) but wasn't clearing. I wanted to re-use the PGraphics with clear() because creating a new one 30x per second is not the way to go, right? But no, clear() does nothing but put a new "backround" on top, full black, fully transparent. On top. Yeah, you read that right. Took me 4 hours of my life and diving into Processing on github. (censored). By the way, whenever someone on github or here found some problem with clear() and pgraphics, the comments are a hoot. Yeah, I can reproduce it. No, I will not loop over 300,000 pixels to reset them 30 times a second, thanks for recommending. Even the clear() example right in the procesing reference (modified to draw on touch, clear on finger-up) does not work on Android. Let me repeat that: IT DOES NOT WORK. Want a (censored) video?
Next, with a lightsensor running, I wanted to build some photographer's helper. Some overlaying rotating discs, aperture, shutter speed, a draggable ISO selector... Let's start with a disc. Made me some nice square metal plate, read some more. Either I take it and mask it with something round to get a disc, or I apply it as a texture onto a circle. Since my first hour trying to texture(...) resp. setTexture(...) somehow failed to bring results, and I saw that masking was the obviously preferred way to go in the forum, I went down that rabbithole.
Want some code? You get some code.
import android.os.Bundle; import android.os.Build; import android.app.Activity; import android.content.Context; import android.view.WindowManager; import android.view.Display; Activity activity; Context context; Display display; int rotation; String rotString; String orientation; float aspectRatio; int canvasX; int canvasY; int fontSizeNormal = 5; int colWidth; int rowHeight; int rows; int cols; int gridUnitX; int gridUnitY; float fScale; int iScale; int i; int loopcount = 0; PGraphics backgroundG; PGraphics maskG; PGraphics balouG; PGraphics balouMaskedG; PGraphics testG; PGraphics jerkG; PImage bgIMG; PImage testIMG; PImage balouIMG; PImage balouorigIMG; PImage cJerkIMG; public void setup() { //fullScreen(); //orientation(PORTRAIT); size(displayWidth, displayHeight, P2D); frameRate(30); background(0,0,0); canvasX = displayWidth; canvasY = displayHeight; activity = this.getActivity(); context = activity.getApplicationContext(); display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); fontSizeNormal = int(float(canvasX)/18); rows = 2; cols = 3; gridUnitX = int(float(canvasX) / 11); gridUnitY = int(float(canvasY) / 14); fScale = canvasX / 1000; iScale = int(fScale); backgroundG = createGraphics(canvasX, canvasY); bgIMG = loadImage("background.jpg"); while (bgIMG.width == 0) { delay(100); } backgroundG.beginDraw(); backgroundG.image(bgIMG,0,0,canvasX, canvasY); // fit to canvas on-the-fly backgroundG.endDraw(); image(backgroundG,0,0); // let's get this out of the way balouG = createGraphics(300, 300); balouorigIMG = loadImage("balou.jpg"); while (balouorigIMG.width == 0) { delay(100); } balouorigIMG.resize(300,300); // resize it balouG.beginDraw(); balouG.image(balouorigIMG,0,0); // and put it in the upper left corner of PGraphics balouG balouG.endDraw(); maskG = createGraphics(300,300); maskG.beginDraw(); maskG.ellipse(150, 150, 300, 300); // nice white circle maskG.endDraw(); balouMaskedG = createGraphics(300, 300); balouIMG = loadImage("balou.jpg"); while (balouIMG.width == 0) { delay(100); } balouIMG.resize(300,300); // if I don't resize here, balouIMG.mask(maskG); // I get an error that the mask doesn't fit the image balouMaskedG.beginDraw(); // so something happens in resize(int, int) balouMaskedG.image(balouIMG,0,0); // but what?!? balouMaskedG.endDraw(); // and just for the heck of it: balouMaskedG.clear(); // outside a beginDraw/endDraw balouMaskedG.beginDraw(); balouMaskedG.clear(); // inside a beginDraw/endDraw balouMaskedG.endDraw(); // at least one of those should return balouMaskedG to a completely transparent state. // if you check the Processing -> Android port's source, you should immediately see why that fails. testG = createGraphics(300, 300); testIMG = loadImage("balou.jpg"); while (testIMG.width == 0) { delay(100); } testG.beginDraw(); testG.image(testIMG,0,0,300,300); // fit to 300x300 canvas testG.endDraw(); // Afterthought: testIMG.resize(300,300); // should work just fine, right? jerkG = createGraphics(300, 300); cJerkIMG = loadImage("balou.jpg"); while (cJerkIMG.width == 0) { delay(100); } cJerkIMG.resize(300,300); // resize it jerkG.beginDraw(); jerkG.image(cJerkIMG,0,0); // and put it in the upper left corner of PGraphics cJerkIMG.mask(maskG); jerkG.image(cJerkIMG,50,50); // and NOT put it in the upper left corner of PGraphics jerkG.clear(); // does nothing jerkG.endDraw(); jerkG.clear(); // still does nothing loop(); } public void draw() { textSize(15); fill(200,200,200); background(0); // black is beautiful image(backgroundG,0,0); // nicely stretched background text("Background fit to canvas on-the-fly",0,20); image(maskG,25,25); // white circle text("Mask",25,50); image(balouG,350,25); // nicely resized PGraphics text("resized and\nput into PGraphics",350,50); image(testG,675,25); // nicely resized PGraphics text("on-the-fly-resize while\nput into PGraphics",50,375); image(balouMaskedG,1000,25); //gives a black circle?!? text("resized, masked and\nput into PGraphics\n(should be cleared)",1000,50); image(balouorigIMG,25, 350); text("resized image\nWITHOUT PGraphics\nbut put through a PGraphics\nbefore",25,375); image(testIMG,350,350); // text("just a resized image\nwithout PGraphics",350,375); image(cJerkIMG,675,350); // text("Why is that black\noutside the cirle??",675,375); image(jerkG,1000,350); // text("I go destroy something now.",1000,375); } // last line of draw()
Sorry for those seemingly random missing linebreaks, we have some translation error here(LF/CRLF stuff, old but gold). Also, there are a lot of unused vars, as I yanked that out of the lightmeter sketch and expanded on it.
Anyways. Now, if I resize a loaded image, it'll be black unless I draw it into a PGraphics? Really? And the mask does nothing unless I put the masked image through a PGraphics, and then the background is black? Why? I feel like Del Shannon crying Why why why why why in"Runaway".
And don't even get me started on lines in the console, like "The pixel array has a length of 90000, but it should be at least 184041" So, who made that pixel array too small?
Flame me, boot me, whatever, but this needed out, I already had one heart attack, I don't need another one. You need one non-300x300px image to test that code yourself.
Answers
@Mad===
try to format your code, it will be more easy to use it!
As I said: Sorry for those seemingly random missing linebreaks, we have some translation error here(LF/CRLF stuff, old but gold).
nothing changed, just formatted
Thanks, I just found that PRE works here. Sorry again.
What sorcery is this? Now this thread is marked as answered?!?
you don't need these. loadImage blocks until it is done.
and you only need to load the image once, you can copy it the other times. (using the copy() method on PImage)
until it doesn't. the official way is to highlight the code and press ctrl-o.
read the Common Questions over there on the left.
@koogs I had requestImage(...) in there for a while. Just left the while(...) in, might change back. Copy() works unless you run in some ArrayOutOfBounds, or get some more black squares. Erring on the safe side meant distrusting copy in this scenario, for me.
Now, is there anyone with some idea why (all that PGraphics stuff) or why transparent isn't? Otherwise I'd just have to do it all myself, and use APDE only as an editor/compiler/dexer/packer/signer toolchain. Oh, wait, scratch that editor part, because.... ah well, don't even get me started on that one. But thanks for the toolchain.
ok, long rambling post which mentions several problems.
you might get further posting ONE error at a time. with a minimal runnable code and a clear description of your expectations (mock-up expected result images if that helps). rather than the 8 vague problems we currently have.
(extra points for modular code rather than one monolithic block
simple well-defined methods, solvable individually. eating an elephant one bit at a time.)
@Mad
You need to remember Processing is and open source project. Therefore, any errors and improvements are done by the group of people that are under the Processing foundation and by volunteers like most people in the forum. In other words, there is no guarantee everything works in Processing as advertised. As new versions are released, new bugs can be generated and they need to be addressed. The best way (read this more as "proper way" although no guarantee any fast turn out response) to address bugs in Processing is by creating a github ticket describing your problem. What you could do is to create a ticket, describe your problem and provide an MVCE. You can add previous post relevant to your discussion to reinforced your point. If you create a post in the forum, also added to your ticket so any generated discussions are visible from the ticket in github. My understanding is that the Processing foundation will address the ticket based on priority, meaning how bad the bug is.
Now, related to the clear() function... yes, I have experience that problem myself. People make assumptions that what works for one flavor of Processing, it should work in another. That is incorrect. Processing Java, Processing Android, Processing P5.js, Processing.R, Processing.js, Processing.py are all projects that are based on the Processing java flavor. However, the mechanics under the hood are different and to try to support the functionalities across each flavor is not easy and really depends on how many people are directly contributing to the source code.
I also agree with koogs. Simple post addressing each issue is the way to go here. I wouldn't know where to start in your post as I can see what you mean but I will need to track your code to link it to your comments. That just means it takes a bit more effort to do. If you create simple post addressing single questions, you will have more people looking into that.
My contribution to clear(), yes... did you try creating a new PGrahpics buffer instead of resetting its pixels? If it works, well... problem solved. If, it doesn't... then tell us what it didn't work. Don't be afraid of abusing your device just to make a point. This could not be a good practice, but if it works then you can move to another problem. That is what most people have done in the forum and that is probly the reason why it hasn't been address in the first place.
Kf
@kfrajer Thank you for taking the time to respond in that fashion. I understand that serving smaller bites makes it easier to solve the underlying riddles. I was trying to find out where exactly the riddle is, the above code is a result of that. In other words, there's an elephant, it is ill, I don't exactly know where, but I tried to collect symptoms.
I fought hard with the mask problem and the transparency. Seems if (mask or image) is ARGB and the other is RGB, then mask() reacts strangely. Also, l'm not sure if loadImage returns ARGB or RGB when loading an image without transparency like JPG, didn't dig deeper there. Sadly, there is no param for that in loadImage(), but:
Yes, I know, that's not runnable without some more declarations, but it should help.
About abusing my hardware: you don't even want to know... Yes, I tried just creating a PGraphics for debug output by just making a new one each draw(). That's sloooooooow! Like, dividing framerate by 20 slow. Don't do that in draw(). Nononono. No.
I wonder if.... 1px*1px transparent.gif once resized and somehow brutally loaded into a PGraphics might do the trick.... Back later, maybe.
About CLEAR()-ing a PGraphics: Runnable Proof-of-concept.
if you out-comment the for(){}, you see the slightly tinted clear image cumulating. You'll also feel the speed difference. You could put all the testG stuff in a function, and declare PGraphics there instead of globally, then image(testG...) from the function. Tried that. Hurts watching.