Skip to main content

macroquad_ply/
models.rs

1//! 3D shapes and models, loading 3d models from files, drawing 3D primitives.
2
3use crate::{color::Color, get_context};
4
5use crate::{quad_gl::DrawMode, texture::Texture2D};
6use glam::{vec2, vec3, vec4, Quat, Vec2, Vec3, Vec4};
7
8#[repr(C)]
9#[derive(Clone, Debug, Copy)]
10pub struct Vertex {
11    pub position: Vec3,
12    pub uv: Vec2,
13    pub color: [u8; 4],
14    /// Normal is not used by macroquad and is completely optional.
15    /// Might be usefull for custom shaders.
16    /// While normal is not used by macroquad, it is completely safe to use it
17    /// to pass arbitary user data, hence Vec4.
18    pub normal: Vec4,
19}
20
21impl Vertex {
22    pub fn new(x: f32, y: f32, z: f32, u: f32, v: f32, color: Color) -> Vertex {
23        Vertex {
24            position: vec3(x, y, z),
25            uv: vec2(u, v),
26            color: color.into(),
27            normal: vec4(0.0, 0.0, 0.0, 0.0),
28        }
29    }
30
31    pub fn new2(position: Vec3, uv: Vec2, color: Color) -> Vertex {
32        Vertex {
33            position,
34            uv,
35            color: color.into(),
36            normal: vec4(0.0, 0.0, 0.0, 0.0),
37        }
38    }
39}
40
41pub struct Mesh {
42    pub vertices: Vec<Vertex>,
43    pub indices: Vec<u16>,
44    pub texture: Option<Texture2D>,
45}
46
47pub fn draw_mesh(mesh: &Mesh) {
48    let context = get_context();
49
50    context.gl.texture(mesh.texture.as_ref());
51    context.gl.draw_mode(DrawMode::Triangles);
52    context.gl.geometry(&mesh.vertices[..], &mesh.indices[..]);
53}
54
55fn draw_quad(vertices: [Vertex; 4]) {
56    let context = get_context();
57    let indices = [0, 1, 2, 0, 2, 3];
58    context.gl.draw_mode(DrawMode::Triangles);
59    context.gl.geometry(&vertices, &indices);
60}
61
62pub fn draw_line_3d(start: Vec3, end: Vec3, color: Color) {
63    let context = get_context();
64    let uv = vec2(0., 0.);
65    let indices = [0, 1];
66
67    let line = [Vertex::new2(start, uv, color), Vertex::new2(end, uv, color)];
68
69    context.gl.texture(None);
70    context.gl.draw_mode(DrawMode::Lines);
71    context.gl.geometry(&line, &indices);
72}
73
74/// Draw a grid centered at (0, 0, 0)
75pub fn draw_grid(slices: u32, spacing: f32, axes_color: Color, other_color: Color) {
76    draw_grid_ex(
77        slices,
78        spacing,
79        axes_color,
80        other_color,
81        vec3(0., 0., 0.),
82        Quat::IDENTITY,
83    );
84}
85
86/// Draw a rotated grid centered at a specified point
87pub fn draw_grid_ex(
88    slices: u32,
89    spacing: f32,
90    axes_color: Color,
91    other_color: Color,
92    center: Vec3,
93    rotation: Quat,
94) {
95    let half_slices = (slices as i32) / 2;
96    for i in -half_slices..half_slices + 1 {
97        let color = if i == 0 { axes_color } else { other_color };
98
99        let start = vec3(i as f32 * spacing, 0., -half_slices as f32 * spacing);
100        let end = vec3(i as f32 * spacing, 0., half_slices as f32 * spacing);
101
102        draw_line_3d(
103            rotation.mul_vec3(start) + center,
104            rotation.mul_vec3(end) + center,
105            color,
106        );
107
108        let start = vec3(-half_slices as f32 * spacing, 0., i as f32 * spacing);
109        let end = vec3(half_slices as f32 * spacing, 0., i as f32 * spacing);
110
111        draw_line_3d(
112            rotation.mul_vec3(start) + center,
113            rotation.mul_vec3(end) + center,
114            color,
115        );
116    }
117}
118
119pub fn draw_plane(center: Vec3, size: Vec2, texture: Option<&Texture2D>, color: Color) {
120    let v1 = Vertex::new2(center + vec3(-size.x, 0., -size.y), vec2(0., 0.), color);
121    let v2 = Vertex::new2(center + vec3(-size.x, 0., size.y), vec2(0., 1.), color);
122    let v3 = Vertex::new2(center + vec3(size.x, 0., size.y), vec2(1., 1.), color);
123    let v4 = Vertex::new2(center + vec3(size.x, 0., -size.y), vec2(1., 0.), color);
124
125    {
126        let context = get_context();
127        context.gl.texture(texture);
128    }
129    draw_quad([v1, v2, v3, v4]);
130}
131
132/// Draw an affine (2D) parallelogram at given position, as two triangles.
133///
134/// The drawn parallelogram will have the vertices: `offset`, `offset + e1`, `offset + e2` and `offset + e1 + e2`
135///
136/// # Arguments
137///
138/// * `offset` - Offset of the first point from the origin
139/// * `e1`, `e2` - Base vectors for the parallelogram
140/// * `texture` - Optional [Texture2D] to apply, which will be streched on the entire shape (todo!
141/// support custom uv values per vertex)
142/// * `color` - The [Color] to draw the parallelogram
143///
144/// # Examples
145///
146/// Draw an axis aligned rectangle
147/// ```no_run
148/// # use macroquad::prelude::*;
149/// draw_affine_parallelogram(Vec3::ZERO, 3. * Vec3::X, 5. * Vec3::Z, None, RED);
150/// ```
151pub fn draw_affine_parallelogram(
152    offset: Vec3,
153    e1: Vec3,
154    e2: Vec3,
155    texture: Option<&Texture2D>,
156    color: Color,
157) {
158    let v1 = Vertex::new2(offset, vec2(0., 0.), color);
159    let v2 = Vertex::new2(offset + e1, vec2(0., 1.), color);
160    let v3 = Vertex::new2(offset + e1 + e2, vec2(1., 1.), color);
161    let v4 = Vertex::new2(offset + e2, vec2(1., 0.), color);
162
163    {
164        let context = get_context();
165        context.gl.texture(texture);
166    }
167    draw_quad([v1, v2, v3, v4]);
168}
169
170/// Draw an affine (3D) parallelepiped at given position, using six parallelograms.
171///
172/// The drawn parallelepiped will be built from the followwing parallelograms:
173///
174/// * `offset, offset + e1, offset + e2`
175/// * `offset, offset + e2, offset + e3`
176/// * `offset, offset + e1, offset + e3`
177/// * `offset, offset + e1 + e2, offset + e1 + e3`
178/// * `offset, offset + e2 + e1, offset + e2 + e3`
179/// * `offset, offset + e3 + e1, offset + e3 + e2`
180///
181/// # Arguments
182///
183/// * `offset` - Offset of the first point from the origin
184/// * `e1`, `e2`, `e3` - Base vectors for the parallelepiped
185/// * `texture` - Optional [Texture2D] to apply, which will repeat on each face (todo!
186/// support custom uv values per vertex, multiple textures?)
187/// * `color` - The [Color] to draw the parallelepiped (todo! support color per face?)
188///
189/// # Examples
190///
191/// Draw an axis aligned cube
192/// ```no_run
193/// # use macroquad::prelude::*;
194/// draw_affine_parallelepiped(Vec3::ZERO, 3. * Vec3::X, 2. * Vec3::Y, 5. * Vec3::Z, None, RED);
195/// ```
196pub fn draw_affine_parallelepiped(
197    offset: Vec3,
198    e1: Vec3,
199    e2: Vec3,
200    e3: Vec3,
201    texture: Option<&Texture2D>,
202    color: Color,
203) {
204    draw_affine_parallelogram(offset, e1, e2, texture, color);
205    draw_affine_parallelogram(offset, e1, e3, texture, color);
206    draw_affine_parallelogram(offset, e2, e3, texture, color);
207
208    draw_affine_parallelogram(offset + e1, e2, e3, texture, color);
209    draw_affine_parallelogram(offset + e2, e1, e3, texture, color);
210    draw_affine_parallelogram(offset + e3, e1, e2, texture, color);
211}
212
213pub fn draw_cube(position: Vec3, size: Vec3, texture: Option<&Texture2D>, color: Color) {
214    let context = get_context();
215    context.gl.texture(texture);
216
217    let (x, y, z) = (position.x, position.y, position.z);
218    let (width, height, length) = (size.x, size.y, size.z);
219
220    // Front face
221    let bl_pos = vec3(x - width / 2., y - height / 2., z + length / 2.);
222    let bl_uv = vec2(0., 0.);
223    let br_pos = vec3(x + width / 2., y - height / 2., z + length / 2.);
224    let br_uv = vec2(1., 0.);
225
226    let tr_pos = vec3(x + width / 2., y + height / 2., z + length / 2.);
227    let tr_uv = vec2(1., 1.);
228
229    let tl_pos = vec3(x - width / 2., y + height / 2., z + length / 2.);
230    let tl_uv = vec2(0., 1.);
231
232    draw_quad([
233        Vertex::new2(bl_pos, bl_uv, color),
234        Vertex::new2(br_pos, br_uv, color),
235        Vertex::new2(tr_pos, tr_uv, color),
236        Vertex::new2(tl_pos, tl_uv, color),
237    ]);
238
239    // Back face
240    let bl_pos = vec3(x - width / 2., y - height / 2., z - length / 2.);
241    let bl_uv = vec2(0., 0.);
242    let br_pos = vec3(x + width / 2., y - height / 2., z - length / 2.);
243    let br_uv = vec2(1., 0.);
244
245    let tr_pos = vec3(x + width / 2., y + height / 2., z - length / 2.);
246    let tr_uv = vec2(1., 1.);
247
248    let tl_pos = vec3(x - width / 2., y + height / 2., z - length / 2.);
249    let tl_uv = vec2(0., 1.);
250
251    draw_quad([
252        Vertex::new2(bl_pos, bl_uv, color),
253        Vertex::new2(br_pos, br_uv, color),
254        Vertex::new2(tr_pos, tr_uv, color),
255        Vertex::new2(tl_pos, tl_uv, color),
256    ]);
257
258    // Top face
259    let bl_pos = vec3(x - width / 2., y + height / 2., z - length / 2.);
260    let bl_uv = vec2(0., 1.);
261    let br_pos = vec3(x - width / 2., y + height / 2., z + length / 2.);
262    let br_uv = vec2(0., 0.);
263
264    let tr_pos = vec3(x + width / 2., y + height / 2., z + length / 2.);
265    let tr_uv = vec2(1., 0.);
266
267    let tl_pos = vec3(x + width / 2., y + height / 2., z - length / 2.);
268    let tl_uv = vec2(1., 1.);
269
270    draw_quad([
271        Vertex::new2(bl_pos, bl_uv, color),
272        Vertex::new2(br_pos, br_uv, color),
273        Vertex::new2(tr_pos, tr_uv, color),
274        Vertex::new2(tl_pos, tl_uv, color),
275    ]);
276
277    // Bottom face
278    let bl_pos = vec3(x - width / 2., y - height / 2., z - length / 2.);
279    let bl_uv = vec2(0., 1.);
280    let br_pos = vec3(x - width / 2., y - height / 2., z + length / 2.);
281    let br_uv = vec2(0., 0.);
282
283    let tr_pos = vec3(x + width / 2., y - height / 2., z + length / 2.);
284    let tr_uv = vec2(1., 0.);
285
286    let tl_pos = vec3(x + width / 2., y - height / 2., z - length / 2.);
287    let tl_uv = vec2(1., 1.);
288
289    draw_quad([
290        Vertex::new2(bl_pos, bl_uv, color),
291        Vertex::new2(br_pos, br_uv, color),
292        Vertex::new2(tr_pos, tr_uv, color),
293        Vertex::new2(tl_pos, tl_uv, color),
294    ]);
295
296    // Right face
297    let bl_pos = vec3(x + width / 2., y - height / 2., z - length / 2.);
298    let bl_uv = vec2(0., 1.);
299    let br_pos = vec3(x + width / 2., y + height / 2., z - length / 2.);
300    let br_uv = vec2(0., 0.);
301
302    let tr_pos = vec3(x + width / 2., y + height / 2., z + length / 2.);
303    let tr_uv = vec2(1., 0.);
304
305    let tl_pos = vec3(x + width / 2., y - height / 2., z + length / 2.);
306    let tl_uv = vec2(1., 1.);
307
308    draw_quad([
309        Vertex::new2(bl_pos, bl_uv, color),
310        Vertex::new2(br_pos, br_uv, color),
311        Vertex::new2(tr_pos, tr_uv, color),
312        Vertex::new2(tl_pos, tl_uv, color),
313    ]);
314
315    // Left face
316    let bl_pos = vec3(x - width / 2., y - height / 2., z - length / 2.);
317    let bl_uv = vec2(0., 1.);
318    let br_pos = vec3(x - width / 2., y + height / 2., z - length / 2.);
319    let br_uv = vec2(0., 0.);
320
321    let tr_pos = vec3(x - width / 2., y + height / 2., z + length / 2.);
322    let tr_uv = vec2(1., 0.);
323
324    let tl_pos = vec3(x - width / 2., y - height / 2., z + length / 2.);
325    let tl_uv = vec2(1., 1.);
326
327    draw_quad([
328        Vertex::new2(bl_pos, bl_uv, color),
329        Vertex::new2(br_pos, br_uv, color),
330        Vertex::new2(tr_pos, tr_uv, color),
331        Vertex::new2(tl_pos, tl_uv, color),
332    ]);
333}
334
335pub fn draw_cube_wires(position: Vec3, size: Vec3, color: Color) {
336    let (x, y, z) = (position.x, position.y, position.z);
337    let (width, height, length) = (size.x, size.y, size.z);
338
339    // Front Face
340
341    // Bottom Line
342    draw_line_3d(
343        vec3(x - width / 2., y - height / 2., z + length / 2.),
344        vec3(x + width / 2., y - height / 2., z + length / 2.),
345        color,
346    );
347
348    // Left Line
349    draw_line_3d(
350        vec3(x + width / 2., y - height / 2., z + length / 2.),
351        vec3(x + width / 2., y + height / 2., z + length / 2.),
352        color,
353    );
354
355    // Top Line
356    draw_line_3d(
357        vec3(x + width / 2., y + height / 2., z + length / 2.),
358        vec3(x - width / 2., y + height / 2., z + length / 2.),
359        color,
360    );
361
362    // Right Line
363    draw_line_3d(
364        vec3(x - width / 2., y + height / 2., z + length / 2.),
365        vec3(x - width / 2., y - height / 2., z + length / 2.),
366        color,
367    );
368
369    // Back Face
370    // Bottom Line
371    draw_line_3d(
372        vec3(x - width / 2., y - height / 2., z - length / 2.),
373        vec3(x + width / 2., y - height / 2., z - length / 2.),
374        color,
375    );
376
377    // Left Line
378    draw_line_3d(
379        vec3(x + width / 2., y - height / 2., z - length / 2.),
380        vec3(x + width / 2., y + height / 2., z - length / 2.),
381        color,
382    );
383
384    // Top Line
385    draw_line_3d(
386        vec3(x + width / 2., y + height / 2., z - length / 2.),
387        vec3(x - width / 2., y + height / 2., z - length / 2.),
388        color,
389    );
390
391    // Right Line
392    draw_line_3d(
393        vec3(x - width / 2., y + height / 2., z - length / 2.),
394        vec3(x - width / 2., y - height / 2., z - length / 2.),
395        color,
396    );
397
398    // Top Face
399    // Left Line
400    draw_line_3d(
401        vec3(x - width / 2., y + height / 2., z + length / 2.),
402        vec3(x - width / 2., y + height / 2., z - length / 2.),
403        color,
404    );
405
406    // Right Line
407    draw_line_3d(
408        vec3(x + width / 2., y + height / 2., z + length / 2.),
409        vec3(x + width / 2., y + height / 2., z - length / 2.),
410        color,
411    );
412
413    // Bottom Face
414    // Left Line
415    draw_line_3d(
416        vec3(x - width / 2., y - height / 2., z + length / 2.),
417        vec3(x - width / 2., y - height / 2., z - length / 2.),
418        color,
419    );
420
421    // Right Line
422    draw_line_3d(
423        vec3(x + width / 2., y - height / 2., z + length / 2.),
424        vec3(x + width / 2., y - height / 2., z - length / 2.),
425        color,
426    );
427}
428
429#[derive(Debug, Clone)]
430pub struct DrawSphereParams {
431    pub rings: usize,
432    pub slices: usize,
433    pub draw_mode: DrawMode,
434}
435
436impl Default for DrawSphereParams {
437    fn default() -> DrawSphereParams {
438        DrawSphereParams {
439            rings: 16,
440            slices: 16,
441            draw_mode: DrawMode::Triangles,
442        }
443    }
444}
445
446pub fn draw_sphere(center: Vec3, radius: f32, texture: Option<&Texture2D>, color: Color) {
447    draw_sphere_ex(center, radius, texture, color, Default::default());
448}
449
450pub fn draw_sphere_wires(center: Vec3, radius: f32, texture: Option<&Texture2D>, color: Color) {
451    let params = DrawSphereParams {
452        draw_mode: DrawMode::Lines,
453        ..Default::default()
454    };
455    draw_sphere_ex(center, radius, texture, color, params);
456}
457
458pub fn draw_sphere_ex(
459    center: Vec3,
460    radius: f32,
461    texture: Option<&Texture2D>,
462    color: Color,
463    params: DrawSphereParams,
464) {
465    let context = get_context();
466
467    let rings = params.rings;
468    let slices = params.slices;
469
470    let scale = vec3(radius, radius, radius);
471
472    context.gl.texture(texture);
473    context.gl.draw_mode(params.draw_mode);
474
475    for i in 0..rings + 1 {
476        for j in 0..slices {
477            use std::f32::consts::PI;
478
479            let pi34 = PI / 2. * 3.;
480            let pi2 = PI * 2.;
481            let i = i as f32;
482            let j = j as f32;
483            let rings: f32 = rings as _;
484            let slices: f32 = slices as _;
485
486            let v1 = vec3(
487                (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).sin(),
488                (pi34 + (PI / (rings + 1.)) * i).sin(),
489                (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).cos(),
490            );
491            let uv1 = vec2(i / rings, j / slices);
492            let v2 = vec3(
493                (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).sin(),
494                (pi34 + (PI / (rings + 1.)) * (i + 1.)).sin(),
495                (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).cos(),
496            );
497            let uv2 = vec2((i + 1.) / rings, (j + 1.) / slices);
498            let v3 = vec3(
499                (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * (j * pi2 / slices).sin(),
500                (pi34 + (PI / (rings + 1.)) * (i + 1.)).sin(),
501                (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * (j * pi2 / slices).cos(),
502            );
503            let uv3 = vec2((i + 1.) / rings, j / slices);
504
505            context.gl.geometry(
506                &[
507                    Vertex::new2(v1 * scale + center, uv1, color),
508                    Vertex::new2(v2 * scale + center, uv2, color),
509                    Vertex::new2(v3 * scale + center, uv3, color),
510                ],
511                &[0, 1, 2],
512            );
513
514            let v1 = vec3(
515                (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).sin(),
516                (pi34 + (PI / (rings + 1.)) * i).sin(),
517                (pi34 + (PI / (rings + 1.)) * i).cos() * (j * pi2 / slices).cos(),
518            );
519            let uv1 = vec2(i / rings, j / slices);
520            let v2 = vec3(
521                (pi34 + (PI / (rings + 1.)) * (i)).cos() * ((j + 1.) * pi2 / slices).sin(),
522                (pi34 + (PI / (rings + 1.)) * (i)).sin(),
523                (pi34 + (PI / (rings + 1.)) * (i)).cos() * ((j + 1.) * pi2 / slices).cos(),
524            );
525            let uv2 = vec2(i / rings, (j + 1.) / slices);
526            let v3 = vec3(
527                (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).sin(),
528                (pi34 + (PI / (rings + 1.)) * (i + 1.)).sin(),
529                (pi34 + (PI / (rings + 1.)) * (i + 1.)).cos() * ((j + 1.) * pi2 / slices).cos(),
530            );
531            let uv3 = vec2((i + 1.) / rings, (j + 1.) / slices);
532
533            context.gl.geometry(
534                &[
535                    Vertex::new2(v1 * scale + center, uv1, color),
536                    Vertex::new2(v2 * scale + center, uv2, color),
537                    Vertex::new2(v3 * scale + center, uv3, color),
538                ],
539                &[0, 1, 2],
540            );
541        }
542    }
543}
544
545#[derive(Debug, Clone)]
546pub struct DrawCylinderParams {
547    pub sides: usize,
548    pub draw_mode: DrawMode,
549}
550
551impl Default for DrawCylinderParams {
552    fn default() -> DrawCylinderParams {
553        DrawCylinderParams {
554            sides: 16,
555            draw_mode: DrawMode::Triangles,
556        }
557    }
558}
559
560pub fn draw_cylinder(
561    position: Vec3,
562    radius_top: f32,
563    radius_bottom: f32,
564    height: f32,
565    texture: Option<&Texture2D>,
566    color: Color,
567) {
568    draw_cylinder_ex(
569        position,
570        radius_top,
571        radius_bottom,
572        height,
573        texture,
574        color,
575        Default::default(),
576    );
577}
578
579pub fn draw_cylinder_wires(
580    position: Vec3,
581    radius_top: f32,
582    radius_bottom: f32,
583    height: f32,
584    texture: Option<&Texture2D>,
585    color: Color,
586) {
587    let params = DrawCylinderParams {
588        draw_mode: DrawMode::Lines,
589        ..Default::default()
590    };
591    draw_cylinder_ex(
592        position,
593        radius_top,
594        radius_bottom,
595        height,
596        texture,
597        color,
598        params,
599    );
600}
601
602//Note: can also be used to draw a cone by setting radius_top or radius_bottom to 0
603pub fn draw_cylinder_ex(
604    position: Vec3,
605    radius_top: f32,
606    radius_bottom: f32,
607    height: f32,
608    texture: Option<&Texture2D>,
609    color: Color,
610    params: DrawCylinderParams,
611) {
612    let context = get_context();
613
614    let sides = params.sides;
615
616    context.gl.texture(texture);
617    context.gl.draw_mode(params.draw_mode);
618
619    use std::f32::consts::PI;
620    let angle_step = PI * 2.0 / sides as f32;
621    //draw body
622    for i in 0..sides + 1 {
623        let i = i as f32;
624        //bottom left
625        let v1 = vec3(
626            (i * angle_step).sin() * radius_bottom,
627            0.0,
628            (i * angle_step).cos() * radius_bottom,
629        );
630        //bottom right
631        let v2 = vec3(
632            ((i + 1.0) * angle_step).sin() * radius_bottom,
633            0.0,
634            ((i + 1.0) * angle_step).cos() * radius_bottom,
635        );
636        //top right
637        let v3 = vec3(
638            ((i + 1.0) * angle_step).sin() * radius_top,
639            height,
640            ((i + 1.0) * angle_step).cos() * radius_top,
641        );
642
643        context.gl.geometry(
644            &[
645                Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
646                Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
647                Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
648            ],
649            &[0, 1, 2],
650        );
651
652        //top left
653        let v1 = vec3(
654            (i * angle_step).sin() * radius_top,
655            height,
656            (i * angle_step).cos() * radius_top,
657        );
658        //bottom left
659        let v2 = vec3(
660            (i * angle_step).sin() * radius_bottom,
661            0.0,
662            (i * angle_step).cos() * radius_bottom,
663        );
664        //top right
665        let v3 = vec3(
666            ((i + 1.0) * angle_step).sin() * radius_top,
667            height,
668            ((i + 1.0) * angle_step).cos() * radius_top,
669        );
670
671        context.gl.geometry(
672            &[
673                Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
674                Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
675                Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
676            ],
677            &[0, 1, 2],
678        );
679    }
680
681    //draw cap
682    for i in 0..sides + 1 {
683        let i = i as f32;
684        let v1 = vec3(0.0, height, 0.0);
685        let v2 = vec3(
686            (i * angle_step).sin() * radius_top,
687            height,
688            (i * angle_step).cos() * radius_top,
689        );
690        let v3 = vec3(
691            ((i + 1.0) * angle_step).sin() * radius_top,
692            height,
693            ((i + 1.0) * angle_step).cos() * radius_top,
694        );
695
696        context.gl.geometry(
697            &[
698                Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
699                Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
700                Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
701            ],
702            &[0, 1, 2],
703        );
704    }
705
706    //draw base
707    for i in 0..sides + 1 {
708        let i = i as f32;
709        let v1 = vec3(0.0, 0.0, 0.0);
710        let v2 = vec3(
711            (i * angle_step).sin() * radius_bottom,
712            0.0,
713            (i * angle_step).cos() * radius_bottom,
714        );
715        let v3 = vec3(
716            ((i + 1.0) * angle_step).sin() * radius_bottom,
717            0.0,
718            ((i + 1.0) * angle_step).cos() * radius_bottom,
719        );
720
721        context.gl.geometry(
722            &[
723                Vertex::new2(v1 + position, vec2(0.0, 0.0), color),
724                Vertex::new2(v2 + position, vec2(1.0, 0.0), color),
725                Vertex::new2(v3 + position, vec2(1.0, 1.0), color),
726            ],
727            &[0, 1, 2],
728        );
729    }
730}