From 9416d436fed692b5c5d49b9faf992b203fb356c2 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 1 Dec 2016 02:38:32 +0100 Subject: [PATCH] Move software renderer into its own namespace to isolate its globals and make any access explicit. This reveals the places in the code where they are being accessed where they shouldn't and prevents accidental usage. --- src/gl/system/gl_swframebuffer.cpp | 7 ++-- src/r_3dfloors.cpp | 8 +++- src/r_3dfloors.h | 8 +++- src/r_bsp.cpp | 10 ++++- src/r_bsp.h | 8 +++- src/r_defs.h | 2 +- src/r_draw.cpp | 14 +++++-- src/r_draw.h | 19 ++++++---- src/r_draw_rgba.cpp | 15 +++++--- src/r_draw_rgba.h | 5 +++ src/r_drawt.cpp | 5 +++ src/r_drawt_rgba.cpp | 5 +++ src/r_main.cpp | 61 +++++++++++++++--------------- src/r_main.h | 12 ++++-- src/r_plane.cpp | 14 ++++--- src/r_plane.h | 5 +++ src/r_poly.cpp | 12 +++--- src/r_poly_decal.cpp | 4 +- src/r_poly_particle.cpp | 4 +- src/r_poly_plane.cpp | 10 ++--- src/r_poly_playersprite.cpp | 14 +++---- src/r_poly_portal.cpp | 10 ++--- src/r_poly_sky.cpp | 2 +- src/r_poly_sprite.cpp | 14 +++---- src/r_poly_triangle.cpp | 4 +- src/r_poly_triangle.h | 4 +- src/r_poly_wall.cpp | 4 +- src/r_poly_wallsprite.cpp | 2 +- src/r_segs.cpp | 29 ++++---------- src/r_segs.h | 5 +++ src/r_state.h | 2 +- src/r_swrenderer.cpp | 7 ++++ src/r_things.cpp | 25 +++++++----- src/r_things.h | 9 ++++- src/r_thread.h | 14 ++++--- src/v_draw.cpp | 6 ++- src/win32/fb_d3d9.cpp | 9 ++--- 37 files changed, 231 insertions(+), 157 deletions(-) diff --git a/src/gl/system/gl_swframebuffer.cpp b/src/gl/system/gl_swframebuffer.cpp index 4b10326a43..421fe92781 100644 --- a/src/gl/system/gl_swframebuffer.cpp +++ b/src/gl/system/gl_swframebuffer.cpp @@ -1377,15 +1377,16 @@ void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d) uint32_t color0, color1; if (Accel2D) { - if (realfixedcolormap == nullptr) + auto &map = swrenderer::realfixedcolormap; + if (map == nullptr) { color0 = 0; color1 = 0xFFFFFFF; } else { - color0 = ColorValue(realfixedcolormap->ColorizeStart[0] / 2, realfixedcolormap->ColorizeStart[1] / 2, realfixedcolormap->ColorizeStart[2] / 2, 0); - color1 = ColorValue(realfixedcolormap->ColorizeEnd[0] / 2, realfixedcolormap->ColorizeEnd[1] / 2, realfixedcolormap->ColorizeEnd[2] / 2, 1); + color0 = ColorValue(map->ColorizeStart[0] / 2, map->ColorizeStart[1] / 2, map->ColorizeStart[2] / 2, 0); + color1 = ColorValue(map->ColorizeEnd[0] / 2, map->ColorizeEnd[1] / 2, map->ColorizeEnd[2] / 2, 1); if (IsBgra()) SetPixelShader(Shaders[SHADER_SpecialColormap]); else diff --git a/src/r_3dfloors.cpp b/src/r_3dfloors.cpp index 61a23187d4..4289b78433 100644 --- a/src/r_3dfloors.cpp +++ b/src/r_3dfloors.cpp @@ -15,6 +15,11 @@ #include "c_cvars.h" #include "r_3dfloors.h" +CVAR(Int, r_3dfloors, true, 0); + +namespace swrenderer +{ + // external variables int fake3D; F3DFloor *fakeFloor; @@ -28,8 +33,6 @@ HeightLevel *height_cur = NULL; int CurrentMirror = 0; int CurrentSkybox = 0; -CVAR(Int, r_3dfloors, true, 0); - // private variables int height_max = -1; TArray toplist; @@ -160,3 +163,4 @@ void R_3D_LeaveSkybox() CurrentSkybox--; } +} diff --git a/src/r_3dfloors.h b/src/r_3dfloors.h index cacb974443..a703ae19a4 100644 --- a/src/r_3dfloors.h +++ b/src/r_3dfloors.h @@ -3,6 +3,11 @@ #include "p_3dfloors.h" +EXTERN_CVAR(Int, r_3dfloors); + +namespace swrenderer +{ + // special types struct HeightLevel @@ -57,7 +62,6 @@ extern HeightLevel *height_top; extern HeightLevel *height_cur; extern int CurrentMirror; extern int CurrentSkybox; -EXTERN_CVAR(Int, r_3dfloors); // functions void R_3D_DeleteHeights(); @@ -67,4 +71,6 @@ void R_3D_ResetClip(); void R_3D_EnterSkybox(); void R_3D_LeaveSkybox(); +} + #endif diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 8d423b3b31..92581f01b3 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -58,6 +58,12 @@ #include "po_man.h" #include "r_data/colormaps.h" +CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? +EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); + +namespace swrenderer +{ + seg_t* curline; side_t* sidedef; line_t* linedef; @@ -104,8 +110,6 @@ TArray WallPortals(1000); // note: this array needs to go away as subsector_t *InSubsector; -CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? -EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); void R_StoreWallRange (int start, int stop); @@ -1396,3 +1400,5 @@ void R_RenderBSPNode (void *node) } R_Subsector ((subsector_t *)((BYTE *)node - 1)); } + +} diff --git a/src/r_bsp.h b/src/r_bsp.h index 48ca7565bb..e4b518e75d 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -27,6 +27,11 @@ #include #include "r_defs.h" +EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs? + +namespace swrenderer +{ + // The 3072 below is just an arbitrary value picked to avoid // drawing lines the player is too close to that would overflow // the texture calculations. @@ -109,8 +114,6 @@ extern WORD MirrorFlags; typedef void (*drawfunc_t) (int start, int stop); -EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs? - // BSP? void R_ClearClipSegs (short left, short right); void R_ClearDrawSegs (); @@ -119,5 +122,6 @@ void R_RenderBSPNode (void *node); // killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: sector_t *R_FakeFlat(sector_t *, sector_t *, int *, int *, bool); +} #endif diff --git a/src/r_defs.h b/src/r_defs.h index 97552fb524..8b176da917 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -59,7 +59,7 @@ enum SIL_BOTH }; -extern size_t MaxDrawSegs; +namespace swrenderer { extern size_t MaxDrawSegs; } struct FDisplacement; // diff --git a/src/r_draw.cpp b/src/r_draw.cpp index d04b1dcf6c..c1e96b329e 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -47,6 +47,14 @@ #undef RANGECHECK +EXTERN_CVAR (Int, r_drawfuzz) +EXTERN_CVAR (Bool, r_drawtrans) +EXTERN_CVAR (Float, transsouls) +EXTERN_CVAR (Int, r_columnmethod) + +namespace swrenderer +{ + // status bar height at bottom of screen // [RH] status bar position at bottom of screen extern int ST_Y; @@ -194,7 +202,6 @@ FDynamicColormap identitycolormap; bool drawer_needs_pal_input; -EXTERN_CVAR (Int, r_columnmethod) void R_InitShadeMaps() { @@ -2734,9 +2741,6 @@ void R_InitColumnDrawers () } // [RH] Choose column drawers in a single place -EXTERN_CVAR (Int, r_drawfuzz) -EXTERN_CVAR (Bool, r_drawtrans) -EXTERN_CVAR (Float, transsouls) static FDynamicColormap *basecolormapsave; @@ -3122,3 +3126,5 @@ void R_SetDSColorMapLight(FSWColormap *base_colormap, float light, int shade) ds_colormap = base_colormap->Maps + (GETPALOOKUP(light, shade) << COLORMAPSHIFT); } } + +} diff --git a/src/r_draw.h b/src/r_draw.h index 7556575bd1..d312ac8fbc 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -25,14 +25,23 @@ #include "r_defs.h" +struct FSWColormap; + +EXTERN_CVAR(Bool, r_multithreaded); +EXTERN_CVAR(Bool, r_magfilter); +EXTERN_CVAR(Bool, r_minfilter); +EXTERN_CVAR(Bool, r_mipmap); +EXTERN_CVAR(Float, r_lod_bias); + +namespace swrenderer +{ + // Spectre/Invisibility. #define FUZZTABLE 50 extern "C" int fuzzoffset[FUZZTABLE + 1]; // [RH] +1 for the assembly routine extern "C" int fuzzpos; extern "C" int fuzzviewheight; -struct FSWColormap; - struct ShadeConstants { uint16_t light_alpha; @@ -395,10 +404,6 @@ void R_DrawDoubleSkyCol4_rgba(uint32_t solid_top, uint32_t solid_bottom); extern bool r_swtruecolor; -EXTERN_CVAR(Bool, r_multithreaded); -EXTERN_CVAR(Bool, r_magfilter); -EXTERN_CVAR(Bool, r_minfilter); -EXTERN_CVAR(Bool, r_mipmap); -EXTERN_CVAR(Float, r_lod_bias); +} #endif diff --git a/src/r_draw_rgba.cpp b/src/r_draw_rgba.cpp index 716b30c0d3..61e0a8932f 100644 --- a/src/r_draw_rgba.cpp +++ b/src/r_draw_rgba.cpp @@ -46,11 +46,6 @@ #include "x86.h" #include -extern "C" short spanend[MAXHEIGHT]; -extern float rw_light; -extern float rw_lightstep; -extern int wallshade; - // Use linear filtering when scaling up CVAR(Bool, r_magfilter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); @@ -63,6 +58,14 @@ CVAR(Bool, r_mipmap, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); // Level of detail texture bias CVAR(Float, r_lod_bias, -1.5, 0); // To do: add CVAR_ARCHIVE | CVAR_GLOBALCONFIG when a good default has been decided +namespace swrenderer +{ + +extern "C" short spanend[MAXHEIGHT]; +extern float rw_light; +extern float rw_lightstep; +extern int wallshade; + ///////////////////////////////////////////////////////////////////////////// class DrawSpanLLVMCommand : public DrawerCommand @@ -1622,3 +1625,5 @@ void R_DrawFogBoundary_rgba(int x1, int x2, short *uclip, short *dclip) R_DrawFogBoundarySection_rgba(t2, b2, x1); } } + +} diff --git a/src/r_draw_rgba.h b/src/r_draw_rgba.h index 4aa1a02aff..8e66b7a720 100644 --- a/src/r_draw_rgba.h +++ b/src/r_draw_rgba.h @@ -36,6 +36,9 @@ struct FSpecialColormap; EXTERN_CVAR(Bool, r_mipmap) EXTERN_CVAR(Float, r_lod_bias) +namespace swrenderer +{ + ///////////////////////////////////////////////////////////////////////////// // Drawer functions: @@ -285,4 +288,6 @@ public: } }; +} + #endif diff --git a/src/r_drawt.cpp b/src/r_drawt.cpp index 0baf6d38c9..d87c8f4c09 100644 --- a/src/r_drawt.cpp +++ b/src/r_drawt.cpp @@ -47,6 +47,9 @@ #include "r_things.h" #include "v_video.h" +namespace swrenderer +{ + // I should have commented this stuff better. // // dc_temp is the buffer R_DrawColumnHoriz writes into. @@ -1130,3 +1133,5 @@ void R_FillColumnHorizP_C (void) dest += 8; } while (--count); } + +} diff --git a/src/r_drawt_rgba.cpp b/src/r_drawt_rgba.cpp index 57de59eba3..98d27adecf 100644 --- a/src/r_drawt_rgba.cpp +++ b/src/r_drawt_rgba.cpp @@ -45,6 +45,9 @@ #include "r_draw_rgba.h" #include "r_drawers.h" +namespace swrenderer +{ + extern unsigned int dc_tspans[4][MAXHEIGHT]; extern unsigned int *dc_ctspan[4]; extern unsigned int *horizspan[4]; @@ -506,3 +509,5 @@ void R_FillColumnHoriz_rgba (void) DrawerCommandQueue::QueueCommand(); } + +} diff --git a/src/r_main.cpp b/src/r_main.cpp index 5c7ab39bcb..b236dc0e7d 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -62,6 +62,34 @@ #include "p_setup.h" #include "version.h" +CVAR (String, r_viewsize, "", CVAR_NOSET) +CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE) + +CUSTOM_CVAR (Int, r_columnmethod, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self != 0 && self != 1) + { + self = 1; + } + else + { // Trigger the change + setsizeneeded = true; + } +} + +CVAR(Int, r_portal_recursions, 4, CVAR_ARCHIVE) +CVAR(Bool, r_highlight_portals, false, CVAR_ARCHIVE) + +EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) + +extern cycle_t WallCycles, PlaneCycles, MaskedCycles, WallScanCycles; +extern cycle_t FrameCycles; + +extern bool r_showviewer; + +namespace swrenderer +{ + // MACROS ------------------------------------------------------------------ #if 0 @@ -91,7 +119,6 @@ extern short *openings; extern bool r_fakingunderwater; extern "C" int fuzzviewheight; extern subsector_t *InSubsector; -extern bool r_showviewer; // PRIVATE DATA DECLARATIONS ----------------------------------------------- @@ -103,9 +130,6 @@ bool r_dontmaplines; // PUBLIC DATA DEFINITIONS ------------------------------------------------- -CVAR (String, r_viewsize, "", CVAR_NOSET) -CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE) - bool r_swtruecolor; double r_BaseVisibility; @@ -366,26 +390,6 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, R_SetVisibility(R_GetVisibility()); } -//========================================================================== -// -// CVAR r_columnmethod -// -// Selects which version of the seg renderers to use. -// -//========================================================================== - -CUSTOM_CVAR (Int, r_columnmethod, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self != 0 && self != 1) - { - self = 1; - } - else - { // Trigger the change - setsizeneeded = true; - } -} - //========================================================================== // // R_Init @@ -450,8 +454,6 @@ void R_CopyStackedViewParameters() // //========================================================================== -EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) - void R_SetupColormap(player_t *player) { realfixedcolormap = NULL; @@ -569,9 +571,6 @@ void R_SetupFreelook() // //========================================================================== -CVAR(Int, r_portal_recursions, 4, CVAR_ARCHIVE) -CVAR(Bool, r_highlight_portals, false, CVAR_ARCHIVE) - void R_HighlightPortal (PortalDrawseg* pds) { // [ZZ] NO OVERFLOW CHECKS HERE @@ -1023,8 +1022,6 @@ void R_MultiresInit () // Displays statistics about rendering times // //========================================================================== -extern cycle_t WallCycles, PlaneCycles, MaskedCycles, WallScanCycles; -extern cycle_t FrameCycles; ADD_STAT (fps) { @@ -1104,3 +1101,5 @@ CCMD (clearscancycles) bestscancycles = HUGE_VAL; } #endif + +} diff --git a/src/r_main.h b/src/r_main.h index 6a802e7993..f4d0a144ab 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -28,6 +28,13 @@ #include "v_palette.h" #include "r_data/colormaps.h" +extern double ViewCos; +extern double ViewSin; +extern int viewwindowx; +extern int viewwindowy; + +namespace swrenderer +{ typedef BYTE lighttable_t; // This could be wider for >8 bit display. @@ -35,16 +42,12 @@ typedef BYTE lighttable_t; // This could be wider for >8 bit display. // POV related. // extern bool bRenderingToCanvas; -extern double ViewCos; -extern double ViewSin; extern fixed_t viewingrangerecip; extern double FocalLengthX, FocalLengthY; extern double InvZtoScale; extern double WallTMapScale2; -extern int viewwindowx; -extern int viewwindowy; extern double CenterX; extern double CenterY; @@ -152,5 +155,6 @@ extern DAngle stacked_angle; extern void R_CopyStackedViewParameters(); +} #endif // __R_MAIN_H__ diff --git a/src/r_plane.cpp b/src/r_plane.cpp index ca85470035..da58ad16c6 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -64,10 +64,14 @@ #pragma warning(disable:4244) #endif +CVAR(Bool, r_linearsky, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, tilt, false, 0); +CVAR(Bool, r_skyboxes, true, 0) + EXTERN_CVAR(Int, r_skymode) -//EXTERN_CVAR (Int, tx) -//EXTERN_CVAR (Int, ty) +namespace swrenderer +{ extern subsector_t *InSubsector; @@ -889,7 +893,6 @@ static DWORD lastskycol_bgra[MAXSKYBUF]; static int skycolplace; static int skycolplace_bgra; -CVAR(Bool, r_linearsky, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); // Get a column of sky when there is only one sky texture. static const BYTE *R_GetOneSkyColumn (FTexture *fronttex, int x) @@ -1312,8 +1315,6 @@ static void R_DrawSkyStriped (visplane_t *pl) // //========================================================================== -CVAR (Bool, tilt, false, 0); -//CVAR (Int, pa, 0, 0) int R_DrawPlanes () { @@ -1450,7 +1451,6 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske // 9. Put the camera back where it was to begin with. // //========================================================================== -CVAR (Bool, r_skyboxes, true, 0) static int numskyboxes; void R_DrawPortals () @@ -2190,3 +2190,5 @@ bool R_PlaneInitData () return true; } + +} diff --git a/src/r_plane.h b/src/r_plane.h index b199d34776..5e91a4b0be 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -27,6 +27,9 @@ class ASkyViewpoint; +namespace swrenderer +{ + // // The infamous visplane // @@ -121,4 +124,6 @@ bool R_PlaneInitData (void); extern visplane_t* floorplane; extern visplane_t* ceilingplane; +} + #endif // __R_PLANE_H__ diff --git a/src/r_poly.cpp b/src/r_poly.cpp index 3809c56391..cadf92adf6 100644 --- a/src/r_poly.cpp +++ b/src/r_poly.cpp @@ -46,16 +46,16 @@ RenderPolyScene *RenderPolyScene::Instance() void RenderPolyScene::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines) { const bool savedviewactive = viewactive; - const bool savedoutputformat = r_swtruecolor; + const bool savedoutputformat = swrenderer::r_swtruecolor; viewwidth = width; RenderTarget = canvas; - bRenderingToCanvas = true; + swrenderer::bRenderingToCanvas = true; R_SetWindow(12, width, height, height, true); viewwindowx = x; viewwindowy = y; viewactive = true; - r_swtruecolor = canvas->IsBgra(); + swrenderer::r_swtruecolor = canvas->IsBgra(); canvas->Lock(true); @@ -64,17 +64,17 @@ void RenderPolyScene::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, canvas->Unlock(); RenderTarget = screen; - bRenderingToCanvas = false; + swrenderer::bRenderingToCanvas = false; R_ExecuteSetViewSize(); viewactive = savedviewactive; - r_swtruecolor = savedoutputformat; + swrenderer::r_swtruecolor = savedoutputformat; } void RenderPolyScene::RenderActorView(AActor *actor, bool dontmaplines) { NetUpdate(); - r_dontmaplines = dontmaplines; + //swrenderer::r_dontmaplines = dontmaplines; P_FindParticleSubsectors(); PO_LinkToSubsectors(); diff --git a/src/r_poly_decal.cpp b/src/r_poly_decal.cpp index 9d47c014a0..e91e25b582 100644 --- a/src/r_poly_decal.cpp +++ b/src/r_poly_decal.cpp @@ -135,7 +135,7 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan args.uniforms.flags = 0; args.SetColormap(front->ColorMap); args.SetTexture(tex, decal->Translation, true); - if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) + if (fullbrightSprite || swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) { args.uniforms.light = 256; args.uniforms.flags |= TriUniforms::fixed_light; @@ -146,7 +146,7 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan } args.uniforms.subsectorDepth = subsectorDepth; - if (r_swtruecolor) + if (swrenderer::r_swtruecolor) { args.uniforms.color = 0xff000000 | decal->AlphaColor; } diff --git a/src/r_poly_particle.cpp b/src/r_poly_particle.cpp index 73e1819d4f..0d31614d22 100644 --- a/src/r_poly_particle.cpp +++ b/src/r_poly_particle.cpp @@ -72,7 +72,7 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipP PolyDrawArgs args; - if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) + if (fullbrightSprite || swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) { args.uniforms.light = 256; args.uniforms.flags = TriUniforms::fixed_light; @@ -84,7 +84,7 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipP } args.uniforms.subsectorDepth = subsectorDepth; - if (r_swtruecolor) + if (swrenderer::r_swtruecolor) { uint32_t alpha = particle->trans; args.uniforms.color = (alpha << 24) | (particle->color & 0xffffff); diff --git a/src/r_poly_plane.cpp b/src/r_poly_plane.cpp index b17b0ec2c3..41898fa8b8 100644 --- a/src/r_poly_plane.cpp +++ b/src/r_poly_plane.cpp @@ -28,7 +28,7 @@ #include "r_poly_plane.h" #include "r_poly_portal.h" #include "r_poly.h" -#include "r_sky.h" // for skyflatnum +#include "r_sky.h" EXTERN_CVAR(Int, r_3dfloors) @@ -96,10 +96,10 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c return; int lightlevel = 255; - if (fixedlightlev < 0 && sub->sector->e->XFloor.lightlist.Size()) + if (swrenderer::fixedlightlev < 0 && sub->sector->e->XFloor.lightlist.Size()) { lightlist_t *light = P_GetPlaneLight(sub->sector, &sub->sector->ceilingplane, false); - basecolormap = light->extra_colormap; + swrenderer::basecolormap = light->extra_colormap; lightlevel = *light->p_lightlevel; } @@ -107,7 +107,7 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &c PolyDrawArgs args; args.uniforms.light = (uint32_t)(lightlevel / 255.0f * 256.0f); - if (fixedlightlev >= 0 || fixedcolormap) + if (swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) args.uniforms.light = 256; args.uniforms.flags = 0; args.uniforms.subsectorDepth = subsectorDepth; @@ -251,7 +251,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlan PolyDrawArgs args; args.uniforms.light = (uint32_t)(frontsector->lightlevel / 255.0f * 256.0f); - if (fixedlightlev >= 0 || fixedcolormap) + if (swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) args.uniforms.light = 256; args.uniforms.flags = 0; args.uniforms.subsectorDepth = isSky ? RenderPolyPortal::SkySubsectorDepth : subsectorDepth; diff --git a/src/r_poly_playersprite.cpp b/src/r_poly_playersprite.cpp index 1a657d1a21..381f2e2033 100644 --- a/src/r_poly_playersprite.cpp +++ b/src/r_poly_playersprite.cpp @@ -143,14 +143,14 @@ void RenderPolyPlayerSprites::RenderSprite(DPSprite *sprite, AActor *owner, floa double tx = sx - BaseXCenter; tx -= tex->GetScaledLeftOffset(); - int x1 = xs_RoundToInt(CenterX + tx * pspritexscale); + int x1 = xs_RoundToInt(swrenderer::CenterX + tx * swrenderer::pspritexscale); // off the right side if (x1 > viewwidth) return; tx += tex->GetScaledWidth(); - int x2 = xs_RoundToInt(CenterX + tx * pspritexscale); + int x2 = xs_RoundToInt(swrenderer::CenterX + tx * swrenderer::pspritexscale); // off the left side if (x2 <= 0) @@ -183,19 +183,19 @@ void RenderPolyPlayerSprites::RenderSprite(DPSprite *sprite, AActor *owner, floa int clipped_x1 = MAX(x1, 0); int clipped_x2 = MIN(x2, viewwidth); - double xscale = pspritexscale / tex->Scale.X; - double yscale = pspriteyscale / tex->Scale.Y; + double xscale = swrenderer::pspritexscale / tex->Scale.X; + double yscale = swrenderer::pspriteyscale / tex->Scale.Y; uint32_t translation = 0; // [RH] Use default colors double xiscale, startfrac; if (flip) { - xiscale = -pspritexiscale * tex->Scale.X; + xiscale = -swrenderer::pspritexiscale * tex->Scale.X; startfrac = 1; } else { - xiscale = pspritexiscale * tex->Scale.X; + xiscale = swrenderer::pspritexiscale * tex->Scale.X; startfrac = 0; } @@ -217,7 +217,7 @@ void RenderPolyPlayerSprites::RenderSprite(DPSprite *sprite, AActor *owner, floa int actualextralight = foggy ? 0 : extralight << 4; int spriteshade = LIGHT2SHADE(owner->Sector->lightlevel + actualextralight); double minz = double((2048 * 4) / double(1 << 20)); - visstyle.ColormapNum = GETPALOOKUP(r_SpriteVisibility / minz, spriteshade); + visstyle.ColormapNum = GETPALOOKUP(swrenderer::r_SpriteVisibility / minz, spriteshade); if (sprite->GetID() < PSP_TARGETCENTER) { diff --git a/src/r_poly_portal.cpp b/src/r_poly_portal.cpp index 3257afc702..5c4dbc89fd 100644 --- a/src/r_poly_portal.cpp +++ b/src/r_poly_portal.cpp @@ -163,7 +163,7 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front return; // Tell automap we saw this - if (!r_dontmaplines && line->linedef) + if (!swrenderer::r_dontmaplines && line->linedef) { line->linedef->flags |= ML_MAPPED; sub->flags |= SSECF_DRAWN; @@ -367,7 +367,7 @@ void PolyDrawSectorPortal::SaveGlobals() savedextralight = extralight; savedpos = ViewPos; savedangle = ViewAngle; - savedvisibility = R_GetVisibility(); + savedvisibility = swrenderer::R_GetVisibility(); savedcamera = camera; savedsector = viewsector; @@ -376,14 +376,14 @@ void PolyDrawSectorPortal::SaveGlobals() // Don't let gun flashes brighten the sky box ASkyViewpoint *sky = barrier_cast(Portal->mSkybox); extralight = 0; - R_SetVisibility(sky->args[0] * 0.25f); + swrenderer::R_SetVisibility(sky->args[0] * 0.25f); ViewPos = sky->InterpolatedPosition(r_TicFracF); ViewAngle = savedangle + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * r_TicFracF); } else //if (Portal->mType == PORTS_STACKEDSECTORTHING || Portal->mType == PORTS_PORTAL || Portal->mType == PORTS_LINKEDPORTAL) { //extralight = pl->extralight; - //R_SetVisibility(pl->visibility); + //swrenderer::R_SetVisibility(pl->visibility); ViewPos.X += Portal->mDisplacement.X; ViewPos.Y += Portal->mDisplacement.Y; } @@ -404,7 +404,7 @@ void PolyDrawSectorPortal::RestoreGlobals() camera = savedcamera; viewsector = savedsector; ViewPos = savedpos; - R_SetVisibility(savedvisibility); + swrenderer::R_SetVisibility(savedvisibility); extralight = savedextralight; ViewAngle = savedangle; R_SetViewAngle(); diff --git a/src/r_poly_sky.cpp b/src/r_poly_sky.cpp index c0a219c799..a19e0d40b3 100644 --- a/src/r_poly_sky.cpp +++ b/src/r_poly_sky.cpp @@ -85,7 +85,7 @@ void PolySkyDome::RenderRow(PolyDrawArgs &args, int row) void PolySkyDome::RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap) { uint32_t solid = skytex->GetSkyCapColor(bottomCap); - if (!r_swtruecolor) + if (!swrenderer::r_swtruecolor) solid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)]; args.vinput = &mVertices[mPrimStart[row]]; diff --git a/src/r_poly_sprite.cpp b/src/r_poly_sprite.cpp index eb1328b485..46c90adc26 100644 --- a/src/r_poly_sprite.cpp +++ b/src/r_poly_sprite.cpp @@ -119,7 +119,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla PolyDrawArgs args; args.uniforms.flags = 0; - if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) + if (fullbrightSprite || swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) { args.uniforms.light = 256; args.uniforms.flags |= TriUniforms::fixed_light; @@ -228,7 +228,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla args.SetTexture(tex, thing->Translation, true); } - if (!r_swtruecolor) + if (!swrenderer::r_swtruecolor) { uint32_t r = (args.uniforms.color >> 16) & 0xff; uint32_t g = (args.uniforms.color >> 8) & 0xff; @@ -309,9 +309,9 @@ visstyle_t RenderPolySprite::GetSpriteVisStyle(AActor *thing, double z) } // get light level - if (fixedcolormap != nullptr) + if (swrenderer::fixedcolormap != nullptr) { // fixed map - visstyle.BaseColormap = fixedcolormap; + visstyle.BaseColormap = swrenderer::fixedcolormap; visstyle.ColormapNum = 0; } else @@ -320,10 +320,10 @@ visstyle_t RenderPolySprite::GetSpriteVisStyle(AActor *thing, double z) { mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate); } - if (fixedlightlev >= 0) + if (swrenderer::fixedlightlev >= 0) { visstyle.BaseColormap = mybasecolormap; - visstyle.ColormapNum = fixedlightlev >> COLORMAPSHIFT; + visstyle.ColormapNum = swrenderer::fixedlightlev >> COLORMAPSHIFT; } else if (!foggy && ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT))) { // full bright @@ -333,7 +333,7 @@ visstyle_t RenderPolySprite::GetSpriteVisStyle(AActor *thing, double z) else { // diminished light double minz = double((2048 * 4) / double(1 << 20)); - visstyle.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(z, minz), spriteshade); + visstyle.ColormapNum = GETPALOOKUP(swrenderer::r_SpriteVisibility / MAX(z, minz), spriteshade); visstyle.BaseColormap = mybasecolormap; } } diff --git a/src/r_poly_triangle.cpp b/src/r_poly_triangle.cpp index a3398df2b1..4b6e1c344a 100644 --- a/src/r_poly_triangle.cpp +++ b/src/r_poly_triangle.cpp @@ -498,8 +498,8 @@ TriMatrix TriMatrix::viewToClip() float near = 5.0f; float far = 65536.0f; float width = (float)(FocalTangent * near); - float top = (float)(CenterY / InvZtoScale * near); - float bottom = (float)(top - viewheight / InvZtoScale * near); + float top = (float)(swrenderer::CenterY / swrenderer::InvZtoScale * near); + float bottom = (float)(top - viewheight / swrenderer::InvZtoScale * near); return frustum(-width, width, bottom, top, near, far); } diff --git a/src/r_poly_triangle.h b/src/r_poly_triangle.h index 1c07ce5bd0..46948310fe 100644 --- a/src/r_poly_triangle.h +++ b/src/r_poly_triangle.h @@ -70,7 +70,7 @@ public: { textureWidth = texture->GetWidth(); textureHeight = texture->GetHeight(); - if (r_swtruecolor) + if (swrenderer::r_swtruecolor) texturePixels = (const uint8_t *)texture->GetPixelsBgra(); else texturePixels = texture->GetPixels(); @@ -84,7 +84,7 @@ public: FRemapTable *table = TranslationToTable(translationID); if (table != nullptr && !table->Inactive) { - if (r_swtruecolor) + if (swrenderer::r_swtruecolor) translation = (uint8_t*)table->Palette; else translation = table->Remap; diff --git a/src/r_poly_wall.cpp b/src/r_poly_wall.cpp index cd4d32077f..4dd24887d9 100644 --- a/src/r_poly_wall.cpp +++ b/src/r_poly_wall.cpp @@ -31,7 +31,7 @@ #include "r_poly_wall.h" #include "r_poly_decal.h" #include "r_poly.h" -#include "r_sky.h" // for skyflatnum +#include "r_sky.h" EXTERN_CVAR(Bool, r_drawmirrors) @@ -330,7 +330,7 @@ FTexture *RenderPolyWall::GetTexture() int RenderPolyWall::GetLightLevel() { - if (fixedlightlev >= 0 || fixedcolormap) + if (swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) { return 255; } diff --git a/src/r_poly_wallsprite.cpp b/src/r_poly_wallsprite.cpp index 351e24e364..0521fb06e3 100644 --- a/src/r_poly_wallsprite.cpp +++ b/src/r_poly_wallsprite.cpp @@ -99,7 +99,7 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &cli bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); PolyDrawArgs args; - if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) + if (fullbrightSprite || swrenderer::fixedlightlev >= 0 || swrenderer::fixedcolormap) { args.uniforms.light = 256; args.uniforms.flags = TriUniforms::fixed_light; diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 175768aecd..0e59ef0f74 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -56,12 +56,14 @@ #define WALLYREPEAT 8 - CVAR(Bool, r_np2, true, 0) +CVAR(Bool, r_fogboundary, true, 0) +CVAR(Bool, r_drawmirrors, true, 0) EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); +EXTERN_CVAR(Bool, r_mipmap) -//CVAR (Int, ty, 8, 0) -//CVAR (Int, tx, 8, 0) +namespace swrenderer +{ #define HEIGHTBITS 12 #define HEIGHTSHIFT (FRACBITS-HEIGHTBITS) @@ -142,16 +144,6 @@ void wallscan_np2(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t static void wallscan_np2_ds(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat); static void call_wallscan(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, bool mask); -//============================================================================= -// -// CVAR r_fogboundary -// -// If true, makes fog look more "real" by shading the walls separating two -// sectors with different fog. -//============================================================================= - -CVAR(Bool, r_fogboundary, true, 0) - inline bool IsFogBoundary (sector_t *front, sector_t *back) { return r_fogboundary && fixedcolormap == NULL && front->ColorMap->Fade && @@ -159,14 +151,6 @@ inline bool IsFogBoundary (sector_t *front, sector_t *back) (front->GetTexture(sector_t::ceiling) != skyflatnum || back->GetTexture(sector_t::ceiling) != skyflatnum); } -//============================================================================= -// -// CVAR r_drawmirrors -// -// Set to false to disable rendering of mirrors -//============================================================================= - -CVAR(Bool, r_drawmirrors, true, 0) // // R_RenderMaskedSegRange @@ -1065,7 +1049,6 @@ void R_RenderFakeWallRange (drawseg_t *ds, int x1, int x2) return; } -EXTERN_CVAR(Bool, r_mipmap) struct WallscanSampler { @@ -3162,3 +3145,5 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, done: WallC = savecoord; } + +} diff --git a/src/r_segs.h b/src/r_segs.h index 1fc428c964..7d34a78f40 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -23,6 +23,9 @@ #ifndef __R_SEGS_H__ #define __R_SEGS_H__ +namespace swrenderer +{ + struct drawseg_t; void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2); @@ -70,4 +73,6 @@ extern int CurrentPortalUniq; extern bool CurrentPortalInSkybox; extern TArray WallPortals; +} + #endif diff --git a/src/r_state.h b/src/r_state.h index b66ad57eb7..cd4aee4be3 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -80,7 +80,7 @@ extern int numgamesubsectors; extern AActor* camera; // [RH] camera instead of viewplayer extern sector_t* viewsector; // [RH] keep track of sector viewing from -extern angle_t xtoviewangle[MAXWIDTH+1]; +namespace swrenderer { extern angle_t xtoviewangle[MAXWIDTH+1]; } extern DAngle FieldOfView; int R_FindSkin (const char *name, int pclass); // [RH] Find a skin diff --git a/src/r_swrenderer.cpp b/src/r_swrenderer.cpp index 0f30fc3dff..56820e5361 100644 --- a/src/r_swrenderer.cpp +++ b/src/r_swrenderer.cpp @@ -58,11 +58,18 @@ CUSTOM_CVAR(Bool, r_polyrenderer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOI } } +namespace swrenderer +{ + void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio); void R_SetupColormap(player_t *); void R_SetupFreelook(); void R_InitRenderer(); +} + +using namespace swrenderer; + FSoftwareRenderer::FSoftwareRenderer() { } diff --git a/src/r_things.cpp b/src/r_things.cpp index 8f91b17408..659ad916aa 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -66,6 +66,19 @@ #include "p_local.h" #include "p_maputl.h" +EXTERN_CVAR(Bool, st_scale) +EXTERN_CVAR(Bool, r_shadercolormaps) +EXTERN_CVAR(Int, r_drawfuzz) +EXTERN_CVAR(Bool, r_deathcamera); +EXTERN_CVAR(Bool, r_drawplayersprites) +EXTERN_CVAR(Bool, r_drawvoxels) + +CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, r_splitsprites, true, CVAR_ARCHIVE) + +namespace swrenderer +{ + // [RH] A c-buffer. Used for keeping track of offscreen voxel spans. struct FCoverageBuffer @@ -96,12 +109,6 @@ extern float MaskedScaleY; #define BASEXCENTER (160) #define BASEYCENTER (100) -EXTERN_CVAR (Bool, st_scale) -EXTERN_CVAR(Bool, r_shadercolormaps) -EXTERN_CVAR(Int, r_drawfuzz) -EXTERN_CVAR(Bool, r_deathcamera); -CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); - // // Sprite rotation 0 is facing the viewer, // rotation 1 is one angle turn CLOCKWISE around the axis. @@ -133,8 +140,6 @@ FTexture *WallSpriteTile; short zeroarray[MAXWIDTH]; short screenheightarray[MAXWIDTH]; -EXTERN_CVAR (Bool, r_drawplayersprites) -EXTERN_CVAR (Bool, r_drawvoxels) // // INITIALIZATION FUNCTIONS @@ -1903,8 +1908,6 @@ static int sd_comparex (const void *arg1, const void *arg2) return (*(drawseg_t **)arg2)->x2 - (*(drawseg_t **)arg1)->x2; } -CVAR (Bool, r_splitsprites, true, CVAR_ARCHIVE) - // Split up vissprites that intersect drawsegs void R_SplitVisSprites () { @@ -3446,3 +3449,5 @@ void R_CheckOffscreenBuffer(int width, int height, bool spansonly) OffscreenBufferWidth = width; OffscreenBufferHeight = height; } + +} diff --git a/src/r_things.h b/src/r_things.h index e354898924..0e036d633e 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -25,6 +25,12 @@ #include "r_bsp.h" +struct particle_t; +struct FVoxel; + +namespace swrenderer +{ + // A vissprite_t is a thing // that will be drawn during a refresh. // I.e. a sprite object that is partly visible. @@ -94,8 +100,6 @@ struct vissprite_t vissprite_t() {} }; -struct particle_t; - extern void(*R_DrawParticle)(vissprite_t *); void R_DrawParticle_C (vissprite_t *); void R_DrawParticle_rgba (vissprite_t *); @@ -148,5 +152,6 @@ void R_DrawVoxel(const FVector3 &viewpos, FAngle viewangle, void R_ClipVisSprite (vissprite_t *vis, int xl, int xh); +} #endif diff --git a/src/r_thread.h b/src/r_thread.h index 3271d80506..d80fd02031 100644 --- a/src/r_thread.h +++ b/src/r_thread.h @@ -99,7 +99,7 @@ protected: void DetectRangeError(uint32_t *&dest, int &dest_y, int &count) { #if defined(_MSC_VER) && defined(_DEBUG) - if (dest_y < 0 || count < 0 || dest_y + count > dc_destheight) + if (dest_y < 0 || count < 0 || dest_y + count > swrenderer::dc_destheight) __debugbreak(); // Buffer overrun detected! #endif @@ -107,24 +107,26 @@ protected: { count += dest_y; dest_y = 0; - dest = (uint32_t*)dc_destorg; + dest = (uint32_t*)swrenderer::dc_destorg; } - else if (dest_y >= dc_destheight) + else if (dest_y >= swrenderer::dc_destheight) { dest_y = 0; count = 0; } if (count < 0 || count > MAXHEIGHT) count = 0; - if (dest_y + count >= dc_destheight) - count = dc_destheight - dest_y; + if (dest_y + count >= swrenderer::dc_destheight) + count = swrenderer::dc_destheight - dest_y; } public: DrawerCommand() { - _dest_y = static_cast((dc_dest - dc_destorg) / (dc_pitch * 4)); + _dest_y = static_cast((swrenderer::dc_dest - swrenderer::dc_destorg) / (swrenderer::dc_pitch * 4)); } + + virtual ~DrawerCommand() { } virtual void Execute(DrawerThread *thread) = 0; virtual FString DebugInfo() = 0; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 05cfdd0dc2..985238071b 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -133,6 +133,8 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, .. void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) { #ifndef NO_SWRENDER + using namespace swrenderer; + static short bottomclipper[MAXWIDTH], topclipper[MAXWIDTH]; const BYTE *translation = NULL; @@ -1026,7 +1028,7 @@ void DCanvas::PUTTRANSDOT (int xx, int yy, int basecolor, int level) { uint32_t *spot = (uint32_t*)GetBuffer() + oldyyshifted + xx; - uint32_t fg = LightBgra::shade_pal_index_simple(basecolor, LightBgra::calc_light_multiplier(0)); + uint32_t fg = swrenderer::LightBgra::shade_pal_index_simple(basecolor, swrenderer::LightBgra::calc_light_multiplier(0)); uint32_t fg_red = (fg >> 16) & 0xff; uint32_t fg_green = (fg >> 8) & 0xff; uint32_t fg_blue = fg & 0xff; @@ -1359,6 +1361,8 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, FDynamicColormap *colormap, int lightlevel, int bottomclip) { #ifndef NO_SWRENDER + using namespace swrenderer; + // Use an equation similar to player sprites to determine shade fixed_t shade = LIGHT2SHADE(lightlevel) - 12*FRACUNIT; float topy, boty, leftx, rightx; diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 3ede15b395..5b8670088a 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1405,17 +1405,16 @@ void D3DFB::Draw3DPart(bool copy3d) D3DCOLOR color0, color1; if (Accel2D) { - if (realfixedcolormap == NULL) + auto &map = swrenderer::realfixedcolormap; + if (map == NULL) { color0 = 0; color1 = 0xFFFFFFF; } else { - color0 = D3DCOLOR_COLORVALUE(realfixedcolormap->ColorizeStart[0]/2, - realfixedcolormap->ColorizeStart[1]/2, realfixedcolormap->ColorizeStart[2]/2, 0); - color1 = D3DCOLOR_COLORVALUE(realfixedcolormap->ColorizeEnd[0]/2, - realfixedcolormap->ColorizeEnd[1]/2, realfixedcolormap->ColorizeEnd[2]/2, 1); + color0 = D3DCOLOR_COLORVALUE(map->ColorizeStart[0]/2, map->ColorizeStart[1]/2, map->ColorizeStart[2]/2, 0); + color1 = D3DCOLOR_COLORVALUE(map->ColorizeEnd[0]/2, map->ColorizeEnd[1]/2, map->ColorizeEnd[2]/2, 1); if (IsBgra()) SetPixelShader(Shaders[SHADER_SpecialColormap]); else