From 0667f2ec553a08a4f3edc6d85c55e58adb92494a Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 26 Nov 2017 09:59:28 +0200 Subject: [PATCH 01/39] Fixed string format issues reported by GCC/Clang d_net.cpp:2874:25: warning: format specifies type 'int' but the argument has type 'unsigned long long' [-Wformat] gl/utility/gl_clock.cpp:240:38: warning: format specifies type 'int' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat] v_video.cpp:883:71: warning: format specifies type 'unsigned int' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat] v_video.cpp:883:80: warning: format specifies type 'unsigned int' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat] --- src/d_net.cpp | 3 ++- src/gl/utility/gl_clock.cpp | 4 +++- src/v_video.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index e8711bda5..57dbb93b7 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -26,6 +26,7 @@ //----------------------------------------------------------------------------- #include +#include #include "version.h" #include "menu/menu.h" @@ -2871,7 +2872,7 @@ CCMD (pings) int i; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) - Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i], + Printf ("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.GetName()); } diff --git a/src/gl/utility/gl_clock.cpp b/src/gl/utility/gl_clock.cpp index df96fb6b8..1003fae86 100644 --- a/src/gl/utility/gl_clock.cpp +++ b/src/gl/utility/gl_clock.cpp @@ -43,6 +43,8 @@ #include #endif +#include + #include "i_system.h" #include "g_level.h" #include "c_console.h" @@ -237,7 +239,7 @@ void CheckBench() AppendRenderTimes(compose); AppendLightStats(compose); AppendMissingTextureStats(compose); - compose.AppendFormat("%d fps\n\n", screen->GetLastFPS()); + compose.AppendFormat("%" PRIu64 " fps\n\n", screen->GetLastFPS()); FILE *f = fopen("benchmarks.txt", "at"); if (f != NULL) diff --git a/src/v_video.cpp b/src/v_video.cpp index 01ae8b428..814dc4615 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -880,7 +880,7 @@ void DFrameBuffer::DrawRateStuff () int textScale = active_con_scale(); - chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount); + chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2" PRIu64 " ms (%3" PRIu64 " fps)", howlong, LastCount); rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]); Clear (rate_x * textScale, 0, Width, ConFont->GetHeight() * textScale, GPalette.BlackIndex, 0); DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], From d43ac8b9ae18d79c4072447924191cb9bf9df082 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 27 Nov 2017 23:47:26 +0100 Subject: [PATCH 02/39] - Add model rendering to the software renderer --- src/CMakeLists.txt | 1 + src/polyrenderer/drawers/poly_draw_args.cpp | 18 ++ src/polyrenderer/drawers/poly_draw_args.h | 2 + src/polyrenderer/drawers/screen_triangle.cpp | 197 +++++++----- src/polyrenderer/drawers/screen_triangle.h | 1 + src/polyrenderer/math/tri_matrix.cpp | 8 +- src/polyrenderer/math/tri_matrix.h | 4 +- src/polyrenderer/scene/poly_model.cpp | 12 + src/polyrenderer/scene/poly_model.h | 4 +- src/swrenderer/drawers/r_draw.cpp | 121 ++++++++ src/swrenderer/drawers/r_draw.h | 4 + src/swrenderer/line/r_walldraw.cpp | 17 +- src/swrenderer/plane/r_flatplane.cpp | 2 + src/swrenderer/plane/r_skyplane.cpp | 2 + src/swrenderer/plane/r_slopeplane.cpp | 11 +- src/swrenderer/r_all.cpp | 1 + src/swrenderer/scene/r_opaque_pass.cpp | 14 +- src/swrenderer/scene/r_scene.cpp | 2 + src/swrenderer/things/r_model.cpp | 307 +++++++++++++++++++ src/swrenderer/things/r_model.h | 100 ++++++ src/swrenderer/things/r_playersprite.cpp | 8 + src/swrenderer/things/r_playersprite.h | 1 + src/swrenderer/things/r_visiblesprite.cpp | 6 + src/swrenderer/things/r_visiblesprite.h | 1 + src/swrenderer/viewport/r_skydrawer.cpp | 5 + src/swrenderer/viewport/r_skydrawer.h | 1 + src/swrenderer/viewport/r_spandrawer.cpp | 5 + src/swrenderer/viewport/r_spandrawer.h | 1 + src/swrenderer/viewport/r_viewport.cpp | 12 + src/swrenderer/viewport/r_viewport.h | 7 + src/swrenderer/viewport/r_walldrawer.cpp | 5 + src/swrenderer/viewport/r_walldrawer.h | 1 + 32 files changed, 793 insertions(+), 88 deletions(-) create mode 100644 src/swrenderer/things/r_model.cpp create mode 100644 src/swrenderer/things/r_model.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39bd0933e..8c90fab42 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -734,6 +734,7 @@ set ( SWRENDER_SOURCES swrenderer/things/r_sprite.cpp swrenderer/things/r_wallsprite.cpp swrenderer/things/r_decal.cpp + swrenderer/things/r_model.cpp swrenderer/plane/r_visibleplane.cpp swrenderer/plane/r_visibleplanelist.cpp swrenderer/plane/r_skyplane.cpp diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp index 5fb7f0288..466a39f4a 100644 --- a/src/polyrenderer/drawers/poly_draw_args.cpp +++ b/src/polyrenderer/drawers/poly_draw_args.cpp @@ -126,6 +126,24 @@ void PolyDrawArgs::SetColor(uint32_t bgra, uint8_t palindex) } } +void PolyDrawArgs::DrawArray(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, int vcount, PolyDrawMode mode) +{ + mVertices = vertices; + mVertexCount = vcount; + mElements = nullptr; + mDrawMode = mode; + queue->Push(*this, PolyTriangleDrawer::is_mirror()); +} + +void PolyDrawArgs::DrawElements(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode) +{ + mVertices = vertices; + mElements = elements; + mVertexCount = count; + mDrawMode = mode; + queue->Push(*this, PolyTriangleDrawer::is_mirror()); +} + void PolyDrawArgs::DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode) { mVertices = vertices; diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index 31780d77a..eb543bbbf 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -84,6 +84,8 @@ public: void SetDynLightColor(uint32_t color) { mDynLightColor = color; } void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); void DrawElements(PolyRenderThread *thread, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode = PolyDrawMode::Triangles); + void DrawArray(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); + void DrawElements(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode = PolyDrawMode::Triangles); const TriMatrix *ObjectToClip() const { return mObjectToClip; } const PolyClipPlane &ClipPlane(int index) const { return mClipPlane[index]; } diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index c0e4104fc..f3aad8f47 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -1071,16 +1071,21 @@ void TriangleBlock::DepthWrite(const TriDrawTriangleArgs *args) #endif -#if 1 +EXTERN_CVAR(Bool, r_polyrenderer) void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread) { - TriangleBlock block(args, thread); - block.Render(); + if (r_polyrenderer) + { + TriangleBlock block(args, thread); + block.Render(); + } + else + { + DrawSWRender(args, thread); + } } -#else - static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sortedVertices) { sortedVertices[0] = args->v1; @@ -1095,7 +1100,7 @@ static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sort std::swap(sortedVertices[1], sortedVertices[2]); } -void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread) +void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadData *thread) { // Sort vertices by Y position ShadedTriVertex *sortedVertices[3]; @@ -1179,15 +1184,9 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr bool writeStencil = args->uniforms->WriteStencil(); bool writeDepth = args->uniforms->WriteDepth(); - uint8_t stencilTestValue = args->uniforms->StencilTestValue(); - uint8_t stencilWriteValue = args->uniforms->StencilWriteValue(); - int bmode = (int)args->uniforms->BlendMode(); auto drawFunc = args->destBgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode]; - uint8_t *dest = args->dest; - uint8_t *stencilbuffer = args->stencilValues; - uint32_t *stencilMasks = args->stencilMasks; float *zbuffer = args->zbuffer; int pitch = args->pitch; int stencilpitch = args->stencilPitch * 8; @@ -1206,7 +1205,6 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr float stepYV = args->gradientY.V; int texWidth = args->uniforms->TextureWidth(); int texHeight = args->uniforms->TextureHeight(); - const uint8_t *texPixels = args->uniforms->TexturePixels(); auto colormaps = args->uniforms->BaseColormap(); bool is_fixed_light = args->uniforms->FixedLight(); @@ -1218,83 +1216,140 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr // Draw the triangle: - int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + if (args->destBgra) { - int x0 = leftEdge[y]; - int x1 = rightEdge[y]; + uint32_t *dest = (uint32_t*)args->dest; + const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels(); - uint8_t *destLine = dest + pitch * y; - uint8_t *stencilLine = stencilbuffer + stencilpitch * y; - float *zbufferLine = zbuffer + stencilpitch * y; - - if ((stencilMasks[y] & 0xffffff00) == 0xffffff00) // First time we draw a line we have to clear the stencil buffer + int num_cores = thread->num_cores; + for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) { - memset(stencilLine, stencilMasks[y] & 0xff, stencilpitch); - stencilMasks[y] = 0; - } + int x0 = leftEdge[y]; + int x1 = rightEdge[y]; - float posXW = v1W + stepXW * (x0 + (0.5f - v1X)) + stepYW * (y + (0.5f - v1Y)); - float posXU = v1U + stepXU * (x0 + (0.5f - v1X)) + stepYU * (y + (0.5f - v1Y)); - float posXV = v1V + stepXV * (x0 + (0.5f - v1X)) + stepYV * (y + (0.5f - v1Y)); + uint32_t *destLine = dest + pitch * y; + float *zbufferLine = zbuffer + stencilpitch * y; - int x = x0; - while (x < x1) - { - bool processPixel = true; + float posXW = v1W + stepXW * (x0 + (0.5f - v1X)) + stepYW * (y + (0.5f - v1Y)); + float posXU = v1U + stepXU * (x0 + (0.5f - v1X)) + stepYU * (y + (0.5f - v1Y)); + float posXV = v1V + stepXV * (x0 + (0.5f - v1X)) + stepYV * (y + (0.5f - v1Y)); - if (!depthTest) // To do: make the stencil test use its own flag for comparison mode instead of abusing the depth test.. + int x = x0; + while (x < x1) { - processPixel = stencilTestValue == stencilLine[x]; - } - else - { - processPixel = stencilTestValue >= stencilLine[x] && zbufferLine[x] <= posXW; - } - - if (processPixel) // Pixel is visible (passed stencil and depth tests) - { - if (writeColor) + bool processPixel = depthTest ? zbufferLine[x] <= posXW : true; + if (processPixel) // Pixel is visible (passed stencil and depth tests) { - if (texPixels) + if (writeColor) { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + if (texPixels) + { + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint8_t fgcolor = texPixels[texelX * texHeight + texelY]; + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; + uint32_t fgcolor_r = RPART(fgcolor); + uint32_t fgcolor_g = GPART(fgcolor); + uint32_t fgcolor_b = BPART(fgcolor); + uint32_t fgcolor_a = APART(fgcolor); + if (fgcolor_a > 127) + { + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; - lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; - uint8_t shadedfg = colormaps[lightshade + fgcolor]; + fgcolor_r = (fgcolor_r * lightshade) >> 8; + fgcolor_g = (fgcolor_g * lightshade) >> 8; + fgcolor_b = (fgcolor_b * lightshade) >> 8; - if (fgcolor != 0) - destLine[x] = shadedfg; - } - else - { - destLine[x] = color; + destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; + } + } + else + { + destLine[x] = color; + } } + + if (writeDepth) + zbufferLine[x] = posXW; } - if (writeStencil) - stencilLine[x] = stencilWriteValue; - if (writeDepth) - zbufferLine[x] = posXW; - } - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; - x++; + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + x++; + } + } + } + else + { + uint8_t *dest = args->dest; + const uint8_t *texPixels = args->uniforms->TexturePixels(); + + int num_cores = thread->num_cores; + for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + { + int x0 = leftEdge[y]; + int x1 = rightEdge[y]; + + uint8_t *destLine = dest + pitch * y; + float *zbufferLine = zbuffer + stencilpitch * y; + + float posXW = v1W + stepXW * (x0 + (0.5f - v1X)) + stepYW * (y + (0.5f - v1Y)); + float posXU = v1U + stepXU * (x0 + (0.5f - v1X)) + stepYU * (y + (0.5f - v1Y)); + float posXV = v1V + stepXV * (x0 + (0.5f - v1X)) + stepYV * (y + (0.5f - v1Y)); + + int x = x0; + while (x < x1) + { + bool processPixel = depthTest ? zbufferLine[x] <= posXW : true; + if (processPixel) // Pixel is visible (passed stencil and depth tests) + { + if (writeColor) + { + if (texPixels) + { + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint8_t fgcolor = texPixels[texelX * texHeight + texelY]; + + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; + + lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; + uint8_t shadedfg = colormaps[lightshade + fgcolor]; + + if (fgcolor != 0) + destLine[x] = shadedfg; + } + else + { + destLine[x] = color; + } + } + + if (writeDepth) + zbufferLine[x] = posXW; + } + + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + x++; + } } } } -#endif void(*ScreenTriangle::TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *) = { diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index a76dc4b46..4b0666ccf 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -149,6 +149,7 @@ class ScreenTriangle { public: static void Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread); + static void DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadData *thread); static void(*TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *); static void(*TriDrawers32[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *); diff --git a/src/polyrenderer/math/tri_matrix.cpp b/src/polyrenderer/math/tri_matrix.cpp index df0e7d4e0..ed606d793 100644 --- a/src/polyrenderer/math/tri_matrix.cpp +++ b/src/polyrenderer/math/tri_matrix.cpp @@ -132,7 +132,6 @@ TriMatrix TriMatrix::frustum(float left, float right, float bottom, float top, f return m; } -#if 0 TriMatrix TriMatrix::worldToView(const FRenderViewpoint &viewpoint) { TriMatrix m = null(); @@ -145,16 +144,15 @@ TriMatrix TriMatrix::worldToView(const FRenderViewpoint &viewpoint) return m * translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z); } -TriMatrix TriMatrix::viewToClip(double focalTangent, double centerY, double invZtoScale) +TriMatrix TriMatrix::viewToClip(double focalTangent, double centerY, double YaspectMul) { 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)(centerY / viewheight * YaspectMul * near); + float bottom = (float)(top - YaspectMul * near); return frustum(-width, width, bottom, top, near, far); } -#endif TriMatrix TriMatrix::operator*(const TriMatrix &mult) const { diff --git a/src/polyrenderer/math/tri_matrix.h b/src/polyrenderer/math/tri_matrix.h index 908ef247d..592825c20 100644 --- a/src/polyrenderer/math/tri_matrix.h +++ b/src/polyrenderer/math/tri_matrix.h @@ -36,8 +36,8 @@ struct TriMatrix static TriMatrix perspective(float fovy, float aspect, float near, float far); static TriMatrix frustum(float left, float right, float bottom, float top, float near, float far); - //static TriMatrix worldToView(const FRenderViewpoint &viewpoint); // Software renderer world to view space transform - //static TriMatrix viewToClip(double focalTangent, double centerY, double invZtoScale); // Software renderer shearing projection + static TriMatrix worldToView(const FRenderViewpoint &viewpoint); // Software renderer world to view space transform + static TriMatrix viewToClip(double focalTangent, double centerY, double YaspectMul); // Software renderer shearing projection FVector4 operator*(const FVector4 &v) const; TriMatrix operator*(const TriMatrix &m) const; diff --git a/src/polyrenderer/scene/poly_model.cpp b/src/polyrenderer/scene/poly_model.cpp index 285d19e16..c952625c3 100644 --- a/src/polyrenderer/scene/poly_model.cpp +++ b/src/polyrenderer/scene/poly_model.cpp @@ -33,6 +33,9 @@ #include "actorinlines.h" #include "i_time.h" +void gl_FlushModels(); +bool polymodelsInUse; + void PolyRenderModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor) { PolyModelRenderer renderer(thread, worldToClip, clipPlane, stencilValue); @@ -47,6 +50,15 @@ void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip, ///////////////////////////////////////////////////////////////////////////// +PolyModelRenderer::PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), ClipPlane(clipPlane), StencilValue(stencilValue) +{ + if (!polymodelsInUse) + { + gl_FlushModels(); + polymodelsInUse = true; + } +} + void PolyModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) { ModelActor = actor; diff --git a/src/polyrenderer/scene/poly_model.h b/src/polyrenderer/scene/poly_model.h index b4896b7d8..a064459e9 100644 --- a/src/polyrenderer/scene/poly_model.h +++ b/src/polyrenderer/scene/poly_model.h @@ -24,7 +24,7 @@ #include "polyrenderer/drawers/poly_triangle.h" #include "r_data/matrix.h" -#include "gl/models/gl_models.h" +#include "r_data/models/models.h" void PolyRenderModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor); void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy); @@ -32,7 +32,7 @@ void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip, class PolyModelRenderer : public FModelRenderer { public: - PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), ClipPlane(clipPlane), StencilValue(stencilValue) { } + PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue); void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) override; void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override; diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index bc7eb731d..3250c1186 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -215,4 +215,125 @@ namespace swrenderer fuzzpos = (fuzzpos + yh - yl + 1) % FUZZTABLE; } } + + class DepthColumnCommand : public DrawerCommand + { + public: + DepthColumnCommand(const WallDrawerArgs &args, float idepth) : idepth(idepth) + { + auto rendertarget = args.Viewport()->RenderTarget; + if (rendertarget->IsBgra()) + { + uint32_t *destorg = (uint32_t*)rendertarget->GetBuffer(); + uint32_t *dest = (uint32_t*)args.Dest(); + int offset = (int)(ptrdiff_t)(dest - destorg); + x = offset % rendertarget->GetPitch(); + y = offset / rendertarget->GetPitch(); + } + else + { + uint8_t *destorg = rendertarget->GetBuffer(); + uint8_t *dest = (uint8_t*)args.Dest(); + int offset = (int)(ptrdiff_t)(dest - destorg); + x = offset % rendertarget->GetPitch(); + y = offset / rendertarget->GetPitch(); + } + count = args.Count(); + } + + DepthColumnCommand(const SkyDrawerArgs &args, float idepth) : idepth(idepth) + { + auto rendertarget = args.Viewport()->RenderTarget; + if (rendertarget->IsBgra()) + { + uint32_t *destorg = (uint32_t*)rendertarget->GetBuffer(); + uint32_t *dest = (uint32_t*)args.Dest(); + int offset = (int)(ptrdiff_t)(dest - destorg); + x = offset % rendertarget->GetPitch(); + y = offset / rendertarget->GetPitch(); + } + else + { + uint8_t *destorg = rendertarget->GetBuffer(); + uint8_t *dest = (uint8_t*)args.Dest(); + int offset = (int)(ptrdiff_t)(dest - destorg); + x = offset % rendertarget->GetPitch(); + y = offset / rendertarget->GetPitch(); + } + count = args.Count(); + } + + FString DebugInfo() override { return "DepthColumnCommand"; } + + void Execute(DrawerThread *thread) override + { + auto zbuffer = PolyZBuffer::Instance(); + int pitch = PolyStencilBuffer::Instance()->BlockWidth() * 8; + float *values = zbuffer->Values() + y * pitch + x; + int cnt = count; + + values = thread->dest_for_thread(y, pitch, values); + cnt = thread->count_for_thread(y, cnt); + pitch *= thread->num_cores; + + float depth = idepth; + for (int i = 0; i < cnt; i++) + { + *values = depth; + values += pitch; + } + } + + private: + int x, y, count; + float idepth; + }; + + class DepthSpanCommand : public DrawerCommand + { + public: + DepthSpanCommand(const SpanDrawerArgs &args, float idepth) : idepth(idepth) + { + y = args.DestY(); + x1 = args.DestX1(); + x2 = args.DestX2(); + } + + FString DebugInfo() override { return "DepthSpanCommand"; } + + void Execute(DrawerThread *thread) override + { + if (thread->skipped_by_thread(y)) + return; + + auto zbuffer = PolyZBuffer::Instance(); + int pitch = PolyStencilBuffer::Instance()->BlockWidth() * 8; + float *values = zbuffer->Values() + y * pitch; + int end = x2; + float depth = idepth; + for (int x = x1; x <= end; x++) + { + values[x] = depth; + } + } + + private: + int y, x1, x2; + float idepth; + }; + + void SWPixelFormatDrawers::DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth) + { + Queue->Push(args, idepth); + } + + void SWPixelFormatDrawers::DrawDepthWallColumn(const WallDrawerArgs &args, float idepth) + { + Queue->Push(args, idepth); + } + + void SWPixelFormatDrawers::DrawDepthSpan(const SpanDrawerArgs &args, float idepth) + { + Queue->Push(args, idepth); + } } diff --git a/src/swrenderer/drawers/r_draw.h b/src/swrenderer/drawers/r_draw.h index 4672a4fd3..fa83ca6f6 100644 --- a/src/swrenderer/drawers/r_draw.h +++ b/src/swrenderer/drawers/r_draw.h @@ -94,6 +94,10 @@ namespace swrenderer virtual void DrawTiltedSpan(const SpanDrawerArgs &args, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) = 0; virtual void DrawColoredSpan(const SpanDrawerArgs &args) = 0; virtual void DrawFogBoundaryLine(const SpanDrawerArgs &args) = 0; + + void DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth); + void DrawDepthWallColumn(const WallDrawerArgs &args, float idepth); + void DrawDepthSpan(const SpanDrawerArgs &args, float idepth); DrawerCommandQueuePtr Queue; }; diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 5a8a4f465..a1972417a 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -177,16 +177,18 @@ namespace swrenderer // Draw a column with support for non-power-of-two ranges void RenderWallPart::Draw1Column(int x, int y1, int y2, WallSampler &sampler) { + // Find column position in view space + float w1 = 1.0f / WallC.sz1; + float w2 = 1.0f / WallC.sz2; + float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1); + float wcol = w1 * (1.0f - t) + w2 * t; + float zcol = 1.0f / wcol; + float zbufferdepth = 1.0f / (zcol / Thread->Viewport->viewwindow.FocalTangent); + if (r_dynlights && light_list) { auto viewport = Thread->Viewport.get(); - // Find column position in view space - float w1 = 1.0f / WallC.sz1; - float w2 = 1.0f / WallC.sz2; - float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1); - float wcol = w1 * (1.0f - t) + w2 * t; - float zcol = 1.0f / wcol; drawerargs.dc_viewpos.X = (float)((x + 0.5 - viewport->CenterX) / viewport->CenterX * zcol); drawerargs.dc_viewpos.Y = zcol; drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol); @@ -260,6 +262,7 @@ namespace swrenderer drawerargs.SetTextureVStep(sampler.uv_step); drawerargs.SetTextureVPos(sampler.uv_pos); drawerargs.DrawColumn(Thread); + drawerargs.DrawDepthColumn(Thread, zbufferdepth); uint64_t step64 = sampler.uv_step; uint64_t pos64 = sampler.uv_pos; @@ -278,6 +281,7 @@ namespace swrenderer drawerargs.SetTextureVStep(sampler.uv_step); drawerargs.SetTextureVPos(sampler.uv_pos); drawerargs.DrawColumn(Thread); + drawerargs.DrawDepthColumn(Thread, zbufferdepth); uint64_t step64 = sampler.uv_step; uint64_t pos64 = sampler.uv_pos; @@ -304,6 +308,7 @@ namespace swrenderer drawerargs.SetTextureVStep(sampler.uv_step); drawerargs.SetTextureVPos(uv_pos); drawerargs.DrawColumn(Thread); + drawerargs.DrawDepthColumn(Thread, zbufferdepth); y += count; left -= count; diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 513ce9ccc..6161d0619 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -178,6 +178,7 @@ namespace swrenderer double curyfrac = baseyfrac + ystepscale * (x1 - minx); double distance = viewport->PlaneDepth(y, planeheight); + float zbufferdepth = 1.0f / (distance * Thread->Viewport->viewwindow.FocalTangent); drawerargs.SetTextureUStep(distance * xstepscale / drawerargs.TextureWidth()); drawerargs.SetTextureUPos((distance * curxfrac + pviewx) / drawerargs.TextureWidth()); @@ -274,6 +275,7 @@ namespace swrenderer drawerargs.SetDestX2(x2); drawerargs.DrawSpan(Thread); + drawerargs.DrawDepthSpan(Thread, zbufferdepth); } ///////////////////////////////////////////////////////////////////////// diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index d79c06909..eeb72ebe2 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -224,6 +224,8 @@ namespace swrenderer drawerargs.DrawSingleSkyColumn(Thread); else drawerargs.DrawDoubleSkyColumn(Thread); + + drawerargs.DrawDepthSkyColumn(Thread, 1.0f / 65536.0f); } void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2) diff --git a/src/swrenderer/plane/r_slopeplane.cpp b/src/swrenderer/plane/r_slopeplane.cpp index b4fcb5185..bf9c84666 100644 --- a/src/swrenderer/plane/r_slopeplane.cpp +++ b/src/swrenderer/plane/r_slopeplane.cpp @@ -85,7 +85,7 @@ namespace swrenderer { return; } - + auto viewport = Thread->Viewport.get(); drawerargs.SetSolidColor(3); @@ -205,6 +205,15 @@ namespace swrenderer void RenderSlopePlane::RenderLine(int y, int x1, int x2) { + /* To do: project (x1,y) and (x2,y) on the plane to calculate the depth + double distance = Thread->Viewport->PlaneDepth(y, planeheight); + float zbufferdepth = 1.0f / (distance * Thread->Viewport->viewwindow.FocalTangent); + drawerargs.SetDestX1(x1); + drawerargs.SetDestX2(x2); + drawerargs.SetDestY(Thread->Viewport.get(), y); + drawerargs.DrawDepthSpan(Thread, zbufferdepth); + */ + drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, planeshade, planelightfloat, pviewx, pviewy, basecolormap); } } diff --git a/src/swrenderer/r_all.cpp b/src/swrenderer/r_all.cpp index 296fc04cf..91586be6f 100644 --- a/src/swrenderer/r_all.cpp +++ b/src/swrenderer/r_all.cpp @@ -36,6 +36,7 @@ #include "things/r_visiblespritelist.cpp" #include "things/r_voxel.cpp" #include "things/r_wallsprite.cpp" +#include "things/r_model.cpp" #include "viewport/r_drawerargs.cpp" #include "viewport/r_skydrawer.cpp" #include "viewport/r_spandrawer.cpp" diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 03467ce72..3ad3ba1e0 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -45,6 +45,7 @@ #include "swrenderer/things/r_wallsprite.h" #include "swrenderer/things/r_voxel.h" #include "swrenderer/things/r_particle.h" +#include "swrenderer/things/r_model.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/line/r_wallsetup.h" #include "swrenderer/line/r_farclip_line.h" @@ -951,7 +952,18 @@ namespace swrenderer } else { - RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap); + int spritenum = thing->sprite; + bool isPicnumOverride = thing->picnum.isValid(); + FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + if (modelframe) + { + DVector3 pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac); + RenderModel::Project(Thread, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing); + } + else + { + RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap); + } } } } diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 4667f25eb..6cccef52e 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -156,6 +156,8 @@ namespace swrenderer R_UpdateFuzzPosFrameStart(); + MainThread()->Viewport->SetupPolyViewport(); + ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags; // Never draw the player unless in chasecam mode if (!MainThread()->Viewport->viewpoint.showviewer) diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp new file mode 100644 index 000000000..710df506b --- /dev/null +++ b/src/swrenderer/things/r_model.cpp @@ -0,0 +1,307 @@ +/* +** Polygon Doom software renderer +** Copyright (c) 2016 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include +#include "templates.h" +#include "doomdef.h" +#include "sbar.h" +#include "r_data/r_translate.h" +#include "r_model.h" +#include "r_data/r_vanillatrans.h" +#include "actorinlines.h" +#include "i_time.h" +#include "swrenderer/r_memory.h" +#include "swrenderer/r_swcolormaps.h" +#include "swrenderer/viewport/r_viewport.h" +#include "swrenderer/scene/r_light.h" + +void gl_FlushModels(); +extern bool polymodelsInUse; + +namespace swrenderer +{ + void RenderModel::Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor) + { + // transform the origin point + double tr_x = x - thread->Viewport->viewpoint.Pos.X; + double tr_y = y - thread->Viewport->viewpoint.Pos.Y; + double tz = tr_x * thread->Viewport->viewpoint.TanCos + tr_y * thread->Viewport->viewpoint.TanSin; + + // thing is behind view plane? + if (tz < MINZ) + return; + + // too far off the side? + double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos; + if (fabs(tx / 64) > fabs(tz)) + return; + + RenderModel *vis = thread->FrameMemory->NewObject(x, y, z, smf, actor, float(1 / tz)); + thread->SpriteList->Push(vis); + } + + RenderModel::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth) : x(x), y(y), z(z), smf(smf), actor(actor) + { + this->idepth = idepth; + } + + void RenderModel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ) + { + SWModelRenderer renderer(thread); + renderer.RenderModel(x, y, z, smf, actor); + } + + ///////////////////////////////////////////////////////////////////////////// + + void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy) + { + SWModelRenderer renderer(thread); + renderer.RenderHUDModel(psp, ofsx, ofsy); + } + + ///////////////////////////////////////////////////////////////////////////// + + SWModelRenderer::SWModelRenderer(RenderThread *thread) : Thread(thread) + { + if (polymodelsInUse) + { + gl_FlushModels(); + polymodelsInUse = false; + } + } + + void SWModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) + { + ModelActor = actor; + const_cast(objectToWorldMatrix).copy(ObjectToWorld.matrix); + } + + void SWModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf) + { + ModelActor = nullptr; + } + + IModelVertexBuffer *SWModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe) + { + return new SWModelVertexBuffer(needindex, singleframe); + } + + void SWModelRenderer::SetVertexBuffer(IModelVertexBuffer *buffer) + { + } + + void SWModelRenderer::ResetVertexBuffer() + { + } + + VSMatrix SWModelRenderer::GetViewToWorldMatrix() + { + TriMatrix swapYZ = TriMatrix::null(); + swapYZ.matrix[0 + 0 * 4] = 1.0f; + swapYZ.matrix[1 + 2 * 4] = 1.0f; + swapYZ.matrix[2 + 1 * 4] = 1.0f; + swapYZ.matrix[3 + 3 * 4] = 1.0f; + + VSMatrix worldToView; + worldToView.loadMatrix((Thread->Viewport->WorldToView * swapYZ).matrix); + + VSMatrix objectToWorld; + worldToView.inverseMatrix(objectToWorld); + return objectToWorld; + } + + void SWModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix) + { + ModelActor = actor; + const_cast(objectToWorldMatrix).copy(ObjectToWorld.matrix); + } + + void SWModelRenderer::EndDrawHUDModel(AActor *actor) + { + ModelActor = nullptr; + } + + void SWModelRenderer::SetInterpolation(double interpolation) + { + InterpolationFactor = (float)interpolation; + } + + void SWModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation) + { + SkinTexture = skin; + } + + void SWModelRenderer::DrawArrays(int start, int count) + { + const auto &viewpoint = Thread->Viewport->viewpoint; + + bool foggy = false; + int actualextralight = foggy ? 0 : viewpoint.extralight << 4; + sector_t *sector = ModelActor->Sector; + + bool fullbrightSprite = ((ModelActor->renderflags & RF_FULLBRIGHT) || (ModelActor->flags5 & MF5_BRIGHT)); + int lightlevel = fullbrightSprite ? 255 : ModelActor->Sector->lightlevel + actualextralight; + + TriMatrix swapYZ = TriMatrix::null(); + swapYZ.matrix[0 + 0 * 4] = 1.0f; + swapYZ.matrix[1 + 2 * 4] = 1.0f; + swapYZ.matrix[2 + 1 * 4] = 1.0f; + swapYZ.matrix[3 + 3 * 4] = 1.0f; + + TriMatrix *transform = Thread->FrameMemory->NewObject(); + *transform = Thread->Viewport->WorldToClip * swapYZ * ObjectToWorld; + + PolyDrawArgs args; + args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, Thread->Light->SpriteGlobVis(foggy), fullbrightSprite); + args.SetTransform(transform); + args.SetFaceCullCCW(true); + args.SetClipPlane(0, PolyClipPlane()); + args.SetStyle(TriBlendMode::TextureOpaque); + + if (Thread->Viewport->RenderTarget->IsBgra()) + args.SetTexture((const uint8_t *)SkinTexture->GetPixelsBgra(), SkinTexture->GetWidth(), SkinTexture->GetHeight()); + else + args.SetTexture(SkinTexture->GetPixels(), SkinTexture->GetWidth(), SkinTexture->GetHeight()); + + args.SetDepthTest(true); + args.SetWriteDepth(true); + args.SetWriteStencil(false); + args.DrawArray(Thread->DrawQueue, VertexBuffer + start, count); + } + + void SWModelRenderer::DrawElements(int numIndices, size_t offset) + { + const auto &viewpoint = Thread->Viewport->viewpoint; + + bool foggy = false; + int actualextralight = foggy ? 0 : viewpoint.extralight << 4; + sector_t *sector = ModelActor->Sector; + + bool fullbrightSprite = ((ModelActor->renderflags & RF_FULLBRIGHT) || (ModelActor->flags5 & MF5_BRIGHT)); + int lightlevel = fullbrightSprite ? 255 : ModelActor->Sector->lightlevel + actualextralight; + + TriMatrix swapYZ = TriMatrix::null(); + swapYZ.matrix[0 + 0 * 4] = 1.0f; + swapYZ.matrix[1 + 2 * 4] = 1.0f; + swapYZ.matrix[2 + 1 * 4] = 1.0f; + swapYZ.matrix[3 + 3 * 4] = 1.0f; + + TriMatrix *transform = Thread->FrameMemory->NewObject(); + *transform = Thread->Viewport->WorldToClip * swapYZ * ObjectToWorld; + + PolyDrawArgs args; + args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, Thread->Light->SpriteGlobVis(foggy), fullbrightSprite); + args.SetTransform(transform); + args.SetFaceCullCCW(true); + args.SetClipPlane(0, PolyClipPlane()); + args.SetStyle(TriBlendMode::TextureOpaque); + + if (Thread->Viewport->RenderTarget->IsBgra()) + args.SetTexture((const uint8_t *)SkinTexture->GetPixelsBgra(), SkinTexture->GetWidth(), SkinTexture->GetHeight()); + else + args.SetTexture(SkinTexture->GetPixels(), SkinTexture->GetWidth(), SkinTexture->GetHeight()); + + args.SetDepthTest(true); + args.SetWriteDepth(true); + args.SetWriteStencil(false); + args.DrawElements(Thread->DrawQueue, VertexBuffer, IndexBuffer + offset / sizeof(unsigned int), numIndices); + } + + double SWModelRenderer::GetTimeFloat() + { + return (double)screen->FrameTime * (double)TICRATE / 1000.0; + } + + ///////////////////////////////////////////////////////////////////////////// + + SWModelVertexBuffer::SWModelVertexBuffer(bool needindex, bool singleframe) + { + } + + SWModelVertexBuffer::~SWModelVertexBuffer() + { + } + + FModelVertex *SWModelVertexBuffer::LockVertexBuffer(unsigned int size) + { + mVertexBuffer.Resize(size); + return &mVertexBuffer[0]; + } + + void SWModelVertexBuffer::UnlockVertexBuffer() + { + } + + unsigned int *SWModelVertexBuffer::LockIndexBuffer(unsigned int size) + { + mIndexBuffer.Resize(size); + return &mIndexBuffer[0]; + } + + void SWModelVertexBuffer::UnlockIndexBuffer() + { + } + + void SWModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) + { + SWModelRenderer *polyrenderer = (SWModelRenderer *)renderer; + + if (true)//if (frame1 == frame2 || size == 0 || polyrenderer->InterpolationFactor == 0.f) + { + TriVertex *vertices = polyrenderer->Thread->FrameMemory->AllocMemory(size); + + for (unsigned int i = 0; i < size; i++) + { + vertices[i] = + { + mVertexBuffer[frame1 + i].x, + mVertexBuffer[frame1 + i].y, + mVertexBuffer[frame1 + i].z, + 1.0f, + mVertexBuffer[frame1 + i].u, + mVertexBuffer[frame1 + i].v + }; + } + + polyrenderer->VertexBuffer = vertices; + polyrenderer->IndexBuffer = &mIndexBuffer[0]; + } + else + { + TriVertex *vertices = polyrenderer->Thread->FrameMemory->AllocMemory(size); + + float frac = polyrenderer->InterpolationFactor; + for (unsigned int i = 0; i < size; i++) + { + vertices[i].x = mVertexBuffer[frame1 + i].x * (1.0f - frac) + mVertexBuffer[frame2 + i].x * frac; + vertices[i].y = mVertexBuffer[frame1 + i].y * (1.0f - frac) + mVertexBuffer[frame2 + i].y * frac; + vertices[i].z = mVertexBuffer[frame1 + i].z * (1.0f - frac) + mVertexBuffer[frame2 + i].z * frac; + vertices[i].w = 1.0f; + vertices[i].u = mVertexBuffer[frame1 + i].u; + vertices[i].v = mVertexBuffer[frame1 + i].v; + } + + polyrenderer->VertexBuffer = vertices; + polyrenderer->IndexBuffer = &mIndexBuffer[0]; + } + } +} diff --git a/src/swrenderer/things/r_model.h b/src/swrenderer/things/r_model.h new file mode 100644 index 000000000..94ca1d909 --- /dev/null +++ b/src/swrenderer/things/r_model.h @@ -0,0 +1,100 @@ +/* +** Polygon Doom software renderer +** Copyright (c) 2016 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#pragma once + +#include "polyrenderer/drawers/poly_triangle.h" +#include "r_data/matrix.h" +#include "r_data/models/models.h" +#include "swrenderer/r_renderthread.h" +#include "swrenderer/things/r_visiblesprite.h" + +namespace swrenderer +{ + void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy); + + class RenderModel : public VisibleSprite + { + public: + RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth); + + static void Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor); + + protected: + void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ) override; + bool IsModel() const override { return true; } + + private: + float x, y, z; + FSpriteModelFrame *smf; + AActor *actor; + }; + + class SWModelRenderer : public FModelRenderer + { + public: + SWModelRenderer(RenderThread *thread); + + void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) override; + void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override; + IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override; + void SetVertexBuffer(IModelVertexBuffer *buffer) override; + void ResetVertexBuffer() override; + VSMatrix GetViewToWorldMatrix() override; + void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix) override; + void EndDrawHUDModel(AActor *actor) override; + void SetInterpolation(double interpolation) override; + void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) override; + void DrawArrays(int start, int count) override; + void DrawElements(int numIndices, size_t offset) override; + double GetTimeFloat() override; + + RenderThread *Thread = nullptr; + + AActor *ModelActor = nullptr; + TriMatrix ObjectToWorld; + FTexture *SkinTexture = nullptr; + unsigned int *IndexBuffer = nullptr; + TriVertex *VertexBuffer = nullptr; + float InterpolationFactor = 0.0; + }; + + class SWModelVertexBuffer : public IModelVertexBuffer + { + public: + SWModelVertexBuffer(bool needindex, bool singleframe); + ~SWModelVertexBuffer(); + + FModelVertex *LockVertexBuffer(unsigned int size) override; + void UnlockVertexBuffer() override; + + unsigned int *LockIndexBuffer(unsigned int size) override; + void UnlockIndexBuffer() override; + + void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override; + + private: + int mIndexFrame[2]; + TArray mVertexBuffer; + TArray mIndexBuffer; + }; +} diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index 2a51310b6..02f17bde6 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -88,6 +88,8 @@ namespace swrenderer int floorlight, ceilinglight; F3DFloor *rover; + renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); + if (!r_drawplayersprites || !Thread->Viewport->viewpoint.camera || !Thread->Viewport->viewpoint.camera->player || @@ -250,6 +252,12 @@ namespace swrenderer sy += wy; } + if (renderHUDModel) + { + RenderHUDModel(Thread, pspr, (float)sx, (float)sy); + return; + } + auto viewport = Thread->Viewport.get(); double pspritexscale = viewport->viewwindow.centerxwide / 160.0; diff --git a/src/swrenderer/things/r_playersprite.h b/src/swrenderer/things/r_playersprite.h index 755997a2a..3dbfd6edb 100644 --- a/src/swrenderer/things/r_playersprite.h +++ b/src/swrenderer/things/r_playersprite.h @@ -97,5 +97,6 @@ namespace swrenderer TArray AcceleratedSprites; sector_t tempsec; + bool renderHUDModel = false; }; } diff --git a/src/swrenderer/things/r_visiblesprite.cpp b/src/swrenderer/things/r_visiblesprite.cpp index e9ddec275..2a1d36eeb 100644 --- a/src/swrenderer/things/r_visiblesprite.cpp +++ b/src/swrenderer/things/r_visiblesprite.cpp @@ -51,6 +51,12 @@ namespace swrenderer { void VisibleSprite::Render(RenderThread *thread) { + if (IsModel()) + { + Render(thread, nullptr, nullptr, 0, 0); + return; + } + short *clipbot = thread->clipbot; short *cliptop = thread->cliptop; diff --git a/src/swrenderer/things/r_visiblesprite.h b/src/swrenderer/things/r_visiblesprite.h index f31d08b58..c9fff3327 100644 --- a/src/swrenderer/things/r_visiblesprite.h +++ b/src/swrenderer/things/r_visiblesprite.h @@ -52,6 +52,7 @@ namespace swrenderer virtual bool IsParticle() const { return false; } virtual bool IsVoxel() const { return false; } virtual bool IsWallSprite() const { return false; } + virtual bool IsModel() const { return false; } virtual void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ) = 0; diff --git a/src/swrenderer/viewport/r_skydrawer.cpp b/src/swrenderer/viewport/r_skydrawer.cpp index 47409bf08..16e2d2ab3 100644 --- a/src/swrenderer/viewport/r_skydrawer.cpp +++ b/src/swrenderer/viewport/r_skydrawer.cpp @@ -25,6 +25,11 @@ namespace swrenderer { + void SkyDrawerArgs::DrawDepthSkyColumn(RenderThread *thread, float idepth) + { + thread->Drawers(dc_viewport)->DrawDepthSkyColumn(*this, idepth); + } + void SkyDrawerArgs::DrawSingleSkyColumn(RenderThread *thread) { thread->Drawers(dc_viewport)->DrawSingleSkyColumn(*this); diff --git a/src/swrenderer/viewport/r_skydrawer.h b/src/swrenderer/viewport/r_skydrawer.h index 4d7d44839..24c7e6f08 100644 --- a/src/swrenderer/viewport/r_skydrawer.h +++ b/src/swrenderer/viewport/r_skydrawer.h @@ -41,6 +41,7 @@ namespace swrenderer RenderViewport *Viewport() const { return dc_viewport; } + void DrawDepthSkyColumn(RenderThread *thread, float idepth); void DrawSingleSkyColumn(RenderThread *thread); void DrawDoubleSkyColumn(RenderThread *thread); diff --git a/src/swrenderer/viewport/r_spandrawer.cpp b/src/swrenderer/viewport/r_spandrawer.cpp index 245cac2ab..ffc4dfc5f 100644 --- a/src/swrenderer/viewport/r_spandrawer.cpp +++ b/src/swrenderer/viewport/r_spandrawer.cpp @@ -107,6 +107,11 @@ namespace swrenderer } } + void SpanDrawerArgs::DrawDepthSpan(RenderThread *thread, float idepth) + { + thread->Drawers(ds_viewport)->DrawDepthSpan(*this, idepth); + } + void SpanDrawerArgs::DrawSpan(RenderThread *thread) { (thread->Drawers(ds_viewport)->*spanfunc)(*this); diff --git a/src/swrenderer/viewport/r_spandrawer.h b/src/swrenderer/viewport/r_spandrawer.h index 2dd9a959a..fe3363c98 100644 --- a/src/swrenderer/viewport/r_spandrawer.h +++ b/src/swrenderer/viewport/r_spandrawer.h @@ -27,6 +27,7 @@ namespace swrenderer void SetTextureVStep(double vstep) { ds_ystep = (uint32_t)(int64_t)(vstep * 4294967296.0); } void SetSolidColor(int colorIndex) { ds_color = colorIndex; } + void DrawDepthSpan(RenderThread *thread, float idepth); void DrawSpan(RenderThread *thread); void DrawTiltedSpan(RenderThread *thread, int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap); void DrawColoredSpan(RenderThread *thread, int y, int x1, int x2); diff --git a/src/swrenderer/viewport/r_viewport.cpp b/src/swrenderer/viewport/r_viewport.cpp index b243f2265..a0535e434 100644 --- a/src/swrenderer/viewport/r_viewport.cpp +++ b/src/swrenderer/viewport/r_viewport.cpp @@ -47,6 +47,7 @@ CVAR(String, r_viewsize, "", CVAR_NOSET) EXTERN_CVAR(Float, r_visibility); +EXTERN_CVAR(Int, screenblocks) namespace swrenderer { @@ -58,6 +59,17 @@ namespace swrenderer { } + void RenderViewport::SetupPolyViewport() + { + PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0); + PolyZBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight()); + + PolyTriangleDrawer::set_viewport(viewwindowx, viewwindowy, viewwidth, viewheight, RenderTarget); + WorldToView = TriMatrix::worldToView(viewpoint); + ViewToClip = TriMatrix::viewToClip(viewwindow.FocalTangent, CenterY, YaspectMul); + WorldToClip = ViewToClip * WorldToView; + } + void RenderViewport::SetViewport(RenderThread *thread, int fullWidth, int fullHeight, float trueratio) { int virtheight, virtwidth, virtwidth2, virtheight2; diff --git a/src/swrenderer/viewport/r_viewport.h b/src/swrenderer/viewport/r_viewport.h index 1263425ac..b8ce166a7 100644 --- a/src/swrenderer/viewport/r_viewport.h +++ b/src/swrenderer/viewport/r_viewport.h @@ -5,6 +5,7 @@ #include #include "v_video.h" #include "r_defs.h" +#include "polyrenderer/math/tri_matrix.h" namespace swrenderer { @@ -19,6 +20,12 @@ namespace swrenderer void SetViewport(RenderThread *thread, int width, int height, float trueratio); void SetupFreelook(); + void SetupPolyViewport(); + + TriMatrix WorldToView; + TriMatrix ViewToClip; + TriMatrix WorldToClip; + DCanvas *RenderTarget = nullptr; FViewWindow viewwindow; diff --git a/src/swrenderer/viewport/r_walldrawer.cpp b/src/swrenderer/viewport/r_walldrawer.cpp index c61ed3303..50530eec5 100644 --- a/src/swrenderer/viewport/r_walldrawer.cpp +++ b/src/swrenderer/viewport/r_walldrawer.cpp @@ -32,6 +32,11 @@ namespace swrenderer dc_dest_y = y; } + void WallDrawerArgs::DrawDepthColumn(RenderThread *thread, float idepth) + { + thread->Drawers(dc_viewport)->DrawDepthWallColumn(*this, idepth); + } + void WallDrawerArgs::DrawColumn(RenderThread *thread) { (thread->Drawers(dc_viewport)->*wallfunc)(*this); diff --git a/src/swrenderer/viewport/r_walldrawer.h b/src/swrenderer/viewport/r_walldrawer.h index 5dde5cc5c..54bec778d 100644 --- a/src/swrenderer/viewport/r_walldrawer.h +++ b/src/swrenderer/viewport/r_walldrawer.h @@ -30,6 +30,7 @@ namespace swrenderer bool IsMaskedDrawer() const; + void DrawDepthColumn(RenderThread *thread, float idepth); void DrawColumn(RenderThread *thread); uint8_t *Dest() const { return dc_dest; } From e0defb060df62d96cdf7bbafe1e7dc07798b5803 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 28 Nov 2017 21:38:02 +0100 Subject: [PATCH 03/39] - Add a slightly faster truecolor model drawer --- src/polyrenderer/drawers/screen_triangle.cpp | 397 +++++++++++++------ src/polyrenderer/drawers/screen_triangle.h | 2 + 2 files changed, 280 insertions(+), 119 deletions(-) diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index f3aad8f47..b4d2168ae 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -1177,21 +1177,30 @@ void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadD } } - // Make variables local so the compiler can optimize without worrying about pointer aliasing + // Draw the triangle: - bool depthTest = args->uniforms->DepthTest(); - bool writeColor = args->uniforms->WriteColor(); - bool writeStencil = args->uniforms->WriteStencil(); - bool writeDepth = args->uniforms->WriteDepth(); + if (args->destBgra) + { + int num_cores = thread->num_cores; + for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + { + DrawSpan32(y, leftEdge[y], rightEdge[y], args); + } + } + else + { + int num_cores = thread->num_cores; + for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + { + DrawSpan8(y, leftEdge[y], rightEdge[y], args); + } + } +} - int bmode = (int)args->uniforms->BlendMode(); - auto drawFunc = args->destBgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode]; - - float *zbuffer = args->zbuffer; - int pitch = args->pitch; - int stencilpitch = args->stencilPitch * 8; - int color = ((int)(ptrdiff_t)args->uniforms->TexturePixels()) >> 2; +#ifndef NO_SSE +void ScreenTriangle::DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args) +{ float v1X = args->v1->x; float v1Y = args->v1->y; float v1W = args->v1->w; @@ -1200,12 +1209,15 @@ void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadD float stepXW = args->gradientX.W; float stepXU = args->gradientX.U; float stepXV = args->gradientX.V; - float stepYW = args->gradientY.W; - float stepYU = args->gradientY.U; - float stepYV = args->gradientY.V; + float startX = x0 + (0.5f - v1X); + float startY = y + (0.5f - v1Y); + float posXW = v1W + stepXW * startX + args->gradientY.W * startY; + float posXU = v1U + stepXU * startX + args->gradientY.U * startY; + float posXV = v1V + stepXV * startX + args->gradientY.V * startY; + + const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels(); int texWidth = args->uniforms->TextureWidth(); int texHeight = args->uniforms->TextureHeight(); - auto colormaps = args->uniforms->BaseColormap(); bool is_fixed_light = args->uniforms->FixedLight(); uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; @@ -1214,69 +1226,100 @@ void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadD float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); light += light >> 7; // 255 -> 256 - // Draw the triangle: + float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; - if (args->destBgra) + uint32_t *dest = (uint32_t*)args->dest; + uint32_t *destLine = dest + args->pitch * y; + + int x = x0; + int sseEnd = x0 + (x1 - x0) / 2 * 2; + while (x < sseEnd) { - uint32_t *dest = (uint32_t*)args->dest; - const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels(); - - int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + if (zbufferLine[x] <= posXW && zbufferLine[x + 1] <= posXW + stepXW) { - int x0 = leftEdge[y]; - int x1 = rightEdge[y]; + zbufferLine[x] = posXW; + zbufferLine[x + 1] = posXW + stepXW; - uint32_t *destLine = dest + pitch * y; - float *zbufferLine = zbuffer + stencilpitch * y; + uint32_t fgcolor[2]; + int32_t lightshade[2]; - float posXW = v1W + stepXW * (x0 + (0.5f - v1X)) + stepYW * (y + (0.5f - v1Y)); - float posXU = v1U + stepXU * (x0 + (0.5f - v1X)) + stepYU * (y + (0.5f - v1Y)); - float posXV = v1V + stepXV * (x0 + (0.5f - v1X)) + stepYV * (y + (0.5f - v1Y)); + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + fgcolor[0] = texPixels[texelX * texHeight + texelY]; - int x = x0; - while (x < x1) + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + lightshade[0] = lightpos >> 8; + + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + + rcpW = 0x01000000 / posXW; + u = (int32_t)(posXU * rcpW); + v = (int32_t)(posXV * rcpW); + texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + fgcolor[1] = texPixels[texelX * texHeight + texelY]; + + lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + lightshade[1] = lightpos >> 8; + + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + + __m128i mfgcolor = _mm_loadl_epi64((const __m128i*)fgcolor); + mfgcolor = _mm_unpacklo_epi8(mfgcolor, _mm_setzero_si128()); + + __m128i mlightshade = _mm_loadl_epi64((const __m128i*)lightshade); + mlightshade = _mm_shuffle_epi32(mlightshade, _MM_SHUFFLE(1, 0, 1, 0)); + mlightshade = _mm_packs_epi32(mlightshade, mlightshade); + + __m128i mdestcolor = _mm_srli_epi16(_mm_mullo_epi16(mfgcolor, mlightshade), 8); + mdestcolor = _mm_packus_epi16(mdestcolor, _mm_setzero_si128()); + mdestcolor = _mm_or_si128(mdestcolor, _mm_set1_epi32(0xff000000)); + + _mm_storel_epi64((__m128i*)(destLine + x), mdestcolor); + + x += 2; + } + else + { + for (int i = 0; i < 2; i++) { - bool processPixel = depthTest ? zbufferLine[x] <= posXW : true; - if (processPixel) // Pixel is visible (passed stencil and depth tests) + if (zbufferLine[x] <= posXW) { - if (writeColor) + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + + uint32_t fgcolor_r = RPART(fgcolor); + uint32_t fgcolor_g = GPART(fgcolor); + uint32_t fgcolor_b = BPART(fgcolor); + uint32_t fgcolor_a = APART(fgcolor); + if (fgcolor_a > 127) { - if (texPixels) - { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + fgcolor_r = (fgcolor_r * lightshade) >> 8; + fgcolor_g = (fgcolor_g * lightshade) >> 8; + fgcolor_b = (fgcolor_b * lightshade) >> 8; - uint32_t fgcolor_r = RPART(fgcolor); - uint32_t fgcolor_g = GPART(fgcolor); - uint32_t fgcolor_b = BPART(fgcolor); - uint32_t fgcolor_a = APART(fgcolor); - if (fgcolor_a > 127) - { - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; - - fgcolor_r = (fgcolor_r * lightshade) >> 8; - fgcolor_g = (fgcolor_g * lightshade) >> 8; - fgcolor_b = (fgcolor_b * lightshade) >> 8; - - destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; - } - } - else - { - destLine[x] = color; - } + destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; } - if (writeDepth) - zbufferLine[x] = posXW; + zbufferLine[x] = posXW; } posXW += stepXW; @@ -1286,68 +1329,184 @@ void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadD } } } - else + + while (x < x1) { - uint8_t *dest = args->dest; - const uint8_t *texPixels = args->uniforms->TexturePixels(); - - int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + if (zbufferLine[x] <= posXW) { - int x0 = leftEdge[y]; - int x1 = rightEdge[y]; + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); - uint8_t *destLine = dest + pitch * y; - float *zbufferLine = zbuffer + stencilpitch * y; + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; - float posXW = v1W + stepXW * (x0 + (0.5f - v1X)) + stepYW * (y + (0.5f - v1Y)); - float posXU = v1U + stepXU * (x0 + (0.5f - v1X)) + stepYU * (y + (0.5f - v1Y)); - float posXV = v1V + stepXV * (x0 + (0.5f - v1X)) + stepYV * (y + (0.5f - v1Y)); - - int x = x0; - while (x < x1) + uint32_t fgcolor_r = RPART(fgcolor); + uint32_t fgcolor_g = GPART(fgcolor); + uint32_t fgcolor_b = BPART(fgcolor); + uint32_t fgcolor_a = APART(fgcolor); + if (fgcolor_a > 127) { - bool processPixel = depthTest ? zbufferLine[x] <= posXW : true; - if (processPixel) // Pixel is visible (passed stencil and depth tests) - { - if (writeColor) - { - if (texPixels) - { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint8_t fgcolor = texPixels[texelX * texHeight + texelY]; + fgcolor_r = (fgcolor_r * lightshade) >> 8; + fgcolor_g = (fgcolor_g * lightshade) >> 8; + fgcolor_b = (fgcolor_b * lightshade) >> 8; - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; - - lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; - uint8_t shadedfg = colormaps[lightshade + fgcolor]; - - if (fgcolor != 0) - destLine[x] = shadedfg; - } - else - { - destLine[x] = color; - } - } - - if (writeDepth) - zbufferLine[x] = posXW; - } - - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; - x++; + destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; } + + zbufferLine[x] = posXW; } + + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + x++; + } +} + +#else + +void ScreenTriangle::DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args) +{ + float v1X = args->v1->x; + float v1Y = args->v1->y; + float v1W = args->v1->w; + float v1U = args->v1->u * v1W; + float v1V = args->v1->v * v1W; + float stepXW = args->gradientX.W; + float stepXU = args->gradientX.U; + float stepXV = args->gradientX.V; + float startX = x0 + (0.5f - v1X); + float startY = y + (0.5f - v1Y); + float posXW = v1W + stepXW * startX + args->gradientY.W * startY; + float posXU = v1U + stepXU * startX + args->gradientY.U * startY; + float posXV = v1V + stepXV * startX + args->gradientY.V * startY; + + const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels(); + int texWidth = args->uniforms->TextureWidth(); + int texHeight = args->uniforms->TextureHeight(); + + bool is_fixed_light = args->uniforms->FixedLight(); + uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; + uint32_t light = args->uniforms->Light(); + float shade = 2.0f - (light + 12.0f) / 128.0f; + float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); + light += light >> 7; // 255 -> 256 + + float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; + + uint32_t *dest = (uint32_t*)args->dest; + uint32_t *destLine = dest + args->pitch * y; + + int x = x0; + while (x < x1) + { + if (zbufferLine[x] <= posXW) + { + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + + uint32_t fgcolor_r = RPART(fgcolor); + uint32_t fgcolor_g = GPART(fgcolor); + uint32_t fgcolor_b = BPART(fgcolor); + uint32_t fgcolor_a = APART(fgcolor); + if (fgcolor_a > 127) + { + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; + + fgcolor_r = (fgcolor_r * lightshade) >> 8; + fgcolor_g = (fgcolor_g * lightshade) >> 8; + fgcolor_b = (fgcolor_b * lightshade) >> 8; + + destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; + } + + zbufferLine[x] = posXW; + } + + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + x++; + } +} + +#endif + +void ScreenTriangle::DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args) +{ + float v1X = args->v1->x; + float v1Y = args->v1->y; + float v1W = args->v1->w; + float v1U = args->v1->u * v1W; + float v1V = args->v1->v * v1W; + float stepXW = args->gradientX.W; + float stepXU = args->gradientX.U; + float stepXV = args->gradientX.V; + float startX = x0 + (0.5f - v1X); + float startY = y + (0.5f - v1Y); + float posXW = v1W + stepXW * startX + args->gradientY.W * startY; + float posXU = v1U + stepXU * startX + args->gradientY.U * startY; + float posXV = v1V + stepXV * startX + args->gradientY.V * startY; + + auto colormaps = args->uniforms->BaseColormap(); + + const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels(); + int texWidth = args->uniforms->TextureWidth(); + int texHeight = args->uniforms->TextureHeight(); + + bool is_fixed_light = args->uniforms->FixedLight(); + uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; + uint32_t light = args->uniforms->Light(); + float shade = 2.0f - (light + 12.0f) / 128.0f; + float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); + light += light >> 7; // 255 -> 256 + + float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; + + uint32_t *dest = (uint32_t*)args->dest; + uint32_t *destLine = dest + args->pitch * y; + + int x = x0; + while (x < x1) + { + if (zbufferLine[x] <= posXW) + { + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint8_t fgcolor = texPixels[texelX * texHeight + texelY]; + + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; + + lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; + uint8_t shadedfg = colormaps[lightshade + fgcolor]; + + if (fgcolor != 0) + destLine[x] = shadedfg; + } + + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; + x++; } } diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index 4b0666ccf..62f59ba44 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -150,6 +150,8 @@ class ScreenTriangle public: static void Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread); static void DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadData *thread); + static void DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args); + static void DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args); static void(*TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *); static void(*TriDrawers32[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *); From 01fd4041332a3e56b816fce825f9575bcd573087 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 28 Nov 2017 22:03:51 +0100 Subject: [PATCH 04/39] - Fix palette drawer crash --- src/polyrenderer/drawers/screen_triangle.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index b4d2168ae..7984f2523 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -1463,7 +1463,7 @@ void ScreenTriangle::DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs auto colormaps = args->uniforms->BaseColormap(); - const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels(); + const uint8_t *texPixels = args->uniforms->TexturePixels(); int texWidth = args->uniforms->TextureWidth(); int texHeight = args->uniforms->TextureHeight(); @@ -1476,8 +1476,8 @@ void ScreenTriangle::DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; - uint32_t *dest = (uint32_t*)args->dest; - uint32_t *destLine = dest + args->pitch * y; + uint8_t *dest = (uint8_t*)args->dest; + uint8_t *destLine = dest + args->pitch * y; int x = x0; while (x < x1) From fae514923a564a183b51f0eeb89763a87b17f1fb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 28 Nov 2017 23:08:28 +0100 Subject: [PATCH 05/39] - Move depth testing out of span drawers --- src/polyrenderer/drawers/screen_triangle.cpp | 332 ++++++++++--------- 1 file changed, 167 insertions(+), 165 deletions(-) diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index 7984f2523..37a7f843b 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -1179,21 +1179,88 @@ void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadD // Draw the triangle: - if (args->destBgra) + auto drawfunc = (args->destBgra) ? DrawSpan32 : DrawSpan8; + + float stepXW = args->gradientX.W; + float v1X = args->v1->x; + float v1Y = args->v1->y; + float v1W = args->v1->w; + + int num_cores = thread->num_cores; + for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) { - int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + int x = leftEdge[y]; + int xend = rightEdge[y]; + + float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; + + float startX = x + (0.5f - v1X); + float startY = y + (0.5f - v1Y); + float posXW = v1W + stepXW * startX + args->gradientY.W * startY; + +#ifndef NO_SSE + __m128 mstepXW = _mm_set1_ps(stepXW * 4.0f); + __m128 mfirstStepXW = _mm_setr_ps(0.0f, stepXW, stepXW + stepXW, stepXW + stepXW + stepXW); + while (x < xend) { - DrawSpan32(y, leftEdge[y], rightEdge[y], args); + int xstart = x; + + int xendsse = x + ((xend - x) & ~3); + __m128 mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW); + while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 15 && x < xendsse) + { + _mm_storeu_ps(zbufferLine + x, mposXW); + mposXW = _mm_add_ps(mposXW, mstepXW); + x += 4; + } + posXW = _mm_cvtss_f32(mposXW); + + while (zbufferLine[x] <= posXW && x < xend) + { + zbufferLine[x] = posXW; + posXW += stepXW; + x++; + } + + if (x > xstart) + drawfunc(y, xstart, x, args); + + xendsse = x + ((xend - x) & ~3); + mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW); + while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 0 && x < xendsse) + { + mposXW = _mm_add_ps(mposXW, mstepXW); + x += 4; + } + posXW = _mm_cvtss_f32(mposXW); + + while (zbufferLine[x] > posXW && x < xend) + { + posXW += stepXW; + x++; + } } - } - else - { - int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) +#else + while (x < xend) { - DrawSpan8(y, leftEdge[y], rightEdge[y], args); + int xstart = x; + while (zbufferLine[x] <= posXW && x < xend) + { + zbufferLine[x] = posXW; + posXW += stepXW; + x++; + } + + if (x > xstart) + drawfunc(y, xstart, x, args); + + while (zbufferLine[x] > posXW && x < xend) + { + posXW += stepXW; + x++; + } } +#endif } } @@ -1226,140 +1293,87 @@ void ScreenTriangle::DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); light += light >> 7; // 255 -> 256 - float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; - uint32_t *dest = (uint32_t*)args->dest; uint32_t *destLine = dest + args->pitch * y; int x = x0; - int sseEnd = x0 + (x1 - x0) / 2 * 2; + int sseEnd = x0 + ((x1 - x0) & ~3); while (x < sseEnd) { - if (zbufferLine[x] <= posXW && zbufferLine[x + 1] <= posXW + stepXW) - { - zbufferLine[x] = posXW; - zbufferLine[x + 1] = posXW + stepXW; + uint32_t fgcolor[2]; + int32_t lightshade[2]; - uint32_t fgcolor[2]; - int32_t lightshade[2]; + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + fgcolor[0] = texPixels[texelX * texHeight + texelY]; - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - fgcolor[0] = texPixels[texelX * texHeight + texelY]; + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + lightshade[0] = lightpos >> 8; - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - lightshade[0] = lightpos >> 8; + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; + rcpW = 0x01000000 / posXW; + u = (int32_t)(posXU * rcpW); + v = (int32_t)(posXV * rcpW); + texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + fgcolor[1] = texPixels[texelX * texHeight + texelY]; - rcpW = 0x01000000 / posXW; - u = (int32_t)(posXU * rcpW); - v = (int32_t)(posXV * rcpW); - texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - fgcolor[1] = texPixels[texelX * texHeight + texelY]; + lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + lightshade[1] = lightpos >> 8; - lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - lightshade[1] = lightpos >> 8; + posXW += stepXW; + posXU += stepXU; + posXV += stepXV; - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; + __m128i mfgcolor = _mm_loadl_epi64((const __m128i*)fgcolor); + mfgcolor = _mm_unpacklo_epi8(mfgcolor, _mm_setzero_si128()); - __m128i mfgcolor = _mm_loadl_epi64((const __m128i*)fgcolor); - mfgcolor = _mm_unpacklo_epi8(mfgcolor, _mm_setzero_si128()); + __m128i mlightshade = _mm_loadl_epi64((const __m128i*)lightshade); + mlightshade = _mm_shuffle_epi32(mlightshade, _MM_SHUFFLE(1, 0, 1, 0)); + mlightshade = _mm_packs_epi32(mlightshade, mlightshade); - __m128i mlightshade = _mm_loadl_epi64((const __m128i*)lightshade); - mlightshade = _mm_shuffle_epi32(mlightshade, _MM_SHUFFLE(1, 0, 1, 0)); - mlightshade = _mm_packs_epi32(mlightshade, mlightshade); + __m128i mdestcolor = _mm_srli_epi16(_mm_mullo_epi16(mfgcolor, mlightshade), 8); + mdestcolor = _mm_packus_epi16(mdestcolor, _mm_setzero_si128()); + mdestcolor = _mm_or_si128(mdestcolor, _mm_set1_epi32(0xff000000)); - __m128i mdestcolor = _mm_srli_epi16(_mm_mullo_epi16(mfgcolor, mlightshade), 8); - mdestcolor = _mm_packus_epi16(mdestcolor, _mm_setzero_si128()); - mdestcolor = _mm_or_si128(mdestcolor, _mm_set1_epi32(0xff000000)); + _mm_storel_epi64((__m128i*)(destLine + x), mdestcolor); - _mm_storel_epi64((__m128i*)(destLine + x), mdestcolor); - - x += 2; - } - else - { - for (int i = 0; i < 2; i++) - { - if (zbufferLine[x] <= posXW) - { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); - - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; - - uint32_t fgcolor_r = RPART(fgcolor); - uint32_t fgcolor_g = GPART(fgcolor); - uint32_t fgcolor_b = BPART(fgcolor); - uint32_t fgcolor_a = APART(fgcolor); - if (fgcolor_a > 127) - { - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; - - fgcolor_r = (fgcolor_r * lightshade) >> 8; - fgcolor_g = (fgcolor_g * lightshade) >> 8; - fgcolor_b = (fgcolor_b * lightshade) >> 8; - - destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; - } - - zbufferLine[x] = posXW; - } - - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; - x++; - } - } + x += 2; } while (x < x1) { - if (zbufferLine[x] <= posXW) + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + + uint32_t fgcolor_r = RPART(fgcolor); + uint32_t fgcolor_g = GPART(fgcolor); + uint32_t fgcolor_b = BPART(fgcolor); + uint32_t fgcolor_a = APART(fgcolor); + if (fgcolor_a > 127) { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + fgcolor_r = (fgcolor_r * lightshade) >> 8; + fgcolor_g = (fgcolor_g * lightshade) >> 8; + fgcolor_b = (fgcolor_b * lightshade) >> 8; - uint32_t fgcolor_r = RPART(fgcolor); - uint32_t fgcolor_g = GPART(fgcolor); - uint32_t fgcolor_b = BPART(fgcolor); - uint32_t fgcolor_a = APART(fgcolor); - if (fgcolor_a > 127) - { - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; - - fgcolor_r = (fgcolor_r * lightshade) >> 8; - fgcolor_g = (fgcolor_g * lightshade) >> 8; - fgcolor_b = (fgcolor_b * lightshade) >> 8; - - destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; - } - - zbufferLine[x] = posXW; + destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; } posXW += stepXW; @@ -1398,42 +1412,35 @@ void ScreenTriangle::DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); light += light >> 7; // 255 -> 256 - float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; - uint32_t *dest = (uint32_t*)args->dest; uint32_t *destLine = dest + args->pitch * y; int x = x0; while (x < x1) { - if (zbufferLine[x] <= posXW) + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); + + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + + uint32_t fgcolor_r = RPART(fgcolor); + uint32_t fgcolor_g = GPART(fgcolor); + uint32_t fgcolor_b = BPART(fgcolor); + uint32_t fgcolor_a = APART(fgcolor); + if (fgcolor_a > 127) { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint32_t fgcolor = texPixels[texelX * texHeight + texelY]; + fgcolor_r = (fgcolor_r * lightshade) >> 8; + fgcolor_g = (fgcolor_g * lightshade) >> 8; + fgcolor_b = (fgcolor_b * lightshade) >> 8; - uint32_t fgcolor_r = RPART(fgcolor); - uint32_t fgcolor_g = GPART(fgcolor); - uint32_t fgcolor_b = BPART(fgcolor); - uint32_t fgcolor_a = APART(fgcolor); - if (fgcolor_a > 127) - { - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; - - fgcolor_r = (fgcolor_r * lightshade) >> 8; - fgcolor_g = (fgcolor_g * lightshade) >> 8; - fgcolor_b = (fgcolor_b * lightshade) >> 8; - - destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; - } - - zbufferLine[x] = posXW; + destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b; } posXW += stepXW; @@ -1474,34 +1481,29 @@ void ScreenTriangle::DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); light += light >> 7; // 255 -> 256 - float *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y; - uint8_t *dest = (uint8_t*)args->dest; uint8_t *destLine = dest + args->pitch * y; int x = x0; while (x < x1) { - if (zbufferLine[x] <= posXW) - { - float rcpW = 0x01000000 / posXW; - int32_t u = (int32_t)(posXU * rcpW); - int32_t v = (int32_t)(posXV * rcpW); + float rcpW = 0x01000000 / posXW; + int32_t u = (int32_t)(posXU * rcpW); + int32_t v = (int32_t)(posXV * rcpW); - uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; - uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; - uint8_t fgcolor = texPixels[texelX * texHeight + texelY]; + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + uint8_t fgcolor = texPixels[texelX * texHeight + texelY]; - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - int lightshade = lightpos >> 8; + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + int lightshade = lightpos >> 8; - lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; - uint8_t shadedfg = colormaps[lightshade + fgcolor]; + lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; + uint8_t shadedfg = colormaps[lightshade + fgcolor]; - if (fgcolor != 0) - destLine[x] = shadedfg; - } + if (fgcolor != 0) + destLine[x] = shadedfg; posXW += stepXW; posXU += stepXU; From f9fb4a0a1742fddc32a4e1a4e0608a7b3f46d0a9 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 29 Nov 2017 00:12:15 +0100 Subject: [PATCH 06/39] - Cull back facing triangles for the span drawers --- src/polyrenderer/drawers/poly_triangle.cpp | 13 +++++++++++-- src/polyrenderer/drawers/poly_triangle.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp index 386c4c630..990ca581d 100644 --- a/src/polyrenderer/drawers/poly_triangle.cpp +++ b/src/polyrenderer/drawers/poly_triangle.cpp @@ -243,6 +243,15 @@ bool PolyTriangleDrawer::is_degenerate(const ShadedTriVertex *vert) return crosslengthsqr <= 1.e-6f; } +bool PolyTriangleDrawer::is_frontfacing(TriDrawTriangleArgs *args) +{ + float a = + args->v1->x * args->v2->y - args->v2->x * args->v1->y + + args->v2->x * args->v3->y - args->v3->x * args->v2->y + + args->v3->x * args->v1->y - args->v1->x * args->v3->y; + return a <= 0.0f; +} + void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread) { // Reject triangle if degenerate @@ -324,7 +333,7 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool args->v1 = &clippedvert[numclipvert - 1]; args->v2 = &clippedvert[i - 1]; args->v3 = &clippedvert[i - 2]; - if (args->CalculateGradients()) + if (is_frontfacing(args) && args->CalculateGradients()) ScreenTriangle::Draw(args, thread); } } @@ -335,7 +344,7 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool args->v1 = &clippedvert[0]; args->v2 = &clippedvert[i - 1]; args->v3 = &clippedvert[i]; - if (args->CalculateGradients()) + if (!is_frontfacing(args) && args->CalculateGradients()) ScreenTriangle::Draw(args, thread); } } diff --git a/src/polyrenderer/drawers/poly_triangle.h b/src/polyrenderer/drawers/poly_triangle.h index eea3b8531..7ddfbed19 100644 --- a/src/polyrenderer/drawers/poly_triangle.h +++ b/src/polyrenderer/drawers/poly_triangle.h @@ -44,6 +44,7 @@ private: static void draw_arrays(const PolyDrawArgs &args, WorkerThreadData *thread); static void draw_shaded_triangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread); static bool is_degenerate(const ShadedTriVertex *vertices); + static bool is_frontfacing(TriDrawTriangleArgs *args); static int clipedge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert); From b621dccb9cedfe5d0602c1c0ee8e909820ef2e2b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 29 Nov 2017 00:33:37 +0100 Subject: [PATCH 07/39] - Improve weapon hud model in the software renderer --- src/swrenderer/things/r_model.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp index 710df506b..f86a7e384 100644 --- a/src/swrenderer/things/r_model.cpp +++ b/src/swrenderer/things/r_model.cpp @@ -115,6 +115,25 @@ namespace swrenderer VSMatrix SWModelRenderer::GetViewToWorldMatrix() { + // Calculate the WorldToView matrix as it would have looked like without yshearing: + const auto &Viewpoint = Thread->Viewport->viewpoint; + const auto &Viewwindow = Thread->Viewport->viewwindow; + double radPitch = Viewpoint.Angles.Pitch.Normalized180().Radians(); + double angx = cos(radPitch); + double angy = sin(radPitch) * level.info->pixelstretch; + double alen = sqrt(angx*angx + angy*angy); + float adjustedPitch = (float)asin(angy / alen); + float adjustedViewAngle = (float)(Viewpoint.Angles.Yaw - 90).Radians(); + float ratio = Viewwindow.WidescreenRatio; + float fovratio = (Viewwindow.WidescreenRatio >= 1.3f) ? 1.333333f : ratio; + float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(Viewpoint.FieldOfView.Radians() / 2) / fovratio)).Degrees); + TriMatrix altWorldToView = + TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) * + TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) * + TriMatrix::scale(1.0f, level.info->pixelstretch, 1.0f) * + TriMatrix::swapYZ() * + TriMatrix::translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z); + TriMatrix swapYZ = TriMatrix::null(); swapYZ.matrix[0 + 0 * 4] = 1.0f; swapYZ.matrix[1 + 2 * 4] = 1.0f; @@ -122,7 +141,7 @@ namespace swrenderer swapYZ.matrix[3 + 3 * 4] = 1.0f; VSMatrix worldToView; - worldToView.loadMatrix((Thread->Viewport->WorldToView * swapYZ).matrix); + worldToView.loadMatrix((altWorldToView * swapYZ).matrix); VSMatrix objectToWorld; worldToView.inverseMatrix(objectToWorld); From 8cad912db1747330e8f3f6113ea0f9e7f103bc2f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 29 Nov 2017 01:09:26 +0100 Subject: [PATCH 08/39] - Add r_model_distance_cull to control when models turn into sprites --- src/swrenderer/scene/r_opaque_pass.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 3ad3ba1e0..989110e59 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -80,6 +80,7 @@ namespace { double sprite_distance_cull = 1e16; double line_distance_cull = 1e16; + double model_distance_cull = 1e16; } CUSTOM_CVAR(Float, r_sprite_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -106,6 +107,18 @@ CUSTOM_CVAR(Float, r_line_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } +CUSTOM_CVAR(Float, r_model_distance_cull, 1024, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/) // Experimental for the moment until a good default is chosen +{ + if (r_model_distance_cull > 0.0) + { + model_distance_cull = r_model_distance_cull * r_model_distance_cull; + } + else + { + model_distance_cull = 1e16; + } +} + namespace swrenderer { RenderOpaquePass::RenderOpaquePass(RenderThread *thread) : renderline(thread) @@ -955,7 +968,7 @@ namespace swrenderer int spritenum = thing->sprite; bool isPicnumOverride = thing->picnum.isValid(); FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); - if (modelframe) + if (modelframe && (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared() < model_distance_cull) { DVector3 pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac); RenderModel::Project(Thread, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing); From 12a44f5bc9ee03d254eeb791e2cd70939355361a Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Wed, 29 Nov 2017 07:43:17 -0500 Subject: [PATCH 09/39] - prevent nanosecond timer from ever casting into a double --- src/i_time.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i_time.cpp b/src/i_time.cpp index bea027243..ce394fb67 100644 --- a/src/i_time.cpp +++ b/src/i_time.cpp @@ -74,7 +74,7 @@ CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL) static uint64_t GetClockTimeNS() { using namespace std::chrono; - return (uint64_t)((duration_cast(steady_clock::now().time_since_epoch()).count()) * TimeScale); + return (uint64_t)((duration_cast(steady_clock::now().time_since_epoch()).count()) * (uint64_t)(TimeScale * 1000)); } static uint64_t MSToNS(unsigned int ms) From 6c4f6f94f436bb0555312805844217f1abc9aebb Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Wed, 29 Nov 2017 08:41:09 -0500 Subject: [PATCH 10/39] - fixed: prevent i_timescale from freezing the game if set to too low a value --- src/i_time.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/i_time.cpp b/src/i_time.cpp index ce394fb67..0511a79f0 100644 --- a/src/i_time.cpp +++ b/src/i_time.cpp @@ -55,20 +55,21 @@ static double TimeScale = 1.0; CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL) { - if (netgame && self != 1.0f) + if (netgame) { Printf("Time scale cannot be changed in net games.\n"); self = 1.0f; } - else + else if (self >= 0.05f) { I_FreezeTime(true); - float clampValue = (self < 0.05) ? 0.05f : self; - if (self != clampValue) - self = clampValue; TimeScale = self; I_FreezeTime(false); } + else + { + Printf("Time scale must be at least 0.05!\n"); + } } static uint64_t GetClockTimeNS() From a8b79a28c8c5ba90ee47d87cf5e7f555985d45de Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 29 Nov 2017 22:18:21 +0100 Subject: [PATCH 11/39] - Disable model rendering in the software renderer --- src/swrenderer/line/r_walldraw.cpp | 9 ++++++--- src/swrenderer/plane/r_flatplane.cpp | 3 ++- src/swrenderer/plane/r_skyplane.cpp | 3 ++- src/swrenderer/r_renderthread.h | 2 ++ src/swrenderer/scene/r_opaque_pass.cpp | 4 ++++ src/swrenderer/scene/r_scene.cpp | 4 +++- src/swrenderer/things/r_playersprite.cpp | 5 +++-- 7 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index a1972417a..5b7518440 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -262,7 +262,8 @@ namespace swrenderer drawerargs.SetTextureVStep(sampler.uv_step); drawerargs.SetTextureVPos(sampler.uv_pos); drawerargs.DrawColumn(Thread); - drawerargs.DrawDepthColumn(Thread, zbufferdepth); + if (r_models) + drawerargs.DrawDepthColumn(Thread, zbufferdepth); uint64_t step64 = sampler.uv_step; uint64_t pos64 = sampler.uv_pos; @@ -281,7 +282,8 @@ namespace swrenderer drawerargs.SetTextureVStep(sampler.uv_step); drawerargs.SetTextureVPos(sampler.uv_pos); drawerargs.DrawColumn(Thread); - drawerargs.DrawDepthColumn(Thread, zbufferdepth); + if (r_models) + drawerargs.DrawDepthColumn(Thread, zbufferdepth); uint64_t step64 = sampler.uv_step; uint64_t pos64 = sampler.uv_pos; @@ -308,7 +310,8 @@ namespace swrenderer drawerargs.SetTextureVStep(sampler.uv_step); drawerargs.SetTextureVPos(uv_pos); drawerargs.DrawColumn(Thread); - drawerargs.DrawDepthColumn(Thread, zbufferdepth); + if (r_models) + drawerargs.DrawDepthColumn(Thread, zbufferdepth); y += count; left -= count; diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 6161d0619..82e27f89f 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -275,7 +275,8 @@ namespace swrenderer drawerargs.SetDestX2(x2); drawerargs.DrawSpan(Thread); - drawerargs.DrawDepthSpan(Thread, zbufferdepth); + if (r_models) + drawerargs.DrawDepthSpan(Thread, zbufferdepth); } ///////////////////////////////////////////////////////////////////////// diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index eeb72ebe2..ef7a6b898 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -225,7 +225,8 @@ namespace swrenderer else drawerargs.DrawDoubleSkyColumn(Thread); - drawerargs.DrawDepthSkyColumn(Thread, 1.0f / 65536.0f); + if (r_models) + drawerargs.DrawDepthSkyColumn(Thread, 1.0f / 65536.0f); } void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2) diff --git a/src/swrenderer/r_renderthread.h b/src/swrenderer/r_renderthread.h index 6bc23bba5..3e559155b 100644 --- a/src/swrenderer/r_renderthread.h +++ b/src/swrenderer/r_renderthread.h @@ -29,6 +29,8 @@ class DrawerCommandQueue; typedef std::shared_ptr DrawerCommandQueuePtr; class RenderMemory; +EXTERN_CVAR(Bool, r_models); + namespace swrenderer { class VisibleSpriteList; diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 989110e59..f18cdc2ec 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -963,6 +963,10 @@ namespace swrenderer { RenderVoxel::Project(Thread, thing, sprite.pos, sprite.voxel, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap); } + else if (!r_models) + { + RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap); + } else { int spritenum = thing->sprite; diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 6cccef52e..8c0b81cef 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -67,6 +67,7 @@ EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Int, r_clearbuffer) CVAR(Bool, r_scene_multithreaded, false, 0); +CVAR(Bool, r_models, false, 0); namespace swrenderer { @@ -156,7 +157,8 @@ namespace swrenderer R_UpdateFuzzPosFrameStart(); - MainThread()->Viewport->SetupPolyViewport(); + if (r_models) + MainThread()->Viewport->SetupPolyViewport(); ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags; // Never draw the player unless in chasecam mode diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index 02f17bde6..41ec47239 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -88,14 +88,15 @@ namespace swrenderer int floorlight, ceilinglight; F3DFloor *rover; - renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); - if (!r_drawplayersprites || !Thread->Viewport->viewpoint.camera || !Thread->Viewport->viewpoint.camera->player || (players[consoleplayer].cheats & CF_CHASECAM) || (r_deathcamera && Thread->Viewport->viewpoint.camera->health <= 0)) return; + + if (r_models && gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player)) + renderHUDModel = true; FDynamicColormap *basecolormap; CameraLight *cameraLight = CameraLight::Instance(); From 0d05b41f22d6e07ff74020d086cfe1c456083afb Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 2 Dec 2017 11:51:52 +0200 Subject: [PATCH 12/39] Fixed incomplete ACS string pool state after loading of saved game https://forum.zdoom.org/viewtopic.php?t=58571 --- src/p_acs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2dfbec49b..3d93e7a0a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1365,6 +1365,8 @@ void ACSStringPool::ReadStrings(FSerializer &file, const char *key) } } } + + FindFirstFreeEntry(FirstFreeEntry); } //============================================================================ From cbd2fd34a0d267348da3d7b6c924cde0dbec2c9c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 11:51:37 +0100 Subject: [PATCH 13/39] - added seeking capabilities to FileWriter class. --- src/files.cpp | 24 ++++++++++++++++++++++++ src/files.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/files.cpp b/src/files.cpp index 0de13e8ea..5bcc3d7bb 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -634,6 +634,30 @@ size_t FileWriter::Write(const void *buffer, size_t len) } } +long FileWriter::Tell() +{ + if (File != NULL) + { + return ftell(File); + } + else + { + return 0; + } +} + +long FileWriter::Seek(long offset, int mode) +{ + if (File != NULL) + { + return fseek(File, offset, mode); + } + else + { + return 0; + } +} + size_t FileWriter::Printf(const char *fmt, ...) { diff --git a/src/files.h b/src/files.h index 4c73273a1..94255b1a0 100644 --- a/src/files.h +++ b/src/files.h @@ -409,6 +409,8 @@ public: static FileWriter *Open(const char *filename); virtual size_t Write(const void *buffer, size_t len); + virtual long Tell(); + virtual long Seek(long offset, int mode); size_t Printf(const char *fmt, ...) GCCPRINTF(2,3); protected: From 9cc8bab102b47b7f8fd8ac77e6f629f7cff71b7b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 11:55:50 +0100 Subject: [PATCH 14/39] - only have one fopen call in the entire FileReader hierarchy This is for an eventual implementation of UTF-8 handling. On Windows this will require replacement of fopen with _wfopen so let's try to keep the number of fopen calls low. --- src/files.cpp | 7 ++++++- src/files.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/files.cpp b/src/files.cpp index 5bcc3d7bb..b42aefece 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -50,6 +50,11 @@ // //========================================================================== +FILE *FileReader::openfd(const char *filename) +{ + return fopen(filename, "rb"); +} + FileReader::FileReader () : File(NULL), Length(0), StartPos(0), FilePos(0), CloseOnDestruct(false) { @@ -93,7 +98,7 @@ FileReader::~FileReader () bool FileReader::Open (const char *filename) { - File = fopen (filename, "rb"); + File = openfd (filename); if (File == NULL) return false; FilePos = 0; StartPos = 0; diff --git a/src/files.h b/src/files.h index 94255b1a0..d0c769ba1 100644 --- a/src/files.h +++ b/src/files.h @@ -93,6 +93,8 @@ public: class FileReader : public FileReaderBase { +protected: + FILE *openfd(const char *filename); public: FileReader (); FileReader (const char *filename); From e1edb46bbbde70733cdd6843a16a6f127dd35330 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 11:56:26 +0100 Subject: [PATCH 15/39] - - let FWadLump use the newly added fdopen function. --- src/w_wad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 412450d0a..ae52725d2 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -1554,7 +1554,7 @@ FWadLump::FWadLump(int lumpnum, FResourceLump *lump) // Uncompressed lump in a file. For this we will have to open a new FILE, since we need it for streaming int fileno = Wads.GetLumpFile(lumpnum); const char *filename = Wads.GetWadFullName(fileno); - File = fopen(filename, "rb"); + File = openfd(filename); if (File != NULL) { Length = lump->LumpSize; From 20b8c1ef70720296dd618f422e669fe3acd76d1e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 11:57:32 +0100 Subject: [PATCH 16/39] - moved buildtexture.cpp from using stdio-based file IO to FileReader. --- src/textures/buildtexture.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/textures/buildtexture.cpp b/src/textures/buildtexture.cpp index cb7786200..d23e5e6f2 100644 --- a/src/textures/buildtexture.cpp +++ b/src/textures/buildtexture.cpp @@ -306,15 +306,16 @@ int FTextureManager::CountBuildTiles () FString artpath = rffpath; artpath += artfile; - FILE *f = fopen (artpath, "rb"); - if (f == NULL) + FileReader fr; + + if (!fr.Open(artpath)) { break; } - size_t len = Q_filelength (f); + long len = fr.GetLength(); uint8_t *art = new uint8_t[len]; - if (fread (art, 1, len, f) != len || (numtiles = CountTiles(art)) == 0) + if (fr.Read (art, len) != len || (numtiles = CountTiles(art)) == 0) { delete[] art; } @@ -323,7 +324,6 @@ int FTextureManager::CountBuildTiles () BuildTileFiles.Push (art); totaltiles += numtiles; } - fclose (f); } } From e8735e27826b4489f5fd6a736130adbb5e21ef0c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 11:59:31 +0100 Subject: [PATCH 17/39] - use FileWriter to save the statistics file. --- src/statistics.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/statistics.cpp b/src/statistics.cpp index 2abd0bf12..e70642cf4 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -72,6 +72,7 @@ #include "m_crc32.h" #include "serializer.h" #include "g_levellocals.h" +#include "files.h" CVAR(Int, savestatistics, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, statfile, "zdoomstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -260,8 +261,8 @@ static void SaveStatistics(const char *fn, TArray &statlist) { unsigned int j; - FILE * f = fopen(fn, "wt"); - if (f==NULL) return; + FileWriter *fw = FileWriter::Open(fn); + if (fw == nullptr) return; qsort(&statlist[0], statlist.Size(), sizeof(statlist[0]), compare_episode_names); for(unsigned i=0;i &statlist) qsort(&ep_stats.stats[0], ep_stats.stats.Size(), sizeof(ep_stats.stats[0]), compare_dates); - fprintf(f, "%s \"%s\"\n{\n", ep_stats.epi_header.GetChars(), ep_stats.epi_name.GetChars()); + fw->Printf("%s \"%s\"\n{\n", ep_stats.epi_header.GetChars(), ep_stats.epi_name.GetChars()); for(j=0;jinfo[0]>0) { - fprintf(f,"\t%2i. %10s \"%-22s\" %02d:%02d:%02d %i\n", j+1, sst->name, sst->info, + fw->Printf("\t%2i. %10s \"%-22s\" %02d:%02d:%02d %i\n", j+1, sst->name, sst->info, hours(sst->timeneeded), minutes(sst->timeneeded), seconds(sst->timeneeded), sst->skill); TArray &ls = sst->levelstats; if (ls.Size() > 0) { - fprintf(f,"\t{\n"); + fw->Printf("\t{\n"); qsort(&ls[0], ls.Size(), sizeof(ls[0]), compare_level_names); for(unsigned k=0;kPrintf("\t\t%-8s \"%-22s\" %02d:%02d:%02d\n", ls[k].name, ls[k].info, hours(ls[k].timeneeded), minutes(ls[k].timeneeded), seconds(ls[k].timeneeded)); } - fprintf(f,"\t}\n"); + fw->Printf("\t}\n"); } } } - fprintf(f,"}\n\n"); + fw->Printf("}\n\n"); } - fclose(f); + delete fw; } From 5e7dfa7cce24dfa7149f551559f963151fa3a471 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:01:19 +0100 Subject: [PATCH 18/39] - use FileWriter for the Timidity MIDI dumper --- src/sound/i_musicinterns.h | 2 +- .../mididevices/music_timidity_mididevice.cpp | 38 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 7bc5a31e5..4c796ead5 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -239,7 +239,7 @@ public: void Stop(); protected: - FILE *File; + FileWriter *File; }; // WildMidi implementation of a MIDI device --------------------------------- diff --git a/src/sound/mididevices/music_timidity_mididevice.cpp b/src/sound/mididevices/music_timidity_mididevice.cpp index cacddf542..474c0efa9 100644 --- a/src/sound/mididevices/music_timidity_mididevice.cpp +++ b/src/sound/mididevices/music_timidity_mididevice.cpp @@ -89,7 +89,7 @@ struct FmtChunk TimidityMIDIDevice::TimidityMIDIDevice(const char *args) { - Renderer = NULL; + Renderer = nullptr; Renderer = new Timidity::Renderer((float)SampleRate, args); } @@ -102,7 +102,7 @@ TimidityMIDIDevice::TimidityMIDIDevice(const char *args) TimidityMIDIDevice::~TimidityMIDIDevice() { Close(); - if (Renderer != NULL) + if (Renderer != nullptr) { delete Renderer; } @@ -246,10 +246,10 @@ FString TimidityMIDIDevice::GetStats() //========================================================================== TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate) - :TimidityMIDIDevice(NULL) + :TimidityMIDIDevice(nullptr) { - File = fopen(filename, "wb"); - if (File != NULL) + File = FileWriter::Open(filename); + if (File != nullptr) { // Write wave header uint32_t work[3]; FmtChunk fmt; @@ -257,7 +257,7 @@ TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, work[0] = MAKE_ID('R','I','F','F'); work[1] = 0; // filled in later work[2] = MAKE_ID('W','A','V','E'); - if (3 != fwrite(work, 4, 3, File)) goto fail; + if (4*3 != File->Write(work, 4 * 3)) goto fail; fmt.ChunkID = MAKE_ID('f','m','t',' '); fmt.ChunkLen = LittleLong(uint32_t(sizeof(fmt) - 8)); @@ -281,17 +281,17 @@ TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, fmt.SubFormatD[5] = 0x38; fmt.SubFormatD[6] = 0x9b; fmt.SubFormatD[7] = 0x71; - if (1 != fwrite(&fmt, sizeof(fmt), 1, File)) goto fail; + if (sizeof(fmt) != File->Write(&fmt, sizeof(fmt))) goto fail; work[0] = MAKE_ID('d','a','t','a'); work[1] = 0; // filled in later - if (2 != fwrite(work, 4, 2, File)) goto fail; + if (8 !=File->Write(work, 8)) goto fail; return; fail: Printf("Failed to write %s: %s\n", filename, strerror(errno)); - fclose(File); - File = NULL; + delete File; + File = nullptr; } } @@ -303,30 +303,30 @@ fail: TimidityWaveWriterMIDIDevice::~TimidityWaveWriterMIDIDevice() { - if (File != NULL) + if (File != nullptr) { - long pos = ftell(File); + long pos = File->Tell(); uint32_t size; // data chunk size size = LittleLong(uint32_t(pos - 8)); - if (0 == fseek(File, 4, SEEK_SET)) + if (0 == File->Seek(4, SEEK_SET)) { - if (1 == fwrite(&size, 4, 1, File)) + if (4 == File->Write(&size, 4)) { size = LittleLong(uint32_t(pos - 12 - sizeof(FmtChunk) - 8)); - if (0 == fseek(File, 4 + sizeof(FmtChunk) + 4, SEEK_CUR)) + if (0 == File->Seek(4 + sizeof(FmtChunk) + 4, SEEK_CUR)) { - if (1 == fwrite(&size, 4, 1, File)) + if (1 == File->Write(&size, 4)) { - fclose(File); + delete File; return; } } } } Printf("Could not finish writing wave file: %s\n", strerror(errno)); - fclose(File); + delete File; } } @@ -342,7 +342,7 @@ int TimidityWaveWriterMIDIDevice::Resume() while (ServiceStream(writebuffer, sizeof(writebuffer))) { - if (fwrite(writebuffer, sizeof(writebuffer), 1, File) != 1) + if (File->Write(writebuffer, sizeof(writebuffer)) != sizeof(writebuffer)) { Printf("Could not write entire wave file: %s\n", strerror(errno)); return 1; From ab58e4acb05cec76106fa8052b18129346cdf93c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:01:55 +0100 Subject: [PATCH 19/39] - use FileWriter for the AST dump. --- src/scripting/zscript/zcc_parser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index a0af21c14..cb927bb50 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -462,11 +462,11 @@ static void DoParse(int lumpnum) FString filename = Wads.GetLumpFullPath(lumpnum); filename.ReplaceChars(":\\/?|", '.'); filename << ".ast"; - FILE *ff = fopen(filename, "w"); + FileWriter *ff = FileWriter::Open(filename); if (ff != NULL) { - fputs(ast.GetChars(), ff); - fclose(ff); + ff->Write(ast.GetChars(), ast.Len()); + delete ff; } } From 37dc3211f73586795d5f607cbf0be5a447e9d391 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:02:36 +0100 Subject: [PATCH 20/39] - use FileReader for reading the play list. --- src/s_playlist.cpp | 13 ++++++------- src/s_playlist.h | 4 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index e1b0fd5b6..315a2ac76 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -39,6 +39,7 @@ #include "s_playlist.h" #include "templates.h" #include "v_text.h" +#include "files.h" FPlayList::FPlayList (const char *path) { @@ -53,7 +54,7 @@ bool FPlayList::ChangeList (const char *path) { FString playlistdir; FString song; - FILE *file; + FileReader fr; bool first; bool pls; int i; @@ -61,7 +62,7 @@ bool FPlayList::ChangeList (const char *path) Songs.Clear(); Position = 0; - if ( (file = fopen (path, "rb")) == NULL) + if (!fr.Open(path)) { Printf ("Could not open " TEXTCOLOR_BOLD "%s" TEXTCOLOR_NORMAL ": %s\n", path, strerror(errno)); return false; @@ -70,7 +71,7 @@ bool FPlayList::ChangeList (const char *path) first = true; pls = false; playlistdir = ExtractFilePath(path); - while ((song = NextLine(file)).IsNotEmpty()) + while ((song = NextLine(&fr)).IsNotEmpty()) { if (first) { @@ -129,19 +130,17 @@ bool FPlayList::ChangeList (const char *path) Songs.Push(song); } } - fclose (file); - return Songs.Size() != 0; } -FString FPlayList::NextLine (FILE *file) +FString FPlayList::NextLine (FileReader *file) { char buffer[512]; char *skipper; do { - if (NULL == fgets (buffer, countof(buffer), file)) + if (NULL == file->Gets (buffer, countof(buffer))) return ""; for (skipper = buffer; *skipper != 0 && *skipper <= ' '; skipper++) diff --git a/src/s_playlist.h b/src/s_playlist.h index 74c06f857..859f0bce4 100644 --- a/src/s_playlist.h +++ b/src/s_playlist.h @@ -34,6 +34,8 @@ #ifndef __S_PLAYLIST_H__ #define __S_PLAYLIST_H__ +class FileReader; + class FPlayList { public: @@ -51,7 +53,7 @@ public: const char *GetSong (int position) const; private: - static FString NextLine (FILE *file); + static FString NextLine (FileReader *file); unsigned int Position; TArray Songs; From 623f35073c8a3936a4bb51d680e0df95399cecd3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:08:28 +0100 Subject: [PATCH 21/39] - use FileReader consistently for loading cached nodes. --- src/p_glnodes.cpp | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index e1510145e..977426e57 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1133,16 +1133,15 @@ static void CreateCachedNodes(MapData *map) memcpy(compressed + offset - 4, "ZGL3", 4); FString path = CreateCacheName(map, true); - FILE *f = fopen(path, "wb"); + FileWriter *fw = FileWriter::Open(path); - if (f != NULL) + if (fw != nullptr) { - if (fwrite(compressed, outlen+offset, 1, f) != 1) + if (fw->Write(compressed, outlen+offset) != 1) { Printf("Error saving nodes to file %s\n", path.GetChars()); } - - fclose(f); + delete fw; } else { @@ -1162,32 +1161,30 @@ static bool CheckCachedNodes(MapData *map) uint32_t *verts = NULL; FString path = CreateCacheName(map, false); - FILE *f = fopen(path, "rb"); - if (f == NULL) return false; + FileReader fr; - if (fread(magic, 1, 4, f) != 4) goto errorout; + if (!fr.Open(path)) return false; + + if (fr.Read(magic, 4) != 4) goto errorout; if (memcmp(magic, "CACH", 4)) goto errorout; - if (fread(&numlin, 4, 1, f) != 1) goto errorout; + if (fr.Read(&numlin, 4) != 4) goto errorout; numlin = LittleLong(numlin); if (numlin != level.lines.Size()) goto errorout; - if (fread(md5, 1, 16, f) != 16) goto errorout; + if (fr.Read(md5, 16) != 16) goto errorout; map->GetChecksum(md5map); if (memcmp(md5, md5map, 16)) goto errorout; verts = new uint32_t[numlin * 8]; - if (fread(verts, 8, numlin, f) != numlin) goto errorout; + if (fr.Read(verts, 8 * numlin) != 8 * numlin) goto errorout; - if (fread(magic, 1, 4, f) != 4) goto errorout; + if (fr.Read(magic, 4) != 4) goto errorout; if (memcmp(magic, "ZGL2", 4) && memcmp(magic, "ZGL3", 4)) goto errorout; try { - long pos = ftell(f); - FileReader fr(f); - fr.Seek(pos, SEEK_SET); P_LoadZNodes (fr, MAKE_ID(magic[0],magic[1],magic[2],magic[3])); } catch (CRecoverableError &error) @@ -1208,7 +1205,6 @@ static bool CheckCachedNodes(MapData *map) } delete [] verts; - fclose(f); return true; errorout: @@ -1216,7 +1212,6 @@ errorout: { delete[] verts; } - fclose(f); return false; } From ebf5c5763e5c11c01a76e61990264693e5502943 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:15:26 +0100 Subject: [PATCH 22/39] - removed the unused bitmap loading and saving features from hqnx_asm/hqnx_asm_Image. --- src/gl/hqnx_asm/hqnx_asm_Image.cpp | 1072 ---------------------------- src/gl/hqnx_asm/hqnx_asm_Image.h | 75 -- 2 files changed, 1147 deletions(-) diff --git a/src/gl/hqnx_asm/hqnx_asm_Image.cpp b/src/gl/hqnx_asm/hqnx_asm_Image.cpp index 7af120173..31adda874 100644 --- a/src/gl/hqnx_asm/hqnx_asm_Image.cpp +++ b/src/gl/hqnx_asm/hqnx_asm_Image.cpp @@ -106,1078 +106,6 @@ int DLL CImage::Convert32To17( void ) return nRes; } -int DLL CImage::ConvertTo32( void ) -{ - int nRes = eConvUnknownFormat; - if ( m_pBitmap == NULL ) - return eConvSourceMemory; - - switch ( m_BitPerPixel ) - { - case 8: - { - nRes = 0; - m_BitPerPixel = 32; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*4); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp8 = m_pBitmap; - unsigned char * pTemp32 = pNewBitmap; - unsigned char c; - for ( int i=0; i> 3); - *(pTemp24++) = ((rgb & 0xF800) >> 8); - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - case 32: - { - nRes = 0; - m_BitPerPixel = 24; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*3); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp32 = m_pBitmap; - unsigned char * pTemp24 = pNewBitmap; - for ( int i=0; i> 3; - g = m_Pal[c].g >> 2; - b = m_Pal[c].b >> 3; - *(pTemp16++) = (r << 11) + (g << 5) + b; - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - case 24: - { - nRes = 0; - m_BitPerPixel = 16; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*2); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp24 = m_pBitmap; - unsigned short * pTemp16 = (unsigned short *)pNewBitmap; - unsigned short r, g, b; - for ( int i=0; i> 3; - g = (*(pTemp24++)) >> 2; - r = (*(pTemp24++)) >> 3; - *(pTemp16++) = (r << 11) + (g << 5) + b; - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - case 32: - { - nRes = 0; - m_BitPerPixel = 16; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*2); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp32 = m_pBitmap; - unsigned short * pTemp16 = (unsigned short *)pNewBitmap; - unsigned short r, g, b; - for ( int i=0; i> 3; - g = (*(pTemp32++)) >> 2; - r = (*(pTemp32++)) >> 3; - pTemp32++; - *(pTemp16++) = (r << 11) + (g << 5) + b; - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - } - - return nRes; -} - -int CImage::Convert8To17( int transindex ) -{ - int nRes = eConvUnknownFormat; - - if ( m_BitPerPixel == 8 ) - { - m_BitPerPixel = 32; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*4); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp8 = m_pBitmap; - unsigned int * pTemp32 = (unsigned int *)pNewBitmap; - unsigned int r, g, b; - unsigned char c; - for ( int i=0; i> 3; - g = m_Pal[c].g >> 2; - b = m_Pal[c].b >> 3; - *(pTemp32++) = (r << 11) + (g << 5) + b + (transindex != c ? 0x10000 : 0); - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - nRes = 0; - } - - return nRes; -} - -int CImage::SaveBmp(char *szFilename) -{ - _BMPFILEHEADER fh; - _BMPIMAGEHEADER ih; - unsigned char BmpPal[256][4]; - long int SuffLen; - long int Dummy = 0; - unsigned char * pBuf; - short i; - - if (!(f = fopen(szFilename, "wb"))) return eSaveBmpFileOpen; - if ( m_pBitmap == NULL ) return eSaveBmpSourceMemory; - - fh.bfType=0x4D42; - if (m_BitPerPixel==8) - { - SuffLen=((m_Xres+3)/4)*4-m_Xres; - ih.biSize=0x28; - ih.biWidth=m_Xres; - ih.biHeight=m_Yres; - ih.biPlanes=1; - ih.biBitCount=8; - ih.biCompression=0; - ih.biSizeImage=(m_Xres+SuffLen)*m_Yres; - ih.biXPelsPerMeter=ih.biYPelsPerMeter=0x2E23; // 300dpi (pixels per meter) - ih.biClrUsed=ih.biClrImportant=0; - fh.bfSize=(ih.biSizeImage)+0x0436; - fh.bfRes1=0; - fh.bfOffBits=0x0436; - if (fwrite(&fh, 14, 1, f) != 1) return eSaveBmpFileWrite; - if (fwrite(&ih, 40, 1, f) != 1) return eSaveBmpFileWrite; - for (i=0; i<256; i++) - { - BmpPal[i][0]=m_Pal[i].b; - BmpPal[i][1]=m_Pal[i].g; - BmpPal[i][2]=m_Pal[i].r; - BmpPal[i][3]=0; - } - if (fwrite(&BmpPal, 1024, 1, f) != 1) return eSaveBmpFileWrite; - pBuf=m_pBitmap; - pBuf+=m_NumPixel; - for (i=0; i0) - { - if (fwrite(&Dummy, SuffLen, 1, f) != 1) return eSaveBmpFileWrite; - } - } - } - else - if (m_BitPerPixel==24) - { - SuffLen=((m_Xres*3+3)/4)*4-m_Xres*3; - ih.biSize=0x28; - ih.biWidth=m_Xres; - ih.biHeight=m_Yres; - ih.biPlanes=1; - ih.biBitCount=24; - ih.biCompression=0; - ih.biSizeImage=(m_Xres*3+SuffLen)*m_Yres; - ih.biXPelsPerMeter=ih.biYPelsPerMeter=0x2E23; // 300dpi (pixels per meter) - ih.biClrUsed=ih.biClrImportant=0; - fh.bfSize=(ih.biSizeImage)+0x0036; - fh.bfRes1=0; - fh.bfOffBits=0x0036; - if (fwrite(&fh, 14, 1, f) != 1) return eSaveBmpFileWrite; - if (fwrite(&ih, 40, 1, f) != 1) return eSaveBmpFileWrite; - pBuf=m_pBitmap; - pBuf+=m_NumPixel*3; - for (i=0; i0) - { - if (fwrite(&Dummy, SuffLen, 1, f) != 1) return eSaveBmpFileWrite; - } - } - } - else - return eSaveBmpColorDepth; - - fclose(f); - - return 0; -} - -int CImage::LoadBmp(char *szFilename) -{ - _BMPFILEHEADER fh; - _BMPIMAGEHEADEROLD ih_old; - _BMPIMAGEHEADER ih; - unsigned char BmpPal[256][4]; - long int biSize; - long int SuffLen; - long int Dummy = 0; - unsigned char * pBuf; - short i; - long int xres, yres; - unsigned short bits; - - if (!(f = fopen(szFilename, "rb"))) return eLoadBmpFileOpen; - if (fread(&fh, 14, 1, f) != 1) return eLoadBmpFileRead; - if (fh.bfType != 0x4D42) return eLoadBmpBadFormat; - if (fread(&biSize, 4, 1, f) != 1) return eLoadBmpFileRead; - if (biSize > 12) - { - fseek( f, -4, SEEK_CUR ); - if (fread(&ih, biSize, 1, f) != 1) return eLoadBmpFileRead; - xres = ih.biWidth; - yres = ih.biHeight; - bits = ih.biBitCount; - } - else - { - fseek( f, -4, SEEK_CUR ); - if (fread(&ih_old, biSize, 1, f) != 1) return eLoadBmpFileRead; - xres = ih_old.biWidth; - yres = ih_old.biHeight; - bits = ih_old.biBitCount; - } - - if ( Init( xres, yres, bits ) != 0 ) return eLoadBmpInit; - if (m_BitPerPixel==8) - { - SuffLen=((m_Xres+3)/4)*4-m_Xres; - if (fread(&BmpPal, 1024, 1, f) != 1) return eLoadBmpFileRead; - for (i=0; i<256; i++) - { - m_Pal[i].b=BmpPal[i][0]; - m_Pal[i].g=BmpPal[i][1]; - m_Pal[i].r=BmpPal[i][2]; - } - pBuf=m_pBitmap; - pBuf+=m_NumPixel; - for (i=0; i0) - { - if (fread(&Dummy, SuffLen, 1, f) != 1) return eLoadBmpFileRead; - } - } - } - else - if (m_BitPerPixel==24) - { - SuffLen=((m_Xres*3+3)/4)*4-(m_Xres*3); - pBuf=m_pBitmap; - pBuf+=m_NumPixel*3; - for (i=0; i0) - { - if (fread(&Dummy, SuffLen, 1, f) != 1) return eLoadBmpFileRead; - } - } - } - else - return eLoadBmpColorDepth; - - fclose(f); - - return 0; -} - -void CImage::Output( void ) -{ - fwrite(m_cBuf, m_nCount, 1, f); - m_nCount=0; -} - -void CImage::Output( char c ) -{ - if ( m_nCount == sizeof(m_cBuf) ) - { - fwrite(m_cBuf, m_nCount, 1, f); - m_nCount=0; - } - m_cBuf[m_nCount++] = c; -} - -void CImage::Output( char * pcData, int nSize ) -{ - for ( int i=0; i 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+i-nDif-nRep), nDif ); - } - nDif = 1; - } - } - else - { - if ( bEqual && (nRep<127) ) - nRep++; - else - { - Output( nRep+128 ); - Output( (char*)&colOld, 1 ); - nRep = 0; - nDif = 1; - } - } - } - - if ( nRep == 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+m_Xres-nDif), nDif ); - } - else - { - Output( nRep+128 ); - Output( (char*)&colOld, 1 ); - } - Output(); - } - } - } - else - if (m_BitPerPixel==24) - { - fh.tiImageType = bCompressed ? 10 : 2; - if (fwrite(&fh, sizeof(fh), 1, f) != 1) return eSaveTgaFileWrite; - - _BGR * pcolBuf = (_BGR *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+i-nDif-nRep), sizeof(_BGR)*nDif ); - } - nDif = 1; - } - } - else - { - if ( bEqual && (nRep<127) ) - nRep++; - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGR) ); - nRep = 0; - nDif = 1; - } - } - } - - if ( nRep == 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+m_Xres-nDif), sizeof(_BGR)*nDif ); - } - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGR) ); - } - Output(); - } - } - } - else - if (m_BitPerPixel==32) - { - fh.tiImageType = bCompressed ? 10 : 2; - fh.tiAttrBits = 8; - if (fwrite(&fh, sizeof(fh), 1, f) != 1) return eSaveTgaFileWrite; - - _BGRA * pcolBuf = (_BGRA *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+i-nDif-nRep), sizeof(_BGRA)*nDif ); - } - nDif = 1; - } - } - else - { - if ( bEqual && (nRep<127) ) - nRep++; - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGRA) ); - nRep = 0; - nDif = 1; - } - } - } - - if ( nRep == 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+m_Xres-nDif), sizeof(_BGRA)*nDif ); - } - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGRA) ); - } - Output(); - } - } - } - else - return eSaveTgaColorDepth; - - fclose(f); - - return 0; -} - -int CImage::LoadTga(char *szFilename) -{ - _TGAHEADER fh; - int i, j, k; - unsigned char nCount; - - if (!(f = fopen(szFilename, "rb"))) return eLoadTgaFileOpen; - if (fread(&fh, sizeof(fh), 1, f) != 1) return eLoadTgaFileRead; - bool bCompressed = (( fh.tiImageType & 8 ) != 0); - if ((fh.tiBitPerPixel<=0) || (fh.tiBitPerPixel>32)) - return eLoadTgaBadFormat; - - if ( Init( fh.tiXres, fh.tiYres, fh.tiBitPerPixel ) != 0 ) - return eLoadTgaInit; - - if ( m_BitPerPixel == 8 ) - { - if ( fh.tiPaletteIncluded == 1 ) - { - if ( fh.tiPaletteBpp == 24) - { - if (fread(&m_Pal, 3, fh.tiPaletteSize, f) != fh.tiPaletteSize) - return eLoadTgaFileRead; - } - else - if ( fh.tiPaletteBpp == 32) - { - unsigned char BmpPal[256][4]; - - if (fread(&BmpPal, 4, fh.tiPaletteSize, f) != fh.tiPaletteSize) - return eLoadTgaFileRead; - - for (i=0; i= m_pBitmap ) - { - nCount = Input(); - if ((nCount & 128)==0) - { - for (k=0; k<=nCount; k++) - { - colCur = Input(); - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - else - { - colCur = Input(); - for (k=0; k<=nCount-128; k++) - { - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - } - } - } - else - if ( m_BitPerPixel == 24 ) - { - _BGR * pcolBuf = (_BGR *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j= (_BGR *)m_pBitmap ) - { - nCount = Input(); - if ((nCount & 128)==0) - { - for (k=0; k<=nCount; k++) - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - else - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - for (k=0; k<=nCount-128; k++) - { - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - } - } - } - else - if ( m_BitPerPixel == 32 ) - { - _BGRA * pcolBuf = (_BGRA *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j= (_BGRA *)m_pBitmap ) - { - nCount = Input(); - if ((nCount & 128)==0) - { - for (k=0; k<=nCount; k++) - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - colCur.a = Input(); - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - else - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - colCur.a = Input(); - for (k=0; k<=nCount-128; k++) - { - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - } - } - } - else - return eLoadTgaColorDepth; - - fclose(f); - - return 0; -} - -int DLL CImage::Load(char *szFilename) -{ - int nRes = 0; - - if ( szFilename != NULL ) - { - char * szExt = strrchr( szFilename, '.' ); - int nNotTGA = 1; - - if ( szExt != NULL ) - nNotTGA = _stricmp( szExt, ".tga" ); - - if ( nNotTGA != 0 ) - nRes = LoadBmp( szFilename ); - else - nRes = LoadTga( szFilename ); - } - else - nRes = eLoadFilename; - - return nRes; -} - -int DLL CImage::Save(char *szFilename) -{ - int nRes = 0; - int nNotTGA = 1; - - if ( szFilename != NULL ) - { - char * szExt = strrchr( szFilename, '.' ); - - if ( szExt != NULL ) - nNotTGA = _stricmp( szExt, ".tga" ); - - if ( nNotTGA != 0 ) - { - if (( m_BitPerPixel == 16 ) || ( m_BitPerPixel == 32 )) - nRes = ConvertTo24(); - - if (nRes == 0) - nRes = SaveBmp( szFilename ); - } - else - { - if ( m_BitPerPixel == 16 ) - nRes = ConvertTo24(); - - if (nRes == 0) - nRes = SaveTga( szFilename, true ); - } - } - else - nRes = eSaveFilename; - - return nRes; -} } \ No newline at end of file diff --git a/src/gl/hqnx_asm/hqnx_asm_Image.h b/src/gl/hqnx_asm/hqnx_asm_Image.h index 38f0f1d6a..918b904fe 100644 --- a/src/gl/hqnx_asm/hqnx_asm_Image.h +++ b/src/gl/hqnx_asm/hqnx_asm_Image.h @@ -47,91 +47,16 @@ class CImage eConvSourceMemory = 11, eConvDestMemory = 12, - eSaveBmpFileOpen = 20, - eSaveBmpFileWrite = 21, - eSaveBmpSourceMemory = 22, - eSaveBmpColorDepth = 23, - - eLoadBmpFileOpen = 30, - eLoadBmpFileRead = 31, - eLoadBmpBadFormat = 32, - eLoadBmpInit = 33, - eLoadBmpColorDepth = 34, - - eSaveTgaFileOpen = 40, - eSaveTgaFileWrite = 41, - eSaveTgaSourceMemory = 42, - eSaveTgaColorDepth = 43, - - eLoadTgaFileOpen = 50, - eLoadTgaFileRead = 51, - eLoadTgaBadFormat = 52, - eLoadTgaInit = 53, - eLoadTgaColorDepth = 54, - - eLoadFilename = 60, - eSaveFilename = 61, }; - struct _BMPFILEHEADER - { - unsigned short bfType; - long int bfSize, bfRes1, bfOffBits; - }; - - struct _BMPIMAGEHEADEROLD - { - long int biSize; - unsigned short biWidth, biHeight; - unsigned short biPlanes, biBitCount; - }; - - struct _BMPIMAGEHEADER - { - long int biSize, biWidth, biHeight; - unsigned short biPlanes, biBitCount; - long int biCompression, biSizeImage; - long int biXPelsPerMeter, biYPelsPerMeter; - long int biClrUsed, biClrImportant; - }; - - struct _TGAHEADER - { - unsigned char tiIdentSize; - unsigned char tiPaletteIncluded; - unsigned char tiImageType; - unsigned short tiPaletteStart; - unsigned short tiPaletteSize; - unsigned char tiPaletteBpp; - unsigned short tiX0; - unsigned short tiY0; - unsigned short tiXres; - unsigned short tiYres; - unsigned char tiBitPerPixel; - unsigned char tiAttrBits; - }; public: int DLL Init( int Xres, int Yres, unsigned short BitPerPixel ); int DLL SetImage(unsigned char *img, int width, int height, int bpp); int DLL Destroy(); - int DLL ConvertTo32( void ); - int DLL ConvertTo24( void ); - int DLL ConvertTo16( void ); - int DLL Convert8To17( int transindex ); int DLL Convert32To17( void ); - int SaveBmp(char *szFilename); - int LoadBmp(char *szFilename); - int SaveTga(char *szFilename, bool bCompressed ); - int LoadTga(char *szFilename); - int DLL Load(char *szFilename); - int DLL Save(char *szFilename); private: - void Output( char * pcData, int nSize ); - void Output( char c ); - void Output( void ); - unsigned char Input( void ); public: int m_Xres, m_Yres; From 1af42b3d501f00ab6cc5e820ea18326ee291af6e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:31:21 +0100 Subject: [PATCH 23/39] - use FileWriter for the OPL dumper. --- .../music_opldumper_mididevice.cpp | 58 ++++++++++--------- src/win32/win32swiface.h | 13 +---- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/sound/mididevices/music_opldumper_mididevice.cpp b/src/sound/mididevices/music_opldumper_mididevice.cpp index e301a3054..3519103e8 100644 --- a/src/sound/mididevices/music_opldumper_mididevice.cpp +++ b/src/sound/mididevices/music_opldumper_mididevice.cpp @@ -40,6 +40,7 @@ #include "m_swap.h" #include "w_wad.h" #include "opl.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -48,7 +49,7 @@ class OPLDump : public OPLEmul { public: - OPLDump(FILE *file) : File(file), TimePerTick(0), CurTime(0), + OPLDump(FileWriter *file) : File(file), TimePerTick(0), CurTime(0), CurIntTime(0), TickMul(1), CurChip(0) {} // If we're doing things right, these should never be reset. @@ -66,7 +67,7 @@ public: virtual void WriteDelay(int ticks) = 0; protected: - FILE *File; + FileWriter *File; double TimePerTick; // in milliseconds double CurTime; int CurIntTime; @@ -91,10 +92,10 @@ protected: class OPL_RDOSdump : public OPLDump { public: - OPL_RDOSdump(FILE *file) : OPLDump(file) + OPL_RDOSdump(FileWriter *file) : OPLDump(file) { assert(File != NULL); - fwrite("RAWADATA\0", 1, 10, File); + file->Write("RAWADATA\0", 10); NeedClockRate = true; } virtual ~OPL_RDOSdump() @@ -102,8 +103,8 @@ public: if (File != NULL) { uint16_t endmark = 0xFFFF; - fwrite(&endmark, 2, 1, File); - fclose(File); + File->Write(&endmark, 2); + delete File; } } @@ -114,13 +115,13 @@ public: if (chipnum != CurChip) { uint8_t switcher[2] = { (uint8_t)(chipnum + 1), 2 }; - fwrite(switcher, 1, 2, File); + File->Write(switcher, 2); } reg &= 255; if (reg != 0 && reg != 2 && (reg != 255 || v != 255)) { uint8_t cmd[2] = { uint8_t(v), uint8_t(reg) }; - fwrite(cmd, 1, 2, File); + File->Write(cmd, 2); } } @@ -146,15 +147,15 @@ public: if (NeedClockRate) { // Set the initial clock rate. clock_word = LittleShort(clock_word); - fseek(File, 8, SEEK_SET); - fwrite(&clock_word, 2, 1, File); - fseek(File, 0, SEEK_END); + File->Seek(8, SEEK_SET); + File->Write(&clock_word, 2); + File->Seek(0, SEEK_END); NeedClockRate = false; } else { // Change the clock rate in the middle of the song. uint8_t clock_change[4] = { 0, 2, uint8_t(clock_word & 255), uint8_t(clock_word >> 8) }; - fwrite(clock_change, 1, 4, File); + File->Write(clock_change, 4); } } virtual void WriteDelay(int ticks) @@ -170,10 +171,10 @@ public: { ticks -= 255; delay[0] = 255; - fwrite(delay, 1, 2, File); + File->Write(delay, 2); } delay[0] = uint8_t(ticks); - fwrite(delay, 1, 2, File); + File->Write(delay, 2); } } protected: @@ -183,30 +184,30 @@ protected: class OPL_DOSBOXdump : public OPLDump { public: - OPL_DOSBOXdump(FILE *file, bool dual) : OPLDump(file), Dual(dual) + OPL_DOSBOXdump(FileWriter *file, bool dual) : OPLDump(file), Dual(dual) { assert(File != NULL); - fwrite("DBRAWOPL" + File->Write("DBRAWOPL" "\0\0" // Minor version number "\1\0" // Major version number "\0\0\0\0" // Total milliseconds "\0\0\0", // Total data - 1, 20, File); + 20); char type[4] = { (char)(Dual * 2), 0, 0, 0 }; // Single or dual OPL-2 - fwrite(type, 1, 4, File); + File->Write(type, 4); } virtual ~OPL_DOSBOXdump() { if (File != NULL) { - long where_am_i = ftell(File); + long where_am_i =File->Tell(); uint32_t len[2]; - fseek(File, 12, SEEK_SET); + File->Seek(12, SEEK_SET); len[0] = LittleLong(CurIntTime); len[1] = LittleLong(uint32_t(where_am_i - 24)); - fwrite(len, 4, 2, File); - fclose(File); + File->Write(len, 8); + delete File; } } virtual void WriteReg(int reg, int v) @@ -216,11 +217,12 @@ public: if (chipnum != CurChip) { CurChip = chipnum; - fputc(chipnum + 2, File); + chipnum += 2; + File->Write(&chipnum, 1); } reg &= 255; uint8_t cmd[3] = { 4, uint8_t(reg), uint8_t(v) }; - fwrite (cmd + (reg > 4), 1, 3 - (reg > 4), File); + File->Write(cmd + (reg > 4), 3 - (reg > 4)); } virtual void WriteDelay(int ticks) { @@ -234,20 +236,20 @@ public: while (delay > 65536) { uint8_t cmd[3] = { 1, 255, 255 }; - fwrite(cmd, 1, 2, File); + File->Write(cmd, 2); delay -= 65536; } delay--; if (delay <= 255) { uint8_t cmd[2] = { 0, uint8_t(delay) }; - fwrite(cmd, 1, 2, File); + File->Write(cmd, 2); } else { assert(delay <= 65535); uint8_t cmd[3] = { 1, uint8_t(delay & 255), uint8_t(delay >> 8) }; - fwrite(cmd, 1, 3, File); + File->Write(cmd, 3); } } } @@ -338,7 +340,7 @@ DiskWriterIO::~DiskWriterIO() int DiskWriterIO::Init(uint32_t numchips, bool, bool initopl3) { - FILE *file = fopen(Filename, "wb"); + FileWriter *file = FileWriter::Open(Filename); if (file == NULL) { Printf("Could not open %s for writing.\n", Filename.GetChars()); diff --git a/src/win32/win32swiface.h b/src/win32/win32swiface.h index 59101c602..657b120a3 100644 --- a/src/win32/win32swiface.h +++ b/src/win32/win32swiface.h @@ -380,18 +380,7 @@ enum BQS_InGameColormap, }; -#if 0 -#define STARTLOG do { if (!dbg) dbg = fopen ("e:/vid.log", "w"); } while(0) -#define STOPLOG do { if (dbg) { fclose (dbg); dbg=NULL; } } while(0) -#define LOG(x) do { if (dbg) { fprintf (dbg, x); fflush (dbg); } } while(0) -#define LOG1(x,y) do { if (dbg) { fprintf (dbg, x, y); fflush (dbg); } } while(0) -#define LOG2(x,y,z) do { if (dbg) { fprintf (dbg, x, y, z); fflush (dbg); } } while(0) -#define LOG3(x,y,z,zz) do { if (dbg) { fprintf (dbg, x, y, z, zz); fflush (dbg); } } while(0) -#define LOG4(x,y,z,a,b) do { if (dbg) { fprintf (dbg, x, y, z, a, b); fflush (dbg); } } while(0) -#define LOG5(x,y,z,a,b,c) do { if (dbg) { fprintf (dbg, x, y, z, a, b, c); fflush (dbg); } } while(0) -extern FILE *dbg; -#define VID_FILE_DEBUG 1 -#elif _DEBUG && 0 +#if _DEBUG && 0 #define STARTLOG #define STOPLOG #define LOG(x) { OutputDebugString(x); } From 8d26760671f97d5ca13631c597bc0e97fa1f6761 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:33:58 +0100 Subject: [PATCH 24/39] - use FileWriter for 'writemidi' CCMD. --- src/sound/i_music.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 19db0161d..28f839c6c 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -803,18 +803,17 @@ CCMD (writemidi) } TArray midi; - FILE *f; bool success; static_cast(currSong)->CreateSMF(midi, 1); - f = fopen(argv[1], "wb"); + auto f = FileWriter::Open(argv[1]); if (f == NULL) { Printf("Could not open %s.\n", argv[1]); return; } - success = (fwrite(&midi[0], 1, midi.Size(), f) == (size_t)midi.Size()); - fclose (f); + success = (f->Write(&midi[0], midi.Size()) == (size_t)midi.Size()); + delete f; if (!success) { From 14af7818b8d90286e61e8dba6139e8d84a0f7ab8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:38:38 +0100 Subject: [PATCH 25/39] - use FileReader for all operations on external lumps. --- src/resourcefiles/resourcefile.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 7c9c957e3..96bd50e0f 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -669,12 +669,11 @@ FExternalLump::FExternalLump(const char *_filename, int filesize) if (filesize == -1) { - FILE *f = fopen(_filename,"rb"); - if (f != NULL) + FileReader f; + + if (f.Open(_filename)) { - fseek(f, 0, SEEK_END); - LumpSize = ftell(f); - fclose(f); + LumpSize = f.GetLength(); } else { @@ -703,11 +702,11 @@ FExternalLump::~FExternalLump() int FExternalLump::FillCache() { Cache = new char[LumpSize]; - FILE *f = fopen(filename, "rb"); - if (f != NULL) + FileReader f; + + if (f.Open(filename)) { - fread(Cache, 1, LumpSize, f); - fclose(f); + f.Read(Cache, LumpSize); } else { From e15b23f1324bb3324ce596e0052ed3673cd919a7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 12:46:25 +0100 Subject: [PATCH 26/39] - use FileWriter for writing zip files (i.e. savegames.) --- src/resourcefiles/file_zip.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 02e350998..3d842131d 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -542,7 +542,7 @@ static void time_to_dos(struct tm *time, unsigned short *dosdate, unsigned short // //========================================================================== -int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time) +int AppendToZip(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time) { FZipLocalFileHeader local; int position; @@ -562,12 +562,12 @@ int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content // Fill in local directory header. - position = (int)ftell(zip_file); + position = (int)zip_file->Tell(); // Write out the header, file name, and file data. - if (fwrite(&local, sizeof(local), 1, zip_file) != 1 || - fwrite(filename, strlen(filename), 1, zip_file) != 1 || - fwrite(content.mBuffer, 1, content.mCompressedSize, zip_file) != content.mCompressedSize) + if (zip_file->Write(&local, sizeof(local)) != sizeof(local) || + zip_file->Write(filename, strlen(filename)) != strlen(filename) || + zip_file->Write(content.mBuffer, content.mCompressedSize) != content.mCompressedSize) { return -1; } @@ -583,7 +583,7 @@ int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content // //========================================================================== -int AppendCentralDirectory(FILE *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time, int position) +int AppendCentralDirectory(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time, int position) { FZipCentralDirectoryInfo dir; @@ -607,8 +607,8 @@ int AppendCentralDirectory(FILE *zip_file, const char *filename, FCompressedBuff dir.ExternalAttributes = 0; dir.LocalHeaderOffset = LittleLong(position); - if (fwrite(&dir, sizeof(dir), 1, zip_file) != 1 || - fwrite(filename, strlen(filename), 1, zip_file) != 1) + if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) || + zip_file->Write(filename, strlen(filename)) != strlen(filename)) { return -1; } @@ -629,7 +629,7 @@ bool WriteZip(const char *filename, TArray &filenames, TArray &filenames, TArrayTell(); for (unsigned i = 0; i < filenames.Size(); i++) { if (AppendCentralDirectory(f, filenames[i], content[i], mydate, mytime, positions[i]) < 0) { - fclose(f); + delete f; remove(filename); return false; } @@ -662,15 +662,15 @@ bool WriteZip(const char *filename, TArray &filenames, TArrayTell() - dirofs); dirend.ZipCommentLength = 0; - if (fwrite(&dirend, sizeof(dirend), 1, f) != 1) + if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend)) { - fclose(f); + delete f; remove(filename); return false; } - fclose(f); + delete f; return true; } return false; From 838e52001cd27b05b2f3d647b5174753587514aa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 13:09:59 +0100 Subject: [PATCH 27/39] - got rid of M_ReadFile(Malloc) which werew each used only once in the entire code. These were still using the low level POSIX-style file interface which shouldn't really be used anymore. - let FScanner::OpenFile return an error instead of throwing an exception. The exception was never used anyway aside from being caught right away to be ignored. --- src/b_game.cpp | 8 ++----- src/g_game.cpp | 12 +++++++++- src/m_misc.cpp | 54 ------------------------------------------- src/m_misc.h | 2 -- src/posix/i_steam.cpp | 23 +++++++++--------- src/sc_man.cpp | 17 ++++++++++---- src/sc_man.h | 2 +- src/statistics.cpp | 2 +- 8 files changed, 39 insertions(+), 81 deletions(-) diff --git a/src/b_game.cpp b/src/b_game.cpp index 1cb91ddf4..4300e0ada 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -532,13 +532,9 @@ bool FCajunMaster::LoadBots () DPrintf (DMSG_ERROR, "No " BOTFILENAME ", so no bots\n"); return false; } - try + if (!sc.OpenFile(tmp)) { - sc.OpenFile(tmp); - } - catch (CRecoverableError &err) - { - Printf("%s. So no bots\n", err.GetMessage()); + Printf("Unable to open %s. So no bots\n"); return false; } diff --git a/src/g_game.cpp b/src/g_game.cpp index ec1a7be50..b2e27eed4 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2798,7 +2798,17 @@ void G_DoPlayDemo (void) { FixPathSeperator (defdemoname); DefaultExtension (defdemoname, ".lmp"); - M_ReadFileMalloc (defdemoname, &demobuffer); + FileReader fr; + if (!fr.Open(defdemoname)) + { + I_Error("Unable to open demo '%s'", defdemoname.GetChars()); + } + auto len = fr.GetLength(); + demobuffer = (uint8_t*)M_Malloc(len); + if (fr.Read(demobuffer, len) != len) + { + I_Error("Unable to read demo '%s'", defdemoname.GetChars()); + } } demo_p = demobuffer; diff --git a/src/m_misc.cpp b/src/m_misc.cpp index bda8dcb80..2b23ef6c2 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -115,60 +115,6 @@ bool M_WriteFile (char const *name, void *source, int length) } -// -// M_ReadFile -// -int M_ReadFile (char const *name, uint8_t **buffer) -{ - int handle, count, length; - struct stat fileinfo; - uint8_t *buf; - - handle = open (name, O_RDONLY | O_BINARY, 0666); - if (handle == -1) - I_Error ("Couldn't read file %s", name); - // [BL] Use stat instead of fstat for v140_xp hack - if (stat (name,&fileinfo) == -1) - I_Error ("Couldn't read file %s", name); - length = fileinfo.st_size; - buf = new uint8_t[length]; - count = read (handle, buf, length); - close (handle); - - if (count < length) - I_Error ("Couldn't read file %s", name); - - *buffer = buf; - return length; -} - -// -// M_ReadFile (same as above but use malloc instead of new to allocate the buffer.) -// -int M_ReadFileMalloc (char const *name, uint8_t **buffer) -{ - int handle, count, length; - struct stat fileinfo; - uint8_t *buf; - - handle = open (name, O_RDONLY | O_BINARY, 0666); - if (handle == -1) - I_Error ("Couldn't read file %s", name); - // [BL] Use stat instead of fstat for v140_xp hack - if (stat (name,&fileinfo) == -1) - I_Error ("Couldn't read file %s", name); - length = fileinfo.st_size; - buf = (uint8_t*)M_Malloc(length); - count = read (handle, buf, length); - close (handle); - - if (count < length) - I_Error ("Couldn't read file %s", name); - - *buffer = buf; - return length; -} - //--------------------------------------------------------------------------- // // PROC M_FindResponseFile diff --git a/src/m_misc.h b/src/m_misc.h index 660eb7a58..2eee63b7d 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -34,8 +34,6 @@ class FIWadManager; extern FGameConfigFile *GameConfig; bool M_WriteFile (char const *name, void *source, int length); -int M_ReadFile (char const *name, uint8_t **buffer); -int M_ReadFileMalloc (char const *name, uint8_t **buffer); void M_FindResponseFile (void); // [RH] M_ScreenShot now accepts a filename parameter. diff --git a/src/posix/i_steam.cpp b/src/posix/i_steam.cpp index 9819bc09e..9542bdd4a 100644 --- a/src/posix/i_steam.cpp +++ b/src/posix/i_steam.cpp @@ -122,27 +122,28 @@ static TArray ParseSteamRegistry(const char* path) // Read registry data FScanner sc; - sc.OpenFile(path); - sc.SetCMode(true); - - // Find the SteamApps listing - if(PSR_FindAndEnterBlock(sc, "InstallConfigStore")) + if (sc.OpenFile(path)) { - if(PSR_FindAndEnterBlock(sc, "Software")) + sc.SetCMode(true); + + // Find the SteamApps listing + if (PSR_FindAndEnterBlock(sc, "InstallConfigStore")) { - if(PSR_FindAndEnterBlock(sc, "Valve")) + if (PSR_FindAndEnterBlock(sc, "Software")) { - if(PSR_FindAndEnterBlock(sc, "Steam")) + if (PSR_FindAndEnterBlock(sc, "Valve")) { - dirs = PSR_ReadBaseInstalls(sc); + if (PSR_FindAndEnterBlock(sc, "Steam")) + { + dirs = PSR_ReadBaseInstalls(sc); + } + PSR_FindEndBlock(sc); } PSR_FindEndBlock(sc); } PSR_FindEndBlock(sc); } - PSR_FindEndBlock(sc); } - return dirs; } diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 2a515d91b..277604d68 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -244,18 +244,25 @@ void FScanner::Open (const char *name) // //========================================================================== -void FScanner::OpenFile (const char *name) +bool FScanner::OpenFile (const char *name) { - uint8_t *filebuf; - int filesize; - Close (); - filesize = M_ReadFile (name, &filebuf); + + FileReader fr(name); + if (!fr.Open(name)) return false; + auto filesize = fr.GetLength(); + auto filebuf = new uint8_t[filesize]; + if (fr.Read(filebuf, filesize) != filesize) + { + delete[] filebuf; + return false; + } ScriptBuffer = FString((const char *)filebuf, filesize); delete[] filebuf; ScriptName = name; // This is used for error messages so the full file name is preferable LumpNum = -1; PrepareScript (); + return true; } //========================================================================== diff --git a/src/sc_man.h b/src/sc_man.h index 44dd9370a..9962cbde0 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -19,7 +19,7 @@ public: FScanner &operator=(const FScanner &other); void Open(const char *lumpname); - void OpenFile(const char *filename); + bool OpenFile(const char *filename); void OpenMem(const char *name, const char *buffer, int size); void OpenString(const char *name, FString buffer); void OpenLumpNum(int lump); diff --git a/src/statistics.cpp b/src/statistics.cpp index e70642cf4..865ba0411 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -137,7 +137,7 @@ static void ParseStatistics(const char *fn, TArray &statlist) try { FScanner sc; - sc.OpenFile(fn); + if (!sc.OpenFile(fn)) return; while (sc.GetString()) { From 690e7d8a84a4cb68aabef3400d15cf97ed217e4d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 13:18:20 +0100 Subject: [PATCH 28/39] - got rid of M_WriteFile as well for the same reasons as M_ReadFile. --- src/g_game.cpp | 10 +++++++++- src/m_misc.cpp | 26 -------------------------- src/m_misc.h | 1 - 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index b2e27eed4..f56bdac8e 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2974,7 +2974,15 @@ bool G_CheckDemoStatus (void) formlen = demobuffer + 4; WriteLong (int(demo_p - demobuffer - 8), &formlen); - bool saved = M_WriteFile (demoname, demobuffer, int(demo_p - demobuffer)); + auto fw = FileWriter::Open(demoname); + bool saved = false; + if (fw != nullptr) + { + auto size = long(demo_p - demobuffer); + saved = fw->Write(demobuffer, size) == size; + delete fw; + if (!saved) remove(demoname); + } M_Free (demobuffer); demorecording = false; stoprecording = false; diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 2b23ef6c2..21a0bfc74 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -88,32 +88,6 @@ EXTERN_CVAR(Bool, longsavemessages); static long ParseCommandLine (const char *args, int *argc, char **argv); -// -// M_WriteFile -// -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -bool M_WriteFile (char const *name, void *source, int length) -{ - int handle; - int count; - - handle = open ( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); - - if (handle == -1) - return false; - - count = write (handle, source, length); - close (handle); - - if (count < length) - return false; - - return true; -} - //--------------------------------------------------------------------------- // diff --git a/src/m_misc.h b/src/m_misc.h index 2eee63b7d..47db77bb7 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -33,7 +33,6 @@ class FIWadManager; extern FGameConfigFile *GameConfig; -bool M_WriteFile (char const *name, void *source, int length); void M_FindResponseFile (void); // [RH] M_ScreenShot now accepts a filename parameter. From 2ba029ec8d21d55bfc0954aa89d7539da70bdbdd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 14:02:51 +0100 Subject: [PATCH 29/39] - fixed potential memory leak in M_VerifyPNG. If the 'takereader' parameter is true, the function must delete the reader if it fails before creating the PNGHandle. --- src/m_png.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/m_png.cpp b/src/m_png.cpp index 28f015e7b..0f4af87e4 100644 --- a/src/m_png.cpp +++ b/src/m_png.cpp @@ -383,18 +383,22 @@ PNGHandle *M_VerifyPNG (FileReader *filer, bool takereader) if (filer->Read(&data, 8) != 8) { + if (takereader) delete filer; return NULL; } if (data[0] != MAKE_ID(137,'P','N','G') || data[1] != MAKE_ID(13,10,26,10)) { // Does not have PNG signature + if (takereader) delete filer; return NULL; } if (filer->Read (&data, 8) != 8) { + if (takereader) delete filer; return NULL; } if (data[1] != MAKE_ID('I','H','D','R')) { // IHDR must be the first chunk + if (takereader) delete filer; return NULL; } From 4003e7ca118780a138779b8adda4a8708af9057c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 14:10:42 +0100 Subject: [PATCH 30/39] - use FileReader for savegame loading in the menu. - simplify the check for existing files here, since a function for doing just that already existed. --- src/m_png.cpp | 6 ------ src/m_png.h | 1 - src/menu/loadsavemenu.cpp | 23 +++++++++-------------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/m_png.cpp b/src/m_png.cpp index 0f4af87e4..08cac8d54 100644 --- a/src/m_png.cpp +++ b/src/m_png.cpp @@ -456,12 +456,6 @@ PNGHandle *M_VerifyPNG (FileReader *filer, bool takereader) return NULL; } -PNGHandle *M_VerifyPNG(FILE *file) -{ - FileReader *fr = new FileReader(file); - return M_VerifyPNG(fr, true); -} - //========================================================================== // // M_FreePNG diff --git a/src/m_png.h b/src/m_png.h index 70c45b710..4182440fb 100644 --- a/src/m_png.h +++ b/src/m_png.h @@ -90,7 +90,6 @@ struct PNGHandle // each chunk is not done. If it is valid, you get a PNGHandle to pass to // the following functions. PNGHandle *M_VerifyPNG (FileReader *file, bool takereader = false); -PNGHandle *M_VerifyPNG (FILE *file); // Finds a chunk in a PNG file. The file pointer will be positioned at the // beginning of the chunk data, and its length will be returned. A return diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index bec3082b1..c9fb7aeba 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -236,8 +236,8 @@ void FSavegameManager::ReadSaveStrings() } else // check for old formats. { - FILE *file = fopen(filepath, "rb"); - if (file != nullptr) + FileReader file; + if (file.Open(filepath)) { PNGHandle *png; char sig[16]; @@ -255,8 +255,7 @@ void FSavegameManager::ReadSaveStrings() title[OLDSAVESTRINGSIZE] = 0; - - if (nullptr != (png = M_VerifyPNG(file))) + if (nullptr != (png = M_VerifyPNG(&file, false))) { char *ver = M_GetPNGText(png, "ZDoom Save Version"); if (ver != nullptr) @@ -273,13 +272,13 @@ void FSavegameManager::ReadSaveStrings() } else { - fseek(file, 0, SEEK_SET); - if (fread(sig, 1, 16, file) == 16) + file.Seek(0, SEEK_SET); + if (file.Read(sig, 16) == 16) { if (strncmp(sig, "ZDOOMSAVE", 9) == 0) { - if (fread(title, 1, OLDSAVESTRINGSIZE, file) == OLDSAVESTRINGSIZE) + if (file.Read(title, OLDSAVESTRINGSIZE) == OLDSAVESTRINGSIZE) { addIt = true; } @@ -287,8 +286,8 @@ void FSavegameManager::ReadSaveStrings() else { memcpy(title, sig, 16); - if (fread(title + 16, 1, OLDSAVESTRINGSIZE - 16, file) == OLDSAVESTRINGSIZE - 16 && - fread(sig, 1, 16, file) == 16 && + if (file.Read(title + 16, OLDSAVESTRINGSIZE - 16) == OLDSAVESTRINGSIZE - 16 && + file.Read(sig, 16) == 16 && strncmp(sig, "ZDOOMSAVE", 9) == 0) { addIt = true; @@ -306,7 +305,6 @@ void FSavegameManager::ReadSaveStrings() node->SaveTitle = title; InsertSaveNode(node); } - fclose(file); } } } while (I_FindNext(filefirst, &c_file) == 0); @@ -418,17 +416,14 @@ void FSavegameManager::DoSave(int Selected, const char *savegamestring) // Find an unused filename and save as that FString filename; int i; - FILE *test; for (i = 0;; ++i) { filename = G_BuildSaveName("save", i); - test = fopen(filename, "rb"); - if (test == nullptr) + if (!FileExists(filename)) { break; } - fclose(test); } G_SaveGame(filename, savegamestring); } From 7d0759e2fa95d0fa2e96ca2c932df0c6d8e7d9e2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 14:24:28 +0100 Subject: [PATCH 31/39] - handled all other uses of fopen that could reasonably converted to FileReader or FileWriter. --- src/d_dehacked.cpp | 11 +++++------ src/files.cpp | 9 +++++++-- src/files.h | 1 + src/m_misc.cpp | 12 ++++-------- src/md5.cpp | 7 +++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 87f1d589e..f68fd1d63 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2488,17 +2488,16 @@ bool D_LoadDehLump(int lumpnum) bool D_LoadDehFile(const char *patchfile) { - FILE *deh; + FileReader fr; - deh = fopen(patchfile, "rb"); - if (deh != NULL) + if (!fr.Open(patchfile)) { - PatchSize = Q_filelength(deh); + PatchSize = fr.GetLength(); PatchName = copystring(patchfile); PatchFile = new char[PatchSize + 1]; - fread(PatchFile, 1, PatchSize, deh); - fclose(deh); + fr.Read(PatchFile, PatchSize); + fr.Close(); PatchFile[PatchSize] = '\0'; // terminate with a '\0' character return DoDehPatch(); } diff --git a/src/files.cpp b/src/files.cpp index b42aefece..8ad4d6329 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -87,13 +87,18 @@ FileReader::FileReader (FILE *file, long length) FilePos = StartPos = ftell (file); } -FileReader::~FileReader () +FileReader::~FileReader() +{ + Close(); +} + +void FileReader::Close() { if (CloseOnDestruct && File != NULL) { fclose (File); - File = NULL; } + File = NULL; } bool FileReader::Open (const char *filename) diff --git a/src/files.h b/src/files.h index d0c769ba1..808f24d94 100644 --- a/src/files.h +++ b/src/files.h @@ -101,6 +101,7 @@ public: FileReader (FILE *file); FileReader (FILE *file, long length); bool Open (const char *filename); + void Close(); virtual ~FileReader (); virtual long Tell () const; diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 21a0bfc74..d07415248 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -122,22 +122,18 @@ void M_FindResponseFile (void) if (added_stuff < limit) { // READ THE RESPONSE FILE INTO MEMORY - handle = fopen (Args->GetArg(i) + 1,"rb"); - if (!handle) + FileReader fr; + if (!fr.Open(Args->GetArg(i) + 1)) { // [RH] Make this a warning, not an error. Printf ("No such response file (%s)!\n", Args->GetArg(i) + 1); } else { Printf ("Found response file %s!\n", Args->GetArg(i) + 1); - fseek (handle, 0, SEEK_END); - size = ftell (handle); - fseek (handle, 0, SEEK_SET); + size = fr.GetLength(); file = new char[size+1]; - fread (file, size, 1, handle); + fr.Read (file, size); file[size] = 0; - fclose (handle); - argsize = ParseCommandLine (file, &argc, NULL); } } diff --git a/src/md5.cpp b/src/md5.cpp index aa4b506da..d345e00d6 100644 --- a/src/md5.cpp +++ b/src/md5.cpp @@ -269,8 +269,8 @@ CCMD (md5sum) } for (int i = 1; i < argv.argc(); ++i) { - FILE *file = fopen(argv[i], "rb"); - if (file == NULL) + FileReader fr; + if (!fr.Open(argv[i])) { Printf("%s: %s\n", argv[i], strerror(errno)); } @@ -280,7 +280,7 @@ CCMD (md5sum) uint8_t readbuf[8192]; size_t len; - while ((len = fread(readbuf, 1, sizeof(readbuf), file)) > 0) + while ((len = fr.Read(readbuf, sizeof(readbuf))) > 0) { md5.Update(readbuf, (unsigned int)len); } @@ -290,7 +290,6 @@ CCMD (md5sum) Printf("%02x", readbuf[j]); } Printf(" *%s\n", argv[i]); - fclose (file); } } } From 1afc3b48a196888028d8e49c5957f50669d79a4c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 14:27:49 +0100 Subject: [PATCH 32/39] - removed Q_filelength which is no longer being used. --- src/cmdlib.cpp | 20 -------------------- src/cmdlib.h | 1 - 2 files changed, 21 deletions(-) diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index 3c2e7e280..f2d4389d1 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -145,26 +145,6 @@ void ReplaceString (char **ptr, const char *str) */ -//========================================================================== -// -// Q_filelength -// -//========================================================================== - -int Q_filelength (FILE *f) -{ - int pos; - int end; - - pos = ftell (f); - fseek (f, 0, SEEK_END); - end = ftell (f); - fseek (f, pos, SEEK_SET); - - return end; -} - - //========================================================================== // // FileExists diff --git a/src/cmdlib.h b/src/cmdlib.h index e2119ed8a..f168cb910 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -18,7 +18,6 @@ // the dec offsetof macro doesnt work very well... #define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type)) -int Q_filelength (FILE *f); bool FileExists (const char *filename); bool DirExists(const char *filename); bool DirEntryExists (const char *pathname); From 8627a48b343d72f7941a554079c00f150c94a1ff Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 16:07:09 +0100 Subject: [PATCH 33/39] - consolidation of 'stat' calls. Since this is a non-standard function it's better kept to as few places as possible, so now DirEntryExists returns an additional flag to say what type an entry is and is being used nearly everywhere where stat was used, excluding a few low level parts in the POSIX code. --- src/c_bind.cpp | 2 +- src/cmdlib.cpp | 34 +++++++++++----------------- src/cmdlib.h | 2 +- src/d_main.cpp | 4 +--- src/m_misc.cpp | 1 - src/posix/cocoa/i_system.mm | 7 +++--- src/posix/i_steam.cpp | 3 ++- src/posix/sdl/i_system.cpp | 11 +++++---- src/resourcefiles/file_directory.cpp | 5 +--- src/w_wad.cpp | 6 ++--- 10 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/c_bind.cpp b/src/c_bind.cpp index b1a557514..5098b9a95 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -744,7 +744,7 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) dclick = false; // This used level.time which didn't work outside a level. - nowtime = I_msTime(); + nowtime = (unsigned)I_msTime(); if (doublebinds != NULL && int(DClickTime[ev->data1] - nowtime) > 0 && ev->type == EV_KeyDown) { // Key pressed for a double click diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index f2d4389d1..bccb4afcd 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -155,13 +155,9 @@ void ReplaceString (char **ptr, const char *str) bool FileExists (const char *filename) { - struct stat buff; - - // [RH] Empty filenames are never there - if (filename == NULL || *filename == 0) - return false; - - return stat(filename, &buff) == 0 && !(buff.st_mode & S_IFDIR); + bool isdir; + bool res = DirEntryExists(filename, &isdir); + return res && !isdir; } //========================================================================== @@ -174,13 +170,9 @@ bool FileExists (const char *filename) bool DirExists(const char *filename) { - struct stat buff; - - // [RH] Empty filenames are never there - if (filename == NULL || *filename == 0) - return false; - - return stat(filename, &buff) == 0 && (buff.st_mode & S_IFDIR); + bool isdir; + bool res = DirEntryExists(filename, &isdir); + return res && isdir; } //========================================================================== @@ -191,13 +183,16 @@ bool DirExists(const char *filename) // //========================================================================== -bool DirEntryExists(const char *pathname) +bool DirEntryExists(const char *pathname, bool *isdir) { + if (isdir) *isdir = false; if (pathname == NULL || *pathname == 0) return false; struct stat info; - return stat(pathname, &info) == 0; + bool res = stat(pathname, &info) == 0; + if (isdir) *isdir = !!(info.st_mode & S_IFDIR); + return res; } //========================================================================== @@ -550,7 +545,7 @@ void CreatePath(const char *fn) *p = '\0'; } struct stat info; - if (stat(copy, &info) == 0) + if (DirEntryExists(copy)) { if (info.st_mode & S_IFDIR) goto exists; @@ -1009,10 +1004,7 @@ void ScanDirectory(TArray &list, const char *dirpath) FFileList *fl = &list[list.Reserve(1)]; fl->Filename << dirpath << file->d_name; - struct stat fileStat; - stat(fl->Filename, &fileStat); - fl->isDirectory = S_ISDIR(fileStat.st_mode); - + fl->isDirectory = DirExists(fl->Filename); if(fl->isDirectory) { FString newdir = fl->Filename; diff --git a/src/cmdlib.h b/src/cmdlib.h index f168cb910..76a2798da 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -20,7 +20,7 @@ bool FileExists (const char *filename); bool DirExists(const char *filename); -bool DirEntryExists (const char *pathname); +bool DirEntryExists (const char *pathname, bool *isdir = nullptr); extern FString progdir; diff --git a/src/d_main.cpp b/src/d_main.cpp index 301be20f8..9d8055b0d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1946,13 +1946,11 @@ static FString CheckGameInfo(TArray & pwads) const char *filename = pwads[i]; // Does this exist? If so, is it a directory? - struct stat info; - if (stat(pwads[i], &info) != 0) + if (!DirEntryExists(pwads[i], &isdir)) { Printf(TEXTCOLOR_RED "Could not stat %s\n", filename); continue; } - isdir = (info.st_mode & S_IFDIR) != 0; if (!isdir) { diff --git a/src/m_misc.cpp b/src/m_misc.cpp index d07415248..c2fa021f6 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -112,7 +112,6 @@ void M_FindResponseFile (void) char **argv; char *file = NULL; int argc = 0; - FILE *handle; int size; long argsize = 0; int index; diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index bb1ea2e1b..3be9a067c 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -49,6 +49,7 @@ #include "st_console.h" #include "v_text.h" #include "x86.h" +#include "cmdlib.h" EXTERN_CVAR(String, language) @@ -336,11 +337,11 @@ int I_FindClose(void* const handle) int I_FindAttr(findstate_t* const fileinfo) { dirent* const ent = fileinfo->namelist[fileinfo->current]; - struct stat buf; + bool isdir; - if (stat(ent->d_name, &buf) == 0) + if (DirEntryExists(ent->d_name, &isdir)) { - return S_ISDIR(buf.st_mode) ? FA_DIREC : 0; + return isdir ? FA_DIREC : 0; } return 0; diff --git a/src/posix/i_steam.cpp b/src/posix/i_steam.cpp index 9542bdd4a..f233f4ce8 100644 --- a/src/posix/i_steam.cpp +++ b/src/posix/i_steam.cpp @@ -42,6 +42,7 @@ #include "d_main.h" #include "zstring.h" #include "sc_man.h" +#include "cmdlib.h" static void PSR_FindEndBlock(FScanner &sc) { @@ -224,7 +225,7 @@ TArray I_GetSteamPath() { struct stat st; FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath); - if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode)) + if(DirExists(candidate)) result.Push(candidate); } } diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp index 7bf23af11..b71acb8f8 100644 --- a/src/posix/sdl/i_system.cpp +++ b/src/posix/sdl/i_system.cpp @@ -397,15 +397,16 @@ int I_FindClose (void *handle) return 0; } -int I_FindAttr (findstate_t *fileinfo) +int I_FindAttr(findstate_t* const fileinfo) { - dirent *ent = fileinfo->namelist[fileinfo->current]; - struct stat buf; + dirent* const ent = fileinfo->namelist[fileinfo->current]; + bool isdir; - if (stat(ent->d_name, &buf) == 0) + if (DirEntryExists(ent->d_name, &isdir)) { - return S_ISDIR(buf.st_mode) ? FA_DIREC : 0; + return isdir ? FA_DIREC : 0; } + return 0; } diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp index 77e5d0141..02c70a21e 100644 --- a/src/resourcefiles/file_directory.cpp +++ b/src/resourcefiles/file_directory.cpp @@ -209,10 +209,7 @@ int FDirectory::AddDirectory(const char *dirpath) FString fullFileName = scanDirectories[i] + file->d_name; - struct stat fileStat; - stat(fullFileName.GetChars(), &fileStat); - - if(S_ISDIR(fileStat.st_mode)) + if(DirExists(fullFileName.GetChars())) { scanDirectories.Push(scanDirectories[i] + file->d_name + "/"); continue; diff --git a/src/w_wad.cpp b/src/w_wad.cpp index ae52725d2..1e1de76f0 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -233,14 +233,12 @@ void FWadCollection::AddFile (const char *filename, FileReader *wadinfo) if (wadinfo == NULL) { // Does this exist? If so, is it a directory? - struct stat info; - if (stat(filename, &info) != 0) + if (!DirEntryExists(filename, &isdir)) { - Printf(TEXTCOLOR_RED "Could not stat %s\n", filename); + Printf(TEXTCOLOR_RED "%s: File or Directory not found\n", filename); PrintLastError(); return; } - isdir = (info.st_mode & S_IFDIR) != 0; if (!isdir) { From 4ca3acb0e3172a9dc224c2f25be0d3b0f23ccecd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 16:51:53 +0100 Subject: [PATCH 34/39] - made tmpfileplus a .cpp file so that it can access ZDoom's own utility code. --- src/CMakeLists.txt | 2 +- src/{tmpfileplus.c => tmpfileplus.cpp} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{tmpfileplus.c => tmpfileplus.cpp} (99%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c90fab42..60d906766 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1169,6 +1169,7 @@ set (PCH_SOURCES events.cpp GuillotineBinPack.cpp SkylineBinPack.cpp + tmpfileplus.cpp ) enable_precompiled_headers( g_pch.h PCH_SOURCES ) @@ -1183,7 +1184,6 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE ${PCH_SOURCES} x86.cpp strnatcmp.c - tmpfileplus.c zstring.cpp math/asin.c math/atan.c diff --git a/src/tmpfileplus.c b/src/tmpfileplus.cpp similarity index 99% rename from src/tmpfileplus.c rename to src/tmpfileplus.cpp index ddb71de09..5475d8f8f 100644 --- a/src/tmpfileplus.c +++ b/src/tmpfileplus.cpp @@ -217,7 +217,7 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart); DPRINTF1("lentempname=%d\n", lentempname); - tmpname = malloc(lentempname + 1); + tmpname = (char*)malloc(lentempname + 1); if (!tmpname) { errno = ENOMEM; From e78503b7706527802b3bfc69d69e2f0319084eef Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 16:54:24 +0100 Subject: [PATCH 35/39] - removed some debug stuff from tmpfileplus. --- src/tmpfileplus.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/tmpfileplus.cpp b/src/tmpfileplus.cpp index 5475d8f8f..4bb9f4586 100644 --- a/src/tmpfileplus.cpp +++ b/src/tmpfileplus.cpp @@ -113,13 +113,6 @@ #endif -/* DEBUGGING STUFF */ -#if defined(_DEBUG) && defined(SHOW_DPRINTF) -#define DPRINTF1(s, a1) printf(s, a1) -#else -#define DPRINTF1(s, a1) -#endif - #ifdef _WIN32 #define FILE_SEPARATOR "\\" @@ -216,7 +209,6 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp } lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart); - DPRINTF1("lentempname=%d\n", lentempname); tmpname = (char*)malloc(lentempname + 1); if (!tmpname) { @@ -227,11 +219,9 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp for (i = 0; i < 10; i++) { sprintf(tmpname, "%s%s%s%s", tmpdir, FILE_SEPARATOR, pfx, set_randpart(randpart)); - DPRINTF1("[%s]\n", tmpname); fd = OPEN_(tmpname, oflag, pmode); if (fd != -1) break; } - DPRINTF1("strlen(tmpname)=%d\n", strlen(tmpname)); if (fd != -1) { /* Success, so return user a proper ANSI C file pointer */ fp = FDOPEN_(fd, "w+b"); @@ -293,7 +283,6 @@ FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep for (i = 0; i < ntempdirs; i++) { tmpdir = tempdirs[i]; - DPRINTF1("Trying tmpdir=[%s]\n", tmpdir); fp = mktempfile_internal(tmpdir, pfx, &tmpname, keep); if (fp) break; } From f6f17fbfb48a62cc2f499c82cef8698c196879fc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 17:05:39 +0100 Subject: [PATCH 36/39] - give tmpfileplus its own RNG. This should not interfere with the global one which can be explicitly seeded. It also seems a bit pointless to constantly re-seed the RNG for something this inconsequential. --- src/tmpfileplus.cpp | 75 +++++---------------------------------------- src/tmpfileplus.h | 20 ------------ 2 files changed, 7 insertions(+), 88 deletions(-) diff --git a/src/tmpfileplus.cpp b/src/tmpfileplus.cpp index 4bb9f4586..0ebb23185 100644 --- a/src/tmpfileplus.cpp +++ b/src/tmpfileplus.cpp @@ -67,23 +67,6 @@ * */ -/* ADDED IN v2.0 */ - -/* -* NAME -* tmpfileplus_f - create a unique temporary file with filename stored in a fixed-length buffer -* -* SYNOPSIS -* FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep); -* -* DESCRIPTION -* Same as tmpfileplus() except receives filename in a fixed-length buffer. No allocated memory to free. - -* ERRORS -* E2BIG Resulting filename is too big for the buffer `pathnamebuf`. - -*/ - #include "tmpfileplus.h" #include @@ -112,47 +95,32 @@ #define FDOPEN_ fdopen #endif +#include "m_random.h" +#include "cmdlib.h" -#ifdef _WIN32 -#define FILE_SEPARATOR "\\" -#else #define FILE_SEPARATOR "/" -#endif #define RANDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" #define NRANDCHARS (sizeof(RANDCHARS) - 1) +static FRandom pr_tmpfile; + /** Replace each byte in string s with a random character from TEMPCHARS */ static char *set_randpart(char *s) { size_t i; unsigned int r; - static unsigned int seed; /* NB static */ - if (seed == 0) - { /* First time set our seed using current time and clock */ - seed = ((unsigned)time(NULL)<<8) ^ (unsigned)clock(); - } - srand(seed++); + for (i = 0; i < strlen(s); i++) { - r = rand() % NRANDCHARS; + r = pr_tmpfile() % NRANDCHARS; s[i] = (RANDCHARS)[r]; } return s; } -/** Return 1 if path is a valid directory otherwise 0 */ -static int is_valid_dir(const char *path) -{ - struct stat st; - if ((stat(path, &st) == 0) && (st.st_mode & S_IFDIR)) - return 1; - - return 0; -} - /** Call getenv and save a copy in buf */ static char *getenv_save(const char *varname, char *buf, size_t bufsize) { @@ -203,7 +171,7 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp pmode = S_IRUSR|S_IWUSR; #endif - if (!tmpdir || !is_valid_dir(tmpdir)) { + if (!tmpdir || !DirExists(tmpdir)) { errno = ENOENT; return NULL; } @@ -295,32 +263,3 @@ FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep return fp; } -/* Same as tmpfileplus() but with fixed length buffer for output filename and no memory allocation */ -FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep) -{ - char *tmpbuf = NULL; - FILE *fp; - - /* If no buffer provided, do the normal way */ - if (!pathnamebuf || (int)pathsize <= 0) { - return tmpfileplus(dir, prefix, NULL, keep); - } - /* Call with a temporary buffer */ - fp = tmpfileplus(dir, prefix, &tmpbuf, keep); - if (fp && strlen(tmpbuf) > pathsize - 1) { - /* Succeeded but not enough room in output buffer, so clean up and return an error */ - pathnamebuf[0] = 0; - fclose(fp); - if (keep) remove(tmpbuf); - free(tmpbuf); - errno = E2BIG; - return NULL; - } - /* Copy name into buffer */ - strcpy(pathnamebuf, tmpbuf); - free(tmpbuf); - - return fp; -} - - diff --git a/src/tmpfileplus.h b/src/tmpfileplus.h index e32ff5042..07b5ca0d5 100644 --- a/src/tmpfileplus.h +++ b/src/tmpfileplus.h @@ -23,10 +23,6 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - /** Create a unique temporary file. @param dir (optional) directory to create file. If NULL use default TMP directory. @param prefix (optional) prefix for file name. If NULL use "tmp.". @@ -40,22 +36,6 @@ extern "C" { FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep); -/** Create a unique temporary file with filename stored in a fixed-length buffer. -@param dir (optional) directory to create file. If NULL use default directory. -@param prefix (optional) prefix for file name. If NULL use "tmp.". -@param pathnamebuf (optional) buffer to receive full pathname of temporary file. Ignored if NULL. -@param pathsize Size of buffer to receive filename and its terminating null character. -@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing. - Otherwise file is automatically deleted when closed. -@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error. -@exception E2BIG Resulting filename is too big for the buffer `pathnamebuf`. -*/ -FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep); - #define TMPFILE_KEEP 1 -#ifdef __cplusplus -} -#endif - #endif /* end TMPFILEPLUS_H_ */ From 7cbcbe66c06f9b0c9537988311b5119f802c8a28 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 17:33:43 +0100 Subject: [PATCH 37/39] - sanitization of temporary file stuff for Timidity++. * do not use the global temp directory. Instead create one in the AppData folder. * removed lots of unneeded code from tmpfileplus. * use C++ strings in there. --- src/m_misc.h | 1 + src/posix/osx/i_specialpaths.mm | 30 +++++++ src/posix/unix/i_specialpaths.cpp | 20 +++++ .../music_timiditypp_mididevice.cpp | 18 ++-- src/tmpfileplus.cpp | 84 +++---------------- src/tmpfileplus.h | 4 +- src/win32/i_specialpaths.cpp | 31 +++++++ 7 files changed, 105 insertions(+), 83 deletions(-) diff --git a/src/m_misc.h b/src/m_misc.h index 47db77bb7..8f375b930 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -53,6 +53,7 @@ FString M_ZLibError(int zerrnum); #ifdef __unix__ FString GetUserFile (const char *path); // Prepends ~/.zdoom to path #endif +FString M_GetAppDataPath(bool create); FString M_GetCachePath(bool create); FString M_GetAutoexecPath(); FString M_GetCajunPath(const char *filename); diff --git a/src/posix/osx/i_specialpaths.mm b/src/posix/osx/i_specialpaths.mm index 843fb82d6..fbb32cec6 100644 --- a/src/posix/osx/i_specialpaths.mm +++ b/src/posix/osx/i_specialpaths.mm @@ -39,6 +39,35 @@ #include "m_misc.h" #include "version.h" // for GAMENAME +//=========================================================================== +// +// M_GetAppDataPath macOS +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + FString path; + + char pathstr[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) + { + path = pathstr; + } + else + { + path = progdir; + } + path += "/" GAMENAMELOWERCASE; + if (create) CreatePath(path); + return path; +} + //=========================================================================== // // M_GetCachePath macOS @@ -64,6 +93,7 @@ FString M_GetCachePath(bool create) path = progdir; } path += "/zdoom/cache"; + if (create) CreatePath(path); return path; } diff --git a/src/posix/unix/i_specialpaths.cpp b/src/posix/unix/i_specialpaths.cpp index 5dedba057..581fda5d5 100644 --- a/src/posix/unix/i_specialpaths.cpp +++ b/src/posix/unix/i_specialpaths.cpp @@ -98,6 +98,26 @@ FString GetUserFile (const char *file) return path; } +//=========================================================================== +// +// M_GetAppDataPath Unix +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + FString path = NicePath("~/.config/" GAMENAMELOWERCASE); + if (create) + { + CreatePath(path); + } + return path; +} + //=========================================================================== // // M_GetCachePath Unix diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index d4c03534d..42733ce38 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -43,6 +43,7 @@ #include "templates.h" #include "version.h" #include "tmpfileplus.h" +#include "m_misc.h" #ifndef _WIN32 #include @@ -82,7 +83,7 @@ public: protected: bool LaunchTimidity(); - char* DiskName; + FString DiskName; #ifdef _WIN32 HANDLE ReadWavePipe; HANDLE WriteWavePipe; @@ -165,8 +166,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) - : DiskName(nullptr), +TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), ChildProcess(INVALID_HANDLE_VALUE), @@ -204,10 +204,9 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) TimidityPPMIDIDevice::~TimidityPPMIDIDevice () { - if (nullptr != DiskName) + if (DiskName.IsNotEmpty()) { remove(DiskName); - free(DiskName); } #if _WIN32 @@ -257,7 +256,10 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) // Write MIDI song to temporary file song->CreateSMF(midi, looping ? 0 : 1); - f = tmpfileplus(nullptr, "zmid", &DiskName, 1); + FString path = M_GetAppDataPath(false); + path += "/tmp"; + CreatePath(path); + f = tmpfileplus(path, "zmid", &DiskName, 1); if (f == NULL) { Printf(PRINT_BOLD, "Could not open temp music file\n"); @@ -454,7 +456,7 @@ bool TimidityPPMIDIDevice::ValidateTimidity() bool TimidityPPMIDIDevice::LaunchTimidity () { - if (ExeName.IsEmpty() || nullptr == DiskName) + if (ExeName.IsEmpty() || DiskName.IsEmpty()) { return false; } @@ -565,7 +567,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity () arglist.push_back("-"); arglist.push_back(outmodearg.c_str()); arglist.push_back(ifacearg.c_str()); - arglist.push_back(DiskName); + arglist.push_back(DiskName.GetChars()); DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename); int i = 1; diff --git a/src/tmpfileplus.cpp b/src/tmpfileplus.cpp index 0ebb23185..bfe021dbb 100644 --- a/src/tmpfileplus.cpp +++ b/src/tmpfileplus.cpp @@ -97,10 +97,9 @@ #include "m_random.h" #include "cmdlib.h" +#include "zstring.h" -#define FILE_SEPARATOR "/" - #define RANDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" #define NRANDCHARS (sizeof(RANDCHARS) - 1) @@ -121,27 +120,13 @@ static char *set_randpart(char *s) return s; } -/** Call getenv and save a copy in buf */ -static char *getenv_save(const char *varname, char *buf, size_t bufsize) -{ - char *ptr = getenv(varname); - buf[0] = '\0'; - if (ptr) - { - strncpy(buf, ptr, bufsize); - buf[bufsize-1] = '\0'; - return buf; - } - return NULL; -} - /** * Try and create a randomly-named file in directory `tmpdir`. * If successful, allocate memory and set `tmpname_ptr` to full filepath, and return file pointer; * otherwise return NULL. * If `keep` is zero then create the file as temporary and it should not exist once closed. */ -static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmpname_ptr, int keep) +static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, FString *tmpname_ptr, int keep) /* PRE: * pfx is not NULL and points to a valid null-terminated string * tmpname_ptr is not NULL. @@ -150,9 +135,7 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp FILE *fp; int fd; char randpart[] = "1234567890"; - size_t lentempname; int i; - char *tmpname = NULL; int oflag, pmode; /* In Windows, we use the _O_TEMPORARY flag with `open` to ensure the file is deleted when closed. @@ -176,18 +159,13 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp return NULL; } - lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart); - tmpname = (char*)malloc(lentempname + 1); - if (!tmpname) - { - errno = ENOMEM; - return NULL; - } + FString tempname; + /* If we don't manage to create a file after 10 goes, there is something wrong... */ for (i = 0; i < 10; i++) { - sprintf(tmpname, "%s%s%s%s", tmpdir, FILE_SEPARATOR, pfx, set_randpart(randpart)); - fd = OPEN_(tmpname, oflag, pmode); + tempname.Format("%s/%s%s", tmpdir, pfx, set_randpart(randpart)); + fd = OPEN_(tempname, oflag, pmode); if (fd != -1) break; } if (fd != -1) @@ -205,13 +183,8 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp { /* We failed */ fp = NULL; } - if (!fp) - { - free(tmpname); - tmpname = NULL; - } - *tmpname_ptr = tmpname; + if (tmpname_ptr) *tmpname_ptr = tempname; return fp; } @@ -219,47 +192,10 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp /* EXPORTED FUNCTIONS */ /**********************/ -FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep) +FILE *tmpfileplus(const char *dir, const char *prefix, FString *pathname, int keep) { - FILE *fp = NULL; - char *tmpname = NULL; - char *tmpdir = NULL; - const char *pfx = (prefix ? prefix : "tmp."); - char *tempdirs[12] = { 0 }; - char env1[FILENAME_MAX+1] = { 0 }; - char env2[FILENAME_MAX+1] = { 0 }; - char env3[FILENAME_MAX+1] = { 0 }; - int ntempdirs = 0; - int i; - - /* Set up a list of temp directories we will try in order */ - i = 0; - tempdirs[i++] = (char *)dir; -#ifdef _WIN32 - tempdirs[i++] = getenv_save("TMP", env1, sizeof(env1)); - tempdirs[i++] = getenv_save("TEMP", env2, sizeof(env2)); -#else - tempdirs[i++] = getenv_save("TMPDIR", env3, sizeof(env3)); - tempdirs[i++] = P_tmpdir; -#endif - tempdirs[i++] = "."; - ntempdirs = i; - - errno = 0; - - /* Work through list we set up before, and break once we are successful */ - for (i = 0; i < ntempdirs; i++) - { - tmpdir = tempdirs[i]; - fp = mktempfile_internal(tmpdir, pfx, &tmpname, keep); - if (fp) break; - } - /* If we succeeded and the user passed a pointer, set it to the alloc'd pathname: the user must free this */ - if (fp && pathname) - *pathname = tmpname; - else /* Otherwise, free the alloc'd memory */ - free(tmpname); - + FILE *fp = mktempfile_internal(dir, (prefix ? prefix : "tmp."), pathname, keep); + if (!fp && pathname) *pathname = ""; return fp; } diff --git a/src/tmpfileplus.h b/src/tmpfileplus.h index 07b5ca0d5..06219edd6 100644 --- a/src/tmpfileplus.h +++ b/src/tmpfileplus.h @@ -23,6 +23,8 @@ #include +class FString; + /** Create a unique temporary file. @param dir (optional) directory to create file. If NULL use default TMP directory. @param prefix (optional) prefix for file name. If NULL use "tmp.". @@ -33,7 +35,7 @@ @return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error. @exception ENOMEM Not enough memory to allocate filename. */ -FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep); +FILE *tmpfileplus(const char *dir, const char *prefix, FString *pathname, int keep); #define TMPFILE_KEEP 1 diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 58c87a8ca..4a790798f 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -153,6 +153,33 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create } } +//=========================================================================== +// +// M_GetAppDataPath Windows +// +// Returns the path for the AppData folder. +// +//=========================================================================== + +FString M_GetAppDataPath(bool create) +{ + FString path; + + if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path)) + { // Failed (e.g. On Win9x): use program directory + path = progdir; + } + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + path += "/" GAMENAMELOWERCASE; + path.Substitute("//", "/"); // needed because progdir ends with a slash. + if (create) + { + CreatePath(path); + } + return path; +} + //=========================================================================== // // M_GetCachePath Windows @@ -173,6 +200,10 @@ FString M_GetCachePath(bool create) // share the node cache. path += "/zdoom/cache"; path.Substitute("//", "/"); // needed because progdir ends with a slash. + if (create) + { + CreatePath(path); + } return path; } From cc54db6e6df481e94d669f58fcbf58810a02504a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 2 Dec 2017 21:21:57 +0100 Subject: [PATCH 38/39] - let the 3 relevant text functions handle UTF-8 strings These functions are: DCanvas::DrawTextCommon, V_BreakLines and FFont::StringWidth. This will allow strings from UTF-8 encoded assets to display properly, but also handle the OpenAL device name on international systems, as this will be returned as an UTF-8 string. Due to backwards compatibility needs the decoding function is rather lax to allow both UTF-8 and ISO 8859-1 to pass through correctly - and this also implies that it will allow mixed encodings which may happen if strings from different sources get concatenated. --- src/v_font.cpp | 10 +++---- src/v_text.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/v_text.h | 2 ++ 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index b475fb558..9716f2744 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -890,9 +890,10 @@ int FFont::StringWidth(const uint8_t *string) const while (*string) { - if (*string == TEXTCOLOR_ESCAPE) + auto chr = GetCharFromString(string); + if (chr == TEXTCOLOR_ESCAPE) { - ++string; + // We do not need to check for UTF-8 in here. if (*string == '[') { while (*string != '\0' && *string != ']') @@ -906,16 +907,15 @@ int FFont::StringWidth(const uint8_t *string) const } continue; } - else if (*string == '\n') + else if (chr == '\n') { if (w > maxw) maxw = w; w = 0; - ++string; } else { - w += GetCharWidth(*string++) + GlobalKerning; + w += GetCharWidth(chr) + GlobalKerning; } } diff --git a/src/v_text.cpp b/src/v_text.cpp index cf8ce8cc7..f4829ec18 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -51,6 +51,78 @@ int ListGetInt(VMVa_List &tags); +//========================================================================== +// +// reads one character from the string. +// This can handle both ISO 8859-1 and UTF-8, as well as mixed strings +// between both encodings, which may happen if inconsistent encoding is +// used between different files in a mod. +// +//========================================================================== + +int GetCharFromString(const uint8_t *&string) +{ + int z, y, x; + + z = *string++; + + if (z < 192) + { + return z; + } + else if (z <= 223) + { + y = *string++; + if (y < 128 || y >= 192) + { + // not an UTF-8 sequence so return the first byte unchanged + string--; + } + else + { + z = (z - 192) * 64 + (y - 128); + } + } + else if (z >= 224 && z <= 239) + { + y = *string++; + if (y < 128 || y >= 192) + { + // not an UTF-8 sequence so return the first byte unchanged + string--; + } + else + { + x = *string++; + if (x < 128 || x >= 192) + { + // not an UTF-8 sequence so return the first byte unchanged + string -= 2; + } + else + { + z = (z - 224) * 4096 + (y - 128) * 64 + (x - 128); + } + } + } + else if (z >= 240) + { + y = *string++; + if (y < 128 || y >= 192) + { + // not an UTF-8 sequence so return the first byte unchanged + string--; + } + else + { + // we do not support 4-Byte UTF-8 here + string += 2; + return '?'; + } + } + return z; +} + //========================================================================== // // DrawChar @@ -170,7 +242,7 @@ void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, c while ((const char *)ch - string < parms.maxstrlen) { - c = *ch++; + c = GetCharFromString(ch); if (!c) break; @@ -288,7 +360,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo w = 0; - while ( (c = *string++) ) + while ( (c = GetCharFromString(string)) ) { if (c == TEXTCOLOR_ESCAPE) { diff --git a/src/v_text.h b/src/v_text.h index b76024fa5..cd7d3e6ad 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -86,4 +86,6 @@ inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, b inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false, unsigned int *count = nullptr) { return V_BreakLines (font, maxwidth, (const uint8_t *)str.GetChars(), preservecolor, count); } +int GetCharFromString(const uint8_t *&string); + #endif //__V_TEXT_H__ From 52be9895b74a8de22de128b04f213d18b57fe2dc Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 3 Dec 2017 00:23:28 +0100 Subject: [PATCH 39/39] - Disable softpoly models --- src/polyrenderer/scene/poly_playersprite.cpp | 2 +- src/polyrenderer/scene/poly_sprite.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/polyrenderer/scene/poly_playersprite.cpp b/src/polyrenderer/scene/poly_playersprite.cpp index 017396ffb..3c17941ba 100644 --- a/src/polyrenderer/scene/poly_playersprite.cpp +++ b/src/polyrenderer/scene/poly_playersprite.cpp @@ -43,7 +43,7 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread) // // We also can't move it because the model render code relies on it - renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); + //renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index 9ea184c35..f3ce12a5e 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -74,7 +74,7 @@ bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right) void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2) { - int spritenum = thing->sprite; + /*int spritenum = thing->sprite; bool isPicnumOverride = thing->picnum.isValid(); FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); if (modelframe) @@ -83,7 +83,7 @@ void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldTo DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); PolyRenderModel(thread, worldToClip, clipPlane, stencilValue, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing); return; - } + }*/ DVector2 line[2]; if (!GetLine(thing, line[0], line[1]))