aboutsummaryrefslogtreecommitdiffstats
path: root/ardor3d-core
diff options
context:
space:
mode:
Diffstat (limited to 'ardor3d-core')
-rw-r--r--ardor3d-core/src/main/java/com/ardor3d/ui/text/BMTextBackground.java308
1 files changed, 308 insertions, 0 deletions
diff --git a/ardor3d-core/src/main/java/com/ardor3d/ui/text/BMTextBackground.java b/ardor3d-core/src/main/java/com/ardor3d/ui/text/BMTextBackground.java
new file mode 100644
index 0000000..f3a474b
--- /dev/null
+++ b/ardor3d-core/src/main/java/com/ardor3d/ui/text/BMTextBackground.java
@@ -0,0 +1,308 @@
+/**
+ * Copyright (c) 2008-2017 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <https://github.com/Renanse/Ardor3D/blob/master/LICENSE>.
+ */
+
+package com.ardor3d.ui.text;
+
+import java.io.IOException;
+import java.nio.FloatBuffer;
+
+import com.ardor3d.image.Image;
+import com.ardor3d.image.Texture;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector4;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.math.type.ReadOnlyVector2;
+import com.ardor3d.math.type.ReadOnlyVector4;
+import com.ardor3d.renderer.IndexMode;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.renderer.state.ZBufferState;
+import com.ardor3d.scenegraph.IndexBufferData;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.hint.CullHint;
+import com.ardor3d.scenegraph.hint.LightCombineMode;
+import com.ardor3d.scenegraph.hint.TextureCombineMode;
+import com.ardor3d.util.export.InputCapsule;
+import com.ardor3d.util.export.OutputCapsule;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * A 9-slice capable background, suitable for sitting behind BMText to increase readability.
+ *
+ * @author Mark B. Allan
+ * @author Joshua Slack
+ */
+public class BMTextBackground extends Mesh implements BMTextChangeListener {
+
+ final BMText _text;
+ ColorRGBA _tintColor = new ColorRGBA(ColorRGBA.WHITE);
+
+ Vector4 _textureBorderOffsets = new Vector4();
+ Vector4 _contentPadding = new Vector4();
+ float _borderScale = 1f;
+
+ transient Texture _texture;
+
+ public BMTextBackground(final String name, final BMText text, final Texture texture) {
+ this(name, text, texture, new Vector4(0.25, 0.25, 0.25, 0.25));
+ }
+
+ public BMTextBackground(final String name, final BMText text, final Texture texture,
+ final ReadOnlyVector4 textureBorderOffsets) {
+ super(name);
+ _text = text;
+ _texture = texture;
+
+ _textureBorderOffsets.set(textureBorderOffsets);
+ setRenderStates(texture);
+
+ // allocate vertex data
+ _meshData.setVertexBuffer(BufferUtils.createVector3Buffer(16));
+ _meshData.setTextureBuffer(BufferUtils.createVector2Buffer(16), 0);
+ _meshData.setIndices(BufferUtils.createIndexBufferData(28, 15));
+
+ // Set initial static data.
+ setTextureData();
+ setIndexData();
+
+ // -- add self as change listener
+ _text.addChangeListener(this);
+ }
+
+ private void setRenderStates(final Texture texture) {
+ final BlendState bs = new BlendState();
+ bs.setBlendEnabled(true);
+ bs.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
+ bs.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
+ bs.setTestEnabled(true);
+ bs.setReference(0.5f);
+ bs.setTestFunction(BlendState.TestFunction.GreaterThan);
+ // setRenderState(bs);
+
+ final TextureState ts = new TextureState();
+ ts.setTexture(texture);
+ setRenderState(ts);
+
+ final ZBufferState zs = new ZBufferState();
+ zs.setWritable(false);
+ setRenderState(zs);
+
+ setDefaultColor(_tintColor);
+ setModelBound(null);
+
+ getSceneHints().setLightCombineMode(LightCombineMode.Off);
+ getSceneHints().setTextureCombineMode(TextureCombineMode.Replace);
+ getSceneHints().setCullHint(CullHint.Never);
+ }
+
+ private void setIndexData() {
+ final IndexBufferData<?> indices = _meshData.getIndices();
+ indices.getBuffer().rewind();
+ indices.put(9).put(5).put(10).put(6);
+ indices.put(4).put(0).put(5).put(1).put(6).put(2);
+ indices.put(2).put(3).put(6).put(7).put(10).put(11);
+ indices.put(11).put(15).put(10).put(14).put(9).put(13);
+ indices.put(13).put(12).put(9).put(8).put(5).put(4);
+ _meshData.setIndexLengths(new int[] { 4, 6, 6, 6, 6 });
+ _meshData.setIndexMode(IndexMode.TriangleStrip);
+ }
+
+ private void setTextureData() {
+ // x = left, y = top, z = right, w = bottom
+ final FloatBuffer coords = _meshData.getTextureBuffer(0);
+ coords.rewind();
+ coords.put(0).put(0);
+ coords.put(_textureBorderOffsets.getXf()).put(0);
+ coords.put(1f - _textureBorderOffsets.getZf()).put(0);
+ coords.put(1).put(0);
+
+ coords.put(0).put(_textureBorderOffsets.getWf());
+ coords.put(_textureBorderOffsets.getXf()).put(_textureBorderOffsets.getWf());
+ coords.put(1f - _textureBorderOffsets.getZf()).put(_textureBorderOffsets.getWf());
+ coords.put(1).put(_textureBorderOffsets.getWf());
+
+ coords.put(0).put(1f - _textureBorderOffsets.getYf());
+ coords.put(_textureBorderOffsets.getXf()).put(1f - _textureBorderOffsets.getYf());
+ coords.put(1f - _textureBorderOffsets.getZf()).put(1f - _textureBorderOffsets.getYf());
+ coords.put(1).put(1f - _textureBorderOffsets.getYf());
+
+ coords.put(0).put(1);
+ coords.put(_textureBorderOffsets.getXf()).put(1);
+ coords.put(1f - _textureBorderOffsets.getZf()).put(1);
+ coords.put(1).put(1);
+ }
+
+ public void setBackgroundColor(final ReadOnlyColorRGBA color) {
+ _tintColor.set(color);
+ textAlphaChanged(_text, _text.getDefaultColor().getAlpha());
+ }
+
+ /**
+ * Sets the scale of the 9 slice border texture. By default this is set to 1 meaning we attempt to make it pixel
+ * perfect. If the source texture is too large or small, leading to an undesired border size, changing this value
+ * will adjust the border without scaling other transform values.
+ */
+ public void setBorderScale(final float scale) {
+ _borderScale = scale;
+ textSizeChanged(_text, _text.getSize());
+ }
+
+ public float getBorderScale() {
+ return _borderScale;
+ }
+
+ /**
+ * Splits up the texture drawn on this background into a grid. x,y,z, and w of the given vector are interpreted as
+ * the u/v coordinate offset from the left, top, right and bottom edges of the texture respectively. This forms a 9
+ * slice/patch grid. The edges of the grid are stretched along their given axis to fit. The corners are presented
+ * without stretching their natural ratio. The center patch is stretched to fit on both axis. The default value is
+ * (.25, .25, .25, .25) which reserves a 25% border around the center content.
+ */
+ public void setTexBorderOffsets(final ReadOnlyVector4 offsets) {
+ setTexBorderOffsets(offsets.getXf(), offsets.getYf(), offsets.getZf(), offsets.getWf());
+ }
+
+ /**
+ * Set the amount of texture uv space to reserve for the border for all sides to the same value.
+ */
+ public void setTexBorderOffsets(final float offset) {
+ setTexBorderOffsets(offset, offset, offset, offset);
+ }
+
+ public void setTexBorderOffsets(final float x, final float y, final float z, final float w) {
+ _textureBorderOffsets.set(x, y, z, w);
+ setTextureData();
+ }
+
+ public ReadOnlyVector4 getTexBorderOffsets() {
+ return _textureBorderOffsets;
+ }
+
+ /**
+ * Set internal padding between text and border.
+ */
+ public void setContentPadding(final ReadOnlyVector4 padding) {
+ setContentPadding(padding.getXf(), padding.getYf(), padding.getZf(), padding.getWf());
+ }
+
+ /**
+ * Set internal padding between text and border.
+ */
+ public void setContentPadding(final float padding) {
+ setContentPadding(padding, padding, padding, padding);
+ }
+
+ /**
+ * Set internal padding between text and border.
+ */
+ public void setContentPadding(final float x, final float y, final float z, final float w) {
+ _contentPadding.set(x, y, z, w);
+ textSizeChanged(_text, _text.getSize());
+ }
+
+ public ReadOnlyVector4 getContentPadding() {
+ return _contentPadding;
+ }
+
+ @Override
+ public synchronized void draw(final Renderer r) {
+ this.setWorldRotation(_text.getWorldRotation());
+ this.setWorldTranslation(_text.getWorldTranslation());
+ this.setWorldScale(_text.getWorldScale());
+ super.draw(r);
+ }
+
+ @Override
+ public void textSizeChanged(final BMText text, final ReadOnlyVector2 size) {
+ final ReadOnlyVector2 fixedOffset = text.getFixedOffset();
+ final BMText.Align align = text.getAlign();
+ float x = size.getXf() * align.horizontal;
+ float y = size.getYf() * align.vertical;
+ x += fixedOffset.getX();
+ y += fixedOffset.getY();
+ float xs = x + size.getXf();
+ float ys = y + size.getYf();
+
+ x -= _contentPadding.getXf();
+ ys += _contentPadding.getYf();
+ xs += _contentPadding.getZf();
+ y -= _contentPadding.getWf();
+
+ float leftB = 0f, topB = 0f, rightB = 0f, bottomB = 0f;
+
+ if (_texture != null && _texture.getImage() != null) {
+ final Image img = _texture.getImage();
+ leftB = img.getWidth() * _textureBorderOffsets.getXf() * _borderScale;
+ rightB = img.getWidth() * _textureBorderOffsets.getZf() * _borderScale;
+ topB = img.getHeight() * _textureBorderOffsets.getYf() * _borderScale;
+ bottomB = img.getHeight() * _textureBorderOffsets.getWf() * _borderScale;
+ }
+
+ final FloatBuffer vertices = _meshData.getVertexBuffer();
+ vertices.rewind();
+ vertices.put(x - leftB).put(0).put(y - bottomB);
+ vertices.put(x).put(0).put(y - bottomB);
+ vertices.put(xs).put(0).put(y - bottomB);
+ vertices.put(xs + rightB).put(0).put(y - bottomB);
+
+ vertices.put(x - leftB).put(0).put(y);
+ vertices.put(x).put(0).put(y);
+ vertices.put(xs).put(0).put(y);
+ vertices.put(xs + rightB).put(0).put(y);
+
+ vertices.put(x - leftB).put(0).put(ys);
+ vertices.put(x).put(0).put(ys);
+ vertices.put(xs).put(0).put(ys);
+ vertices.put(xs + rightB).put(0).put(ys);
+
+ vertices.put(x - leftB).put(0).put(ys + topB);
+ vertices.put(x).put(0).put(ys + topB);
+ vertices.put(xs).put(0).put(ys + topB);
+ vertices.put(xs + rightB).put(0).put(ys + topB);
+ }
+
+ @Override
+ public void textAlphaChanged(final BMText text, final float alpha) {
+ setDefaultColor(_tintColor.getRed(), _tintColor.getGreen(), _tintColor.getBlue(), _tintColor.getAlpha() * alpha);
+ }
+
+ // /////////////////
+ // Methods for Savable
+ // /////////////////
+
+ @Override
+ public Class<? extends BMTextBackground> getClassTag() {
+ return this.getClass();
+ }
+
+ @Override
+ public void write(final OutputCapsule capsule) throws IOException {
+ super.write(capsule);
+ capsule.write(_tintColor, "tintColor", new ColorRGBA(ColorRGBA.WHITE));
+ capsule.write(_textureBorderOffsets, "borderCoords", new Vector4(0.25, 0.25, 0.25, 0.25));
+ capsule.write(_contentPadding, "contentPadding", new Vector4());
+ capsule.write(_borderScale, "borderScale", 1f);
+ }
+
+ @Override
+ public void read(final InputCapsule capsule) throws IOException {
+ super.read(capsule);
+ _tintColor = (ColorRGBA) capsule.readSavable("tintColor", new ColorRGBA(ColorRGBA.WHITE));
+ _textureBorderOffsets = (Vector4) capsule.readSavable("borderCoords", new Vector4(0.25, 0.25, 0.25, 0.25));
+ _contentPadding = (Vector4) capsule.readSavable("contentPadding", new Vector4());
+ _borderScale = capsule.readFloat("borderScale", 1f);
+ final TextureState ts = ((TextureState) getLocalRenderState(StateType.Texture));
+ if (ts != null) {
+ _texture = ts.getTexture();
+ }
+ }
+}