Significantly speed up the collision detection for Pixel Perfect
This commit is contained in:
parent
0994a32c23
commit
50b54afc2f
|
@ -8,6 +8,7 @@ include(GenerateG1A)
|
|||
include(GenerateG3A)
|
||||
include(Fxconv)
|
||||
find_package(Gint 2.9 REQUIRED)
|
||||
find_package(LibProf 2.4 REQUIRED)
|
||||
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
|
@ -32,7 +33,7 @@ fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
|
|||
|
||||
add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
|
||||
target_compile_options(myaddin PRIVATE -Wall -Wextra -Os -std=c++20)
|
||||
target_link_libraries(myaddin Gint::Gint)
|
||||
target_link_libraries(myaddin LibProf::LibProf Gint::Gint -lstdc++)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
generate_g1a(TARGET myaddin OUTPUT "MyAddin.g1a"
|
||||
|
|
BIN
PixColli.g3a
BIN
PixColli.g3a
Binary file not shown.
|
@ -1,6 +1,6 @@
|
|||
mainship1.png:
|
||||
type: bopti-image
|
||||
profile: rgb565a
|
||||
profile: p8_rgb565a
|
||||
name: img_player
|
||||
|
||||
Boss1.png:
|
||||
|
|
75
src/main.cpp
75
src/main.cpp
|
@ -2,6 +2,9 @@
|
|||
#include "extrakeyboard.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <libprof.h>
|
||||
#include <fxlibc/printf.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
|
@ -53,23 +56,28 @@ void update()
|
|||
|
||||
int main(void)
|
||||
{
|
||||
/* */
|
||||
uint32_t time_AABB=0, time_FastPP=0, time_DebugPP=0;
|
||||
prof_t perf_AABB, perf_FastPP, perf_DebugPP;
|
||||
|
||||
prof_init();
|
||||
|
||||
__printf_enable_fp();
|
||||
|
||||
|
||||
xmin[0] = 10;
|
||||
ymin[0] = 10;
|
||||
|
||||
xmin[1] = DWIDTH/2 - img_rock.width/2;
|
||||
ymin[1] = (DHEIGHT-50)/2 - img_rock.height/2;
|
||||
|
||||
sprite1 = { .x = xmin[0],
|
||||
.y = ymin[0],
|
||||
.image = &img_player };
|
||||
|
||||
sprite2 = { .x = xmin[1],
|
||||
.y = ymin[1],
|
||||
.image = &img_rock };
|
||||
|
||||
sprite1 = { .x = xmin[0], .y = ymin[0], .image = &img_player };
|
||||
sprite2 = { .x = xmin[1], .y = ymin[1], .image = &img_rock };
|
||||
update();
|
||||
|
||||
bool AABB = false;
|
||||
bool FastPP = false;
|
||||
bool DebugPP = false;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
|
@ -85,21 +93,58 @@ int main(void)
|
|||
dimage( xmin[1], ymin[1], &img_rock );
|
||||
drect_border( xmin[1], ymin[1], xmax[1], ymax[1], C_NONE, 1, C_WHITE );
|
||||
|
||||
dtext( 50, DHEIGHT-40, C_WHITE, "AABB Collide");
|
||||
if (AABB_Collision( sprite1, sprite2 )) drect( 10, DHEIGHT-40, 40, DHEIGHT-10, C_RED);
|
||||
perf_AABB = prof_make();
|
||||
prof_enter(perf_AABB);
|
||||
|
||||
AABB = AABB_Collision( sprite1, sprite2 );
|
||||
|
||||
prof_leave(perf_AABB);
|
||||
time_AABB = prof_time(perf_AABB);
|
||||
|
||||
|
||||
perf_FastPP = prof_make();
|
||||
prof_enter(perf_FastPP);
|
||||
|
||||
FastPP = Pixel_Perfect_Collision( sprite1, sprite2 );
|
||||
|
||||
prof_leave(perf_FastPP);
|
||||
time_FastPP = prof_time(perf_FastPP);
|
||||
|
||||
|
||||
perf_DebugPP = prof_make();
|
||||
prof_enter(perf_DebugPP);
|
||||
|
||||
DebugPP = DEBUG_Pixel_Perfect_Collision( sprite1, sprite2 );
|
||||
|
||||
prof_leave(perf_DebugPP);
|
||||
time_DebugPP = prof_time(perf_DebugPP);
|
||||
|
||||
|
||||
|
||||
dtext( 50, DHEIGHT-35, C_WHITE, "AABB");
|
||||
if (AABB) drect( 10, DHEIGHT-40, 40, DHEIGHT-10, C_RED);
|
||||
else drect( 10, DHEIGHT-40, 40, DHEIGHT-10, C_GREEN );
|
||||
//dprint( 10, DHEIGHT-35, C_WHITE, "%.3f", (float) time_AABB / 1000.0f);
|
||||
dprint( 10, DHEIGHT-35, C_WHITE, "%d", time_AABB);
|
||||
|
||||
dtext( 200, DHEIGHT-40, C_WHITE, "Pixel Perfect Collide");
|
||||
if (Pixel_Perfect_Collision( sprite1, sprite2 )) drect( DWIDTH-40, DHEIGHT-40, DWIDTH-10, DHEIGHT-10, C_RED);
|
||||
dtext( 215, DHEIGHT-35, C_WHITE, " Pixel Perfect");
|
||||
dtext( 215, DHEIGHT-20, C_WHITE, "<DEBUG vs Fast>");
|
||||
if (FastPP) drect( DWIDTH-40, DHEIGHT-40, DWIDTH-10, DHEIGHT-10, C_RED);
|
||||
else drect( DWIDTH-40, DHEIGHT-40, DWIDTH-10, DHEIGHT-10, C_GREEN );
|
||||
//dprint( DWIDTH-40, DHEIGHT-35, C_WHITE, "%.3f", (float) time_FastPP / 1000.0f);
|
||||
dprint( DWIDTH-40, DHEIGHT-35, C_WHITE, "%d", time_FastPP);
|
||||
|
||||
|
||||
if (DebugPP) drect( DWIDTH/2-15, DHEIGHT-40, DWIDTH/2+15, DHEIGHT-10, C_RED);
|
||||
else drect( DWIDTH/2-15, DHEIGHT-40, DWIDTH/2+15, DHEIGHT-10, C_GREEN );
|
||||
//dprint( DWIDTH/2-15, DHEIGHT-35, C_WHITE, "%.3f", (float) time_DebugPP / 1000.0f);
|
||||
dprint( DWIDTH/2-15, DHEIGHT-35, C_WHITE, "%d", time_DebugPP);
|
||||
|
||||
dupdate();
|
||||
|
||||
}
|
||||
while (exit==false);
|
||||
|
||||
prof_quit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
|
||||
bool AABB_Collision( SpriteLocator image1, SpriteLocator image2 )
|
||||
{
|
||||
if( (image2.x >= image1.x + image1.image->width)
|
||||
|
@ -27,14 +29,14 @@ bool AABB_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
}
|
||||
|
||||
|
||||
bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
||||
|
||||
bool DEBUG_Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
||||
{
|
||||
if( !AABB_Collision( image1, image2 ) )
|
||||
return false; // bounding box not overlapping, impossible to have collision
|
||||
return false; // bounding boxes not overlapping, impossible to have collision
|
||||
|
||||
/* if we reach that point, this means that we need to perform pixel perfect collsion detection */
|
||||
|
||||
|
||||
/* First we will calculate the corners of the zone to be tested for collision */
|
||||
/* as it is not usefull to check for all the surface of the image, only the */
|
||||
/* overlapping area will be verified */
|
||||
|
@ -102,8 +104,10 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
&& (data_u16_2[ bdeltax + i ] != transp2 ) )
|
||||
return true;
|
||||
}
|
||||
data_u16_1 += image1.image->width;
|
||||
data_u16_2 += image2.image->width;
|
||||
data1 += image1.image->stride;
|
||||
data_u16_1 = (uint16_t *) data1;
|
||||
data2 += image2.image->stride;
|
||||
data_u16_2 = (uint16_t *) data2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -116,8 +120,8 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
void *data1 = image1.image->data + adeltay * image1.image->stride;
|
||||
void *data2 = image2.image->data + bdeltay * image2.image->stride;
|
||||
|
||||
uint8_t *data_u8_1 = (uint8_t *) data1;
|
||||
uint8_t *data_u8_2 = (uint8_t *) data2;
|
||||
int8_t *data_u8_1 = (int8_t *) data1;
|
||||
int8_t *data_u8_2 = (int8_t *) data2;
|
||||
|
||||
int transp1 = image_alpha(image1.image->format);
|
||||
int transp2 = image_alpha(image2.image->format);
|
||||
|
@ -130,14 +134,15 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
&& (data_u8_2[ bdeltax + i ] != transp2 ) )
|
||||
return true;
|
||||
}
|
||||
data_u8_1 += image1.image->width;
|
||||
data_u8_2 += image2.image->width;
|
||||
data1 += image1.image->stride;
|
||||
data_u8_1 = (int8_t *) data1;
|
||||
data2 += image2.image->stride;
|
||||
data_u8_2 = (int8_t *) data2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* for the other cases, we need to use masks as we cannot directly compare the values contained in the data member */
|
||||
|
||||
uint8_t *mask1 = (uint8_t *) malloc( rows * columns );
|
||||
|
@ -155,6 +160,8 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
int transp1 = image_alpha(image1.image->format);
|
||||
int transp2 = image_alpha(image2.image->format);
|
||||
|
||||
|
||||
|
||||
if (image1.image->format == IMAGE_RGB565 || image1.image->format == IMAGE_RGB565A )
|
||||
{
|
||||
for( int j=0; j<rows; j++)
|
||||
|
@ -163,9 +170,24 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
{
|
||||
mask1[j*columns+i] = data_u16_1[ adeltax + i ] == transp1 ? 0 : 1;
|
||||
}
|
||||
data_u16_1 += image1.image->width;
|
||||
data1 += image1.image->stride;
|
||||
data_u16_1 = (uint16_t *) data1;
|
||||
}
|
||||
}
|
||||
else if (image1.image->format == IMAGE_P8_RGB565 || image1.image->format == IMAGE_P8_RGB565A )
|
||||
{
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
for (int i=0; i<columns; i++)
|
||||
{
|
||||
mask1[j*columns+i] = data_u8_1[ adeltax + i ] == transp1 ? 0 : 1;
|
||||
}
|
||||
data1 += image1.image->stride;
|
||||
data_u8_1 = (int8_t *) data1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (image2.image->format == IMAGE_RGB565 || image2.image->format == IMAGE_RGB565A )
|
||||
{
|
||||
|
@ -175,23 +197,11 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
{
|
||||
mask2[j*columns+i] = data_u16_2[ bdeltax + i ] == transp2 ? 0 : 1;
|
||||
}
|
||||
data_u16_2 += image2.image->width;
|
||||
data2 += image2.image->stride;
|
||||
data_u16_2 = (uint16_t *) data2;
|
||||
}
|
||||
}
|
||||
|
||||
if (image1.image->format == IMAGE_P8_RGB565 || image1.image->format == IMAGE_P8_RGB565A )
|
||||
{
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
for (int i=0; i<columns; i++)
|
||||
{
|
||||
mask1[j*columns+i] = data_u8_1[ adeltax + i ] == transp1 ? 0 : 1;
|
||||
}
|
||||
data_u8_1 += image1.image->width;
|
||||
}
|
||||
}
|
||||
|
||||
if (image2.image->format == IMAGE_P8_RGB565 || image2.image->format == IMAGE_P8_RGB565A )
|
||||
else if (image2.image->format == IMAGE_P8_RGB565 || image2.image->format == IMAGE_P8_RGB565A )
|
||||
{
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
|
@ -199,12 +209,16 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
{
|
||||
mask2[j*columns+i] = data_u8_2[ bdeltax + i ] == transp2 ? 0 : 1;
|
||||
}
|
||||
data_u8_2 += image2.image->width;
|
||||
data2 += image2.image->stride;
|
||||
data_u8_2 = (int8_t *) data2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
drect( 0, 0, columns+2, rows+2, C_BLUE );
|
||||
drect( DWIDTH-columns-2, 0, DWIDTH, rows+2, C_BLUE );
|
||||
*/
|
||||
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
|
@ -230,5 +244,176 @@ bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
|||
free( mask1 );
|
||||
free( mask2 );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 )
|
||||
{
|
||||
if( !AABB_Collision( image1, image2 ) )
|
||||
return false; // bounding boxes not overlapping, impossible to have collision
|
||||
|
||||
/* if we reach that point, this means that we need to perform pixel perfect collsion detection */
|
||||
|
||||
/* First we will calculate the corners of the zone to be tested for collision */
|
||||
/* as it is not usefull to check for all the surface of the image, only the */
|
||||
/* overlapping area will be verified */
|
||||
|
||||
|
||||
|
||||
/* WARNING !! */
|
||||
/* P4 format is not supported yet has it is currently focused on use with Azur */
|
||||
/* that is mostly P8/RGB565 oriented for ultra fast performances */
|
||||
if ( IMAGE_IS_P4(image1.image->format) || IMAGE_IS_P4(image2.image->format) )
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
|
||||
int astartx, aendx;
|
||||
int astarty, aendy;
|
||||
int adeltax, adeltay;
|
||||
|
||||
int bstartx, bendx;
|
||||
int bstarty, bendy;
|
||||
int bdeltax, bdeltay;
|
||||
|
||||
int rows, columns;
|
||||
|
||||
if (image1.x <= image2.x)
|
||||
{
|
||||
adeltax = image2.x - image1.x;
|
||||
columns = MIN(image1.image->width - adeltax, image2.image->width);
|
||||
bdeltax = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bdeltax = image1.x - image2.x;
|
||||
columns = MIN(image2.image->width - bdeltax, image1.image->width);
|
||||
adeltax = 0;
|
||||
}
|
||||
|
||||
if (image1.y <= image2.y)
|
||||
{
|
||||
adeltay = image2.y - image1.y;
|
||||
rows = MIN(image1.image->height - adeltay, image2.image->height);
|
||||
bdeltay = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bdeltay = image1.y - image2.y;
|
||||
rows = MIN(image2.image->height - bdeltay, image1.image->height);
|
||||
adeltay = 0;
|
||||
}
|
||||
|
||||
/* if BOTH images are in a 16bits color format, we will not use masks and will quicken the process */
|
||||
if ( IMAGE_IS_RGB16(image1.image->format) && IMAGE_IS_RGB16(image2.image->format) )
|
||||
{
|
||||
void *data1 = image1.image->data + adeltay * image1.image->stride;
|
||||
void *data2 = image2.image->data + bdeltay * image2.image->stride;
|
||||
|
||||
uint16_t *data_u16_1 = (uint16_t *) data1;
|
||||
uint16_t *data_u16_2 = (uint16_t *) data2;
|
||||
|
||||
int transp1 = image_alpha(image1.image->format);
|
||||
int transp2 = image_alpha(image2.image->format);
|
||||
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
for (int i=0; i<columns; i++)
|
||||
{
|
||||
if( (data_u16_1[ adeltax + i ] != transp1 )
|
||||
&& (data_u16_2[ bdeltax + i ] != transp2 ) )
|
||||
return true;
|
||||
}
|
||||
data1 += image1.image->stride;
|
||||
data_u16_1 = (uint16_t *) data1;
|
||||
data2 += image2.image->stride;
|
||||
data_u16_2 = (uint16_t *) data2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if BOTH images are in a 8bits color format, we will not use masks and will quicken the process */
|
||||
|
||||
if ( IMAGE_IS_P8(image1.image->format) && IMAGE_IS_P8(image2.image->format) )
|
||||
{
|
||||
void *data1 = image1.image->data + adeltay * image1.image->stride;
|
||||
void *data2 = image2.image->data + bdeltay * image2.image->stride;
|
||||
|
||||
int8_t *data_u8_1 = (int8_t *) data1;
|
||||
int8_t *data_u8_2 = (int8_t *) data2;
|
||||
|
||||
int transp1 = image_alpha(image1.image->format);
|
||||
int transp2 = image_alpha(image2.image->format);
|
||||
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
for (int i=0; i<columns; i++)
|
||||
{
|
||||
if( (data_u8_1[ adeltax + i ] != transp1 )
|
||||
&& (data_u8_2[ bdeltax + i ] != transp2 ) )
|
||||
return true;
|
||||
}
|
||||
data1 += image1.image->stride;
|
||||
data_u8_1 = (int8_t *) data1;
|
||||
data2 += image2.image->stride;
|
||||
data_u8_2 = (int8_t *) data2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if we reach that point, this means that images have differnt format and we need to manage this */
|
||||
|
||||
uint8_t d1;
|
||||
uint8_t d2;
|
||||
|
||||
void *data1 = image1.image->data + adeltay * image1.image->stride;
|
||||
void *data2 = image2.image->data + bdeltay * image2.image->stride;
|
||||
|
||||
int8_t *data_u8_1 = (int8_t *) data1;
|
||||
uint16_t *data_u16_1 = (uint16_t *) data1;
|
||||
|
||||
int8_t *data_u8_2 = (int8_t *) data2;
|
||||
uint16_t *data_u16_2 = (uint16_t *) data2;
|
||||
|
||||
int transp1 = image_alpha(image1.image->format);
|
||||
int transp2 = image_alpha(image2.image->format);
|
||||
|
||||
bool im1_P16 = IMAGE_IS_RGB16(image1.image->format);
|
||||
bool im1_P8 = IMAGE_IS_P8(image1.image->format);
|
||||
|
||||
bool im2_P16 = IMAGE_IS_RGB16(image2.image->format);
|
||||
bool im2_P8 = IMAGE_IS_P8(image2.image->format);
|
||||
|
||||
for( int j=0; j<rows; j++)
|
||||
{
|
||||
for (int i=0; i<columns; i++)
|
||||
{
|
||||
/* d1 is set to 1 if pixel of image1 is not transparent and to 0 if transparent */
|
||||
/* need to be format dependant here so quite time consumming test at each loop :( )*/
|
||||
if (im1_P16)
|
||||
d1 = data_u16_1[ adeltax + i ] == transp1 ? 0 : 1;
|
||||
else if (im1_P8)
|
||||
d1 = data_u8_1[ adeltax + i ] == transp1 ? 0 : 1;
|
||||
|
||||
/* d2 is set to 1 if pixel of image2 is not transparent and to 0 if transparent */
|
||||
/* need to be format dependant here so quite time consumming test at each loop :( )*/
|
||||
if (im2_P16)
|
||||
d2 = data_u16_2[ bdeltax + i ] == transp2 ? 0 : 1;
|
||||
else if (im2_P8)
|
||||
d2 = data_u8_2[ bdeltax + i ] == transp2 ? 0 : 1;
|
||||
|
||||
/* if d1 + d2 = 2 means that both coincident pixels are not transparent and then we have collision*/
|
||||
if (d1 + d2 == 2) return true;
|
||||
}
|
||||
/* we move the pointer to the next line of both images */
|
||||
data1 += image1.image->stride;
|
||||
data2 += image2.image->stride;
|
||||
data_u8_1 = (int8_t *) data1;
|
||||
data_u8_2 = (int8_t *) data2;
|
||||
data_u16_1 = (uint16_t *) data1;
|
||||
data_u16_2 = (uint16_t *) data2;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -21,4 +21,7 @@ bool AABB_Collision( SpriteLocator image1, SpriteLocator image2 );
|
|||
|
||||
bool Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 );
|
||||
|
||||
bool DEBUG_Pixel_Perfect_Collision( SpriteLocator image1, SpriteLocator image2 );
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue