all repos — mgba @ 554276d5c379401baa618ec4f4b4f0440be09b19

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