1 /* 2 * Copyright 2009, Christian Packmann. 3 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>. 4 * Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>. 5 * Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de> 6 * All rights reserved. Distributed under the terms of the MIT License. 7 */ 8 #ifndef DRAW_BITMAP_NEAREST_NEIGHBOR_H 9 #define DRAW_BITMAP_NEAREST_NEIGHBOR_H 10 11 #include "Painter.h" 12 13 14 struct DrawBitmapNearestNeighborCopy { 15 static void 16 Draw(const Painter* painter, PainterAggInterface& aggInterface, 17 agg::rendering_buffer& bitmap, BPoint offset, 18 double scaleX, double scaleY, BRect destinationRect) 19 { 20 //bigtime_t now = system_time(); 21 uint32 dstWidth = destinationRect.IntegerWidth() + 1; 22 uint32 dstHeight = destinationRect.IntegerHeight() + 1; 23 uint32 srcWidth = bitmap.width(); 24 uint32 srcHeight = bitmap.height(); 25 26 // Do not calculate more filter weights than necessary and also 27 // keep the stack based allocations reasonably sized 28 const BRegion& clippingRegion = *painter->ClippingRegion(); 29 if (clippingRegion.Frame().IntegerWidth() + 1 < (int32)dstWidth) 30 dstWidth = clippingRegion.Frame().IntegerWidth() + 1; 31 if (clippingRegion.Frame().IntegerHeight() + 1 < (int32)dstHeight) 32 dstHeight = clippingRegion.Frame().IntegerHeight() + 1; 33 34 // When calculating less filter weights than specified by 35 // destinationRect, we need to compensate the offset. 36 uint32 filterWeightXIndexOffset = 0; 37 uint32 filterWeightYIndexOffset = 0; 38 if (clippingRegion.Frame().left > destinationRect.left) { 39 filterWeightXIndexOffset = (int32)(clippingRegion.Frame().left 40 - destinationRect.left); 41 } 42 if (clippingRegion.Frame().top > destinationRect.top) { 43 filterWeightYIndexOffset = (int32)(clippingRegion.Frame().top 44 - destinationRect.top); 45 } 46 47 // should not pose a problem with stack overflows 48 // (needs around 6Kb for 1920x1200) 49 uint16 xIndices[dstWidth]; 50 uint16 yIndices[dstHeight]; 51 52 // Extract the cropping information for the source bitmap, 53 // If only a part of the source bitmap is to be drawn with scale, 54 // the offset will be different from the destinationRect left top 55 // corner. 56 const int32 xBitmapShift = (int32)(destinationRect.left - offset.x); 57 const int32 yBitmapShift = (int32)(destinationRect.top - offset.y); 58 59 for (uint32 i = 0; i < dstWidth; i++) { 60 // index into source 61 uint16 index = (uint16)((i + filterWeightXIndexOffset) * srcWidth 62 / (srcWidth * scaleX)); 63 // round down to get the left pixel 64 xIndices[i] = index; 65 // handle cropped source bitmap 66 xIndices[i] += xBitmapShift; 67 // precompute index for 32 bit pixels 68 xIndices[i] *= 4; 69 } 70 71 for (uint32 i = 0; i < dstHeight; i++) { 72 // index into source 73 uint16 index = (uint16)((i + filterWeightYIndexOffset) * srcHeight 74 / (srcHeight * scaleY)); 75 // round down to get the top pixel 76 yIndices[i] = index; 77 // handle cropped source bitmap 78 yIndices[i] += yBitmapShift; 79 } 80 //printf("X: %d ... %d, %d (%ld or %f)\n", 81 // xIndices[0], xIndices[dstWidth - 2], xIndices[dstWidth - 1], 82 // dstWidth, srcWidth * scaleX); 83 //printf("Y: %d ... %d, %d (%ld or %f)\n", 84 // yIndices[0], yIndices[dstHeight - 2], yIndices[dstHeight - 1], 85 // dstHeight, srcHeight * scaleY); 86 87 const int32 left = (int32)destinationRect.left; 88 const int32 top = (int32)destinationRect.top; 89 const int32 right = (int32)destinationRect.right; 90 const int32 bottom = (int32)destinationRect.bottom; 91 92 const uint32 dstBPR = aggInterface.fBuffer.stride(); 93 94 renderer_base& baseRenderer = aggInterface.fBaseRenderer; 95 96 // iterate over clipping boxes 97 baseRenderer.first_clip_box(); 98 do { 99 const int32 x1 = max_c(baseRenderer.xmin(), left); 100 const int32 x2 = min_c(baseRenderer.xmax(), right); 101 if (x1 > x2) 102 continue; 103 104 int32 y1 = max_c(baseRenderer.ymin(), top); 105 int32 y2 = min_c(baseRenderer.ymax(), bottom); 106 if (y1 > y2) 107 continue; 108 109 // buffer offset into destination 110 uint8* dst = aggInterface.fBuffer.row_ptr(y1) + x1 * 4; 111 112 // x and y are needed as indeces into the wheight arrays, so the 113 // offset into the target buffer needs to be compensated 114 const int32 xIndexL = x1 - left - filterWeightXIndexOffset; 115 const int32 xIndexR = x2 - left - filterWeightXIndexOffset; 116 y1 -= top + filterWeightYIndexOffset; 117 y2 -= top + filterWeightYIndexOffset; 118 119 //printf("x: %ld - %ld\n", xIndexL, xIndexR); 120 //printf("y: %ld - %ld\n", y1, y2); 121 122 for (; y1 <= y2; y1++) { 123 // buffer offset into source (top row) 124 const uint8* src = bitmap.row_ptr(yIndices[y1]); 125 // buffer handle for destination to be incremented per pixel 126 uint32* d = (uint32*)dst; 127 128 for (int32 x = xIndexL; x <= xIndexR; x++) { 129 *d = *(uint32*)(src + xIndices[x]); 130 d++; 131 } 132 dst += dstBPR; 133 } 134 } while (baseRenderer.next_clip_box()); 135 136 //printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale, 137 // system_time() - now); 138 } 139 }; 140 141 142 143 #endif // DRAW_BITMAP_NEAREST_NEIGHBOR_H 144