I thought and just decided to continue working on my project: i need to make some improvements with my fonts:
- to compile fonts containing russian chars from russian fonts and other chars from english ones
- to add shadows to russian chars
- to add and probably fix some russian chars
I don't want to do that manually in bmp, i prefer to make most actions in c++ code.
Ok cool. I was thinking about doing something like this as an example, just for fixed pitch fonts where I could easily extract them from a screen grab.
At the same time i think working via .bmp is a very good idea.
So, my idea: to continue writing my code for exporting fnt to bmp and then to use your code to importing them back from .bmp to .fnt.
Ok, but my code is very dependant on the format being
exactly what it is expecting, so the format would have to be exactly the same. It would probably be easier to just use my export code as it is already 100% compatible with the import code. idc it's up to you.
So, i stole your code working with bmp and added it to my project.
Also updated my project on bitbucket.
You're very welcome to re-use my code. Thanks for crediting me in the comments
@Lambchops looks like your code and my code make different .bmp-files from the same fonts:
Differents touch palette only and increases from begin to end.
OK.
What I did for the bitmap handling in this project was this:
I got a wc2 .pcx SS and converted it to a bitmap (8 bit palette based, as is the native format for the game).
Then I discarded the pixel data (made it all black) and resized it to 64x64 pixels. Then I just converted the entire file to a c-style declaration.
*Have attached the original .bmp file just for interest's sake.This way it has all the default values for the bitmap headers and the wc2 palette already in place AND it is defined in the .data section so it can be also be directly used as the actual buffer (for read and write).
You can see that nowhere in the code is any other memory allocated to hold the bitmap - the BITMAPFILEHEADER and BITMAPINFOHEADER pointers are cast direcly over this initialsed data declaration, the pixels are modified there, when loading the files are read and written over this same place and when saving this region is saved directly to a file.
This was just a conveniant way to handle the bitmaps as only one bitmap is ever in memory at one time, so they can all use the same space. Plus all the values are already initialised, so less work... also I can cheat and define things like the pixmap pointer and the actual line width as globals (again less work
)
For example, i comparing mine and yours font10x_246.bmp (i changed char szBmpTmpl[] = "_%2.2X.bmp"; to char szBmpTmpl[] = "_%03d.bmp"; to make win sort files properly, that's the only change i made in your code):
0000042A: FC 00
0000042B: 00 C7
0000042E: FC 00
0000042F: FC 4A
00000432: FC 4A
00000433: FC 4A
As i understand, it's a palette, pixels begin from 00000436. And your code changes values from 1-st char to another, but my code gives similar values every time (and looks like they are similar with bmp8 array).
And i don't understand how that can happen: eighter you change the palette in bmp8 somehow (i didn't find that in your code) or that is a bug or something else i don't understand.
Yes for this case the pixmap always starts at offset 0x436, this is defined in BITMAPFILEHEADER.bfOffBits ( it's the 0x04360000 which is the 3rd DWORD in the declaration ). Add this value to the base address of the data and you have the address of the pixel data.
I'm not sure how you got the values you have posted (starting at 0000042A), but I can see what has occurred. You mention
font10x_246.bmp. 246 = 0xF6 and the
font10x.fnt file stops at 0xEF so I do not know the bitmap you are working with...
... that being said, yes this area holds the end of the palette. 0x042A... should be FC:00:FC:FC:FC:FC as per the first column you have posted.
This area has obviously been overwritten by pixel data as 00, C7 and 4A are all values from the clrndx[] array. Notably 0x4A is the grey color I put in for the .fnt pixel value of 3, and as previously mentioned the value 3 does not appear in font10x.fnt ( I just picked a grey color and put it there because EC said it was grey ).
MS .bmp format has a couple of peculiarities:
- Each line of pixel data is DWORD aligned.
- The pixel data is stored starting with the
bottom line first and the
top line last.
As the blizzard guys (and any other sane people) work with pixels from the top down, all the Y co-ordinates must be inverted when converting from .fnt to .bmp and back again.
This is handled in
get_pixel() and
set_pixel() by the line:
BYTE* pptr = pixmap+(linew*(bmh-y-1))+x;
bmh-y-1 inverts the pixel position then this is multiplied by linew
linew is the actual size of a pixel line in memory, which may be different from the width of the bitmap due to the DWORD alignment.
This size is calculated by:
linew = ((bmw+3)>>2)<<2;
This just ensures that the width is rounded up to the next 4-byte boundary.
.... so: back to the issue ...
If the palette is being overwritten then at some stage there is an extra line of pixels being written at the
bottom of a bitmap that won't fit... i.e. the bitmap has been defined with a height of 8 (lines 0->7) but then some pixels have been written to line 8.
When writing to a bitmap, if it is first defined with
init_bmp(w,h) and
set_pixel() is only used with x = 0 -> (w-1) and y = 0 -> (h-1) then the palette should never be written to.
I don't know what you are extracting when this error occurs, if you post the file you are using then I can comment more specifically.
The .bmp routines I wrote specifically for this project, they were not written to be 'safe' for general purpose use.
For debugging purposes you could use something like:
void Bmp::set_pixel(int x,int y,int c){
// set a pixel in the current bitmap
BYTE* pptr = pixmap+(linew*(bmh-y-1))+x;
if(x>=0&&y>=0&&x<bmw&&y<bmh){
*pptr = c;
}else{
std::cout << "Invalid Pixel Write Location\n";
}
}
Checked out your bitbucket you have done lots of cool stuff there, and for Warcraft II in general. PMd you some suggestions
Hope this is useful.
--- edit ---
Added an extra check to stop over-write. I didn't notice this because I was still looking at previous extracted bitmaps from before this issue was introduced. Had 0 effect on functionality, but better fixed. Thanks
@iL for testing.