]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu-div0test/draw.qc
background image support; align "quit" to the bottom of the screen
[divverent/nexuiz.git] / data / qcsrc / menu-div0test / draw.qc
1 float drawfont;
2 string draw_mousepointer;
3
4 string draw_UseSkinFor(string pic)
5 {
6         if(substring(pic, 0, 1) == "/")
7                 return substring(pic, 1, strlen(pic)-1);
8         else
9                 return strcat(draw_currentSkin, "/", pic);
10 }
11
12 void draw_setMousePointer(string pic)
13 {
14         draw_mousepointer = strzone(draw_UseSkinFor(pic));
15 }
16
17 void draw_drawMousePointer(vector where)
18 {
19         drawpic(boxToGlobal(where, draw_shift, draw_scale), draw_mousepointer, '32 32 0', '1 1 1', draw_alpha, 0);
20 }
21
22 void draw_reset()
23 {
24         drawfont = 8;
25         draw_shift = '0 0 0';
26         draw_scale = '1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight");
27         draw_alpha = 1;
28 }
29
30 vector globalToBox(vector v, vector theOrigin, vector theScale)
31 {
32         v -= theOrigin;
33         v_x /= theScale_x;
34         v_y /= theScale_y;
35         return v;
36 }
37
38 vector globalToBoxSize(vector v, vector theScale)
39 {
40         v_x /= theScale_x;
41         v_y /= theScale_y;
42         return v;
43 }
44
45 vector boxToGlobal(vector v, vector theOrigin, vector theScale)
46 {
47         v_x *= theScale_x;
48         v_y *= theScale_y;
49         v += theOrigin;
50         return v;
51 }
52
53 vector boxToGlobalSize(vector v, vector theScale)
54 {
55         v_x *= theScale_x;
56         v_y *= theScale_y;
57         return v;
58 }
59
60 void draw_PreloadPicture(string pic)
61 {
62         pic = draw_UseSkinFor(pic);
63         precache_pic(pic);
64 }
65
66 void draw_Picture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
67 {
68         pic = draw_UseSkinFor(pic);
69         drawpic(boxToGlobal(theOrigin, draw_shift, draw_scale), pic, boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
70 }
71
72 vector draw_PictureSize(string pic)
73 {
74         pic = draw_UseSkinFor(pic);
75         return drawgetimagesize(pic);
76 }
77
78 void draw_Fill(vector theOrigin, vector theSize, vector theColor, float theAlpha)
79 {
80         drawfill(boxToGlobal(theOrigin, draw_shift, draw_scale), boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
81 }
82
83 // a button picture is a texture containing three parts:
84 //   1/4 width: left part
85 //   1/2 width: middle part (stretched)
86 //   1/4 width: right part
87 // it is assumed to be 4x as wide as high for aspect ratio purposes, which
88 // means, the parts are a square, two squares and a square.
89 void draw_ButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
90 {
91         vector square;
92         vector width, height;
93         vector bW;
94         pic = draw_UseSkinFor(pic);
95         theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
96         theSize = boxToGlobalSize(theSize, draw_scale);
97         theAlpha *= draw_alpha;
98         width = eX * theSize_x;
99         height = eY * theSize_y;
100         if(theSize_x <= theSize_y * 2)
101         {
102                 // button not wide enough
103                 // draw just left and right part then
104                 square = eX * theSize_x * 0.5;
105                 bW = eX * (0.25 * theSize_x / (theSize_y * 2));
106                 drawsubpic(theOrigin,          square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, 0);
107                 drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, 0);
108         }
109         else
110         {
111                 square = eX * theSize_y;
112                 drawsubpic(theOrigin,                  height  +     square, pic, '0    0 0', '0.25 1 0', theColor, theAlpha, 0);
113                 drawsubpic(theOrigin +         square, theSize - 2 * square, pic, '0.25 0 0', '0.5  1 0', theColor, theAlpha, 0);
114                 drawsubpic(theOrigin + width - square, height  +     square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, 0);
115         }
116 }
117
118 // a vertical button picture is a texture containing three parts:
119 //   1/4 height: left part
120 //   1/2 height: middle part (stretched)
121 //   1/4 height: right part
122 // it is assumed to be 4x as high as wide for aspect ratio purposes, which
123 // means, the parts are a square, two squares and a square.
124 void draw_VertButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
125 {
126         vector square;
127         vector width, height;
128         vector bH;
129         pic = draw_UseSkinFor(pic);
130         theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
131         theSize = boxToGlobalSize(theSize, draw_scale);
132         theAlpha *= draw_alpha;
133         width = eX * theSize_x;
134         height = eY * theSize_y;
135         if(theSize_y <= theSize_x * 2)
136         {
137                 // button not high enough
138                 // draw just upper and lower part then
139                 square = eY * theSize_y * 0.5;
140                 bH = eY * (0.25 * theSize_y / (theSize_x * 2));
141                 drawsubpic(theOrigin,          square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, 0);
142                 drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, 0);
143         }
144         else
145         {
146                 square = eY * theSize_x;
147                 drawsubpic(theOrigin,                   width   +     square, pic, '0 0    0', '1 0.25 0', theColor, theAlpha, 0);
148                 drawsubpic(theOrigin +          square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5  0', theColor, theAlpha, 0);
149                 drawsubpic(theOrigin + height - square, width   +     square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, 0);
150         }
151 }
152
153 // a border picture is a texture containing nine parts:
154 //   1/4 width: left part
155 //   1/2 width: middle part (stretched)
156 //   1/4 width: right part
157 // divided into
158 //   1/4 height: top part
159 //   1/2 height: middle part (stretched)
160 //   1/4 height: bottom part
161 void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
162 {
163         vector dX, dY;
164         vector width, height;
165         vector bW, bH;
166         pic = draw_UseSkinFor(pic);
167         theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
168         theSize = boxToGlobalSize(theSize, draw_scale);
169         theBorderSize = boxToGlobalSize(theBorderSize, draw_scale);
170         theAlpha *= draw_alpha;
171         width = eX * theSize_x;
172         height = eY * theSize_y;
173         if(theSize_x <= theBorderSize_x * 2)
174         {
175                 // not wide enough... draw just left and right then
176                 bW = eX * (0.25 * theSize_x / (theBorderSize_x * 2));
177                 if(theSize_y <= theBorderSize_y * 2)
178                 {
179                         // not high enough... draw just corners
180                         bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2));
181                         drawsubpic(theOrigin,                 width * 0.5 + height * 0.5, pic, '0 0 0',           bW + bH, theColor, theAlpha, 0);
182                         drawsubpic(theOrigin + width   * 0.5, width * 0.5 + height * 0.5, pic, eX - bW,           bW + bH, theColor, theAlpha, 0);
183                         drawsubpic(theOrigin + height  * 0.5, width * 0.5 + height * 0.5, pic, eY - bH,           bW + bH, theColor, theAlpha, 0);
184                         drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
185                 }
186                 else
187                 {
188                         dY = theBorderSize_x * eY;
189                         drawsubpic(theOrigin,                             width * 0.5          +     dY, pic, '0 0    0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
190                         drawsubpic(theOrigin + width * 0.5,               width * 0.5          +     dY, pic, '0 0    0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
191                         drawsubpic(theOrigin                        + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0',           '0 0.5  0' + bW, theColor, theAlpha, 0);
192                         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);
193                         drawsubpic(theOrigin               + height - dY, width * 0.5          +     dY, pic, '0 0.75 0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
194                         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);
195                 }
196         }
197         else
198         {
199                 if(theSize_y <= theBorderSize_y * 2)
200                 {
201                         // not high enough... draw just top and bottom then
202                         bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2));
203                         dX = theBorderSize_x * eX;
204                         drawsubpic(theOrigin,                                         dX + height * 0.5, pic, '0    0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
205                         drawsubpic(theOrigin + dX,                        width - 2 * dX + height * 0.5, pic, '0.25 0 0',           '0.5  0 0' + bH, theColor, theAlpha, 0);
206                         drawsubpic(theOrigin + width - dX,                            dX + height * 0.5, pic, '0.75 0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
207                         drawsubpic(theOrigin              + height * 0.5,             dX + height * 0.5, pic, '0    0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
208                         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);
209                         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);
210                 }
211                 else
212                 {
213                         dX = theBorderSize_x * eX;
214                         dY = theBorderSize_x * eY;
215                         drawsubpic(theOrigin,                                        dX          +     dY, pic, '0    0    0', '0.25 0.25 0', theColor, theAlpha, 0);
216                         drawsubpic(theOrigin                  + dX,      width - 2 * dX          +     dY, pic, '0.25 0    0', '0.5  0.25 0', theColor, theAlpha, 0);
217                         drawsubpic(theOrigin          + width - dX,                  dX          +     dY, pic, '0.75 0    0', '0.25 0.25 0', theColor, theAlpha, 0);
218                         drawsubpic(theOrigin          + dY,                          dX + height - 2 * dY, pic, '0    0.25 0', '0.25 0.5  0', theColor, theAlpha, 0);
219                         drawsubpic(theOrigin          + dY         + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5  0.5  0', theColor, theAlpha, 0);
220                         drawsubpic(theOrigin          + dY + width - dX,             dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5  0', theColor, theAlpha, 0);
221                         drawsubpic(theOrigin + height - dY,                          dX          +     dY, pic, '0    0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
222                         drawsubpic(theOrigin + height - dY         + dX, width - 2 * dX          +     dY, pic, '0.25 0.75 0', '0.5  0.25 0', theColor, theAlpha, 0);
223                         drawsubpic(theOrigin + height - dY + width - dX,             dX          +     dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
224                 }
225         }
226 }
227 void draw_Text(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
228 {
229         if(theSize_x <= 0 || theSize_y <= 0)
230                 error("Drawing zero size text?\n");
231         if(ICanHasKallerz)
232                 drawcolorcodedstring(boxToGlobal(theOrigin, draw_shift, draw_scale), theText, boxToGlobalSize(theSize, draw_scale), theAlpha * draw_alpha, 0);
233         else
234                 drawstring(boxToGlobal(theOrigin, draw_shift, draw_scale), theText, boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
235 }
236 void draw_CenterText(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
237 {
238         draw_Text(theOrigin - eX * theSize_x * 0.5 * draw_TextWidth(theText, ICanHasKallerz), theText, theSize, theColor, theAlpha, ICanHasKallerz);
239 }
240
241 float draw_TextWidth(string theText, float ICanHasKallerz)
242 {
243         //return strlen(theText);
244         //print("draw_TextWidth \"", theText, "\"\n");
245         return stringwidth(theText, ICanHasKallerz);
246 }
247
248 float draw_clipSet;
249 void draw_SetClip()
250 {
251         if(draw_clipSet)
252                 error("Already clipping, no stack implemented here, sorry");
253         drawsetcliparea(draw_shift_x, draw_shift_y, draw_scale_x, draw_scale_y);
254         draw_clipSet = 1;
255 }
256
257 void draw_SetClipRect(vector theOrigin, vector theScale)
258 {
259         vector o, s;
260         if(draw_clipSet)
261                 error("Already clipping, no stack implemented here, sorry");
262         o = boxToGlobal(theOrigin, draw_shift, draw_scale);
263         s = boxToGlobalSize(theScale, draw_scale);
264         drawsetcliparea(o_x, o_y, s_x, s_y);
265         draw_clipSet = 1;
266 }
267
268 void draw_ClearClip()
269 {
270         if(!draw_clipSet)
271                 error("Not clipping, can't clear it then");
272         drawresetcliparea();
273         draw_clipSet = 0;
274 }
275
276 string draw_TextShortenToWidth(string theText, float maxWidth, float ICanHasKallerz)
277 {
278         if(draw_TextWidth(theText, ICanHasKallerz) <= maxWidth)
279                 return theText;
280         else
281                 return strcat(substring(theText, 0, draw_TextLengthUpToWidth(theText, maxWidth - draw_TextWidth("...", ICanHasKallerz), ICanHasKallerz)), "...");
282 }
283
284 float draw_TextLengthUpToWidth(string theText, float maxWidth, float ICanHasKallerz)
285 {
286         // STOP.
287         // The following function is SLOW.
288         // For your safety and for the protection of those around you...
289         // DO NOT CALL THIS AT HOME.
290         // No really, don't.
291         if(draw_TextWidth(theText, ICanHasKallerz) <= maxWidth)
292                 return strlen(theText); // yeah!
293
294         // binary search for right place to cut string
295         float left, right, middle; // this always works
296         left = 0;
297         right = strlen(theText); // this always fails
298         do
299         {
300                 middle = floor((left + right) / 2);
301                 if(draw_TextWidth(substring(theText, 0, middle), ICanHasKallerz) <= maxWidth)
302                         left = middle;
303                 else
304                         right = middle;
305         }
306         while(left < right - 1);
307
308         // NOTE: when color codes are involved, this binary search is,
309         // mathematically, BROKEN. However, it is obviously guaranteed to
310         // terminate, as the range still halves each time - but nevertheless, it is
311         // guaranteed that it finds ONE valid cutoff place (where "left" is in
312         // range, and "right" is outside).
313
314         return left;
315 }