diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 023de80d34..5176d2c366 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -966,6 +966,9 @@ static void R_DrawCubeSky(visplane_t *pl) }; TriMatrix objectToWorld = TriMatrix::translate((float)ViewPos.X, (float)ViewPos.Y, (float)ViewPos.Z) * TriMatrix::scale(1000.0f, 1000.0f, 1000.0f); + TriMatrix objectToClip = TriMatrix::viewToClip() * TriMatrix::worldToView() * objectToWorld; + //TriMatrix objectToWorld = TriMatrix::scale(1000.0f, 1000.0f, 1000.0f); + //TriMatrix objectToClip = TriMatrix::viewToClip() * objectToWorld; uint32_t solid_top = frontskytex->GetSkyCapColor(false); uint32_t solid_bottom = frontskytex->GetSkyCapColor(true); @@ -973,9 +976,9 @@ static void R_DrawCubeSky(visplane_t *pl) solid_top = RGB32k.RGB[(RPART(solid_top) >> 3)][(GPART(solid_top) >> 3)][(BPART(solid_top) >> 3)]; solid_bottom = RGB32k.RGB[(RPART(solid_bottom) >> 3)][(GPART(solid_bottom) >> 3)][(BPART(solid_bottom) >> 3)]; - TriangleDrawer::fill(objectToWorld, cube, 6, TriangleDrawMode::Normal, false, x1, x2 - 1, uwal, dwal, solid_top); - TriangleDrawer::fill(objectToWorld, cube + 6, 6, TriangleDrawMode::Normal, false, x1, x2 - 1, uwal, dwal, solid_bottom); - TriangleDrawer::draw(objectToWorld, cube + 2 * 6, 4 * 6, TriangleDrawMode::Normal, false, x1, x2 - 1, uwal, dwal, frontskytex); + TriangleDrawer::fill(objectToClip, cube, 6, TriangleDrawMode::Normal, false, x1, x2 - 1, uwal, dwal, solid_top); + TriangleDrawer::fill(objectToClip, cube + 6, 6, TriangleDrawMode::Normal, false, x1, x2 - 1, uwal, dwal, solid_bottom); + TriangleDrawer::draw(objectToClip, cube + 2 * 6, 4 * 6, TriangleDrawMode::Normal, false, x1, x2 - 1, uwal, dwal, frontskytex); } namespace @@ -1102,7 +1105,8 @@ namespace short *uwal = (short *)pl->top; short *dwal = (short *)pl->bottom; TriMatrix objectToWorld = TriMatrix::translate((float)ViewPos.X, (float)ViewPos.Y, (float)ViewPos.Z); - TriangleDrawer::draw(objectToWorld, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], TriangleDrawMode::Strip, false, x1, x2 - 1, uwal, dwal, frontskytex); + TriMatrix objectToClip = TriMatrix::viewToClip() * TriMatrix::worldToView() * objectToWorld; + TriangleDrawer::draw(objectToClip, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], TriangleDrawMode::Strip, false, x1, x2 - 1, uwal, dwal, frontskytex); } void SkyDome::RenderCapColorRow(int row, bool bottomCap, visplane_t *pl) @@ -1115,7 +1119,8 @@ namespace short *uwal = (short *)pl->top; short *dwal = (short *)pl->bottom; TriMatrix objectToWorld = TriMatrix::translate((float)ViewPos.X, (float)ViewPos.Y, (float)ViewPos.Z); - TriangleDrawer::fill(objectToWorld, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], TriangleDrawMode::Fan, bottomCap, x1, x2 - 1, uwal, dwal, solid); + TriMatrix objectToClip = TriMatrix::viewToClip() * TriMatrix::worldToView() * objectToWorld; + TriangleDrawer::fill(objectToClip, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], TriangleDrawMode::Fan, bottomCap, x1, x2 - 1, uwal, dwal, solid); } void SkyDome::Render(visplane_t *pl) diff --git a/src/r_triangle.cpp b/src/r_triangle.cpp index b6e7b1b2b6..b039ed1ffe 100644 --- a/src/r_triangle.cpp +++ b/src/r_triangle.cpp @@ -36,17 +36,17 @@ #include "r_data/colormaps.h" #include "r_triangle.h" -void TriangleDrawer::draw(const TriMatrix &objectToWorld, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture) +void TriangleDrawer::draw(const TriMatrix &objectToClip, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture) { - draw_arrays(objectToWorld, vinput, vcount, mode, ccw, clipleft, clipright, cliptop, clipbottom, texture, 0, &ScreenTriangleDrawer::draw); + draw_arrays(objectToClip, vinput, vcount, mode, ccw, clipleft, clipright, cliptop, clipbottom, texture, 0, &ScreenTriangleDrawer::draw); } -void TriangleDrawer::fill(const TriMatrix &objectToWorld, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, int solidcolor) +void TriangleDrawer::fill(const TriMatrix &objectToClip, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, int solidcolor) { - draw_arrays(objectToWorld, vinput, vcount, mode, ccw, clipleft, clipright, cliptop, clipbottom, nullptr, solidcolor, &ScreenTriangleDrawer::fill); + draw_arrays(objectToClip, vinput, vcount, mode, ccw, clipleft, clipright, cliptop, clipbottom, nullptr, solidcolor, &ScreenTriangleDrawer::fill); } -void TriangleDrawer::draw_arrays(const TriMatrix &objectToWorld, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture, int solidcolor, void(*drawfunc)(const ScreenTriangleDrawerArgs *)) +void TriangleDrawer::draw_arrays(const TriMatrix &objectToClip, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture, int solidcolor, void(*drawfunc)(const ScreenTriangleDrawerArgs *)) { if (vcount < 3) return; @@ -78,28 +78,28 @@ void TriangleDrawer::draw_arrays(const TriMatrix &objectToWorld, const TriVertex for (int i = 0; i < vcount / 3; i++) { for (int j = 0; j < 3; j++) - vert[j] = shade_vertex(objectToWorld, *(vinput++)); + vert[j] = shade_vertex(objectToClip, *(vinput++)); draw_shaded_triangle(vert, ccw, &args, drawfunc); } } else if (mode == TriangleDrawMode::Fan) { - vert[0] = shade_vertex(objectToWorld, *(vinput++)); - vert[1] = shade_vertex(objectToWorld, *(vinput++)); + vert[0] = shade_vertex(objectToClip, *(vinput++)); + vert[1] = shade_vertex(objectToClip, *(vinput++)); for (int i = 2; i < vcount; i++) { - vert[2] = shade_vertex(objectToWorld, *(vinput++)); + vert[2] = shade_vertex(objectToClip, *(vinput++)); draw_shaded_triangle(vert, ccw, &args, drawfunc); vert[1] = vert[2]; } } else // TriangleDrawMode::Strip { - vert[0] = shade_vertex(objectToWorld, *(vinput++)); - vert[1] = shade_vertex(objectToWorld, *(vinput++)); + vert[0] = shade_vertex(objectToClip, *(vinput++)); + vert[1] = shade_vertex(objectToClip, *(vinput++)); for (int i = 2; i < vcount; i++) { - vert[2] = shade_vertex(objectToWorld, *(vinput++)); + vert[2] = shade_vertex(objectToClip, *(vinput++)); draw_shaded_triangle(vert, ccw, &args, drawfunc); vert[0] = vert[1]; vert[1] = vert[2]; @@ -108,25 +108,10 @@ void TriangleDrawer::draw_arrays(const TriMatrix &objectToWorld, const TriVertex } } -TriVertex TriangleDrawer::shade_vertex(const TriMatrix &objectToWorld, TriVertex v) +TriVertex TriangleDrawer::shade_vertex(const TriMatrix &objectToClip, TriVertex v) { - // Apply transform to get world coordinates: - v = objectToWorld * v; - - // The software renderer world to clip transform: - double nearp = 5.0f; - double farp = 65536.f; - double tr_x = v.x - ViewPos.X; - double tr_y = v.y - ViewPos.Y; - double tr_z = v.z - ViewPos.Z; - double tx = tr_x * ViewSin - tr_y * ViewCos; - double tz = tr_x * ViewTanCos + tr_y * ViewTanSin; - v.x = (float)tx * 0.5f; - v.y = (float)tr_z * 0.5f; - v.z = (float)((-tz * (farp + nearp) / (nearp - farp) + (2.0f * farp * nearp) / (nearp - farp))); - v.w = (float)tz; - - return v; + // Apply transform to get clip coordinates: + return objectToClip * v; } void TriangleDrawer::draw_shaded_triangle(const TriVertex *vert, bool ccw, ScreenTriangleDrawerArgs *args, void(*drawfunc)(const ScreenTriangleDrawerArgs *)) @@ -150,8 +135,8 @@ void TriangleDrawer::draw_shaded_triangle(const TriVertex *vert, bool ccw, Scree v.z *= v.w; // Apply viewport scale to get screen coordinates: - v.x = (float)(CenterX + v.x * 2.0f * CenterX); - v.y = (float)(CenterY - v.y * 2.0f * InvZtoScale); + v.x = viewwidth * (1.0f + v.x) * 0.5f; + v.y = viewheight * (1.0f - v.y) * 0.5f; } // Draw screen triangles @@ -717,6 +702,45 @@ TriMatrix TriMatrix::rotate(float angle, float x, float y, float z) return m; } +TriMatrix TriMatrix::frustum(float left, float right, float bottom, float top, float near, float far) +{ + float a = (right + left) / (right - left); + float b = (top + bottom) / (top - bottom); + float c = -(far + near) / (far - near); + float d = -(2.0f * far) / (far - near); + TriMatrix m = null(); + m.matrix[0 + 0 * 4] = 2.0f * near / (right - left); + m.matrix[1 + 1 * 4] = 2.0f * near / (top - bottom); + m.matrix[0 + 2 * 4] = a; + m.matrix[1 + 2 * 4] = b; + m.matrix[2 + 2 * 4] = c; + m.matrix[2 + 3 * 4] = d; + m.matrix[3 + 2 * 4] = -1; + return m; +} + +TriMatrix TriMatrix::worldToView() +{ + TriMatrix m = null(); + m.matrix[0 + 0 * 4] = (float)ViewSin; + m.matrix[0 + 1 * 4] = (float)-ViewCos; + m.matrix[1 + 2 * 4] = 1.0f; + m.matrix[2 + 0 * 4] = (float)-ViewCos; + m.matrix[2 + 1 * 4] = (float)-ViewSin; + m.matrix[3 + 3 * 4] = 1.0f; + return m * translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z); +} + +TriMatrix TriMatrix::viewToClip() +{ + 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); + return frustum(-width, width, bottom, top, near, far); +} + TriMatrix TriMatrix::operator*(const TriMatrix &mult) const { TriMatrix result; diff --git a/src/r_triangle.h b/src/r_triangle.h index f1ff220b66..05cfada980 100644 --- a/src/r_triangle.h +++ b/src/r_triangle.h @@ -46,6 +46,10 @@ struct TriMatrix static TriMatrix translate(float x, float y, float z); static TriMatrix scale(float x, float y, float z); static TriMatrix rotate(float angle, float x, float y, float z); + static TriMatrix frustum(float left, float right, float bottom, float top, float near, float far); + + static TriMatrix worldToView(); // Software renderer world to view space transform + static TriMatrix viewToClip(); // Software renderer shearing projection TriVertex operator*(TriVertex v) const; TriMatrix operator*(const TriMatrix &m) const; @@ -63,12 +67,12 @@ enum class TriangleDrawMode class TriangleDrawer { public: - static void draw(const TriMatrix &objectToWorld, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture); - static void fill(const TriMatrix &objectToWorld, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, int solidcolor); + static void draw(const TriMatrix &objectToClip, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture); + static void fill(const TriMatrix &objectToClip, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, int solidcolor); private: - static TriVertex shade_vertex(const TriMatrix &objectToWorld, TriVertex v); - static void draw_arrays(const TriMatrix &objectToWorld, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture, int solidcolor, void(*drawfunc)(const ScreenTriangleDrawerArgs *)); + static TriVertex shade_vertex(const TriMatrix &objectToClip, TriVertex v); + static void draw_arrays(const TriMatrix &objectToClip, const TriVertex *vinput, int vcount, TriangleDrawMode mode, bool ccw, int clipleft, int clipright, const short *cliptop, const short *clipbottom, FTexture *texture, int solidcolor, void(*drawfunc)(const ScreenTriangleDrawerArgs *)); static void draw_shaded_triangle(const TriVertex *vertices, bool ccw, ScreenTriangleDrawerArgs *args, void(*drawfunc)(const ScreenTriangleDrawerArgs *)); static bool cullhalfspace(float clipdistance1, float clipdistance2, float &t1, float &t2); static void clipedge(const TriVertex &v1, const TriVertex &v2, TriVertex *clippedvert, int &numclipvert);