src/gba/renderers/software-private.h (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#ifndef SOFTWARE_PRIVATE_H
7#define SOFTWARE_PRIVATE_H
8
9#include "video-software.h"
10
11#ifdef NDEBUG
12#define VIDEO_CHECKS false
13#else
14#define VIDEO_CHECKS true
15#endif
16
17void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y);
18void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y);
19void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y);
20void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y);
21void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y);
22
23int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y);
24void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority);
25
26static inline unsigned _brighten(unsigned color, int y);
27static inline unsigned _darken(unsigned color, int y);
28static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB);
29
30
31// We stash the priority on the top bits so we can do a one-operator comparison
32// The lower the number, the higher the priority, and sprites take precendence over backgrounds
33// We want to do special processing if the color pixel is target 1, however
34
35static inline void _compositeBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) {
36 if (color >= current) {
37 if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
38 color = _mix(renderer->blda, current, renderer->bldb, color);
39 } else {
40 color = current & 0x00FFFFFF;
41 }
42 } else {
43 color = (color & ~FLAG_TARGET_2) | (current & FLAG_OBJWIN);
44 }
45 *pixel = color;
46}
47
48static inline void _compositeBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) {
49 if (color >= current) {
50 if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
51 color = _mix(renderer->blda, current, renderer->bldb, color);
52 } else {
53 color = current & 0x00FFFFFF;
54 }
55 } else {
56 color = color & ~FLAG_TARGET_2;
57 }
58 *pixel = color;
59}
60
61static inline void _compositeNoBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) {
62 UNUSED(renderer);
63 if (color < current) {
64 *pixel = color | (current & FLAG_OBJWIN);
65 }
66}
67
68static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) {
69 UNUSED(renderer);
70 if (color < current) {
71 *pixel = color;
72 }
73}
74
75#define COMPOSITE_16_OBJWIN(BLEND) \
76 if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \
77 unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[paletteData | pixelData] : palette[pixelData]; \
78 unsigned mergedFlags = flags; \
79 if (current & FLAG_OBJWIN) { \
80 mergedFlags = objwinFlags; \
81 } \
82 _composite ## BLEND ## Objwin(renderer, pixel, color | mergedFlags, current); \
83 }
84
85#define COMPOSITE_16_NO_OBJWIN(BLEND) \
86 _composite ## BLEND ## NoObjwin(renderer, pixel, palette[pixelData] | flags, current);
87
88#define COMPOSITE_256_OBJWIN(BLEND) \
89 if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \
90 unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[pixelData] : palette[pixelData]; \
91 unsigned mergedFlags = flags; \
92 if (current & FLAG_OBJWIN) { \
93 mergedFlags = objwinFlags; \
94 } \
95 _composite ## BLEND ## Objwin(renderer, pixel, color | mergedFlags, current); \
96 }
97
98#define COMPOSITE_256_NO_OBJWIN(BLEND) \
99 COMPOSITE_16_NO_OBJWIN(BLEND)
100
101#define BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN) \
102 pixelData = tileData & 0xF; \
103 current = *pixel; \
104 if (pixelData && IS_WRITABLE(current)) { \
105 COMPOSITE_16_ ## OBJWIN (BLEND); \
106 } \
107 tileData >>= 4;
108
109#define BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN) \
110 pixelData = tileData & 0xFF; \
111 current = *pixel; \
112 if (pixelData && IS_WRITABLE(current)) { \
113 COMPOSITE_256_ ## OBJWIN (BLEND); \
114 } \
115 tileData >>= 8;
116
117// TODO: Remove UNUSEDs after implementing OBJWIN for modes 3 - 5
118#define PREPARE_OBJWIN \
119 int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); \
120 int objwinOnly = 0; \
121 int objwinForceEnable = 0; \
122 UNUSED(objwinForceEnable); \
123 color_t* objwinPalette = renderer->normalPalette; \
124 UNUSED(objwinPalette); \
125 if (objwinSlowPath) { \
126 if (background->target1 && GBAWindowControlIsBlendEnable(renderer->objwin.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN)) { \
127 objwinPalette = renderer->variantPalette; \
128 } \
129 switch (background->index) { \
130 case 0: \
131 objwinForceEnable = GBAWindowControlIsBg0Enable(renderer->objwin.packed) && GBAWindowControlIsBg0Enable(renderer->currentWindow.packed); \
132 objwinOnly = !GBAWindowControlIsBg0Enable(renderer->objwin.packed); \
133 break; \
134 case 1: \
135 objwinForceEnable = GBAWindowControlIsBg1Enable(renderer->objwin.packed) && GBAWindowControlIsBg1Enable(renderer->currentWindow.packed); \
136 objwinOnly = !GBAWindowControlIsBg1Enable(renderer->objwin.packed); \
137 break; \
138 case 2: \
139 objwinForceEnable = GBAWindowControlIsBg2Enable(renderer->objwin.packed) && GBAWindowControlIsBg2Enable(renderer->currentWindow.packed); \
140 objwinOnly = !GBAWindowControlIsBg2Enable(renderer->objwin.packed); \
141 break; \
142 case 3: \
143 objwinForceEnable = GBAWindowControlIsBg3Enable(renderer->objwin.packed) && GBAWindowControlIsBg3Enable(renderer->currentWindow.packed); \
144 objwinOnly = !GBAWindowControlIsBg3Enable(renderer->objwin.packed); \
145 break; \
146 } \
147 }
148
149#define BACKGROUND_BITMAP_INIT \
150 int32_t x = background->sx + (renderer->start - 1) * background->dx; \
151 int32_t y = background->sy + (renderer->start - 1) * background->dy; \
152 int mosaicH = 0; \
153 int mosaicWait = 0; \
154 if (background->mosaic) { \
155 int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
156 y -= (inY % mosaicV) * background->dmy; \
157 x -= (inY % mosaicV) * background->dmx; \
158 mosaicH = GBAMosaicControlGetBgH(renderer->mosaic); \
159 mosaicWait = renderer->start % (mosaicH + 1); \
160 } \
161 int32_t localX; \
162 int32_t localY; \
163 \
164 int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
165 flags |= FLAG_TARGET_2 * background->target2; \
166 int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \
167 objwinFlags |= flags; \
168 flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); \
169 if (renderer->blda == 0x10 && renderer->bldb == 0) { \
170 flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
171 objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
172 } \
173 int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \
174 color_t* palette = renderer->normalPalette; \
175 if (variant) { \
176 palette = renderer->variantPalette; \
177 } \
178 UNUSED(palette); \
179 PREPARE_OBJWIN;
180
181#define BACKGROUND_BITMAP_ITERATE(W, H) \
182 x += background->dx; \
183 y += background->dy; \
184 \
185 if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \
186 continue; \
187 } else { \
188 localX = x; \
189 localY = y; \
190 }
191
192static inline unsigned _brighten(unsigned color, int y) {
193 unsigned c = 0;
194 unsigned a;
195#ifdef COLOR_16_BIT
196 a = color & 0x1F;
197 c |= (a + ((0x1F - a) * y) / 16) & 0x1F;
198
199#ifdef COLOR_5_6_5
200 a = color & 0x7C0;
201 c |= (a + ((0x7C0 - a) * y) / 16) & 0x7C0;
202
203 a = color & 0xF800;
204 c |= (a + ((0xF800 - a) * y) / 16) & 0xF800;
205#else
206 a = color & 0x3E0;
207 c |= (a + ((0x3E0 - a) * y) / 16) & 0x3E0;
208
209 a = color & 0x7C00;
210 c |= (a + ((0x7C00 - a) * y) / 16) & 0x7C00;
211#endif
212#else
213 a = color & 0xF8;
214 c |= (a + ((0xF8 - a) * y) / 16) & 0xF8;
215
216 a = color & 0xF800;
217 c |= (a + ((0xF800 - a) * y) / 16) & 0xF800;
218
219 a = color & 0xF80000;
220 c |= (a + ((0xF80000 - a) * y) / 16) & 0xF80000;
221#endif
222 return c;
223}
224
225static inline unsigned _darken(unsigned color, int y) {
226 unsigned c = 0;
227 unsigned a;
228#ifdef COLOR_16_BIT
229 a = color & 0x1F;
230 c |= (a - (a * y) / 16) & 0x1F;
231
232#ifdef COLOR_5_6_5
233 a = color & 0x7C0;
234 c |= (a - (a * y) / 16) & 0x7C0;
235
236 a = color & 0xF800;
237 c |= (a - (a * y) / 16) & 0xF800;
238#else
239 a = color & 0x3E0;
240 c |= (a - (a * y) / 16) & 0x3E0;
241
242 a = color & 0x7C00;
243 c |= (a - (a * y) / 16) & 0x7C00;
244#endif
245#else
246 a = color & 0xF8;
247 c |= (a - (a * y) / 16) & 0xF8;
248
249 a = color & 0xF800;
250 c |= (a - (a * y) / 16) & 0xF800;
251
252 a = color & 0xF80000;
253 c |= (a - (a * y) / 16) & 0xF80000;
254#endif
255 return c;
256}
257
258static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB) {
259 unsigned c = 0;
260 unsigned a, b;
261#ifdef COLOR_16_BIT
262#ifdef COLOR_5_6_5
263 a = colorA & 0xF81F;
264 b = colorB & 0xF81F;
265 a |= (colorA & 0x7C0) << 16;
266 b |= (colorB & 0x7C0) << 16;
267 c = ((a * weightA + b * weightB) / 16);
268 if (c & 0x08000000) {
269 c = (c & ~0x0FC00000) | 0x07C00000;
270 }
271 if (c & 0x0020) {
272 c = (c & ~0x003F) | 0x001F;
273 }
274 if (c & 0x10000) {
275 c = (c & ~0x1F800) | 0xF800;
276 }
277 c = (c & 0xF81F) | ((c >> 16) & 0x07C0);
278#else
279 a = colorA & 0x7C1F;
280 b = colorB & 0x7C1F;
281 a |= (colorA & 0x3E0) << 16;
282 b |= (colorB & 0x3E0) << 16;
283 c = ((a * weightA + b * weightB) / 16);
284 if (c & 0x04000000) {
285 c = (c & ~0x07E00000) | 0x03E00000;
286 }
287 if (c & 0x0020) {
288 c = (c & ~0x003F) | 0x001F;
289 }
290 if (c & 0x10000) {
291 c = (c & ~0x1F800) | 0xF800;
292 }
293 c = (c & 0x7C1F) | ((c >> 16) & 0x03E0);
294#endif
295#else
296 a = colorA & 0xF8;
297 b = colorB & 0xF8;
298 c |= ((a * weightA + b * weightB) / 16) & 0x1F8;
299 if (c & 0x00000100) {
300 c = 0x000000F8;
301 }
302
303 a = colorA & 0xF800;
304 b = colorB & 0xF800;
305 c |= ((a * weightA + b * weightB) / 16) & 0x1F800;
306 if (c & 0x00010000) {
307 c = (c & 0x000000F8) | 0x0000F800;
308 }
309
310 a = colorA & 0xF80000;
311 b = colorB & 0xF80000;
312 c |= ((a * weightA + b * weightB) / 16) & 0x1F80000;
313 if (c & 0x01000000) {
314 c = (c & 0x0000F8F8) | 0x00F80000;
315 }
316#endif
317 return c;
318}
319
320#endif