Display.cpp 156 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define D3D_DEBUG 0
  6. #define FORCE_D3D9_3 0
  7. #define FORCE_D3D10_0 0
  8. #define FORCE_D3D10_1 0
  9. #define MAC_GL_MT 1 // enable multi threaded rendering, TODO: test on newer hardware if improves performance, all GL Contexts should have the same value, otherwise creating VAO's from VBO's on other threads could fail
  10. #if D3D_DEBUG || FORCE_D3D9_3 || FORCE_D3D10_0 || FORCE_D3D10_1
  11. #pragma message("!! Warning: Use this only for debugging !!")
  12. #endif
  13. #define FORCE_MAIN_DISPLAY (DX9 || WINDOWS && GL) // for DX9 and WindowsOpenGL we need to use the main screen
  14. #if 0
  15. #define LOG(x) LogN(x)
  16. #else
  17. #define LOG(x)
  18. #endif
  19. #define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF
  20. /******************************************************************************/
  21. Display D;
  22. #if DX9 // DirectX 9
  23. static IDirect3D9 *D3DBase;
  24. IDirect3DDevice9 *D3D;
  25. static IDirect3DQuery9 *Query;
  26. static D3DPRESENT_PARAMETERS D3DPP;
  27. #elif DX11 // DirectX 10/11
  28. #define GDI_COMPATIBLE 0 // requires DXGI_FORMAT_B8G8R8A8_UNORM
  29. static Bool AllowTearing;
  30. static UInt PresentFlags;
  31. ID3D11Device *D3D;
  32. ID3D11DeviceContext *D3DC;
  33. ID3D11DeviceContext1 *D3DC1;
  34. #if WINDOWS_OLD
  35. IDXGIFactory1 *Factory;
  36. IDXGISwapChain *SwapChain;
  37. DXGI_SWAP_CHAIN_DESC SwapChainDesc;
  38. #else
  39. IDXGIFactory2 *Factory;
  40. IDXGISwapChain1 *SwapChain;
  41. DXGI_SWAP_CHAIN_DESC1 SwapChainDesc;
  42. #endif
  43. IDXGIAdapter *Adapter;
  44. IDXGIOutput *Output;
  45. ID3D11Query *Query;
  46. D3D_FEATURE_LEVEL FeatureLevel;
  47. #elif GL // OpenGL
  48. #if WINDOWS
  49. static HDC hDC;
  50. #elif MAC
  51. NSOpenGLContext *OpenGLContext;
  52. #elif LINUX
  53. typedef void (*glXSwapIntervalType)(::Display *display, GLXDrawable drawable, int interval);
  54. static glXSwapIntervalType glXSwapInterval;
  55. ::Display *XDisplay;
  56. GLXFBConfig GLConfig;
  57. static int vid_modes=0;
  58. static XF86VidModeModeInfo **vid_mode=null;
  59. #elif ANDROID
  60. static EGLConfig GLConfig;
  61. static EGLDisplay GLDisplay;
  62. #endif
  63. GLContext MainContext;
  64. static Mems<GLContext> SecondaryContexts;
  65. static SyncLock ContextLock;
  66. static SyncCounter ContextUnlocked; // have to use counter and not event, because if there would be 2 unlocks at the same time while 2 other are waiting, then only 1 would get woken up with event
  67. UInt FBO, VAO;
  68. #if VARIABLE_MAX_MATRIX
  69. Bool MeshBoneSplit;
  70. #endif
  71. #endif
  72. #if WINDOWS_NEW
  73. Flt ScreenScale; // can't initialize here because crash will occur
  74. #elif IOS
  75. Flt ScreenScale=([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)] ? [UIScreen mainScreen].nativeScale : [UIScreen mainScreen].scale);
  76. #endif
  77. /******************************************************************************/
  78. static Bool ActualSync() {return D.sync() && !VR.active();} // we can synchronize only when not using VR, otherwise, it will handle synchronization based on the VR refresh rate
  79. /******************************************************************************/
  80. static Bool CustomMode;
  81. #if MAC
  82. extern NSOpenGLView *OpenGLView;
  83. static CGDisplayModeRef GetDisplayMode(Int width, Int height)
  84. {
  85. CFArrayRef modes=CGDisplayCopyAllDisplayModes(CGMainDisplayID(), null);
  86. CGDisplayModeRef ret=null;
  87. Flt refresh;
  88. REP(CFArrayGetCount(modes))
  89. {
  90. CGDisplayModeRef mode=(CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
  91. UInt flags=CGDisplayModeGetIOFlags(mode);
  92. Bool ok =FlagTest(flags, kDisplayModeSafetyFlags);
  93. if( ok)
  94. {
  95. Int w=CGDisplayModeGetWidth (mode),
  96. h=CGDisplayModeGetHeight (mode);
  97. Flt r=CGDisplayModeGetRefreshRate(mode);
  98. if(w==width && h==height)
  99. if(!ret || r>refresh) // choose highest refresh rate
  100. {
  101. ret =mode;
  102. refresh=r;
  103. }
  104. }
  105. }
  106. CFRelease(modes);
  107. return ret;
  108. }
  109. #endif
  110. Bool SetDisplayMode(Int mode)
  111. {
  112. Bool full=(D.full() && (mode==2 || mode==1 && App.active()));
  113. VecI2 size=(full ? D.res() : App.desktop());
  114. Bool same=(D.screen()==size);
  115. #if WINDOWS_OLD
  116. if(full)
  117. {
  118. if(same)return true;
  119. DEVMODE screen; Zero(screen);
  120. screen.dmSize =SIZE(DEVMODE);
  121. screen.dmPelsWidth =D.resW();
  122. screen.dmPelsHeight =D.resH();
  123. screen.dmDisplayFixedOutput=DMDFO_STRETCH; // this will stretch to entire screen if aspect ratio is not the same
  124. screen.dmFields =DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFIXEDOUTPUT;
  125. again:
  126. Int result=ChangeDisplaySettings(&screen, CDS_FULLSCREEN); if(result==DISP_CHANGE_SUCCESSFUL)
  127. {
  128. CustomMode=true;
  129. return true;
  130. }
  131. if(result==DISP_CHANGE_BADMODE && (screen.dmFields&DM_DISPLAYFIXEDOUTPUT)) // this can fail if trying to set the biggest resolution with stretching
  132. {FlagDisable(screen.dmFields, DM_DISPLAYFIXEDOUTPUT); screen.dmDisplayFixedOutput=0; goto again;} // try again without scaling
  133. }else
  134. {
  135. if(!CustomMode)return true;
  136. if(ChangeDisplaySettings(null, 0)==DISP_CHANGE_SUCCESSFUL)
  137. {
  138. CustomMode=false;
  139. return true;
  140. }
  141. }
  142. #elif MAC
  143. if(OpenGLView)
  144. {
  145. REPA(Ms._button)Ms.release(i); // Mac will not detect mouse button release if it was pressed during screen changing, so we need to disable it manually
  146. if([OpenGLView isInFullScreenMode])[OpenGLView exitFullScreenModeWithOptions:nil];
  147. // set screen mode
  148. Bool ok=false;
  149. if(same)ok=true;else
  150. if(CGDisplayModeRef mode=GetDisplayMode(size.x, size.y))
  151. ok=(CGDisplaySetDisplayMode(kCGDirectMainDisplay, mode, null)==noErr);
  152. if(ok && full)
  153. {
  154. #if 0
  155. ok=[OpenGLView enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
  156. #else
  157. NSApplicationPresentationOptions options=NSApplicationPresentationHideDock|NSApplicationPresentationHideMenuBar;
  158. ok=[OpenGLView enterFullScreenMode:[NSScreen mainScreen] withOptions:@{NSFullScreenModeApplicationPresentationOptions:@(options)}];
  159. #endif
  160. }
  161. return ok;
  162. }
  163. #elif LINUX
  164. if(XDisplay)
  165. {
  166. // set screen mode
  167. Bool ok=false;
  168. if(same)ok=true;else
  169. FREP(vid_modes)
  170. {
  171. XF86VidModeModeInfo &mode=*vid_mode[i];
  172. if(mode.hdisplay==size.x && mode.vdisplay==size.y)
  173. if(XF86VidModeSwitchToMode(XDisplay, DefaultScreen(XDisplay), &mode) && XFlush(XDisplay)){ok=true; break;}
  174. }
  175. return ok;
  176. }
  177. #endif
  178. return false;
  179. }
  180. #if WINDOWS_NEW
  181. void RequestDisplayMode(Int w, Int h, Int full)
  182. {
  183. if(full> 0)Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->TryEnterFullScreenMode();else
  184. if(full==0)Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->ExitFullScreenMode ();
  185. if(w>0 || h>0)
  186. {
  187. if(w<=0)w=D.resW();
  188. if(h<=0)h=D.resH();
  189. Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->TryResizeView(Windows::Foundation::Size(PixelsToDips(w), PixelsToDips(h)));
  190. }
  191. }
  192. #endif
  193. #if WINDOWS && GL
  194. static void glewSafe()
  195. {
  196. #define V(x, y, z) {if(!x)x=y; if(!x)Exit("OpenGL " z " function not supported.\nGraphics Driver not installed or better video card is required.");}
  197. V(glGenRenderbuffers , glGenRenderbuffersEXT , "glGenRenderbuffers")
  198. V(glDeleteRenderbuffers , glDeleteRenderbuffersEXT , "glDeleteRenderbuffers")
  199. V(glRenderbufferStorage , glRenderbufferStorageEXT , "glRenderbufferStorage")
  200. V(glGetRenderbufferParameteriv, glGetRenderbufferParameterivEXT, "glGetRenderbufferParameteriv")
  201. V(glBindRenderbuffer , glBindRenderbufferEXT , "glBindRenderbuffer")
  202. V(glGenFramebuffers , glGenFramebuffersEXT , "glGenFramebuffers")
  203. V(glDeleteFramebuffers , glDeleteFramebuffersEXT , "glDeleteFramebuffers")
  204. V(glBindFramebuffer , glBindFramebufferEXT , "glBindFramebuffer")
  205. V(glBlitFramebuffer , glBlitFramebufferEXT , "glBlitFramebuffer")
  206. #if DEBUG
  207. V(glCheckFramebufferStatus , glCheckFramebufferStatusEXT , "glCheckFramebufferStatus")
  208. #endif
  209. V(glFramebufferTexture2D , glFramebufferTexture2DEXT , "glFramebufferTexture2D")
  210. V(glFramebufferRenderbuffer , glFramebufferRenderbufferEXT , "glFramebufferRenderbuffer")
  211. V(glBlendColor , glBlendColorEXT , "glBlendColor")
  212. V(glBlendEquation , glBlendEquationEXT , "glBlendEquation")
  213. V(glBlendEquationSeparate , glBlendEquationSeparateEXT , "glBlendEquationSeparate")
  214. V(glBlendFuncSeparate , glBlendFuncSeparateEXT , "glBlendFuncSeparate")
  215. V(glColorMaski, glColorMaskIndexedEXT, "glColorMaski")
  216. #undef V
  217. }
  218. #endif
  219. /******************************************************************************/
  220. // GL CONTEXT
  221. /******************************************************************************/
  222. #if GL
  223. static Ptr GetCurrentContext()
  224. {
  225. #if WINDOWS
  226. return wglGetCurrentContext();
  227. #elif MAC
  228. return CGLGetCurrentContext();
  229. #elif LINUX
  230. return glXGetCurrentContext();
  231. #elif ANDROID
  232. return eglGetCurrentContext();
  233. #elif IOS
  234. return [EAGLContext currentContext];
  235. #elif WEB
  236. return (Ptr)emscripten_webgl_get_current_context();
  237. #endif
  238. }
  239. Bool GLContext::is()C
  240. {
  241. #if WEB
  242. return context!=NULL;
  243. #else
  244. return context!=null;
  245. #endif
  246. }
  247. GLContext::GLContext()
  248. {
  249. locked=false;
  250. #if WEB
  251. context=NULL;
  252. #else
  253. context=null;
  254. #endif
  255. #if ANDROID
  256. surface=null;
  257. #endif
  258. }
  259. void GLContext::del()
  260. {
  261. if(context)
  262. {
  263. #if WINDOWS
  264. wglMakeCurrent(null, null); wglDeleteContext(context); context=null;
  265. #elif MAC
  266. CGLDestroyContext(context); context=null;
  267. #elif LINUX
  268. if(XDisplay){glXMakeCurrent(XDisplay, NULL, NULL); glXDestroyContext(XDisplay, context);} context=null;
  269. #elif ANDROID
  270. if(GLDisplay){eglMakeCurrent(GLDisplay, null, null, null); eglDestroyContext(GLDisplay, context);} context=null;
  271. #elif IOS
  272. [EAGLContext setCurrentContext:null]; [context release]; context=null;
  273. #elif WEB
  274. emscripten_webgl_destroy_context(context); context=NULL;
  275. #endif
  276. }
  277. #if ANDROID
  278. if(surface){if(GLDisplay)eglDestroySurface(GLDisplay, surface); surface=null;}
  279. #endif
  280. }
  281. Bool GLContext::createSecondary()
  282. {
  283. #if WINDOWS
  284. if(context=wglCreateContext(hDC))if(!wglShareLists(MainContext.context, context))return false;
  285. #elif MAC
  286. CGLCreateContext(CGLGetPixelFormat(MainContext.context), MainContext.context, &context);
  287. #elif LINUX
  288. context=glXCreateNewContext(XDisplay, GLConfig, GLX_RGBA_TYPE, MainContext.context, true);
  289. #elif ANDROID
  290. EGLint attribs[]={EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
  291. if(surface=eglCreatePbufferSurface(GLDisplay, GLConfig, attribs))
  292. {
  293. EGLint ctx_attribs[]={EGL_CONTEXT_CLIENT_VERSION, (D.shaderModel()==SM_GL_ES_3) ? 3 : 2, EGL_NONE};
  294. context=eglCreateContext(GLDisplay, GLConfig, MainContext.context, ctx_attribs);
  295. }
  296. #elif IOS
  297. context=[[EAGLContext alloc] initWithAPI:[MainContext.context API] sharegroup:[MainContext.context sharegroup]];
  298. #elif WEB
  299. // currently WEB is not multi-threaded
  300. #if HAS_THREADS
  301. add support
  302. #endif
  303. #endif
  304. if(context)
  305. {
  306. lock();
  307. // these settings are per-context
  308. #if MAC && MAC_GL_MT
  309. Bool mt_ok=(CGLEnable(context, kCGLCEMPEngine)!=kCGLNoError);
  310. #endif
  311. glPixelStorei(GL_PACK_ALIGNMENT , 1);
  312. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  313. unlock(); // to clear 'locked'
  314. return true;
  315. }
  316. return false;
  317. }
  318. void GLContext::lock()
  319. {
  320. #if WINDOWS
  321. if(wglMakeCurrent(hDC, context))
  322. #elif MAC
  323. if(CGLSetCurrentContext(context)==kCGLNoError)
  324. #elif LINUX
  325. if(glXMakeCurrent(XDisplay, App.Hwnd(), context))
  326. #elif ANDROID
  327. if(eglMakeCurrent(GLDisplay, surface, surface, context)==EGL_TRUE)
  328. #elif IOS
  329. if([EAGLContext setCurrentContext:context]==YES)
  330. #elif WEB
  331. if(emscripten_webgl_make_context_current(context)==EMSCRIPTEN_RESULT_SUCCESS)
  332. #endif
  333. {
  334. locked=true;
  335. }else
  336. {
  337. Exit("Can't activate OpenGL Context.");
  338. }
  339. }
  340. void GLContext::unlock()
  341. {
  342. #if WINDOWS
  343. if(wglMakeCurrent(hDC, null))
  344. #elif MAC
  345. if(CGLSetCurrentContext(null)==kCGLNoError)
  346. #elif LINUX
  347. if(glXMakeCurrent(XDisplay, NULL, NULL))
  348. #elif ANDROID
  349. if(eglMakeCurrent(GLDisplay, null, null, null)==EGL_TRUE)
  350. #elif IOS
  351. if([EAGLContext setCurrentContext:null]==YES)
  352. #elif WEB
  353. if(emscripten_webgl_make_context_current(NULL)==EMSCRIPTEN_RESULT_SUCCESS)
  354. #endif
  355. {
  356. locked=false;
  357. }else
  358. {
  359. Exit("Can't deactivate OpenGL Context.");
  360. }
  361. }
  362. #endif
  363. /******************************************************************************/
  364. // DISPLAY
  365. /******************************************************************************/
  366. VecI2 Display::screen()C
  367. {
  368. #if WINDOWS_OLD
  369. return VecI2(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
  370. #elif WINDOWS_NEW
  371. IDXGIOutput *output=null;
  372. if(SwapChain)
  373. {
  374. SyncLocker locker(_lock); if(SwapChain)SwapChain->GetContainingOutput(&output);
  375. }
  376. if(!output)
  377. {
  378. IDXGIFactory1 *factory=null; CreateDXGIFactory1(__uuidof(IDXGIFactory1), (Ptr*)&factory); if(factory)
  379. {
  380. IDXGIAdapter *adapter=null; factory->EnumAdapters(0, &adapter); if(adapter)
  381. {
  382. adapter->EnumOutputs(0, &output);
  383. adapter->Release();
  384. }
  385. factory->Release();
  386. }
  387. }
  388. if(output)
  389. {
  390. VecI2 size=-1; DXGI_OUTPUT_DESC desc; if(OK(output->GetDesc(&desc)))size.set(desc.DesktopCoordinates.right-desc.DesktopCoordinates.left, desc.DesktopCoordinates.bottom-desc.DesktopCoordinates.top);
  391. output->Release();
  392. if(size.x>=0)return size;
  393. }
  394. #elif MAC
  395. if(CGDisplayModeRef mode=CGDisplayCopyDisplayMode(kCGDirectMainDisplay))
  396. {
  397. VecI2 s(CGDisplayModeGetWidth(mode), CGDisplayModeGetHeight(mode));
  398. CGDisplayModeRelease(mode);
  399. return s;
  400. }
  401. #elif LINUX
  402. if(XDisplay)
  403. {
  404. int clock; XF86VidModeModeLine mode; if(XF86VidModeGetModeLine(XDisplay, DefaultScreen(XDisplay), &clock, &mode))return VecI2(mode.hdisplay, mode.vdisplay);
  405. Screen *screen=DefaultScreenOfDisplay(XDisplay); return VecI2(WidthOfScreen(screen), HeightOfScreen(screen));
  406. }
  407. #elif ANDROID // fall down to the App.desktop()
  408. #elif IOS
  409. CGSize size;
  410. if([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)])
  411. {
  412. size=[[UIScreen mainScreen] nativeBounds].size; // 'nativeBounds' is not changed when device is rotated
  413. }else
  414. {
  415. size=[[UIScreen mainScreen] bounds].size; // 'bounds' is changed when device is rotated
  416. size.width *=ScreenScale;
  417. size.height*=ScreenScale;
  418. }
  419. return VecI2(RoundPos(size.width), RoundPos(size.height));
  420. #elif WEB
  421. return VecI2(JavaScriptRunI("screen.width"), JavaScriptRunI("screen.height")); // it's not possible to get correct results, because on Chrome: this value is adjusted by "System DPI/Scaling", but not 'D.browserZoom', and does not change when zooming. Because "System DPI/Scaling" is unknown, it can't be calculated.
  422. #endif
  423. return App.desktop(); // this is not changed when device is rotated (obtained at app startup)
  424. }
  425. /******************************************************************************/
  426. void Display::setShader(C Material *material)
  427. {
  428. if(created())
  429. {
  430. _set_shader_material=material;
  431. {Meshes .lock(); REPA(Meshes )Meshes .lockedData(i).setShader(); Meshes .unlock();}
  432. {ClothMeshes.lock(); REPA(ClothMeshes)ClothMeshes.lockedData(i).setShader(); ClothMeshes.unlock();}
  433. if(set_shader)set_shader();
  434. _set_shader_material=null;
  435. }
  436. }
  437. Display& Display::drawNullMaterials(Bool on)
  438. {
  439. if(_draw_null_mtrl!=on)
  440. {
  441. _draw_null_mtrl=on;
  442. setShader();
  443. }
  444. return T;
  445. }
  446. void Display::screenChanged(Flt old_width, Flt old_height)
  447. {
  448. if(old_width>0 && old_height>0)
  449. {
  450. Gui.screenChanged(old_width, old_height);
  451. if(screen_changed)screen_changed(old_width, old_height);
  452. }
  453. }
  454. #if DX9
  455. Bool Display::validUsage(UInt usage, D3DRESOURCETYPE res_type, Int image_type)
  456. {
  457. if(D3DBase)
  458. {
  459. D3DFORMAT format=ImageTypeToFormat(image_type);
  460. return OK(D3DBase->CheckDeviceFormat(D3DADAPTER_DEFAULT, _no_gpu ? D3DDEVTYPE_NULLREF : D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, usage, res_type, format))
  461. || OK(D3DBase->CheckDeviceFormat(D3DADAPTER_DEFAULT, _no_gpu ? D3DDEVTYPE_NULLREF : D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, usage, res_type, format));
  462. }
  463. return false;
  464. }
  465. #endif
  466. Str8 Display::shaderModelName()C
  467. {
  468. switch(shaderModel())
  469. {
  470. default : return "Unknown"; // SM_UNKNOWN
  471. case SM_GL_ES_2: return "GL ES 2";
  472. case SM_GL_ES_3: return "GL ES 3";
  473. case SM_GL : return "GL";
  474. case SM_3 : return "3";
  475. case SM_4 : return "4";
  476. case SM_4_1 : return "4.1";
  477. case SM_5 : return "5";
  478. }
  479. }
  480. Str8 Display::apiName()C
  481. {
  482. #if DX9
  483. return "DirectX 9";
  484. #elif DX11
  485. return "DirectX 11";
  486. #elif DX12
  487. return "DirectX 12";
  488. #elif METAL
  489. return "Metal";
  490. #elif VULKAN
  491. return "Vulkan";
  492. #elif WEB // check this first before 'GL' and 'GL_ES'
  493. return "Web GL";
  494. #elif GL_ES // check this first before 'GL'
  495. return "OpenGL ES";
  496. #elif GL
  497. return "OpenGL";
  498. #endif
  499. }
  500. Bool Display::smallSize()C
  501. {
  502. #if WINDOWS_NEW
  503. Dbl inches; if(OK(GetIntegratedDisplaySize(&inches)))return inches<7;
  504. #elif ANDROID
  505. Int size=((AndroidApp && AndroidApp->config) ? AConfiguration_getScreenSize(AndroidApp->config) : ACONFIGURATION_SCREENSIZE_NORMAL);
  506. return size==ACONFIGURATION_SCREENSIZE_SMALL || size==ACONFIGURATION_SCREENSIZE_NORMAL;
  507. // HTC EVO 3D ( 4 inch) has ACONFIGURATION_SCREENSIZE_NORMAL
  508. // Samsung Galaxy Note 2 ( 5.5 inch) has ACONFIGURATION_SCREENSIZE_NORMAL
  509. // Asus Transformer Prime (10 inch) has ACONFIGURATION_SCREENSIZE_XLARGE
  510. #elif IOS
  511. // UI_USER_INTERFACE_IDIOM UIUserInterfaceIdiomPhone UIUserInterfaceIdiomPad
  512. return UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone;
  513. #endif
  514. return false;
  515. }
  516. Flt Display::browserZoom()C
  517. {
  518. #if WEB
  519. return emscripten_get_device_pixel_ratio();
  520. #else
  521. return 1;
  522. #endif
  523. }
  524. Bool Display::deferredUnavailable ()C {return created() && _max_rt<2 ;} // deferred requires at least 2 MRT's (#0 Color, #1 Nrm, #2 Vel optional)
  525. Bool Display::deferredMSUnavailable()C {return created() && shaderModel()<SM_4_1;} // only Shader Model 4.1 (DX 10.1) and above support multi-sampled RT's
  526. /******************************************************************************/
  527. // MONITOR
  528. /******************************************************************************/
  529. Display::Monitor::Monitor()
  530. {
  531. primary=false;
  532. full=work.zero();
  533. }
  534. #if WINDOWS_OLD
  535. Bool Display::Monitor::set(HMONITOR monitor)
  536. {
  537. MONITORINFO monitor_info; Zero(monitor_info); monitor_info.cbSize=SIZE(monitor_info);
  538. if(GetMonitorInfo(monitor, &monitor_info))
  539. {
  540. full.set(monitor_info.rcMonitor.left, monitor_info.rcMonitor.top, monitor_info.rcMonitor.right, monitor_info.rcMonitor.bottom);
  541. work.set(monitor_info.rcWork .left, monitor_info.rcWork .top, monitor_info.rcWork .right, monitor_info.rcWork .bottom);
  542. primary=FlagTest(monitor_info.dwFlags, MONITORINFOF_PRIMARY);
  543. return true;
  544. }
  545. return false;
  546. }
  547. static BOOL CALLBACK EnumMonitors(HMONITOR hmonitor, HDC dc, LPRECT rect, LPARAM dwData) {D._monitors.get(hmonitor); return true;} // continue
  548. #elif WINDOWS_NEW
  549. void Display::Monitor::set(C DXGI_OUTPUT_DESC &desc)
  550. {
  551. primary=false;
  552. full=work.set(desc.DesktopCoordinates.left, desc.DesktopCoordinates.top, desc.DesktopCoordinates.right, desc.DesktopCoordinates.bottom);
  553. }
  554. #endif
  555. static Bool Create(Display::Monitor &monitor, C Ptr &hmonitor, Ptr user)
  556. {
  557. #if WINDOWS_OLD
  558. return monitor.set(HMONITOR(hmonitor));
  559. #else
  560. return true;
  561. #endif
  562. }
  563. void Display::monitor(RectI &full, RectI &work, VecI2 &max_normal_win_client_size, VecI2 &maximized_win_client_size, C Monitor *monitor)C
  564. {
  565. if(monitor)
  566. {
  567. full=monitor->full;
  568. work=monitor->work;
  569. }else
  570. {
  571. full.set(0, 0, App.desktopW(), App.desktopH());
  572. work=App.desktopArea();
  573. }
  574. max_normal_win_client_size.set(full.w()-App._bound.w(), full.h()-App._bound.h());
  575. maximized_win_client_size.set(work.w()+App._bound_maximized.min.x+App._bound_maximized.max.x, work.h()+App._bound_maximized.min.y+App._bound_maximized.max.y);
  576. }
  577. void Display::curMonitor(RectI &full, RectI &work, VecI2 &max_normal_win_client_size, VecI2 &maximized_win_client_size)
  578. {
  579. Monitor *monitor=null;
  580. #if WINDOWS_OLD
  581. if(App.hwnd()) // adjust to current monitor
  582. {
  583. #if 1
  584. if(HMONITOR hmonitor=MonitorFromWindow(App.Hwnd(), MONITOR_DEFAULTTONEAREST))
  585. #else
  586. RectI win_rect=WindowRect(false); // watch out because 'WindowRect' can return weird position when the window is minimized
  587. POINT p; p.x=win_rect.centerXI(); p.y=win_rect.centerYI();
  588. if(HMONITOR hmonitor=MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST))
  589. #endif
  590. monitor=_monitors.get(hmonitor);
  591. }
  592. #elif WINDOWS_NEW
  593. if(SwapChain)
  594. {
  595. IDXGIOutput *output=null;
  596. {
  597. SyncLocker locker(_lock);
  598. if(SwapChain)SwapChain->GetContainingOutput(&output);
  599. }
  600. if(output)
  601. {
  602. DXGI_OUTPUT_DESC desc; if(OK(output->GetDesc(&desc)))
  603. {
  604. monitor=_monitors.get(desc.Monitor);
  605. if(monitor && !monitor->full.w())monitor->set(desc);
  606. }
  607. output->Release();
  608. }
  609. }
  610. #endif
  611. T.monitor(full, work, max_normal_win_client_size, maximized_win_client_size, monitor);
  612. }
  613. void Display::mainMonitor(RectI &full, RectI &work, VecI2 &max_normal_win_client_size, VecI2 &maximized_win_client_size)C
  614. {
  615. C Monitor *main=null;
  616. REPA(_monitors){C Monitor &monitor=_monitors[i]; if(monitor.primary){main=&monitor; break;}}
  617. monitor(full, work, max_normal_win_client_size, maximized_win_client_size, main);
  618. }
  619. /******************************************************************************/
  620. // MANAGE
  621. /******************************************************************************/
  622. Display::Display() : _monitors(Compare, Create, null, 4)
  623. {
  624. _full =MOBILE; // by default request fullscreen for MOBILE, on WINDOWS_PHONE this will hide the navigation bar
  625. _sync =true;
  626. _exclusive =true;
  627. _hp_col_rt =false;
  628. _hp_nrm_rt =false;
  629. _hp_lum_rt =false;
  630. _hp_nrm_calc =true;
  631. _dither =true;
  632. _mtrl_blend =true;
  633. _device_mem =-1;
  634. _monitor_prec =IMAGE_PRECISION_8;
  635. _lit_col_rt_prec =IMAGE_PRECISION_8;
  636. _aspect_mode =(MOBILE ? ASPECT_SMALLER : ASPECT_Y);
  637. _tex_filter =(MOBILE ? 2 : 16);
  638. _tex_mip_filter =!MOBILE;
  639. _tex_detail =(MOBILE ? TEX_USE_DISABLE : TEX_USE_MULTI);
  640. _density_filter =(MOBILE ? FILTER_LINEAR : FILTER_CUBIC_FAST);
  641. _tex_lod =0;
  642. _tex_macro =true;
  643. _tex_reflect =TEX_USE_MULTI;
  644. _font_sharpness =0.75f;
  645. _bend_leafs =true;
  646. _particles_soft =!MOBILE;
  647. _particles_smooth=!MOBILE;
  648. _initialized=false;
  649. _resetting =false;
  650. _began =false;
  651. _allow_stereo=true;
  652. _density=127;
  653. _samples=1;
  654. _scale=1;
  655. _aspect_ratio=_aspect_ratio_want=_pixel_aspect=0;
  656. _pixel_size=_pixel_size_2=_pixel_size_inv=0;
  657. _window_pixel_to_screen_mul=1; // init to 1 to avoid div by 0 at app startup which could cause crash on Web
  658. _window_pixel_to_screen_add=0;
  659. _window_pixel_to_screen_scale=1;
  660. _amb_mode =AMBIENT_FLAT;
  661. _amb_soft =1;
  662. _amb_jitter =true;
  663. _amb_normal =true;
  664. _amb_res =FltToByteScale(0.5f);
  665. _amb_color =0.4f;
  666. _amb_contrast=1.2f;
  667. _amb_range =0.3f;
  668. _amb_scale =2.5f;
  669. _amb_bias =0.3f;
  670. _ns_color.zero();
  671. _vol_light=false;
  672. _vol_add =false;
  673. _vol_max =1.0;
  674. _shd_mode =(MOBILE ? SHADOW_NONE : SHADOW_MAP);
  675. _shd_soft =0;
  676. _shd_jitter =false;
  677. _shd_reduce =false;
  678. _shd_frac =1;
  679. _shd_fade =1;
  680. _shd_map_num =6;
  681. _shd_map_size =1024;
  682. _shd_map_size_actual=0;
  683. _shd_map_size_l =1;
  684. _shd_map_size_c =1;
  685. _shd_map_split .set(2, 1);
  686. _cld_map_size =128;
  687. _bump_mode=(MOBILE ? BUMP_FLAT : BUMP_PARALLAX);
  688. _mtn_mode =MOTION_NONE;
  689. _mtn_dilate=DILATE_ORTHO2;
  690. _mtn_scale =0.04f;
  691. _mtn_res =FltToByteScale(1.0f/3);
  692. _dof_mode =DOF_NONE;
  693. _dof_foc_mode =false;
  694. //_dof_focus =0;
  695. _dof_range =30;
  696. _dof_intensity=1;
  697. _eye_adapt =false;
  698. _eye_adapt_brightness=0.37f;
  699. _eye_adapt_max_dark =0.5f;
  700. _eye_adapt_max_bright=2.0f;
  701. _eye_adapt_speed =6.5f;
  702. _eye_adapt_weight.set(0.9f, 1, 0.7f); // use smaller value for blue, to make blue skies have brighter multiplier, because human eye sees blue color as darker than others
  703. _grass_range =50;
  704. _grass_density=(MOBILE ? 0.5f : 1);
  705. _grass_shadow =false;
  706. _grass_mirror =false;
  707. _bloom_original=1.0f;
  708. _bloom_scale =0.5f;
  709. _bloom_cut =0.3f;
  710. _bloom_blurs =1;
  711. _bloom_sat =false;
  712. _bloom_max =false;
  713. _bloom_half =!MOBILE;
  714. _bloom_samples =!MOBILE;
  715. _bloom_allow=!MOBILE;
  716. _glow_allow=!MOBILE;
  717. _color_palette_allow=!MOBILE;
  718. _lod_factor =1;
  719. _lod_factor_shadow=2;
  720. _lod_factor_mirror=2;
  721. _tesselation =false;
  722. _tesselation_allow =true;
  723. _tesselation_heightmap=false;
  724. _tesselation_density =60;
  725. _outline_sky =false;
  726. _outline_mode=EDGE_DETECT_THIN;
  727. _edge_detect =EDGE_DETECT_NONE;
  728. _edge_soften =EDGE_SOFTEN_NONE;
  729. _fur_gravity =-1 ;
  730. _fur_vel_scale=-0.75f;
  731. _eye_dist =0.064f;
  732. _view_square_pixel =false;
  733. _view_main.fov_mode=FOV_Y;
  734. _view_fov =
  735. _view_main.fov.x =
  736. _view_main.fov.y =DegToRad(70);
  737. _view_main.from =_view_from=0.05f;
  738. _view_main.range =100;
  739. _view_main.full =true; // needed for 'viewReset' which will always set full viewport if last was full too
  740. _smaa_threshold=0.1f;
  741. }
  742. void Display::init() // make this as a method because if we put this to Display constructor, then 'SecondaryContexts' may not have been initialized yet
  743. {
  744. secondaryOpenGLContexts(1); // default 1 secondary context
  745. // re-use cached result obtained at app startup, because if the app is currently fullscreen at a custom resolution, then the monitor will return that resolution, however this function is used for getting default resolutions
  746. #if WINDOWS_OLD
  747. EnumDisplayMonitors(null, null, EnumMonitors, 0); // list all monitors at app startup so we can know their original sizes
  748. #elif WINDOWS_NEW
  749. IDXGIFactory1 *factory=null; CreateDXGIFactory1(__uuidof(IDXGIFactory1), (Ptr*)&factory); if(factory)
  750. {
  751. IDXGIAdapter *adapter=null; factory->EnumAdapters(0, &adapter); if(adapter)
  752. {
  753. for(Int i=0; ; i++)
  754. {
  755. IDXGIOutput *output=null; adapter->EnumOutputs(i, &output); if(output)
  756. {
  757. DXGI_OUTPUT_DESC desc; if(OK(output->GetDesc(&desc)))_monitors.get(desc.Monitor)->set(desc);
  758. output->Release();
  759. }else break;
  760. }
  761. adapter->Release();
  762. }
  763. factory->Release();
  764. }
  765. #endif
  766. }
  767. /******************************************************************************/
  768. void Display::del()
  769. {
  770. Gui.del(); // deleting Gui should be outside of '_lock' lock (because for example it can wait for a thread working in the background which is using '_lock')
  771. SyncLocker locker(_lock);
  772. _initialized=false;
  773. gamma(0); // reset gamma when closing app
  774. end();
  775. VR.delImages();
  776. ShutFont();
  777. ShutVtxInd();
  778. DisplayState::del();
  779. Sh.del();
  780. Renderer.del();
  781. Images.del();
  782. _modes.del();
  783. #if DX9
  784. RELEASE(Query );
  785. RELEASE(D3D );
  786. RELEASE(D3DBase);
  787. #elif DX11
  788. if(SwapChain)SwapChain->SetFullscreenState(false, null); // full screen state must be first disabled, according to http://msdn.microsoft.com/en-us/library/windows/desktop/bb205075(v=vs.85).aspx#Destroying
  789. RELEASE(SwapChain);
  790. RELEASE(Output);
  791. RELEASE(Adapter);
  792. RELEASE(Factory);
  793. RELEASE(Query);
  794. RELEASE(D3DC1);
  795. RELEASE(D3DC);
  796. RELEASE(D3D);
  797. #elif GL
  798. if(FBO){glDeleteFramebuffers(1, &FBO); FBO=0;}
  799. if(VAO){glDeleteVertexArrays(1, &VAO); VAO=0;}
  800. SecondaryContexts.del();
  801. MainContext .del();
  802. #if WINDOWS
  803. if(hDC){ReleaseDC(App.Hwnd(), hDC); hDC=null;}
  804. SetDisplayMode(0); // switch back to the desktop
  805. #elif MAC
  806. [OpenGLContext release]; OpenGLContext=null;
  807. #elif LINUX
  808. SetDisplayMode(0); // switch back to the desktop
  809. if(vid_mode){XFree(vid_mode); vid_mode=null;} vid_modes=0; // free after 'SetDisplayMode'
  810. #elif ANDROID
  811. if(GLDisplay){eglTerminate(GLDisplay); GLDisplay=null;}
  812. #endif
  813. #endif
  814. }
  815. /******************************************************************************/
  816. #if DX9
  817. // codes used for detecting GPU VRAM
  818. #define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L
  819. typedef BOOL (FAR PASCAL*LPDDENUMCALLBACKEXA)(GUID FAR *, LPSTR, LPSTR, LPVOID, HMONITOR);
  820. typedef HRESULT (WINAPI*LPDIRECTDRAWENUMERATEEXA)(LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags);
  821. typedef BOOL (WINAPI*PfnCoSetProxyBlanket)(IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities);
  822. static CLSID CLSID_WbemLocator={0x4590F811, 0x1D3A, 0x11D0, {0x89, 0x1F, 0, 0xAA, 0, 0x4B, 0x2E, 0x24}};
  823. static GUID IID_IWbemLocator={0xDC12A687, 0x737F, 0x11CF, {0x88, 0x4D, 0, 0xAA, 0, 0x4B, 0x2E, 0x24}};
  824. struct Match
  825. {
  826. HMONITOR monitor;
  827. Char8 driver_name[512];
  828. Bool found;
  829. Match(HMONITOR monitor) : monitor(monitor) {found=false; driver_name[0]=0;}
  830. };
  831. static BOOL WINAPI DDEnumCallbackEx(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm)
  832. {
  833. Match &match=*(Match*)lpContext;
  834. if(match.monitor==hm)
  835. {
  836. match.found=true;
  837. Set(match.driver_name, lpDriverName);
  838. return false; // stop enumerating
  839. }
  840. return true; // keep looking
  841. }
  842. static Bool GetDeviceIDFromHMonitor(HMONITOR hm, WCHAR *strDeviceID, int cchDeviceID)
  843. {
  844. DLL ddraw;
  845. if( ddraw.createFile(u"Ddraw.dll"))
  846. if(LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateEx=(LPDIRECTDRAWENUMERATEEXA)ddraw.getFunc("DirectDrawEnumerateExA"))
  847. {
  848. Match match(hm); DirectDrawEnumerateEx(DDEnumCallbackEx, &match, DDENUM_ATTACHEDSECONDARYDEVICES);
  849. if(match.found)
  850. {
  851. DISPLAY_DEVICEA dispdev; Zero(dispdev); dispdev.cb=SIZE(dispdev);
  852. for(Int i=0; EnumDisplayDevicesA(null, i, &dispdev, 0); i++)
  853. if(!(dispdev.StateFlags&DISPLAY_DEVICE_MIRRORING_DRIVER ) // skip devices that are monitors that echo another display
  854. && (dispdev.StateFlags&DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) // process only devices that are attached
  855. && Equal(match.driver_name, dispdev.DeviceName))
  856. {
  857. MultiByteToWideChar(CP_ACP, 0, dispdev.DeviceID, -1, strDeviceID, cchDeviceID);
  858. return true;
  859. }
  860. }
  861. }
  862. return false;
  863. }
  864. static Long DeviceMemory(Int adapter_index)
  865. {
  866. Long size=-1;
  867. if(HMONITOR monitor=D3DBase->GetAdapterMonitor(adapter_index))
  868. {
  869. WCHAR strInputDeviceID[1024];
  870. if(GetDeviceIDFromHMonitor(monitor, strInputDeviceID, Elms(strInputDeviceID)))
  871. {
  872. IWbemLocator *pIWbemLocator=null; CoCreateInstance(CLSID_WbemLocator, null, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (Ptr*)&pIWbemLocator);
  873. if( pIWbemLocator)
  874. {
  875. // Using the locator, connect to WMI in the given namespace
  876. BSTR Namespace=SysAllocString(L"\\\\.\\root\\cimv2");
  877. IWbemServices *pIWbemServices=null; pIWbemLocator->ConnectServer(Namespace, null, null, 0, 0, null, null, &pIWbemServices);
  878. if( pIWbemServices)
  879. {
  880. DLL ole;
  881. if( ole.createFile(u"Ole32.dll"))
  882. if(PfnCoSetProxyBlanket pfnCoSetProxyBlanket=(PfnCoSetProxyBlanket)ole.getFunc("CoSetProxyBlanket"))
  883. pfnCoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, null, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, null, 0); // Switch security level to IMPERSONATE
  884. BSTR Win32_VideoController=SysAllocString(L"Win32_VideoController");
  885. IEnumWbemClassObject *pEnumVideoControllers=null; pIWbemServices->CreateInstanceEnum(Win32_VideoController, 0, null, &pEnumVideoControllers);
  886. if( pEnumVideoControllers)
  887. {
  888. BSTR PNPDeviceID=SysAllocString(L"PNPDeviceID"),
  889. AdapterRAM=SysAllocString(L"AdapterRAM");
  890. IWbemClassObject *video_controllers[16]={0};
  891. DWORD returned=0;
  892. Bool found=false;
  893. pEnumVideoControllers->Reset(); // Get the first one in the list
  894. if(OK(pEnumVideoControllers->Next(5000, Elms(video_controllers), video_controllers, &returned))) // 5 second timeout
  895. {
  896. FREP(returned)if(IWbemClassObject *controller=video_controllers[i])
  897. {
  898. if(!found)
  899. {
  900. VARIANT var;
  901. if(OK(controller->Get(PNPDeviceID, 0, &var, null, null)))if(wcsstr(var.bstrVal, strInputDeviceID))found=true;
  902. VariantClear(&var);
  903. if(found)
  904. {
  905. if(OK(controller->Get(AdapterRAM, 0, &var, null, null)))size=var.ulVal;
  906. VariantClear(&var);
  907. }
  908. }
  909. controller->Release();
  910. }
  911. }
  912. if(AdapterRAM )SysFreeString(AdapterRAM);
  913. if(PNPDeviceID)SysFreeString(PNPDeviceID);
  914. pEnumVideoControllers->Release();
  915. }
  916. if(Win32_VideoController)SysFreeString(Win32_VideoController);
  917. pIWbemServices->Release();
  918. }
  919. if(Namespace)SysFreeString(Namespace);
  920. pIWbemLocator->Release();
  921. }
  922. }
  923. }
  924. return size;
  925. }
  926. #endif
  927. void Display::createDevice()
  928. {
  929. if(LogInit)LogN("Display.createDevice");
  930. SyncLocker locker(_lock);
  931. #if DX9
  932. if(!(D3DBase=Direct3DCreate9(D3D_SDK_VERSION)))Exit(MLTC(u"Direct3D not found.\nPlease install the newest DirectX.", PL,u"Direct3D nie odnaleziony.\nProszę zainstalować najnowszy DirectX."));
  933. // get device description
  934. if(!deviceName().is()){D3DADAPTER_IDENTIFIER9 id; if(OK(D3DBase->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &id)))_device_name=id.Description;}
  935. // check required capabilites
  936. D3DCAPS9 caps; D3DBase->GetDeviceCaps(0, D3DDEVTYPE_HAL, &caps);
  937. if(caps.PrimitiveMiscCaps&D3DPMISCCAPS_NULLREFERENCE)Exit(MLTC(u"Video Card supporting minimum requirements not found.", PL,u"Nie odnaleziono karty graficznej spełniającej minimalne wymagania."));
  938. Int vs_ver =D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion),
  939. ps_ver =D3DSHADER_VERSION_MAJOR(caps. PixelShaderVersion);
  940. _shader_model=((ps_ver>=3) ? SM_3 : SM_UNKNOWN);
  941. if(shaderModel()<SM_3)if(!(App.flag&APP_ALLOW_NO_GPU))Exit(MLTC(u"Minimum Shader Model 3.0 required.\nA better video card or installing drivers is required.",
  942. PL, u"Minimum Shader Model 3.0 wymagany.\nWymagana jest lepsza kart graficzna lub doinstalowanie sterowników."));
  943. // set create options
  944. UInt flag=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  945. if((caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT) && vs_ver>=ps_ver) // use hardware vertex processing only if HW T&L and VS ver matches PS ver (in HW)
  946. {
  947. #if 1
  948. flag=D3DCREATE_MIXED_VERTEXPROCESSING; // this was tested and results in better performance for dynamic vertex buffers than D3DCREATE_HARDWARE_VERTEXPROCESSING, TODO: however https://msdn.microsoft.com/en-us/library/windows/desktop/bb172527(v=vs.85).aspx mentions that on Win10 this should be avoided, however tests are inconclusive, check again in the future using "Tests/Vertex Buffering.cpp"
  949. #else
  950. flag=D3DCREATE_HARDWARE_VERTEXPROCESSING;
  951. if(caps.DevCaps&D3DDEVCAPS_PUREDEVICE)flag|=D3DCREATE_PUREDEVICE; // this requires D3DCREATE_HARDWARE_VERTEXPROCESSING
  952. #endif
  953. }
  954. //if(App.flag&APP_DX_THREAD_SAFE)flag|=D3DCREATE_MULTITHREADED ;
  955. //if(App.flag&APP_DX_MANAGEMENT )flag|=D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX;
  956. flag|=D3DCREATE_FPU_PRESERVE ;
  957. // enumerate display modes
  958. MemtN<VecI2, 128> modes;
  959. for(Int i=0; ; i++)
  960. {
  961. DEVMODE mode; Zero(mode); mode.dmSize=SIZE(mode);
  962. if(!EnumDisplaySettings(null, i, &mode))break;
  963. modes.include(VecI2(mode.dmPelsWidth, mode.dmPelsHeight));
  964. }
  965. _modes=modes;
  966. _modes.sort(Compare);
  967. // init
  968. if(!findMode())Exit("Valid display mode not found.");
  969. if(!exclusive() && full()){if(!SetDisplayMode(2))Exit("Can't set fullscreen mode."); adjustWindow();}
  970. if(OK(D3DBase->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, App.Hwnd(), flag, &D3DPP, &D3D)))
  971. {
  972. _can_draw=true;
  973. _no_gpu =false;
  974. }else
  975. {
  976. _can_draw =false;
  977. _no_gpu =true;
  978. _shader_model=SM_3;
  979. if((App.flag&APP_ALLOW_NO_GPU) ? !OK(D3DBase->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, App.Hwnd(), flag, &D3DPP, &D3D)) : true)Exit(MLTC(u"Can't create Direct3D Device.", PL,u"Nie można utworzyć Direct3D."));
  980. }
  981. if(D3D)
  982. {
  983. _device_mem=DeviceMemory(D3DADAPTER_DEFAULT);
  984. //if(_device_mem<0)_device_mem=D3D->GetAvailableTextureMem(); // this is the total memory, including system memory (for example 4GB is returned when having only 2GB GPU)
  985. D3D->CreateQuery(D3DQUERYTYPE_EVENT, &Query);
  986. }
  987. #elif DX11
  988. UInt flags=(D3D_DEBUG ? D3D11_CREATE_DEVICE_DEBUG : 0); // DO NOT include D3D11_CREATE_DEVICE_SINGLETHREADED to allow multi-threaded resource creation - https://docs.microsoft.com/en-us/windows/desktop/direct3d11/overviews-direct3d-11-render-multi-thread
  989. // ADAPTER = GPU
  990. // OUTPUT = MONITOR
  991. U64 adapter_id=VR._adapter_id;
  992. if( adapter_id) // if want a custom adapter
  993. {
  994. IDXGIFactory1 *factory=null; CreateDXGIFactory1(__uuidof(IDXGIFactory1), (Ptr*)&factory); if(factory)
  995. {
  996. for(Int i=0; OK(factory->EnumAdapters(i, &Adapter)); i++)
  997. {
  998. if(!Adapter)break;
  999. #if DEBUG
  1000. IDXGIOutput *output=null; for(Int i=0; OK(Adapter->EnumOutputs(i, &output)); i++)
  1001. {
  1002. DXGI_OUTPUT_DESC desc; output->GetDesc(&desc);
  1003. RELEASE(output);
  1004. }
  1005. #endif
  1006. DXGI_ADAPTER_DESC desc; if(OK(Adapter->GetDesc(&desc)))
  1007. {
  1008. ASSERT(SIZE(desc.AdapterLuid)==SIZE(adapter_id));
  1009. if(EqualMem(&adapter_id, &desc.AdapterLuid, SIZE(adapter_id)))break; // if this is the adapter, then use it and don't look any more
  1010. }
  1011. RELEASE(Adapter);
  1012. }
  1013. RELEASE(factory); // release 'factory' because we need to obtain it from the D3D Device in case it will be different
  1014. }
  1015. }
  1016. D3D_FEATURE_LEVEL *feature_level_force=null;
  1017. #if FORCE_D3D9_3
  1018. D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_9_3 ; feature_level_force=&fl;
  1019. #elif FORCE_D3D10_0
  1020. D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_10_0; feature_level_force=&fl;
  1021. #elif FORCE_D3D10_1
  1022. D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_10_1; feature_level_force=&fl;
  1023. #endif
  1024. if(OK(D3D11CreateDevice(Adapter, Adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, null, flags, feature_level_force, feature_level_force ? 1 : 0, D3D11_SDK_VERSION, &D3D, &FeatureLevel, &D3DC)))
  1025. {
  1026. _can_draw=true;
  1027. _no_gpu =false;
  1028. if(FeatureLevel<D3D_FEATURE_LEVEL_10_0)Exit("Minimum D3D Feature Level 10.0 required.\nA better GPU is required.");
  1029. }else
  1030. {
  1031. _can_draw=true; // we can still draw on DX10+ by using D3D_DRIVER_TYPE_WARP
  1032. _no_gpu =true;
  1033. if((App.flag&APP_ALLOW_NO_GPU) ? !OK(D3D11CreateDevice(null, D3D_DRIVER_TYPE_WARP, null, flags, null, 0, D3D11_SDK_VERSION, &D3D, &FeatureLevel, &D3DC)) : true)Exit(MLTC(u"Can't create Direct3D Device.", PL,u"Nie można utworzyć Direct3D."));
  1034. RELEASE(Adapter); // D3D may have gotten a different adapter
  1035. }
  1036. if(D3D_DEBUG)D3D->SetExceptionMode(D3D11_RAISE_FLAG_DRIVER_INTERNAL_ERROR);
  1037. D3DC->QueryInterface(__uuidof(ID3D11DeviceContext1), (Ptr*)&D3DC1);
  1038. _shader_model=((FeatureLevel>=D3D_FEATURE_LEVEL_11_0) ? SM_5 : (FeatureLevel>=D3D_FEATURE_LEVEL_10_1) ? SM_4_1 : SM_4);
  1039. IDXGIDevice1 *device=null; D3D->QueryInterface(__uuidof(IDXGIDevice1), (Ptr*)&device); if(device)
  1040. {
  1041. device->SetMaximumFrameLatency(1); // set max frame latency, for WINDOWS_OLD this doesn't seem to have any effect, however for WINDOWS_NEW it makes a big difference (it makes it work as WINDOWS_OLD), this may be related to the type of SwapChain, so always call this just in case, as without this, the latency is very slow (for example drawing something at mouse position and moving the mouse in circles)
  1042. if(!Adapter)device->GetAdapter(&Adapter); // if adapter is unknown
  1043. RELEASE(device);
  1044. }
  1045. if(!Adapter) // if adapter is unknown
  1046. {
  1047. IDXGIDevice *device=null; D3D->QueryInterface(__uuidof(IDXGIDevice), (Ptr*)&device); if(device)
  1048. {
  1049. device->GetAdapter(&Adapter);
  1050. RELEASE(device);
  1051. }
  1052. }
  1053. if(!Factory) // if Factory is unknown
  1054. {
  1055. if(Adapter)Adapter->GetParent(WINDOWS_OLD ? __uuidof(IDXGIFactory1) : __uuidof(IDXGIFactory2), (Ptr*)&Factory);
  1056. if(!Factory)Exit("Can't access DXGIFactory.\nPlease install latest DirectX and Graphics Drivers.");
  1057. }
  1058. IDXGIFactory5 *factory5=null; Factory->QueryInterface(__uuidof(IDXGIFactory5), (Ptr*)&factory5); if(factory5)
  1059. {
  1060. int allow_tearing=false; // must be 'int' because 'bool' will fail
  1061. if(OK(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, SIZE(allow_tearing))))AllowTearing=(allow_tearing!=0);
  1062. factory5->Release();
  1063. }
  1064. if(Adapter)
  1065. {
  1066. DXGI_ADAPTER_DESC desc; if(OK(Adapter->GetDesc(&desc)))
  1067. {
  1068. if(!deviceName().is())_device_name=desc.Description;
  1069. _device_mem=desc.DedicatedVideoMemory;
  1070. }
  1071. MemtN<VecI2, 128> modes; // store display modes for all outputs, in case user prefers to use another monitor rather than the main display
  1072. IDXGIOutput *output=null; for(Int i=0; OK(Adapter->EnumOutputs(i, &output)); i++) // first output is always the main display
  1073. {
  1074. DXGI_FORMAT mode=DXGI_FORMAT_R8G8B8A8_UNORM; // always use this mode in case system doesn't support 10-bit color
  1075. UInt descs_elms=0; output->GetDisplayModeList(mode, 0, &descs_elms, null); // get number of mode descs
  1076. MemtN<DXGI_MODE_DESC, 128> descs; descs.setNum(descs_elms ); output->GetDisplayModeList(mode, 0, &descs_elms, descs.data()); // get mode descs
  1077. FREPA(descs)modes.binaryInclude(VecI2(descs[i].Width, descs[i].Height), Compare); // add from the start to avoid unnecessary memory moves
  1078. RELEASE(output);
  1079. }
  1080. _modes=modes;
  1081. }
  1082. // init
  1083. if(!findMode())Exit("Valid display mode not found.");
  1084. #if WINDOWS_OLD
  1085. if(!exclusive() && full()){if(!SetDisplayMode(2))Exit("Can't set fullscreen mode."); adjustWindow();}
  1086. again:
  1087. Factory->CreateSwapChain(D3D, &SwapChainDesc, &SwapChain);
  1088. if(!SwapChain && SwapChainDesc.BufferDesc.Format==DXGI_FORMAT_R10G10B10A2_UNORM){SwapChainDesc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; goto again;} // if failed with 10-bit then try again with 8-bit
  1089. Factory->MakeWindowAssociation(App.Hwnd(), DXGI_MWA_NO_ALT_ENTER|DXGI_MWA_NO_WINDOW_CHANGES|DXGI_MWA_NO_PRINT_SCREEN); // this needs to be called after 'CreateSwapChain'
  1090. #else
  1091. again:
  1092. Factory->CreateSwapChainForCoreWindow(D3D, (IUnknown*)App._hwnd, &SwapChainDesc, null, &SwapChain);
  1093. if(!SwapChain && SwapChainDesc.Format==DXGI_FORMAT_R10G10B10A2_UNORM){SwapChainDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; goto again;} // if failed with 10-bit then try again with 8-bit
  1094. #endif
  1095. if(!SwapChain)Exit("Can't create Direct3D Swap Chain.");
  1096. //if( SwapChain && Output && !SwapChainDesc.Windowed)SwapChain->SetFullscreenState(true, Output); // if we want a custom output then we need to apply it now, otherwise the fullscreen can occur on the main display
  1097. D3D11_QUERY_DESC query_desc={D3D11_QUERY_EVENT, 0};
  1098. D3D->CreateQuery(&query_desc, &Query);
  1099. #elif GL
  1100. _shader_model=(GL_ES ? SM_GL_ES_2 : SM_GL);
  1101. if(FlagTest(App.flag, APP_ALLOW_NO_GPU)) // completely disable hardware on OpenGL because there's no way to know if it's available
  1102. {
  1103. _can_draw=false;
  1104. _no_gpu =true;
  1105. }else
  1106. {
  1107. _can_draw=true;
  1108. _no_gpu =false;
  1109. }
  1110. #if WINDOWS
  1111. PIXELFORMATDESCRIPTOR pfd=
  1112. {
  1113. SIZE(PIXELFORMATDESCRIPTOR), // size of 'pfd'
  1114. 1, // version number
  1115. PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,
  1116. PFD_TYPE_RGBA,
  1117. 32, // color bits
  1118. 0, 0, 0, 0, 0, 0, // color bits ignored
  1119. 0, // no alpha buffer
  1120. 0, // shift bit ignored
  1121. 0, // no accumulation buffer
  1122. 0, 0, 0, 0, // accumulation bits ignored
  1123. 24, // 24-bit depth buffer
  1124. 8, // 8-bit stencil buffer
  1125. 0, // no auxiliary buffer
  1126. PFD_MAIN_PLANE, // main drawing layer
  1127. 0, // reserved
  1128. 0, 0, 0 // layer masks ignored
  1129. };
  1130. Int PixelFormat;
  1131. if(!(hDC = GetDC(App.Hwnd() )))Exit("Can't create an OpenGL Device Context.");
  1132. if(!(PixelFormat =ChoosePixelFormat(hDC, &pfd)))Exit("Can't find a suitable PixelFormat.");
  1133. if(!( SetPixelFormat(hDC, PixelFormat, &pfd)))Exit("Can't set the PixelFormat.");
  1134. if(!(MainContext.context= wglCreateContext(hDC )))Exit("Can't create an OpenGL Context.");
  1135. MainContext.lock();
  1136. if(glewInit()!=GLEW_OK || !GLEW_VERSION_3_2)Exit("OpenGL 3.2 support not available.\nGraphics Driver not installed or better video card is required."); // 3.2 needed for 'glDrawElementsBaseVertex', 3.1 needed for instancing, 3.0 needed for 'glColorMaski', 'gl_ClipDistance', 'glClearBufferfv', 'glGenVertexArrays', 'glMapBufferRange', otherwise 2.0 is good enough
  1137. glewSafe();
  1138. if(wglCreateContextAttribsARB)
  1139. {
  1140. const int attribs[]={WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
  1141. WGL_CONTEXT_MINOR_VERSION_ARB, 2,
  1142. 0};
  1143. if(HGLRC context=wglCreateContextAttribsARB(hDC, 0, attribs))
  1144. {
  1145. MainContext.del();
  1146. MainContext.context=context;
  1147. MainContext.lock();
  1148. }
  1149. }
  1150. // enumerate display modes
  1151. MemtN<VecI2, 128> modes;
  1152. for(Int i=0; ; i++)
  1153. {
  1154. DEVMODE mode; Zero(mode); mode.dmSize=SIZE(mode);
  1155. if(!EnumDisplaySettings(null, i, &mode))break;
  1156. modes.include(VecI2(mode.dmPelsWidth, mode.dmPelsHeight));
  1157. }
  1158. _modes=modes;
  1159. _modes.sort(Compare);
  1160. #elif MAC
  1161. const CGLPixelFormatAttribute profile_versions[]=
  1162. {
  1163. (CGLPixelFormatAttribute)kCGLOGLPVersion_Legacy , // NSOpenGLProfileVersionLegacy
  1164. (CGLPixelFormatAttribute)kCGLOGLPVersion_GL3_Core, // NSOpenGLProfileVersion3_2Core
  1165. (CGLPixelFormatAttribute)kCGLOGLPVersion_GL4_Core, // NSOpenGLProfileVersion4_1Core
  1166. };
  1167. CGLPixelFormatObj pf=null;
  1168. REPD (hw , 2) // HW acceleration, most important !! it's very important to check it first, in case device supports only 3.2 accelerated, and 4.1 perhaps could be done in software (if that's possible, it's very likely as one user with Intel HD 3300 which has 3.3 GL, reported poor performance without this) so first we check all profiles looking for accelerated, and if none are found, then try software !!
  1169. REPAD(ver, profile_versions) // profile version
  1170. REPD (buf, 2)
  1171. {
  1172. const CGLPixelFormatAttribute attribs[]=
  1173. {
  1174. buf ? kCGLPFATripleBuffer : kCGLPFADoubleBuffer, // triple/double buffered
  1175. kCGLPFADepthSize , (CGLPixelFormatAttribute)24, // depth buffer
  1176. kCGLPFAStencilSize, (CGLPixelFormatAttribute) 8, // stencil
  1177. kCGLPFAOpenGLProfile, profile_versions[ver], // version
  1178. hw ? kCGLPFAAccelerated : kCGLPFAAllowOfflineRenderers, // HW/Soft
  1179. (CGLPixelFormatAttribute)0, // end of list
  1180. };
  1181. GLint num_pixel_formats; CGLChoosePixelFormat(attribs, &pf, &num_pixel_formats); if(pf)goto found_pf;
  1182. }
  1183. Exit("Can't create an OpenGL Pixel Format.");
  1184. found_pf:
  1185. CGLCreateContext(pf, null, &MainContext.context);
  1186. CGLDestroyPixelFormat(pf);
  1187. if(!MainContext.context)Exit("Can't create an OpenGL Context.");
  1188. if(MAC_GL_MT)Bool mt_ok=(CGLEnable(MainContext.context, kCGLCEMPEngine)!=kCGLNoError);
  1189. MainContext.lock();
  1190. OpenGLContext=[[NSOpenGLContext alloc] initWithCGLContextObj:MainContext.context];
  1191. [OpenGLContext setView:OpenGLView];
  1192. [App.Hwnd() makeKeyAndOrderFront:NSApp]; // show only after everything finished (including GL context to avoid any flickering)
  1193. // enumerate display modes
  1194. CGDirectDisplayID display[256];
  1195. CGDisplayCount displays=0;
  1196. MemtN<VecI2, 128> modes;
  1197. if(!CGGetActiveDisplayList(Elms(display), display, &displays))REP(displays)
  1198. if(CFArrayRef display_modes=CGDisplayCopyAllDisplayModes(display[i], null))
  1199. {
  1200. REP(CFArrayGetCount(display_modes))
  1201. {
  1202. CGDisplayModeRef mode=(CGDisplayModeRef)CFArrayGetValueAtIndex(display_modes, i);
  1203. UInt flags=CGDisplayModeGetIOFlags(mode);
  1204. Bool ok =FlagTest(flags, kDisplayModeSafetyFlags);
  1205. if( ok)modes.include(VecI2(CGDisplayModeGetWidth(mode), CGDisplayModeGetHeight(mode)));
  1206. }
  1207. CFRelease(display_modes);
  1208. }
  1209. _modes=modes;
  1210. _modes.sort(Compare);
  1211. #elif LINUX
  1212. if(XDisplay)
  1213. {
  1214. #if 0 // 2.0 context
  1215. if(!(MainContext.context=glXCreateNewContext(XDisplay, GLConfig, GLX_RGBA_TYPE, null, true)))Exit("Can't create a OpenGL Context.");
  1216. #else // 3.0+ context (this does not link on some old graphics drivers when compiling, "undefined reference to glXCreateContextAttribsARB", it would need to be accessed using 'glXGetProcAddress')
  1217. // access 'glXCreateContextAttribsARB', on Linux we don't need an existing GL context to be able to load extensions via 'glXGetProcAddressARB'
  1218. typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC) (::Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
  1219. PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB=(PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB((C GLubyte*)"glXCreateContextAttribsARB");
  1220. const int attribs[]=
  1221. {
  1222. GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
  1223. GLX_CONTEXT_MINOR_VERSION_ARB, 2,
  1224. 0,
  1225. };
  1226. // create context
  1227. if(!glXCreateContextAttribsARB
  1228. || !(MainContext.context=glXCreateContextAttribsARB(XDisplay, GLConfig, null, true, attribs)))Exit("Can't create a OpenGL 3.2 Context.");
  1229. #endif
  1230. XSync(XDisplay, false); // Forcibly wait on any resulting X errors
  1231. MainContext.lock();
  1232. glXSwapInterval=(glXSwapIntervalType)glXGetProcAddressARB((C GLubyte*)"glXSwapIntervalEXT"); // access it via 'glXGetProcAddressARB' because some people have linker errors "undefined reference to 'glXSwapIntervalEXT'
  1233. // get available modes
  1234. MemtN<VecI2, 128> modes;
  1235. if(XF86VidModeGetAllModeLines(XDisplay, DefaultScreen(XDisplay), &vid_modes, &vid_mode))for(int i=0; i<vid_modes; i++)
  1236. {
  1237. XF86VidModeModeInfo &vm=*vid_mode[i]; modes.include(VecI2(vm.hdisplay, vm.vdisplay));
  1238. }
  1239. _modes=modes;
  1240. _modes.sort(Compare);
  1241. }else
  1242. {
  1243. _can_draw=false;
  1244. _no_gpu =true;
  1245. return;
  1246. }
  1247. #elif ANDROID
  1248. if(LogInit)LogN("EGL");
  1249. GLDisplay=eglGetDisplay(EGL_DEFAULT_DISPLAY); if(!GLDisplay)Exit("Can't get EGL Display"); if(eglInitialize(GLDisplay, null, null)!=EGL_TRUE)Exit("Can't initialize EGL Display");
  1250. Bool has_alpha=false, bit16=false; Byte samples=1; IMAGE_TYPE ds_type=IMAGE_NONE;
  1251. FREPD(gl_ver, 2)
  1252. if(gl_ver || OSVerNumber().x>=18) // proceed only if we're trying GLES 2.0, or 3.0 AND AndroidAPI>=18 (which is the Android Version which started supporting 3.0), this is because Asus Transformer Prime TF201 succeeds with 3.0 context but it doesn't actually support it (TF201 has Android 4.1.1 which is API 16)
  1253. {
  1254. EGLint ctx_attribs[]=
  1255. {
  1256. EGL_CONTEXT_CLIENT_VERSION, (gl_ver==0) ? 3 : 2, // try OpenGL ES 3.0 context first, then fallback to 2.0
  1257. EGL_NONE,
  1258. };
  1259. FREPD(c, 2) // colors (process this as 1st in loop as it's most important)
  1260. FREPD(d, 3) // depth (process this as 2nd in loop as it's more important)
  1261. FREPD(s, 2) // stencil (process this as 3rd in loop as it's less important)
  1262. FREPD(a, 2) // alpha (process this as 4th in loop as it's least important)
  1263. {
  1264. has_alpha=(c==0 && a==0);
  1265. bit16 =(c==1);
  1266. ds_type =((d==0) ? ((s==0) ? IMAGE_D24S8 : IMAGE_D24X8) : (d==1) ? IMAGE_D32 : IMAGE_D16);
  1267. EGLint attribs[]=
  1268. {
  1269. EGL_SURFACE_TYPE , EGL_WINDOW_BIT,
  1270. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  1271. EGL_BLUE_SIZE , (c==0) ? 8 : 5,
  1272. EGL_GREEN_SIZE , (c==0) ? 8 : 6,
  1273. EGL_RED_SIZE , (c==0) ? 8 : 5,
  1274. EGL_ALPHA_SIZE , has_alpha ? 8 : 0,
  1275. EGL_DEPTH_SIZE , (d==0) ? 24 : (d==1) ? 32 : 16,
  1276. EGL_STENCIL_SIZE , (s==0) ? 8 : 0,
  1277. EGL_NONE
  1278. };
  1279. if(LogInit)LogN(S+"Trying config GL:"+gl_ver+", C:"+c+", D:"+d+", S:"+s+", A:"+a);
  1280. EGLint num_configs=0;
  1281. if(eglChooseConfig(GLDisplay, attribs, &GLConfig, 1, &num_configs)==EGL_TRUE)
  1282. if(num_configs>=1)
  1283. {
  1284. EGLint format; eglGetConfigAttrib(GLDisplay, GLConfig, EGL_NATIVE_VISUAL_ID, &format);
  1285. ANativeWindow_setBuffersGeometry(AndroidApp->window, 0, 0, format);
  1286. if(MainContext.surface=eglCreateWindowSurface(GLDisplay, GLConfig, AndroidApp->window, null))
  1287. {
  1288. if(MainContext.context=eglCreateContext(GLDisplay, GLConfig, null, ctx_attribs))
  1289. {
  1290. if(gl_ver==0)_shader_model=SM_GL_ES_3; // we succeeded with creating a 3.0 context
  1291. goto context_ok;
  1292. }
  1293. MainContext.del();
  1294. }
  1295. }
  1296. }
  1297. }
  1298. Exit("Can't create an OpenGL Context.");
  1299. context_ok:
  1300. MainContext.lock();
  1301. if(LogInit)LogN("EGL OK");
  1302. EGLint width, height;
  1303. eglQuerySurface(GLDisplay, MainContext.surface, EGL_WIDTH , &width );
  1304. eglQuerySurface(GLDisplay, MainContext.surface, EGL_HEIGHT, &height);
  1305. Renderer._main .forceInfo(width, height, 1, bit16 ? IMAGE_B5G6R5 : has_alpha ? IMAGE_R8G8B8A8 : IMAGE_R8G8B8X8, IMAGE_SURF)._samples=samples;
  1306. Renderer._main_ds.forceInfo(width, height, 1, ds_type , IMAGE_DS )._samples=samples;
  1307. if(LogInit)LogN(S+"Renderer._main: "+Renderer._main.w()+'x'+Renderer._main.h()+", type: "+ImageTI[Renderer._main.hwType()].name+", ds_type: "+ImageTI[Renderer._main_ds.hwType()].name);
  1308. #elif IOS
  1309. if(MainContext.context=[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3])_shader_model=SM_GL_ES_3;else
  1310. if(MainContext.context=[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2])
  1311. {
  1312. _shader_model=SM_GL_ES_2;
  1313. // iOS has a bug in which it falsely returns success for creating ETC formats on OpenGL ES 2 even though they're not supported, so as a workaround, disable them completely
  1314. ConstCast(ImageTI[IMAGE_ETC1 ].format)=0;
  1315. ConstCast(ImageTI[IMAGE_ETC2 ].format)=0;
  1316. ConstCast(ImageTI[IMAGE_ETC2_A1].format)=0;
  1317. ConstCast(ImageTI[IMAGE_ETC2_A8].format)=0;
  1318. }else Exit("Can't create a OpenGL ES 2.0 Context.");
  1319. MainContext.context.multiThreaded=false; // disable multi-threaded rendering as enabled actually made things slower, TOOD: check again in the future !! if enabling then probably all contexts have to be enabled as well, secondary too, because VAO from VBO's on a secondary thread could fail, as in Dungeon Hero, needs checking !!
  1320. MainContext.lock();
  1321. #elif WEB
  1322. EmscriptenWebGLContextAttributes attrs;
  1323. emscripten_webgl_init_context_attributes(&attrs);
  1324. attrs.minorVersion=0;
  1325. attrs.alpha =false; // this would enable compositing graphics using transparency onto the web page
  1326. attrs.depth =true;
  1327. attrs.stencil =true;
  1328. attrs.antialias =false;
  1329. attrs.preserveDrawingBuffer=false;
  1330. attrs.enableExtensionsByDefault=true;
  1331. attrs.preferLowPowerToHighPerformance=false;
  1332. for(Int gl_ver=2; gl_ver>=1; gl_ver--) // start from WebGL 2.0 (ES3) down to 1.0 (ES2)
  1333. {
  1334. attrs.majorVersion=gl_ver;
  1335. if(MainContext.context=emscripten_webgl_create_context(null, &attrs))
  1336. {
  1337. _shader_model=((gl_ver>=2) ? SM_GL_ES_3 : SM_GL_ES_2);
  1338. goto context_ok;
  1339. }
  1340. }
  1341. Exit("Can't create an OpenGL Context.");
  1342. context_ok:
  1343. MainContext.lock();
  1344. Byte samples=(attrs.antialias ? 4 : 1);
  1345. int width, height; emscripten_get_canvas_element_size(null, &width, &height);
  1346. Renderer._main .forceInfo(width, height, 1, IMAGE_R8G8B8A8 , IMAGE_SURF)._samples=samples;
  1347. Renderer._main_ds.forceInfo(width, height, 1, attrs.stencil ? IMAGE_D24S8 : IMAGE_D24X8, IMAGE_DS )._samples=samples;
  1348. #endif
  1349. if(!deviceName().is())
  1350. {
  1351. _device_name=(CChar8*)glGetString(GL_RENDERER);
  1352. #if LINUX
  1353. _device_name.removeOuterWhiteChars(); // Linux may have unnecessary spaces at the end
  1354. #endif
  1355. }
  1356. if(LogInit)LogN("Secondary Contexts");
  1357. if(SecondaryContexts.elms())
  1358. {
  1359. REPA(SecondaryContexts)if(!SecondaryContexts[i].createSecondary())
  1360. {
  1361. LogN(S+"Failed to create a Secondary OpenGL Context"
  1362. #if ANDROID
  1363. +", error:"+eglGetError()
  1364. #endif
  1365. );
  1366. SecondaryContexts.remove(i); // remove after error code was displayed
  1367. }
  1368. MainContext.lock(); // lock main context because secondary were locked during creation to set some things
  1369. }
  1370. if(LogInit)LogN("Secondary Contexts OK");
  1371. if(D.shaderModelGLES2()) // GLES2 requires internalFormat to be as follows, without it WebGL1 will fail - https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml
  1372. {
  1373. #define GL_LUMINANCE 0x1909
  1374. #define GL_LUMINANCE_ALPHA 0x190A
  1375. ConstCast(ImageTI[IMAGE_R8G8B8A8].format)=GL_RGBA;
  1376. ConstCast(ImageTI[IMAGE_R8G8B8 ].format)=GL_RGB;
  1377. ConstCast(ImageTI[IMAGE_L8A8 ].format)=GL_LUMINANCE_ALPHA;
  1378. ConstCast(ImageTI[IMAGE_L8 ].format)=GL_LUMINANCE;
  1379. ConstCast(ImageTI[IMAGE_A8 ].format)=GL_ALPHA;
  1380. ConstCast(ImageTI[IMAGE_F32_4 ].format)=GL_RGBA;
  1381. ConstCast(ImageTI[IMAGE_F32_3 ].format)=GL_RGB;
  1382. ConstCast(ImageTI[IMAGE_F16_4 ].format)=GL_RGBA;
  1383. ConstCast(ImageTI[IMAGE_F16_3 ].format)=GL_RGB;
  1384. }
  1385. if(LogInit)
  1386. {
  1387. LogN(S+"Device Name: " +_device_name);
  1388. LogN(S+"Device Vendor: " +(CChar8*)glGetString(GL_VENDOR ));
  1389. LogN(S+"Device Version: " +(CChar8*)glGetString(GL_VERSION ));
  1390. LogN(S+"Device Extensions: "+(CChar8*)glGetString(GL_EXTENSIONS));
  1391. #if GL_ES
  1392. int i;
  1393. glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS , &i); LogN(S+"GL_MAX_VERTEX_UNIFORM_VECTORS: "+i);
  1394. glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &i); LogN(S+"GL_MAX_FRAGMENT_UNIFORM_VECTORS: "+i);
  1395. #endif
  1396. }
  1397. if(!findMode())Exit("Valid display mode not found.");
  1398. setSync();
  1399. if(LogInit)LogN("FBO");
  1400. glGenFramebuffers(1, &FBO); if(!FBO)Exit("Couldn't create OpenGL Frame Buffer Object (FBO)");
  1401. if(D.notShaderModelGLES2()){glGenVertexArrays(1, &VAO); if(!VAO)Exit("Couldn't create OpenGL Vertex Arrays (VAO)");}
  1402. #if WINDOWS
  1403. if(full()){if(!SetDisplayMode(2))Exit("Can't set fullscreen mode."); adjustWindow();}
  1404. #elif MAC
  1405. if(!SetDisplayMode(2))Exit("Can't set display mode.");
  1406. #elif LINUX
  1407. if(full()){if(!SetDisplayMode(2))Exit("Can't set display mode."); adjustWindow();} // 'adjustWindow' because we need to set fullscreen state
  1408. #elif IOS
  1409. fbo(FBO); // set custom frame buffer, on iOS there's only one FBO and one FBO change, and it is here, this is because there's no default(0) fbo on this platform
  1410. #endif
  1411. // call these as soon as possible because they affect all images (including those created in the renderer)
  1412. glPixelStorei(GL_PACK_ALIGNMENT , 1);
  1413. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  1414. #endif
  1415. #if MOBILE
  1416. T._modes.setNum(2);
  1417. T._modes[1]=T._modes[0]=screen();
  1418. T._modes[1].swap();
  1419. #endif
  1420. }
  1421. void Display::androidClose()
  1422. {
  1423. #if ANDROID
  1424. SyncLocker locker(_lock);
  1425. if(GLDisplay)
  1426. {
  1427. MainContext.unlock();
  1428. if(MainContext.surface)eglDestroySurface(GLDisplay, MainContext.surface);
  1429. }
  1430. MainContext.surface=null;
  1431. #endif
  1432. }
  1433. void Display::androidOpen()
  1434. {
  1435. #if ANDROID
  1436. SyncLocker locker(_lock);
  1437. androidClose();
  1438. if(GLDisplay && MainContext.context)
  1439. {
  1440. EGLint format; eglGetConfigAttrib(GLDisplay, GLConfig, EGL_NATIVE_VISUAL_ID, &format);
  1441. ANativeWindow_setBuffersGeometry(AndroidApp->window, 0, 0, format);
  1442. MainContext.surface=eglCreateWindowSurface(GLDisplay, GLConfig, AndroidApp->window, null); if(!MainContext.surface)Exit("Can't create EGLSurface.");
  1443. MainContext.lock();
  1444. }else Exit("OpenGL Display and MainContext not available.");
  1445. #endif
  1446. }
  1447. Bool Display::create()
  1448. {
  1449. if(LogInit)LogN("Display.create");
  1450. createDevice();
  1451. getGamma();
  1452. getCaps();
  1453. Sh.createSamplers();
  1454. DisplayState::create();
  1455. setDeviceSettings();
  1456. Sh.create();
  1457. InitMatrix(); // !! call this after creating main shaders, because it creates the "ObjMatrix, ObjVel" shader buffers !!
  1458. if(!Renderer.rtCreate())Exit("Can't create Render Targets."); // !! call this after creating shaders because it modifies shader values !!
  1459. InitVtxInd();
  1460. Renderer.create();
  1461. colorPalette(ImagePtr().get("Img/color palette.img"));
  1462. VR.createImages(); // !! call this before 'after', because VR gui image may affect aspect ratio of display !!
  1463. after(false);
  1464. begin();
  1465. Gui.create();
  1466. // set default settings
  1467. {Byte v=texFilter (); _tex_filter ^=1 ; texFilter (v);}
  1468. {Bool v=texMipFilter(); _tex_mip_filter^=1 ; texMipFilter(v);}
  1469. {Bool v=bloomMaximum(); _bloom_max =false ; bloomMaximum(v);} // resetting will load shaders
  1470. {auto v=edgeSoften (); _edge_soften =EDGE_SOFTEN_NONE; edgeSoften (v);} // resetting will load shaders
  1471. {auto v=edgeDetect (); _edge_detect =EDGE_DETECT_NONE; edgeDetect (v);} // resetting will load shaders
  1472. {Flt v=grassRange (); _grass_range =-1 ; grassRange (v);}
  1473. lod (_lod_factor, _lod_factor_shadow, _lod_factor_mirror);
  1474. shadowJitterSet ();
  1475. MotionScaleChanged();
  1476. SetMatrix ();
  1477. _initialized=true;
  1478. return true;
  1479. }
  1480. /******************************************************************************/
  1481. Bool Display::created()
  1482. {
  1483. #if DX9
  1484. return D3D!=null;
  1485. #elif DX11
  1486. return D3DC!=null;
  1487. #elif GL
  1488. return MainContext.is();
  1489. #endif
  1490. }
  1491. /******************************************************************************/
  1492. void ThreadMayUseGPUData()
  1493. {
  1494. #if GL && HAS_THREADS
  1495. Ptr context=GetCurrentContext();
  1496. if(!context)
  1497. {
  1498. ContextLock.on();
  1499. for(;;)
  1500. {
  1501. REPA(SecondaryContexts)if(!SecondaryContexts[i].locked)
  1502. {
  1503. SecondaryContexts[i].lock();
  1504. goto context_locked;
  1505. }
  1506. if(!SecondaryContexts.elms())Exit("No secondary OpenGL contexts have been created");
  1507. ContextLock.off(); ContextUnlocked.wait(); // wait until any other context is unlocked
  1508. ContextLock.on ();
  1509. }
  1510. context_locked:
  1511. ContextLock.off();
  1512. }
  1513. #endif
  1514. }
  1515. void ThreadFinishedUsingGPUData()
  1516. {
  1517. #if GL && HAS_THREADS
  1518. if(Ptr context=GetCurrentContext())
  1519. {
  1520. ContextLock.on();
  1521. REPA(SecondaryContexts)if(SecondaryContexts[i].context==context)
  1522. {
  1523. SecondaryContexts[i].unlock();
  1524. goto context_unlocked;
  1525. }
  1526. context_unlocked:
  1527. ContextLock.off();
  1528. ContextUnlocked++; // notify of unlocking
  1529. }
  1530. #endif
  1531. }
  1532. /******************************************************************************/
  1533. static Int DisplaySamples(Int samples)
  1534. {
  1535. Clamp(samples, 1, 16);
  1536. if(Renderer.anyDeferred() && D.deferredMSUnavailable())samples=1;
  1537. #if DX9
  1538. if(D3DBase)
  1539. {
  1540. D3DFORMAT disp_format=D3DFMT_A8R8G8B8; if(!OK(D3DBase->CheckDeviceType(0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, disp_format, D3DPP.Windowed)))disp_format=D3DFMT_X8R8G8B8;
  1541. for(; samples>1; samples--)
  1542. {
  1543. DWORD col_levels=0, ds_levels=0;
  1544. if(samples<=D3DMULTISAMPLE_16_SAMPLES) // there's no higher sample level on DX9
  1545. {
  1546. DWORD levels=0;
  1547. if(OK(D3DBase->CheckDeviceMultiSampleType(0, D3DDEVTYPE_HAL, disp_format , D3DPP.Windowed, D3DMULTISAMPLE_TYPE(samples), &levels)))MAX(col_levels, levels);
  1548. if(OK(D3DBase->CheckDeviceMultiSampleType(0, D3DDEVTYPE_HAL, D3DFMT_D24S8, D3DPP.Windowed, D3DMULTISAMPLE_TYPE(samples), &levels)))MAX( ds_levels, levels);
  1549. if(OK(D3DBase->CheckDeviceMultiSampleType(0, D3DDEVTYPE_HAL, D3DFMT_D24X8, D3DPP.Windowed, D3DMULTISAMPLE_TYPE(samples), &levels)))MAX( ds_levels, levels);
  1550. }
  1551. if(col_levels && ds_levels)break; // if there are some quality levels, then accept this multi-sampling
  1552. }
  1553. }
  1554. #elif DX11
  1555. if(samples>1)samples=4; // only 4 samples are supported in DX10+ implementation
  1556. #else
  1557. samples=1; // other implementations don't support multi-sampling
  1558. #endif
  1559. return samples;
  1560. }
  1561. Bool Display::findMode()
  1562. {
  1563. SyncLocker locker(_lock);
  1564. #if WINDOWS_NEW // on WindowsNew we can't change mode here, we need to set according to what we've got, instead 'RequestDisplayMode' can be called
  1565. _res =WindowSize(true);
  1566. _full=App.Fullscreen();
  1567. #elif IOS
  1568. // '_res' will be set in 'mapMain'
  1569. #elif MOBILE || WEB
  1570. // Renderer._main is already available
  1571. _res=Renderer._main.size();
  1572. #else
  1573. RectI full, work; VecI2 max_normal_win_client_size, maximized_win_client_size;
  1574. curMonitor(full, work, max_normal_win_client_size, maximized_win_client_size);
  1575. #if FORCE_MAIN_DISPLAY
  1576. if(resW()>=D.screenW() && resH()>=D.screenH())_full=true;
  1577. #else
  1578. if(resW()>=full.w() && resH()>=full.h())_full=true; // force fullscreen only if both dimensions are equal-bigger because on Windows it's perfectly fine to have a window as wide as the whole desktop
  1579. #endif
  1580. if(D.full())
  1581. {
  1582. Int nearest=-1; Int desired_area=res().mul(), area_error;
  1583. REPA(_modes)
  1584. {
  1585. C VecI2 &mode=_modes[i];
  1586. if(mode==res()){nearest=i; break;} // exact match
  1587. Int ae=Abs(mode.mul()-desired_area);
  1588. if(nearest<0 || ae<area_error){nearest=i; area_error=ae;}
  1589. }
  1590. if(nearest<0)return false;
  1591. _res=_modes[nearest];
  1592. }else
  1593. {
  1594. if(resW()>=Min(maximized_win_client_size.x, max_normal_win_client_size.x+1)
  1595. && resH()>=Min(maximized_win_client_size.y, max_normal_win_client_size.y+1))_res=maximized_win_client_size;/*else
  1596. { don't limit for 2 reasons: 1) having multiple monitors we can make the window cover multiple monitors 2) on Windows initially we can drag the window only until 'max_normal_win_client_size', however after that we can drag again to make it bigger, and this time it will succeed, which means that making windows bigger than 'max_normal_win_client_size' is actually possible, unless it's a bug in the OS
  1597. MIN(_res.x, max_normal_win_client_size.x);
  1598. MIN(_res.y, max_normal_win_client_size.y);
  1599. }*/
  1600. }
  1601. #endif
  1602. #if DX9
  1603. Zero(D3DPP);
  1604. D3DPP.Windowed =(!exclusive() || !T.full()); // !! set this first !!
  1605. D3DPP.BackBufferCount =(sync() ? 2 : 1);
  1606. D3DPP.BackBufferWidth =resW();
  1607. D3DPP.BackBufferHeight =resH();
  1608. D3DPP.BackBufferFormat =D3DFMT_A8R8G8B8; if(D3DBase && !OK(D3DBase->CheckDeviceType(0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DPP.BackBufferFormat, D3DPP.Windowed)))D3DPP.BackBufferFormat=D3DFMT_X8R8G8B8;
  1609. D3DPP.EnableAutoDepthStencil =false;
  1610. D3DPP.hDeviceWindow =App.Hwnd();
  1611. D3DPP.SwapEffect =D3DSWAPEFFECT_DISCARD;
  1612. D3DPP.MultiSampleQuality =0;
  1613. D3DPP.MultiSampleType =D3DMULTISAMPLE_NONE;
  1614. D3DPP.PresentationInterval =( sync() ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE);
  1615. D3DPP.FullScreen_RefreshRateInHz=((_freq_want && !D3DPP.Windowed) ? _freq_want : D3DPRESENT_RATE_DEFAULT ); // set custom frequency only if desired and in true full-screen
  1616. #elif DX11
  1617. Zero(SwapChainDesc);
  1618. Bool sync=ActualSync();
  1619. #if WINDOWS_OLD
  1620. SwapChainDesc.OutputWindow =App.Hwnd();
  1621. SwapChainDesc.Windowed =(!exclusive() || !T.full());
  1622. SwapChainDesc.BufferCount =(sync ? 3 : 2); // if we're rendering to VR display, then it has its own swap chain, and it handles the most intense rendering, so we don't need to have more buffers here, so keep it low to reduce memory usage
  1623. SwapChainDesc.BufferDesc.Width =resW();
  1624. SwapChainDesc.BufferDesc.Height =resH();
  1625. SwapChainDesc.BufferDesc.Format =(GDI_COMPATIBLE ? DXGI_FORMAT_B8G8R8A8_UNORM : highMonitorPrecision() ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM);
  1626. SwapChainDesc.SampleDesc.Count =1;
  1627. SwapChainDesc.SampleDesc.Quality=0;
  1628. SwapChainDesc.BufferUsage =DXGI_USAGE_RENDER_TARGET_OUTPUT|DXGI_USAGE_SHADER_INPUT|DXGI_USAGE_BACK_BUFFER;
  1629. SwapChainDesc.Flags =DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH|(GDI_COMPATIBLE ? DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE : 0);
  1630. if(_freq_want && !SwapChainDesc.Windowed) // set custom frequency only if desired and in true full-screen
  1631. {
  1632. SwapChainDesc.BufferDesc.RefreshRate.Numerator =_freq_want;
  1633. SwapChainDesc.BufferDesc.RefreshRate.Denominator=1;
  1634. }
  1635. SwapChainDesc.SwapEffect=DXGI_SWAP_EFFECT_DISCARD;
  1636. #if !GDI_COMPATIBLE
  1637. #if 0
  1638. /* disable this as last time this was tested, it provided slower results, also there was a few second slow down when changing sync during app runtime:
  1639. windowed sync=false | windowed sync=true | fullscreen sync=true
  1640. DXGI_SWAP_EFFECT_DISCARD 850 fps | 42 fps | 16.9 fps
  1641. DXGI_SWAP_EFFECT_FLIP_DISCARD 655 fps | 34 fps | 16.4 fps */
  1642. {
  1643. VecI4 ver=OSVerNumber();
  1644. if( ver.x>=10 )SwapChainDesc.SwapEffect=DXGI_SWAP_EFFECT_FLIP_DISCARD ;else // DXGI_SWAP_EFFECT_FLIP_DISCARD is available on Windows 10
  1645. if(Compare(ver, VecI4(6, 2, 0, 0))>=0)SwapChainDesc.SwapEffect=DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL is available on Windows 8 - https://msdn.microsoft.com/en-us/library/windows/desktop/bb173077(v=vs.85).aspx
  1646. }
  1647. #endif
  1648. #endif
  1649. if(AllowTearing && SwapChainDesc.SwapEffect==DXGI_SWAP_EFFECT_FLIP_DISCARD)SwapChainDesc.Flags|=DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
  1650. PresentFlags=((!sync && (SwapChainDesc.Flags&DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) && SwapChainDesc.Windowed) ? DXGI_PRESENT_ALLOW_TEARING : 0); // according to docs, we can use DXGI_PRESENT_ALLOW_TEARING only with DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING and in windowed mode - https://msdn.microsoft.com/en-us/library/windows/desktop/bb509554(v=vs.85).aspx
  1651. SwapChainDesc.BufferDesc.Scaling=DXGI_MODE_SCALING_UNSPECIFIED; // can't always use 'DXGI_MODE_SCALING_STRETCHED' because it will fail to set highest supported resolution by the monitor, because that resolution never supports streching, so we set DXGI_MODE_SCALING_UNSPECIFIED which means it will be set according to the driver settings
  1652. if(1 // find the monitor/output that we're going to use, and iterate all of its modes to check if that mode supports stretched mode
  1653. && !SwapChainDesc.Windowed) // needed for exclusive fullscreen only and only when the driver has scaling set to DXGI_MODE_SCALING_CENTERED
  1654. {
  1655. IDXGIOutput *output;
  1656. Bool ok=false;
  1657. if(SwapChain) // if we already have a swap chain, then reuse its output
  1658. {
  1659. output=null; SwapChain->GetContainingOutput(&output); if(output){ok=true; goto has_output;} // set 'ok' so break will be called
  1660. }
  1661. if(Adapter)
  1662. if(HMONITOR monitor=MonitorFromWindow(App.Hwnd(), MONITOR_DEFAULTTONEAREST)) // get nearest monitor
  1663. for(Int i=0; ; i++) // iterate all outputs
  1664. {
  1665. output=null; Adapter->EnumOutputs(i, &output); if(output)
  1666. {
  1667. DXGI_OUTPUT_DESC desc; ok=(OK(output->GetDesc(&desc)) && desc.Monitor==monitor); // if found the monitor that we're going to use
  1668. if(ok)
  1669. {
  1670. has_output:
  1671. DXGI_FORMAT mode=DXGI_FORMAT_R8G8B8A8_UNORM; // always use this mode in case system doesn't support 10-bit color
  1672. UInt descs_elms=0; output->GetDisplayModeList(mode, 0, &descs_elms, null); // get number of mode descs
  1673. MemtN<DXGI_MODE_DESC, 128> descs; descs.setNum(descs_elms ); output->GetDisplayModeList(mode, 0, &descs_elms, descs.data()); // get mode descs
  1674. FREPA(descs)
  1675. {
  1676. C DXGI_MODE_DESC &mode=descs[i];
  1677. if(mode.Width==resW() && mode.Height==resH() && mode.Scaling!=DXGI_MODE_SCALING_UNSPECIFIED) // can't just check for ==DXGI_MODE_SCALING_STRETCHED because it's never listed, however DXGI_MODE_SCALING_CENTERED will be listed for modes that support stretching, so we use !=DXGI_MODE_SCALING_UNSPECIFIED to support both DXGI_MODE_SCALING_STRETCHED and DXGI_MODE_SCALING_CENTERED
  1678. {
  1679. SwapChainDesc.BufferDesc.Scaling=DXGI_MODE_SCALING_STRETCHED;
  1680. break;
  1681. }
  1682. }
  1683. }
  1684. output->Release();
  1685. if(ok)break;
  1686. }else break;
  1687. }
  1688. }
  1689. #else // WINDOWS_NEW
  1690. SwapChainDesc.Width =resW();
  1691. SwapChainDesc.Height=resH();
  1692. SwapChainDesc.Format=(GDI_COMPATIBLE ? DXGI_FORMAT_B8G8R8A8_UNORM : highMonitorPrecision() ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM);
  1693. SwapChainDesc.Stereo=false;
  1694. SwapChainDesc.SampleDesc.Count =1;
  1695. SwapChainDesc.SampleDesc.Quality=0;
  1696. SwapChainDesc.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT|DXGI_USAGE_SHADER_INPUT|DXGI_USAGE_BACK_BUFFER;
  1697. SwapChainDesc.BufferCount=(sync ? 3 : 2); // if we're rendering to VR display, then it has its own swap chain, and it handles the most intense rendering, so we don't need to have more buffers here, so keep it low to reduce memory usage
  1698. SwapChainDesc.Scaling =DXGI_SCALING_STRETCH;
  1699. SwapChainDesc.SwapEffect =DXGI_SWAP_EFFECT_FLIP_DISCARD;
  1700. SwapChainDesc.AlphaMode =DXGI_ALPHA_MODE_IGNORE;
  1701. SwapChainDesc.Flags =0;
  1702. if(AllowTearing && SwapChainDesc.SwapEffect==DXGI_SWAP_EFFECT_FLIP_DISCARD)SwapChainDesc.Flags|=DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
  1703. PresentFlags=((!sync && (SwapChainDesc.Flags&DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)/* && SwapChainDesc.Windowed*/) ? DXGI_PRESENT_ALLOW_TEARING : 0); // according to docs, we can use DXGI_PRESENT_ALLOW_TEARING only with DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING and in windowed mode, in UWP there's no windowed check because "UWP apps that enter fullscreen mode by calling Windows::UI::ViewManagement::ApplicationView::TryEnterFullscreen() are fullscreen borderless windows and may use the flag" - https://msdn.microsoft.com/en-us/library/windows/desktop/bb509554(v=vs.85).aspx
  1704. #endif
  1705. #endif
  1706. densityUpdate();
  1707. return true;
  1708. }
  1709. /******************************************************************************/
  1710. CChar8* Display::AsText(RESET_RESULT result)
  1711. {
  1712. switch(result)
  1713. {
  1714. case RESET_OK : return "RESET_OK";
  1715. case RESET_DEVICE_NOT_CREATED : return "RESET_DEVICE_NOT_CREATED";
  1716. case RESET_CUSTOM_LOST_FAILED : return "RESET_CUSTOM_LOST_FAILED";
  1717. case RESET_CUSTOM_RESET_FAILED : return "RESET_CUSTOM_RESET_FAILED";
  1718. case RESET_DEVICE_RESET_FAILED : return "RESET_DEVICE_RESET_FAILED";
  1719. case RESET_RENDER_TARGET_FAILED: return "RESET_RENDER_TARGET_FAILED";
  1720. default : return "RESET_UNKNOWN";
  1721. }
  1722. }
  1723. void Display::ResetFailed(RESET_RESULT New, RESET_RESULT old)
  1724. {
  1725. Exit(
  1726. ((New==old) ? S+"Can't set display mode: "+AsText(New)
  1727. : S+"Can't set new display mode: "+AsText(New)
  1728. +"\nCan't set old display mode: "+AsText(old))
  1729. #if DX9
  1730. +((New==RESET_DEVICE_RESET_FAILED || old==RESET_DEVICE_RESET_FAILED) ? "\nDid you forget to delete IMAGE_RT Image in D.lost on DX9?" : "")
  1731. #endif
  1732. );
  1733. }
  1734. #if DX11
  1735. static Bool ResizeTarget()
  1736. {
  1737. #if WINDOWS_OLD
  1738. again:
  1739. if(OK(SwapChain->ResizeTarget(&SwapChainDesc.BufferDesc)))return true;
  1740. if(SwapChainDesc.BufferDesc.Format==DXGI_FORMAT_R10G10B10A2_UNORM){SwapChainDesc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; goto again;} // if failed with 10-bit then try again with 8-bit
  1741. #endif
  1742. return false;
  1743. }
  1744. static Bool ResizeBuffers()
  1745. {
  1746. again:
  1747. #if WINDOWS_OLD
  1748. if(OK(SwapChain->ResizeBuffers(SwapChainDesc.BufferCount, SwapChainDesc.BufferDesc.Width, SwapChainDesc.BufferDesc.Height, SwapChainDesc.BufferDesc.Format, SwapChainDesc.Flags)))return true;
  1749. if(SwapChainDesc.BufferDesc.Format==DXGI_FORMAT_R10G10B10A2_UNORM){SwapChainDesc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; goto again;} // if failed with 10-bit then try again with 8-bit
  1750. #else
  1751. if(OK(SwapChain->ResizeBuffers(SwapChainDesc.BufferCount, SwapChainDesc. Width, SwapChainDesc. Height, SwapChainDesc. Format, SwapChainDesc.Flags)))return true;
  1752. if(SwapChainDesc.Format==DXGI_FORMAT_R10G10B10A2_UNORM){SwapChainDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; goto again;} // if failed with 10-bit then try again with 8-bit
  1753. #endif
  1754. return false;
  1755. }
  1756. #endif
  1757. Display::RESET_RESULT Display::ResetTry()
  1758. {
  1759. SyncLocker locker(_lock);
  1760. _resetting=true;
  1761. RESET_RESULT result;
  1762. if(!created())result=RESET_DEVICE_NOT_CREATED;else
  1763. {
  1764. Bool begin_end=_began;
  1765. if( begin_end)end();
  1766. Renderer.rtDel();
  1767. #if DX9
  1768. VI.lost(); // dynamic buffers
  1769. VideoTexturesLost(); // video textures (render targets)
  1770. RELEASE(Query);
  1771. #endif
  1772. if(lost && !lost())result=RESET_CUSTOM_LOST_FAILED;else
  1773. {
  1774. Bool ok=true;
  1775. #if WINDOWS
  1776. #if (DX9 || DX11) && !WINDOWS_NEW // on WindowsNew we can't change mode here, we need to set according to what we've got, instead 'RequestDisplayMode' can be called
  1777. if(!exclusive())ok=SetDisplayMode();
  1778. #endif
  1779. #if DX9
  1780. if(ok)
  1781. {
  1782. reset:;
  1783. ok=OK(D3D->Reset(&D3DPP));
  1784. if(!ok && WindowActive()!=App.hwnd()) // if reset failed and we're not focused then wait a little and try again (this is important when using 'BackgroundLoader' and pressing Ctrl+Alt+Del, device is lost, fails to reset and secondary thread fails to load data)
  1785. {
  1786. Time.wait(100);
  1787. goto reset;
  1788. }
  1789. setDeviceSettings();
  1790. }
  1791. #elif DX11
  1792. #if WINDOWS_OLD
  1793. if(ok&=OK(SwapChain->SetFullscreenState(!SwapChainDesc.Windowed, SwapChainDesc.Windowed ? null : Output)))
  1794. if(ok&=ResizeTarget())
  1795. #elif 0 // both 'SetFullscreenState' and 'ResizeTarget' fail on WINDOWS_NEW, instead, 'TryEnterFullScreenMode', 'ExitFullScreenMode', 'TryResizeView' are used
  1796. DXGI_MODE_DESC mode; Zero(mode);
  1797. mode.Format =SwapChainDesc.Format;
  1798. mode.Width =SwapChainDesc.Width;
  1799. mode.Height =SwapChainDesc.Height;
  1800. mode.Scaling=DXGI_MODE_SCALING_UNSPECIFIED;
  1801. if(_freq_want && full()) // set custom frequency only if desired and in full-screen
  1802. {
  1803. mode.RefreshRate.Numerator =_freq_want;
  1804. mode.RefreshRate.Denominator=1;
  1805. }
  1806. if(ok&=OK(SwapChain->SetFullscreenState(full(), null)))
  1807. if(ok&=OK(SwapChain->ResizeTarget(&mode)))
  1808. #endif
  1809. {
  1810. // 'ResizeTarget' may select a different resolution than requested for fullscreen mode, so check what we've got
  1811. #if WINDOWS_OLD
  1812. if(!SwapChainDesc.Windowed)
  1813. #else
  1814. if(0) // if(full()) this shouldn't be performed for WINDOWS_NEW because for this we're not setting a custom display mode, but instead we're setting to what we've got
  1815. #endif
  1816. {
  1817. IDXGIOutput *output=null; SwapChain->GetContainingOutput(&output); if(output)
  1818. {
  1819. DXGI_OUTPUT_DESC desc; if(OK(output->GetDesc(&desc)))
  1820. {
  1821. _res.set(desc.DesktopCoordinates.right-desc.DesktopCoordinates.left, desc.DesktopCoordinates.bottom-desc.DesktopCoordinates.top);
  1822. #if WINDOWS_OLD
  1823. SwapChainDesc.BufferDesc.Width =resW();
  1824. SwapChainDesc.BufferDesc.Height=resH();
  1825. #else
  1826. // for WINDOWS_NEW this should adjust '_res' based on relative rotation
  1827. SwapChainDesc.Width =resW();
  1828. SwapChainDesc.Height=resH();
  1829. #endif
  1830. densityUpdate();
  1831. }
  1832. output->Release();
  1833. }
  1834. }
  1835. ok&=ResizeBuffers();
  1836. }
  1837. #elif GL
  1838. if(ok)ok=SetDisplayMode();
  1839. #endif
  1840. #elif MAC || LINUX
  1841. ok=SetDisplayMode();
  1842. #else
  1843. ok=true;
  1844. #endif
  1845. getCaps();
  1846. if(!ok )result=RESET_DEVICE_RESET_FAILED ;else
  1847. if(!Renderer.rtCreate())result=RESET_RENDER_TARGET_FAILED;else
  1848. {
  1849. #if DX9
  1850. D3D->CreateQuery(D3DQUERYTYPE_EVENT, &Query);
  1851. VI.reset(); // dynamic buffers
  1852. #endif
  1853. adjustWindow(); // !! call before 'after' so current monitor can be detected properly based on window position which affects the aspect ratio in 'after' !!
  1854. after(true);
  1855. begin(); // we need begin if 'begin_end' was enabled and also always for the following code
  1856. {
  1857. resetEyeAdaptation(); // make sure we're inside begin because this potentially may use drawing
  1858. #if DX9
  1859. VideoTexturesReset(); // video textures (render targets), make sure we're inside begin
  1860. #endif
  1861. }
  1862. if(!begin_end)end(); // leave in the same state as before the reset
  1863. Time.skipUpdate(2); // when resetting display skip 2 frames, because the slow down can occur for this long
  1864. if(reset && !reset())result=RESET_CUSTOM_RESET_FAILED;
  1865. else result=RESET_OK;
  1866. }
  1867. }
  1868. }
  1869. _resetting=false;
  1870. return result;
  1871. }
  1872. void Display::Reset()
  1873. {
  1874. RESET_RESULT result=ResetTry(); if(result!=RESET_OK)ResetFailed(result, result);
  1875. }
  1876. /******************************************************************************/
  1877. void Display::getGamma()
  1878. {
  1879. Bool ok=false;
  1880. #if WINDOWS_OLD
  1881. if(HDC hdc=GetDC(null)){ok=(GetDeviceGammaRamp(hdc, _gamma_array)!=0); ReleaseDC(null, hdc);}
  1882. #elif MAC
  1883. Int capacity =CGDisplayGammaTableCapacity(kCGDirectMainDisplay);
  1884. if( capacity>=1)
  1885. {
  1886. Memc<CGGammaValue> r, g, b; r.setNum(capacity); g.setNum(capacity); b.setNum(capacity);
  1887. UInt samples=0; CGGetDisplayTransferByTable(kCGDirectMainDisplay, capacity, r.data(), g.data(), b.data(), &samples);
  1888. if( samples>1 && samples<=capacity)
  1889. {
  1890. ok=true;
  1891. REP(256)
  1892. {
  1893. Int src=i*(samples-1)/255;
  1894. _gamma_array[0][i]=RoundU(Sat(r[src])*0xFFFF);
  1895. _gamma_array[1][i]=RoundU(Sat(g[src])*0xFFFF);
  1896. _gamma_array[2][i]=RoundU(Sat(b[src])*0xFFFF);
  1897. }
  1898. }
  1899. }
  1900. #elif LINUX
  1901. if(XDisplay)
  1902. {
  1903. Int size=0; if(XF86VidModeGetGammaRampSize(XDisplay, DefaultScreen(XDisplay), &size))
  1904. {
  1905. if(size==256)
  1906. {
  1907. ok=(XF86VidModeGetGammaRamp(XDisplay, DefaultScreen(XDisplay), 256, _gamma_array[0], _gamma_array[1], _gamma_array[2])!=0);
  1908. }else
  1909. if(size>0)
  1910. {
  1911. Memc<UShort> r, g, b; r.setNum(size); g.setNum(size); b.setNum(size);
  1912. if(XF86VidModeGetGammaRamp(XDisplay, DefaultScreen(XDisplay), size, r.data(), g.data(), b.data()))
  1913. {
  1914. ok=true;
  1915. REP(256)
  1916. {
  1917. Int src=i*(size-1)/255;
  1918. _gamma_array[0][i]=r[src];
  1919. _gamma_array[1][i]=g[src];
  1920. _gamma_array[2][i]=b[src];
  1921. }
  1922. }
  1923. }
  1924. }
  1925. }
  1926. #endif
  1927. if(!ok)REP(256)_gamma_array[0][i]=_gamma_array[1][i]=_gamma_array[2][i]=(i*0xFFFF+128)/255;
  1928. }
  1929. void Display::getCaps()
  1930. {
  1931. if(LogInit)LogN("Display.getCaps");
  1932. #if DX9
  1933. D3DDISPLAYMODE DM ; D3D->GetDisplayMode(0, &DM);
  1934. D3DCAPS9 caps; D3D->GetDeviceCaps ( &caps);
  1935. _freq_got =DM.RefreshRate;
  1936. _max_rt =Mid(caps.NumSimultaneousRTs, 1, 255);
  1937. _max_tex_filter =Mid(caps.MaxAnisotropy , 1, 255);
  1938. _max_tex_size =Min(Int(caps.MaxTextureWidth), Int(caps.MaxTextureHeight));
  1939. _tex_pow2 =(FlagTest(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL) ? 1 : FlagTest(caps.TextureCaps, D3DPTEXTURECAPS_POW2) ? 2 : 0); // 0=non-pow2 supported, 1=non-pow2 conditional, 2=non-pow2 not supported (pow2 required)
  1940. _tex_pow2_3d = FlagTest(caps.TextureCaps, D3DPTEXTURECAPS_VOLUMEMAP_POW2);
  1941. _tex_pow2_cube = FlagTest(caps.TextureCaps, D3DPTEXTURECAPS_CUBEMAP_POW2 );
  1942. _shader_tex_lod =(D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion)>=3);
  1943. _mrt_const_bit_size=((caps.PrimitiveMiscCaps&D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS )==0);
  1944. _mrt_post_process =((caps.PrimitiveMiscCaps&D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING)!=0
  1945. && validUsage(D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, IMAGE_B8G8R8A8)
  1946. && validUsage(D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, IMAGE_F32 )
  1947. && validUsage(D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, IMAGE_F16_4 ));
  1948. #elif DX11
  1949. // values taken from - https://msdn.microsoft.com/en-us/library/windows/desktop/ff476876(v=vs.85).aspx
  1950. DXGI_SWAP_CHAIN_DESC desc;
  1951. SwapChain->GetDesc(&desc); _freq_got=(desc.BufferDesc.RefreshRate.Denominator ? RoundPos(Flt(desc.BufferDesc.RefreshRate.Numerator)/desc.BufferDesc.RefreshRate.Denominator) : 0);
  1952. _max_rt =((FeatureLevel>=D3D_FEATURE_LEVEL_10_0) ? 8 : (FeatureLevel>=D3D_FEATURE_LEVEL_9_3) ? 4 : 1);
  1953. _max_tex_filter =((FeatureLevel>=D3D_FEATURE_LEVEL_9_2 ) ? 16 : 2);
  1954. _max_tex_size =((FeatureLevel>=D3D_FEATURE_LEVEL_11_0) ? 16384 : (FeatureLevel>=D3D_FEATURE_LEVEL_10_0) ? 8192 : (FeatureLevel>=D3D_FEATURE_LEVEL_9_3) ? 4096 : 2048);
  1955. _tex_pow2 = // 0=non-pow2 supported, 1=non-pow2 conditional, 2=non-pow2 not supported (pow2 required)
  1956. _tex_pow2_3d =
  1957. _tex_pow2_cube =(FeatureLevel<=D3D_FEATURE_LEVEL_9_3);
  1958. _shader_tex_lod =(FeatureLevel>=D3D_FEATURE_LEVEL_10_0);
  1959. _mrt_const_bit_size=false;
  1960. _mrt_post_process =true ;
  1961. #elif GL
  1962. CChar8 *ext=(CChar8*)glGetString(GL_EXTENSIONS);
  1963. _max_tex_size =2048; glGetIntegerv(GL_MAX_TEXTURE_SIZE , &_max_tex_size );
  1964. int aniso = 16; glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY, & aniso ); _max_tex_filter =Mid(aniso , 1, 255);
  1965. int max_vtx_attrib = 0; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS , & max_vtx_attrib ); _max_vtx_attribs=Mid(max_vtx_attrib, 0, 255);
  1966. if(shaderModelGLES2())_max_rt=1;else // we don't support MRT on GLES2 (there's no 'glDrawBuffers' function)
  1967. {
  1968. int max_draw_buffers=1; glGetIntegerv(GL_MAX_DRAW_BUFFERS , &max_draw_buffers);
  1969. int max_col_attach =1; glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_col_attach ); _max_rt=Mid(Min(max_draw_buffers, max_col_attach), 1, 255);
  1970. }
  1971. Bool npot=(notShaderModelGLES2() || Contains(ext, "GL_OES_texture_npot", false, true));
  1972. _tex_pow2 =((npot || Contains(ext, "GL_NV_texture_npot_2D_mipmap", false, true)) ? 0 : 1); // 0=non-pow2 supported, 1=non-pow2 conditional, 2=non-pow2 not supported (pow2 required)
  1973. _tex_pow2_3d = !npot;
  1974. _tex_pow2_cube= !npot;
  1975. _shader_tex_lod =(notShaderModelGLES2() || Contains(ext, "GL_ARB_shader_texture_lod", false, true) || Contains(ext, "GL_EXT_shader_texture_lod", false, true));
  1976. _mrt_const_bit_size=false;
  1977. _mrt_post_process =true ;
  1978. #if VARIABLE_MAX_MATRIX
  1979. int max_vs_vectors=0, max_ps_vectors=0;
  1980. glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS , &max_vs_vectors);
  1981. glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &max_ps_vectors);
  1982. MeshBoneSplit=(Min(max_vs_vectors, max_ps_vectors)<768+256+256); // 768 for ObjMatrix, 256 for ObjVel, 256 extra
  1983. #endif
  1984. #endif
  1985. #if IOS
  1986. _freq_got=[UIScreen mainScreen].maximumFramesPerSecond;
  1987. #elif LINUX
  1988. if(XDisplay)
  1989. {
  1990. int dotclock; XF86VidModeModeLine mode;
  1991. if(XF86VidModeGetModeLine(XDisplay, DefaultScreen(XDisplay), &dotclock, &mode))
  1992. {
  1993. int total=mode.htotal*mode.vtotal;
  1994. _freq_got=(total ? dotclock*1000/total : 0);
  1995. }
  1996. }
  1997. #endif
  1998. if(!Physics.precision())Physics.precision(0); // adjust physics precision when possibility of screen refresh rate change
  1999. densityUpdate(); // max texture size affects max allowed density
  2000. if(_mrt_const_bit_size)_hp_col_rt=_hp_nrm_rt=false; // no need to disable '_hp_lum_rt' and '_lit_col_rt_prec' because those RT's are not used as MRT
  2001. _samples=DisplaySamples(_samples);
  2002. if(Renderer.anyDeferred() && deferredUnavailable())
  2003. {
  2004. if(Renderer.type ()==RT_DEFERRED)Renderer.type (RT_FORWARD);
  2005. if(Water .reflectionRenderer()==RT_DEFERRED)Water .reflectionRenderer(RT_FORWARD);
  2006. }
  2007. }
  2008. /******************************************************************************/
  2009. void Display::after(Bool resize_callback)
  2010. {
  2011. if(LogInit)LogN("Display.after");
  2012. if(!full() // if we're setting window
  2013. #if !WEB // for WEB set size even if we're maximized, because for WEB 'App.maximized' means the browser window and not the canvas size
  2014. && !App.maximized() // which is not maximized
  2015. #endif
  2016. )App._window_size=res();
  2017. if(_gamma)gammaSet(); // force reset gamma
  2018. aspectRatioEx(true, !resize_callback);
  2019. }
  2020. /******************************************************************************/
  2021. void Display::begin()
  2022. {
  2023. #if DX9
  2024. if(D3D)
  2025. {
  2026. D3D->BeginScene();
  2027. D._began=true;
  2028. }
  2029. #endif
  2030. }
  2031. void Display::end()
  2032. {
  2033. #if DX9
  2034. if(D3D)
  2035. {
  2036. D3D->EndScene();
  2037. D._began=false;
  2038. }
  2039. #endif
  2040. }
  2041. Bool Display::flip()
  2042. {
  2043. if(created())
  2044. {
  2045. #if DX9
  2046. end();
  2047. Bool ok=OK(D3D->Present(null, null, null, null));
  2048. begin();
  2049. return ok;
  2050. #elif DX11
  2051. Bool sync=ActualSync(); if(!OK(SwapChain->Present(sync, sync ? 0 : PresentFlags)))return false; // we can use 'DXGI_PRESENT_ALLOW_TEARING' only when "sync==false", do this extra check here, because 'ActualSync' depends on VR which may disconnect after 'SwapChain' was created and 'PresentFlags' already set
  2052. if(SwapChainDesc.SwapEffect!=DXGI_SWAP_EFFECT_DISCARD) // when using swap chain flip mode, 'Present' clears the backbuffer from 'OMSetRenderTargets', so reset it
  2053. D3DC->OMSetRenderTargets(Elms(Renderer._cur_id), Renderer._cur_id, Renderer._cur_ds_id);
  2054. #elif GL
  2055. #if WINDOWS
  2056. SwapBuffers(hDC);
  2057. #elif MAC
  2058. CGLFlushDrawable(MainContext.context); // same as "[[OpenGLView openGLContext] flushBuffer];"
  2059. #elif LINUX
  2060. glXSwapBuffers(XDisplay, App.Hwnd());
  2061. #elif ANDROID
  2062. eglSwapBuffers(GLDisplay, MainContext.surface);
  2063. #elif IOS
  2064. glBindRenderbuffer(GL_RENDERBUFFER, Renderer._main._rb);
  2065. [MainContext.context presentRenderbuffer:GL_RENDERBUFFER];
  2066. #elif WEB
  2067. // this is done automatically on Web
  2068. #endif
  2069. #endif
  2070. }
  2071. return true;
  2072. }
  2073. void Display::flush()
  2074. {
  2075. if(created())
  2076. {
  2077. #if DX9
  2078. if(Query)
  2079. {
  2080. Query->Issue(D3DISSUE_END);
  2081. while(S_FALSE==Query->GetData(null, 0, D3DGETDATA_FLUSH));
  2082. }
  2083. #elif DX11
  2084. D3DC->Flush();
  2085. #elif GL
  2086. glFlush();
  2087. #endif
  2088. }
  2089. }
  2090. void Display::finish()
  2091. {
  2092. if(created())
  2093. {
  2094. #if DX9
  2095. if(Query)
  2096. {
  2097. Query->Issue(D3DISSUE_END);
  2098. while(S_FALSE==Query->GetData(null, 0, D3DGETDATA_FLUSH));
  2099. }
  2100. #elif DX11
  2101. if(Query)
  2102. {
  2103. D3DC->End(Query);
  2104. BOOL done=FALSE; while(OK(D3DC->GetData(Query, &done, SIZE(done), 0)) && !done);
  2105. }
  2106. #elif GL
  2107. glFinish();
  2108. #endif
  2109. }
  2110. }
  2111. /******************************************************************************/
  2112. // SETTINGS
  2113. /******************************************************************************/
  2114. void Display::adjustWindow()
  2115. {
  2116. RectI full, work; VecI2 max_normal_win_client_size, maximized_win_client_size;
  2117. #if FORCE_MAIN_DISPLAY
  2118. if(D.full())mainMonitor(full, work, max_normal_win_client_size, maximized_win_client_size);else
  2119. #endif
  2120. curMonitor(full, work, max_normal_win_client_size, maximized_win_client_size);
  2121. #if DEBUG && 0
  2122. LogN(S+"full:"+full.asText()+", work:"+work.asText()+", App._window_pos:"+App._window_pos+", D.res:"+D.res());
  2123. #endif
  2124. #if WINDOWS_OLD
  2125. if(D.full()) // fullscreen
  2126. {
  2127. SetWindowLongPtr(App.Hwnd(), GWL_STYLE , App._style_full);
  2128. SetWindowPos (App.Hwnd(), HWND_TOPMOST, full.min.x, full.min.y, resW(), resH(), 0);
  2129. }else
  2130. if(resW()>=maximized_win_client_size.x && resH()>=maximized_win_client_size.y) // maximized
  2131. {
  2132. SetWindowLongPtr(App.Hwnd(), GWL_STYLE, App._style_window_maximized);
  2133. #if 0 // this doesn't work as expected
  2134. SetWindowPos (App.Hwnd(), HWND_TOP , work.min.x+App._bound_maximized.min.x, work.min.y-App._bound_maximized.max.y, resW()+App._bound_maximized.w(), resH()+App._bound_maximized.h(), SWP_NOACTIVATE);
  2135. #else
  2136. SetWindowPos (App.Hwnd(), HWND_TOP , work.min.x+App._bound_maximized.min.x, work.min.y-App._bound_maximized.max.y, resW()+App._bound_maximized.max.x, resH()-App._bound_maximized.min.y, SWP_NOACTIVATE);
  2137. #endif
  2138. }else // normal window
  2139. {
  2140. Int w=resW()+App._bound.w(),
  2141. h=resH()+App._bound.h();
  2142. if(App._window_pos.x==INT_MAX){if(App.x<=-1)App._window_pos.x=work.min.x;else if(!App.x)App._window_pos.x=work.centerXI()-w/2;else App._window_pos.x=work.max.x-w;}
  2143. if(App._window_pos.y==INT_MAX){if(App.y>= 1)App._window_pos.y=work.min.y;else if(!App.y)App._window_pos.y=work.centerYI()-h/2;else App._window_pos.y=work.max.y-h;}
  2144. // make sure the window is not completely outside of working area
  2145. const Int b=32; Int r=b;
  2146. if(!(App.flag&APP_NO_TITLE_BAR)) // has bar
  2147. {
  2148. Int size=GetSystemMetrics(SM_CXSIZE); // TODO: this should be OK because we're DPI-Aware, however it doesn't work OK
  2149. /*if(HDC hdc=GetDC(App.Hwnd()))
  2150. {
  2151. size=DivCeil(size*GetDeviceCaps(hdc, LOGPIXELSX), 96);
  2152. ReleaseDC(App.Hwnd(), hdc);
  2153. }*/
  2154. if(!(App.flag& APP_NO_CLOSE ))r+=size ; // has close button
  2155. if( App.flag&(APP_MINIMIZABLE|APP_MAXIMIZABLE))r+=size*2; // has minimize or maximize button (if any is enabled, then both will appear)
  2156. }
  2157. if(App._window_pos.x+b>work.max.x)App._window_pos.x=Max(work.min.x, work.max.x-b);else{Int p=App._window_pos.x+w; if(p-r<work.min.x)App._window_pos.x=Min(work.min.x+r, work.max.x)-w;}
  2158. if(App._window_pos.y+b>work.max.y)App._window_pos.y=Max(work.min.y, work.max.y-b);else{Int p=App._window_pos.y+h; if(p-b<work.min.y)App._window_pos.y=Min(work.min.y+b, work.max.y)-h;}
  2159. SetWindowLongPtr(App.Hwnd(), GWL_STYLE , App._style_window);
  2160. SetWindowPos (App.Hwnd(), HWND_NOTOPMOST, App._window_pos.x, App._window_pos.y, w, h, SWP_NOACTIVATE);
  2161. }
  2162. #elif MAC
  2163. if(!D.full()) // on Mac don't adjust the window size/pos when in fullscreen because it's not needed, additionally it will cancel out original window position when later restoring
  2164. {
  2165. WindowSize(resW(), resH(), true);
  2166. RectI r=WindowRect(false); WindowPos(r.min.x, r.min.y); // reset position because if Application was created in fullscreen mode, and then we've toggled to windowed mode, then because system MenuBar was hidden for fullscreen, App's window position could've gone underneath the menu bar, for the windowed mode the bar is unhidden, however just applying new window size doesn't reposition it so it doesn't collide with the MenuBar, that's why we need to trigger repositioning it manually, avoid calling "WindowMove(0, 0)" because that internally does nothing if the delta is zero
  2167. }
  2168. #elif LINUX
  2169. // set window fullscreen state
  2170. if(App.hwnd())
  2171. {
  2172. // setting fullscreen mode will fail if window is not resizable, so force it to be just for this operation
  2173. Bool set_resizable=(D.full() && !(App.flag&APP_RESIZABLE));
  2174. if( set_resizable)App.setWindowFlags(true);
  2175. #define _NET_WM_STATE_REMOVE 0
  2176. #define _NET_WM_STATE_ADD 1
  2177. #define _NET_WM_STATE_TOGGLE 2
  2178. Atom FIND_ATOM(_NET_WM_STATE), FIND_ATOM(_NET_WM_STATE_FULLSCREEN);
  2179. XEvent e; Zero(e);
  2180. e.xclient.type =ClientMessage;
  2181. e.xclient.window =App.Hwnd();
  2182. e.xclient.message_type=_NET_WM_STATE;
  2183. e.xclient.format =32;
  2184. e.xclient.data.l[0] =(D.full() ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE);
  2185. e.xclient.data.l[1] =_NET_WM_STATE_FULLSCREEN;
  2186. e.xclient.data.l[2] =0;
  2187. e.xclient.data.l[3] =1;
  2188. XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false, SubstructureRedirectMask|SubstructureNotifyMask, &e);
  2189. XSync(XDisplay, false);
  2190. if(set_resizable)App.setWindowFlags();
  2191. }
  2192. // set window size
  2193. if(!D.full())WindowSize(resW(), resH(), true);
  2194. #endif
  2195. }
  2196. Display::RESET_RESULT Display::modeTry(Int w, Int h, Int full)
  2197. {
  2198. if(w <=0)w= T.resW();
  2199. if(h <=0)h= T.resH();
  2200. Bool f=((full< 0) ? T.full() : (full!=0));
  2201. if(w==resW() && h==resH() && f==T.full())return RESET_OK;
  2202. if(created())
  2203. {
  2204. SyncLocker locker(_lock);
  2205. Int cur_x =T.resW(); T._res.x=w;
  2206. Int cur_y =T.resH(); T._res.y=h;
  2207. Bool cur_full=T.full(); T._full =f;
  2208. #if WEB
  2209. Renderer._main.forceInfo(w, h, 1, Renderer._main.type(), Renderer._main.mode()); // '_main_ds' will be set in 'rtCreate'
  2210. #endif
  2211. if(!findMode())return RESET_DEVICE_NOT_CREATED;
  2212. if(cur_x==T.resW() && cur_y==T.resH() && cur_full==T.full())return RESET_OK; // new mode matches the current one, need to check again since 'findMode' may have adjusted the T.resW T.resH T.full values
  2213. RESET_RESULT result=ResetTry(); if(result!=RESET_OK)return result ; // reset the device
  2214. Ms.clipUpdate();
  2215. }else
  2216. {
  2217. T._res.x=w;
  2218. T._res.y=h;
  2219. T._full =f;
  2220. densityUpdate();
  2221. }
  2222. return RESET_OK;
  2223. }
  2224. void Display::modeSet(Int w, Int h, Int full)
  2225. {
  2226. RESET_RESULT result=modeTry(w, h, full);
  2227. if(result!=RESET_OK)ResetFailed(result, result);
  2228. }
  2229. Display& Display::mode(Int w, Int h, Int full)
  2230. {
  2231. #if WINDOWS_NEW // on WindowsNew we can only request a change on the window
  2232. if(created())
  2233. {
  2234. RequestDisplayMode(w, h, full);
  2235. return T;
  2236. }
  2237. #elif MOBILE
  2238. return T; // we can't manually change mode for mobile platforms at all because they're always fullscreen
  2239. #elif WEB
  2240. if(created())
  2241. {
  2242. Bool f=((full<0) ? T.full() : (full!=0));
  2243. if(T.full()!=f)
  2244. {
  2245. if(f)
  2246. {
  2247. EmscriptenFullscreenStrategy f; Zero(f);
  2248. f.scaleMode =EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
  2249. f.canvasResolutionScaleMode=EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
  2250. f.filteringMode =EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST;
  2251. emscripten_request_fullscreen_strategy(null, true, &f);
  2252. return T; // after request was made, return and wait until Emscripten handles it
  2253. }else
  2254. {
  2255. emscripten_exit_fullscreen();
  2256. return T; // after request was made, return and wait until Emscripten handles it, we can't process canvas resizes here, because Emscripten still needs to do some stuff
  2257. }
  2258. }
  2259. if(w<=0)w=resW();
  2260. if(h<=0)h=resH();
  2261. if(f // can't change resolution when in full screen mode
  2262. || w==resW() && h==resH() // nothing to change
  2263. )return T;
  2264. // resize canvas
  2265. Flt zoom=browserZoom();
  2266. Vec2 css_size=VecI2(w, h)/zoom; // calculate css
  2267. emscripten_set_element_css_size (null, css_size.x, css_size.y); // this accepts floating point sizes
  2268. emscripten_set_canvas_element_size(null, w, h);
  2269. extern Flt ScreenScale; ScreenScale=zoom; // here we maintain 1:1 pixel ratio so we can set scale to zoom
  2270. }
  2271. #endif
  2272. Int cur_w =T.resW(),
  2273. cur_h =T.resH(),
  2274. cur_full=T.full();
  2275. RESET_RESULT result0=modeTry(w, h, full); // try to set new mode
  2276. if(result0!=RESET_OK)
  2277. {
  2278. RESET_RESULT result1=modeTry(cur_w, cur_h, cur_full); // try to set old mode
  2279. if(result1!=RESET_OK)ResetFailed(result0, result1);
  2280. }
  2281. return T;
  2282. }
  2283. Display& Display::toggle(Bool window_size)
  2284. {
  2285. if(!created())_full^=1;else
  2286. {
  2287. if(full() )mode(App._window_size.x, App._window_size.y, false);else // if app was in fullscreen then set windowed mode based on last known window size
  2288. if(window_size)mode(App._window_size.x, App._window_size.y, true );else // if set fullscreen using last known window size
  2289. { // set full screen based on resolution of the monitor
  2290. #if FORCE_MAIN_DISPLAY
  2291. mode(screenW(), screenH(), true);
  2292. #else
  2293. RectI full, work; VecI2 max_normal_win_client_size, maximized_win_client_size;
  2294. curMonitor(full, work, max_normal_win_client_size, maximized_win_client_size);
  2295. mode(full.w(), full.h(), true);
  2296. #endif
  2297. }
  2298. }
  2299. return T;
  2300. }
  2301. Display& Display::full(Bool full, Bool window_size)
  2302. {
  2303. if(!created())T._full=full;else
  2304. if(full!=T.full())toggle(window_size);
  2305. return T;
  2306. }
  2307. Bool Display::highMonitorPrecision()C {return monitorPrecision()>IMAGE_PRECISION_8 && full() && exclusive();} // on Windows we need fullscreen and exclusive to be able to really enable it, without it, it will be only 8-bit
  2308. Display& Display:: monitorPrecision(IMAGE_PRECISION precision)
  2309. {
  2310. Clamp(precision, IMAGE_PRECISION_8, IMAGE_PRECISION(IMAGE_PRECISION_NUM-1));
  2311. if(!created())_monitor_prec=precision;else
  2312. if(monitorPrecision()!=precision){_monitor_prec=precision; if(findMode())Reset();}
  2313. return T;
  2314. }
  2315. Display& Display::exclusive(Bool exclusive)
  2316. {
  2317. if(_exclusive!=exclusive)
  2318. {
  2319. _exclusive=exclusive;
  2320. #if WINDOWS_OLD && (DX9 || DX11)
  2321. if(created() && full())
  2322. {
  2323. #if DX11 // on DX11 have to disable 'SetFullscreenState' first, otherwise custom resolutions may get reverted to desktop resolution
  2324. if(SwapChain)SwapChain->SetFullscreenState(false, null);
  2325. #endif
  2326. if(findMode())Reset();
  2327. }
  2328. #endif
  2329. }
  2330. return T;
  2331. }
  2332. /******************************************************************************/
  2333. void Display::validateCoords(Int eye)
  2334. {
  2335. if(Sh.h_Coords)
  2336. {
  2337. Vec2 coords_mul(1/w(), 1/h()),
  2338. coords_add=0; // or coords_mul*_draw_offset;
  2339. if(InRange(eye, 2)) // stereo
  2340. {
  2341. coords_add.x+=ProjMatrixEyeOffset[eye];
  2342. coords_mul.x*=2;
  2343. }else
  2344. if(!_view_active.full)
  2345. {
  2346. Vec2 ds_vs(Flt(Renderer.resW())/_view_active.recti.w(),
  2347. Flt(Renderer.resH())/_view_active.recti.h());
  2348. coords_mul *=ds_vs;
  2349. coords_add *=ds_vs;
  2350. coords_add.x-=Flt(_view_active.recti.min.x+_view_active.recti.max.x-Renderer.resW())/_view_active.recti.w();
  2351. coords_add.y+=Flt(_view_active.recti.min.y+_view_active.recti.max.y-Renderer.resH())/_view_active.recti.h();
  2352. }
  2353. #if DX9
  2354. coords_add.x-=1.0f/_view_active.recti.w();
  2355. coords_add.y+=1.0f/_view_active.recti.h();
  2356. #elif GL
  2357. if(!mainFBO()) // in OpenGL when drawing to custom RenderTarget the 'dest.pos.y' must be flipped
  2358. {
  2359. CHS(coords_mul.y);
  2360. CHS(coords_add.y);
  2361. }
  2362. #endif
  2363. Sh.h_Coords->setConditional(Vec4(coords_mul, coords_add));
  2364. }
  2365. }
  2366. /******************************************************************************/
  2367. void Display::sizeChanged()
  2368. {
  2369. D._size =D._unscaled_size/D._scale;
  2370. D._size2=D._size *2;
  2371. C VecI2 &res=((VR.active() && D._allow_stereo) ? VR.guiRes() : D.res());
  2372. D._pixel_size .set( w2()/res.x, h2()/res.y); D._pixel_size_2=D._pixel_size*0.5f;
  2373. D._pixel_size_inv.set(res.x/ w2(), res.y/ h2());
  2374. // this is used by mouse/touch pointers
  2375. D._window_pixel_to_screen_mul.set( D.w2()/(D.resW()-1), // div by "resW-1" so we can have full -D.w .. D.w range !! if this is changed for some reason, then adjust 'rect.max' in 'Ms.clipUpdate' !!
  2376. -D.h2()/(D.resH()-1)); // div by "resH-1" so we can have full -D.h .. D.h range !! if this is changed for some reason, then adjust 'rect.max' in 'Ms.clipUpdate' !!
  2377. D._window_pixel_to_screen_add.set(-D.w(), D.h());
  2378. if(VR.active()) // because VR Gui Rect may be different than Window Rect, we need to adjust scaling
  2379. {
  2380. // '_window_pixel_to_screen_scale' is set so that 'windowPixelToScreen' will always point to VR 'GuiTexture', no matter if 'D._allow_stereo' is enabled/disabled (drawing to 'GuiTexture' or System Window)
  2381. D._window_pixel_to_screen_mul*=D._window_pixel_to_screen_scale;
  2382. D._window_pixel_to_screen_add*=D._window_pixel_to_screen_scale;
  2383. }
  2384. viewReset();
  2385. }
  2386. Display& Display::scale(Flt scale)
  2387. {
  2388. if(T._scale!=scale)
  2389. {
  2390. T._scale=scale;
  2391. if(created())
  2392. {
  2393. Vec2 old_size=size();
  2394. sizeChanged();
  2395. screenChanged(old_size.x, old_size.y);
  2396. }
  2397. }
  2398. return T;
  2399. }
  2400. void Display::densityUpdate()
  2401. {
  2402. again:
  2403. _render_res=ByteScale2Res(res(), densityByte());
  2404. if(_render_res.max()>maxTexSize() && maxTexSize()>0 && densityUpsample()) // if calculated size exceeds possible max texture size, then we need to clamp the density, don't try to go below 1.0 density
  2405. {
  2406. Flt max_density_f=Flt(maxTexSize())/res().max();
  2407. Byte max_density =FltToByteScale2(max_density_f);
  2408. if(_density>max_density)_density=max_density;else _density--;
  2409. goto again;
  2410. }
  2411. }
  2412. Bool Display::densityFast(Byte density)
  2413. {
  2414. if(density!=densityByte())
  2415. {
  2416. T._density=density;
  2417. densityUpdate();
  2418. return true;
  2419. }
  2420. return false;
  2421. }
  2422. Flt Display::density( )C {return ByteScale2ToFlt(densityByte());}
  2423. Display& Display::density(Flt density)
  2424. {
  2425. Byte b=FltToByteScale2(density);
  2426. if(densityFast(b))Renderer.rtClean();
  2427. return T;
  2428. }
  2429. Display& Display::densityFilter(FILTER_TYPE filter) {_density_filter=filter; return T;}
  2430. Display& Display::samples(Byte samples)
  2431. {
  2432. samples=DisplaySamples(samples);
  2433. if(T._samples!=samples){T._samples=samples; Renderer.rtClean();}
  2434. return T;
  2435. }
  2436. /******************************************************************************/
  2437. Display& Display::highPrecColRT(Bool on)
  2438. {
  2439. if(created() && _mrt_const_bit_size)on=false;
  2440. if(_hp_col_rt!=on){_hp_col_rt=on; Renderer.rtClean();}
  2441. return T;
  2442. }
  2443. Display& Display::highPrecNrmRT(Bool on)
  2444. {
  2445. if(created() && _mrt_const_bit_size)on=false;
  2446. if(_hp_nrm_rt!=on){_hp_nrm_rt=on; Renderer.rtClean();}
  2447. return T;
  2448. }
  2449. Display& Display::highPrecLumRT(Bool on)
  2450. {
  2451. // this does not require '_mrt_const_bit_size' because it's always used as a single RT and not one of many
  2452. if(_hp_lum_rt!=on){_hp_lum_rt=on; Renderer.rtClean();}
  2453. return T;
  2454. }
  2455. Display& Display::litColRTPrecision(IMAGE_PRECISION precision)
  2456. {
  2457. // this does not require '_mrt_const_bit_size' because it's always used as a single RT and not one of many
  2458. Clamp(precision, IMAGE_PRECISION_8, IMAGE_PRECISION(IMAGE_PRECISION_NUM-1));
  2459. if(_lit_col_rt_prec!=precision){_lit_col_rt_prec=precision; Renderer.rtClean();}
  2460. return T;
  2461. }
  2462. Display& Display::highPrecNrmCalc(Bool on) {_hp_nrm_calc=on; return T;}
  2463. /******************************************************************************/
  2464. void Display::setSync()
  2465. {
  2466. SyncLocker locker(_lock);
  2467. if(created())
  2468. {
  2469. #if DX9 || DX11
  2470. if(findMode())Reset();
  2471. #elif GL
  2472. Bool sync=(T.sync() && !VR.active()); // if using VR then we have to disable screen sync, because HMD will handle this according to its own refresh rate
  2473. #if WINDOWS
  2474. wglSwapIntervalEXT(sync);
  2475. #elif MAC
  2476. Int value=sync; CGLSetParameter(MainContext.context, kCGLCPSwapInterval, &value);
  2477. #elif LINUX
  2478. if(glXSwapInterval)glXSwapInterval(XDisplay, App.Hwnd(), sync);
  2479. #elif ANDROID
  2480. eglSwapInterval(GLDisplay, sync);
  2481. #elif WEB
  2482. if(sync)emscripten_set_main_loop_timing(EM_TIMING_RAF , 1);
  2483. else emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0); // however be careful as on WEB disabling sync introduces stuttering
  2484. #endif
  2485. #endif
  2486. }
  2487. }
  2488. Display& Display::sync(Bool sync) {if(T._sync!=sync){T._sync=sync; setSync();} return T;}
  2489. /******************************************************************************/
  2490. Display& Display::dither (Bool dither ) { if(T._dither !=dither ){T._dither =dither ; } return T;}
  2491. Display& Display::maxLights (Byte max ) {Clamp(max, 0, 255); if(T._max_lights !=max ){T._max_lights =max ; } return T;}
  2492. Display& Display::texMacro (Bool use ) { if(T._tex_macro !=use ){T._tex_macro =use ; setShader();} return T;}
  2493. Display& Display::texDetail (TEXTURE_USAGE usage ) {Clamp(usage, TEX_USE_DISABLE, TEXTURE_USAGE(TEX_USE_NUM-1)); if(T._tex_detail !=usage ){T._tex_detail =usage ; setShader();} return T;}
  2494. Display& Display::texReflection (TEXTURE_USAGE usage ) {Clamp(usage, TEX_USE_DISABLE, TEXTURE_USAGE(TEX_USE_NUM-1)); if(T._tex_reflect !=usage ){T._tex_reflect =usage ; setShader();} return T;}
  2495. Display& Display::materialBlend (Bool per_pixel) { if(T._mtrl_blend !=per_pixel){T._mtrl_blend =per_pixel; setShader();} return T;}
  2496. Display& Display::bendLeafs (Bool on ) { if(T._bend_leafs !=on ){T._bend_leafs =on ; setShader();} return T;}
  2497. Display& Display::outlineAffectSky (Bool on ) { if(T._outline_sky !=on ){T._outline_sky =on ; } return T;}
  2498. Display& Display::outlineMode (EDGE_DETECT_MODE mode ) {Clamp(mode, EDGE_DETECT_NONE, EDGE_DETECT_MODE(EDGE_DETECT_NUM-1)); if(T._outline_mode !=mode ){T._outline_mode =mode ; } return T;}
  2499. Display& Display::particlesSoft (Bool on ) { if(T._particles_soft !=on ){T._particles_soft =on ; } return T;}
  2500. Display& Display::particlesSmoothAnim(Bool on ) { if(T._particles_smooth!=on ){T._particles_smooth=on ; } return T;}
  2501. Display& Display::eyeDistance (Flt dist ) { if(T._eye_dist !=dist ){T._eye_dist =dist ; } return T;}
  2502. Display& Display::edgeDetect(EDGE_DETECT_MODE mode)
  2503. {
  2504. Clamp(mode, EDGE_DETECT_NONE, EDGE_DETECT_MODE(EDGE_DETECT_NUM-1)); if(T._edge_detect!=mode)
  2505. {
  2506. T._edge_detect=mode; if(!Sh.h_EdgeDetect && mode && created())
  2507. {
  2508. Sh.h_EdgeDetect =Sh.get("EdgeDetect");
  2509. Sh.h_EdgeDetectApply=Sh.get("EdgeDetectApply");
  2510. }
  2511. }
  2512. return T;
  2513. }
  2514. Display& Display::edgeSoften(EDGE_SOFTEN_MODE mode)
  2515. {
  2516. Clamp(mode, EDGE_SOFTEN_NONE, EDGE_SOFTEN_MODE(EDGE_SOFTEN_NUM-1)); if(T._edge_soften!=mode)
  2517. {
  2518. T._edge_soften=mode; if(created())switch(mode) // techniques can be null if failed to load
  2519. {
  2520. case EDGE_SOFTEN_FXAA: if(!Sh.h_FXAA)
  2521. {
  2522. Sh.h_FXAA=Sh.find("FXAA");
  2523. }break;
  2524. #if SUPPORT_MLAA
  2525. case EDGE_SOFTEN_MLAA: if(!Renderer._mlaa_area)
  2526. {
  2527. Sh.h_MLAAEdge =Sh.find("MLAAEdge" );
  2528. Sh.h_MLAABlend=Sh.find("MLAABlend");
  2529. Sh.h_MLAA =Sh.find("MLAA" );
  2530. Renderer._mlaa_area.get("Img/MLAA Area.img");
  2531. }break;
  2532. #endif
  2533. case EDGE_SOFTEN_SMAA: if(!Renderer._smaa_area)
  2534. {
  2535. Sh.h_SMAAEdge =Sh.find("SMAAEdgeColor"); // use 'SMAAEdgeColor' instead of 'SMAAEdgeLuma' to differentiate between different colors
  2536. Sh.h_SMAABlend=Sh.find("SMAABlend" );
  2537. Sh.h_SMAA =Sh.find("SMAA" );
  2538. Sh.h_SMAAThreshold=GetShaderParam("SMAAThreshold"); Sh.h_SMAAThreshold->set(D.smaaThreshold());
  2539. Renderer._smaa_area .get("Img/SMAA Area.img");
  2540. Renderer._smaa_search.get("Img/SMAA Search.img");
  2541. }break;
  2542. }
  2543. }
  2544. return T;
  2545. }
  2546. Display& Display::smaaThreshold(Flt threshold)
  2547. {
  2548. SAT(threshold); _smaa_threshold=threshold; if(Sh.h_SMAAThreshold)Sh.h_SMAAThreshold->setConditional(_smaa_threshold); return T;
  2549. }
  2550. Int Display::secondaryOpenGLContexts( )C {return GPU_API(0, 0, SecondaryContexts.elms());}
  2551. Display& Display::secondaryOpenGLContexts(Byte contexts)
  2552. {
  2553. #if GL && HAS_THREADS
  2554. if(!created())SecondaryContexts.setNum(contexts);
  2555. #endif
  2556. return T;
  2557. }
  2558. Bool Display::canUseGPUDataOnSecondaryThread()C
  2559. {
  2560. #if GL
  2561. return created() && SecondaryContexts.elms(); // was created and there are some secondary GL contexts
  2562. #else
  2563. return true;
  2564. #endif
  2565. }
  2566. /******************************************************************************/
  2567. Display& Display::aspectMode(ASPECT_MODE mode)
  2568. {
  2569. Clamp(mode, ASPECT_MODE(0), ASPECT_MODE(ASPECT_NUM-1));
  2570. if(T._aspect_mode!=mode)
  2571. {
  2572. T._aspect_mode=mode;
  2573. aspectRatioEx();
  2574. }
  2575. return T;
  2576. }
  2577. void Display::aspectRatioEx(Bool force, Bool quiet)
  2578. {
  2579. Flt aspect_ratio=_aspect_ratio_want;
  2580. #if DESKTOP || WEB
  2581. RectI full, work; VecI2 max_normal_win_client_size, maximized_win_client_size;
  2582. curMonitor(full, work, max_normal_win_client_size, maximized_win_client_size); // calculate based on current monitor, as connected monitors may have different aspects
  2583. VecI2 size=full.size(); Flt desktop_aspect=(size.y ? Flt(size.x)/size.y : 1);
  2584. if(aspect_ratio<=EPS)aspect_ratio=desktop_aspect; // if not specified then use default
  2585. #else
  2586. Flt desktop_aspect=Renderer._main.aspect();
  2587. aspect_ratio =Renderer._main.aspect();
  2588. #endif
  2589. if(T._aspect_ratio!=aspect_ratio || force)
  2590. {
  2591. T._aspect_ratio=aspect_ratio;
  2592. if(created())
  2593. {
  2594. Bool vr=(VR.active() && _allow_stereo);
  2595. #if DESKTOP || WEB
  2596. Flt window_aspect=Flt(resW())/resH(),
  2597. #else
  2598. Flt window_aspect=Renderer._main.aspect(),
  2599. #endif
  2600. vr_aspect=Flt(VR.guiRes().x)/VR.guiRes().y,
  2601. mono_aspect=(D.full() ? aspect_ratio : aspect_ratio*window_aspect/desktop_aspect),
  2602. aspect=(vr ? vr_aspect : mono_aspect);
  2603. Vec2 old_size=D.size();
  2604. switch(aspectMode())
  2605. {
  2606. default : aspect_y: _unscaled_size.y=1; _unscaled_size.x=_unscaled_size.y*aspect; break; // ASPECT_Y
  2607. case ASPECT_X : aspect_x: _unscaled_size.x=1; _unscaled_size.y=_unscaled_size.x/aspect; break;
  2608. case ASPECT_SMALLER: if(aspect>=1)goto aspect_y; goto aspect_x;
  2609. }
  2610. T._pixel_aspect=(vr ? 1 : D.full() ? aspect_ratio/window_aspect : aspect_ratio/desktop_aspect);
  2611. // '_window_pixel_to_screen_scale' is set so that 'windowPixelToScreen' will always point to VR 'GuiTexture', no matter if 'D._allow_stereo' is enabled/disabled (drawing to 'GuiTexture' or System Window)
  2612. if(!VR.active())_window_pixel_to_screen_scale=1;else
  2613. if( vr)
  2614. {
  2615. if(mono_aspect>vr_aspect)_window_pixel_to_screen_scale.set(mono_aspect/vr_aspect, 1);
  2616. else _window_pixel_to_screen_scale.set(1, vr_aspect/mono_aspect);
  2617. }else
  2618. {
  2619. if(mono_aspect>vr_aspect)_window_pixel_to_screen_scale=1;
  2620. else _window_pixel_to_screen_scale=vr_aspect/mono_aspect;
  2621. }
  2622. sizeChanged();
  2623. if(!quiet)screenChanged(old_size.x, old_size.y);
  2624. }
  2625. }
  2626. }
  2627. Display& Display::aspectRatio(Flt aspect_ratio)
  2628. {
  2629. T._aspect_ratio_want=Max(0, aspect_ratio);
  2630. aspectRatioEx(false);
  2631. return T;
  2632. }
  2633. /******************************************************************************/
  2634. Display& Display::texFilter(Byte filter)
  2635. {
  2636. if(created())MIN(filter, maxTexFilter());
  2637. if(T._tex_filter!=filter)
  2638. {
  2639. T._tex_filter=filter;
  2640. if(created())
  2641. {
  2642. #if DX9
  2643. // texture filtering is set during rendering
  2644. #elif DX11
  2645. CreateAnisotropicSampler();
  2646. #elif GL
  2647. Images.lock (); REPA(Images)Images.lockedData(i).setGLParams();
  2648. Images.unlock();
  2649. #endif
  2650. }
  2651. }
  2652. return T;
  2653. }
  2654. Display& Display::texMipFilter(Bool on)
  2655. {
  2656. if(T._tex_mip_filter!=on)
  2657. {
  2658. T._tex_mip_filter=on;
  2659. if(created())
  2660. {
  2661. #if DX9
  2662. // texture filtering is set during rendering
  2663. #elif DX11
  2664. CreateAnisotropicSampler();
  2665. #elif GL
  2666. Images.lock (); REPA(Images)Images.lockedData(i).setGLParams();
  2667. Images.unlock();
  2668. #endif
  2669. }
  2670. }
  2671. return T;
  2672. }
  2673. Display& Display::texLod(Byte lod)
  2674. {
  2675. Clamp(lod, 0, 16);
  2676. if(T._tex_lod!=lod)
  2677. {
  2678. T._tex_lod=lod;
  2679. if(created())
  2680. {
  2681. #if DX11
  2682. CreateAnisotropicSampler();
  2683. #endif
  2684. }
  2685. }
  2686. return T;
  2687. }
  2688. /******************************************************************************/
  2689. Display& Display::fontSharpness(Flt value)
  2690. {
  2691. if(T._font_sharpness!=value)
  2692. {
  2693. T._font_sharpness=value;
  2694. if(created())
  2695. {
  2696. #if DX9
  2697. // sampler is set when drawing font
  2698. #elif DX11
  2699. CreateFontSampler();
  2700. #elif GL
  2701. Fonts. lock(); REPA(Fonts)Fonts.lockedData(i).setGLFont();
  2702. Fonts.unlock();
  2703. #endif
  2704. }
  2705. }
  2706. return T;
  2707. }
  2708. /******************************************************************************/
  2709. Display& Display::gamma (Flt gamma) {if(T._gamma!=gamma){T._gamma=gamma; gammaSet();} return T;}
  2710. void Display::gammaSet()
  2711. {
  2712. if(created())
  2713. {
  2714. Flt exp_want=ScaleFactor(gamma()*-0.5f);
  2715. Bool separate=false; // if we can set gamma separately for the system (all monitors) and monitor in use
  2716. #if DX9
  2717. separate=!D3DPP.Windowed; // 'SetGammaRamp' will succeed only in true full screen
  2718. #elif DX11
  2719. #if WINDOWS_OLD
  2720. separate=!SwapChainDesc.Windowed; // 'SetGammaControl' will succeed only in true full screen
  2721. #else
  2722. separate=true;
  2723. #endif
  2724. #endif
  2725. // !! set system gamma first so it won't override device output gamma !!
  2726. Flt exp=(separate ? 1 : exp_want);
  2727. if(_gamma_all || exp!=1) // if custom gamma is already set, or we want to apply custom gamma
  2728. {
  2729. #if WINDOWS_OLD
  2730. SyncLocker locker(_lock);
  2731. if(HDC hdc=GetDC(null))
  2732. {
  2733. UShort gr[3][256];
  2734. REP(256)
  2735. {
  2736. gr[0][i]=RoundU(Pow(_gamma_array[0][i]/65535.0f, exp)*0xFFFF);
  2737. gr[1][i]=RoundU(Pow(_gamma_array[1][i]/65535.0f, exp)*0xFFFF);
  2738. gr[2][i]=RoundU(Pow(_gamma_array[2][i]/65535.0f, exp)*0xFFFF);
  2739. }
  2740. SetDeviceGammaRamp(hdc, gr);
  2741. ReleaseDC(null, hdc);
  2742. }
  2743. #elif MAC
  2744. CGGammaValue r[256], g[256], b[256];
  2745. REP(256)
  2746. {
  2747. r[i]=Pow(_gamma_array[0][i]/65535.0f, exp);
  2748. g[i]=Pow(_gamma_array[1][i]/65535.0f, exp);
  2749. b[i]=Pow(_gamma_array[2][i]/65535.0f, exp);
  2750. }
  2751. SyncLocker locker(_lock);
  2752. CGSetDisplayTransferByTable(kCGDirectMainDisplay, 256, r, g, b);
  2753. #elif LINUX
  2754. UShort r[256], g[256], b[256];
  2755. REP(256)
  2756. {
  2757. r[i]=RoundU(Pow(_gamma_array[0][i]/65535.0f, exp)*0xFFFF);
  2758. g[i]=RoundU(Pow(_gamma_array[1][i]/65535.0f, exp)*0xFFFF);
  2759. b[i]=RoundU(Pow(_gamma_array[2][i]/65535.0f, exp)*0xFFFF);
  2760. }
  2761. XF86VidModeSetGammaRamp(XDisplay, DefaultScreen(XDisplay), 256, r, g, b);
  2762. #endif
  2763. _gamma_all=(exp!=1); // if gamma is set for all monitors
  2764. }
  2765. if(separate)
  2766. {
  2767. exp=exp_want;
  2768. #if DX9
  2769. D3DGAMMARAMP gr;
  2770. REP(256)
  2771. {
  2772. gr.red [i]=RoundU(Pow(_gamma_array[0][i]/65535.0f, exp)*0xFFFF);
  2773. gr.green[i]=RoundU(Pow(_gamma_array[1][i]/65535.0f, exp)*0xFFFF);
  2774. gr.blue [i]=RoundU(Pow(_gamma_array[2][i]/65535.0f, exp)*0xFFFF);
  2775. }
  2776. SyncLocker locker(_lock);
  2777. D3D->SetGammaRamp(0, D3DSGR_CALIBRATE, &gr);
  2778. #elif DX11
  2779. SyncLocker locker(_lock);
  2780. IDXGIOutput *output=null; SwapChain->GetContainingOutput(&output); if(output)
  2781. {
  2782. DXGI_GAMMA_CONTROL gc;
  2783. gc.Scale .Red=gc.Scale .Green=gc.Scale .Blue=1;
  2784. gc.Offset.Red=gc.Offset.Green=gc.Offset.Blue=0;
  2785. REP(256)
  2786. {
  2787. gc.GammaCurve[i].Red =Pow(_gamma_array[0][i]/65535.0f, exp);
  2788. gc.GammaCurve[i].Green=Pow(_gamma_array[1][i]/65535.0f, exp);
  2789. gc.GammaCurve[i].Blue =Pow(_gamma_array[2][i]/65535.0f, exp);
  2790. }
  2791. output->SetGammaControl(&gc);
  2792. output->Release();
  2793. }
  2794. #endif
  2795. }
  2796. }
  2797. }
  2798. /******************************************************************************/
  2799. Display& Display::bumpMode(BUMP_MODE mode)
  2800. {
  2801. Clamp(mode, BUMP_FLAT, BUMP_MODE(BUMP_NUM-1));
  2802. if(_bump_mode!=mode){_bump_mode=mode; setShader();}
  2803. return T;
  2804. }
  2805. /******************************************************************************/
  2806. Display& Display:: glowAllow (Bool allow ) { _glow_allow =allow ; return T;}
  2807. Display& Display::bloomAllow (Bool allow ) { _bloom_allow =allow ; return T;}
  2808. Display& Display::bloomOriginal(Flt original) {MAX (original, 0); _bloom_original=original; return T;}
  2809. Display& Display::bloomScale (Flt scale ) {MAX (scale , 0); _bloom_scale =scale ; return T;}
  2810. Display& Display::bloomCut (Flt cut ) {MAX (cut , 0); _bloom_cut =cut ; return T;}
  2811. Display& Display::bloomHalf (Bool half ) { _bloom_half =half ; return T;}
  2812. Display& Display::bloomBlurs (Byte blurs ) {Clamp(blurs, 0, 4); _bloom_blurs =blurs ; return T;}
  2813. Display& Display::bloomSamples (Bool high ) { _bloom_samples =high ; return T;}
  2814. Display& Display::bloomSaturate(Bool saturate) { _bloom_sat =saturate; return T;}
  2815. Display& Display::bloomMaximum (Bool on ) {if(_bloom_max!=on){ _bloom_max =on ; if(!Sh.h_MaxX && on && created()){Sh.h_MaxX=Sh.get("MaxX"); Sh.h_MaxY=Sh.get("MaxY");}} return T;}
  2816. Bool Display::bloomUsed ( )C{return bloomAllow() && (!Equal(bloomOriginal(), 1, EPS_COL) || !Equal(bloomScale(), 0, EPS_COL));}
  2817. /******************************************************************************/
  2818. Display& Display::volLight(Bool on ) {_vol_light= on ; return T;}
  2819. Display& Display::volAdd (Bool add) {_vol_add = add ; return T;}
  2820. Display& Display::volMax (Flt max) {_vol_max =Max(max, 0); return T;}
  2821. /******************************************************************************/
  2822. Display& Display::shadowMode (SHADOW_MODE mode) {Clamp(mode, SHADOW_NONE, SHADOW_MODE(SHADOW_NUM-1)); _shd_mode=mode; return T;}
  2823. Display& Display::shadowJitter (Bool on ) {if(_shd_jitter!=on){_shd_jitter^=1; shadowJitterSet();} return T;}
  2824. Display& Display::shadowReduceFlicker(Bool reduce ) {_shd_reduce = reduce ; return T;}
  2825. Display& Display::shadowFrac (Flt frac ) {_shd_frac =Sat(frac ); return T;}
  2826. Display& Display::shadowFade (Flt fade ) {_shd_fade =Sat(fade ); return T;}
  2827. Display& Display::shadowSoft (Byte soft ) {_shd_soft =Min(soft , SHADOW_SOFT_NUM-1); return T;}
  2828. Display& Display::shadowMapNum (Byte map_num) {_shd_map_num =Mid(map_num, 1, 6 ); return T;}
  2829. Display& Display::shadowMapSizeLocal (Flt frac ) {_shd_map_size_l=Sat(frac ); return T;}
  2830. Display& Display::shadowMapSizeCone (Flt factor ) {_shd_map_size_c=Mid(factor , 0.0f, 2.0f ); return T;}
  2831. Display& Display::shadowMapSplit (C Vec2 &factor ) {_shd_map_split .set(Max(2, factor.x), Max(0, factor.y)); return T;}
  2832. Display& Display::shadowMapSize(Int map_size)
  2833. {
  2834. MAX(map_size, 0); if(_shd_map_size!=map_size){_shd_map_size=map_size; if(created())Renderer.createShadowMap();}
  2835. return T;
  2836. }
  2837. Display& Display::cloudsMapSize(Int map_size)
  2838. {
  2839. MAX(map_size, 0); if(_cld_map_size!=map_size){_cld_map_size=map_size; if(created())Renderer.createShadowMap();}
  2840. return T;
  2841. }
  2842. Int Display::shadowMapNumActual()C
  2843. {
  2844. return (Renderer._cur_type==RT_FORWARD) ? Ceil2(shadowMapNum()) // align to even numbers on RT_FORWARD
  2845. : shadowMapNum();
  2846. }
  2847. Bool Display::shadowSupported()C
  2848. {
  2849. return Renderer._shd_map.is();
  2850. }
  2851. void Display::shadowJitterSet()
  2852. {
  2853. if(Sh.h_ShdJitter)
  2854. {
  2855. Vec2 j=Flt(shadowJitter())/Renderer._shd_map.hwSize();
  2856. Sh.h_ShdJitter->set(Vec4(j, j*-0.5f));
  2857. }
  2858. }
  2859. /******************************************************************************/
  2860. Bool Display::aoWant()C
  2861. {
  2862. return ambientMode()!=AMBIENT_FLAT
  2863. && (ambientColor()+nightShadeColor()).max()>EPS_COL; // no need to calculate AO if it's too small
  2864. }
  2865. Flt Display::ambientRes ( )C {return ByteScaleToFlt(_amb_res);}
  2866. Display& Display::ambientRes ( Flt scale ) {Byte res=FltToByteScale( scale ); if(res!=_amb_res){_amb_res =res ; Renderer.rtClean();} return T;}
  2867. Display& Display::ambientMode ( AMBIENT_MODE mode ) {Clamp(mode, AMBIENT_FLAT, AMBIENT_MODE(AMBIENT_NUM-1)); _amb_mode=mode; return T;}
  2868. Display& Display::ambientSoft ( Byte soft ) {MIN (soft, AMBIENT_SOFT_NUM-1 ); _amb_soft=soft; return T;}
  2869. Display& Display::ambientJitter ( Bool jitter ) {_amb_jitter=jitter; return T;}
  2870. Display& Display::ambientNormal ( Bool normal ) {_amb_normal=normal; return T;}
  2871. Display& Display::ambientPower ( Flt power ) {MAX(power, 0); if(_amb_color !=power ){_amb_color =power ; if(Renderer.ambient_color)Renderer.ambient_color->set(ambientColor ());} return T;}
  2872. Display& Display::ambientColor (C Vec &color ) {Vec c(Max(color.x, 0), Max(color.y, 0), Max(color.z, 0)); if(_amb_color !=c ){_amb_color =c ; if(Renderer.ambient_color)Renderer.ambient_color->set(ambientColor ());} return T;}
  2873. Display& Display::ambientContrast( Flt contrast) {MAX(contrast, 0); if(_amb_contrast!=contrast){_amb_contrast=contrast; if(Sh.h_AmbientContrast )Sh.h_AmbientContrast ->set(ambientContrast());} return T;}
  2874. Display& Display::ambientRange (C Vec2 &range ) {Vec2 r(Max(range.x, 0.01f), Max(range.y, 0.01f)); if(_amb_range !=r ){_amb_range =r ; if(Sh.h_AmbientRange )Sh.h_AmbientRange ->set(ambientRange ());} return T;}
  2875. Display& Display::ambientScale ( Flt scale ) {MAX(scale, 0.05f); if(_amb_scale !=scale ){_amb_scale =scale ; if(Sh.h_AmbientScale )Sh.h_AmbientScale ->set(ambientScale ());} return T;}
  2876. Display& Display::ambientBias ( Flt bias ) {SAT(bias); if(_amb_bias !=bias ){_amb_bias =bias ; if(Sh.h_AmbientBias )Sh.h_AmbientBias ->set(ambientBias ());} return T;}
  2877. /******************************************************************************/
  2878. Display& Display::nightShadeColor(C Vec &color) {Vec c(Max(color.x, 0), Max(color.y, 0), Max(color.z, 0)); if(_ns_color!=c){_ns_color=c; if(Sh.h_NightShadeColor)Sh.h_NightShadeColor->set(_ns_color);} return T;}
  2879. /******************************************************************************/
  2880. Flt Display::motionRes ( )C {return ByteScaleToFlt(_mtn_res);}
  2881. Display& Display::motionRes (Flt scale ) {Byte res=FltToByteScale(scale); if(res!=_mtn_res){_mtn_res=res; Renderer.rtClean();} return T;}
  2882. Display& Display::motionMode (MOTION_MODE mode ) {Clamp(mode , MOTION_NONE , MOTION_MODE(MOTION_NUM-1)); _mtn_mode =mode ; return T;}
  2883. Display& Display::motionDilate(DILATE_MODE mode ) {Clamp(mode , DILATE_MODE(0), DILATE_MODE(DILATE_NUM-1)); _mtn_dilate=mode ; return T;}
  2884. Display& Display::motionScale (Flt scale ) {MAX (scale, 0 ); if(_mtn_scale!=scale){_mtn_scale =scale; MotionScaleChanged();} return T;} // this parameter affects 'Camera.set' -> 'CamMatrixInvMotionScale', and 'SetAngVelShader'
  2885. /******************************************************************************/
  2886. Display& Display::dofMode (DOF_MODE mode ) {Clamp(mode, DOF_NONE, DOF_MODE(DOF_NUM-1)); _dof_mode =mode ; return T;}
  2887. Display& Display::dofFocusMode(Bool realistic) { _dof_foc_mode =(realistic!=0) ; return T;}
  2888. Display& Display::dofFocus (Flt z ) { _dof_focus =Max(z , 0); return T;}
  2889. Display& Display::dofRange (Flt range ) { _dof_range =Max(range , 0); return T;}
  2890. Display& Display::dofIntensity(Flt intensity) { _dof_intensity=Max(intensity, 0); return T;}
  2891. /******************************************************************************/
  2892. Display& Display::eyeAdaptation ( Bool on ) { _eye_adapt =on ; return T;}
  2893. Display& Display::eyeAdaptationBrightness( Flt brightness) {MAX(brightness, 0); if(_eye_adapt_brightness!=brightness){_eye_adapt_brightness=brightness; if(Sh.h_HdrBrightness)Sh.h_HdrBrightness->set(eyeAdaptationBrightness());} return T;}
  2894. Display& Display::eyeAdaptationMaxDark ( Flt max_dark ) {MAX(max_dark , 0); if(_eye_adapt_max_dark !=max_dark ){_eye_adapt_max_dark =max_dark ; if(Sh.h_HdrMaxDark )Sh.h_HdrMaxDark ->set(eyeAdaptationMaxDark ());} return T;}
  2895. Display& Display::eyeAdaptationMaxBright ( Flt max_bright) {MAX(max_bright, 0); if(_eye_adapt_max_bright!=max_bright){_eye_adapt_max_bright=max_bright; if(Sh.h_HdrMaxBright )Sh.h_HdrMaxBright ->set(eyeAdaptationMaxBright ());} return T;}
  2896. Display& Display::eyeAdaptationSpeed ( Flt speed ) {MAX(speed , 1); if(_eye_adapt_speed !=speed ){_eye_adapt_speed =speed ; } return T;}
  2897. Display& Display::eyeAdaptationWeight (C Vec &weight ) { if(_eye_adapt_weight !=weight ){_eye_adapt_weight =weight ; if(Sh.h_HdrWeight )Sh.h_HdrWeight ->set(eyeAdaptationWeight()/4 );} return T;}
  2898. Display& Display::resetEyeAdaptation ( Flt brightness)
  2899. {
  2900. if(Renderer._eye_adapt_scale[0].is())
  2901. {
  2902. MAX(brightness, 0);
  2903. SyncLocker locker(_lock);
  2904. REPAO(Renderer._eye_adapt_scale).clearFull(brightness, true);
  2905. }
  2906. return T;
  2907. }
  2908. /******************************************************************************/
  2909. Display& Display::grassDensity(Flt density) {_grass_density=Sat(density); return T;}
  2910. Display& Display::grassShadow (Bool on ) {_grass_shadow = on ; return T;}
  2911. Display& Display::grassMirror (Bool on ) {_grass_mirror = on ; return T;}
  2912. Display& Display::grassRange (Flt range )
  2913. {
  2914. MAX(range, 0); if(_grass_range!=range)
  2915. {
  2916. _grass_range =range;
  2917. _grass_range_sqr=Sqr(_grass_range);
  2918. if(Sh.h_GrassRangeMulAdd)
  2919. {
  2920. Flt from=Sqr(_grass_range*0.8f), to=_grass_range_sqr, mul, add; if(to>from+EPSL){mul=1/(to-from); add=-from*mul;}else{mul=0; add=1;} // else{no grass} because distance is 0
  2921. Sh.h_GrassRangeMulAdd->set(Vec2(mul, add));
  2922. }
  2923. }
  2924. return T;
  2925. }
  2926. static Flt BendFactor;
  2927. Display& Display::grassUpdate()
  2928. {
  2929. BendFactor+=Time.d();
  2930. if(Sh.h_BendFactor)Sh.h_BendFactor->set(Vec4(1.6f, 1.2f, 1.4f, 1.1f)*BendFactor+Vec4(0.1f, 0.5f, 0.7f, 1.1f));
  2931. return T;
  2932. }
  2933. /******************************************************************************/
  2934. Display& Display::furStaticGravity (Flt gravity ) {_fur_gravity =gravity ; return T;}
  2935. Display& Display::furStaticVelScale(Flt vel_scale) {_fur_vel_scale=vel_scale; return T;}
  2936. /******************************************************************************/
  2937. void Display::lodSetCurrentFactor()
  2938. {
  2939. // '_lod_current_factor' contains information about '_lod_factors_fov' in current rendering mode
  2940. _lod_current_factor=_lod_factors_fov[Renderer()==RM_SHADOW][Renderer.mirror()];
  2941. }
  2942. void Display::lodUpdateFactors()
  2943. {
  2944. // '_lod_fov2' is a value based on Fov (viewFovY()), squared
  2945. if(FovPerspective(viewFovMode()))_lod_fov2=Sqr(Tan(viewFovY()*0.5f));
  2946. else _lod_fov2=Sqr( viewFovY() );
  2947. REPD(s, 2)
  2948. REPD(m, 2)_lod_factors_fov[s][m]=_lod_factors[s][m]*_lod_fov2;
  2949. lodSetCurrentFactor();
  2950. }
  2951. Display& Display::lod(Flt general, Flt shadow, Flt mirror)
  2952. {
  2953. // set values
  2954. _lod_factor =Max(0, general);
  2955. _lod_factor_shadow=Max(0, shadow );
  2956. _lod_factor_mirror=Max(0, mirror );
  2957. // build precomputed helper array
  2958. REPD(s, 2)
  2959. REPD(m, 2)
  2960. {
  2961. Flt &factor =_lod_factors[s][m];
  2962. factor =_lod_factor;
  2963. if(s)factor*=_lod_factor_shadow;
  2964. if(m)factor*=_lod_factor_mirror;
  2965. factor*= factor; // make square
  2966. }
  2967. lodUpdateFactors();
  2968. return T;
  2969. }
  2970. Display& Display::lodFactor (Flt factor) {return lod( factor, _lod_factor_shadow, _lod_factor_mirror);}
  2971. Display& Display::lodFactorShadow(Flt factor) {return lod(_lod_factor, factor , _lod_factor_mirror);}
  2972. Display& Display::lodFactorMirror(Flt factor) {return lod(_lod_factor, _lod_factor_shadow, factor );}
  2973. /******************************************************************************/
  2974. Display& Display::tesselationAllow (Bool on ) { if(_tesselation_allow !=on ) _tesselation_allow =on ; return T;}
  2975. Display& Display::tesselation (Bool on ) { if(_tesselation !=on ){_tesselation =on ; setShader();} return T;}
  2976. Display& Display::tesselationHeightmap(Bool on ) { if(_tesselation_heightmap!=on ){_tesselation_heightmap=on ; setShader();} return T;}
  2977. Display& Display::tesselationDensity (Flt density) {MAX(density, EPS_GPU); if(_tesselation_density !=density){_tesselation_density =density; if(Sh.h_TesselationDensity)Sh.h_TesselationDensity->set(tesselationDensity());} return T;}
  2978. /******************************************************************************/
  2979. void Display::setViewFovTan()
  2980. {
  2981. Vec2 mul(Renderer.resW()/(_view_active.recti.w()*w()), Renderer.resH()/(_view_active.recti.h()*h()));
  2982. _view_fov_tan_full=_view_active.fov_tan*mul;
  2983. if(VR.active() && _allow_stereo
  2984. && !(Renderer.inside() && !Renderer._stereo) // if we're inside rendering, and stereo is disabled, then we need to process this normally, this is so that we can do mono rendering in Gui, and use correct '_view_fov_tan' (PosToScreen,ScreenToPos) in that space
  2985. )
  2986. {
  2987. Flt scale=VR.guiSize()*0.5f, aspect=Flt(VR.guiRes().x)/VR.guiRes().y;
  2988. _view_fov_tan_gui.x=scale*aspect;
  2989. _view_fov_tan_gui.y=scale;
  2990. if(Renderer.inside() && Renderer._stereo)_view_fov_tan_gui.x*=0.5f;
  2991. _view_fov_tan_gui*=mul;
  2992. }else
  2993. {
  2994. _view_fov_tan_gui=_view_fov_tan_full;
  2995. }
  2996. if(Sh.h_DepthWeightScale)Sh.h_DepthWeightScale->set(_view_active.fov_tan.y*0.00714074011f);
  2997. }
  2998. void Display::viewUpdate()
  2999. {
  3000. if(created())
  3001. {
  3002. _view_active=_view_main;
  3003. if(_lock.owned())_view_active.setViewport(false); // set actual viewport only if we own the lock, this is because this method can be called outside of 'Draw' where we don't have the lock, however to avoid locking which could affect performance (for example GPU still owning the lock on other thread, for example for flipping back buffer, we would have to wait until it finished), we can skip setting the viewport because drawing is not allowed in update anyway. To counteract this skip here, instead we always reset the viewport at the start of Draw in 'DrawState'
  3004. _view_active.setShader().setProjMatrix(true);
  3005. }
  3006. _view_from =(FovPerspective(viewFovMode()) ? viewFrom() : 0);
  3007. _view_fov =(FovHorizontal (viewFovMode()) ? viewFovX() : viewFovY());
  3008. _view_rect =Renderer.pixelToScreen(viewRectI());
  3009. _view_center=_view_rect.center();
  3010. REPAO(_view_eye_rect)=_view_rect;
  3011. _view_eye_rect[0].max.x=_view_eye_rect[1].min.x=_view_rect.centerX();
  3012. setViewFovTan ();
  3013. validateCoords ();
  3014. lodUpdateFactors();
  3015. }
  3016. void Display::viewReset()
  3017. {
  3018. Rect rect=viewRect(); _view_main.recti.set(0, -1); _view_rect.set(0, -1); if(_view_main.full)viewRect(null);else viewRect(rect); // if last was full then set full, otherwise set based on rect
  3019. }
  3020. Display& Display::view(C Rect &rect, Flt from, Flt range, C Vec2 &fov, FOV_MODE fov_mode) {_view_main.set(screenToPixelI(rect), from, range, fov, fov_mode); viewUpdate(); return T;}
  3021. Display& Display::view(C RectI &rect, Flt from, Flt range, C Vec2 &fov, FOV_MODE fov_mode) {_view_main.set( rect , from, range, fov, fov_mode); viewUpdate(); return T;}
  3022. Display& Display::viewRect (C RectI *rect ) {RectI recti=(rect ? *rect : RectI(0, 0, Renderer.resW(), Renderer.resH())); if( viewRectI() !=recti ){ _view_main.setRect (recti ).setFov(); viewUpdate();} return T;} // need to use 'Renderer.res' in case VR is enabled and we're rendering to its 'GuiTexture'
  3023. Display& Display::viewRect (C Rect &rect ) {RectI recti=screenToPixelI(rect); if( viewRectI() !=recti ){ _view_main.setRect (recti ).setFov(); viewUpdate();} return T;}
  3024. Display& Display::viewFrom ( Flt from ) { if( viewFrom () !=from ){ _view_main.setFrom (from ) ; viewUpdate();} return T;}
  3025. Display& Display::viewRange( Flt range ) { if( viewRange() !=range ){ _view_main.setRange(range ) ; viewUpdate();} return T;}
  3026. Display& Display::viewFov ( Flt fov, FOV_MODE mode) { if( viewFov () !=fov || viewFovMode()!=mode ){ _view_main.setFov (fov, mode ) ; viewUpdate();} return T;}
  3027. Display& Display::viewFov (C Vec2 &fov ) { if( viewFovXY() !=fov || viewFovMode()!=FOV_XY){ _view_main.setFov (fov, FOV_XY) ; viewUpdate();} return T;}
  3028. Display& Display::viewForceSquarePixel(Bool on ) { if(_view_square_pixel!=on ){_view_square_pixel=on; _view_main.setFov ( ) ; viewUpdate();} return T;}
  3029. Flt Display::viewQuadDist()C
  3030. {
  3031. Vec view_quad_max(_view_main.fov_tan.x*_view_main.from, _view_main.fov_tan.y*_view_main.from, _view_main.from);
  3032. return view_quad_max.length();
  3033. }
  3034. /******************************************************************************/
  3035. // CLEAR
  3036. /******************************************************************************/
  3037. #define CLEAR_DEPTH_VALUE (!REVERSE_DEPTH) // Warning: for GL this is set at app startup and not here
  3038. #if DX9
  3039. // DX9 'clearDepth' clears partial depth buffer (only this covered by active viewport)
  3040. void Display::clear ( C Color &color) {UInt flag=D3DCLEAR_TARGET; if(Renderer._cur_ds){ flag|=D3DCLEAR_ZBUFFER; if(ImageTI[Renderer._cur_ds->hwType()].s)flag|=D3DCLEAR_STENCIL;} D3D->Clear(0, null, flag , VecB4(color.b, color.g, color.r, color.a).u, CLEAR_DEPTH_VALUE, 0); } // call will fail if D3DCLEAR_ZBUFFER/D3DCLEAR_STENCIL is specified but not available
  3041. void Display::clearCol ( C Color &color) { D3D->Clear(0, null, D3DCLEAR_TARGET , VecB4(color.b, color.g, color.r, color.a).u, CLEAR_DEPTH_VALUE, 0); }
  3042. void Display::clearDepth ( ) { D3D->Clear(0, null, D3DCLEAR_ZBUFFER, 0, CLEAR_DEPTH_VALUE, 0); }
  3043. void Display::clearDS ( Byte s ) { if(Renderer._cur_ds){UInt flag =D3DCLEAR_ZBUFFER; if(ImageTI[Renderer._cur_ds->hwType()].s)flag|=D3DCLEAR_STENCIL; D3D->Clear(0, null, flag , 0, CLEAR_DEPTH_VALUE, s);}} // call will fail if D3DCLEAR_STENCIL is specified but not available
  3044. void Display::clearStencil( Byte s ) { D3D->Clear(0, null, D3DCLEAR_STENCIL, 0, CLEAR_DEPTH_VALUE, s); }
  3045. void Display::clearCol (Int i, C Color &color) {RANGE_ASSERT(i, Renderer._cur); if(Image *image=Renderer._cur[i])image->clearHw(color);}
  3046. #elif DX11
  3047. void Display::clear(C Color &color)
  3048. {
  3049. clearCol(color);
  3050. clearDS ( );
  3051. }
  3052. void Display::clearCol(C Color &color) {return clearCol(color.asVec4());}
  3053. void Display::clearCol(C Vec4 &color)
  3054. {
  3055. if(Renderer._cur[0])
  3056. {
  3057. if(D._view_active.full)Renderer._cur[0]->clearHw(color);else
  3058. {
  3059. Bool clip=D._clip_allow; D.clipAllow(false); ALPHA_MODE alpha=D.alpha(ALPHA_NONE); Sh.clear(color);
  3060. D.clipAllow(clip ); D.alpha(alpha );
  3061. }
  3062. }
  3063. }
  3064. void Display::clearCol(Int i, C Vec4 &color) {RANGE_ASSERT(i, Renderer._cur); if(Image *image=Renderer._cur[i])image->clearHw(color);}
  3065. // DX10+ 'clearDepth' always clears full depth buffer (viewport is ignored)
  3066. void Display::clearDepth ( ) {if(Renderer._cur_ds)D3DC->ClearDepthStencilView(Renderer._cur_ds->_dsv, D3D11_CLEAR_DEPTH , CLEAR_DEPTH_VALUE, 0);}
  3067. void Display::clearDS (Byte s) {if(Renderer._cur_ds)D3DC->ClearDepthStencilView(Renderer._cur_ds->_dsv, D3D11_CLEAR_DEPTH|(ImageTI[Renderer._cur_ds->hwType()].s ? D3D11_CLEAR_STENCIL : 0), CLEAR_DEPTH_VALUE, s);}
  3068. void Display::clearStencil(Byte s) {if(Renderer._cur_ds)D3DC->ClearDepthStencilView(Renderer._cur_ds->_dsv, D3D11_CLEAR_STENCIL , CLEAR_DEPTH_VALUE, s);}
  3069. #elif GL
  3070. void Display::clear(C Color &color)
  3071. {
  3072. clearCol(color);
  3073. clearDS ( );
  3074. }
  3075. void Display::clearCol(C Color &color) {return clearCol(color.asVec4());}
  3076. void Display::clearCol(C Vec4 &color)
  3077. {
  3078. if(Renderer._cur[0])
  3079. {
  3080. if(D._clip_real)glDisable(GL_SCISSOR_TEST); // scissor test affects clear on OpenGL so we need to temporarily disable it to have the same functionality as in DirectX
  3081. if(D._view_active.full)
  3082. {
  3083. glClearColor(color.x, color.y, color.z, color.w); // Values specified by glClearColor are clamped to the range [0,1] - https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearColor.xhtml
  3084. glClear(GL_COLOR_BUFFER_BIT);
  3085. }else
  3086. {
  3087. ALPHA_MODE alpha=D.alpha(ALPHA_NONE); Sh.clear(color);
  3088. D.alpha(alpha );
  3089. }
  3090. if(D._clip_real)glEnable(GL_SCISSOR_TEST);
  3091. }
  3092. }
  3093. // 'glClearBufferfv' always clears full RT (viewport is ignored)
  3094. void Display::clearCol(Int i, C Vec4 &color)
  3095. {
  3096. if(D.notShaderModelGLES2())
  3097. {
  3098. RANGE_ASSERT(i, Renderer._cur); if(Renderer._cur[i])glClearBufferfv(GL_COLOR, i, color.c);
  3099. }
  3100. }
  3101. // GL 'clearDepth' always clears full depth buffer (viewport is ignored)
  3102. // Don't check for '_cur_ds_id' because this can be 0 for RenderBuffers
  3103. void Display::clearDepth ( ) {if(Renderer._cur_ds){if(D._clip_real)glDisable(GL_SCISSOR_TEST); glClear(GL_DEPTH_BUFFER_BIT ); if(D._clip_real)glEnable(GL_SCISSOR_TEST);}}
  3104. void Display::clearDS (Byte s) {if(Renderer._cur_ds){if(D._clip_real)glDisable(GL_SCISSOR_TEST); glClearStencil(s); glClear(GL_DEPTH_BUFFER_BIT|(ImageTI[Renderer._cur_ds->hwType()].s?GL_STENCIL_BUFFER_BIT:0)); if(D._clip_real)glEnable(GL_SCISSOR_TEST);}}
  3105. void Display::clearStencil(Byte s) {if(Renderer._cur_ds){if(D._clip_real)glDisable(GL_SCISSOR_TEST); glClearStencil(s); glClear( GL_STENCIL_BUFFER_BIT ); if(D._clip_real)glEnable(GL_SCISSOR_TEST);}}
  3106. #endif
  3107. /******************************************************************************/
  3108. // CONVERT COORDINATES
  3109. /******************************************************************************/
  3110. Vec2 Display::screenToUV(C Vec2 &screen)
  3111. {
  3112. return Vec2((screen.x+D.w())/D.w2(),
  3113. (D.h()-screen.y)/D.h2());
  3114. }
  3115. Rect Display::screenToUV(C Rect &screen)
  3116. {
  3117. return Rect((screen.min.x+D.w())/D.w2(), (D.h()-screen.max.y)/D.h2(),
  3118. (screen.max.x+D.w())/D.w2(), (D.h()-screen.min.y)/D.h2());
  3119. }
  3120. Vec2 Display::UVToScreen(C Vec2 &uv)
  3121. {
  3122. return Vec2(uv.x*D.w2()-D.w(),
  3123. D.h()-uv.y*D.h2());
  3124. }
  3125. Vec2 Display::screenToPixel(C Vec2 &screen)
  3126. {
  3127. return Vec2((screen.x+D.w())*D._pixel_size_inv.x,
  3128. (D.h()-screen.y)*D._pixel_size_inv.y);
  3129. }
  3130. Rect Display::screenToPixel(C Rect &screen)
  3131. {
  3132. return Rect((screen.min.x+D.w())*D._pixel_size_inv.x, (D.h()-screen.max.y)*D._pixel_size_inv.y,
  3133. (screen.max.x+D.w())*D._pixel_size_inv.x, (D.h()-screen.min.y)*D._pixel_size_inv.y);
  3134. }
  3135. // use 'Round' instead of 'Floor' to match GPU vertex rounding, so that all 3 ways of rect drawing will be identical: Rect r; 1) r.draw 2) D.clip(r) full_rect.draw() 3) D.viewRect(r) full_rect.draw()
  3136. VecI2 Display::screenToPixelI(C Vec2 &screen) {return RoundGPU(screenToPixel(screen));}
  3137. RectI Display::screenToPixelI(C Rect &screen) {return RoundGPU(screenToPixel(screen));}
  3138. Vec2 Display::pixelToScreen(C Vec2 &pixel)
  3139. {
  3140. return Vec2(pixel.x*D._pixel_size.x-D.w(),
  3141. D.h()-pixel.y*D._pixel_size.y);
  3142. }
  3143. Vec2 Display::pixelToScreen(C VecI2 &pixel)
  3144. {
  3145. return Vec2(pixel.x*D._pixel_size.x-D.w(),
  3146. D.h()-pixel.y*D._pixel_size.y);
  3147. }
  3148. Rect Display::pixelToScreen(C Rect &pixel)
  3149. {
  3150. return Rect(pixel.min.x*D._pixel_size.x-D.w(), D.h()-pixel.max.y*D._pixel_size.y,
  3151. pixel.max.x*D._pixel_size.x-D.w(), D.h()-pixel.min.y*D._pixel_size.y);
  3152. }
  3153. Rect Display::pixelToScreen(C RectI &pixel)
  3154. {
  3155. return Rect(pixel.min.x*D._pixel_size.x-D.w(), D.h()-pixel.max.y*D._pixel_size.y,
  3156. pixel.max.x*D._pixel_size.x-D.w(), D.h()-pixel.min.y*D._pixel_size.y);
  3157. }
  3158. Vec2 Display::screenToPixelSize(C Vec2 &screen) {return screen*D._pixel_size_inv;}
  3159. Vec2 Display::pixelToScreenSize( Flt pixel ) {return pixel*D._pixel_size ;}
  3160. Vec2 Display::pixelToScreenSize(C Vec2 &pixel ) {return pixel*D._pixel_size ;}
  3161. Vec2 Display::pixelToScreenSize(C VecI2 &pixel ) {return pixel*D._pixel_size ;}
  3162. Vec2 Display::windowPixelToScreen(C Vec2 &pixel) // this is used by mouse/touch pointers
  3163. {
  3164. return Vec2(pixel.x*D._window_pixel_to_screen_mul.x+D._window_pixel_to_screen_add.x,
  3165. pixel.y*D._window_pixel_to_screen_mul.y+D._window_pixel_to_screen_add.y);
  3166. }
  3167. Vec2 Display::windowPixelToScreen(C VecI2 &pixel) // this is used by mouse/touch pointers
  3168. {
  3169. return Vec2(pixel.x*D._window_pixel_to_screen_mul.x+D._window_pixel_to_screen_add.x,
  3170. pixel.y*D._window_pixel_to_screen_mul.y+D._window_pixel_to_screen_add.y);
  3171. }
  3172. VecI2 Display::screenToWindowPixelI(C Vec2 &screen)
  3173. {
  3174. return VecI2(Round((screen.x-D._window_pixel_to_screen_add.x)/D._window_pixel_to_screen_mul.x),
  3175. Round((screen.y-D._window_pixel_to_screen_add.y)/D._window_pixel_to_screen_mul.y));
  3176. }
  3177. RectI Display::screenToWindowPixelI(C Rect &screen)
  3178. { // since Y gets flipped, we need to swap min.y <-> max.y
  3179. return RectI(Round((screen.min.x-D._window_pixel_to_screen_add.x)/D._window_pixel_to_screen_mul.x),
  3180. Round((screen.max.y-D._window_pixel_to_screen_add.y)/D._window_pixel_to_screen_mul.y),
  3181. Round((screen.max.x-D._window_pixel_to_screen_add.x)/D._window_pixel_to_screen_mul.x),
  3182. Round((screen.min.y-D._window_pixel_to_screen_add.y)/D._window_pixel_to_screen_mul.y));
  3183. }
  3184. /* following functions were based on these codes:
  3185. static Image img; if(!img.is()){img.create2D(16, 16, IMAGE_R8G8B8A8, 1); img.lock(); REPD(y,img.h())REPD(x,img.w())img.color(x, y, (x^y)&1 ? WHITE : BLACK); img.unlock();}
  3186. for(Int i=0; i<D.resW(); i+=2)
  3187. {
  3188. Vec2 pos=D.pixelToScreen(Vec2(i*1.111f+0.5f, 0)), s=D.pixelToScreenSize(VecI2(1)), p;
  3189. p=pos;
  3190. Rect_LU(p.x, p.y, s.x, 0.1f).draw(RED, true);
  3191. D.lineY(RED, p.x, p.y-0.2f, p.y-0.3f);
  3192. p=pos-Vec2(0, 0.1f); D.screenAlignToPixel (p); Rect_LU(p.x, p.y, s.x, 0.1f).draw(RED, true);
  3193. p=pos-Vec2(0, 0.1f); D.screenAlignToPixelL(p); D.lineY(RED, p.x, p.y-0.2f, p.y-0.3f);
  3194. p=pos-Vec2(0, 0.4f); D.screenAlignToPixel(p);
  3195. if(!(i%16))img.draw(Rect_LU(Vec2(p.x, p.y), D.pixelToScreenSize(img.size())));
  3196. }
  3197. D.text(0, D.h()-0.05f, "Rect");
  3198. D.text(0, D.h()-0.15f, "Rect aligned");
  3199. D.text(0, D.h()-0.25f, "Line");
  3200. D.text(0, D.h()-0.35f, "Line aligned");
  3201. */
  3202. Vec2 Display::screenAlignedToPixel (C Vec2 &screen ) {return pixelToScreen(screenToPixelI(screen));}
  3203. Vec2 Display:: alignScreenToPixelOffset(C Vec2 &screen ) {return screenAlignedToPixel(screen)-screen;}
  3204. void Display:: alignScreenToPixel ( Vec2 &screen ) {screen =screenAlignedToPixel(screen);}
  3205. void Display:: alignScreenToPixel ( Rect &screen ) {screen+=alignScreenToPixelOffset(screen.lu());}
  3206. void Display:: alignScreenXToPixel ( Flt &screen_x)
  3207. {
  3208. Int pixel=RoundGPU((screen_x+D.w())*D._pixel_size_inv.x); // use 'RoundGPU' to match 'screenToPixelI'
  3209. screen_x=pixel*D._pixel_size.x-D.w();
  3210. }
  3211. void Display::alignScreenYToPixel(Flt &screen_y)
  3212. {
  3213. Int pixel=RoundGPU((D.h()-screen_y)*D._pixel_size_inv.y); // use 'RoundGPU' to match 'screenToPixelI'
  3214. screen_y=D.h()-pixel*D._pixel_size.y;
  3215. }
  3216. /******************************************************************************/
  3217. // FADE
  3218. /******************************************************************************/
  3219. Bool Display::fading()C {return Renderer._fade || _fade_get;}
  3220. void Display::setFade(Flt seconds, Bool previous_frame)
  3221. {
  3222. if(!VR.active()) // fading is currently not supported in VR mode
  3223. {
  3224. if(seconds<=0)
  3225. {
  3226. clearFade();
  3227. }else
  3228. if(previous_frame)
  3229. {
  3230. if(Renderer._main.is())
  3231. {
  3232. SyncLocker locker(_lock);
  3233. Renderer._fade.get(ImageRTDesc(Renderer._main.w(), Renderer._main.h(), IMAGERT_RGB)); // doesn't use Alpha
  3234. Renderer._main.copyHw(*Renderer._fade, true, null, null, &_fade_flipped);
  3235. _fade_get =false ;
  3236. _fade_step=0 ;
  3237. _fade_len =seconds;
  3238. }
  3239. }else
  3240. {
  3241. _fade_get=true;
  3242. _fade_len=seconds;
  3243. }
  3244. }
  3245. }
  3246. void Display::clearFade()
  3247. {
  3248. Renderer._fade.clear();
  3249. _fade_get=_fade_flipped=false;
  3250. _fade_step=_fade_len=0;
  3251. }
  3252. void Display::fadeUpdate()
  3253. {
  3254. if(Renderer._fade && (_fade_step+=Time.ad()/_fade_len)>=1)clearFade();
  3255. }
  3256. void Display::fadeDraw()
  3257. {
  3258. if(Renderer._fade)
  3259. {
  3260. Sh.h_Step->set(1-_fade_step);
  3261. Sh.h_DrawA->draw(*Renderer._fade, _fade_flipped ? &Rect(-w(), h(), w(), -h()) : null);
  3262. }
  3263. if(_fade_get)
  3264. {
  3265. _fade_get =false;
  3266. _fade_step=0 ;
  3267. Renderer._fade.get(ImageRTDesc(Renderer._main.w(), Renderer._main.h(), IMAGERT_RGB)); // doesn't use Alpha
  3268. Renderer._main.copyHw(*Renderer._fade, true, null, null, &_fade_flipped);
  3269. }
  3270. }
  3271. /******************************************************************************/
  3272. // COLOR PALETTE
  3273. /******************************************************************************/
  3274. static void SetPalette(Int index, C ImagePtr &palette) // !! Warning: '_color_palette_soft' must be of IMAGE_SOFT IMAGE_R8G8B8A8 type because 'Particles.draw' codes require that !!
  3275. {
  3276. D._color_palette[index]=palette;
  3277. if(palette)palette->copyTry(D._color_palette_soft[index], -1, -1, -1, IMAGE_R8G8B8A8, IMAGE_SOFT, 1);
  3278. else D._color_palette_soft[index].del();
  3279. }
  3280. Display& Display::colorPalette (C ImagePtr &palette) {SetPalette(0, palette); return T;}
  3281. Display& Display::colorPalette1 (C ImagePtr &palette) {SetPalette(1, palette); return T;}
  3282. Display& Display::colorPaletteAllow( Bool on ) {D._color_palette_allow=on; return T;}
  3283. /******************************************************************************/
  3284. // DIRECTX TEMPORARY DEVICE FOR DATA PROCESSING
  3285. /******************************************************************************/
  3286. #if WINDOWS_OLD
  3287. IDirect3DDevice9* GetD3D9()
  3288. {
  3289. #if DX9
  3290. return D3D;
  3291. #else
  3292. SyncLocker locker(D._lock);
  3293. static IDirect3DDevice9 *dev=null;
  3294. if(!dev)
  3295. {
  3296. if(IDirect3D9 *d3d=Direct3DCreate9(D3D_SDK_VERSION))
  3297. {
  3298. D3DPRESENT_PARAMETERS d3dpp; Zero(d3dpp);
  3299. d3dpp.BackBufferWidth =0*D.resW();
  3300. d3dpp.BackBufferHeight=0*D.resH();
  3301. d3dpp.BackBufferCount =0*1;
  3302. d3dpp.BackBufferFormat=D3DFMT_A8R8G8B8;
  3303. d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
  3304. d3dpp.hDeviceWindow=App.Hwnd();
  3305. d3dpp.Windowed=true;
  3306. d3dpp.EnableAutoDepthStencil=false;
  3307. d3dpp.Flags=0;
  3308. d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
  3309. d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
  3310. d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, App.Hwnd(), D3DCREATE_FPU_PRESERVE|D3DCREATE_NOWINDOWCHANGES|D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &dev);
  3311. }
  3312. if(!dev)Exit("Can't create DirectX 9 Device.\nTry using DX9 Engine version.");
  3313. }
  3314. return dev;
  3315. #endif
  3316. }
  3317. /******************************************************************************
  3318. ID3D10Device* GetD3D10()
  3319. {
  3320. static ID3D10Device *dev=null;
  3321. #if DX11
  3322. SyncLocker locker(D._lock);
  3323. D3D10CreateDevice(null, D3D10_DRIVER_TYPE_HARDWARE , null, 0, D3D10_SDK_VERSION, &dev);
  3324. if(!dev)D3D10CreateDevice(null, D3D10_DRIVER_TYPE_WARP , null, 0, D3D10_SDK_VERSION, &dev);
  3325. if(!dev)D3D10CreateDevice(null, D3D10_DRIVER_TYPE_REFERENCE, null, 0, D3D10_SDK_VERSION, &dev);
  3326. #endif
  3327. if(!dev)Exit("Can't create DirectX 10 Device.\nTry using DX10 Engine version.");
  3328. return dev;
  3329. }
  3330. /******************************************************************************/
  3331. #elif WINDOWS_NEW
  3332. Int DipsToPixels(Flt dips) {return Round(dips*ScreenScale);}
  3333. Flt PixelsToDips(Int pix ) {return pix /ScreenScale ;}
  3334. #endif
  3335. /******************************************************************************/
  3336. }
  3337. /******************************************************************************/