aboutsummaryrefslogtreecommitdiffstats
path: root/src/menu/display.cpp
blob: 200f961f52a8dba07395f4f779df4d6da780357e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
/*
 * UltraStar Deluxe - Karaoke Game
 *
 * UltraStar Deluxe is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 */

#include "display.hpp"
#include <math.h>
#include <SDL/SDL.h>
#include <GL/glu.h>

// constants for software cursor effects time in milliseconds
const int Cursor_FadeIn_Time = 500;      // seconds the fade in effect lasts
const int Cursor_FadeOut_Time = 2000;    // seconds the fade out effect lasts
const int Cursor_AutoHide_Time = 5000;   // seconds until auto fade out starts if there is no mouse movement

namespace usdx
{
	Display* Display::get_instance(void)
	{
		if (!instance) {
			instance = new Display();
		}

		return instance;
	}

	Display::Display(void)
	{
		//popup hack
		check_ok = false;
		next_screen = NULL;
		next_screen_with_check = NULL;
		black_screen = false;

		// fade mod
		fade_state = 0;
		fade_enabled = (Ini.ScreenFade == 1);
		fade_failed = false;

		glGenTextures(2, fade_tex);

		for (int i = 0; i < 2; i++) {
			glBindTexture(GL_TEXTURE_2D, fade_tex[i]);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		}

		//Set LastError for OSD to No Error
		osd_last_error = "No Errors";

		// software cursor default values
		cursor_last_move = 0;
		cursor_visible = false;
		cursor_pressed = false;
		cursor_x = -1;
		cursor_y = -1;
		cursor_fade = false;
		cursor_hidden_by_screen = true;
	}

	Display::~Display(void)
	{
		glDeleteTextures(2, fade_tex);
	}

	bool Display::draw(void)
	{
		//We don't need this here anymore,
		//Because the background care about cleaning the buffers
		//glClearColor(1, 1, 1 , 0);
		//glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

		for (int s = 0; s < screens; s++)
		{
			int ScreenAct = s;

			//if Screens = 1 then ScreenX := 0;
			//if (Screens = 2) and (S = 1) then ScreenX := -1;
			//if (Screens = 2) and (S = 2) then ScreenX := 1;
			int ScreenX = 0;

			glViewPort((s-1) * screen_w / screens, 0, screen_w / screens, screen_h);

			// popup hack
			// check was successful... move on
			if (check_ok) {
				if (next_screen_with_check) {
					next_screen = next_screen_with_check;
					next_screen_with_check = NULL;
					check_ok = false;
				}
				else {
					// on end of game fade to black before exit
					black_screen = true;
				}
			}

			if (!next_screen && !black_screen) {
				current_screen->Draw();

				//popup mod
				if (screen_popup_error && screen_popup_error->visible)
					screen_popup_error->Draw();
				else if (screen_popup_info && screen_popup_info->visible)
					screen_popup_info->Draw();
				else if (screen_popup_check && screen_popup_check->visible)
					screen_popup_check->Draw();

				// fade mod
				fade_state = 0;
				if ((Ini.ScreenFade == 1) && !fade_failed)
					fade_enabled = true;
				else if (Ini.ScreenFade == 0)
					fade_enabled = false;
			}
			else {
				// disable fading if initialization failed
				if (fade_enabled && fade_failed)
					fade_enabled = false;

				if (fade_enabled && !fade_failed) {
					//Create Fading texture if we're just starting
					if (fade_state == 0) {
						// save old viewport and resize to fit texture
						glPushAttrib(GL_VIEWPORT_BIT);
						glViewPort(0, 0, 512, 512);

						// draw screen that will be faded
						current_screen->Draw();

						// clear OpenGL errors, otherwise fading might be disabled due to some
						// older errors in previous OpenGL calls.
						glGetError();

						// copy screen to texture
						glBindTexture(GL_TEXTURE_2D, fade_tex[s]);
						glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 512, 512, 0);

						GLenum glError = glGetError();
						if (glError != GL_NO_ERROR) {
							fade_failed = true;
							Log->LogWarn(std::string("Fading disabled: ") + gluErrorString(glError), "TDisplay.Draw");
						}

						// restore viewport
						glPopAttrib();

						// blackscreen-hack
						if (!black_screen)
							next_screen->on_show();

						// update fade state
						last_fade_time = SDL_GetTicks();
						if ((s == 1) || (screens == 1))
							fade_state++;
					} // end texture creation in first fading step

					//do some time-based fading
					unsigned int current_time = SDL_GetTicks();
					if ((current_time > last_fade_time + 30) && (s == 0))
					{
						fade_state += 4;
						last_fade_time = current_time;
					}

					// blackscreen-hack
					if (!black_screen)
						next_screen->Draw(); // draw next screen
					else if (screen_act == 0)
					{
						glClearColor(0, 0, 0 , 0);
						glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
					}

					// and draw old screen over it... slowly fading out
					float fade_state_square = (fade_state * fade_state) / 10000.0;

					glBindTexture(GL_TEXTURE_2D, fade_tex[s]);
					glColor4f(1, 1, 1, 1 - fade_state_square);

					glEnable(GL_TEXTURE_2D);
					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
					glEnable(GL_BLEND);
					glBegin(GL_QUADS);
					 glTexCoord2f(0 + fade_state_square, 0 + fade_state_square); glVertex2f(0,   600);
					 glTexCoord2f(0 + fade_state_square, 1 - fade_state_square); glVertex2f(0,   0);
					 glTexCoord2f(1 - fade_state_square, 1 - fade_state_square); glVertex2f(800, 0);
					 glTexCoord2f(1 - fade_state_square, 0 + fade_state_square); glVertex2f(800, 600);
					glEnd();
					glDisable(GL_BLEND);
					glDisable(GL_TEXTURE_2D);
				}

				// blackscreen hack
				else if (!black_screen)
					next_screen->on_show();

				if ((((fade_state > 40) || !fade_enabled) || fade_failed) && (s == 0)) {
					// fade out complete...
					fade_state = 0;
					current_screen->on_hide();
					current_screen->show_finish = false;
					current_screen = next_screen;
					next_screen = NULL;

					if (!black_screen) {
						current_screen->on_show_finish();
						current_screen->show_finish = true;
					}
					else {
						return false;
					}
				}
			}

			// Draw OSD only on first Screen if Debug Mode is enabled
			if (((Ini->Debug == 1) || (Params->Debug)) && (s == 0))
				draw_debug_information();

		} // for

		if (!black_screen)
			draw_cursor();

		return true;
	}

	// sets SDL_ShowCursor depending on options set in Ini
	void Display::set_cursor(void)
	{
		int cursor = 0;

		if ((current_screen != screen_sing) || (cursor_hidden_by_screen)) {

			// hide cursor on singscreen
			if ((Ini->Mouse == 0) and (Ini->FullScreen == 0))
				// show sdl (os) cursor in window mode even when mouse support is off
				cursor = 1;

			else if ((Ini->Mouse == 1))
				// show sdl (os) cursor when hardware cursor is selected
				cursor = 1;

			if ((Ini->Mouse != 2))
				cursor_hidden_by_screen = false;
		}
		else if ((Ini.Mouse != 2))
			cursor_hidden_by_screen = true;

		SDL_ShowCursor(cursor);

		if (Ini->Mouse == 2)
		{
			if (cursor_hidden_by_screen)
			{
				// show software cursor
				cursor_hidden_by_screen = false;
				cursor_visible = false;
				cursor_fade = false;
			}
			else if (current_screen == screen_sing)
			{
				// hide software cursor in singscreen
				cursor_hidden_by_screen = true;
				cursor_visible = false;
				cursor_fade = false;
			}
		}
	}

	// called by MoveCursor and OnMouseButton to update last move and start fade in
	void Display::update_cursor_fade(void)
	{
		unsigned int ticks = SDL_GetTicks();

		// fade in on movement (or button press) if not first movement
		if ((!cursor_visible) && (cursor_last_move != 0))
		{
			if (cursor_fade)  // we use a trick here to consider progress of fade out
				cursor_last_move = ticks - (int)(Cursor_FadeIn_Time * (1 - (ticks - cursor_last_move) / (float)Cursor_FadeOut_Time) + 0.5);
			else
				cursor_last_move = ticks;

			cursor_visible = true;
			cursor_fade = true;
		}
		else if (!cursor_fade)
		{
			cursor_last_move = ticks;
		}
	}

	// called when cursor moves, positioning of software cursor
	void Display::move_cursor(double x, double y)
	{
		if ((Ini->Mouse == 2) && ((x != cursor_x) || (y != cursor_y)))
		{
			cursor_x = x;
			cursor_y = y;

			update_cursor_fade();
		}
	}

	// called when left or right mousebutton is pressed or released
	void Display::on_mouse_button(bool pressed)
	{
		if (Ini->Mouse == 2)
		{
			cursor_pressed = pressed;
			update_cursor_fade();
		}
	}

	// draws software cursor
	void Display::draw_cursor(void)
	{
		float alpha;
		unsigned int ticks;
		if (Ini->Mouse == 2)
		{
			// draw software cursor
			ticks = SDL_GetTicks();

			if ((cursor_visible) && (cursor_last_move + Cursor_AutoHide_Time <= ticks))
			{
				// start fade out after 5 secs w/o activity
				cursor_visible = false;
				cursor_last_move = ticks;
				cursor_fade = true;
			}

			// fading
			if (cursor_fade)
			{
				if (cursor_visible)
				{
					// fade in
					if (cursor_last_move + Cursor_FadeIn_Time <= ticks)
						cursor_fade = false;
					else
						alpha = sin((ticks - cursor_last_move) * 0.5 * M_PI / Cursor_FadeIn_Time) * 0.7;
				}
				else
				{
					//fade out
					if (cursor_last_move + Cursor_FadeOut_Time <= ticks)
						cursor_fade = false;
					else
						alpha = cos((ticks - cursor_last_move) * 0.5 * M_PI / Cursor_FadeOut_Time) * 0.7;
				}
			}

			// no else if here because we may turn off fade in if block
			if (!cursor_fade)
			{
				if (cursor_visible)
					// alpha when cursor visible and not fading
					alpha = 0.7;
				else
					// alpha when cursor is hidden
					alpha = 0;
			}

			if ((alpha > 0) && (!cursor_hidden_by_screen))
			{
				glColor4f(1, 1, 1, alpha);
				glEnable(GL_TEXTURE_2D);
				glEnable(GL_BLEND);
				glDisable(GL_DEPTH_TEST);

				if ((cursor_pressed) && (tex_cursor_pressed->tex_num > 0))
					glBindTexture(GL_TEXTURE_2D, tex_cursor_pressed->tex_num);
				else
					glBindTexture(GL_TEXTURE_2D, tex_cursor_unpressed->tex_num);

				glBegin(GL_QUADS);
				glTexCoord2f(0, 0);
				glVertex2f(cursor_x, cursor_x);

				glTexCoord2f(0, 1);
				glVertex2f(cursor_x, cursor_y + 32);

				glTexCoord2f(1, 1);
				glVertex2f(cursor_x + 32, cursor_y + 32);

				glTexCoord2f(1, 0);
				glVertex2f(cursor_x + 32, cursor_y);
				glEnd();

				glDisable(GL_BLEND);
				glDisable(GL_TEXTURE_2D);
			}
		}
	}

	bool Display::parse_input(unsigned int pressed_key, UCS4Char char_code, bool pressed_down)
	{
		if (next_screen)
			return next_screen->parse_input(pressed_key, char_code, pressed_down);

		if (current_screen)
			return current_screen->parse_input(pressed_key, char_code, pressed_down);

		return true;
	}

	void Display::save_screen_shot()
	{
		Path *file_name;
		std::string prefix;
		char *screen_data;
		SDL_Surface *surface;
		bool success;
		int align;
		int row_size;

		// Exit if Screenshot-path does not exist or read-only
		if (!screenshots_path)
			return;

		for (int num = 1; num < 10000; num++)
		{
			/** TODO:

			// fill prefix to 4 digits with leading '0', e.g. '0001'
			Prefix = Format('screenshot%.4d', [Num]);
			FileName = ScreenshotsPath.Append(Prefix + '.png');

			if not FileName.Exists()
				       break;
			*/
		}

		// we must take the row-alignment (4byte by default) into account
		glGetIntegerv(GL_PACK_ALIGNMENT, &align);

		// calc aligned row-size
		row_size = ((screen_w * 3 + (align - 1)) / align) * align;

		malloc(screen_data, row_size * screen_h);
		glReadPixels(0, 0, screen_w, screen_h, GL_RGB, GL_UNSIGNED_BYTE, screen_data);

		// on big endian machines (powerpc) this may need to be changed to
		// Needs to be tests. KaMiSchi Sept 2008
		// in this case one may have to add " glext, " to the list of used units
		//  glReadPixels(0, 0, ScreenW, ScreenH, GL_BGR, GL_UNSIGNED_BYTE, ScreenData);
		Surface = SDL_CreateRGBSurfaceFrom(
			screen_data, screen_w, screen_h, 24, row_size,
			0x0000ff, 0x00ff00, 0xff0000, 0);

		//  Success = WriteJPGImage(FileName, Surface, 95);
		//  Success = WriteBMPImage(FileName, Surface);
		success = WritePNGImage(file_name, surface);
		if (success)
			ScreenPopupInfo->ShowPopup(Format(Language.Translate("SCREENSHOT_SAVED"), [FileName.GetName.ToUTF8()]));
		else
			ScreenPopupError->ShowPopup(Language.Translate("SCREENSHOT_FAILED"));

		SDL_FreeSurface(surface);
		free(screen_data);
	}

	//------------
	// DrawDebugInformation - procedure draw fps and some other informations on screen
	//------------
	void Display::draw_debug_information()
	{
		// Some White Background for information
		glEnable(GL_BLEND);
		glDisable(GL_TEXTURE_2D);
		glColor4f(1, 1, 1, 0.5);
		glBegin(GL_QUADS);
		 glVertex2f(690, 44);
		 glVertex2f(690, 0);
		 glVertex2f(800, 0);
		 glVertex2f(800, 44);
		glEnd();
		glDisable(GL_BLEND);

		// set font specs
		SetFontStyle(0);
		SetFontSize(21);
		SetFontItalic(false);
		glColor4f(0, 0, 0, 1);

		// calculate fps
		unsigned int ticks = SDL_GetTicks();
		if (ticks >= next_fps_swap) {
			last_fps = fps_counter * 4;
			fps_counter = 0;
			next_fps_swap = ticks + 250;
		}

		fps_counter++;

		// draw text

		// TODO:
		// fps
		SetFontPos(695, 0);
		glPrint ("FPS: " + itoa(last_fps));

		// rspeed
		SetFontPos(695, 13);
		glPrint ("RSpeed: " + itoa((int)(1000 * time_mid)));

		// lasterror
		SetFontPos(695, 26);
		glColor4f(1, 0, 0, 1);
		glPrint(osd_last_error.c_str());

		glColor4f(1, 1, 1, 1);
	}
};