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