ValveSoftware / source-sdk-2013

The 2013 edition of the Source SDK
https://developer.valvesoftware.com/wiki/SDK2013_GettingStarted
Other
3.7k stars 1.99k forks source link

Problem with .vtf file modification. #458

Closed Mine228 closed 6 years ago

Mine228 commented 6 years ago

So I've been trying to modify the contents of a .vtf file and then save it as a new file. I have this:

unsigned char * pSrcImage = pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z );

float * ImgArray = (float *)pSrcImage;

for (int i = 0; i < iWidth*iHeight * 3; i+=3)
{
    ImgArray[i] = 0.0f;
    ImgArray[i+1] = 1.0f;
    ImgArray[i+2] = 0.0f;
}

*pSrcImage = * (unsigned char *)ImgArray;

CUtlBuffer finBuf;
pTex->Serialize(finBuf);

FILE * fin;
fin = fopen("output.vtf", "w+b");

fwrite(finBuf.Base(), 1, srcVTFLength, fin);
fclose(fin);

This is meant to change the color of a particular bitmap to a green color. It successfully creates a working vtf file but it doesn't seem to modify its contents. It says that ImageData() returns a pointer to the bitmap data of the vtf interface for the selected face,frame, etc. So I'm considering that this pointer should be replacing the data of the vtf that I'm modifying unless it makes a copy of the data and returns the pointer to the copied data. If anyone has any info on this it would be much appreciated.

PatrickSHYee commented 6 years ago

I'm just looking at it, but you take look at your type casting of your unsigned char. I know the char should give you an address, but in c++ it gives an actual char and not int value. Please try an int.

On Tue, Jul 3, 2018, 11:53 AM Mince228 notifications@github.com wrote:

So I've been trying to modify the contents of a .vtf file and then save it as a new file. I have this:

` unsigned char *pSrcImage = pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z );

float ImgArray = (float)pSrcImage;

for (int i = 0; i < iWidthiHeight 3; i+=3) { ImgArray[i] = 0.0f; ImgArray[i+1] = 1.0f; ImgArray[i+2] = 0.0f; }

pSrcImage = (unsigned char*)ImgArray;

CUtlBuffer finBuf; pTex->Serialize(finBuf);

FILE *fin; fin = fopen("output.vtf", "w+b");

fwrite(finBuf.Base(), 1, srcVTFLength, fin); fclose(fin);`

This is meant to change the color of a particular bitmap to a green color. It successfully creates a working vtf file but it doesn't seem to modify its contents. It says that ImageData() returns a pointer to the bitmap data of the vtf interface for the selected face,frame, etc. So I'm considering that this pointer should be replacing the data of the vtf that I'm modifying unless it makes a copy of the data and returns the pointer to the copied data. If anyone has any info on this it would be much appreciated.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ValveSoftware/source-sdk-2013/issues/458, or mute the thread https://github.com/notifications/unsubscribe-auth/AGDYvk-BQAXdzZPKZz4gJpxBJt7ComFIks5uC6-pgaJpZM4VBYnA .

PatrickSHYee commented 6 years ago

i also want to say that in that statement that you given the address of the array for your pointer. I can see your reasoning why your thought type casting it. Where ever your array is in location, it could be a negative if you type cast as a char.

On Tue, Jul 3, 2018, 11:53 AM Mince228 notifications@github.com wrote:

So I've been trying to modify the contents of a .vtf file and then save it as a new file. I have this:

` unsigned char *pSrcImage = pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z );

float ImgArray = (float)pSrcImage;

for (int i = 0; i < iWidthiHeight 3; i+=3) { ImgArray[i] = 0.0f; ImgArray[i+1] = 1.0f; ImgArray[i+2] = 0.0f; }

pSrcImage = (unsigned char*)ImgArray;

CUtlBuffer finBuf; pTex->Serialize(finBuf);

FILE *fin; fin = fopen("output.vtf", "w+b");

fwrite(finBuf.Base(), 1, srcVTFLength, fin); fclose(fin);`

This is meant to change the color of a particular bitmap to a green color. It successfully creates a working vtf file but it doesn't seem to modify its contents. It says that ImageData() returns a pointer to the bitmap data of the vtf interface for the selected face,frame, etc. So I'm considering that this pointer should be replacing the data of the vtf that I'm modifying unless it makes a copy of the data and returns the pointer to the copied data. If anyone has any info on this it would be much appreciated.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ValveSoftware/source-sdk-2013/issues/458, or mute the thread https://github.com/notifications/unsubscribe-auth/AGDYvk-BQAXdzZPKZz4gJpxBJt7ComFIks5uC6-pgaJpZM4VBYnA .

PatrickSHYee commented 6 years ago

And last thing where are ya sending your pointer unsigned char variable to. it doesn't look like you are writing to your file.

On Tue, Jul 3, 2018, 11:53 AM Mince228 notifications@github.com wrote:

So I've been trying to modify the contents of a .vtf file and then save it as a new file. I have this:

` unsigned char *pSrcImage = pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z );

float ImgArray = (float)pSrcImage;

for (int i = 0; i < iWidthiHeight 3; i+=3) { ImgArray[i] = 0.0f; ImgArray[i+1] = 1.0f; ImgArray[i+2] = 0.0f; }

pSrcImage = (unsigned char*)ImgArray;

CUtlBuffer finBuf; pTex->Serialize(finBuf);

FILE *fin; fin = fopen("output.vtf", "w+b");

fwrite(finBuf.Base(), 1, srcVTFLength, fin); fclose(fin);`

This is meant to change the color of a particular bitmap to a green color. It successfully creates a working vtf file but it doesn't seem to modify its contents. It says that ImageData() returns a pointer to the bitmap data of the vtf interface for the selected face,frame, etc. So I'm considering that this pointer should be replacing the data of the vtf that I'm modifying unless it makes a copy of the data and returns the pointer to the copied data. If anyone has any info on this it would be much appreciated.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ValveSoftware/source-sdk-2013/issues/458, or mute the thread https://github.com/notifications/unsubscribe-auth/AGDYvk-BQAXdzZPKZz4gJpxBJt7ComFIks5uC6-pgaJpZM4VBYnA .

Mine228 commented 6 years ago

Oh so I found that the last bit of casting was unnecessary and I could just modify the value in the ImgArray and it would modify the vtf output. To answer your last question, pSrcImage is a pointer that points to whatever pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z ); returns.

FILE *vtfFp = fopen( pActualVTFFileName, "rb" );
    if( !vtfFp )
    {
        Error( "Can't open %s\n", pActualVTFFileName );
        exit( -1 );
    }

    fseek( vtfFp, 0, SEEK_END );
    int srcVTFLength = ftell( vtfFp );
    fseek( vtfFp, 0, SEEK_SET );

    CUtlBuffer buf;
    buf.EnsureCapacity( srcVTFLength );
    int nBytesRead = fread( buf.Base(), 1, srcVTFLength, vtfFp );
    fclose( vtfFp );
    buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );

    IVTFTexture *pTex = CreateVTFTexture();
    if (!pTex->Unserialize( buf ))
    {
        Error( "*** Error reading in .VTF file %s\n", pActualVTFFileName );
        exit(-1);
    }
Mine228 commented 6 years ago

Ok, so the last bit of the problem is that if I output the array into a .pfm file using

PFMWrite(ImgArray, pTempNameBuf, iWidth, iHeight);
static void PFMWrite( float *pFloatImage, const char *pFilename, int width, int height )
{
    FILE *fp;
    fp = fopen( pFilename, "wb" );
    fprintf( fp, "PF\n%d %d\n-1.000000\n", width, height );
    int i;
    for( i = height-1; i >= 0; i-- )
    {
        float *pRow = &pFloatImage[3 * width * i];
        fwrite( pRow, width * sizeof( float ) * 3, 1, fp );
    }
    fclose( fp );
}

it outputs a correctly working .pfm file with the whole image being colored either red, green or blue based on the "for" loop, but the .vtf seems to be addressed differently: https://imgur.com/RDh2RUf

the first image being

for (int i = 0; i < iWidth*iHeight * 3; i+=3)
{
    ImgArray[i] = 1.0f;
    ImgArray[i+1] = 0.0f;
    ImgArray[i+2] = 0.0f;
}

the second

for (int i = 0; i < iWidth*iHeight * 3; i+=3)
{
    ImgArray[i] = 0.0f;
    ImgArray[i+1] = 1.0f;
    ImgArray[i+2] = 0.0f;
}

and the third

for (int i = 0; i < iWidth*iHeight * 3; i+=3)
{
    ImgArray[i] = 0.0f;
    ImgArray[i+1] = 0.0f;
    ImgArray[i+2] = 1.0f;
}

I'm not sure how to solve this, and the strange thing is that it only colors the green channel and not the red or blue one.

Mine228 commented 6 years ago

Ok, so I figured it out. The image needs to be converted into an IMAGE_FORMAT_RGB323232F using ImageLoader::ConvertImageFormat(), later you can modify its content like a normal rgb stream of data after converting to float (range 0.0-1.0), then if you want to output it into a .vtf file you need to convert the image to something other than 32bpp like for example in my case IMAGE_FORMAT_RGBA16161616F, and it works perfectly.