all repos — mgba @ 60577e83948647d36a2e6a8b4ec8f8556df3f72f

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