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_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 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* screenBase = &((uint8_t*) renderer->d.vram)[background->screenBase];
70 uint8_t* charBase = &((uint8_t*) renderer->d.vram)[background->charBase];
71 uint8_t mapData;
72 uint8_t pixelData = 0;
73
74 int outX;
75 uint32_t* pixel;
76
77 if (!objwinSlowPath) {
78 if (!(flags & FLAG_TARGET_2)) {
79 DRAW_BACKGROUND_MODE_2(NoBlend, NO_OBJWIN);
80 } else {
81 DRAW_BACKGROUND_MODE_2(Blend, NO_OBJWIN);
82 }
83 } else {
84 if (!(flags & FLAG_TARGET_2)) {
85 DRAW_BACKGROUND_MODE_2(NoBlend, OBJWIN);
86 } else {
87 DRAW_BACKGROUND_MODE_2(Blend, OBJWIN);
88 }
89 }
90}
91
92void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
93 BACKGROUND_BITMAP_INIT;
94
95 uint32_t color = renderer->normalPalette[0];
96
97 int outX;
98 uint32_t* pixel;
99 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
100 BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
101
102 if (!mosaicWait) {
103 LOAD_16(color, ((localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram);
104#ifndef COLOR_16_BIT
105 unsigned color32;
106 color32 = 0;
107 color32 |= (color << 3) & 0xF8;
108 color32 |= (color << 6) & 0xF800;
109 color32 |= (color << 9) & 0xF80000;
110 color32 |= (color32 >> 5) & 0x070707;
111 color = color32;
112#elif COLOR_5_6_5
113 uint16_t color16 = 0;
114 color16 |= (color & 0x001F) << 11;
115 color16 |= (color & 0x03E0) << 1;
116 color16 |= (color & 0x7C00) >> 10;
117 color = color16;
118#endif
119 mosaicWait = mosaicH;
120 } else {
121 --mosaicWait;
122 }
123
124 uint32_t current = *pixel;
125 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
126 unsigned mergedFlags = flags;
127 if (current & FLAG_OBJWIN) {
128 mergedFlags = objwinFlags;
129 }
130 if (!variant) {
131 _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current);
132 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
133 _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current);
134 } else if (renderer->blendEffect == BLEND_DARKEN) {
135 _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current);
136 }
137 }
138 }
139}
140
141void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
142 BACKGROUND_BITMAP_INIT;
143
144 uint16_t color = renderer->normalPalette[0];
145 uint32_t offset = 0;
146 if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
147 offset = 0xA000;
148 }
149
150 int outX;
151 uint32_t* pixel;
152 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
153 BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
154
155 if (!mosaicWait) {
156 color = ((uint8_t*)renderer->d.vram)[offset + (localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS];
157
158 mosaicWait = mosaicH;
159 } else {
160 --mosaicWait;
161 }
162
163 uint32_t current = *pixel;
164 if (color && IS_WRITABLE(current)) {
165 if (!objwinSlowPath) {
166 _compositeBlendNoObjwin(renderer, pixel, palette[color] | flags, current);
167 } else if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) {
168 color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette;
169 unsigned mergedFlags = flags;
170 if (current & FLAG_OBJWIN) {
171 mergedFlags = objwinFlags;
172 }
173 _compositeBlendObjwin(renderer, pixel, currentPalette[color] | mergedFlags, current);
174 }
175 }
176 }
177}
178
179void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
180 BACKGROUND_BITMAP_INIT;
181
182 uint32_t color = renderer->normalPalette[0];
183 uint32_t offset = 0;
184 if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
185 offset = 0xA000;
186 }
187
188 int outX;
189 uint32_t* pixel;
190 for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) {
191 BACKGROUND_BITMAP_ITERATE(160, 128);
192
193 if (!mosaicWait) {
194 LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram);
195#ifndef COLOR_16_BIT
196 unsigned color32 = 0;
197 color32 |= (color << 9) & 0xF80000;
198 color32 |= (color << 3) & 0xF8;
199 color32 |= (color << 6) & 0xF800;
200 color32 |= (color32 >> 5) & 0x070707;
201 color = color32;
202#elif COLOR_5_6_5
203 uint16_t color16 = 0;
204 color16 |= (color & 0x001F) << 11;
205 color16 |= (color & 0x03E0) << 1;
206 color16 |= (color & 0x7C00) >> 10;
207 color = color16;
208#endif
209 mosaicWait = mosaicH;
210 } else {
211 --mosaicWait;
212 }
213
214 uint32_t current = *pixel;
215 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
216 unsigned mergedFlags = flags;
217 if (current & FLAG_OBJWIN) {
218 mergedFlags = objwinFlags;
219 }
220 if (!variant) {
221 _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current);
222 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
223 _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current);
224 } else if (renderer->blendEffect == BLEND_DARKEN) {
225 _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current);
226 }
227 }
228 }
229}