all repos — mgba @ c62d913e233e7ea3bb23a3f52fcb7b481f2faed5

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	uint8_t* screenBlock = (uint8_t*) renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET]; \
 37	if (UNLIKELY(!screenBlock)) { \
 38		mapData = 0; \
 39	} else { \
 40		mapData = screenBlock[screenBase & VRAM_BLOCK_MASK]; \
 41	} \
 42	uint32_t charBase = background->charBase + (mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8); \
 43	pixelData = ((uint8_t*) renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET])[charBase & VRAM_BLOCK_MASK]; \
 44
 45#define MODE_2_MOSAIC(COORD) \
 46		if (!mosaicWait) { \
 47			MODE_2_NO_MOSAIC(COORD)	\
 48			mosaicWait = mosaicH; \
 49		} else { \
 50			--mosaicWait; \
 51		}
 52
 53#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
 54	for (outX = renderer->start; outX < renderer->end; ++outX) { \
 55		x += background->dx; \
 56		y += background->dy; \
 57		\
 58		uint32_t current = renderer->row[outX]; \
 59		MOSAIC(COORD) \
 60		if (pixelData) { \
 61			COMPOSITE_256_ ## OBJWIN (BLEND, 0); \
 62		} \
 63	}
 64
 65#define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \
 66	if (background->overflow) { \
 67		if (mosaicH > 1) { \
 68			MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
 69		} else { \
 70			MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
 71		} \
 72	} else { \
 73		if (mosaicH > 1) { \
 74			MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
 75		} else { \
 76			MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
 77		} \
 78	}
 79
 80void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
 81	int sizeAdjusted = 0x8000 << background->size;
 82
 83	BACKGROUND_BITMAP_INIT;
 84
 85	uint8_t mapData;
 86	uint8_t pixelData = 0;
 87
 88	int outX;
 89
 90	if (!objwinSlowPath) {
 91		if (!(flags & FLAG_TARGET_2)) {
 92			DRAW_BACKGROUND_MODE_2(NoBlend, NO_OBJWIN);
 93		} else {
 94			DRAW_BACKGROUND_MODE_2(Blend, NO_OBJWIN);
 95		}
 96	} else {
 97		if (!(flags & FLAG_TARGET_2)) {
 98			DRAW_BACKGROUND_MODE_2(NoBlend, OBJWIN);
 99		} else {
100			DRAW_BACKGROUND_MODE_2(Blend, OBJWIN);
101		}
102	}
103}
104
105void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
106	BACKGROUND_BITMAP_INIT;
107
108	uint32_t color = renderer->normalPalette[0];
109
110	int outX;
111	for (outX = renderer->start; outX < renderer->end; ++outX) {
112		BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_VIDEO_VERTICAL_PIXELS);
113
114		if (!mosaicWait) {
115			LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
116			color = mColorFrom555(color);
117			mosaicWait = mosaicH;
118		} else {
119			--mosaicWait;
120		}
121
122		uint32_t current = renderer->row[outX];
123		if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
124			unsigned mergedFlags = flags;
125			if (current & FLAG_OBJWIN) {
126				mergedFlags = objwinFlags;
127			}
128			if (!variant) {
129				_compositeBlendObjwin(renderer, outX, color | mergedFlags, current);
130			} else if (renderer->blendEffect == BLEND_BRIGHTEN) {
131				_compositeBlendObjwin(renderer, outX, _brighten(color, renderer->bldy) | mergedFlags, current);
132			} else if (renderer->blendEffect == BLEND_DARKEN) {
133				_compositeBlendObjwin(renderer, outX, _darken(color, renderer->bldy) | mergedFlags, current);
134			}
135		}
136	}
137}
138
139void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
140	BACKGROUND_BITMAP_INIT;
141
142	uint16_t color = 0;
143	uint32_t offset = 0;
144	if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
145		offset = 0xA000;
146	}
147
148	int outX;
149	for (outX = renderer->start; outX < renderer->end; ++outX) {
150		BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_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 = renderer->row[outX];
161		if (color && IS_WRITABLE(current)) {
162			if (!objwinSlowPath) {
163				_compositeBlendNoObjwin(renderer, outX, 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, outX, 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	for (outX = renderer->start; outX < renderer->end; ++outX) {
187		BACKGROUND_BITMAP_ITERATE(160, 128);
188
189		if (!mosaicWait) {
190			LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vramBG[0]);
191			color = mColorFrom555(color);
192			mosaicWait = mosaicH;
193		} else {
194			--mosaicWait;
195		}
196
197		uint32_t current = renderer->row[outX];
198		if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
199			unsigned mergedFlags = flags;
200			if (current & FLAG_OBJWIN) {
201				mergedFlags = objwinFlags;
202			}
203			if (!variant) {
204				_compositeBlendObjwin(renderer, outX, color | mergedFlags, current);
205			} else if (renderer->blendEffect == BLEND_BRIGHTEN) {
206				_compositeBlendObjwin(renderer, outX, _brighten(color, renderer->bldy) | mergedFlags, current);
207			} else if (renderer->blendEffect == BLEND_DARKEN) {
208				_compositeBlendObjwin(renderer, outX, _darken(color, renderer->bldy) | mergedFlags, current);
209			}
210		}
211	}
212}