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