How to Create a 1-bit-per-pixel Surface with SDL2
Asked Answered
H

1

7

I'm trying to write a retro-computer emulator in C (with SDL2 for graphics and sound) that has memory mapped graphics.

This will be a 16-bit WORD machine, with each RAM location holding 16-bits. The screen is 512 x 256 pixels, black and white only. The graphics are memory mapped in an 8 K block of memory (so 8192 locations, each holding 16-bits).

Each bit in this area of memory holds the data for a single pixel, either black (0) or white (1).

From what I know about SDL2, I believe its limited to 8-bits per pixel as a minimum pixel format, but I'm not sure. This would be an index into a palette of 256 colors.

Does anyone know of a way to send this raw bitmapped data directly to an SDL2 function that will return a Surface I can then blit to the display?

Harkness answered 11/3, 2019 at 17:42 Comment(4)
Parse the bitmapped data yourself and set pixels accordingly with SDL. I made a similar emulator a while back where 1 bit represented 1 pixel, and the easiest was just to parse it myself. I don’t think what you are asking for is possible.Symphonic
Ok thanks. Can I ask you how large your screen was that you were mapping to? Did you parse every pixel value every single frame?Harkness
SDL supports two formats for 1-bit monochrome images: SDL_PIXELFORMAT_INDEX1MSB (preferred) and SDL_PIXELFORMAT_INDEX1LSB. The number of bits per pixel is still at least 8, but it should be easily convertible to a true 1-bit per pixel custom format.Beach
The simplest thing to do is use a SDL_PIXELFORMAT_INDEX8 format with a 2-color (black & white) palette. Then just map each pixel in the image to 0 or 1.Tautomerism
D
2

A surface created with SDL_PIXELFORMAT_INDEX1MSB is one-bit-per-pixel. The 1 and 0 are indexed to colors you can set.

SDL_Init(SDL_INIT_VIDEO);    
/* scale here to make the window larger than the surface itself.
 Integer scalings only as set by function below. */
SDL_Window * window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED,
                           SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
    
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
const int width = SCREEN_WIDTH; //
const int height = SCREEN_HEIGHT;
    
/* Since we are going to display a low resolution buffer,
it is best to limit the window size so that it cannot be
smaller than our internal buffer size. */
SDL_SetWindowMinimumSize(window, width, height);
SDL_RenderSetLogicalSize(renderer, width, height);
SDL_RenderSetIntegerScale(renderer, 1);

/* A one-bit-per-pixel Surface, indexed to these colors */
SDL_Surface * surface = SDL_CreateRGBSurfaceWithFormat(SDL_SWSURFACE,
   width, height, 1, SDL_PIXELFORMAT_INDEX1MSB);
SDL_Color colors[2] = {{0, 0, 0, 255}, {255, 255, 255, 255}};
SDL_SetPaletteColors(surface->format->palette, colors, 0, 2);

while (!done) {
    /* draw things into the byte array at surface->pixels. bit-math stuff. */
    /* docs are here: https://wiki.libsdl.org/SDL_Surface */

    /* draw the Surface to the screen */
    SDL_RenderClear(renderer);
    SDL_Texture * screen_texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_RenderCopy(renderer, screen_texture, NULL, NULL);
    SDL_RenderPresent(renderer);
    SDL_DestroyTexture(screen_texture);
}

Links:
https://wiki.libsdl.org/SDL_Surface
https://wiki.libsdl.org/SDL_PixelFormatEnum

Duhl answered 2/7, 2022 at 15:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.