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