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 MODE_2_COORD_OVERFLOW \
12 localX = x & (sizeAdjusted - 1); \
13 localY = y & (sizeAdjusted - 1); \
14
15#define MODE_2_COORD_NO_OVERFLOW \
16 if ((x | y) & ~(sizeAdjusted - 1)) { \
17 continue; \
18 } \
19 localX = x; \
20 localY = y;
21
22#define MODE_2_NO_MOSAIC(COORD) \
23 COORD \
24 uint32_t screenBase = background->screenBase + (localX >> 11) + (((localY >> 7) & 0x7F0) << background->size); \
25 mapData = ((uint8_t*) renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET])[screenBase & VRAM_BLOCK_MASK]; \
26 uint32_t charBase = background->charBase + (mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8); \
27 pixelData = ((uint8_t*) renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET])[charBase & VRAM_BLOCK_MASK]; \
28
29#define MODE_2_MOSAIC(COORD) \
30 if (!mosaicWait) { \
31 MODE_2_NO_MOSAIC(COORD) \
32 mosaicWait = mosaicH; \
33 } else { \
34 --mosaicWait; \
35 }
36
37#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
38 for (outX = renderer->start; outX < renderer->end; ++outX) { \
39 x += background->dx; \
40 y += background->dy; \
41 \
42 uint32_t current = renderer->row[outX]; \
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 mapData;
70 uint8_t pixelData = 0;
71
72 int outX;
73
74 if (!objwinSlowPath) {
75 if (!(flags & FLAG_TARGET_2)) {
76 DRAW_BACKGROUND_MODE_2(NoBlend, NO_OBJWIN);
77 } else {
78 DRAW_BACKGROUND_MODE_2(Blend, NO_OBJWIN);
79 }
80 } else {
81 if (!(flags & FLAG_TARGET_2)) {
82 DRAW_BACKGROUND_MODE_2(NoBlend, OBJWIN);
83 } else {
84 DRAW_BACKGROUND_MODE_2(Blend, OBJWIN);
85 }
86 }
87}
88
89void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
90 BACKGROUND_BITMAP_INIT;
91
92 uint32_t color = renderer->normalPalette[0];
93
94 int outX;
95 for (outX = renderer->start; outX < renderer->end; ++outX) {
96 BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_VIDEO_VERTICAL_PIXELS);
97
98 if (!mosaicWait) {
99 LOAD_16(color, ((localX >> 8) + (localY >> 8) * renderer->masterEnd) << 1, renderer->d.vramBG[0]);
100 color = mColorFrom555(color);
101 mosaicWait = mosaicH;
102 } else {
103 --mosaicWait;
104 }
105
106 uint32_t current = renderer->row[outX];
107 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
108 unsigned mergedFlags = flags;
109 if (current & FLAG_OBJWIN) {
110 mergedFlags = objwinFlags;
111 }
112 if (!variant) {
113 _compositeBlendObjwin(renderer, outX, color | mergedFlags, current);
114 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
115 _compositeBlendObjwin(renderer, outX, _brighten(color, renderer->bldy) | mergedFlags, current);
116 } else if (renderer->blendEffect == BLEND_DARKEN) {
117 _compositeBlendObjwin(renderer, outX, _darken(color, renderer->bldy) | mergedFlags, current);
118 }
119 }
120 }
121}
122
123void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
124 BACKGROUND_BITMAP_INIT;
125
126 uint16_t color = renderer->normalPalette[0];
127 uint32_t offset = 0;
128 if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
129 offset = 0xA000;
130 }
131
132 int outX;
133 for (outX = renderer->start; outX < renderer->end; ++outX) {
134 BACKGROUND_BITMAP_ITERATE(renderer->masterEnd, GBA_VIDEO_VERTICAL_PIXELS);
135
136 if (!mosaicWait) {
137 color = ((uint8_t*)renderer->d.vramBG[0])[offset + (localX >> 8) + (localY >> 8) * renderer->masterEnd];
138
139 mosaicWait = mosaicH;
140 } else {
141 --mosaicWait;
142 }
143
144 uint32_t current = renderer->row[outX];
145 if (color && IS_WRITABLE(current)) {
146 if (!objwinSlowPath) {
147 _compositeBlendNoObjwin(renderer, outX, palette[color] | flags, current);
148 } else if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) {
149 color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette;
150 unsigned mergedFlags = flags;
151 if (current & FLAG_OBJWIN) {
152 mergedFlags = objwinFlags;
153 }
154 _compositeBlendObjwin(renderer, outX, currentPalette[color] | mergedFlags, current);
155 }
156 }
157 }
158}
159
160void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) {
161 BACKGROUND_BITMAP_INIT;
162
163 uint32_t color = renderer->normalPalette[0];
164 uint32_t offset = 0;
165 if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
166 offset = 0xA000;
167 }
168
169 int outX;
170 for (outX = renderer->start; outX < renderer->end; ++outX) {
171 BACKGROUND_BITMAP_ITERATE(160, 128);
172
173 if (!mosaicWait) {
174 LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vramBG[0]);
175 color = mColorFrom555(color);
176 mosaicWait = mosaicH;
177 } else {
178 --mosaicWait;
179 }
180
181 uint32_t current = renderer->row[outX];
182 if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) {
183 unsigned mergedFlags = flags;
184 if (current & FLAG_OBJWIN) {
185 mergedFlags = objwinFlags;
186 }
187 if (!variant) {
188 _compositeBlendObjwin(renderer, outX, color | mergedFlags, current);
189 } else if (renderer->blendEffect == BLEND_BRIGHTEN) {
190 _compositeBlendObjwin(renderer, outX, _brighten(color, renderer->bldy) | mergedFlags, current);
191 } else if (renderer->blendEffect == BLEND_DARKEN) {
192 _compositeBlendObjwin(renderer, outX, _darken(color, renderer->bldy) | mergedFlags, current);
193 }
194 }
195 }
196}