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];
75 //#define SS_WIDTH 128
76 //#define SS_HEIGHT 128
77 //#define kSpriteSheetStrideShift 7
78 //static uint8_t spritesheet[SS_HEIGHT][SS_WIDTH];
79 //static uint8_t *spritesheet = NULL;
81 struct BZSpritesheet
{
89 typedef struct BZSpritesheet BZSpritesheet
;
91 static BZSpritesheet
*spritesheet
= NULL
;
93 static BZFont
*currentFont
;
95 /*uint8_t palettes[16][16] = {
96 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
97 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
98 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
99 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
100 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
101 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
102 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
103 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
106 static size_t gPaletteCount
;
107 static size_t gPaletteColorCount
;
108 static uint8_t *gPalettes
;
110 //BZRect bzCalculateCullRect() {
111 // return bzRectMake(cameraX, cameraY, canvasWidth, SS_HEIGHT);
114 void bzGfxPreparePalettes(BZMemoryArenaID arena
, size_t paletteCount
, size_t colorCount
) {
115 gPaletteCount
= paletteCount
;
116 gPaletteColorCount
= colorCount
;
117 gPalettes
= bzMemoryAlloc(arena
, gPaletteCount
* gPaletteColorCount
* sizeof(uint8_t));
119 for (size_t p
= 0, i
= 0; p
< gPaletteCount
; ++p
) {
120 for (size_t c
= 0; c
< gPaletteColorCount
; ++c
, ++i
) {
126 void bzGfxPrepareCanvasBuffer(BZMemoryArenaID arena
, size_t width
, size_t height
) {
128 canvasHeight
= height
;
130 bufferStrideShift
= __SIZE_WIDTH__
- __builtin_clzl(canvasWidth
- 1);
131 bufferStride
= 1 << bufferStrideShift
;
133 size_t canvasMemorySize
= bufferStride
* height
* sizeof(uint8_t);
134 drawBuffer
= bzMemoryAlloc(arena
, canvasMemorySize
);
135 paletteBuffer
= bzMemoryAlloc(arena
, canvasMemorySize
);
136 maskBuffer
= bzMemoryAlloc(arena
, canvasMemorySize
);
137 overlayBuffer
= bzMemoryAlloc(arena
, canvasMemorySize
);
138 bzGfxCompositedBuffer
= bzMemoryAlloc(arena
, canvasMemorySize
);
140 bzSetOutputBuffer(0);
142 bzLog("Data: %d %d %d %d", canvasWidth
, canvasMemorySize
, bufferStrideShift
, bufferStride
);
145 void bzGfxPrepareSpritesheet(BZMemoryArenaID arena
, size_t frames
, size_t width
, size_t height
, void *data
) {
146 uint8_t *imageData
= (uint8_t *)data
;
147 bzLog("Preparing spritesheet %dx%dx%d", frames
, width
, height
);
149 size_t spritesheetDataSize
= frames
* width
* height
* sizeof(uint8_t);
150 spritesheet
= bzMemoryAlloc(arena
, sizeof(BZSpritesheet
) + spritesheetDataSize
);
152 spritesheet
->width
= width
;
153 spritesheet
->height
= height
* frames
;
154 spritesheet
->spriteCount
= frames
;
155 spritesheet
->spriteWidth
= width
;
156 spritesheet
->spriteHeight
= height
;
157 memcpy(&spritesheet
->data
, data
, spritesheetDataSize
);
160 void bzGfxPrepareFont(BZMemoryArenaID arena
, void *font
) {
164 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
) {
165 int xMin
= x0
, xMax
= x1
;
166 int yMin
= y0
, yMax
= y1
;
178 int xMinOut
= xMin
/* - cameraX*/, xMaxOut
= xMax
/* - cameraX*/;
179 int yMinOut
= yMin
/* - cameraY*/, yMaxOut
= yMax
/* - cameraY*/;
181 if (xMaxOut
< 0 || yMaxOut
< 0 || xMinOut
>= canvasWidth
|| yMinOut
>= canvasHeight
) {
185 int safeXMinOut
= bzMax(0, xMinOut
);
186 int safeXMaxOut
= bzMin(canvasWidth
- 1, xMaxOut
);
187 int safeYMinOut
= bzMax(0, yMinOut
);
188 int safeYMaxOut
= bzMin(canvasHeight
- 1, yMaxOut
);
190 *minXOut
= safeXMinOut
;
191 *minYOut
= safeYMinOut
;
192 *maxXOut
= safeXMaxOut
;
193 *maxYOut
= safeYMaxOut
;
195 if (clippedLeftX
!= NULL
) {
196 *clippedLeftX
= safeXMinOut
- xMinOut
;
197 *clippedTopY
= safeYMinOut
- yMinOut
;
199 *clippedRightX
= xMaxOut
- safeXMaxOut
;
200 *clippedBottomY
= yMaxOut
- safeYMaxOut
;
206 static bool preparePositionXY(int *xOut
, int *yOut
, float x
, float y
) {
207 //BZVector origin = bzVectorMake(, );
208 //bzMatrixTransformVector(&origin, &origin, &globalViewMatrix);
209 BZVector position
= bzVectorMake(x
, y
);
210 bzMatrixTransformVector
/*bzMatrixTranslateVector*/(&position
, &position
, &globalViewMatrix
);
211 //bzMatrixTransformVector(&position, &position, &globalViewMatrix);
212 //bzVectorAdd(&position, &origin, &position);
213 *xOut
= bzFloor(position
.x
- cameraX
);
214 *yOut
= bzFloor(position
.y
- cameraY
);
218 static bool prepareSizeXY(int *xOut
, int *yOut
, float x
, float y
) {
219 BZVector size
= bzVectorMake(x
, y
);
220 bzMatrixScaleRotateVector(&size
, &size
, &globalViewMatrix
);
221 *xOut
= bzFloor(size
.x
);
222 if (yOut
!= NULL
) *yOut
= bzFloor(size
.y
);
223 return size
.x
> 0 && size
.y
> 0;
226 static bool prepareRadius(int *rOut
, float r
) {
227 BZVector size
= bzVectorMake(r
, 0);
228 bzMatrixScaleRotateVector(&size
, &size
, &globalViewMatrix
);
229 *rOut
= bzFloor(bzAbs(size
.x
) + bzAbs(size
.y
));
233 static bool prepareColor(int *colorOut
, int color
) {
234 *colorOut
= gPalettes
[color
% gPaletteColorCount
]; // FIXME
236 /*int c = (color < gPaletteColorCount) ? gPalettes[color] : color;
238 *colorOut = c & globalBlendColor;
245 void bzPSet(BZCoordinate x
, BZCoordinate y
, BZPaletteColor c
) {
246 //if (c == 0) return;
248 //c = ((c < gPaletteColorCount) ? gPalettes[c] : c);
253 preparePositionXY(&ox
, &oy
, x
, y
);
254 if (ox
>= 0 && ox
< canvasWidth
&& oy
>=0 && oy
< canvasHeight
) {
255 bzBufferSet(currentBuffer
, ox
, oy
, c
);
259 BZPaletteColor
bzSGet(int x
, int y
) {
260 bzAssert(spritesheet
!= NULL
);
261 if (x
>= 0 && x
< spritesheet
->width
&& y
>=0 && y
< spritesheet
->height
) {
262 return spritesheet
->data
[y
* spritesheet
->width
+ x
];
263 //return spritesheet->data[(y << kSpriteSheetStrideShift) + x];
269 //void bzSSet(int x, int y, int c);
271 //bool bzFGet(int n, int f);
272 //void bzFSet(int n, int f, bool v);
274 void bzCls(BZPaletteColor c
) {
275 memset(currentBuffer
, c
, bufferStride
* canvasHeight
);
277 //memset(&buffer[currentBuffer], c, BUFFER_WIDTH * canvasHeight);
279 // for (size_t i = 0; i < )
281 // for (size_t y = 0; y < canvasHeight; ++y) {
282 // for (size_t x = 0; x < canvasWidth; ++x) {
283 // bzBufferSet(currentBuffer, x, y, c);
291 void bzGetCamera(BZCoordinate
*x
, BZCoordinate
*y
) {
292 if (x
!= NULL
) *x
= cameraX
;
293 if (y
!= NULL
) *y
= cameraY
;
296 void bzCamera(BZCoordinate x
, BZCoordinate y
) {
299 cameraXInt
= bzFloor(cameraX
);
300 cameraYInt
= bzFloor(cameraY
);
303 void bzCirc(BZCoordinate xm
, BZCoordinate ym
, BZCoordinate r
, BZPaletteColor c
) {
304 int oxm
, oym
, or, xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
;
305 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
)) {
308 int err
= 2 - 2 * or;
313 if (x0
>= 0 && x0
< canvasWidth
&& y0
>=0 && y0
< canvasHeight
) { // FIXME, easier way to offset this...
314 bzBufferSet(currentBuffer
, x0
, y0
, cOut
);
319 if (x1
>= 0 && x1
< canvasWidth
&& y1
>=0 && y1
< canvasHeight
) { // FIXME, easier way to offset this...
320 bzBufferSet(currentBuffer
, x1
, y1
, cOut
);
325 if (x2
>= 0 && x2
< canvasWidth
&& y2
>=0 && y2
< canvasHeight
) { // FIXME, easier way to offset this...
326 bzBufferSet(currentBuffer
, x2
, y2
, cOut
);
331 if (x3
>= 0 && x3
< canvasWidth
&& y3
>=0 && y3
< canvasHeight
) { // FIXME, easier way to offset this...
332 bzBufferSet(currentBuffer
, x3
, y3
, cOut
);
337 if (or <= y
) err
+= (++y
<< 1) + 1;
338 if (or > x
|| err
> y
) err
+= (++x
<< 1) + 1;
343 void bzCircFill(BZCoordinate xm
, BZCoordinate ym
, BZCoordinate r
, BZPaletteColor c
) {
344 int oxm
, oym
, or, xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
;
345 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
)) {
348 int err
= 2 - 2 * or;
351 int fy1
= oym
- bzAbs(y
);
352 int fy2
= oym
+ bzAbs(y
);
353 int fx
= bzMax(oxm
- bzAbs(x
), 0);
354 int tx
= bzMin(oxm
+ bzAbs(x
), canvasWidth
- 1); // FIXME, not as many abs
356 bool validFy1
= fy1
>= 0 && fy1
< canvasHeight
;
357 bool validFy2
= fy2
>= 0 && fy2
< canvasHeight
;
359 if (validFy1
&& validFy2
) {
360 for (int px
= fx
; px
<= tx
; ++px
) {
361 bzBufferSet(currentBuffer
, px
, fy1
, cOut
); // FIXME, speed
362 bzBufferSet(currentBuffer
, px
, fy2
, cOut
);
364 } else if (validFy1
) {
365 for (int px
= fx
; px
<= tx
; ++px
) {
366 bzBufferSet(currentBuffer
, px
, fy1
, cOut
);
368 } else if (validFy2
) {
369 for (int px
= fx
; px
<= tx
; ++px
) {
370 bzBufferSet(currentBuffer
, px
, fy2
, cOut
);
376 if (or <= y
) err
+= (++y
<< 1) + 1;
377 if (or > x
|| err
> y
) err
+= (++x
<< 1) + 1;
382 //void bzOval(int x0, int y0, int x1, int y1, int c);
383 //void bzOvalFill(int x0, int y0, int x1, int y1, int c);
385 void bzLine(BZCoordinate x0
, BZCoordinate y0
, BZCoordinate x1
, BZCoordinate y1
, BZPaletteColor c
) {
386 int ox0
, oy0
, ox1
, oy1
, xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
, clipLeft
, clipTop
, clipRight
, clipBottom
;
387 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
)) {
388 bresenhamVariables(line_
, ox0
, oy0
, ox1
, oy1
)
391 if (line_x
>= 0 && line_x
< canvasWidth
&& line_y
>=0 && line_y
< canvasHeight
) { // FIXME, easier way to offset this...
392 bzBufferSet(currentBuffer
, line_x
, line_y
, cOut
);
400 void bzRect(BZCoordinate x0
, BZCoordinate y0
, BZCoordinate x1
, BZCoordinate y1
, BZPaletteColor c
) {
401 int ox0
, oy0
, ox1
, oy1
, xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
, clipLeft
, clipTop
, clipRight
, clipBottom
;
402 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
)) {
403 if (clipLeft
== 0 && clipRight
== 0) {
404 for (int py
= yMinOut
; py
<= yMaxOut
; ++py
) {
405 bzBufferSet(currentBuffer
, xMinOut
, py
, cOut
);
406 bzBufferSet(currentBuffer
, xMaxOut
, py
, cOut
);
408 } else if (clipLeft
== 0) {
409 for (int py
= yMinOut
; py
<= yMaxOut
; ++py
) {
410 bzBufferSet(currentBuffer
, xMinOut
, py
, cOut
);
412 } else if (clipRight
== 0) {
413 for (int py
= yMinOut
; py
<= yMaxOut
; ++py
) {
414 bzBufferSet(currentBuffer
, xMaxOut
, py
, cOut
);
418 if (clipTop
== 0 && clipBottom
== 0) {
419 for (int px
= xMinOut
; px
<= xMaxOut
; ++px
) {
420 bzBufferSet(currentBuffer
, px
, yMinOut
, cOut
);
421 bzBufferSet(currentBuffer
, px
, yMaxOut
, cOut
);
423 } else if (clipTop
== 0) {
424 for (int px
= xMinOut
; px
<= xMaxOut
; ++px
) {
425 bzBufferSet(currentBuffer
, px
, yMinOut
, cOut
);
427 } else if (clipBottom
== 0) {
428 for (int px
= xMinOut
; px
<= xMaxOut
; ++px
) {
429 bzBufferSet(currentBuffer
, px
, yMaxOut
, cOut
);
435 void bzRectFill(BZCoordinate x0
, BZCoordinate y0
, BZCoordinate x1
, BZCoordinate y1
, BZPaletteColor c
) {
436 int ox0
, oy0
, ox1
, oy1
, xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
, clipLeft
, clipTop
, clipRight
, clipBottom
;
437 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
)) {
438 for (int py
= yMinOut
; py
<= yMaxOut
; ++py
) {
439 for (int px
= xMinOut
; px
<= xMaxOut
; ++px
) {
440 bzBufferSet(currentBuffer
, px
, py
, cOut
);
446 void bzTriangle(BZCoordinate x0
, BZCoordinate y0
, BZCoordinate x1
, BZCoordinate y1
, BZCoordinate x2
, BZCoordinate y2
, BZPaletteColor c
) {
447 int ox0
, oy0
, ox1
, oy1
, ox2
, oy2
;
449 preparePositionXY(&ox0
, &oy0
, x0
, y0
);
450 preparePositionXY(&ox1
, &oy1
, x1
, y1
);
451 preparePositionXY(&ox2
, &oy2
, x2
, y2
);
453 if (oy2
< oy1
|| (oy2
== oy1
&& ox2
< ox1
)) {
458 // after this, x0&y0 are always the smallest
459 if (oy1
< oy0
|| (oy1
== oy0
&& ox1
< ox0
)) {
464 // one final comparison to swap for mid values
465 if (oy2
< oy1
|| (oy2
== oy1
&& ox2
< ox1
)) {
470 // The above sorts pairs by Y position, but X isn't sorted
471 int minX
= bzMin(bzMin(ox0
, ox1
), ox2
);
472 int maxX
= bzMax(bzMax(ox0
, ox1
), ox2
);
474 int xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
, clipLeft
, clipTop
, clipRight
, clipBottom
;
475 if (prepareColor(&cOut
, c
) && prepareFrame(&xMinOut
, &yMinOut
, &xMaxOut
, &yMaxOut
, minX
, oy0
, maxX
, oy2
, &clipLeft
, &clipTop
, &clipRight
, &clipBottom
)) {
476 bresenhamVariables(triangleLow_
, ox0
, oy0
, ox1
, oy1
)
477 bresenhamVariables(triangleMid_
, ox1
, oy1
, ox2
, oy2
)
478 bresenhamVariables(triangleHigh_
, ox0
, oy0
, ox2
, oy2
)
481 int targetY
= triangleLow_y
;
483 int fromX1
= triangleLow_x
, fromX2
= triangleLow_x
;
484 while (triangleLow_y
== targetY
) {
485 fromX1
= triangleLow_x
, fromX2
= triangleLow_x
;
486 bresenhamStep(triangleLow_
)
489 int toX1
= triangleHigh_x
, toX2
= triangleHigh_x
;
490 targetY
= triangleHigh_y
;
491 while (triangleHigh_y
== targetY
) {
492 toX1
= triangleHigh_x
, toX2
= triangleHigh_x
;
493 bresenhamStep(triangleHigh_
)
496 if (targetY
>=0 && targetY
< canvasHeight
) {
500 fromX
= bzMin(fromX1
, fromX2
);
501 toX
= bzMax(toX1
, toX2
);
503 fromX
= bzMin(toX1
, toX2
);
504 toX
= bzMax(fromX1
, fromX2
);
507 if (!((fromX
< 0 && toX
< 0) || (fromX
>= canvasWidth
&& toX
>= canvasWidth
))) {
508 fromX
= bzMax(0, bzMin(fromX
, canvasWidth
- 1));
509 toX
= bzMax(0, bzMin(toX
, canvasWidth
- 1));
511 for (int x
= fromX
; x
<= toX
; ++x
) {
512 bzBufferSet(currentBuffer
, x
, targetY
, cOut
);
517 if (targetY
>= oy1
) {
523 int targetY
= triangleMid_y
;
525 int fromX1
= triangleMid_x
, fromX2
= triangleMid_x
;
526 while (triangleMid_y
== targetY
) {
527 fromX1
= triangleMid_x
, fromX2
= triangleMid_x
;
528 bresenhamStep(triangleMid_
)
531 int toX1
= triangleHigh_x
, toX2
= triangleHigh_x
;
532 targetY
= triangleHigh_y
;
533 while (triangleHigh_y
== targetY
) {
534 toX1
= triangleHigh_x
, toX2
= triangleHigh_x
;
535 bresenhamStep(triangleHigh_
)
538 if (targetY
>=0 && targetY
< canvasHeight
) {
542 fromX
= bzMin(fromX1
, fromX2
);
543 toX
= bzMax(toX1
, toX2
);
545 fromX
= bzMin(toX1
, toX2
);
546 toX
= bzMax(fromX1
, fromX2
);
549 if (!((fromX
< 0 && toX
< 0) || (fromX
>= canvasWidth
&& toX
>= canvasWidth
))) {
550 fromX
= bzMax(0, bzMin(fromX
, canvasWidth
- 1));
551 toX
= bzMax(0, bzMin(toX
, canvasWidth
- 1));
553 for (int x
= fromX
; x
<= toX
; ++x
) {
554 bzBufferSet(currentBuffer
, x
, targetY
, cOut
);
559 if (targetY
>= oy2
) {
566 void bzSpr(size_t n
, BZCoordinate x
, BZCoordinate y
) {
567 bzSprExt(n
, x
, y
, 1, 1, false, false);
570 void bzSprExt(size_t n
, BZCoordinate x
, BZCoordinate y
, BZCoordinate w
, BZCoordinate h
, bool flipX
, bool flipY
) {
571 int px
= 0;//(n % 16) * 8;
572 int py
= n
* spritesheet
->spriteHeight
;//(n / 16) * 8;
573 int pw
= w
* spritesheet
->spriteWidth
;
574 int ph
= h
* spritesheet
->spriteHeight
;
575 bzSSprExt(px
, py
, pw
, ph
, x
, y
, pw
, ph
, flipX
, flipY
);
577 // int px = (n % 16) * 8;
578 // int py = (n / 16) * 8;
581 // bzSSprExt(px, py, pw, ph, x, y, pw, ph, flipX, flipY);
584 void bzSSpr(BZCoordinate sx
, BZCoordinate sy
, BZCoordinate sw
, BZCoordinate sh
, BZCoordinate dx
, BZCoordinate dy
) {
585 bzSSprExt(sx
, sy
, sw
, sh
, dx
, dy
, sw
, sh
, false, false);
588 void bzSSprExt(BZCoordinate sx
, BZCoordinate sy
, BZCoordinate sw
, BZCoordinate sh
, BZCoordinate dx
, BZCoordinate dy
, BZCoordinate dw
, BZCoordinate dh
, bool flipX
, bool flipY
) {
589 bzAssert(spritesheet
!= NULL
);
590 int odx
, ody
, odw
, odh
, xMinOut
, yMinOut
, xMaxOut
, yMaxOut
, cOut
, clipLeft
, clipTop
, clipRight
, clipBottom
;
591 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
)) {
592 int osx
= bzFloor(sx
);
593 int osy
= bzFloor(sy
);
594 int osw
= bzFloor(sw
);
595 int osh
= bzFloor(sh
);
597 for (size_t y
= 0; y
< osh
- (clipTop
+ clipBottom
); ++y
) {
598 for (size_t x
= 0; x
< osw
- (clipLeft
+ clipRight
); ++x
) {
599 int color
= gPalettes
[spritesheet
->data
[(clipTop
+osy
+y
) * spritesheet
->width
+ clipLeft
+osx
+x
]];
600 if (color
> 0) bzBufferSet(currentBuffer
, xMinOut
+x
, yMinOut
+y
, color
); // FIXME, scaled up and 0 check removal??
625 for (int rY = fromY, wY = dy; rY != toY; rY += dY, ++wY) {
626 for (int rX = fromX, wX = dx; rX != toX; rX += dX, ++wX) {
627 bzPSet(wX, wY, bzSGet(sx + rX, sy + rY));
632 void bzFillP(BZPattern p
) {
636 static void bzPrintPSet(int x
, int y
, int c
) {
637 if (x
>= 0 && x
< canvasWidth
&& y
>=0 && y
< canvasHeight
) {
638 //c = ((c < gPaletteColorCount) ? gPalettes[c] : c);
640 bzBufferSet(currentBuffer
, x
, y
, c
);
644 void bzPrint(BZCoordinate x
, BZCoordinate y
, BZPaletteColor color
, const char *text
) {
646 preparePositionXY(&ox
, &oy
, x
, y
);
647 bzGfxRenderFont(bzPrintPSet
, &ox
, &oy
, currentFont
, (int)color
, text
);
648 //if (preparePositionXY(&ox, &oy, x, y)) {
649 // bzGfxRenderFont(bzPSet, &ox, &oy, currentFont, (int)color, text);
650 // FIXME, this won't work
654 void bzSetPaletteColor(size_t palette
, BZPaletteColor colorIdx
, BZPaletteColor color
) {
655 gPalettes
[(palette
* gPaletteColorCount
) + (colorIdx
% gPaletteColorCount
)] = color
;
658 void bzSetGlobalViewMatrix(const BZMatrix
*mtx
) {
659 bzMatrixCopy(&globalViewMatrix
, mtx
);
662 //void bzSetGlobalLocalMatrix(const BZMatrix *mtx) {
663 // bzMatrixCopy(&globalLocalMatrix, mtx);
666 //void bzSetGlobalBlendColor(BZPaletteColor color) {
667 // globalBlendColor = color;
670 void bzSetOutputBuffer(size_t idx
) {
671 bzAssert(idx
>= 0 && idx
< 4);
675 currentBuffer
= drawBuffer
;
679 currentBuffer
= paletteBuffer
;
683 currentBuffer
= maskBuffer
;
687 currentBuffer
= overlayBuffer
;
691 bzError("invalid output buffer");
696 void bzGfxComposite() {
697 bzPerfTimerStart("game.blit.composite");
699 uint8_t *drawBufferReadHead
= drawBuffer
;
700 uint8_t *paletteBufferReadHead
= paletteBuffer
;
701 uint8_t *maskBufferReadHead
= maskBuffer
;
702 uint8_t *overlayBufferReadHead
= overlayBuffer
;
703 uint8_t *outputBufferWriteHead
= bzGfxCompositedBuffer
;
704 for (size_t i
= 0, end
= bufferStride
* canvasHeight
; i
< end
; ++i
) {
705 //*outputBufferWriteHead = (palettes[*paletteBufferReadHead + 1][*drawBufferReadHead] & *maskBufferReadHead) | *overlayBufferReadHead;
706 *outputBufferWriteHead
= *overlayBufferReadHead
> 0 ? gPalettes
[*overlayBufferReadHead
] : gPalettes
[(*paletteBufferReadHead
+ 1) *gPaletteColorCount
+ *drawBufferReadHead
];
708 ++drawBufferReadHead
;
709 ++paletteBufferReadHead
;
710 ++maskBufferReadHead
;
711 ++overlayBufferReadHead
;
712 ++outputBufferWriteHead
;
715 bzPerfTimerStop("game.blit.composite");