diff --git a/panda/src/pnmimage/pnm-image-filter-core.cxx b/panda/src/pnmimage/pnm-image-filter-core.cxx index 273a4b0713..882c4c41e1 100644 --- a/panda/src/pnmimage/pnm-image-filter-core.cxx +++ b/panda/src/pnmimage/pnm-image-filter-core.cxx @@ -43,8 +43,9 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, WorkType *filter; float filter_width; + int actual_width; - make_filter(scale, width, filter, filter_width); + make_filter(scale, width, filter, filter_width, actual_width); for (b = 0; b < source.BSIZE(); b++) { for (a = 0; a < source.ASIZE(); a++) { @@ -54,7 +55,7 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, filter_row(temp_dest, dest.ASIZE(), temp_source, source.ASIZE(), scale, - filter, filter_width); + filter, filter_width, actual_width); for (a = 0; a < dest.ASIZE(); a++) { matrix[a][b] = temp_dest[a]; @@ -69,13 +70,13 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, scale = (float)dest.BSIZE() / (float)source.BSIZE(); temp_dest = (StoreType *)PANDA_MALLOC_ARRAY(dest.BSIZE() * sizeof(StoreType)); - make_filter(scale, width, filter, filter_width); + make_filter(scale, width, filter, filter_width, actual_width); for (a = 0; a < dest.ASIZE(); a++) { filter_row(temp_dest, dest.BSIZE(), matrix[a], source.BSIZE(), scale, - filter, filter_width); + filter, filter_width, actual_width); for (b = 0; b < dest.BSIZE(); b++) { dest.SETVAL(a, b, channel, (float)temp_dest[b]/(float)source_max); diff --git a/panda/src/pnmimage/pnm-image-filter-sparse-core.cxx b/panda/src/pnmimage/pnm-image-filter-sparse-core.cxx index 4edf632ee4..49336dd301 100644 --- a/panda/src/pnmimage/pnm-image-filter-sparse-core.cxx +++ b/panda/src/pnmimage/pnm-image-filter-sparse-core.cxx @@ -49,10 +49,12 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, WorkType *filter; float filter_width; + int actual_width; - make_filter(scale, width, filter, filter_width); + make_filter(scale, width, filter, filter_width, actual_width); for (b = 0; b < source.BSIZE(); b++) { + memset(temp_source, 0, source.ASIZE() * sizeof(StoreType)); memset(temp_source_weight, 0, source.ASIZE() * sizeof(StoreType)); for (a = 0; a < source.ASIZE(); a++) { if (source.HASVAL(a, b)) { @@ -64,9 +66,10 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, filter_sparse_row(temp_dest, temp_dest_weight, dest.ASIZE(), temp_source, temp_source_weight, source.ASIZE(), scale, - filter, filter_width); + filter, filter_width, actual_width); for (a = 0; a < dest.ASIZE(); a++) { + nassertv(!isnan(temp_dest[a]) && !isnan(temp_dest_weight[a])); matrix[a][b] = temp_dest[a]; matrix_weight[a][b] = temp_dest_weight[a]; } @@ -83,17 +86,19 @@ FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, temp_dest = (StoreType *)PANDA_MALLOC_ARRAY(dest.BSIZE() * sizeof(StoreType)); temp_dest_weight = (StoreType *)PANDA_MALLOC_ARRAY(dest.BSIZE() * sizeof(StoreType)); - make_filter(scale, width, filter, filter_width); + make_filter(scale, width, filter, filter_width, actual_width); for (a = 0; a < dest.ASIZE(); a++) { filter_sparse_row(temp_dest, temp_dest_weight, dest.BSIZE(), matrix[a], matrix_weight[a], source.BSIZE(), scale, - filter, filter_width); + filter, filter_width, actual_width); for (b = 0; b < dest.BSIZE(); b++) { + nassertv(!isnan(temp_dest[b]) && !isnan(temp_dest_weight[b])); if (temp_dest_weight[b] != 0) { - dest.SETVAL(a, b, channel, (float)temp_dest[b]/(float)source_max); + dest.SETVAL(a, b, channel, (float)temp_dest[b]/(float)temp_dest_weight[b]); + nassertv(!isnan(dest.GETVAL(a, b, channel))); } } } diff --git a/panda/src/pnmimage/pnm-image-filter.cxx b/panda/src/pnmimage/pnm-image-filter.cxx index 6ca6a145d6..a19ee75f5c 100644 --- a/panda/src/pnmimage/pnm-image-filter.cxx +++ b/panda/src/pnmimage/pnm-image-filter.cxx @@ -110,7 +110,8 @@ filter_row(StoreType dest[], int dest_len, const StoreType source[], int source_len, float scale, // == dest_len / source_len const WorkType filter[], - float filter_width) { + float filter_width, + int actual_width) { // If we are expanding the row (scale > 1.0), we need to look at a // fractional granularity. Hence, we scale our filter index by scale. If // we are compressing (scale < 1.0), we don't need to fiddle with the filter @@ -147,13 +148,15 @@ filter_row(StoreType dest[], int dest_len, // of center--so we don't have to incur the overhead of calling fabs() // each time through the loop. for (source_x = left; source_x < right_center; source_x++) { - index = (int)(iscale * (center - source_x) + 0.5f); + index = (int)cfloor(iscale * (center - source_x) + 0.5f); + nassertv(index >= 0 && index < actual_width); net_value += filter[index] * source[source_x]; net_weight += filter[index]; } for (; source_x <= right; source_x++) { - index = (int)(iscale * (source_x - center) + 0.5f); + index = (int)cfloor(iscale * (source_x - center) + 0.5f); + nassertv(index >= 0 && index < actual_width); net_value += filter[index] * source[source_x]; net_weight += filter[index]; } @@ -174,15 +177,16 @@ filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len, const StoreType source[], const StoreType source_weight[], int source_len, float scale, // == dest_len / source_len const WorkType filter[], - float filter_width) { + float filter_width, + int actual_width) { // If we are expanding the row (scale > 1.0), we need to look at a // fractional granularity. Hence, we scale our filter index by scale. If // we are compressing (scale < 1.0), we don't need to fiddle with the filter // index, so we leave it at one. float iscale; - if (scale < 1.0) { - iscale = 1.0; + if (scale < 1.0f) { + iscale = 1.0f; filter_width /= scale; } else { iscale = scale; @@ -211,13 +215,15 @@ filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len, // of center--so we don't have to incur the overhead of calling fabs() // each time through the loop. for (source_x = left; source_x < right_center; source_x++) { - index = (int)(iscale * (center - source_x) + 0.5f); + index = (int)cfloor(iscale * (center - source_x) + 0.5f); + nassertv(index >= 0 && index < actual_width); net_value += filter[index] * source[source_x] * source_weight[source_x]; net_weight += filter[index] * source_weight[source_x]; } for (; source_x <= right; source_x++) { - index = (int)(iscale * (source_x - center) + 0.5f); + index = (int)cfloor(iscale * (source_x - center) + 0.5f); + nassertv(index >= 0 && index < actual_width); net_value += filter[index] * source[source_x] * source_weight[source_x]; net_weight += filter[index] * source_weight[source_x]; } @@ -244,11 +250,12 @@ filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len, // corresponding to values in the range -filter_width to filter_width. typedef void FilterFunction(float scale, float width, - WorkType *&filter, float &filter_width); + WorkType *&filter, float &filter_width, int &actual_width); static void box_filter_impl(float scale, float width, - WorkType *&filter, float &filter_width) { + WorkType *&filter, float &filter_width, + int &actual_width) { float fscale; if (scale < 1.0) { // If we are compressing the image, we want to expand the range of the @@ -263,7 +270,11 @@ box_filter_impl(float scale, float width, fscale = scale; } filter_width = width; - int actual_width = (int)cceil((filter_width + 1) * fscale) + 1; + + // It seems we need a buffer of two extra values in the filter array + // to allow room for all calculations (especially including the 1/2 + // pixel offset). + actual_width = (int)cceil((filter_width + 1) * fscale) + 2; filter = (WorkType *)PANDA_MALLOC_ARRAY(actual_width * sizeof(WorkType)); @@ -274,7 +285,8 @@ box_filter_impl(float scale, float width, static void gaussian_filter_impl(float scale, float width, - WorkType *&filter, float &filter_width) { + WorkType *&filter, float &filter_width, + int &actual_width) { float fscale; if (scale < 1.0) { // If we are compressing the image, we want to expand the range of the @@ -291,7 +303,11 @@ gaussian_filter_impl(float scale, float width, float sigma = width/2; filter_width = 3.0 * sigma; - int actual_width = (int)cceil((filter_width + 1) * fscale); + + // It seems we need a buffer of two extra values in the filter array + // to allow room for all calculations (especially including the 1/2 + // pixel offset). + actual_width = (int)cceil((filter_width + 1) * fscale) + 2; // G(x, y) = (1(2 pi sigma^2)) * exp( - (x^2 + y^2) (2 sigma^2))