Introduction:
CL_Sprite contains set_linear_filter(), that determines if CL_Texture uses linear filtering or nearest filtering.

This is used to control how the source texture pixels are stretced.
Linear Filtering - Uses the average of neighbouring pixels
Nearest Filtering - Uses the nearest pixel

Usage:
Lets say we have an Image somewhere within the CL_Texture

For linear filtering, we want to ensure that the Image coordinates denote the center of the pixel:
For example: coordinate_x = (image_position_x + cl_pixelcenter_constant) / texture_width

The cl_pixelcenter_constant is 0.375, that is the "magic" number that looks best in most situations.

This has a side effect; the pixel position of the image may be a pixel outside of the image (depending on the destination scale/rotation)

This is solved by giving the image within the texture a 1 pixel outline in the same color as the inner pixels

For nearest filtering, since we do not care about the neighbouring pixels, we do not not need to add the cl_pixelcenter_constant or require the pixel outline

Problem

CL_SpriteRenderBatch::to_sprite_vertex() and CL_SpriteRenderBatch::draw_image()

Contains: coordinate_x = (image_position_x + cl_pixelcenter_constant) / texture_width

- Even when the CL_Texture filtering is set to nearest filtering

Thus, it is a requirement to always have a pixel outline.

Solution 1

Modify CL_Sprite to automatically add a pixel outline (in the same color as the inner pixel) if scaling is used

(Ideally, this should also be required for CL_Font_Texture, as it compacts font glyphs within the same texture)

Make it a requirement for CL_Image's to have a pixel outline. The Utilities/TexturePacker already adds this extra pixel

Solution 2

If filtering is "linear", use Solution 1

If filtering is "nearest", modify CL_SpriteRenderBatch::to_sprite_vertex() and CL_SpriteRenderBatch::draw_image() to not use the cl_pixelcenter_constant (thus negating the need to have a 1 pixel outline)

Notes

The calculation for the texture position in CL_SpriteRenderBatch::draw_image() can be precalculated (in the CL_Image constructor)

How to determine the filtering used is not straightforward:
We could use... if (texture.get_mag_filter() == cl_filter_nearest)
But there is also texure_get_min_filter() and mipmap filters.

Proof

See Tests/Display/TexelCenter