PDA

View Full Version : another question... now about bitmaps


zoviac
10-07-2002, 02:06 PM
zoviac, lazy n00b who cant find tutorials himself, needs help. (again...)


so, how do i make a dos program wit djgpp or tc that shows bmp images? (pcx is fine too)

Kamikaze!
10-13-2002, 08:03 AM
The tutorials I found weren't very helpful and posting code is easier and clearer than explaining everything:
/*
pcx.h
Contains all pcx file and pallete functions
as well as the pcxfile structure.
*/
#include <stdio.h>

typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;

/*
PCX header information.
The first 128 bytes of a pcx file.
*/
struct pcxheader
{
byte version; // byte 1
//byte bpp; // bytes per pixel, byte 3
int xmin, ymin; // byte (4 + 5) and (6 + 7).
int xmax, ymax; // byte 8, size 2-2
};

/*
PCX file structure.
*/
struct pcxfile
{
struct pcxheader header; // pcx header.
int w, h; // width, height.
byte* pixels; // This holds all the pixels.
dword pixelcnt; // pixelcount (xsize * ysize) for pixels[].
char* file; // the pcx file used.
};

// PCX FILE FUNCTIONS
struct pcxfile load_pcx(char*);
void pcx_pal_extractor(char*, char*);
int ipow(int x, int y);
void draw_pcx_direct(struct pcxfile*, int, int, int);


/******************
PCX FUNCTIONS
*******************/

/********************
LOAD A PCX FILE
*********************/
struct pcxfile load_pcx(char* file)
{
FILE* f_in = fopen(file,"rb"); // pcxfile
struct pcxheader header; // pcx header
struct pcxfile pcx;
byte pixel, runlen, pixel2, n;
dword i = 0;
byte xexp,yexp;

pcx.file = file;

/* GET THE VERSION NUMBER */
fseek(f_in,1,SEEK_SET); // set to byte 1
header.version = fgetc(f_in); // Read the version number (should be 5).

/* GET BITS PER PIXELS */
//fseek(f_in,3,SEEK_SET);
//header.bpp = fgetc(f_in);

/*GET XMIN, YMIN, XMAX, YMAX */

// XMIN ( byte 4 & 5).
fseek(f_in,4,SEEK_SET);
header.xmin = fgetc(f_in);
header.xmin += fgetc(f_in);

//YMIN (byte 6 & 7).
header.ymin = fgetc(f_in);
header.ymin += fgetc(f_in);

//XMAX (byte 8 & 9).
header.xmax = fgetc(f_in);
xexp = fgetc(f_in); // this byte tells you how many times to add 256.

//YMAX ( byte 10 & 11).
header.ymax = fgetc(f_in);
yexp = fgetc(f_in); // this byte tells you how many times to add 256.



// Calculate the width and height of the pcx image.
pcx.w = header.xmax - header.xmin + (xexp * 256) + 1;
pcx.h = header.ymax - header.ymin + (yexp * 256) + 1;

pcx.pixelcnt = pcx.w * pcx.h; // Calculate the amount of pixels.

// resize the pixel array so it is exactly as large as the amount of pixels.
pcx.pixels = new byte[pcx.pixelcnt];

fseek(f_in,128,SEEK_SET); // set to the start of the pixel data ( byte 128).

// read the body
while(i < pcx.pixelcnt)
{
pixel = fgetc(f_in); // get a byte

// there is a pixel run
if ( pixel >= 192)
{
runlen = pixel - 192; // get the run length
pixel2 = fgetc(f_in); // get next byte

// pixel run
for (n=0; n<runlen; n++)
{
pcx.pixels[i + n] = pixel2; // set the pixel index
}

i += runlen - 1; // increment i accordingly
}
else // there is no pixel run
{
pcx.pixels[i] = pixel; // set the pixel index
}

i++; // increment i
}

fclose(f_in); // close f_in

pcx.header = header;

return pcx;
}


/**************************
PCX PALETTE EXTRACTOR
***************************/
void pcx_pal_extractor(char* infile, char* outfile)
{
FILE* fpal = fopen(infile,"rb");
FILE* fout = fopen(outfile,"wb");
byte b;

fseek(fpal,-768,SEEK_END); //goto start of palette
while (!feof(fpal))
{
b = fgetc(fpal);
fputc(b,fout);
}
fclose(fpal);
fclose(fout);
}

/*
Integer power function (because pow() returns a double)
*/
int ipow(int x, int y)
{
int i,r=x;
for(i=0; i<y-1; i++)
{
r*=x;
}
return r;
}

/*
Draw a pcxfile struct directly to the screen buffer
*/
void draw_pcx_direct(struct pcxfile* pcx, int x, int y, int mask = -1)
{
int i;
int x1, y1;

for(i = 0; i < pcx->w * pcx->h; i++) // loop through all pixels
{
x1 = (i % pcx->w); // get the x
y1 = (i - x1) / pcx->w; // get the y

if (pcx->pixels[y1 * pcx->w + x1] != mask) // draw the pixel
put_pixelb(x, y, pcx->pixels[y1 * pcx->w + x1]); // set the pixel (x,y,color)
}

}

Obviously there are some things specific for my library but it should be easy to figure out.

zoviac
10-15-2002, 05:00 AM
ok thx

zoviac
10-16-2002, 03:01 PM
there's a problem: "new byte[pcx.pixelcnt];"

Kamikaze!
10-16-2002, 03:37 PM
What did you change exactly? It works perfectly for me.

bwkaz
10-16-2002, 04:03 PM
Originally posted by zoviac
there's a problem: "new byte[pcx.pixelcnt];" That's C++ syntax; are you using a C++ compiler?

If so, what errors are you getting?

Kamikaze!
10-16-2002, 05:41 PM
Originally posted by bwkaz
That's C++ syntax; are you using a C++ compiler?

If so, what errors are you getting? Whoops, that right. Forgot to tell you. Compile your program with gxx -s <program>.cpp -o <program>.exe (where <program> is the name of your program of course).

zoviac
10-18-2002, 06:06 AM
hmm, i get more problems if i change it to cpp...

Kamikaze!
10-18-2002, 07:58 AM
Eh, you could try it with malloc() in C, but I'm not sure how malloc works exactly.

pcx.pixels = malloc(pcx.pixelcnt);

What errors are you getting exactly?

zoviac
10-22-2002, 03:43 PM
shit, theres too many.. and i would like it in c, not c++

Kamikaze!
10-23-2002, 12:51 PM
You output the errors to a text file with

gcc program.c -o program.exe > errors.txt

Put it in a batch file.

zoviac
10-24-2002, 01:57 PM
yo, i was looking for source on this, and found source for a pcx viewer, but it got some assembly shit, that aint workin good, it causes problems with the palette... so could u tell me how to change that into c:

void SetBlockPal( char Pal, char *Array, char Num ) {
asm {
push es
les di,Array
mov dx,di
xor ch, ch
mov cl, Num
mov ax, 0x1012
xor bh, bh
mov bl, Pal
int 0x10
pop es
}
}

Kamikaze!
10-25-2002, 06:41 PM
I don't know how assembly works, unfortunately (not good enough anyway).

sedarious
10-25-2002, 07:57 PM
Here is commenting. the *'d lines are most likely wrong.


push es ;moves the es register to a safe place so it can be preserved
les di,Array ;moves the segment of Array to es and offset to di
mov dx,di ;move di (offset of array) to dx
xor ch, ch ;set high 8 bits of ch to zero
* mov cl, Num ;move the offset of num to cl (incorrect)
* mov ax, 0x1012 ;not a valid al value for the 0x10 function for video services
xor bh, bh ;set high 8 bits of bh to zero
* mov bl, Pal ;moves offset of pal to bl (wrong)
int 0x10 ;call video service
pop es ;restore es


this is what I am THINKING it should be


push es ;moves the es register to a safe place so it can be preserved
les dx,Array ;moves the segment of Array to es and offset to dx
xor ch, ch ;set high 8 bits of ch to zero
mov cl,[Num] ;move the value of num to cl
mov ax, 0x1002 ;use to 0x10 function with the 0x02 subfuction
xor bh, bh ;set high 8 bits of bh to zero
mov bl,[Pal] ;moves value of pal to bl
int 0x10 ;call video service
pop es ;restore es


Its also important to note that this probably isn't what you want since it works with PCjr/EGA with are 16 colors with a border color. What I would recommend to you is this. Hit up gamedev.net and look for stuffs on bitmaps. Here is a short shopping list of what you are going to want to look for...

1. BMP file format
2. Changing/Restoring video mode
3. Writing data to the video buffer

If you don't know how to use memory allocation and file i/o you are going to need to learn that also.


edit: you could also use allegro - a complete vesa 2.0 games library for djgpp. You won't learn as much that way though.

zoviac
10-26-2002, 06:32 AM
well thx, but i was asking how to change that into c, i can see it has something to do wit regs and int86

zoviac
10-26-2002, 06:35 AM
and, i got a problem wit asm, it complains about statement missing and that kinda shit

zoviac
10-26-2002, 06:49 AM
ok, solved those problems, now it complains about not finding executable TASM

sedarious
10-26-2002, 11:31 AM
Its also important to note that this probably isn't what you want since it works with PCjr/EGA with are 16 colors with a border color.

This isn't what you want to be using. Unless you are working with a PCjr display or EGA color scheme and WANT you bitmap to display in 16 colors.

zoviac
10-26-2002, 02:55 PM
well.. hmm, ok.

anyway, the palette is fucked up, the colors aint the same as in paint shop pro.. i changed the asm into c:

void setblockpal(char pal, char *array, char num)
{
union REGS regs;
struct SREGS sregs;
regs.x.di = *array;
regs.x.dx = regs.x.di;
regs.h.cl = num;
regs.x.ax = 0x1012;
regs.h.bl = pal;
int86(0x10, &regs, &regs);
}

so... what is wrong wit that, it views the image, but as i said, the palette aint workin good

and kamikaze, could u tell me how to use the code u gave, i dont know how to use the functions right...

zoviac
10-26-2002, 03:17 PM
hmm, in86(0x10, & regs, & regs);

thats one fucked up thing

Kamikaze!
10-27-2002, 04:08 PM
Because the VGA pallette actually uses values 0-64 you have to divide the RGB values by 4, or better yet: bitshift them to the right by 2.

My pallette function:

#define PALETTE_MASK 0x3C6
#define PALETTE_READ 0x3C7
#define PALETTE_WRITE 0x3C8
#define PALETTE_DATA 0x3C9

void set_palette_color( byte index, byte r, byte g, byte b)
{
vsync(); // sync with monitor
outportb(PALETTE_MASK, 0xff);
outportb(PALETTE_WRITE, index);
outportb(PALETTE_DATA, r >> 2); // <= This is bitshift to the right
outportb(PALETTE_DATA, g >> 2);
outportb(PALETTE_DATA, b >> 2);
}

You'd probably understand my code better if you can see all of it: http://www.xs4all.nl/~cmeelker/public/vgalib.zip
(protip: start with mcga.h and pcx.h - Those have the functions you need)

Also: http://www.xs4all.nl/~cmeelker/public/mcgadoc.zip (I made it because at some point I'll officially upload it somewhere :) Also, I was bored)

zoviac
10-28-2002, 09:20 AM
i do it as it was in the doc, and it only puts a purple pixel in the middle of the screen...

sedarious
10-28-2002, 10:46 AM
/me bangs head against desk...

Kamikaze!
10-28-2002, 02:10 PM
I suggest looking at my code a bit more, I know it works. I've tested on several computers (only with a small test program though).

Pallette functions are explained here: http://www-scf.usc.edu/~akotaobi/gptut.html

zoviac
10-28-2002, 03:55 PM
aww fuck, there s something wrong wit my cpu, it just doesnt want to work... i compiled the program, didnt do any changes, and still it just shows black screen or one pixel...

zoviac
10-28-2002, 04:07 PM
and i would like to have it workin in borland C...

sans-hubris
10-28-2002, 04:13 PM
zoviac, please edit your posts instead of having multiple responses of your own in a row.

sedarious
10-28-2002, 04:30 PM
zoviac, posts like

Originally posted by zoviac
aww fuck, there s something wrong wit my cpu, it just doesnt want to work... i compiled the program, didnt do any changes, and still it just shows black screen or one pixel...

dont really help in getting a problem solved. Programming requires thought, analysis and time. It seems that you aren't investing much of any of them in this project. Nor are you listening to what we have to tell you. Most people here are willing to help from what I have seen, but we aren't going to invest hours of our time in your problem. I apologize if I seem harsh.

The best way to get a solid answer is to ask a solid and direct question. Saying a peice of code doesn't work and giving us where it breaks isn't really all that helpful. If you have problems with a specific function, make a small app to test it. If that fails, post your code (via attatchment if its long) so we can see the entire picture.

Kamikaze!
10-28-2002, 04:50 PM
It doesn't work in Borland anyway. Only in DJGPP and maybe Turbo C (but I've never tried Turbo C and you'd have to change your code a lot anyway).

Make some small program with my lib (use the test program, vga.cc - It's in the zip file) and see if that works (it should).

zoviac
10-29-2002, 02:53 PM
ive been looking at the docs and the code, and tried to understand it as much as i can, and i wrote this:

#include <dos.h>
#include <conio.h>
#include "include/mcga.h"
#include "include/common.h"
#include "include/pcx.h"


int main()
{
struct pcxfile pcx;
pcx = load_pcx("ship.pcx");
set_mode(0x13);
draw_pcx_direct(&pcx, 100, 100, 0);
getch();
set_mode(0x03);
return 0;
}

kamikaze could you correct that code

zoviac
10-29-2002, 03:36 PM
OK, i got it, thx for your help yall. (i looked at brackeen.com tutorial, which is for bmp files, if u still wanna help wit that pcx shit, it would be really nice, but its not so important anymore..)

Kamikaze!
10-29-2002, 04:45 PM
Don't be alarmed, the code just looks big because of the comments!

getch() didn't work for some reason, I have no clue why :\
draw_pcx_direct() doesn't work yet either. I completely forgot to test it.

Basically you forgot 2 things: Load a pallette file after set_mode() and using a main loop (technically init_regions() too but that comes with pcx_draw_simple() so that's not your fault).

I do think pcx files are easier to use for this kind of programs, because pcx files have a very simple format and their default color depth is 256 colors, instead of 16 million like bmp files). Pcx files are smaller too. It's good if bmp files work though, as long if you put the pixels (well, their values) in one large array, 'cause that's faster to use and everything.

The code looks like a mess because vBulletin fucked my tabs up :(

Also, compile it with gxx (gxx vga.cpp -o vga.exe). I'm sorry but it doesn't work with C yet.


// headers need to be included in a certain order, I'm going to remove that
// (seemed like a good idea to auto-include headers in other headers in my head)
#include "include/mcga.h" // mcga graphics functions
#include "include/common.h" // includes common typedefs etc
#include "include/pcx.h" // pcx functions
#include "include/regions.h" // regions
#include "include/draw.h" // drawing functions
#include "include/keyboard.h" // keyboard

/**********
MAIN
***********/
int main(int argc, char* argv[])
{
bool ext; // when this bool is true the loop exits
struct palette p; // the pcx pallette file
struct pcxfile pcx;

set_mode(0x13); // first wwe set the mode
init_regions(); // then we init the regions (actually just sets g_region[0] to the default values).
// regions are portions of the screen where images are drawn on. think of them as boundaries. g_region[0] is the whole screen.
install_key_interrupt(); // install the keyboard interrupt handler

pcx = load_pcx("ship.pcx"); // load a pcx file

p = load_pal("stdpal.rpl"); // load the pallette file. you can extract a pallette from a .pcx file with pcx_pal_extractor().
apply_pal(p); // apply the pallette (copy the values into the video memory)

while(!ext) // loop while ext is not true. this is the main loop
{

// getch() doesnt work for some reason. I have no clue why not. The keyboard handler is vastly superior though.
if(tbl[KEY_ESC]) // escape is pressed
ext = true;

// draw_pcx_direct() doesnt work yet apparently
pcx_draw_simple(&pcx,&g_region[0], 100,100,0, 0, 0); // draw the pcx to the video buffer (just a large byte array).
// arguments: address of pcxfile struct, address of g_region struct (use g_region[0])
// x, y, mask/transparent color

blit(); // copy the video buffer to the video memory and clear the buffer
}

// if we are here it means the loop was exited

uninstall_key_interrupt(); // uninstall the keyboard handler. we dont want other programs using our handler.
set_mode(0x03); // return to text mode

return 0;
}

zoviac
10-30-2002, 10:39 AM
ok i got that too, thanx yall, see u in next thread :)