joeyismusic
|
 |
«
Posted
2012-04-25 12:47:24 » |
|
I couldn't come up with a more elegant way of drawing any color font from a single bitmap (png) font loaded in memory. The only way I could get it to work was to render everything into a buffered image, which is then modified at pixel level by the font drawing. The only other way I can think of how to do this would be to create the buffered image, then steal its array, and have to do my own pixel copying / color operations from there on instead of using drawImage calls... But I'd really like to avoid going that far if I could! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| public final class Font {
private static int trans = 16777215;
public static final int w = 8; public static final int h = 8; public static void printString(BufferedImage bimg, String string, int x, int y, int width, int color, int bgcolor) { int px = 0; int py = 0; char c; int sx; int sy; int pixel_x = 0; int pixel_y = 0; int ix = 0; int iy = 0; int i = 0; int src_color = 0; for(i = 0; i < string.length(); i++) { c = string.charAt(i); if(c == 32) { px += w * 2; if(px / (w * 2) > width) { px = 0; py += h * 2; } continue; } sx = c; sy = 0; while(sx > 15) { sx -= 16; sy++; } sx *= w; sy *= h; for(ix = 0; ix < w; ix++) { for(iy = 0; iy < h; iy++) { src_color = Art.font.getRGB(sx + ix, sy + iy); if(src_color != trans) { pixel_x = x + px + (ix * 2); pixel_y = y + py + (iy * 2); if(pixel_x >= 0 && pixel_x + 2 < Game.WIDTH && pixel_y >= 0 && pixel_y + 2 < Game.HEIGHT) { bimg.setRGB(pixel_x + 1, pixel_y + 1, bgcolor); bimg.setRGB(pixel_x + 2, pixel_y + 2, bgcolor); bimg.setRGB(pixel_x + 2, pixel_y + 1, bgcolor); bimg.setRGB(pixel_x + 1, pixel_y + 2, bgcolor); } if(pixel_x >= 0 && pixel_x + 1 < Game.WIDTH && pixel_y >= 0 && pixel_y + 1 < Game.HEIGHT) { bimg.setRGB(pixel_x + 0, pixel_y + 0, color); bimg.setRGB(pixel_x + 1, pixel_y + 1, color); bimg.setRGB(pixel_x + 1, pixel_y + 0, color); bimg.setRGB(pixel_x + 0, pixel_y + 1, color); } } } } px += w * 2; if(px / (w * 2) > width) { px = 0; py += h * 2; } } } } |
|
|
|
|
Tom-Todd
Senior Newbie 
|
 |
«
Reply #1 - Posted
2012-04-25 18:50:03 » |
|
I'd be tempted to take a look at Notch's code for Prelude of the Chambered, pretty sure he did it in there... in particular I'd look at the Art and Bitmap classes... think that's where it's handled.
|
|
|
|
joeyismusic
|
 |
«
Reply #2 - Posted
2012-04-25 21:02:59 » |
|
Hmm. I'll have a look. I am pretty sure he's just modifying the int's in the array, which sucks because I'd have to write a lot of new rendering code.
I guess I don't have too much to worry about. If I fill the screen with as many characters as it can possibly show, it goes from 60 fps to 47 fps. Any other normal text display doesn't phase it.
Looking forward to any other contributions anyone else might have to this topic. Thanks.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ra4king
|
 |
«
Reply #3 - Posted
2012-04-26 03:30:53 » |
|
Wait, you want to copy a portion of a BufferedImage into another BufferedImage right? 1 2 3 4 5
| BufferedImage destination = .... Graphics g = destination.getGraphics();
g.drawImage(fontImage,dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2,null); |
To draw it a certain color, you use AlphaComposite to blend a color with the font image.
|
|
|
|
joeyismusic
|
 |
«
Reply #4 - Posted
2012-04-26 03:44:05 » |
|
i have an image of a font my artist drew. its black and transparent
wherever there is a black pixel, i want to put a color of my choice in place of where that black pixel would go
|
|
|
|
ra4king
|
 |
«
Reply #5 - Posted
2012-04-26 05:21:13 » |
|
Make the font white, draw it, then use AlphaComposite.SRC_IN to draw a colored rectangle above it.
|
|
|
|
joeyismusic
|
 |
«
Reply #6 - Posted
2012-04-26 15:50:41 » |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public static void test(Graphics2D g, String string, int x, int y, int cwidth, int color, int bgcolor) { int px = 0; int py = 0; char c; int sx; int sy; int pixel_x = 0; int pixel_y = 0; int ix = 0; int iy = 0; int i = 0; int src_color = 0; for(i = 0; i < string.length(); i++) { c = string.charAt(i); if(c == 32) { px += w * 2; if(px / (w * 2) > cwidth) { px = 0; py += h * 2; } continue; } sx = c; sy = 0; while(sx > 15) { sx -= 16; sy++; } sx *= w; sy *= h; pixel_x = x + px; pixel_y = y + py; g.drawImage(Art.font_white, pixel_x, pixel_y, pixel_x + w * 2, pixel_y + h * 2, sx, sy, sx + w, sy + h, null); px += w * 2; if(px / (w * 2) > cwidth) { px = 0; py += h * 2; } } Composite comp = g.getComposite(); g.setComposite(AlphaComposite.SrcIn); g.setColor(Color.red); g.fillRect(x, y, cwidth * 16, 32); g.setComposite(comp); } |
 What am I doing wrong? Here's what happens if I comment out the composite / fillrect section 
|
|
|
|
ra4king
|
 |
«
Reply #7 - Posted
2012-04-26 21:40:20 » |
|
You're supposed to set the Composite before you draw the rect  Also, make sure you reset the AlphaComposite to what it was previously after drawing the rect.
|
|
|
|
joeyismusic
|
 |
«
Reply #8 - Posted
2012-04-27 01:03:09 » |
|
did you read my code? because i did that.
|
|
|
|
joeyismusic
|
 |
«
Reply #9 - Posted
2012-04-27 01:20:30 » |
|
You're supposed to set the Composite before you draw the rect  Also, make sure you reset the AlphaComposite to what it was previously after drawing the rect. Oh wait, you're assuming that I'm rendering text to a image which gets drawn to another image, I think... which would explain why none of this is working because I'm just drawing the text (bitmapped font) directly onto the canvas. So I'm guessing this would work if I was using a BufferedImage just for text rendering, clearing it to black every frame (  ) and then using alpha composite to draw that to the canvas.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
ra4king
|
 |
«
Reply #10 - Posted
2012-04-27 01:23:24 » |
|
:O I must be going blind, I swear I saw you setting the AlphaComposite after the fillRect XD Anyway, according to the description of SRC_IN, only the overlapping source pixels are left. And I just realized that you are drawing the text directly onto the screen right? There are already pixels there  You need to draw onto a blank and transparent BufferedImage, then use the composite  EDIT: haha, you just posted the same thing  EDIT2: no, you simply need to clear the BufferedImage, draw the text, then draw the colored rect using the composite. After that, simply draw that image onto the screen.
|
|
|
|
joeyismusic
|
 |
«
Reply #11 - Posted
2012-04-27 01:26:40 » |
|
How do I clear the BufferedImage back to transparent each frame, to prevent dirty-ness 
|
|
|
|
ra4king
|
 |
«
Reply #12 - Posted
2012-04-27 01:31:47 » |
|
g.setComposite(AlphaComposite.CLEAR); g.setColor(new Color(0,0,0,0)); g.fillRect(0,0,width,height);
|
|
|
|
joeyismusic
|
 |
«
Reply #13 - Posted
2012-04-27 01:40:54 » |
|
oh my god it works
:evil laugh:
|
|
|
|
joeyismusic
|
 |
«
Reply #14 - Posted
2012-04-27 01:44:33 » |
|
BLAH! its not any faster than setRGB
|
|
|
|
ra4king
|
 |
«
Reply #15 - Posted
2012-04-27 02:07:27 » |
|
Try to reuse objects. This should be faster since you're not un-managing the BufferedImage.
|
|
|
|
joeyismusic
|
 |
«
Reply #16 - Posted
2012-04-27 02:35:43 » |
|
I read that setRGB doesn't unmanage the BufferedImage
|
|
|
|
ra4king
|
 |
«
Reply #17 - Posted
2012-04-27 02:51:23 » |
|
O_o last time I checked, it should.
|
|
|
|
joeyismusic
|
 |
«
Reply #18 - Posted
2012-04-27 03:02:31 » |
|
I get 47 FPS @ rendering 1872 characters (the most that will fit on the screen, at once) with both methods (setRGB, and the AlphaComposite)
I'm not recreating BufferedImages every frame or anything like that, so when you say re-use objects I'm not sure what you mean. I am already re-using objects.
|
|
|
|
ra4king
|
 |
«
Reply #19 - Posted
2012-04-27 03:40:16 » |
|
Hmm, well I would stick with the AlphaComposite way, but it really should be a bit faster. Oh well 
|
|
|
|
joeyismusic
|
 |
«
Reply #20 - Posted
2012-04-27 03:45:36 » |
|
Would it be stupid to keep switching the composite mode for each character being drawn, so the color rect that goes over it EXACTLY fits each letter drawn?
|
|
|
|
ra4king
|
 |
«
Reply #21 - Posted
2012-04-27 03:48:32 » |
|
How would it be any different from drawing 1 rect? Yes, it would be 
|
|
|
|
joeyismusic
|
 |
«
Reply #22 - Posted
2012-04-27 03:49:45 » |
|
There's no way to get a single rect to fit the shape of the text exactly if there's a line wrap.
|
|
|
|
ra4king
|
 |
«
Reply #23 - Posted
2012-04-27 03:54:25 » |
|
Then stretch the rect to the entire BufferedImage, or calculate the wrap.
|
|
|
|
joeyismusic
|
 |
«
Reply #24 - Posted
2012-04-27 03:56:55 » |
|
the stretch method won't allow multiple colors?
|
|
|
|
ra4king
|
 |
«
Reply #25 - Posted
2012-04-27 04:08:00 » |
|
Draw the letters, set the Composite, set the Color, fill the entire image, draw the image to the screen, clear the image. Repeat 
|
|
|
|
joeyismusic
|
 |
«
Reply #26 - Posted
2012-04-27 04:11:01 » |
|
oh are you saying to do all of that within one frame, per text && text_color?
so if i wanna draw something in red, then something in orange, i'm "drawing the letters, setting the composite, setting the color, filling the image, drawing the image, clearing the image" once for red, and once again for orange (all in the same rendering frame)
|
|
|
|
ra4king
|
 |
«
Reply #27 - Posted
2012-04-27 04:18:25 » |
|
Well if you want to draw multiple colors at time, you will have to know the X, Y, width and height of each letter draw, which you already should know. So you can do it all at one time. 1 2 3 4 5 6 7 8
| public void drawString(....) { for(each letter) { } } |
|
|
|
|
joeyismusic
|
 |
«
Reply #28 - Posted
2012-04-27 04:28:40 » |
|
er...
|
|
|
|
joeyismusic
|
 |
«
Reply #29 - Posted
2012-04-27 05:00:00 » |
|
Perhaps I did not explain my example very well...
Let's say I want to draw a string of information in red, and then later (somewhere else, in some other class or on some other GUI window) in a completely separate function call, I want to draw a string of information in orange.
|
|
|
|
|