diff options
Diffstat (limited to 'ardor3d-ui/src/main')
14 files changed, 1245 insertions, 24 deletions
diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/IPopOver.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/IPopOver.java new file mode 100644 index 0000000..01dfdc7 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/IPopOver.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2008-2010 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui; + +import com.ardor3d.renderer.Renderer; + +public interface IPopOver { + + public abstract void showAt(int x, int y); + + public abstract void setHud(UIHud hud); + + public abstract UIComponent getUIComponent(int hudX, int hudY); + + public abstract void onDraw(Renderer renderer); + + public abstract void updateGeometricState(double time, boolean initiator); + + public abstract void close(); + +}
\ No newline at end of file diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java index 0ece8fa..391cc1b 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java @@ -117,9 +117,9 @@ public class UIHud extends Node { private MouseManager _mouseManager; /** - * The list of currently displayed popup menus, with each entry being a submenu of the one previous. + * The list of currently displayed pop-overs, with each entry being a "child" of the one previous. */ - private final List<UIPopupMenu> _popupMenus = Lists.newArrayList(); + private final List<IPopOver> _popovers = Lists.newArrayList(); /** * Construct a new UIHud @@ -247,9 +247,11 @@ public class UIHud extends Node { */ public UIComponent getUIComponent(final int x, final int y) { UIComponent found = null; - for (int i = _popupMenus.size(); --i >= 0;) { - final UIPopupMenu menu = _popupMenus.get(i); - found = menu.getUIComponent(x, y); + + // check for a popover first + for (int i = _popovers.size(); --i >= 0;) { + final IPopOver popover = _popovers.get(i); + found = popover.getUIComponent(x, y); if (found != null) { return found; } @@ -339,9 +341,9 @@ public class UIHud extends Node { child.onDraw(r); } } - if (!_popupMenus.isEmpty()) { - for (i = 0, max = _popupMenus.size(); i < max; i++) { - _popupMenus.get(i).onDraw(r); + if (!_popovers.isEmpty()) { + for (i = 0, max = _popovers.size(); i < max; i++) { + _popovers.get(i).onDraw(r); } } if (_ttip != null && _ttip.isVisible()) { @@ -360,9 +362,9 @@ public class UIHud extends Node { @Override public void updateGeometricState(final double time, final boolean initiator) { super.updateGeometricState(time, initiator); - if (!_popupMenus.isEmpty()) { - for (int i = 0, max = _popupMenus.size(); i < max; i++) { - _popupMenus.get(i).updateGeometricState(time, true); + if (!_popovers.isEmpty()) { + for (int i = 0, max = _popovers.size(); i < max; i++) { + _popovers.get(i).updateGeometricState(time, true); } } if (_ttip != null && _ttip.isVisible()) { @@ -680,7 +682,7 @@ public class UIHud extends Node { // bring any clicked components to front final UIComponent component = over.getTopLevelComponent(); - if (component != null && !(component instanceof UIPopupMenu)) { + if (component != null && !(component instanceof IPopOver)) { bringToFront(component); closePopupMenus(); } @@ -858,10 +860,10 @@ public class UIHud extends Node { } public void closePopupMenus() { - for (final UIPopupMenu menu : _popupMenus) { + for (final IPopOver menu : _popovers) { menu.close(); } - _popupMenus.clear(); + _popovers.clear(); } public void closePopupMenusAfter(final Object parent) { @@ -871,8 +873,8 @@ public class UIHud extends Node { } boolean found = false; - for (final Iterator<UIPopupMenu> it = _popupMenus.iterator(); it.hasNext();) { - final UIPopupMenu pMenu = it.next(); + for (final Iterator<IPopOver> it = _popovers.iterator(); it.hasNext();) { + final IPopOver pMenu = it.next(); if (found) { pMenu.close(); it.remove(); @@ -882,14 +884,14 @@ public class UIHud extends Node { } } - public void showPopupMenu(final UIPopupMenu menu) { + public void showPopOver(final IPopOver pop) { closePopupMenus(); - _popupMenus.add(menu); - menu.setHud(this); + _popovers.add(pop); + pop.setHud(this); } - public void showSubPopupMenu(final UIPopupMenu menu) { - _popupMenus.add(menu); - menu.setHud(this); + public void showSubPopupMenu(final IPopOver pop) { + _popovers.add(pop); + pop.setHud(this); } } diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java new file mode 100644 index 0000000..206d2b1 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java @@ -0,0 +1,253 @@ +/** + * 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui; + +import java.util.List; + +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Rectangle2; +import com.ardor3d.math.Vector2; +import com.ardor3d.scenegraph.Spatial; +import com.google.common.collect.Lists; + +/** + * A special frame meant to display menu items. + */ +public class UIPieMenu extends UIContainer implements IPopOver { + + public static final int DEFAULT_INNER_RADIUS = 50; + + private int _innerRadius, _outerRadius; + private double _radians = 1.0; + + private boolean _menuDirty = true; + + private UIPieMenuItem _center; + + public UIPieMenu(final UIHud hud) { + this(hud, UIPieMenu.DEFAULT_INNER_RADIUS, Math.min(hud.getWidth() / 2, hud.getHeight() / 2)); + } + + public UIPieMenu(final UIHud hud, final int innerRadius, final int outerRadius) { + super(); + _innerRadius = innerRadius; + _outerRadius = outerRadius; + setHud(hud); + applySkin(); + } + + @Override + public void showAt(final int x, final int y) { + setHudXY(x - _outerRadius, y - _outerRadius); + updateGeometricState(0, true); + } + + @Override + public void setHud(final UIHud hud) { + _parent = hud; + attachedToHud(); + } + + public int getInnerRadius() { + return _innerRadius; + } + + public int getOuterRadius() { + return _outerRadius; + } + + public void setInnerRadius(final int radius) { + _menuDirty = true; + _innerRadius = radius; + } + + public void setOuterRadius(final int radius) { + _menuDirty = true; + _outerRadius = radius; + } + + public double getCurrentArcLength() { + return _radians; + } + + public void addItem(final UIPieMenuItem item) { + _menuDirty = true; + add(item); + } + + public void removeItem(final UIPieMenuItem item) { + _menuDirty = true; + remove(item); + } + + public UIPieMenuItem getCenterItem() { + return _center; + } + + public void setCenterItem(final UIPieMenuItem item) { + _menuDirty = true; + if (_center != null) { + remove(_center); + } + if (item != null) { + add(item); + } + _center = item; + } + + public void clearCenterItem() { + setCenterItem(null); + } + + public void clearItems() { + _menuDirty = true; + removeAllComponents(); + } + + @Override + public UIComponent getUIComponent(final int hudX, final int hudY) { + final Vector2 vec = new Vector2(hudX - getHudX() - _outerRadius, hudY - _outerRadius); + + // check we are inside the pie + final double distSq = vec.lengthSquared(); + if (distSq < _innerRadius * _innerRadius) { + return _center != null ? _center : this; + } + if (distSq > _outerRadius * _outerRadius) { + return this; + } + + vec.normalizeLocal(); + + double r = Math.atan2(1, 0) - Math.atan2(vec.getY(), vec.getX()); + + r += _radians / 2; + if (r < 0) { + r += MathUtils.TWO_PI; + } + + int index = (int) (r / _radians); + for (int i = 0; i < getNumberOfChildren(); i++) { + final Spatial s = getChild(i); + if (s == _center) { + continue; + } + if (s instanceof UIComponent) { + if (index == 0) { + return (UIComponent) s; + } + index--; + } + } + return this; + } + + @Override + public void layout() { + if (!_menuDirty) { + return; + } + + final List<Spatial> content = getChildren(); + if (content == null) { + return; + } + + // gather our components + final List<UIComponent> comps = Lists.newArrayList(); + final Rectangle2 storeA = Rectangle2.fetchTempInstance(); + for (int i = 0; i < content.size(); i++) { + final Spatial spat = content.get(i); + if (spat instanceof UIComponent) { + final UIComponent comp = (UIComponent) spat; + final Rectangle2 minRect = comp.getRelativeMinComponentBounds(storeA); + comp.fitComponentIn(minRect.getWidth(), minRect.getHeight()); + if (comp == _center) { + final Rectangle2 rect = comp.getRelativeComponentBounds(storeA); + comp.setLocalXY(_outerRadius - rect.getWidth() / 2, _outerRadius - rect.getHeight() / 2); + continue; + } + comps.add(comp); + } + } + + // if we don't have components to layout, exit + if (comps.isEmpty()) { + Rectangle2.releaseTempInstance(storeA); + return; + } + + // Figure out slice size + _radians = MathUtils.TWO_PI / Math.max(2, comps.size()); + final int radius = (_innerRadius + _outerRadius) / 2; + double position = 0; + for (int i = 0, maxI = comps.size(); i < maxI; i++) { + final UIComponent comp = comps.get(i); + + final Rectangle2 rect = comp.getRelativeComponentBounds(storeA); + final int x = (int) MathUtils.round(radius * MathUtils.sin(position)); + final int y = (int) MathUtils.round(radius * MathUtils.cos(position)); + + comp.setLocalXY(_outerRadius + x - rect.getWidth() / 2, _outerRadius + y - rect.getHeight() / 2); + + // step forward + position += _radians; + } + + Rectangle2.releaseTempInstance(storeA); + _menuDirty = false; + } + + @Override + public void updateMinimumSizeFromContents() { + setMinimumContentSize(_outerRadius * 2, _outerRadius * 2); + } + + @Override + public void close() { + final UIHud hud = getHud(); + if (hud == null) { + throw new IllegalStateException("UIPieMenu is not attached to a hud."); + } + + // Close any open tooltip + hud.getTooltip().setVisible(false); + + // clear any resources for standin + clearStandin(); + + hud.remove(this); + _parent = null; + } + + public int getSliceIndex(final UIPieMenuItem item) { + final List<Spatial> content = getChildren(); + if (content == null) { + return -1; + } + + int x = 0; + for (int i = 0; i < content.size(); i++) { + final Spatial spat = content.get(i); + if (spat == _center) { + continue; + } + if (spat == item) { + return x; + } + if (spat instanceof UIPieMenuItem) { + x++; + } + } + + return -1; + } +}
\ No newline at end of file diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenuItem.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenuItem.java new file mode 100644 index 0000000..cd97024 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenuItem.java @@ -0,0 +1,34 @@ +/** + * 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui; + +import com.ardor3d.extension.ui.event.ActionListener; +import com.ardor3d.extension.ui.util.SubTex; + +/** + * + */ +public class UIPieMenuItem extends UIMenuItem { + + public UIPieMenuItem(final String text) { + this(text, null); + } + + public UIPieMenuItem(final String text, final SubTex icon) { + this(text, icon, true, null); + } + + public UIPieMenuItem(final String text, final SubTex icon, final boolean closeMenuOnSelect, + final ActionListener listener) { + super(text, icon, closeMenuOnSelect, listener); + } + +} diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java index 11df42b..2050865 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java @@ -17,7 +17,7 @@ import com.ardor3d.extension.ui.util.Insets; /** * A special frame meant to display menu items. */ -public class UIPopupMenu extends UIFrame { +public class UIPopupMenu extends UIFrame implements IPopOver { public UIPopupMenu() { super(null, EnumSet.noneOf(UIFrame.FrameButtons.class)); @@ -25,6 +25,7 @@ public class UIPopupMenu extends UIFrame { applySkin(); } + @Override public void showAt(final int x, int y) { final int width = getLocalComponentWidth(); final int height = getLocalComponentHeight(); @@ -49,6 +50,7 @@ public class UIPopupMenu extends UIFrame { updateGeometricState(0, true); } + @Override public void setHud(final UIHud hud) { _parent = hud; attachedToHud(); diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/ImageArcBackdrop.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/ImageArcBackdrop.java new file mode 100644 index 0000000..9df7596 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/ImageArcBackdrop.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2008-2010 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui.backdrop; + +import com.ardor3d.extension.ui.UIComponent; +import com.ardor3d.extension.ui.util.SubTex; +import com.ardor3d.extension.ui.util.UIArc; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.state.TextureState; + +public class ImageArcBackdrop extends SolidArcBackdrop { + + /** The image to draw. */ + protected SubTex _image = null; + + protected TextureState _texState = new TextureState(); + + /** The arc used across all arc backdrops to render with. */ + private static UIArc _standin = SolidArcBackdrop.createStandinArc(); + + /** + * Construct this back drop, using the given image. + * + * @param image + */ + public ImageArcBackdrop(final SubTex image) { + this(image, ColorRGBA.WHITE); + } + + /** + * Construct this back drop, using the given image and color. + * + * @param image + * the image to draw + * @param color + * the color of the backdrop + */ + public ImageArcBackdrop(final SubTex image, final ReadOnlyColorRGBA color) { + super(color); + setImage(image); + } + + @Override + public void draw(final Renderer renderer, final UIComponent comp) { + + if (_texState.getNumberOfSetTextures() == 0 || _texState.getTexture().getTextureKey() == null + || !_texState.getTexture().getTextureKey().equals(_image.getTexture().getTextureKey())) { + _texState.setTexture(_image.getTexture()); + ImageArcBackdrop._standin.setRenderState(_texState); + ImageArcBackdrop._standin.updateWorldRenderStates(false); + } + + drawBackdrop(ImageArcBackdrop._standin, renderer, comp, _image); + } + + public SubTex getImage() { + return _image; + } + + public void setImage(final SubTex image) { + _image = image; + } +} diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/ImageDiskBackdrop.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/ImageDiskBackdrop.java new file mode 100644 index 0000000..c373ad4 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/ImageDiskBackdrop.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2008-2010 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui.backdrop; + +import com.ardor3d.extension.ui.UIComponent; +import com.ardor3d.extension.ui.UIPieMenu; +import com.ardor3d.extension.ui.util.Insets; +import com.ardor3d.extension.ui.util.SubTex; +import com.ardor3d.extension.ui.util.UIDisk; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.Transform; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.state.TextureState; + +public class ImageDiskBackdrop extends SolidDiskBackdrop { + + /** The image to draw. */ + protected SubTex _image = null; + + protected TextureState _texState = new TextureState(); + + /** The disk used across all disk backdrops to render with. */ + private static UIDisk _standin = SolidDiskBackdrop.createStandinDisk(); + + /** + * Construct this back drop, using the given image. + * + * @param image + */ + public ImageDiskBackdrop(final SubTex image) { + super(ColorRGBA.BLACK_NO_ALPHA); + setImage(image); + } + + /** + * Construct this back drop, using the given image and color. + * + * @param image + * the image to draw + * @param color + * the color of the backdrop + */ + public ImageDiskBackdrop(final SubTex image, final ReadOnlyColorRGBA color) { + super(color); + setImage(image); + } + + @Override + public void draw(final Renderer renderer, final UIComponent comp) { + final float oldA = _color.getAlpha(); + if (oldA == 0) { + // no need to draw. + return; + } + + _color.setAlpha(oldA * UIComponent.getCurrentOpacity()); + ImageDiskBackdrop._standin.setDefaultColor(_color); + + final Vector3 v = Vector3.fetchTempInstance(); + final Insets margin = comp.getMargin() != null ? comp.getMargin() : Insets.EMPTY; + final Insets border = comp.getBorder() != null ? comp.getBorder() : Insets.EMPTY; + v.set(margin.getLeft() + border.getLeft(), margin.getBottom() + border.getBottom(), 0); + v.addLocal(comp.getContentWidth() / 2, comp.getContentHeight() / 2, 0); + + final Transform t = Transform.fetchTempInstance(); + t.set(comp.getWorldTransform()); + t.applyForwardVector(v); + t.translate(v); + Vector3.releaseTempInstance(v); + + ImageDiskBackdrop._standin.setWorldTransform(t); + Transform.releaseTempInstance(t); + + double size = 0; + if (comp instanceof UIPieMenu) { + size = ((UIPieMenu) comp).getOuterRadius(); + } else { + size = Math.max(UIBackdrop.getBackdropWidth(comp), UIBackdrop.getBackdropHeight(comp)) / 2; + } + + if (_texState.getNumberOfSetTextures() == 0 || _texState.getTexture().getTextureKey() == null + || !_texState.getTexture().getTextureKey().equals(_image.getTexture().getTextureKey())) { + _texState.setTexture(_image.getTexture()); + ImageDiskBackdrop._standin.setRenderState(_texState); + ImageDiskBackdrop._standin.updateWorldRenderStates(false); + } + + ImageDiskBackdrop._standin.resetGeometry(size, 0, _image); + ImageDiskBackdrop._standin.render(renderer); + + _color.setAlpha(oldA); + } + + public SubTex getImage() { + return _image; + } + + public void setImage(final SubTex image) { + _image = image; + } +} diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/SolidArcBackdrop.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/SolidArcBackdrop.java new file mode 100644 index 0000000..32b3908 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/SolidArcBackdrop.java @@ -0,0 +1,144 @@ +/** + * 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui.backdrop; + +import com.ardor3d.extension.ui.UIComponent; +import com.ardor3d.extension.ui.UIPieMenu; +import com.ardor3d.extension.ui.UIPieMenuItem; +import com.ardor3d.extension.ui.util.Insets; +import com.ardor3d.extension.ui.util.SubTex; +import com.ardor3d.extension.ui.util.UIArc; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Transform; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.state.BlendState; +import com.ardor3d.renderer.state.BlendState.DestinationFunction; +import com.ardor3d.renderer.state.BlendState.SourceFunction; + +/** + * This backdrop paints a solid arc of color behind a UI component. + */ +public class SolidArcBackdrop extends UIBackdrop { + + /** The color to draw */ + protected final ColorRGBA _color = new ColorRGBA(ColorRGBA.GRAY); + /** The disk used across all disk backdrops to render with. */ + private static UIArc _standin = SolidArcBackdrop.createStandinArc(); + + /** + * Construct this backdrop, using the given color. + * + * @param color + * the color of the backdrop + */ + public SolidArcBackdrop(final ReadOnlyColorRGBA color) { + setColor(color); + } + + /** + * @return the color of this back drop. + */ + public ReadOnlyColorRGBA getColor() { + return _color; + } + + /** + * Set the color of this back drop. + * + * @param color + * the color to use + */ + public void setColor(final ReadOnlyColorRGBA color) { + if (color != null) { + _color.set(color); + } + } + + @Override + public void draw(final Renderer renderer, final UIComponent comp) { + drawBackdrop(SolidArcBackdrop._standin, renderer, comp, null); + } + + protected void drawBackdrop(final UIArc arc, final Renderer renderer, final UIComponent comp, final SubTex sub) { + final float oldA = _color.getAlpha(); + if (oldA == 0) { + // no need to draw. + return; + } + + _color.setAlpha(oldA * UIComponent.getCurrentOpacity()); + arc.setDefaultColor(_color); + + final Vector3 v = Vector3.fetchTempInstance(); + final Insets margin = comp.getMargin() != null ? comp.getMargin() : Insets.EMPTY; + final Insets border = comp.getBorder() != null ? comp.getBorder() : Insets.EMPTY; + v.set(margin.getLeft() + border.getLeft(), margin.getBottom() + border.getBottom(), 0); + + final Transform t = Transform.fetchTempInstance(); + if (comp instanceof UIPieMenuItem && comp.getParent() instanceof UIPieMenu) { + final UIPieMenu pie = (UIPieMenu) comp.getParent(); + t.set(comp.getParent().getWorldTransform()).translate(pie.getOuterRadius(), pie.getOuterRadius(), 0); + } else { + t.set(comp.getWorldTransform()); + v.addLocal(comp.getContentWidth() / 2, comp.getContentHeight() / 2, 0); + } + t.applyForwardVector(v); + t.translate(v); + Vector3.releaseTempInstance(v); + + arc.setWorldTransform(t); + Transform.releaseTempInstance(t); + + double size = 0, inner = 0, angle = 0, length = MathUtils.TWO_PI; + if (comp instanceof UIPieMenu) { + final UIPieMenu pie = (UIPieMenu) comp; + size = pie.getOuterRadius(); + inner = 0; + } else if (comp instanceof UIPieMenuItem && comp.getParent() instanceof UIPieMenu) { + final UIPieMenuItem item = (UIPieMenuItem) comp; + final UIPieMenu pie = (UIPieMenu) comp.getParent(); + if (pie.getCenterItem() == item) { + size = pie.getInnerRadius(); + inner = 0; + angle = 0; + length = MathUtils.TWO_PI; + } else { + size = pie.getOuterRadius(); + inner = pie.getInnerRadius(); + length = pie.getCurrentArcLength(); + angle = pie.getSliceIndex(item) * length - length / 2; + } + } else { + size = Math.max(UIBackdrop.getBackdropWidth(comp), UIBackdrop.getBackdropHeight(comp)) / 2; + } + + arc.resetGeometry(angle, length, size, inner, sub); + arc.render(renderer); + + _color.setAlpha(oldA); + } + + public static UIArc createStandinArc() { + final UIArc arc = new UIArc("standin", MathUtils.TWO_PI / 60, 1, 0.5); + + final BlendState blend = new BlendState(); + blend.setBlendEnabled(true); + blend.setSourceFunction(SourceFunction.SourceAlpha); + blend.setDestinationFunction(DestinationFunction.OneMinusSourceAlpha); + arc.setRenderState(blend); + arc.updateWorldRenderStates(false); + + return arc; + } +}
\ No newline at end of file diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/SolidDiskBackdrop.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/SolidDiskBackdrop.java new file mode 100644 index 0000000..6825b46 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/backdrop/SolidDiskBackdrop.java @@ -0,0 +1,118 @@ +/** + * 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui.backdrop; + +import com.ardor3d.extension.ui.UIComponent; +import com.ardor3d.extension.ui.UIPieMenu; +import com.ardor3d.extension.ui.util.Insets; +import com.ardor3d.extension.ui.util.UIDisk; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.Transform; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.state.BlendState; +import com.ardor3d.renderer.state.BlendState.DestinationFunction; +import com.ardor3d.renderer.state.BlendState.SourceFunction; +import com.ardor3d.renderer.state.RenderState.StateType; + +/** + * This backdrop paints a solid disk of color behind a UI component. + */ +public class SolidDiskBackdrop extends UIBackdrop { + + /** The color to draw */ + protected final ColorRGBA _color = new ColorRGBA(ColorRGBA.GRAY); + /** The disk used across all disk backdrops to render with. */ + private static UIDisk _standin = SolidDiskBackdrop.createStandinDisk(); + + /** + * Construct this backdrop, using the given color. + * + * @param color + * the color of the backdrop + */ + public SolidDiskBackdrop(final ReadOnlyColorRGBA color) { + setColor(color); + } + + /** + * @return the color of this back drop. + */ + public ReadOnlyColorRGBA getColor() { + return _color; + } + + /** + * Set the color of this back drop. + * + * @param color + * the color to use + */ + public void setColor(final ReadOnlyColorRGBA color) { + if (color != null) { + _color.set(color); + } + } + + @Override + public void draw(final Renderer renderer, final UIComponent comp) { + final float oldA = _color.getAlpha(); + if (oldA == 0) { + // no need to draw. + return; + } + + _color.setAlpha(oldA * UIComponent.getCurrentOpacity()); + SolidDiskBackdrop._standin.setDefaultColor(_color); + + final Vector3 v = Vector3.fetchTempInstance(); + final Insets margin = comp.getMargin() != null ? comp.getMargin() : Insets.EMPTY; + final Insets border = comp.getBorder() != null ? comp.getBorder() : Insets.EMPTY; + v.set(margin.getLeft() + border.getLeft(), margin.getBottom() + border.getBottom(), 0); + v.addLocal(comp.getContentWidth() / 2, comp.getContentHeight() / 2, 0); + + final Transform t = Transform.fetchTempInstance(); + t.set(comp.getWorldTransform()); + t.applyForwardVector(v); + t.translate(v); + Vector3.releaseTempInstance(v); + + SolidDiskBackdrop._standin.setWorldTransform(t); + Transform.releaseTempInstance(t); + + double size = 0; + if (comp instanceof UIPieMenu) { + size = ((UIPieMenu) comp).getOuterRadius(); + } else { + size = Math.max(UIBackdrop.getBackdropWidth(comp), UIBackdrop.getBackdropHeight(comp)) / 2; + } + + SolidDiskBackdrop._standin.clearRenderState(StateType.Texture); + SolidDiskBackdrop._standin.resetGeometry(size, 0, null); + SolidDiskBackdrop._standin.render(renderer); + + _color.setAlpha(oldA); + } + + public static UIDisk createStandinDisk() { + final UIDisk disk = new UIDisk("standin", 60, 1, 0); + + final BlendState blend = new BlendState(); + blend.setBlendEnabled(true); + blend.setSourceFunction(SourceFunction.SourceAlpha); + blend.setDestinationFunction(DestinationFunction.OneMinusSourceAlpha); + disk.setRenderState(blend); + disk.updateWorldRenderStates(false); + + return disk; + } +}
\ No newline at end of file diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java index f1358d7..69203d6 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java @@ -19,6 +19,8 @@ import com.ardor3d.extension.ui.UILabel; import com.ardor3d.extension.ui.UIMenuItem; import com.ardor3d.extension.ui.UIPanel; import com.ardor3d.extension.ui.UIPasswordField; +import com.ardor3d.extension.ui.UIPieMenu; +import com.ardor3d.extension.ui.UIPieMenuItem; import com.ardor3d.extension.ui.UIPopupMenu; import com.ardor3d.extension.ui.UIProgressBar; import com.ardor3d.extension.ui.UIRadioButton; @@ -41,6 +43,8 @@ public abstract class Skin { applyToCheckBox((UICheckBox) component); } else if (component instanceof UIRadioButton) { applyToRadioButton((UIRadioButton) component); + } else if (component instanceof UIPieMenuItem) { + applyToPieMenuItem((UIPieMenuItem) component); } else if (component instanceof UIMenuItem) { applyToMenuItem((UIMenuItem) component); } else if (component instanceof UIButton) { @@ -68,6 +72,8 @@ public abstract class Skin { applyToComboBox((UIComboBox) component); } else if (component instanceof UIScrollBar) { applyToScrollBar((UIScrollBar) component); + } else if (component instanceof UIPieMenu) { + applyToPieMenu((UIPieMenu) component); } else if (component instanceof UIPanel) { applyToPanel((UIPanel) component); } @@ -95,6 +101,8 @@ public abstract class Skin { protected abstract void applyToMenuItem(UIMenuItem component); + protected abstract void applyToPieMenuItem(UIPieMenuItem component); + protected abstract void applyToButton(UIButton component); protected abstract void applyToLabel(UILabel component); @@ -105,6 +113,8 @@ public abstract class Skin { protected abstract void applyToTextArea(UITextArea component); + protected abstract void applyToPieMenu(UIPieMenu component); + protected abstract void applyToPanel(UIPanel component); protected abstract void applyToTooltip(UITooltip component); diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java index 2013294..1ac2974 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java @@ -23,6 +23,8 @@ import com.ardor3d.extension.ui.UILabel; import com.ardor3d.extension.ui.UIMenuItem; import com.ardor3d.extension.ui.UIPanel; import com.ardor3d.extension.ui.UIPasswordField; +import com.ardor3d.extension.ui.UIPieMenu; +import com.ardor3d.extension.ui.UIPieMenuItem; import com.ardor3d.extension.ui.UIPopupMenu; import com.ardor3d.extension.ui.UIProgressBar; import com.ardor3d.extension.ui.UIRadioButton; @@ -37,7 +39,9 @@ import com.ardor3d.extension.ui.UITextField; import com.ardor3d.extension.ui.UITooltip; import com.ardor3d.extension.ui.backdrop.EmptyBackdrop; import com.ardor3d.extension.ui.backdrop.GradientBackdrop; +import com.ardor3d.extension.ui.backdrop.ImageArcBackdrop; import com.ardor3d.extension.ui.backdrop.ImageBackdrop; +import com.ardor3d.extension.ui.backdrop.SolidArcBackdrop; import com.ardor3d.extension.ui.backdrop.SolidBackdrop; import com.ardor3d.extension.ui.backdrop.UIBackdrop; import com.ardor3d.extension.ui.border.EmptyBorder; @@ -47,6 +51,7 @@ import com.ardor3d.extension.ui.border.UIBorder; import com.ardor3d.extension.ui.layout.RowLayout; import com.ardor3d.extension.ui.skin.Skin; import com.ardor3d.extension.ui.skin.SkinningTask; +import com.ardor3d.extension.ui.text.StyleConstants; import com.ardor3d.extension.ui.util.Alignment; import com.ardor3d.extension.ui.util.Insets; import com.ardor3d.extension.ui.util.SubTex; @@ -312,7 +317,7 @@ public class GenericSkin extends Skin { closeButton.updateMinimumSizeFromContents(); closeButton.compact(); closeButton - .setMaximumContentSize(closeButton.getContentWidth(), closeButton.getContentHeight()); + .setMaximumContentSize(closeButton.getContentWidth(), closeButton.getContentHeight()); } } @@ -484,6 +489,37 @@ public class GenericSkin extends Skin { } @Override + protected void applyToPieMenu(final UIPieMenu component) { + final UIBackdrop pieBack = new SolidArcBackdrop(new ColorRGBA(.9f, .9f, .9f, .8f)); + component.setBackdrop(pieBack); + } + + @Override + protected void applyToPieMenuItem(final UIPieMenuItem component) { + final EmptyBorder itemBorder = new EmptyBorder(); + final SubTex bgImage = new SubTex(_sharedTex, 10, 102, 7, 45, 4, 4, 3, 0); + final UIBackdrop overBackdrop = new ImageArcBackdrop(bgImage, new ColorRGBA(.9f, .9f, .9f, 1f)); + final UIBackdrop pieBack = new ImageArcBackdrop(bgImage, new ColorRGBA(.9f, .9f, .9f, .8f)); + component.setBackdrop(pieBack); + component.setBorder(itemBorder); + component.addFontStyle(StyleConstants.KEY_BOLD, Boolean.TRUE); + component.setMargin(new Insets(0, 0, 0, 0)); + component.setPadding(new Insets(0, 2, 0, 2)); + component.setForegroundColor(ColorRGBA.BLACK); + component.setAlignment(Alignment.LEFT); + for (final UIState state : component.getStates()) { + state.setBorder(null); + state.setBackdrop(pieBack); + state.setForegroundColor(ColorRGBA.BLACK); + } + + final LabelState over = component.getMouseOverState(); + over.setForegroundColor(ColorRGBA.BLACK); + over.setBackdrop(overBackdrop); + + } + + @Override protected void applyToPanel(final UIPanel component) { ; // nothing to do } diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/util/UIArc.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/util/UIArc.java new file mode 100644 index 0000000..f92b928 --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/util/UIArc.java @@ -0,0 +1,266 @@ +/** + * Copyright (c) 2008-2010 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui.util; + +import java.nio.FloatBuffer; + +import com.ardor3d.image.Image; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Vector2; +import com.ardor3d.renderer.IndexMode; +import com.ardor3d.scenegraph.FloatBufferData; +import com.ardor3d.scenegraph.IndexBufferData; +import com.ardor3d.scenegraph.Mesh; +import com.ardor3d.util.geom.BufferUtils; + +public class UIArc extends Mesh { + + protected double _sampleRate; + + protected double _radius, _innerRadius, _arcLength; + + public UIArc() {} + + /** + * Creates a flat disk (circle) at the origin flat along the Z. Usually, a higher sample number creates a better + * looking cylinder, but at the cost of more vertex information. + * + * @param name + * The name of the arc. + * @param sampleRate + * The number of radial samples per radian. + * @param radius + * The radius of the arc. + * @param innerRadius + * The innerRadius of the arc. + */ + public UIArc(final String name, final double sampleRate, final double radius, final double innerRadius) { + super(name); + + _sampleRate = sampleRate; + resetGeometry(0, MathUtils.PI, radius, innerRadius, null); + getMeshData().setIndexMode(IndexMode.Triangles); + } + + public void resetGeometry(final double startAngle, final double arcLength, final double radius, + final double innerRadius, final SubTex subTex) { + _radius = radius; + _innerRadius = innerRadius; + _arcLength = arcLength; + + // allocate vertices + final int radialVerts = (int) MathUtils.round(_arcLength / _sampleRate); + final int verts = radialVerts * 4 + 4 * 4; // bg verts + edge decorations + if (_meshData.getVertexBuffer() == null || _meshData.getVertexBuffer().capacity() < verts * 2) { + _meshData.setVertexCoords(new FloatBufferData(verts * 2, 2)); + } else { + _meshData.getVertexBuffer().clear(); + } + if (_meshData.getTextureBuffer(0) == null || _meshData.getTextureBuffer(0).capacity() < verts * 2) { + _meshData.setTextureCoords(new FloatBufferData(verts * 2, 2), 0); + } else { + _meshData.getTextureBuffer(0).clear(); + } + + // allocate indices + final int tris = (radialVerts + 1) * 6; // bg tris + edge decorations + final int indices = tris * 3; + if (_meshData.getIndexBuffer() == null || _meshData.getIndexBuffer().capacity() < indices) { + _meshData.setIndices(BufferUtils.createIndexBufferData(indices, verts - 1)); + } else { + _meshData.getIndexBuffer().clear(); + } + _meshData.setIndexLengths(new int[] { indices - 36, 18 }); + + // generate geometry + float txOff = 0f, tyOff = 0f, txScale = 1f, tyScale = 1f; + int topBrd = 0, leftBrd = 0, bottomBrd = 0, rightBrd = 0; + float topOffTx = 0f, leftOffTx = 0f, bottomOffTx = 0f, rightOffTx = 0f; + if (subTex != null && subTex.getTexture() != null && subTex.getTexture() != null) { + txOff = subTex.getStartX(); + tyOff = subTex.getStartY(); + txScale = subTex.getEndX() - subTex.getStartX(); + tyScale = subTex.getEndY() - subTex.getStartY(); + + topBrd = subTex.getBorderTop(); + leftBrd = subTex.getBorderLeft(); + bottomBrd = subTex.getBorderBottom(); + rightBrd = subTex.getBorderRight(); + + final Image image = subTex.getTexture().getImage(); + topOffTx = topBrd / (float) image.getHeight(); + leftOffTx = leftBrd / (float) image.getWidth(); + bottomOffTx = bottomBrd / (float) image.getHeight(); + rightOffTx = rightBrd / (float) image.getWidth(); + } + + /***** VERT DATA *****/ + { + final Vector2 radialOffset = new Vector2(); + final Vector2 radialEdge = new Vector2(); + final Vector2 texCoord = new Vector2(); + final FloatBuffer vertBuffer = _meshData.getVertexBuffer(); + final FloatBuffer texBuffer = _meshData.getTextureBuffer(0); + + int i = 0; + final double actualSampleRate = _arcLength / (radialVerts - 1); + double angle = startAngle; + for (int x = 0; x < radialVerts; x++) { + final float radialU = txOff + leftOffTx + (txScale - leftOffTx - rightOffTx) + * ((float) x / (radialVerts - 1)); + final Vector2 radial = new Vector2(MathUtils.sin(angle), MathUtils.cos(angle)); + radialOffset.set(radial).multiplyLocal(_innerRadius); + + // inner edge + radialEdge.zero().addLocal(radialOffset); + BufferUtils.setInBuffer(radialEdge, vertBuffer, i); + texCoord.set(radialU, tyOff + tyScale); + BufferUtils.setInBuffer(texCoord, texBuffer, i++); + + // inner edge border + radialEdge.set(radial).multiplyLocal(bottomBrd).addLocal(radialOffset); + BufferUtils.setInBuffer(radialEdge, vertBuffer, i); + texCoord.set(radialU, tyOff + tyScale - topOffTx); + BufferUtils.setInBuffer(texCoord, texBuffer, i++); + + // outer edge border + radialEdge.set(radial).multiplyLocal(_radius - _innerRadius - topBrd).addLocal(radialOffset); + BufferUtils.setInBuffer(radialEdge, vertBuffer, i); + texCoord.set(radialU, tyOff + bottomOffTx); + BufferUtils.setInBuffer(texCoord, texBuffer, i++); + + // outer edge + radialEdge.set(radial).multiplyLocal(_radius - _innerRadius).addLocal(radialOffset); + BufferUtils.setInBuffer(radialEdge, vertBuffer, i); + texCoord.set(radialU, tyOff); + BufferUtils.setInBuffer(texCoord, texBuffer, i++); + + angle += actualSampleRate; + } + + // *** edge decoration - left + { + angle = startAngle + MathUtils.HALF_PI; + final float radialU1 = txOff; + final float radialU2 = txOff + leftOffTx; + final Vector2 radial = new Vector2(MathUtils.sin(angle), MathUtils.cos(angle)); + radialOffset.set(radial).multiplyLocal(leftBrd); + + for (int s = 0; s < 4; s++) { + BufferUtils.copyInternalVector2(vertBuffer, s, i + s); + BufferUtils.copyInternalVector2(vertBuffer, s, i + 4 + s); + BufferUtils.addInBuffer(radialOffset, vertBuffer, i + 4 + s); + } + + // inner edge + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff + tyScale), texBuffer, i + 0); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff + tyScale), texBuffer, i + 4); + + // inner edge border + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff + tyScale - topOffTx), texBuffer, i + 1); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff + tyScale - topOffTx), texBuffer, i + 5); + + // outer edge border + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff + bottomOffTx), texBuffer, i + 2); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff + bottomOffTx), texBuffer, i + 6); + + // outer edge + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff), texBuffer, i + 3); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff), texBuffer, i + 7); + + i += 8; + } + + // *** edge decoration - right + { + angle = startAngle + arcLength - MathUtils.HALF_PI; + final float radialU1 = txOff + txScale - rightOffTx; + final float radialU2 = txOff + txScale; + final Vector2 radial = new Vector2(MathUtils.sin(angle), MathUtils.cos(angle)); + radialOffset.set(radial).multiplyLocal(rightBrd); + + for (int s = 0; s < 4; s++) { + BufferUtils.copyInternalVector2(vertBuffer, s, i + s); + BufferUtils.copyInternalVector2(vertBuffer, s, i + 4 + s); + BufferUtils.addInBuffer(radialOffset, vertBuffer, i + 4 + s); + } + + // inner edge + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff + tyScale), texBuffer, i + 0); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff + tyScale), texBuffer, i + 4); + + // inner edge border + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff + tyScale - topOffTx), texBuffer, i + 1); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff + tyScale - topOffTx), texBuffer, i + 5); + + // outer edge border + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff + bottomOffTx), texBuffer, i + 2); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff + bottomOffTx), texBuffer, i + 6); + + // outer edge + BufferUtils.setInBuffer(texCoord.set(radialU1, tyOff), texBuffer, i + 3); + BufferUtils.setInBuffer(texCoord.set(radialU2, tyOff), texBuffer, i + 7); + + i += 8; + } + + /***** INDICE DATA *****/ + { + final IndexBufferData<?> indBuff = _meshData.getIndices(); + for (int r = 0; r < radialVerts - 1; r++) { + for (int iS = 0; iS < 3; iS++) { + final int i00 = iS + 4 * r; + final int i01 = iS + 4 * (r + 1); + final int i10 = i00 + 1; + final int i11 = i01 + 1; + indBuff.put(i00).put(i10).put(i11); + indBuff.put(i00).put(i11).put(i01); + } + } + + // edge decoration - left + int e = verts - 16; + for (int iS = 0; iS < 3; iS++) { + final int i00 = e + iS; + final int i01 = e + iS + 4; + final int i10 = i00 + 1; + final int i11 = i01 + 1; + indBuff.put(i00).put(i10).put(i11); + indBuff.put(i00).put(i11).put(i01); + } + + // edge decoration - right + e = verts - 8; + for (int iS = 0; iS < 3; iS++) { + final int i00 = e + iS; + final int i01 = e + iS + 4; + final int i10 = i00 + 1; + final int i11 = i01 + 1; + indBuff.put(i00).put(i10).put(i11); + indBuff.put(i00).put(i11).put(i01); + } + } + } + } + + public double getSampleRate() { + return _sampleRate; + } + + public double getRadius() { + return _radius; + } + + public double getInnerRadius() { + return _innerRadius; + } + +} diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/util/UIDisk.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/util/UIDisk.java new file mode 100644 index 0000000..de75cba --- /dev/null +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/util/UIDisk.java @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2008-2010 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 <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.ui.util; + +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Vector2; +import com.ardor3d.scenegraph.FloatBufferData; +import com.ardor3d.scenegraph.Mesh; +import com.ardor3d.util.geom.BufferUtils; + +public class UIDisk extends Mesh { + + protected int _radialSamples; + + protected double _radius; + + protected double _innerRadius; + + public UIDisk() {} + + /** + * Creates a flat disk (circle) at the origin flat along the Z. Usually, a higher sample number creates a better + * looking disk, but at the cost of more vertex information. + * + * @param name + * The name of the disk. + * @param radialSamples + * The number of radial samples. + * @param radius + * The outer radius of the disk. + */ + public UIDisk(final String name, final int radialSamples, final double radius) { + this(name, radialSamples, radius, 0); + } + + /** + * Creates a flat disk (circle) at the origin flat along the Z. Usually, a higher sample number creates a better + * looking disk, but at the cost of more vertex information. + * + * @param name + * The name of the disk. + * @param radialSamples + * The number of radial samples. + * @param radius + * The outer radius of the disk. + * @param innerRadius + * The inner radius of the disk. If greater than 0, the center of the disk has a hole of this size. + */ + public UIDisk(final String name, final int radialSamples, final double radius, final double innerRadius) { + super(name); + + _radialSamples = radialSamples; + + // allocate vertices + final int verts = radialSamples * 2; + _meshData.setVertexCoords(new FloatBufferData(verts * 2, 2)); + _meshData.setTextureBuffer(BufferUtils.createVector2Buffer(verts), 0); + + final int tris = radialSamples * 2; + _meshData.setIndices(BufferUtils.createIndexBufferData(3 * tris, verts - 1)); + + resetGeometry(radius, innerRadius, null); + setIndexData(); + + } + + public void resetGeometry(final double radius, final double innerRadius, final SubTex subTex) { + _radius = radius; + _innerRadius = innerRadius; + + // generate geometry + final double inverseRadial = 1.0 / _radialSamples; + final Vector2 radialFraction = new Vector2(); + final Vector2 texCoord = new Vector2(); + + float txOff = 0f, tyOff = 0f, txScale = 1f, tyScale = 1f; + if (subTex != null && subTex.getTexture() != null && subTex.getTexture() != null) { + txOff = subTex.getStartX(); + tyOff = subTex.getStartY(); + txScale = subTex.getEndX() - subTex.getStartX(); + tyScale = subTex.getEndY() - subTex.getStartY(); + } + + final Vector2 radialInner = new Vector2(); + for (int radialCount = 0; radialCount < _radialSamples; radialCount++) { + final double angle = MathUtils.TWO_PI * inverseRadial * radialCount; + final double cos = MathUtils.cos(angle); + final double sin = MathUtils.sin(angle); + final Vector2 radial = new Vector2(cos, sin); + radialInner.set(radial).multiplyLocal(_innerRadius); + + for (int shellCount = 0; shellCount < 2; shellCount++) { + radialFraction.set(radial).multiplyLocal(shellCount); + + final int i = shellCount + 2 * radialCount; + + radialFraction.multiplyLocal(_radius - _innerRadius).addLocal(radialInner); + BufferUtils.setInBuffer(radialFraction, _meshData.getVertexBuffer(), i); + + texCoord.setX(txOff + txScale * 0.5 * (1.0 + radialFraction.getX() / _radius)); + texCoord.setY(tyOff + tyScale * 0.5 * (1.0 + radialFraction.getY() / _radius)); + BufferUtils.setInBuffer(texCoord, _meshData.getTextureCoords(0).getBuffer(), i); + } + } + } + + private void setIndexData() { + // generate connectivity + for (int radialCount0 = _radialSamples - 1, radialCount1 = 0; radialCount1 < _radialSamples; radialCount0 = radialCount1++) { + final int i00 = 2 * radialCount0; + final int i01 = 2 * radialCount1; + final int i10 = i00 + 1; + final int i11 = i01 + 1; + _meshData.getIndices().put(i00); + _meshData.getIndices().put(i10); + _meshData.getIndices().put(i11); + _meshData.getIndices().put(i00); + _meshData.getIndices().put(i11); + _meshData.getIndices().put(i01); + } + } + + public int getRadialSamples() { + return _radialSamples; + } + + public double getRadius() { + return _radius; + } + + public double getInnerRadius() { + return _innerRadius; + } + +} diff --git a/ardor3d-ui/src/main/resources/com/ardor3d/extension/ui/skin/generic/genericSkin.png b/ardor3d-ui/src/main/resources/com/ardor3d/extension/ui/skin/generic/genericSkin.png Binary files differindex 8de8d1a..bea78cc 100644 --- a/ardor3d-ui/src/main/resources/com/ardor3d/extension/ui/skin/generic/genericSkin.png +++ b/ardor3d-ui/src/main/resources/com/ardor3d/extension/ui/skin/generic/genericSkin.png |