| 1167 | } |
| 1168 | |
| 1169 | void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, const int maxWidth, |
| 1170 | const int maxHeight) const { |
| 1171 | float scale = 1.0f; |
| 1172 | bool isScaled = false; |
| 1173 | if (maxWidth > 0 && bitmap.getWidth() > maxWidth) { |
| 1174 | scale = static_cast<float>(maxWidth) / static_cast<float>(bitmap.getWidth()); |
| 1175 | isScaled = true; |
| 1176 | } |
| 1177 | if (maxHeight > 0 && bitmap.getHeight() > maxHeight) { |
| 1178 | scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>(bitmap.getHeight())); |
| 1179 | isScaled = true; |
| 1180 | } |
| 1181 | |
| 1182 | // For 1-bit BMP, output is still 2-bit packed (for consistency with readNextRow) |
| 1183 | const int outputRowSize = (bitmap.getWidth() + 3) / 4; |
| 1184 | auto* outputRow = static_cast<uint8_t*>(malloc(outputRowSize)); |
| 1185 | auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes())); |
| 1186 | |
| 1187 | if (!outputRow || !rowBytes) { |
| 1188 | LOG_ERR("GFX", "!! Failed to allocate 1-bit BMP row buffers"); |
| 1189 | free(outputRow); |
| 1190 | free(rowBytes); |
| 1191 | return; |
| 1192 | } |
| 1193 | |
| 1194 | for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) { |
| 1195 | // Read rows sequentially using readNextRow |
| 1196 | if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) { |
| 1197 | LOG_ERR("GFX", "Failed to read row %d from 1-bit bitmap", bmpY); |
| 1198 | free(outputRow); |
| 1199 | free(rowBytes); |
| 1200 | return; |
| 1201 | } |
| 1202 | |
| 1203 | // Calculate screen Y based on whether BMP is top-down or bottom-up |
| 1204 | const int bmpYOffset = bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY; |
| 1205 | int screenY = y + (isScaled ? static_cast<int>(std::floor(bmpYOffset * scale)) : bmpYOffset); |
| 1206 | if (screenY >= getScreenHeight()) { |
| 1207 | continue; // Continue reading to keep row counter in sync |
| 1208 | } |
| 1209 | if (screenY < 0) { |
| 1210 | continue; |
| 1211 | } |
| 1212 | |
| 1213 | for (int bmpX = 0; bmpX < bitmap.getWidth(); bmpX++) { |
| 1214 | int screenX = x + (isScaled ? static_cast<int>(std::floor(bmpX * scale)) : bmpX); |
| 1215 | if (screenX >= getScreenWidth()) { |
| 1216 | break; |
| 1217 | } |
| 1218 | if (screenX < 0) { |
| 1219 | continue; |
| 1220 | } |
| 1221 | |
| 1222 | // Get 2-bit value (result of readNextRow quantization) |
| 1223 | const uint8_t val = outputRow[bmpX / 4] >> (6 - ((bmpX * 2) % 8)) & 0x3; |
| 1224 | |
| 1225 | // For 1-bit source: 0 or 1 -> map to black (0,1,2) or white (3) |
| 1226 | // val < 3 means black pixel (draw it) |
nothing calls this directly
no test coverage detected