1 #include <bz/gfx/gfx_internal.h>
3 #include <bz/gfx/font_internal.h>
4 #include <bz/math/math.h>
5 #include <bz/memory/allocator.h>
8 #include <string.h> // memset.....
10 // http://members.chello.at/~easyfilter/Bresenham.pdf
12 size_t bufferStride = 0;
13 size_t bufferStrideShift = 0;
14 static uint8_t *drawBuffer;
15 static uint8_t *paletteBuffer;
16 static uint8_t *maskBuffer;
17 static uint8_t *overlayBuffer;
19 uint8_t *bzGfxCompositedBuffer;
21 static uint8_t *currentBuffer;
23 static int32_t canvasWidth = 0; // These need to be signed because of comparisons (don't want to keep casting...)
24 static int32_t canvasHeight = 0;
26 static float cameraX = 0;
27 static float cameraY = 0;
28 static int cameraXInt = 0;
29 static int cameraYInt = 0;
30 static uint16_t fillPattern;
32 static BZMatrix globalViewMatrix = { .a = 1, .b = 0, .c = 0, .d = 1, .x = 0, .y = 0 };
33 //static BZMatrix globalLocalMatrix = { .a = 1, .b = 0, .c = 0, .d = 1, .x = 0, .y = 0 };
35 //static bool fillPattern[4][4];
37 #define _bzBufferLocation(buffer, x, y) buffer[((size_t)(y) << bufferStrideShift) + (size_t)(x)]
38 #define fillPatternBit(x,y) (((fillPattern >> (12 - (((y + cameraYInt) & 0b11) * 4)) >> (3 - ((x + cameraXInt) & 0b11))) & 1) * 255)
39 #define patternVal(buffer, x,y,c) ((_bzBufferLocation(buffer, x, y) & ~(fillPatternBit(x, y))) | ((c) & fillPatternBit(x, y)))
41 //#define _bzBufferSet(buffer, x, y, value) buffer[((y) << bufferStrideShift) + (x)] = (value)
42 #define _bzBufferSet(buffer, x, y, value) _bzBufferLocation(buffer, x, y) = patternVal(buffer, x, y, value)
43 #define _bzBufferSetSafe(buffer, x, y, value) { if ((x)>= 0 && (x)<canvasWidth && (y)>= 0 && (y)<canvasHeight) _bzBufferSet(buffer, x, y, value); }
44 #define _bzBufferSetAssert(buffer, x, y, value) { bzAssert(buffer!=NULL);bzAssertMessage((x)>= 0 && (x)<canvasWidth, "invalid x: %d %s, %d", x, __FILE__, __LINE__);bzAssertMessage((y)>= 0 && (y)<canvasHeight, "invalid y: %d %s, %d", y, __FILE__, __LINE__);_bzBufferSet(buffer, x, y, value); }
45 #define _bzBufferSetNull(buffer, x, y, value) {}
47 #define bzBufferSet _bzBufferSet
49 #define swap(a, b) { typeof(a) tmp = b; b = a; a = tmp; }
51 #define bresenhamVariables(id, x0, y0, x1, y1) \
52 int id##xEnd = x1, id##yEnd = y1; \
53 int id##deltaX = bzAbs(x1 - x0); \
54 int id##deltaY = -bzAbs(y1 - y0); \
55 int id##signX = bzSgn(x1 - x0); \
56 int id##signY = bzSgn(y1 - y0); \
57 int id##err = id##deltaX + id##deltaY; \
58 int id##x = x0, id##y = y0;
60 #define bresenhamStep(id) \
61 int id##e2 = id##err << 1; \
62 if (id##e2 >= id##deltaY) { \
63 if (id##x == id##xEnd) break; \
64 id##err += id##deltaY; \
67 if (id##e2 <= id##deltaX) { \
68 if (id##y == id##yEnd) break; \
69 id##err += id##deltaX; \
73 //uint32_t intermediateBuffer[canvasHeight][canvasWidth];
77 #define kSpriteSheetStrideShift 7
79 //static uint8_t spritesheet[SS_HEIGHT][SS_WIDTH];
80 static uint8_t *spritesheet = NULL;
82 static BZFont *currentFont;
84 /*uint8_t palettes[16][16] = {
85 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
86 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
87 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
88 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
89 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
90 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
91 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
92 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
95 static size_t gPaletteCount;
96 static size_t gPaletteColorCount;
97 static uint8_t *gPalettes;
99 //BZRect bzCalculateCullRect() {
100 // return bzRectMake(cameraX, cameraY, canvasWidth, SS_HEIGHT);
103 void bzGfxPreparePalettes(BZMemoryArenaID arena, size_t paletteCount, size_t colorCount) {
104 gPaletteCount = paletteCount;
105 gPaletteColorCount = colorCount;
106 gPalettes = bzMemoryAlloc(arena, gPaletteCount * gPaletteColorCount * sizeof(uint8_t));
108 for (size_t p = 0, i = 0; p < gPaletteCount; ++p) {
109 for (size_t c = 0; c < gPaletteColorCount; ++c, ++i) {
115 void bzGfxPrepareCanvasBuffer(BZMemoryArenaID arena, size_t width, size_t height) {
117 canvasHeight = height;
119 bufferStrideShift = __SIZE_WIDTH__ - __builtin_clzl(canvasWidth - 1);
120 bufferStride = 1 << bufferStrideShift;
122 size_t canvasMemorySize = bufferStride * height * sizeof(uint8_t);
123 drawBuffer = bzMemoryAlloc(arena, canvasMemorySize);
124 paletteBuffer = bzMemoryAlloc(arena, canvasMemorySize);
125 maskBuffer = bzMemoryAlloc(arena, canvasMemorySize);
126 overlayBuffer = bzMemoryAlloc(arena, canvasMemorySize);
127 bzGfxCompositedBuffer = bzMemoryAlloc(arena, canvasMemorySize);
129 bzSetOutputBuffer(0);
131 bzLog("Data: %d %d %d %d", canvasWidth, canvasMemorySize, bufferStrideShift, bufferStride);
134 void bzGfxPrepareSpritesheet(BZMemoryArenaID arena, size_t width, size_t height, void *data) {
135 uint8_t *imageData = (uint8_t *)data;
136 bzLog("Preparing spritesheet %dx%d", width, height);
138 size_t spritesheetMemorySize = width * height * sizeof(uint8_t);
139 spritesheet = bzMemoryAlloc(arena, spritesheetMemorySize);
140 memcpy(spritesheet, data, spritesheetMemorySize);
143 void bzGfxPrepareFont(BZMemoryArenaID arena, void *font) {
147 static bool prepareFrame(int *minXOut, int *minYOut, int *maxXOut, int *maxYOut, int x0, int y0, int x1, int y1, int *clippedLeftX, int *clippedTopY, int *clippedRightX, int *clippedBottomY) {
148 int xMin = x0, xMax = x1;
149 int yMin = y0, yMax = y1;
161 int xMinOut = xMin/* - cameraX*/, xMaxOut = xMax/* - cameraX*/;
162 int yMinOut = yMin/* - cameraY*/, yMaxOut = yMax/* - cameraY*/;
164 if (xMaxOut < 0 || yMaxOut < 0 || xMinOut >= canvasWidth || yMinOut >= canvasHeight) {
168 int safeXMinOut = bzMax(0, xMinOut);
169 int safeXMaxOut = bzMin(canvasWidth - 1, xMaxOut);
170 int safeYMinOut = bzMax(0, yMinOut);
171 int safeYMaxOut = bzMin(canvasHeight - 1, yMaxOut);
173 *minXOut = safeXMinOut;
174 *minYOut = safeYMinOut;
175 *maxXOut = safeXMaxOut;
176 *maxYOut = safeYMaxOut;
178 if (clippedLeftX != NULL) {
179 *clippedLeftX = safeXMinOut - xMinOut;
180 *clippedTopY = safeYMinOut - yMinOut;
182 *clippedRightX = xMaxOut - safeXMaxOut;
183 *clippedBottomY = yMaxOut - safeYMaxOut;
189 static bool preparePositionXY(int *xOut, int *yOut, float x, float y) {
190 //BZVector origin = bzVectorMake(, );
191 //bzMatrixTransformVector(&origin, &origin, &globalViewMatrix);
192 BZVector position = bzVectorMake(x, y);
193 bzMatrixTransformVector/*bzMatrixTranslateVector*/(&position, &position, &globalViewMatrix);
194 //bzMatrixTransformVector(&position, &position, &globalViewMatrix);
195 //bzVectorAdd(&position, &origin, &position);
196 *xOut = bzFloor(position.x - cameraX);
197 *yOut = bzFloor(position.y - cameraY);
201 static bool prepareSizeXY(int *xOut, int *yOut, float x, float y) {
202 BZVector size = bzVectorMake(x, y);
203 bzMatrixScaleRotateVector(&size, &size, &globalViewMatrix);
204 *xOut = bzFloor(size.x);
205 if (yOut != NULL) *yOut = bzFloor(size.y);
206 return size.x > 0 && size.y > 0;
209 static bool prepareRadius(int *rOut, float r) {
210 BZVector size = bzVectorMake(r, 0);
211 bzMatrixScaleRotateVector(&size, &size, &globalViewMatrix);
212 *rOut = bzFloor(bzAbs(size.x) + bzAbs(size.y));
216 static bool prepareColor(int *colorOut, int color) {
217 *colorOut = gPalettes[color % gPaletteColorCount]; // FIXME
219 /*int c = (color < gPaletteColorCount) ? gPalettes[color] : color;
221 *colorOut = c & globalBlendColor;
228 void bzPSet(BZCoordinate x, BZCoordinate y, BZPaletteColor c) {
229 //if (c == 0) return;
231 //c = ((c < gPaletteColorCount) ? gPalettes[c] : c);
236 preparePositionXY(&ox, &oy, x, y);
237 if (ox >= 0 && ox < canvasWidth && oy >=0 && oy < canvasHeight) {
238 bzBufferSet(currentBuffer, ox, oy, c);
242 BZPaletteColor bzSGet(int x, int y) {
243 bzAssert(spritesheet != NULL);
244 if (x >= 0 && x < SS_WIDTH && y >=0 && y < SS_HEIGHT) {
245 return spritesheet[(y << kSpriteSheetStrideShift) + x];
251 //void bzSSet(int x, int y, int c);
253 //bool bzFGet(int n, int f);
254 //void bzFSet(int n, int f, bool v);
256 void bzCls(BZPaletteColor c) {
257 memset(currentBuffer, c, bufferStride * canvasHeight);
259 //memset(&buffer[currentBuffer], c, BUFFER_WIDTH * canvasHeight);
261 // for (size_t i = 0; i < )
263 // for (size_t y = 0; y < canvasHeight; ++y) {
264 // for (size_t x = 0; x < canvasWidth; ++x) {
265 // bzBufferSet(currentBuffer, x, y, c);
273 void bzGetCamera(BZCoordinate *x, BZCoordinate *y) {
274 if (x != NULL) *x = cameraX;
275 if (y != NULL) *y = cameraY;
278 void bzCamera(BZCoordinate x, BZCoordinate y) {
281 cameraXInt = bzFloor(cameraX);
282 cameraYInt = bzFloor(cameraY);
285 void bzCirc(BZCoordinate xm, BZCoordinate ym, BZCoordinate r, BZPaletteColor c) {
286 int oxm, oym, or, xMinOut, yMinOut, xMaxOut, yMaxOut, cOut;
287 if (preparePositionXY(&oxm, &oym, xm, ym) && prepareRadius(&or, r) && prepareColor(&cOut, c) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, oxm - or, oym - or, oxm + or, oym + or, NULL, NULL, NULL, NULL)) {
290 int err = 2 - 2 * or;
295 if (x0 >= 0 && x0 < canvasWidth && y0 >=0 && y0 < canvasHeight) { // FIXME, easier way to offset this...
296 bzBufferSet(currentBuffer, x0, y0, cOut);
301 if (x1 >= 0 && x1 < canvasWidth && y1 >=0 && y1 < canvasHeight) { // FIXME, easier way to offset this...
302 bzBufferSet(currentBuffer, x1, y1, cOut);
307 if (x2 >= 0 && x2 < canvasWidth && y2 >=0 && y2 < canvasHeight) { // FIXME, easier way to offset this...
308 bzBufferSet(currentBuffer, x2, y2, cOut);
313 if (x3 >= 0 && x3 < canvasWidth && y3 >=0 && y3 < canvasHeight) { // FIXME, easier way to offset this...
314 bzBufferSet(currentBuffer, x3, y3, cOut);
319 if (or <= y) err += (++y << 1) + 1;
320 if (or > x || err > y) err += (++x << 1) + 1;
325 void bzCircFill(BZCoordinate xm, BZCoordinate ym, BZCoordinate r, BZPaletteColor c) {
326 int oxm, oym, or, xMinOut, yMinOut, xMaxOut, yMaxOut, cOut;
327 if (preparePositionXY(&oxm, &oym, xm, ym) && prepareRadius(&or, r) && prepareColor(&cOut, c) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, oxm - or, oym - or, oxm + or, oym + or, NULL, NULL, NULL, NULL)) {
330 int err = 2 - 2 * or;
333 int fy1 = oym - bzAbs(y);
334 int fy2 = oym + bzAbs(y);
335 int fx = bzMax(oxm - bzAbs(x), 0);
336 int tx = bzMin(oxm + bzAbs(x), canvasWidth - 1); // FIXME, not as many abs
338 bool validFy1 = fy1 >= 0 && fy1 < canvasHeight;
339 bool validFy2 = fy2 >= 0 && fy2 < canvasHeight;
341 if (validFy1 && validFy2) {
342 for (int px = fx; px <= tx; ++px) {
343 bzBufferSet(currentBuffer, px, fy1, cOut); // FIXME, speed
344 bzBufferSet(currentBuffer, px, fy2, cOut);
346 } else if (validFy1) {
347 for (int px = fx; px <= tx; ++px) {
348 bzBufferSet(currentBuffer, px, fy1, cOut);
350 } else if (validFy2) {
351 for (int px = fx; px <= tx; ++px) {
352 bzBufferSet(currentBuffer, px, fy2, cOut);
358 if (or <= y) err += (++y << 1) + 1;
359 if (or > x || err > y) err += (++x << 1) + 1;
364 //void bzOval(int x0, int y0, int x1, int y1, int c);
365 //void bzOvalFill(int x0, int y0, int x1, int y1, int c);
367 void bzLine(BZCoordinate x0, BZCoordinate y0, BZCoordinate x1, BZCoordinate y1, BZPaletteColor c) {
368 int ox0, oy0, ox1, oy1, xMinOut, yMinOut, xMaxOut, yMaxOut, cOut, clipLeft, clipTop, clipRight, clipBottom;
369 if (preparePositionXY(&ox0, &oy0, x0, y0) && preparePositionXY(&ox1, &oy1, x1, y1) && prepareColor(&cOut, c) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, ox0, oy0, ox1, oy1, &clipLeft, &clipTop, &clipRight, &clipBottom)) {
370 bresenhamVariables(line_, ox0, oy0, ox1, oy1)
373 if (line_x >= 0 && line_x < canvasWidth && line_y >=0 && line_y < canvasHeight) { // FIXME, easier way to offset this...
374 bzBufferSet(currentBuffer, line_x, line_y, cOut);
382 void bzRect(BZCoordinate x0, BZCoordinate y0, BZCoordinate x1, BZCoordinate y1, BZPaletteColor c) {
383 int ox0, oy0, ox1, oy1, xMinOut, yMinOut, xMaxOut, yMaxOut, cOut, clipLeft, clipTop, clipRight, clipBottom;
384 if (preparePositionXY(&ox0, &oy0, x0, y0) && preparePositionXY(&ox1, &oy1, x1, y1) && prepareColor(&cOut, c) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, ox0, oy0, ox1, oy1, &clipLeft, &clipTop, &clipRight, &clipBottom)) {
385 if (clipLeft == 0 && clipRight == 0) {
386 for (int py = yMinOut; py <= yMaxOut; ++py) {
387 bzBufferSet(currentBuffer, xMinOut, py, cOut);
388 bzBufferSet(currentBuffer, xMaxOut, py, cOut);
390 } else if (clipLeft == 0) {
391 for (int py = yMinOut; py <= yMaxOut; ++py) {
392 bzBufferSet(currentBuffer, xMinOut, py, cOut);
394 } else if (clipRight == 0) {
395 for (int py = yMinOut; py <= yMaxOut; ++py) {
396 bzBufferSet(currentBuffer, xMaxOut, py, cOut);
400 if (clipTop == 0 && clipBottom == 0) {
401 for (int px = xMinOut; px <= xMaxOut; ++px) {
402 bzBufferSet(currentBuffer, px, yMinOut, cOut);
403 bzBufferSet(currentBuffer, px, yMaxOut, cOut);
405 } else if (clipTop == 0) {
406 for (int px = xMinOut; px <= xMaxOut; ++px) {
407 bzBufferSet(currentBuffer, px, yMinOut, cOut);
409 } else if (clipBottom == 0) {
410 for (int px = xMinOut; px <= xMaxOut; ++px) {
411 bzBufferSet(currentBuffer, px, yMaxOut, cOut);
417 void bzRectFill(BZCoordinate x0, BZCoordinate y0, BZCoordinate x1, BZCoordinate y1, BZPaletteColor c) {
418 int ox0, oy0, ox1, oy1, xMinOut, yMinOut, xMaxOut, yMaxOut, cOut, clipLeft, clipTop, clipRight, clipBottom;
419 if (preparePositionXY(&ox0, &oy0, x0, y0) && preparePositionXY(&ox1, &oy1, x1, y1) && prepareColor(&cOut, c) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, ox0, oy0, ox1, oy1, &clipLeft, &clipTop, &clipRight, &clipBottom)) {
420 for (int py = yMinOut; py <= yMaxOut; ++py) {
421 for (int px = xMinOut; px <= xMaxOut; ++px) {
422 bzBufferSet(currentBuffer, px, py, cOut);
428 void bzTriangle(BZCoordinate x0, BZCoordinate y0, BZCoordinate x1, BZCoordinate y1, BZCoordinate x2, BZCoordinate y2, BZPaletteColor c) {
429 int ox0, oy0, ox1, oy1, ox2, oy2;
431 preparePositionXY(&ox0, &oy0, x0, y0);
432 preparePositionXY(&ox1, &oy1, x1, y1);
433 preparePositionXY(&ox2, &oy2, x2, y2);
435 if (oy2 < oy1 || (oy2 == oy1 && ox2 < ox1)) {
440 // after this, x0&y0 are always the smallest
441 if (oy1 < oy0 || (oy1 == oy0 && ox1 < ox0)) {
446 // one final comparison to swap for mid values
447 if (oy2 < oy1 || (oy2 == oy1 && ox2 < ox1)) {
452 // The above sorts pairs by Y position, but X isn't sorted
453 int minX = bzMin(bzMin(ox0, ox1), ox2);
454 int maxX = bzMax(bzMax(ox0, ox1), ox2);
456 int xMinOut, yMinOut, xMaxOut, yMaxOut, cOut, clipLeft, clipTop, clipRight, clipBottom;
457 if (prepareColor(&cOut, c) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, minX, oy0, maxX, oy2, &clipLeft, &clipTop, &clipRight, &clipBottom)) {
458 bresenhamVariables(triangleLow_, ox0, oy0, ox1, oy1)
459 bresenhamVariables(triangleMid_, ox1, oy1, ox2, oy2)
460 bresenhamVariables(triangleHigh_, ox0, oy0, ox2, oy2)
463 int targetY = triangleLow_y;
465 int fromX1 = triangleLow_x, fromX2 = triangleLow_x;
466 while (triangleLow_y == targetY) {
467 fromX1 = triangleLow_x, fromX2 = triangleLow_x;
468 bresenhamStep(triangleLow_)
471 int toX1 = triangleHigh_x, toX2 = triangleHigh_x;
472 targetY = triangleHigh_y;
473 while (triangleHigh_y == targetY) {
474 toX1 = triangleHigh_x, toX2 = triangleHigh_x;
475 bresenhamStep(triangleHigh_)
478 if (targetY >=0 && targetY < canvasHeight) {
482 fromX = bzMin(fromX1, fromX2);
483 toX = bzMax(toX1, toX2);
485 fromX = bzMin(toX1, toX2);
486 toX = bzMax(fromX1, fromX2);
489 if (!((fromX < 0 && toX < 0) || (fromX >= canvasWidth && toX >= canvasWidth))) {
490 fromX = bzMax(0, bzMin(fromX, canvasWidth - 1));
491 toX = bzMax(0, bzMin(toX, canvasWidth - 1));
493 for (int x = fromX; x <= toX; ++x) {
494 bzBufferSet(currentBuffer, x, targetY, cOut);
499 if (targetY >= oy1) {
505 int targetY = triangleMid_y;
507 int fromX1 = triangleMid_x, fromX2 = triangleMid_x;
508 while (triangleMid_y == targetY) {
509 fromX1 = triangleMid_x, fromX2 = triangleMid_x;
510 bresenhamStep(triangleMid_)
513 int toX1 = triangleHigh_x, toX2 = triangleHigh_x;
514 targetY = triangleHigh_y;
515 while (triangleHigh_y == targetY) {
516 toX1 = triangleHigh_x, toX2 = triangleHigh_x;
517 bresenhamStep(triangleHigh_)
520 if (targetY >=0 && targetY < canvasHeight) {
524 fromX = bzMin(fromX1, fromX2);
525 toX = bzMax(toX1, toX2);
527 fromX = bzMin(toX1, toX2);
528 toX = bzMax(fromX1, fromX2);
531 if (!((fromX < 0 && toX < 0) || (fromX >= canvasWidth && toX >= canvasWidth))) {
532 fromX = bzMax(0, bzMin(fromX, canvasWidth - 1));
533 toX = bzMax(0, bzMin(toX, canvasWidth - 1));
535 for (int x = fromX; x <= toX; ++x) {
536 bzBufferSet(currentBuffer, x, targetY, cOut);
541 if (targetY >= oy2) {
548 void bzSpr(size_t n, BZCoordinate x, BZCoordinate y) {
549 bzSprExt(n, x, y, 1, 1, false, false);
552 void bzSprExt(size_t n, BZCoordinate x, BZCoordinate y, BZCoordinate w, BZCoordinate h, bool flipX, bool flipY) {
553 int px = (n % 16) * 8;
554 int py = (n / 16) * 8;
557 bzSSprExt(px, py, pw, ph, x, y, pw, ph, flipX, flipY);
560 void bzSSpr(BZCoordinate sx, BZCoordinate sy, BZCoordinate sw, BZCoordinate sh, BZCoordinate dx, BZCoordinate dy) {
561 bzSSprExt(sx, sy, sw, sh, dx, dy, sw, sh, false, false);
564 void bzSSprExt(BZCoordinate sx, BZCoordinate sy, BZCoordinate sw, BZCoordinate sh, BZCoordinate dx, BZCoordinate dy, BZCoordinate dw, BZCoordinate dh, bool flipX, bool flipY) {
565 bzAssert(spritesheet != NULL);
566 int odx, ody, odw, odh, xMinOut, yMinOut, xMaxOut, yMaxOut, cOut, clipLeft, clipTop, clipRight, clipBottom;
567 if (preparePositionXY(&odx, &ody, dx, dy) && prepareSizeXY(&odw, &odh, dw, dh) && prepareFrame(&xMinOut, &yMinOut, &xMaxOut, &yMaxOut, odx, ody, odx + odw - 1, ody + odh - 1, &clipLeft, &clipTop, &clipRight, &clipBottom)) {
568 int osx = bzFloor(sx);
569 int osy = bzFloor(sy);
570 int osw = bzFloor(sw);
571 int osh = bzFloor(sh);
573 for (size_t y = 0; y < osh - (clipTop + clipBottom); ++y) {
574 for (size_t x = 0; x < osw - (clipLeft + clipRight); ++x) {
575 int color = gPalettes[spritesheet[((clipTop+osy+y) << kSpriteSheetStrideShift) + clipLeft+osx+x]];
576 if (color > 0) bzBufferSet(currentBuffer, xMinOut+x, yMinOut+y, color); // FIXME, scaled up and 0 check removal??
601 for (int rY = fromY, wY = dy; rY != toY; rY += dY, ++wY) {
602 for (int rX = fromX, wX = dx; rX != toX; rX += dX, ++wX) {
603 bzPSet(wX, wY, bzSGet(sx + rX, sy + rY));
608 void bzFillP(BZPattern p) {
612 static void bzPrintPSet(int x, int y, int c) {
613 if (x >= 0 && x < canvasWidth && y >=0 && y < canvasHeight) {
614 //c = ((c < gPaletteColorCount) ? gPalettes[c] : c);
616 bzBufferSet(currentBuffer, x, y, c);
620 void bzPrint(BZCoordinate x, BZCoordinate y, BZPaletteColor color, const char *text) {
622 preparePositionXY(&ox, &oy, x, y);
623 bzGfxRenderFont(bzPrintPSet, &ox, &oy, currentFont, (int)color, text);
624 //if (preparePositionXY(&ox, &oy, x, y)) {
625 // bzGfxRenderFont(bzPSet, &ox, &oy, currentFont, (int)color, text);
626 // FIXME, this won't work
630 void bzSetPaletteColor(size_t palette, BZPaletteColor colorIdx, BZPaletteColor color) {
631 gPalettes[(palette * gPaletteColorCount) + (colorIdx % gPaletteColorCount)] = color;
634 void bzSetGlobalViewMatrix(const BZMatrix *mtx) {
635 bzMatrixCopy(&globalViewMatrix, mtx);
638 //void bzSetGlobalLocalMatrix(const BZMatrix *mtx) {
639 // bzMatrixCopy(&globalLocalMatrix, mtx);
642 //void bzSetGlobalBlendColor(BZPaletteColor color) {
643 // globalBlendColor = color;
646 void bzSetOutputBuffer(size_t idx) {
647 bzAssert(idx >= 0 && idx < 4);
651 currentBuffer = drawBuffer;
655 currentBuffer = paletteBuffer;
659 currentBuffer = maskBuffer;
663 currentBuffer = overlayBuffer;
667 bzError("invalid output buffer");
672 void bzGfxComposite() {
673 bzPerfTimerStart("game.blit.composite");
675 uint8_t *drawBufferReadHead = drawBuffer;
676 uint8_t *paletteBufferReadHead = paletteBuffer;
677 uint8_t *maskBufferReadHead = maskBuffer;
678 uint8_t *overlayBufferReadHead = overlayBuffer;
679 uint8_t *outputBufferWriteHead = bzGfxCompositedBuffer;
680 for (size_t i = 0, end = bufferStride * canvasHeight; i < end; ++i) {
681 //*outputBufferWriteHead = (palettes[*paletteBufferReadHead + 1][*drawBufferReadHead] & *maskBufferReadHead) | *overlayBufferReadHead;
682 *outputBufferWriteHead = *overlayBufferReadHead > 0 ? gPalettes[*overlayBufferReadHead] : gPalettes[(*paletteBufferReadHead + 1) *gPaletteColorCount + *drawBufferReadHead];
684 ++drawBufferReadHead;
685 ++paletteBufferReadHead;
686 ++maskBufferReadHead;
687 ++overlayBufferReadHead;
688 ++outputBufferWriteHead;
691 bzPerfTimerStop("game.blit.composite");