diff --git a/source/common/2d/v_2ddrawer.cpp b/source/common/2d/v_2ddrawer.cpp index a3b3bd12d..157101160 100644 --- a/source/common/2d/v_2ddrawer.cpp +++ b/source/common/2d/v_2ddrawer.cpp @@ -34,6 +34,8 @@ #include #include "templates.h" +#include "v_2ddrawer.h" +#include "vectors.h" #include "vm.h" #include "c_cvars.h" #include "v_draw.h" @@ -107,7 +109,6 @@ IMPLEMENT_CLASS(DShape2D, false, false) static void Shape2D_SetTransform(DShape2D* self, DShape2DTransform *transform) { self->transform = transform->transform; - self->dirty = true; } DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, SetTransform, Shape2D_SetTransform) @@ -120,13 +121,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, SetTransform, Shape2D_SetTransform) static void Shape2D_Clear(DShape2D* self, int which) { - if (which & C_Verts) - { - self->mVertices.Clear(); - self->dirty = true; - } + if (which & C_Verts) self->mVertices.Clear(); if (which & C_Coords) self->mCoords.Clear(); if (which & C_Indices) self->mIndices.Clear(); + self->needsVertexUpload = true; } DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear) @@ -140,7 +138,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear) static void Shape2D_PushVertex(DShape2D* self, double x, double y) { self->mVertices.Push(DVector2(x, y)); - self->dirty = true; + self->needsVertexUpload = true; } DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex) @@ -155,6 +153,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex) static void Shape2D_PushCoord(DShape2D* self, double u, double v) { self->mCoords.Push(DVector2(u, v)); + self->needsVertexUpload = true; } DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord) @@ -171,6 +170,7 @@ static void Shape2D_PushTriangle(DShape2D* self, int a, int b, int c) self->mIndices.Push(a); self->mIndices.Push(b); self->mIndices.Push(c); + self->needsVertexUpload = true; } DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle) @@ -556,26 +556,33 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms) if (!img->isHardwareCanvas() && parms.TranslationId != -1) dg.mTranslationId = parms.TranslationId; - if (shape->dirty) { - if (shape->mVertices.Size() != shape->mTransformedVertices.Size()) - shape->mTransformedVertices.Resize(shape->mVertices.Size()); - for (int i = 0; i < dg.mVertCount; i++) { - shape->mTransformedVertices[i] = (shape->transform * DVector3(shape->mVertices[i], 1.0)).XY(); - } - shape->dirty = false; - } - auto osave = offset; if (parms.nooffset) offset = { 0,0 }; - double minx = 16383, miny = 16383, maxx = -16384, maxy = -16384; - for ( int i=0; ineedsVertexUpload) { - if ( shape->mTransformedVertices[i].X < minx ) minx = shape->mTransformedVertices[i].X; - if ( shape->mTransformedVertices[i].Y < miny ) miny = shape->mTransformedVertices[i].Y; - if ( shape->mTransformedVertices[i].X > maxx ) maxx = shape->mTransformedVertices[i].X; - if ( shape->mTransformedVertices[i].Y > maxy ) maxy = shape->mTransformedVertices[i].Y; + shape->minx = 16383; + shape->miny = 16383; + shape->maxx = -16384; + shape->maxy = -16384; + for ( int i=0; imVertices[i].X < shape->minx ) shape->minx = shape->mVertices[i].X; + if ( shape->mVertices[i].Y < shape->miny ) shape->miny = shape->mVertices[i].Y; + if ( shape->mVertices[i].X > shape->maxx ) shape->maxx = shape->mVertices[i].X; + if ( shape->mVertices[i].Y > shape->maxy ) shape->maxy = shape->mVertices[i].Y; + } } + auto tCorners = { + (shape->transform * DVector3(shape->minx, shape->miny, 1.0)).XY(), + (shape->transform * DVector3(shape->minx, shape->maxy, 1.0)).XY(), + (shape->transform * DVector3(shape->maxx, shape->miny, 1.0)).XY(), + (shape->transform * DVector3(shape->maxx, shape->maxy, 1.0)).XY() + }; + double minx = std::min_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.X < d1.X; })->X; + double maxx = std::max_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.X < d1.X; })->X; + double miny = std::min_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.Y < d1.Y; })->Y; + double maxy = std::max_element(tCorners.begin(), tCorners.end(), [] (auto d0, auto d1) { return d0.Y < d1.Y; })->Y; if (minx < (double)parms.lclip || miny < (double)parms.uclip || maxx >(double)parms.rclip || maxy >(double)parms.dclip) { dg.mScissor[0] = parms.lclip + int(offset.X); @@ -587,24 +594,39 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms) else memset(dg.mScissor, 0, sizeof(dg.mScissor)); - dg.mVertIndex = (int)mVertices.Reserve(dg.mVertCount); - TwoDVertex *ptr = &mVertices[dg.mVertIndex]; - for ( int i=0; imTransformedVertices[i].X, shape->mTransformedVertices[i].Y, 0, shape->mCoords[i].X, shape->mCoords[i].Y, vertexcolor); - dg.mIndexIndex = mIndices.Size(); - dg.mIndexCount += shape->mIndices.Size(); - for ( int i=0; imIndices.Size()); i+=3 ) + dg.useTransform = true; + dg.transform = shape->transform; + dg.transform.Cells[0][2] += offset.X; + dg.transform.Cells[1][2] += offset.Y; + dg.shape2D = shape; + dg.shape2DIndexCount = shape->mIndices.Size(); + if (shape->needsVertexUpload) { - // [MK] bail out if any indices are out of bounds - for ( int j=0; j<3; j++ ) + shape->bufIndex += 1; + + shape->buffers.Reserve(1); + auto buf = &shape->buffers[shape->bufIndex]; + + auto verts = TArray(dg.mVertCount, true); + for ( int i=0; imVertices[i].X, shape->mVertices[i].Y, 0, shape->mCoords[i].X, shape->mCoords[i].Y, vertexcolor); + + for ( int i=0; imIndices.Size()); i+=3 ) { - if ( shape->mIndices[i+j] < 0 ) - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u is negative: %i\n", i/3, j, shape->mIndices[i+j]); - if ( shape->mIndices[i+j] >= dg.mVertCount ) - ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u: %u, max: %u\n", i/3, j, shape->mIndices[i+j], dg.mVertCount-1); + // [MK] bail out if any indices are out of bounds + for ( int j=0; j<3; j++ ) + { + if ( shape->mIndices[i+j] < 0 ) + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u is negative: %i\n", i/3, j, shape->mIndices[i+j]); + if ( shape->mIndices[i+j] >= dg.mVertCount ) + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Triangle %u index %u: %u, max: %u\n", i/3, j, shape->mIndices[i+j], dg.mVertCount-1); + } } - AddIndices(dg.mVertIndex, 3, shape->mIndices[i], shape->mIndices[i+1], shape->mIndices[i+2]); + + buf->UploadData(&verts[0], dg.mVertCount, &shape->mIndices[0], shape->mIndices.Size()); + shape->needsVertexUpload = false; } + dg.shape2DBufIndex = shape->bufIndex; AddCommand(&dg); offset = osave; } @@ -1014,3 +1036,16 @@ void F2DDrawer::Clear() } screenFade = 1.f; } + +F2DVertexBuffer::F2DVertexBuffer() +{ + mVertexBuffer = screen->CreateVertexBuffer(); + mIndexBuffer = screen->CreateIndexBuffer(); + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(F2DDrawer::TwoDVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(F2DDrawer::TwoDVertex, u) }, + { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(F2DDrawer::TwoDVertex, color0) } + }; + mVertexBuffer->SetFormat(1, 3, sizeof(F2DDrawer::TwoDVertex), format); +} diff --git a/source/common/2d/v_2ddrawer.h b/source/common/2d/v_2ddrawer.h index 2e02e9160..ce94c4233 100644 --- a/source/common/2d/v_2ddrawer.h +++ b/source/common/2d/v_2ddrawer.h @@ -1,6 +1,7 @@ #ifndef __2DDRAWER_H #define __2DDRAWER_H +#include "buffers.h" #include "tarray.h" #include "vectors.h" #include "textures.h" @@ -31,6 +32,8 @@ enum EClearWhich C_Indices = 4, }; +class F2DVertexBuffer; + class DShape2D : public DObject { @@ -45,12 +48,16 @@ public: TArray mVertices; TArray mCoords; + double minx = 0.0; + double maxx = 0.0; + double miny = 0.0; + double maxy = 0.0; + DMatrix3x3 transform; - // dirty stores whether we need to re-apply the transformation - // otherwise it uses the cached values - bool dirty = true; - TArray mTransformedVertices; + TArray buffers; + bool needsVertexUpload = true; + int bufIndex = -1; }; struct F2DPolygons @@ -67,6 +74,7 @@ struct F2DPolygons }; + class F2DDrawer { public: @@ -136,6 +144,13 @@ public: uint8_t mLightLevel; uint8_t mFlags; + bool useTransform; + DMatrix3x3 transform; + + DShape2D* shape2D; + int shape2DBufIndex; + int shape2DIndexCount; + RenderCommand() { memset(this, 0, sizeof(*this)); @@ -144,6 +159,7 @@ public: // If these fields match, two draw commands can be batched. bool isCompatible(const RenderCommand &other) const { + if (shape2D != nullptr || other.shape2D != nullptr) return false; return mTexture == other.mTexture && mType == other.mType && mTranslationId == other.mTranslationId && @@ -155,8 +171,16 @@ public: mDrawMode == other.mDrawMode && mFlags == other.mFlags && mLightLevel == other.mLightLevel && - mColor1.d == other.mColor1.d; - + mColor1.d == other.mColor1.d && + useTransform == other.useTransform && + ( + !useTransform || + ( + transform[0] == other.transform[0] && + transform[1] == other.transform[1] && + transform[2] == other.transform[2] + ) + ); } }; @@ -238,5 +262,39 @@ public: bool mIsFirstPass = true; }; +//=========================================================================== +// +// Vertex buffer for 2D drawer +// +//=========================================================================== + +class F2DVertexBuffer +{ + IVertexBuffer *mVertexBuffer; + IIndexBuffer *mIndexBuffer; + + +public: + + F2DVertexBuffer(); + + ~F2DVertexBuffer() + { + delete mIndexBuffer; + delete mVertexBuffer; + } + + void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount) + { + mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, false); + mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, false); + } + + std::pair GetBufferObjects() const + { + return std::make_pair(mVertexBuffer, mIndexBuffer); + } +}; + #endif diff --git a/source/common/audio/sound/oalsound.cpp b/source/common/audio/sound/oalsound.cpp index d97c9d5a6..252688572 100644 --- a/source/common/audio/sound/oalsound.cpp +++ b/source/common/audio/sound/oalsound.cpp @@ -1304,7 +1304,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + alSourcef(source, AL_MAX_DISTANCE, std::numeric_limits::max()); alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); manualRolloff = false; } @@ -1324,77 +1324,49 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener // when AL_EXT_source_distance_model is not supported, we have to play // around a bit to get appropriate distance attenation. What we do is // calculate the attenuation that should be applied, then given an - // Inverse Distance rolloff model with OpenAL, reverse the calculation - // to get the distance needed for that much attenuation. The Inverse - // Distance calculation is: + // Inverse Distance rolloff model with OpenAL, calculate the reference + // distance that will achieve that much attenuation with the current + // distance. The Inverse Distance calculation is: // // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) // - // Thus, the reverse is: + // Simplifying for RolloffFactor=1, it can be broken down by: // - // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist + // Gain = MinDist / (MinDist + (Distance - MinDist)) + // Gain = MinDist / Distance + // Gain * Distance = MinDist // - // This can be simplified by using a MinDist and RolloffFactor of 1, - // which makes it: - // - // Distance = 1.0f/Gain; - // - // The source position is then set that many units away from the - // listener position, and OpenAL takes care of the rest. + // The source's reference distance is then set according to the desired + // gain and effective distance from the listener, and OpenAL takes care + // of the rest. if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 100000.f); + + float dist = sqrtf(dist_sqr); + float gain = GetRolloff(rolloff, dist * distscale); + // Don't let the ref distance go to 0, or else distance attenuation is + // lost with the inverse distance model. + alSourcef(source, AL_REFERENCE_DISTANCE, std::max(gain*dist, 0.0004f)); + alSourcef(source, AL_MAX_DISTANCE, std::numeric_limits::max()); alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + } - if(AL.EXT_SOURCE_RADIUS) - { - /* Since the OpenAL distance is decoupled from the sound's distance, get the OpenAL - * distance that corresponds to the area radius. */ - float gain = GetRolloff(rolloff, AREA_SOUND_RADIUS); - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? - // Clamp in case the max distance is <= the area radius - ((gain > 0.00001f) ? 1.f/gain : 100000.f) : 0.f - ); - } - - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale); - FVector3 dir = pos - listener->position; - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); - dir += listener->position; - - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } + if(dist_sqr < (0.0004f*0.0004f)) + { + // Head relative + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); } else { - if(AL.EXT_SOURCE_RADIUS) - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); - - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - } + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); } alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); alSourcef(source, AL_DOPPLER_FACTOR, 0.f); + if(AL.EXT_SOURCE_RADIUS) + alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); @@ -1633,8 +1605,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh if(chan == NULL || chan->SysChannel == NULL) return; - FVector3 dir = pos - listener->position; - float dist_sqr = (float)dir.LengthSquared(); + float dist_sqr = (float)(pos - listener->position).LengthSquared(); chan->DistanceSqr = dist_sqr; alDeferUpdatesSOFT(); @@ -1649,13 +1620,13 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh { if(chan->ManualRolloff) { - float gain = GetRolloff(&chan->Rolloff, sqrtf(dist_sqr)*chan->DistanceScale); - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); + float dist = sqrtf(dist_sqr); + float gain = GetRolloff(&chan->Rolloff, dist * chan->DistanceScale); + alSourcef(source, AL_REFERENCE_DISTANCE, std::max(gain*dist, 0.0004f)); } - dir += listener->position; alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); } alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); getALError(); diff --git a/source/common/engine/namedef.h b/source/common/engine/namedef.h index 6433972f5..41572fade 100644 --- a/source/common/engine/namedef.h +++ b/source/common/engine/namedef.h @@ -27,6 +27,10 @@ xx(Spray) xx(Ghost) xx(Reflective) +// Iron Feet types +//xx(Normal) // defined below +xx(Full) + // Invisibility types xx(Additive) xx(Cumulative) diff --git a/source/common/menu/menu.cpp b/source/common/menu/menu.cpp index 6191f1b60..bf773214d 100644 --- a/source/common/menu/menu.cpp +++ b/source/common/menu/menu.cpp @@ -637,7 +637,8 @@ bool M_Responder (event_t *ev) { // We do our own key repeat handling but still want to eat the // OS's repeated keys. - return true; + if (CurrentMenu->TranslateKeyboardEvents()) return true; + else return CurrentMenu->CallResponder(ev); } else if (ev->subtype == EV_GUI_BackButtonDown || ev->subtype == EV_GUI_BackButtonUp) { diff --git a/source/common/platform/posix/sdl/i_main.cpp b/source/common/platform/posix/sdl/i_main.cpp index a984721fc..b52561fdf 100644 --- a/source/common/platform/posix/sdl/i_main.cpp +++ b/source/common/platform/posix/sdl/i_main.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include "engineerrors.h" #include "m_argv.h" @@ -49,6 +51,7 @@ #include "engineerrors.h" #include "i_system.h" #include "i_interface.h" +#include "printf.h" // MACROS ------------------------------------------------------------------ @@ -93,7 +96,50 @@ static int GetCrashInfo (char *buffer, char *end) void I_DetectOS() { - // The POSIX version never implemented this. + FString operatingSystem; + + const char *paths[] = {"/etc/os-release", "/usr/lib/os-release"}; + + for (const char *path : paths) + { + struct stat dummy; + + if (stat(path, &dummy) != 0) + continue; + + char cmdline[256]; + snprintf(cmdline, sizeof cmdline, ". %s && echo ${PRETTY_NAME}", path); + + FILE *proc = popen(cmdline, "r"); + + if (proc == nullptr) + continue; + + char distribution[256] = {}; + fread(distribution, sizeof distribution - 1, 1, proc); + + const size_t length = strlen(distribution); + + if (length > 1) + { + distribution[length - 1] = '\0'; + operatingSystem = distribution; + } + + pclose(proc); + break; + } + + utsname unameInfo; + + if (uname(&unameInfo) == 0) + { + const char* const separator = operatingSystem.Len() > 0 ? ", " : ""; + operatingSystem.AppendFormat("%s%s %s on %s", separator, unameInfo.sysname, unameInfo.release, unameInfo.machine); + } + + if (operatingSystem.Len() > 0) + Printf("OS: %s\n", operatingSystem.GetChars()); } void I_StartupJoysticks(); diff --git a/source/common/rendering/gl/gl_renderer.h b/source/common/rendering/gl/gl_renderer.h index c75927c0f..3a4c55a70 100644 --- a/source/common/rendering/gl/gl_renderer.h +++ b/source/common/rendering/gl/gl_renderer.h @@ -90,7 +90,7 @@ private: bool QuadStereoCheckInitialRenderContextState(); void PresentAnaglyph(bool r, bool g, bool b); - void PresentSideBySide(); + void PresentSideBySide(int); void PresentTopBottom(); void prepareInterleavedPresent(FPresentShaderBase& shader); void PresentColumnInterleaved(); diff --git a/source/common/rendering/gl/gl_stereo3d.cpp b/source/common/rendering/gl/gl_stereo3d.cpp index 032fb71ad..35bcf2fa0 100644 --- a/source/common/rendering/gl/gl_stereo3d.cpp +++ b/source/common/rendering/gl/gl_stereo3d.cpp @@ -76,25 +76,59 @@ void FGLRenderer::PresentAnaglyph(bool r, bool g, bool b) // //========================================================================== -void FGLRenderer::PresentSideBySide() +void FGLRenderer::PresentSideBySide(int vrmode) { - mBuffers->BindOutputFB(); - ClearBorders(); + if (vrmode == VR_SIDEBYSIDEFULL || vrmode == VR_SIDEBYSIDESQUISHED) + { + mBuffers->BindOutputFB(); + ClearBorders(); - // Compute screen regions to use for left and right eye views - int leftWidth = screen->mOutputLetterbox.width / 2; - int rightWidth = screen->mOutputLetterbox.width - leftWidth; - IntRect leftHalfScreen = screen->mOutputLetterbox; - leftHalfScreen.width = leftWidth; - IntRect rightHalfScreen = screen->mOutputLetterbox; - rightHalfScreen.width = rightWidth; - rightHalfScreen.left += leftWidth; + // Compute screen regions to use for left and right eye views + int leftWidth = screen->mOutputLetterbox.width / 2; + int rightWidth = screen->mOutputLetterbox.width - leftWidth; + IntRect leftHalfScreen = screen->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + IntRect rightHalfScreen = screen->mOutputLetterbox; + rightHalfScreen.width = rightWidth; + rightHalfScreen.left += leftWidth; - mBuffers->BindEyeTexture(0, 0); - DrawPresentTexture(leftHalfScreen, true); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(leftHalfScreen, true); - mBuffers->BindEyeTexture(1, 0); - DrawPresentTexture(rightHalfScreen, true); + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(rightHalfScreen, true); + } + else if (vrmode == VR_SIDEBYSIDELETTERBOX) + { + mBuffers->BindOutputFB(); + screen->mOutputLetterbox.top = screen->mOutputLetterbox.height; + + ClearBorders(); + screen->mOutputLetterbox.top = 0; //reset so screenshots can be taken + + // Compute screen regions to use for left and right eye views + int leftWidth = screen->mOutputLetterbox.width / 2; + int rightWidth = screen->mOutputLetterbox.width - leftWidth; + //cut letterbox height in half + int height = screen->mOutputLetterbox.height / 2; + int top = height * .5; + IntRect leftHalfScreen = screen->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + leftHalfScreen.height = height; + leftHalfScreen.top = top; + IntRect rightHalfScreen = screen->mOutputLetterbox; + rightHalfScreen.width = rightWidth; + rightHalfScreen.left += leftWidth; + //give it those cinematic black bars on top and bottom + rightHalfScreen.height = height; + rightHalfScreen.top = top; + + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(leftHalfScreen, true); + + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(rightHalfScreen, true); + } } @@ -360,7 +394,8 @@ void FGLRenderer::PresentStereo() case VR_SIDEBYSIDEFULL: case VR_SIDEBYSIDESQUISHED: - PresentSideBySide(); + case VR_SIDEBYSIDELETTERBOX: + PresentSideBySide(vr_mode); break; case VR_TOPBOTTOM: diff --git a/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp b/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp index bde88b5a7..caf11f947 100644 --- a/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp +++ b/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp @@ -73,6 +73,7 @@ const VRMode *VRMode::GetVRMode(bool toscreen) case VR_REDCYAN: case VR_QUADSTEREO: case VR_AMBERBLUE: + case VR_SIDEBYSIDELETTERBOX: return &vrmi_stereo; case VR_SIDEBYSIDESQUISHED: diff --git a/source/common/rendering/hwrenderer/data/hw_vrmodes.h b/source/common/rendering/hwrenderer/data/hw_vrmodes.h index a80ecaf57..26c9fd211 100644 --- a/source/common/rendering/hwrenderer/data/hw_vrmodes.h +++ b/source/common/rendering/hwrenderer/data/hw_vrmodes.h @@ -14,6 +14,7 @@ enum VR_LEFTEYEVIEW = 5, VR_RIGHTEYEVIEW = 6, VR_QUADSTEREO = 7, + VR_SIDEBYSIDELETTERBOX = 8, VR_AMBERBLUE = 9, VR_TOPBOTTOM = 11, VR_ROWINTERLEAVED = 12, diff --git a/source/common/rendering/hwrenderer/hw_draw2d.cpp b/source/common/rendering/hwrenderer/hw_draw2d.cpp index be1c6831e..21b7f5afc 100644 --- a/source/common/rendering/hwrenderer/hw_draw2d.cpp +++ b/source/common/rendering/hwrenderer/hw_draw2d.cpp @@ -43,51 +43,6 @@ #include "r_videoscale.h" #include "v_draw.h" - -//=========================================================================== -// -// Vertex buffer for 2D drawer -// -//=========================================================================== - -class F2DVertexBuffer -{ - IVertexBuffer *mVertexBuffer; - IIndexBuffer *mIndexBuffer; - - -public: - - F2DVertexBuffer() - { - mVertexBuffer = screen->CreateVertexBuffer(); - mIndexBuffer = screen->CreateIndexBuffer(); - - static const FVertexBufferAttribute format[] = { - { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(F2DDrawer::TwoDVertex, x) }, - { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(F2DDrawer::TwoDVertex, u) }, - { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(F2DDrawer::TwoDVertex, color0) } - }; - mVertexBuffer->SetFormat(1, 3, sizeof(F2DDrawer::TwoDVertex), format); - } - ~F2DVertexBuffer() - { - delete mIndexBuffer; - delete mVertexBuffer; - } - - void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount) - { - mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, false); - mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, false); - } - - std::pair GetBufferObjects() const - { - return std::make_pair(mVertexBuffer, mIndexBuffer); - } -}; - //=========================================================================== // // Draws the 2D stuff. This is the version for OpenGL 3 and later. @@ -174,6 +129,29 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state) state.AlphaFunc(Alpha_GEqual, 0.f); + if (cmd.useTransform) + { + FLOATTYPE m[16] = { + 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + }; + for (size_t i = 0; i < 2; i++) + { + for (size_t j = 0; j < 2; j++) + { + m[4 * j + i] = (FLOATTYPE) cmd.transform.Cells[i][j]; + } + } + for (size_t i = 0; i < 2; i++) + { + m[4 * 3 + i] = (FLOATTYPE) cmd.transform.Cells[i][2]; + } + state.mModelMatrix.loadMatrix(m); + state.EnableModelMatrix(true); + } + if (cmd.mTexture != nullptr && cmd.mTexture->isValid()) { auto flags = cmd.mTexture->GetUseType() >= ETextureType::Special? UF_None : cmd.mTexture->GetUseType() == ETextureType::FontChar? UF_Font : UF_Texture; @@ -200,26 +178,42 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state) state.EnableTexture(false); } - switch (cmd.mType) + if (cmd.shape2D != nullptr) { - default: - case F2DDrawer::DrawTypeTriangles: - state.DrawIndexed(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount); - break; + state.SetVertexBuffer(&cmd.shape2D->buffers[cmd.shape2DBufIndex]); + state.DrawIndexed(DT_Triangles, 0, cmd.shape2DIndexCount); + state.SetVertexBuffer(&vb); + if (cmd.shape2D->bufIndex > 0 && cmd.shape2DBufIndex == cmd.shape2D->bufIndex) + { + cmd.shape2D->needsVertexUpload = true; + cmd.shape2D->buffers.Clear(); + cmd.shape2D->bufIndex = -1; + } + } + else + { + switch (cmd.mType) + { + default: + case F2DDrawer::DrawTypeTriangles: + state.DrawIndexed(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount); + break; - case F2DDrawer::DrawTypeLines: - state.Draw(DT_Lines, cmd.mVertIndex, cmd.mVertCount); - break; + case F2DDrawer::DrawTypeLines: + state.Draw(DT_Lines, cmd.mVertIndex, cmd.mVertCount); + break; - case F2DDrawer::DrawTypePoints: - state.Draw(DT_Points, cmd.mVertIndex, cmd.mVertCount); - break; + case F2DDrawer::DrawTypePoints: + state.Draw(DT_Points, cmd.mVertIndex, cmd.mVertCount); + break; + } } state.SetObjectColor(0xffffffff); state.SetObjectColor2(0); state.SetAddColor(0); state.EnableTextureMatrix(false); + state.EnableModelMatrix(false); state.SetEffect(EFF_NONE); } diff --git a/source/common/rendering/vulkan/system/vk_builders.h b/source/common/rendering/vulkan/system/vk_builders.h index 7eca4c6a1..5f0e3c0fc 100644 --- a/source/common/rendering/vulkan/system/vk_builders.h +++ b/source/common/rendering/vulkan/system/vk_builders.h @@ -144,7 +144,7 @@ public: private: VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - FixedSizeVector bindings; + TArray bindings; }; class DescriptorPoolBuilder @@ -636,10 +636,10 @@ inline void DescriptorSetLayoutBuilder::addBinding(int index, VkDescriptorType t binding.descriptorCount = arrayCount; binding.stageFlags = stageFlags; binding.pImmutableSamplers = nullptr; - bindings.push_back(binding); + bindings.Push(binding); - layoutInfo.bindingCount = (uint32_t)bindings.size(); - layoutInfo.pBindings = bindings.data(); + layoutInfo.bindingCount = (uint32_t)bindings.Size(); + layoutInfo.pBindings = &bindings[0]; } inline std::unique_ptr DescriptorSetLayoutBuilder::create(VulkanDevice *device) diff --git a/source/common/scripting/backend/codegen.cpp b/source/common/scripting/backend/codegen.cpp index 11db32019..f28da4cb0 100644 --- a/source/common/scripting/backend/codegen.cpp +++ b/source/common/scripting/backend/codegen.cpp @@ -9014,7 +9014,6 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) { - assert(ValueType == ArgList[0]->ValueType); ExpEmit from = ArgList[0]->Emit(build); ExpEmit to; assert(from.Konst == 0); diff --git a/source/common/scripting/core/types.cpp b/source/common/scripting/core/types.cpp index 3b7057acb..260aff106 100644 --- a/source/common/scripting/core/types.cpp +++ b/source/common/scripting/core/types.cpp @@ -451,7 +451,7 @@ PInt::PInt(unsigned int size, bool unsign, bool compatible) else { Symbols.AddSymbol(Create(NAME_Min, this, 0u)); - Symbols.AddSymbol(Create(NAME_Max, this, (1u << ((8 * size) - 1)))); + Symbols.AddSymbol(Create(NAME_Max, this, (uint32_t) (((uint64_t) 1u << (size * 8)) - 1uL))); } SetOps(); } diff --git a/source/common/scripting/vm/vmexec.h b/source/common/scripting/vm/vmexec.h index 76e7596e7..dc32d86c0 100644 --- a/source/common/scripting/vm/vmexec.h +++ b/source/common/scripting/vm/vmexec.h @@ -40,7 +40,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) { #if COMPGOTO - static const void * const ops[256] = + static void * const ops[256] = { #define xx(op,sym,mode,alt,kreg,ktype) &&op, #include "vmops.h" diff --git a/source/common/utility/cmdlib.cpp b/source/common/utility/cmdlib.cpp index dac58292a..8786a1c70 100644 --- a/source/common/utility/cmdlib.cpp +++ b/source/common/utility/cmdlib.cpp @@ -590,7 +590,7 @@ int strbin (char *str) while ( (c = *p++) ) { if (c != '\\') { *str++ = c; - } else { + } else if (*p != 0) { switch (*p) { case 'a': *str++ = '\a'; @@ -693,7 +693,7 @@ FString strbin1 (const char *start) while ( (c = *p++) ) { if (c != '\\') { result << c; - } else { + } else if (*p) { switch (*p) { case 'a': result << '\a';