raysan5 / raylib

A simple and easy-to-use library to enjoy videogames programming
http://www.raylib.com
zlib License
22.38k stars 2.25k forks source link

[rlgl][rshapes] rlBegin discards texture when drawing mode switches #4347

Open Destructor17 opened 4 weeks ago

Destructor17 commented 4 weeks ago

Issue description

When using GL version other then 1.1 and rlBegin is called with mode which differs from previous one, it sets textuteID to RLGL.State.defaultTextureId. It is a problem because texture is set using rlSetTexture function BEFORE rlBegin is called. Possible solution is to preserve textureID whet drawing mode switches, as it is done in https://github.com/raysan5/raylib/pull/4296. Surprisingly, many functions in rshapes, such as DrawEllipse(and maybe in other modules) depends on this wrong behavior: they don't set texture while hoping it is already set to default one(ID 1). It means that fixing this bug in rlBegin will uncover a lot of other bugs in rshapes (this is one of reasons why I closed my PR).

The brightest example is textures_polygon. The current implementation works but has the following comment:

// Texturing is only supported on RL_QUADS

and uses quads QUADS where two last vertices are same instead of triangles.

Environment

GLFW, Linux, OpenGL ES 3.2 I guess this bug may be reproduced at any OpenGL version other than 1.1

Issue Screenshot

See code example. This is without preserving textureID (polygon is white) image

And this is with preserving (ellipse is missing) image

Code Example

Code of modified DrawTexturePoly. Note DrawEllipse and RL_TRIANGLES

void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint)
{
    DrawEllipse(GetScreenWidth()/2.0f, GetScreenHeight()/2.0f, GetScreenWidth()/4.0f, GetScreenHeight()/4.0f, RED);
    rlSetTexture(texture.id);

    // Texturing is only supported on RL_QUADS
    rlBegin(RL_TRIANGLES);

        rlColor4ub(tint.r, tint.g, tint.b, tint.a);

        for (int i = 0; i < pointCount - 1; i++)
        {
            rlTexCoord2f(0.5f, 0.5f);
            rlVertex2f(center.x, center.y);

            rlTexCoord2f(texcoords[i].x, texcoords[i].y);
            rlVertex2f(points[i].x + center.x, points[i].y + center.y);

            rlTexCoord2f(texcoords[i + 1].x, texcoords[i + 1].y);
            rlVertex2f(points[i + 1].x + center.x, points[i + 1].y + center.y);

            // same as previous
            // rlTexCoord2f(texcoords[i + 1].x, texcoords[i + 1].y);
            // rlVertex2f(points[i + 1].x + center.x, points[i + 1].y + center.y);
        }
    rlEnd();

    rlSetTexture(0);
}

Code(two lines at rlBegin) used to preserve texture on second screenshot can be found in https://github.com/raysan5/raylib/pull/4296

raysan5 commented 3 weeks ago

@Destructor17 It is implemented this way because none of the rshapes shapes drawing funtions using RL_TRIANGLES or RL_LINES define texture coordinates, so they require to use the default texture. Changing this behaviour would imply adding a rlSetTexture(rlGetTextureDefault().id) to all shapes drawing functions.

It means that fixing this bug in rlBegin will uncover a lot of other bugs in rshapes (this is one of reasons why I closed my PR).

Yeah, exactly that situation.

Is it possible to call rlSetTexture() after rlBegin()? I haven't looked into detail this situation so maybe that's not possible...

Destructor17 commented 3 weeks ago

@raysan5 If this behaviour is expected and texture must be default if not specified, then rlEnd should reset it, not rlBegin. Here is a PR https://github.com/raysan5/raylib/pull/4364