I want a 16x16 monochromatic sprite to be displayed on my screen. The sprite has 8 different shades, which correspond to 8 different colours. Each color can have his own shade as well, but I want to limit that to 8. So instead of FF00FF, I want it to be like 707.
I've got the project on github
What I've got so far is as follows:
This is where I create all the possible colors:
int[] colours = new int[8 * 8 * 8];
int index = 0;
for(int r = 0; r < 8; r++) {
for(int g = 0; g < 8; g++) {
for(int b = 0; b < 8; b++) {
int rr = r * 255 / 7;
int gg = g * 255 / 7;
int bb = b * 255 / 7;
colours[index++] = rr << 16 | gg << 8 | bb;
}
}
}
This is where I want to call a long int containing all the color information:
public class Colours {
public static int get(int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8) {
//bit shifting with 56 on an integer removes data
return((get(c8) << 28) + (get(c7) << 24) + (get(c6) << 20) + (get(c5) >> 16) +
(get(c4) << 12) + (get(c3) << 8) + (get(c2) << 4) + (get(c1)));
}
private static int get(int colour) {
if(colour < 0) {
return 255;
}
int r = colour / 100 % 10;
int g = colour / 10 % 10;
int b = colour % 10;
return r * 64 + g * 8 + b;
}
}
This is where the screen gets rendered:
public void render(int xPos, int yPos, int tile, int colour) {
xPos -= xOffset;
yPos -= yOffset;
int xTile = tile % 32;
int yTile = tile / 32;
int tileOffset = (xTile << 4) + (yTile << 4) * sheet.width;
for (int y = 0; y < 16; y++) {
if (y + yPos < 0 || y + yPos >= height) {
continue;
}
int ySheet = y;
for (int x = 0; x < 16; x++) {
if (x + xPos < 0 || x + xPos >= width) {
continue;
}
int xSheet = x;
int col = (colour >> (sheet.pixels[xSheet + ySheet * sheet.width + tileOffset] * 16)) & 255;
if (col < 255) {
pixels[(x + xPos) + (y + yPos) * width] = col;
}
}
}
}
I fixed it by returning an integer array.
Related
I'm trying fill my Ellipse, the code works although I was wondering if there is a more efficient approach.
This will fill the first half of the circle given a percentage. And then it will fill the second half of the circle.
Let me know if you want to see any other functions. I was mainly concerned about filling it.
public void drawOrb() {
this.icon.drawSprite(this.xPos - this.icon.getWidth() / 2, 29 - this.icon.getHeight() / 2);
int radius = 19;
fillCircleAlpha(this.xPos, this.yPos, radius, 0, 35); // Draws a filled circle given a radius and alpha value.
Ellipse2D.Double circleToAvoid = drawCircle(this.xPos - radius, this.yPos - radius, radius * 2, 0, //The inner circle.
125);
Ellipse2D.Double circleToStart = drawCircle(this.xPos - (radius + 4), this.yPos - (radius + 4),
radius * 2 + 8, 0, 150); // The outer circle.
radius = 23;
int r2 = radius * radius;
int area = r2 << 2;
int rr = radius << 1;
for (int area2 = (int) (area * progress * 2.0), i = 0; i < area2; ++i) { //
int tx = i % rr;
int ty = i / rr;
if (!circleToAvoid.contains(circleToStart.getCenterX() + tx, circleToStart.getY() + ty) //If the index is inside the circle.
&& circleToStart.contains(circleToStart.getCenterX() + tx, circleToStart.getY() + ty)) {
drawPixelsWithOpacity(16777215, this.yPos + ty - radius, 1, 1, 75, this.xPos + tx); // Used to fill each pixel within the circle.
}
}
if (progress > 0.5) {
for (int area3 = (int) (area * (progress - 0.5) * 2.0), j = 0; j < area3; ++j) {
int tx2 = j % rr;
int ty2 = j / rr;
if (!circleToAvoid.contains(circleToStart.getCenterX() - tx2, circleToStart.getMaxY() - ty2)
&& circleToStart.contains(circleToStart.getCenterX() - tx2 - 1.0,
circleToStart.getMaxY() - ty2)) {
drawPixelsWithOpacity(16777215, (int) circleToStart.getMaxY() - ty2, 1, 1, 75,
(int) circleToStart.getCenterX() - tx2 - 1);
}
}
}
radius = 19;
drawCircle(this.xPos - (radius + 4), this.yPos - (radius + 4), radius * 2 + 8, 0, 150);
}
public static void drawPixelsWithOpacity(int color, int yPos, int pixelWidth, int pixelHeight, int opacityLevel, int xPos) {
if (xPos < topX) {
pixelWidth -= topX - xPos;
xPos = topX;
}
if (yPos < topY) {
pixelHeight -= topY - yPos;
yPos = topY;
}
if (xPos + pixelWidth > bottomX)
pixelWidth = bottomX - xPos;
if (yPos + pixelHeight > bottomY)
pixelHeight = bottomY - yPos;
int l1 = 256 - opacityLevel;
int i2 = (color >> 16 & 0xff) * opacityLevel;
int j2 = (color >> 8 & 0xff) * opacityLevel;
int k2 = (color & 0xff) * opacityLevel;
int k3 = width - pixelWidth;
int l3 = xPos + yPos * width;
if (l3 > pixels.length - 1) {
l3 = pixels.length - 1;
}
for (int i4 = 0; i4 < pixelHeight; i4++) {
for (int j4 = -pixelWidth; j4 < 0; j4++) {
int l2 = (pixels[l3] >> 16 & 0xff) * l1;
int i3 = (pixels[l3] >> 8 & 0xff) * l1;
int j3 = (pixels[l3] & 0xff) * l1;
int k4 = ((i2 + l2 >> 8) << 16) + ((j2 + i3 >> 8) << 8) + (k2 + j3 >> 8);
pixels[l3++] = k4;
}
l3 += k3;
}
}
public static Ellipse2D.Double drawCircle(final int x, final int y, final int diameter, final int color, final int opacity) {
final Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
for (int i = 0; i < diameter; ++i) {
for (int i2 = 0; i2 < diameter; ++i2) {
if (circle.contains(i + x, i2 + y) && (!circle.contains(i + x - 1, i2 + y - 1) || !circle.contains(i + x + 1, i2 + y + 1) || !circle.contains(i + x - 1, i2 + y + 1) || !circle.contains(i + x + 1, i2 + y - 1))) {
drawPixelsWithOpacity(color, i2 + y, 1, 1, opacity, i + x);
}
}
}
return circle;
}
I am trying to convert JPEG byte[] data from Camera.PictureCallback to NV21 byte[] format but it didn't work.
I try to do this:
byte [] getNV21(int inputWidth, int inputHeight, Bitmap scaled) {
int [] argb = new int[inputWidth * inputHeight];
scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);
byte [] yuv = new byte[inputWidth*inputHeight*3/2];
encodeYUV420SP(yuv, argb, inputWidth, inputHeight);
scaled.recycle();
return yuv;
}
void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
final int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int a, R, G, B, Y, U, V;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
a = (argb[index] & 0xff000000) >> 24; // a is not used obviously
R = (argb[index] & 0xff0000) >> 16;
G = (argb[index] & 0xff00) >> 8;
B = (argb[index] & 0xff) >> 0;
// well known RGB to YUV algorithm
Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
// NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
// meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other
// pixel AND every other scanline.
yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
if (j % 2 == 0 && index % 2 == 0) {
yuv420sp[uvIndex++] = (byte)((V<0) ? 0 : ((V > 255) ? 255 : V));
yuv420sp[uvIndex++] = (byte)((U<0) ? 0 : ((U > 255) ? 255 : U));
}
index ++;
}
}
}
I am currently making a game in Java and I am trying to draw an image on my screen, but nothing show up ( only a black screen but no errors ) :(
Here is the code to import the image:
public static Bitmap loadBitmap(String fileName) {
try {
BufferedImage img = ImageIO.read(Art.class.getResource(fileName));
int w = img.getWidth();
int h = img.getHeight();
Bitmap result = new Bitmap(w, h);
img.getRGB(0, 0, w, h, result.pixels, 0, w);
for (int I = 0; I < result.pixels.length; i++) {
int in = result.pixels[i];
int col = (in & 0xf) >> 2;
if (in == 0xffff00ff) col = -1;
result.pixels[i] = col;
}
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
And the Bitmap class:
public void draw(Bitmap bitmap, int xOffs, int yOffs)
{
for(int y = 0; y < bitmap.height; y++)
{
int yPix = y + yOffs;
if(yPix < 0 || yPix >= height) continue;
for(int x = 0; x < bitmap.width; x++)
{
int xPix = x + xOffs;
if(xPix < 0 || xPix >= width) continue;
int alpha = bitmap.pixels[x + y * bitmap.width];
if(alpha > 0)
pixels[xPix + yPix * width] = bitmap.pixels[x + y * bitmap.width];
}
}
}
And to draw all of this :
public void render(Game game)
{
for(int y = 0; y < height; y++)
{
float yd = ((y + 0.5f) - height / 2.0f) / height;
if(yd < 0) yd *= -1;
float z = 10 / yd;
for(int x = 0; x < width; x++)
{
float xd = (x - width / 2.0f) / height;
xd *= z;
int xx = (int) (xd) & 7;
int yy = (int) (z + game.time * 0.1f) & 7;
pixels[x + y * width] = Art.floors.pixels[xx + yy * 64];
}
}
}
I have no errors! I don't really understand.. is this a bug caused by alpha or something? Ho and my image.png is 64x64 made in paint.net
I'm converting a single pixel of NV21 to RGB, it is what I did:
public int getYUVvalue(byte[] yuv,int width,int height,int x,int y){
int total=width*height;
int Y=(0xff&yuv[y*width+x])-16;
int U=(0xff&yuv[(y/2)*(width/2)+(x/2)+total])-128;
int V=(0xff&yuv[(y/2)*(width/2)+(x/2)+total+1])-128;
return this.convertYUVtoRGB(Y, U, V);
}
private static int convertYUVtoRGB(int y, int u, int v) {
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
return 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
but the result is just black and white, looks like the U and V value are not correct, can someone help me with this issue?
thank you!
update: I confirm my Y value is right, so I think the problem is at the U and V value, which I have no clue where the problem is.
update#2: My code is very similar to decodeYUV420sp(), which is a widely used function to convert the whole image, it works perfectly, mine is just to convert a single pixel, still trying to figure out the problem by comparing it with my code. Here is the decodeyuv420sp function:
static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
I still can't see where my mistake is.
update#3: problem solved, thanks for your help everyone!
The logic for the array indexes of U & V in the getYUVvalue function does not match the logic in decodeYUV420SP. (I count 3 differences.) Without a sample byte array in this format to test with, I can't be sure, but I think it should be:
int U=(0xff&yuv[(y/2)*width+(x&~1)+total+1])-128;
int V=(0xff&yuv[(y/2)*width+(x&~1)+total])-128;
It's missing the if (y < 0) y = 0; check also. Maybe that matters.
I have been trying to implement a box blur algorithm in android.
The code seems to be fine but when trying to apply it, some areas in the blurred image have big yellow and white smudges all over the blurred photo.
Can anyone help me find out what i'm doing wrong?
Thanks:
Here is what i have:
public static Bitmap boxBlur(Bitmap bmp, int range) {
assert (range & 1) == 0 : "Range must be odd.";
Bitmap blurred = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(),
Config.ARGB_8888);
Canvas c = new Canvas(blurred);
int w = bmp.getWidth();
int h = bmp.getHeight();
int[] pixels = new int[bmp.getWidth() * bmp.getHeight()];
bmp.getPixels(pixels, 0, w, 0, 0, w, h);
boxBlurHorizontal(pixels, w, h, range / 2);
boxBlurVertical(pixels, w, h, range / 2);
c.drawBitmap(pixels, 0, w, 0.0F, 0.0F, w, h, true, null);
return blurred;
}
private static void boxBlurHorizontal(int[] pixels, int w, int h,
int halfRange) {
int index = 0;
int[] newColors = new int[w];
for (int y = 0; y < h; y++) {
int hits = 0;
long r = 0;
long g = 0;
long b = 0;
for (int x = -halfRange; x < w; x++) {
int oldPixel = x - halfRange - 1;
if (oldPixel >= 0) {
int color = pixels[index + oldPixel];
if (color != 0) {
r -= Color.red(color);
g -= Color.green(color);
b -= Color.blue(color);
}
hits--;
}
int newPixel = x + halfRange;
if (newPixel < w) {
int color = pixels[index + newPixel];
if (color != 0) {
r += Color.red(color);
g += Color.green(color);
b += Color.blue(color);
}
hits++;
}
if (x >= 0) {
newColors[x] = Color.argb(0xFF, (byte) (r / hits),
(byte) (g / hits), (byte) (b / hits));
}
}
for (int x = 0; x < w; x++) {
pixels[index + x] = newColors[x];
}
index += w;
}
}
private static void boxBlurVertical(int[] pixels, int w, int h,
int halfRange) {
int[] newColors = new int[h];
int oldPixelOffset = -(halfRange + 1) * w;
int newPixelOffset = (halfRange) * w;
for (int x = 0; x < w; x++) {
int hits = 0;
long r = 0;
long g = 0;
long b = 0;
int index = -halfRange * w + x;
for (int y = -halfRange; y < h; y++) {
int oldPixel = y - halfRange - 1;
if (oldPixel >= 0) {
int color = pixels[index + oldPixelOffset];
if (color != 0) {
r -= Color.red(color);
g -= Color.green(color);
b -= Color.blue(color);
}
hits--;
}
int newPixel = y + halfRange;
if (newPixel < h) {
int color = pixels[index + newPixelOffset];
if (color != 0) {
r += Color.red(color);
g += Color.green(color);
b += Color.blue(color);
}
hits++;
}
if (y >= 0) {
newColors[y] = Color.argb(0xFF, (byte) (r / hits),
(byte) (g / hits), (byte) (b / hits));
}
index += w;
}
for (int y = 0; y < h; y++) {
pixels[y * w + x] = newColors[y];
}
}
}
Found the problem!
The line:
newColors[x] = Color.argb(0xFF, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits));
I converted the averages to bytes, where they should have been ints.
Changed it to:
newColors[x] = Color.argb(0xFF, (int) (r / hits), (int) (g / hits), (int) (b / hits));