How do I create a simple rounded rectangle button in libgdx without using images? The button should have a drop shadow and should handle pressed state. I want it to be programmatic to make it easy to change the color, style later, etc.
My understanding of your question was how to create a rounded rectangle within the program without having to pre-generate any images outside of code.
I was in a similar situation a while back and I ended writing the function below which generates a Pixmap rounded rectangle based on the parameters (all units are in pixels). It also works with differing alpha values to allow for opacity (which is why there are two Pixmap objects used).
The resulting Pixmap can then easily be passed to a constructor of a Texture if you find that easier to render with.
public static Pixmap createRoundedRectangle(int width, int height, int cornerRadius, Color color) {
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
Pixmap ret = new Pixmap(width, height, Pixmap.Format.RGBA8888);
pixmap.setColor(color);
pixmap.fillCircle(cornerRadius, cornerRadius, cornerRadius);
pixmap.fillCircle(width - cornerRadius - 1, cornerRadius, cornerRadius);
pixmap.fillCircle(cornerRadius, height - cornerRadius - 1, cornerRadius);
pixmap.fillCircle(width - cornerRadius - 1, height - cornerRadius - 1, cornerRadius);
pixmap.fillRectangle(cornerRadius, 0, width - cornerRadius * 2, height);
pixmap.fillRectangle(0, cornerRadius, width, height - cornerRadius * 2);
ret.setColor(color);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (pixmap.getPixel(x, y) != 0) ret.drawPixel(x, y);
}
}
pixmap.dispose();
return ret;
}
Using this function it shouldn't be too difficult to make your own wrapper object (e.g. RoundedRectangle) which would re-draw the image every time one of the parameters was changed and needed to be rendered.
Related
I know that there are many questions related to this, but none are relevant to my problem.
So, I have a TiledMap which has 2 layers for boxes in my game - one for the box graphics and one for the box objects. Now, I want to get the textures of all the boxes because I want to be able to draw them anywhere freely. So I wrote some code to find out which tiles a given rectangle (attained from the object layer of the boxes) is covering (this code works fine). Then, from the graphics layer (TileMapTileLayer), I am accessing the textures in those tiles and drawing them to a single texture using Pixmaps. Finally, I store this texture. However, when I render these textures, they are black. Heres the code -
TiledMapTileLayer boxLayer = (TiledMapTileLayer) (map.getLayers().get(2)); // this is the graphics layer
ArrayList<Vector2> cells;
Texture tex;
Pixmap pmap, pmapScld;
int numCols, numRows, cellNum;
int boxInd = 0;
FileTextureData texData;
StaticTiledMapTile tile;
for(RectangleMapObject boxBody : map.getLayers().get(3).getObjects().getByType(RectangleMapObject.class)) { //object layer
bounds = boxBody.getRectangle();
cells = getOccupiedCells(bounds);
numCols = (int) cells.get(0).x; //I have stored the width and height of the texture
numRows = (int) cells.get(0).y; //in tiles in the first Vector2 of the Array
tex = new Texture(numCols * tileWidthOrg, numRows * tileHeightOrg, Format.RGBA8888);
cellNum = 1;
System.out.println(cells);
for(int i = 0 ; i < numCols ; i++) {
for(int j = 0 ; j < numRows ; j++) {
tile = (StaticTiledMapTile) (boxLayer.getCell((int) cells.get(cellNum).x, (int) cells.get(cellNum).y).getTile());
texData = (FileTextureData) tile.getTextureRegion().getTexture().getTextureData();
texData.prepare();
pmap = texData.consumePixmap();
//pmapScld = new Pixmap(tileWidthScld, tileHeightScld, pmap.getFormat());
//pmapScld.drawPixmap(pmap, 0, pmap.getHeight(), pmap.getWidth(), pmap.getHeight(),
//0, pmapScld.getHeight(), pmapScld.getWidth(), pmapScld.getHeight());
tex.draw(pmap, i * tileWidthOrg, j * tileHeightOrg);
pmap.dispose();
texData.disposePixmap();
//pmapScld.dispose();
cellNum++;
}
}
contactListener.addBox(new GBox(world, tex, bounds, boxInd));
tex.dispose();
boxInd++;
}
The code for rendering these boxes -
for(GBox box : contactListener.boxes) {
box.render(sb);
}
public void render(SpriteBatch sb) {
sb.draw(tex, body.getPosition().x - width / 2, body.getPosition().y - height / 2, width, height);
//System.out.println("rendering box " + index + " at position " + body.getPosition());
}
I've been working on a Typescript based touch screen client for our CQC home automation platform, and ran across something odd. There are lots of places where various graphical elements are layered over images. When it's time to update some area of the screen, I set a clip area and update.
But I always ended up with a line around everything, which was the color of the underlying color fill behind the image. I of course blamed myself. But, in the end, instead of committing suicide, I did a little test program.
It seems to indicate that drawImage() does NOT include the clip path boundary, while a color fill does. So blitting over the part of the images that underlies the area I'm updating doesn't completely fill the target area, leaving a line around the area.
After that simple program demonstrated the problem, I went back and for image updates I inflated the clip area by one, but left it alone for everything else, and now it's all working. I tested this in Chrome and Edge, just to make sure it wasn't some bug, and they both act exactly the same.
Strangely, I've never see any statement in the docs about whether clip paths are intended to be exclusive or inclusive of the boundary, but surely it shouldn't be one way for one type of primitive and another way for others, right?
function drawRect(ctx, x, y, w, h) {
ctx.moveTo(x, y);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w, y + h);
ctx.lineTo(x, y + h);
ctx.lineTo(x, y);
}
function init()
{
var canvas = document.getElementById("output");
canvas.style.width = 480;
canvas.style.height = 480;
canvas.width = 480;
canvas.height = 480;
var drawCtx = canvas.getContext("2d");
drawCtx.translate(0.5, 0.5);
var img = new Image();
img.src = "test.jpg";
img.onload = function() {
// DRaw the image
drawCtx.drawImage(img, 0, 0);
// SEt a clip path
drawCtx.beginPath();
drawRect(drawCtx, 10, 10, 200, 200);
drawCtx.clip();
// Fill the whole area, which fills the clip area
drawCtx.fillStyle = "black";
drawCtx.fillRect(0, 0, 480, 480);
// Draw the image again, which should fill the area
drawCtx.drawImage(img, 0, 0);
// But it ends up with a black line around it
}
}
window.addEventListener("load", init, false);
I think they behave same.
Clip region are not inclusive of the border, but they can use anti aliasing.
Chrome was not using this techinque and was giving jagged lines on clipping. ( probably they changed recently ).
The thin black border is the side effect of a compositing operation.
The clip region is across a pixel. so the fillRect will draw black everywhere, but the border will be 50% black and 50% transparent, compositing with the first image draw.
The second draw image get clpped, at the border with 50% opacity to simulate the half pixel. at this point at the clip border you have:
image 100%
black fill 50%
image 50%
This will make a small dark border appear.
function drawRect(ctx, x, y, w, h) {
ctx.moveTo(x, y);
ctx.lineTo(x, y + h);
ctx.lineTo(x + w, y + h);
ctx.lineTo(x + w, y);
ctx.closePath();
}
function init()
{
var canvas = document.getElementById("output");
canvas.style.width = 480;
canvas.style.height = 480;
canvas.width = 480;
canvas.height = 480;
var drawCtx = canvas.getContext("2d");
drawCtx.translate(0.5, 0.5);
var img = new Image();
img.src = "http://fabricjs.com/assets/printio.png";
img.onload = function() {
// DRaw the image
drawCtx.drawImage(img, 0, 0);
// SEt a clip path
drawCtx.beginPath();
drawRect(drawCtx, 10, 10, 200, 200);
drawCtx.clip();
// Fill the whole area, which fills the clip area
drawCtx.fillStyle = "black";
drawCtx.fillRect(0, 0, 480, 480);
// Draw the image again, which should fill the area
drawCtx.drawImage(img, 0, 0);
// But it ends up with a black line around it
}
}
init();
<canvas id="output" />
How do I create Pixmap from TextureRegion or from Sprite? I need this in order to change color of some pixels and then create new Texture from Pixmap (during loading screen).
Texture texture = textureRegion.getTexture();
if (!texture.getTextureData().isPrepared()) {
texture.getTextureData().prepare();
}
Pixmap pixmap = texture.getTextureData().consumePixmap();
If you want only a part of that texture (the region), then you'll have to do some manual processing:
for (int x = 0; x < textureRegion.getRegionWidth(); x++) {
for (int y = 0; y < textureRegion.getRegionHeight(); y++) {
int colorInt = pixmap.getPixel(textureRegion.getRegionX() + x, textureRegion.getRegionY() + y);
// you could now draw that color at (x, y) of another pixmap of the size (regionWidth, regionHeight)
}
}
If you don't want to walk through the TextureRegion Pixel by Pixel you also can draw the Region onto a new Pixmap
public Pixmap extractPixmapFromTextureRegion(TextureRegion textureRegion) {
TextureData textureData = textureRegion.getTexture().getTextureData()
if (!textureData.isPrepared()) {
textureData.prepare();
}
Pixmap pixmap = new Pixmap(
textureRegion.getRegionWidth(),
textureRegion.getRegionHeight(),
textureData.getFormat()
);
pixmap.drawPixmap(
textureData.consumePixmap(), // The other Pixmap
0, // The target x-coordinate (top left corner)
0, // The target y-coordinate (top left corner)
textureRegion.getRegionX(), // The source x-coordinate (top left corner)
textureRegion.getRegionY(), // The source y-coordinate (top left corner)
textureRegion.getRegionWidth(), // The width of the area from the other Pixmap in pixels
textureRegion.getRegionHeight() // The height of the area from the other Pixmap in pixels
);
return pixmap;
}
I'm trying to run DFT in 4x4 blocks over this image (look closely, it's small) It may be a bit too small to see, but it's a 4x12 pixel image. The first 4x4 square is a checkerboard pattern with each square having one pixel, the second 4x4 square is the same pattern with each square having two pixels, and the last 4x4 square is a black square.
The problem I have is that the frequency components I get are not what I expect at all. For example, for the first square I expect to have a DC component in the matrix, but it's not there. I figure I must be doing something wrong but I'm new to EMGU so I'm not sure what. Below is my code.
using (Image<Bgr, byte> image = new Image<Bgr, byte>(Openfile.FileName))
using (Image<Gray, float> gray = image.Convert<Gray, float>())
{
int numRectanglesPerRow = image.Width / WIDTH;
int numRectanglesPerColumn = image.Height / HEIGHT;
for (int i = 0; i < numRectanglesPerColumn; i++)
{
for (int j = 0; j < numRectanglesPerRow; j++)
{
Rectangle rectangle = new Rectangle(WIDTH * j, HEIGHT * i, WIDTH, HEIGHT);
Image<Gray, float> subImage = gray.Copy(rectangle);
Matrix<float> dft = new Matrix<float>(subImage.Rows, subImage.Cols, 2);
CvInvoke.cvDFT(subImage, dft, Emgu.CV.CvEnum.CV_DXT.CV_DXT_FORWARD, -1);
//The Real part of the Fourier Transform
Matrix<float> outReal = new Matrix<float>(subImage.Size);
//The imaginary part of the Fourier Transform
Matrix<float> outIm = new Matrix<float>(subImage.Size);
CvInvoke.cvSplit(dft, outReal, outIm, IntPtr.Zero, IntPtr.Zero);
}
}
}
I'm trying to scale a base image based on a movieclip's x and y position? The base image image is also a MC.
infoIconCompFit.addEventListener(MouseEvent.ROLL_OVER, zoomInCompFit);
infoIconCompFit.addEventListener(MouseEvent.ROLL_OUT, zoomOutCompFit);
function zoomInCompFit(event:MouseEvent):void {
TweenLite.to(baseImage, 1, {scaleX:2, scaleY:2});
}
function zoomOutCompFit(event:MouseEvent):void {
TweenLite.to(baseImage, 1, {scaleX:1, scaleY:1});
}
What I mean is; is it possible to scale a movieclip at another movieclip's x and y position on the stage? Like I want the base movieclip to scale (zoom in) at the position of another movieclip on Mouse ROLL_OVER then zoom out on Mouse ROLL_OUT.
I get it to where it zooms in and out on the handlers, but how do I get it to zoom at that position relative to the other MC?
(Before) http://www.marketingfanatics.co.za/images/exampleNormal.jpg
(After) http://www.marketingfanatics.co.za/images/exampleZoomedl.jpg
Yes you can. But you need to write some code and have in mind where is transformation pivot of those Objects.
/**
* Calculate position and dimensions of image to zoom.
* #param img - image to animate, need to have transformation pivot in top left corner!
* #param point - point to zoom in (or null if zoom out) that will be new center of image
* #param scale - scale in zoom in
* #param viewWidth - container width
* #param viewHeight - container height
* #return object for tween engine with parameters to animate
*/
private function centerOn(img:DisplayObject, point:Point=null, scale:Number=2, viewWidth:Number=300, viewHeight:Number=200):Object
{
var r:Object;
var mm:Matrix = img.transform.matrix;
img.transform.matrix = new Matrix();
if (point == null) { // oryginal size
r = { x: 0, y: 0, width: img.width, height: img.height };
}else { // zoom
img.scaleX = img.scaleY = scale;
point.x *= scale;
point.y *= scale;
img.x = -point.x + viewWidth / 2;
img.y = -point.y + viewHeight / 2;
r = { x: img.x, y: img.y, width: img.width, height: img.height };
}
img.transform.matrix = mm;
return r;
}
Use example:
TweenLite.to(baseImage, 1, centerOn(baseIMG, new Point(100, 150))); //zoom in
TweenLite.to(baseImage, 1, centerOn(baseIMG)); //zoom out
centerOn(img, new Point(200, 135), 4, stage.stageWidth, stage.stageHeight); // to fit stage size
Remember that your Display Object is not masked and sometimes (zoom near borders) you will see scene under it!
PS. Code tested.