diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index debb10cea4..b8fbfc24a0 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -141,3 +141,94 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, bo } + + +//========================================================================== +// +// Sets up the parameters to render one dynamic light onto one plane +// +//========================================================================== +bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, Vector & nearPt, Vector & up, Vector & right, + float & scale, int desaturation, bool checkside, bool forceadditive) +{ + Vector fn, pos; + + DVector3 lpos = light->PosRelative(group); + + float dist = fabsf(p.DistToPoint(lpos.X, lpos.Z, lpos.Y)); + float radius = (light->GetRadius() * gl_lights_size); + + if (radius <= 0.f) return false; + if (dist > radius) return false; + if (checkside && gl_lights_checkside && p.PointOnSide(lpos.X, lpos.Z, lpos.Y)) + { + return false; + } + if (light->owned && light->target != NULL && !light->target->IsVisibleToPlayer()) + { + return false; + } + + scale = 1.0f / ((2.f * radius) - dist); + + // project light position onto plane (find closest point on plane) + + + pos.Set(lpos.X, lpos.Z, lpos.Y); + fn = p.Normal(); + fn.GetRightUp(right, up); + +#ifdef _MSC_VER + nearPt = pos + fn * dist; +#else + Vector tmpVec = fn * dist; + nearPt = pos + tmpVec; +#endif + + float cs = 1.0f - (dist / radius); + if (gl_lights_additive || light->flags4&MF4_ADDITIVE || forceadditive) cs *= 0.2f; // otherwise the light gets too strong. + float r = light->GetRed() / 255.0f * cs * gl_lights_intensity; + float g = light->GetGreen() / 255.0f * cs * gl_lights_intensity; + float b = light->GetBlue() / 255.0f * cs * gl_lights_intensity; + + if (light->IsSubtractive()) + { + Vector v; + + gl_RenderState.BlendEquation(GL_FUNC_REVERSE_SUBTRACT); + v.Set(r, g, b); + r = v.Length() - r; + g = v.Length() - g; + b = v.Length() - b; + } + else + { + gl_RenderState.BlendEquation(GL_FUNC_ADD); + } + if (desaturation > 0 && gl.glslversion > 0) // no-shader excluded because no desaturated textures. + { + float gray = (r * 77 + g * 143 + b * 37) / 257; + + r = (r*(32 - desaturation) + gray*desaturation) / 32; + g = (g*(32 - desaturation) + gray*desaturation) / 32; + b = (b*(32 - desaturation) + gray*desaturation) / 32; + } + glColor3f(r, g, b); + return true; +} + + +//========================================================================== +// +// +// +//========================================================================== + +bool gl_SetupLightTexture() +{ + + if (GLRenderer->gllight == NULL) return false; + FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, true); + pat->Bind(CLAMP_XY, 0); + return true; +} diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index f266bcd370..cc5aa9d533 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -71,6 +71,7 @@ public: unsigned int mFBID; unsigned int mVAOID; + FTexture *gllight; FTexture *glpart2; FTexture *glpart; FTexture *mirrortexture; diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 5bbf26d929..40aae91657 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -372,6 +372,54 @@ inline void GLSprite::PutSprite(bool translucent) gl_drawinfo->drawlists[list].AddSprite(this); } +//========================================================================== +// +// +// +//========================================================================== +void GLSprite::SplitSprite(sector_t * frontsector, bool translucent) +{ + GLSprite copySprite; + double lightbottom; + unsigned int i; + bool put=false; + TArray & lightlist=frontsector->e->XFloor.lightlist; + + for(i=0;ifloorplane.ZatPoint(actor); + + if (lightbottom>8; + copySprite.Colormap.LightColor.g=(copySprite.Colormap.LightColor.g*ThingColor.g)>>8; + copySprite.Colormap.LightColor.b=(copySprite.Colormap.LightColor.b*ThingColor.b)>>8; + } + + z1=copySprite.z2=lightbottom; + vt=copySprite.vb=copySprite.vt+ + (lightbottom-copySprite.z1)*(copySprite.vb-copySprite.vt)/(z2-copySprite.z1); + copySprite.PutSprite(translucent); + put=true; + } + } +} + //========================================================================== // // @@ -722,7 +770,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, bool thruportal) RenderStyle.CheckFuzz(); if (RenderStyle.BlendOp == STYLEOP_Fuzz) { - if (gl_fuzztype != 0) + if (gl_fuzztype != 0 && gl.glslversion > 0) { // Todo: implement shader selection here RenderStyle = LegacyRenderStyles[STYLE_Translucent]; @@ -819,7 +867,18 @@ void GLSprite::Process(AActor* thing, sector_t * sector, bool thruportal) if (thing->Sector->e->XFloor.lightlist.Size() != 0 && gl_fixedcolormap == CM_DEFAULT && !fullbright && RenderStyle.BlendOp != STYLEOP_Shadow && RenderStyle.BlendOp != STYLEOP_RevSub) { - lightlist = &thing->Sector->e->XFloor.lightlist; + if (gl.glslversion < 1.3) // on old hardware we are rather limited... + { + lightlist = NULL; + if (!drawWithXYBillboard && !modelframe) + { + SplitSprite(thing->Sector, hw_styleflags != STYLEHW_Solid); + } + } + else + { + lightlist = &thing->Sector->e->XFloor.lightlist; + } } else { diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 3bc3b8a58f..e2334f7dee 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -350,6 +350,7 @@ public: particle_t * particle; TArray *lightlist; + void SplitSprite(sector_t * frontsector, bool translucent); void SetLowerParam(); void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight); diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 89b3714d10..702b9a61b1 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -31,10 +31,11 @@ ** */ +#include "gl/system/gl_load.h" + #include "i_common.h" #import -#import // Avoid collision between DObject class and Objective-C #define Class ObjectClass @@ -45,6 +46,7 @@ #include "hardware.h" #include "i_system.h" #include "m_argv.h" +#include "m_png.h" #include "r_renderer.h" #include "r_swrenderer.h" #include "st_console.h" @@ -56,6 +58,11 @@ #include "v_video.h" #include "version.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_interface.h" +#include "gl/utility/gl_clock.h" + #undef Class @@ -111,6 +118,41 @@ CUSTOM_CVAR(Bool, vid_autoswitch, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_ Printf("You must restart " GAMENAME " to apply graphics switching mode\n"); } +static int s_currentRenderer; + +CUSTOM_CVAR(Int, vid_renderer, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + // 0: Software renderer + // 1: OpenGL renderer + + if (self != s_currentRenderer) + { + switch (self) + { + case 0: + Printf("Switching to software renderer...\n"); + break; + case 1: + Printf("Switching to OpenGL renderer...\n"); + break; + default: + Printf("Unknown renderer (%d). Falling back to software renderer...\n", + static_cast(vid_renderer)); + self = 0; + break; + } + + Printf("You must restart " GAMENAME " to switch the renderer\n"); + } +} + +CUSTOM_CVAR(Int, gl_vid_multisample, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} + +EXTERN_CVAR(Bool, gl_smooth_rendered) + RenderBufferOptions rbOpts; @@ -187,7 +229,6 @@ namespace @end - // --------------------------------------------------------------------------- @@ -235,6 +276,9 @@ private: }; +// --------------------------------------------------------------------------- + + class CocoaFrameBuffer : public DFrameBuffer { public: @@ -286,6 +330,83 @@ private: // --------------------------------------------------------------------------- +class NonCopyable +{ +protected: + NonCopyable() { } + ~NonCopyable() { } + +private: + NonCopyable(const NonCopyable&); + const NonCopyable& operator=(const NonCopyable&); +}; + + +// --------------------------------------------------------------------------- + + +class RenderTarget : private NonCopyable +{ +public: + RenderTarget(const GLsizei width, const GLsizei height); + ~RenderTarget(); + + void Bind(); + void Unbind(); + + FHardwareTexture& GetColorTexture() + { + return m_texture; + } + +private: + GLuint m_ID; + GLuint m_oldID; + + FHardwareTexture m_texture; + + static GLuint GetBoundID(); + +}; // class RenderTarget + + +// --------------------------------------------------------------------------- + + +struct CapabilityChecker +{ + CapabilityChecker(); +}; + + +// --------------------------------------------------------------------------- + + +class CocoaOpenGLFrameBuffer : public OpenGLFrameBuffer, private CapabilityChecker, private NonCopyable +{ + typedef OpenGLFrameBuffer Super; + +public: + CocoaOpenGLFrameBuffer(void* hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen); + + virtual bool Lock(bool buffered); + virtual void Update(); + + virtual void GetScreenshotBuffer(const BYTE*& buffer, int& pitch, ESSType& color_type); + + virtual void SetSmoothPicture(bool smooth); + +private: + RenderTarget m_renderTarget; + + void DrawRenderTarget(); + +}; // class CocoaOpenGLFrameBuffer + + +// --------------------------------------------------------------------------- + + EXTERN_CVAR(Float, Gamma) CUSTOM_CVAR(Float, rgamma, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -542,7 +663,17 @@ DFrameBuffer* CocoaVideo::CreateFrameBuffer(const int width, const int height, c delete old; } - CocoaFrameBuffer* fb = new CocoaFrameBuffer(width, height, fullscreen); + DFrameBuffer* fb = NULL; + + if (1 == s_currentRenderer) + { + fb = new CocoaOpenGLFrameBuffer(NULL, width, height, 32, 60, fullscreen); + } + else + { + fb = new CocoaFrameBuffer(width, height, fullscreen); + } + fb->SetFlash(flashColor, flashAmount); SetMode(width, height, fullscreen, vid_hidpi); @@ -762,6 +893,9 @@ CocoaVideo* CocoaVideo::GetInstance() } +// --------------------------------------------------------------------------- + + CocoaFrameBuffer::CocoaFrameBuffer(int width, int height, bool fullscreen) : DFrameBuffer(width, height) , m_needPaletteUpdate(false) @@ -772,6 +906,14 @@ CocoaFrameBuffer::CocoaFrameBuffer(int width, int height, bool fullscreen) , m_pixelBuffer(new uint8_t[width * height * BYTES_PER_PIXEL]) , m_texture(0) { + static bool isOpenGLInitialized; + + if (!isOpenGLInitialized) + { + ogl_LoadFunctions(); + isOpenGLInitialized = true; + } + glEnable(GL_TEXTURE_RECTANGLE_ARB); glGenTextures(1, &m_texture); @@ -1011,6 +1153,423 @@ void CocoaFrameBuffer::Flip() } +// --------------------------------------------------------------------------- + + +static const uint32_t GAMMA_TABLE_ALPHA = 0xFF000000; + + +SDLGLFB::SDLGLFB(void*, const int width, const int height, int, int, const bool fullscreen) +: DFrameBuffer(width, height) +, m_lock(-1) +, m_isUpdatePending(false) +, m_supportsGamma(true) +, m_gammaTexture(GAMMA_TABLE_SIZE, 1, false, false, true, true) +{ +} + +SDLGLFB::SDLGLFB() +: m_gammaTexture(0, 0, false, false, false, false) +{ +} + +SDLGLFB::~SDLGLFB() +{ +} + + +bool SDLGLFB::Lock(bool buffered) +{ + m_lock++; + + Buffer = MemBuffer; + + return true; +} + +void SDLGLFB::Unlock() +{ + if (m_isUpdatePending && 1 == m_lock) + { + Update(); + } + else if (--m_lock <= 0) + { + m_lock = 0; + } +} + +bool SDLGLFB::IsLocked() +{ + return m_lock > 0; +} + + +bool SDLGLFB::IsFullscreen() +{ + return CocoaVideo::IsFullscreen(); +} + +void SDLGLFB::SetVSync(bool vsync) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 + const long value = vsync ? 1 : 0; +#else // 10.5 or newer + const GLint value = vsync ? 1 : 0; +#endif // prior to 10.5 + + [[NSOpenGLContext currentContext] setValues:&value + forParameter:NSOpenGLCPSwapInterval]; +} + + +void SDLGLFB::InitializeState() +{ +} + +bool SDLGLFB::CanUpdate() +{ + if (m_lock != 1) + { + if (m_lock > 0) + { + m_isUpdatePending = true; + --m_lock; + } + + return false; + } + + return true; +} + +void SDLGLFB::SwapBuffers() +{ + [[NSOpenGLContext currentContext] flushBuffer]; +} + +void SDLGLFB::SetGammaTable(WORD* table) +{ + const WORD* const red = &table[ 0]; + const WORD* const green = &table[256]; + const WORD* const blue = &table[512]; + + for (size_t i = 0; i < GAMMA_TABLE_SIZE; ++i) + { + // Convert 16 bits colors to 8 bits by dividing on 256 + + const uint32_t r = red[i] >> 8; + const uint32_t g = green[i] >> 8; + const uint32_t b = blue[i] >> 8; + + m_gammaTable[i] = GAMMA_TABLE_ALPHA + (b << 16) + (g << 8) + r; + } + + m_gammaTexture.CreateTexture( + reinterpret_cast(m_gammaTable), + GAMMA_TABLE_SIZE, 1, false, 1, 0); +} + + +// --------------------------------------------------------------------------- + + +void BoundTextureSetFilter(const GLenum target, const GLint filter) +{ + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); + + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +void BoundTextureDraw2D(const GLsizei width, const GLsizei height) +{ + const bool flipX = width < 0; + const bool flipY = height < 0; + + const float u0 = flipX ? 1.0f : 0.0f; + const float v0 = flipY ? 1.0f : 0.0f; + const float u1 = flipX ? 0.0f : 1.0f; + const float v1 = flipY ? 0.0f : 1.0f; + + const float x1 = 0.0f; + const float y1 = 0.0f; + const float x2 = abs(width ); + const float y2 = abs(height); + + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + + glBegin(GL_QUADS); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexCoord2f(u0, v1); + glVertex2f(x1, y1); + glTexCoord2f(u1, v1); + glVertex2f(x2, y1); + glTexCoord2f(u1, v0); + glVertex2f(x2, y2); + glTexCoord2f(u0, v0); + glVertex2f(x1, y2); + glEnd(); + + glEnable(GL_ALPHA_TEST); + glEnable(GL_BLEND); +} + +bool BoundTextureSaveAsPNG(const GLenum target, const char* const path) +{ + if (NULL == path) + { + return false; + } + + GLint width = 0; + GLint height = 0; + + glGetTexLevelParameteriv(target, 0, GL_TEXTURE_WIDTH, &width ); + glGetTexLevelParameteriv(target, 0, GL_TEXTURE_HEIGHT, &height); + + if (0 == width || 0 == height) + { + Printf("BoundTextureSaveAsPNG: invalid texture size %ix%i\n", width, height); + + return false; + } + + static const int BYTES_PER_PIXEL = 4; + + const int imageSize = width * height * BYTES_PER_PIXEL; + unsigned char* imageBuffer = static_cast(malloc(imageSize)); + + if (NULL == imageBuffer) + { + Printf("BoundTextureSaveAsPNG: cannot allocate %i bytes\n", imageSize); + + return false; + } + + glGetTexImage(target, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageBuffer); + + const int lineSize = width * BYTES_PER_PIXEL; + unsigned char lineBuffer[lineSize]; + + for (GLint line = 0; line < height / 2; ++line) + { + void* frontLinePtr = &imageBuffer[line * lineSize]; + void* backLinePtr = &imageBuffer[(height - line - 1) * lineSize]; + + memcpy( lineBuffer, frontLinePtr, lineSize); + memcpy(frontLinePtr, backLinePtr, lineSize); + memcpy( backLinePtr, lineBuffer, lineSize); + } + + FILE* file = fopen(path, "w"); + + if (NULL == file) + { + Printf("BoundTextureSaveAsPNG: cannot open file %s\n", path); + + free(imageBuffer); + + return false; + } + + const bool result = + M_CreatePNG(file, &imageBuffer[0], NULL, SS_BGRA, width, height, width * BYTES_PER_PIXEL) + && M_FinishPNG(file); + + fclose(file); + + free(imageBuffer); + + return result; +} + + +// --------------------------------------------------------------------------- + + +RenderTarget::RenderTarget(const GLsizei width, const GLsizei height) +: m_ID(0) +, m_oldID(0) +, m_texture(width, height, false, false, true, true) +{ + glGenFramebuffersEXT(1, &m_ID); + + Bind(); + m_texture.CreateTexture(NULL, width, height, false, 0, 0); + m_texture.BindToFrameBuffer(); + Unbind(); +} + +RenderTarget::~RenderTarget() +{ + glDeleteFramebuffersEXT(1, &m_ID); +} + + +void RenderTarget::Bind() +{ + const GLuint boundID = GetBoundID(); + + if (m_ID != boundID) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_ID); + m_oldID = boundID; + } +} + +void RenderTarget::Unbind() +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_oldID); + m_oldID = 0; +} + + +GLuint RenderTarget::GetBoundID() +{ + GLint result; + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &result); + + return static_cast(result); +} + + +// --------------------------------------------------------------------------- + + +CapabilityChecker::CapabilityChecker() +{ + if (!(gl.flags & RFL_FRAMEBUFFER)) + { + I_FatalError( + "The graphics hardware in your system does not support Frame Buffer Object (FBO).\n" + "It is required to run this version of " GAMENAME ".\n"); + } +} + + +// --------------------------------------------------------------------------- + + +CocoaOpenGLFrameBuffer::CocoaOpenGLFrameBuffer(void* hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) +: OpenGLFrameBuffer(hMonitor, width, height, bits, refreshHz, fullscreen) +, m_renderTarget(width, height) +{ + SetSmoothPicture(gl_smooth_rendered); + + // Setup uniform samplers for gamma correction shader + + m_gammaProgram.Load("GammaCorrection", "shaders/glsl/main.vp", + "shaders/glsl/gamma_correction.fp", NULL, ""); + + const GLuint program = m_gammaProgram.GetHandle(); + + glUseProgram(program); + glUniform1i(glGetUniformLocation(program, "backbuffer"), 0); + glUniform1i(glGetUniformLocation(program, "gammaTable"), 1); + glUseProgram(0); + + // Fill render target with black color + + m_renderTarget.Bind(); + glClear(GL_COLOR_BUFFER_BIT); + m_renderTarget.Unbind(); +} + + +bool CocoaOpenGLFrameBuffer::Lock(bool buffered) +{ + if (0 == m_lock) + { + m_renderTarget.Bind(); + } + + return Super::Lock(buffered); +} + +void CocoaOpenGLFrameBuffer::Update() +{ + if (!CanUpdate()) + { + GLRenderer->Flush(); + return; + } + + Begin2D(false); + + DrawRateStuff(); + GLRenderer->Flush(); + + DrawRenderTarget(); + + Swap(); + Unlock(); + + CheckBench(); +} + + +void CocoaOpenGLFrameBuffer::GetScreenshotBuffer(const BYTE*& buffer, int& pitch, ESSType& color_type) +{ + m_renderTarget.Bind(); + + Super::GetScreenshotBuffer(buffer, pitch, color_type); + + m_renderTarget.Unbind(); +} + + +void CocoaOpenGLFrameBuffer::DrawRenderTarget() +{ + m_renderTarget.Unbind(); + + m_renderTarget.GetColorTexture().Bind(0, 0); + m_gammaTexture.Bind(1, 0); + + if (rbOpts.dirty) + { + // TODO: Figure out why the following glClear() call is needed + // to avoid drawing of garbage in fullscreen mode when + // in-game's aspect ratio is different from display one + glClear(GL_COLOR_BUFFER_BIT); + + rbOpts.dirty = false; + } + + glViewport(rbOpts.shiftX, rbOpts.shiftY, rbOpts.width, rbOpts.height); + + m_gammaProgram.Bind(0.0f); + BoundTextureDraw2D(Width, Height); + + glViewport(0, 0, Width, Height); +} + + +void CocoaOpenGLFrameBuffer::SetSmoothPicture(const bool smooth) +{ + FHardwareTexture& texture = m_renderTarget.GetColorTexture(); + texture.Bind(0, 0); + BoundTextureSetFilter(GL_TEXTURE_2D, smooth ? GL_LINEAR : GL_NEAREST); +} + + +// --------------------------------------------------------------------------- + + +CUSTOM_CVAR(Bool, gl_smooth_rendered, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (NULL != screen) + { + screen->SetSmoothPicture(self); + } +} + + +// --------------------------------------------------------------------------- + + ADD_STAT(blit) { FString result; @@ -1022,6 +1581,9 @@ ADD_STAT(blit) IVideo* Video; +// --------------------------------------------------------------------------- + + void I_ShutdownGraphics() { if (NULL != screen) @@ -1042,7 +1604,7 @@ void I_InitGraphics() val.Bool = !!Args->CheckParm("-devparm"); ticker.SetGenericRepDefault(val, CVAR_Bool); - Video = new CocoaVideo(0); + Video = new CocoaVideo(gl_vid_multisample); atterm(I_ShutdownGraphics); } @@ -1055,9 +1617,15 @@ static void I_DeleteRenderer() void I_CreateRenderer() { + s_currentRenderer = vid_renderer; + if (NULL == Renderer) { - Renderer = new FSoftwareRenderer; + extern FRenderer* gl_CreateInterface(); + + Renderer = 1 == s_currentRenderer + ? gl_CreateInterface() + : new FSoftwareRenderer; atterm(I_DeleteRenderer); } } @@ -1129,6 +1697,9 @@ void I_ClosestResolution(int *width, int *height, int bits) } +// --------------------------------------------------------------------------- + + EXTERN_CVAR(Int, vid_maxfps); EXTERN_CVAR(Bool, cl_capfps); @@ -1167,6 +1738,9 @@ CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } +// --------------------------------------------------------------------------- + + CCMD(vid_listmodes) { if (Video == NULL) diff --git a/src/v_video.h b/src/v_video.h index 693bfa687c..0f3fb82244 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -416,6 +416,8 @@ public: virtual bool Is8BitMode() = 0; #endif + virtual void SetSmoothPicture(bool smooth) {} + protected: void DrawRateStuff (); void CopyFromBuff (BYTE *src, int srcPitch, int width, int height, BYTE *dest); diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index 9ce3c88373..76099babb5 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -811,7 +811,7 @@ bool Win32GLVideo::InitHardware (HWND Window, int multisample) if (m_hRC == NULL && prof == WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) { - I_Error ("R_OPENGL: Unable to create an OpenGL 3.x render context.\n"); + I_Error ("R_OPENGL: Unable to create an OpenGL render context.\n"); return false; } @@ -832,7 +832,7 @@ bool Win32GLVideo::InitHardware (HWND Window, int multisample) } } // We get here if the driver doesn't support the modern context creation API which always means an old driver. - I_Error ("R_OPENGL: Unable to create an OpenGL 3.x render context.\n"); + I_Error ("R_OPENGL: Unable to create an OpenGL render context.\n"); return false; }