The way I did it was to get a grid of floats the size you want the texture to be. Then fill that with noise between 0 and 1. Then get another grid of noise half that size, fill that with noise. At this point you could resize this new noise on the graphics card to take advantage of the bilinear filtering, or if you're doing it in software you need to implement a lerp that will get a value in between four others. Then add this on to the original grid, and repeat by halving the size of the texture you're adding on each time. Then divide each value in the original grid by the number of iterations you've done.
Here's some C# code for the lerp
// where mLayers is an array of 2d float arrays each half the size of the previous one
float GetValue(int layer, int x, int y)
{
int plus = (layer + 1);
plus = (int)(Math.Pow(2, plus));
int w = (mWidth / plus);
int h = (mHeight / plus);
int xindex = (int)(x / plus);
int yindex = (int)(y / plus);
float dx = ((x % plus) + 1) / (float)plus;
int right = (xindex + 1) % w;
int down = (yindex + 1) % h;
float valuex0 = mLayers[layer][xindex, yindex] + (mLayers[layer][right, yindex] - mLayers[layer][xindex, yindex]) * dx;
float valuex1 = mLayers[layer][xindex, down] + (mLayers[layer][right, down] - mLayers[layer][xindex, down]) * dx;
float dy = ((y % plus) + 1) / (float)plus;
float value = valuex0 + (valuex1 - valuex0) * dy;
return value;
}
SDL.NET code for drawing it:
float val = 0;
for (int i = 0; i < mNumLayers; i++)
{
val += GetValue(i, mX, mY);
}
val /= mNumLayers;
int col = (int)(val * 255);
mSurface.Draw(new Point(mX, mY), Color.FromArgb(255, col, col, col));
As a note, it's really REALLY easy to make wrapping perlin noise by making sure the values you use for the edges of the grid are the same. So if you have a 16x16 grid of noise you want to use the pixel at (0,0) instead of the pixel at (15,0) etc.