Forum: Compiler & IDEs 8x8 Font auf 96x96 Framebuffer kopieren


von Michael (Gast)


Lesenswert?

Hallo,

Ich habe folgendes Problem:
Ich habe ein Display mit 96x96 Pixel, das wird als Array mit 12 Byte pro 
Line im Speicher dargestellt.(Display ist noch nicht vorhanden, bzw 
aktuell defekt...kann deshalb sein das im Code unten noch ein Fehler 
ist..am Debugger im Memory Fenster schaut's aber OK aus)

Ich habe jetzt eine 8x8 Font als Header, den ich in den Framebuffer 
kopieren möchte. Mein erster Versuch kopiert das jeweilige Byte vom Font 
Zeile für Zeile an die Cursor Position. Geht zum nächsten Zeichen usw.

Aber wie bekomm' ich dort jetzt einen Abstand von zB. 2 Pixel unter.

Ich stehe im Moment echt auf dem Schlauch...Kann mir wer einen Schubs in 
die richtige Richtung geben?
1
ret_code_t  printText(uint8_t* fb, uint8_t x, uint8_t y, char* text, uint8_t length){
2
  
3
  uint8_t i,a;
4
  uint8_t cursor;
5
  uint8_t* draw;
6
  
7
  char c;
8
  
9
  // cursor is top left 
10
  cursor = (y * LS013_BYTES_LINE) + x;
11
  draw = fb + cursor;
12
  
13
  for(i=0;i<length;i++){
14
    c = text[i];
15
    for (a=0;a<8;a++){  
16
      *draw = font8x8_basic[c][a];
17
      draw = draw + LS013_BYTES_LINE;
18
    }
19
    cursor++;
20
    draw = fb + cursor;
21
  }
22
  return NRF_SUCCESS;
23
}

von Rolf M. (rmagnus)


Lesenswert?

Nun, so wie du es jetzt machst, kann ein Zeichen nur an einem Vielfachen 
von 8 Pixeln stehen. Wenn du das pixelgenau positionieren willst, ist 
das deutlich mehr Rechenaufwand, da jede Zeile deines Zeichens nun auf 
zwei Bytes im Framebuffer verteilt werden muss. Dazu kommt noch, dass du 
diese beiden Bytes nicht komplett überschreiben darfst, sondern sie erst 
von dort einlesen, mit deinen neuen Bits befüllen und dann wieder 
rausschreiben musst.

Ich würde die Zeichen nur 7 Pixel breit machen und einen Pixel leer 
lassen, so dass man sie direkt nebeneinander zeichnen kann. Dann spart 
man sich diese umständliche Handhabung. 7 Pixel sind eh geschickter.

von Michael (Gast)


Lesenswert?

Ist zwar eine Möglichkeit, aber löst leider das grundlegende Problem 
nicht. Ich muss Bit genau adressieren.
Vielleicht sogar noch mehr Info: das Problem wird im Endausbau dann noch 
schlimmer, wenn der Text auch aufs Pixel genau platziert werden muss.Und 
dann setz ich noch eins drauf und muss mit 3Bit/Pixel (RGB jeweils 1 
Bit) hantieren.
Mir ist es deshalb wichtig eine Lösung für das Problem zu finden und es 
nicht zu umschiffen.

Ich hab jetzt auch noch weiterüberlegt:
Den Buffer auf 1Byte pro Pixel aufblasen, alle Framebuffer Operationen 
dort erledigen und im Anschluss auf das Displayformat in einem Rutsch 
runterbiegen. Nicht gerade Ressourcen schonend :(

von guest (Gast)


Lesenswert?

Bitmanipulation
Eigentlich steht da alles drin was Du wissen mußt.

Ansonsten, wer suchet der findet:
Beitrag "Re: Bits aus einem unsigned char array extrahieren"
Geht zwar um das extrhieren von Bits, aber zumindest das Prinzip sollte 
damit klar werden.

von Michael (Gast)


Lesenswert?

Gut Bitmanipulation ist klar, wenn ich einzelne Bits schreiben will :)
Aber eine Möglichkeit wenn ich wirklich Pixel für Pixel schreiben will 
ist mir dadurch trotzdem gekommen...Division bzw Modulo...mit der 
Divison das richtige Byte im Array selektieren und um den Restwert 
shiften. Pixel für Pixel, Bit für Bit...

Hmmm klingt wie wenn da trotzdem viel zum optimieren überbleibt?!

von Markus F. (mfro)


Lesenswert?

Man merkt, daß man alt wird. In den 80er und 90ern war das Schreiben in 
Bitmap-Displays täglich Brot (alle Homecomputer arbeiteten so) und da 
wurden unendlich Stunden reininvestiert um auf den lahmen Gurken 
schnelle Algorithmen zu basteln.
Leider ist in unserem modernen Internet nicht mehr viel davon zu finden 
und man muß das Rad neu basteln.

Für dein Problem ist es wahrscheinlich am einfachsten, die 
Display-Bitmap nicht als char-Array, sondern als 16-Bit short-Array zu 
betrachten (dann hast Du Platz, dein Zeichen an die richtige Stelle zu 
shiften).

Du brauchst eine linke und eine rechte Bitmaske, die die Zielbits 
markiert, die Du ändern willst (dazu shiftest Du einfach 0xffff um x % 8 
einmal nach rechts und einmal nach links und machst ein short draus). 
Dann holst Du dir das Bitmuster, das Du ändern willst, aus deinem 
Displaybuffer, maskierst es mit der Maske, kopierst das geshiftete 
Bitmuster des Zeichens, das Du schreiben willst, da rein und schreibst 
das ganze Wort in den Displaybuffer zurück. Das machst Du für jede Zeile 
des Zeichens und schon bist Du fertig.

von Michael (Gast)


Lesenswert?

oh da war ja ein zweiter Beitrag...^^ da stehts ja so ;) Danke!

von summsumm (Gast)


Lesenswert?

Michael schrieb:
> Und
> dann setz ich noch eins drauf und muss mit 3Bit/Pixel (RGB jeweils 1
> Bit) hantieren.
...also nur 8 unterschiedliche Farben oder wie viel Farben sollen pro 
Pixel möglich sein?

von Michael (Gast)


Lesenswert?

Markus F. schrieb:

> Für dein Problem ist es wahrscheinlich am einfachsten, die
> Display-Bitmap nicht als char-Array, sondern als 16-Bit short-Array zu
> betrachten (dann hast Du Platz, dein Zeichen an die richtige Stelle zu
> shiften).



Danke! Jetzt hats Klick gemacht! 16bit war das Stichwort...kommt davon 
wenn man die ganze Zeit auf der Leitung steht :)

von Falk B. (falk)


Lesenswert?

@ Michael (Gast)

>Ist zwar eine Möglichkeit, aber löst leider das grundlegende Problem
>nicht. Ich muss Bit genau adressieren.

Pixelgenau. Ist auch nicht WIRKLICH schwer. Wie es geht, wurde mehrfach 
gesagt.

>Den Buffer auf 1Byte pro Pixel aufblasen, alle Framebuffer Operationen
>dort erledigen und im Anschluss auf das Displayformat in einem Rutsch
>runterbiegen. Nicht gerade Ressourcen schonend :(

Unsinn ^3!

Hier gibt es ein Beispiel, wie es in etwa funktioniert.

Beitrag "Re: ATMEGA8(Pong) - Grundsatzfrage bzgl. Überschreiben des alten Zustands der LED"

>Gut Bitmanipulation ist klar,

Wenn es dir WIRKLICH klar wäre, wärst du läbgst mit der Umsetzung 
beschäftigt und würdest nciht sinnlos rumlabern.

>Aber eine Möglichkeit wenn ich wirklich Pixel für Pixel schreiben will
>ist mir dadurch trotzdem gekommen...Division bzw Modulo...mit der
>Divison das richtige Byte im Array selektieren und um den Restwert
>shiften. Pixel für Pixel, Bit für Bit...

Diesen Unsinn macht keiner, denn das dauert deutlich länger, als mit ein 
paar passenden Bitmasken je 2 Bytes / Zeile zu überschreiben.

sinngemäß so
1
bitoffset = spalte % 8;
2
bitmask = 0xFF >> bitoffset;
3
4
for (i=0; i<8; i++) {
5
  framebuffer[zeile+i][spalte] = framebuffer[zeile+i][spalte] & ~bitmask ) |
6
                                 ((font[zeichen][i] >> bitoffset) & bitmask);
7
  framebuffer[zeile+i][spalte+1] = framebuffer[zeile+i][spalte+1] & bitmask ) |
8
                                 ((font[zeichen][i] << (7-bitoffset)) & ~bitmask);
9
}

>Hmmm klingt wie wenn da trotzdem viel zum optimieren überbleibt?!

In der Tat.

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Warum den so aggressiv? Ich sitze vormittag bei nem Kaffee und nicht 
gleich vorm Code...

Falk B. schrieb:
>>Gut Bitmanipulation ist klar,
>
> Wenn es dir WIRKLICH klar wäre, wärst du läbgst mit der Umsetzung
> beschäftigt und würdest nciht sinnlos rumlabern.

Wie grundsätzlich Bitmanipulation funktioniert ist klar..das hat nichts 
mit rumlabern zu tun. Hat mir nur nicht bei der Lösung des Problems 
geholfen...der zweite Link von guest allerdings schon! Dafür hab ich 
mich auch bedankt.
Man steht halt manchmal auf dem Schlauch wenn man mit dem Kopf eig. bei 
ganz anderen Problem ist ;)

Zum Rest: Markus F. hat mich schon auf den richtigen Weg gebracht...

von summsumm (Gast)


Lesenswert?

summsumm schrieb:
> Michael schrieb:
>> Und
>> dann setz ich noch eins drauf und muss mit 3Bit/Pixel (RGB jeweils 1
>> Bit) hantieren.
> ...also nur 8 unterschiedliche Farben oder wie viel Farben sollen pro
> Pixel möglich sein?

...und nochmal die Frage...! Da mir das etwas komisch vorkommt und die 
Lösung dann etwas anders aussehen muss...

von Michael (Gast)


Lesenswert?

summsumm schrieb:
>> Michael schrieb:
>>> Und
>>> dann setz ich noch eins drauf und muss mit 3Bit/Pixel (RGB jeweils 1
>>> Bit) hantieren.

Ja ist so wie du sagst, aber das bekomm ich jetzt in den Griff..mir hat 
nur ein Tritt in die richtige Richtung gefehlt :)

von guest (Gast)


Lesenswert?

Ob Du in Deinem Array uint8_t oder uint16_t hast spielt eigentlich keine 
Rolle, das Prinzip bleibt gleich und auch bei 16 Bit hast Du irgendwann 
das Problem über eine Elementgrenze hinweg schreiben zu müssen. Kommt 
auch auf den µC an, auf einem AVR sind sowieso alle Zugriffe 8-bittig, 
da kommst Du mit uint8 am Ende besser weg. Auf einem ARM und X86 wäre 
uint32_t besser und bei X64/ARM64 halt uint64_t.
Wenn Du RGB mit 1 Bit pro Farbe brauchst kannst Du überlegen, ob Du 
jedem Pixel noch ein viertes Bit spendierst, also exakt 2 Pixel pro 
Byte. Das erspart die Probleme mit dem Alignment kostet aber etwas 
Speicher. Je nachdem was die Displayhardware tatsächlich hergibt könnte 
man das zusätzliche Bit noch als Blink-/Helligkeitsbit interpretieren, 
so ala CGA zu seligen DOS Zeiten.

Irgendwann landest Du sowieso bei etwas ähnlichem wie:
Michael schrieb:
> Ich hab jetzt auch noch weiterüberlegt:
> Den Buffer auf 1Byte pro Pixel aufblasen, alle Framebuffer Operationen
> dort erledigen und im Anschluss auf das Displayformat in einem Rutsch
> runterbiegen. Nicht gerade Ressourcen schonend :(
Denn egal wie Du Deinen Framebuffer organisierst, am Ende müssen die 
Daten zum Display. Und wenn das Display einem eigenen Framebuffer hat, 
kanns Du dessen Organisation eh nicht ändern (oder zumindest nur sehr 
eingeschränkt).

von Peter D. (peda)


Lesenswert?

Oftmals haben GLCDs auch einen PutPixel Befehl. Geht zwar langsamer, 
erspart aber einen Schattenspeicher bzw. das Rücklesen.

von jo (Gast)


Lesenswert?

>Hmmm klingt wie wenn da trotzdem viel zum optimieren überbleibt?!

Aber nicht für dich - für den Compiler.

Gruß J

von W.S. (Gast)


Lesenswert?

Michael schrieb:
> Aber wie bekomm' ich dort jetzt einen Abstand von zB. 2 Pixel unter.

Trenne mal zwischen der physischen Belegung und deinem logischen 
Display-RAM. Wenn du was durchgängig funktionierendes haben willst, dann 
lade dir die Lernbetty hier im Forum herunter. Ich hatte damals in der 
BettyBase eine durchaus universell benutzbare Grafikschnittstelle 
geschrieben. Als primitivste Funktion brauchst du dort was zum Setzen 
eines Pixels (also sinngemäß SetzePixel(x,y,color);) und alle anderen 
Funktionen wie CgPutChar und so sind dort draufgesetzt. Fonts gibt's 
dazu auch, Positionierung ist frei wählbar.

W.S.

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.