Splash screen and image converter

All this experimenting needs to lead somewhere. I am doing it partly to learn a new platform and partly because I want to make a game for it. I am not sure how to incorporate all the motors and sensor into the game, but I want them to be there somehow. Why bother making the game for the EV3 if I don’t use any of the hardware.

Anyways, I’ve started with the most essential part of the game. The splash screen. :)Game splash pt. 1

To get it onto the Brick I also created an image converter, that can read any file that SDL supports and create an RGF file.

The RGF file format is dead simple. First there are two unsigned byte, one for width and one for height of the image. Then each pixel in the image is stored in a bit. So 8 pixels are stored in 1 byte. Left most pixel is stored in the least significant bit, and rightmost pixel is stored in most significant bit.

This is the source I ended up writing. As you can see I have a hardcoded string for the in and out file names instead of using argv[1] and argv[2], but .. you know. Gotta keep stuff that can be improved. :)

//
//  main.cpp
//  bmpconverter
//
//  Created by Magnus Runesson on 2014-08-17.
//  Copyright (c) 2014 Magnus Runesson. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "CImage.h"

int main(int argc, const char * argv[])
{
    CImage* pImage = new CImage( "splashfont2.png" );

    int outwidth = pImage->m_Width>>3;
    if( pImage->m_Width&7 )
        outwidth++;
    int outsize = outwidth * pImage->m_Height;
    
    unsigned char* outpixels = new unsigned char[ outsize ];

    int x, y;
    int readx;
    int writex;
    int inofs = 0;
    for( y=0; y<pImage->m_Height; y++ )
    {
        readx = pImage->m_Width;
        for( writex=0; writex<outwidth; writex++ )
        {
            int readpixelcount = 8;
            if( writex == outwidth-1 )
                readpixelcount = readx;
            readx -= readpixelcount;
            
            int outofs = (y*outwidth) + writex;

            unsigned char outbyte = 0;
            
            int i;
            for( i=0; i<readpixelcount; i++ )
            {
                unsigned char r = pImage->m_aPixels[ inofs + 0 ];
                unsigned char g = pImage->m_aPixels[ inofs + 1 ];
                unsigned char b = pImage->m_aPixels[ inofs + 2 ];
                unsigned char a = pImage->m_aPixels[ inofs + 3 ];
                
                inofs += 4;
                
                if( a > 127 )
                {
                    if( r < 127 )
                        outbyte |= (1<<i);
                }
            }
            
            outpixels[ outofs ] = outbyte;
        }
    }

    FILE* fout = fopen("splashfont2.rgf", "wb");
    unsigned char widthub = pImage->m_Width;
    unsigned char heightub = pImage->m_Height;
    fwrite( &widthub, 1, 1, fout );
    fwrite( &heightub, 1, 1, fout );
    fwrite( outpixels, 1, outsize, fout);
    fclose(fout);
    
    return 0;
}

So as long as you can read a file into a 32 BPP array in the order I read them you can pretty much plug any image reader into this.

I use SDL for reading images. Here is my CImage class

/*
 *  CImage.h
 *
 *  Created by Magnus Runesson on 1/28/12.
 *  Copyright 2012 Pokewhat. All rights reserved.
 *
 */

#pragma once

class SDL_Surface;

class CImage
{
public:
    CImage(const char* _pszFileName);
    CImage(CImage* _pReference, CImage* _pDiff);
    CImage(unsigned char* _aPixels, int _w, int _h);
    ~CImage();
    void SaveRAW(const char* _pszFileName);

private:
    unsigned int GetRGBA(SDL_Surface* _pSurface, int _x, int _y);
    void LoadSDL(const char* _pszFileName);

public:
    unsigned char* m_aPixels;
    char* m_pszFileName;
    int m_Width, m_Height;
};
/*
 *  CImage.cpp
 *
 *  Created by Magnus Runesson on 1/28/12.
 *  Copyright 2012 Pokewhat. All rights reserved.
 *
 */

#include "CImage.h"
#include "SDL_Image/SDL_Image.h"

void* fileRead(const char* _pszFileName, int* _pDatasize);
void fileWrite(const char* _pszFileName, void* _pImageData, int _Length);
void _fileFree(void* _pData, const void* _pReadData, size_t _Size);

void* fileRead(const char* _pszFileName, int* _pDatasize)
{
    FILE* f = fopen(_pszFileName, "rb");
    if( !f )
        return NULL;
    
    fseek(f, 0, SEEK_END);
    int size = ftell(f);
    fseek(f, 0, SEEK_SET);
    
    void* pRet = malloc(size);
    
    fread(pRet, 1, size, f);
    fclose(f);
    
    *_pDatasize = size;
    return pRet;
}

void fileWrite(const char* _pszFileName, void* _pImageData, int _Length)
{
    FILE* f = fopen(_pszFileName, "wb");
    fwrite(_pImageData, 1, _Length, f);
    fclose(f);
}

void _fileFree(void* _pData, const void* _pReadData, size_t _Size)
{
    free(_pData);
}



CImage::CImage(const char* _pszFileName)
{
    m_aPixels = NULL;
    LoadSDL( _pszFileName );
}

CImage::CImage(unsigned char* _aPixels, int _w, int _h)
{
    m_Width = _w;
    m_Height = _h;

    int size = _w*_h*4;
    m_aPixels = new unsigned char[size];
    
    memcpy(m_aPixels, _aPixels, size);
}

CImage::~CImage()
{
    delete[] m_aPixels;
    m_aPixels = NULL;
}

unsigned int CImage::GetRGBA(SDL_Surface* _pSurface, int _x, int _y)
{
    SDL_PixelFormat* pFormat = _pSurface->format;
    int readofs = (_y * (_pSurface->w)) + _x;
    int r,g,b,a;
    if( _pSurface->format->BytesPerPixel == 2 )
    {
        unsigned short* pData = (unsigned short*)_pSurface->pixels;
        r = ((pData[readofs]&pFormat->Rmask) >> pFormat->Rshift);
        g = ((pData[readofs]&pFormat->Gmask) >> pFormat->Gshift);
        b = ((pData[readofs]&pFormat->Bmask) >> pFormat->Bshift);
        r *= (255/15);
        g *= (255/15);
        b *= (255/15);
        
        if( pFormat->Amask )
        {
            a = ((pData[readofs]&pFormat->Amask) >> pFormat->Ashift);
            a *= (255/15);
        } else
        {
            a = 255;
        }
    }
    else if( _pSurface->format->BytesPerPixel == 4 )
    {
        unsigned int* pData = (unsigned int*)_pSurface->pixels;
        r = ((pData[readofs]&pFormat->Rmask) >> pFormat->Rshift);
        g = ((pData[readofs]&pFormat->Gmask) >> pFormat->Gshift);
        b = ((pData[readofs]&pFormat->Bmask) >> pFormat->Bshift);
        if( pFormat->Amask )
        {
            a = ((pData[readofs]&pFormat->Amask) >> pFormat->Ashift);
        } else {
            a = 255;
        }
    } else
    {
        unsigned char* pData = (unsigned char*)_pSurface->pixels;
        r=pData[readofs*4+0];
        g=pData[readofs*4+1];
        b=pData[readofs*4+2];
        a=pData[readofs*4+3];
    }

    unsigned int ret = (r<<24) + (g<<16) + (b<<8) + a;
    return ret;
}

void CImage::LoadSDL(const char* _pszFileName)
{
    m_pszFileName = strdup(_pszFileName);
    SDL_Surface* pSurface = IMG_Load(_pszFileName);
    if( pSurface == NULL )
    {
        printf("Failed to load texture '%s'\n", _pszFileName);
        return;
    }

    int src_width = pSurface->w;
    int src_height = pSurface->h;

    m_Width = src_width;
    m_Height = src_height;
    
    // Allocated memory needed for the bitmap context
    int texelsSize = m_Width * m_Height * 4;
    m_aPixels = new unsigned char[texelsSize];
    memset(m_aPixels, 0, texelsSize);

    // Convert image to texture
    int x, y;
    for( y=0; y<src_height; y++ )
    {
        for( x=0; x<src_width; x++ )
        {
            unsigned int rgba = GetRGBA(pSurface, x, y);
            int writeofs = (y*m_Width)+x;
            writeofs *= 4;    // 4 bytes per pixel in all of our textures
            m_aPixels[writeofs++] = (rgba>>24) & 0xff;
            m_aPixels[writeofs++] = (rgba>>16) & 0xff;
            m_aPixels[writeofs++] = (rgba>>8) & 0xff;
            int alpha = (rgba) & 0xff;
            m_aPixels[writeofs++] = alpha;
            //int a = (alpha & 0x80) != 0;
            //m_aCollisionMask[collwriteofs] = a;
        }
    }

    //
    SDL_FreeSurface(pSurface);
}

void CImage::SaveRAW(const char* _pszFileName)
{
    FILE* f = fopen(_pszFileName, "w");
    fwrite(m_aPixels, 1, m_Width*m_Height*4, f);
    fclose(f);
}

That image reader have a hack that I’m not proud of. The images that SDL read for me all had bits per pixel, bytes per pixel and the palette set to 0, so in the GetRGBA() method I simply just read 32 bpp RGBA colours if SDL doesn’t report a specific format. Because you know .. this isn’t what I want to spend time on. :)

Leave a Reply