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/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/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..37a7f843b 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]; @@ -1172,27 +1177,97 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr } } - // 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(); + auto drawfunc = (args->destBgra) ? DrawSpan32 : DrawSpan8; - uint8_t stencilTestValue = args->uniforms->StencilTestValue(); - uint8_t stencilWriteValue = args->uniforms->StencilWriteValue(); + float stepXW = args->gradientX.W; + float v1X = args->v1->x; + float v1Y = args->v1->y; + float v1W = args->v1->w; - int bmode = (int)args->uniforms->BlendMode(); - auto drawFunc = args->destBgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode]; + 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]; - 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; - int color = ((int)(ptrdiff_t)args->uniforms->TexturePixels()) >> 2; + 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) + { + 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 + while (x < xend) + { + 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 + } +} + +#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; @@ -1201,13 +1276,15 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr 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(); - const uint8_t *texPixels = args->uniforms->TexturePixels(); - auto colormaps = args->uniforms->BaseColormap(); bool is_fixed_light = args->uniforms->FixedLight(); uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; @@ -1216,86 +1293,225 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); light += light >> 7; // 255 -> 256 - // Draw the triangle: + uint32_t *dest = (uint32_t*)args->dest; + uint32_t *destLine = dest + args->pitch * y; - int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + int x = x0; + int sseEnd = x0 + ((x1 - x0) & ~3); + while (x < sseEnd) { - int x0 = leftEdge[y]; - int x1 = rightEdge[y]; + uint32_t fgcolor[2]; + int32_t lightshade[2]; - uint8_t *destLine = dest + pitch * y; - uint8_t *stencilLine = stencilbuffer + stencilpitch * y; - float *zbufferLine = zbuffer + stencilpitch * y; + 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]; - if ((stencilMasks[y] & 0xffffff00) == 0xffffff00) // First time we draw a line we have to clear the stencil buffer + 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; + } + + while (x < x1) + { + 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) { - memset(stencilLine, stencilMasks[y] & 0xff, stencilpitch); - stencilMasks[y] = 0; + 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; } - 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 = true; - - if (!depthTest) // To do: make the stencil test use its own flag for comparison mode instead of abusing the depth test.. - { - processPixel = stencilTestValue == stencilLine[x]; - } - else - { - processPixel = stencilTestValue >= stencilLine[x] && zbufferLine[x] <= posXW; - } - - 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 (writeStencil) - stencilLine[x] = stencilWriteValue; - if (writeDepth) - zbufferLine[x] = posXW; - } - - posXW += stepXW; - posXU += stepXU; - posXV += stepXV; - x++; - } + 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 + + uint32_t *dest = (uint32_t*)args->dest; + uint32_t *destLine = dest + args->pitch * y; + + int x = x0; + while (x < x1) + { + 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; + } + + 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 uint8_t *texPixels = 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 + + uint8_t *dest = (uint8_t*)args->dest; + uint8_t *destLine = dest + args->pitch * y; + + int x = x0; + while (x < x1) + { + 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++; + } +} + void(*ScreenTriangle::TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *) = { &TriScreenDrawer8::Execute, // TextureOpaque diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index a76dc4b46..62f59ba44 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -149,6 +149,9 @@ 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 *); 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; } 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],