Plotting PixelsThe first thing is to typecast the pointer we got from the Lock() function. Logically, we're going to want a pointer that's the same size as the pixels we're writing. So we want a UCHAR* for 8-bit color depth, a USHORT* for 16-bit, and a UINT* for 32-bit. But what about 24-bit? Since there's no 24-bit data type, we'll need to use a UCHAR* for this also, and do things a little differently. We should also convert the lPitch member so it's in the same units as our pointer. Remember, when we first retrieve lPitch from the DDSURFACEDESC2 structure, it's in bytes. For 16-bit mode, we should divide it by 2 to get the pitch in terms of USHORTs, and for 32-bit mode, we divide by 4 to get it in terms of UINTs. Let's stop for a second and look at some example code. Suppose we are in 32-bit mode and want to lock the primary surface for plotting pixels. Here's what we would do: // declare and initialize structure DDSURFACEDESC2 ddsd; INIT_DXSTRUCT(ddsd); // lock the surface lpddsPrimary->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL); // now convert the pointer and the pitch UINT* buffer = (UINT*)ddsd.lpSurface; UINT nPitch = ddsd.lPitch >> 2; Now let me go ahead and show you a pixel-plotting function, and then I'll explain it in detail: inline void PlotPixel32(int x, int y, UINT color, UINT *buffer, int nPitch) { buffer[y*nPitch + x] = color; } All right, let's take it apart. First of all, notice that I have declared it as an inline function. This is to eliminate the overhead of passing all the parameters every time we want to do something as simple as plotting one pixel. Now, the only line in the function locates the pixel of interest and sets it to the color we want. Note that the color is just one value, not one each for red, green, and blue, so we'll need to use our RGB_32BIT() macro to create the color for this function. The formula used to locate the pixel at location (x, y) is y*nPitch + x. This makes sense because nPitch is the number of UINTs in a line. Multiplying that by the y value yields the correct row, and then we just need to add x to locate the correct column. That's all you need to know! Pretty simple, hey? Let me show you a couple of functions for plotting pixels in 16-bit and 8-bit modes, because they're very similar: inline void PlotPixel8(int x, int y, UCHAR color, UCHAR* buffer, int byPitch) { buffer[y*byPitch + x] = color; } inline void PlotPixel16(int x, int y, USHORT color, USHORT* buffer, int nPitch) { buffer[y*nPitch + x] = color; } The only things different about these functions are the data types used for the parameters. Also remember that for the 8-bit version, the pitch is in bytes, and for the 16-bit version, the pitch is in USHORTs. That just leaves one mode left, and that's 24-bit. Since there's no data type that's 24 bits, we need to pass and write values for red, green, and blue individually. The function might look like this: inline void PlotPixel24(int x, int y, UCHAR r, UCHAR g, UCHAR b, UCHAR* buffer, int byPitch) { int index = y*byPitch + x*3; buffer[index] = r; buffer[index+1] = g; buffer[index+2] = b; } As you can see, this is going to be a bit slower because we have an extra multiply, and three memory writes. You can speed it up a little bit by replacing x*3 with (x+x+x) or (x<<1)+x, but that probably won't do a lot for you. Still, it can't hurt to throw it in for good measure. Now you can see why working with 24-bit color is a bit of a pain. |
|