Forum: PC-Programmierung CGA und Byteaufteilung in der Darstellung mit Farben.


von Peter B. (funkheld)


Angehängte Dateien:

Lesenswert?

Hallo, gute Tag.

Ich kenne von CGA nur die Textdarstellung.

Das einzelne Byte setzen mit Farbe kenne ich nicht.
Ich lese von CGA immer nur über die Textauflösung.

Im Bild habe ich mal 2 Byte gesetzt mit dem TC3, das erste und das 
letzte.
Es ist weiß.

Wie setzt sich bitte 1 Byte zusammen für eine farbige Darstellung?

Warum hält beim TC3 das "return 0;" die Programführung nicht an?

--------------------------------------------
#include <dos.h>

int adr;
char byte;

void setze()
{
   pokeb(0xb800,adr,byte);
}

void cga()
{
  asm{
  mov ax,04h
  int 10h
  }
}

main()
{
  cga();

  adr=32;
  byte=255;
  setze();

  adr=8031;
  byte=255;
  setze();

  return 0;
}
-----------------------------

Gruss

von cppbert (Gast)


Lesenswert?

wenn schon dann schon

int main()

und bitte keine globalen

void setze(int adr, char byte)
{
   pokeb(0xb800,adr,byte);
}

und dann

setze(32, 255);
setze(8031, 255);

und zur besseren Lesbarkeit ax splitten

void cga()
{
  asm{
  mov ah,0
  mov al,4 // 320 x 200 Pixel, vier Farben
  int 10h
  }
}

keine Ahung wie dieser CGA Modus auf gebaut ist - 2 Bits per Farbe? 4 
Planes?

von Jim M. (turboj)


Lesenswert?

Peter B. schrieb:
> Warum hält beim TC3 das "return 0;" die Programführung nicht an?

Das Programm wird beendet - allerdings schaltet unter DOS(BOX) niemand 
den Grafik Modus zurück. Der bleibt auf CGA Mode stehen.

Peter B. schrieb:
> Wie setzt sich bitte 1 Byte zusammen für eine farbige Darstellung?

Ein Byte sind 4 Pixel á 2 Bit. Probiere mal andere Werte aus.

von cppbert (Gast)


Lesenswert?


von cppbert (Gast)


Lesenswert?

cppbert schrieb:
> der 1. Post könnte passen
>
> 
http://www.vcfed.org/forum/showthread.php?54561-CGA-mode-4-(320x200x4)-put-pixel-in-C

und JA der CGA Modus ist viel schwieriger als der 320x200x256 Mode 19

von cppbert (Gast)


Lesenswert?

oder so

static void write_pixel2(unsigned x, unsigned y, unsigned c)
{
  unsigned wd_in_bytes, off, mask;

  c = (c & 3) * 0x55;
  wd_in_bytes = 320 / 4;
  off = wd_in_bytes * y + x / 4;
  x = (x & 3) * 2;
  mask = 0xC0 >> x;
  pokeb(0xB800, off, (peekb(0xB800, off) & ~mask) | (c & mask));
}

von cppbert (Gast)


Lesenswert?

und noch eine Info zum Memory Layout: 
http://www.techhelpmanual.com/89-video_memory_layouts.html

von cppbert (Gast)


Lesenswert?

CGA Low-res 320x200, 4-color (video modes 04H and 05H)
 Segment: b800
  Layout: Interleaved scan lines, packed-pixel.  Even-numbered scan 
lines
          begin at b800:0, and odd-numbered lines begin at b800:2000.

          Each scan line is 80-bytes long and there are 200 scan lines
          (regen size=8000 bytes * 2 regions).  Each byte contains 4 
pixels
          (16,000 total pixels):
          ╓7┬6┬5┬4┬3┬2┬1┬0╖
          ║   │   │   │   ║
          ╙─┴─┴─┴─┴─┴─┴─┴─╜  bits mask
           ╚╦╝ ╚╦╝ ╚╦╝ ╚═╩═► 0-1:  03H  fourth pixel in byte
            ║   ║   ╚══════► 2-3:  0cH  third pixel in byte
            ║   ╚══════════► 4-5:  30H  second pixel in byte
            ╚══════════════► 6-7:  c0H  first pixel in byte
                                        00=black;       01=green/cyan
                                        10=red/magenta; 11=brown/white

          Each 2-bit field selects one of four colors, depending on the
          setting of the CGA palette.  Use INT 10H 0bH.

von Peter B. (funkheld)


Lesenswert?

Danke für die Information,
Wusste nicht ,das CGA mehr braucht als dieses VGA.

Warum wird hier bitte bei y=199 2x durchlaufen?

1x mit eine Leerzeile und dann wird beim zweiten mal die Leerzeile 
gefüllt.

--------------------------------
static void write_pixel2(unsigned x, unsigned y, unsigned c)
{
  unsigned wd_in_bytes, off, mask;

  c = (c & 3) * 0x55;
  wd_in_bytes = 320 / 4;
  off = wd_in_bytes * y + x / 4;
  x = (x & 3) * 2;
  mask = 0xC0 >> x;
  pokeb(0xB800, off, (peekb(0xB800, off) & ~mask) | (c & mask));
}
---------------------------------

Danke.

von cppbert (Gast)


Lesenswert?

Peter B. schrieb:
> 1x mit eine Leerzeile und dann wird beim zweiten mal die Leerzeile
> gefüllt.

hier wird nichts mehrfach durchlaufen - man muss eben das bestehende 
byte lesen um darin die entsprechenden 2 bits zu veraendern

von Peter B. (funkheld)


Angehängte Dateien:

Lesenswert?

Wenn ich y=199 habe dann werden 100 Zeilen ab der ersten nach unten 
geschrieben mit einer Leerzeile dann fängt es oben bei der zweiten an 
und schreibt wieder 100 nach unten , wobei jetzt die Leerzeilen gefüllt 
werden.

Hier ein Zwischenfoto.

----------------------------------------
#include <dos.h>
#include <conio.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

int x,y,col;

void cga_graf()
{
  asm{
   mov ax,04h
   int 10h
  }
}

void cga_text()
{
  asm{
    mov ax,05h
    int 10h
  }
}

void plot(unsigned x, unsigned y, unsigned c)
{
  unsigned wd_in_bytes, off, mask;

  c = (c & 3) * 0x55;
  wd_in_bytes = 320 / 4;
  off = wd_in_bytes * y + x / 4;
  x = (x & 3) * 2;
  mask = 0xC0 >> x;
  pokeb(0xB800, off, (peekb(0xB800, off) & ~mask) | (c & mask));
}

main()
{
  cga_graf();

  col=2;

  for (y = 0; y <= 199; y++) {
    for (x = 0; x <= 320; x++) {
      plot(x,y,2);
      }
   }

  return 0;
}
-------------------------------------------

Gruss

: Bearbeitet durch User
von cppbert (Gast)


Lesenswert?

>   for (y = 0; y <= 199; y++) {
>     for (x = 0; x <= 320; x++) {

auf jeden Fall mal

y < 200
x < 320

von cppbert (Gast)


Lesenswert?

cppbert schrieb:
>>   for (y = 0; y <= 199; y++) {
>>     for (x = 0; x <= 320; x++) {
>
> auf jeden Fall mal
>
> y < 200
> x < 320

btw: halte deine variablen immer möglichst nah im dem Scope wo du sie 
brauchst
d.h. die globalen x,y,col lieber in die main - hilft alles auf dauer 
Fehler zu vemeiden

von cppbert (Gast)


Lesenswert?

einfach #include <assert.h> rein

und in deine

void plot(unsigned x, unsigned y, unsigned c)
{
  unsigned wd_in_bytes, off, mask;

  // Vorbedingung die erfuellt sein muessen
  assert(x >= 0 && x < 320);
  assert(y >= 0 && y < 200);
  assert(c >= 0 && c < 4);

  c = (c & 3) * 0x55;
  wd_in_bytes = 320 / 4;
  off = wd_in_bytes * y + x / 4;
  x = (x & 3) * 2;
  mask = 0xC0 >> x;
  pokeb(0xB800, off, (peekb(0xB800, off) & ~mask) | (c & mask));
}

dann fallen dir solche "Anwendungsfehler" schneller auf

von Peter B. (funkheld)


Lesenswert?

Danke für die Hilfe.

Gruss

von Peter B. (funkheld)


Lesenswert?

Hallo, guten Tag.

Ich bekomme es nicht hin dieses Byte :  byte=0xb11111111;
zu setzen damit 4 Pixel grün werden oder auch 4 Pixel rot .

Ich bekomme die Aufteilung der 8 Pixel nicht hin.
Zur Zeit sind 4 Pixel weiß : byte=0xb11111111;

Auch warum muss die Adresse Hex : B800:20 sein damit das Byte als erstes 
oben links erscheint.

Gruss


----------------------------------------
#include <dos.h>
#include <conio.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

void setze(int adr, char byte)
{
   pokeb(0xb800,adr,byte);
}

void cga_graf()
{
  asm{
    mov ah,0
    mov al,4
    int 10h
  }
}

void cga_text()
{
  asm{
     mov ax,05h
     int 10h
  }
}

int main()
{
  int adr;
  char byte;

  cga_graf();

  adr=32;
  byte=0xb11111111;

  setze(adr,byte);

  while (1)
  {
    switch (getche())
    {
      case 'e': cga_text();  exit(0);
    }
  }

  return 0;
}
--------------------------------------------

von cppbert (Gast)


Lesenswert?

1. geht mein Beispiel mit der plot-Funktion?
2. du willst jetzt den Algorithmus selbst schreiben?

Ich hab den Algorithmus mal ein bisschen aufgeschluesselt
aber Bit-Operationen musst du verstehen sonst geht es nicht
1
        const int WIDTH = 320;
2
        const int HEIGHT = 200;
3
        const int COLORS = 4;
4
        const int BITS_PER_COLOR = COLORS / 2;
5
        const int PIXEL_PER_BYTE = 8 / BITS_PER_COLOR;
6
        const int BYTES_PER_LINE = WIDTH / PIXEL_PER_BYTE;
7
        
8
        volatile unsigned char* cga_mem = (volatile unsigned char*)(0xb800);
9
10
        int x = 6;
11
        int y = 0;
12
        int color = 2;
13
        
14
        assert(x >= 0 && x < WIDTH);
15
        assert(y >= 0 && y < HEIGHT);
16
        assert(color >= 0 && color < COLORS);
17
18
        //prepare color_mask and shiftet_color
19
20
        // which Pixel inside the byte (left to right, 0..3)
21
        const unsigned pixel_offset = x % PIXEL_PER_BYTE;
22
        const unsigned rshift = pixel_offset * 2;
23
        const unsigned color_mask = 0b11000000 >> rshift;
24
        const unsigned shiftet_color = color >> (6 - rshift);
25
26
        // which byte?
27
        const unsigned y_offset = y * BYTES_PER_LINE;
28
        const unsigned x_offset = x / PIXEL_PER_BYTE;
29
        const unsigned byte_offset = y_offset + x_offset;
30
        
31
        volatile unsigned char* byte = &cga_mem[byte_offset];
32
        
33
        *byte = (*byte & ~color_mask) | shiftet_color;

von guest (Gast)


Lesenswert?

Peter B. schrieb:
> Ich bekomme es nicht hin dieses Byte :  byte=0xb11111111;
> zu setzen damit 4 Pixel grün werden oder auch 4 Pixel rot .

Wenn Du vier grüne Pixel haben willst, dann schreib halt auch viermal 
grün in das Byte: byte=0xb01010101 oder eben rot: byte=0xb10101010

von Peter B. (funkheld)


Lesenswert?

Nein, deiner geht soweit wunderbar.
Den ändere ich nicht.

Gruss

von Walter T. (nicolas)


Lesenswert?

Peter B. schrieb:
> #include <dos.h>

Welche Build-Umgebung nutzt Du?

von cppbert (Gast)


Lesenswert?

Peter B. schrieb:
> Nein, deiner geht soweit wunderbar.
> Den ändere ich nicht.
>
> Gruss

den hatte ich auch nur im Internet gefunden und dann sauber gemacht - so 
das man auch versteht was da passiert

von Peter B. (funkheld)


Angehängte Dateien:

Lesenswert?

Das hatte ich schon aus der Tabelle:

(16,000 total pixels):
          ╓7┬6┬5┬4┬3┬2┬1┬0╖
          ║   │   │   │   ║
          ╙─┴─┴─┴─┴─┴─┴─┴─╜  bits mask
           ╚╦╝ ╚╦╝ ╚╦╝ ╚═╩═► 0-1:  03H  fourth pixel in byte
            ║   ║   ╚══════► 2-3:  0cH  third pixel in byte
            ║   ╚══════════► 4-5:  30H  second pixel in byte
            ╚══════════════► 6-7:  c0H  first pixel in byte
                                        00=black;       01=green/cyan
                                        10=red/magenta; 11=brown/white

---------------------------
adr=0x20;
byte=0xb01010101;
setze(adr,byte);
----------------------------

Es kommt nur 1 Pixel.

Warum weiss ich nicht, was falsch ist.
Was bedeutet da drin 03h , 0c, 30h, c0h ?

Gruss

von Peter B. (funkheld)


Lesenswert?

------------------------
Welche Build-Umgebung nutzt Du?
------------------------

Borland Turbo C++ 3.0 (3.5-720k)
Borland Turbo C++ 3.0 (5.25-1.2mb)

/*  dos.h

    Defines structs, unions, macros, and functions for dealing
    with MSDOS and the Intel iAPX86 microprocessor family.

    Copyright (c) 1987, 1991 by Borland International
    All Rights Reserved.
*/

Habe beide getestet.

byte=0xb11111111; , das geht ja und es sind 4 weiße Pixel da.

Gruss

: Bearbeitet durch User
von guest (Gast)


Lesenswert?

cppbert schrieb:
> ...

War da nicht noch was mit "Interleaved scan lines"?
Also sowas in der Art:
1
const unsigned y_offset = ( y & 0x01 ) ? y / 2 * BYTES_PER_LINE + 0x2000 : y / 2 * BYTES_PER_LINE;

Btw.
1
volatile unsigned char* cga_mem = (volatile unsigned char*)(0xb800);
Das kann so auch nicht funktionieren. Zum einen muß das wohl ein 'far' 
Pointer sein und zu anderen ist 0xb800 eine Segmentaddresse. Also eher:
1
volatile unsigned char far* cga_mem = (volatile unsigned char far*)(0xb800:0000);
oder falls TC die Schreibweise nicht versteht:
1
volatile unsigned char far* cga_mem = (volatile unsigned char far*)(0xb8000);
bzw. falls das Makro existiert noch bessesr:
1
volatile unsigned char far* cga_mem = (volatile unsigned char far*)MK_FP(0xB800,0x0000);

von Peter B. (funkheld)


Angehängte Dateien:

Lesenswert?

Hmm...eine komische Sache.

WEnn ich statt  byte=0xb01010101 dieses eingebe : byte=85 geht es.
Stimmt die Hexmarkierung nicht?

Aber warum wird byte=0xb11111111 weiß?
Gruss

: Bearbeitet durch User
von cppbert (Gast)


Lesenswert?

guest schrieb:
> cppbert schrieb:
>> ...
>
> War da nicht noch was mit "Interleaved scan lines"?
> Also sowas in der Art:const unsigned y_offset = ( y & 0x01 ) ? y / 2 *
> BYTES_PER_LINE + 0x2000 : y / 2 * BYTES_PER_LINE;


ist nicht richtig kompilierbar - speziell nicht unter TC 3, ich wollte 
nur die Algorithmus ein wenig zerlegt aufzeige, die orginal plot 
funktion geht ja

von cppbert (Gast)


Lesenswert?

Peter B. schrieb:
> WEnn ich statt  byte=0xb01010101 dieses eingebe : byte=85 geht es.
> Stimmt die Hexmarkierung nicht?
>
> Aber warum wird byte=0xb11111111 weiß?
> Gruss

bitte nur 0b als Prefix für Binär - nicht 0xb, das x ist kein Trenner 
sondern steht fuer Hex und 0xb heisst dann Hexbinär???

also 0b[01]+ oder 0x[A-F0-9]+

bitte ein ganzes Beispiel - es ist schwer dir zu folgen mit so 
Häppchen-Fragen

von cppbert (Gast)


Lesenswert?

Peter B. schrieb:
> Hmm...eine komische Sache.
>
> WEnn ich statt  byte=0xb01010101 dieses eingebe : byte=85 geht es.
> Stimmt die Hexmarkierung nicht?
>
> Aber warum wird byte=0xb11111111 weiß?
> Gruss

die 0b schreibweise gibt es erst seit 1-2 Jahren, und keine Ahnung was 
dein Kompiler mit 0xb macht???

von guest (Gast)


Lesenswert?

Peter B. schrieb:
> adr=0x20;
> byte=0xb01010101;
> setze(adr,byte);
> ----------------------------
>
> Es kommt nur 1 Pixel.
>
> Warum weiss ich nicht, was falsch ist.
> Was bedeutet da drin 03h , 0c, 30h, c0h ?
>
> Gruss

Sorry, da hab ich auch noch was übersehen.
Die binäre Schreibweise dürfte TC nicht kennen und mit 0x am Anfang 
wirds eh als hex interpretiert. Also für grün so: byte=0x55 und für rot: 
byte=0xAA.
Oder falls TC doch damit klarkommt: byte=0b01010101, also ohne das 'x'.

"03h , 0c, 30h, c0h" Das sind die Masken (in hex) um die vier Pixel 
innerhalb eines Byte zu maskieren. Im Endeffekt das, was cppbert in 
'color_mask' stehen hat.

von cppbert (Gast)


Lesenswert?

cppbert schrieb:
> und keine Ahnung was
> dein Kompiler mit 0xb macht???

er interpretiert es ja klarerweise als hex ist also ein Hexzahl: 
0xB11111111
da ist nicht binär also kommt da ein völlig falscher Wert aus

wie gesagt 0b gibt es erst seit kurzem - du musst die Binärdarstellung 
wohl oder übel durch den Calc oder sonstwas jagen

von guest (Gast)


Lesenswert?

cppbert schrieb:
> und keine Ahnung was
> dein Kompiler mit 0xb macht???

'b' ist eine gültige Hex-Ziffer, von meinem falschen Bsp. "0xb01010101" 
(dez. 47261483265) bleibt am Ende in dem Byte nur noch 0x01 übrig und 
damit genau der von Peter erwähnte eine Pixel.

von Peter B. (funkheld)


Lesenswert?

Alles klar ,danke.

Ist keine Problem in HEX oder Deci zu schreiben.

Das Binäre war halt mehr übersichtlicher.

Gruss

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

cppbert schrieb:
> und JA der CGA Modus ist viel schwieriger als der 320x200x256 Mode 19

Allerdings ist letzterer ziemlich blöde umgesetzt mit seinem skurrilen 
chain4 und der damit einhergehenden Verschwendung von 3/4 des 
Grafikspeichers.

von Dirk B. (dirkb2)


Lesenswert?

Peter B. schrieb:
> Was bedeutet da drin 03h , 0c, 30h, c0h ?

Das sind die Wert zum maskieren der Pixel

03h = 0x03 = 0b00000011
0Ch = 0x0C = 0b00001100
30h = 0x30 = 0b00110000
C0h = 0xC0 = 0b11000000

Die Schreibweise mit dem h als Suffix stammt vom Assembler (MASM ?)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.