all repos — mgba @ e7be40e80ccb6dbeee0b79c97f349859b1b4afb8

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