1 #include <stdlib.h>
2 #include <string.h>
3 
4 #define WIN32_MEAN_AND_LEAN
5 #include <windows.h>
6 #include "gdiplus.h"
7 
8 #include <ui/display.h>
9 #include <ui/window.h>
10 
11 #include <nuklear.h>
12 
13 #include "canvas.h"
14 #include "font.h"
15 #include "display.h"
16 #include "window.h"
17 
18 extern struct ui_display display;
19 
20 static ARGB
ui_convert_color(struct nk_color c)21 ui_convert_color(struct nk_color c)
22 {
23 	return (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b;
24 }
25 
26 struct ui_canvas *
ui_create_canvas(HWND target,struct ui_font * font,unsigned width,unsigned height)27 ui_create_canvas(HWND target, struct ui_font *font, unsigned width,
28 	unsigned height)
29 {
30 	struct nk_user_font *ufont;
31 	struct ui_canvas *canvas;
32 
33 	canvas = calloc(1, sizeof *canvas);
34 
35 	if (!canvas)
36 		return NULL;
37 
38 	canvas->width = width;
39 	canvas->height = height;
40 
41 	GdipCreateFromHWND(target, &canvas->window);
42 	GdipCreateBitmapFromGraphics(width, height, canvas->window, &canvas->bitmap);
43 	GdipGetImageGraphicsContext(canvas->bitmap, &canvas->memory);
44 	GdipCreatePen1(0, 1.0f, UnitPixel, &canvas->pen);
45 	GdipCreateSolidFill(0, &canvas->brush);
46 	GdipStringFormatGetGenericTypographic(&canvas->format);
47 	GdipSetStringFormatFlags(canvas->format,
48 		StringFormatFlagsNoFitBlackBox |
49 		StringFormatFlagsMeasureTrailingSpaces |
50 		StringFormatFlagsNoWrap |
51 		StringFormatFlagsNoClip);
52 
53 	font->canvas = canvas;
54 	ufont = &font->handle;
55 
56 	nk_init_default(&canvas->ctx, ufont);
57 	nk_set_user_data(&canvas->ctx, nk_handle_ptr(canvas));
58 
59 	return canvas;
60 }
61 
62 void
ui_destroy_canvas(struct ui_canvas * canvas)63 ui_destroy_canvas(struct ui_canvas *canvas)
64 {
65 	GdipDeleteGraphics(canvas->window);
66 	GdipDeleteGraphics(canvas->memory);
67 	GdipDisposeImage(canvas->bitmap);
68 	GdipDeletePen(canvas->pen);
69 	GdipDeleteBrush(canvas->brush);
70 	GdipDeleteStringFormat(canvas->format);
71 	free(canvas);
72 }
73 
74 void
ui_invalidate_canvas(struct ui_canvas * canvas)75 ui_invalidate_canvas(struct ui_canvas *canvas)
76 {
77 }
78 
79 void
ui_resize_canvas(struct ui_window * window,struct ui_canvas * canvas,unsigned width,unsigned height)80 ui_resize_canvas(struct ui_window *window, struct ui_canvas *canvas, unsigned width, unsigned height)
81 {
82 	if (!canvas)
83 		return;
84 
85 	canvas->width = width;
86 	canvas->height = height;
87 
88 	GdipDeleteGraphics(canvas->window);
89 	GdipDeleteGraphics(canvas->memory);
90 	GdipDisposeImage(canvas->bitmap);
91 	GdipCreateFromHWND(window->win, &canvas->window);
92 	GdipCreateBitmapFromGraphics(width, height, canvas->window, &canvas->bitmap);
93 	GdipGetImageGraphicsContext(canvas->bitmap, &canvas->memory);
94 }
95 
96 void
ui_clear_canvas(struct ui_canvas * canvas,struct nk_color color)97 ui_clear_canvas(struct ui_canvas *canvas, struct nk_color color)
98 {
99 	GdipGraphicsClear(canvas->memory, ui_convert_color(color));
100 	GdipSetTextRenderingHint(canvas->memory,
101 		TextRenderingHintSystemDefault);
102 	GdipSetSmoothingMode(canvas->memory,
103 		SmoothingModeDefault);
104 }
105 
106 void
ui_blit_canvas(GpGraphics * graphics,struct ui_canvas * canvas)107 ui_blit_canvas(GpGraphics *graphics, struct ui_canvas *canvas)
108 {
109 	GdipDrawImageI(graphics, canvas->bitmap, 0, 0);
110 }
111 
112 void
ui_scissor_canvas(struct ui_canvas * canvas,float x,float y,float width,float height)113 ui_scissor_canvas(struct ui_canvas *canvas, float x, float y, float width,
114 	float height)
115 {
116 	GdipSetClipRectI(canvas->memory, (INT)x, (INT)y,
117 		(INT)(width + 1), (INT)(height + 1), CombineModeReplace);
118 }
119 
120 void
ui_stroke_line(struct ui_canvas * canvas,short x0,short y0,short x1,short y1,unsigned line_thickness,struct nk_color color)121 ui_stroke_line(struct ui_canvas *canvas, short x0, short y0, short x1, short y1,
122 	unsigned line_thickness, struct nk_color color)
123 {
124 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
125 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
126 	GdipDrawLineI(canvas->memory, canvas->pen, x0, y0, x1, y1);
127 }
128 
129 void
ui_stroke_rect(struct ui_canvas * canvas,short x,short y,unsigned short w,unsigned short h,unsigned short r,unsigned short line_thickness,struct nk_color color)130 ui_stroke_rect(struct ui_canvas *canvas, short x, short y, unsigned short w,
131 	unsigned short h, unsigned short r, unsigned short line_thickness,
132 	struct nk_color color)
133 {
134 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
135 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
136 
137 	if (r == 0) {
138 		GdipDrawRectangleI(canvas->memory, canvas->pen, x, y, w, h);
139 	} else {
140 		INT d = 2 * r;
141 		GdipDrawArcI(canvas->memory, canvas->pen, x, y, d, d, 180, 90);
142 		GdipDrawLineI(canvas->memory, canvas->pen, x + r, y, x + w - r, y);
143 		GdipDrawArcI(canvas->memory, canvas->pen, x + w - d, y, d, d, 270, 90);
144 		GdipDrawLineI(canvas->memory, canvas->pen, x + w, y + r, x + w, y + h - r);
145 		GdipDrawArcI(canvas->memory, canvas->pen, x + w - d, y + h - d, d, d, 0, 90);
146 		GdipDrawLineI(canvas->memory, canvas->pen, x, y + r, x, y + h - r);
147 		GdipDrawArcI(canvas->memory, canvas->pen, x, y + h - d, d, d, 90, 90);
148 		GdipDrawLineI(canvas->memory, canvas->pen, x + r, y + h, x + w - r, y + h);
149 	}
150 }
151 
152 void
ui_fill_rect(struct ui_canvas * canvas,short x,short y,unsigned short w,unsigned short h,unsigned short r,struct nk_color color)153 ui_fill_rect(struct ui_canvas *canvas, short x, short y, unsigned short w,
154 	unsigned short h, unsigned short r, struct nk_color color)
155 {
156 	GdipSetSolidFillColor(canvas->brush, ui_convert_color(color));
157 
158 	if (r == 0) {
159 		GdipFillRectangleI(canvas->memory, canvas->brush, x, y, w, h);
160 	} else {
161 		INT d = 2 * r;
162 
163 		GdipFillRectangleI(canvas->memory, canvas->brush, x + r, y, w - d, h);
164 		GdipFillRectangleI(canvas->memory, canvas->brush, x, y + r, r, h - d);
165 		GdipFillRectangleI(canvas->memory, canvas->brush, x + w - r, y + r, r, h - d);
166 		GdipFillPieI(canvas->memory, canvas->brush, x, y, d, d, 180, 90);
167 		GdipFillPieI(canvas->memory, canvas->brush, x + w - d, y, d, d, 270, 90);
168 		GdipFillPieI(canvas->memory, canvas->brush, x + w - d, y + h - d, d, d, 0, 90);
169 		GdipFillPieI(canvas->memory, canvas->brush, x, y + h - d, d, d, 90, 90);
170 	}
171 }
172 
173 void
ui_fill_triangle(struct ui_canvas * canvas,short x0,short y0,short x1,short y1,short x2,short y2,struct nk_color color)174 ui_fill_triangle(struct ui_canvas *canvas, short x0, short y0, short x1,
175 	short y1, short x2, short y2, struct nk_color color)
176 {
177 	POINT points[] = {
178 		{ x0, y0 },
179 		{ x1, y1 },
180 		{ x2, y2 },
181 	};
182 
183 	GdipSetSolidFillColor(canvas->brush, ui_convert_color(color));
184 	GdipFillPolygonI(canvas->memory, canvas->brush, points, 3, FillModeAlternate);
185 }
186 
187 void
ui_stroke_triangle(struct ui_canvas * canvas,short x0,short y0,short x1,short y1,short x2,short y2,unsigned short line_thickness,struct nk_color color)188 ui_stroke_triangle(struct ui_canvas *canvas, short x0, short y0, short x1,
189 	short y1, short x2, short y2, unsigned short line_thickness,
190 	struct nk_color color)
191 {
192 	POINT points[] = {
193 		{ x0, y0 },
194 		{ x1, y1 },
195 		{ x2, y2 },
196 		{ x0, y0 },
197 	};
198 
199 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
200 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
201 	GdipDrawPolygonI(canvas->memory, canvas->pen, points, 4);
202 }
203 
204 void
ui_fill_polygon(struct ui_canvas * canvas,const struct nk_vec2i * pnts,int count,struct nk_color color)205 ui_fill_polygon(struct ui_canvas *canvas,  const struct nk_vec2i *pnts, int count,
206 	struct nk_color color)
207 {
208 	int i = 0;
209 
210 	#define MAX_POINTS 64
211 	POINT points[MAX_POINTS];
212 	GdipSetSolidFillColor(canvas->brush, ui_convert_color(color));
213 
214 	for (i = 0; i < count && i < MAX_POINTS; ++i) {
215 		points[i].x = pnts[i].x;
216 		points[i].y = pnts[i].y;
217 	}
218 
219 	GdipFillPolygonI(canvas->memory, canvas->brush, points, i, FillModeAlternate);
220 	#undef MAX_POINTS
221 }
222 
223 void
ui_stroke_polygon(struct ui_canvas * canvas,const struct nk_vec2i * pnts,int count,unsigned short line_thickness,struct nk_color color)224 ui_stroke_polygon(struct ui_canvas *canvas, const struct nk_vec2i *pnts, int count,
225 	unsigned short line_thickness, struct nk_color color)
226 {
227 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
228 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
229 
230 	if (count > 0) {
231 		int i;
232 		for (i = 1; i < count; ++i)
233 			GdipDrawLineI(canvas->memory, canvas->pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
234 		GdipDrawLineI(canvas->memory, canvas->pen, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
235 	}
236 }
237 
238 void
ui_stroke_polyline(struct ui_canvas * canvas,const struct nk_vec2i * pnts,int count,unsigned short line_thickness,struct nk_color color)239 ui_stroke_polyline(struct ui_canvas *canvas, const struct nk_vec2i *pnts,
240 	int count, unsigned short line_thickness, struct nk_color color)
241 {
242 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
243 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
244 
245 	if (count > 0) {
246 		int i;
247 
248 		for (i = 1; i < count; ++i) {
249 			GdipDrawLineI(canvas->memory, canvas->pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
250 		}
251 	}
252 }
253 
254 void
ui_fill_circle(struct ui_canvas * canvas,short x,short y,unsigned short w,unsigned short h,struct nk_color color)255 ui_fill_circle(struct ui_canvas *canvas, short x, short y, unsigned short w,
256 	unsigned short h, struct nk_color color)
257 {
258 	GdipSetSolidFillColor(canvas->brush, ui_convert_color(color));
259 	GdipFillEllipseI(canvas->memory, canvas->brush, x, y, w, h);
260 }
261 
262 void
ui_stroke_circle(struct ui_canvas * canvas,short x,short y,unsigned short w,unsigned short h,unsigned short line_thickness,struct nk_color color)263 ui_stroke_circle(struct ui_canvas *canvas, short x, short y, unsigned short w,
264 	unsigned short h, unsigned short line_thickness, struct nk_color color)
265 {
266 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
267 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
268 	GdipDrawEllipseI(canvas->memory, canvas->pen, x, y, w, h);
269 }
270 
271 void
ui_stroke_curve(struct ui_canvas * canvas,struct nk_vec2i p1,struct nk_vec2i p2,struct nk_vec2i p3,struct nk_vec2i p4,unsigned int num_segments,unsigned short line_thickness,struct nk_color color)272 ui_stroke_curve(struct ui_canvas *canvas, struct nk_vec2i p1,
273 	struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
274 	unsigned int num_segments, unsigned short line_thickness,
275 	struct nk_color color)
276 {
277 	GdipSetPenWidth(canvas->pen, (REAL)line_thickness);
278 	GdipSetPenColor(canvas->pen, ui_convert_color(color));
279 	GdipDrawBezierI(canvas->memory, canvas->pen, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
280 }
281 
282 void
ui_draw_text(struct ui_canvas * canvas,short x,short y,unsigned short w,unsigned short h,const char * text,int len,struct ui_font * font,struct nk_color cbg,struct nk_color cfg)283 ui_draw_text(struct ui_canvas *canvas, short x, short y, unsigned short w,
284 	unsigned short h, const char *text, int len, struct ui_font *font,
285 	struct nk_color cbg, struct nk_color cfg)
286 {
287 	int wsize;
288 	WCHAR* wstr;
289 	RectF layout = { (FLOAT)x, (FLOAT)y, (FLOAT)w, (FLOAT)h };
290 
291 	if(!text || !font || !len) return;
292 
293 	wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
294 	wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
295 	MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
296 
297 	GdipSetSolidFillColor(canvas->brush, ui_convert_color(cfg));
298 	GdipDrawString(canvas->memory, wstr, wsize, font->ft, &layout, canvas->format, canvas->brush);
299 }
300