mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
- added back sprite splitting for low end, plus some dynamic light code.
This commit is contained in:
parent
89f36fb963
commit
6e1b21d513
7 changed files with 737 additions and 9 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
unsigned int mFBID;
|
||||
unsigned int mVAOID;
|
||||
|
||||
FTexture *gllight;
|
||||
FTexture *glpart2;
|
||||
FTexture *glpart;
|
||||
FTexture *mirrortexture;
|
||||
|
|
|
@ -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_t> & lightlist=frontsector->e->XFloor.lightlist;
|
||||
|
||||
for(i=0;i<lightlist.Size();i++)
|
||||
{
|
||||
// Particles don't go through here so we can safely assume that actor is not NULL
|
||||
if (i<lightlist.Size()-1) lightbottom=lightlist[i+1].plane.ZatPoint(actor);
|
||||
else lightbottom=frontsector->floorplane.ZatPoint(actor);
|
||||
|
||||
if (lightbottom<z2) lightbottom=z2;
|
||||
|
||||
if (lightbottom<z1)
|
||||
{
|
||||
copySprite=*this;
|
||||
copySprite.lightlevel = gl_ClampLight(*lightlist[i].p_lightlevel);
|
||||
copySprite.Colormap.CopyLightColor(lightlist[i].extra_colormap);
|
||||
|
||||
if (glset.nocoloredspritelighting)
|
||||
{
|
||||
copySprite.Colormap.Decolorize();
|
||||
}
|
||||
|
||||
if (!gl_isWhite(ThingColor))
|
||||
{
|
||||
copySprite.Colormap.LightColor.r=(copySprite.Colormap.LightColor.r*ThingColor.r)>>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];
|
||||
|
@ -818,9 +866,20 @@ void GLSprite::Process(AActor* thing, sector_t * sector, bool thruportal)
|
|||
// 5. anything with render style reverse subtract (light effect is not what would be desired here)
|
||||
if (thing->Sector->e->XFloor.lightlist.Size() != 0 && gl_fixedcolormap == CM_DEFAULT && !fullbright &&
|
||||
RenderStyle.BlendOp != STYLEOP_Shadow && RenderStyle.BlendOp != STYLEOP_RevSub)
|
||||
{
|
||||
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
|
||||
{
|
||||
lightlist = NULL;
|
||||
|
|
|
@ -350,6 +350,7 @@ public:
|
|||
particle_t * particle;
|
||||
TArray<lightlist_t> *lightlist;
|
||||
|
||||
void SplitSprite(sector_t * frontsector, bool translucent);
|
||||
void SetLowerParam();
|
||||
void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight);
|
||||
|
||||
|
|
|
@ -31,10 +31,11 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include "gl/system/gl_load.h"
|
||||
|
||||
#include "i_common.h"
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <OpenGL/gl.h>
|
||||
|
||||
// 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<int>(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<unsigned char*>(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<unsigned char*>(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<GLuint>(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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue