Viacom New Media Graphics File Format

From ModdingWiki
Jump to navigation Jump to search
Viacom New Media Graphics File Format
Viacom New Media Graphics File Format.png
Format typeTileset
HardwareVGA
Max tile count232-1
PaletteInternal
Tile names?No
Minimum tile size (pixels)0×0
Maximum tile size (pixels)Unlimited
Plane count1
Plane arrangementLinear
Transparent pixels?Palette-based
Hitmap pixels?No
Metadata?None
Supports sub-tilesets?No
Compressed tiles?Yes
Hidden data?Yes
Games

Beavis and Butthead In Virtual Stupidity stores its graphics externally in .VNM/.000 files. This information here is preliminary and needs verification and is subject to change.

VNM_HEADER: VNM File Header

Data Type Description
UINT32LE Signature File Signature (should match 0x564E4D1A aka "VNM\x1A")
UINT32LE Flags Possibly file information flags.
UINT32LE Size Size Of Data
UINT32LE OffsetPal Offset to Pal Data.
UINT32LE OffsetUnknown1 Offset to currently Unknown Data.
UINT32LE OffsetUnknown2 Offset to currently Unknown Data.
UINT32LE OffsetImages Offset to VNM_IMAGE array.
UINT32LE PalIndexFirst First Valid Index in Colour Palette.
UINT32LE PalIndexSize Count of Palette Indexes stored in file at OffsetPal.
UINT32LE ImageCount Count of Images stored in file at OffsetImages.

VNM_IMAGE: VNM Image Header

Data Type Description
UINT32LE Offset Offset in file to where raw image data starts.
UINT32LE Type 0 = Bitmap, 1 = Sprite
UINT32LE Width Width of this Image
UINT32LE Height Height of this Image.
UINT32LE XPos XPos of this Image.
UINT32LE YPos YPos of this Image.

Example code

This is test code that decompresses/decodes/extracts Sprite 196 from VNM raw data in the BBLOOGIE Mini-game. Image can be seen in the infobox.

spr196.zip

An somewhat explained version of the raw data is below.

F800                          19 FD00  18F700                              0F                 FB 
F901                       18 19 FF00  18FF0117 19             F801        0E 10 FD00  0F 
FA07                       19 18 18 17 18 19 17 19             F801        0E 10 FD00  0F 
FA08                    19 17 19 19 17 19 18 18 19 FF00  19    FB05     0F 11 0F 11 0F 10 
FB0B                    19 18 17 19 18 17 18 18 17 19 17 18    FB05     10 11 10 11 0E 11 
FB0C                    18 18 19 19 18 17 18 19 17 19 17 19 18 FC04     11 0E 0F 10 0E        FF 
FC0D                 19 17 19 18 19 19 17 18 19 17 18 17 19 18 FD05     10 0E 11 10 11 0F     FF 
FC0D                 19 17 19 18 19 17 18 19 17 18 19 17 19 17 FD05     10 0F 11 11 10 11     FF 
FC0D                 18 17 19 17 18 17 19 18 17 18 19 18 19 19 FC04     11 10 10 0F 10        FF 
FC0E                 18 18 19 17 17 19 19 18 17 18 19 19 18 19 18 FD03  11 0F 0F 10           FE 
FC0E                 19 18 19 18 19 18 19 18 17 18 19 18 17 18 19 FD02  11 11 10              FD 
FC0E                 19 18 19 18 19 17 19 19 17 18 19 17 17 19 19 FD02  11 10 0F              FD 
FC0E                 19 17 18 10 0F 18 19 17 18 19 19 18 17 19 19 FD02  11 0F 10              FD 
FC0E                 18 17 19 0F 0E 0F 18 18 19 0F 10 18 17 19 18 FD02  11 0F 10              FD 
FC0E                 19 17 19 0E 0E 0E 0E 0E 0E 0E 0E 0F 18 19 18 FD02  11 0E 10              FD 
FC0E                 19 18 10 0E 0F 0F 0E 0E 0E 0E 0F 0F 10 17 19 FD02  11 0E 10              FD 
FC0E                 18 19 0F 10 11 11 10 0E 0F 10 11 10 0F 17 19 FD02  11 0E 10              FD 
FC0E                 17 19 0E 0F 10 10 11 0F 10 11 10 0F 0E 18 19 FD02  11 0E 10              FD 
FC0E                 19 17 10 0E 0F 0E 0F 0E 10 0F 0E 0E 0E 19 18 FD02  11 0E 10              FD 
FC0E                 18 11 0F 0E 0E 0F 10 0E 0E 10 0F 0E 0E 19 17 FD02  11 0E 10              FD 
FB0D                 10 0F 0E 0E 10 11 0F 11 10 10 0E 0F 10 17 FD02     10 0E 11              FD 
FB0C                 11 10 0F 0E 0E 0F 10 10 0F 0F 0E 0F 0FFC02         10 0E 11              FD 
FA0B                    11 0F 0E 0E 0E 0F 0F 0F 0E 0E 0F 11FC02         0E 0F 11              FD 
FA0B                    11 10 0F 0E 0F 20 10 20 0F 0E 0F 11FD02      10 0E 10                 FC 
F90A                       10 0F 0E 10 20 20 20 10 0F 10 11FD02      0E 0F 11                 FC 
F909                       11 0F 0E 11 15 16 15 11 0F 10FD02      10 0E 10                    FB 
F909                       11 0F 0E 11 1C 1C 1C 11 0F 11FD02      0E 0F 11                    FB 
F808                          10 0F 10 11 1C 11 10 0F 11FE02   10 0E 10                       FA 
F807                          10 0F 0F 10 11 10 0F 10FE03   10 0E 0F 11                       FA 
F807                          11 10 0F 0E 0F 0E 0F 11FF041B 10 0E 10 11                       FA 
F70B                             11 10 0F 0E 0F 10 11 17 1B 10 0F 11                          F9 
F70B                             11 10 10 10 10 11 17 1B 1A 1B 10 11                          F9 
F60A                                11 10 0F 10 11 1C 1B 1A 1A 1B 1B                          F9 
F70B                             1B 1B 10 10 10 1B 1C 1B 1A 1A 1A 1C                          F9 
F90D                       1B 1B 1A 1A 1B 1B 1B 1A 1B 1A 1A 1A 1B 1C                          F9 
FA0D                    1B 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                             F8 
FB0E                 1B 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                             F8 
FC0E              1B 1A 1A 1A 1B 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                                F7 
FC0E              1B 1A 1A 1B 1C 1B 1A 1A 1A 1A 1A 1A 1B 1B 1C                                F7 
FD0F           10 10 1B 1B 1C 1B 1B 1A 1A 1A 1A 1A 1A 1B 1B 1C                                F7 
FD0F           10 0F 10 1C 1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1B 1C                                F7 
FE03        10 0E 10 11FF0A1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
FE02        10 0F 11   FE0A1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
FF03     10 0E 10 11   FE0A1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
FF02     10 0F 11   FD0A   1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
FF02     10 10 11   FD0A   1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 0F 10      FC0A   1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 0E 11      FC0A   1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 0E 11      FC0A   1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 0E 11      FC0A   1C 1B 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 0E 11      FD0B1C 1B 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 0F 11      FD0B1C 1B 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
02    10 10 11      FD0B1C 1B 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
03    10 0F 0F 10   FE0B1C 1B 1A 1A 1A 1A 1A 1A 1A 1A 1B 1C                                   F6 
04    11 0E 10 0F 10FF0B1C 1B 1B 1A 1A 1A 1A 1A 1A 1B 1B 1C                                   F6 
03    11 0E 0F 11   FE0B1C 1C 1C 1B 1B 1B 1B 1B 1B 1C 1C 1C                                   F6 
03    11 0F 0E 10   FE0B22 22 22 21 21 21 21 21 21 21 22 22                                   F6 
FF02     11 11 11   FE0B22 21 21 20 20 20 20 20 20 20 21 22                                   F6 
FA0B                    22 21 20 20 20 20 20 20 20 20 21 22                                   F6 
FA0B                    22 21 20 20 20 21 20 20 20 20 21 22                                   F6 
FA0B                    22 21 20 20 21 22 21 20 20 20 21 22                                   F6 
FA0B                    22 21 20 20 21 22 22 21 20 20 21 22                                   F6 
FA0B                    22 21 21 21 21 22 22 21 21 21 21 22                                   F6 
F909                       11 10 0F 10 11 11 10 0F 10 11                                      F5 
F909                       11 0F 0E 0F 11 11 0F 0E 0F 11                                      F5 
F909                       11 0F 0E 0F 11 11 0F 0E 0F 11                                      F5 
F909                       11 0F 0E 0F 11 11 0F 0E 0F 11                                      F5 
F909                       11 0F 0E 0F 11 11 0F 0E 0F 11                                      F5 
F909                       11 10 0E 0F 11 11 0F 0E 10 11                                      F5 
F807                          11 0E 0F 11 11 0F 0E 11                                         F4 
F807                          11 0E 0F 11 11 0F 0E 11                                         F4 
F807                          11 0E 0F 11 11 0F 0E 11                                         F4 
F807                          11 0E 0F 11 11 0F 0E 11                                         F4 
F807                          11 0E 10 11 11 10 0E 11                                         F4 
F802                          16 16 16  FE02 16 16 16                                         F4 
F802                          16 15 16  FE02 16 15 16                                         F4 
F802                          16 15 16  FE02 16 15 16                                         F4 
F802                          16 15 16  FE02 16 15 16                                         F4 
F807                          1C 1C 1C 1C 1C 1C 1C 1C                                         F4 
FA0B                    1C 1B 1A 1B 1B 1C 1C 1B 1B 1A 1B 1C                                   F6 
FB0D                 1C 1B 1A 1B 1B 1C 1C 1C 1C 1B 1B 1A 1B 1C                                F7 
FB04                 1C 1C 1C 1C 1C     FC04    1C 1C 1C 1C 1C                                F7

Some current BETA demo code is below. Fully functional.

// 
// .VNM/.000 Image Extractor - by Napalm
// BETA - Please do not use this in production mods
// 
// License: Creative Commons Attribution-Share Alike 2.0 UK: England & Wales
// http://creativecommons.org/licenses/by-sa/2.0/uk/
// 
// If you use this all or part of my code please credit me as the license states.
// 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pshpack2.h>
typedef struct _BITMAPFILEHDR {
	unsigned short type;
	unsigned long  size;
	unsigned short reserved1;
	unsigned short reserved2;
	unsigned long  offset;
} BITMAPFILEHDR;

typedef struct _BITMAPINFOHDR {
	unsigned long  size;
	  signed long  width;
	  signed long  height;
	unsigned short planes;
	unsigned short bitcount;
	unsigned long  compression;
	unsigned long  image_size;
	  signed long  x_per_meter;
	  signed long  y_per_meter;
	unsigned long  colors_used;
	unsigned long  colors_important;
} BITMAPINFOHDR;
#include <poppack.h>

typedef struct _VNMSPRITE {
	unsigned long offset; // to bitmap/frame data
	unsigned long type;   // 0 = Bitmap, 1 = Sprite
	  signed long width;
	  signed long height;
	  signed long x;
	  signed long y;
} VNMSPRITE;

typedef struct _VNMHEADER {
	unsigned long signature;     // 0x564E4D1A 'VNM\x1A' // 1.10 version?
	unsigned long zero;          // 0         ? start of file? always zero?
	unsigned long size;          // 324764    ? size of file
	unsigned long paletteoffset; 
	unsigned long offset1;		 // fixed 256 long array of something?
	unsigned long offset2;		 // fixed 256 long array of something?
	unsigned long spriteoffset;  //
	unsigned long palettestart;  // 10  start palette index?
	unsigned long palettesize;   // 236 number of palette entries?
	  signed long spritecount;   // 212 number of sprite index?
} VNMHEADER;


void extractpalette(unsigned long *palette, unsigned char *data,
				   unsigned long start, unsigned long size)
{
	unsigned char buffer[4];
	unsigned long index;

	buffer[3] = 0;
	memset(palette, 0, sizeof(unsigned long) * 256);
	for(index = start; index < (start + size); index++){
		buffer[0] = (data[2] << 2);
		buffer[1] = (data[1] << 2);
		buffer[2] = (data[0] << 2);
		data += 3;
		palette[index] = *(unsigned long *)buffer;
	}
}

void extractbitmap(FILE *bmp, unsigned char *buffer,
				   VNMSPRITE *spr, BITMAPINFOHDR *bmpinfo, long rounding)
{
	unsigned char *line = (buffer + spr->offset + bmpinfo->image_size);
	char zerobuffer[4] = { 0 };

	while(line > buffer + spr->offset){
		line -= spr->width;
		fwrite(line, 1, spr->width, bmp);
		if(rounding)
			fwrite(zerobuffer, 1, rounding, bmp);
	}
}

void extractsprite(FILE *bmp, unsigned char *buffer,
				   VNMSPRITE *spr, BITMAPINFOHDR *bmpinfo, long rounding, int transparent)
{
	unsigned long *index = (unsigned long *)(buffer + spr->offset);
	unsigned char *row;
	char zerobuffer[4] = { 0 };
	int y, j, pixel, count, width, escape;

	escape = (0x100 - spr->width);
	for(y = (spr->height - 1); y >= 0; y--){
		row = (buffer + index[y]);
		j = width = spr->width;
		while(j > 0){
			pixel = *row++;
			if(pixel >= escape){
				count = (0x100 - pixel);
				pixel = transparent;
				row++; // whats this byte for?
				while(count-- && j--)
					fputc(pixel, bmp);
			}else if(j == width && pixel < escape){
				width++;
			}else{
				fputc(pixel, bmp);
				j--;
			}
		}
		if(rounding)
			fwrite(zerobuffer, 1, rounding, bmp);
	}
}

void initbmpheaders(BITMAPFILEHDR *filehdr, BITMAPINFOHDR *infohdr)
{
	memset(filehdr, 0, sizeof(BITMAPFILEHDR));
	memset(infohdr, 0, sizeof(BITMAPINFOHDR));
	infohdr->size        = sizeof(BITMAPINFOHDR);
	infohdr->planes      = 1;
	infohdr->bitcount    = 8; // BI_8_BIT
	infohdr->compression = 0; // BI_RGB
	filehdr->type        = 'MB';
	filehdr->offset      = sizeof(BITMAPFILEHDR) +
		infohdr->size + (sizeof(unsigned long) * 256);
}

int main(int argc, char *argv[])
{
	unsigned long palette[256], *index;
	unsigned char *buffer;
	BITMAPFILEHDR bmpfile;
	BITMAPINFOHDR bmpinfo;
	VNMHEADER *hdr;
	VNMSPRITE *spr;
	FILE *vnm, *bmp;
	long size, i, rounding;
	char name[32];
	
	vnm = fopen(argv[1], "rb");
	if(!vnm){
		perror(argv[1]);
		exit(1);
	}
	fseek(vnm, 0, SEEK_END);
	size = ftell(vnm);
	fseek(vnm, 0, SEEK_SET);

	buffer = (unsigned char *)malloc(size);
	if(!buffer){
		perror("malloc filesize");
		exit(1);
	}
	fread(buffer, 1, size, vnm);
	fclose(vnm);

	hdr = (VNMHEADER *)buffer;
	if(hdr->signature != 0x564E4D1A && hdr->signature != 0x1A4D4E56){
		perror("invalid vnm signature");
		free(buffer);
		exit(1);
	}

	extractpalette(palette, buffer + hdr->paletteoffset, hdr->palettestart, hdr->palettesize);
	initbmpheaders(&bmpfile, &bmpinfo);
	
	index = (unsigned long *)(buffer + hdr->spriteoffset);
	for(i = 0; i < hdr->spritecount; i++){ // 
		spr = (VNMSPRITE *)(buffer + index[i]);
		printf("spr %#3d: %c(%#3d,%#3d)-(%#3d,%#3d)\n", i, ((spr->type) ? 'S':'B'),
			spr->x, spr->y, spr->width, spr->height);
		
		rounding = (spr->width % 4);
		if(rounding > 0) rounding = (4 - rounding);
		bmpinfo.width      = spr->width;
		bmpinfo.height     = spr->height;
		bmpinfo.image_size = ((spr->width + rounding) * spr->height);
		bmpfile.size       = (bmpfile.offset + bmpinfo.image_size);
		
		sprintf(name, "output\\%03d.bmp", i);
		bmp = fopen(name, "wb");
		if(!bmp){
			sprintf(name, "error opening %03d.bmp", i);
			perror(name);
			exit(1);
		}

		fwrite(&bmpfile, sizeof(bmpfile), 1, bmp);
		fwrite(&bmpinfo, sizeof(bmpinfo), 1, bmp);
		fwrite(palette,  sizeof(palette), 1, bmp);
		
		if(spr->type)
			extractsprite(bmp, buffer, spr, &bmpinfo, rounding, 189); // 187
		else
			extractbitmap(bmp, buffer, spr, &bmpinfo, rounding);
		
		fclose(bmp);
	}

	free(buffer);
	return 0;
}

Credits

This file format was reverse engineered by Napalm.