Renderer.cpp 99 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #include "../Shaders/!Header CPU.h"
  4. namespace EE{
  5. #define SVEL_CLEAR Vec4Zero
  6. #define VEL_CLEAR Vec4(0.5f, 0.5f, 0.5f, 0)
  7. #define SNRM_CLEAR Vec4(0 , 0 , -1, 0) // set Z to 0 to set VecZero normals, however Z set to -1 makes ambient occlusion more precise when it uses normals (because ambient occlusion will not work good on the VecZero normals)
  8. #define NRM_CLEAR Vec4(0.5f, 0.5f, 0, 0) // set Z to 0.5 to set VecZero normals, however Z set to 0 makes ambient occlusion more precise when it uses normals (because ambient occlusion will not work good on the VecZero normals)
  9. #define NRM_CLEAR_START 1 // 1 works faster on GeForce 650m GT, TODO: check on newer hardware
  10. inline Bool ClearNrm() {return D.aoWant() && D.ambientNormal() || Renderer.stage==RS_NORMAL;}
  11. /******************************************************************************
  12. Graphics API differences:
  13. Reading and Writing to the same Render Target - Yes: DX9, GL No: DX10+
  14. null Color Render Target - Yes: DX10+, GL No: DX9 (Render Target always must be specified, IMAGE_NULL IMAGE_TYPE is used instead, which driver interprets as empty render target - video memory shouldn't be allocated)
  15. Depth Textures - Yes: DX10+, GL Limited: DX9 (only INTZ - GeForce>=8 Radeon>=4000, RAWZ - GeForce 6 and 7, DF24 Radeon x1000..3000) do not work with Multi-Sampling
  16. Deferred Multi-Sampling - Yes: DX>=10.1 No: DX9, DX10.0, GL
  17. Lost/Reset of D3DPOOL_DEFAULT (IMAGE_RT, dynamic VB/IB) - Yes: DX9 No: DX10+, GL
  18. Multiple Render Targets - Yes: DX9, DX10+, GL No: GLES2
  19. TODO: remove RT_SIMPLE, simplePrecision, simpleVertexFog
  20. /******************************************************************************/
  21. RendererClass Renderer;
  22. MeshRender MshrBox ,
  23. MshrBoxR,
  24. MshrBall;
  25. /******************************************************************************/
  26. static void InitMshr()
  27. {
  28. MeshBase mshb;
  29. mshb.createFast(Box(1));
  30. MshrBox .create(mshb);
  31. mshb.reverse(); MshrBoxR.create(mshb);
  32. mshb.create(Ball(1), 0, 12);
  33. MshrBall.create(mshb);
  34. }
  35. static void ShutMshr()
  36. {
  37. MshrBox .del();
  38. MshrBoxR.del();
  39. MshrBall.del();
  40. }
  41. /******************************************************************************/
  42. RendererClass::RendererClass() : ambient_color(null), highlight(null), material_color(null)
  43. {
  44. stage =RS_DEFAULT;
  45. _solid_mode_index=RM_SIMPLE;
  46. lowest_visible_point=-DBL_MAX;
  47. _first_pass=true;
  48. _get_target=false;
  49. _set_depth_needed=false;
  50. _stereo=false;
  51. _eye=0; _eye_num=1;
  52. _type=_cur_type=(MOBILE ? RT_SIMPLE : RT_DEFERRED);
  53. #if MOBILE
  54. _simple_prec=false;
  55. #else
  56. _simple_prec=true;
  57. #endif
  58. _mesh_blend_alpha =ALPHA_BLEND_FACTOR;
  59. _mesh_stencil_value=STENCIL_REF_ZERO;
  60. _mesh_stencil_mode =STENCIL_NONE;
  61. _mesh_highlight .zero();
  62. _mesh_draw_mask =0xFFFFFFFF;
  63. _shader_param_changes=null;
  64. SetVariation(0);
  65. #if DX9
  66. _cull_mode[0]=D3DCULL_NONE;
  67. _cull_mode[1]=D3DCULL_CCW ;
  68. #elif DX11
  69. _cull_mode[0]=0;
  70. _cull_mode[1]=1;
  71. #endif
  72. _vtx_fog_start=0.80f;
  73. _vtx_fog_end =1.00f;
  74. _vtx_fog_color.set(0.40f, 0.48f, 0.64f);
  75. _gui =_cur_main =&_main;
  76. _gui_ds=_cur_main_ds=&_main_ds;
  77. }
  78. void RendererClass::del()
  79. {
  80. Sky .del();
  81. Astros.del();
  82. Clouds.del();
  83. Water .del();
  84. ShutInstances();
  85. ShutMshr ();
  86. ShutParticles();
  87. ShutMesh ();
  88. ShutMaterial ();
  89. ShutLight ();
  90. rtDel();
  91. }
  92. void RendererClass::create()
  93. {
  94. if(LogInit)LogN("RendererClass.create");
  95. #if 0 // convert DDS from SMAA source to Esenthel Image format
  96. Str in="D:/!/SMAA/", out="C:/Esenthel/Data/Img/";
  97. Image img;
  98. img.Import(in+"SearchTex.dds", -1, IMAGE_2D); img._type=IMAGE_R8;
  99. img.save(out+"SMAA Search.img");
  100. img.Import(in+"AreaTexDX10.dds", IMAGE_R8G8, IMAGE_2D);
  101. img.save(out+"SMAA Area.img");
  102. #endif
  103. #if SUPPORT_EARLY_Z
  104. _shader_early_z =DefaultShaders(&MaterialDefault, VTX_POS , 0, false).EarlyZ();
  105. #endif
  106. _shader_shd_map =DefaultShaders(&MaterialDefault, VTX_POS , 0, false).Shadow();
  107. _shader_shd_map_skin=DefaultShaders(&MaterialDefault, VTX_POS|VTX_SKIN, 0, false).Shadow();
  108. InitCamera ();
  109. InitLight ();
  110. InitMaterial ();
  111. InitFur ();
  112. InitMshr ();
  113. InitInstances();
  114. Sky .create();
  115. Clouds.create();
  116. Water .create();
  117. }
  118. RendererClass& RendererClass::type(RENDER_TYPE type)
  119. {
  120. Clamp(type, RENDER_TYPE(0), RENDER_TYPE(RT_NUM-1));
  121. if(type==RT_DEFERRED && D.deferredUnavailable())return T;
  122. if(T._type!=type)
  123. {
  124. T._type=T._cur_type=type;
  125. if(type==RT_DEFERRED && D.deferredMSUnavailable())D.samples(1); // disable multi-sampling if we can't support it
  126. D.setShader(); // needed because shaders are set only for current renderer type
  127. }
  128. return T;
  129. }
  130. void RendererClass::mode(RENDER_MODE mode)
  131. {
  132. T._mode =mode;
  133. T._palette_mode =(mode==RM_PALETTE || mode==RM_PALETTE1);
  134. T._mesh_shader_vel =(_vel && (mode==RM_SOLID || mode==RM_BLEND));
  135. T._solid_mode_index=((_cur_type==RT_SIMPLE) ? RM_SIMPLE : mirror() ? RM_SOLID_M : RM_SOLID);
  136. #if DX9
  137. T._cull_mode[1] =((mirror() && mode!=RM_SHADOW) ? D3DCULL_CW : D3DCULL_CCW);
  138. #elif DX11
  139. T._cull_mode[1] =((mirror() && mode!=RM_SHADOW) ? 2 : 1);
  140. #elif GL
  141. D.cullGL();
  142. #endif
  143. Bool cull=D._cull; D.cull(false); D.cull(cull); // force reset
  144. D.lodSetCurrentFactor();
  145. MaterialClear();
  146. }
  147. RendererClass& RendererClass::simplePrecision(Bool per_pixel)
  148. {
  149. if(T._simple_prec!=per_pixel)
  150. {
  151. T._simple_prec=per_pixel;
  152. D.setShader();
  153. }
  154. return T;
  155. }
  156. /******************************************************************************/
  157. RendererClass& RendererClass::simpleVertexFogRange(Flt start_frac, Flt end_frac)
  158. {
  159. T._vtx_fog_start=start_frac;
  160. T._vtx_fog_end = end_frac;
  161. return T;
  162. }
  163. RendererClass& RendererClass::simpleVertexFogColor(C Vec &fog_color)
  164. {
  165. T._vtx_fog_color=fog_color;
  166. return T;
  167. }
  168. /******************************************************************************/
  169. void RendererClass::requestMirror(C PlaneM &plane, Int priority, Bool shadows, Int resolution)
  170. {
  171. if(!_mirror_want || priority>T._mirror_priority)
  172. {
  173. _mirror_want =true;
  174. _mirror_priority =priority;
  175. _mirror_plane =plane;
  176. _mirror_shadows =shadows;
  177. _mirror_resolution=resolution;
  178. }
  179. }
  180. /******************************************************************************/
  181. void RendererClass::linearizeDepth(Image &dest, Image &depth)
  182. {
  183. D.alpha(ALPHA_NONE);
  184. set(&dest, null, true);
  185. #if DX9
  186. if(depth.type()==IMAGE_RAWZ)Sh.h_LinearizeDepthRAWZ[FovPerspective(D.viewFovMode())]->draw(depth);else // 1s->1s
  187. #endif
  188. if(!depth.multiSample() || depth.size()!=dest.size())Sh.h_LinearizeDepth[FovPerspective(D.viewFovMode())][0]->draw(depth);else // 1s->1s, if we're resizing then we also need to use the simple version
  189. if(!dest .multiSample() )Sh.h_LinearizeDepth[FovPerspective(D.viewFovMode())][1]->draw(depth);else // ms->1s
  190. Sh.h_LinearizeDepth[FovPerspective(D.viewFovMode())][2]->draw(depth); // ms->ms
  191. Sh.h_ImageCol[0]->set(null);
  192. Sh.h_ImageColMS ->set(null);
  193. }
  194. void RendererClass::setDepthForDebugDrawing()
  195. {
  196. if(_set_depth_needed)
  197. {
  198. _set_depth_needed=false;
  199. if(_ds_1s)if(Shader *shader=Sh.h_SetDepth)
  200. {
  201. #if DX9
  202. D.colWrite(0); // DX9 always requires a RT set
  203. #else
  204. Image *rt=_cur[0]; set(null, _cur_ds, true);
  205. #endif
  206. ALPHA_MODE alpha=D.alpha(ALPHA_NONE); D.depthLock (true); D.depthFunc(FUNC_ALWAYS); shader->draw(_ds_1s);
  207. D.alpha(alpha ); D.depthUnlock( ); D.depthFunc(FUNC_LESS );
  208. #if DX9
  209. D.colWrite(COL_WRITE_RGBA);
  210. #else
  211. set(rt, _cur_ds, true);
  212. #endif
  213. }
  214. }
  215. }
  216. ImageRTPtr RendererClass::getBackBuffer() // this may get called during rendering and outside of it
  217. {
  218. if(Image *src=_cur[0])
  219. {
  220. ImageRTPtr hlp(ImageRTDesc(src->w(), src->h(), IMAGERT_RGBA)); // here Alpha is used for storing opacity
  221. src->copyHw(*hlp, true);
  222. return hlp;
  223. }
  224. return null;
  225. }
  226. void RendererClass::adaptEye(ImageRC &src, Image &dest)
  227. {
  228. Hdr.load();
  229. ImageRTPtr temp=&src;
  230. VecI2 size=RoundPos(fx()*(D.viewRect().size()/D.size2())); // calculate viewport size in pixels
  231. Int max_size=size.min()/4;
  232. Int s=1, num=1; for(;;){Int next_size=s*4; if(next_size>max_size)break; s=next_size; num++;} // go from 1 up to 'max_size', inrease *4 in each step
  233. FREP(num) // now go backwards, from up to 'max_size' to 1 inclusive
  234. {
  235. ImageRTPtr next=temp; next.get(ImageRTDesc(s, s, IMAGERT_F32)); s/=4; // we could use 16-bit as according to calculations, the max error for 1920x1080, starting with 256x256 as first step and going down to 1x1, with average luminance of 1.0 (255 byte) is 0.00244140625 at the final stage, which gives 410 possible colors, however we may use some special tricks in the shader that requires higher precision (for example BRIGHT with Sqr and Sqrt later, or use Linear/sRGB)
  236. set(next(), null, false);
  237. if(i)Hdr.h_HdrDS[1]->draw(temp());
  238. else Hdr.h_HdrDS[0]->draw(temp(), null, D.screenToUV(D.viewRect()));
  239. temp=next;
  240. }
  241. Sh.h_Step ->set(Pow(Mid(1/D.eyeAdaptationSpeed(), EPS, 1.0f), Time.d())); // can use EPS and not EPS_GPU because we're using Pow here and not on GPU
  242. Sh.h_ImageLum->set(_eye_adapt_scale[_eye_adapt_scale_cur]); _eye_adapt_scale_cur^=1; _eye_adapt_scale[_eye_adapt_scale_cur].discard(); set(&_eye_adapt_scale[_eye_adapt_scale_cur], null, false); Hdr.h_HdrUpdate->draw(temp());
  243. Sh.h_ImageLum->set(_eye_adapt_scale[_eye_adapt_scale_cur]); set(&dest , null, true ); Hdr.h_Hdr ->draw(src ); // TODO: for simple mode we could do ALPHA_MUL_KEEP (if that would be faster)
  244. MaterialClear();
  245. }
  246. INLINE Shader* GetBloomDS(Bool glow, Bool viewport_clamp, Bool half, Bool saturate) {Shader* &s=Sh.h_BloomDS[glow][viewport_clamp][half][saturate]; if(SLOW_SHADER_LOAD && !s)s=Sh.getBloomDS(glow, viewport_clamp, half, saturate); return s;}
  247. INLINE Shader* GetBloom (Bool dither ) {Shader* &s=Sh.h_Bloom [dither] ; if(SLOW_SHADER_LOAD && !s)s=Sh.getBloom (dither ); return s;}
  248. // !! Assumes that 'ColClamp' was already set !!
  249. void RendererClass::bloom(Image &src, Image &dest, Bool dither)
  250. {
  251. const Int shift=(D.bloomHalf() ? 1 : 2);
  252. ImageRTDesc rt_desc(fxW()>>shift, fxH()>>shift, IMAGERT_RGB);
  253. ImageRTPtrRef rt0(D.bloomHalf() ? _h0 : _q0); rt0.get(rt_desc);
  254. ImageRTPtrRef rt1(D.bloomHalf() ? _h1 : _q1); rt1.get(rt_desc); Bool discard=false; // we've already discarded in 'get' so no need to do it again
  255. if(_has_glow || D.bloomScale()) // if we have something there
  256. {
  257. set(rt0(), null, false);
  258. Rect ext_rect, *rect=null; // set rect, after setting render target
  259. if(!D._view_main.full){ext_rect=D.viewRect(); rect=&ext_rect.extend(Renderer.pixelToScreenSize((D.bloomMaximum()+D.bloomBlurs())*SHADER_BLUR_RANGE+1));} // when not rendering entire viewport, then extend the rectangle, add +1 because of texture filtering, have to use 'Renderer.pixelToScreenSize' and not 'D.pixelToScreenSize'
  260. Bool half=(Flt(src.h())/rt0->h() <= 2.5f); // half=scale 2, ..3.., quarter=scale 4, 2.5 was the biggest scale that didn't cause jittering when using half down-sampling
  261. Sh.h_BloomParams->setConditional(Vec(D.bloomOriginal(), _has_glow ? D.bloomScale()/Sqr(half ? 2 : 4) : half ? D.bloomScale() : D.bloomScale()/4, -D.bloomCut()*D.bloomScale()));
  262. GetBloomDS(_has_glow, !D._view_main.full, half, D.bloomSaturate())->draw(src, rect);
  263. if(D.bloomMaximum())
  264. { // 'discard' before 'set' because it already may have requested discard, and if we 'discard' manually after 'set' then we might discard 2 times
  265. set(rt1(), null, false); Sh.h_MaxX->draw(rt0(), rect); discard=true; // discard next time
  266. rt0->discard(); set(rt0(), null, false); Sh.h_MaxY->draw(rt1(), rect);
  267. }
  268. REP(D.bloomBlurs())
  269. { // 'discard' before 'set' because it already may have requested discard, and if we 'discard' manually after 'set' then we might discard 2 times
  270. if(discard)rt1->discard(); set(rt1(), null, false); Sh.h_BlurX[D.bloomSamples()]->draw(rt0(), rect); discard=true; // discard next time
  271. rt0->discard(); set(rt0(), null, false); Sh.h_BlurY[D.bloomSamples()]->draw(rt1(), rect);
  272. }
  273. }else
  274. {
  275. rt0()->clearFull();
  276. }
  277. set(&dest, null, true);
  278. Sh.h_ImageCol[1]->set(rt0()); MaterialClear();
  279. GetBloom(dither /*&& (src.highPrecision() || rt0->highPrecision())*/ && !dest.highPrecision())->draw(src); // merging 2 RT's ('src' and 'rt0') with some scaling factors will give us high precision
  280. }
  281. static Flt PixelsToScale(Flt pixels, Int res) {return pixels*2/res;} // 'pixels=max blur range in pixels in one direction, 'res'=total resolution
  282. static Flt ScaleToPixels(Flt scale , Int res) {return scale*res/2 ;}
  283. static void SetMotionBlurParams(Flt pixels) // !! this needs to be called when the RT is 'D.motionRes' sized because it needs that size and not the full size !!
  284. {
  285. // see "C:\Users\Greg\SkyDrive\Code\Tests\Motion Blur.cpp"
  286. const Flt scale=PixelsToScale(MAX_MOTION_BLUR_PIXEL_RANGE, 1080); // scale should be small, because inside the shader we do "x/(1 +- blur.z)"
  287. const Flt limit=pixels/MAX_MOTION_BLUR_PIXEL_RANGE; // if we're using only 'pixels' then we have to limit from the full 0..1 range to the fraction
  288. Vec2 viewport_center=D._view_active.recti.centerF()/Renderer.res(), size2=D._unscaled_size*(2/scale)*limit;
  289. // pos=(inTex-viewport_center)*size2;
  290. // pos=inTex*size2 - viewport_center*size2;
  291. Mtn.h_MotionUVMulAdd ->setConditional(Vec4(size2.x, size2.y, -viewport_center.x*size2.x, -viewport_center.y*size2.y));
  292. Mtn.h_MotionVelScaleLimit->setConditional(Vec4(D.scale()/D.viewFovTanFull().x*limit, -D.scale()/D.viewFovTanFull().y*limit, scale, limit));
  293. Mtn.h_MotionPixelSize ->setConditional(Flt(MAX_MOTION_BLUR_PIXEL_RANGE)/Renderer.res()); // the same value is used for 'SetDirs' (D.motionRes) and 'Blur' (D.res)
  294. }
  295. // !! Assumes that 'ColClamp' was already set !!
  296. Bool RendererClass::motionBlur(Image &src, Image &dest, Bool dither)
  297. {
  298. if(stage==RS_VEL && set(_vel))return true;
  299. Mtn.load();
  300. Bool camera_object=(_vel!=null); // remember blur mode because it depends on '_vel' which gets cleared
  301. VecI2 res;
  302. res.y=Min(ByteScaleRes(fxH(), D._mtn_res), 1080); // only up to 1080 is supported, because shaders support only up to MAX_MOTION_BLUR_PIXEL_RANGE pixels, but if we enable higher resolution then it would require more pixels
  303. res.x=Max(1, Round(res.y*D._unscaled_size.div())); // calculate proportionally to 'res.y' and current mode aspect (do not use 'D.aspectRatio' because that's the entire monitor screen aspect, and not application window), all of this is needed because we need to have square pixels for motion blur render targets, however the main application resolution may not have square pixels
  304. const Flt pixels=res.y*(Flt(MAX_MOTION_BLUR_PIXEL_RANGE)/1080);
  305. const Int dilate_round_range=1; // this value should be the same as "Int range" in "Dilate_PS" Motion Blur shader
  306. Int dilate_round_steps;
  307. switch(D.motionDilate()) // get round dilate steps
  308. {
  309. default:
  310. case DILATE_ORTHO :
  311. case DILATE_ORTHO2: dilate_round_steps= 0; break; // zero round steps
  312. case DILATE_MIXED : dilate_round_steps=Round(pixels/dilate_round_range*0.3f); break; // 0.3f was chosen to achieve quality/performance that's between orthogonal and round mode
  313. case DILATE_ROUND : dilate_round_steps=Round(pixels/dilate_round_range ); break; // 'Round' should be enough
  314. }
  315. Int dilate_round_pixels=dilate_round_steps*dilate_round_range, dilate_ortho_pixels=Max(Round(pixels)-dilate_round_pixels, 0);
  316. Bool diagonal=(D.motionDilate()==DILATE_ORTHO2);
  317. C MotionBlur::Pixel *ortho=Mtn.pixel(dilate_ortho_pixels, diagonal); if(ortho)dilate_ortho_pixels=ortho->pixels; // reset 'dilate_ortho_pixels' because it can actually be bigger based on what is supported
  318. const Int total_pixels=dilate_round_pixels+dilate_ortho_pixels; // round+ortho
  319. DEBUG_ASSERT(D.motionDilate()==DILATE_ROUND ? dilate_ortho_pixels==0 : true, "Ortho should be zero in round mode");
  320. ImageRTDesc rt_desc(res.x, res.y, D.signedVelRT() ? IMAGERT_RGB_S : IMAGERT_RGB); // Alpha not used (XY=Dir, Z=Dir.length)
  321. ImageRTPtr converted(rt_desc);
  322. Shader *shader;
  323. if(camera_object)shader=Mtn.h_Convert[true ][!D._view_main.full];else
  324. { shader=Mtn.h_Convert[false][!D._view_main.full];
  325. SetFastVel();
  326. }
  327. set(converted(), null, false);
  328. Rect ext_rect, *rect=null;
  329. if(D._view_main.full)REPS(_eye, _eye_num)
  330. {
  331. Rect *eye_rect=setEyeParams();
  332. SetMotionBlurParams(pixels); // call after 'setEyeParams' because we need to set 'D._view_active'
  333. shader->draw(_vel, eye_rect);
  334. }else
  335. {
  336. SetMotionBlurParams(pixels);
  337. ext_rect=D.viewRect(); rect=&ext_rect.extend(Renderer.pixelToScreenSize(total_pixels+1)); // when not rendering entire viewport, then extend the rectangle because of 'Dilate' and 'SetDirs' checking neighbors, add +1 because of texture filtering, we can ignore stereoscopic there because that's always disabled for not full viewports, have to use 'Renderer.pixelToScreenSize' and not 'D.pixelToScreenSize'
  338. shader->draw(_vel, rect);
  339. }
  340. _vel.clear();
  341. if(stage==RS_VEL_CONVERT && set(converted))return true;
  342. ImageRTPtr dilated=converted, helper;
  343. if(camera_object) // we apply Dilation only in MOTION_CAMERA_OBJECT mode, for MOTION_CAMERA it's not needed
  344. {
  345. rt_desc.rt_type=(D.signedVelRT() ? IMAGERT_RGB_S : IMAGERT_RGB); // Alpha not used (XY=Dir, Z=Max Dir length of all nearby pixels)
  346. // we need to apply Dilation, for example, if a ball object has movement, then it should be blurred, and also pixels around the ball should be blurred too
  347. // however velocity for pixels around the ball (the background) may be zero, so we need to apply dilation and apply the velocity onto neighboring pixels
  348. // remember that it doesn't make sense to perform depth based tests on not first steps "dilated!=converted",
  349. // because the depth tests compare only center pixels and the pixels around it, however if in step #0 we dilate velocity from pixel with X coordinate=2,
  350. // onto pixel X=1, then in step #1, we dilate pixel X=1 onto X=0 (the velocity is carried over from pixel X=2 into X=0, however we don't store information
  351. // about what was the depth of that velocity, so in step #1 we're comparing depth of pixel X=0 with X=1, however we're using velocity from X=2,
  352. // so we should have information about X=2 depth, however there's no easy way to do that
  353. // TODO: check if depth tests are useful for the first step ("dilated==converted")
  354. if(ortho) // do orthogonal first (this will result in slightly less artifacts when the camera is moving)
  355. {
  356. helper .get(rt_desc); set(helper (), null, false); ortho->h_DilateX[diagonal]->draw(dilated(), rect);
  357. dilated.get(rt_desc); set(dilated(), null, false); ortho->h_DilateY[diagonal]->draw(helper (), rect);
  358. }
  359. REP(dilate_round_steps)
  360. {
  361. if(!helper || helper==converted)helper.get(rt_desc);else helper->discard(); // don't write to original 'converted' in the next step, because we need it later
  362. set(helper(), null, false); Mtn.h_Dilate->draw(dilated(), rect); Swap(dilated, helper);
  363. }
  364. }
  365. if(stage==RS_VEL_DILATED && set(dilated))return true;
  366. // check how far can we go (remove leaks)
  367. Sh.h_ImageCol[1]->set(dilated()); MaterialClear();
  368. rt_desc.rt_type=(D.signedVelRT() ? IMAGERT_RGBA_S : IMAGERT_RGBA); // XY=Dir#0, ZW=Dir#1
  369. helper.get(rt_desc); // we always need to call this because 'helper' can be set to 'converted'
  370. set(helper(), null, false); Mtn.h_SetDirs[!D._view_main.full]->draw(converted(), rect);
  371. if(stage==RS_VEL_LEAK && set(helper))return true;
  372. Sh.h_ImageCol[1]->set(helper()); MaterialClear();
  373. set(&dest, null, true);
  374. Mtn.h_Blur[dither /*&& src.highPrecision()*/ && !dest.highPrecision()]->draw(src); // here blurring may generate high precision values
  375. return false;
  376. }
  377. INLINE Shader* GetDofDS(Bool clamp , Bool realistic, Bool half) {Shader* &s=Dof.h_DofDS[clamp ][realistic][half]; if(SLOW_SHADER_LOAD && !s)s=Dof.getDS(clamp , realistic, half); return s;}
  378. INLINE Shader* GetDof (Bool dither, Bool realistic ) {Shader* &s=Dof.h_Dof [dither][realistic] ; if(SLOW_SHADER_LOAD && !s)s=Dof.get (dither, realistic ); return s;}
  379. // !! Assumes that 'ColClamp' was already set !!
  380. void RendererClass::dof(Image &src, Image &dest, Bool dither)
  381. { // Depth of Field shader does not require stereoscopic processing because it just reads the depth buffer
  382. const Int shift=1; // half
  383. ImageRTDesc rt_desc(fxW()>>shift, fxH()>>shift, src.highPrecision() ? IMAGERT_RGBA_H : IMAGERT_RGBA); // here Alpha is used to store amount of Blur, use high precision if source is to don't lose smooth gradients when having full blur (especially visible on sky), IMAGERT_RGBA_H vs IMAGERT_RGBA has no significant difference on GeForce 1050Ti
  384. ImageRTPtr rt0(rt_desc),
  385. rt1(rt_desc);
  386. Bool half=(Flt(src.h())/rt0->h() <= 2.5f); // half=scale 2, ..3.., quarter=scale 4, 2.5 was the biggest scale that didn't cause jittering when using half down-sampling
  387. Dof.load();
  388. C DepthOfField::Pixel &pixel=Dof.pixel(Round(fxH()*(5.0f/1080))); // use 5 pixel range blur on a 1080 resolution
  389. Flt range_inv=1.0f/Max(D.dofRange(), EPS);
  390. Dof.h_DofParams->setConditional(Vec4(D.dofIntensity(), D.dofFocus(), range_inv, -D.dofFocus()*range_inv));
  391. set(rt0(), null, false); Rect ext_rect, *rect=null; if(!D._view_main.full){ext_rect=D.viewRect(); rect=&ext_rect.extend(Renderer.pixelToScreenSize(pixel.pixels+1));} // when not rendering entire viewport, then extend the rectangle because of blurs checking neighbors, add +1 because of texture filtering, we can ignore stereoscopic there because that's always disabled for not full viewports, have to use 'Renderer.pixelToScreenSize' and not 'D.pixelToScreenSize' and call after setting RT
  392. GetDofDS(!D._view_main.full, D.dofFocusMode(), half)->draw(src , rect);
  393. set(rt1(), null, false); pixel.h_BlurX->draw(rt0(), rect);
  394. set(rt0(), null, false); rt0->discard(); pixel.h_BlurY->draw(rt1(), rect);
  395. set(&dest, null, true);
  396. Sh.h_ImageCol[1]->set(rt0()); MaterialClear();
  397. GetDof(dither && (src.highPrecision() || rt0->highPrecision()) && !dest.highPrecision(), D.dofFocusMode())->draw(src);
  398. }
  399. INLINE Shader* GetCombine () {Shader* &s=Sh.h_Combine ; if(SLOW_SHADER_LOAD && !s)s=Sh.get("Combine" ); return s;}
  400. INLINE Shader* GetCombineMS () {Shader* &s=Sh.h_CombineMS ; if(SLOW_SHADER_LOAD && !s)s=Sh.get("CombineMS" ); return s;}
  401. INLINE Shader* GetCombineSS () {Shader* &s=Sh.h_CombineSS ; if(SLOW_SHADER_LOAD && !s)s=Sh.get("CombineSS" ); return s;}
  402. INLINE Shader* GetCombineSSAlpha() {Shader* &s=Sh.h_CombineSSAlpha; if(SLOW_SHADER_LOAD && !s)s=Sh.get("CombineSSAlpha"); return s;}
  403. void RendererClass::Combine()
  404. {
  405. Bool alpha_premultiplied=false;
  406. if(_ds->multiSample() && Sh.h_CombineMS) // '_col' could have been resolved already, so check '_ds' instead
  407. {
  408. ImageRTPtr resolve=_final; if(resolve->compatible(*_ds_1s))D.alpha(ALPHA_BLEND);else
  409. {
  410. resolve.get(ImageRTDesc(_ds_1s->w(), _ds_1s->h(), IMAGERT_RGBA)); // resolve to a temp RT and apply that later, here Alpha is used for storing image opacity
  411. D.alpha(ALPHA_SETBLEND_SET); alpha_premultiplied=true;
  412. }
  413. set(resolve(), _ds_1s(), true, NEED_DEPTH_READ);
  414. if(hasStencilAttached())
  415. {
  416. D.stencil(STENCIL_MSAA_TEST, STENCIL_REF_MSAA); GetCombineMS()->draw(_col);
  417. D.stencilRef(0 ); GetCombine ()->draw(_col);
  418. D.stencil(STENCIL_NONE );
  419. }else
  420. {
  421. GetCombineMS()->draw(_col); // we have to run all at multi-sampled frequency
  422. }
  423. _col=resolve;
  424. }else
  425. if(_col->w()<_final->w()) // resolve first to small buffer
  426. {
  427. ImageRTPtr resolve=_col; resolve.get(ImageRTDesc(_col->w(), _col->h(), IMAGERT_RGBA)); // here Alpha is used for storing image opacity
  428. set(resolve(), null, false); // request full viewport because we will need it below, when drawing black borders
  429. D.alpha(ALPHA_SETBLEND_SET); alpha_premultiplied=true;
  430. GetCombine()->draw(_col, &D.viewRect());
  431. _col=resolve;
  432. }else
  433. if(_ds->w()>_final->w()) // resolve Alpha first to full buffer, check '_ds' because '_col' could have been already downsampled
  434. {
  435. ImageRTPtr alpha; alpha.get(ImageRTDesc(_ds_1s->w(), _ds_1s->h(), IMAGERT_ONE));
  436. set(alpha(), null, true);
  437. D.alpha(ALPHA_NONE);
  438. GetCombineSSAlpha()->draw();
  439. Sh.h_ImageCol[1]->set(alpha); MaterialClear();
  440. set(_final(), null, true);
  441. D.alpha(ALPHA_BLEND);
  442. GetCombineSS()->draw(_col);
  443. _col=_final;
  444. }else
  445. {
  446. set(_final(), null, true);
  447. D.alpha(ALPHA_BLEND);
  448. GetCombine()->draw(_col);
  449. _col=_final;
  450. }
  451. if(_col!=_final)
  452. {
  453. Shader *shader=null;
  454. Bool upscale_none=false;
  455. if(_col->w()<_final->w()) // upscale
  456. {
  457. Bool dither=(D.dither() && !_final->highPrecision()); // disable dithering if destination has high precision
  458. Int pixels=1+1; // 1 for filtering + 1 for borders (because source is smaller and may not cover the entire range for dest, for example in dest we want 100 pixels, but 1 source pixel covers 30 dest pixels, so we may get only 3 source pixels covering 90 dest pixels)
  459. switch(D.densityFilter()) // remember that cubic shaders are optional and can be null if failed to load
  460. {
  461. case FILTER_NONE:
  462. {
  463. upscale_none=true;
  464. pixels=1; // 1 for borders
  465. #if DX9
  466. Sh.h_ImageCol[0]->_sampler=&SamplerPoint;
  467. #elif DX11
  468. SamplerPoint.setPS(SSI_DEFAULT);
  469. #elif GL // in GL 'ShaderImage.Sampler' does not affect filtering, so modify it manually
  470. D.texBind(GL_TEXTURE_2D, _col->_txtr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  471. #endif
  472. }break;
  473. case FILTER_CUBIC_FAST :
  474. case FILTER_CUBIC_FAST_SMOOTH:
  475. case FILTER_CUBIC_FAST_SHARP :
  476. pixels=2+1; // 2 for filtering + 1 for borders
  477. shader=(dither ? Sh.h_DrawTexCubicFastD : Sh.h_DrawTexCubicFast1); // this doesn't need to check for "_col->highPrecision" because resizing and cubic filtering generates smooth values
  478. break;
  479. case FILTER_BEST :
  480. case FILTER_CUBIC :
  481. case FILTER_CUBIC_SHARP:
  482. pixels=3+1; // 3 for filtering + 1 for borders
  483. Sh.loadCubicShaders(); shader=(dither ? Sh.h_DrawTexCubicD : Sh.h_DrawTexCubic1); // this doesn't need to check for "_col->highPrecision" because resizing and cubic filtering generates smooth values
  484. break;
  485. }
  486. if(!D._view_main.full)
  487. {
  488. set(_col(), null, false); // need full viewport
  489. D.viewRect().drawBorder(TRANSPARENT, Renderer.pixelToScreenSize(-pixels)); // draw black border around the viewport to clear and prevent from potential artifacts on viewport edges
  490. }
  491. }
  492. if(!shader)shader=Sh.h_Draw; // ignore dithering for simple filtering because we've resolved this to low precision RT
  493. set(_final(), null, true);
  494. D.alpha(alpha_premultiplied ? ALPHA_MERGE : ALPHA_BLEND);
  495. shader->draw(_col);
  496. if(upscale_none)
  497. {
  498. #if DX9
  499. Sh.h_ImageCol[0]->_sampler=null;
  500. #elif DX11
  501. SamplerLinearClamp.setPS(SSI_DEFAULT);
  502. #elif GL
  503. if(!GL_ES || ImageTI[_col->hwType()].precision<IMAGE_PRECISION_32) // GLES2/3 don't support filtering F32 textures, without this check reading from F32 textures will fail - https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml
  504. {D.texBind(GL_TEXTURE_2D, _col->_txtr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}
  505. #endif
  506. }
  507. _col=_final;
  508. }
  509. }
  510. /******************************************************************************/
  511. inline void TexLod(Int lod)
  512. {
  513. #if DX9
  514. REP(16)D3D->SetSamplerState(i, D3DSAMP_MAXMIPLEVEL, lod); // this is 'D3D11_SAMPLER_DESC.MinLOD'
  515. #elif DX11
  516. // handled in 'CreateAnisotropicSampler'
  517. #endif
  518. }
  519. inline void TexLodLimit() {if(D.texLod())TexLod(D.texLod());} // this sets the 'D.texLod' into device settings, it's handled only during rendering to affect only 3D graphics and not the 2D interface (DX11 version operates on 'AnisotropicSampler' which is used only in 3D graphics)
  520. inline void TexLodFull () {if(D.texLod())TexLod( 0);} // this resets the device settings to have full quality (all LOD's)
  521. void RendererClass::cleanup()
  522. {
  523. _ds .clear();
  524. //_ds_1s .clear(); do not clear '_ds_1s' because 'setDepthForDebugDrawing' may be called after rendering finishes, also 'capture' makes use of it
  525. _nrm .clear();
  526. _vel .clear();
  527. _lum .clear();
  528. _lum_1s .clear();
  529. _shd_1s .clear();
  530. _shd_ms .clear();
  531. _water_col .clear();
  532. _water_nrm .clear();
  533. _water_ds .clear();
  534. _water_lum .clear();
  535. _vol .clear();
  536. _ao .clear();
  537. _mirror_rt .clear();
  538. _outline_rt .clear();
  539. _sky_coverage.clear();
  540. Lights.clear();
  541. ClearInstances();
  542. }
  543. RendererClass& RendererClass::operator()(void (&render)())
  544. {
  545. #if DEBUG
  546. if(Kb.b(KB_NP0))stage=RS_DEPTH;else
  547. if(Kb.b(KB_NP1))stage=RS_COLOR;else
  548. if(Kb.b(KB_NP2))stage=RS_NORMAL;else
  549. if(Kb.b(KB_NP3))stage=RS_VEL;else
  550. if(Kb.b(KB_NP4))stage=(Kb.b(KB_NP5) ? RS_LIGHT_AO : RS_LIGHT);else
  551. if(Kb.b(KB_NP5))stage=RS_AO;else
  552. if(Kb.b(KB_NP6))stage=RS_LIT_COLOR;else
  553. if(Kb.b(KB_NP7))stage=RS_WATER_COLOR;else
  554. if(Kb.b(KB_NP8))stage=RS_WATER_NORMAL;else
  555. if(Kb.b(KB_NP9))stage=RS_WATER_LIGHT;else
  556. if(Kb.b(KB_NPDIV))stage=RS_REFLECTION;else
  557. if(Kb.br(KB_NP0) || Kb.br(KB_NP1) || Kb.br(KB_NP2) || Kb.br(KB_NP3) || Kb.br(KB_NP4) || Kb.br(KB_NP5) || Kb.br(KB_NP6) || Kb.br(KB_NP7) || Kb.br(KB_NP8) || Kb.br(KB_NP9)
  558. || Kb.br(KB_NPDIV))stage=RS_DEFAULT;
  559. #endif
  560. // Shadow Settings
  561. Sh.h_ShdRange->setConditional(T._shd_range=D._shd_frac*D.viewRange());
  562. {
  563. Flt from=T._shd_range*D._shd_fade,
  564. to =T._shd_range;
  565. if(from>=D.viewRange()-EPSL) // disabled
  566. {
  567. Sh.h_ShdRangeMulAdd->setConditional(Vec2(0));
  568. }else
  569. {
  570. MAX(to, from+0.01f);
  571. from*=from; to*=to;
  572. Flt mul=1/(to-from), add=-from*mul;
  573. Sh.h_ShdRangeMulAdd->setConditional(Vec2(mul, add));
  574. }
  575. }
  576. // vertex fog settings
  577. {
  578. Flt from=D.viewRange()*simpleVertexFogStart(),
  579. to =D.viewRange()*simpleVertexFogEnd (); MAX(to, from+0.01f);
  580. // remember that GL ES MP precision is in range Pow2(2, -14) .. Pow2(2, 14) : (0.000061035 .. 16384)
  581. #if 1 // quadratic mul add (currently used) (does not qualify for MP), must be HP because of high values !!
  582. //Flt fog_intensity=Length2(O.pos)*VertexFogMulAdd.x+VertexFogMulAdd.y;
  583. // 0=Sqr (from )*VertexFogMulAdd.x+VertexFogMulAdd.y;
  584. // 1=Sqr (to )*VertexFogMulAdd.x+VertexFogMulAdd.y;
  585. Flt mul, add;
  586. if(simpleVertexFogStart()>=1){mul=0; add=1;}else // no fog
  587. { // fog
  588. to*=to; from*=from;
  589. mul=1/(to-from); add=-from*mul;
  590. // now reverse (fog_intensity -> 1-fog_intensity)
  591. mul=-mul ; // for viewRange(350).fogRange(1, 1) mul = ~ -0.14269789
  592. add=-add+1; // for viewRange(350).fogRange(1, 1) add = ~ 17481.490
  593. }
  594. #elif 0 // linear mul add (does not qualify for MP)
  595. //Flt fog_intensity=Length(O.pos)*VertexFogMulAdd.x+VertexFogMulAdd.y;
  596. // 0= (from )*VertexFogMulAdd.x+VertexFogMulAdd.y;
  597. // 1= (to )*VertexFogMulAdd.x+VertexFogMulAdd.y;
  598. Flt mul=1/(to-from), add=-from*mul;
  599. // now reverse (fog_intensity -> 1-fog_intensity)
  600. mul=-mul ; // for viewRange(350).fogRange(1, 1) mul = ~ - 100
  601. add=-add+1; // for viewRange(350).fogRange(1, 1) add = ~ -35000
  602. #elif 0 // quadratic add mul (does not qualify for MP)
  603. //Flt fog_intensity=(Length2(O.pos)+VertexFogMulAdd.y)*VertexFogMulAdd.x;
  604. // 0=(Sqr (from )+VertexFogMulAdd.y)*VertexFogMulAdd.x;
  605. // 1=(Sqr (to )+VertexFogMulAdd.y)*VertexFogMulAdd.x;
  606. //Flt add=-Sqr(from), mul=1.0f/(Sqr(to)-Sqr(from));
  607. // reversed (fog_intensity -> 1-fog_intensity)
  608. Flt add=-Sqr(to), // for viewRange(350).fogRange(1, 1) add = ~ -122507 , for viewRange(2000).fogRange(0, 1); add = ~ -4000000
  609. mul=1.0f/(Sqr(from)-Sqr(to)); // for viewRange(350).fogRange(1, 1) mul = ~ -0.14271572, for viewRange(2000).fogRange(0, 1); mul = ~ -2.5000000e-007
  610. #else // linear add mul (qualifies for MP) (however since Length(Vec) is required, it can't be MP because Length(Vec(128)) = Sqrt(Dot(Vec(128), Vec(128))) where Dot would result in 16384 values which is the MP limit (and making only first 128 meters usable)
  611. //Flt fog_intensity=(Length(O.pos)+VertexFogMulAdd.y)*VertexFogMulAdd.x;
  612. // 0=( (from )+VertexFogMulAdd.y)*VertexFogMulAdd.x;
  613. // 1=( (to )+VertexFogMulAdd.y)*VertexFogMulAdd.x;
  614. //Flt add=-from, mul=1.0f/(to-from);
  615. // reversed (fog_intensity -> 1-fog_intensity)
  616. Flt add=-to, // for viewRange(350).fogRange(1, 1) add = ~ -350, for viewRange(2000).fogRange(0, 1); add = ~ -2000
  617. mul=1.0f/(from-to); // for viewRange(350).fogRange(1, 1) mul = ~ -100, for viewRange(2000).fogRange(0, 1); mul = ~ -0.0005
  618. #endif
  619. Sh.h_VertexFogMulAdd->setConditional(Vec2(mul, add));
  620. Sh.h_VertexFogColor ->setConditional(_vtx_fog_color);
  621. }
  622. // prepare
  623. _render =render;
  624. _stereo =(VR.active() && D._view_main.full && !combine && !target && !_get_target && D._allow_stereo); // use stereo only for full viewport, if we're not combining (games may use combining to display 3D items/characters in Gui)
  625. _eye_num =_stereo+1; // _stereo ? 2 : 1
  626. _has_glow =false;
  627. _fur_is =false;
  628. _mirror_want=false;
  629. _outline =0;
  630. _final =(target ? target : _stereo ? VR.getNewRender() : _cur_main);
  631. if(VR.active())D.setViewFovTan(); // !! call after setting _stereo and _render !!
  632. // !! it is important to call this as the first thing during rendering, because 'Game.WorldManager.draw' assumes so, if this needs to be changed then rework 'Game.WorldManager.draw' !!
  633. // set water
  634. Water.prepare();
  635. #define MEASURE(x) if(_t_measure){D.finish(); Dbl c=Time.curTime(); x+=c-t; t=c;}
  636. // render
  637. {
  638. Dbl t; Flt temp, water;
  639. if(_t_measure){D.finish(); t=Time.curTime(); temp=water=0; _t_measures[0]++;}
  640. TexLodLimit();
  641. if(reflection())goto finished; MEASURE(_t_reflection[1])
  642. prepare(); MEASURE(_t_prepare[1])
  643. solid (); MEASURE(_t_solid [1])
  644. #if GL_ES && !WEB // we need to make sure that depth RT is flushed to depth texture on tile-based deferred renderers, this is because on those devices the RT's (including depth buffer) are stored in fast on-chip memory and to be able to read from them, we need to flush them to the texture memory. This is done after reading solid's and before we may read from the depth buffer. No need to do on WEB because there we can never read from depth while writing to it.
  645. if(canReadDepth())
  646. if(D.edgeDetect() || D.particlesSoft() || Sky.wantDepth() || Clouds.wantDepth() || Fog.draw/* || Sun.wantDepth()*/) // here we need to check only effects that may read from depth without changing any RT's, because on any RT change the depth is flushed. Sun doesn't bind DS to FBO when drawing rays. TODO: we wouldn't need to do this if all shaders reading from the depth would use gl_LastFragDepth - https://www.khronos.org/registry/OpenGL/extensions/ARM/ARM_shader_framebuffer_fetch_depth_stencil.txt
  647. { // unbinding will force the flush (calling just 'glFlush' was not enough)
  648. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, 0);
  649. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
  650. _cur_ds=null; _cur_ds_id=0;
  651. }
  652. #endif
  653. overlay(); MEASURE(_t_overlay[1])
  654. // set background sky pixels not drawn by foreground object meshes (everything at the end of depth buffer), this needs to be done before 'blend' because fur may set depth buffer without setting velocities, and before water surface
  655. {
  656. Bool clear_nrm=(_nrm && !NRM_CLEAR_START && ClearNrm());
  657. if( clear_nrm || _vel)
  658. {
  659. D.alpha (ALPHA_NONE);
  660. D.depth2DOn(true);
  661. if(clear_nrm)
  662. {
  663. set(_nrm(), _ds(), true); Sh.clear(D.signedNrmRT() ? SNRM_CLEAR : NRM_CLEAR); // use DS because we use it for 'D.depth2D' optimization
  664. }
  665. if(_vel)
  666. {
  667. Mtn.load(); set(_vel(), _ds(), true); Mtn.h_ClearSkyVel->draw(null); // use DS because we use it for 'D.depth2D' optimization
  668. }
  669. D.depth2DOff();
  670. }
  671. }
  672. if(stage)switch(stage)
  673. {
  674. case RS_COLOR : if(_cur_type==RT_DEFERRED && set(_col ))goto finished; break; // only on deferred renderer the color is unlit
  675. case RS_NORMAL: if( set(_nrm ))goto finished; break;
  676. case RS_DEPTH : if( set(_ds_1s))goto finished; break; // this may be affected by test blend materials later
  677. }
  678. waterPreLight(); MEASURE(water)
  679. light (); MEASURE(_t_light[1])
  680. if(stage)switch(stage)
  681. {
  682. case RS_LIT_COLOR: if(set(_col))goto finished; break;
  683. case RS_LIGHT: if(_lum_1s)
  684. {
  685. if(_ao) // if there's AO available, then it means that ambient hasn't been applied yet to '_lum_1s', to keep consistency with '_lum_1s' when AO is disabled, apply flat ambient here
  686. {
  687. set(_lum_1s(), null, true);
  688. D.alpha(ALPHA_ADD);
  689. Sh.clear(Vec4(D.ambientColor(), 0));
  690. }
  691. if(set(_lum_1s))goto finished;
  692. }break;
  693. case RS_AO: if(_ao)
  694. {
  695. set(_final(), null, true); D.alpha(ALPHA_NONE); VI.shader(GPU_API(Sh.h_DrawTexW, Sh.h_DrawTexX, Sh.h_DrawTexX)); _ao->drawFs(FIT_FULL, FILTER_LINEAR); // DX9 uses A8 while others use R8 RT
  696. goto finished;
  697. }break;
  698. case RS_LIGHT_AO: if(_lum_1s)
  699. {
  700. if(_ao)
  701. {
  702. set(_lum_1s(), null, true); D.alpha(ALPHA_ADD);
  703. Sh.h_Color[0]->set(Vec4(D.ambientColor(), 0));
  704. Sh.h_Color[1]->set(Vec4Zero );
  705. Sh.GPU_API(h_DrawTexWC, h_DrawTexXC, h_DrawTexXC)->draw(_ao); // DX9 uses A8 while others use R8 RT
  706. }
  707. if(set(_lum_1s))goto finished;
  708. }break;
  709. }
  710. if(waterPostLight())goto finished; MEASURE(_t_water[1])if(_t_measure)_t_water[1]+=water;
  711. edgeDetect ();
  712. MEASURE(temp)
  713. TexLodFull();
  714. sky(); MEASURE(_t_sky[1])
  715. TexLodLimit();
  716. blend(); MEASURE(_t_blend[1])
  717. /*if(stage)switch(stage)
  718. {
  719. case RS_DEPTH: if(set(_ds_1s))goto finished; break;
  720. }*/
  721. palette(0);
  722. palette(1); MEASURE(_t_palette[1])
  723. behind ( ); MEASURE(_t_behind [1])
  724. outline( );
  725. // 2D
  726. TexLodFull ();
  727. finalizeGlow (); // !! assume that nothing below can trigger glow on the scene !!
  728. applyOutline ();
  729. edgeSoften (); MEASURE(temp)
  730. // all following effects below that modify '_col' (and not create new '_col') should call 'downSample' first, otherwise they should call 'resolveMultiSample'
  731. if(AstroDrawRays())goto finished; MEASURE(_t_rays[1])
  732. volumetric (); MEASURE(_t_volumetric[1])
  733. refract (); MEASURE(_t_refract[1])
  734. postProcess (); MEASURE(_t_post_process[1])
  735. finished:;
  736. }
  737. // cleanup
  738. {
  739. TexLodFull();
  740. _render=null; // this specifies that we're outside of Rendering
  741. _final.clear();
  742. D.alpha(ALPHA_BLEND); mode(RM_SIMPLE);
  743. set(_cur_main, _cur_main_ds, true);
  744. Sky.setFracMulAdd(); // in case user draws billboards/particles outside of Renderer, call before 'cleanup' because this relies on depth buffer being available
  745. cleanup();
  746. if(VR.active())
  747. {
  748. D.setViewFovTan(); // !! call after clearing _render !!
  749. if(_stereo)
  750. {
  751. D.clearCol(); // normally after rendering has finished we expect to draw on top of the result, however for stereoscopic, we've rendered to a separate render target, that won't be used for 2D drawing now, instead we're now back to '_cur_main' which is not yet initialized, so we need to clear it here
  752. // restore settings to centered (not one of the eyes)
  753. D._view_main.setShader().setProjMatrix(false); // viewport
  754. SetCam(ActiveCam.matrix, false); Frustum=FrustumMain; // camera and frustum
  755. }
  756. }
  757. }
  758. if(_shader_param_changes)Exit("'LinkShaderParamChanges' was called without 'UnlinkShaderParamChanges'.");
  759. return T;
  760. }
  761. ImageRTPtr RendererClass::get(void (&render)())
  762. {
  763. _get_target=true ; T(render);
  764. _get_target=false; ImageRTPtr temp=_col; _col.clear(); return temp;
  765. }
  766. Bool RendererClass::reflection()
  767. {
  768. // render reflection
  769. if(_mirror_want)
  770. {
  771. // remember current settings and disable fancy effects
  772. Camera cam =ActiveCam ;
  773. Bool combine =T. combine ; T. combine =false ;
  774. Bool stereo =T._stereo ; T._stereo =false ; // don't reset FOV because we want to render the reflection with the same exact FOV settings as only one eye, because this reflection will be reused for both eyes
  775. Int eye_num =T._eye_num ; T._eye_num =1 ;
  776. RENDER_TYPE render_type =T._cur_type ; T._cur_type =Water.reflectionRenderer();
  777. Bool hp_col_rt =D.highPrecColRT (); D._hp_col_rt =false ;
  778. Bool hp_nrm_rt =D.highPrecNrmRT (); D._hp_nrm_rt =false ;
  779. Bool hp_lum_rt =D.highPrecLumRT (); D._hp_lum_rt =false ;
  780. IMAGE_PRECISION lit_col_rt_prec=D.litColRTPrecision(); D._lit_col_rt_prec=IMAGE_PRECISION_8 ;
  781. Bool hp_nrm_calc =D.highPrecNrmCalc (); D.highPrecNrmCalc (false );
  782. Bool eye_adapt =D.eyeAdaptation (); D.eyeAdaptation (false );
  783. Bool vol_light =D.volLight (); D.volLight (false ); // if it will be enabled, then calling 'volumetric' is required and clearing Renderer._vol_is
  784. AMBIENT_MODE amb_mode =D.ambientMode (); D.ambientMode (AMBIENT_FLAT );
  785. MOTION_MODE mtn_mode =D.motionMode (); D.motionMode (MOTION_NONE );
  786. SHADOW_MODE shd_mode =D.shadowMode (); if(!_mirror_shadows)D.shadowMode (SHADOW_NONE );
  787. Byte shd_soft =D.shadowSoft (); D.shadowSoft (0 );
  788. Bool shd_jitter =D.shadowJitter (); D.shadowJitter (false );
  789. EDGE_SOFTEN_MODE edge_soft =D.edgeSoften (); D._edge_soften =EDGE_SOFTEN_NONE ;
  790. Bool tesselation =D.tesselationAllow (); D.tesselationAllow(false );
  791. Byte density =D.densityByte (); D.densityFast (Mid(((D.densityByte()+1)>>_mirror_resolution)-1, 0, 255));
  792. // set new settings
  793. _mirror=true; // set before viewport and camera
  794. // <- change viewport here if needed
  795. ConstCast(ActiveCam).matrix.mirror(_mirror_plane); SetCam(ActiveCam.matrix); // set mirrored camera
  796. D.clipPlane(_mirror_plane); // set clip plane after viewport and camera
  797. Sh.h_AllowBackFlip->set(1); // disable back flipping
  798. // render !! adding new modes here will require setting there D.clipPlane !!
  799. prepare();
  800. solid ();
  801. light ();
  802. sky ();
  803. blend ();
  804. AstroDrawRays();
  805. // cleanup
  806. cleanup(); Swap(_mirror_rt, _col); // 'cleanup' clears '_mirror_rt' so we need to set it after calling the function
  807. // restore effects (before viewport and camera, because stereoscopic affects viewport fov)
  808. T. combine =combine ;
  809. T._stereo =stereo ;
  810. T._eye_num =eye_num ;
  811. T._cur_type =render_type ;
  812. D._hp_col_rt =hp_col_rt ;
  813. D._hp_nrm_rt =hp_nrm_rt ;
  814. D._hp_lum_rt =hp_lum_rt ;
  815. D._lit_col_rt_prec=lit_col_rt_prec;
  816. D.highPrecNrmCalc (hp_nrm_calc );
  817. D.eyeAdaptation (eye_adapt );
  818. D.volLight (vol_light );
  819. D.ambientMode (amb_mode );
  820. D.motionMode (mtn_mode );
  821. D.shadowMode (shd_mode );
  822. D.shadowSoft (shd_soft );
  823. D.shadowJitter (shd_jitter );
  824. D._edge_soften =edge_soft ;
  825. D.tesselationAllow(tesselation );
  826. D.densityFast (density );
  827. // restore previous settings (mirror, viewport and camera)
  828. Sh.h_AllowBackFlip->set(-1); // re-enable back flipping
  829. _mirror=false; // !! set before viewport and camera, because it affects the Frustum, and after 'cleanup' !!
  830. // <- reset viewport here if needed
  831. cam.set(); // camera
  832. if(stage==RS_REFLECTION && set(_mirror_rt))return true;
  833. }
  834. return false;
  835. }
  836. /******************************************************************************/
  837. Bool RendererClass:: hasEdgeSoften()C {return wantEdgeSoften() && !fastCombine();}
  838. Bool RendererClass::wantEdgeSoften()C
  839. {
  840. switch(D.edgeSoften())
  841. {
  842. case EDGE_SOFTEN_FXAA: return Sh.h_FXAA!=null;
  843. #if SUPPORT_MLAA
  844. case EDGE_SOFTEN_MLAA: return Sh.h_MLAAEdge && Sh.h_MLAABlend && Sh.h_MLAA && _mlaa_area;
  845. #endif
  846. case EDGE_SOFTEN_SMAA: return Sh.h_SMAAEdge && Sh.h_SMAABlend && Sh.h_SMAA && _smaa_area && _smaa_search;
  847. }
  848. return false;
  849. }
  850. Bool RendererClass::wantDepth ()C {return wantMotion() || wantDof() || D.aoWant() || D.edgeDetect() || D.particlesSoft() || D.volLight() || Sky.wantDepth() || Clouds.wantDepth() || Fog.draw || Sun.wantDepth() || !Water.max1Light();} // TODO: even though we check all known things here, there are still some things about we don't know up-front (like local fog, decals, Image.drawVolume, ..)
  851. Bool RendererClass::canReadDepth ()C {return _ds->depthTexture();} // have to check '_ds' because this is the original source depth, it can be multi-sampled (in that case it's possible depth reading won't be available), but '_ds_1s' is 1-sampled (and could have depth-reads even if '_ds' doesn't)
  852. Bool RendererClass::safeCanReadDepth ()C {return _ds && _ds->depthTexture();}
  853. Bool RendererClass::hasStencilAttached()C {return hasDepthAttached() && ImageTI[_cur_ds->hwType()].s;}
  854. Bool RendererClass::hasDepthAttached ()C
  855. {
  856. #if GL
  857. return _cur_ds && _cur_ds->_txtr==_cur_ds_id; // check both '_cur_ds' and '_cur_ds_id' because '_cur_ds_id' will be 0 when Image is a RenderBuffer or temporarily unbound Texture (only Textures can be temporarily unbound), this will work OK for RenderBuffers because both '_cur_ds_id' and 'cur_ds->_txtr' will be zero
  858. #else
  859. return _cur_ds_id!=null; // we have to check '_cur_ds_id' because on DX10 it can be null if read-only is not supported
  860. #endif
  861. }
  862. Bool RendererClass::canReadDepth1S()C
  863. {
  864. return canReadDepth()
  865. #if DX11
  866. && _ds_1s->_dsv !=_cur_ds_id // we always read from '_ds_1s', we can do that only if it's not bound as Depth RT, on purpose we check '_dsv' and not '_rdsv' because '_rdsv' IS allowed
  867. #elif WEB
  868. && _ds_1s->_txtr!=_cur_ds_id // we always read from '_ds_1s', we can do that only if it's not bound as Depth RT
  869. #endif
  870. ;
  871. }
  872. Bool RendererClass::wantBloom ()C {return D.bloomUsed();}
  873. Bool RendererClass:: hasBloom ()C {return wantBloom() && !fastCombine();}
  874. Bool RendererClass::wantEyeAdapt()C {return D.eyeAdaptation() && _eye_adapt_scale[0].is();}
  875. Bool RendererClass:: hasEyeAdapt()C {return wantEyeAdapt() && !fastCombine();}
  876. Bool RendererClass::wantMotion ()C {return D.motionMode() && FovPerspective(D.viewFovMode());}
  877. Bool RendererClass:: hasMotion ()C {return wantMotion() && canReadDepth() && !fastCombine();}
  878. Bool RendererClass::wantDof ()C {return D.dofWant();}
  879. Bool RendererClass:: hasDof ()C {return wantDof() && canReadDepth() && !fastCombine();}
  880. Bool RendererClass:: hasAO ()C {return D.aoWant() && canReadDepth() && !fastCombine();}
  881. Bool RendererClass::fastCombine ()C {return combine && _col==_final;}
  882. Bool RendererClass::slowCombine ()C {return combine && !fastCombine() && canReadDepth();}
  883. Bool RendererClass::hasVolLight ()C {return D.volLight() && canReadDepth();}
  884. Bool RendererClass::anyDeferred ()C {return type()==RT_DEFERRED || Water.reflectionRenderer()==RT_DEFERRED;}
  885. Bool RendererClass::anyForward ()C {return type()==RT_FORWARD || Water.reflectionRenderer()==RT_FORWARD ;}
  886. Bool RendererClass::lowDepthPrecision()C {return _main_ds.type()==IMAGE_D16;} // this can happen only on Android, and there we do have information about the depth buffer
  887. /******************************************************************************/
  888. Bool RendererClass::set(C ImageRTPtr &image)
  889. {
  890. if(image)
  891. {
  892. if(ImageTI[image->hwType()].d) // depth
  893. {
  894. if(!image->depthTexture())return false; // can't read
  895. set(_final(), null, true); D.alpha(ALPHA_NONE); Sh.get("DrawDepth")->draw(image);
  896. }else
  897. if(image->type()!=IMAGE_R8G8B8A8_SIGN
  898. && image->type()!=IMAGE_R8G8_SIGN
  899. && image->type()!=IMAGE_R8_SIGN)image->copyHw(*_final, false, D.viewRect());else
  900. {
  901. set(_final(), null, true); D.alpha(ALPHA_NONE);
  902. // we need to draw image*0.5f+0.5f
  903. Sh.h_Color[0]->set (Vec4(0.5f, 0.5f, 0.5f, 0));
  904. Sh.h_Color[1]->set (Vec4(0.5f, 0.5f, 0.5f, 1));
  905. Sh.h_DrawC ->draw(image);
  906. }
  907. return true;
  908. }
  909. return false;
  910. }
  911. Bool RendererClass::swapDS1S(ImageRTPtr &ds_1s)
  912. {
  913. if(!T._ds_1s->accessible())return false; // can't swap if current DS is not accessible
  914. if( T._ds==T._ds_1s)
  915. {
  916. if(T._ds==T._cur_main_ds)T._cur_main_ds=ds_1s.rc();
  917. T._ds = ds_1s ; Sh.h_ImageDepthMS->set(T._ds );
  918. } Swap(T._ds_1s, ds_1s); Sh.h_ImageDepth ->set(T._ds_1s);
  919. return true;
  920. }
  921. void RendererClass::setDS()
  922. {
  923. if(_col==&_main )_ds=&_main_ds ;else // we should always pair '_main' with '_main_ds', even if it's not 'accessible'
  924. if(_col== _cur_main)_ds= _cur_main_ds;else // reuse '_cur_main_ds' if we're rendering to '_cur_main'
  925. _ds.getDS(_col->w(), _col->h(), _col->samples()); // create a new one
  926. }
  927. void RendererClass::prepare()
  928. {
  929. Byte samples=(mirror() ? 1 : D.samples()); // disable multi-sampling for reflection
  930. VecI2 rt_size; if(VR.active() && D._allow_stereo) // following conditions affect this: _stereo, _allow_stereo, mirror()
  931. { /* We want this case when:
  932. -rendering to VR 'GuiTexture'
  933. -rendering to VR 'RenderTexture'
  934. -rendering to mirror reflection to be used for VR 'RenderTexture'
  935. Remember that '_stereo' gets temporarily disabled when rendering mirror reflection */
  936. rt_size=_final->size();
  937. if(D.densityUsed())
  938. {
  939. Int mul=D.densityByte()+1;
  940. rt_size.set(Mid((rt_size.x*mul+64)/128, 1, D.maxTexSize()),
  941. Mid((rt_size.y*mul+64)/128, 1, D.maxTexSize()));
  942. }
  943. }else rt_size=D.render();
  944. start:
  945. IMAGE_PRECISION prec=((_cur_type==RT_DEFERRED) ? D.highPrecColRT() ? IMAGE_PRECISION_10 : IMAGE_PRECISION_8 : D.litColRTPrecision()); // for deferred renderer we first render to col and only after that we mix it with light, other modes render color already mixed with light, for high precision we need only 10-bit, no need for 16-bit
  946. _col=_final;
  947. if(_cur_type==RT_DEFERRED || mirror() || _get_target // <- these always require
  948. || _col->size()!=rt_size || _col->samples()!=samples || _col->precision()<prec // if current RT does not match the requested rendering settings
  949. || wantBloom() || wantEdgeSoften() || wantMotion() || wantDof() || wantEyeAdapt() // if we want to perform post process effects then we will be rendering to a secondary RT anyway, so let's start with secondary with a chance that during the effect we can render directly to '_final'
  950. || (D.glowAllow() && ImageTI[_col->hwType()].a<8) // we need alpha for glow, this check is needed for example if we have IMAGE_R10G10B10A2
  951. || (_col==&_main && !_main_ds.depthTexture() && wantDepth()) // if we're setting '_main' which is always paired with '_main_ds', and that is not a depth texture but we need to access depth, then try getting custom RT with depth texture (don't check for '_cur_main' and '_cur_main_ds' because depth buffers other than '_main_ds' are always tried to be created as depth texture first, so if that failed, then there's no point in trying to create one again)
  952. )_col.get(ImageRTDesc(rt_size.x, rt_size.y, GetImageRTType(D.glowAllow(), prec), samples)); // here Alpha is used for glow
  953. // depth stencil buffer
  954. setDS();
  955. if(combine && !canReadDepth() && _col!=_final) // if we need to combine (treat combine with priority), but after getting the depth buffer it turns out we can't read it (can't do combine), then we must render to final render target directly
  956. {
  957. _col=_final; setDS();
  958. }
  959. if(!canReadDepth() && _cur_type==RT_DEFERRED) // if depth access is not available and we want deferred renderer then fall back to forward renderer
  960. {
  961. if(type ()==RT_DEFERRED)type (RT_FORWARD);
  962. if(Water.reflectionRenderer()==RT_DEFERRED)Water.reflectionRenderer(RT_FORWARD);
  963. _cur_type =RT_FORWARD ;
  964. goto start;
  965. }
  966. if(!_ds->multiSample ())_ds_1s=_ds;else // if the source is not multisampled then reuse it
  967. if( _ds->depthTexture())_ds_1s.getDS(_ds->w(), _ds->h());else // create new only if we can resolve multi-sample onto 1-sample
  968. _ds_1s.clear(); // there's no point in creating a 1-sampled depth buffer if we can't resolve from the multi-sampled
  969. Sh.h_ImageDepth ->set(_ds_1s);
  970. Sh.h_ImageDepthMS->set(_ds );
  971. _set_depth_needed=(_ds!=_cur_main_ds && _ds_1s!=_cur_main_ds && canReadDepth()); // if we're not rendering to currently main depth buffer and we have depth access
  972. D.alpha(ALPHA_NONE);
  973. mode(RM_PREPARE); AstroPrepare(); // !! call after obtaining '_col', '_ds' and '_ds_1s' because we rely on having them, and after RM_PREPARE because we may add lights !!
  974. _eye=0; if(_stereo)SetCam(EyeMatrix[_eye], false); // start with the first eye and set camera so we can calculate view_matrix for instances, this is important, because precalculated view_matrix is assumed to be for the first eye, so when rendering instances we need to adjust the projection matrix for next eye, this affects 'BeginPrecomputedViewMatrix'
  975. _render(); // we can call '_render' only once for RM_PREPARE
  976. Bool clear_ds=true; // if need to clear depth
  977. #if SUPPORT_EARLY_Z
  978. if(HasEarlyZInstances())
  979. {
  980. set(GPU_API(_col(), null, null), _ds(), true); // DX9 always requires a RT to be set
  981. D.clearDS(); clear_ds=false; // already cleared so no need anymore
  982. D.set3D(); if(DX9)D.colWrite(0);
  983. early_z:
  984. setEyeViewport();
  985. DrawEarlyZInstances();
  986. if(++_eye<_eye_num)goto early_z;
  987. ClearEarlyZInstances();
  988. D.set2D(); if(DX9)D.colWrite(COL_WRITE_RGBA);
  989. }
  990. #endif
  991. const Bool clear_col=((!Sky.isActual() || stage==RS_COLOR || stage==RS_LIT_COLOR || _col->multiSample()) && !fastCombine()); // performance tests suggested it's better don't clear unless necessary, instead 'Image.discard' is used and improves performance (at least on Mobile), always have to clear for multi-sampled to allow for proper detection of MSAA pixels using 'Sh.h_DetectMSCol' (this is needed for all renderers, not only Deferred, without this edges of sky/meshes may not get multi-sampled, especially when there's small variation in material color texture or no texture at all having just a single color)
  992. switch(_cur_type)
  993. {
  994. case RT_DEFERRED:
  995. {
  996. const Bool merged_clear=D._view_main.full // use when possible, should improve performance on tile-based renderers
  997. #if GL && WINDOWS
  998. && glClearBufferfv!=null // on Desktop GL we need this function to make "D.clearCol(Int i, .." work, on GLES3 it's always available, on GLES2 it's not but it doesn't have deferred renderer either
  999. #endif
  1000. , clear_nrm =(NRM_CLEAR_START && ClearNrm()),
  1001. clear_vel =false; // this is not needed because "ClearSkyVel" is used later, performance tests suggested it's better don't clear unless necessary, instead 'Image.discard' is used and improves performance (at least on Mobile)
  1002. if(D.motionMode()==MOTION_CAMERA_OBJECT && hasMotion() && D._max_rt>=3)
  1003. {
  1004. _vel.get(ImageRTDesc(_col->w(), _col->h(), D.signedVelRT() ? IMAGERT_RGB_S : IMAGERT_RGB, _col->samples())); // "_vel!=null" is treated as MOTION_CAMERA_OBJECT mode across the engine, doesn't use Alpha
  1005. if(clear_vel && !merged_clear)_vel->clearViewport(D.signedVelRT() ? SVEL_CLEAR : VEL_CLEAR);
  1006. }
  1007. _nrm.get(ImageRTDesc(_col->w(), _col->h(), D.signedNrmRT() ? (D.highPrecNrmRT() ? IMAGERT_RGBA_SP : IMAGERT_RGBA_S) : (D.highPrecNrmRT() ? IMAGERT_RGBA_P : IMAGERT_RGBA), _col->samples())); // here Alpha is used for specular
  1008. if(clear_nrm && !merged_clear)_nrm->clearViewport(D.signedNrmRT() ? SNRM_CLEAR : NRM_CLEAR);
  1009. Sh.h_ImageNrmMS->set(_nrm);
  1010. if(clear_col && !merged_clear)_col->clearViewport();
  1011. set(_col(), _nrm(), _vel(), null, _ds(), true);
  1012. if(merged_clear)
  1013. {
  1014. if(clear_col)D.clearCol(0, Vec4Zero);
  1015. if(clear_nrm)D.clearCol(1, D.signedNrmRT() ? SNRM_CLEAR : NRM_CLEAR);
  1016. if(clear_vel)D.clearCol(2, D.signedVelRT() ? SVEL_CLEAR : VEL_CLEAR);
  1017. }
  1018. }break;
  1019. case RT_FORWARD:
  1020. {
  1021. set(_col(), _ds(), true);
  1022. if(clear_col)D.clearCol(combine ? TRANSPARENT : Color(clear_color.r, clear_color.g, clear_color.b, 0));
  1023. }break;
  1024. case RT_SIMPLE:
  1025. {
  1026. set(_col(), _ds(), true);
  1027. if(clear_col)D.clearCol(combine ? TRANSPARENT : Color(clear_color.r, clear_color.g, clear_color.b, 0));
  1028. }break;
  1029. }
  1030. if(clear_ds)D.clearDS();
  1031. }
  1032. void RendererClass::solid()
  1033. {
  1034. switch(_cur_type)
  1035. {
  1036. case RT_DEFERRED:
  1037. {
  1038. D.stencil(STENCIL_ALWAYS_SET, 0); D.set3D(); mode(RM_SOLID);
  1039. REPS(_eye, _eye_num)
  1040. {
  1041. setEyeViewport();
  1042. DrawSolidInstances(); _render();
  1043. }
  1044. ClearSolidInstances();
  1045. D.stencil(STENCIL_NONE); D.set2D();
  1046. resolveDepth();
  1047. }break;
  1048. case RT_FORWARD:
  1049. {
  1050. // Lights + Solid
  1051. LimitLights();
  1052. SortLights();
  1053. // find initial directional light
  1054. Int start_light=-1;
  1055. if(Lights.elms() && !hasAO()) // if we do AO then first we need to draw without lights (ambient only)
  1056. {
  1057. if(Lights[0].type==LIGHT_DIR && Lights[0].shadow) // for shadow mapping 0-th light is the most significant, its shadow map must be rendered last to be used by BLEND_LIGHT
  1058. {
  1059. start_light=0; // assume it's 0-th
  1060. REPA(Lights)if(i!=0) // check all other lights
  1061. if(Lights[i].shadow) // if at least one has shadows
  1062. {
  1063. if(Lights[i].type==LIGHT_DIR){start_light=i; break;} // if it's some other directional light, we can draw it first
  1064. start_light=-1; // if it's not directional light, we can't use 0-th light as the starting light, but keep on checking for other directional lights
  1065. }
  1066. }else // most significant light doesn't require shadows, so pick any directional light
  1067. {
  1068. REPA(Lights)if(Lights[i].type==LIGHT_DIR){start_light=i; break;} // find any directional light
  1069. }
  1070. }
  1071. // draw main light
  1072. if(start_light>=0)
  1073. {
  1074. Lights[start_light].drawForward(_col(), fastCombine() ? ALPHA_NONE_ADD : ALPHA_NONE);
  1075. }else // no light
  1076. {
  1077. _frst_light_offset=OFFSET(FRST, none);
  1078. D.alpha(fastCombine() ? ALPHA_NONE_ADD : ALPHA_NONE);
  1079. D.stencil(STENCIL_ALWAYS_SET, 0); D.set3D(); mode(RM_SOLID);
  1080. REPS(_eye, _eye_num)
  1081. {
  1082. setEyeViewport();
  1083. DrawSolidInstances(); _render();
  1084. }
  1085. ClearSolidInstances();
  1086. D.stencil(STENCIL_NONE); D.set2D();
  1087. resolveDepth();
  1088. }
  1089. // apply ambient occlusion
  1090. if(hasAO())
  1091. {
  1092. ao(); if(_ao)
  1093. {
  1094. set(_col(), _ds(), true); // restore rendering RT's after calculating AO
  1095. D.alpha(ALPHA_MUL);
  1096. D.depth2DOn();
  1097. Sh.h_Color[0]->set(Vec4(1, 1, 1, 0));
  1098. Sh.h_Color[1]->set(Vec4(0, 0, 0, 1));
  1099. Sh.GPU_API(h_DrawTexWC, h_DrawTexXC, h_DrawTexXC)->draw(_ao); // DX9 uses A8 while others use R8 RT
  1100. D.depth2DOff();
  1101. }
  1102. }
  1103. // draw rest of the lights
  1104. if(Lights.elms()-(start_light>=0)>0)
  1105. {
  1106. _first_pass=false;
  1107. Bool clip=D._clip, clip_allow=D._clip_allow; T._clip=(clip ? D._clip_rect : D.rect()); // remember clipping because 'drawForward' may change it
  1108. ambient_color->set(VecZero); Sh.h_AmbientMaterial->set(0); // disable ambient lighting
  1109. D.depthFunc(FUNC_LESS_EQUAL); // need to make sure we can apply lights on existing depth
  1110. REPA(Lights)if(i!=start_light)Lights[i].drawForward(_col(), ALPHA_ADD_KEEP); // draw 0-th at the end to setup shadow maps (needed for BLEND_LIGHT), keep alpha which is glow
  1111. D.clip(clip ? &T._clip : null); D.clipAllow(clip_allow);
  1112. D.depthFunc(FUNC_LESS);
  1113. _first_pass=true;
  1114. // restore settings
  1115. ambient_color->set(D.ambientColor()); Sh.h_AmbientMaterial->set(1); // restore ambient lighting
  1116. Frustum.set(); // restore frustum after it being potentially changed when drawing shadow maps or setting frustum for visible objects for lights
  1117. }
  1118. //resolveDepth(); was already called for the main light
  1119. }break;
  1120. case RT_SIMPLE:
  1121. {
  1122. // Light + Solid
  1123. SortLights();
  1124. // set light
  1125. if(Lights.elms() && Lights[0].type==LIGHT_DIR)Lights[0].dir.set();else LightDir(Vec(0, -1, 0), VecZero).set();
  1126. // solid
  1127. D.alpha (fastCombine() ? ALPHA_NONE_ADD : ALPHA_NONE);
  1128. D.stencil(STENCIL_ALWAYS_SET, 0); D.set3D(); mode(RM_SOLID);
  1129. REPS(_eye, _eye_num)
  1130. {
  1131. setEyeViewport();
  1132. DrawSolidInstances(); _render();
  1133. }
  1134. ClearSolidInstances();
  1135. D.stencil(STENCIL_NONE); D.set2D();
  1136. resolveDepth();
  1137. }break;
  1138. }
  1139. }
  1140. void RendererClass::resolveDepth()
  1141. {
  1142. // this resolves the entire '_ds' into '_ds_1s' (by choosing Min of depth samples), and sets 'STENCIL_REF_MSAA' if needed
  1143. if(_ds->multiSample() && _ds->depthTexture())
  1144. {
  1145. D.alpha(ALPHA_NONE);
  1146. // set multi-sampled '_ds' MSAA
  1147. if(_cur_type==RT_DEFERRED // for deferred set it always (needed for lighting)
  1148. || Fog.draw || Sky.isActual()) // for non-deferred it will be used only for fog and sky
  1149. {
  1150. D.stencil(STENCIL_MSAA_SET, STENCIL_REF_MSAA);
  1151. set(null, _ds(), true);
  1152. //if(_nrm)Sh.h_DetectMSNrm->draw(_nrm);else 'DetectMSNrm' generates too many MS pixels, making rendering slower, so don't use
  1153. Sh.h_DetectMSCol->draw(_col);
  1154. }
  1155. // always resolve '_ds' into '_ds_1s'
  1156. set(null, _ds_1s(), true);
  1157. D.stencil(STENCIL_ALWAYS_SET, 0); // use 'STENCIL_ALWAYS_SET' here so when down-sampling depth, we clear the entire stencil mask for '_ds_1s'
  1158. D.depthFunc(FUNC_ALWAYS); D.depthLock (true); Sh.h_ResolveDepth->draw(_ds);
  1159. D.depthFunc(FUNC_LESS ); D.depthUnlock( );
  1160. // set 1-sampled '_ds_1s' MSAA
  1161. if(_cur_type==RT_DEFERRED // for deferred set it always (needed for lighting)
  1162. || slowCombine()) // for non-deferred it will be used only for slow combine
  1163. {
  1164. D.stencilRef(STENCIL_REF_MSAA);
  1165. //if(_nrm)Sh.h_DetectMSNrm->draw(_nrm);else 'DetectMSNrm' generates too many MS pixels, making rendering slower, so don't use
  1166. Sh.h_DetectMSCol->draw(_col);
  1167. }
  1168. D.stencil(STENCIL_NONE);
  1169. }
  1170. }
  1171. void RendererClass::overlay()
  1172. {
  1173. D.stencilRef(STENCIL_REF_TERRAIN); // set in case draw codes will use stencil
  1174. if(_cur_type==RT_DEFERRED && D._mrt_post_process && D.bumpMode()!=BUMP_FLAT){set(_col(), _nrm(), null, null, _ds(), true, WANT_DEPTH_READ); D.colWrite(COL_WRITE_RGB, 1);} // if we can blend normals
  1175. else set(_col(), _ds(), true, WANT_DEPTH_READ);
  1176. setDSLookup(); // 'setDSLookup' after 'set'
  1177. D.alpha(ALPHA_BLEND_FACTOR);
  1178. D.set3D(); D.depthWrite(false); D.bias(BIAS_OVERLAY); D.depthFunc(FUNC_LESS_EQUAL); D.depth(true); mode(RM_OVERLAY); // overlay requires BIAS because we may use 'MeshOverlay' which generates triangles by clipping existing ones
  1179. REPS(_eye, _eye_num)
  1180. {
  1181. setEyeViewport();
  1182. DrawOverlayObjects(); _render();
  1183. }
  1184. D.set2D(); D.depthWrite(true); D.bias(BIAS_ZERO); D.depthFunc(FUNC_LESS);
  1185. D.colWrite(COL_WRITE_RGBA, 1);
  1186. D.stencil(STENCIL_NONE); // disable any stencil that might have been enabled
  1187. OverlayObjects.clear();
  1188. }
  1189. void RendererClass::waterPreLight()
  1190. {
  1191. Water._use_secondary_rt=(!Water.max1Light()
  1192. && canReadDepth()
  1193. && D._max_rt>=2 // col+nrm
  1194. && _cur_type!=RT_FORWARD && _cur_type!=RT_SIMPLE); // for forward/simple for the moment we can't do it, because all lights have already been applied, but in current mode we expect solids to be drawn (so we have depth set because we copy it, and stencil set because we swap DS to preserve it and restore later)
  1195. if(Water._use_secondary_rt)Water.drawSurfaces(); // if we use secondary RT's then we need to draw water surfaces before we calculate lights (otherwise setup lights first and then draw surfaces having shadow-maps known)
  1196. }
  1197. inline Shader* AmbientOcclusion::get(Int quality, Bool jitter, Bool normal)
  1198. {
  1199. Shader* &s=h_AO[quality][jitter][normal]; if(!s)
  1200. {
  1201. if(!shader)shader=ShaderFiles("Ambient Occlusion");
  1202. s=shader->get(S8+"AO"+quality+(jitter?'J':'\0')+(normal?'N':'\0'));
  1203. }
  1204. return s;
  1205. }
  1206. void RendererClass::ao()
  1207. {
  1208. D.alpha(ALPHA_NONE);
  1209. Shader *tech_occl=AO.get(D.ambientMode()-1, D.ambientJitter(), D.ambientNormal() && _nrm);
  1210. VecI2 res=ByteScaleRes(fx(), D._amb_res); _ao.get(ImageRTDesc(res.x, res.y, IMAGERT_ONE));
  1211. // always downsample and linearize at the same time
  1212. ImageRTPtr ao_depth;
  1213. ao_depth.get(ImageRTDesc(_ao->w(), _ao->h(), IMAGERT_F32)); // don't try to reduce to IMAGERT_F16 because it can create artifacts on big view ranges under certain angles (especially when we don't use normal maps, like in forward renderer)
  1214. linearizeDepth(*ao_depth, *_ds_1s);
  1215. Sh.h_ImageNrm[0]->set(_nrm);
  1216. Sh.h_ImageDepth ->set(ao_depth);
  1217. Bool foreground=_ao->compatible(*_ds_1s);
  1218. if(_col->multiSample())foreground&=Sky.isActual(); // when having multi-sampling, then allow this optimization only if we're rendering Sky, this is related to smooth edges between solid and sky pixels
  1219. if(stage)if(stage==RS_AO || stage==RS_LIGHT_AO)foreground=false; // if we will display AO then set fully
  1220. if(foreground)D.depth2DOn();
  1221. set(_ao(), foreground ? _ds_1s() : null, true, NEED_DEPTH_READ); // use DS for 'D.depth2D'
  1222. REPS(_eye, _eye_num)tech_occl->draw(ao_depth, setEyeParams()); // calculate occlusion
  1223. ao_depth.clear(); // this one is no longer needed
  1224. Sh.h_ImageDepth->set(_ds_1s); // restore full resolution depth
  1225. if(D.ambientSoft()) // this needs to be in sync with 'D.shadowSoft'
  1226. {
  1227. ImageRTDesc rt_desc(_ao->w(), _ao->h(), IMAGERT_ONE);
  1228. if(D.ambientSoft()>=5)
  1229. {
  1230. ImageRTPtr temp; temp.get(rt_desc);
  1231. set(temp(), foreground ? _ds_1s() : null, true, NEED_DEPTH_READ); Sh.h_ShdBlurX->draw( _ao); // use DS for 'D.depth2D'
  1232. set( _ao(), foreground ? _ds_1s() : null, true, NEED_DEPTH_READ); _ao->discard(); Sh.h_ShdBlurY->draw(temp); // use DS for 'D.depth2D'
  1233. }else
  1234. {
  1235. ImageRTPtr src=_ao; _ao.get(rt_desc);
  1236. set(_ao(), foreground ? _ds_1s() : null, true, NEED_DEPTH_READ); Sh.h_ShdBlur[D.ambientSoft()-1]->draw(src); // use DS for 'D.depth2D'
  1237. }
  1238. }
  1239. if(foreground)D.depth2DOff();
  1240. }
  1241. INLINE Shader* GetColLight(Int multi_sample, Bool ao, Bool cel_shade, Bool night_shade) {Shader* &s=Sh.h_ColLight[multi_sample][ao][cel_shade][night_shade]; if(SLOW_SHADER_LOAD && !s)s=Sh.getColLight(multi_sample, ao, cel_shade, night_shade); return s;}
  1242. void RendererClass::light()
  1243. {
  1244. if(_cur_type==RT_DEFERRED) // on other renderers light is applied when rendering solid
  1245. {
  1246. /*
  1247. -set '_ao' as Ambient Occlusion (one channel, without D.ambientColor)
  1248. -clear '_lum' and '_lum_1s'
  1249. -add ambient light from meshes
  1250. -calculate screen space light (on MSAA and non-MSAA)
  1251. -final light = sum of all buffers together
  1252. _ao = AO;
  1253. _lum = 0 ; _lum+=mesh_ambient; MSAA of _lum +=light;
  1254. _lum_1s= 0 ; non-MSAA of _lum_1s+=light;
  1255. LIGHT =_lum + _lum_1s + _ao*D.ambientColor
  1256. OR LIGHT =_lum + _lum_1s + D.ambientColor (if "_ao==null")
  1257. */
  1258. // Ambient Occlusion
  1259. if(hasAO())ao();
  1260. // add dynamic lights
  1261. LimitLights();
  1262. SortLights();
  1263. DrawLights();
  1264. _nrm.clear();
  1265. //_water_nrm.clear(); we may still need it for refraction
  1266. getLumRT();
  1267. // add ambient light from meshes
  1268. set(_lum(), _ds(), true);
  1269. D.alpha(ALPHA_ADD);
  1270. D.set3D(); mode(RM_AMBIENT); D.depth(true);
  1271. SortAmbientInstances();
  1272. REPS(_eye, _eye_num)
  1273. {
  1274. setEyeViewport();
  1275. DrawAmbientInstances(); _render();
  1276. }
  1277. ClearAmbientInstances();
  1278. D.set2D();
  1279. // light buffer is ready so we can combine it with color
  1280. Bool ao=(_ao!=null), cel_shade=(cel_shade_palette!=null), night_shade=(D.nightShadeColor().max()>EPS_COL);
  1281. Sh.h_ImageLum ->set(_lum_1s);
  1282. Sh.h_ImageDet[0]->set(_ao );
  1283. Sh.h_ImageDet[1]->set( cel_shade_palette());
  1284. D .alpha(ALPHA_NONE);
  1285. ImageRTPtr src=_col; // can't read and write to the same RT
  1286. Bool has_last_frag_color=false, // TODO: there would be no need to write to a new RT if we would use gl_LastFragColor/gl_LastFragData[0] using extensions - https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_shader_framebuffer_fetch.txt and https://www.khronos.org/registry/OpenGL/extensions/ARM/ARM_shader_framebuffer_fetch.txt
  1287. use_last_frag_color=(has_last_frag_color && (D.highPrecColRT() ? IMAGE_PRECISION_10 : IMAGE_PRECISION_8)==D.litColRTPrecision());
  1288. if(!use_last_frag_color)_col.get(ImageRTDesc(_col->w(), _col->h(), GetImageRTType(D.glowAllow(), D.litColRTPrecision()), _col->samples())); // glow requires alpha
  1289. set(_col(), _ds(), true, NEED_DEPTH_READ); // use DS because it may be used for 'D.depth2D' optimization and stencil tests
  1290. if((_col==src || Sky.isActual()) && stage!=RS_LIT_COLOR)D.depth2DOn(); // we can skip background only if we're applying to the same RT or if the background will be later overwritten by Sky
  1291. if(!_col->multiSample())GetColLight(0, ao, cel_shade, night_shade)->draw(src);else
  1292. {
  1293. Sh.h_ImageLumMS->set(_lum);
  1294. if(hasStencilAttached())
  1295. {
  1296. D.stencil (STENCIL_MSAA_TEST, 0); GetColLight(1, ao, cel_shade, night_shade)->draw(src); // 1 sample
  1297. if(Sky.isActual())D.depth2DOff(); // multi-sampled always fill fully when sky will be rendered
  1298. D.stencilRef(STENCIL_REF_MSAA ); GetColLight(2, ao, cel_shade, night_shade)->draw(src); // n samples
  1299. D.stencil (STENCIL_NONE );
  1300. }else
  1301. {
  1302. if(Sky.isActual())D.depth2DOff(); // multi-sampled always fill fully when sky will be rendered
  1303. GetColLight(2, ao, cel_shade, night_shade)->draw(src); // n samples
  1304. }
  1305. }
  1306. D.depth2DOff();
  1307. src.clear();
  1308. if(_lum!=_lum_1s && (_fur_is || stage==RS_LIGHT || stage==RS_LIGHT_AO)){set(_lum_1s(), null, true); D.alpha(ALPHA_ADD); Sh.draw(*_lum);} // need to apply multi-sampled lum to 1-sample for fur and light stage
  1309. _lum.clear(); // '_lum' will not be used after this point, however '_lum_1s' may be for rendering fur
  1310. MaterialClear();
  1311. }
  1312. }
  1313. Bool RendererClass::waterPostLight()
  1314. {
  1315. if(!Water._use_secondary_rt)Water.drawSurfaces();else // if we don't want to use secondary RT's
  1316. if(_water_col) // only if we've got some water
  1317. {
  1318. /* -we can always do soft, because '_use_secondary_rt' is enabled only if we can read from depth buffer
  1319. -we need to read from both depth buffers to perform softing, so in order to modify depth, we need to do this after in another operation
  1320. -when doing refraction, we need to have a copy of '_col' and apply to '_col' (this is better for multi-sampling because copy can be 1-sampled)
  1321. or alternatively apply to a new RT using existing '_col' (however the new RT would have to be multi-sampled for MS case)
  1322. -when not doing refraction, we don't need any copy or separate RT, we can just apply to existing '_col' using alpha blending without reading from it, however doing this would prevent from applying glow, so don't do it
  1323. -we can't use stencil optimizations, because:
  1324. -when applying to MS RT the DS is MS and does not have any information about water
  1325. -otherwise we apply to another RT and we have to write all pixels
  1326. */
  1327. getWaterLumRT(); // get in case we still haven't initialized it
  1328. Bool refract=(Water.refract>EPS_MATERIAL_BUMP);
  1329. ImageRTPtr src=_col;
  1330. Bool depth_test;
  1331. if( depth_test=src->multiSample()) // multi-sampled textures can't be sampled smoothly as there will be artifacts, so resolve them, also in this case we render back to '_col' (which is not set to a new RT because we have a copy of it in 'src') but only to pixels with depth FUNC_LESS, this solves the problem of AA with water
  1332. { // convert to 1 sample
  1333. ImageRTPtr temp(ImageRTDesc(src->w(), src->h(), GetImageRTType(src->type())));
  1334. #if DX11
  1335. src->copyMs(*temp, false, false, D.viewRect()); Swap(src, temp);
  1336. #endif
  1337. D.depthLock (true); // we need depth testing
  1338. D.depthWrite(false); // disable depth writing because we can't read and write to same DS
  1339. D.depthFunc (FUNC_LESS); // process only pixels that are closer (which means water on top of existing solid)
  1340. }
  1341. if(_col==src)_col.get(ImageRTDesc(_col->w(), _col->h(), GetImageRTType(_col->type()), _col->samples())); // can't read and write to same RT, in multi-sampling we're writing back to '_col' as it's not changed
  1342. SetOneMatrix(); // needed for refraction
  1343. set(_col(), _ds(), true, NEED_DEPTH_READ); // we need depth read because we always need to read depth buffer for softing, but still use '_ds' in case we apply to existing '_col'
  1344. D.alpha(ALPHA_NONE);
  1345. Water.set();
  1346. Water.setImages(src(), _water_ds());
  1347. Sh.h_ImageCol[3]->set(_water_col());
  1348. Sh.h_ImageNrm[0]->set(_water_nrm());
  1349. Sh.h_ImageLum ->set(_water_lum());
  1350. REPS(_eye, _eye_num)
  1351. {
  1352. Water.setEyeViewport();
  1353. WS.h_Apply[refract][depth_test]->draw(src()); // we need to output depth only if we need it for depth testing
  1354. }
  1355. if(depth_test)
  1356. {
  1357. D.depthUnlock();
  1358. D.depthWrite(true);
  1359. }
  1360. Water.endImages();
  1361. // now we have to modify the depth buffer
  1362. if((!Water._swapped_ds || !swapDS1S(_water_ds)) && Sh.h_SetDepth) // if we haven't swapped before, or swap back failed, then we have to apply '_water_ds' on top of existing '_ds_1s', otherwise we just swap back '_water_ds' because it had the stencil values
  1363. {
  1364. if(!DX9)set(null, _ds_1s(), true);else{set(_col(), _ds_1s(), true); D.colWrite(0);} // DX9 always requires RT
  1365. D.depthLock(true); Sh.h_SetDepth->draw(_water_ds); // keep FUNC_LESS to modify only those that are closer
  1366. D.depthUnlock();
  1367. if(DX9)D.colWrite(COL_WRITE_RGBA);
  1368. }
  1369. if(_ds!=_ds_1s && Sh.h_SetDepth) // multi-sample
  1370. {
  1371. if(!DX9)set(null, _ds(), true);else{set(_col(), _ds(), true); D.colWrite(0);} // DX9 always requires RT
  1372. D.depthLock(true); Sh.h_SetDepth->draw(_water_ds); // keep FUNC_LESS to modify only those that are closer
  1373. D.depthUnlock();
  1374. if(DX9)D.colWrite(COL_WRITE_RGBA);
  1375. }
  1376. if(stage)switch(stage)
  1377. {
  1378. case RS_WATER_COLOR : if(set(_water_col))return true; break;
  1379. case RS_WATER_NORMAL: if(set(_water_nrm))return true; break;
  1380. case RS_WATER_LIGHT : if(set(_water_lum))return true; break;
  1381. }
  1382. }
  1383. _water_col.clear();
  1384. _water_nrm.clear();
  1385. _water_ds .clear();
  1386. _water_lum.clear();
  1387. _mirror_rt.clear();
  1388. return false;
  1389. }
  1390. void RendererClass::edgeDetect()
  1391. {
  1392. if(D.edgeDetect() && !mirror() && canReadDepth())switch(D.edgeDetect())
  1393. {
  1394. case EDGE_DETECT_THIN:
  1395. {
  1396. D.depth2DOn (); D.alpha(ALPHA_MUL); set(_col(), _ds(), true, NEED_DEPTH_READ); Sh.h_EdgeDetect->draw(_ds_1s);
  1397. D.depth2DOff();
  1398. }break;
  1399. case EDGE_DETECT_FAT:
  1400. {
  1401. ImageRTPtr edge(ImageRTDesc(fxW(), fxH(), IMAGERT_ONE));
  1402. D.alpha (ALPHA_NONE); set(edge(), null , true, NEED_DEPTH_READ); Sh.h_EdgeDetect ->draw(_ds_1s); // we need to fill the entire buffer because below we're using blurring (which takes nearby texels)
  1403. D.depth2DOn ();
  1404. D.alpha (ALPHA_MUL ); set(_col(), _ds(), true, NO_DEPTH_READ); Sh.h_EdgeDetectApply->draw(edge());
  1405. D.depth2DOff();
  1406. }break;
  1407. }
  1408. }
  1409. void RendererClass::sky()
  1410. {
  1411. Fog.Draw(false);
  1412. Sky.draw();
  1413. if(!mirror())AstroDraw();
  1414. Clouds.drawAll();
  1415. Fog.Draw(true);
  1416. }
  1417. void RendererClass::blend()
  1418. {
  1419. Sky.setFracMulAdd();
  1420. // set main light parameters for *BLEND_LIGHT* and 'Mesh.drawBlend'
  1421. if(Lights.elms() && Lights[0].type==LIGHT_DIR) // use 0 index as it has already been set in 'SortLights'
  1422. {
  1423. Lights[0].dir.set();
  1424. _blst_light_offset=OFFSET(BLST, dir[Lights[0].shadow ? D.shadowMapNumActual() : 0]);
  1425. }else
  1426. {
  1427. LightDir(Vec(0, -1, 0), VecZero).set(); // set dummy light
  1428. _blst_light_offset=OFFSET(BLST, dir[0]);
  1429. }
  1430. // apply light in case of drawing fur, which samples the light buffer
  1431. if(_fur_is)
  1432. {
  1433. if(_ao)
  1434. {
  1435. set(_lum_1s(), null, true);
  1436. D.alpha(ALPHA_ADD);
  1437. Sh.h_Color[0]->set(Vec4(D.ambientColor(), 0));
  1438. Sh.h_Color[1]->set(Vec4Zero );
  1439. Sh.GPU_API(h_DrawTexWC, h_DrawTexXC, h_DrawTexXC)->draw(_ao); // DX9 uses A8 while others use R8 RT
  1440. }
  1441. PrepareFur();
  1442. }
  1443. _ao.clear(); // '_ao' will not be used after this point
  1444. D.stencilRef(STENCIL_REF_TERRAIN); // set in case draw codes will use stencil
  1445. const Bool blend_affect_vel=true; // #BlendRT
  1446. set(_col(), blend_affect_vel ? _vel() : null, null, null, _ds(), true); setDSLookup(); // 'setDSLookup' after 'set'
  1447. D.alpha(ALPHA_BLEND_FACTOR);
  1448. D.set3D(); D.depthWrite(false); D.depthFunc(FUNC_LESS_EQUAL); D.depth(true); mode(RM_BLEND); // use less equal for blend because we may want to draw blend graphics on top of existing pixels (for example world editor terrain highlight)
  1449. SortBlendInstances();
  1450. REPS(_eye, _eye_num)
  1451. {
  1452. setEyeViewport();
  1453. #if 1
  1454. _render(); DrawBlendInstances(); // first call '_render' to for example get 'getBackBuffer' and then draw objects in 'DrawBlendInstances'
  1455. #else
  1456. DrawBlendInstances(); _render();
  1457. #endif
  1458. }
  1459. ClearBlendInstances();
  1460. _SetHighlight(TRANSPARENT);
  1461. D.set2D(); D.depthWrite(true); D.depthFunc(FUNC_LESS);
  1462. D.stencil(STENCIL_NONE); // disable any stencil that might have been enabled
  1463. _lum_1s.clear(); // '_lum_1s' will not be used after this point
  1464. }
  1465. void RendererClass::palette(Int index)
  1466. {
  1467. if(D.colorPaletteAllow())
  1468. if(C ImagePtr &palette=D._color_palette[index])
  1469. {
  1470. Image &ds=(_ds_1s ? *_ds_1s : *_ds); // Warning: this will disable applying palette only on terrain using STENCIL_REF_TERRAIN for multisampling
  1471. Sky.setFracMulAdd();
  1472. ImageRTPtr intensity(ImageRTDesc(_col->w(), _col->h(), IMAGERT_RGBA, ds.samples())); // we need to match depth multi-sampling, here Alpha is used for 4th palette channel
  1473. D.stencilRef(STENCIL_REF_TERRAIN); // set in case draw codes will use stencil
  1474. set(intensity(), &ds, true, WANT_DEPTH_READ); setDSLookup(); // we need depth-testing, but want depth-read for particle softing, 'setDSLookup' after 'set'
  1475. D.clearCol();
  1476. D.alpha(ALPHA_ADD);
  1477. D.set3D(); D.depthWrite(false); mode(index ? RM_PALETTE1 : RM_PALETTE);
  1478. REPS(_eye, _eye_num)
  1479. {
  1480. setEyeViewport();
  1481. _render(); if(index)DrawPalette1Objects();else DrawPaletteObjects();
  1482. }
  1483. D.set2D(); D.depthWrite(true);
  1484. D.stencil(STENCIL_NONE); // disable any stencil that might have been enabled
  1485. #if !DX11
  1486. if(intensity->multiSample()) // we need to resolve the multi-sampled surface first
  1487. {
  1488. ImageRTPtr src=intensity; intensity.get(ImageRTDesc(src->w(), src->h(), IMAGERT_RGBA)); src->copyHw(*intensity, false, D.viewRect()); // here Alpha is used for 4th palette channel
  1489. }
  1490. #endif
  1491. set(_col(), null, true);
  1492. D .alpha(ALPHA_BLEND_DEC);
  1493. Sh.h_ImageCol[1]->set ( palette()); MaterialClear();
  1494. Sh.h_PaletteDraw->draw(*intensity);
  1495. }
  1496. if(index)
  1497. {
  1498. Palette1Objects.clear();
  1499. Palette1Areas .clear();
  1500. }else
  1501. {
  1502. PaletteObjects.clear();
  1503. PaletteAreas .clear();
  1504. }
  1505. }
  1506. void RendererClass::behind()
  1507. {
  1508. if(canReadDepth())
  1509. {
  1510. Sky.setFracMulAdd();
  1511. set(_col(), _ds(), true, NEED_DEPTH_READ); // we will read from the depth buffer
  1512. D.alpha(ALPHA_BLEND_DEC);
  1513. D.set3D(); D.depthWrite(false); D.depthFunc(FUNC_GREATER); D.depth(true); mode(RM_BEHIND);
  1514. REPS(_eye, _eye_num)
  1515. {
  1516. setEyeViewport();
  1517. _render(); DrawBehindObjects();
  1518. }
  1519. D.set2D(); D.depthWrite(true); D.depthFunc(FUNC_LESS);
  1520. }
  1521. BehindObjects.clear();
  1522. }
  1523. void RendererClass::setOutline(C Color &color)
  1524. {
  1525. _SetHighlight(color);
  1526. if(!_outline) // not initialized at all
  1527. {
  1528. _outline_rt.get(ImageRTDesc(_col->w(), _col->h(), IMAGERT_RGBA, _col->samples())); // here Alpha is used for outline opacity
  1529. set(_outline_rt(), _ds(), true);
  1530. D.clearCol ();
  1531. D.alpha (ALPHA_NONE);
  1532. D.sampler3D ();
  1533. D.depthFunc (FUNC_LESS_EQUAL);
  1534. D.depthWrite(false);
  1535. if(D.outlineMode()==EDGE_DETECT_THIN)D.stencil(STENCIL_OUTLINE_SET, STENCIL_REF_OUTLINE);
  1536. }
  1537. Int outline_eye=(1<<_eye);
  1538. if(!(_outline&outline_eye)) // not yet enabled for this eye
  1539. {
  1540. _outline|=outline_eye; // enable
  1541. setEyeViewport(); // set viewport if needed
  1542. }
  1543. }
  1544. void RendererClass::applyOutline()
  1545. {
  1546. if(_outline_rt)
  1547. {
  1548. _SetHighlight(TRANSPARENT); // disable 'SetHighlight' which was called during mesh drawing
  1549. D.sampler2D ();
  1550. D.depthFunc (FUNC_LESS); // restore default
  1551. D.depthWrite(true);
  1552. resolveMultiSample(); // don't do 'downSample' here because 'edgeSoften' will be called later and it requires to operate on full-sampled data
  1553. #if !DX11
  1554. if(_outline_rt->multiSample()) // we need to resolve the multi-sampled surface first
  1555. {
  1556. ImageRTPtr src=_outline_rt; _outline_rt.get(ImageRTDesc(src->w(), src->h(), IMAGERT_RGBA)); src->copyHw(*_outline_rt, false, D.viewRect()); // here Alpha is used for outline opacity
  1557. }
  1558. #endif
  1559. Image *ds=_ds_1s(); // we've resolved multi-sample so have to use 1-sample
  1560. if(!Sh.h_Outline)
  1561. {
  1562. Sh.h_Outline =Sh.get("Outline");
  1563. Sh.h_OutlineDS =Sh.get("OutlineDS");
  1564. Sh.h_OutlineClip =Sh.get("OutlineClip");
  1565. Sh.h_OutlineApply=Sh.get("OutlineApply");
  1566. }
  1567. switch(D.outlineMode())
  1568. {
  1569. case EDGE_DETECT_THIN: if(Sh.h_OutlineClip)
  1570. {
  1571. set(_col(), (ds && ds->compatible(*_col)) ? ds : null, true);
  1572. D.depth2DOn ();
  1573. D.stencil ((_cur_ds==_ds()) ? STENCIL_OUTLINE_TEST : STENCIL_NONE); // we can use the stencil optimization only if we will use the DS to which we've written stencil to
  1574. D.alpha (ALPHA_BLEND_DEC);
  1575. Sh.h_OutlineClip->draw(_outline_rt);
  1576. D.stencil (STENCIL_NONE);
  1577. D.depth2DOff();
  1578. }break;
  1579. case EDGE_DETECT_FAT: if(Sh.h_Outline && Sh.h_OutlineDS && Sh.h_OutlineApply)
  1580. {
  1581. ImageRTPtr temp(ImageRTDesc(fxW(), fxH(), IMAGERT_RGBA)); // here Alpha is used for outline opacity
  1582. set(temp(), null, true);
  1583. D.alpha(ALPHA_NONE);
  1584. ((temp->w()<_outline_rt->w()) ? Sh.h_OutlineDS : Sh.h_Outline)->draw(_outline_rt);
  1585. set(_col(), (ds && ds->compatible(*_col)) ? ds : null, true);
  1586. D .alpha (ALPHA_BLEND_DEC);
  1587. if(!D.outlineAffectSky())D.depth2DOn();
  1588. Sh.h_OutlineApply->draw(temp);
  1589. D.depth2DOff();
  1590. }break;
  1591. }
  1592. _outline_rt.clear();
  1593. }
  1594. }
  1595. void RendererClass::outline()
  1596. {
  1597. // start outline
  1598. if(D.outlineMode())
  1599. {
  1600. mode(RM_OUTLINE); // 'sampler3D/2D' is called in 'setOutline' and 'applyOutline'
  1601. REPS(_eye, _eye_num)
  1602. {
  1603. //setEyeViewport(); viewport is set in 'setOutline' method
  1604. DrawOutlineObjects(); _render();
  1605. }
  1606. }
  1607. OutlineObjects.clear();
  1608. }
  1609. void RendererClass::resolveMultiSample() // !! assumes that 'finalizeGlow' was called !! this should be called before 'downSample'
  1610. {
  1611. if(_col->multiSample())
  1612. {
  1613. ImageRTPtr src=_col; _col.get(ImageRTDesc(_col->w(), _col->h(), GetImageRTType(_has_glow, D.litColRTPrecision())));
  1614. #if DX11
  1615. src->copyMs(*_col, false, true, D.viewRect());
  1616. #else
  1617. src->copyHw(*_col, false, D.viewRect());
  1618. #endif
  1619. }
  1620. }
  1621. void RendererClass::downSample() // !! assumes that 'finalizeGlow' was called !!
  1622. {
  1623. resolveMultiSample();
  1624. if(_col->w()>_final->w()) // if down-sample is needed
  1625. {
  1626. ImageRTPtr src=_col; _col.get(ImageRTDesc(_final->w(), _final->h(), GetImageRTType(_has_glow, D.litColRTPrecision())));
  1627. src->copyHw(*_col, false, D.viewRect());
  1628. }
  1629. }
  1630. void RendererClass::edgeSoften() // !! assumes that 'finalizeGlow' was called !!
  1631. {
  1632. if(hasEdgeSoften())
  1633. {
  1634. resolveMultiSample();
  1635. D.alpha(ALPHA_NONE);
  1636. if(!D._view_main.full)
  1637. {
  1638. const Int pixel_range=6; // currently FXAA/SMAA shaders use this range
  1639. set(_col(), null, false); // need full viewport
  1640. D.viewRect().drawBorder(TRANSPARENT, Renderer.pixelToScreenSize(-pixel_range)); // draw black border around the viewport to clear and prevent from potential artifacts on viewport edges
  1641. }
  1642. ImageRTPtr dest(ImageRTDesc(_col->w(), _col->h(), GetImageRTType(_has_glow, D.litColRTPrecision())));
  1643. // D.depth2DOn/depth2DOff can't be applied here, this was tested and resulted in loss of softening at object/sky edges
  1644. switch(D.edgeSoften())
  1645. {
  1646. case EDGE_SOFTEN_FXAA:
  1647. {
  1648. set(dest(), null, true); Sh.h_FXAA->draw(_col());
  1649. }break;
  1650. #if SUPPORT_MLAA
  1651. case EDGE_SOFTEN_MLAA:
  1652. {
  1653. _col->copyHw(*dest, false, D.viewRect());
  1654. D.stencil(STENCIL_EDGE_SOFT_SET, STENCIL_REF_EDGE_SOFT); // have to use '_ds_1s' in write mode to be able to use stencil
  1655. ImageRTPtr edge (ImageRTDesc(_col->w(), _col->h(), IMAGERT_TWO )); set(edge (), _ds_1s(), true); D.clearCol(); Sh.h_MLAAEdge ->draw(_col ()); Sh.h_ImageCol[1]->set(_mlaa_area()); D.stencil(STENCIL_EDGE_SOFT_TEST);
  1656. ImageRTPtr blend(ImageRTDesc(_col->w(), _col->h(), IMAGERT_RGBA)); set(blend(), _ds_1s(), true); D.clearCol(); Sh.h_MLAABlend->draw( edge()); Sh.h_ImageCol[1]->set( blend ()); edge.clear();
  1657. set(dest (), _ds_1s(), true); Sh.h_MLAA ->draw(_col ()); D.stencil(STENCIL_NONE );
  1658. MaterialClear();
  1659. }break;
  1660. #endif
  1661. case EDGE_SOFTEN_SMAA:
  1662. {
  1663. #if GL // in GL 'ShaderImage.Sampler' does not affect filtering, so modify it manually
  1664. D.texBind(GL_TEXTURE_2D, _smaa_search->_txtr);
  1665. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1666. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1667. #endif
  1668. D.stencil(STENCIL_EDGE_SOFT_SET, STENCIL_REF_EDGE_SOFT); // have to use '_ds_1s' in write mode to be able to use stencil
  1669. ImageRTPtr edge (ImageRTDesc(_col->w(), _col->h(), IMAGERT_TWO )); set(edge (), _ds_1s(), true); D.clearCol(); Sh.h_SMAAEdge ->draw(_col ()); Sh.h_ImageCol[1]->set(_smaa_area()); Sh.h_ImageCol[2]->set(_smaa_search()); Sh.h_ImageCol[2]->_sampler=&SamplerPoint; D.stencil(STENCIL_EDGE_SOFT_TEST);
  1670. ImageRTPtr blend(ImageRTDesc(_col->w(), _col->h(), IMAGERT_RGBA)); set(blend(), _ds_1s(), true); D.clearCol(); Sh.h_SMAABlend->draw( edge()); Sh.h_ImageCol[1]->set( blend() ); edge.clear(); Sh.h_ImageCol[2]->_sampler= null; D.stencil(STENCIL_NONE );
  1671. set(dest (), null , true); Sh.h_SMAA ->draw(_col ());
  1672. MaterialClear();
  1673. }break;
  1674. }
  1675. Swap(dest, _col);
  1676. }
  1677. }
  1678. void RendererClass::volumetric()
  1679. {
  1680. if(_vol)
  1681. {
  1682. downSample(); // we're modifying existing RT, so downSample if needed
  1683. set(_col(), null, true);
  1684. SPSet("VolMax", Vec(D.volMax()));
  1685. D.alpha(D.volAdd() ? ALPHA_ADD : ALPHA_BLEND_DEC);
  1686. (D.volAdd() ? VL.h_VolumetricA : VL.h_Volumetric)->draw(_vol());
  1687. _vol.clear();
  1688. }
  1689. }
  1690. void RendererClass::refract() // !! assumes that 'finalizeGlow' was called !!
  1691. {
  1692. if(Water._under_mtrl && canReadDepth() && !fastCombine())
  1693. {
  1694. WS.load();
  1695. C WaterMtrl &under=*Water._under_mtrl;
  1696. Flt under_step =Sat(Water._under_step),
  1697. refract_val=under_step*under.refract_underwater;
  1698. Bool refract=(refract_val>EPS_MATERIAL_BUMP);
  1699. if( !refract)downSample (); // we're modifying existing RT, so downSample if needed
  1700. else resolveMultiSample(); // we're writing to new RT so resolve the old first
  1701. ImageRTPtr src=_col;
  1702. if( refract)_col.get(ImageRTDesc(Min(_col->w(), _final->w()), Min(_col->h(), _final->h()), GetImageRTType(_has_glow, D.litColRTPrecision())));
  1703. set(_col(), null, true);
  1704. D .alpha(refract ? ALPHA_NONE : ALPHA_BLEND_DEC);
  1705. Sh.h_Step->set(Time.time());
  1706. SPSet("WaterPlnPos" , Water._under_plane.pos *CamMatrixInv );
  1707. SPSet("WaterPlnNrm" , Water._under_plane.normal*CamMatrixInv.orn());
  1708. SPSet("WaterUnder" , under_step);
  1709. SPSet("WaterUnderRfr" , refract_val);
  1710. SPSet("WaterDns" , Vec2(Mid(under.density_underwater , 0.0f, 1-EPS_GPU), under.density_underwater_add)); // avoid 1 in case "Pow(1-density, ..)" in shader would cause NaN or slow-downs
  1711. SPSet("WaterUnderCol0", under. color_underwater0 );
  1712. SPSet("WaterUnderCol1", under. color_underwater1 );
  1713. REPS(_eye, _eye_num)WS.h_Under[refract]->draw(*src, setEyeParams());
  1714. }
  1715. }
  1716. void RendererClass::postProcess()
  1717. {
  1718. Bool eye_adapt= hasEyeAdapt(),
  1719. bloom =(hasBloom () || _has_glow),
  1720. motion = hasMotion (),
  1721. dof = hasDof (),
  1722. combine = slowCombine(), // shader combine
  1723. upscale =(_final->w()>_col->w() || _final->h()>_col->h()), // we're going to upscale at the end
  1724. fx_dither=(D.dither() && !upscale), // allow post process dither only if we're not going to upscale the image (because it would look bad)
  1725. alpha_set=fastCombine(); // if alpha channel is set properly in the RT, skip this if we're doing 'fastCombine' because we're rendering to existing RT which has its Alpha already set
  1726. VecI2 size =_col->size(); MIN(size.x, _final->w()); MIN(size.y, _final->h()); // don't do post-process at higher res than needed
  1727. D.alpha(ALPHA_NONE);
  1728. ImageRTPtr dest;
  1729. if(eye_adapt || bloom || motion || dof || combine || _get_target)resolveMultiSample(); // we need to resolve the MS Image so it's smooth for the effects
  1730. Int fxs=((upscale || _get_target) ? -1 : eye_adapt+bloom+motion+dof+combine); // this counter specifies how many effects are still left in the queue, and if we can render directly to '_final', when up sampling then don't render to '_final'
  1731. if( D._view_main.full && !_get_target && !combine && _col!=_final)_final->discard();
  1732. if(!D._view_main.full)Sh.h_ColClamp->setConditional(colClamp(size)); // set ColClamp that may be needed for Bloom, DoF, MotionBlur, this is the viewport rect within texture, so reading will be clamped to what was rendered inside the viewport
  1733. if(eye_adapt)
  1734. {
  1735. if(!--fxs)dest=_final;else dest.get(ImageRTDesc(size.x, size.y, GetImageRTType(_has_glow, D.litColRTPrecision()))); // can't read and write to the same RT, glow requires Alpha channel
  1736. T.adaptEye(*_col.rc(), *dest); Swap(_col, dest); // Eye Adaptation keeps Alpha
  1737. }
  1738. if(bloom) // bloom needs to be done before motion/dof especially because of per-pixel glow
  1739. {
  1740. if(!--fxs)dest=_final;else dest.get(ImageRTDesc(size.x, size.y, IMAGERT_RGB)); // can't read and write to the same RT
  1741. T.bloom(*_col, *dest, fx_dither); alpha_set=true; Swap(_col, dest); // Bloom sets Alpha
  1742. }
  1743. if(motion) // tests have shown that it's better to do Motion Blur before Depth of Field
  1744. {
  1745. if(!--fxs)dest=_final;else dest.get(ImageRTDesc(size.x, size.y, IMAGERT_RGB)); // can't read and write to the same RT
  1746. if(T.motionBlur(*_col, *dest, fx_dither))return; alpha_set=true; Swap(_col, dest); // Motion Blur sets Alpha
  1747. }
  1748. if(dof) // after Motion Blur
  1749. {
  1750. if(!--fxs)dest=_final;else dest.get(ImageRTDesc(size.x, size.y, IMAGERT_RGB)); // can't read and write to the same RT
  1751. T.dof(*_col, *dest, fx_dither); alpha_set=true; Swap(_col, dest); // DoF sets Alpha
  1752. }
  1753. // 'upscale' will happen somewhere below
  1754. if(combine)
  1755. {
  1756. T.Combine(); alpha_set=true; // Combine sets Alpha
  1757. }
  1758. if(!_get_target) // for '_get_target' leave the '_col' result for further processing
  1759. {
  1760. if(_col!=_final)
  1761. {
  1762. #if DX11
  1763. if(_col->multiSample())
  1764. {
  1765. if(_col->size()==_final->size()){_col->copyMs(*_final, false, true, D.viewRect()); _col=_final;}else resolveMultiSample(); // if the size is the same then we can resolve directly into the '_final', otherwise resolve first to temp RT and copy will be done below
  1766. }
  1767. if(_col!=_final) // if after resolve this is still not equal, then
  1768. #elif DX9 || GL // in DX9, GL we can't read from '_main'
  1769. if(_col==&_main || _col->multiSample())_col->copyHw(*_final, false, D.viewRect());else
  1770. #endif
  1771. {
  1772. D.alpha(ALPHA_NONE);
  1773. set(_final(), null, true);
  1774. Bool dither=(D.dither() && !_final->highPrecision()); // disable dithering if destination has high precision
  1775. Shader *shader=null;
  1776. if(upscale)switch(D.densityFilter()) // remember that cubic shaders are optional and can be null if failed to load
  1777. {
  1778. case FILTER_NONE:
  1779. {
  1780. #if DX9
  1781. Sh.h_ImageCol[0]->_sampler=&SamplerPoint;
  1782. #elif DX11
  1783. SamplerPoint.setPS(SSI_DEFAULT);
  1784. #elif GL // in GL 'ShaderImage.Sampler' does not affect filtering, so modify it manually
  1785. D.texBind(GL_TEXTURE_2D, _col->_txtr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1786. #endif
  1787. }break;
  1788. case FILTER_CUBIC_FAST :
  1789. case FILTER_CUBIC_FAST_SMOOTH:
  1790. case FILTER_CUBIC_FAST_SHARP : shader=(dither ? Sh.h_DrawTexCubicFastRGBD : Sh.h_DrawTexCubicFastRGB); break; // this doesn't need to check for "_col->highPrecision" because resizing and cubic filtering generates smooth values
  1791. case FILTER_BEST :
  1792. case FILTER_CUBIC :
  1793. case FILTER_CUBIC_SHARP: Sh.loadCubicShaders(); shader=(dither ? Sh.h_DrawTexCubicRGBD : Sh.h_DrawTexCubicRGB); break; // this doesn't need to check for "_col->highPrecision" because resizing and cubic filtering generates smooth values
  1794. }
  1795. if(!shader)
  1796. {
  1797. if(dither && (_col->size()!=_final->size() || _col->highPrecision()))shader=Sh.h_Dither; // allow dithering only if we're resizing (because that generates high precision too) or if the source has high precision
  1798. else {Sh.h_Step->set(1); shader=Sh.h_DrawA ;} // use 'DrawA' to set Alpha Channel
  1799. }
  1800. shader->draw(_col); alpha_set=true;
  1801. if(upscale && D.densityFilter()==FILTER_NONE)
  1802. {
  1803. #if DX9
  1804. Sh.h_ImageCol[0]->_sampler=null;
  1805. #elif DX11
  1806. SamplerLinearClamp.setPS(SSI_DEFAULT);
  1807. #elif GL
  1808. if(!GL_ES || ImageTI[_col->hwType()].precision<IMAGE_PRECISION_32) // GLES2/3 don't support filtering F32 textures, without this check reading from F32 textures will fail - https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml
  1809. {D.texBind(GL_TEXTURE_2D, _col->_txtr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}
  1810. #endif
  1811. }
  1812. }
  1813. }
  1814. _col.clear(); // release as it's no longer needed
  1815. if(!alpha_set && _back==_final) // if we need to have alpha channel set for back buffer effect
  1816. {
  1817. set(_final(), null, true);
  1818. D.alpha(ALPHA_ADD);
  1819. Sh.clear(Vec4(0, 0, 0, 1)); // force full alpha so back buffer effects can work ok
  1820. }
  1821. }
  1822. }
  1823. /******************************************************************************/
  1824. }
  1825. /******************************************************************************/