I do not use the SDL but there is a very easy way in Direct3D.
You can use a translation matrix and set it accordingly. Then set your texture transform to the appropriate mode and use the translation matrix you created.
This is how I scrolled my clouds across the sky in my terrain engine. Direct3D already has built in functionality for scrolling bitmaps.
Here is some sample code from my CSkyPlane class which is derived from CTexturedPlane. However I think you should be able to see what is going on w/o posting the entire source for CTexturedPlane.
Code:
void CSkyPlane::Render(void)
{
//Setup render states
//Will not be done here later - will be done in state blocks
_Device->SetRenderState(D3DRS_LIGHTING, false);
_Device->SetRenderState(D3DRS_ZWRITEENABLE,false);
_Device->SetStreamSource(0,_VB,0,sizeof(TexturedPlaneVertex));
_Device->SetFVF(TexturedPlaneVertex::FVF);
_Device->SetIndices(_IB);
_Device->SetTexture(0,_Texture);
//For translucency in clouds - if clouds lower than mountains..mountains visible
//slightly through terrain - lowers frames a lot
//_Device->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
D3DXMATRIX world=_rot*_pos;
_Device->SetTransform(D3DTS_WORLD,&world);
//Advanced texturing - disable for now
//Possible later display option for altered method of rendering sky
//Part of the translucent rendering and altered lighting rendering
//_Device->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
//_Device->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TEXTURE);
//_Device->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_ADD);
//Scroll the texture
_curtu+=_tu;
_curtv+=_tv;
if (_curtu>(_scale-.5f)) _curtu=0.0f;
if (_curtv>(_scale-.5f)) _curtv=0.0f;
//Setup translation matrix
D3DXMATRIX ttrans;
D3DXMatrixIdentity(&ttrans);
//Set appropriate members of matrix for east/west scrolling
//Can be changed to accomodate any type of 2D scrolling
ttrans._31=_curtu;
ttrans._32=_curtv;
//Set transform to texture transform and use above matrix as input matrix
_Device->SetTransform(D3DTS_TEXTURE0,&ttrans);
_Device->SetTextureStageState(0,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
//Set texture to current texture and render as one large primitive - very very fast
_Device->SetTexture(1,_Texture);
_Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0,0,4,0,2);
_Device->SetRenderState(D3DRS_LIGHTING, true);
_Device->SetRenderState(D3DRS_ZWRITEENABLE,true);
_Device->SetTextureStageState(0,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_DISABLE);
//Only needed if we used altered method of rendering - translucent rendering
//_Device->SetRenderState(D3DRS_ALPHABLENDENABLE,false);
}
Notice that because this uses the transform and lighting pipeline all scrolling is done in hardware not software. This results in extremely smooth and extremely efficient scrolling.
However it only works well for single textures. It is possible to use a tile engine with this if you render all your world/tiles to one big texture and then use this to scroll the world. However, if the quad is too large you might end up losing some resolution in your texture.
You could build the tile world on loadup of the level and load in an alpha map the same size as the map. Set all alphas to 0 except for the area that the player is in. This will result in a fog of war type effect and will auto-smooth the edges of the viewing area if you set the alpha based on distance from the player. Quite nice. Once the map is built all you need to do is scroll it with the transform in Direct3D - no extra loading, rendering, etc. Also for the fog of war you simply have to access the alpha texture and set alpha blending to the correct states.....all done in hardware. Should give very good frames.