2 #include "../common/util.qh"
3 #include "../common/constants.qh"
5 string draw_mousepointer;
6 vector draw_mousepointer_offset;
7 vector draw_mousepointer_size;
9 void draw_setMousePointer(string pic, vector theSize, vector theOffset)
11 draw_mousepointer = strzone(draw_UseSkinFor(pic));
12 draw_mousepointer_size = theSize;
13 draw_mousepointer_offset = eX * (theOffset.x * theSize.x) + eY * (theOffset.y * theSize.y);
16 void draw_drawMousePointer(vector where)
18 drawpic(boxToGlobal(where, draw_shift, draw_scale) - draw_mousepointer_offset, draw_mousepointer, draw_mousepointer_size, '1 1 1', draw_alpha, 0);
21 void draw_reset(float cw, float ch, float ox, float oy)
23 draw_shift = '1 0 0' * ox + '0 1 0' * oy;
24 draw_scale = '1 0 0' * cw + '0 1 0' * ch;
26 draw_fontscale = '1 1 0';
30 vector globalToBox(vector v, vector theOrigin, vector theScale)
38 vector globalToBoxSize(vector v, vector theScale)
45 vector boxToGlobal(vector v, vector theOrigin, vector theScale)
53 vector boxToGlobalSize(vector v, vector theScale)
60 string draw_PreloadPicture(string pic)
62 pic = draw_UseSkinFor(pic);
63 return precache_pic(pic);
66 string draw_PreloadPictureWithFlags(string pic, float f)
68 pic = draw_UseSkinFor(pic);
69 return precache_pic(pic, f);
72 void draw_Picture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
74 if(theSize.x == 0 || theSize.y <= 0) // no default sizing please
76 pic = draw_UseSkinFor(pic);
77 drawpic(boxToGlobal(theOrigin, draw_shift, draw_scale), pic, boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
80 vector draw_PictureSize(string pic)
82 pic = draw_UseSkinFor(pic);
83 return drawgetimagesize(pic);
86 void draw_Fill(vector theOrigin, vector theSize, vector theColor, float theAlpha)
88 drawfill(boxToGlobal(theOrigin, draw_shift, draw_scale), boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
91 // a button picture is a texture containing three parts:
92 // 1/4 width: left part
93 // 1/2 width: middle part (stretched)
94 // 1/4 width: right part
95 // it is assumed to be 4x as wide as high for aspect ratio purposes, which
96 // means, the parts are a square, two squares and a square.
97 void draw_ButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
100 vector width, height;
102 pic = draw_UseSkinFor(pic);
103 theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
104 theSize = boxToGlobalSize(theSize, draw_scale);
105 theAlpha *= draw_alpha;
106 width = eX * theSize.x;
107 height = eY * theSize.y;
108 if(theSize.x <= theSize.y * 2)
110 // button not wide enough
111 // draw just left and right part then
112 square = eX * theSize.x * 0.5;
113 bW = eX * (0.25 * theSize.x / (theSize.y * 2));
114 drawsubpic(theOrigin, square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, 0);
115 drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, 0);
119 square = eX * theSize.y;
120 drawsubpic(theOrigin, height + square, pic, '0 0 0', '0.25 1 0', theColor, theAlpha, 0);
121 drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0.25 0 0', '0.5 1 0', theColor, theAlpha, 0);
122 drawsubpic(theOrigin + width - square, height + square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, 0);
126 // a vertical button picture is a texture containing three parts:
127 // 1/4 height: left part
128 // 1/2 height: middle part (stretched)
129 // 1/4 height: right part
130 // it is assumed to be 4x as high as wide for aspect ratio purposes, which
131 // means, the parts are a square, two squares and a square.
132 void draw_VertButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
135 vector width, height;
137 pic = draw_UseSkinFor(pic);
138 theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
139 theSize = boxToGlobalSize(theSize, draw_scale);
140 theAlpha *= draw_alpha;
141 width = eX * theSize.x;
142 height = eY * theSize.y;
143 if(theSize.y <= theSize.x * 2)
145 // button not high enough
146 // draw just upper and lower part then
147 square = eY * theSize.y * 0.5;
148 bH = eY * (0.25 * theSize.y / (theSize.x * 2));
149 drawsubpic(theOrigin, square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, 0);
150 drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, 0);
154 square = eY * theSize.x;
155 drawsubpic(theOrigin, width + square, pic, '0 0 0', '1 0.25 0', theColor, theAlpha, 0);
156 drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5 0', theColor, theAlpha, 0);
157 drawsubpic(theOrigin + height - square, width + square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, 0);
161 // a border picture is a texture containing nine parts:
162 // 1/4 width: left part
163 // 1/2 width: middle part (stretched)
164 // 1/4 width: right part
166 // 1/4 height: top part
167 // 1/2 height: middle part (stretched)
168 // 1/4 height: bottom part
169 void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
172 vector width, height;
174 pic = draw_UseSkinFor(pic);
175 theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
176 theSize = boxToGlobalSize(theSize, draw_scale);
177 theBorderSize = boxToGlobalSize(theBorderSize, draw_scale);
178 theAlpha *= draw_alpha;
179 width = eX * theSize.x;
180 height = eY * theSize.y;
181 // zero size? bail out, we cannot handle this
182 if(theSize.x <= 0 || theSize.y <= 0)
184 if(theBorderSize.x <= 0) // no x border
186 if(theBorderSize.y <= 0)
188 drawsubpic(theOrigin, width + height, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
190 else if(theSize.y <= theBorderSize.y * 2)
192 // not high enough... draw just top and bottom then
193 bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
194 drawsubpic(theOrigin, width + height * 0.5, pic, '0.25 0 0', '0.5 0 0' + bH, theColor, theAlpha, 0);
195 drawsubpic(theOrigin + height * 0.5, width + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5 0 0' + bH, theColor, theAlpha, 0);
199 dY = theBorderSize.y * eY;
200 drawsubpic(theOrigin, width + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0);
201 drawsubpic(theOrigin + dY, width + height - 2 * dY, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
202 drawsubpic(theOrigin + height - dY, width + dY, pic, '0.25 0.75 0', '0.5 0.25 0', theColor, theAlpha, 0);
205 else if(theSize.x <= theBorderSize.x * 2)
207 // not wide enough... draw just left and right then
208 bW = eX * (0.25 * theSize.x / (theBorderSize.x * 2));
209 if(theBorderSize.y <= 0)
211 drawsubpic(theOrigin, width * 0.5 + height, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0);
212 drawsubpic(theOrigin + width * 0.5, width * 0.5 + height, pic, '0 0.25 0' + eX - bW, '0 0.5 0' + bW, theColor, theAlpha, 0);
214 else if(theSize.y <= theBorderSize.y * 2)
216 // not high enough... draw just corners
217 bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
218 drawsubpic(theOrigin, width * 0.5 + height * 0.5, pic, '0 0 0', bW + bH, theColor, theAlpha, 0);
219 drawsubpic(theOrigin + width * 0.5, width * 0.5 + height * 0.5, pic, eX - bW, bW + bH, theColor, theAlpha, 0);
220 drawsubpic(theOrigin + height * 0.5, width * 0.5 + height * 0.5, pic, eY - bH, bW + bH, theColor, theAlpha, 0);
221 drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
225 dY = theBorderSize.y * eY;
226 drawsubpic(theOrigin, width * 0.5 + dY, pic, '0 0 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
227 drawsubpic(theOrigin + width * 0.5, width * 0.5 + dY, pic, '0 0 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
228 drawsubpic(theOrigin + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0);
229 drawsubpic(theOrigin + width * 0.5 + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0' + eX - bW, '0 0.5 0' + bW, theColor, theAlpha, 0);
230 drawsubpic(theOrigin + height - dY, width * 0.5 + dY, pic, '0 0.75 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
231 drawsubpic(theOrigin + width * 0.5 + height - dY, width * 0.5 + dY, pic, '0 0.75 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
236 if(theBorderSize.y <= 0)
238 dX = theBorderSize.x * eX;
239 drawsubpic(theOrigin, dX + height, pic, '0 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
240 drawsubpic(theOrigin + dX, width - 2 * dX + height, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
241 drawsubpic(theOrigin + width - dX, dX + height, pic, '0.75 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
243 else if(theSize.y <= theBorderSize.y * 2)
245 // not high enough... draw just top and bottom then
246 bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
247 dX = theBorderSize.x * eX;
248 drawsubpic(theOrigin, dX + height * 0.5, pic, '0 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
249 drawsubpic(theOrigin + dX, width - 2 * dX + height * 0.5, pic, '0.25 0 0', '0.5 0 0' + bH, theColor, theAlpha, 0);
250 drawsubpic(theOrigin + width - dX, dX + height * 0.5, pic, '0.75 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
251 drawsubpic(theOrigin + height * 0.5, dX + height * 0.5, pic, '0 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
252 drawsubpic(theOrigin + dX + height * 0.5, width - 2 * dX + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5 0 0' + bH, theColor, theAlpha, 0);
253 drawsubpic(theOrigin + width - dX + height * 0.5, dX + height * 0.5, pic, '0.75 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
257 dX = theBorderSize.x * eX;
258 dY = theBorderSize.y * eY;
259 drawsubpic(theOrigin, dX + dY, pic, '0 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
260 drawsubpic(theOrigin + dX, width - 2 * dX + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0);
261 drawsubpic(theOrigin + width - dX, dX + dY, pic, '0.75 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
262 drawsubpic(theOrigin + dY, dX + height - 2 * dY, pic, '0 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
263 drawsubpic(theOrigin + dY + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
264 drawsubpic(theOrigin + dY + width - dX, dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
265 drawsubpic(theOrigin + height - dY, dX + dY, pic, '0 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
266 drawsubpic(theOrigin + height - dY + dX, width - 2 * dX + dY, pic, '0.25 0.75 0', '0.5 0.25 0', theColor, theAlpha, 0);
267 drawsubpic(theOrigin + height - dY + width - dX, dX + dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
271 void draw_Text(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
273 if(theSize.x <= 0 || theSize.y <= 0) {
274 LOG_TRACE("Drawing zero size text?");
279 //wi = draw_TextWidth(theText, ICanHasKallerz, theSize);
280 //draw_Fill(theOrigin, '1 0 0' * wi + '0 1 0' * theSize_y, '1 0 0', 0.3);
283 drawcolorcodedstring(boxToGlobal(theOrigin, draw_shift, draw_scale), theText, globalToBoxSize(boxToGlobalSize(theSize, draw_scale), draw_fontscale), theAlpha * draw_alpha, 0);
285 drawstring(boxToGlobal(theOrigin, draw_shift, draw_scale), theText, globalToBoxSize(boxToGlobalSize(theSize, draw_scale), draw_fontscale), theColor, theAlpha * draw_alpha, 0);
287 void draw_CenterText(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
289 //dprint(strcat("orig = ", vtos(theOrigin) ," tx = ", ftos(draw_TextWidth(theText, ICanHasKallerz, theSize)), "\n"));
290 draw_Text(theOrigin - eX * 0.5 * draw_TextWidth(theText, ICanHasKallerz, theSize), theText, theSize, theColor, theAlpha, ICanHasKallerz);
293 float draw_TextWidth(string theText, float ICanHasKallerz, vector SizeThxBye)
295 //return strlen(theText);
296 //dprint("draw_TextWidth \"", theText, "\"\n");
300 v.x = stringwidth(theText, ICanHasKallerz, globalToBoxSize(boxToGlobalSize(SizeThxBye, draw_scale), draw_fontscale));
301 v = globalToBoxSize(v, draw_scale);
305 float draw_CondensedFontFactor(string theText, float ICanHasKallerz, vector SizeThxBye, float maxWidth)
307 float w = draw_TextWidth(theText, ICanHasKallerz, SizeThxBye);
309 //dprintf("NOTE: label text %s too wide for label, condensed by factor %f\n", theText, maxWidth / w);
315 IntrusiveList draw_clip;
316 STATIC_INIT(draw_clip) { draw_clip = IL_NEW(); }
317 CLASS(ClipFrame, Object)
318 ATTRIB(ClipFrame, clip_shift, vector, '0 0 0');
319 ATTRIB(ClipFrame, clip_scale, vector, '0 0 0');
322 void _draw_SetClip(vector o, vector s)
324 ClipFrame prev = IL_PEEK(draw_clip);
326 o.x = bound(prev.clip_shift.x, o.x, prev.clip_shift.x + prev.clip_scale.x);
327 o.y = bound(prev.clip_shift.y, o.y, prev.clip_shift.y + prev.clip_scale.y);
328 s.x = bound(0, s.x, prev.clip_scale.x - (o.x - prev.clip_shift.x));
329 s.y = bound(0, s.y, prev.clip_scale.y - (o.y - prev.clip_shift.y));
331 ClipFrame e = NEW(ClipFrame);
334 IL_PUSH(draw_clip, e);
335 drawsetcliparea(o.x, o.y, s.x, s.y);
340 _draw_SetClip(draw_shift, draw_scale);
343 void draw_SetClipRect(vector theOrigin, vector theScale)
346 boxToGlobal(theOrigin, draw_shift, draw_scale),
347 boxToGlobalSize(theScale, draw_scale)
351 void draw_ClearClip()
353 if (IL_EMPTY(draw_clip)) {
354 LOG_FATAL("Not clipping, can't clear it then");
356 entity currentSettings = IL_PEEK(draw_clip);
357 IL_REMOVE(draw_clip, currentSettings);
358 delete(currentSettings);
360 ClipFrame e = IL_PEEK(draw_clip);
362 drawsetcliparea(e.clip_shift.x, e.clip_shift.y, e.clip_scale.x, e.clip_scale.y);
366 string draw_TextShortenToWidth(string theText, float maxWidth, float ICanHasKallerz, vector SizeThxBye)
369 if(draw_TextWidth(theText, ICanHasKallerz, SizeThxBye) <= maxWidth)
372 return strcat(substring(theText, 0, draw_TextLengthUpToWidth(theText, maxWidth - draw_TextWidth("...", ICanHasKallerz, SizeThxBye), ICanHasKallerz, SizeThxBye)), "...");
375 return textShortenToWidth(theText, maxWidth, SizeThxBye, draw_TextWidth_WithColors);
377 return textShortenToWidth(theText, maxWidth, SizeThxBye, draw_TextWidth_WithoutColors);
380 float draw_TextWidth_WithColors(string s, vector theFontSize)
382 return draw_TextWidth(s, true, theFontSize);
385 float draw_TextWidth_WithoutColors(string s, vector theFontSize)
387 return draw_TextWidth(s, false, theFontSize);
390 float draw_TextLengthUpToWidth(string theText, float maxWidth, float allowColorCodes, vector theFontSize)
393 return textLengthUpToWidth(theText, maxWidth, theFontSize, draw_TextWidth_WithColors);
395 return textLengthUpToWidth(theText, maxWidth, theFontSize, draw_TextWidth_WithoutColors);