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/internal/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 } \
18 localX = x; \
19 localY = y;
20
21#define MODE_2_NO_MOSAIC(COORD) \
22 COORD \
23 uint32_t screenBase = background->screenBase + (localX >> 11) + (((localY >> 7) & 0x7F0) << background->size); \
24 mapData = ((uint8_t*) renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET])[screenBase & VRAM_BLOCK_MASK]; \
25 uint32_t charBase = background->charBase + (mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8); \
26 pixelData = ((uint8_t*) renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET])[charBase & VRAM_BLOCK_MASK]; \
27
28#define MODE_2_MOSAIC(COORD) \
29 if (!mosaicWait) { \
30 MODE_2_NO_MOSAIC(COORD) \
31 mosaicWait = mosaicH; \
32 } else { \
33 --mosaicWait; \
34 }
35
36#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
37 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { \
38 x += background->dx; \
39 y += background->dy; \
40 \
41 uint32_t current = *pixel; \
42 MOSAIC(COORD) \
43 if (pixelData) { \
44 COMPOSITE_256_ ## OBJWIN (BLEND, 0); \
45 } \
46 }
47
48#define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \
49 if (background->overflow) { \
50 if (mosaicH > 1) { \
51 MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
52 } else { \
53 MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
54 } \
55 } else { \
56 if (mosaicH > 1) { \
57 MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
58 } else { \
59 MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
60 } \
61 }
62
63void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
64 int sizeAdjusted = 0x8000 << background->size;
65
66 BACKGROUND_BITMAP_INIT;
67
68 uint8_t mapData;
69 uint8_t pixelData = 0;
70
71 int outX;
72 uint32_t* pixel;
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 uint32_t* pixel;
96 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
97 BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, VIDEO_VERTICAL_PIXELS);
98
99 if (!mosaicWait) {
100 LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
101#ifndef COLOR_16_BIT
102 unsigned color32;
103 color32 = 0;
104 color32 |= (color << 3) & 0xF8;
105 color32 |= (color << 6) & 0xF800;
106 color32 |= (color << 9) & 0xF80000;
107 color32 |= (color32 >> 5) & 0x070707;
108 color = color32;
109#elif COLOR_5_6_5
110 uint16_t color16 = 0;
111 color16 |= (color & 0x001F) << 11;
112 color16 |= (color & 0x03E0) << 1;
113 color16 |= (color & 0x7C00) >> 10;
114 color = color16;
115#endif
116 mosaicWait = mosaicH;
117 } else {
118 --mosaicWait;
119 }
120
121 uint32_t current = *pixel;
122 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
123 unsigned mergedFlags = flags;
124 if (current & FLAG_OBJWIN) {
125 mergedFlags = objwinFlags;
126 }
127 if (!variant) {
128 _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current);
129 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
130 _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current);
131 } else if (renderer->blendEffect == BLEND_DARKEN) {
132 _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current);
133 }
134 }
135 }
136}
137
138void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
139 BACKGROUND_BITMAP_INIT;
140
141 uint16_t color = renderer->normalPalette[0];
142 uint32_t offset = 0;
143 if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
144 offset = 0xA000;
145 }
146
147 int outX;
148 uint32_t* pixel;
149 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
150 BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, 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 = *pixel;
161 if (color && IS_WRITABLE(current)) {
162 if (!objwinSlowPath) {
163 _compositeBlendNoObjwin(renderer, pixel, 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, pixel, 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 uint32_t* pixel;
187 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
188 BACKGROUND_BITMAP_ITERATE(160, 128);
189
190 if (!mosaicWait) {
191 LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vramBG[0]);
192#ifndef COLOR_16_BIT
193 unsigned color32 = 0;
194 color32 |= (color << 9) & 0xF80000;
195 color32 |= (color << 3) & 0xF8;
196 color32 |= (color << 6) & 0xF800;
197 color32 |= (color32 >> 5) & 0x070707;
198 color = color32;
199#elif COLOR_5_6_5
200 uint16_t color16 = 0;
201 color16 |= (color & 0x001F) << 11;
202 color16 |= (color & 0x03E0) << 1;
203 color16 |= (color & 0x7C00) >> 10;
204 color = color16;
205#endif
206 mosaicWait = mosaicH;
207 } else {
208 --mosaicWait;
209 }
210
211 uint32_t current = *pixel;
212 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
213 unsigned mergedFlags = flags;
214 if (current & FLAG_OBJWIN) {
215 mergedFlags = objwinFlags;
216 }
217 if (!variant) {
218 _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current);
219 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
220 _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current);
221 } else if (renderer->blendEffect == BLEND_DARKEN) {
222 _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current);
223 }
224 }
225 }
226}