Search code examples
c++renderingsdlrenderculling

SDL Screen Render Position Error Along Top of Window


I am making a top down isometric game using SDL 2.0 and C++ and have come across a glitch.

When a texture is rendered to the screen using the SDL_RenderCopyfunction, the moment the top of the texture hits the top of the screen it gets pushed down by one pixel, thus causing the missing borders seen in the following picture:

Pre-edit with no annotations

Post-edit with with annotations

The following is my render function specific to the world itself, as the world renders differently from everything else in the game, because I am simply copying a "source" texture instead of loading a texture for every single tile in the game, which would be absurdly inefficient.

//-----------------------------------------------------------------------------
// Rendering

DSDataTypes::Sint32 World::Render()
{
    //TODO: Change from indexing to using an interator (pointer) for efficiency
    for(int index = 0; index < static_cast<int>(mWorldSize.mX * mWorldSize.mY); ++index)
    {
        const int kTileType = static_cast<int>(mpTilesList[index].GetType());

        //Translate the world so that when camera panning occurs the objects in the world will all be in the accurate position

I am also incorporating camera panning as follows (paraphrased with some snippets of code included as my camera panning logic spans multiple files due to the object orientated design of my game):

(code from above immediately continued below)

        mpTilesList[index].SetRenderOffset(Window::GetPanOffset());

        //position (dstRect)
        SDL_Rect position;
        position.x = static_cast<int>(mpTilesList[index].GetPositionCurrent().mX + Window::GetPanOffset().mX);
        position.y = static_cast<int>(mpTilesList[index].GetPositionCurrent().mY + Window::GetPanOffset().mY);
        position.w = static_cast<int>(mpTilesList[index].GetSize().mX);
        position.h = static_cast<int>(mpTilesList[index].GetSize().mY);

        //clip (frame)
        SDL_Rect clip;
        clip.x = static_cast<int>(mpSourceList[kTileType].GetFramePos().mX);
        clip.y = static_cast<int>(mpSourceList[kTileType].GetFramePos().mY);
        clip.w = static_cast<int>(mpSourceList[kTileType].GetFrameSize().mX);
        clip.h = static_cast<int>(mpSourceList[kTileType].GetFrameSize().mY);

I am confused as to why this is happening, as regardless of whether I include my simple culling algorithm or not (as shown below), the same result occurs.

(code from above immediately continued below)

        //Check to ensure tile is being drawn within the screen size. If so, rendercopy it, else simply skip over and do not render it.
        //If the tile's position.x is greather than the left border of the screen
        if(position.x > (-mpSourceList[kTileType].GetRenderSize().mX))
        {
            //If the tile's position.y is greather than the top border of the screen
            if(position.y > (-mpSourceList[kTileType].GetRenderSize().mY))
            {
                //If the tile's position.x is less than the right border of the screen
                if(position.x < Window::msWindowSize.w)
                {
                    //If the tile's position.y is less than the bottom border of the screen
                    if(position.y < Window::msWindowSize.h)
                    {
                        SDL_RenderCopy(Window::mspRenderer.get(), mpSourceList[kTileType].GetTexture(), &clip, &position);
                    }
                }
            }
        }
    }

    return 0;//TODO
}

Solution

  • Short version of answer, restated at bottom:

    • By fixing my data types issue, that allowed me to fix my math library, which removed the issue of rounding parts of pixels, since there is no such thing as less than 1 but greater than 0 pixels on the screen when rendering.

    Long Answer:

    I believe the issue to have been caused by a rounding error with the offset logic used when rotating a 2D grid to a diagonal isometric perspective, with the rounding error only occurring when dealing with screen coordinates between -1 and +1.

    Since I based the conversion from changing an orthogonal grid to a diagonal grid on the y axis (rows), this would explain why the single pixel offset was occurring only at the top border of the screen and not bottom border.

    Even though every single row had implicit rounding occurring without any safety checks, only the conversion from world coordinates to screen coordinates dealt with rounding between a positive and negative number.

    The reason behind all of this is because my math library which was templatized had an issue a lot of my code being based on type defined user types such as:

    typedef unsigned int Uint32;
    typedef signed int Sint32;
    

    So I simply used DSMathematics::Vector2<float> instead of the proper implementation of DSMathematics::Vector2<int>.

    The reason this is an issue is because there cannot be "half a pixel" on the screen, and thus integers must be used instead of floating point values.

    By fixing my data types issue, that allowed me to fix my math library, which removed the issue of rounding parts of pixels, since there is no such thing as less than 1 but greater than 0 pixels on the screen when rendering.