1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup gpu
19 *
20 * GPU immediate mode drawing utilities
21 */
22
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "BLI_math.h"
27 #include "BLI_utildefines.h"
28
29 #include "GPU_immediate.h"
30 #include "GPU_immediate_util.h"
31
32 #include "UI_resources.h"
33
34 static const float cube_coords[8][3] = {
35 {-1, -1, -1},
36 {-1, -1, +1},
37 {-1, +1, -1},
38 {-1, +1, +1},
39 {+1, -1, -1},
40 {+1, -1, +1},
41 {+1, +1, -1},
42 {+1, +1, +1},
43 };
44 static const int cube_quad_index[6][4] = {
45 {0, 1, 3, 2},
46 {0, 2, 6, 4},
47 {0, 4, 5, 1},
48 {1, 5, 7, 3},
49 {2, 3, 7, 6},
50 {4, 6, 7, 5},
51 };
52 static const int cube_line_index[12][2] = {
53 {0, 1},
54 {0, 2},
55 {0, 4},
56 {1, 3},
57 {1, 5},
58 {2, 3},
59 {2, 6},
60 {3, 7},
61 {4, 5},
62 {4, 6},
63 {5, 7},
64 {6, 7},
65 };
66
immRectf(uint pos,float x1,float y1,float x2,float y2)67 void immRectf(uint pos, float x1, float y1, float x2, float y2)
68 {
69 immBegin(GPU_PRIM_TRI_FAN, 4);
70 immVertex2f(pos, x1, y1);
71 immVertex2f(pos, x2, y1);
72 immVertex2f(pos, x2, y2);
73 immVertex2f(pos, x1, y2);
74 immEnd();
75 }
76
immRecti(uint pos,int x1,int y1,int x2,int y2)77 void immRecti(uint pos, int x1, int y1, int x2, int y2)
78 {
79 immBegin(GPU_PRIM_TRI_FAN, 4);
80 immVertex2i(pos, x1, y1);
81 immVertex2i(pos, x2, y1);
82 immVertex2i(pos, x2, y2);
83 immVertex2i(pos, x1, y2);
84 immEnd();
85 }
86
immRectf_fast(uint pos,float x1,float y1,float x2,float y2)87 void immRectf_fast(uint pos, float x1, float y1, float x2, float y2)
88 {
89 immVertex2f(pos, x1, y1);
90 immVertex2f(pos, x2, y1);
91 immVertex2f(pos, x2, y2);
92
93 immVertex2f(pos, x1, y1);
94 immVertex2f(pos, x2, y2);
95 immVertex2f(pos, x1, y2);
96 }
97
immRectf_fast_with_color(uint pos,uint col,float x1,float y1,float x2,float y2,const float color[4])98 void immRectf_fast_with_color(
99 uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4])
100 {
101 immAttr4fv(col, color);
102 immVertex2f(pos, x1, y1);
103 immAttr4fv(col, color);
104 immVertex2f(pos, x2, y1);
105 immAttr4fv(col, color);
106 immVertex2f(pos, x2, y2);
107
108 immAttr4fv(col, color);
109 immVertex2f(pos, x1, y1);
110 immAttr4fv(col, color);
111 immVertex2f(pos, x2, y2);
112 immAttr4fv(col, color);
113 immVertex2f(pos, x1, y2);
114 }
115
immRecti_fast_with_color(uint pos,uint col,int x1,int y1,int x2,int y2,const float color[4])116 void immRecti_fast_with_color(
117 uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4])
118 {
119 immAttr4fv(col, color);
120 immVertex2i(pos, x1, y1);
121 immAttr4fv(col, color);
122 immVertex2i(pos, x2, y1);
123 immAttr4fv(col, color);
124 immVertex2i(pos, x2, y2);
125
126 immAttr4fv(col, color);
127 immVertex2i(pos, x1, y1);
128 immAttr4fv(col, color);
129 immVertex2i(pos, x2, y2);
130 immAttr4fv(col, color);
131 immVertex2i(pos, x1, y2);
132 }
133
134 #if 0 /* more complete version in case we want that */
135 void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
136 {
137 GPUVertFormat *format = immVertexFormat();
138 uint pos = add_attr(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
139 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
140 immUniformColor4fv(color);
141 immRecti(pos, x1, y1, x2, y2);
142 immUnbindProgram();
143 }
144 #endif
145
146 /**
147 * Pack color into 3 bytes
148 *
149 * This define converts a numerical value to the equivalent 24-bit
150 * color, while not being endian-sensitive. On little-endian, this
151 * is the same as doing a 'naive' indexing, on big-endian, it is not!
152 *
153 * \note BGR format (i.e. 0xBBGGRR)...
154 *
155 * \param x: color.
156 */
imm_cpack(uint x)157 void imm_cpack(uint x)
158 {
159 immUniformColor3ub(((x)&0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF));
160 }
161
imm_draw_circle(GPUPrimType prim_type,const uint shdr_pos,float x,float y,float rad_x,float rad_y,int nsegments)162 static void imm_draw_circle(GPUPrimType prim_type,
163 const uint shdr_pos,
164 float x,
165 float y,
166 float rad_x,
167 float rad_y,
168 int nsegments)
169 {
170 immBegin(prim_type, nsegments);
171 for (int i = 0; i < nsegments; i++) {
172 const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
173 immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
174 }
175 immEnd();
176 }
177
178 /**
179 * Draw a circle outline with the given \a radius.
180 * The circle is centered at \a x, \a y and drawn in the XY plane.
181 *
182 * \param shdr_pos: The vertex attribute number for position.
183 * \param x: Horizontal center.
184 * \param y: Vertical center.
185 * \param rad: The circle's radius.
186 * \param nsegments: The number of segments to use in drawing (more = smoother).
187 */
imm_draw_circle_wire_2d(uint shdr_pos,float x,float y,float rad,int nsegments)188 void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
189 {
190 imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments);
191 }
192
193 /**
194 * Draw a filled circle with the given \a radius.
195 * The circle is centered at \a x, \a y and drawn in the XY plane.
196 *
197 * \param shdr_pos: The vertex attribute number for position.
198 * \param x: Horizontal center.
199 * \param y: Vertical center.
200 * \param rad: The circle's radius.
201 * \param nsegments: The number of segments to use in drawing (more = smoother).
202 */
imm_draw_circle_fill_2d(uint shdr_pos,float x,float y,float rad,int nsegments)203 void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
204 {
205 imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments);
206 }
207
imm_draw_circle_wire_aspect_2d(uint shdr_pos,float x,float y,float rad_x,float rad_y,int nsegments)208 void imm_draw_circle_wire_aspect_2d(
209 uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
210 {
211 imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments);
212 }
imm_draw_circle_fill_aspect_2d(uint shdr_pos,float x,float y,float rad_x,float rad_y,int nsegments)213 void imm_draw_circle_fill_aspect_2d(
214 uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
215 {
216 imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments);
217 }
218
imm_draw_circle_partial(GPUPrimType prim_type,uint pos,float x,float y,float rad,int nsegments,float start,float sweep)219 static void imm_draw_circle_partial(GPUPrimType prim_type,
220 uint pos,
221 float x,
222 float y,
223 float rad,
224 int nsegments,
225 float start,
226 float sweep)
227 {
228 /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */
229 const float angle_start = -(DEG2RADF(start)) + (float)(M_PI / 2);
230 const float angle_end = -(DEG2RADF(sweep) - angle_start);
231 nsegments += 1;
232 immBegin(prim_type, nsegments);
233 for (int i = 0; i < nsegments; i++) {
234 const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
235 const float angle_sin = sinf(angle);
236 const float angle_cos = cosf(angle);
237 immVertex2f(pos, x + rad * angle_cos, y + rad * angle_sin);
238 }
239 immEnd();
240 }
241
imm_draw_circle_partial_wire_2d(uint pos,float x,float y,float rad,int nsegments,float start,float sweep)242 void imm_draw_circle_partial_wire_2d(
243 uint pos, float x, float y, float rad, int nsegments, float start, float sweep)
244 {
245 imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, rad, nsegments, start, sweep);
246 }
247
imm_draw_disk_partial(GPUPrimType prim_type,uint pos,float x,float y,float rad_inner,float rad_outer,int nsegments,float start,float sweep)248 static void imm_draw_disk_partial(GPUPrimType prim_type,
249 uint pos,
250 float x,
251 float y,
252 float rad_inner,
253 float rad_outer,
254 int nsegments,
255 float start,
256 float sweep)
257 {
258 /* to avoid artifacts */
259 const float max_angle = 3 * 360;
260 CLAMP(sweep, -max_angle, max_angle);
261
262 /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */
263 const float angle_start = -(DEG2RADF(start)) + (float)(M_PI / 2);
264 const float angle_end = -(DEG2RADF(sweep) - angle_start);
265 nsegments += 1;
266 immBegin(prim_type, nsegments * 2);
267 for (int i = 0; i < nsegments; i++) {
268 const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
269 const float angle_sin = sinf(angle);
270 const float angle_cos = cosf(angle);
271 immVertex2f(pos, x + rad_inner * angle_cos, y + rad_inner * angle_sin);
272 immVertex2f(pos, x + rad_outer * angle_cos, y + rad_outer * angle_sin);
273 }
274 immEnd();
275 }
276
277 /**
278 * Draw a filled arc with the given inner and outer radius.
279 * The circle is centered at \a x, \a y and drawn in the XY plane.
280 *
281 * \note Arguments are `gluPartialDisk` compatible.
282 *
283 * \param pos: The vertex attribute number for position.
284 * \param x: Horizontal center.
285 * \param y: Vertical center.
286 * \param rad_inner: The inner circle's radius.
287 * \param rad_outer: The outer circle's radius (can be zero).
288 * \param nsegments: The number of segments to use in drawing (more = smoother).
289 * \param start: Specifies the starting angle, in degrees, of the disk portion.
290 * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
291 */
imm_draw_disk_partial_fill_2d(uint pos,float x,float y,float rad_inner,float rad_outer,int nsegments,float start,float sweep)292 void imm_draw_disk_partial_fill_2d(uint pos,
293 float x,
294 float y,
295 float rad_inner,
296 float rad_outer,
297 int nsegments,
298 float start,
299 float sweep)
300 {
301 imm_draw_disk_partial(
302 GPU_PRIM_TRI_STRIP, pos, x, y, rad_inner, rad_outer, nsegments, start, sweep);
303 }
304
imm_draw_circle_3D(GPUPrimType prim_type,uint pos,float x,float y,float rad,int nsegments)305 static void imm_draw_circle_3D(
306 GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments)
307 {
308 immBegin(prim_type, nsegments);
309 for (int i = 0; i < nsegments; i++) {
310 float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
311 immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
312 }
313 immEnd();
314 }
315
imm_draw_circle_wire_3d(uint pos,float x,float y,float rad,int nsegments)316 void imm_draw_circle_wire_3d(uint pos, float x, float y, float rad, int nsegments)
317 {
318 imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, rad, nsegments);
319 }
320
imm_draw_circle_dashed_3d(uint pos,float x,float y,float rad,int nsegments)321 void imm_draw_circle_dashed_3d(uint pos, float x, float y, float rad, int nsegments)
322 {
323 imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, rad, nsegments / 2);
324 }
325
imm_draw_circle_fill_3d(uint pos,float x,float y,float rad,int nsegments)326 void imm_draw_circle_fill_3d(uint pos, float x, float y, float rad, int nsegments)
327 {
328 imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, rad, nsegments);
329 }
330
331 /**
332 * Draw a lined box.
333 *
334 * \param pos: The vertex attribute number for position.
335 * \param x1: left.
336 * \param y1: bottom.
337 * \param x2: right.
338 * \param y2: top.
339 */
imm_draw_box_wire_2d(uint pos,float x1,float y1,float x2,float y2)340 void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
341 {
342 immBegin(GPU_PRIM_LINE_LOOP, 4);
343 immVertex2f(pos, x1, y1);
344 immVertex2f(pos, x1, y2);
345 immVertex2f(pos, x2, y2);
346 immVertex2f(pos, x2, y1);
347 immEnd();
348 }
349
imm_draw_box_wire_3d(uint pos,float x1,float y1,float x2,float y2)350 void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
351 {
352 /* use this version when GPUVertFormat has a vec3 position */
353 immBegin(GPU_PRIM_LINE_LOOP, 4);
354 immVertex3f(pos, x1, y1, 0.0f);
355 immVertex3f(pos, x1, y2, 0.0f);
356 immVertex3f(pos, x2, y2, 0.0f);
357 immVertex3f(pos, x2, y1, 0.0f);
358 immEnd();
359 }
360
361 /**
362 * Draw a standard checkerboard to indicate transparent backgrounds.
363 */
imm_draw_box_checker_2d_ex(float x1,float y1,float x2,float y2,const float color_primary[4],const float color_secondary[4],int checker_size)364 void imm_draw_box_checker_2d_ex(float x1,
365 float y1,
366 float x2,
367 float y2,
368 const float color_primary[4],
369 const float color_secondary[4],
370 int checker_size)
371 {
372 uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
373
374 immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
375
376 immUniform4fv("color1", color_primary);
377 immUniform4fv("color2", color_secondary);
378 immUniform1i("size", checker_size);
379
380 immRectf(pos, x1, y1, x2, y2);
381
382 immUnbindProgram();
383 }
imm_draw_box_checker_2d(float x1,float y1,float x2,float y2)384 void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
385 {
386 float checker_primary[4];
387 float checker_secondary[4];
388 UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary);
389 UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary);
390 int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE);
391 imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size);
392 }
393
imm_draw_cube_fill_3d(uint pos,const float co[3],const float aspect[3])394 void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
395 {
396 float coords[ARRAY_SIZE(cube_coords)][3];
397
398 for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
399 madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
400 }
401
402 immBegin(GPU_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2);
403 for (int i = 0; i < ARRAY_SIZE(cube_quad_index); i++) {
404 immVertex3fv(pos, coords[cube_quad_index[i][0]]);
405 immVertex3fv(pos, coords[cube_quad_index[i][1]]);
406 immVertex3fv(pos, coords[cube_quad_index[i][2]]);
407
408 immVertex3fv(pos, coords[cube_quad_index[i][0]]);
409 immVertex3fv(pos, coords[cube_quad_index[i][2]]);
410 immVertex3fv(pos, coords[cube_quad_index[i][3]]);
411 }
412 immEnd();
413 }
414
imm_draw_cube_wire_3d(uint pos,const float co[3],const float aspect[3])415 void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3])
416 {
417 float coords[ARRAY_SIZE(cube_coords)][3];
418
419 for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
420 madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
421 }
422
423 immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2);
424 for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) {
425 immVertex3fv(pos, coords[cube_line_index[i][0]]);
426 immVertex3fv(pos, coords[cube_line_index[i][1]]);
427 }
428 immEnd();
429 }
430
431 /**
432 * Draw a cylinder. Replacement for gluCylinder.
433 * _warning_ : Slow, better use it only if you no other choices.
434 *
435 * \param pos: The vertex attribute number for position.
436 * \param nor: The vertex attribute number for normal.
437 * \param base: Specifies the radius of the cylinder at z = 0.
438 * \param top: Specifies the radius of the cylinder at z = height.
439 * \param height: Specifies the height of the cylinder.
440 * \param slices: Specifies the number of subdivisions around the z axis.
441 * \param stacks: Specifies the number of subdivisions along the z axis.
442 */
imm_draw_cylinder_fill_normal_3d(uint pos,uint nor,float base,float top,float height,int slices,int stacks)443 void imm_draw_cylinder_fill_normal_3d(
444 uint pos, uint nor, float base, float top, float height, int slices, int stacks)
445 {
446 immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
447 for (int i = 0; i < slices; i++) {
448 const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
449 const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
450 const float cos1 = cosf(angle1);
451 const float sin1 = sinf(angle1);
452 const float cos2 = cosf(angle2);
453 const float sin2 = sinf(angle2);
454
455 for (int j = 0; j < stacks; j++) {
456 float fac1 = (float)j / (float)stacks;
457 float fac2 = (float)(j + 1) / (float)stacks;
458 float r1 = base * (1.f - fac1) + top * fac1;
459 float r2 = base * (1.f - fac2) + top * fac2;
460 float h1 = height * ((float)j / (float)stacks);
461 float h2 = height * ((float)(j + 1) / (float)stacks);
462
463 const float v1[3] = {r1 * cos2, r1 * sin2, h1};
464 const float v2[3] = {r2 * cos2, r2 * sin2, h2};
465 const float v3[3] = {r2 * cos1, r2 * sin1, h2};
466 const float v4[3] = {r1 * cos1, r1 * sin1, h1};
467 float n1[3], n2[3];
468
469 /* calc normals */
470 sub_v3_v3v3(n1, v2, v1);
471 normalize_v3(n1);
472 n1[0] = cos1;
473 n1[1] = sin1;
474 n1[2] = 1 - n1[2];
475
476 sub_v3_v3v3(n2, v3, v4);
477 normalize_v3(n2);
478 n2[0] = cos2;
479 n2[1] = sin2;
480 n2[2] = 1 - n2[2];
481
482 /* first tri */
483 immAttr3fv(nor, n2);
484 immVertex3fv(pos, v1);
485 immVertex3fv(pos, v2);
486 immAttr3fv(nor, n1);
487 immVertex3fv(pos, v3);
488
489 /* second tri */
490 immVertex3fv(pos, v3);
491 immVertex3fv(pos, v4);
492 immAttr3fv(nor, n2);
493 immVertex3fv(pos, v1);
494 }
495 }
496 immEnd();
497 }
498
imm_draw_cylinder_wire_3d(uint pos,float base,float top,float height,int slices,int stacks)499 void imm_draw_cylinder_wire_3d(
500 uint pos, float base, float top, float height, int slices, int stacks)
501 {
502 immBegin(GPU_PRIM_LINES, 6 * slices * stacks);
503 for (int i = 0; i < slices; i++) {
504 const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
505 const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
506 const float cos1 = cosf(angle1);
507 const float sin1 = sinf(angle1);
508 const float cos2 = cosf(angle2);
509 const float sin2 = sinf(angle2);
510
511 for (int j = 0; j < stacks; j++) {
512 float fac1 = (float)j / (float)stacks;
513 float fac2 = (float)(j + 1) / (float)stacks;
514 float r1 = base * (1.f - fac1) + top * fac1;
515 float r2 = base * (1.f - fac2) + top * fac2;
516 float h1 = height * ((float)j / (float)stacks);
517 float h2 = height * ((float)(j + 1) / (float)stacks);
518
519 const float v1[3] = {r1 * cos2, r1 * sin2, h1};
520 const float v2[3] = {r2 * cos2, r2 * sin2, h2};
521 const float v3[3] = {r2 * cos1, r2 * sin1, h2};
522 const float v4[3] = {r1 * cos1, r1 * sin1, h1};
523
524 immVertex3fv(pos, v1);
525 immVertex3fv(pos, v2);
526
527 immVertex3fv(pos, v2);
528 immVertex3fv(pos, v3);
529
530 immVertex3fv(pos, v1);
531 immVertex3fv(pos, v4);
532 }
533 }
534 immEnd();
535 }
536
imm_draw_cylinder_fill_3d(uint pos,float base,float top,float height,int slices,int stacks)537 void imm_draw_cylinder_fill_3d(
538 uint pos, float base, float top, float height, int slices, int stacks)
539 {
540 immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
541 for (int i = 0; i < slices; i++) {
542 const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
543 const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
544 const float cos1 = cosf(angle1);
545 const float sin1 = sinf(angle1);
546 const float cos2 = cosf(angle2);
547 const float sin2 = sinf(angle2);
548
549 for (int j = 0; j < stacks; j++) {
550 float fac1 = (float)j / (float)stacks;
551 float fac2 = (float)(j + 1) / (float)stacks;
552 float r1 = base * (1.f - fac1) + top * fac1;
553 float r2 = base * (1.f - fac2) + top * fac2;
554 float h1 = height * ((float)j / (float)stacks);
555 float h2 = height * ((float)(j + 1) / (float)stacks);
556
557 const float v1[3] = {r1 * cos2, r1 * sin2, h1};
558 const float v2[3] = {r2 * cos2, r2 * sin2, h2};
559 const float v3[3] = {r2 * cos1, r2 * sin1, h2};
560 const float v4[3] = {r1 * cos1, r1 * sin1, h1};
561
562 /* first tri */
563 immVertex3fv(pos, v1);
564 immVertex3fv(pos, v2);
565 immVertex3fv(pos, v3);
566
567 /* second tri */
568 immVertex3fv(pos, v3);
569 immVertex3fv(pos, v4);
570 immVertex3fv(pos, v1);
571 }
572 }
573 immEnd();
574 }
575