Bitmaps in MCGA

Please use this Board for QBasic related requests ( file research, programming, etc.)

Moderators:Administrator, Global Moderator

Post Reply
Xus
Bitmaps in MCGA

Post by Xus » Fri Jan 21, 2005 6:30 pm

Putting aside my general lack of knowledge, can someone please tell me where I can get a program to display 256 color bitmaps in screen mode 13. I can't seem to find one that works; they all seem to distort the pic in some way or another. That, or a lot of them use some screwy palette thing (see general lack of knowledge) so that when I modify the program to try and save the picture as a gfx, it screws up the colors and deletes about 4 pixels from the bottom right corner. Please, someone help! I didn't spend 10 hours designing tiles on Paint so that I can fail at loading them into QBasic. Speed of the program is not an issue. I want the simplest thing possible for 256 colors, 320x200 pixels. Thanks for even taking the time to read this ridiculously long post.

Dr_Davenstein
QBasic God
Posts:166
Joined:Tue Mar 25, 2003 12:45 am
Location:U.S.A.
Contact:

Post by Dr_Davenstein » Fri Jan 21, 2005 11:57 pm

Well, if your image is missing pixels like that, it's usually due to not allocating enough memory to store the image. The standard formula for screen 13 is:

Code: Select all

MemSize% = ((ImageWidth% * ImageHeight%) / 2) + 2
As for a .bmp loader, there are tons of them around. Here's one that uses assembly!

Code: Select all

' Bmpload Version 2 By Doug Barry (PD Computers)
'  This is the fastest BMP Loader I have ever seen, and I wrote it !!!!
'  God it's fast, anyway it uses assembler to copy a variable to the another
'  part of the memory, here I have used it to put the image data into the
'  bit of the Physical ram that overlaps the video memory, hence loading
'  the picture in one vertical blank space (one 50Hz cycle)
'
' Thanks load to Dan Holmes for finding out the memory copying routine, and
'  Andrew Griffin/Jon Sutton for info on the BMP structure.
'  Also to the guy/gal that posted ShowBMP9.bas on the net and to the
'  guy/gal that wrote CPLASMA.BAS for the "OUT" command for palette setting.

' Enjoy, even though it's uncommented it should be easy to understand,
'  being only 65, yes count 'em 65 lines of code (WOW!!!!!!!!).

' My E-Mail is pdcomputers@iname.com
' or s3dougla@doreen.rainhammark.kent.sch.uk if this don't work.
' i will try to reply and help with any of your problems.

DECLARE SUB SetPALETTE (Slot%, R%, G%, B%)
DECLARE SUB memcopy (fromseg%, fromoffset%, toseg%, tooffset%, bytes%)
DIM SHARED Buffer(319, 199) AS STRING * 1
DIM SHARED Pointer AS STRING * 1
DIM SHARED ImageDataSegment(200) AS STRING * 320
DEFINT A-Z
FileName$ = LCASE$(LTRIM$(RTRIM$(COMMAND$)))
'FileName$ = "Test.Bmp"
OPEN FileName$ FOR BINARY AS #1
IF LOF(1) < 2 THEN PRINT "File does not exist": KILL FileName$: SYSTEM
GET #1, 54, Pointer
SCREEN 13
FOR Slot% = 0 TO 255
 GET #1, , Pointer
 B% = INT(ASC(Pointer) / 4)
 GET #1, , Pointer
 G% = INT(ASC(Pointer) / 4)
 GET #1, , Pointer
 R% = INT(ASC(Pointer) / 4)
 SetPALETTE Slot%, R%, B%, G%
 GET #1, , Pointer
NEXT Slot%
FOR Y = 199 TO 0 STEP -1
  GET #1, , ImageDataSegment(Y)
NEXT
CLOSE
memcopy VARSEG(ImageDataSegment(0)), VARPTR(ImageDataSegment(0)), &HA000, 0, &HFA00
SYSTEM

SUB memcopy (fromseg%, fromoffset%, toseg%, tooffset%, bytes%)
  asm$ = ""
  asm$ = asm$ + CHR$(85)
  asm$ = asm$ + CHR$(137) + CHR$(229)
  asm$ = asm$ + CHR$(30)
  asm$ = asm$ + CHR$(139) + CHR$(70) + CHR$(10)
  asm$ = asm$ + CHR$(142) + CHR$(192)
  asm$ = asm$ + CHR$(139) + CHR$(70) + CHR$(14)
  asm$ = asm$ + CHR$(142) + CHR$(216)
  asm$ = asm$ + CHR$(139) + CHR$(118) + CHR$(8)
  asm$ = asm$ + CHR$(139) + CHR$(126) + CHR$(12)
  asm$ = asm$ + CHR$(139) + CHR$(78) + CHR$(6)
  asm$ = asm$ + CHR$(243)
  asm$ = asm$ + CHR$(164)
  asm$ = asm$ + CHR$(31)
  asm$ = asm$ + CHR$(93)
  asm$ = asm$ + CHR$(203)
  WAIT &H3DA, 8
  DEF SEG = VARSEG(asm$)
    CALL Absolute(BYVAL fromseg%, BYVAL fromoffset%, BYVAL toseg%, BYVAL tooffset%, BYVAL bytes%, SADD(asm$))
  DEF SEG
END SUB

SUB SetPALETTE (Slot, R, G, B)
  OUT &H3C8, Slot
  OUT &H3C9, R
  OUT &H3C9, B
  OUT &H3C9, G
END SUB
Come check out [url=http://www.freebasic.net/forum/index.php]FreeBASIC[/url]. The syntax is based on QuickBasic, but it expands to use pointers, operator overloading, etc... The list goes on and on!

(Xus)

Post by (Xus) » Sat Jan 22, 2005 9:12 pm

Thanks much, good sir. You are a huge help.

(Xus)

Post by (Xus) » Sun Jan 23, 2005 12:39 am

In 'memcopy' it says "CALL Absolute", but that's not a sub at all. Also, if I were to use BSAVE for a pic I load, and open it with BLOAD, would it distort the colors on the pic?

Dr_Davenstein
QBasic God
Posts:166
Joined:Tue Mar 25, 2003 12:45 am
Location:U.S.A.
Contact:

Post by Dr_Davenstein » Sun Jan 23, 2005 1:36 am

CALL ABSOLUTE is the QuickBasic function that calls an assembly language procedure. You need to include QB.BI to use it. Here's a copy of QB.BI in case you don'y have it.

Code: Select all

'***
' QB.BI - Assembly Support Include File
'
'       Copyright <C> 1987 Microsoft Corporation
'
' Purpose:
'      This include file defines the types and gives the DECLARE
'       statements for the assembly language routines ABSOLUTE,
'       INTERRUPT, INTERRUPTX, INT86OLD, and INT86XOLD.
'
'***************************************************************************
'
' Define the type needed for INTERRUPT
'
TYPE RegType
     ax    AS INTEGER
     bx    AS INTEGER
     cx    AS INTEGER
     dx    AS INTEGER
     bp    AS INTEGER
     si    AS INTEGER
     di    AS INTEGER
     flags AS INTEGER
END TYPE
'
' Define the type needed for INTERUPTX
'
TYPE RegTypeX
     ax    AS INTEGER
     bx    AS INTEGER
     cx    AS INTEGER
     dx    AS INTEGER
     bp    AS INTEGER
     si    AS INTEGER
     di    AS INTEGER
     flags AS INTEGER
     ds    AS INTEGER
     es    AS INTEGER
END TYPE
'
'                 DECLARE statements for the 5 routines
'                 -------------------------------------
'
' Generate a software interrupt, loading all but the segment registers
'
DECLARE SUB INTERRUPT (intnum AS INTEGER,inreg AS RegType,outreg AS RegType)
'
' Generate a software interrupt, loading all registers
'
DECLARE SUB INTERRUPTX (intnum AS INTEGER,inreg AS RegTypeX, outreg AS RegTypeX)
'
' Call a routine at an absolute address.
' NOTE: If the routine called takes parameters, then they will have to
'       be added to this declare statement before the parameter given.
'
DECLARE SUB ABSOLUTE (address AS INTEGER)
'
' Generate a software interrupt, loading all but the segment registers
'       (old version)
'
DECLARE SUB INT86OLD (intnum AS INTEGER,_
		      inarray(1) AS INTEGER,_
		      outarray(1) AS INTEGER)
'
' Gemerate a software interrupt, loading all the registers
'       (old version)
'
DECLARE SUB INT86XOLD (intnum AS INTEGER,_
		       inarray(1) AS INTEGER,_
		       outarray(1) AS INTEGER)
'

Copy the code from above and paste it into a new .txt file in your QB45 dir and save it. Then, rename the file QB.BI. At the beginning of your program, add this line:

Code: Select all

'$INCLUDE: 'QB.BI'
So, the .bmp loading program should look like this:

Code: Select all

'$INCLUDE: 'QB.BI'

DECLARE SUB SetPALETTE (Slot%, R%, G%, B%)
DECLARE SUB memcopy (fromseg%, fromoffset%, toseg%, tooffset%, bytes%)
DIM SHARED Buffer(319, 199) AS STRING * 1
DIM SHARED Pointer AS STRING * 1
DIM SHARED ImageDataSegment(200) AS STRING * 320
DEFINT A-Z
FileName$ = LCASE$(LTRIM$(RTRIM$(COMMAND$)))
'FileName$ = "Test.Bmp"
OPEN FileName$ FOR BINARY AS #1
IF LOF(1) < 2 THEN PRINT "File does not exist": KILL FileName$: SYSTEM
GET #1, 54, Pointer
SCREEN 13
FOR Slot% = 0 TO 255
 GET #1, , Pointer
 B% = INT(ASC(Pointer) / 4)
 GET #1, , Pointer
 G% = INT(ASC(Pointer) / 4)
 GET #1, , Pointer
 R% = INT(ASC(Pointer) / 4)
 SetPALETTE Slot%, R%, B%, G%
 GET #1, , Pointer
NEXT Slot%
FOR Y = 199 TO 0 STEP -1
  GET #1, , ImageDataSegment(Y)
NEXT
CLOSE
memcopy VARSEG(ImageDataSegment(0)), VARPTR(ImageDataSegment(0)), &HA000, 0, &HFA00
SYSTEM

SUB memcopy (fromseg%, fromoffset%, toseg%, tooffset%, bytes%)
  asm$ = ""
  asm$ = asm$ + CHR$(85)
  asm$ = asm$ + CHR$(137) + CHR$(229)
  asm$ = asm$ + CHR$(30)
  asm$ = asm$ + CHR$(139) + CHR$(70) + CHR$(10)
  asm$ = asm$ + CHR$(142) + CHR$(192)
  asm$ = asm$ + CHR$(139) + CHR$(70) + CHR$(14)
  asm$ = asm$ + CHR$(142) + CHR$(216)
  asm$ = asm$ + CHR$(139) + CHR$(118) + CHR$(8)
  asm$ = asm$ + CHR$(139) + CHR$(126) + CHR$(12)
  asm$ = asm$ + CHR$(139) + CHR$(78) + CHR$(6)
  asm$ = asm$ + CHR$(243)
  asm$ = asm$ + CHR$(164)
  asm$ = asm$ + CHR$(31)
  asm$ = asm$ + CHR$(93)
  asm$ = asm$ + CHR$(203)
  WAIT &H3DA, 8
  DEF SEG = VARSEG(asm$)
    CALL Absolute(BYVAL fromseg%, BYVAL fromoffset%, BYVAL toseg%, BYVAL tooffset%, BYVAL bytes%, SADD(asm$))
  DEF SEG
END SUB

SUB SetPALETTE (Slot, R, G, B)
  OUT &H3C8, Slot
  OUT &H3C9, R
  OUT &H3C9, B
  OUT &H3C9, G
END SUB

If you still have problems just post again. ;)


P.S.
If you want to use BLOAD/BSAVE, then you have to save the palette because those functions do not. :(
Come check out [url=http://www.freebasic.net/forum/index.php]FreeBASIC[/url]. The syntax is based on QuickBasic, but it expands to use pointers, operator overloading, etc... The list goes on and on!

Post Reply