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