all repos — mgba @ 17759173f2898b1caf4259fa5e4b7e46ecd6f3c2

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