LCOV - code coverage report
Current view: top level - engine/render - renderwindow.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 36 390 9.2 %
Date: 2024-11-22 05:07:59 Functions: 6 29 20.7 %

          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 : }

Generated by: LCOV version 1.14