1 #include "nuklear.h"
2 #include "nuklear_internal.h"
3 
4 /* ==============================================================
5  *
6  *                          DRAW
7  *
8  * ===============================================================*/
9 NK_LIB void
nk_command_buffer_init(struct nk_command_buffer * cb,struct nk_buffer * b,enum nk_command_clipping clip)10 nk_command_buffer_init(struct nk_command_buffer *cb,
11     struct nk_buffer *b, enum nk_command_clipping clip)
12 {
13     NK_ASSERT(cb);
14     NK_ASSERT(b);
15     if (!cb || !b) return;
16     cb->base = b;
17     cb->use_clipping = (int)clip;
18     cb->begin = b->allocated;
19     cb->end = b->allocated;
20     cb->last = b->allocated;
21 }
22 NK_LIB void
nk_command_buffer_reset(struct nk_command_buffer * b)23 nk_command_buffer_reset(struct nk_command_buffer *b)
24 {
25     NK_ASSERT(b);
26     if (!b) return;
27     b->begin = 0;
28     b->end = 0;
29     b->last = 0;
30     b->clip = nk_null_rect;
31 #ifdef NK_INCLUDE_COMMAND_USERDATA
32     b->userdata.ptr = 0;
33 #endif
34 }
35 NK_LIB void*
nk_command_buffer_push(struct nk_command_buffer * b,enum nk_command_type t,nk_size size)36 nk_command_buffer_push(struct nk_command_buffer* b,
37     enum nk_command_type t, nk_size size)
38 {
39     NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);
40     struct nk_command *cmd;
41     nk_size alignment;
42     void *unaligned;
43     void *memory;
44 
45     NK_ASSERT(b);
46     NK_ASSERT(b->base);
47     if (!b) return 0;
48     cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);
49     if (!cmd) return 0;
50 
51     /* make sure the offset to the next command is aligned */
52     b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);
53     unaligned = (nk_byte*)cmd + size;
54     memory = NK_ALIGN_PTR(unaligned, align);
55     alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);
56 #ifdef NK_ZERO_COMMAND_MEMORY
57     NK_MEMSET(cmd, 0, size + alignment);
58 #endif
59 
60     cmd->type = t;
61     cmd->next = b->base->allocated + alignment;
62 #ifdef NK_INCLUDE_COMMAND_USERDATA
63     cmd->userdata = b->userdata;
64 #endif
65     b->end = cmd->next;
66     return cmd;
67 }
68 NK_API void
nk_push_scissor(struct nk_command_buffer * b,struct nk_rect r)69 nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)
70 {
71     struct nk_command_scissor *cmd;
72     NK_ASSERT(b);
73     if (!b) return;
74 
75     b->clip.x = r.x;
76     b->clip.y = r.y;
77     b->clip.w = r.w;
78     b->clip.h = r.h;
79     cmd = (struct nk_command_scissor*)
80         nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));
81 
82     if (!cmd) return;
83     cmd->x = (short)r.x;
84     cmd->y = (short)r.y;
85     cmd->w = (unsigned short)NK_MAX(0, r.w);
86     cmd->h = (unsigned short)NK_MAX(0, r.h);
87 }
88 NK_API void
nk_stroke_line(struct nk_command_buffer * b,float x0,float y0,float x1,float y1,float line_thickness,struct nk_color c)89 nk_stroke_line(struct nk_command_buffer *b, float x0, float y0,
90     float x1, float y1, float line_thickness, struct nk_color c)
91 {
92     struct nk_command_line *cmd;
93     NK_ASSERT(b);
94     if (!b || line_thickness <= 0) return;
95     cmd = (struct nk_command_line*)
96         nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));
97     if (!cmd) return;
98     cmd->line_thickness = (unsigned short)line_thickness;
99     cmd->begin.x = (short)x0;
100     cmd->begin.y = (short)y0;
101     cmd->end.x = (short)x1;
102     cmd->end.y = (short)y1;
103     cmd->color = c;
104 }
105 NK_API void
nk_stroke_curve(struct nk_command_buffer * b,float ax,float ay,float ctrl0x,float ctrl0y,float ctrl1x,float ctrl1y,float bx,float by,float line_thickness,struct nk_color col)106 nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,
107     float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,
108     float bx, float by, float line_thickness, struct nk_color col)
109 {
110     struct nk_command_curve *cmd;
111     NK_ASSERT(b);
112     if (!b || col.a == 0 || line_thickness <= 0) return;
113 
114     cmd = (struct nk_command_curve*)
115         nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));
116     if (!cmd) return;
117     cmd->line_thickness = (unsigned short)line_thickness;
118     cmd->begin.x = (short)ax;
119     cmd->begin.y = (short)ay;
120     cmd->ctrl[0].x = (short)ctrl0x;
121     cmd->ctrl[0].y = (short)ctrl0y;
122     cmd->ctrl[1].x = (short)ctrl1x;
123     cmd->ctrl[1].y = (short)ctrl1y;
124     cmd->end.x = (short)bx;
125     cmd->end.y = (short)by;
126     cmd->color = col;
127 }
128 NK_API void
nk_stroke_rect(struct nk_command_buffer * b,struct nk_rect rect,float rounding,float line_thickness,struct nk_color c)129 nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,
130     float rounding, float line_thickness, struct nk_color c)
131 {
132     struct nk_command_rect *cmd;
133     NK_ASSERT(b);
134     if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return;
135     if (b->use_clipping) {
136         const struct nk_rect *clip = &b->clip;
137         if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
138             clip->x, clip->y, clip->w, clip->h)) return;
139     }
140     cmd = (struct nk_command_rect*)
141         nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));
142     if (!cmd) return;
143     cmd->rounding = (unsigned short)rounding;
144     cmd->line_thickness = (unsigned short)line_thickness;
145     cmd->x = (short)rect.x;
146     cmd->y = (short)rect.y;
147     cmd->w = (unsigned short)NK_MAX(0, rect.w);
148     cmd->h = (unsigned short)NK_MAX(0, rect.h);
149     cmd->color = c;
150 }
151 NK_API void
nk_fill_rect(struct nk_command_buffer * b,struct nk_rect rect,float rounding,struct nk_color c)152 nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,
153     float rounding, struct nk_color c)
154 {
155     struct nk_command_rect_filled *cmd;
156     NK_ASSERT(b);
157     if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;
158     if (b->use_clipping) {
159         const struct nk_rect *clip = &b->clip;
160         if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
161             clip->x, clip->y, clip->w, clip->h)) return;
162     }
163 
164     cmd = (struct nk_command_rect_filled*)
165         nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));
166     if (!cmd) return;
167     cmd->rounding = (unsigned short)rounding;
168     cmd->x = (short)rect.x;
169     cmd->y = (short)rect.y;
170     cmd->w = (unsigned short)NK_MAX(0, rect.w);
171     cmd->h = (unsigned short)NK_MAX(0, rect.h);
172     cmd->color = c;
173 }
174 NK_API void
nk_fill_rect_multi_color(struct nk_command_buffer * b,struct nk_rect rect,struct nk_color left,struct nk_color top,struct nk_color right,struct nk_color bottom)175 nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,
176     struct nk_color left, struct nk_color top, struct nk_color right,
177     struct nk_color bottom)
178 {
179     struct nk_command_rect_multi_color *cmd;
180     NK_ASSERT(b);
181     if (!b || rect.w == 0 || rect.h == 0) return;
182     if (b->use_clipping) {
183         const struct nk_rect *clip = &b->clip;
184         if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,
185             clip->x, clip->y, clip->w, clip->h)) return;
186     }
187 
188     cmd = (struct nk_command_rect_multi_color*)
189         nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));
190     if (!cmd) return;
191     cmd->x = (short)rect.x;
192     cmd->y = (short)rect.y;
193     cmd->w = (unsigned short)NK_MAX(0, rect.w);
194     cmd->h = (unsigned short)NK_MAX(0, rect.h);
195     cmd->left = left;
196     cmd->top = top;
197     cmd->right = right;
198     cmd->bottom = bottom;
199 }
200 NK_API void
nk_stroke_circle(struct nk_command_buffer * b,struct nk_rect r,float line_thickness,struct nk_color c)201 nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,
202     float line_thickness, struct nk_color c)
203 {
204     struct nk_command_circle *cmd;
205     if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return;
206     if (b->use_clipping) {
207         const struct nk_rect *clip = &b->clip;
208         if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
209             return;
210     }
211 
212     cmd = (struct nk_command_circle*)
213         nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));
214     if (!cmd) return;
215     cmd->line_thickness = (unsigned short)line_thickness;
216     cmd->x = (short)r.x;
217     cmd->y = (short)r.y;
218     cmd->w = (unsigned short)NK_MAX(r.w, 0);
219     cmd->h = (unsigned short)NK_MAX(r.h, 0);
220     cmd->color = c;
221 }
222 NK_API void
nk_fill_circle(struct nk_command_buffer * b,struct nk_rect r,struct nk_color c)223 nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)
224 {
225     struct nk_command_circle_filled *cmd;
226     NK_ASSERT(b);
227     if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;
228     if (b->use_clipping) {
229         const struct nk_rect *clip = &b->clip;
230         if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))
231             return;
232     }
233 
234     cmd = (struct nk_command_circle_filled*)
235         nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));
236     if (!cmd) return;
237     cmd->x = (short)r.x;
238     cmd->y = (short)r.y;
239     cmd->w = (unsigned short)NK_MAX(r.w, 0);
240     cmd->h = (unsigned short)NK_MAX(r.h, 0);
241     cmd->color = c;
242 }
243 NK_API void
nk_stroke_arc(struct nk_command_buffer * b,float cx,float cy,float radius,float a_min,float a_max,float line_thickness,struct nk_color c)244 nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
245     float a_min, float a_max, float line_thickness, struct nk_color c)
246 {
247     struct nk_command_arc *cmd;
248     if (!b || c.a == 0 || line_thickness <= 0) return;
249     cmd = (struct nk_command_arc*)
250         nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));
251     if (!cmd) return;
252     cmd->line_thickness = (unsigned short)line_thickness;
253     cmd->cx = (short)cx;
254     cmd->cy = (short)cy;
255     cmd->r = (unsigned short)radius;
256     cmd->a[0] = a_min;
257     cmd->a[1] = a_max;
258     cmd->color = c;
259 }
260 NK_API void
nk_fill_arc(struct nk_command_buffer * b,float cx,float cy,float radius,float a_min,float a_max,struct nk_color c)261 nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,
262     float a_min, float a_max, struct nk_color c)
263 {
264     struct nk_command_arc_filled *cmd;
265     NK_ASSERT(b);
266     if (!b || c.a == 0) return;
267     cmd = (struct nk_command_arc_filled*)
268         nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));
269     if (!cmd) return;
270     cmd->cx = (short)cx;
271     cmd->cy = (short)cy;
272     cmd->r = (unsigned short)radius;
273     cmd->a[0] = a_min;
274     cmd->a[1] = a_max;
275     cmd->color = c;
276 }
277 NK_API void
nk_stroke_triangle(struct nk_command_buffer * b,float x0,float y0,float x1,float y1,float x2,float y2,float line_thickness,struct nk_color c)278 nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
279     float y1, float x2, float y2, float line_thickness, struct nk_color c)
280 {
281     struct nk_command_triangle *cmd;
282     NK_ASSERT(b);
283     if (!b || c.a == 0 || line_thickness <= 0) return;
284     if (b->use_clipping) {
285         const struct nk_rect *clip = &b->clip;
286         if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
287             !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
288             !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
289             return;
290     }
291 
292     cmd = (struct nk_command_triangle*)
293         nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));
294     if (!cmd) return;
295     cmd->line_thickness = (unsigned short)line_thickness;
296     cmd->a.x = (short)x0;
297     cmd->a.y = (short)y0;
298     cmd->b.x = (short)x1;
299     cmd->b.y = (short)y1;
300     cmd->c.x = (short)x2;
301     cmd->c.y = (short)y2;
302     cmd->color = c;
303 }
304 NK_API void
nk_fill_triangle(struct nk_command_buffer * b,float x0,float y0,float x1,float y1,float x2,float y2,struct nk_color c)305 nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
306     float y1, float x2, float y2, struct nk_color c)
307 {
308     struct nk_command_triangle_filled *cmd;
309     NK_ASSERT(b);
310     if (!b || c.a == 0) return;
311     if (!b) return;
312     if (b->use_clipping) {
313         const struct nk_rect *clip = &b->clip;
314         if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&
315             !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&
316             !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))
317             return;
318     }
319 
320     cmd = (struct nk_command_triangle_filled*)
321         nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));
322     if (!cmd) return;
323     cmd->a.x = (short)x0;
324     cmd->a.y = (short)y0;
325     cmd->b.x = (short)x1;
326     cmd->b.y = (short)y1;
327     cmd->c.x = (short)x2;
328     cmd->c.y = (short)y2;
329     cmd->color = c;
330 }
331 NK_API void
nk_stroke_polygon(struct nk_command_buffer * b,float * points,int point_count,float line_thickness,struct nk_color col)332 nk_stroke_polygon(struct nk_command_buffer *b,  float *points, int point_count,
333     float line_thickness, struct nk_color col)
334 {
335     int i;
336     nk_size size = 0;
337     struct nk_command_polygon *cmd;
338 
339     NK_ASSERT(b);
340     if (!b || col.a == 0 || line_thickness <= 0) return;
341     size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
342     cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);
343     if (!cmd) return;
344     cmd->color = col;
345     cmd->line_thickness = (unsigned short)line_thickness;
346     cmd->point_count = (unsigned short)point_count;
347     for (i = 0; i < point_count; ++i) {
348         cmd->points[i].x = (short)points[i*2];
349         cmd->points[i].y = (short)points[i*2+1];
350     }
351 }
352 NK_API void
nk_fill_polygon(struct nk_command_buffer * b,float * points,int point_count,struct nk_color col)353 nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count,
354     struct nk_color col)
355 {
356     int i;
357     nk_size size = 0;
358     struct nk_command_polygon_filled *cmd;
359 
360     NK_ASSERT(b);
361     if (!b || col.a == 0) return;
362     size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
363     cmd = (struct nk_command_polygon_filled*)
364         nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);
365     if (!cmd) return;
366     cmd->color = col;
367     cmd->point_count = (unsigned short)point_count;
368     for (i = 0; i < point_count; ++i) {
369         cmd->points[i].x = (short)points[i*2+0];
370         cmd->points[i].y = (short)points[i*2+1];
371     }
372 }
373 NK_API void
nk_stroke_polyline(struct nk_command_buffer * b,float * points,int point_count,float line_thickness,struct nk_color col)374 nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count,
375     float line_thickness, struct nk_color col)
376 {
377     int i;
378     nk_size size = 0;
379     struct nk_command_polyline *cmd;
380 
381     NK_ASSERT(b);
382     if (!b || col.a == 0 || line_thickness <= 0) return;
383     size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;
384     cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);
385     if (!cmd) return;
386     cmd->color = col;
387     cmd->point_count = (unsigned short)point_count;
388     cmd->line_thickness = (unsigned short)line_thickness;
389     for (i = 0; i < point_count; ++i) {
390         cmd->points[i].x = (short)points[i*2];
391         cmd->points[i].y = (short)points[i*2+1];
392     }
393 }
394 NK_API void
nk_draw_image(struct nk_command_buffer * b,struct nk_rect r,const struct nk_image * img,struct nk_color col)395 nk_draw_image(struct nk_command_buffer *b, struct nk_rect r,
396     const struct nk_image *img, struct nk_color col)
397 {
398     struct nk_command_image *cmd;
399     NK_ASSERT(b);
400     if (!b) return;
401     if (b->use_clipping) {
402         const struct nk_rect *c = &b->clip;
403         if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
404             return;
405     }
406 
407     cmd = (struct nk_command_image*)
408         nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));
409     if (!cmd) return;
410     cmd->x = (short)r.x;
411     cmd->y = (short)r.y;
412     cmd->w = (unsigned short)NK_MAX(0, r.w);
413     cmd->h = (unsigned short)NK_MAX(0, r.h);
414     cmd->img = *img;
415     cmd->col = col;
416 }
417 NK_API void
nk_draw_nine_slice(struct nk_command_buffer * b,struct nk_rect r,const struct nk_nine_slice * slc,struct nk_color col)418 nk_draw_nine_slice(struct nk_command_buffer *b, struct nk_rect r,
419     const struct nk_nine_slice *slc, struct nk_color col)
420 {
421     struct nk_image img;
422     const struct nk_image *slcimg = (const struct nk_image*)slc;
423     nk_ushort rgnX, rgnY, rgnW, rgnH;
424     rgnX = slcimg->region[0];
425     rgnY = slcimg->region[1];
426     rgnW = slcimg->region[2];
427     rgnH = slcimg->region[3];
428 
429     /* top-left */
430     img.handle = slcimg->handle;
431     img.w = slcimg->w;
432     img.h = slcimg->h;
433     img.region[0] = rgnX;
434     img.region[1] = rgnY;
435     img.region[2] = slc->l;
436     img.region[3] = slc->t;
437 
438     nk_draw_image(b,
439         nk_rect(r.x, r.y, (float)slc->l, (float)slc->t),
440         &img, col);
441 
442 #define IMG_RGN(x, y, w, h) img.region[0] = (nk_ushort)(x); img.region[1] = (nk_ushort)(y); img.region[2] = (nk_ushort)(w); img.region[3] = (nk_ushort)(h);
443 
444     /* top-center */
445     IMG_RGN(rgnX + slc->l, rgnY, rgnW - slc->l - slc->r, slc->t);
446     nk_draw_image(b,
447         nk_rect(r.x + (float)slc->l, r.y, (float)(r.w - slc->l - slc->r), (float)slc->t),
448         &img, col);
449 
450     /* top-right */
451     IMG_RGN(rgnX + rgnW - slc->r, rgnY, slc->r, slc->t);
452     nk_draw_image(b,
453         nk_rect(r.x + r.w - (float)slc->r, r.y, (float)slc->r, (float)slc->t),
454         &img, col);
455 
456     /* center-left */
457     IMG_RGN(rgnX, rgnY + slc->t, slc->l, rgnH - slc->t - slc->b);
458     nk_draw_image(b,
459         nk_rect(r.x, r.y + (float)slc->t, (float)slc->l, (float)(r.h - slc->t - slc->b)),
460         &img, col);
461 
462     /* center */
463     IMG_RGN(rgnX + slc->l, rgnY + slc->t, rgnW - slc->l - slc->r, rgnH - slc->t - slc->b);
464     nk_draw_image(b,
465         nk_rect(r.x + (float)slc->l, r.y + (float)slc->t, (float)(r.w - slc->l - slc->r), (float)(r.h - slc->t - slc->b)),
466         &img, col);
467 
468     /* center-right */
469     IMG_RGN(rgnX + rgnW - slc->r, rgnY + slc->t, slc->r, rgnH - slc->t - slc->b);
470     nk_draw_image(b,
471         nk_rect(r.x + r.w - (float)slc->r, r.y + (float)slc->t, (float)slc->r, (float)(r.h - slc->t - slc->b)),
472         &img, col);
473 
474     /* bottom-left */
475     IMG_RGN(rgnX, rgnY + rgnH - slc->b, slc->l, slc->b);
476     nk_draw_image(b,
477         nk_rect(r.x, r.y + r.h - (float)slc->b, (float)slc->l, (float)slc->b),
478         &img, col);
479 
480     /* bottom-center */
481     IMG_RGN(rgnX + slc->l, rgnY + rgnH - slc->b, rgnW - slc->l - slc->r, slc->b);
482     nk_draw_image(b,
483         nk_rect(r.x + (float)slc->l, r.y + r.h - (float)slc->b, (float)(r.w - slc->l - slc->r), (float)slc->b),
484         &img, col);
485 
486     /* bottom-right */
487     IMG_RGN(rgnX + rgnW - slc->r, rgnY + rgnH - slc->b, slc->r, slc->b);
488     nk_draw_image(b,
489         nk_rect(r.x + r.w - (float)slc->r, r.y + r.h - (float)slc->b, (float)slc->r, (float)slc->b),
490         &img, col);
491 
492 #undef IMG_RGN
493 }
494 NK_API void
nk_push_custom(struct nk_command_buffer * b,struct nk_rect r,nk_command_custom_callback cb,nk_handle usr)495 nk_push_custom(struct nk_command_buffer *b, struct nk_rect r,
496     nk_command_custom_callback cb, nk_handle usr)
497 {
498     struct nk_command_custom *cmd;
499     NK_ASSERT(b);
500     if (!b) return;
501     if (b->use_clipping) {
502         const struct nk_rect *c = &b->clip;
503         if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
504             return;
505     }
506 
507     cmd = (struct nk_command_custom*)
508         nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));
509     if (!cmd) return;
510     cmd->x = (short)r.x;
511     cmd->y = (short)r.y;
512     cmd->w = (unsigned short)NK_MAX(0, r.w);
513     cmd->h = (unsigned short)NK_MAX(0, r.h);
514     cmd->callback_data = usr;
515     cmd->callback = cb;
516 }
517 NK_API void
nk_draw_text(struct nk_command_buffer * b,struct nk_rect r,const char * string,int length,const struct nk_user_font * font,struct nk_color bg,struct nk_color fg)518 nk_draw_text(struct nk_command_buffer *b, struct nk_rect r,
519     const char *string, int length, const struct nk_user_font *font,
520     struct nk_color bg, struct nk_color fg)
521 {
522     float text_width = 0;
523     struct nk_command_text *cmd;
524 
525     NK_ASSERT(b);
526     NK_ASSERT(font);
527     if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;
528     if (b->use_clipping) {
529         const struct nk_rect *c = &b->clip;
530         if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))
531             return;
532     }
533 
534     /* make sure text fits inside bounds */
535     text_width = font->width(font->userdata, font->height, string, length);
536     if (text_width > r.w){
537         int glyphs = 0;
538         float txt_width = (float)text_width;
539         length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);
540     }
541 
542     if (!length) return;
543     cmd = (struct nk_command_text*)
544         nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));
545     if (!cmd) return;
546     cmd->x = (short)r.x;
547     cmd->y = (short)r.y;
548     cmd->w = (unsigned short)r.w;
549     cmd->h = (unsigned short)r.h;
550     cmd->background = bg;
551     cmd->foreground = fg;
552     cmd->font = font;
553     cmd->length = length;
554     cmd->height = font->height;
555     NK_MEMCPY(cmd->string, string, (nk_size)length);
556     cmd->string[length] = '\0';
557 }
558 
559