Line data Source code
1 : /* renderwindow: screen rendering functionality
2 : *
3 : * screen rendering functions, such as background, progress bar
4 : * also handles stuff such as main menu rendering and other non-intensive rendering
5 : * as well as global rendering settings such as gamma
6 : */
7 : #include "SDL_ttf.h"
8 :
9 : #include "../libprimis-headers/cube.h"
10 : #include "../../shared/geomexts.h"
11 : #include "../../shared/glemu.h"
12 : #include "../../shared/glexts.h"
13 :
14 : #include "hud.h"
15 : #include "octarender.h"
16 : #include "rendergl.h"
17 : #include "renderlights.h"
18 : #include "rendermodel.h"
19 : #include "renderparticles.h"
20 : #include "rendertext.h"
21 : #include "renderttf.h"
22 : #include "renderva.h"
23 : #include "renderwindow.h"
24 : #include "shader.h"
25 : #include "shaderparam.h"
26 : #include "stain.h"
27 : #include "texture.h"
28 :
29 : #include "interface/console.h"
30 : #include "interface/control.h"
31 : #include "interface/input.h"
32 : #include "interface/menus.h"
33 :
34 : #include "world/octaedit.h"
35 :
36 0 : VARFN(screenw, scr_w, SCR_MINW, -1, SCR_MAXW, initwarning("screen resolution"));
37 0 : VARFN(screenh, scr_h, SCR_MINH, -1, SCR_MAXH, initwarning("screen resolution"));
38 :
39 : VAR(menufps, 0, 60, 1000); //maximum framerate while in main menu
40 : VARP(maxfps, 0, 240, 1000); //maximum framerate while world is being rendered
41 :
42 : VAR(desktopw, 1, 0, 0);
43 : VAR(desktoph, 1, 0, 0);
44 : int screenw = 0,
45 : screenh = 0;
46 : SDL_Window *screen = nullptr;
47 : static SDL_GLContext glcontext = nullptr;
48 :
49 : //helper function for main menu rendering routines
50 : //returns w and h if both are above 1024x768
51 : //returns w and h multiplied by the factor by which the smallest dimension is smaller than 1024x768
52 0 : static void getbackgroundres(int &w, int &h)
53 : {
54 0 : float wk = 1,
55 0 : hk = 1;
56 0 : if(w < 1024)
57 : {
58 0 : wk = 1024.0f/w; //calculate w subsize factor (if greater than 1)
59 : }
60 0 : if(h < 768)
61 : {
62 0 : hk = 768.0f/h; //calculate h subsize factor (if greater than 1)
63 : }
64 0 : wk = hk = std::max(wk, hk); //pick the largest factor and multiply both by this
65 0 : w = static_cast<int>(std::ceil(w*wk));
66 0 : h = static_cast<int>(std::ceil(h*hk));
67 0 : }
68 :
69 : static std::string backgroundcaption = "",
70 : backgroundmapname = "",
71 : backgroundmapinfo = "";
72 : static Texture *backgroundmapshot = nullptr;
73 :
74 0 : static void bgquad(float x, float y, float w, float h, float tx = 0, float ty = 0, float tw = 1, float th = 1)
75 : {
76 0 : gle::begin(GL_TRIANGLE_STRIP);
77 0 : gle::attribf(x, y); gle::attribf(tx, ty);
78 0 : gle::attribf(x+w, y); gle::attribf(tx + tw, ty);
79 0 : gle::attribf(x, y+h); gle::attribf(tx, ty + th);
80 0 : gle::attribf(x+w, y+h); gle::attribf(tx + tw, ty + th);
81 0 : gle::end();
82 0 : }
83 :
84 : // void renderbackgroundview(int, int, const char*, Texture*, const char*, const char*)
85 : // Background picture / text handler
86 :
87 : /*
88 : Notes:
89 : * Unsure what 'w' and 'h' refers to, maybe screen resolution?
90 : */
91 :
92 0 : static void renderbackgroundview(int win_w, int win_h, const char *caption, Texture *mapshot, const char *mapname, const char *mapinfo)
93 : {
94 : static int lastupdate = -1,
95 : lastw = -1,
96 : lasth = -1;
97 : static float backgroundu = 0,
98 : backgroundv = 0;
99 0 : const bool needsRefresh =
100 0 : (renderedframe && !mainmenu && lastupdate != lastmillis)
101 0 : || lastw != win_w
102 0 : || lasth != win_h;
103 0 : if(needsRefresh)
104 : {
105 0 : lastupdate = lastmillis;
106 0 : lastw = win_w;
107 0 : lasth = win_h;
108 :
109 0 : backgroundu = randomfloat(1);
110 0 : backgroundv = randomfloat(1);
111 : }
112 0 : else if(lastupdate != lastmillis)
113 : {
114 0 : lastupdate = lastmillis;
115 : }
116 0 : hudmatrix.ortho(0, win_w, win_h, 0, -1, 1);
117 0 : resethudmatrix();
118 0 : resethudshader();
119 :
120 0 : gle::defvertex(2);
121 0 : gle::deftexcoord0();
122 0 : settexture("media/interface/background.png", 0); //main menu background
123 0 : float bu = win_w*0.67f/256.0f,
124 0 : bv = win_h*0.67f/256.0f;
125 0 : bgquad(0, 0, win_w, win_h, backgroundu, backgroundv, bu, bv);
126 :
127 0 : glEnable(GL_BLEND);
128 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
129 0 : settexture("media/interface/shadow.png", 3); //peripheral shadow effect
130 0 : bgquad(0, 0, win_w, win_h);
131 0 : glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
132 : // Set position and size of logo
133 0 : float logo_h = (1.f/3.f)*std::min(win_w, win_h),
134 0 : logo_w = logo_h*(2.f/1.f), // Aspect ratio of logo, defined here
135 0 : logo_x = 0.5f*(win_w - logo_w),
136 0 : logo_y = 0.5f*(win_h*0.5f - logo_h);
137 :
138 0 : settexture( (maxtexsize >= 1024 || maxtexsize == 0) && (hudw() > 1280 || hudh() > 800)
139 : ? "<premul>media/interface/logo_1024.png" //1024x wide logo
140 : : "<premul>media/interface/logo.png", //512x wide logo for small screens
141 : 3);
142 0 : bgquad(logo_x, logo_y, logo_w, logo_h);
143 :
144 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
145 :
146 0 : if(caption)
147 : {
148 0 : int tw = text_width(caption);
149 0 : float tsz = 0.04f*std::min(win_w, win_h)/FONTH,
150 0 : tx = 0.5f*(win_w - tw*tsz),
151 0 : ty = win_h - 0.075f*1.5f*std::min(win_w, win_h) - FONTH*tsz;
152 0 : pushhudtranslate(tx, ty, tsz);
153 : //draw_text(caption, 0, 0);
154 0 : ttr.renderttf(caption, {0xFF, 0xFF, 0xFF, 0}, 0, 0);
155 0 : pophudmatrix();
156 : }
157 0 : if(mapshot || mapname)
158 : {
159 0 : float infowidth = 14*FONTH,
160 0 : sz = 0.35f*std::min(win_w, win_h),
161 0 : msz = (0.85f*std::min(win_w, win_h) - sz)/(infowidth + FONTH),
162 0 : x = 0.5f*win_w,
163 0 : y = logo_y+logo_h - sz/15,
164 0 : mx = 0,
165 0 : my = 0,
166 0 : mw = 0,
167 0 : mh = 0;
168 : // Prepare text area for map info
169 0 : if(mapinfo)
170 : {
171 0 : text_boundsf(mapinfo, mw, mh, infowidth);
172 0 : x -= 0.5f * mw * msz;
173 0 : if (mapshot && mapshot!=notexture)
174 : {
175 0 : x -= 0.5f*FONTH * msz;
176 0 : mx = sz + FONTH * msz;
177 : }
178 : }
179 : // Map shot was provided and isn't empty
180 0 : if(mapshot && mapshot!=notexture)
181 : {
182 0 : x -= 0.5f * sz;
183 0 : resethudshader();
184 0 : glBindTexture(GL_TEXTURE_2D, mapshot->id);
185 0 : bgquad(x, y, sz, sz);
186 : }
187 : // Map name was provided
188 0 : if(mapname)
189 : {
190 0 : float tw = text_widthf(mapname),
191 0 : tsz = sz/(8*FONTH),
192 0 : tx = std::max(0.5f * (mw*msz - tw * tsz), 0.0f);
193 0 : pushhudtranslate(x + mx + tx, y, tsz);
194 : //draw_text(mapname, 0, 0);
195 0 : ttr.fontsize(42);
196 0 : ttr.renderttf(mapname, {0xFF, 0xFF, 0xFF, 0}, 0, 0);
197 0 : pophudmatrix();
198 0 : my = 1.5f*FONTH*tsz;
199 : }
200 : // Map info was provided
201 0 : if(mapinfo)
202 : {
203 0 : pushhudtranslate(x + mx, y + my, msz);
204 : //draw_text(mapinfo, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, -1, infowidth);
205 0 : ttr.fontsize(42);
206 0 : ttr.renderttf(mapinfo, {0xFF, 0xFF, 0xFF, 0}, 0, 0);
207 0 : pophudmatrix();
208 : }
209 : }
210 0 : glDisable(GL_BLEND);
211 0 : }
212 :
213 0 : void swapbuffers(bool)
214 : {
215 0 : gle::disable();
216 0 : SDL_GL_SwapWindow(screen);
217 0 : }
218 :
219 0 : static void setbackgroundinfo(const char *caption = nullptr, Texture *mapshot = nullptr, const char *mapname = nullptr, const char *mapinfo = nullptr)
220 : {
221 0 : renderedframe = false;
222 0 : backgroundcaption = std::string(caption ? caption : "");
223 0 : backgroundmapshot = mapshot;
224 0 : backgroundmapname = std::string(mapname ? mapname : "");
225 0 : std::string minfo = std::string(mapinfo ? mapinfo : "");
226 0 : if(minfo != backgroundmapinfo)
227 : {
228 0 : backgroundmapinfo = "";
229 0 : if(!minfo.empty())
230 : {
231 0 : backgroundmapinfo = std::string(mapinfo);
232 : }
233 : else
234 : {
235 0 : backgroundmapinfo = "";
236 : }
237 : }
238 0 : }
239 :
240 0 : void renderbackground(const char *caption, Texture *mapshot, const char *mapname, const char *mapinfo, bool force)
241 : {
242 0 : if(!inbetweenframes && !force)
243 : {
244 0 : return;
245 : }
246 0 : int w = hudw(),
247 0 : h = hudh();
248 0 : if(forceaspect)
249 : {
250 0 : w = std::ceil(h*forceaspect);
251 : }
252 0 : getbackgroundres(w, h);
253 0 : gettextres(w, h);
254 0 : if(force)
255 : {
256 0 : renderbackgroundview(w, h, caption, mapshot, mapname, mapinfo);
257 0 : return;
258 : }
259 : //renders renderbackgroundview three times, with an identical call each time
260 0 : for(int i = 0; i < 3; ++i)
261 : {
262 0 : renderbackgroundview(w, h, caption, mapshot, mapname, mapinfo);
263 0 : swapbuffers(false);
264 : }
265 0 : setbackgroundinfo(caption, mapshot, mapname, mapinfo);
266 : }
267 :
268 0 : static void restorebackground(int w, int h, bool force = false)
269 : {
270 0 : if(renderedframe)
271 : {
272 0 : if(!force)
273 : {
274 0 : return;
275 : }
276 0 : setbackgroundinfo();
277 : }
278 0 : renderbackgroundview(w, h, backgroundcaption.c_str(), backgroundmapshot, backgroundmapname.c_str(), backgroundmapinfo.c_str());
279 : }
280 :
281 : float loadprogress = 0;
282 :
283 0 : static void renderprogressview(int w, int h, float bar, const char *text) // also used during loading
284 : {
285 0 : hudmatrix.ortho(0, w, h, 0, -1, 1);
286 0 : resethudmatrix();
287 0 : resethudshader();
288 :
289 0 : gle::defvertex(2);
290 0 : gle::deftexcoord0();
291 :
292 0 : float fh = 0.060f*std::min(w, h),
293 0 : fw = fh * 15,
294 0 : fx = renderedframe ? w - fw - fh/4 : 0.5f * (w - fw),
295 0 : fy = renderedframe ? fh/4 : h - fh * 1.5f;
296 0 : settexture("media/interface/loading_frame.png", 3);
297 0 : bgquad(fx, fy, fw, fh);
298 :
299 0 : glEnable(GL_BLEND);
300 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
301 :
302 0 : float bw = fw * (512 - 2*8)/512.0f,
303 0 : bh = fh * 20/32.0f,
304 0 : bx = fx + fw * 8/512.0f,
305 0 : by = fy + fh * 6/32.0f,
306 0 : su1 = 0/32.0f,
307 0 : su2 = 8/32.0f,
308 0 : sw = fw * 8/512.0f,
309 0 : eu1 = 24/32.0f,
310 0 : eu2 = 32/32.0f,
311 0 : ew = fw * 8/512.0f,
312 0 : mw = bw - sw - ew,
313 0 : ex = bx+sw + std::max(mw*bar, fw * 8/512.0f);
314 0 : if(bar > 0)
315 : {
316 0 : settexture("media/interface/loading_bar.png", 3);
317 0 : bgquad(bx, by, sw, bh, su1, 0, su2-su1, 1);
318 0 : bgquad(bx+sw, by, ex-(bx+sw), bh, su2, 0, eu1-su2, 1);
319 0 : bgquad(ex, by, ew, bh, eu1, 0, eu2-eu1, 1);
320 : }
321 0 : if(text)
322 : {
323 0 : int tw = text_width(text);
324 0 : float tsz = bh * 0.6f/FONTH;
325 0 : if(tw * tsz > mw)
326 : {
327 0 : tsz = mw/tw;
328 : }
329 0 : pushhudtranslate(bx+sw, by + (bh - FONTH*tsz)/2, tsz);
330 : //draw_text(text, 0, 0);
331 0 : ttr.fontsize(50);
332 0 : ttr.renderttf(text, {0xFF, 0xFF, 0xFF, 0}, 0, 4);
333 0 : pophudmatrix();
334 : }
335 0 : glDisable(GL_BLEND);
336 0 : }
337 :
338 : VAR(progressbackground, 0, 0, 1); //force rendering progress bar background texture
339 : static int curvsync = -1;
340 :
341 7 : void renderprogress(float bar, const char *text, bool background) // also used during loading
342 : {
343 7 : if(!inbetweenframes || drawtex)
344 : {
345 7 : return;
346 : }
347 0 : int fps = menufps ? (maxfps ? std::min(maxfps, menufps) : menufps) : maxfps;
348 0 : if(fps)
349 : {
350 : static int lastprogress = 0;
351 0 : int ticks = SDL_GetTicks(),
352 0 : diff = ticks - lastprogress;
353 0 : if(bar > 0 && diff >= 0 && diff < (1000 + fps-1)/fps)
354 : {
355 0 : return;
356 : }
357 0 : lastprogress = ticks;
358 : }
359 0 : int w = hudw(),
360 0 : h = hudh();
361 0 : if(forceaspect)
362 : {
363 0 : w = static_cast<int>(std::ceil(h*forceaspect));
364 : }
365 0 : getbackgroundres(w, h);
366 0 : gettextres(w, h);
367 :
368 0 : bool forcebackground = progressbackground || (mesa_swap_bug && (curvsync || totalmillis==1));
369 0 : if(background || forcebackground)
370 : {
371 0 : restorebackground(w, h, forcebackground);
372 : }
373 0 : renderprogressview(w, h, bar, text);
374 0 : swapbuffers(false);
375 : }
376 :
377 : static bool initwindowpos = false;
378 :
379 0 : void setfullscreen(bool enable)
380 : {
381 0 : if(!screen)
382 : {
383 0 : return;
384 : }
385 : //initwarning(enable ? "fullscreen" : "windowed");
386 0 : SDL_SetWindowFullscreen(screen, enable ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
387 0 : if(!enable)
388 : {
389 0 : SDL_SetWindowSize(screen, scr_w, scr_h);
390 0 : if(initwindowpos)
391 : {
392 0 : int winx = SDL_WINDOWPOS_CENTERED,
393 0 : winy = SDL_WINDOWPOS_CENTERED;
394 0 : SDL_SetWindowPosition(screen, winx, winy);
395 0 : initwindowpos = false;
396 : }
397 : }
398 : }
399 :
400 0 : VARF(fullscreen, 0, 1, 1, setfullscreen(fullscreen!=0));
401 :
402 : /* screenres: sets the window size to w * h pixels, or reduces fullscreen
403 : * resolution to w * h pixels
404 : *
405 : * arguments:
406 : * w: width of new screen res
407 : * h: height of new screen res
408 : */
409 1 : void screenres(int w, int h)
410 : {
411 : //need to cast enum to int for std's clamp implementation
412 1 : scr_w = std::clamp(w, static_cast<int>(SCR_MINW), static_cast<int>(SCR_MAXW));
413 1 : scr_h = std::clamp(h, static_cast<int>(SCR_MINH), static_cast<int>(SCR_MAXH));
414 1 : if(screen)
415 : {
416 0 : scr_w = std::min(scr_w, desktopw);
417 0 : scr_h = std::min(scr_h, desktoph);
418 0 : if(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN)
419 : {
420 0 : gl_resize();
421 : }
422 : else
423 : {
424 0 : SDL_SetWindowSize(screen, scr_w, scr_h);
425 : }
426 : }
427 : else
428 : {
429 1 : initwarning("screen resolution");
430 : }
431 1 : }
432 :
433 :
434 0 : static void setgamma(int val)
435 : {
436 0 : if(screen && SDL_SetWindowBrightness(screen, val/100.0f) < 0)
437 : {
438 0 : conoutf(Console_Error, "Could not set gamma: %s", SDL_GetError());
439 : }
440 0 : }
441 :
442 : static int curgamma = 100;
443 0 : static VARFNP(gamma, reqgamma, 30, 100, 300,
444 : {
445 : if(initing || reqgamma == curgamma)
446 : {
447 : return;
448 : }
449 : curgamma = reqgamma;
450 : setgamma(curgamma);
451 : });
452 :
453 : /* restoregamma: sets gamma to the previous set value, useful for reverting bad-
454 : * looking gamma trial settings
455 : *
456 : * used in iengine.h
457 : */
458 0 : void restoregamma()
459 : {
460 0 : if(initing || reqgamma == 100)
461 : {
462 0 : return;
463 : }
464 0 : curgamma = reqgamma;
465 0 : setgamma(curgamma);
466 : }
467 :
468 0 : void cleargamma()
469 : {
470 0 : if(curgamma != 100 && screen)
471 : {
472 0 : SDL_SetWindowBrightness(screen, 1.0f);
473 : }
474 0 : }
475 :
476 : void restorevsync(); //prototype to fix chicken-egg initialization problem caused by VARFP
477 :
478 0 : VARFP(vsync, 0, 0, 1, restorevsync()); //vertical sync of framebuffer to refresh rate
479 0 : VARFP(vsynctear, 0, 0, 1, { if(vsync) restorevsync(); }); //toggles sdl2's adaptive sync function
480 :
481 0 : void restorevsync()
482 : {
483 0 : if(initing || !glcontext)
484 : {
485 0 : return;
486 : }
487 0 : if(!SDL_GL_SetSwapInterval(vsync ? (vsynctear ? -1 : 1) : 0))
488 : {
489 0 : curvsync = vsync;
490 : }
491 : }
492 :
493 : //used in iengine.h
494 0 : void setupscreen()
495 : {
496 : //clear prior gl context/screen if present
497 0 : if(glcontext)
498 : {
499 0 : SDL_GL_DeleteContext(glcontext);
500 0 : glcontext = nullptr;
501 : }
502 0 : if(screen)
503 : {
504 0 : SDL_DestroyWindow(screen);
505 0 : screen = nullptr;
506 : }
507 0 : curvsync = -1;
508 :
509 : SDL_Rect desktop;
510 0 : if(SDL_GetDisplayBounds(0, &desktop) < 0)
511 : {
512 0 : fatal("failed querying desktop bounds: %s", SDL_GetError());
513 : }
514 0 : desktopw = desktop.w;
515 0 : desktoph = desktop.h;
516 :
517 0 : if(scr_h < 0)
518 : {
519 0 : scr_h = SCR_DEFAULTH;
520 : }
521 0 : if(scr_w < 0)
522 : {
523 0 : scr_w = (scr_h*desktopw)/desktoph;
524 : }
525 0 : scr_w = std::min(scr_w, desktopw);
526 0 : scr_h = std::min(scr_h, desktoph);
527 :
528 0 : int winx = SDL_WINDOWPOS_UNDEFINED,
529 0 : winy = SDL_WINDOWPOS_UNDEFINED,
530 0 : winw = scr_w,
531 0 : winh = scr_h,
532 0 : flags = SDL_WINDOW_RESIZABLE;
533 0 : if(fullscreen)
534 : {
535 0 : winw = desktopw;
536 0 : winh = desktoph;
537 0 : flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
538 0 : initwindowpos = true;
539 : }
540 :
541 0 : SDL_GL_ResetAttributes();
542 0 : SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
543 0 : SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
544 0 : SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
545 :
546 0 : uint32_t windowflags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS | flags;
547 : //create new screen title x y w h flags
548 0 : screen = SDL_CreateWindow("Imprimis", winx, winy, winw, winh, windowflags);
549 0 : ttr.initttf();
550 0 : ttr.openfont("media/interface/font/default.ttf", 24);
551 :
552 0 : if(!screen)
553 : {
554 0 : fatal("failed to create OpenGL window: %s", SDL_GetError());
555 : }
556 0 : SDL_Surface *icon = loadsurface("media/interface/icon.png"); //path to taskbar icon
557 0 : if(icon)
558 : {
559 0 : SDL_SetWindowIcon(screen, icon);
560 0 : SDL_FreeSurface(icon); //don't need it any more
561 : }
562 :
563 0 : SDL_SetWindowMinimumSize(screen, SCR_MINW, SCR_MINH);
564 0 : SDL_SetWindowMaximumSize(screen, SCR_MAXW, SCR_MAXH);
565 : //set opengl version to 4.0
566 0 : SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
567 0 : SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
568 : //set core profile
569 0 : SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
570 0 : glcontext = SDL_GL_CreateContext(screen);
571 :
572 : //
573 0 : GLenum err = glewInit();
574 0 : if (GLEW_OK != err)
575 : {
576 : /* Problem: glewInit failed, something is seriously wrong. */
577 0 : logoutf("Error: %s", glewGetErrorString(err));
578 : }
579 0 : logoutf("init: GLEW %s", glewGetString(GLEW_VERSION));
580 : //check if OpenGL context is sane
581 0 : if(!glcontext)
582 : {
583 0 : fatal("failed to create OpenGL context: %s", SDL_GetError());
584 : }
585 0 : SDL_GetWindowSize(screen, &screenw, &screenh);
586 0 : }
587 :
588 : //full reset of renderer
589 2 : void resetgl()
590 : {
591 2 : if(!glslversion)
592 : {
593 2 : conoutf(Console_Error, "Cannot reset GL without GL initialized, operation not performed");
594 2 : return;
595 : }
596 0 : clearchanges(Change_Graphics|Change_Shaders);
597 :
598 0 : renderbackground("resetting OpenGL");
599 :
600 0 : rootworld.cleanupva();
601 0 : cleanupparticles();
602 0 : cleanupstains();
603 0 : cleanupmodels();
604 0 : cleanupprefabs();
605 0 : cleanuptextures();
606 0 : cleanuplights();
607 0 : cleanupshaders();
608 0 : cleanupgl();
609 :
610 0 : setupscreen();
611 :
612 0 : inputgrab(grabinput);
613 :
614 0 : gl_init();
615 :
616 0 : inbetweenframes = false;
617 : //texture reloading
618 0 : if(!notexture->reload() ||
619 0 : !reloadtexture("<premul>media/interface/logo.png") ||
620 0 : !reloadtexture("<premul>media/interface/logo_1024.png") ||
621 0 : !reloadtexture("media/interface/background.png") ||
622 0 : !reloadtexture("media/interface/shadow.png") ||
623 0 : !reloadtexture("media/interface/mapshot_frame.png") ||
624 0 : !reloadtexture("media/interface/loading_frame.png") ||
625 0 : !reloadtexture("media/interface/loading_bar.png"))
626 : {
627 0 : fatal("failed to reload core texture");
628 : }
629 0 : reloadfonts();
630 0 : inbetweenframes = true;
631 0 : renderbackground("initializing...");
632 0 : restoregamma();
633 0 : restorevsync();
634 0 : initgbuffer();
635 0 : reloadshaders();
636 0 : reloadtextures();
637 0 : rootworld.allchanged(true);
638 : }
639 :
640 : /* limitfps: uses SDL_Delay to delay a frame, given the time the last frame was
641 : * rendered and the current time
642 : *
643 : * Arguments:
644 : * millis: the time (in ms) since program started
645 : * curmillis: the last registered frame time
646 : */
647 0 : void limitfps(int &millis, int curmillis)
648 : {
649 0 : int limit = (mainmenu || minimized) && menufps ? (maxfps ? std::min(maxfps, menufps) : menufps) : maxfps;
650 0 : if(!limit)
651 : {
652 0 : return;
653 : }
654 : static int fpserror = 0;
655 0 : int delay = 1000/limit - (millis-curmillis);
656 0 : if(delay < 0)
657 : {
658 0 : fpserror = 0;
659 : }
660 : else
661 : {
662 0 : fpserror += 1000%limit;
663 0 : if(fpserror >= limit)
664 : {
665 0 : ++delay;
666 0 : fpserror -= limit;
667 : }
668 0 : if(delay > 0)
669 : {
670 0 : SDL_Delay(delay);
671 0 : millis += delay;
672 : }
673 : }
674 : }
675 :
676 : #ifdef WIN32
677 : // Force Optimus setups to use the NVIDIA GPU
678 : // or also for AMD dual graphics
679 : extern "C"
680 : {
681 : #ifdef __GNUC__
682 : __attribute__((dllexport))
683 : #else
684 : __declspec(dllexport)
685 : #endif
686 : DWORD NvOptimusEnablement = 1;
687 :
688 : #ifdef __GNUC__
689 : __attribute__((dllexport))
690 : #else
691 : __declspec(dllexport)
692 : #endif
693 : DWORD AmdPowerXpressRequestHighPerformance = 1;
694 : }
695 : #endif
696 :
697 : static constexpr int maxfpshistory = 60;
698 :
699 : int fpspos = 0;
700 : std::array<int, maxfpshistory> fpshistory;
701 :
702 0 : void resetfpshistory()
703 : {
704 0 : fpshistory.fill(1);
705 0 : fpspos = 0;
706 0 : }
707 :
708 0 : void updatefpshistory(int millis)
709 : {
710 0 : fpshistory[fpspos++] = std::max(1, std::min(1000, millis));
711 0 : if(fpspos>=maxfpshistory)
712 : {
713 0 : fpspos = 0;
714 : }
715 0 : }
716 :
717 1 : void getfps(int &fps, int &bestdiff, int &worstdiff)
718 : {
719 1 : int total = fpshistory.at(maxfpshistory-1),
720 1 : best = total,
721 1 : worst = total;
722 61 : for(const int &millis : fpshistory)
723 : {
724 60 : total += millis;
725 60 : if(millis < best)
726 : {
727 0 : best = millis;
728 : }
729 60 : if(millis > worst)
730 : {
731 0 : worst = millis;
732 : }
733 : }
734 1 : if(total) //guard against div by 0
735 : {
736 0 : fps = (1000*maxfpshistory)/total;
737 0 : bestdiff = 1000/best-fps;
738 0 : worstdiff = fps-1000/worst;
739 : }
740 : else
741 : {
742 1 : fps = 0;
743 1 : bestdiff = 0;
744 1 : worstdiff = 0;
745 : }
746 1 : }
747 :
748 1 : void getfpscmd(const int *raw)
749 : {
750 1 : if(*raw)
751 : {
752 0 : floatret(1000.0f/fpshistory[(fpspos+maxfpshistory-1)%maxfpshistory]);
753 : }
754 : else
755 : {
756 : int fps, bestdiff, worstdiff;
757 1 : getfps(fps, bestdiff, worstdiff);
758 1 : intret(fps);
759 : }
760 1 : }
761 :
762 1 : void initrenderwindowcmds()
763 : {
764 1 : addcommand("getfps", reinterpret_cast<identfun>(getfpscmd), "i", Id_Command);
765 1 : addcommand("resetgl", reinterpret_cast<identfun>(resetgl), "", Id_Command);
766 1 : addcommand("screenres", reinterpret_cast<identfun>(screenres), "ii", Id_Command);
767 1 : }
|