all repos — mgba @ 0293e723d805c3255c2873f4a1cb9de0128ee217

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