use of com.badlogic.gdx.math.Rectangle in project libgdx by libgdx.
the class FreeTypeFontGenerator method createGlyph.
/** @return null if glyph was not found. */
Glyph createGlyph(char c, FreeTypeBitmapFontData data, FreeTypeFontParameter parameter, Stroker stroker, float baseLine, PixmapPacker packer) {
boolean missing = face.getCharIndex(c) == 0 && c != 0;
if (missing)
return null;
if (!loadChar(c, getLoadingFlags(parameter)))
return null;
GlyphSlot slot = face.getGlyph();
FreeType.Glyph mainGlyph = slot.getGlyph();
try {
mainGlyph.toBitmap(parameter.mono ? FreeType.FT_RENDER_MODE_MONO : FreeType.FT_RENDER_MODE_NORMAL);
} catch (GdxRuntimeException e) {
mainGlyph.dispose();
Gdx.app.log("FreeTypeFontGenerator", "Couldn't render char: " + c);
return null;
}
Bitmap mainBitmap = mainGlyph.getBitmap();
Pixmap mainPixmap = mainBitmap.getPixmap(Format.RGBA8888, parameter.color, parameter.gamma);
if (mainBitmap.getWidth() != 0 && mainBitmap.getRows() != 0) {
int offsetX = 0, offsetY = 0;
if (parameter.borderWidth > 0) {
// execute stroker; this generates a glyph "extended" along the outline
int top = mainGlyph.getTop(), left = mainGlyph.getLeft();
FreeType.Glyph borderGlyph = slot.getGlyph();
borderGlyph.strokeBorder(stroker, false);
borderGlyph.toBitmap(parameter.mono ? FreeType.FT_RENDER_MODE_MONO : FreeType.FT_RENDER_MODE_NORMAL);
offsetX = left - borderGlyph.getLeft();
offsetY = -(top - borderGlyph.getTop());
// Render border (pixmap is bigger than main).
Bitmap borderBitmap = borderGlyph.getBitmap();
Pixmap borderPixmap = borderBitmap.getPixmap(Format.RGBA8888, parameter.borderColor, parameter.borderGamma);
// Draw main glyph on top of border.
for (int i = 0, n = parameter.renderCount; i < n; i++) borderPixmap.drawPixmap(mainPixmap, offsetX, offsetY);
mainPixmap.dispose();
mainGlyph.dispose();
mainPixmap = borderPixmap;
mainGlyph = borderGlyph;
}
if (parameter.shadowOffsetX != 0 || parameter.shadowOffsetY != 0) {
int mainW = mainPixmap.getWidth(), mainH = mainPixmap.getHeight();
int shadowOffsetX = Math.max(parameter.shadowOffsetX, 0), shadowOffsetY = Math.max(parameter.shadowOffsetY, 0);
int shadowW = mainW + Math.abs(parameter.shadowOffsetX), shadowH = mainH + Math.abs(parameter.shadowOffsetY);
Pixmap shadowPixmap = new Pixmap(shadowW, shadowH, mainPixmap.getFormat());
Color shadowColor = parameter.shadowColor;
float a = shadowColor.a;
if (a != 0) {
byte r = (byte) (shadowColor.r * 255), g = (byte) (shadowColor.g * 255), b = (byte) (shadowColor.b * 255);
ByteBuffer mainPixels = mainPixmap.getPixels();
ByteBuffer shadowPixels = shadowPixmap.getPixels();
for (int y = 0; y < mainH; y++) {
int shadowRow = shadowW * (y + shadowOffsetY) + shadowOffsetX;
for (int x = 0; x < mainW; x++) {
int mainPixel = (mainW * y + x) * 4;
byte mainA = mainPixels.get(mainPixel + 3);
if (mainA == 0)
continue;
int shadowPixel = (shadowRow + x) * 4;
shadowPixels.put(shadowPixel, r);
shadowPixels.put(shadowPixel + 1, g);
shadowPixels.put(shadowPixel + 2, b);
shadowPixels.put(shadowPixel + 3, (byte) ((mainA & 0xff) * a));
}
}
}
// Draw main glyph (with any border) on top of shadow.
for (int i = 0, n = parameter.renderCount; i < n; i++) shadowPixmap.drawPixmap(mainPixmap, Math.max(-parameter.shadowOffsetX, 0), Math.max(-parameter.shadowOffsetY, 0));
mainPixmap.dispose();
mainPixmap = shadowPixmap;
} else if (parameter.borderWidth == 0) {
// No shadow and no border, draw glyph additional times.
for (int i = 0, n = parameter.renderCount - 1; i < n; i++) mainPixmap.drawPixmap(mainPixmap, 0, 0);
}
}
GlyphMetrics metrics = slot.getMetrics();
Glyph glyph = new Glyph();
glyph.id = c;
glyph.width = mainPixmap.getWidth();
glyph.height = mainPixmap.getHeight();
glyph.xoffset = mainGlyph.getLeft();
glyph.yoffset = parameter.flip ? -mainGlyph.getTop() + (int) baseLine : -(glyph.height - mainGlyph.getTop()) - (int) baseLine;
glyph.xadvance = FreeType.toInt(metrics.getHoriAdvance()) + (int) parameter.borderWidth + parameter.spaceX;
if (bitmapped) {
mainPixmap.setColor(Color.CLEAR);
mainPixmap.fill();
ByteBuffer buf = mainBitmap.getBuffer();
int whiteIntBits = Color.WHITE.toIntBits();
int clearIntBits = Color.CLEAR.toIntBits();
for (int h = 0; h < glyph.height; h++) {
int idx = h * mainBitmap.getPitch();
for (int w = 0; w < (glyph.width + glyph.xoffset); w++) {
int bit = (buf.get(idx + (w / 8)) >>> (7 - (w % 8))) & 1;
mainPixmap.drawPixel(w, h, ((bit == 1) ? whiteIntBits : clearIntBits));
}
}
}
Rectangle rect = packer.pack(mainPixmap);
// Glyph is always packed into the last page for now.
glyph.page = packer.getPages().size - 1;
glyph.srcX = (int) rect.x;
glyph.srcY = (int) rect.y;
// If a page was added, create a new texture region for the incrementally added glyph.
if (parameter.incremental && data.regions != null && data.regions.size <= glyph.page)
packer.updateTextureRegions(data.regions, parameter.minFilter, parameter.magFilter, parameter.genMipMaps);
mainPixmap.dispose();
mainGlyph.dispose();
return glyph;
}
use of com.badlogic.gdx.math.Rectangle in project libgdx by libgdx.
the class ParticleEmitter method getBoundingBox.
/** Returns the bounding box for all active particles. z axis will always be zero. */
public BoundingBox getBoundingBox() {
if (bounds == null)
bounds = new BoundingBox();
Particle[] particles = this.particles;
boolean[] active = this.active;
BoundingBox bounds = this.bounds;
bounds.inf();
for (int i = 0, n = active.length; i < n; i++) if (active[i]) {
Rectangle r = particles[i].getBoundingRectangle();
bounds.ext(r.x, r.y, 0);
bounds.ext(r.x + r.width, r.y + r.height, 0);
}
return bounds;
}
use of com.badlogic.gdx.math.Rectangle in project libgdx by libgdx.
the class PixmapPacker method pack.
/** Inserts the pixmap. If name was not null, you can later retrieve the image's position in the output image via
* {@link #getRect(String)}.
* @param name If null, the image cannot be looked up by name.
* @return Rectangle describing the area the pixmap was rendered to.
* @throws GdxRuntimeException in case the image did not fit due to the page size being too small or providing a duplicate
* name. */
public synchronized Rectangle pack(String name, Pixmap image) {
if (disposed)
return null;
if (name != null && getRect(name) != null)
throw new GdxRuntimeException("Pixmap has already been packed with name: " + name);
Rectangle rect = new Rectangle(0, 0, image.getWidth(), image.getHeight());
if (rect.getWidth() > pageWidth || rect.getHeight() > pageHeight) {
if (name == null)
throw new GdxRuntimeException("Page size too small for pixmap.");
throw new GdxRuntimeException("Page size too small for pixmap: " + name);
}
Page page = packStrategy.pack(this, name, rect);
if (name != null) {
page.rects.put(name, rect);
page.addedRects.add(name);
}
int rectX = (int) rect.x, rectY = (int) rect.y, rectWidth = (int) rect.width, rectHeight = (int) rect.height;
if (packToTexture && !duplicateBorder && page.texture != null && !page.dirty) {
page.texture.bind();
Gdx.gl.glTexSubImage2D(page.texture.glTarget, 0, rectX, rectY, rectWidth, rectHeight, image.getGLFormat(), image.getGLType(), image.getPixels());
} else
page.dirty = true;
page.image.setBlending(Blending.None);
page.image.drawPixmap(image, rectX, rectY);
if (duplicateBorder) {
int imageWidth = image.getWidth(), imageHeight = image.getHeight();
// Copy corner pixels to fill corners of the padding.
page.image.drawPixmap(image, 0, 0, 1, 1, rectX - 1, rectY - 1, 1, 1);
page.image.drawPixmap(image, imageWidth - 1, 0, 1, 1, rectX + rectWidth, rectY - 1, 1, 1);
page.image.drawPixmap(image, 0, imageHeight - 1, 1, 1, rectX - 1, rectY + rectHeight, 1, 1);
page.image.drawPixmap(image, imageWidth - 1, imageHeight - 1, 1, 1, rectX + rectWidth, rectY + rectHeight, 1, 1);
// Copy edge pixels into padding.
page.image.drawPixmap(image, 0, 0, imageWidth, 1, rectX, rectY - 1, rectWidth, 1);
page.image.drawPixmap(image, 0, imageHeight - 1, imageWidth, 1, rectX, rectY + rectHeight, rectWidth, 1);
page.image.drawPixmap(image, 0, 0, 1, imageHeight, rectX - 1, rectY, 1, rectHeight);
page.image.drawPixmap(image, imageWidth - 1, 0, 1, imageHeight, rectX + rectWidth, rectY, 1, rectHeight);
}
return rect;
}
use of com.badlogic.gdx.math.Rectangle in project libgdx by libgdx.
the class PixmapPacker method updateTextureAtlas.
/** Updates the {@link TextureAtlas}, adding any new {@link Pixmap} instances packed since the last call to this method. This
* can be used to insert Pixmap instances on a separate thread via {@link #pack(String, Pixmap)} and update the TextureAtlas on
* the rendering thread. This method must be called on the rendering thread. After calling this method, disposing the packer
* will no longer dispose the page pixmaps. */
public synchronized void updateTextureAtlas(TextureAtlas atlas, TextureFilter minFilter, TextureFilter magFilter, boolean useMipMaps) {
updatePageTextures(minFilter, magFilter, useMipMaps);
for (Page page : pages) {
if (page.addedRects.size > 0) {
for (String name : page.addedRects) {
Rectangle rect = page.rects.get(name);
TextureRegion region = new TextureRegion(page.texture, (int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
atlas.addRegion(name, region);
}
page.addedRects.clear();
atlas.getTextures().add(page.texture);
}
}
}
use of com.badlogic.gdx.math.Rectangle in project libgdx by libgdx.
the class PixmapPackerIO method save.
/** Saves the provided PixmapPacker to the provided file. The resulting file will use the standard TextureAtlas file format and
* can be loaded by TextureAtlas as if it had been created using TexturePacker.
*
* @param file the file to which the atlas descriptor will be written, images will be written as siblings
* @param packer the PixmapPacker to be written
* @param parameters the SaveParameters specifying how to save the PixmapPacker
* @throws IOException if the atlas file can not be written */
public void save(FileHandle file, PixmapPacker packer, SaveParameters parameters) throws IOException {
Writer writer = file.writer(false);
int index = 0;
for (Page page : packer.pages) {
if (page.rects.size > 0) {
FileHandle pageFile = file.sibling(file.nameWithoutExtension() + "_" + (++index) + parameters.format.getExtension());
switch(parameters.format) {
case CIM:
{
PixmapIO.writeCIM(pageFile, page.image);
break;
}
case PNG:
{
PixmapIO.writePNG(pageFile, page.image);
break;
}
}
writer.write("\n");
writer.write(pageFile.name() + "\n");
writer.write("size: " + page.image.getWidth() + "," + page.image.getHeight() + "\n");
writer.write("format: " + packer.pageFormat.name() + "\n");
writer.write("filter: " + parameters.minFilter.name() + "," + parameters.magFilter.name() + "\n");
writer.write("repeat: none" + "\n");
for (String name : page.rects.keys()) {
writer.write(name + "\n");
Rectangle rect = page.rects.get(name);
writer.write("rotate: false" + "\n");
writer.write("xy: " + (int) rect.x + "," + (int) rect.y + "\n");
writer.write("size: " + (int) rect.width + "," + (int) rect.height + "\n");
writer.write("orig: " + (int) rect.width + "," + (int) rect.height + "\n");
writer.write("offset: 0, 0" + "\n");
writer.write("index: -1" + "\n");
}
}
}
writer.close();
}
Aggregations