Skip to content

Commit

Permalink
Added texture wrap modes (clamp, repeat, and mirror repeat). Implemen…
Browse files Browse the repository at this point in the history
…ted in OpenGL and Direct3d renderers.
  • Loading branch information
dingogames committed Mar 1, 2022
1 parent 9835353 commit 32b1ed1
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 16 deletions.
12 changes: 12 additions & 0 deletions include/SDL_hints.h
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,18 @@ extern "C" {
*/
#define SDL_HINT_RENDER_SCALE_QUALITY "SDL_RENDER_SCALE_QUALITY"

/**
* \brief A variable controlling texture wrapping
*
* This variable can be set to the following values:
* "0" or "clamp" - Clamp to edge
* "1" or "repeat" - Repeat texture
* "2" or "mirrorrepeat" - Mirrored repeat
*
* By default clamp is used
*/
#define SDL_HINT_RENDER_TEXTURE_WRAP "SDL_RENDER_TEXTURE_WRAP"

/**
* \brief A variable controlling whether updates to the SDL screen surface should be synchronized with the vertical refresh, to avoid tearing.
*
Expand Down
16 changes: 16 additions & 0 deletions include/SDL_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ typedef enum
SDL_ScaleModeBest /**< anisotropic filtering */
} SDL_ScaleMode;

/**
* The scaling mode for a texture.
*/
typedef enum
{
SDL_WRAP_MODE_CLAMP, /**< clamp to edge */
SDL_WRAP_MODE_REPEAT, /**< repeat */
SDL_WRAP_MODE_MIRROR_REPEAT /**< mirrored repeat */
} SDL_WrapMode;

/**
* The access pattern allowed for a texture.
*/
Expand Down Expand Up @@ -527,6 +537,12 @@ extern DECLSPEC int SDLCALL SDL_SetTextureScaleMode(SDL_Texture * texture,
extern DECLSPEC int SDLCALL SDL_GetTextureScaleMode(SDL_Texture * texture,
SDL_ScaleMode *scaleMode);

extern DECLSPEC int SDLCALL SDL_SetTextureWrapMode(SDL_Texture* texture,
SDL_WrapMode wrapMode);

extern DECLSPEC int SDLCALL SDL_GetTextureWrapMode(SDL_Texture* texture,
SDL_WrapMode* wrapMode);

/**
* Associate a user-specified pointer with a texture.
*
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,8 @@
#define SDL_JoystickSetPlayerIndex SDL_JoystickSetPlayerIndex_REAL
#define SDL_SetTextureScaleMode SDL_SetTextureScaleMode_REAL
#define SDL_GetTextureScaleMode SDL_GetTextureScaleMode_REAL
#define SDL_SetTextureWrapMode SDL_SetTextureWrapMode_REAL
#define SDL_GetTextureWrapMode SDL_GetTextureWrapMode_REAL
#define SDL_OnApplicationWillTerminate SDL_OnApplicationWillTerminate_REAL
#define SDL_OnApplicationDidReceiveMemoryWarning SDL_OnApplicationDidReceiveMemoryWarning_REAL
#define SDL_OnApplicationWillResignActive SDL_OnApplicationWillResignActive_REAL
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,8 @@ SDL_DYNAPI_PROC(SDL_Joystick*,SDL_JoystickFromPlayerIndex,(int a),(a),return)
SDL_DYNAPI_PROC(void,SDL_JoystickSetPlayerIndex,(SDL_Joystick *a, int b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_SetTextureScaleMode,(SDL_Texture *a, SDL_ScaleMode b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetTextureScaleMode,(SDL_Texture *a, SDL_ScaleMode *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetTextureWrapMode,(SDL_Texture *a, SDL_WrapMode b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetTextureWrapMode,(SDL_Texture *a, SDL_WrapMode *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_OnApplicationWillTerminate,(void),(),)
SDL_DYNAPI_PROC(void,SDL_OnApplicationDidReceiveMemoryWarning,(void),(),)
SDL_DYNAPI_PROC(void,SDL_OnApplicationWillResignActive,(void),(),)
Expand Down
47 changes: 47 additions & 0 deletions src/render/SDL_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,21 @@ static SDL_ScaleMode SDL_GetScaleMode(void)
}
}

static SDL_WrapMode SDL_GetWrapMode(void)
{
const char *hint = SDL_GetHint(SDL_HINT_RENDER_TEXTURE_WRAP);

if (!hint || SDL_strcasecmp(hint, "clamp") == 0) {
return SDL_WRAP_MODE_CLAMP;
} else if (SDL_strcasecmp(hint, "repeat") == 0) {
return SDL_WRAP_MODE_REPEAT;
} else if (SDL_strcasecmp(hint, "mirrorrepeat") == 0) {
return SDL_WRAP_MODE_MIRROR_REPEAT;
} else {
return (SDL_WrapMode)SDL_atoi(hint);
}
}

SDL_Texture *
SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
{
Expand Down Expand Up @@ -1247,6 +1262,7 @@ SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int
texture->color.b = 255;
texture->color.a = 255;
texture->scaleMode = SDL_GetScaleMode();
texture->wrapMode = SDL_GetWrapMode();
texture->renderer = renderer;
texture->next = renderer->textures;
if (renderer->textures) {
Expand Down Expand Up @@ -1611,6 +1627,33 @@ SDL_GetTextureScaleMode(SDL_Texture * texture, SDL_ScaleMode *scaleMode)
return 0;
}

int
SDL_SetTextureWrapMode(SDL_Texture * texture, SDL_WrapMode wrapMode)
{
SDL_Renderer *renderer;

CHECK_TEXTURE_MAGIC(texture, -1);

renderer = texture->renderer;
renderer->SetTextureWrapMode(renderer, texture, wrapMode);
texture->wrapMode = wrapMode;
if (texture->native) {
return SDL_SetTextureWrapMode(texture->native, wrapMode);
}
return 0;
}

int
SDL_GetTextureWrapMode(SDL_Texture * texture, SDL_WrapMode *wrapMode )
{
CHECK_TEXTURE_MAGIC(texture, -1);

if (wrapMode) {
*wrapMode = texture->wrapMode;
}
return 0;
}

int
SDL_SetTextureUserData(SDL_Texture * texture, void *userdata)
{
Expand Down Expand Up @@ -4168,6 +4211,9 @@ SDL_RenderGeometryRaw(SDL_Renderer *renderer,
texture = texture->native;
}

// We have to remove this code because it prevents repeated texture wrapping from working
// I'm unclear if there is some other use to it (maybe software renderer has issue with out of bounds UV?)
/*
if (texture) {
for (i = 0; i < num_vertices; ++i) {
const float *uv_ = (const float *)((const char*)uv + i * uv_stride);
Expand All @@ -4178,6 +4224,7 @@ SDL_RenderGeometryRaw(SDL_Renderer *renderer,
}
}
}
*/

if (indices) {
for (i = 0; i < num_indices; ++i) {
Expand Down
2 changes: 2 additions & 0 deletions src/render/SDL_sysrender.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct SDL_Texture
int modMode; /**< The texture modulation mode */
SDL_BlendMode blendMode; /**< The texture blend mode */
SDL_ScaleMode scaleMode; /**< The texture scale mode */
SDL_WrapMode wrapMode; /**< The texture wrap mode */
SDL_Color color; /**< Texture modulation values */

SDL_Renderer *renderer;
Expand Down Expand Up @@ -168,6 +169,7 @@ struct SDL_Renderer
const SDL_Rect * rect, void **pixels, int *pitch);
void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
void (*SetTextureScaleMode) (SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode);
void (*SetTextureWrapMode) (SDL_Renderer * renderer, SDL_Texture * texture, SDL_WrapMode wrapMode);
int (*SetRenderTarget) (SDL_Renderer * renderer, SDL_Texture * texture);
int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 format, void * pixels, int pitch);
Expand Down
56 changes: 50 additions & 6 deletions src/render/direct3d/SDL_render_d3d.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct
SDL_bool beginScene;
SDL_bool enableSeparateAlphaBlend;
D3DTEXTUREFILTERTYPE scaleMode[8];
D3DTEXTUREADDRESS wrapMode[8];
IDirect3DSurface9 *defaultRenderTarget;
IDirect3DSurface9 *currentRenderTarget;
void* d3dxDLL;
Expand All @@ -94,6 +95,7 @@ typedef struct
{
D3D_TextureRep texture;
D3DTEXTUREFILTERTYPE scaleMode;
D3DTEXTUREADDRESS wrapMode;

/* YV12 texture support */
SDL_bool yuv;
Expand Down Expand Up @@ -280,6 +282,9 @@ D3D_InitRenderState(D3D_RenderData *data)
/* Reset our current scale mode */
SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));

/* Reset our current wrap mode */
SDL_memset(data->wrapMode, 0xFF, sizeof(data->wrapMode));

/* Start the render with beginScene */
data->beginScene = SDL_TRUE;
}
Expand Down Expand Up @@ -371,6 +376,20 @@ static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
}
}

static D3DTEXTUREADDRESS GetWrapMode(SDL_WrapMode wrapMode)
{
switch (wrapMode) {
case SDL_WRAP_MODE_CLAMP:
return D3DTADDRESS_CLAMP;
case SDL_WRAP_MODE_REPEAT:
return D3DTADDRESS_WRAP;
case SDL_WRAP_MODE_MIRROR_REPEAT:
return D3DTADDRESS_MIRROR;
default:
return (D3DTEXTUREADDRESS)0;
}
}

static SDL_bool
D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
{
Expand Down Expand Up @@ -522,6 +541,7 @@ D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
return SDL_OutOfMemory();
}
texturedata->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
texturedata->wrapMode = GetWrapMode(texture->wrapMode);

texture->driverdata = texturedata;

Expand Down Expand Up @@ -731,6 +751,18 @@ D3D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Scal
texturedata->scaleMode = (scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
}

static void
D3D_SetTextureWrapMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_WrapMode wrapMode)
{
D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;

if (!texturedata) {
return;
}

texturedata->wrapMode = GetWrapMode(wrapMode);
}

static int
D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
{
Expand Down Expand Up @@ -922,11 +954,19 @@ UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsig
texturedata->scaleMode);
IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
texturedata->scaleMode);
data->scaleMode[index] = texturedata->scaleMode;
}
}

static void
UpdateTextureWrapMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
{
if (texturedata->wrapMode != data->wrapMode[index]) {
IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU,
D3DTADDRESS_CLAMP);
texturedata->wrapMode);
IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV,
D3DTADDRESS_CLAMP);
data->scaleMode[index] = texturedata->scaleMode;
texturedata->wrapMode);
data->wrapMode[index] = texturedata->wrapMode;
}
}

Expand All @@ -942,6 +982,7 @@ SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSH
}

UpdateTextureScaleMode(data, texturedata, 0);
UpdateTextureWrapMode(data, texturedata, 0);

if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
return -1;
Expand All @@ -962,8 +1003,10 @@ SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSH
return SDL_SetError("Unsupported YUV conversion mode");
}

UpdateTextureScaleMode(data, texturedata, 1);
UpdateTextureScaleMode(data, texturedata, 2);
UpdateTextureScaleMode(data, texturedata, 1);
UpdateTextureWrapMode(data, texturedata, 1);
UpdateTextureScaleMode(data, texturedata, 2);
UpdateTextureWrapMode(data, texturedata, 2);

if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
return -1;
Expand Down Expand Up @@ -1559,7 +1602,8 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->LockTexture = D3D_LockTexture;
renderer->UnlockTexture = D3D_UnlockTexture;
renderer->SetTextureScaleMode = D3D_SetTextureScaleMode;
renderer->SetRenderTarget = D3D_SetRenderTarget;
renderer->SetTextureWrapMode = D3D_SetTextureWrapMode;
renderer->SetRenderTarget = D3D_SetRenderTarget;
renderer->QueueSetViewport = D3D_QueueSetViewport;
renderer->QueueSetDrawColor = D3D_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = D3D_QueueDrawPoints;
Expand Down
Loading

0 comments on commit 32b1ed1

Please sign in to comment.