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/core/interface.h>
9#include <mgba/internal/gba/gba.h>
10
11#define BACKGROUND_BITMAP_ITERATE(W, H) \
12 x += background->dx; \
13 y += background->dy; \
14 \
15 if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \
16 continue; \
17 } else { \
18 localX = x; \
19 localY = y; \
20 }
21
22#define MODE_2_COORD_OVERFLOW \
23 localX = x & (sizeAdjusted - 1); \
24 localY = y & (sizeAdjusted - 1); \
25
26#define MODE_2_COORD_NO_OVERFLOW \
27 if ((x | y) & ~(sizeAdjusted - 1)) { \
28 continue; \
29 } \
30 localX = x; \
31 localY = y;
32
33#define MODE_2_NO_MOSAIC(COORD) \
34 COORD \
35 uint32_t screenBase = background->screenBase + (localX >> 11) + (((localY >> 7) & 0x7F0) << background->size); \
36 uint8_t* screenBlock = (uint8_t*) renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET]; \
37 if (UNLIKELY(!screenBlock)) { \
38 mapData = 0; \
39 } else { \
40 mapData = screenBlock[screenBase & VRAM_BLOCK_MASK]; \
41 } \
42 uint32_t charBase = background->charBase + (mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8); \
43 pixelData = ((uint8_t*) renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET])[charBase & VRAM_BLOCK_MASK]; \
44
45#define MODE_2_MOSAIC(COORD) \
46 if (!mosaicWait) { \
47 MODE_2_NO_MOSAIC(COORD) \
48 mosaicWait = mosaicH; \
49 } else { \
50 --mosaicWait; \
51 }
52
53#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
54 for (outX = renderer->start; outX < renderer->end; ++outX) { \
55 x += background->dx; \
56 y += background->dy; \
57 \
58 uint32_t current = renderer->row[outX]; \
59 MOSAIC(COORD) \
60 if (pixelData) { \
61 COMPOSITE_256_ ## OBJWIN (BLEND, 0); \
62 } \
63 }
64
65#define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \
66 if (background->overflow) { \
67 if (mosaicH > 1) { \
68 MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
69 } else { \
70 MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
71 } \
72 } else { \
73 if (mosaicH > 1) { \
74 MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
75 } else { \
76 MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
77 } \
78 }
79
80void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
81 int sizeAdjusted = 0x8000 << background->size;
82
83 BACKGROUND_BITMAP_INIT;
84
85 uint8_t mapData;
86 uint8_t pixelData = 0;
87
88 int outX;
89
90 if (!objwinSlowPath) {
91 if (!(flags & FLAG_TARGET_2)) {
92 DRAW_BACKGROUND_MODE_2(NoBlend, NO_OBJWIN);
93 } else {
94 DRAW_BACKGROUND_MODE_2(Blend, NO_OBJWIN);
95 }
96 } else {
97 if (!(flags & FLAG_TARGET_2)) {
98 DRAW_BACKGROUND_MODE_2(NoBlend, OBJWIN);
99 } else {
100 DRAW_BACKGROUND_MODE_2(Blend, OBJWIN);
101 }
102 }
103}
104
105void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
106 BACKGROUND_BITMAP_INIT;
107
108 uint32_t color = renderer->normalPalette[0];
109
110 int outX;
111 for (outX = renderer->start; outX < renderer->end; ++outX) {
112 BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_VIDEO_VERTICAL_PIXELS);
113
114 if (!mosaicWait) {
115 LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
116 color = mColorFrom555(color);
117 mosaicWait = mosaicH;
118 } else {
119 --mosaicWait;
120 }
121
122 uint32_t current = renderer->row[outX];
123 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
124 unsigned mergedFlags = flags;
125 if (current & FLAG_OBJWIN) {
126 mergedFlags = objwinFlags;
127 }
128 if (!variant) {
129 _compositeBlendObjwin(renderer, outX, color | mergedFlags, current);
130 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
131 _compositeBlendObjwin(renderer, outX, _brighten(color, renderer->bldy) | mergedFlags, current);
132 } else if (renderer->blendEffect == BLEND_DARKEN) {
133 _compositeBlendObjwin(renderer, outX, _darken(color, renderer->bldy) | mergedFlags, current);
134 }
135 }
136 }
137}
138
139void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
140 BACKGROUND_BITMAP_INIT;
141
142 uint16_t color = 0;
143 uint32_t offset = 0;
144 if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
145 offset = 0xA000;
146 }
147
148 int outX;
149 for (outX = renderer->start; outX < renderer->end; ++outX) {
150 BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_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 = renderer->row[outX];
161 if (color && IS_WRITABLE(current)) {
162 if (!objwinSlowPath) {
163 _compositeBlendNoObjwin(renderer, outX, 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, outX, 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 for (outX = renderer->start; outX < renderer->end; ++outX) {
187 BACKGROUND_BITMAP_ITERATE(160, 128);
188
189 if (!mosaicWait) {
190 LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vramBG[0]);
191 color = mColorFrom555(color);
192 mosaicWait = mosaicH;
193 } else {
194 --mosaicWait;
195 }
196
197 uint32_t current = renderer->row[outX];
198 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
199 unsigned mergedFlags = flags;
200 if (current & FLAG_OBJWIN) {
201 mergedFlags = objwinFlags;
202 }
203 if (!variant) {
204 _compositeBlendObjwin(renderer, outX, color | mergedFlags, current);
205 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
206 _compositeBlendObjwin(renderer, outX, _brighten(color, renderer->bldy) | mergedFlags, current);
207 } else if (renderer->blendEffect == BLEND_DARKEN) {
208 _compositeBlendObjwin(renderer, outX, _darken(color, renderer->bldy) | mergedFlags, current);
209 }
210 }
211 }
212}