SDL2将像素数组制作成纹理

SDL2 make pixel array into texture

我试图渲染一张特殊的图像,它只是一堆没有格式的像素。它是一种 42x 42 像素的原始图像。这些图像是调色板,所以我也很好奇我应该如何处理这种情况。

如何在 SDL2 中将像素数组转换为纹理?

我最后应用调色板了吗?

更多详情: 目前我正在打开图像并添加一些透明(黑色字节)并将其存储到 char 数组中。我需要渲染这些像素。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <stdio.h>
#include <windows.h>
#include <vector>

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480


FILE* OpenCelFile(const char * filepath) {
    
    FILE* ptr = fopen(filepath, "rb");
    return ptr;
}

DWORD FrameCount[1]    = { 0 };
DWORD DataStart[1]     = { 0 };
DWORD dummy[1] = { 0 };
signed char  CommandByte[1]   = { 0 };


void SkipToData(FILE* pFile, DWORD* dataStart, int bytesRead)
{
    int MoveForwardBytes = *dataStart - bytesRead;
    fseek(pFile, MoveForwardBytes, SEEK_CUR);

}

// There is more to this , but it isn't 100% important.
void ReadCelHeader(FILE* pFile)
{
    fread((void*)FrameCount, 4, 1, pFile);
    fread((void*)DataStart,  4, 1, pFile);
    SkipToData(pFile, DataStart, 8);
}

void ReadCommandByte(FILE* pFile)
{
    fread((void*)CommandByte, 1, 1, pFile);
}

std::vector<char> backBuffer;


int CreateRawImageBuffer(FILE* pFile) {
    
    ReadCommandByte(pFile);
    int bytesRead = 0;


    // handel transparent bytes;
    if (*(BYTE*)CommandByte >= 0x80) {
        // this is a negative byte
        signed int skipBytes = *(BYTE*)CommandByte - 256;
        // convert it to positive number.
        skipBytes = abs(skipBytes);
        for (skipBytes; skipBytes != NULL; skipBytes--) {
            backBuffer.push_back(0x00);
            bytesRead++;
        }
    }

    // set real pixels
    if (*(BYTE*)CommandByte < 0x80) {
        signed int byteCount = *(BYTE*)CommandByte;
        for (byteCount; byteCount != NULL; byteCount--) {
            
            BYTE t_char[1] = {0x00};
            fread((void*)t_char, 1, 1, pFile);
            backBuffer.push_back(*t_char);
            bytesRead++;
        }
    }
    return bytesRead;
}


int main(int argc, char* args[]) {

    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = NULL;
    bool RunningMainGameLoop = true;

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "could not initialize sdl2: %s\n", SDL_GetError());
        return 1;
    }
    window = SDL_CreateWindow("Renderunkimage", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );

    if (window == NULL) {
        fprintf(stderr, "could not create window: %s\n", SDL_GetError());
        return 1;
    }


    FILE* ptr = OpenCelFile("C:\Users\luzer\source\repos\unkimages\unkimage.cel");
    ReadCelHeader(ptr);
    int TotalFramePixels = 48 * 48;
    int fc = *FrameCount;
    int pixelsAdded = { 0 };

    for (fc; fc != 0; fc--) {

        for (TotalFramePixels; TotalFramePixels != NULL; TotalFramePixels = TotalFramePixels - pixelsAdded) {
            pixelsAdded = CreateRawImageBuffer(ptr);
        }
    }

    
    screenSurface = SDL_GetWindowSurface(window);
    SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x00, 0x00, 0x00));
    SDL_UpdateWindowSurface(window);

    while (RunningMainGameLoop)
    {
        SDL_Event event;

        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                RunningMainGameLoop = false;
                break;
            }
        }

        // handle renders...


    }

    
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

您需要先使用 SDL_Surface 使用以下内容:

SDL_CreateRGBSurfaceFrom(data, IMAGE_WIDTH, IMAGE_HEIGHT, 8, IMAGE_WIDTH /*pitch*/, 0, 0, 0, 0);

我正在加载的图像实际上只是每种颜色的一个字节,然后我必须对它们应用调色板。有一种 RLE 编码或压缩,这就是为什么我必须加载它们,否则你只需加载它们并将它们传递到表面。

这里是所有感兴趣的人的完整代码。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <stdio.h>
#include <windows.h>
#include <vector>

#include <fstream>
#include <iterator>
#include <algorithm>
#include <array>

#define SCREEN_WIDTH 200
#define SCREEN_HEIGHT 200
#define TICK_INTERVAL 45

static Uint32 next_time;
SDL_Color palData[256];
DWORD FrameCount[1] = { 0 };
DWORD DataStart[1] = { 0 };
DWORD dummy[1] = { 0 };
signed char  CommandByte[1] = { 0 };
int TotalFramePixels = 48 * 48;
int IMAGE_WIDTH = 48;
int IMAGE_HEIGHT = 48;

struct Color {
    uint8_t  r;
    uint8_t  g;
    uint8_t  b;
};

struct celFrame {
    byte ImageData[2304]; //fixed size of image. 48*48

};

FILE* OpenCelFile(const char * filepath) {
    
    FILE* ptr = fopen(filepath, "rb");
    return ptr;
}

void LoadPalette(const char* pszFileName)
{
    FILE* PalFile = fopen(pszFileName, "rb");

    for (int idx = 0; idx < 255; idx++) {
        fread(&palData[idx].r, 1, 1, PalFile);
        fread(&palData[idx].g, 1, 1, PalFile);
        fread(&palData[idx].b, 1, 1, PalFile);
    }
}

void SkipToData(FILE* pFile, DWORD* dataStart, int bytesRead)
{
    int MoveForwardBytes = *dataStart - bytesRead;
    fseek(pFile, MoveForwardBytes, SEEK_CUR);

}

// There is more to this , but it isn't 100% important.
void ReadCelHeader(FILE* pFile)
{
    fread((void*)FrameCount, 4, 1, pFile);
    fread((void*)DataStart,  4, 1, pFile);
    SkipToData(pFile, DataStart, 8);
}

void ReadCommandByte(FILE* pFile)
{
    fread((void*)CommandByte, 1, 1, pFile);
}

int CreateRawImageBuffer(FILE* pFile, struct celFrame* s_celFrame, int bytesRead) {
    
    ReadCommandByte(pFile);

    // handel transparent bytes;
    if (*(BYTE*)CommandByte >= 0x80) {
        // this is a negative byte
        signed int skipBytes = *(BYTE*)CommandByte - 256;
        // convert it to positive number.
        skipBytes = abs(skipBytes);
        for (skipBytes; skipBytes != NULL; skipBytes--) {
            s_celFrame->ImageData[bytesRead] = 0xff;
            bytesRead++;
        }
    }

    // set real pixels
    if (*(BYTE*)CommandByte < 0x80) {
        signed int byteCount = *(BYTE*)CommandByte;
        for (byteCount; byteCount != NULL; byteCount--) {
            
            BYTE t_char[1] = {0xff};
            fread((void*)t_char, 1, 1, pFile);
            s_celFrame->ImageData[bytesRead] = *t_char;
            bytesRead++;
        }
    }

    if (bytesRead >= TotalFramePixels) {
        return bytesRead;
    }

    CreateRawImageBuffer(pFile, s_celFrame, bytesRead);
    
}

Uint32 time_left(void)
{
    Uint32 now;

    now = SDL_GetTicks();
    if (next_time <= now)
        return 0;
    else
        return next_time - now;
}



int main(int argc, char* args[]) {

    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = NULL;
    SDL_Renderer* renderer = NULL;
    SDL_Surface* PentagramSurface[8] = {0};
    SDL_Texture* pentagramTexture[8] = { 0 };
    int frameCount = 0;

    bool RunningMainGameLoop = true;

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "could not initialize sdl2: %s\n", SDL_GetError());
        return 1;
    }
    window = SDL_CreateWindow("RenderCEL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN  );

    if (window == nullptr) {
        fprintf(stderr, "could not create window: %s\n", SDL_GetError());
        return 1;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (renderer == nullptr) {
        std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
        return 1;
    }


    FILE* pfile = OpenCelFile("C:\Users\luzer\source\repos\RenderCEL\PentSpin.cel");
    LoadPalette("C:\Users\luzer\source\luzer\RenderCEL\cut2.pal");
    ReadCelHeader(pfile);


    int fc = *FrameCount;
    int pixelsAdded = { 0 };
    celFrame s_celFrame[8] = {0};

    // Create individual frames of each image
    // by storing them in structs
    for (int fidx = 0; fidx != fc; fidx++) {
        int bytes_read = CreateRawImageBuffer(pfile, &s_celFrame[fidx], 0);

        PentagramSurface[fidx] = SDL_CreateRGBSurfaceFrom(&s_celFrame[fidx], IMAGE_WIDTH, IMAGE_HEIGHT, 8, IMAGE_WIDTH /*pitch*/, 0, 0, 0, 0);
        SDL_SetPaletteColors(PentagramSurface[fidx]->format->palette, palData, 0, 256);
        pentagramTexture[fidx] = SDL_CreateTextureFromSurface(renderer, PentagramSurface[fidx]);
        SDL_FreeSurface(PentagramSurface[fidx]);
    }

    
    screenSurface = SDL_GetWindowSurface(window);
    SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x00, 0x00, 0x00));
    

    while (RunningMainGameLoop)
    {
        next_time = SDL_GetTicks() + TICK_INTERVAL;
        SDL_Event event;

        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                RunningMainGameLoop = false;
                break;
            }
        }

        // handle renders...
        SDL_Rect drect = {0,0,48,48};
        SDL_RenderClear(renderer);
        SDL_RenderCopyEx(renderer, pentagramTexture[frameCount], NULL, NULL, 0, NULL, SDL_FLIP_VERTICAL);
        SDL_RenderPresent(renderer);

        SDL_Delay(time_left());

        next_time += TICK_INTERVAL;
        
        frameCount++;
        if (frameCount == 8) { frameCount = 0; }

    }

    for (int idx = 0; idx < 8; idx++) {
        SDL_DestroyTexture(pentagramTexture[idx]);
    }
    
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}