all repos — mgba @ 98f2d14b81b89bcc287ccf47722bfbd2fa917b27

mGBA Game Boy Advance Emulator

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 <mgba/internal/arm/macros.h>
 10#include <mgba/internal/gba/renderers/video-software.h>
 11
 12#ifdef NDEBUG
 13#define VIDEO_CHECKS false
 14#else
 15#define VIDEO_CHECKS true
 16#endif
 17
 18void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer,
 19                                                 struct GBAVideoSoftwareBackground* background, int y);
 20void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer,
 21                                                 struct GBAVideoSoftwareBackground* background, int y);
 22void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer,
 23                                                 struct GBAVideoSoftwareBackground* background, int y);
 24void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer,
 25                                                 struct GBAVideoSoftwareBackground* background, int y);
 26void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer,
 27                                                 struct GBAVideoSoftwareBackground* background, int y);
 28
 29int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int index, int y);
 30void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority);
 31
 32static inline unsigned _brighten(unsigned color, int y);
 33static inline unsigned _darken(unsigned color, int y);
 34static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB);
 35
 36
 37// We stash the priority on the top bits so we can do a one-operator comparison
 38// The lower the number, the higher the priority, and sprites take precedence over backgrounds
 39// We want to do special processing if the color pixel is target 1, however
 40
 41static inline void _compositeBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) {
 42	if (color >= current) {
 43		if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
 44			color = _mix(renderer->blda, current, renderer->bldb, color);
 45		} else {
 46			color = current & (0x00FFFFFF | FLAG_REBLEND | FLAG_OBJWIN);
 47		}
 48	} else {
 49		color = (color & ~FLAG_TARGET_2) | (current & FLAG_OBJWIN);
 50	}
 51	*pixel = color;
 52}
 53
 54static inline void _compositeBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) {
 55	if (color >= current) {
 56		if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) {
 57			color = _mix(renderer->blda, current, renderer->bldb, color);
 58		} else {
 59			color = current & (0x00FFFFFF | FLAG_REBLEND | FLAG_OBJWIN);
 60		}
 61	} else {
 62		color = color & ~FLAG_TARGET_2;
 63	}
 64	*pixel = color;
 65}
 66
 67static inline void _compositeNoBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color,
 68                                           uint32_t current) {
 69	UNUSED(renderer);
 70	if (color < current) {
 71		color |= (current & FLAG_OBJWIN);
 72	} else {
 73		color = current & (0x00FFFFFF | FLAG_REBLEND | FLAG_OBJWIN);
 74	}
 75	*pixel = color;
 76}
 77
 78static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color,
 79                                             uint32_t current) {
 80	UNUSED(renderer);
 81	if (color >= current) {
 82		color = current & (0x00FFFFFF | FLAG_REBLEND | FLAG_OBJWIN);
 83	}
 84	*pixel = color;
 85}
 86
 87#define COMPOSITE_16_OBJWIN(BLEND, IDX)  \
 88	if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) {                                          \
 89		unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[paletteData | pixelData] : palette[pixelData]; \
 90		unsigned mergedFlags = flags; \
 91		if (current & FLAG_OBJWIN) { \
 92			mergedFlags = objwinFlags; \
 93		} \
 94		_composite ## BLEND ## Objwin(renderer, &pixel[IDX], color | mergedFlags, current); \
 95	}
 96
 97#define COMPOSITE_16_NO_OBJWIN(BLEND, IDX) \
 98	_composite ## BLEND ## NoObjwin(renderer, &pixel[IDX], palette[pixelData] | flags, current);
 99
100#define COMPOSITE_256_OBJWIN(BLEND, IDX) \
101	if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \
102		unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[pixelData] : palette[pixelData]; \
103		unsigned mergedFlags = flags; \
104		if (current & FLAG_OBJWIN) { \
105			mergedFlags = objwinFlags; \
106		} \
107		_composite ## BLEND ## Objwin(renderer, &pixel[IDX], color | mergedFlags, current); \
108	}
109
110#define COMPOSITE_256_NO_OBJWIN COMPOSITE_16_NO_OBJWIN
111
112#define BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, IDX) \
113	pixelData = tileData & 0xF; \
114	current = pixel[IDX]; \
115	if (pixelData && IS_WRITABLE(current)) { \
116		COMPOSITE_16_ ## OBJWIN (BLEND, IDX); \
117	} \
118	tileData >>= 4;
119
120#define BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, IDX) \
121	pixelData = tileData & 0xFF; \
122	current = pixel[IDX]; \
123	if (pixelData && IS_WRITABLE(current)) { \
124		COMPOSITE_256_ ## OBJWIN (BLEND, IDX); \
125	} \
126	tileData >>= 8;
127
128// TODO: Remove UNUSEDs after implementing OBJWIN for modes 3 - 5
129#define PREPARE_OBJWIN                                                                            \
130	int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt);                     \
131	int objwinOnly = 0;                                                                           \
132	int objwinForceEnable = 0;                                                                    \
133	UNUSED(objwinForceEnable);                                                                    \
134	color_t* objwinPalette = renderer->normalPalette;                                             \
135	if (renderer->d.highlightAmount && background->highlight) {                                   \
136		objwinPalette = renderer->highlightPalette;                                               \
137	}                                                                                             \
138	UNUSED(objwinPalette);                                                                        \
139	if (objwinSlowPath) {                                                                         \
140		if (background->target1 && GBAWindowControlIsBlendEnable(renderer->objwin.packed) &&      \
141		    (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN)) { \
142			objwinPalette = renderer->variantPalette;                                             \
143			if (renderer->d.highlightAmount && background->highlight) {                           \
144				palette = renderer->highlightVariantPalette;                                      \
145			}                                                                                     \
146		}                                                                                         \
147		switch (background->index) {                                                              \
148		case 0:                                                                                   \
149			objwinForceEnable = GBAWindowControlIsBg0Enable(renderer->objwin.packed) &&           \
150			    GBAWindowControlIsBg0Enable(renderer->currentWindow.packed);                      \
151			objwinOnly = !GBAWindowControlIsBg0Enable(renderer->objwin.packed);                   \
152			break;                                                                                \
153		case 1:                                                                                   \
154			objwinForceEnable = GBAWindowControlIsBg1Enable(renderer->objwin.packed) &&           \
155			    GBAWindowControlIsBg1Enable(renderer->currentWindow.packed);                      \
156			objwinOnly = !GBAWindowControlIsBg1Enable(renderer->objwin.packed);                   \
157			break;                                                                                \
158		case 2:                                                                                   \
159			objwinForceEnable = GBAWindowControlIsBg2Enable(renderer->objwin.packed) &&           \
160			    GBAWindowControlIsBg2Enable(renderer->currentWindow.packed);                      \
161			objwinOnly = !GBAWindowControlIsBg2Enable(renderer->objwin.packed);                   \
162			break;                                                                                \
163		case 3:                                                                                   \
164			objwinForceEnable = GBAWindowControlIsBg3Enable(renderer->objwin.packed) &&           \
165			    GBAWindowControlIsBg3Enable(renderer->currentWindow.packed);                      \
166			objwinOnly = !GBAWindowControlIsBg3Enable(renderer->objwin.packed);                   \
167			break;                                                                                \
168		}                                                                                         \
169	}
170
171static inline unsigned _brighten(unsigned color, int y) {
172	unsigned c = 0;
173	unsigned a;
174#ifdef COLOR_16_BIT
175	a = color & 0x1F;
176	c |= (a + ((0x1F - a) * y) / 16) & 0x1F;
177
178#ifdef COLOR_5_6_5
179	a = color & 0x7C0;
180	c |= (a + ((0x7C0 - a) * y) / 16) & 0x7C0;
181
182	a = color & 0xF800;
183	c |= (a + ((0xF800 - a) * y) / 16) & 0xF800;
184#else
185	a = color & 0x3E0;
186	c |= (a + ((0x3E0 - a) * y) / 16) & 0x3E0;
187
188	a = color & 0x7C00;
189	c |= (a + ((0x7C00 - a) * y) / 16) & 0x7C00;
190#endif
191#else
192	a = color & 0xFF;
193	c |= (a + ((0xFF - a) * y) / 16) & 0xFF;
194
195	a = color & 0xFF00;
196	c |= (a + ((0xFF00 - a) * y) / 16) & 0xFF00;
197
198	a = color & 0xFF0000;
199	c |= (a + ((0xFF0000 - a) * y) / 16) & 0xFF0000;
200#endif
201	return c;
202}
203
204static inline unsigned _darken(unsigned color, int y) {
205	unsigned c = 0;
206	unsigned a;
207#ifdef COLOR_16_BIT
208	a = color & 0x1F;
209	c |= (a - (a * y) / 16) & 0x1F;
210
211#ifdef COLOR_5_6_5
212	a = color & 0x7C0;
213	c |= (a - (a * y) / 16) & 0x7C0;
214
215	a = color & 0xF800;
216	c |= (a - (a * y) / 16) & 0xF800;
217#else
218	a = color & 0x3E0;
219	c |= (a - (a * y) / 16) & 0x3E0;
220
221	a = color & 0x7C00;
222	c |= (a - (a * y) / 16) & 0x7C00;
223#endif
224#else
225	a = color & 0xFF;
226	c |= (a - (a * y) / 16) & 0xFF;
227
228	a = color & 0xFF00;
229	c |= (a - (a * y) / 16) & 0xFF00;
230
231	a = color & 0xFF0000;
232	c |= (a - (a * y) / 16) & 0xFF0000;
233#endif
234	return c;
235}
236
237static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB) {
238	unsigned c = 0;
239	unsigned a, b;
240#ifdef COLOR_16_BIT
241#ifdef COLOR_5_6_5
242	a = colorA & 0xF81F;
243	b = colorB & 0xF81F;
244	a |= (colorA & 0x7C0) << 16;
245	b |= (colorB & 0x7C0) << 16;
246	c = ((a * weightA + b * weightB) / 16);
247	if (c & 0x08000000) {
248		c = (c & ~0x0FC00000) | 0x07C00000;
249	}
250	if (c & 0x0020) {
251		c = (c & ~0x003F) | 0x001F;
252	}
253	if (c & 0x10000) {
254		c = (c & ~0x1F800) | 0xF800;
255	}
256	c = (c & 0xF81F) | ((c >> 16) & 0x07C0);
257#else
258	a = colorA & 0x7C1F;
259	b = colorB & 0x7C1F;
260	a |= (colorA & 0x3E0) << 16;
261	b |= (colorB & 0x3E0) << 16;
262	c = ((a * weightA + b * weightB) / 16);
263	if (c & 0x04000000) {
264		c = (c & ~0x07E00000) | 0x03E00000;
265	}
266	if (c & 0x0020) {
267		c = (c & ~0x003F) | 0x001F;
268	}
269	if (c & 0x8000) {
270		c = (c & ~0xF800) | 0x7C00;
271	}
272	c = (c & 0x7C1F) | ((c >> 16) & 0x03E0);
273#endif
274#else
275	a = colorA & 0xFF;
276	b = colorB & 0xFF;
277	c |= ((a * weightA + b * weightB) / 16) & 0x1FF;
278	if (c & 0x00000100) {
279		c = 0x000000FF;
280	}
281
282	a = colorA & 0xFF00;
283	b = colorB & 0xFF00;
284	c |= ((a * weightA + b * weightB) / 16) & 0x1FF00;
285	if (c & 0x00010000) {
286		c = (c & 0x000000FF) | 0x0000FF00;
287	}
288
289	a = colorA & 0xFF0000;
290	b = colorB & 0xFF0000;
291	c |= ((a * weightA + b * weightB) / 16) & 0x1FF0000;
292	if (c & 0x01000000) {
293		c = (c & 0x0000FFFF) | 0x00FF0000;
294	}
295#endif
296	return c;
297}
298
299#endif