Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[textures] DrawTextureEx() is not sub-pixel precise #527

Closed
dbriemann opened this issue May 1, 2018 · 9 comments
Closed

[textures] DrawTextureEx() is not sub-pixel precise #527

dbriemann opened this issue May 1, 2018 · 9 comments
Labels
enhancement This is an improvement of some feature

Comments

@dbriemann
Copy link

As you can see here:

Rectangle destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale };
the drawing of textures is not sub-pixel precise, It is just casted to an int. So a moving sprite "jumps" from pixel to pixel.

Some kind of sub-pixel rendering or anti-aliasing here would be good!

@raysan5 raysan5 changed the title DrawTextureEx is not sub-pixel precise. [textures] DrawTextureEx() is not sub-pixel precise May 1, 2018
@raysan5 raysan5 added the enhancement This is an improvement of some feature label May 1, 2018
@sherjilozair
Copy link
Contributor

Antialiasing tends to produce blurry graphics and harm pixel art aesthetics, though. Maybe this feature should only be optional. IMO, jumping from one pixel to another is okay. For instance, check this for how in Towerfall, the characters move 1 pixel at a time. There's no sub-pixel movement.

@dbriemann
Copy link
Author

You are right it depends on the use case. And maybe it isn't even needed. I compared the movement of a sprite to the movement of a circle (with DrawCircleV), both use float coordinates. The movement of the circle is smoother. Now the only difference is that DrawCircleV directly calls rlVertex2f which takes float values whereas DrawTexturePro (which is called by all DrawTexture functions) expects a rectangle (int values).

I think that the DrawTexture functions should skip rectangles in favor of Vector2s, so the float values are not touched before being passed to OpenGL.

And for the record. This is the kind of jumpy movement I mean:

orbiteer-jumpy

It should be smooth. You can also observe similar problems in the core/camera2d example, especially when zooming out and moving the block continuously.

@raysan5
Copy link
Owner

raysan5 commented May 3, 2018

Keep thinking but not sure how to fix this, there is no easy solution...

  1. First idea (and the simpler one) is just defining:
typedef struct Rectangle {
    float x;
    float y;
    float width;
    float height;
} Rectangle;
  1. Another idea was letting the user choose the desired precision:
typedef struct Rectangle {
#if defined(SUPPORT_FLOAT_RECTANGLE)
    float x;
    float y;
    float width;
    float height;
#else
    int x;
    int y;
    int width;
    int height;
#endif
} Rectangle;
  1. Just rewrite functions to support float parameters (Vector2) instead of Rectangle but this solution implies changing lots of functions...

Functions affected by this change:

void DrawRectangleRec(Rectangle rec, Color color);
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color);
void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4);
void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color);
bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2);
bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec);
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
bool CheckCollisionPointRec(Vector2 point, Rectangle rec);
void ImageCrop(Image *image, Rectangle crop);
void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec);
void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color);
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint);
void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint);
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint);

Any other idea?

@sherjilozair
Copy link
Contributor

I think 1 is probably the best among these. Those (like me) who want integer-precision can just make sure all their floats are integers.

@egonelbre
Copy link

egonelbre commented May 3, 2018

+1 for using floats in rectangle. Also add function Rectangle RectangleSnap(r Rectangle, snap int) and Vector2 Vector2Snap(r Vector2, snap int) (or some other name). This would make life easier with snapping to those who need it.

Getting pixel-art aesthetic right would need some better solution anyways. Currently with high-resolution displays you need to change the snapping amount and adjust them to match image scaling. More likely you will need to snap every 4px or more to make the "pixel-art" look right. Also, don't forget about the problems moving Camera2D.

@sherjilozair
Copy link
Contributor

sherjilozair commented May 3, 2018

I think the best way to support pixel art graphics is to have virtual canvases. That is, have a virtual screen of size (320, 180), where all the pixels are drawn. Then each pixel in this virtual buffer is drawn scaled up for 16:9 screens. This way, the physics code does not need to deal with anything other than a (320, 180) screen, but the display can do any 16:9 screen or even 16:10 with letterboxing.

Currently, in raylib, I have to pass in a scale parameter to every DrawTexture call and multiply my position vectors as well, which imo is not very convenient. A virtual canvas would be a nice feature. But I understand if this is too complex for raylib.

@raysan5
Copy link
Owner

raysan5 commented May 3, 2018

@sherjilozair @egonelbre thank you very much for your feedback! I think I'll go for 1.

@sherjilozair virtual canvas has already been available in raylib for some time, it can be accomplished with a RenderTarget2D. You can see create a 320x180 target to render to and then use that texture to draw to fullscreen. Some reference could be found here, despite using same size for target and screen. Mouse input could be scaled with SetMouseScale().

One usage example could be found on my tool rFXGen, it has a button to scale window to double size... while internal render size keeps being original size.

@raysan5
Copy link
Owner

raysan5 commented May 4, 2018

Implemented proposed solution 1. in commit 6324697

This change is more critical than I expected, it could break some things... let's see...

@raysan5
Copy link
Owner

raysan5 commented May 7, 2018

Just note here that changing Rectangle parameters to float is breaking several raylib examples, including all based on RenderTexture2D, related to drawing...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement This is an improvement of some feature
Projects
None yet
Development

No branches or pull requests

4 participants