all repos — mgba @ 63ed9bfe9138691759d3759364cb182ca09c0571

mGBA Game Boy Advance Emulator

src/gba/renderers/software-bg.c (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#include "software-private.h"
  7
  8#include "gba/gba.h"
  9
 10#define MODE_2_COORD_OVERFLOW \
 11	localX = x & (sizeAdjusted - 1); \
 12	localY = y & (sizeAdjusted - 1); \
 13
 14#define MODE_2_COORD_NO_OVERFLOW \
 15	if ((x | y) & ~(sizeAdjusted - 1)) { \
 16		continue; \
 17	} \
 18	localX = x; \
 19	localY = y;
 20
 21#define MODE_2_MOSAIC(COORD) \
 22		if (!mosaicWait) { \
 23			COORD \
 24			mapData = screenBase[(localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; \
 25			pixelData = charBase[(mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)]; \
 26			\
 27			mosaicWait = mosaicH; \
 28		} else { \
 29			--mosaicWait; \
 30		}
 31
 32#define MODE_2_NO_MOSAIC(COORD) \
 33	COORD \
 34	mapData = screenBase[(localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; \
 35	pixelData = charBase[(mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)];
 36
 37#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
 38	for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { \
 39		x += background->dx; \
 40		y += background->dy; \
 41		\
 42		uint32_t current = *pixel; \
 43		if (!IS_WRITABLE(current)) { \
 44			continue; \
 45		} \
 46		MOSAIC(COORD) \
 47		if (pixelData) { \
 48			COMPOSITE_256_ ## OBJWIN (BLEND); \
 49		} \
 50	}
 51
 52#define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \
 53	if (background->overflow) { \
 54		if (mosaicH > 1) { \
 55			MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
 56		} else { \
 57			MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
 58		} \
 59	} else { \
 60		if (mosaicH > 1) { \
 61			MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
 62		} else { \
 63			MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
 64		} \
 65	}
 66
 67void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
 68	int sizeAdjusted = 0x8000 << background->size;
 69
 70	BACKGROUND_BITMAP_INIT;
 71
 72	uint8_t* screenBase = &((uint8_t*) renderer->d.vram)[background->screenBase];
 73	uint8_t* charBase = &((uint8_t*) renderer->d.vram)[background->charBase];
 74	uint8_t mapData;
 75	uint8_t pixelData = 0;
 76
 77	int outX;
 78	uint32_t* pixel;
 79
 80	if (!objwinSlowPath) {
 81		if (!(flags & FLAG_TARGET_2)) {
 82			DRAW_BACKGROUND_MODE_2(NoBlend, NO_OBJWIN);
 83		} else {
 84			DRAW_BACKGROUND_MODE_2(Blend, NO_OBJWIN);
 85		}
 86	} else {
 87		if (!(flags & FLAG_TARGET_2)) {
 88			DRAW_BACKGROUND_MODE_2(NoBlend, OBJWIN);
 89		} else {
 90			DRAW_BACKGROUND_MODE_2(Blend, OBJWIN);
 91		}
 92	}
 93}
 94
 95void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
 96	BACKGROUND_BITMAP_INIT;
 97
 98	uint32_t color = renderer->normalPalette[0];
 99
100	int outX;
101	uint32_t* pixel;
102	for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
103		BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
104
105		if (!mosaicWait) {
106			LOAD_16(color, ((localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram);
107#ifndef COLOR_16_BIT
108			unsigned color32;
109			color32 = 0;
110			color32 |= (color << 3) & 0xF8;
111			color32 |= (color << 6) & 0xF800;
112			color32 |= (color << 9) & 0xF80000;
113			color = color32;
114#elif COLOR_5_6_5
115			uint16_t color16 = 0;
116			color16 |= (color & 0x001F) << 11;
117			color16 |= (color & 0x03E0) << 1;
118			color16 |= (color & 0x7C00) >> 10;
119			color = color16;
120#endif
121			mosaicWait = mosaicH;
122		} else {
123			--mosaicWait;
124		}
125
126		uint32_t current = *pixel;
127		if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
128			unsigned mergedFlags = flags;
129			if (current & FLAG_OBJWIN) {
130				mergedFlags = objwinFlags;
131			}
132			if (!variant) {
133				_compositeBlendObjwin(renderer, pixel, color | mergedFlags, current);
134			} else if (renderer->blendEffect == BLEND_BRIGHTEN) {
135				_compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current);
136			} else if (renderer->blendEffect == BLEND_DARKEN) {
137				_compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current);
138			}
139		}
140	}
141}
142
143void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
144	BACKGROUND_BITMAP_INIT;
145
146	uint16_t color = renderer->normalPalette[0];
147	uint32_t offset = 0;
148	if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
149		offset = 0xA000;
150	}
151
152	int outX;
153	uint32_t* pixel;
154	for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
155		BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
156
157		if (!mosaicWait) {
158			color = ((uint8_t*)renderer->d.vram)[offset + (localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS];
159
160			mosaicWait = mosaicH;
161		} else {
162			--mosaicWait;
163		}
164
165		uint32_t current = *pixel;
166		if (color && IS_WRITABLE(current)) {
167			if (!objwinSlowPath) {
168				_compositeBlendNoObjwin(renderer, pixel, palette[color] | flags, current);
169			} else if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) {
170				color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette;
171				unsigned mergedFlags = flags;
172				if (current & FLAG_OBJWIN) {
173					mergedFlags = objwinFlags;
174				}
175				_compositeBlendObjwin(renderer, pixel, currentPalette[color] | mergedFlags, current);
176			}
177		}
178	}
179}
180
181void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
182	BACKGROUND_BITMAP_INIT;
183
184	uint32_t color = renderer->normalPalette[0];
185	uint32_t offset = 0;
186	if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
187		offset = 0xA000;
188	}
189
190	int outX;
191	uint32_t* pixel;
192	for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
193		BACKGROUND_BITMAP_ITERATE(160, 128);
194
195		if (!mosaicWait) {
196			LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram);
197#ifndef COLOR_16_BIT
198			unsigned color32 = 0;
199			color32 |= (color << 9) & 0xF80000;
200			color32 |= (color << 3) & 0xF8;
201			color32 |= (color << 6) & 0xF800;
202			color = color32;
203#elif COLOR_5_6_5
204			uint16_t color16 = 0;
205			color16 |= (color & 0x001F) << 11;
206			color16 |= (color & 0x03E0) << 1;
207			color16 |= (color & 0x7C00) >> 10;
208			color = color16;
209#endif
210			mosaicWait = mosaicH;
211		} else {
212			--mosaicWait;
213		}
214
215		uint32_t current = *pixel;
216		if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
217			unsigned mergedFlags = flags;
218			if (current & FLAG_OBJWIN) {
219				mergedFlags = objwinFlags;
220			}
221			if (!variant) {
222				_compositeBlendObjwin(renderer, pixel, color | mergedFlags, current);
223			} else if (renderer->blendEffect == BLEND_BRIGHTEN) {
224				_compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current);
225			} else if (renderer->blendEffect == BLEND_DARKEN) {
226				_compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current);
227			}
228		}
229	}
230}