{"id":446,"date":"2009-09-02T19:01:55","date_gmt":"2009-09-03T00:01:55","guid":{"rendered":"http:\/\/www.andygibson.net\/blog\/?p=446"},"modified":"2010-07-27T21:53:16","modified_gmt":"2010-07-28T02:53:16","slug":"glass-button-tutorial-in-java","status":"publish","type":"post","link":"http:\/\/www.andygibson.net\/blog\/tutorial\/glass-button-tutorial-in-java\/","title":{"rendered":"Glass Button Tutorial &#8211; In Java"},"content":{"rendered":"<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/mainButton.png\" class=\"leftImg\" \/><br \/>\nCreate glass effect buttons using nothing but Java code and <a href=\"http:\/\/www.andygibson.net\/blog\/index.php\/2009\/08\/02\/jtexgen-procedural-texture-library-released\/\">JTexGen<\/a>, a procedural texture library for Java. First create a new project in your favorite IDE and add the JTextGen jar file, or create a new maven project and add the JTexgen dependency if you installed it from the source distribution into your local repository.<br \/>\n<!--more--><br \/>\nOur glass button will be round-ish, and will have a margin at the edge where we will render the shadow. We&#8217;ll start by writing our main method and creating the glass button class and rendering it. First create a new class called <code>GlassButton.java<\/code> and make it extend <code>AbstractTexture<\/code>. We&#8217;ll add a constructor that takes the base color of the button and returns it in the <code>getColor<\/code> method.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class GlassButton extends AbstractTexture {\r\n\r\n\tprivate final RGBAColor color;\r\n\t\r\n\tpublic GlassButton(RGBAColor color) {\r\n\t\tthis.color = new RGBAColor(color);\r\n\t}\r\n\t\r\n\tpublic void getColor(double u, double v, RGBAColor value) {\r\n\t\tvalue.setColor(color);\r\n\t}\t\r\n}\r\n<\/pre>\n<p>Next we&#8217;ll create our main class and add some code to create and render our texture.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class Main {\r\n\t\r\n\tpublic static void main(String[] args) {\r\n\t\tRGBAColor color = RGBAColor.red();\r\n\t\tTexture texture = new Background(new GlassButton(color),RGBAColor.white());\r\n\t\tTextureViewer.show(texture);\t\t\r\n\t}\r\n}\r\n<\/pre>\n<p>Ok, a fairly simple start, we create our texture with a red color over a white background and pass it to the viewer. If you save and run this, you should get a window with a start button, which will render the red texture when clicked. Let&#8217;s add a method to our texture to calculate where on the button the textures <code>u,v<\/code> co-ordinates are. We do this by calculating the distance from the center of the texture the U,V co-ordinates are. The value returned will range from 0..1 inside the circle and outside the circle, it will return 1+ and grow larger the further it gets from the center. This lets us determine what should appear for any given point on the texture. Since we want a border around the edge of the button, we will have to scale the <code>u,v<\/code> values so when the result ramps up to 1 before getting to the edge of the texture. Add the following method to the <code>GlassButton<\/code> class.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nprotected double calculateCircleRange(double u,double v) {\r\n\t\/\/displace point\r\n\tu = u - 0.5;\r\n\tv = v - 0.5;\r\n\t\/\/calculate distance\r\n\tdouble distance = Math.sqrt((u*u)+(v*v));\r\n\t\/\/double it since the range will only be from 0 to 0.5\r\n\treturn distance * 2;\r\n}\r\n<\/pre>\n<p>We can verify this works by changing our get value method to return this value in the alpha channel.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic void getColor(double u, double v, RGBAColor value) {\r\n\tdouble range = calculateCircleRange(u, v) * 1.2;\r\n\tvalue.setColor(color);\r\n\tvalue.setAlpha(1-range);\r\n}\r\n<\/pre>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/coefAlpha.png\" class=\"leftImg\" \/><br \/>\nWe inverted the signal (<code>1-range<\/code>) so the color would be stronger at the center and weaker at the edge. Since the range goes beyond 1, then the value is truncated to the range 0..1 which is why the pattern repeats at the edge of the circle. <\/p>\n<p>What we need to do is calculate the color based on the return value of this function. Values greater than 1 will result in rendering the shadow with a strength inversely proportional to the distance from the edge. For 0 to 1 values, we will render the button color and overlay the highlight onto it. We will also add an inner shadow in the range 0.7 to 1 with a strength based on the distance from the edge. The button color will consists of a base color which slowly transforms into a darker version of that base color the further down the button we go. The highlight is added as a lighter version of the base color with the alpha channel decreasing the further down the button we go. This has the effect of fading out the highlight the further down we go. Let&#8217;s flesh out a simple version to indicate where each piece is going. <\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic void getColor(double u, double v, RGBAColor value) {\r\n\tdouble range = calculateCircleRange(u, v) * 1.2;\r\n\t\r\n\tif (range &gt; 1) {\r\n\t\t\/\/render shadow\r\n\t\tvalue.setColor(RGBAColor.black());\r\n\t\treturn;\r\n\t}\t\t\r\n\t\t\r\n\tvalue.setColor(color);\r\n\t\t\r\n\tif (range &gt; 0.7) {\r\n\t\tvalue.setColor(RGBAColor.yellow());\r\n\t}\t\t\t\t\r\n}\r\n<\/pre>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/buttonLayout.png\" class=\"leftImg\" \/><br \/>\nThis gives us a fairly predictable result, you can see where the button ends and the shadow starts and you can see which parts the inner shadow affects. We multiply the range value by 1.2 so we can shrink the circle down a bit to give us our margin around the edge for the shadow to sit in.<\/p>\n<p>Time to add some actual colors to our template starting with the shadow. Our shadow is essentially the color black with the alpha ranging from 0.9 to 0 based on how far the point is from the edge of the button. We make the shadow fall off exponentially so the shadow becomes much lighter faster. Bear in mind that the range value for the shadow area is 1+ so we need to adjust the value into the 0..1 range.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic void getColor(double u, double v, RGBAColor value) {\r\n\tdouble range = calculateCircleRange(u, v) * 1.2;\r\n\t\t\r\n\tif (range &gt; 1) {\r\n\t\t\/\/render shadow\r\n\t\tvalue.setColor(RGBAColor.black());\r\n\t\tdouble shadow = Math.pow(2-range-0.1, 8);\r\n\t\tvalue.setAlpha( shadow);\r\n\t\treturn;\r\n\t}\t\t\r\n\t\t\r\n\tvalue.setColor(color);\r\n\t\t\r\n\tif (range &gt; 0.8) {\r\n\t\tvalue.setColor(RGBAColor.yellow());\r\n\t}\t\t\t\t\r\n}\r\n<\/pre>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/shadowButton.png\" class=\"leftImg\" \/><br \/>\nWe specified a white background in our main class and the shadow has a varying alpha value so the white background show through. We can also change the background to see how it looks on different colors.<\/p>\n<p>Now would be a good time to set up the different colors we&#8217;ll be using in our button. We have our base color passed in to the constructor, and from that, we can calculate the darker button color and the lighter highlight color. Let&#8217;s add those in to the constructor first.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class GlassButton extends AbstractTexture {\r\n\r\n\tprivate final RGBAColor color;\r\n\tprivate final RGBAColor darkerColor;\r\n\tprivate final RGBAColor highlightColor;\r\n\t\r\n\tpublic GlassButton(RGBAColor color) {\r\n\t\tthis.color = new RGBAColor(color);\r\n\t\t\r\n\t\t\/\/make a copy and darken it\r\n\t\tthis.darkerColor = new RGBAColor(color);\r\n\t\tthis.darkerColor.merge(RGBAColor.black(),0.5);\r\n\t\t\r\n\t\t\/\/make a copy and lighten it\r\n\t\tthis.highlightColor = new RGBAColor(color);\r\n\t\tthis.highlightColor.merge(RGBAColor.white(),0.8);\r\n\t}\r\n<\/pre>\n<p>With our colors in place, we can start adding them to the final button image. We&#8217;ll start with the main button color which ranges from the base color to dark color as the v value increases and we evaluate pixels further down the image. This can be done with one line of code since we take the base color and merge the darker color based on the v value after we assign the base color to the value.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nvalue.setColor(color);\r\nvalue.merge(darkerColor,(v-0.1)*1.2);\r\n<\/pre>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/coloredButton.png\" class=\"leftImg\" \/><br \/>\nWe shift and scale the v value to try and make the color transformation apply across the whole face of the button which is scaled down. This gives as a gentle transformation across the face of the button. <\/p>\n<p>The button has an inner shadow which gives us the impression that the edges of the button are bending away from us. The code for this looks at the circle range value and if greater than 0.8 adds the inner shadow based on the distance from the edge. To calculate this, we subtract the 0.8 and scale it to get a value in the range of 0 to 0.4 which is perfect since we don&#8217;t want a strong shadow.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\t\t\/\/add the inner shadow\r\n\t\tif (range &gt; 0.8) {\r\n\t\t\tdouble shadow = (range-0.8)*2;\t\t\t\r\n\t\t\tvalue.merge(RGBAColor.black(),shadow);\r\n\t\t}\r\n<\/pre>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/innerShadowButton.png\" class=\"leftImg\" \/><br \/>\nThe last piece we need to add is the highlight which is rendered in the shape of an smaller circle that is offset upwards slightly. This means we can reuse our <code>calculateCircleRange<\/code> method to determine which points are in the smaller circle. Once we have determined whether we are in the highlight circle or not we will merge the highlight color based on the <code>v<\/code> value so the highlight fades out as we move down the button. <\/p>\n<p>Here is the complete <code>getColor<\/code> method with the code to add the highlight at the end.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic void getColor(double u, double v, RGBAColor value) {\r\n\tdouble range = calculateCircleRange(u, v) * 1.2;\r\n\r\n\tif (range &gt; 1) {\r\n\t\t\/\/ render shadow\r\n\t\tvalue.setColor(RGBAColor.black());\r\n\t\tdouble shadow = Math.pow(2 - range - 0.1, 8);\r\n\t\tvalue.setAlpha(shadow);\r\n\t\treturn;\r\n\t}\r\n\r\n\t\/\/ set the base color\r\n\tvalue.setColor(color);\r\n\r\n\t\/\/ add the darker color transform\r\n\tvalue.merge(darkerColor, (v - 0.1) * 1.2);\r\n\r\n\t\/\/ add the inner shadow\r\n\tif (range &gt; 0.8) {\r\n\t\tdouble shadow = (range - 0.8) * 2;\r\n\t\tvalue.merge(RGBAColor.black(), shadow);\r\n\t}\r\n\r\n\t\/\/ finally add the highlight\r\n\tdouble highlightRadius = calculateCircleRange(u, v + 0.05) * 1.5;\r\n\tif (highlightRadius &lt; 1) {\r\n\t\tdouble highlight = v * 2;\r\n\t\tvalue.merge(highlightColor, Gradient.clip(1 - highlight));\r\n\t}\r\n}\r\n<\/pre>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/final.png\" class=\"leftImg\" \/><br \/>\nThis is our final button image which is a round red glass button. However, because this is a procedural texture, we can scale the image in both the u and v directions without loss of quality and we can also create oval buttons. Below you can see a number of different variations. <\/p>\n<p>I&#8217;ve also added an enhancement with regards to the inner shadow. Rather than making it a fixed black color, I have used a <code>ColorGradient<\/code> so the inner shadow transforms from dark to light from the top to the bottom of the button.  We did this by adding this private member <\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nprivate final ColorGradient shadowColor = ColorGradient.buildBlackAndWhite();\r\n<\/pre>\n<p>and in our inner shadow code, we use this gradient color instead of the fixed black color :<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\t\/\/ add the inner shadow\r\n\tif (range &gt; 0.8) {\r\n\t\tdouble shadow = (range - 0.8) * 2.5;\t\t\t\r\n\t\tvalue.merge(shadowColor.interpolate((v+0.3)), shadow);\r\n\t}\r\n<\/pre>\n<p>Also, for the last image, instead of using a solid color, I used a <code>ColorGradient<\/code> from the highlight color to the base color and then the darker color to give it that radial gradient. I plan on writing a generalized version of this texture for inclusion in the next release that will let you set parameters and even pass <code>Texture<\/code> objects for the main color and the inner shadow.<\/p>\n<p><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/logoButton.png\" class=\"leftImg\" \/><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/oval1.png\" class=\"leftImg\" \/><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/lightShadow.png\" class=\"leftImg\" \/><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/onMarble.png\" class=\"leftImg\" \/><img src=\"\/blog\/wp-content\/uploads\/2009\/08\/purpleRadial.png\" class=\"leftImg\" \/><br \/>\n<\/p>\n<div style=\"clear:both\">\n<script type=\"text\/javascript\">var dzone_url = 'http:\/\/www.andygibson.net\/blog\/index.php\/2009\/09\/02\/glass-button-tutorial-in-java\/';<\/script><br \/>\n<script type=\"text\/javascript\">var dzone_title = 'Glass Button Tutorial In Java';<\/script><br \/>\n<script type=\"text\/javascript\">var dzone_style = '1';<\/script><br \/>\n<script language=\"javascript\" src=\"http:\/\/widgets.dzone.com\/links\/widgets\/zoneit.js\"><\/script>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Create glass effect buttons using nothing but Java code and JTexGen, a procedural texture library for Java. First create a new project in your favorite IDE and add the JTextGen jar file, or create a new maven project and add the JTexgen dependency if you installed it from the source distribution into your local repository.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[64],"tags":[31,22,6,37],"_links":{"self":[{"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts\/446"}],"collection":[{"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/comments?post=446"}],"version-history":[{"count":63,"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts\/446\/revisions"}],"predecessor-version":[{"id":536,"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts\/446\/revisions\/536"}],"wp:attachment":[{"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/media?parent=446"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/categories?post=446"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/tags?post=446"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}