The "dirty" method of doing this is keeping a copy of texture you use for a sprite in RAM as a bitmap, and just testing it with custom code. For example, something like this should work.
Code: Select all
//sprite1 and sprite2 are RGBA 32bit raw bitmap data.
//x1,y1,x2,y2 are the coordinates of the sprites.
//w1,h1,w2,h2 are width and height of two sprites.
int collisionTest(char *sprite1, char *sprite2, int x1, int y1, int x2, int y2, int w1, int h1, int w2, int h2)
{
int xp1, yp1, xp2, yp2;
for(yp1=0;yp1<h;yp1++)for(xp1=0;xp1<w;xp1++)
{
if(!sprite1[4*(w1*yp1+xp1)+3])continue;//Transparent, no collision.
xp2=x1+xp1-x2;
yp2=y1+yp1-y2;
if(xp2<0 || xp2>=w2 || yp2<0 || yp2>=h2)continue; //Out of bounds, no collision.
if(!sprite2[4*(w2*yp2+xp2)+3])continue;//Transparent, no collision.
return 1; //Collision. It only takes one pixel.
}
return 0; //No collision.
}
Considering the fact that you don't really have a reason to worry about optimal performance, and that you probably keep a copy of sprites in RAM anyways, this should work rather neatly.
There is an alternative. If you are rendering in 3D, which you probably are if you are using DX8 or OGL, you can use the combination of depth and stencil buffers to do the dirty work for you. For every frame, you want to clear depth and stencil buffers. Set some reasonable depth. Add an alpha test. Test must fail if you try to draw a pixel with 0 alpha. Otherwise, you will still get a collision on transparent pixels. Set depth test to greater then. Set reasonable depth. Set stencil buffer to increment on failed depth test, and no change on pass. Stencil test is disabled. Now, render all collidable sprites first. Once all sprites are done, check the stencil buffer. Any value>0 indicates collision at that pixel. Now, lower depth, and render background. It will not render over sprites, since depth test will fail there. Finally, disable depth test and render any partially transparent FX. Note: Any collidable sprite with alpha other than 1.0 or 0.0 will cause artifacts, so any translucent sprites must be rendered on FX layer.
I do not recall DX8 functions for stencil operations, but I'm sure you can find them. The OGL functions include:
glStencilOp(GL_KEEP,GL_INCR,GL_KEEP); //Makes sure that stencil buffer is incremented on collision.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //Clears color, depth, and stencil buffers.
glClearStencil(0); //Sets clear stencil value to 0.
glEnable(GL_DEPTH_TEST);//Turns on depth test.
glDisable(GL_DEPTH_TEST);//Turns it off
glDepthFunc(GL_GREATER);//Depth test passed only if Z value is greater.
glEnable(GL_ALPHA_TEST);//Enable it before collision detection.
glAlphaFunc(GL_GREATER,0.0);//Makes sure transparent pixels are not rendered.
glDisable(GL_ALPHA_TEST);//Disable alpha test before alpha blending.
glEnable(GL_BLEND);//Enable alpha blending.
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);//Standard blending function for transparency.
There is still a matter of getting to the stencil buffer. There might be a way of accessing it almost directly. I know that depth buffer can be accessed with the glCopyTexImage2D function by substituting the format with GL_DEPTH_COMPONENT. You can try it with GL_STENCIL_COMPONENT and see if that will copy the stencil to texture. Alternatively, switch to an auxiliary buffer (glDrawBuffer(GL_AUX0)) render solid color to the whole screen with all but stencil test disabled and with a stencil test enabled. (glEnable(GL_STENCIL_TEST), glStencilFunc(GL_GREATER,0,1);) The resulting screen should be still cleared in all points other than collision. All you have to do is read pixels from auxiliary buffer to RAM, and do whatever tests you want with the result.
None of my projects (Minus One converter, W3D/W4 Map Viewer, and WMapEditor) are endorsed, supported or otherwise affiliated with Dream17. I just find Dream17 forums to be a nice place to share and discuss my work with others.