1 /*
2  * Zaz
3  * Copyright (C) Remigiusz Dybka 2009 <remigiusz.dybka@gmail.com>
4  *
5  Zaz is free software: you can redistribute it and/or modify it
6  under the terms of the GNU General Public License as published by the
7  Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  Zaz is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  See the GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License along
16  with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "mainmenu.h"
20 #include "textureloader.h"
21 #include "game.h"
22 #include "sample.h"
23 #include "gameloop.h"
24 #include "profile.h"
25 #include "directorylister.h"
26 #include <cstdio>
27 
MainMenu(SDL_Surface * surf,uint fps)28 MainMenu::MainMenu(SDL_Surface *surf, uint fps)
29         :Scenes::Scene(surf, fps), currentMenu(&startMenu),
30         menuLev(settings.getCFilename("menu.lvl")), nBallPaths(menuLev.paths.size() - 1), music(NULL),
31         renderHiscores(true), showCredits(false), showBrowser(false), showProfiles(false), showNewProfile(false), showSets(false),
32         oldFullscreen(settings.getb("fullscreen", false)),
33         oldRes(settings.get("resolution", "")), oldMusicVol(atoi(settings.get("musicVolume", "50").c_str())),
34         oldLanguage(settings.get("language", "")),startup(true), browserSelectedLevel(-1), browserUsedKeyboard(false)
35 {
36     startMenu.Add(new GenericMenuItem(_("Start game"), startMenuStartHandler, this));
37     startMenu.Add(new GenericMenuItem(_("Options"), startMenuOptionsHandler, this));
38     startMenu.Add(new GenericMenuItem(_("Credits"), startMenuCreditsHandler, this));
39     startMenu.Add(new GenericMenuItem(_("Exit"), startMenuExitHandler, this));
40     startMenu.Add(new GenericMenuItem(_("Profile:") + profile.getName(), startMenuShowProfilesHandler, this));
41 
42     startMenu.SetDimensions(60, 40, 40);
43 
44     startMenu.items[4]->width = 80;
45     startMenu.items[4]->y = 6;
46     startMenu.items[4]->x = 10;
47 
48     creditsMenu.Add(new GenericMenuItem(_("Back"), menuBackHandler, this));
49     creditsMenu.SetDimensions(30, 10, 40);
50 
51     std::vector<std::string>game_types;
52 
53     game_types.push_back(_("Sequential"));
54     game_types.push_back(_("Survival"));
55 
56     browserMenu.Add(new GenericMenuItem(_("Back"), menuBackHandler, this));
57     browserMenu.Add(new GenericMenuItem("<<", browserMenuRightHandler, this));
58     browserMenu.Add(new GenericMenuItem(">>", browserMenuLeftHandler, this));
59     browserMenu.Add(new OptionMenuItem(_("Game type:"), game_types, "game_type"));
60 
61     browserMenu.SetDimensions(30, 6, 40);
62 
63     browserMenu.items[1]->x = 10;
64     browserMenu.items[1]->width = 10;
65     browserMenu.items[1]->y = 11;
66 
67     browserMenu.items[2]->x = 80;
68     browserMenu.items[2]->width = 10;
69     browserMenu.items[2]->y = 11;
70 
71     browserMenu.items[3]->x = 20;
72     browserMenu.items[3]->width = 60;
73     browserMenu.items[3]->y = 45;
74 
75     profileActionsMenu.Add(new GenericMenuItem(_("New profile"), profileActionsMenuNewHandler, this));
76     profileActionsMenu.Add(new GenericMenuItem(_("Delete"), profileActionsMenuDeleteHandler, this));
77 //    profileActionsMenu.Add(new GenericMenuItem(_("Use"), profileActionsMenuUseHandler, this));
78 
79     profileActionsMenu.SetDimensions(0, 10, 30);
80 
81     profileActionsMenu.items[0]->y = 10;
82     profileActionsMenu.items[0]->x = 30;
83     profileActionsMenu.items[0]->width = 40;
84 
85     for (int p = 0; p < nBallPaths; p++)
86     {
87         bp.push_back(BallPath(menuLev.paths[p + 1], ballText, 0));
88         bp[p].state.feedRate = 2;
89         bp[p].state.colors = 16;
90         bp[p].state.ballsToDraw = -1;
91         bp[p].state.ballsFromStart = 0;
92     }
93 
94     lmx = lmy = 0;
95 
96     setNames = LevelSet::getSetNames();
97     nleveldesc = 0;
98 
99     hiScoreRep = hiScores.GenerateReport(linesPerHiScorePage);
100     hiScorePage = 0;
101     hiScoreTimeout = hiScoreWaitPageSec * desiredFPS;
102 
103     CreateOptionsMenu();
104     CreateCredits();
105     creditsScroll = creditsScrollClearance * -1;
106 }
107 
CreateCredits()108 void MainMenu::CreateCredits()
109 {
110     credits.push_back(CreditsLine(string("Zaz ") + VERSION, true));
111     credits.push_back(CreditsLine("-"));
112     credits.push_back(CreditsLine(_("code, gfx, snd & design:")));
113     credits.push_back(CreditsLine(_("Remigiusz Dybka"), true));
114     credits.push_back(CreditsLine(_("[remigiusz.dybka@gmail.com] Released under GPLv3 License")));
115     credits.push_back(CreditsLine("-"));
116     credits.push_back(CreditsLine(_("music:")));
117     credits.push_back(CreditsLine(_("paniq - Leonard Ritter"), true));
118     credits.push_back(CreditsLine(_("[http://www.paniq.org] Released under CC BY-SA License")));
119     credits.push_back(CreditsLine("-"));
120     credits.push_back(CreditsLine(_("quality assurance:")));
121     credits.push_back(CreditsLine(_("Kinga Dybka"), true));
122     credits.push_back(CreditsLine(_("Michael Sterrett"), true));
123     credits.push_back(CreditsLine("-"));
124     credits.push_back(CreditsLine("-"));
125     credits.push_back(CreditsLine(_("translations:"), true));
126     credits.push_back(CreditsLine("-"));
127     credits.push_back(CreditsLine(_("German:")));
128     credits.push_back(CreditsLine(_("Frederik Schwarzer"), true));
129     credits.push_back(CreditsLine("-"));
130     credits.push_back(CreditsLine(_("Spanish:")));
131     credits.push_back(CreditsLine(_("Dámaso Domínguez (AmiSpaTra)"), true));
132     credits.push_back(CreditsLine("-"));
133     credits.push_back(CreditsLine(_("French:")));
134     credits.push_back(CreditsLine(_("Nouvel Hugues"), true));
135     credits.push_back(CreditsLine("-"));
136     credits.push_back(CreditsLine(_("Hungarian:")));
137     credits.push_back(CreditsLine(_("Gabor Kmetyko"), true));
138     credits.push_back(CreditsLine("-"));
139     credits.push_back(CreditsLine(_("Italian:")));
140     credits.push_back(CreditsLine(_("Andrea Musuruane"), true));
141     credits.push_back(CreditsLine("-"));
142     credits.push_back(CreditsLine(_("Russian:")));
143     credits.push_back(CreditsLine(_("Николай Рощупкин"), true));
144     credits.push_back(CreditsLine("-"));
145     credits.push_back(CreditsLine(_("Turkish:")));
146     credits.push_back(CreditsLine(_("Anıl Özbek"), true));
147     credits.push_back(CreditsLine("-"));
148     credits.push_back(CreditsLine("-"));
149     credits.push_back(CreditsLine(_("additional coding:")));
150     credits.push_back(CreditsLine(_("Nouvel Hugues"), true));
151     credits.push_back(CreditsLine("-"));
152     credits.push_back(CreditsLine(_("additional testing:")));
153     credits.push_back(CreditsLine(_("Irena Klon"), true));
154     credits.push_back(CreditsLine(_("Kamil Krzyspiak"), true));
155     credits.push_back(CreditsLine(_("Mateusz Jakubowski"), true));
156     credits.push_back(CreditsLine("-"));
157     credits.push_back(CreditsLine("Copyright (C) Remigiusz Dybka 2009-2010 <remigiusz.dybka@gmail.com>"));
158     credits.push_back(CreditsLine("-"));
159     credits.push_back(CreditsLine("Zaz is free software: you can redistribute it and/or modify it"));
160     credits.push_back(CreditsLine("under the terms of the GNU General Public License as published by the"));
161     credits.push_back(CreditsLine("Free Software Foundation, either version 3 of the License, or"));
162     credits.push_back(CreditsLine("(at your option) any later version."));
163     credits.push_back(CreditsLine("-"));
164     credits.push_back(CreditsLine("Zaz is distributed in the hope that it will be useful, but"));
165     credits.push_back(CreditsLine("WITHOUT ANY WARRANTY; without even the implied warranty of"));
166     credits.push_back(CreditsLine("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."));
167     credits.push_back(CreditsLine("See the GNU General Public License for more details."));
168     credits.push_back(CreditsLine("-"));
169     credits.push_back(CreditsLine("You should have received a copy of the GNU General Public License along"));
170     credits.push_back(CreditsLine("with this program.  If not, see <http://www.gnu.org/licenses/>."));
171 }
172 
CreateOptionsMenu()173 void MainMenu::CreateOptionsMenu()
174 {
175     optionsMenu.Clear();
176 
177     std::vector<std::string>resolutions;
178     std::vector<std::string>tempRes;
179 
180     for (uint m = 0; screenModes[m]; ++m)
181     {
182         stringstream sm;
183         sm << screenModes[m]->w << "x" << screenModes[m]->h;
184 
185         tempRes.push_back(sm.str());
186     }
187 
188     // reverse the resolutions
189     for (int m = (unsigned int)tempRes.size() - 1; m >= 0; m--)
190     {
191         resolutions.push_back(tempRes[m]);
192     }
193 
194     int y = 9;
195 
196 #ifdef ENABLE_NLS
197     y++;
198     std::vector<std::string>languages;
199     std::vector<std::string>descriptions;
200     std::map<std::string, std::string>::iterator iter;
201 
202     for (iter = settings.languages.begin(); iter != settings.languages.end(); ++iter)
203     {
204         languages.push_back(iter->first);
205         descriptions.push_back(iter->second);
206     }
207 
208     optionsMenu.Add(new OptionMenuItem(_("Language"), languages, "language", &settings, descriptions));
209 #endif
210 
211     optionsMenu.Add(new OptionMenuItem(_("Resolution"), resolutions, "resolution", &settings));
212     optionsMenu.Add(new BooleanMenuItem(_("Fullscreen"), &settings, "fullscreen"));
213     optionsMenu.Add(new BooleanMenuItem(_("Show FPS"), &settings, "showFps"));
214     optionsMenu.Add(new BooleanMenuItem(_("Colour hints"), &settings, "colourHints"));
215     optionsMenu.Add(new BooleanMenuItem(_("Disable speed-up"), &settings, "disableSpeedup"));
216     optionsMenu.Add(new ValueMenuItem(_("Mouse sensivity"), 1, 10, &settings, "mouseSensivity"));
217     optionsMenu.Add(new ValueMenuItem(_("Keyb. sensivity"), 1, 10, &settings, "keyboardSensivity"));
218     optionsMenu.Add(new ValueMenuItem(_("SFX volume"), 0, 100, &settings, "sfxVolume"));
219     optionsMenu.Add(new ValueMenuItem(_("Music volume"), 0, 100, &settings, "musicVolume"));
220     optionsMenu.Add(new GenericMenuItem(_("Cancel"), optionsMenuCancelHandler, this));
221     optionsMenu.Add(new GenericMenuItem(_("Apply"), optionsMenuApplyHandler, this));
222     optionsMenu.SetDimensions(10, 80, 80);
223 
224     optionsMenu.items[y]->width = 29;
225     optionsMenu.items[y+1]->width = 29;
226     optionsMenu.items[y+1]->x = 61;
227     optionsMenu.items[y+1]->y = optionsMenu.items[y]->y;
228 }
229 
RenderStartupProgress()230 void MainMenu::RenderStartupProgress()
231 {
232     float pbarwidth = 80;
233     float pbarheight = 5;
234 
235     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
236     glMatrixMode( GL_MODELVIEW );
237     glLoadIdentity( );
238     glTranslated((100 - pbarwidth) / 2, (vheight + pbarheight) / 2, 0);
239 
240     glBegin(GL_QUADS);
241     glColor3d( .1, .1, .7);
242     glVertex3d(0, 0, 0);
243     glVertex3d(0, -pbarheight, 0);
244     glColor3d( 0, 0, 0.5);
245     glVertex3d((startupProgress / startupProgressSteps) * pbarwidth, -pbarheight, 0);
246     glVertex3d((startupProgress / startupProgressSteps) * pbarwidth, 0, 0);
247     glEnd();
248 
249     glColor3d( 0, 0, 0.5);
250     glBegin(GL_LINE_STRIP);
251     glVertex3d(0, 0, 0);
252     glVertex3d(0, -pbarheight, 0);
253     glVertex3d(pbarwidth, -pbarheight, 0);
254     glVertex3d(pbarwidth, 0, 0);
255     glVertex3d(0, 0, 0);
256     glEnd();
257 
258     startupProgress++;
259     glFlush();
260     SDL_GL_SwapBuffers();
261 }
262 
LoadLevelSets()263 void MainMenu::LoadLevelSets()
264 {
265     vector<string>::iterator i;
266     for (i = setNames.begin(); i!= setNames.end(); ++i)
267     {
268         LevelSet s = LevelSet(*i);
269         sets.push_back(s);
270         setTex.push_back(LoadTextureFile (settings.getCFilename(s.thumbTexFilename)));
271         RenderStartupProgress();
272     }
273 
274     RenderStartupProgress();
275 }
276 
LoadTextures()277 void MainMenu::LoadTextures()
278 {
279     startupProgress = 0;
280 
281     bool useColourHints = settings.getb("colourHints", false);
282 
283     for (int b = 0; b < 16; b++)
284     {
285         BallDesc bd = BallDescriptions[b];
286         ballText[b] = LoadBallsTexture(bd.fileName, bd.r, bd.g, bd.b, useColourHints?bd.overlay:0);
287         RenderStartupProgress();
288     }
289 
290     ballText[16] = LoadTexture("bonus1.png");
291     RenderStartupProgress();
292     ballText[17] = LoadTexture("bonus2.png");
293     RenderStartupProgress();
294     ballText[18] = LoadTexture("bonus3.png");
295     RenderStartupProgress();
296     ballText[19] = LoadTexture("bonus4.png");
297     RenderStartupProgress();
298     ballText[20] = LoadTexture("bonus5.png");
299     RenderStartupProgress();
300     ballText[21] = LoadTexture("explosion.png");
301     RenderStartupProgress();
302 
303     logoTex = LoadTexture("logo.png");
304     RenderStartupProgress();
305     logoGpl = LoadTexture ("gpl3.png");
306     RenderStartupProgress();
307 
308     pointer = LoadTexture("ptr.png");
309 }
310 
311 
StartMusic()312 void MainMenu::StartMusic()
313 {
314     int musicVol = atoi(settings.get("musicVolume", "50").c_str());
315 
316     music = (Scenes::Sample *)new Scenes::StreamingOggSample(Game::getRandomMusic());
317     mixer->EnqueueSample(music, musicVol, 0, true);
318 }
319 
StopMusic()320 void MainMenu::StopMusic()
321 {
322     mixer->DisposeSample(music);
323 }
324 
profileActionsMenuNewHandler(void * ptr)325 void profileActionsMenuNewHandler(void *ptr)
326 {
327     MainMenu *p = (MainMenu *)ptr;
328     p->showNewProfile = true;
329     p->newProfileEditor = new LineEditor("", 60, 16, 30);
330 }
331 
profileActionsMenuDeleteHandler(void * ptr)332 void profileActionsMenuDeleteHandler(void *ptr)
333 {
334     MainMenu *p = (MainMenu *)ptr;
335     // delete the profile file
336     string ph = p->profileNames[p->profileListMenu.getHoverItem()];
337     ph = settings.getDefaultDirectory() + SEPARATOR + ph + ".profile";
338 #ifdef WIN32
339     DeleteFile(Settings::W32_GetFileName(ph).c_str());
340 #else
341     remove(ph.c_str());
342 #endif
343 
344     startMenuShowProfilesHandler(ptr);
345 }
346 
profileActionsMenuUseHandler(void * ptr)347 void profileActionsMenuUseHandler(void *ptr)
348 {
349     MainMenu *p = (MainMenu *)ptr;
350     profile.Save();
351     profile = Profile(p->profileNames[p->profileListMenu.getHoverItem()]);
352 
353     p->startMenu.items[4] = new GenericMenuItem(_("Profile:") + profile.getName(), startMenuShowProfilesHandler, p);
354     p->startMenu.SetDimensions(60, 40, 40);
355     p->startMenu.items[4]->width = 80;
356     p->startMenu.items[4]->y = 6;
357     p->startMenu.items[4]->x = 10;
358 
359     settings.set("last_profile", profile.getName());
360 
361     profile.Save();
362     p->showProfiles = false;
363     p->renderHiscores = true;
364     p->currentMenu = &p->startMenu;
365 }
366 
browserMenuLeftHandler(void * ptr)367 void browserMenuLeftHandler(void *ptr)
368 {
369     MainMenu *p = (MainMenu *)ptr;
370     int sz;
371 
372     if (p->showBrowser)
373     {
374         sz = p->nleveldesc; //p->levels.size();
375     }
376     else
377     {
378         sz = p->sets.size();
379     }
380 
381     if (p->browserScrollOffsetDest >= sz - p->browserNLevelsPerPage)
382         return;
383 
384     p->browserScrollOffsetDest+=p->browserNLevelsPerPage;
385 
386     if (p->browserScrollOffsetDest > (int)(sz - p->browserNLevelsPerPage))
387         p->browserScrollOffsetDest = sz - p->browserNLevelsPerPage;
388 }
389 
browserMenuRightHandler(void * ptr)390 void browserMenuRightHandler(void *ptr)
391 {
392     MainMenu *p = (MainMenu *)ptr;
393     p->browserScrollOffsetDest-=p->browserNLevelsPerPage;
394     if (p->browserScrollOffsetDest < 0)
395         p->browserScrollOffsetDest = 0;
396 
397 }
398 
optionsMenuApplyHandler(void * ptr)399 void optionsMenuApplyHandler(void *ptr)
400 {
401     MainMenu *p = (MainMenu *)ptr;
402 
403     menuBackHandler (ptr);
404 
405     wantReinit = false;
406 #ifdef ENABLE_NLS
407     if (p->oldLanguage != settings.get("language", ""))
408     {
409         settings.setLanguage(settings.get("language", ""));
410         wantReinit = true;
411     }
412 #endif
413     if (p->oldFullscreen != settings.getb("fullscreen", false))
414         wantReinit = true;
415 
416     if (p->oldRes != settings.get("resolution", ""))
417         wantReinit = true;
418 
419     if (p->oldColourHints != settings.getb("colourHints", false))
420         wantReinit = true;
421 
422     if (p->oldMusicVol != atoi(settings.get("musicVolume", "50").c_str()))
423         wantReinit = true;
424 
425     if (wantReinit)
426     {
427         p->quit = true;
428         p->StopMusic();
429     }
430 
431     ((Scene *)p)->show_fps = settings.getb("showFps", false);
432 };
433 
optionsMenuCancelHandler(void * ptr)434 void optionsMenuCancelHandler(void *ptr)
435 {
436     MainMenu *p = (MainMenu *)ptr;
437 
438     menuBackHandler (ptr);
439 
440     int y = 9;
441 
442 #ifdef ENABLE_NLS
443     y++;
444 #endif
445     for (int f = 0; f < y; f++)
446         p->optionsMenu.items[f]->Revert();
447 }
448 
menuBackHandler(void * ptr)449 void menuBackHandler(void *ptr)
450 {
451     MainMenu *p = (MainMenu *)ptr;
452     if (p->showBrowser)
453     {
454         p->showBrowser = false;
455         p->showSets = true;
456         p->browserScrollOffset = -5.0;
457         p->browserScrollOffsetDest = 0;
458         p->browserSelectedLevel = -1;
459         return;
460     }
461 
462     ((MainMenu*)ptr)->currentMenu = &((MainMenu*)ptr)->startMenu;
463     ((MainMenu*)ptr)->renderHiscores = true;
464     ((MainMenu*)ptr)->showCredits = false;
465     ((MainMenu*)ptr)->showBrowser = false;
466     ((MainMenu*)ptr)->showSets = false;
467 }
468 
startMenuOptionsHandler(void * ptr)469 void startMenuOptionsHandler(void *ptr)
470 {
471     ((MainMenu*)ptr)->oldFullscreen = settings.getb("fullscreen", false);
472     ((MainMenu*)ptr)->oldRes = settings.get("resolution", "");
473     ((MainMenu*)ptr)->oldColourHints = settings.getb("colourHints", "");
474     ((MainMenu*)ptr)->oldLanguage = settings.get("language", "");
475     ((MainMenu*)ptr)->oldMusicVol = atoi(settings.get("musicVolume", "50").c_str());
476 
477     ((MainMenu*)ptr)->currentMenu = &((MainMenu*)ptr)->optionsMenu;
478     ((MainMenu*)ptr)->renderHiscores = false;
479 };
480 
startMenuCreditsHandler(void * ptr)481 void startMenuCreditsHandler(void *ptr)
482 {
483     ((MainMenu*)ptr)->currentMenu = &((MainMenu*)ptr)->creditsMenu;
484     ((MainMenu*)ptr)->renderHiscores = false;
485     ((MainMenu*)ptr)->showCredits = true;
486     ((MainMenu*)ptr)->creditsScroll = ((MainMenu*)ptr)->creditsScrollClearance * -1;
487 };
488 
startMenuExitHandler(void * ptr)489 void startMenuExitHandler(void *ptr)
490 {
491     ((MainMenu*)ptr)->quit = true;
492     ((MainMenu*)ptr)->StopMusic();
493 };
494 
startMenuShowProfilesHandler(void * ptr)495 void startMenuShowProfilesHandler(void *ptr)
496 {
497     profile.Save();
498     MainMenu *p = (MainMenu *)ptr;
499     p->currentMenu = &p->profileActionsMenu;
500 
501     // regenerate profile list
502     p->profileListMenu.items.clear();
503 
504     p->profileNames = ListFiles(settings.getDefaultDirectory(), ".profile");
505 
506     for (uint f = 0; f < p->profileNames.size(); f++)
507     {
508         string n = p->profileNames[f];
509         n = n.substr(0, n.find(".profile"));
510 
511         p->profileNames[f] = n;
512     }
513 
514     for (uint f = 0; f < p->profileNames.size() && f < 5; f++)
515         p->profileListMenu.Add(new GenericMenuItem(p->profileNames[f], profileActionsMenuUseHandler, ptr));
516 
517     p->profileListMenu.SetDimensions(25, 45, 50);
518 
519     p->profileActionsMenu.items[0]->show = true;
520     if (p->profileNames.size() > 4)
521         p->profileActionsMenu.items[0]->show = false;
522 
523     p->profileActionsMenu.items[1]->show = true;
524 
525     if (p->profileNames.empty())
526     {
527         p->profileActionsMenu.items[1]->show = false;
528     }
529 
530     p->showProfiles = true;
531     p->renderHiscores = false;
532     if (p->profileListMenu.getHoverItem() >= p->profileListMenu.items.size())
533     {
534         p->profileListMenu.setHoverItem(p->profileListMenu.items.size() - 1);
535     }
536 }
537 
startMenuStartHandler(void * ptr)538 void startMenuStartHandler(void *ptr)
539 {
540     MainMenu *p = (MainMenu *)ptr;
541     p->browserScrollOffset = -5.0;
542     p->browserScrollOffsetDest = 0;
543     p->browserSelectedLevel = -1;
544     p->showSets = true;
545     p->showBrowser = false;
546     p->renderHiscores = false;
547     p->currentMenu = &((MainMenu*)ptr)->browserMenu;
548     p->browserUsedKeyboard = false;
549 };
550 
~MainMenu()551 MainMenu::~MainMenu()
552 {
553     glDeleteTextures(1, &logoTex);
554     glDeleteTextures(1, &logoGpl);
555     glDeleteTextures(1, &pointer);
556     glDeleteTextures(14, ballText);
557 
558     for (uint f = 0; f < setTex.size(); f++)
559         glDeleteTextures(1, &setTex[f]);
560 
561     if (nleveldesc)
562         delete [] levels;
563 }
564 
GLSetup()565 void MainMenu::GLSetup()
566 {
567     int width = surface->w;
568     int height = surface->h;
569 
570     SDL_ShowCursor(0);
571 
572     /* Our shading model--Gouraud (smooth). */
573     glShadeModel( GL_SMOOTH );
574 
575     /* Culling. */
576     glCullFace( GL_BACK );
577     glFrontFace( GL_CCW );
578     glEnable( GL_CULL_FACE );
579     glEnable(GL_DEPTH_TEST);
580     glEnable( GL_ALPHA_TEST );
581     glAlphaFunc(GL_GREATER, 0.0);
582     glEnable(GL_LINE_SMOOTH);
583 
584     glEnable(GL_BLEND);
585     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
586 
587     glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
588     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
589     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
590 
591     glClearColor( .1f, .1f, .7f, 1.0f );
592     glViewport( 0, 0, width, height);
593     glMatrixMode( GL_PROJECTION );
594     glLoadIdentity( );
595 
596     glOrtho(vleft, vwidth + vleft, 0, 100, -100, 100);
597     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
598 }
599 
Render(ulong frame)600 void MainMenu::Render(ulong frame)
601 {
602     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
603     glColor3f(1.0, 1.0, 1.0);
604     glMatrixMode( GL_MODELVIEW );
605     glLoadIdentity( );
606 
607     for (int p = 0; p < nBallPaths; ++p)
608     {
609         bp[p].Render();
610     }
611 
612     // logo
613     glLoadIdentity( );
614     glPushMatrix();
615     glEnable(GL_TEXTURE_2D);
616     glTranslated(vleft + 5, 95, 5);
617     glBindTexture(GL_TEXTURE_2D, logoTex);
618     glScalef(80, 48, 5);
619     glBegin(GL_QUADS);
620     glTexCoord2d(0, 0);
621     glVertex3d(0, 0, 0);
622     glTexCoord2d(0, 1);
623     glVertex3d(0, -1, 0);
624     glTexCoord2d(1, 1);
625     glVertex3d(1, -1, 0);
626     glTexCoord2d(1, 0);
627     glVertex3d(1, 0, 0);
628     glEnd();
629     glDisable(GL_TEXTURE_2D);
630     glPopMatrix();
631 
632     currentMenu->Render();
633 
634     if (renderHiscores && !hiScoreRep.empty())
635     {
636         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
637 
638         glPushMatrix();
639         glTranslatef(18, 42, 5);
640         glScalef(0.15f, 0.15f, 0.15f);
641         glColor4d(1.0, 1.0, 1.0, 1.0);
642 
643         font->Render(_("Hall of Fame"), -1);
644         glPopMatrix();
645 
646 
647         double alpha = 1.0;
648         int a = (hiScoreWaitPageSec * desiredFPS) - hiScoreTimeout;
649         int b = (hiScoreWaitPageSec * desiredFPS) / 5;
650         int c = (hiScoreWaitPageSec * desiredFPS);
651 
652         if (a < b)
653         { // fadein
654             alpha = (double)a / (double)b;
655         }
656 
657         if (a > (c - b))
658         { // fadeout
659             alpha = 1.0 - ((double)(a - (c - b)) / (double)b);
660         }
661 
662 
663         float y = 37;
664         glPushMatrix();
665         glTranslatef(-5, y, 5);
666         glScalef(0.1f, 0.1f, 0.1f);
667         glColor4d(1.0, 0.0, 1.0, alpha);
668 
669         font->Render(hiScoreRep[hiScorePage].header.c_str(), -1);
670         glPopMatrix();
671 
672         y-= 3;
673 
674         uint nHigh = hiScoreRep[hiScorePage].lines.size();
675         for (uint f = 0; f < nHigh; f++)
676         {
677             glPushMatrix();
678             glTranslatef(-3, y, 5);
679             glScalef(0.1f, 0.1f, 0.1f);
680             glColor4d(1.0, 1.0, 1.0, alpha);
681 
682             font4->Render(hiScoreRep[hiScorePage].lines[f].c_str(), -1);
683             glPopMatrix();
684 
685             y-=2.5;
686         }
687     }
688 
689     if (showProfiles)
690     {
691         profileListMenu.Render();
692         if (showNewProfile)
693             newProfileEditor->Render();
694     }
695 
696     if (showCredits)
697     {
698         double creditsY = 45;
699         double scrollLength = 21;
700         int pos = creditsScroll / 100;
701 
702         double starty = creditsY + ((creditsScroll%100) / 100.0) * 2.5;
703         double y = starty;
704 
705         while (y > (starty - scrollLength))
706         {
707             if (pos < 0)
708             {
709                 y = y - 2.5;
710                 pos++;
711                 continue;
712             }
713 
714             if (pos >= credits.size())
715             {
716                 y = y - 2.5;
717                 continue;
718             }
719 
720             if (creditsY - y < (scrollLength) / 2)
721             {
722                 glColor4f(1.0, 1.0, 1.0, (creditsY - y) / (scrollLength / 4));
723             }
724             else
725             {
726                 glColor4f(1.0, 1.0, 1.0, (scrollLength - (creditsY - y)) / (scrollLength / 4) - 0.2);
727             }
728 
729             double size = 0.08;
730             if (credits[pos].fat)
731                 size = 0.12;
732             if (credits[pos].txt != "-")
733                 CenterMsg(_(credits[pos].txt.c_str()), y, font, size);
734 
735             pos++;
736 
737             y = y - 2.5;
738         }
739 
740         glLoadIdentity();
741         glEnable(GL_TEXTURE_2D);
742         glTranslatef(50, 18, 5);
743         glBindTexture(GL_TEXTURE_2D, logoGpl);
744         glScalef(20, 10, 1);
745         glBegin(GL_QUADS);
746         glTexCoord2d(0, 0);
747         glVertex3d(-.5, .5, 0);
748         glTexCoord2d(0, 1);
749         glVertex3d(-.5, -.5, 0);
750         glTexCoord2d(1, 1);
751         glVertex3d(.5, -.5, 0);
752         glTexCoord2d(1, 0);
753         glVertex3d(.5, .5, 0);
754         glEnd();
755         glDisable(GL_TEXTURE_2D);
756     }
757 
758     if (showSets)
759     {
760         glColor4f(1.0, 1.0, 1.0, 1.0);
761         CenterMsg(_("choose a level set"), 37, font, 0.1);
762         int lstart = (int)iround(browserScrollOffset) - 1;
763         if (lstart < 0)
764             lstart = 0;
765 
766         int lend = lstart + browserNLevelsPerPage + browserNLevelsPerPage;
767         if (lend > (int)sets.size())
768             lend = sets.size();
769 
770         double tw = (100.0 - double((browserThumbSpacing * (browserNLevelsPerPage - 1)))) / browserNLevelsPerPage;
771         double th = tw / (640.0/480.0);
772 
773         double xmv = -(browserScrollOffset - lstart) * (tw + browserThumbSpacing);
774 
775         double xx = 0;
776         double spc = 0;
777 
778         if (!browserUsedKeyboard)
779             browserSelectedLevel = -1;
780 
781         browserMouseOverLevel = -1;
782 
783         for (int f = lstart; f < lend; f++)
784         {
785             glLoadIdentity();
786             glTranslated(xx * tw + spc + xmv, 25 - (th / 2), 5);
787 
788             if ((mx > xx * tw + spc + xmv) &&
789                     (mx < xx * tw + spc + xmv + tw) &&
790                     (my > 25 - (th / 2)) &&
791                     (my < 25 + (th / 2)))
792             {
793                 if (!browserUsedKeyboard)
794                     browserSelectedLevel = f;
795                 browserMouseOverLevel = f;
796 
797             }
798 
799             glColor4d(.7, .7, .7, 1.0);
800             if (browserSelectedLevel == f)
801             {
802                 glColor4d(1.0, 1.0, 1.0, 1.0);
803             }
804 
805             glEnable(GL_TEXTURE_2D);
806             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
807             glBindTexture(GL_TEXTURE_2D, setTex[f]);
808             glBegin(GL_QUADS);
809             glTexCoord2d(0, 0);
810             glVertex3d(0, th, 0);
811             glTexCoord2d(0, 1);
812             glVertex3d(0, 0, 0);
813             glTexCoord2d(1, 1);
814             glVertex3d(tw, 0, 0);
815             glTexCoord2d(1, 0);
816             glVertex3d(tw, th, 0);
817             glEnd();
818 
819             glDisable(GL_TEXTURE_2D);
820             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
821 
822             glLoadIdentity();
823             glTranslated(xx * tw + spc + xmv, 25 - (th / 2), 7);
824             glColor4d(0, 0, 0, 1);
825             glLineWidth(2.0);
826             glBegin(GL_LINE_STRIP);
827             glVertex3d(0, 0, 0);
828             glVertex3d(0, th, 0);
829             glVertex3d(tw, th, 0);
830             glVertex3d(tw, 0, 0);
831             glVertex3d(0, 0, 0);
832             glEnd();
833 
834             double size = 0.08;
835             glLoadIdentity( );
836             glColor4d(1.0, 1.0, 1.0, 1);
837             char levelName[256];
838             sprintf(levelName, "%s", sets[f].getDesc().c_str());
839 
840             FTBBox b = font->BBox(gettext(levelName));
841             double txtw = b.Upper().X() / (1.0 / size);
842             glTranslated((xx * tw + spc) + (tw / 2) - (txtw / 2) + xmv, 11.5, 5);
843             glScaled(size, size, size);
844 
845             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
846             font->Render(gettext(levelName));
847 
848             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
849 
850             spc += browserThumbSpacing;
851             xx += 1.0;
852         }
853     }
854 
855     if (showBrowser)
856     {
857         glColor4f(1.0, 1.0, 1.0, 1.0);
858         CenterMsg(_(sets[selectedSet].description.c_str()), 37, font, 0.1);
859 
860         int lstart = (int)iround(browserScrollOffset) - 1;
861         if (lstart < 0)
862             lstart = 0;
863 
864         int lend = lstart + browserNLevelsPerPage + browserNLevelsPerPage;
865         if (lend > nleveldesc)
866             lend = nleveldesc;
867 
868         double tw = (100.0 - double((browserThumbSpacing * (browserNLevelsPerPage - 1)))) / browserNLevelsPerPage;
869         double th = tw / (640.0/480.0);
870 
871         double xmv = -(browserScrollOffset - lstart) * (tw + browserThumbSpacing);
872 
873         double xx = 0;
874         double spc = 0;
875 
876         if (!browserUsedKeyboard)
877             browserSelectedLevel = -1;
878 
879         browserMouseOverLevel = -1;
880 
881         for (int f = lstart; f < lend; f++)
882         {
883             glLoadIdentity();
884             glTranslated(xx * tw + spc + xmv, 25 - (th / 2), 5);
885 
886 
887             if ((mx > xx * tw + spc + xmv) &&
888                     (mx < xx * tw + spc + xmv + tw) &&
889                     (my > 25 - (th / 2)) &&
890                     (my < 25 + (th / 2)))
891             {
892                 if (!levels[f].locked && iround(browserScrollOffset) >= 0)
893                 {
894                     if (!browserUsedKeyboard)
895                         browserSelectedLevel = f;
896 
897                     browserMouseOverLevel = f;
898                 }
899             }
900 
901             glColor4d(.7, .7, .7, 1.0);
902             if (browserSelectedLevel == f)
903             {
904                 glColor4d(1.0, 1.0, 1.0, 1.0);
905             }
906 
907             glEnable(GL_TEXTURE_2D);
908             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
909             glBindTexture(GL_TEXTURE_2D, levels[f].tex);
910 
911             XY tl(0,0);
912             XY tr(1,0);
913             XY bl(0,1);
914             XY br(1,1);
915 
916             if (levels[f].lev.mirrorX)
917             {
918                 XY t = tl;
919                 tl = tr;
920                 tr = t;
921 
922                 t = bl;
923                 bl = br;
924                 br = t;
925             }
926 
927             if (levels[f].lev.mirrorY)
928             {
929                 XY t = tl;
930                 tl = bl;
931                 bl = t;
932 
933                 t = br;
934                 br = tr;
935                 tr = t;
936             }
937 
938             glBegin(GL_QUADS);
939             glTexCoord2d(tl.x, tl.y);
940             glVertex3d(0, th, 0);
941             glTexCoord2d(bl.x, bl.y);
942             glVertex3d(0, 0, 0);
943             glTexCoord2d(br.x, br.y);
944             glVertex3d(tw, 0, 0);
945             glTexCoord2d(tr.x, tr.y);
946             glVertex3d(tw, th, 0);
947             glEnd();
948 
949             glDisable(GL_TEXTURE_2D);
950             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
951 
952             glLoadIdentity();
953             glTranslated(xx * tw + spc + xmv, 25 - (th / 2), 7);
954             glColor4d(0, 0, 0, 1);
955             glLineWidth(2.0);
956             glBegin(GL_LINE_STRIP);
957             glVertex3d(0, 0, 0);
958             glVertex3d(0, th, 0);
959             glVertex3d(tw, th, 0);
960             glVertex3d(tw, 0, 0);
961             glVertex3d(0, 0, 0);
962             glEnd();
963 
964             double size = 0.08;
965             glLoadIdentity( );
966             glColor4d(1.0, 1.0, 1.0, 1);
967             char levelName[256];
968             sprintf(levelName, "%s", levels[f].lev.name.c_str());
969 
970             FTBBox b = font->BBox(gettext(levelName));
971             double txtw = b.Upper().X() / (1.0 / size);
972             glTranslated((xx * tw + spc) + (tw / 2) - (txtw / 2) + xmv, 11.5, 5);
973             glScaled(size, size, size);
974 
975             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
976             font->Render(gettext(levelName));
977             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
978 
979             if (levels[f].locked)
980             {
981                 char lockedTxt[256];
982 
983                 sprintf(lockedTxt, "%s", _("locked"));
984                 size = 0.3;
985                 glLoadIdentity( );
986                 glColor4d(1.0, 0, 0, 1);
987                 b = font->BBox(lockedTxt);
988                 txtw = b.Upper().X() / (1.0 / size);
989                 glTranslated((xx * tw + spc) + (tw / 2) - (txtw / 2) + xmv, 28, 7);
990                 glScaled(size, size, size);
991 
992                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
993                 font->Render(lockedTxt);
994                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
995             }
996 
997             spc += browserThumbSpacing;
998             xx += 1.0;
999         }
1000     }
1001 
1002     // render pointer
1003     glLoadIdentity();
1004     glEnable(GL_TEXTURE_2D);
1005     glTranslatef(mx, my, 20);
1006     glColor4f(1.0, 1.0, 1.0, 1.0);
1007     glBindTexture(GL_TEXTURE_2D, pointer);
1008     glScalef(5, 5, 5);
1009     glBegin(GL_QUADS);
1010     glTexCoord2d(0, 0);
1011     glVertex3d(0, 0, 0);
1012     glTexCoord2d(0, 1);
1013     glVertex3d(0, -1, 0);
1014     glTexCoord2d(1, 1);
1015     glVertex3d(1, -1, 0);
1016     glTexCoord2d(1, 0);
1017     glVertex3d(1, 0, 0);
1018     glEnd();
1019     glDisable(GL_TEXTURE_2D);
1020 
1021     int pf = pointerFrame / 2;
1022     double ts = 1.0 / double(BALLTEXTURECOUNT);
1023     double tx = (double)((pf % BALLTEXTURECOUNT)) * ts;
1024     double ty = (double)((pf / BALLTEXTURECOUNT)) * ts;
1025 
1026     glLoadIdentity();
1027     glEnable(GL_TEXTURE_2D);
1028     glTranslated(mx, my, 20);
1029     glBindTexture(GL_TEXTURE_2D, ballText[1]);
1030     glTranslated(3.5, -3.5, 0);
1031     glScalef(3, 3, 3);
1032     glRotated(pointerRot, 0, 0, 1.0);
1033 
1034     glBegin(GL_QUADS);
1035     glTexCoord2d(tx, ty);
1036     glVertex3d(-0.5, 0.5, 0);
1037     glTexCoord2d(tx, ty + ts);
1038     glVertex3d(-0.5, -0.5, 0);
1039     glTexCoord2d(tx + ts, ty + ts);
1040     glVertex3d(0.5, -0.5, 0);
1041     glTexCoord2d(tx + ts, ty);
1042     glVertex3d(0.5, 0.5, 0);
1043     glEnd();
1044     glDisable(GL_TEXTURE_2D);
1045 }
1046 
FixLevelLocks()1047 void MainMenu::FixLevelLocks()
1048 {
1049     if (currentLevelSet.getEmpty())
1050         return;
1051 
1052 
1053 }
1054 
Logic(ulong frame)1055 void MainMenu::Logic(ulong frame)
1056 {
1057     pointerFrame++;
1058     if (pointerFrame >= BALLTEXTURECOUNT*BALLTEXTURECOUNT*2)
1059         pointerFrame = 0;
1060 
1061     pointerRot = pointerRot + 0.1;
1062 
1063     if (startup)
1064     {
1065         // handle LCTRL to reset screenmode
1066         if (!resReset && (SDL_GetModState() & KMOD_LCTRL))
1067         {
1068             settings.setb("fullscreen", false);
1069             settings.set("resolution", "640x480");
1070 
1071             wantReinit = true;
1072             quit = true;
1073             StopMusic();
1074             resReset = true;
1075             return;
1076         }
1077 
1078         startupProgressSteps = (float)(25 + setNames.size());
1079         GLSetup();
1080         LoadTextures();
1081         LoadLevelSets();
1082         resync = true;
1083         startup = false;
1084         return;
1085     }
1086 
1087     if (music == NULL)
1088         StartMusic ();
1089 
1090     if (showNewProfile)
1091     {
1092         newProfileEditor->Logic(events);
1093     }
1094 
1095     bool click = false;
1096 
1097     if (!events.empty)
1098     {
1099         if (events.keyDown.size() > 0)
1100             for (vector<SDLKey>::iterator i = events.keyDown.begin(); i != events.keyDown.end(); ++i)
1101             {
1102                 if (*i == SDLK_ESCAPE && !showNewProfile)
1103                 {
1104                     if (currentMenu == &startMenu)
1105                     {
1106                         quit = true;
1107                     }
1108                     else
1109                     {
1110                         if (currentMenu == &optionsMenu)
1111                         {
1112                             optionsMenuCancelHandler(this);
1113                             return;
1114                         }
1115 
1116                         if (showBrowser)
1117                         {
1118                             showBrowser = false;
1119                             showSets = true;
1120                             browserScrollOffset = -5.0;
1121                             browserScrollOffsetDest = 0;
1122                             browserSelectedLevel = -1;
1123                             return;
1124                         }
1125                         else
1126                         {
1127                             currentMenu = &startMenu;
1128                             renderHiscores = true;
1129                             showBrowser = false;
1130                             showCredits = false;
1131                             showSets = false;
1132                             if (showProfiles)
1133                             { // we could have deleted current profile and escaped
1134                                 profile.Save();
1135                                 showProfiles = false;
1136                                 renderHiscores = true;
1137                             }
1138                         }
1139                     }
1140                 }
1141 
1142                 if (*i == SDLK_ESCAPE && showNewProfile)
1143                 {
1144                     showNewProfile = false;
1145                     delete(newProfileEditor);
1146                 }
1147 
1148                 if (!showNewProfile)
1149                     if (showProfiles && (*i == SDLK_RETURN || *i == SDLK_KP_ENTER))
1150                     {
1151                         profileActionsMenuUseHandler(this);
1152                         return;
1153                     }
1154 
1155                 if (showNewProfile && (*i == SDLK_RETURN || *i == SDLK_KP_ENTER))
1156                 {
1157                     showNewProfile = false;
1158                     if (!newProfileEditor->txt.empty())
1159                     {
1160 #ifndef WIN32
1161                         string ph = settings.getDefaultDirectory() + SEPARATOR + newProfileEditor->txt + ".profile";
1162                         FILE *phile = fopen(ph.c_str(), "wb");
1163                         if (phile)
1164                             fclose(phile);
1165 #endif
1166 
1167 #ifdef WIN32
1168                         Settings::W32_CreateFile(settings.getDefaultDirectory() + SEPARATOR + newProfileEditor->txt + ".profile");
1169 #endif
1170                         startMenuShowProfilesHandler(this);
1171                     }
1172 
1173                     delete(newProfileEditor);
1174                     return;
1175                 }
1176 
1177                 if (showBrowser || showSets)
1178                 {
1179                     if (*i == SDLK_LEFT)
1180                     {
1181                         browserSelectedLevel--;
1182                         browserUsedKeyboard = true;
1183                     }
1184 
1185                     if (*i == SDLK_RIGHT)
1186                     {
1187                         browserSelectedLevel++;
1188                         browserUsedKeyboard = true;
1189                     }
1190 
1191                     if (*i == SDLK_TAB)
1192                     {
1193                         browserMenu.items[3]->Key(SDLK_RIGHT);
1194                     }
1195 
1196                     if (showSets)
1197                     {
1198                         clamp(browserSelectedLevel, 0, (int)(sets.size() - 1))
1199                     }
1200                     else
1201                     {
1202                         clamp(browserSelectedLevel, 0, (int)(currentLevelSet.levels.size() - 1))
1203                     }
1204 
1205                     if (browserUsedKeyboard)
1206                     {
1207                         browserScrollOffsetDest=(browserSelectedLevel/browserNLevelsPerPage) * browserNLevelsPerPage;
1208                     }
1209 
1210                     if (*i == SDLK_RETURN || *i == SDLK_KP_ENTER)
1211                     {
1212                         click = true;
1213                     }
1214                 }
1215             }
1216 
1217         if (lmx != mx || lmy != my)
1218             browserUsedKeyboard = false;
1219 
1220         lmx = mx;
1221         lmy = my;
1222 
1223         if (events.buttDown[0])
1224         {
1225             if (browserMouseOverLevel != -1)
1226                 click = true;
1227         }
1228 
1229         // we have to translate mouse events to local coords for the menu
1230         FrameEvents tempEvents = events;
1231         tempEvents.mouseX = mx;
1232         tempEvents.mouseY = my;
1233 
1234         if (showProfiles)
1235         {
1236             if (!showNewProfile)
1237                 profileListMenu.Logic(tempEvents);
1238 
1239             // move menuactions to hovered item in profilelist
1240             int h = profileListMenu.getHoverItem();
1241 
1242             if (profileListMenu.items.size())
1243             {
1244                 profileActionsMenu.items[1]->x = 0;
1245                 profileActionsMenu.items[1]->y = profileListMenu.items[h]->y;
1246                 profileActionsMenu.items[1]->width = 25;
1247 
1248                 profileActionsMenu.items[1]->show = true;
1249                 string ph = profileNames[profileListMenu.getHoverItem()];
1250                 if (ph == profile.getName())
1251                 {
1252                     profileActionsMenu.items[1]->show = false;
1253                 }
1254 
1255 
1256                 /*profileActionsMenu.items[2]->x = 70;
1257                 profileActionsMenu.items[2]->y = profileListMenu.items[h]->y;
1258                 profileActionsMenu.items[2]->width = 30;*/
1259             }
1260         }
1261 
1262         // have to strip the key events from browser menu
1263         if (!showBrowser && !showProfiles && !showSets)
1264         {
1265             currentMenu->Logic(tempEvents);
1266         }
1267         else
1268         {
1269             tempEvents.keyUp.clear();
1270             tempEvents.keyDown.clear();
1271             if (!showNewProfile)
1272                 currentMenu->Logic(tempEvents);
1273         }
1274 
1275 
1276         if (showBrowser && browserSelectedLevel >= 0 && click)
1277         {
1278             currentMenu = &startMenu;
1279             renderHiscores = true;
1280             showBrowser = false;
1281 
1282             StopMusic();
1283             currentLevelSet = sets[selectedSet];
1284 
1285             bool survival = false;
1286             if (((OptionMenuItem*)browserMenu.items[3])->getV() == 1)
1287                 survival = true;
1288 
1289             GameLoop(surface, ballText, browserSelectedLevel, Scenes::DEFAULT_FPS, survival).Run();
1290             resync = true;
1291             RecalculateMousePos();
1292 
1293             StartMusic();
1294             GLSetup();
1295             SDL_ShowCursor(SDL_ENABLE);
1296             SDL_WM_GrabInput(SDL_GRAB_OFF);
1297             hiScoreRep = hiScores.GenerateReport(linesPerHiScorePage);
1298             hiScorePage = 0;
1299             hiScoreTimeout = hiScoreWaitPageSec * desiredFPS;
1300         }
1301 
1302         if (showSets && browserSelectedLevel >= 0 && click)
1303         {
1304             showSets = false;
1305             showBrowser = true;
1306             browserScrollOffset = -5.0;
1307             browserScrollOffsetDest = 0;
1308             selectedSet = browserSelectedLevel;
1309             browserSelectedLevel = -1;
1310             currentLevelSet = sets[selectedSet];
1311             FillLevelDesc();
1312         }
1313     }
1314 
1315     for (int p = 0; p < nBallPaths; ++p)
1316     {
1317         bp[p].state.ballOut = false;
1318         bp[p].Logic();
1319     }
1320 
1321     if (showBrowser || showSets)
1322     {
1323         browserScrollOffset = browserScrollOffset + (browserScrollOffsetDest - browserScrollOffset) / 20.0;
1324     }
1325 
1326     if (renderHiscores)
1327     {
1328         if (hiScoreTimeout)
1329             hiScoreTimeout--;
1330 
1331         if (hiScoreTimeout == 0)
1332         {
1333             hiScorePage++;
1334             hiScoreTimeout = hiScoreWaitPageSec * desiredFPS;
1335             if (hiScorePage >= hiScoreRep.size())
1336             {
1337                 hiScorePage = 0;
1338             }
1339         }
1340     }
1341 
1342     if (showCredits)
1343     {
1344         creditsScroll++;
1345         if (creditsScroll > (int)((credits.size() * 100)))
1346             creditsScroll = -creditsScrollClearance;
1347     }
1348 }
1349 
FillLevelDesc()1350 void MainMenu::FillLevelDesc()
1351 {
1352     if (nleveldesc > 0)
1353         delete [] levels;
1354 
1355     nleveldesc = sets[selectedSet].levels.size();
1356     levels = new LevelDesc[nleveldesc];
1357     if (nleveldesc > 0)
1358         levels[0].locked = false;
1359 
1360     for (int f = 0; f < nleveldesc; f++)
1361     {
1362         levels[f].lev = sets[selectedSet].levels[f];
1363         levels[f].tex = LoadTextureFile(sets[selectedSet].levels[f].thumbTexFilename.c_str());
1364 
1365         stringstream setname;
1366         setname << sets[selectedSet].filename << ":" << (f + 1) << ":completed";
1367 
1368         if (f < nleveldesc - 1)
1369         {
1370             levels[f + 1].locked = true;
1371 
1372             if (profile.getb(setname.str(), false))
1373             {
1374                 levels[f+1].locked = false;
1375             }
1376         }
1377     }
1378 }
1379 
CenterMsg(string msg,double y,FTFont * font,double size)1380 void MainMenu::CenterMsg(string msg, double y, FTFont *font, double size)
1381 {
1382     glLoadIdentity( );
1383     FTBBox b = font->BBox(msg.c_str());
1384     double tw = b.Upper().X() / (1.0 / size);
1385     glTranslated((100 - tw) / 2, y, 5);
1386     glScaled(size, size, size);
1387 
1388     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1389     font->Render(msg.c_str());
1390     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1391 }
1392 
1393