all repos — mgba @ be2641c77b4a438e0db487bc82b43bc27a26e0c2

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