Grafik aus einem String lesen und anzeigen



  • Hallo

    Ich habe mir eine Kernel geschrieben, die eine Grafik anzeigen soll.
    Dazu wechsle ich erst in den VGA-Modus und lese dann die Grafik aus
    einm String aus.
    Das hat soweit auch gut funktioniert. Nur ist die Grafik extrem groß.

    Also habe ich das Bild mit hilfe eines schnell geschriebenen C++ Proggs
    in Binäre Daten umgewandelt. Eins = Pixel wird gesetzt, Null = Kein Pixel wird gesetzt.

    Leider funzt das ganze nicht so wirklich 😞

    Code: (Bitte nicht meckern, hab erst seit kurzem mit ASM angefangen 😉 )

    ;PARAMS:
    ;    AX = BILDHÖHE
    ;    BX = BILDBREITE
    ;    ES:DI = ADRESSE DES GRAFIK-STRINGS
    ;--------------------------------------------------------------------------
    putCompressedBMPString:
    
    mov cx,0
    mov dx,0
    
    jmp  .cBMP_loop
    
    .cBMP_NextLine
            inc cx
            cmp cx,ax
            jz .cputBMP_end
            mov dx,0
    jmp .cBMP_loop
    
    .SetP
            mov al,7
            call putpixel
    jmp bx
    
    ;MAIN-LOOP
    .cBMP_loop
    
       push ax
            LODSB        
    
       push bx
    
            inc dx
    
            mov bx,.Go1
            test ah,10000000b
            jne .SetP
            .Go1
            inc dx
    
            mov bx,.Go2
            test ah,010000000b
            jne .SetP
            .Go2
            inc dx
    
            mov bx,.Go3
            test ah,001000000b
            jne .SetP
            .Go3
            inc dx
    
            mov bx,.Go4
            test ah,000100000b
            jne .SetP
            .Go4
            inc dx
    
            mov bx,.Go5
            test ah,00001000b
            jne .SetP
            .Go5
            inc dx
    
            mov bx,.Go6
            test ax,00000100b
            jne .SetP
            .Go6
            inc dx
    
            mov bx,.Go7
            test ax,00000010b
            jne .SetP
            .Go7
            inc dx
    
            mov bx,.Go8
            test ax,00000001b
            jne .SetP
            .Go8
    
       pop bx
       pop ax 
            cmp dx,bx
            jz .cBMP_NextLine
    
            jmp     .cBMP_loop
    
    .cputBMP_end
    
    ret
    
    ;PARAMS:
    ;    AL = FARBE
    ;    CX = Y
    ;    DX = X
    ;--------------------------------------------------------------------------
    putpixel:
    	push	es
    	push	bx
    	mov	bx , 0xa000
    	mov	es , bx
    	mov	bx , ax
    	mov	ax , 320
    	push	dx
    	mul	cx
    	pop	dx
    	add	ax , dx
    	xchg	bx , ax
    	mov [es:bx],al
    	pop	bx
    	pop	es
    ret
    


  • ; ES:DI = ADRESSE DES GRAFIK-STRINGS

    Meintest du hier vielleicht ds:si (von dieser Adresse laedt lods)?

    BTW:
    Diese ganzen tests koenntest du auch in einer Schleife zusammenfassen.
    Dann zB. mit shl immer ein bit oben von ah abpfluecken und gucken, ob das cf gesetzt ist, oder nicht...
    Zudem ist es IMO ein bissel zu viel des guten, den Index im Bildschirmspeicher fuer jeden Pixel extra aus den Koordinaten neu zu berechnen.
    Das geht auch effektiver. 😉



  • man sollte sich auch immer ueberlegen, wann und warum man assembler einsetzen will.
    jeder c-compiler macht da 10x schnelleren und kuerzeren code draus, der algorithmus waere in 5-10 zeilen formuliert gewesen und wuerde ausserdem schon funktionieren...



  • hellihjb schrieb:

    man sollte sich auch immer ueberlegen, wann und warum man assembler einsetzen will.
    jeder c-compiler macht da 10x schnelleren und kuerzeren code draus, der algorithmus waere in 5-10 zeilen formuliert gewesen und wuerde ausserdem schon funktionieren...

    😮 Ich bitte um ein Beispiel!


  • Mod

    das ist schon ziemlicher spaghetti code - und das ist gar nicht so einfach mit so in paar anweisungen 😉 der hinweis von nabuto ist gut. auf jedenfall solltest du auf bedingte sprünge in unterprogramme (SetP) verzichten - besser ist ein normaler call und vorher ein bedingter sprung um den call herum (bei den 8bit rechnern, mit denen ich assembler gelernt habe, gabs noch bedingte calls 🙂 ) - das erleichtert die lesbarkeit enorm. was oder warum es jetzt nicht funktioniert, kann ich nicht sagen ohne bessere fehlerbeschreibung. ist zwar sehr umständlich, aber für mein verständnis nicht offensichtlich falsch.



  • Ich bitte um ein Beispiel!

    ungefaehr so:

    // parameter:
    // dst: zieladresse im grafikspeicher (0xa0000 + irgendwo)
    // data= zeiger auf 1bit monochrom daten (jedes uchar enthaelt 8 pixel)
    // sizex= breite der bitmap
    // sizey= hoehe der bitmap
    void drawBitmap(uchar *dst, uchar *data, int sizex, int sizey)
    {
      uchar palette[2]={0,255}; // farbpalette mappt pixel-bit 0/1 auf vga-farben
      for (int y=0;y<sizey;y++)
      {
        for (int x=0;x<sizex;x+=8) // in der innerloop werden jeweils 8 pixel gefuellt
        {
          uchar p= *data++; // 8bits
          // geht durch alle bits des gelesenen bytes,
          // schreibt die dem bit entsprechende farbe in den grafikspeicher
          // und geht zum naechsten pixel
          for (int bit=0;bit<8;bit++,p>>=1) *dst++= palette[p & 1]; 
        }
        // spring vom ende der jetztigen zeile zum anfang der naechsten
        dst+=320-sizex; 
      }
    }
    

    die trivial-implementation nimmt an, dass die breite der bitmap durch 8 teilbar ist. das unterste bit entspricht dabei dem vordersten von 8 pixeln.
    sollte sich leicht 1:1 auf assembler uebertragen lassen und wird dem lehrling zur uebung ueberlassen 🙂



  • THX @ all

    Leide habe ich (tatsächlich) die Absicht, ein reines ASM-Programm zu schreiben 😉

    Ich hab den Code jetzt mal etwas umgeschrieben:

    ;PARAMS:
    ;    AX = BILDHÖHE
    ;    BX = BILDBREITE
    ;    DS:SI = ADRESSE DES GRAFIK-STRINGS
    ;--------------------------------------------------------------------------
    putCompressedBMPString:
         mov  cx, 0
         mov  dx,  0 
         jmp  .cBMP_loop
    
       .cBMP_NextLine
         inc  cx
         cmp  cx,  ax
         jz   .iputBMP_end
         mov  dx,  0
         jmp  .cBMP_loop
    
         ;MAIN-LOOP
       .cBMP_loop
    
         push ax
         push cx
         push bx
         push dx
         LODSB   
         mov  [Zahl],ax
         mov  bh,  10000000b
       .iBMPloop
         test ah,  bh
         jne  iputpixel
       .iLoopA
    
         SAL  bh,  1
         dec  word [Zahl]
         cmp  word [Zahl],0
         jz . iBMPloop
    
         pop  dx
         pop  bx 
         pop  cx
         pop  ax 
         cmp  dx,  bx
         jge  .cBMP_NextLine
         jmp  .cBMP_loop
    
       .iputBMP_end
    
    ret
    

    Aufrufen tu ich meine Funktion so:

    mov SI,compressedBMPString
    mov ax,105;HÖHE DES BILDES
    mov bx,144;BREITE DES BILDES
    call putCompressedBMPString
    

    Jedoch sehe ich bei dieser Version keinen einzigen Pixel auf dem Bildschirm.
    Außerdem scheint sich eine Endlosschleife aufgetan zu haben, da die Programmausführung
    nach der putCompressedBMPString Funktion nicht fortgesetzt wird...

    Vielen Dank schonmal!



  • innerhalb der "iBMPloop" willst du doch fuer jedes der 8 bits eines gelesenen bytes pruefen, ob es gesetzt ist oder nicht.
    dieses byte laedst du mit lodsb nach al, pruefst aber ah.
    dafuer benutzt du eine bitmaske die nach dem ersten sal bh,1 nur noch 0 enthaellt.
    der zaheler fuer diese schleife ist zahl. sollte da nicht 8 drinstehen? stattdessen setzt der sich aus 8 pixel-bits und dem high-byte der bildhoehe zusammen.
    da stimmt doch was nicht! 🙂

    edit: ich habe den algorithmus mal ungetestet "aufgeraeumt"
    vielleicht hilft dir das was...

    register:
    cx= breite
    dx= hoehe
    al= farbe der bitmap
    es:di= grafikspeicher-position (a000h:0= oben links)
    ds:si= adresse der bitmap
    putCompressedBMPString:
         mov  bx, 320       ; x-aufloesung mode 13
         sub  bx, cx    
         mov  pitch, bx     ; step vom ende einer scanline zum anfang der naechsten
         shr  cx, 3         ; breite /8
       .yloop
         push cx            ; breite retten
       .xloop
         mov  bh, 10000000b ; oberstes bit zuerst pruefen
         mov  bl, [ds:si]   ; 8bit laden
       .bitloop
         test bl,  bh       ; bit pruefen
         jz   skip          ; nicht gesetzt: keinen pixel zeichnen
         mov  [es:di], al   ; pixel setzen
       .skip
         inc  di            ; naechster pixel
         shr  bh,1          ; zu pruefendes bit um 1 verschieben
         jnc  bitloop       ; widerholen solang das pruefbit nicht weggeshiftet wurde
         inc  si            ; adresse vom naechsten bitmap-byte
         dec  cx            ; breite--
         jnz  xloop         ; wiederholen solange ungleich 0
         pop  cx            ; breite wiederherstellen
         add  di, pitch     ; zum anfang der naechsten zeile springen
         dec  dx            ; hoehe--
         jnz  yloop         ; wiederholen solange ungleich 0
    ret
    


  • Vielen Dank für deine Mühe!

    Leider muss ich sagen, dass es bei mir noch immer nicht funktioniert 😞
    Ich rufe deinen Code wie folgt auf:

    ...
         mov cx,144
         mov dx,105
         mov ax,0xa000
         mov [es:di],ax
         mov ax,compressedBMPString
         mov [ds:si],ax
         mov al,7
         call putCompressedBMPString
    
         CALL WaitBIOSKey
         ...
    

    Doch mein Bildschirm bleibt schwarz. Meine "Bitmap" sieht dabei so aus:

    compressedBMPString db 0000000b, 0000000b, 0000000b, 0000000b, 0000000b, 0000111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1110000b, 0000000b, 0000000b, 0000000b, 
    db 0000000b, 0000000b, 0000000b, 0000000b, 0000000b, 1111000b, 0000000b, 0111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111110b, 0000000b, 0001100b, 0000000b, 0000000b, 0000000b, 
    db 0000000b, 0000000b, 0000000b, 0000000b, 1111111b, 1111000b, 0000000b, 0000001b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111111b, 1100000b, 0000000b, 0001111b, 1111100b, 0000000b, 0000000b, 
    db 0000000b, 0000000b, 0000000b, 0001111b, 1111111b, 1111000b, 0000000b, 0000000b, 0011111b, 1111111b, 1111111b, 1111111b, 1111111b, 1111110b, 0000000b, 0000000b, 0001111b, 1111111b, 1100000b, 0000000b, 
    ...
    

    (erste 4 Zeilen)

    Hoffe, ich stress dich nicht zu sehr 😞



  • mov ax,0xa000
    mov [es:di],ax
    

    das schreibt den 16bit wert "0xa000" in die speicherstelle auf die es:di zeigt.
    richtiger waere wohl

    mov ax,0xa000
    mov es,ax
    mov di,0
    

    darueber hinaus solltest du nicht davon ausgehen, dass mein code-beispiel funktioniert, denn ich hatte wenig lust einen 16bit-assembler rauszuholen 😉



  • ich hatte wenig lust einen 16bit-assembler rauszuholen

    😃

    Es funzt zwar noch immer nicht, aber vielen Dank für deine Hilfe!

    P.S. Einer der Admins des Forums scheinen nicht mitbekommen zu haben,
    dass es nichts bringt, mich dauernd zu bannen. Einmal den Routerstecker
    gezogen, schon komm ich wieder rein.

    Aber da hab ich mal ne Frage: War dieser Beitrag wirklich SO schlimm?



  • @PS: Pannen passieren hier auch mal. Wenn du unbedingt registriert schreiben willst, und meinst zu unrecht gebannt worden zu sein, schlage ich vor mal eine Mail an Marc++us zu schreiben. 😉



  • Hallo!

    Ich stress schonwieder!
    Ich habs jetzt soweit hinbekommen, dass (was jetzt mal völlig neu ist) keine Endlosschleife oder ein Sprung ins nichts entsteht.

    Die Pixelreihen werden wie gewünscht durchlaufen, aber: Es werden keine entsprechenden Pixel gesetzt 😕

    putCompressedBMPString:
    
        ;PARAMS:::::::::::::::::::
         mov    ax,   105;HÖHE DES BILDES
         mov    bx,   137;BREITE DES BILDES
         mov    si,   compressedBMPString
        ;PARAMS:::::::::::::::::::
    
         mov    [XMax],bx
         mov    [YMax],ax
         mov    ax,    0
    
         mov    word [XPos],0
         mov    word [YPos],0
    
        .pCBS_loop
         LODSB                                ;AL = Zeichen im String (8 Bit)
         mov    cl,  0
    .pCBS_Bitloop
         inc    word  [XPos]
         push   bx
         mov    bx,   [XPos]
         cmp    bx,  word [XMax]
         jge    .pCBS_NextLine 
    .pCBS_ret1
         pop    bx
    
         test   al,   bl                      ;Vergleiche
         jnz    .pCBS_PutPixel
    .pCBS_ret2
         shr    bl,   1
         inc    cl
         cmp    cl,   7
         jz     .pCBS_loop
         jmp    .pCBS_Bitloop
    
    .pCBS_NextLine
         push   bx
         mov    word [XPos],0
         inc    word [YPos]
         mov    bx,   word [YPos]
         cmp    bx,   word [YMax]
         pop    bx
         jge    .pCBS_End
         jmp    .pCBS_ret1
    
    .pCBS_PutPixel
         push   ax
         push   cx
         push   dx
         mov    al,7
         mov    cx,   word [YPos]
         mov    dx,   word [XPos]
         call   putpixel
         pop    dx
         pop    cx
         pop    ax
         jmp    .pCBS_ret2
    
    .pCBS_End    
    pop bx
    ret
    

    Wenn ich statt compressedBMPString einen anderen String angebe, werden irgendwelche Punkte gesetzt (was ja normal ist), wenn ich aber compressedBMPString angebe, wird entweder alles weiß, oder alles schwarz gelassen-.- (ja nach jnz oder jz .pCBS_PutPixel).

    Ich versteh nicht warum 😕



  • ja, ganz recht! Ich bins wieder. Ich habs jetzt hinbekommen. (Hat ja auch lang genug gedauert.)

    Gefehlt hat diese Befehlszeile:

    mov    bl,  10000000b
    

    unter

    .pCBS_loop
    


  • schwere geburt 😉



  • hellihjb schrieb:

    schwere geburt 😉

    In der Tat 🙂


Anmelden zum Antworten