]> git.bts.cx Git - benzene.git/blob - src/bz/gfx/gfx.c
0f26e3bdb0193a74843996e9d6a2688bb2adedd0
[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
79 //static uint8_t spritesheet[SS_HEIGHT][SS_WIDTH];
80 static uint8_t *spritesheet = NULL;
81
82 static BZFont *currentFont;
83
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},
93 };*/
94
95 static size_t gPaletteCount;
96 static size_t gPaletteColorCount;
97 static uint8_t *gPalettes;
98
99 //BZRect bzCalculateCullRect() {
100 // return bzRectMake(cameraX, cameraY, canvasWidth, SS_HEIGHT);
101 //}
102
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));
107
108 for (size_t p = 0, i = 0; p < gPaletteCount; ++p) {
109 for (size_t c = 0; c < gPaletteColorCount; ++c, ++i) {
110 gPalettes[i] = c;
111 }
112 }
113 }
114
115 void bzGfxPrepareCanvasBuffer(BZMemoryArenaID arena, size_t width, size_t height) {
116 canvasWidth = width;
117 canvasHeight = height;
118
119 bufferStrideShift = __SIZE_WIDTH__ - __builtin_clzl(canvasWidth - 1);
120 bufferStride = 1 << bufferStrideShift;
121
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);
128
129 bzSetOutputBuffer(0);
130
131 bzLog("Data: %d %d %d %d", canvasWidth, canvasMemorySize, bufferStrideShift, bufferStride);
132 }
133
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);
137
138 size_t spritesheetMemorySize = width * height * sizeof(uint8_t);
139 spritesheet = bzMemoryAlloc(arena, spritesheetMemorySize);
140 memcpy(spritesheet, data, spritesheetMemorySize);
141 }
142
143 void bzGfxPrepareFont(BZMemoryArenaID arena, void *font) {
144 currentFont = font;
145 }
146
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;
150
151 if (x1 < x0) {
152 xMin = x1;
153 xMax = x0;
154 }
155
156 if (y1 < y0) {
157 yMin = y1;
158 yMax = y0;
159 }
160
161 int xMinOut = xMin/* - cameraX*/, xMaxOut = xMax/* - cameraX*/;
162 int yMinOut = yMin/* - cameraY*/, yMaxOut = yMax/* - cameraY*/;
163
164 if (xMaxOut < 0 || yMaxOut < 0 || xMinOut >= canvasWidth || yMinOut >= canvasHeight) {
165 return false;
166 }
167
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);
172
173 *minXOut = safeXMinOut;
174 *minYOut = safeYMinOut;
175 *maxXOut = safeXMaxOut;
176 *maxYOut = safeYMaxOut;
177
178 if (clippedLeftX != NULL) {
179 *clippedLeftX = safeXMinOut - xMinOut;
180 *clippedTopY = safeYMinOut - yMinOut;
181
182 *clippedRightX = xMaxOut - safeXMaxOut;
183 *clippedBottomY = yMaxOut - safeYMaxOut;
184 }
185
186 return true;
187 }
188
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);
198 return true;
199 }
200
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;
207 }
208
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));
213 return *rOut > 0;
214 }
215
216 static bool prepareColor(int *colorOut, int color) {
217 *colorOut = gPalettes[color % gPaletteColorCount]; // FIXME
218 return true;
219 /*int c = (color < gPaletteColorCount) ? gPalettes[color] : color;
220 if (c > 0) {
221 *colorOut = c & globalBlendColor;
222 return true;
223 } else {
224 return false;
225 }*/
226 }
227
228 void bzPSet(BZCoordinate x, BZCoordinate y, BZPaletteColor c) {
229 //if (c == 0) return;
230
231 //c = ((c < gPaletteColorCount) ? gPalettes[c] : c);
232
233 prepareColor(&c, c);
234
235 int ox, oy;
236 preparePositionXY(&ox, &oy, x, y);
237 if (ox >= 0 && ox < canvasWidth && oy >=0 && oy < canvasHeight) {
238 bzBufferSet(currentBuffer, ox, oy, c);
239 }
240 }
241
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];
246 } else {
247 return 0;
248 }
249 }
250
251 //void bzSSet(int x, int y, int c);
252
253 //bool bzFGet(int n, int f);
254 //void bzFSet(int n, int f, bool v);
255
256 void bzCls(BZPaletteColor c) {
257 memset(currentBuffer, c, bufferStride * canvasHeight);
258
259 //memset(&buffer[currentBuffer], c, BUFFER_WIDTH * canvasHeight);
260
261 // for (size_t i = 0; i < )
262
263 // for (size_t y = 0; y < canvasHeight; ++y) {
264 // for (size_t x = 0; x < canvasWidth; ++x) {
265 // bzBufferSet(currentBuffer, x, y, c);
266 // }
267 // }
268
269 //bzCamera(0, 0);
270 bzFillP(0x0000);
271 }
272
273 void bzGetCamera(BZCoordinate *x, BZCoordinate *y) {
274 if (x != NULL) *x = cameraX;
275 if (y != NULL) *y = cameraY;
276 }
277
278 void bzCamera(BZCoordinate x, BZCoordinate y) {
279 cameraX = x;
280 cameraY = y;
281 cameraXInt = bzFloor(cameraX);
282 cameraYInt = bzFloor(cameraY);
283 }
284
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)) {
288 int x = -or;
289 int y = 0;
290 int err = 2 - 2 * or;
291
292 do {
293 int x0 = oxm-x;
294 int y0 = oym+y;
295 if (x0 >= 0 && x0 < canvasWidth && y0 >=0 && y0 < canvasHeight) { // FIXME, easier way to offset this...
296 bzBufferSet(currentBuffer, x0, y0, cOut);
297 }
298
299 int x1 = oxm-y;
300 int y1 = oym-x;
301 if (x1 >= 0 && x1 < canvasWidth && y1 >=0 && y1 < canvasHeight) { // FIXME, easier way to offset this...
302 bzBufferSet(currentBuffer, x1, y1, cOut);
303 }
304
305 int x2 = oxm+x;
306 int y2 = oym-y;
307 if (x2 >= 0 && x2 < canvasWidth && y2 >=0 && y2 < canvasHeight) { // FIXME, easier way to offset this...
308 bzBufferSet(currentBuffer, x2, y2, cOut);
309 }
310
311 int x3 = oxm+y;
312 int y3 = oym+x;
313 if (x3 >= 0 && x3 < canvasWidth && y3 >=0 && y3 < canvasHeight) { // FIXME, easier way to offset this...
314 bzBufferSet(currentBuffer, x3, y3, cOut);
315 }
316
317 or = err;
318
319 if (or <= y) err += (++y << 1) + 1;
320 if (or > x || err > y) err += (++x << 1) + 1;
321 } while (x <= 0);
322 }
323 }
324
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)) {
328 int x = -or;
329 int y = 0;
330 int err = 2 - 2 * or;
331
332 do {
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
337
338 bool validFy1 = fy1 >= 0 && fy1 < canvasHeight;
339 bool validFy2 = fy2 >= 0 && fy2 < canvasHeight;
340
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);
345 }
346 } else if (validFy1) {
347 for (int px = fx; px <= tx; ++px) {
348 bzBufferSet(currentBuffer, px, fy1, cOut);
349 }
350 } else if (validFy2) {
351 for (int px = fx; px <= tx; ++px) {
352 bzBufferSet(currentBuffer, px, fy2, cOut);
353 }
354 }
355
356 or = err;
357
358 if (or <= y) err += (++y << 1) + 1;
359 if (or > x || err > y) err += (++x << 1) + 1;
360 } while (x <= 0);
361 }
362 }
363
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);
366
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)
371
372 for (;;) {
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);
375 }
376
377 bresenhamStep(line_)
378 }
379 }
380 }
381
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);
389 }
390 } else if (clipLeft == 0) {
391 for (int py = yMinOut; py <= yMaxOut; ++py) {
392 bzBufferSet(currentBuffer, xMinOut, py, cOut);
393 }
394 } else if (clipRight == 0) {
395 for (int py = yMinOut; py <= yMaxOut; ++py) {
396 bzBufferSet(currentBuffer, xMaxOut, py, cOut);
397 }
398 }
399
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);
404 }
405 } else if (clipTop == 0) {
406 for (int px = xMinOut; px <= xMaxOut; ++px) {
407 bzBufferSet(currentBuffer, px, yMinOut, cOut);
408 }
409 } else if (clipBottom == 0) {
410 for (int px = xMinOut; px <= xMaxOut; ++px) {
411 bzBufferSet(currentBuffer, px, yMaxOut, cOut);
412 }
413 }
414 }
415 }
416
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);
423 }
424 }
425 }
426 }
427
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;
430
431 preparePositionXY(&ox0, &oy0, x0, y0);
432 preparePositionXY(&ox1, &oy1, x1, y1);
433 preparePositionXY(&ox2, &oy2, x2, y2);
434
435 if (oy2 < oy1 || (oy2 == oy1 && ox2 < ox1)) {
436 swap(ox1, ox2);
437 swap(oy1, oy2);
438 }
439
440 // after this, x0&y0 are always the smallest
441 if (oy1 < oy0 || (oy1 == oy0 && ox1 < ox0)) {
442 swap(ox0, ox1);
443 swap(oy0, oy1);
444 }
445
446 // one final comparison to swap for mid values
447 if (oy2 < oy1 || (oy2 == oy1 && ox2 < ox1)) {
448 swap(ox1, ox2);
449 swap(oy1, oy2);
450 }
451
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);
455
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)
461
462 for (;;) {
463 int targetY = triangleLow_y;
464
465 int fromX1 = triangleLow_x, fromX2 = triangleLow_x;
466 while (triangleLow_y == targetY) {
467 fromX1 = triangleLow_x, fromX2 = triangleLow_x;
468 bresenhamStep(triangleLow_)
469 }
470
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_)
476 }
477
478 if (targetY >=0 && targetY < canvasHeight) {
479 int fromX, toX;
480
481 if (fromX1 < toX2) {
482 fromX = bzMin(fromX1, fromX2);
483 toX = bzMax(toX1, toX2);
484 } else {
485 fromX = bzMin(toX1, toX2);
486 toX = bzMax(fromX1, fromX2);
487 }
488
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));
492
493 for (int x = fromX; x <= toX; ++x) {
494 bzBufferSet(currentBuffer, x, targetY, cOut);
495 }
496 }
497 }
498
499 if (targetY >= oy1) {
500 break;
501 }
502 }
503
504 for (;;) {
505 int targetY = triangleMid_y;
506
507 int fromX1 = triangleMid_x, fromX2 = triangleMid_x;
508 while (triangleMid_y == targetY) {
509 fromX1 = triangleMid_x, fromX2 = triangleMid_x;
510 bresenhamStep(triangleMid_)
511 }
512
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_)
518 }
519
520 if (targetY >=0 && targetY < canvasHeight) {
521 int fromX, toX;
522
523 if (fromX1 < toX2) {
524 fromX = bzMin(fromX1, fromX2);
525 toX = bzMax(toX1, toX2);
526 } else {
527 fromX = bzMin(toX1, toX2);
528 toX = bzMax(fromX1, fromX2);
529 }
530
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));
534
535 for (int x = fromX; x <= toX; ++x) {
536 bzBufferSet(currentBuffer, x, targetY, cOut);
537 }
538 }
539 }
540
541 if (targetY >= oy2) {
542 break;
543 }
544 }
545 }
546 }
547
548 void bzSpr(size_t n, BZCoordinate x, BZCoordinate y) {
549 bzSprExt(n, x, y, 1, 1, false, false);
550 }
551
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;
555 int pw = w * 8;
556 int ph = h * 8;
557 bzSSprExt(px, py, pw, ph, x, y, pw, ph, flipX, flipY);
558 }
559
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);
562 }
563
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);
572
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??
577 }
578 }
579 }
580
581 /*int fromX = 0;
582 int toX = sw;
583 int dX = 1;
584
585 if (flipX) {
586 fromX = toX - 1;
587 toX = -1;
588 dX = -1;
589 }
590
591 int fromY = 0;
592 int toY = sh;
593 int dY = 1;
594
595 if (flipY) {
596 fromY = toY - 1;
597 toY = -1;
598 dY = -1;
599 }
600
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));
604 }
605 }*/
606 }
607
608 void bzFillP(BZPattern p) {
609 fillPattern = ~p;
610 }
611
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);
615 prepareColor(&c, c);
616 bzBufferSet(currentBuffer, x, y, c);
617 }
618 }
619
620 void bzPrint(BZCoordinate x, BZCoordinate y, BZPaletteColor color, const char *text) {
621 int ox, oy;
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
627 //}
628 }
629
630 void bzSetPaletteColor(size_t palette, BZPaletteColor colorIdx, BZPaletteColor color) {
631 gPalettes[(palette * gPaletteColorCount) + (colorIdx % gPaletteColorCount)] = color;
632 }
633
634 void bzSetGlobalViewMatrix(const BZMatrix *mtx) {
635 bzMatrixCopy(&globalViewMatrix, mtx);
636 }
637
638 //void bzSetGlobalLocalMatrix(const BZMatrix *mtx) {
639 // bzMatrixCopy(&globalLocalMatrix, mtx);
640 //}
641
642 //void bzSetGlobalBlendColor(BZPaletteColor color) {
643 // globalBlendColor = color;
644 //}
645
646 void bzSetOutputBuffer(size_t idx) {
647 bzAssert(idx >= 0 && idx < 4);
648
649 switch (idx) {
650 case 0:
651 currentBuffer = drawBuffer;
652 break;
653
654 case 1:
655 currentBuffer = paletteBuffer;
656 break;
657
658 case 2:
659 currentBuffer = maskBuffer;
660 break;
661
662 case 3:
663 currentBuffer = overlayBuffer;
664 break;
665
666 default: // FIXME
667 bzError("invalid output buffer");
668 break;
669 }
670 }
671
672 void bzGfxComposite() {
673 bzPerfTimerStart("game.blit.composite");
674
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];
683
684 ++drawBufferReadHead;
685 ++paletteBufferReadHead;
686 ++maskBufferReadHead;
687 ++overlayBufferReadHead;
688 ++outputBufferWriteHead;
689 }
690
691 bzPerfTimerStop("game.blit.composite");
692 }