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");