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}