all repos — mgba @ 09c46ca2c4e019d25e5e0301db738d557605e105

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