1+ /*
2+ * Copyright (c) 2009-2025 jMonkeyEngine
3+ * All rights reserved.
4+ *
5+ * Redistribution and use in source and binary forms, with or without
6+ * modification, are permitted provided that the following conditions are
7+ * met:
8+ *
9+ * * Redistributions of source code must retain the above copyright
10+ * notice, this list of conditions and the following disclaimer.
11+ *
12+ * * Redistributions in binary form must reproduce the above copyright
13+ * notice, this list of conditions and the following disclaimer in the
14+ * documentation and/or other materials provided with the distribution.
15+ *
16+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+ package com .jme3 .environment .util ;
33+
34+ import com .jme3 .asset .AssetManager ;
35+ import com .jme3 .material .Material ;
36+ import com .jme3 .material .RenderState ;
37+ import com .jme3 .math .ColorRGBA ;
38+ import com .jme3 .math .FastMath ;
39+ import com .jme3 .renderer .queue .RenderQueue ;
40+ import com .jme3 .scene .Geometry ;
41+ import com .jme3 .scene .Mesh ;
42+ import com .jme3 .scene .VertexBuffer .Type ;
43+ import com .jme3 .util .BufferUtils ;
44+
45+ import java .nio .FloatBuffer ;
46+ import java .nio .ShortBuffer ;
47+
48+ /**
49+ * <p>A `Circle` is a 2D mesh representing a circular outline (wireframe).
50+ * It's defined by a specified number of radial samples, which determine its smoothness.</p>
51+ *
52+ * <p>The circle is centered at (0,0,0) in its local coordinate space and has a radius of 1.0.</p>
53+ */
54+ public class Circle extends Mesh {
55+
56+ // The number of segments used to approximate the circle.
57+ protected int radialSamples = 256 ;
58+
59+ /**
60+ * Creates a new `Circle` mesh.
61+ */
62+ public Circle () {
63+ setGeometryData ();
64+ setIndexData ();
65+ }
66+
67+ /**
68+ * Creates a new `Circle` mesh with the specified number of radial samples.
69+ * The circle will be centered at (0,0,0) with a radius of 1.0.
70+ *
71+ * @param radialSamples The number of segments (vertices) to use for the circle's perimeter.
72+ * @throws IllegalArgumentException if `radialSamples` is less than 2.
73+ */
74+ public Circle (int radialSamples ) {
75+ if (radialSamples < 2 ) {
76+ throw new IllegalArgumentException ("radialSamples must be at least 2 for a valid circle." );
77+ }
78+ this .radialSamples = radialSamples ;
79+ setGeometryData ();
80+ setIndexData ();
81+ }
82+
83+ /**
84+ * builds the vertices based on the radius.
85+ */
86+ private void setGeometryData () {
87+ setMode (Mode .Lines );
88+
89+ FloatBuffer posBuf = BufferUtils .createVector3Buffer ((radialSamples + 1 ));
90+ FloatBuffer colBuf = BufferUtils .createFloatBuffer ((radialSamples + 1 ) * 4 );
91+ FloatBuffer texBuf = BufferUtils .createVector2Buffer (radialSamples + 1 );
92+
93+ setBuffer (Type .Position , 3 , posBuf );
94+ setBuffer (Type .Color , 4 , colBuf );
95+ setBuffer (Type .TexCoord , 2 , texBuf );
96+
97+ // generate geometry
98+ float fInvRS = 1.0f / radialSamples ;
99+
100+ // Generate points on the unit circle to be used in computing the mesh
101+ // points on a sphere slice.
102+ float [] sin = new float [(radialSamples + 1 )];
103+ float [] cos = new float [(radialSamples + 1 )];
104+ for (int i = 0 ; i < radialSamples ; i ++) {
105+ float angle = FastMath .TWO_PI * fInvRS * i ;
106+ cos [i ] = FastMath .cos (angle );
107+ sin [i ] = FastMath .sin (angle );
108+ }
109+ sin [radialSamples ] = sin [0 ];
110+ cos [radialSamples ] = cos [0 ];
111+
112+ ColorRGBA color = ColorRGBA .Orange ;
113+ for (int iR = 0 ; iR <= radialSamples ; iR ++) {
114+ posBuf .put (cos [iR ]).put (sin [iR ]).put (0 );
115+ colBuf .put (color .r ).put (color .g ).put (color .b ).put (color .a );
116+ texBuf .put (iR % 2f ).put (iR % 2f );
117+ }
118+
119+ updateBound ();
120+ setStatic ();
121+ }
122+
123+ /**
124+ * sets the indices for rendering the circle.
125+ */
126+ private void setIndexData () {
127+ // allocate connectivity
128+ int nbSegments = (radialSamples );
129+
130+ ShortBuffer idxBuf = BufferUtils .createShortBuffer (2 * nbSegments );
131+ setBuffer (Type .Index , 2 , idxBuf );
132+
133+ int idx = 0 ;
134+ int segDone = 0 ;
135+ while (segDone < nbSegments ) {
136+ idxBuf .put ((short ) idx );
137+ idxBuf .put ((short ) (idx + 1 ));
138+ idx ++;
139+ segDone ++;
140+ }
141+ }
142+
143+ /**
144+ * Creates a {@link Geometry} object representing a dashed wireframe circle.
145+ *
146+ * @param assetManager The application's AssetManager to load materials.
147+ * @param name The desired name for the Geometry.
148+ * @return A new Geometry instance with a `Circle` mesh.
149+ */
150+ public static Geometry createShape (AssetManager assetManager , String name ) {
151+ return createShape (assetManager , name , 256 );
152+ }
153+
154+ /**
155+ * Creates a {@link Geometry} object representing a dashed wireframe circle
156+ * with a specified number of radial samples.
157+ *
158+ * @param assetManager The application's AssetManager to load materials.
159+ * @param name The desired name for the Geometry.
160+ * @param radialSamples The number of segments to use for the circle's perimeter.
161+ * @return A new Geometry instance with a `Circle` mesh.
162+ */
163+ public static Geometry createShape (AssetManager assetManager , String name , int radialSamples ) {
164+ Circle mesh = new Circle (radialSamples );
165+ Geometry geom = new Geometry (name , mesh );
166+ geom .setQueueBucket (RenderQueue .Bucket .Transparent );
167+
168+ Material mat = new Material (assetManager , "Common/MatDefs/Dashed/dashed.j3md" );
169+ mat .getAdditionalRenderState ().setWireframe (true );
170+ mat .getAdditionalRenderState ().setBlendMode (RenderState .BlendMode .Alpha );
171+ mat .getAdditionalRenderState ().setDepthWrite (false );
172+ mat .getAdditionalRenderState ().setDepthTest (false );
173+ mat .getAdditionalRenderState ().setLineWidth (2f );
174+ mat .setColor ("Color" , ColorRGBA .Orange );
175+ mat .setFloat ("DashSize" , 0.5f );
176+ geom .setMaterial (mat );
177+
178+ return geom ;
179+ }
180+
181+ }
0 commit comments