Forum: PC-Programmierung [GTK+] Animation mit Cairo viel zu langsam


von xpler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

dies ist mehr oder weniger die Fortsetzung von 
Beitrag "[C] Win7: Console in Vollbildmodus - SetConsoleDisplayMode not implemented" ...

Kurz: Ich hab ein kleines Spiel ("2D-Shooter" oder so ähnlich) 
programmiert. Für die Grafik hab ich einfach die DOS-Konsole maximiert 
und nutze ASCII-Zeichen. Geht unter XP prima, unter Windows 7 aufgrund 
anderer API nicht. Der Versuch der Sache mit GTK+ und einer Art 
Eigenbaukonsole Herr zu werden ist bisher an der Komplexität dieses 
Frameworks gescheitert.

Aber: Ich habe mittlerweile ein kleines Programm "entwickelt" 
(Guttenbergmethode = Code aus dem Internet zusammenkopiert) welches sich 
als Ersatz für eine maximierte DOS-Konsole eignet. Darin lässt sich 
mittels Pfeiltasten eine Spur zeichnen.

Problem: Das ganze ist viel zu langsam, obwohl ich den Timer auf 1ms 
gestellt habe. Hat jemand einen Vorschlag wie ich die Sache deutlich 
schneller kriege? Ich hatte schon testweise den Buffer als String-Array 
definiert
(
1
typedef char string_t[XMAX+1];
2
string_t buffer[YMAX];
3
//...
4
for(y=0;y<YMAX;y++)
5
  buffer[y][80]='\0';
6
//...
7
cairo_show_text(cr, buffer[y]);
), macht die Sache aber nicht merklich schneller.

Vorschläge?

PS: Das Programm lässt sich mit Alt+F4 beenden.

von Andreas B. (andreasb)


Lesenswert?

Ja, zeichne alles in ein Bild.

Danach zeichnest du das Bild auf den Bildschirm. Wenn sich etwas ändert 
zeichnest du nur das neu was sich geändert hat.

Ist bei deiner Konsole alles schwarz / weiss oder verwendest du Farben?

Ggf. wäre ein Textfeld oder ein Label Besser geieignet für dich, habe 
ich aber selbst noch nie ausprobiert.



mfg Andreas

von Andreas B. (andreasb)


Lesenswert?

Aja, ich lese gerade noch von einem Timer mit 1ms?

Was ist das für ein Timer? Codestück?
Du wirst wohl kaum 1ms hinkriegen, da macht der Scheduler bei weitem 
nicht mehr mit.

Viellicht solltest du mal genauer beschreiben was der Ablauf deines 
Programms ist, warscheinlich hast du noch einen Groben Denkfehler 
drin...



mfg Andreas

von Andreas B. (andreasb)


Lesenswert?

Ahh, Anhang ist ja da!

Sorry, dann noch ein Post...

http://developer.gnome.org/glib/2.26/glib-The-Main-Event-Loop.html#g-timeout-add

Note that timeout functions may be delayed, due to the processing of 
other event sources. Thus they should not be relied on for precise 
timing. After each call to the timeout function, the time of the next 
timeout is recalculated based on the current time and the given interval 
(it does not try to 'catch up' time lost in delays).


Also dieser Timeout wird sicher nicht alle 1ms auftreten.

Dann weiter:

  gtk_widget_queue_draw(window); //neuzeichnen auslösen

da steht queue drin, also dein neuzeichnen wird in die Warteschlange 
gestellt.

neu gezeichnet wird dann wenn er Zeit hat. Leider hat er aber keine 
Zeit, da die ganze Zeit dein Timer auslöst, und ihm sagt er soll dann 
mal neu zeichnen...

Versuche mal den Timer höher zu stellen, und nur neu zeichnen was 
wirklich nötig ist.

Zudem geht das rendern von Text relativ lange, ggf. könntest du ein Bild 
machen (dynamisch) und dann dieses Zeichnen, das könnte noch einen 
Performance Vorteil bringen.

Mit den richtigen Parametern ist das dann sicher kein Problem, ich 
stelle PDFs so dar, und da lässt sich flüssig scrollen...


mfg Andreas

von Der Weise (Gast)


Lesenswert?

Wie wäre es mit OpenGL? Dann hättest du Hartwarebeschleunigung und es 
wäre schneller.

von xpler (Gast)


Lesenswert?

Oh - das ging schnell!

Andreas B. schrieb:
> Ja, zeichne alles in ein Bild.
>
> Danach zeichnest du das Bild auf den Bildschirm. Wenn sich etwas ändert
> zeichnest du nur das neu was sich geändert hat.
Da werd ich erstmal googeln müssen, die GTK bzw Cairo-Doku ist imho 
fürchterlich unübersichtlich und kompliziert. :-(

> Ist bei deiner Konsole alles schwarz / weiss oder verwendest du Farben?
Nur S/W.

> Ggf. wäre ein Textfeld oder ein Label Besser geieignet für dich, habe
> ich aber selbst noch nie ausprobiert.
Kann man das auf weiße Schrift mit schwarzem Hintergrund stellen? Die 
Idee gefällt mir, ich guck mal ob das so geht.

Andreas B. schrieb:
> Aja, ich lese gerade noch von einem Timer mit 1ms?
>
> Was ist das für ein Timer? Codestück?
show_image() ist die Callbackfunktion und der Timer steckt hier:
1
  g_timeout_add(1, show_image, NULL); //Timer

> Du wirst wohl kaum 1ms hinkriegen, da macht der Scheduler bei weitem
> nicht mehr mit.
Schon klar, 1ms heißt "so schnell wie möglich", testweise. Eigentlich 
reicht alle 20 ms oder so, aber das ist eben viel zu langsam, deshalb 
hatte ich mal am Timer gedreht.

> Viellicht solltest du mal genauer beschreiben was der Ablauf deines
> Programms ist, warscheinlich hast du noch einen Groben Denkfehler
> drin...
Das eigentliche Programm welches halt nur unter XP läuft funktioniert 
prima, der Ablauf ist ganz einfach (Pseudocode):
1
volatile int timertick;
2
3
CALLBACK void timer(void) 
4
{
5
  timertick++;
6
}
7
8
int main(void)
9
{
10
  initkrempel();
11
  setze Timer: timer() jede ms aufrufen
12
  
13
  timertick=0;
14
  while(!ende)
15
  {
16
    while(timertick<20)
17
      Sleep(1);
18
    
19
    Gegner bewegen();
20
    Tasten abfragen und Spielfigur bewegen();
21
    usw.
22
23
    Alles neu in versteckten Buffer zeichnen();
24
    
25
    Buffer anzeigen();
26
  }
27
}
Ob der Timer jetzt wirklich jede ms aufgerufen wird ist mir egal, das 
ganze ist schnell genug mit viel Spielraum in Richtung schneller. Den 
Timer auf 20ms zu setzen ginge auch, ich war bisher nur zu faul den Code 
zu ändern.

Mit GTK geht das aufgrund von gtk_main() so nicht, also hab ich die 
Spiellogik (Tastenabfrage und Bewegung) in eine Callbackfunktion gepackt 
welche per Timer regelmäßig aufgerufen wird. Um die Änderungen sichtbar 
zu machen feuere ich dann noch ein passendes event ab, die 
Zeichenfunktion steckt in der Callbackfunktion welche aufgerufen wird. 
Das klappt auch, ist nur eben zu langsam.

Allein für die paar Codezeilen hab ich ewig gegoogelt...

von Andreas B. (andreasb)


Lesenswert?

Der Weise schrieb:
> Wie wäre es mit OpenGL? Dann hättest du Hartwarebeschleunigung und es
> wäre schneller.

Nein, da du bei OpenGL den Text auf der CPU renderst, dann als Textur 
einfügen musst und dann erst dargestellt wird wirst du nicht schneller 
sein.

Von der Komplexität wollen wir garnicht sprechen...


mfg Andreas

von xpler (Gast)


Lesenswert?

Der Weise schrieb:
> Wie wäre es mit OpenGL? Dann hättest du Hartwarebeschleunigung und es
> wäre schneller.
Das ist wahrscheinlich wieder hochkompliziert und was vollkommen neues, 
jetzt wo ich gerade anfange das Prinzip von GTK so ein ganz kleines 
bisschen zu verstehen...

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
>   gtk_widget_queue_draw(window); //neuzeichnen auslösen
>
> da steht queue drin, also dein neuzeichnen wird in die Warteschlange
> gestellt.
>
> neu gezeichnet wird dann wenn er Zeit hat. Leider hat er aber keine
> Zeit, da die ganze Zeit dein Timer auslöst, und ihm sagt er soll dann
> mal neu zeichnen...
Das ist nicht doof... Ich hab mal gtk_widget_queue_draw durch den 
eigentlichen Code fürs neuzeichnen ersetzt, die Callbackfunktion redraw 
geleert und den Timer auf 20ms gestellt: Fehlanzeige, das zeichnet nur 
mit ein paar Hertz, von 50 sind wir weit entfernt...

> Zudem geht das rendern von Text relativ lange, ggf. könntest du ein Bild
> machen (dynamisch) und dann dieses Zeichnen, das könnte noch einen
> Performance Vorteil bringen.
Das verstehe ich jetzt nicht, was meinst du mit "Bild machen"?

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:
> Oh - das ging schnell!
Zu schnell, ich musste 3 mal Posten bis ich alles gesagt hatte=)

> Allein für die paar Codezeilen hab ich ewig gegoogelt...

Jaja, kenne ich.

Mein Projekt ist OpenSource, da du aber wohl Anfänger bist nützt es dir 
nichts wenn ich dir das gebe...

Ich gebe hier ein paar Codeschnipsel, und hoffe die bringen dir was:

Die Variable in die neu gezeichnet wird:
1
  cairo_surface_t * rectBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
width, height);
1
  cairo_t * crRect = cairo_create(rectBuffer);

Hier die Position einstellen, also willst nur (40,40) / (60, 60) neu 
zeichnen, so verschibst du du einfach um -40, -40, und oben bei der 
Grösse gibst du 20, 20 an.
1
  cairo_translate(crRect, -x, -y);

Hier zeichnen.
1
  cairo_destroy(crRect);


Hier wird dann tatsächlich auf das Fenster gezeichnet, das geht schnell!
1
  cairo_t * crPageBuffer = cairo_create(view->crBuffer);
2
3
  cairo_set_operator(crPageBuffer, CAIRO_OPERATOR_SOURCE);
4
  cairo_set_source_surface(crPageBuffer, rectBuffer, x, y);
5
  cairo_rectangle(crPageBuffer, x, y, width, height);
6
  cairo_fill(crPageBuffer);
7
8
  cairo_destroy(crPageBuffer);
9
10
  cairo_surface_destroy(rectBuffer);

In etwa so geht das ziemlich gut, Timing nicht zu schnell machen! 
Schnelles Timing wird dich negativ, nicht positiv beeinflussen!

Du sollste ggf. eher KeyEvents auf dem Window abfangen, anstatt zu 
Pollen, das braucht viel Leistung.


mfg Andreas

von xpler (Gast)


Lesenswert?

Puh, den Code muss ich erstmal verdauen. Schonmal Danke für die Hilfe!

googlevorheiz

von Andreas B. (andreasb)


Angehängte Dateien:

Lesenswert?

Ich habe dein Beispiel etwas angepasst, so läufts.

Das mit der Grafik bringt sicher was, wenn du das Multihtreaded und 
korrekt machst, mein Auszug oben reicht nicht, aber wenn du nur den 
geänderten Bereich neu zeichnest ist es viel schneller.


IST NUR EIN EINFACHES BEISPIEL.

Am besten machst du Setter die dann die Daten korrekt handeln etc.


mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Ich habe dein Beispiel etwas angepasst, so läufts.

Irgendwie steig ich da nicht durch. Wenn ich das laufen lasse sehe ich 
nur ein ganz kleines Stückchen schwarzen Hintergrund, ich will doch das 
ganze Fenster schwarz haben... Naja, vielleicht brauch ich eine Pause.

80*50 Labels zu erstellen klappt übrigens auch nicht wirklich, das 
Ändern der Beschriftung braucht seine Zeit.

Wenn ich meinen Code so abändere dass nur noch geänderte Teile des 
Bildes neu gezeichnet werden
1
      if(buffer_ch[x][y])
2
      {
3
        cairo_move_to(cr, (width/80)*x, (height/50)*y + _MIN(width/80,height/50));
4
        s[0]=buffer[x][y];
5
        cairo_show_text(cr, s);
6
        buffer_ch[x][y]=0;
7
      }
funktioniert es schnell genug, aber eben nur so lange nur nur wenig 
geändert wird, das ist auch keine Lösung.

Ich geb die Suche nach der schnellsten Funktion für heute auf, bis 
morgen...

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

xpler schrieb:
> Ich geb die Suche nach der schnellsten Funktion für heute auf,
> bis morgen...
Eventuell statt mal nach der "schnellen einfachen unkomplizierten 
Funktion" zu suchen mal einen geeigneten Algorithmus/Datenstruktur 
wählen?
Wenn du wirklich "nur" eine Textkonsole haben willst, würde ich:
- char array als Schnittstelle zwischen "Konsole" und Programm
- Ein großes Canvas
- Alle zu verwendenden Zeichen als Bild einmalig erstellen (dynamisch 
oder statisch)
- Immer wenn sich ein Buchstabe ändert das vorgerechnete Bild an die 
passende Stelle malen
- das Ganze noch in passenden Model/View/Controller Klassen kapseln
fertig ist deine Konsole und auch noch bestimmt unschlagbar schnell als 
die Variante "immer alles malen".

von Andreas B. (andreasb)


Lesenswert?

Ich weiss das nicht alles neu gezeichnet wird, ist auch nur ein 
Beispiel, und nicht die fertige Lösung.

Mach folgendes:

Erstelle dir eine Grafik, in der legst du das ganze Alphabet ab.

Wie siehst du oben, dann zeichnest du keine Buchstaben mehr sondern 
kopierst Stücke des Bildes auf deinen Bildschirm.

Zudem zeichnest du nur neu was du wirklich musst, siehe GdkEventExpose 
*event, da drin hats ein Area oder so.

Dann erreichst du diese Performance locker.

Falls nicht, oder du Probleme hast: melde dich einfach nochmal hier.

Warum so: Schriften sind Vektorgrafiken, um diese auf den Bildschirm zu 
bringen müssen diese gerendert werden, also es müssen Bezierkurven etc. 
berechnet werden, das braucht viel Zeit. Das kopieren eines 
Speicherbereiches geht schneller.

Und ich muss meine obige Aussage nochmals korrigieren: am schnellsten 
wärst du wenn du das mit OpenGL machen würdest, alle möglichen Zeichen 
als Texturen auf die Grafikkarte lädst und dann das Bild so 
zusammenbaust. Kannst du aber vergessen, da viel zu aufwändig, und das 
einfache "Text schreiben" mit OpenGL ist nicht schneller wie das hier. 
Würde natürlich so nur mit proportionalen Schriften funktionieren;-)



mfg Andreas

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

Andreas B. schrieb:
> Mach folgendes:
> [...]
Genau das habe ich versucht zu basteln (s. Anhang), so wirklich schnell 
ist es aber auch nicht... Verbesserungsvorschläge?

Es gibt einen kleinen Schönheitsfehler bei der Darstellung, das liegt 
aber nur an der verwendeten Bilddatei (auf die Schnelle mit Paint 
gemacht).

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

xpler schrieb:
> so wirklich schnell
> ist es aber auch nicht
Definiere wirklich schnell.. wieso lädst du z.B. das PNG ständig neu? 
Eine Sinnvolle Kapselung ist auch nicht zu erkenne und daher auch schwer 
zu durchschauen ob du nun wirklich nur den benötigten Bereich 
neuzeichest/neuzeichnen lässt...

von xpler (Gast)


Lesenswert?

Läubi .. schrieb:
> xpler schrieb:
>> so wirklich schnell
>> ist es aber auch nicht
> Definiere wirklich schnell..
Der Timer steht auf 20ms, das heißt wenn man eine der Pfeiltasten drückt 
müsste das Ding im Idealfall innerhalb einer Sekunde quer über den 
Monitor flitzen. Tut es aber nicht, subjektiv ist es also zu langsam.

> wieso lädst du z.B. das PNG ständig neu?
Weil ich Anfänger bin? ;-) Ich änder das mal schnell.

> Eine Sinnvolle Kapselung ist auch nicht zu erkenne und daher auch schwer
> zu durchschauen ob du nun wirklich nur den benötigten Bereich
> neuzeichest/neuzeichnen lässt...
Mit Kapselung meinst du irgendwas Objektorientertes oder? Da bin ich 
überfragt, hab im Gegensatz zu dir kein Informatikstudium im Lebenslauf 
stehen...

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

So, jetzt wird das Bild nur noch einmal geladen. Wirklich gebracht hat 
es nichts.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

xpler schrieb:
> Mit Kapselung meinst du irgendwas Objektorientertes oder?

Nicht zwangsläufig, aber bei C++ böte es sich zumindest an.
Du hast aber wenigstens zweilaml eine gleiche/sehr ähnliche Codestückke, 
das sollte man besser in eine Funktion auslagern.

Auch so was:
1
buffer[Px][Py]='x';
ist unschön, besser
1
function setChar(int x, int y, char c) {
2
buffer[x][y]=c;
3
}
 dann ist klar was passiert, und falls nachher noch irgendwelche 
Umrechnungen machen muss hat man nur eine Stelle ändern und man hat den 
Code nicht mehrmals, wenn dir jetzt auffällt das die indizierung besser 
umgekehrt geschehen sollte.

xpler schrieb:
> Der Timer steht auf 20ms
Kenne mich mit GTK nicht so aus, aber das ist eine Schlechte Idee, es 
muss für Keyevents bei GTK bestimmt spezielle Eventhandler geben, so 
verbrätst du unnötig Rechenzeit, auch das zeichnen im Timerevent scheint 
mir etwas suspekt.

von xpler (Gast)


Lesenswert?

Läubi .. schrieb:
> xpler schrieb:
>> Mit Kapselung meinst du irgendwas Objektorientertes oder?
>
> Nicht zwangsläufig, aber bei C++ böte es sich zumindest an.
Ich programmier aber in C...

> Du hast aber wenigstens zweilaml eine gleiche/sehr ähnliche Codestückke,
> das sollte man besser in eine Funktion auslagern.
Ja, stimmt. Das was ich da erzeugt habe ist Testcode, da kommen solche 
Unschönheiten schonmal vor. Wenn alles funktioniert mach ich das 
ordentlich (schlechte Vorgehensweise, ich weiß).

> Auch so was:
1
buffer[Px][Py]='x';
ist unschön, besser
1
function
2
> setChar(int x, int y, char c) {
3
> buffer[x][y]=c;
4
> }
 dann ist klar was passiert, und falls nachher noch irgendwelche
> Umrechnungen machen muss hat man nur eine Stelle ändern und man hat den
> Code nicht mehrmals, wenn dir jetzt auffällt das die indizierung besser
> umgekehrt geschehen sollte.
S.o.

> xpler schrieb:
> Kenne mich mit GTK nicht so aus, aber das ist eine Schlechte Idee, es
> muss für Keyevents bei GTK bestimmt spezielle Eventhandler geben,
Ich wühl mich mal weiter durch die Doku, mal sehen

> auch das zeichnen im Timerevent scheint
> mir etwas suspekt.
Das ist mir auch suspekt, aber ich sehe bisher keine andere Möglichkeit 
das neue Zeichen auf den Monitor zu bringen. Es müsste eine Funktion 
gtk_widget_queue_draw() geben die nur für einen bestimmten Bereich eine 
"neu zeichnen"-Anforderung stellt (ich krieg es nicht besser erklärt).

von xpler (Gast)


Lesenswert?

> Kenne mich mit GTK nicht so aus, aber das ist eine Schlechte Idee, es
> muss für Keyevents bei GTK bestimmt spezielle Eventhandler geben,
Habe ich mittlerweile gefunden: 
http://developer.gnome.org/gtk/2.24/GtkWidget.html#GtkWidget-key-press-event

Problem: schnarchlangsam! Code kann ich wenn gewünscht hochladen, ist ja 
nur eine neue Callbackfunktion und ein paar Abfragen.

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:
> Problem: schnarchlangsam! Code kann ich wenn gewünscht hochladen, ist ja
> nur eine neue Callbackfunktion und ein paar Abfragen.

Kein Wunder!

Ich habe frühestens Freitag Abend Zeit, habe gerade Prüfungen.

Mach mal folgendes (oder versuchs zumindest, wenns nicht klappt bin ich 
schon hilfsbereit;-))

1. Verwende GTK Events, entferne dein windows.h include (dann kann ich 
es unter Linux problemlos Testen...)

2. Entferne deinen Timer, den brauchst du nicht mehr da du ja events 
kriegst.

3. mach eine Funktion setChar(int x, int y, char c), diese setzt den 
Char im Array. NUR DA darfst du ins Array schreiben.

4. Die Funktion setChar sagt das neu gezeichnet werden muss, und zwar 
mit
1
void                gtk_widget_queue_draw_area          (GtkWidget *widget,
2
                                                         gint x,
3
                                                         gint y,
4
                                                         gint width,
5
                                                         gint height);

5. In deinem Draw zeichnest du nur neu was verlangt wird. Du findest das 
heraus über
1
gboolean gtk_xournal_expose(GtkWidget * widget, GdkEventExpose * event)
2
event->area


Tipp: gboolean gdk_rectangle_intersect(GdkRectangle *src1, GdkRectangle 
*src2, NULL);

So findest du einfach heraus ob was du neu zeichnen musst und was nicht, 
du musst auch die angeschnittenen Teile neu zeichnen.


mfg Andreas

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

Andreas B. schrieb:
> xpler schrieb:
>> Problem: schnarchlangsam! Code kann ich wenn gewünscht hochladen, ist ja
>> nur eine neue Callbackfunktion und ein paar Abfragen.
>
> Kein Wunder!
Wieso?

> Ich habe frühestens Freitag Abend Zeit, habe gerade Prüfungen.
Oh Oh, viel Erfolg!

> 5. In deinem Draw zeichnest du nur neu was verlangt wird. Du findest das
> heraus über
>
1
> gboolean gtk_xournal_expose(GtkWidget * widget, GdkEventExpose * event)
2
> event->area
3
>
Das ist wohl die Callbackfunktion oder? Google kennt den Namen nämlich 
nicht.

Ich hab jetzt alle Tipps umgesetzt (inkl. event->area beim neu 
zeichnen), aber es ist immer noch viel zu langsam. :-(

> Tipp: gboolean gdk_rectangle_intersect(GdkRectangle *src1, GdkRectangle
> *src2, NULL);
> So findest du einfach heraus ob was du neu zeichnen musst und was nicht,
> du musst auch die angeschnittenen Teile neu zeichnen.
Hab ich jetzt nicht gebraucht, hab das anders gelöst (s. Code).

von xpler (Gast)


Lesenswert?

Kleine Änderung (dafür lad ich jetzt keine neue Version hoch):
1
...
2
--int Px=0,Py=0;
3
...
4
5
gboolean process_keys(GtkWidget *widget, GdkEvent *event, gpointer data)
6
{
7
++static int Px=0,Py=0;
8
...

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:
> Andreas B. schrieb:
>> xpler schrieb:
>>> Problem: schnarchlangsam! Code kann ich wenn gewünscht hochladen, ist ja
>>> nur eine neue Callbackfunktion und ein paar Abfragen.
>>
>> Kein Wunder!
> Wieso?

Du hast bei jedem Tastendruck ein komplettes neuzeichnen erzwungen.

Dein Auge ist jedoch garnicht in der Lage diese Geschwindigkeit zu 
sehen.

Und dein PC weigert sich das zu rendern;-)


>
>> Ich habe frühestens Freitag Abend Zeit, habe gerade Prüfungen.
> Oh Oh, viel Erfolg!

Danke.

>
>> 5. In deinem Draw zeichnest du nur neu was verlangt wird. Du findest das
>> heraus über
>>
1
>> gboolean gtk_xournal_expose(GtkWidget * widget, GdkEventExpose * event)
2
>> event->area
3
>>
> Das ist wohl die Callbackfunktion oder? Google kennt den Namen nämlich
> nicht.

Sorry, natürlich;-) Aber hast du ja korrekt erkannt, soweit ich das auf 
der kürze beurteilen kann.

>
> Ich hab jetzt alle Tipps umgesetzt (inkl. event->area beim neu
> zeichnen), aber es ist immer noch viel zu langsam. :-(
>
>> Tipp: gboolean gdk_rectangle_intersect(GdkRectangle *src1, GdkRectangle
>> *src2, NULL);
>> So findest du einfach heraus ob was du neu zeichnen musst und was nicht,
>> du musst auch die angeschnittenen Teile neu zeichnen.
> Hab ich jetzt nicht gebraucht, hab das anders gelöst (s. Code).

Auch gut, was ist dein Problem jetzt? Ich habs gerade getestet, ich 
würde sagen läuft flüssig?

Ggf. ist für dich die Keywiderholungsfrequenz noch das Problem, oder was 
ist das Problem?

Du kannst auf Release und Press reagieren, dann ignorierst du mehrere 
Press events, und reagierst erst wider beim Loslassen.

Intern verwendest du einen Timer, bei dem du dann nichts machst als die 
Variable zu verändern und ein queue draw oder sowas aufrufst.

Warscheinlich ist das was du willst.
1
struct GdkEventKey {
2
  GdkEventType type;
3
  GdkWindow *window;
4
  gint8 send_event;
5
  guint32 time;
6
  guint state;
7
  guint keyval;
8
  gint length;
9
  gchar *string;
10
  guint16 hardware_keycode;
11
  guint8 group;
12
  guint is_modifier : 1;
13
};

GdkEventType type;
  the type of the event (GDK_KEY_PRESS or GDK_KEY_RELEASE).


mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Du hast bei jedem Tastendruck ein komplettes neuzeichnen erzwungen.
>
> Dein Auge ist jedoch garnicht in der Lage diese Geschwindigkeit zu
> sehen.
>
> Und dein PC weigert sich das zu rendern;-)
Ah, ok.

> Auch gut, was ist dein Problem jetzt? Ich habs gerade getestet, ich
> würde sagen läuft flüssig?
Naja, bei mir läuft es zwar "flüssig" aber eben mit einer Refreshrate 
von ein paar Hertz, für ein Spiel ein bisschen langsam. So ein Bilder 
mehr pro Sekunde sollten es schon sein. Wenn du ein Windowsystem (<=XP) 
hast kann ich mal ein Testcode der alten Version (ohne GTK) hochladen, 
das flitzt wie geölt.

> Ggf. ist für dich die Keywiderholungsfrequenz noch das Problem, oder was
> ist das Problem?
Ach so, Moment... Das Neuzeichnen wird ja jetzt durch Key-Events 
ausgelöst, wenn diese also nur mit begrenzter Geschwindigkeit 
verarbeitet werden bremst das auch die Framerate. Moment mal... (Test 
Test Test) OK, wenn ich GetAsyncKeyState() und einen Timer verwende sind 
die Wiederholungsfrequenz der Tastendrücke und die Framerate der Anzeige 
hoch genug. Da ich kein Linux brauche kann ich das so machen, dann würde 
ich mal sagen Problem erstmal gelöst. :-)

Danke für die Hilfe!

von xpler (Gast)


Lesenswert?

Ach so, hat vielleicht jemand einen Tipp wie ich ein PNG mit allen 
Zeichen vom DOS-Zeichensatz erstellen kann?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

xpler schrieb:
> dann würde
> ich mal sagen Problem erstmal gelöst. :-)

nein! Wieso soll der PC den alle paar hunder ms ein Bild neuzeichnen 
wenn sich nix ändert? Das ist doch der Witz, wenn sich nur alle 10 sek 
was ändert zeichnet man auch nur dann neu, eine "Framerate" macht bei 
einer Konsole überhaut keinen Sinn.

xpler schrieb:
> Ach so, hat vielleicht jemand einen Tipp wie ich ein PNG mit allen
> Zeichen vom DOS-Zeichensatz erstellen kann?

http://acspro.atari.org/KeyTab/Modern/0604.html

von xpler (Gast)


Lesenswert?

Läubi .. schrieb:
> xpler schrieb:
>> dann würde
>> ich mal sagen Problem erstmal gelöst. :-)
>
> nein! Wieso soll der PC den alle paar hunder ms ein Bild neuzeichnen
> wenn sich nix ändert? Das ist doch der Witz, wenn sich nur alle 10 sek
> was ändert zeichnet man auch nur dann neu, eine "Framerate" macht bei
> einer Konsole überhaut keinen Sinn.
Aber er zeichnet doch nur neu wenn sich etwas ändert!

>
> xpler schrieb:
>> Ach so, hat vielleicht jemand einen Tipp wie ich ein PNG mit allen
>> Zeichen vom DOS-Zeichensatz erstellen kann?
>
> http://acspro.atari.org/KeyTab/Modern/0604.html
Sieht gut aus, Danke.

von xpler (Gast)


Lesenswert?

xpler schrieb:
> Läubi .. schrieb:
>> nein! Wieso soll der PC den alle paar hunder ms ein Bild neuzeichnen
>> wenn sich nix ändert? Das ist doch der Witz, wenn sich nur alle 10 sek
>> was ändert zeichnet man auch nur dann neu, eine "Framerate" macht bei
>> einer Konsole überhaut keinen Sinn.
> Aber er zeichnet doch nur neu wenn sich etwas ändert!
Ne, halt, stimmt nicht. setChar() wird durch die Timerfunktion  in der 
die Tastenabfrage läuft ja doch wieder regelmäßig aufgerufen. :-(

von xpler (Gast)


Lesenswert?

Ok, jetzt kommt die Gummihammermethode. So sieht die Callbackfunktion 
vom Timer jetzt aus:
1
gboolean process(gpointer data)
2
{
3
  static int Px=0,Py=0;
4
  int left,right,up,down;
5
6
  left=GetAsyncKeyState(VK_LEFT);
7
  right=GetAsyncKeyState(VK_RIGHT);
8
  up=GetAsyncKeyState(VK_UP);
9
  down=GetAsyncKeyState(VK_DOWN);
10
  if(left)
11
  {
12
    if(Px)
13
      Px--;
14
  }
15
  else if(right)
16
  {
17
    if(Px<XMAX)
18
      Px++;
19
  }
20
  if(down)
21
  {
22
    if(Py<YMAX)
23
      Py++;
24
  }
25
  else if(up)
26
  {
27
    if(Py)
28
      Py--;
29
  }
30
31
  if(left||right||up||down)
32
    setChar(Px,Py,'x');
33
34
  return TRUE;
35
}

In setChar() wird auch das neu zeichnen ausgelöst. Was meint ihr/du 
(Läubi), kann man das so lassen oder ist es all zu großer Murks?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

xpler schrieb:
> In setChar() wird auch das neu zeichnen ausgelöst. Was meint ihr/du
> (Läubi), kann man das so lassen oder ist es all zu großer Murks?

In setChar solltest du wenigstens noch prüfen ob an der stelle eventuell 
schon das passende Zeichen steht.

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

So, mittlerweile funktioniert das Ganze fast zufriedenstellend. "Fast" 
weil es durch die Größe der Buchstaben nicht bildschirmfüllend ist. 
Cairo hat ja eine scale-Funktion aber damit bekomme ich die Sache nicht 
hin, kann mir jemand einen Tipp geben?

von xpler (Gast)


Lesenswert?

Ich bekomme ständig folgende Meldung wenn ich cairo_scale benutze:
1
Assertion failed: status == CAIRO_STATUS_SUCCESS, file cairo-pattern.c, line 224
2
9
3
4
This application has requested the Runtime to terminate it in an unusual way.
5
Please contact the application's support team for more information.
6
7
Process returned 3 (0x3)   execution time : 1.687 s
8
Press any key to continue.

?

von Andreas B. (andreasb)


Lesenswert?

Also, am einfachsten machst du dir eine Variable, in der du den 
zoomfaktor speicherst. (Wenn du Vollbild startest machst du das ein mal 
beim Starten, sonst beim Resizen des Fensters)

Der Zoomfaktor ist ganz einfach: 1.0 = 1:1 Abbild, 0.5 = Halb so gross, 
2.0 = doppelt so gross.

also
1
double zoom = (double)fenstegrösse / (double)aktuelle_grösse;

Ist die Aktuelle grösse 100px, das Fenster aber 200px so entsteht ein 
Faktor 200 / 100 = 2.0.

Beim Zeichnen machst du nach
1
  cr=gdk_cairo_create(widget->window);
ein
1
  cairo_scale(crRect, zoom, zoom);

WICHTIG: du musst dein Koordinaten durch den Zoom teilen, also
1
  x1=event->area.x/SZ_PIC_X / zoom;
2
  y1=event->area.y/SZ_PIC_Y / zoom;
3
  x2=x1+event->area.width/SZ_PIC_X / zoom;
4
  y2=y1+event->area.height/SZ_PIC_Y / zoom;

Dafür musst du in setChar die Koordinaten multiplizieren:
1
  gtk_widget_queue_draw_area(window,x*SZ_PIC_X * zoom, y*SZ_PIC_Y * zoom, SZ_PIC_X * zoom, SZ_PIC_Y * zoom);

Dies hebt sich dann schlussendlich wider auf. Du musst es aber trotzdem 
machen, GTK optimiert das ganze, und dann kann es sein das sonst 
Artefakte entstehen könnten.

Und wenns nicht gleich klappt: Denk mal darüber nach ob ggf. etwas 
verkehrt herum ist, ich habs nicht ausprobiert, und bei dem Zoom zeugs 
hat man schnell mal ein 1/x zuviel oder zuwenig...


mfg Andreas

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:
> Ich bekomme ständig folgende Meldung wenn ich cairo_scale benutze:
>
>
1
Assertion failed: status == CAIRO_STATUS_SUCCESS, file
2
> cairo-pattern.c, line 224
3
> 9
4
> 
5
> This application has requested the Runtime to terminate it in an unusual
6
> way.
7
> Please contact the application's support team for more information.
8
> 
9
> Process returned 3 (0x3)   execution time : 1.687 s
10
> Press any key to continue.
>
> ?

Dann musst du einfach Debuggen, also "Steop Over", bis abschmiert, 
nachher schaust du dir die Zeile an die nicht funktioniert hat und 
denkst darüber nach warum nicht.

Wenn du selbst nicht darauf kommst was das Problem ist fragst du hier 
nochmals nach, natürlich die entsprechende Zeile angeben, sonst wirds 
schwierig...


mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Also, am einfachsten machst du dir eine Variable, in der du den
> zoomfaktor speicherst. (Wenn du Vollbild startest machst du das ein mal
> beim Starten, sonst beim Resizen des Fensters)
>
> Der Zoomfaktor ist ganz einfach: 1.0 = 1:1 Abbild, 0.5 = Halb so gross,
> 2.0 = doppelt so gross.
Ok, soweit war ich schon gekommen. Erstmal testweise für meine 
Auflösung:
1
double zoomX=(double)1280/(XMAX*SZ_PIC_X), zoomY=(double)1024/(YMAX*SZ_PIC_Y);

> Und wenns nicht gleich klappt: Denk mal darüber nach ob ggf. etwas
> verkehrt herum ist, ich habs nicht ausprobiert, und bei dem Zoom zeugs
> hat man schnell mal ein 1/x zuviel oder zuwenig...
Also in X-Richtung funktioniert es prima, aber sobald zoomY einen 
anderen Wert als 1 hat kommt nur noch Käse raus. Irgendwo ist da noch 
der Wurm drin, ich geh dann mal auf die Suche...

Andreas B. schrieb:
> xpler schrieb:
>> Ich bekomme ständig folgende Meldung wenn ich cairo_scale benutze:
>>
>>
1
Assertion failed: status == CAIRO_STATUS_SUCCESS, file
2
>> cairo-pattern.c, line 224
3
>> 9
4
>>
5
>> This application has requested the Runtime to terminate it in an unusual
6
>> way.
7
>> Please contact the application's support team for more information.
8
>>
9
>> Process returned 3 (0x3)   execution time : 1.687 s
10
>> Press any key to continue.
>>
> Dann musst du einfach Debuggen, also "Steop Over", bis abschmiert,
> nachher schaust du dir die Zeile an die nicht funktioniert hat und
> denkst darüber nach warum nicht.
Stimmt natürlich, nur habe ich keine cairo-pattern.c...

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

xpler schrieb:
> sobald zoomY einen anderen Wert als 1 hat kommt nur noch Käse raus
Hier noch ein Bild.

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:

>> Dann musst du einfach Debuggen, also "Steop Over", bis abschmiert,
>> nachher schaust du dir die Zeile an die nicht funktioniert hat und
>> denkst darüber nach warum nicht.
> Stimmt natürlich, nur habe ich keine cairo-pattern.c...

Bei "Step Over" brauchst du das auch nicht.

Du musst nur DEIN code Debuggen, denn mit ziemlicher Sicherheit liegt 
der Fehler da.

mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Du musst nur DEIN code Debuggen, denn mit ziemlicher Sicherheit liegt
> der Fehler da.
Ach so, manchmal sieht man den Wald vor lauter Bäumen nicht mehr...

von xpler (Gast)


Lesenswert?

Ich komm nicht drauf. Der Code läuft fehlerlos durch, in X-Richtung 
passt es mit dem Zoom aber sobald ZoomY einen anderen Wert als 1 hat 
bekomme ich nur Streifen auf dem Monitor. Argh.

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

Quellcode vergessen...

von Andreas B. (andreasb)


Lesenswert?

Gibt mal die Zoomfaktoren aus.

Hier könnte das Problem liegen, ich bin mir gerade nicht sicher mit den 
Prioritäten.
double zoomX=(double)1280/(XMAX*SZ_PIC_X), 
zoomY=(double)1024/(YMAX*SZ_PIC_Y);

Schreibe lieber:
double zoomX=1280.0/(XMAX*SZ_PIC_X);
double zoomY=1024.0/(YMAX*SZ_PIC_Y);




mfg Andreas

von xpler (Gast)


Lesenswert?

Hm... Die Zoomfaktoren sind mit beiden Methoden korrekt (zoomX=2 und 
zoomY=1,28), das Problem bleibt.

Aber: Wenn ich zoomY auf eine Ganzzahl (2) setze funktioniert es (aber 
ist natürlich zu groß). Offensichtlich gibt die Gleitkommazahl irgendwo 
Probleme. Hab mal testweise ein paar Casts eingebaut, das löst das 
Problem leider auch nicht. Hätte mich auch gewundert, ich sehe keine 
Stelle (außer der Faktorenberechnung) wo Casts nötig wären.

von Andreas B. (andreasb)


Lesenswert?

setze mal beide auf 1.2x und schaue obs dann geht...

Ich habe immer zwei mal den gleichen Wert verwendet.
(Etwas anderes macht bei einem PDF auch keinen Sinn)



mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> setze mal beide auf 1.2x und schaue obs dann geht...
Es geht nicht, ich bekomme horizontale und vertikale Streifen. Ist das 
vielleicht eine Einschränkung in der Library dass die Werte Ganzzahlen 
sein müssen?!?

von Andreas B. (andreasb)


Lesenswert?

Definitiv nicht, bei mir funktioniert es mit Fliesskomma zahlen 
Problemlos.

Mit Ganzzahlen funktioniert es?


mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Mit Ganzzahlen funktioniert es?
Ja. Mit zoomX=2 (berechneter Wert) und zoomY=1 oder zoomY=2 funktioniert 
es. Mit zoomX=2 und zoomY=1.28 funktioniert es nicht.

von Andreas B. (andreasb)


Lesenswert?

Und beide 1.28? Funktioniert das auch?


mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Und beide 1.28? Funktioniert das auch?
Nein, s.o.

von xpler (Gast)


Lesenswert?

Ich hab mal folgendes ausprobiert:

Statt
1
cairo_set_source_surface (cr,image, x*SZ_PIC_X-MUL_PIC_X*buffer[x][y]-OFF_PIC_X, y*MUL_PIC_Y-OFF_PIC_Y);
2
cairo_rectangle(cr,x*SZ_PIC_X,y*SZ_PIC_Y,SZ_PIC_X,SZ_PIC_Y);
3
cairo_fill(cr);

steht jetzt folgender Code
1
cairo_rectangle(cr,x*SZ_PIC_X,y*SZ_PIC_Y,SZ_PIC_X,SZ_PIC_Y);
2
cairo_stroke(cr);

in der Schleife und siehe da, ich bekomme immer vernünftige Rechtecke, 
auch mit zoomY!=1. Es liegt also am Befehl cairo_set_source_surface() 
oder am Bild.

von xpler (Gast)


Lesenswert?

Ich kann machen was ich will, cairo_scale() und 
cairo_set_source_surface() vertragen sich nicht. Was meint ihr, könnte 
es eine Lösung sein die Buchstaben erst in ein PNG zu schreiben, dieses 
irgendwie zu zoomen (ohne cairo_scale) (wie?) und anzuzeigen oder gibt 
das wieder andere Probleme? Ich weiß langsam nicht mehr weiter.

von Andreas B. (andreasb)


Lesenswert?

Habs jetzt gerade nicht mehr im Kopf, nim mal für x und y den gleichen 
Faktor.

Wenns dann nicht geht lade nochmals den kompletten Code hoch. Dann 
schaue ich nochmals rein.



mfg Andreas

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

Andreas B. schrieb:
> Habs jetzt gerade nicht mehr im Kopf, nim mal für x und y den gleichen
> Faktor.
Geht auch nicht.

> Wenns dann nicht geht lade nochmals den kompletten Code hoch. Dann
> schaue ich nochmals rein.
Ist im Anhang, Dankeschön.

von xpler (Gast)


Lesenswert?

Kann mir vielleicht jemand ein Forum empfehlen wo mehr GTK-Kenner 
unterwegs sind? Ich will in dieser Sache endlich mal zu einem Ergebnis 
kommen...

von Andreas B. (andreasb)


Lesenswert?

Schreibe direkt auf die GTK Mailinglists.

Da sind auch die GTK Leute unterwegs.



mfg Andreas

von xpler (Gast)


Lesenswert?

Gibt es diese Mailinglists auch auf deutsch?

Mein letzter verzweifelter Versuch sah übrigens so aus, geht auch nicht:
1
cairo_scale(cr, zoomX, 1);
2
cairo_rotate(cr,M_PI/2);
3
cairo_scale(cr, zoomY, 1);
4
cairo_rotate(cr,-M_PI/2);

von Andreas B. (andreasb)


Lesenswert?

Mailinglist sind normalerweise auf Englisch.

Wenn du kein Englisch kannst schreibe auf Deutsch, lasse es von Google 
Translator übersetzten und sende beides auf die Mailinglist;-)

Es werden sich warscheinlich ein paar Leute beschweren, aber es hat 
ziemlich sicher auch Deutschsprachige Dabei...


Ansonsten, schaue dir doch mal noch Gnome-terminal an...

http://git.gnome.org/browse/gnome-terminal/tree/src?h=gnome-2-30


Ich habe momentan keine Zeit um mehr zu helfen...




mfg Andreas

von Salewski, Stefan (Gast)


Lesenswert?

Autor: Andreas B. (andreasb)
Datum: 18.02.2012 17:20

>Schreibe direkt auf die GTK Mailinglists.

Na ja, wenn es um Cairo geht wohl eher

cairo@cairographics.org

Aber für wirklich schnelle Animation ist Cairo nicht so gut geeignet, da 
wäre wohl OpenGL besser. Achje, Windows -- warum muss man da GTK und 
Cairo verwenden, haben die nichts eigenes?

von Andreas B. (andreasb)


Lesenswert?

Salewski, Stefan schrieb:
> Autor: Andreas B. (andreasb)
> Datum: 18.02.2012 17:20
>
>>Schreibe direkt auf die GTK Mailinglists.
>
> Na ja, wenn es um Cairo geht wohl eher
>
> cairo@cairographics.org

Hast du natürlich recht...

> Aber für wirklich schnelle Animation ist Cairo nicht so gut geeignet, da
> wäre wohl OpenGL besser. Achje, Windows -- warum muss man da GTK und
> Cairo verwenden, haben die nichts eigenes?

Vergiss OpenGL, dafür hat er 1. zuwenig Erfahrung und 2. ist der 
Performance Unterschied zu gering.

Was würdest du denn unter Windows verwenden?

Ich denke vom Komfort her ist Cairo definitiv eine sehr gute Wahl...




mfg Andreas

von Andreas B. (andreasb)


Lesenswert?

Im übrigen handelt es sich um einen einen Programierfehler, nicht um ein 
Cairo Problem.

Ich bin gerade am suchen. Kann doch nicht so schwer sein:-/



mfg Andreas

von Andreas B. (andreasb)


Angehängte Dateien:

Lesenswert?

Hier die Lösung

Es waren mehrere Problem, das wichtigste: Cairo Zeichnet das Zeichen 
Oberhalb der angegebenen Koordinate, und das war ausserhalb des neu 
gezeichneten Bereiches.

ps. wenn ich mich nicht irre macht auch Java das so...

Bei mir funktioniert das jetzt flüssig, ich habe noch ein Rechteck um 
den Buchstaben gezeichnet, das ist nur zum Debuggen, kannst du ja wider 
raus nehmen.



mfg Andreas

von xpler (Gast)


Lesenswert?

Danke! Funktioniert prima, jetzt kann ich endlich weitermachen.

von xpler (Gast)


Lesenswert?

Öhh Moment, du nutzt ja das PNG gar nicht sondern hast das wieder auf 
Text umgestrickt. Warum? Geht es mit dem PNG nicht?

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:
> Öhh Moment, du nutzt ja das PNG gar nicht sondern hast das wieder auf
> Text umgestrickt. Warum? Geht es mit dem PNG nicht?

weil so das Problem mit der Skalierung weg ist.

Optimieren könntest du es indem du zur Laufzeit am Anfang die Bilder 
zeichnest, und im Speicher behälst, aber die Performance auch so reicht 
denke ich sollte das für dich OK sein...

In solchen Dingen hilft oft nur experimentieren, und ich bin der Meinung 
es läuft genug schnell;-)




mfg Andreas

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> xpler schrieb:
>> Öhh Moment, du nutzt ja das PNG gar nicht sondern hast das wieder auf
>> Text umgestrickt. Warum? Geht es mit dem PNG nicht?
>
> weil so das Problem mit der Skalierung weg ist.
Stimmt natürlich, aber irgendwie wüsste ich schon gerne wie es mit dem 
PNG geht. Zumal dein Quellcode zwar prima funktioniert aber eine zu 
kleine Fläche (ich brauche 80x50 Zeichen) erzeugt und ich gerade nicht 
so durchblicke was ich da ändern müsste.

Ich hab mich mal bei der Cairo Mailinglist angemeldet und werde mal 
meine drei Englischkentnisse zusammenfegen um nach dem PNG-scale-Problem 
zu fragen. Ich berichte dann hier wenn es was neues gibt.

Danke für die Hilfe!

von Andreas B. (andreasb)


Lesenswert?

Es geht, ich habe nur den Fehler in deinem Code nicht gesehen.

Als Referenz kann ich sonst meine Applikation noch angeben.

http://xournal.svn.sourceforge.net/viewvc/xournal/trunk/xournalpp/


Hier wird zwar ein PDF gerendert, aber ob das von einem PDF oder von 
einem PNG geladen wurde ist beim Skalieren egal, da schlussendlich 
beides beim Anzeigen nur noch ein Cairo image sourface ist.





mfg Andreas

von Salewski, Stefan (Gast)


Lesenswert?

>Ich hab mich mal bei der Cairo Mailinglist angemeldet

Ich habe zwar keine Ahnung um was es eigentlich geht, verstehe die 
Bildchen nicht, und kann auch nichts probieren, da ich kein Windows 
verwende...

Aber nach

>As long as i not use cairo_scale() or use
>only integer values for scaling this works great

würde ich Integer/Float Rechenprobleme vermuten, etwa bei

int x1,x2,y1,y2;
int x,y;
x1=event->area.x/SZ_PIC_X/zoomX;

cairo_rectangle(cr,x*SZ_PIC_X,y*SZ_PIC_Y,SZ_PIC_X*zoomX,SZ_PIC_Y*zoomY);

Erst Teilen durch zoomX, dann wieder multiplizieren, mit Integer 
Beteiligung -- da muss man aufpassen.

Und grundsätzlich braucht man bei Cairo ja oft gar nicht so viel 
Rechnungen, durch scale() und translate() lässt sich ja viel direkt 
erschlagen, siehe etwa die Beispiele

http://cairographics.org/threaded_animation_with_cairo/

Cairo sieht schon ganz nett aus, aber man muss sich schon überlegen was 
man wie tut, sonst wird es etwas langsam, wie derzeit bei meiner 
Spielerei
http://www.ssalewski.de/PetEd.html.en

von Andreas B. (andreasb)


Lesenswert?

Salewski, Stefan schrieb:
>>Ich hab mich mal bei der Cairo Mailinglist angemeldet
>
> Ich habe zwar keine Ahnung um was es eigentlich geht, verstehe die
> Bildchen nicht, und kann auch nichts probieren, da ich kein Windows
> verwende...

Da du aufgrund deiner Homepage Ahnung davon hast noch ein Tipp;-)

gcc -Wall -g main.c -o main `pkg-config --cflags --libs gtk+-2.0` && 
./main

Zumindest meine Version kompiliert so ohne Probleme unter Ubuntu...

>
> Aber nach
>
>>As long as i not use cairo_scale() or use
>>only integer values for scaling this works great
>
> würde ich Integer/Float Rechenprobleme vermuten, etwa bei

Wird auch so etwas gewesen sein, aber ich habs nicht gesehen...

> Erst Teilen durch zoomX, dann wieder multiplizieren, mit Integer
> Beteiligung -- da muss man aufpassen.
>
> Und grundsätzlich braucht man bei Cairo ja oft gar nicht so viel
> Rechnungen, durch scale() und translate() lässt sich ja viel direkt
> erschlagen, siehe etwa die Beispiele

Ich habs jetzt absichtlich OHNE scale gemacht, da beim redraw die 
Faktoren auch eingerechnet werden müssen, und das ist dann wieder eine 
Potenzielle Fehlerquelle...

>
> http://cairographics.org/threaded_animation_with_cairo/
>
> Cairo sieht schon ganz nett aus, aber man muss sich schon überlegen was
> man wie tut, sonst wird es etwas langsam, wie derzeit bei meiner
> Spielerei
> http://www.ssalewski.de/PetEd.html.en

Sieht gut aus;-)

Wobei da sollte es eigentlich noch kein Problem sein, ich habs 
unterdessen geschafft bei 300 PDF Seiten noch eine brauchbare 
Scrollgeschwindigkeit zu erreichen;-)
Einfach in Images rendern und dann die Images auf den Bildschirm 
zeichnen, dann geht es relativ schnell...

http://xournal.svn.sourceforge.net/viewvc/xournal/trunk/xournalpp/

ps. nicht lauffähig unter Windows;-)



mfg Andreas

von Jonas K. (jonas_k56)


Lesenswert?

Hi!
Bin über deinen Post auf der mailing list hier drauf gestoßen.

Zu der Sache mit dem png: du könntest doch beim Start stattdessen ein 
cairo_surface_t* array erstellen, in welches du alle Buchstaben 
reinrenderst und dann müsstest du beim Neuzeichnen immer jeweils nur die 
entsprechende surface malen. Dann hättest du dir die png gespart und den 
selben Effekt erreicht.

Und generell: cairo_scale manipuliert in erster Linie die 
Transformationsmatrix, sprich es wirkt sich auf alles aus, was irgendwie 
mit Koordinaten zutun hat. Was es nicht beeinflusst, ist das Skalieren 
von Bildern bzw. surfaces. (Hoffe ich sag jetzt nichts was schon gesagt 
wurde..)

Ich hab mal bei der neusten Version hier (von Andreas) in process_keys() 
am Anfang
1
int oldX = Px,
2
    oldY = Py;
und vor dem setChar am Ende
1
setChar(oldX, oldY, ' ');
eingefügt, damit das x nicht so ne Spur von sich hinterlässt..

von xpler (Gast)


Lesenswert?

Andreas B. schrieb:
> Es geht, ich habe nur den Fehler in deinem Code nicht gesehen.
Ok, kein Problem.

> Als Referenz kann ich sonst meine Applikation noch angeben.
> http://xournal.svn.sourceforge.net/viewvc/xournal/trunk/xournalpp/
Wow, so gut möchte ich auch programmieren können!

Salewski, Stefan schrieb:
> Erst Teilen durch zoomX, dann wieder multiplizieren, mit Integer
> Beteiligung -- da muss man aufpassen.
Da hast du wohl Recht, allerdings kann ich einfach keinen Fehler finden. 
Das ganze ist vermutlich sowieso suboptimal, aber auf eine 
Division/Multiplikation kommt es beim PC nicht an...

> http://www.ssalewski.de/PetEd.html.en
Nett.

Jonas K. schrieb:
> Hi!
> Bin über deinen Post auf der mailing list hier drauf gestoßen.
Herzlich Willkommen. Wenigstens war also mein Post erfolgreich, hab 
bisher nie zuvor eine Mailinglist benutzt...

> Zu der Sache mit dem png: du könntest doch beim Start stattdessen ein
> cairo_surface_t* array erstellen, in welches du alle Buchstaben
> reinrenderst und dann müsstest du beim Neuzeichnen immer jeweils nur die
> entsprechende surface malen. Dann hättest du dir die png gespart und den
> selben Effekt erreicht.
Puh, mal gucken ob ich das in Code umgesetzt bekomme. Du meinst also 
sowas wie
1
cairo_surface_t pattern[256];
2
foreach pattern do
3
  zeichne einen(!) Buchstaben vom png nach pattern[buchstabe];
4
5
...
6
7
redraw: kopierere pattern[buchstabe] nach cr;
?

> Und generell: cairo_scale manipuliert in erster Linie die
> Transformationsmatrix, sprich es wirkt sich auf alles aus, was irgendwie
> mit Koordinaten zutun hat. Was es nicht beeinflusst, ist das Skalieren
> von Bildern bzw. surfaces.
Das heißt es gibt für Bilder noch eine andere scale-Funktion?

von xpler (Gast)


Lesenswert?

> Zu der Sache mit dem png: du könntest doch beim Start stattdessen ein
> cairo_surface_t* array erstellen, in welches du alle Buchstaben
> reinrenderst und dann müsstest du beim Neuzeichnen immer jeweils nur die
> entsprechende surface malen. Dann hättest du dir die png gespart und den
> selben Effekt erreicht.
Hab ich ausprobiert (Code auf Wunsch), bringt leider nix, Zoomproblem 
bleibt. Ach Mensch dass das so kompliziert sein muss. Ich warte auf 
Antworten in der Mailinglist, mal schauen.

von Jonas K. (jonas_k56)


Lesenswert?

xpler schrieb:
>> Hi!
>> Bin über deinen Post auf der mailing list hier drauf gestoßen.
> Herzlich Willkommen. Wenigstens war also mein Post erfolgreich, hab
> bisher nie zuvor eine Mailinglist benutzt...
>
Kann dich verstehen (; Bin bei meinem ersten Post auf einer direkt 
gebannt worden, hab seit dem glaub ich nie wieder auf eine geschrieben..

>> Zu der Sache mit dem png: du könntest doch beim Start stattdessen ein
>> cairo_surface_t* array erstellen, in welches du alle Buchstaben
>> reinrenderst und dann müsstest du beim Neuzeichnen immer jeweils nur die
>> entsprechende surface malen. Dann hättest du dir die png gespart und den
>> selben Effekt erreicht.
> Puh, mal gucken ob ich das in Code umgesetzt bekomme. Du meinst also
> sowas wiecairo_surface_t pattern[256];
> foreach pattern do
>   zeichne einen(!) Buchstaben vom png nach pattern[buchstabe];
>
> ...
>
> redraw: kopierere pattern[buchstabe] nach cr;
> ?
So ähnlich. Meine Idee war: zeichne in jede surface einen char mit 
'cairo_show_text()'.
Mir fällt aber gerade auf dass du ja genau die DOS Font haben wolltest, 
von daher vergiss bitte wieder, was ich da gesagt habe (; Die png Lösung 
ist da wohl doch am angebrachtesten.

>> Und generell: cairo_scale manipuliert in erster Linie die
>> Transformationsmatrix, sprich es wirkt sich auf alles aus, was irgendwie
>> mit Koordinaten zutun hat. Was es nicht beeinflusst, ist das Skalieren
>> von Bildern bzw. surfaces.
> Das heißt es gibt für Bilder noch eine andere scale-Funktion?
Ahh sry hab da was verwechselt. Tut mir Leid, vergiss das auch bitte 
wieder..

von Salewski, Stefan (Gast)


Lesenswert?

Andreas B. (andreasb) schrieb:

>gcc -Wall -g main.c -o main `pkg-config --cflags --libs gtk+-2.0` &&
./main

>Zumindest meine Version kompiliert so ohne Probleme unter Ubuntu...

Ja, Deine Version sicher, aber die funktioniert ja wohl eh.

Seine Version, auf die er sich auf der Cairo Mailing-Liste bezieht, 
nutzt aber Windows-Funktionen, dass kann ich so nicht kompilieren.

Was mir eben beim Durchscrollen ins Auge fiel, bei seiner Version:

>gtk_widget_queue_draw_area(window,x*SZ_PIC_X*zoomX, y*SZ_PIC_Y*zoomY, 
>SZ_PIC_X*zoomX, SZ_PIC_Y*zoomY);

Ich kann mir kaum vorstellen, dass da Double als Parameter akzeptiert 
wird (durch zoomX), dass ist ja nicht Cairo, sondern GTK, sollte also 
Int sein.

Ist wohl auch so

http://developer.gnome.org/gtk/2.24/GtkWidget.html#gtk-widget-queue-draw-area

Aber unter C geht wohl fast aller Blödsinn.

von Salewski, Stefan (Gast)


Lesenswert?

Autor: Jonas K. (jonas_k56)

>Und generell: cairo_scale manipuliert in erster Linie die
>Transformationsmatrix, sprich es wirkt sich auf alles aus, was irgendwie
>mit Koordinaten zutun hat. Was es nicht beeinflusst, ist das Skalieren
>von Bildern bzw. surfaces. (Hoffe ich sag jetzt nichts was schon gesagt
>wurde..)

Nein, die Transformationen können durchaus auf Bilder, Patterns usw. 
angewendet werden -- meist sieht das aber nicht gut aus, weil man dann 
eine bereits gerasterte Grafik skaliert. Wobei, ich habe das noch nicht 
gemacht, aber soweit ich die Doku richtig verstanden habe...

>> bisher nie zuvor eine Mailinglist benutzt...
>>
>Kann dich verstehen (; Bin bei meinem ersten Post auf einer direkt
>gebannt worden, hab seit dem glaub ich nie wieder auf eine geschrieben..

Komisch, die Listen, die ich kenne dulden auch Dummschwätzer, nur wird 
dann eben meist nicht geantwortet.

von Salewski, Stefan (Gast)


Lesenswert?

>Ist wohl auch so

>http://developer.gnome.org/gtk/2.24/GtkWidget.html...

>Aber unter C geht wohl fast aller Blödsinn.

Ist wohl aber auch nicht das Problem und auch kein wirklicher Blödsinn,
bei Zuweisung von float/double an int wird wohl automatisch konvertiert, 
wie ich eben ausprobiert habe. Wusste ich nicht, ich kannte für C nur 
die erlaubte Zuweisung von int an float und habe sonst wenn nötig stets 
explizite Typumwandlung genutzt.

von Salewski, Stefan (Gast)


Lesenswert?

>Also in X-Richtung funktioniert es prima, aber sobald zoomY einen
>anderen Wert als 1 hat kommt nur noch Käse raus.

Da wohl auf der Cairo-Liste keiner geantwortet hat, habe ich doch noch 
mal einen kurzen Blick in diesen Thread geworfen. Wobei es für mich 
schon etwas verwirrend ist, erst geht es um zu langsam, dann um scale() 
mit double, dann wieder um...

Und Andreas hat ja schon versuch Dir gut zu helfen -- wenn Du wirklich 
Interesse hättest würdest Du dich systematisch selber etwas bemühen. 
Wenn es letztlich nur Probleme mit double für zoomY gibt, könnte man ja 
mal an einigen Stellen 1.01 und anderswo 1 verwenden, um die kritische 
Stelle zu finden. Aber was mir einfiel nach Deiner obigen Aussage: Du 
weist schon, wie das bei Cairo mit dem Koordinatennullpunkt ist? Der ist 
vorgabemäßig unter links! Und sonst: Eines Deiner Bildchen PNG war ja 
extrem lang in X-Richtung, könnte die Länge das Problem sein?

Jetzt aber Schluss.

von xpler (Gast)


Lesenswert?

Salewski, Stefan schrieb:
> Wobei es für mich
> schon etwas verwirrend ist, erst geht es um zu langsam, dann um scale()
> mit double, dann wieder um...
Ja, langsam wird es unübersichtlich. Also mal kurz von vorne: Zuerst 
hatte ich das Problem das mein Code (noch ohne scale) viel zu langsam 
war. Das Geschwindigkeitsproblem habe ich dann mit der png-Methode 
gelöst was auch prinzipiell funktioniert hat (noch immer ohne scale). 
Dann wollte ich das ganze noch über den ganzen Monitor strecken, habe 
scale eingebaut und festgestellt dass es damit nicht richtig 
funktioniert. Das ist auch das aktuelle Problem weswegen ich die 
Mailinglist angeschrieben habe. Soweit alles klar?

> Und Andreas hat ja schon versuch Dir gut zu helfen -- wenn Du wirklich
> Interesse hättest würdest Du dich systematisch selber etwas bemühen.
Ich habe Interesse und habe schon viel alleine gesucht und probiert 
(systematisch und unsystematisch), das Problem bleibt aber. Für die 
Hilfe von Andreas habe ich mich (mehrfach) bedankt.

> Wenn es letztlich nur Probleme mit double für zoomY gibt, könnte man ja
> mal an einigen Stellen 1.01 und anderswo 1 verwenden, um die kritische
> Stelle zu finden.
Die kritische Stelle ist der scale-Aufruf, sobald dort eine 
Gleitkommazahl für ZoomY eingesetzt wird kommt nur noch Käse raus.

> Aber was mir einfiel nach Deiner obigen Aussage: Du
> weist schon, wie das bei Cairo mit dem Koordinatennullpunkt ist? Der ist
> vorgabemäßig unter links!
Äh... nicht eher oben links? Das passt eher zu dem was ich beobachtet 
habe.

> Und sonst: Eines Deiner Bildchen PNG war ja
> extrem lang in X-Richtung, könnte die Länge das Problem sein?
Es gibt nur ein Bild, das ist in der Tat extrem lang. Wenn ich es 
testweise verkürze bleibt das Problem mit scale.

Die Konvertierungsissues auf die du mich in der Mailinglist hingewiesen 
hast habe ich testweise korrigiert (auf int gecastet), bringt leider 
nichts.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

xpler schrieb:
> sobald dort eine Gleitkommazahl für ZoomY
> eingesetzt wird kommt nur noch Käse raus
Auch wenn du es bisher geflissentlich überlesen hast: Man kann nicht ein 
Bild ohne Verluste/Artefakte auf beliebige Faktoren skalieren!

Wieso machst du nicht erst mal eine Konsole die einen "fixen" Font hat 
(von miraus mit 2 oder 3 möglichen Auflösungen)?

Wenn du wirklich beliebige Zoomfaktoren haben willst (was spätestens 
dann schwer wird wenn du eigentlich einen 80x40 Konsole erwartest und 
das Bild 500x20 Pixel hat) musst du (wie vorgeschlagen) einen passenden 
Font wählen und bei jeder Größenänderung dein Alphabet neu aufbauen.

von Andreas B. (andreasb)


Lesenswert?

xpler schrieb:
> Hilfe von Andreas habe ich mich (mehrfach) bedankt.

Schon OK, wenn mich die Leute nerven oder so ist ziemlich schnell die 
Mailbenachrichtigung abgeschaltet;-)

>> Aber was mir einfiel nach Deiner obigen Aussage: Du
>> weist schon, wie das bei Cairo mit dem Koordinatennullpunkt ist? Der ist
>> vorgabemäßig unter links!
> Äh... nicht eher oben links? Das passt eher zu dem was ich beobachtet
> habe.

Naja, beide haben recht, und das verursacht ggf. etwas Verwirrung.

Auf dem Bildschirm / Bild wird tatsächlich von oben links her gezählt. 
Beim Text wird von unten links her gezählt, also der Text wird 
oberhalb der Koordinate gezeichnet.

Ich verweise hiermit mal auf 
http://zetcode.com/tutorials/cairographicstutorial/cairotext/

Hier ein Beispiel zu cairo_text_extents_t.

Das ganze ist am Anfang ziemlich unübersichtlich, aber ist bei Java oder 
auch anderen Libraries oft ähnlich...

(Bei genauer Betrachtung macht es im übrigen auch Sinn!)

>> Und sonst: Eines Deiner Bildchen PNG war ja
>> extrem lang in X-Richtung, könnte die Länge das Problem sein?

Ich schliesse das aus, da ich selbst für Xournal++ bei 400 fachem Zoom 
und 300 DPI bilder mit ca. 3'500px Breite durchaus noch darstellen kann, 
und im übrigen auch Skalieren=)

> Die Konvertierungsissues auf die du mich in der Mailinglist hingewiesen
> hast habe ich testweise korrigiert (auf int gecastet), bringt leider
> nichts.

@xpler

Nim den Code der läuft, und leg de alten einfach weg.

Theoretisch funktioniert das ganze mit dem PNG. Der Fehler liegt mit 
Sicherheit in deinem Code.

Da aber weder ich noch Stefan und wer auch immer noch in den Code 
geschaut hat den Fehler auch nicht sehen ist er wohl sehr gut getarnt...

Wenn du jetzt etwas Erfahrung sammelst mit GTK oder so, dann kannst du 
in einem halben Jahr noch mal einen Blick auf deinen Code werfen, wenn 
du etwas Abstand hast, und nicht mehr so genau weisst wie das ganze 
funktioniert, dann nochmals genauer hinschaust siehst du plötzlich was 
bis jetzt verborgen blieb;-)

mfg Andreas

von Salewski, Stefan (Gast)


Lesenswert?

>Äh... nicht eher oben links? Das passt eher zu dem was ich beobachtet
>habe.

Ja, da habe ich mich mal wieder vertan, ich hatte bei meiner Anwendung 
ganz zu Anfang

cr.translate(0, @darea.allocation.height)
cr.scale(1, -1)

um den Ursprung von links oben nach links unten zu setzen.

von Salewski, Stefan (Gast)


Lesenswert?

>Die kritische Stelle ist der scale-Aufruf, sobald dort eine
>Gleitkommazahl für ZoomY eingesetzt wird kommt nur noch Käse raus.

Da müsste man ein Minimalbeispiel machen und dann auf der Mailingliste 
fragen. Je überschaubarer es ist, um so eher bekommt man Antwort, oder 
man sieht das Problem sogar selbst. (Das Beispiel sollte auf Linux 
lauffähig sein, denn die Meisten Entwickler haben eher Linux.) Zu PNG 
scaling gibt es ein Beispiel

http://www.cairographics.org/samples/clip_image/

damit könntest du etwas experimentieren.

Aber wie gesagt, Skalierung einer Rastergrafik ist von der Qualität nie 
gut. Du könntest das PNG-Bild auch einfach mit Gimp skalieren, wenn Du 
nur eine feste größere Größe willst. Oder Du könntest dann mehrere 
PNG-Bildchen nehmen, oder verschiedene Font-Größen in einem PNG.

von Salewski, Stefan (Gast)


Lesenswert?

Und hier noch das von Andreas erwähnte Beispiel von Zetcode

http://zetcode.com/tutorials/cairographicstutorial/cairoimages/

um scale() erweitert und mit deinem Bildchen getestet.

Unter Linux funktioniert alles, vielleicht ist das ja auch ein 
Windows-Problem?
1
#include <cairo.h>
2
#include <gtk/gtk.h>
3
4
cairo_surface_t *image;
5
6
static gboolean
7
on_expose_event(GtkWidget *widget,
8
    GdkEventExpose *event,
9
    gpointer data)
10
{
11
  cairo_t *cr;
12
13
  cr = gdk_cairo_create (widget->window);
14
15
16
17
  cairo_scale(cr, 2.3, 1.4);
18
19
  cairo_set_source_surface(cr, image, 10, 10);
20
21
  cairo_paint(cr);
22
23
  cairo_destroy(cr);
24
25
  return FALSE;
26
}
27
28
29
int main(int argc, char *argv[])
30
{
31
  GtkWidget *window;
32
33
  image = cairo_image_surface_create_from_png("chars.png");
34
35
  gtk_init(&argc, &argv);
36
37
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
38
39
  g_signal_connect(window, "expose-event",
40
      G_CALLBACK (on_expose_event), NULL);
41
  g_signal_connect(window, "destroy",
42
      G_CALLBACK (gtk_main_quit), NULL);
43
44
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
45
  gtk_window_set_default_size(GTK_WINDOW(window), 640, 250); 
46
  gtk_widget_set_app_paintable(window, TRUE);
47
48
  gtk_widget_show_all(window);
49
50
  gtk_main();
51
52
  cairo_surface_destroy(image);
53
54
  return 0;
55
}

von xpler (Gast)


Angehängte Dateien:

Lesenswert?

So, nach weiterem Debuggen: Der Fehler liegt irgendwo zwischen 
gtk_widget_queue_draw_area() und dem event dazu. Ich habe mal den ganzen 
PNG-Krempel durch
1
cairo_rectangle(cr,x*SZ_PIC_X*zoomX,y*SZ_PIC_Y*zoomY,SZ_PIC_X*zoomX,SZ_PIC_Y*zoomY);
2
if(buffer[x][y]=='X' || buffer[x][y]=='x')
3
{
4
  cairo_move_to(cr, x*SZ_PIC_X*zoomX, y*SZ_PIC_Y*zoomY);
5
  cairo_line_to(cr, x*SZ_PIC_X*zoomX+SZ_PIC_X*zoomX, y*SZ_PIC_Y*zoomY+SZ_PIC_Y*zoomY);
6
}
7
cairo_stroke(cr);
ersetzt, ZoomX=1, ZoomY=1.01, Bild siehe Anhang. Irgendwie scheinen sich 
da die Koordinaten zu verschieben, wenn ich statt 
gtk_widget_queue_draw_area() gtk_widget_queue_draw() (ohne Area!) nehme 
passt alles.

ABER: Ich kann verstehen wenn die Helfer langsam genug haben und mir 
stinkt es auch gewaltig nicht weiterzukommen. Ich hasse es zwar wenn ich 
etwas nicht gelöst kriege und bin auch eigentlich ziemlich ausdauernd, 
aber das hier hat ja keinen Sinn mehr. Deshalb mache ich jetzt wie von 
Läubi vorgeschlagen einen fixen Font für 1024x768 oä und schalte dann 
einfach mittels WinAPI die Auflösung um, halt so wie es jedes normale 
Spiel macht. Auf die Idee hätte ich vor zig Wochen auch schon kommen 
können... Ich will grundsätzlich bei der PNG-Methode bleiben um den 
vollen DOS-Zeichensatz nutzen zu können.

Nochmals Danke für die Hilfe!

over and out...

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.