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}