I'm starter with Canvas and Paint. I want to paint a text in a Canvas but it can be longer than the original Bitmap. So the text go out the Bitmap.
Is there some kind of automatic manager for this making a new line when the end is reached? or should I play with heights and distances? Thanks
yes, you can manage this with a StaticLayout or DynamicLayout
The best way is to draw text with StaticLayout:
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(
gText, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth)/2;
float y = (bitmap.getHeight() - textHeight)/2;
// draw text to the Canvas center
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
See my blogpost for more details.
I would suggest that you also look at this code snippet found here:
https://stackoverflow.com/a/15092729/1759409
As it will manage the writing of your text within a certain width and height and automatically draws onto the canvas correctly.
Related
This problem seemed very obvious for me to solve, but whatever I try, it doesn't work. What I'm trying to do is to incorporate a mini-version of my PlayScreen in a ScrollPane as a tutorial where you can read text and try it out immediately.
Because I didn't find any better solution to add this to the Table inside the ScrollPane, I edited the draw() method of the PlayScreen to take the ScrollPane.getScrollPercentY() and offset the camera of the PlayScreen accordingly.
What I want to do now is to only render only part of the viewport that would be normally visible in the real game. Subsequently, I want to be able to control the size and position of this "window".
I also want to be able to resize and move the content, while cutting off the edges that are not visible to the camera. This is what I tried inside the PlayScreenDraw:
public void draw(final float yOffset,
final int xTiles,
final int yTiles) {
view.getCamera().position.y = yTiles / 2f - yOffset * yTiles / HEIGHT; // HEIGHT = 800
view.getCamera().position.x = xTiles / 2f;
view.setWorldSize(xTiles, yTiles); //Do i even need to change the world size?
b.setProjectionMatrix(view.getCamera().combined);
b.begin();
...
b.end();
view.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
What this gives me, in terms of the picture above, is this
How do I need to change the viewport and/or the camera? Btw., this is how i set the two up:
cam = new OrthographicCamera();
cam.setToOrtho(false, WIDTH, HEIGHT); // WIDTH = 8, HEIGHT = 16
batch.setProjectionMatrix(cam.combined);
view = new FitViewport(WIDTH, HEIGHT, cam);
The Pixmap class can help you achieve what you want since you stated that you wanted to "cut off" the parts outside of the green selection box.
You need to render what the camera sees to an FBO and then get the pixmap from the FBO itself.
Framebuffer Objects are OpenGL Objects, which allow for the creation of user-defined Framebuffers. With them, one can render to non-Default Framebuffer locations, and thus render without disturbing the main screen.
-- OpenGL wiki
// Construct an FBO and keep a reference to it. Remember to dispose of it.
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
public void render() {
//Start rendering to the fbo.
fbo.begin();
//From the camera's perspective.
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Draw whatever you want to draw with the camera.
batch.end();
// Finished drawing, get pixmap.
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, width, height);
//Stop drawing to your fbo.
fbo.end();
}
After getting the pixmap you can iterate through the pixels and set the alpha of the pixels outside your green selection window to 0 making them invisible or "cutting them off"
I'm working on a drawing application and am pretty close to release but I'm having issues with the eraser part of the app. I have 2 main screens (fragments) one is just a blank white canvas that the user can draw on with some options and so on. The other is a note taking fragment. This note taking fragment looks like notebook paper. So for erasing on the drawing fragment, I can simply use the background of the canvas and the user wont know the difference. On the note fragment though I cannot do this beacuse I need to keep the background in tact. I have looked into PorterDuffer modes and have tried the clear version and tried to draw onto a separate bitmap but nothing has worked. If there was a way to control what gets draw ontop of what then that would be useful. I'm open to any suggestions, I can't seem to get anything to work.
Ive also played with enabling a drawing cache before erasing and that doesn't work. In addition I tried hardware enabling and that made my custom view behave oddly. Below is the relavent code. My on draw methods goes through a lot of paths because I am querying them in order to allow for some other functionallity.
#Override
protected void onDraw(Canvas canvas) {
//draw the backgroumd type
if(mDrawBackground) {
//draw the background
//if the bitmap is not null draw it as the background, otherwise we are in a note view
if(mBackgroundBitmap != null) {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
} else {
drawBackgroundType(mBackgroundType, canvas);
}
}
for (int i = 0; i < paths.size(); i++ ) {
//Log.i("DRAW", "On draw: " + i);
//draw each previous path.
mDrawPaint.setStrokeWidth(strokeSizes.get(i));
mDrawPaint.setColor(colors.get(i));
canvas.drawPath(paths.get(i), mDrawPaint);
}
//set paint attributes to the current value
mDrawPaint.setStrokeWidth(strokeSize);
mDrawPaint.setColor(mDrawColor);
canvas.drawPath(mPath, mDrawPaint);
}
and my draw background method
/**
* Method that actually draws the notebook paper background
* #param canvas the {#code Canvas} to draw on.
*/
private void drawNoteBookPaperBackground(Canvas canvas) {
//create bitmap for the background and a temporary canvas.
mBackgroundBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBackgroundBitmap);
//set the color to white.
mBackgroundBitmap.eraseColor(Color.WHITE);
//get the height and width of the view minus padding.
int height = getHeight() - getPaddingTop() - getPaddingBottom();
int width = getWidth() - getPaddingLeft() - getPaddingRight();
//figure out how many lines we can draw given a certain line width.
int lineWidth = 50;
int numOfLines = Math.round(height / lineWidth);
Log.i("DRAWVIEW", "" + numOfLines);
//iterate through the number of lines and draw them.
for(int i = 0; i < numOfLines * lineWidth; i+=lineWidth) {
mCanvas.drawLine(0+getPaddingLeft(), i+getPaddingTop(), width, i+getPaddingTop(), mNoteBookPaperLinePaint);
}
//now we need to draw the vertical lines on the left side of the view.
float startPoint = 30;
//set the color to be red.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_vertical_line_color));
//draw first line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//space the second line next to the first one.
startPoint+=20;
//draw the second line
mCanvas.drawLine(startPoint, 0, startPoint, getHeight(), mNoteBookPaperLinePaint);
//reset the paint color.
mNoteBookPaperLinePaint.setColor(getResources().getColor(R.color.notebook_paper_horizontal_line_color));
canvas.drawBitmap(mBackgroundBitmap, 0, 0, backPaint);
}
To all who see this question I thought I would add how I solved the problem. What I'm doing is creating a background bitmap in my custom view and then passing that to my hosting fragment. The fragment then sets that bitmap as its background for the containing view group so that when I use the PorterDuff.CLEAR Xfermode, the drawn paths are cleared but the background in the fragment parent remains untouched.
I have some problems with font drawing in the center of the sprite. The sprite is moving along the screen. I set my orthographic camera to:
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(1, h/w);
and:
Sprite spr = new Sprite(starTx);
spr.setSize(0.3f, 0.3f);
spr.setOrigin(0.15f, 0.15f);
spr.setPosition(0.2f, 0.25f*(i+1));
Inside render I have the code:
batch.setProjectionMatrix(camera.combined);
batch.begin();
spr.draw(batch);
font.setScale(1, (w/h)*3);
font.draw(batchFont, mDate, valueX, valueY);
batch.end();
I must draw the font in the center of the sprite. Could anyone tell me how to calculate valueX and ValueY?
Not exactly what you posted, the screen width is 1, so multiplying for it is useless :p More general approach:
valueX = spr.getX()+spr.getWidth()/2F;
valueY = spr.getY()+spr.getHeight()/2F;
I have found a good way to draw text in openGL by creating a Bitmap, drawing text on it, and making it into a texture.
I have screenCoordinates(320,~~480) and gameCoordinates(20,28), in which quads' dimensions are defined. Example constructor: GameObject(x, y, width, height, text).
To create the bitmap I create a Canvas with this size:
// get width and height in px (p is a Paint() object)
p.setTextSize(textSize * Main.getMainResources().getDisplayMetrics().density);
final int width = (int) p.measureText(text);
final int height = (int) (p.descent() + -p.ascent());
canvas.drawText(text, 0, -p.ascent(), p);
Create a bitmap of this, scaled to the next power of 2, and you have your texture-bitmap.
However the problem is that because the quad's dimensions are not adapted to the bitmap(text) dimensions, the text isn't very smooth. I have the possibility to change the quad's dimensions with quad.setDimensions(width, height), but what would be the size I'd have to give it, and also shouldn't I also have to worry about the textSize(sp) of the text i'm drawing?
This all is in 2D, and some simple math's might get involved, but how should I get the right dimensions?
i want my Bitmap that has the height of the screen and has a bigger width than the screen to be moved a little bit to the right or left if the user changes the desktop so he can see the entire image.
Here is my code that just works partially:
int x = -1*(int)((xOffset*bmp.getWidth()));
canvas.drawBitmap(bmp, x, 0, null);
thank you!
You get exact pixel values via the variables xPixels and yPixels in onOffsetsChanged(). See my answer here: android live wallpaper rescaling
For example, in onOffsetsChanged(), you can set a private class variable
mPixels = xPixels;
Then, in your draw routine
holder = getSurfaceHolder();
c = holder.lockCanvas();
c.translate(mPixels, 0f);
// c.drawBitmap ... goes here :-)
Typically, you will want a bitmap twice the width of your screen, with your artwork centered in the middle. For example: 320 pixel width screen -> 640 pixel width bitmap with "center" from 160 to 480. mPixels will be 0 at the left most launcher screen (of 5), -160 at the center, and -320 at the rightmost screen.