So I've got this nice Android game (a snake-clone with animations), doing the final testing, when BAM! My second testing device (Nexus 1, HTC Magic was my 1.) flickers when drawing.
Does anyone know why this code won't work correctly with the Nexus 1?
public void draw(Canvas canv) {
int count = 0;
isHead = false;
for (int i = 0; i < SPACES; i++) {
if (mDrawSpaces[i]) {
count++;
if (count == SPACES - 1) {
setDrawSpacesToFalse();
if (bmp != null)
super.drawPlaceable(canv);
}
} else {
mDrawSpaces[i] = true;
return;
}
}
}
I have a list of Birds (Birds / UFOs / others) with SPACES (4) times as many elements which are being drawn on the screen. So I thought to myself, instead of calculating the rotation and scale of the pictures for every Bird, I merely have 3 placeholders between the Birds which each have a picture to be drawn once they're set to visible. These pictures are generated by the first Bird:
public void drawHead(Canvas canv) {
//calculate the rotation & mirroring of the picture
super.drawPlaceable(canv);
//generate the pics for smaller birds following it
mat.preScale((float) 0.6, (float) 0.6);
this.bmp = Bitmap.createBitmap(SPRITESHEET, Bird.mCurFrame
* BIG_W[mUseBird], 0, BIG_W[mUseBird], BIG_H[mUseBird],
mat, true);
}
Any ideas? Is my draw(Canvas) method wrong in some part?
EDIT: I don't know why, I don't know how, but this afternoon when I tested it again, it magically worked...
I can see you are using matrix to scale - another option would be to use
canvas.DrawBitmap(spriteSheet, fromRect, toRect, paint);
Where toRect should be a Rect class of any size, in this way you would create no bitmap objects when drawing game frames. The piant should have filter bitmap enabled.
To rotate you would have to use:
canvas.save();
canvas.rotate(spriteAngle,spriteCenterX, spriteCenterY);
canvas.DrawBitmap(spriteSheet, fromRect, toRect, paint);
canvas.restore();
This is a fast enough code for many 2D games, though not as fast and powerful as OpenGL.
Related
I love experimenting with operating on images pixel by pixel using pixels[]. However, I’d like to work on a matrix of 100x100 pixels but have the display be several times larger than 100x100 on my screen.
Is there an efficient and straightforward way to zoom, magnify, scale, resize, or etc… to allow me to work with pixels[] just… bigger?
I was disappointed to see that scale() doesn’t work with pixel arrays.
My first idea to scale by a factor of S is by iterating through my pixel array and drawing a board of SxS rects with the fill of each pixel’s color val. However, this is computationally intensive, and I can’t get my frameRate above 5 or so.
Ah great idea #sorifiend. Since I was calling loadPixels() immediately after setting the window size() and leaving it blank (rather than loading pixels from a image and putting it in the window,) I hadn't thought of that. I found you can use createImage() to make an empty image, which resizes crisply with noSmooth(); on! Thanks for the start.
Here's my code for posterity:
void setup() {
i = createImage(100, 100, RGB);
background(0);
size(800, 800);
i.loadPixels();
noSmooth();
}
void draw() {
i.loadPixels();
for (int x = 0; x < i.width; x++) {
for (int y = 0; y < i.height; y++) {
if (random(0,max(i.width,i.height)) < y) {
i.pixels[x + y*i.height] = color(255);
} else {
i.pixels[x + y*i.height] = color(0);
}
}
}
i.updatePixels();
image(i,0,0,width,height);
}
I would like to build a kind of image morphing tool in Processing. Similar to what you can see in this link:
https://giphy.com/gifs/painting-morph-oil-c8ygOpL64UDuw
My first step to achieve this was to build a two-dimensional grid of pixels. The pixels are filled with colour. The fill colour is created by reading colour from an image (PImage img1;) with the get(); function. This is how I recreated an image with my pixels. In the second step, I thought I would use the lerp(); function to give the respective pixels the colour of a second image (PImage img2;) - I thought this would create the desired morph effect. But I was wrong! The whole thing works - but the effect is only that a fade-in takes place between the two images. And no morphing. What exactly happens to pixels while this morph effect? How could I recreate it in Processing?
float pixel;
float pixelsize;
PImage img1;
PImage img2;
float counter;
void setup() {
size(1080, 1080);
pixel = 100;
pixelsize = width/pixel;
noStroke();
img1 = loadImage("0.jpg");
img2 = loadImage("1.jpg");
counter = 0;
}
void draw() {
background(255);
for (int y = 0; y < pixel; y++) {
for (int x = 0; x < pixel; x++) {
color c1 = img1.get(int(pixelsize*x), int(pixelsize*y));
color c2 = img2.get(int(pixelsize*x), int(pixelsize*y));
color from = c1;
color to = c2;
color interA = lerpColor(from, to, counter);
pushMatrix();
translate(pixelsize*x, pixelsize*y);
fill(interA);
rect(0, 0, pixelsize, pixelsize);
popMatrix();
}
}
counter= counter + 0.01;
}
Indeed it is not a straight forward task.
You're approach is not a bad start: it would result in a nice crossfade between the two images.
Bare in mind get() can be costly on the CPU.
You can however use the pixels[]:
PImage img1;
PImage img2;
// transition image
PImage imgT;
void setup() {
size(1080, 1080);
img1 = loadImage("0.jpg");
img2 = loadImage("1.jpg");
// copy the 1st image (copies width/height as well)
imgT = img1.get();
}
void draw() {
background(255);
// map transition amount to mouse X position
float t = map(mouseX, 0, width, 0.0, 1.0);
// make all pixels readable
imgT.loadPixels();
// lerp each pixel
for(int i = 0 ; i < imgT.pixels.length; i++){
imgT.pixels[i] = lerpColor(img1.pixels[i], img2.pixels[i], t);
}
// update all pixels in one go
imgT.updatePixels();
// display result
image(imgT, 0, 0);
}
Implementing a full morph image is non-trivial.
I can recomend two options to make use of existing algorithms, however these options are also not beginner friendly:
ImageMagick implements shepards distortion and there is a java library that interfaces with imagemagick: im4java. Note that you'd need to download the precompiled java library and drop the .jar file on top of your sketch and processing the output might take time: probably not feasible for realtime (however it should be possible to save individual frames to disk and assemble them as a gif/movie/etc.)
Using OpenCV: there's an OpenCV Face Morph tutorial with source code in c++ or Python and there is a Processing OpenCV library. It would be a matter of porting the c++/Python OpenCV calls to the Java OpenCV API.
I struggle with problem relayed on code (rendering) optimization.
I have 650 hexagons on screen and I need to move them all together and zoom them freely.
As far I have 2d map that stores hexagon objects that contains some parameters as vertexes, center point etc.
my onDraw method looks like this:
#Override
public void onDraw(final Canvas canvas) {
if(hexMap == null || hexMap.length <= 0) {
populateHexMap();
}
if(radiusChanged) {
changeRadius();
}
for(int i = 0; i < hexMap.length; i++) {
for(int j = 0; j < hexMap[i].length; j++) {
if(hexMap[i][j] != null && hexMap[i][j].isToDraw()) {
paint.setColor(hexMap[i][j].getColor());
drawPath.rewind();
drawPath.moveTo(hexMap[i][j].getPoint(0).x, hexMap[i][j].getPoint(0).y);
drawPath.lineTo(hexMap[i][j].getPoint(1).x, hexMap[i][j].getPoint(1).y);
drawPath.lineTo(hexMap[i][j].getPoint(2).x, hexMap[i][j].getPoint(2).y);
drawPath.lineTo(hexMap[i][j].getPoint(3).x, hexMap[i][j].getPoint(3).y);
drawPath.lineTo(hexMap[i][j].getPoint(4).x, hexMap[i][j].getPoint(4).y);
drawPath.lineTo(hexMap[i][j].getPoint(5).x, hexMap[i][j].getPoint(5).y);
drawPath.lineTo(hexMap[i][j].getPoint(0).x, hexMap[i][j].getPoint(0).y);
canvas.drawPath(drawPath, paint);
}
}
}
}
Drawing works great as far. To zoom I catch pinch event gesture and change radius of hexagon then recalculate its vertexes. To move I simply add shift value to center points and recalculate vertexes.
Everything has worked great when I had for example ~30 hexagons. With 650 everything is super slow.
I've tried to enable hardware acceleration but it didn't help. I've tried to reduce amount of invalidate() calls but in my opinion it's not the problem. The problem lays on drawPath.
Is there any way to speed things up? I don't have much time to switch on opengl right now or maybe you know some opensource solutions for drawing hexagons with opengl?
Thanks in advance!
I'm currently working on a system which displays video frames (as bitmaps) via OpenGL ES 1.0 on Android. My issue is that I have not been able to get more than about 10 fps.
After doing some testing, I've determined that one of the biggest bottlenecks is the need for the bitmap to have its width and height both be a power of 2. A 640x480 video has to be scaled up to 1024x1024, for example. Without the scaling, I've been able to get about 40-50fps, but the texture just appears white, which does me no good.
I know that OpenGL ES 2.0 supports using non-power of two textures, but I have no experience with shaders / anything else new in 2.0
Is there any way I can get around this issue? How do other video plays get such good performance in comparison to what I have? I have included some code for reference.
private Bitmap makePowerOfTwo(Bitmap bitmap)
{
// If one of the bitmap's resolutions is not a power of two
if(!isPowerOfTwo(bitmap.getWidth()) || !isPowerOfTwo(bitmap.getHeight()))
{
int newWidth = nextPowerOfTwo(bitmap.getWidth());
int newHeight = nextPowerOfTwo(bitmap.getHeight());
// Generate a new bitmap which has the needed padding
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
}
else
{
return bitmap;
}
}
private static boolean isPowerOfTwo(int num)
{
// Check if a bitwise and of the number and itself minus one is zero
return (num & (num - 1)) == 0;
}
private static int nextPowerOfTwo(int num)
{
if(num <= 0)
{
return 0;
}
int nextPowerOfTwo = 1;
while(nextPowerOfTwo < num)
{
nextPowerOfTwo <<= 1; // Bitwise shift left one bit
}
return nextPowerOfTwo;
}
Just because a texture has to be a power of two, doesn't mean that your data has to be a power of two.
You're free to create a 1024x1024 (or 1024x512) texture during initialization with glTexImage, fill in the lower 640x480 with your bitmap data with glTexSubImage, and then display the lower 640x480 of the texture with some intelligent texcoords (0,0) to (640/1024, 480/1024). The remainder of the texture will just contain empty space that's never seen.
Very simple thing I'm trying to do here. I would like to have 2 images on top of one another. When i use my mouse event dragged and clicked on the top image, the area of the top level image selected will fade and make the lower image visible.
The way I see it, there are 2 ways I can do this:
I can make the top image Transparent over time (within the selected area)
or
I can delete the pixels individually in a spray can style fashion. Think the spray can tool from MS paint back in the day.
Heres some very basic code that i started which just lays the images on top of eachother
PImage sand;
PImage fossil;
void setup()
{
size(400,400);
background(255,255,0);
frameRate(30);
fossil = loadImage("foss.jpg");
sand = loadImage("sand.jpeg");
}
void draw()
{
image(fossil, 0, 0, width,height);
image(sand, 0, 0, width,height);
smooth();
if (mousePressed) {
fill(0);
tint(255,127); //the opacity function
} else {
fill(255);
}
}
So has anyone any comments on these 2 ways of creating opacity or perhaps there an easier way I've overlooked?
Perhaps I wasn't clear in my Spec as the 2 comments below are asking for clarification.
In its simplest terms, I have 2 images on top of each other. I would like to be able to make some modification to the top level image which would make the bottom image visible. However I need to make this modification to only part of the top level image.
I would like to know which is the better option. To make part of the top image become transparent using tint() or to delete the pixels from the top layer.
Then I will proceed with that approach. Any indication as to how to do it is also appreciated.
I hope this clears up any confusion.
If you simply want to crossfade between images, it can be with tint() as you code suggest. You were in fact quite close:
PImage sand;
PImage fossil;
void setup()
{
size(400, 400);
fossil = loadImage("CellNoise.jpg");
sand = loadImage("CellVoronoi.jpg");
}
void draw()
{
//tint from 255 to 0 for the top image
tint(255,map(mouseX,0,width,255,0));
image(fossil, 0, 0, width, height);
//tint from 0 to 255 for the bottom image - 'cross fade'
tint(255,map(mouseX,0,width,0,255));
image(sand, 0, 0, width, height);
}
For the "spray can style " erosion you can simply copy pixels from a source image into the destination image. It's up to you how you loop through pixels (how many, what order, etc.) to get the "spray" like effect you want, but here's a basic example of how to use the copy() function:
PImage sand,fossil;
int side = 40;//size of square 'brush'
void setup()
{
size(400, 400);
fossil = loadImage("CellNoise.jpg");
sand = loadImage("CellVoronoi.jpg");
}
void draw()
{
image(fossil, 0, 0, 400, 400);
if(mousePressed) {
for(int y = 0 ; y < side ; y++){
for(int x = 0; x < side; x++){
//copy pixel from 'bottom' image to the top one
//map sketch dimensions to sand/fossil an dimensions to copy from/to right coords
int srcX = (int)map(mouseX+x,0,width+side,0,sand.width);
int srcY = (int)map(mouseY+y,0,height+side,0,sand.height);
int dstX = (int)map(mouseX+x,0,width+side,0,fossil.width);
int dstY = (int)map(mouseY+y,0,height+side,0,fossil.height);
fossil.set(dstX, dstY, sand.get(srcX,srcY));
}
}
}
}
Note what I am simply looping to copy a square (40x40 in my case), but you can find other fun ways to loop and get different effects.
Have fun!