]> git.bts.cx Git - benzene.git/blob - src/bz/gfx/gfx.c
Sprites
[benzene.git] / src / bz / gfx / gfx.c
1 #include <bz/gfx/gfx_internal.h>
2
3 #include <bz/gfx/font_internal.h>
4 #include <bz/math/math.h>
5 #include <bz/memory/allocator.h>
6
7 #include <stdlib.h>
8 #include <string.h> // memset.....
9
10 // http://members.chello.at/~easyfilter/Bresenham.pdf
11
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;
18
19 uint8_t *bzGfxCompositedBuffer;
20
21 static uint8_t *currentBuffer;
22
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;
25
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;
31
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 };
34
35 //static bool fillPattern[4][4];
36
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)))
40
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) {}
46
47 #define bzBufferSet _bzBufferSet
48
49 #define swap(a, b) { typeof(a) tmp = b; b = a; a = tmp; }
50
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;
59
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; \
65 id##x += id##signX; \
66 } \
67 if (id##e2 <= id##deltaX) { \
68 if (id##y == id##yEnd) break; \
69 id##err += id##deltaX; \
70 id##y += id##signY; \
71 }
72
73 //uint32_t intermediateBuffer[canvasHeight][canvasWidth];
74
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;
80
81 struct BZSpritesheet {
82 size_t width;
83 size_t height;
84 size_t spriteWidth;
85 size_t spriteHeight;
86 size_t spriteCount;
87 uint8_t data[];
88 };
89 typedef struct BZSpritesheet BZSpritesheet;
90
91 static BZSpritesheet *spritesheet = NULL;
92
93 static BZFont *currentFont;
94
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},
104 };*/
105
106 static size_t gPaletteCount;
107 static size_t gPaletteColorCount;
108 static uint8_t *gPalettes;
109
110 //BZRect bzCalculateCullRect() {
111 // return bzRectMake(cameraX, cameraY, canvasWidth, SS_HEIGHT);
112 //}
113
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));
118
119 for (size_t p = 0, i = 0; p < gPaletteCount; ++p) {
120 for (size_t c = 0; c < gPaletteColorCount; ++c, ++i) {
121 gPalettes[i] = c;
122 }
123 }
124 }
125
126 void bzGfxPrepareCanvasBuffer(BZMemoryArenaID arena, size_t width, size_t height) {
127 canvasWidth = width;
128 canvasHeight = height;
129
130 bufferStrideShift = __SIZE_WIDTH__ - __builtin_clzl(canvasWidth - 1);
131 bufferStride = 1 << bufferStrideShift;
132
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);
139
140 bzSetOutputBuffer(0);
141
142 bzLog("Data: %d %d %d %d", canvasWidth, canvasMemorySize, bufferStrideShift, bufferStride);
143 }
144
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);
148
149 size_t spritesheetDataSize = frames * width * height * sizeof(uint8_t);
150 spritesheet = bzMemoryAlloc(arena, sizeof(BZSpritesheet) + spritesheetDataSize);
151
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);
158 }
159
160 void bzGfxPrepareFont(BZMemoryArenaID arena, void *font) {
161 currentFont = font;
162 }
163
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;
167
168 if (x1 < x0) {
169 xMin = x1;
170 xMax = x0;
171 }
172
173 if (y1 < y0) {
174 yMin = y1;
175 yMax = y0;
176 }
177
178 int xMinOut = xMin/* - cameraX*/, xMaxOut = xMax/* - cameraX*/;
179 int yMinOut = yMin/* - cameraY*/, yMaxOut = yMax/* - cameraY*/;
180
181 if (xMaxOut < 0 || yMaxOut < 0 || xMinOut >= canvasWidth || yMinOut >= canvasHeight) {
182 return false;
183 }
184
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);
189
190 *minXOut = safeXMinOut;
191 *minYOut = safeYMinOut;
192 *maxXOut = safeXMaxOut;
193 *maxYOut = safeYMaxOut;
194
195 if (clippedLeftX != NULL) {
196 *clippedLeftX = safeXMinOut - xMinOut;
197 *clippedTopY = safeYMinOut - yMinOut;
198
199 *clippedRightX = xMaxOut - safeXMaxOut;
200 *clippedBottomY = yMaxOut - safeYMaxOut;
201 }
202
203 return true;
204 }
205
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);
215 return true;
216 }
217
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;
224 }
225
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));
230 return *rOut > 0;
231 }
232
233 static bool prepareColor(int *colorOut, int color) {
234 *colorOut = gPalettes[color % gPaletteColorCount]; // FIXME
235 return true;
236 /*int c = (color < gPaletteColorCount) ? gPalettes[color] : color;
237 if (c > 0) {
238 *colorOut = c & globalBlendColor;
239 return true;
240 } else {
241 return false;
242 }*/
243 }
244
245 void bzPSet(BZCoordinate x, BZCoordinate y, BZPaletteColor c) {
246 //if (c == 0) return;
247
248 //c = ((c < gPaletteColorCount) ? gPalettes[c] : c);
249
250 prepareColor(&c, c);
251
252 int ox, oy;
253 preparePositionXY(&ox, &oy, x, y);
254 if (ox >= 0 && ox < canvasWidth && oy >=0 && oy < canvasHeight) {
255 bzBufferSet(currentBuffer, ox, oy, c);
256 }
257 }
258
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];
264 } else {
265 return 0;
266 }
267 }
268
269 //void bzSSet(int x, int y, int c);
270
271 //bool bzFGet(int n, int f);
272 //void bzFSet(int n, int f, bool v);
273
274 void bzCls(BZPaletteColor c) {
275 memset(currentBuffer, c, bufferStride * canvasHeight);
276
277 //memset(&buffer[currentBuffer], c, BUFFER_WIDTH * canvasHeight);
278
279 // for (size_t i = 0; i < )
280
281 // for (size_t y = 0; y < canvasHeight; ++y) {
282 // for (size_t x = 0; x < canvasWidth; ++x) {
283 // bzBufferSet(currentBuffer, x, y, c);
284 // }
285 // }
286
287 //bzCamera(0, 0);
288 bzFillP(0x0000);
289 }
290
291 void bzGetCamera(BZCoordinate *x, BZCoordinate *y) {
292 if (x != NULL) *x = cameraX;
293 if (y != NULL) *y = cameraY;
294 }
295
296 void bzCamera(BZCoordinate x, BZCoordinate y) {
297 cameraX = x;
298 cameraY = y;
299 cameraXInt = bzFloor(cameraX);
300 cameraYInt = bzFloor(cameraY);
301 }
302
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)) {
306 int x = -or;
307 int y = 0;
308 int err = 2 - 2 * or;
309
310 do {
311 int x0 = oxm-x;
312 int y0 = oym+y;
313 if (x0 >= 0 && x0 < canvasWidth && y0 >=0 && y0 < canvasHeight) { // FIXME, easier way to offset this...
314 bzBufferSet(currentBuffer, x0, y0, cOut);
315 }
316
317 int x1 = oxm-y;
318 int y1 = oym-x;
319 if (x1 >= 0 && x1 < canvasWidth && y1 >=0 && y1 < canvasHeight) { // FIXME, easier way to offset this...
320 bzBufferSet(currentBuffer, x1, y1, cOut);
321 }
322
323 int x2 = oxm+x;
324 int y2 = oym-y;
325 if (x2 >= 0 && x2 < canvasWidth && y2 >=0 && y2 < canvasHeight) { // FIXME, easier way to offset this...
326 bzBufferSet(currentBuffer, x2, y2, cOut);
327 }
328
329 int x3 = oxm+y;
330 int y3 = oym+x;
331 if (x3 >= 0 && x3 < canvasWidth && y3 >=0 && y3 < canvasHeight) { // FIXME, easier way to offset this...
332 bzBufferSet(currentBuffer, x3, y3, cOut);
333 }
334
335 or = err;
336
337 if (or <= y) err += (++y << 1) + 1;
338 if (or > x || err > y) err += (++x << 1) + 1;
339 } while (x <= 0);
340 }
341 }
342
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)) {
346 int x = -or;
347 int y = 0;
348 int err = 2 - 2 * or;
349
350 do {
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
355
356 bool validFy1 = fy1 >= 0 && fy1 < canvasHeight;
357 bool validFy2 = fy2 >= 0 && fy2 < canvasHeight;
358
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);
363 }
364 } else if (validFy1) {
365 for (int px = fx; px <= tx; ++px) {
366 bzBufferSet(currentBuffer, px, fy1, cOut);
367 }
368 } else if (validFy2) {
369 for (int px = fx; px <= tx; ++px) {
370 bzBufferSet(currentBuffer, px, fy2, cOut);
371 }
372 }
373
374 or = err;
375
376 if (or <= y) err += (++y << 1) + 1;
377 if (or > x || err > y) err += (++x << 1) + 1;
378 } while (x <= 0);
379 }
380 }
381
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);
384
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)
389
390 for (;;) {
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);
393 }
394
395 bresenhamStep(line_)
396 }
397 }
398 }
399
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);
407 }
408 } else if (clipLeft == 0) {
409 for (int py = yMinOut; py <= yMaxOut; ++py) {
410 bzBufferSet(currentBuffer, xMinOut, py, cOut);
411 }
412 } else if (clipRight == 0) {
413 for (int py = yMinOut; py <= yMaxOut; ++py) {
414 bzBufferSet(currentBuffer, xMaxOut, py, cOut);
415 }
416 }
417
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);
422 }
423 } else if (clipTop == 0) {
424 for (int px = xMinOut; px <= xMaxOut; ++px) {
425 bzBufferSet(currentBuffer, px, yMinOut, cOut);
426 }
427 } else if (clipBottom == 0) {
428 for (int px = xMinOut; px <= xMaxOut; ++px) {
429 bzBufferSet(currentBuffer, px, yMaxOut, cOut);
430 }
431 }
432 }
433 }
434
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);
441 }
442 }
443 }
444 }
445
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;
448
449 preparePositionXY(&ox0, &oy0, x0, y0);
450 preparePositionXY(&ox1, &oy1, x1, y1);
451 preparePositionXY(&ox2, &oy2, x2, y2);
452
453 if (oy2 < oy1 || (oy2 == oy1 && ox2 < ox1)) {
454 swap(ox1, ox2);
455 swap(oy1, oy2);
456 }
457
458 // after this, x0&y0 are always the smallest
459 if (oy1 < oy0 || (oy1 == oy0 && ox1 < ox0)) {
460 swap(ox0, ox1);
461 swap(oy0, oy1);
462 }
463
464 // one final comparison to swap for mid values
465 if (oy2 < oy1 || (oy2 == oy1 && ox2 < ox1)) {
466 swap(ox1, ox2);
467 swap(oy1, oy2);
468 }
469
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);
473
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)
479
480 for (;;) {
481 int targetY = triangleLow_y;
482
483 int fromX1 = triangleLow_x, fromX2 = triangleLow_x;
484 while (triangleLow_y == targetY) {
485 fromX1 = triangleLow_x, fromX2 = triangleLow_x;
486 bresenhamStep(triangleLow_)
487 }
488
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_)
494 }
495
496 if (targetY >=0 && targetY < canvasHeight) {
497 int fromX, toX;
498
499 if (fromX1 < toX2) {
500 fromX = bzMin(fromX1, fromX2);
501 toX = bzMax(toX1, toX2);
502 } else {
503 fromX = bzMin(toX1, toX2);
504 toX = bzMax(fromX1, fromX2);
505 }
506
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));
510
511 for (int x = fromX; x <= toX; ++x) {
512 bzBufferSet(currentBuffer, x, targetY, cOut);
513 }
514 }
515 }
516
517 if (targetY >= oy1) {
518 break;
519 }
520 }
521
522 for (;;) {
523 int targetY = triangleMid_y;
524
525 int fromX1 = triangleMid_x, fromX2 = triangleMid_x;
526 while (triangleMid_y == targetY) {
527 fromX1 = triangleMid_x, fromX2 = triangleMid_x;
528 bresenhamStep(triangleMid_)
529 }
530
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_)
536 }
537
538 if (targetY >=0 && targetY < canvasHeight) {
539 int fromX, toX;
540
541 if (fromX1 < toX2) {
542 fromX = bzMin(fromX1, fromX2);
543 toX = bzMax(toX1, toX2);
544 } else {
545 fromX = bzMin(toX1, toX2);
546 toX = bzMax(fromX1, fromX2);
547 }
548
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));
552
553 for (int x = fromX; x <= toX; ++x) {
554 bzBufferSet(currentBuffer, x, targetY, cOut);
555 }
556 }
557 }
558
559 if (targetY >= oy2) {
560 break;
561 }
562 }
563 }
564 }
565
566 void bzSpr(size_t n, BZCoordinate x, BZCoordinate y) {
567 bzSprExt(n, x, y, 1, 1, false, false);
568 }
569
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);
576
577 // int px = (n % 16) * 8;
578 // int py = (n / 16) * 8;
579 // int pw = w * 8;
580 // int ph = h * 8;
581 // bzSSprExt(px, py, pw, ph, x, y, pw, ph, flipX, flipY);
582 }
583
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);
586 }
587
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);
596
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??
601 }
602 }
603 }
604
605 /*int fromX = 0;
606 int toX = sw;
607 int dX = 1;
608
609 if (flipX) {
610 fromX = toX - 1;
611 toX = -1;
612 dX = -1;
613 }
614
615 int fromY = 0;
616 int toY = sh;
617 int dY = 1;
618
619 if (flipY) {
620 fromY = toY - 1;
621 toY = -1;
622 dY = -1;
623 }
624
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));
628 }
629 }*/
630 }
631
632 void bzFillP(BZPattern p) {
633 fillPattern = ~p;
634 }
635
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);
639 prepareColor(&c, c);
640 bzBufferSet(currentBuffer, x, y, c);
641 }
642 }
643
644 void bzPrint(BZCoordinate x, BZCoordinate y, BZPaletteColor color, const char *text) {
645 int ox, oy;
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
651 //}
652 }
653
654 void bzSetPaletteColor(size_t palette, BZPaletteColor colorIdx, BZPaletteColor color) {
655 gPalettes[(palette * gPaletteColorCount) + (colorIdx % gPaletteColorCount)] = color;
656 }
657
658 void bzSetGlobalViewMatrix(const BZMatrix *mtx) {
659 bzMatrixCopy(&globalViewMatrix, mtx);
660 }
661
662 //void bzSetGlobalLocalMatrix(const BZMatrix *mtx) {
663 // bzMatrixCopy(&globalLocalMatrix, mtx);
664 //}
665
666 //void bzSetGlobalBlendColor(BZPaletteColor color) {
667 // globalBlendColor = color;
668 //}
669
670 void bzSetOutputBuffer(size_t idx) {
671 bzAssert(idx >= 0 && idx < 4);
672
673 switch (idx) {
674 case 0:
675 currentBuffer = drawBuffer;
676 break;
677
678 case 1:
679 currentBuffer = paletteBuffer;
680 break;
681
682 case 2:
683 currentBuffer = maskBuffer;
684 break;
685
686 case 3:
687 currentBuffer = overlayBuffer;
688 break;
689
690 default: // FIXME
691 bzError("invalid output buffer");
692 break;
693 }
694 }
695
696 void bzGfxComposite() {
697 bzPerfTimerStart("game.blit.composite");
698
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];
707
708 ++drawBufferReadHead;
709 ++paletteBufferReadHead;
710 ++maskBufferReadHead;
711 ++overlayBufferReadHead;
712 ++outputBufferWriteHead;
713 }
714
715 bzPerfTimerStop("game.blit.composite");
716 }