1 
2 #include <stdint.h>
3 #include <string.h>
4 #include <ctype.h>
5 
6 #include "../core/gl_util.h"
7 #include "../core/gl_font.h"
8 #include "../core/gl_text.h"
9 #include "../core/system.h"
10 #include "../core/console.h"
11 #include "../core/vmath.h"
12 
13 #include "../render/camera.h"
14 #include "../render/render.h"
15 #include "../render/shader_description.h"
16 #include "../render/shader_manager.h"
17 #include "../script/script.h"
18 #include "../audio/audio.h"
19 #include "../image.h"
20 #include "../mesh.h"
21 #include "../skeletal_model.h"
22 #include "../entity.h"
23 #include "../character_controller.h"
24 #include "../engine.h"
25 #include "../engine_string.h"
26 #include "../world.h"
27 #include "gui.h"
28 #include "gui_inventory.h"
29 
30 gui_ProgressBar     Bar[BAR_LASTINDEX];
31 static GLuint       crosshairBuffer = 0;
32 static GLuint       rectBuffer = 0;
33 static GLuint       load_screen_tex = 0;
34 GLuint      backgroundBuffer = 0;
35 GLfloat     guiProjectionMatrix[16];
36 
37 static GLfloat screenSize[2];
38 
39 static void Gui_FillCrosshairBuffer();
40 static void Gui_FillBackgroundBuffer();
41 
Gui_Init()42 void Gui_Init()
43 {
44     Gui_InitBars();
45     Gui_InitNotifier();
46 
47     qglGenBuffersARB(1, &crosshairBuffer);
48     qglGenBuffersARB(1, &backgroundBuffer);
49     qglGenBuffersARB(1, &rectBuffer);
50     qglGenTextures(1, &load_screen_tex);
51     Gui_FillCrosshairBuffer();
52     Gui_FillBackgroundBuffer();
53 
54     main_inventory_manager = new gui_InventoryManager();
55 }
56 
57 
Gui_InitBars()58 void Gui_InitBars()
59 {
60     for(int i = 0; i < BAR_LASTINDEX; i++)
61     {
62         switch(i)
63         {
64             case BAR_HEALTH:
65                 {
66                     Bar[i].Visible =      false;
67                     Bar[i].Alternate =    false;
68                     Bar[i].Invert =       false;
69                     Bar[i].Vertical =     false;
70 
71                     Bar[i].SetSize(250, 15, 3);
72                     Bar[i].SetPosition(GUI_ANCHOR_HOR_LEFT, 30, GUI_ANCHOR_VERT_TOP, 30);
73                     Bar[i].SetColor(BASE_MAIN, 255, 50, 50, 200);
74                     Bar[i].SetColor(BASE_FADE, 100, 255, 50, 200);
75                     Bar[i].SetColor(ALT_MAIN, 255, 180, 0, 255);
76                     Bar[i].SetColor(ALT_FADE, 255, 255, 0, 255);
77                     Bar[i].SetColor(BACK_MAIN, 0, 0, 0, 160);
78                     Bar[i].SetColor(BACK_FADE, 60, 60, 60, 130);
79                     Bar[i].SetColor(BORDER_MAIN, 200, 200, 200, 50);
80                     Bar[i].SetColor(BORDER_FADE, 80, 80, 80, 100);
81                     Bar[i].SetValues(LARA_PARAM_HEALTH_MAX, LARA_PARAM_HEALTH_MAX / 3);
82                     Bar[i].SetBlink(300);
83                     Bar[i].SetExtrude(true, 100);
84                     Bar[i].SetAutoshow(true, 2000, true, 400);
85                 }
86                 break;
87 
88             case BAR_AIR:
89                 {
90                     Bar[i].Visible =      false;
91                     Bar[i].Alternate =    false;
92                     Bar[i].Invert =       true;
93                     Bar[i].Vertical =     false;
94 
95                     Bar[i].SetSize(250, 15, 3);
96                     Bar[i].SetPosition(GUI_ANCHOR_HOR_RIGHT, 30, GUI_ANCHOR_VERT_TOP, 30);
97                     Bar[i].SetColor(BASE_MAIN, 0, 50, 255, 200);
98                     Bar[i].SetColor(BASE_FADE, 190, 190, 255, 200);
99                     Bar[i].SetColor(BACK_MAIN, 0, 0, 0, 160);
100                     Bar[i].SetColor(BACK_FADE, 60, 60, 60, 130);
101                     Bar[i].SetColor(BORDER_MAIN, 200, 200, 200, 50);
102                     Bar[i].SetColor(BORDER_FADE, 80, 80, 80, 100);
103                     Bar[i].SetValues(LARA_PARAM_AIR_MAX, (LARA_PARAM_AIR_MAX / 3));
104                     Bar[i].SetBlink(300);
105                     Bar[i].SetExtrude(true, 100);
106                     Bar[i].SetAutoshow(true, 2000, true, 400);
107                 }
108                 break;
109 
110             case BAR_STAMINA:
111                 {
112                     Bar[i].Visible =      false;
113                     Bar[i].Alternate =    false;
114                     Bar[i].Invert =       false;
115                     Bar[i].Vertical =     false;
116 
117                     Bar[i].SetSize(250, 15, 3);
118                     Bar[i].SetPosition(GUI_ANCHOR_HOR_LEFT, 30, GUI_ANCHOR_VERT_TOP, 55);
119                     Bar[i].SetColor(BASE_MAIN, 255, 100, 50, 200);
120                     Bar[i].SetColor(BASE_FADE, 255, 200, 0, 200);
121                     Bar[i].SetColor(BACK_MAIN, 0, 0, 0, 160);
122                     Bar[i].SetColor(BACK_FADE, 60, 60, 60, 130);
123                     Bar[i].SetColor(BORDER_MAIN, 110, 110, 110, 100);
124                     Bar[i].SetColor(BORDER_FADE, 60, 60, 60, 180);
125                     Bar[i].SetValues(LARA_PARAM_STAMINA_MAX, 0);
126                     Bar[i].SetExtrude(true, 100);
127                     Bar[i].SetAutoshow(true, 500, true, 300);
128                 }
129                 break;
130 
131             case BAR_WARMTH:
132                 {
133                     Bar[i].Visible =      false;
134                     Bar[i].Alternate =    false;
135                     Bar[i].Invert =       true;
136                     Bar[i].Vertical =     false;
137 
138                     Bar[i].SetSize(250, 15, 3);
139                     Bar[i].SetPosition(GUI_ANCHOR_HOR_RIGHT, 30, GUI_ANCHOR_VERT_TOP, 55);
140                     Bar[i].SetColor(BASE_MAIN, 255, 0, 255, 255);
141                     Bar[i].SetColor(BASE_FADE, 190, 120, 255, 255);
142                     Bar[i].SetColor(BACK_MAIN, 0, 0, 0, 160);
143                     Bar[i].SetColor(BACK_FADE, 60, 60, 60, 130);
144                     Bar[i].SetColor(BORDER_MAIN, 200, 200, 200, 50);
145                     Bar[i].SetColor(BORDER_FADE, 80, 80, 80, 100);
146                     Bar[i].SetValues(LARA_PARAM_WARMTH_MAX, LARA_PARAM_WARMTH_MAX / 3);
147                     Bar[i].SetBlink(200);
148                     Bar[i].SetExtrude(true, 60);
149                     Bar[i].SetAutoshow(true, 500, true, 300);
150                 }
151                 break;
152 
153             case BAR_LOADING:
154                 {
155                     Bar[i].Visible =      true;
156                     Bar[i].Alternate =    false;
157                     Bar[i].Invert =       false;
158                     Bar[i].Vertical =     false;
159 
160                     Bar[i].SetSize(800, 25, 3);
161                     Bar[i].SetPosition(GUI_ANCHOR_HOR_CENTER, 0, GUI_ANCHOR_VERT_BOTTOM, 40);
162                     Bar[i].SetColor(BASE_MAIN, 255, 225, 127, 230);
163                     Bar[i].SetColor(BASE_FADE, 255, 187, 136, 230);
164                     Bar[i].SetColor(BACK_MAIN, 30, 30, 30, 100);
165                     Bar[i].SetColor(BACK_FADE, 60, 60, 60, 100);
166                     Bar[i].SetColor(BORDER_MAIN, 200, 200, 200, 80);
167                     Bar[i].SetColor(BORDER_FADE, 80, 80, 80, 80);
168                     Bar[i].SetValues(1000, 0);
169                     Bar[i].SetExtrude(true, 70);
170                     Bar[i].SetAutoshow(false, 500, false, 300);
171                 }
172                 break;
173         } // end switch(i)
174     } // end for(int i = 0; i < BAR_LASTINDEX; i++)
175 }
176 
Gui_Destroy()177 void Gui_Destroy()
178 {
179     if(main_inventory_manager)
180     {
181         delete main_inventory_manager;
182         main_inventory_manager = NULL;
183     }
184 
185     qglDeleteTextures(1, &load_screen_tex);
186     qglDeleteBuffersARB(1, &crosshairBuffer);
187     qglDeleteBuffersARB(1, &backgroundBuffer);
188     qglDeleteBuffersARB(1, &rectBuffer);
189 }
190 
191 
Gui_UpdateResize()192 void Gui_UpdateResize()
193 {
194     for(int i = 0; i < BAR_LASTINDEX; i++)
195     {
196         Bar[i].Resize();
197     }
198 
199     Gui_FillCrosshairBuffer();
200     Gui_FillBackgroundBuffer();
201 }
202 
203 
Gui_Render()204 void Gui_Render()
205 {
206     const text_shader_description *shader = renderer.shaderManager->getTextShader();
207     screenSize[0] = screen_info.w;
208     screenSize[1] = screen_info.h;
209     qglUseProgramObjectARB(shader->program);
210     qglUniform1iARB(shader->sampler, 0);
211     qglUniform2fvARB(shader->screenSize, 1, screenSize);
212     qglUniform1fARB(shader->colorReplace, 0.0f);
213 
214     qglPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT);
215     qglPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT | GL_CLIENT_VERTEX_ARRAY_BIT);
216 
217     qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
218     qglPolygonMode(GL_FRONT, GL_FILL);
219     qglFrontFace(GL_CCW);
220     qglEnable(GL_BLEND);
221     qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
222     qglDisable(GL_ALPHA_TEST);
223 
224     if(World_GetPlayer() && main_inventory_manager)
225     {
226         Gui_DrawInventory(engine_frame_time);
227     }
228     Gui_DrawNotifier(engine_frame_time);
229     qglUseProgramObjectARB(shader->program);
230 
231     qglDepthMask(GL_FALSE);
232 
233     qglPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
234     qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
235 
236     if(screen_info.crosshair != 0)
237     {
238         Gui_DrawCrosshair();
239     }
240     Gui_DrawBars();
241 
242     qglUniform1fARB(shader->colorReplace, 1.0f);
243     GLText_RenderStrings();
244     Con_Draw(engine_frame_time);
245 
246     qglUniform1fARB(shader->colorReplace, 0.0f);
247     qglDepthMask(GL_TRUE);
248     qglPopClientAttrib();
249     qglPopAttrib();
250 }
251 
252 /*
253  * Other GUI options
254  */
Gui_SwitchGLMode(char is_gui)255 void Gui_SwitchGLMode(char is_gui)
256 {
257     if(0 != is_gui)                                                             // set gui coordinate system
258     {
259         const GLfloat far_dist = 4096.0f;
260         const GLfloat near_dist = -1.0f;
261 
262         Mat4_E_macro(guiProjectionMatrix);
263         guiProjectionMatrix[0 * 4 + 0] = 2.0 / ((GLfloat)screen_info.w);
264         guiProjectionMatrix[1 * 4 + 1] = 2.0 / ((GLfloat)screen_info.h);
265         guiProjectionMatrix[2 * 4 + 2] =-2.0 / (far_dist - near_dist);
266         guiProjectionMatrix[3 * 4 + 0] =-1.0;
267         guiProjectionMatrix[3 * 4 + 1] =-1.0;
268         guiProjectionMatrix[3 * 4 + 2] =-(far_dist + near_dist) / (far_dist - near_dist);
269     }
270     else                                                                        // set camera coordinate system
271     {
272         memcpy(guiProjectionMatrix, engine_camera.gl_proj_mat, sizeof(guiProjectionMatrix));
273     }
274 }
275 
Gui_FillBackgroundBuffer()276 void Gui_FillBackgroundBuffer()
277 {
278     GLfloat x0 = 0.0f;
279     GLfloat y0 = 0.0f;
280     GLfloat x1 = screen_info.w;
281     GLfloat y1 = screen_info.h;
282     GLfloat *v, backgroundArray[32];
283     GLfloat color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
284 
285     v = backgroundArray;
286    *v++ = x0; *v++ = y0;
287     vec4_copy(v, color);
288     v += 4;
289    *v++ = 0.0f; *v++ = 0.0f;
290 
291    *v++ = x1; *v++ = y0;
292     vec4_copy(v, color);
293     v += 4;
294    *v++ = 1.0f; *v++ = 0.0f;
295 
296    *v++ = x1; *v++ = y1;
297     vec4_copy(v, color);
298     v += 4;
299    *v++ = 1.0f; *v++ = 1.0f;
300 
301    *v++ = x0; *v++ = y1;
302     vec4_copy(v, color);
303     v += 4;
304    *v++ = 0.0f; *v++ = 1.0f;
305 
306     qglBindBufferARB(GL_ARRAY_BUFFER, backgroundBuffer);
307     qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), backgroundArray, GL_STATIC_DRAW);
308 }
309 
Gui_FillCrosshairBuffer()310 void Gui_FillCrosshairBuffer()
311 {
312     GLfloat x = (GLfloat)screen_info.w / 2.0f;
313     GLfloat y = (GLfloat)screen_info.h / 2.0f;
314     GLfloat *v, crosshairArray[32];
315     const GLfloat size = 8.0f;
316     const GLfloat color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
317 
318     v = crosshairArray;
319    *v++ = x; *v++ = y - size;
320     vec4_copy(v, color);
321     v += 4;
322    *v++ = 0.0; *v++ = 0.0;
323 
324    *v++ = x; *v++ = y + size;
325     vec4_copy(v, color);
326     v += 4;
327    *v++ = 0.0; *v++ = 0.0;
328 
329    *v++ = x - size; *v++ = y;
330     vec4_copy(v, color);
331     v += 4;
332    *v++ = 0.0; *v++ = 0.0;
333 
334    *v++ = x + size; *v++ = y;
335     vec4_copy(v, color);
336     v += 4;
337    *v++ = 0.0; *v++ = 0.0;
338 
339     // copy vertices into GL buffer
340     qglBindBufferARB(GL_ARRAY_BUFFER, crosshairBuffer);
341     qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), crosshairArray, GL_STATIC_DRAW);
342 }
343 
Gui_DrawCrosshair()344 void Gui_DrawCrosshair()
345 {
346     // TBI: actual ingame crosshair
347     BindWhiteTexture();
348     qglBindBufferARB(GL_ARRAY_BUFFER_ARB, crosshairBuffer);
349     qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)0);
350     qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[2]));
351     qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[6]));
352     qglDrawArrays(GL_LINES, 0, 4);
353 }
354 
Gui_DrawBars()355 void Gui_DrawBars()
356 {
357     entity_p player = World_GetPlayer();
358     if(player && player->character)
359     {
360         if(player->character->weapon_state > WEAPON_STATE_HIDE_TO_READY)
361         {
362             Bar[BAR_HEALTH].Forced = true;
363         }
364 
365         Bar[BAR_AIR].Show    (Character_GetParam(player, PARAM_AIR    ));
366         Bar[BAR_STAMINA].Show(Character_GetParam(player, PARAM_STAMINA));
367         Bar[BAR_HEALTH].Show (Character_GetParam(player, PARAM_HEALTH ));
368         Bar[BAR_WARMTH].Show (Character_GetParam(player, PARAM_WARMTH ));
369     }
370 }
371 
Gui_DrawLoadScreen(int value)372 void Gui_DrawLoadScreen(int value)
373 {
374     qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
375 
376     qglPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT);
377     qglPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
378     qglPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
379     qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
380 
381     qglEnableClientState(GL_VERTEX_ARRAY);
382     qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
383     qglEnableClientState(GL_COLOR_ARRAY);
384     qglDisableClientState(GL_NORMAL_ARRAY);
385 
386     qglEnable(GL_BLEND);
387     qglEnable(GL_TEXTURE_2D);
388     qglDisable(GL_ALPHA_TEST);
389     qglDepthMask(GL_FALSE);
390 
391     qglPolygonMode(GL_FRONT, GL_FILL);
392     qglFrontFace(GL_CCW);
393 
394     const GLfloat color_w[4] = {1.0f, 1.0f, 1.0f, 1.0f};
395     const text_shader_description *shader = renderer.shaderManager->getTextShader();
396     screenSize[0] = screen_info.w;
397     screenSize[1] = screen_info.h;
398     qglUseProgramObjectARB(shader->program);
399     qglUniform1iARB(shader->sampler, 0);
400     qglUniform2fvARB(shader->screenSize, 1, screenSize);
401 
402     Gui_DrawRect(0.0, 0.0, screen_info.w, screen_info.h, color_w, color_w, color_w, color_w, BM_OPAQUE, load_screen_tex);
403     if(value >= 0)
404     {
405         Bar[BAR_LOADING].Show(value);
406     }
407     qglDepthMask(GL_TRUE);
408     qglPopClientAttrib();
409     qglPopAttrib();
410 
411     Engine_GLSwapWindow();
412 }
413 
414 
Gui_SetScreenTexture(void * data,int w,int h,int bpp)415 bool Gui_SetScreenTexture(void *data, int w, int h, int bpp)
416 {
417     GLenum       texture_format;
418     GLuint       color_depth;
419 
420     if(bpp == 32)        // Contains an alpha channel
421     {
422         texture_format = GL_RGBA;
423         color_depth = GL_RGBA;
424     }
425     else if(bpp == 24)   // No alpha channel
426     {
427         texture_format = GL_RGB;
428         color_depth = GL_RGB;
429     }
430     else
431     {
432         return false;
433     }
434 
435     // Bind the texture object
436     qglBindTexture(GL_TEXTURE_2D, load_screen_tex);
437 
438     // Set the texture's stretching properties
439     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
440     qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
441 
442     // Edit the texture object's image data using the information SDL_Surface gives us
443     qglTexImage2D(GL_TEXTURE_2D, 0, color_depth, w, h, 0,
444                  texture_format, GL_UNSIGNED_BYTE, data);
445     qglBindTexture(GL_TEXTURE_2D, 0);
446 
447     return true;
448 }
449 
Gui_LoadScreenAssignPic(const char * pic_name)450 bool Gui_LoadScreenAssignPic(const char* pic_name)
451 {
452     size_t pic_len = strlen(pic_name);
453     size_t base_len = strlen(Engine_GetBasePath());
454     size_t buf_len = pic_len + base_len + 5;
455     char image_name_buf[buf_len];
456     int image_format = 0;
457 
458     strncpy(image_name_buf, Engine_GetBasePath(), buf_len);
459     strncat(image_name_buf, pic_name, buf_len);
460     if(pic_len > 3)
461     {
462         char *ext = image_name_buf + pic_len + base_len;
463         if(strncpy(ext, ".png", 5) && Sys_FileFound(image_name_buf, 0))
464         {
465             image_format = IMAGE_FORMAT_PNG;
466         }else if(strncpy(ext, ".pcx", 5) && Sys_FileFound(image_name_buf, 0))
467         {
468             image_format = IMAGE_FORMAT_PCX;
469         }
470     }
471 
472     uint8_t *img_pixels = NULL;
473     uint32_t img_w = 0;
474     uint32_t img_h = 0;
475     uint32_t img_bpp = 32;
476     if(Image_Load(image_name_buf, image_format, &img_pixels, &img_w, &img_h, &img_bpp))
477     {
478         bool ret = Gui_SetScreenTexture(img_pixels, img_w, img_h, img_bpp);
479         free(img_pixels);
480         return ret;
481     }
482 
483     return false;
484 }
485 
486 /**
487  * Draws simple colored rectangle with given parameters.
488  */
Gui_DrawRect(const GLfloat & x,const GLfloat & y,const GLfloat & width,const GLfloat & height,const float colorUpperLeft[],const float colorUpperRight[],const float colorLowerLeft[],const float colorLowerRight[],const int & blendMode,const GLuint texture)489 void Gui_DrawRect(const GLfloat &x, const GLfloat &y,
490                   const GLfloat &width, const GLfloat &height,
491                   const float colorUpperLeft[], const float colorUpperRight[],
492                   const float colorLowerLeft[], const float colorLowerRight[],
493                   const int &blendMode,
494                   const GLuint texture)
495 {
496     switch(blendMode)
497     {
498         case BM_HIDE:
499             return;
500         case BM_MULTIPLY:
501             qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
502             break;
503         case BM_SIMPLE_SHADE:
504             qglBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
505             break;
506         case BM_SCREEN:
507             qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
508             break;
509         default:
510         case BM_OPAQUE:
511             qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
512             break;
513     };
514 
515     GLfloat x0 = x;
516     GLfloat y0 = y + height;
517     GLfloat x1 = x + width;
518     GLfloat y1 = y;
519     GLfloat *v, rectArray[32];
520 
521     v = rectArray;
522    *v++ = x0; *v++ = y0;
523    *v++ = 0.0f; *v++ = 0.0f;
524     vec4_copy(v, colorUpperLeft);
525     v += 4;
526 
527    *v++ = x1; *v++ = y0;
528    *v++ = 1.0f; *v++ = 0.0f;
529     vec4_copy(v, colorUpperRight);
530     v += 4;
531 
532    *v++ = x1; *v++ = y1;
533    *v++ = 1.0f; *v++ = 1.0f;
534     vec4_copy(v, colorLowerRight);
535     v += 4;
536 
537    *v++ = x0; *v++ = y1;
538    *v++ = 0.0f; *v++ = 1.0f;
539     vec4_copy(v, colorLowerLeft);
540 
541     if(qglIsTexture(texture))
542     {
543         qglBindTexture(GL_TEXTURE_2D, texture);
544     }
545     else
546     {
547         BindWhiteTexture();
548     }
549     qglBindBufferARB(GL_ARRAY_BUFFER, rectBuffer);
550     qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), rectArray, GL_DYNAMIC_DRAW);
551     qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)0);
552     qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[2]));
553     qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[4]));
554     qglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
555 }
556 
557 // ===================================================================================
558 // ======================== PROGRESS BAR CLASS IMPLEMENTATION ========================
559 // ===================================================================================
560 
gui_ProgressBar()561 gui_ProgressBar::gui_ProgressBar()
562 {
563     // Set up some defaults.
564     Visible   = false;
565     Alternate = false;
566     Invert    = false;
567     Vertical  = false;
568     Forced    = false;
569 
570     // Initialize parameters.
571     // By default, bar is initialized with TR5-like health bar properties.
572     SetPosition(GUI_ANCHOR_HOR_LEFT, 20, GUI_ANCHOR_VERT_TOP, 20);
573     SetSize(250, 25, 3);
574     SetColor(BASE_MAIN, 255, 50, 50, 150);
575     SetColor(BASE_FADE, 100, 255, 50, 150);
576     SetColor(ALT_MAIN, 255, 180, 0, 220);
577     SetColor(ALT_FADE, 255, 255, 0, 220);
578     SetColor(BACK_MAIN, 0, 0, 0, 160);
579     SetColor(BACK_FADE, 60, 60, 60, 130);
580     SetColor(BORDER_MAIN, 200, 200, 200, 50);
581     SetColor(BORDER_FADE, 80, 80, 80, 100);
582     SetValues(1000, 300);
583     SetBlink(300);
584     SetExtrude(true, 100);
585     SetAutoshow(true, 5000, true, 1000);
586 }
587 
588 // Resize bar.
589 // This function should be called every time resize event occurs.
590 
Resize()591 void gui_ProgressBar::Resize()
592 {
593     RecalculateSize();
594     RecalculatePosition();
595 }
596 
597 // Set specified color.
SetColor(BarColorType colType,uint8_t R,uint8_t G,uint8_t B,uint8_t A)598 void gui_ProgressBar::SetColor(BarColorType colType,
599                            uint8_t R, uint8_t G, uint8_t B, uint8_t A)
600 {
601     float maxColValue = 255.0;
602 
603     switch(colType)
604     {
605         case BASE_MAIN:
606             mBaseMainColor[0] = (float)R / maxColValue;
607             mBaseMainColor[1] = (float)G / maxColValue;
608             mBaseMainColor[2] = (float)B / maxColValue;
609             mBaseMainColor[3] = (float)A / maxColValue;
610             mBaseMainColor[4] = mBaseMainColor[3];
611             return;
612         case BASE_FADE:
613             mBaseFadeColor[0] = (float)R / maxColValue;
614             mBaseFadeColor[1] = (float)G / maxColValue;
615             mBaseFadeColor[2] = (float)B / maxColValue;
616             mBaseFadeColor[3] = (float)A / maxColValue;
617             mBaseFadeColor[4] = mBaseFadeColor[3];
618             return;
619         case ALT_MAIN:
620             mAltMainColor[0] = (float)R / maxColValue;
621             mAltMainColor[1] = (float)G / maxColValue;
622             mAltMainColor[2] = (float)B / maxColValue;
623             mAltMainColor[3] = (float)A / maxColValue;
624             mAltMainColor[4] = mAltMainColor[3];
625             return;
626         case ALT_FADE:
627             mAltFadeColor[0] = (float)R / maxColValue;
628             mAltFadeColor[1] = (float)G / maxColValue;
629             mAltFadeColor[2] = (float)B / maxColValue;
630             mAltFadeColor[3] = (float)A / maxColValue;
631             mAltFadeColor[4] = mAltFadeColor[3];
632             return;
633         case BACK_MAIN:
634             mBackMainColor[0] = (float)R / maxColValue;
635             mBackMainColor[1] = (float)G / maxColValue;
636             mBackMainColor[2] = (float)B / maxColValue;
637             mBackMainColor[3] = (float)A / maxColValue;
638             mBackMainColor[4] = mBackMainColor[3];
639             return;
640         case BACK_FADE:
641             mBackFadeColor[0] = (float)R / maxColValue;
642             mBackFadeColor[1] = (float)G / maxColValue;
643             mBackFadeColor[2] = (float)B / maxColValue;
644             mBackFadeColor[3] = (float)A / maxColValue;
645             mBackFadeColor[4] = mBackFadeColor[3];
646             return;
647         case BORDER_MAIN:
648             mBorderMainColor[0] = (float)R / maxColValue;
649             mBorderMainColor[1] = (float)G / maxColValue;
650             mBorderMainColor[2] = (float)B / maxColValue;
651             mBorderMainColor[3] = (float)A / maxColValue;
652             mBorderMainColor[4] = mBorderMainColor[3];
653             return;
654         case BORDER_FADE:
655             mBorderFadeColor[0] = (float)R / maxColValue;
656             mBorderFadeColor[1] = (float)G / maxColValue;
657             mBorderFadeColor[2] = (float)B / maxColValue;
658             mBorderFadeColor[3] = (float)A / maxColValue;
659             mBorderFadeColor[4] = mBorderFadeColor[3];
660             return;
661         default:
662             return;
663     }
664 }
665 
SetPosition(int8_t anchor_X,float offset_X,int8_t anchor_Y,float offset_Y)666 void gui_ProgressBar::SetPosition(int8_t anchor_X, float offset_X, int8_t anchor_Y, float offset_Y)
667 {
668     mXanchor = anchor_X;
669     mYanchor = anchor_Y;
670     mAbsXoffset = offset_X;
671     mAbsYoffset = offset_Y;
672 
673     RecalculatePosition();
674 }
675 
676 // Set bar size
SetSize(float width,float height,float borderSize)677 void gui_ProgressBar::SetSize(float width, float height, float borderSize)
678 {
679     // Absolute values are needed to recalculate actual bar size according to resolution.
680     mAbsWidth  = width;
681     mAbsHeight = height;
682     mAbsBorderSize = borderSize;
683 
684     RecalculateSize();
685 }
686 
687 // Recalculate size, according to viewport resolution.
RecalculateSize()688 void gui_ProgressBar::RecalculateSize()
689 {
690     mWidth  = (float)mAbsWidth  * screen_info.scale_factor;
691     mHeight = (float)mAbsHeight * screen_info.scale_factor;
692 
693     mBorderWidth  = (float)mAbsBorderSize  * screen_info.scale_factor;
694     mBorderHeight = (float)mAbsBorderSize  * screen_info.scale_factor;
695 
696     // Calculate range unit, according to maximum bar value set up.
697     // If bar alignment is set to horizontal, calculate it from bar width.
698     // If bar is vertical, then calculate it from height.
699 
700     mRangeUnit = (!Vertical) ? ( (mWidth) / mMaxValue ) : ( (mHeight) / mMaxValue );
701 }
702 
703 // Recalculate position, according to viewport resolution.
RecalculatePosition()704 void gui_ProgressBar::RecalculatePosition()
705 {
706     switch(mXanchor)
707     {
708         case GUI_ANCHOR_HOR_LEFT:
709             mX = (float)(mAbsXoffset+mAbsBorderSize) * screen_info.scale_factor;
710             break;
711         case GUI_ANCHOR_HOR_CENTER:
712             mX = ((float)screen_info.w - ((float)(mAbsWidth+mAbsBorderSize*2) * screen_info.scale_factor)) / 2 +
713                  ((float)mAbsXoffset * screen_info.scale_factor);
714             break;
715         case GUI_ANCHOR_HOR_RIGHT:
716             mX = (float)screen_info.w - ((float)(mAbsXoffset+mAbsWidth+mAbsBorderSize*2)) * screen_info.scale_factor;
717             break;
718     }
719 
720     switch(mYanchor)
721     {
722         case GUI_ANCHOR_VERT_TOP:
723             mY = (float)screen_info.h - ((float)(mAbsYoffset+mAbsHeight+mAbsBorderSize*2)) * screen_info.scale_factor;
724             break;
725         case GUI_ANCHOR_VERT_CENTER:
726             mY = ((float)screen_info.h - ((float)(mAbsHeight+mAbsBorderSize * 2) * screen_info.h)) / 2 +
727                  ((float)mAbsYoffset * screen_info.scale_factor);
728             break;
729         case GUI_ANCHOR_VERT_BOTTOM:
730             mY = (mAbsYoffset + mAbsBorderSize) * screen_info.scale_factor;
731             break;
732     }
733 }
734 
735 // Set maximum and warning state values.
SetValues(float maxValue,float warnValue)736 void gui_ProgressBar::SetValues(float maxValue, float warnValue)
737 {
738     mMaxValue  = maxValue;
739     mWarnValue = warnValue;
740 
741     RecalculateSize();  // We need to recalculate size, because max. value is changed.
742 }
743 
744 // Set warning state blinking interval.
SetBlink(int interval)745 void gui_ProgressBar::SetBlink(int interval)
746 {
747     mBlinkInterval = (float)interval / 1000.0f;
748     mBlinkCnt      = (float)interval / 1000.0f;  // Also reset blink counter.
749 }
750 
751 // Set extrude overlay effect parameters.
SetExtrude(bool enabled,uint8_t depth)752 void gui_ProgressBar::SetExtrude(bool enabled, uint8_t depth)
753 {
754     mExtrude = enabled;
755     memset(mExtrudeDepth, 0, sizeof(float) * 5);    // Set all colors to 0.
756     mExtrudeDepth[3] = (float)depth / 255.0f;       // We need only alpha transparency.
757     mExtrudeDepth[4] = mExtrudeDepth[3];
758 }
759 
760 // Set autoshow and fade parameters.
761 // Please note that fade parameters are actually independent of autoshow.
SetAutoshow(bool enabled,int delay,bool fade,int fadeDelay)762 void gui_ProgressBar::SetAutoshow(bool enabled, int delay, bool fade, int fadeDelay)
763 {
764     mAutoShow = enabled;
765 
766     mAutoShowDelay = (float)delay / 1000.0f;
767     mAutoShowCnt   = (float)delay / 1000.0f;     // Also reset autoshow counter.
768 
769     mAutoShowFade = fade;
770     mAutoShowFadeDelay = 1000 / (float)fadeDelay;
771     mAutoShowFadeCnt = 0; // Initially, it's 0.
772 }
773 
774 // Main bar show procedure.
775 // Draws a bar with a given value. Please note that it also accepts float,
776 // so effectively you can create bars for floating-point parameters.
Show(float value)777 void gui_ProgressBar::Show(float value)
778 {
779     // Initial value limiters (to prevent bar overflow).
780     value  = (value >= 0.0f) ? (value) : (0.0f);
781     value  = (value > mMaxValue) ? (mMaxValue):(value);
782 
783     // Enable blink mode, if value is gone below warning value.
784     mBlink = (value <= mWarnValue);
785 
786     if(mAutoShow)   // Check autoshow visibility conditions.
787     {
788         // 0. If bar drawing was forced, then show a bar without additional
789         //    autoshow delay set. This condition has to be overwritten by
790         //    any other conditions, that's why it is set first.
791         if(Forced)
792         {
793             Visible = true;
794             Forced  = false;
795         }
796         else
797         {
798             Visible = false;
799         }
800 
801         // 1. If bar value gone less than warning value, we show it
802         //    in any case, bypassing all other conditions.
803         if(value <= mWarnValue)
804             Visible = true;
805 
806         // 2. Check if bar's value changed,
807         //    and if so, start showing it automatically for a given delay time.
808         if(mLastValue != value)
809         {
810             mLastValue = value;
811             Visible = true;
812             mAutoShowCnt = mAutoShowDelay;
813         }
814 
815         // 3. If autoshow time is up, then we hide bar,
816         //    otherwise decrease delay counter.
817         if(mAutoShowCnt > 0.0f)
818         {
819             Visible = true;
820             mAutoShowCnt -= engine_frame_time;
821 
822             if(mAutoShowCnt <= 0.0f)
823             {
824                 mAutoShowCnt = 0.0f;
825                 Visible = false;
826             }
827         }
828     } // end if(AutoShow)
829 
830 
831     if(mAutoShowFade)   // Process fade-in and fade-out effect, if enabled.
832     {
833         if(!Visible)
834         {
835             // If visibility flag is off and bar is still on-screen, gradually decrease
836             // fade counter, else simply don't draw anything and exit.
837             if(mAutoShowFadeCnt == 0)
838             {
839                 return;
840             }
841             else
842             {
843                 mAutoShowFadeCnt -= engine_frame_time * mAutoShowFadeDelay;
844                 if(mAutoShowFadeCnt < 0)
845                     mAutoShowFadeCnt = 0;
846             }
847         }
848         else
849         {
850             // If visibility flag is on, and bar is not yet fully visible, gradually
851             // increase fade counter, until it's 1 (i. e. fully opaque).
852             if(mAutoShowFadeCnt < 1)
853             {
854                 mAutoShowFadeCnt += engine_frame_time * mAutoShowFadeDelay;
855                 if(mAutoShowFadeCnt > 1)
856                     mAutoShowFadeCnt = 1;
857             }
858         } // end if(!Visible)
859 
860         // Multiply all layers' alpha by current fade counter.
861         mBaseMainColor[3]   = mBaseMainColor[4]   * mAutoShowFadeCnt;
862         mBaseFadeColor[3]   = mBaseFadeColor[4]   * mAutoShowFadeCnt;
863         mAltMainColor[3]    = mAltMainColor[4]    * mAutoShowFadeCnt;
864         mAltFadeColor[3]    = mAltFadeColor[4]    * mAutoShowFadeCnt;
865         mBackMainColor[3]   = mBackMainColor[4]   * mAutoShowFadeCnt;
866         mBackFadeColor[3]   = mBackFadeColor[4]   * mAutoShowFadeCnt;
867         mBorderMainColor[3] = mBorderMainColor[4] * mAutoShowFadeCnt;
868         mBorderFadeColor[3] = mBorderFadeColor[4] * mAutoShowFadeCnt;
869         mExtrudeDepth[3]    = mExtrudeDepth[4]    * mAutoShowFadeCnt;
870 
871     }
872     else
873     {
874         if(!Visible) return;   // Obviously, quit, if bar is not visible.
875     } // end if(mAutoShowFade)
876 
877     // Draw border rect.
878     // Border rect should be rendered first, as it lies beneath actual bar,
879     // and additionally, we need to show it in any case, even if bar is in
880     // warning state (blinking).
881     Gui_DrawRect(mX, mY, mWidth + (mBorderWidth * 2), mHeight + (mBorderHeight * 2),
882                  mBorderMainColor, mBorderMainColor,
883                  mBorderFadeColor, mBorderFadeColor,
884                  BM_OPAQUE);
885 
886     // SECTION FOR BASE BAR RECTANGLE.
887 
888     // We check if bar is in a warning state. If it is, we blink it continously.
889     if(mBlink)
890     {
891         mBlinkCnt -= engine_frame_time;
892         if(mBlinkCnt > mBlinkInterval)
893         {
894             value = 0; // Force zero value, which results in empty bar.
895         }
896         else if(mBlinkCnt <= 0)
897         {
898             mBlinkCnt = mBlinkInterval * 2.0f;
899         }
900     }
901 
902     // If bar value is zero, just render background overlay and immediately exit.
903     // It is needed in case bar is used as a simple UI box to bypass unnecessary calculations.
904     if(!value)
905     {
906           // Draw full-sized background rect (instead of base bar rect)
907           Gui_DrawRect(mX + mBorderWidth, mY + mBorderHeight, mWidth, mHeight,
908                        mBackMainColor, (Vertical) ? (mBackFadeColor) : (mBackMainColor),
909                        (Vertical) ? (mBackMainColor) : (mBackFadeColor), mBackFadeColor,
910                        BM_OPAQUE);
911           return;
912     }
913 
914     // Calculate base bar width, according to current value and range unit.
915     mBaseSize  = mRangeUnit * value;
916     mBaseRatio = value / mMaxValue;
917 
918     float RectAnchor;           // Anchor to stick base bar rect, according to Invert flag.
919     float RectFirstColor[4];    // Used to recalculate gradient, according to current value.
920     float RectSecondColor[4];
921 
922     // If invert decrease direction style flag is set, we position bar in a way
923     // that it seems like it's decreasing to another side, and also swap main / fade colours.
924     if(Invert)
925     {
926         memcpy(RectFirstColor,
927                (Alternate) ? (mAltMainColor) : (mBaseMainColor),
928                sizeof(float) * 4);
929 
930         // Main-fade gradient is recalculated according to current / maximum value ratio.
931         for(int i = 0; i <= 3; i++)
932             RectSecondColor[i] = (Alternate) ? ((mBaseRatio * mAltFadeColor[i])  + ((1 - mBaseRatio) * mAltMainColor[i]))
933                                              : ((mBaseRatio * mBaseFadeColor[i]) + ((1 - mBaseRatio) * mBaseMainColor[i]));
934 
935     }
936     else
937     {
938         memcpy(RectSecondColor,
939                (Alternate) ? (mAltMainColor) : (mBaseMainColor),
940                sizeof(float) * 4);
941 
942         // Main-fade gradient is recalculated according to current / maximum value ratio.
943         for(int i = 0; i <= 3; i++)
944             RectFirstColor[i] = (Alternate) ? ((mBaseRatio * mAltFadeColor[i])  + ((1 - mBaseRatio) * mAltMainColor[i]))
945                                             : ((mBaseRatio * mBaseFadeColor[i]) + ((1 - mBaseRatio) * mBaseMainColor[i]));
946 
947     } // end if(Invert)
948 
949     // If vertical style flag is set, we draw bar base top-bottom, else we draw it left-right.
950     if(Vertical)
951     {
952         RectAnchor = ((Invert) ? (mY + mHeight - mBaseSize) : (mY)) + mBorderHeight;
953 
954         // Draw actual bar base.
955         Gui_DrawRect(mX + mBorderWidth, RectAnchor,
956                      mWidth, mBaseSize,
957                      RectFirstColor,  RectFirstColor,
958                      RectSecondColor, RectSecondColor,
959                      BM_OPAQUE);
960 
961         // Draw background rect.
962         Gui_DrawRect(mX + mBorderWidth,
963                      (Invert) ? (mY + mBorderHeight) : (RectAnchor + mBaseSize),
964                      mWidth, mHeight - mBaseSize,
965                      mBackMainColor, mBackFadeColor,
966                      mBackMainColor, mBackFadeColor,
967                      BM_OPAQUE);
968 
969         if(mExtrude)    // Draw extrude overlay, if flag is set.
970         {
971             float transparentColor[4] = {0};  // Used to set counter-shade to transparent.
972 
973             Gui_DrawRect(mX + mBorderWidth, RectAnchor,
974                          mWidth / 2, mBaseSize,
975                          mExtrudeDepth, transparentColor,
976                          mExtrudeDepth, transparentColor,
977                          BM_OPAQUE);
978             Gui_DrawRect(mX + mBorderWidth + mWidth / 2, RectAnchor,
979                          mWidth / 2, mBaseSize,
980                          transparentColor, mExtrudeDepth,
981                          transparentColor, mExtrudeDepth,
982                          BM_OPAQUE);
983         }
984     }
985     else
986     {
987         RectAnchor = ((Invert) ? (mX + mWidth - mBaseSize) : (mX)) + mBorderWidth;
988 
989         // Draw actual bar base.
990         Gui_DrawRect(RectAnchor, mY + mBorderHeight,
991                      mBaseSize, mHeight,
992                      RectSecondColor, RectFirstColor,
993                      RectSecondColor, RectFirstColor,
994                      BM_OPAQUE);
995 
996         // Draw background rect.
997         Gui_DrawRect((Invert) ? (mX + mBorderWidth) : (RectAnchor + mBaseSize),
998                      mY + mBorderHeight,
999                      mWidth - mBaseSize, mHeight,
1000                      mBackMainColor, mBackMainColor,
1001                      mBackFadeColor, mBackFadeColor,
1002                      BM_OPAQUE);
1003 
1004         if(mExtrude)    // Draw extrude overlay, if flag is set.
1005         {
1006             float transparentColor[4] = {0};  // Used to set counter-shade to transparent.
1007 
1008             Gui_DrawRect(RectAnchor, mY + mBorderHeight,
1009                          mBaseSize, mHeight / 2,
1010                          transparentColor, transparentColor,
1011                          mExtrudeDepth, mExtrudeDepth,
1012                          BM_OPAQUE);
1013             Gui_DrawRect(RectAnchor, mY + mBorderHeight + (mHeight / 2),
1014                          mBaseSize, mHeight / 2,
1015                          mExtrudeDepth, mExtrudeDepth,
1016                          transparentColor, transparentColor,
1017                          BM_OPAQUE);
1018         }
1019     } // end if(Vertical)
1020 }
1021