Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Mär 28, 2024 13:22

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Di Sep 14, 2010 15:19 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Hallo..

ich suche eine Lösung für einen Fehler mit Textsuite.

Bei mir laufen auf 2 Fenstern im selben Programm jeweils eine OpenGL-Darstellung. Dies funktioniert solange, bis ein Fenster geschlossen wird. Bei dem Fenster wird natürlich das Destroy durchlaufen. Das Fenster schließt sich und gleichzeitig kommt die Fehlermeldung von TextSuite "no active font".

Ich glaube, dass beim Beenden von dem einen Textsuite die Fonteinstellungen des anderen Fensters zerstört wird.

Meine Frage ist jetzt, ist das richtig und wie kann ich das vermeiden.

Gruss Jens


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Sep 14, 2010 15:39 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Hallo Jens.

So ganz ohne Code lässt sich das echt nur sehr schwer sagen was du da überhaupt machst. Deswegen vermute ich jetzt einfach mal ins Blaue. Du hast zwei OpenGL Fenster. Hast du auch 2 TextSuite Kontexte? Du benötigst für jeden OpenGL Kontext auch einen TextSuite Kontext. Genau wie bei OpenGL auch musst du bei der TextSuite vor dem Zeichnen erst einmal den Kontext aktivieren. Wenn du nur einen Kontext hättest müsstest du das nicht tun. Bei zweien oder mehr ist das aber nötig, da die Bibliothek nicht weiß worauf du sonst arbeiten möchtest.

Mehr kann ich anhand deiner Beschreibung gerade nicht ableiten.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Sep 14, 2010 16:04 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Code:
procedure TCad3DDraw.Init_TextSuite;
begin
  // Textsuite muss erst gelöscht werden bevor es neu aufgerufen wird!
  if IsTextsuite then
    TextSuiteDestroy
  else
    IsTextsuite := True;

  if tsInit(TS_INIT_TEXTSUITE) = TS_FALSE then
  begin
    ShowMessage('Initialing TextSuite failed.');
    Halt;
  end;
  if tsInit(TS_INIT_OPENGL) = TS_FALSE then
  begin
    ShowMessage('Initialing OpenGL failed.');
    Halt;
  end;
  if tsInit(TS_INIT_GDI) = TS_FALSE then
  begin
    ShowMessage('Initialing GDI failed.');
    Halt;
  end;

  tsContextCreate(@fContextID);
  tsSetParameteri(TS_RENDERER, TS_RENDERER_OPENGL);
  CheckError;
  tsSetParameteri(TS_CREATOR, TS_CREATOR_GDI);
  CheckError;
  //tsSetParameteri(TS_RENDERER_OPENGL_TEXTURE_SIZE, TS_RENDERER_OPENGL_TEXTURE_SIZE_1024);
  //CheckError;
  tsFontCreateCreatorA(pAnsiChar(GetFontFileName),
    70, TS_STYLE_NORMAL, TS_DEFAULT, TS_DEFAULT, @fLargeFontID);
  // shadow
  tsPostAddShadow4f(1, 0, 0, 1, 1, 1, 0);
  // white border
  tsPostAddBorder3ub(1.5, 1, $FF, $FF, $FF);
  tsPostAddShadow4ub(2, 0, 0, $FF, $FF, $FF, $80);
end;

Code:
procedure TCad3DDraw.TextSuiteDestroy;
begin
  tsFontDestroy(fLargeFontID);
  tsContextDestroy(fContextID);
  tsQuit;
end;

Also hier einmal Init und Destroy.
Bei mir tritt hinsichtlich des Kontexes ein kleines gelöstest Problem auf. Ich habe ein Docking-System. Wenn die Fenster gedockt oder entdockt werden, dann wird ein neues Handle vergeben und ich muß für OpenGL ein neuen Kontext mit DGLopenGL und mit Textsuite erstellen. Kann es daran liegen?

[Edit]
Hier der Aufruf :
Code:
procedure TCad3DDraw.DrawText(Nr: integer; T: ansistring);
...
  // activate large font
  tsFontBind(fLargeFontID);
  case Ausr of
    taLeftJustify: tsSetParameteri(TS_ALIGN, TS_ALIGN_LEFT);
    taRightJustify: tsSetParameteri(TS_ALIGN, TS_ALIGN_RIGHT);
    taCenter: tsSetParameteri(TS_ALIGN, TS_ALIGN_CENTER);
  else
    tsSetParameteri(TS_ALIGN, TS_ALIGN_CENTER);
  end;
...
  SetColor(color);
  tsTextOutA(PAnsiChar(T));
  glPopMatrix;

  // Check for Errors
  CheckError;
...
end;


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Sep 14, 2010 19:49 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Die Kontexte der TextSuite werden beim Binden in eine Threadvariable geschrieben. Diese Variable ist innerhalb des Threads überall die Selbe. Das heißt. Du erstelllst einen Kontext und erstellst ein paar Fonts etc. Erstellst dann aus einem anderem Fenster noch einen Kontext und ein paar Fonts. Alles was du jetzt aufrufst wird auf den zweiten Kontext angewendet. So lange bist du tsContextBind aufrufst und einen anderen Kontext bindest.

In deinem Fall ist es sogar so, dass neu erstellte Zeichen vernünftig aussehen sollten, da die Fonts 100%tig identische Einstellungen besitzen und einfach die Zeichen in andere Texturen mit reingeworfen werden. Was auch ein richtiges Verhalten ist.

Wenn du also ein Font löschen willst oder so etwas, dann solltest du vor dem Löschen des Fonts den Kontext aktivieren. Das erste Font auf jedem deiner Kontexte hat als ID die 1. Im Falle von TextSuiteDestroy sollte es ausreichen, wenn du einfach nur den Kontext löscht. Dann ist der Rest auch mit weg. Sogar ohne Binden, da du direkt einen Kontext ansprichst. Ich würde es der Einheitlichkeit aber dennoch empfehlen. Vor dem Zeichnen aber musst du den Kontext in jedem Fall binden. Dabei genügt es sogar im OnPaint oder ganz zu Beginn ein Mal den Kontext zu binden. So lange du sicherstellen kannst, dass zwischendurch nicht was anderes aufgerufen wird.


Wenn dein OpenGL Kontext verlohren geht werden logisch auch alle Texturen mit entsorgt. In diesem Fall müsstest du zu mindest die Zeichen der Fonts löschen. Wenn keine Zeichen mehr existieren werden die Texturen gelöscht. Und das ist das Einzige was derzeit OpenGL Abhängig ist. Alle anderen Daten sind nur rein intern TextSuite. ABER. Der einfachste Weg die Fonts zu leeren ist sie zu löschen und neu zu erstellen. Den Kontext müsstest du eigentlich nicht löschen bzw die Bibliothek auch nicht komplett neu Initialisieren. Weil dann auch alle externen Bibliotheken entsorgt und neu geladen würden. Schlimm ist das aber auch nicht. Das sollte fix gehen. Und so ist es von der Codestruktur her einfacher.
ABER auch hier ein aber. Wenn du zu erst deinen OpenGL Kontext entsorgst den neu erstellst und dann den TextSuite Kontext entsorgst, dann versucht die TextSuite eventuell erstellte Texturen zu löschen. Für den Fall, dass du in der Zwischenzeit eine Textur an diese ID geladen haben solltest ist die anschließend weg.
Perfekt wäre also vor dem sicheren Docken den TextSuite Kontext und dann den OpenGL Kontext zu löschen. Nach dem Docken OpenGL Kontext neu erstellen und TextSuite Kontext neu erstellen.

PS: Die 1024x1024 Texturgröße ist gar nicht mal wenig. Egal ob du 1 oder 20 Zeichen erstellt hast, es wird immer die volle Textur belegt. Obendrein werden die Texturen zwischen den Kontexten nicht geshared. Jeder Kontext hat seine eigene(n) Textur(en). Bei 2 Fenstern mit jeweils 2 Zeichen (die Selben oder nicht ist egal) sind mal eben garantiert 8 MB Texturspeicher weg.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Sep 14, 2010 21:29 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Danke für die ausführliche Antwort.

Ich habe schon gemerkt, dass dieser Textsuite-Fehler nur die Spitze der Eisberges ist. Bei OpenGL ist es ein grundsätzliches Problem, 2 Fenster parallel laufen zu lassen. Ich habe jetzt gemerkt, dass eigentlich nur ein Fenster richtig zur selben Zeit funktioniert.

Ich werde das jetzt mal richtig durchprobieren und mich dann noch eimal melden.
Gruss Jens


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 07:35 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Jens01 hat geschrieben:
Ich habe schon gemerkt, dass dieser Textsuite-Fehler nur die Spitze der Eisberges ist. Bei OpenGL ist es ein grundsätzliches Problem, 2 Fenster parallel laufen zu lassen. Ich habe jetzt gemerkt, dass eigentlich nur ein Fenster richtig zur selben Zeit funktioniert.

OpenGL arbeitet ähnlich wie die TextSuite. Oder anders gesagt. Bei der TextSuite habe ich mir abgeschaut was OpenGL macht. Du musst den OpenGL Kontext natürlich auch immer erst aktivieren bevor du ihn verwenden kannst. Entweder mit ActivateRenderingContext. Dann aber muss der dritte Paramater false sein. Dann werden die Funktionspointer nicht erneut geladen. Was sonst einige Zeit dauert. Nach dem Erstellen eines Kontextes muss dieser Parameter aber weg oder true sein. Denn sonst würden die nie geladen werden. Alternativ geht natürlich auch wglMakeCurrent. Was eh intern aufgerufen wird.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 13:02 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
soo..
Ich habe das jetzt alles einmal durchprobiert und es funktioniert, ich will noch nicht von gelöst sprechen.

Beide OpenGL-Darstellung auf den jeweiligen Fenstern funktionieren, nachdem ich ActivateRenderingContext vor jedem Render-Durchlauf eingefügt habe. wglMakeCurrent hat aber nicht funktioniert.
Hinsichtlich Textsuite habe ich aus meinem TextSuiteDestroy tsFontDestroy und tsContextDestroy auskommentiert und in DrawText tsContextBind und tsFontBind eingefügt.

Jetzt scheint es zu laufen. FastMM zeigt mir auch keine Speicherlöcher ... mal sehen ob s weiterhin läuft.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 13:45 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
ActivateRenderingContext ruft eigentlich auch nur wglMakeCurrent auf. Gut so lange der dritte Parameter false ist dürfte der Unterschied nur marginal sein.

TextSuiteDestroy: Das irritiert mich gerade etwas. Mehr oder weniger steht also nur noch tsQuit da drinne? Wenn ja, dann hast du zu viel auskommentiert. Ja FastMM stellt zwar keinen Speicherleck fest. Allerdings denke ich, dass da dennoch eines existiert. FastMM wertet seine Daten nur beim Beenden aus. Beim Beenden sind die Lecks dann auch alle weg nur die Kontexte können deutlich längererhalten bleiben als sie es eigentlich sollten. Und zwar bis kurz vor dem Beenden.

tsQuit zählt nur einen Counter runter. Erst wenn dieser 0 erreicht hat wird alles innerhalb der TextSuite entsorgt. Also auch alle übriggebliebenen Kontexte und dazugehörigen Fonts. Das passiert aber erst, wenn alle deine Fenster geschlossen wurden. So lange immer noch eines offen ist bleibt die TextSuite initialisiert und alle verschollenen Kontexte erhalten. Da du aber den OpenGL Kontext löscht ist der Großteil dennoch weg. Also die Textur, da die automatisch beim Kontextlöschen mit gelöscht wird. Wobei so etwas von FastMM auch nicht erfasst werden kann.

Wenn du deinen Kontext nach wie vor beim Docken wieder erstellst, dann solltest du in TextSuiteDestroy mindestens das tsContextDestroy behalten.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 14:22 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Ja, es steht nur noch tsQuit drin.
Wenn ich tsContextDestroy(fContextID) wieder im TextsuiteDestroy aktiviere, passiert Folgendes:
Beide Fenster laufen gemeinsam soweit okay. Wenn aber eins geschlossen wird, dann wird beim verbleibenden die Textur der Rechtecke nicht mehr angezeigt, sprich ich habe nur noch schwarze Rechtecke anstatt Buchstaben.

Ich habe es zwar nur kurz probiert, aber das docken ging, wenn nur noch tsQuit aktiv ist.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 14:47 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Nun. Zwei Mal tsInit(TS_TEXTSUITE) und ein Mal tsQuit aufgerufen. In dem Fall macht tsQuit rein gar nichts.

Wenn du also nach dem Aufruf von tsContextDestroy Fehler bekommst, dann behaupte ich jetzt einfach mal, dass da irgendwas mit den Kontexten durcheinander kommt. Du kannst ja auch mal spaßeshalber die Fonts mit einer zufälligen Farbe füllen (also PostAddFill(random, random, random)). Wenn die Fonts in den unterschiedlichen Fenstern dann aber doch die gleiche Farbe haben, dann arbeiten beide Fenster auf dem gleichen TextSuite Kontext.

Wichtig ist, dass du vor dem Benutzen eines Kontext diesen Bindest. Und natürlich muss du dich auch in dem richtigen OpenGL Kontext befinden. Ansonsten greift die TextSuite auf andere Texturen zu. Also Texturen in denen die Zeichen nicht erstellt wurden etc.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 15:35 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Du hast Recht! Beide Fonts der Fenster haben die selbe Farbe.
Zitat:
Wichtig ist, dass du vor dem Benutzen eines Kontext diesen Bindest. Und natürlich muss du dich auch in dem richtigen OpenGL Kontext befinden.


Wie meinst Du das konkret?
Ich mache in jedem Fenster/ Instanz das Init_Textsuite mit tsContextCreate für fContextID
und tsFontCreateCreatorA für fLargeFontID.
und binde es in DrawText :
Code:
..
  tsContextBind(fContextID);
  tsFontBind(fLargeFontID);
  tsTextOutA(PAnsiChar(T));
  glPopMatrix;

  // Check for Errors
  CheckError;
..


Ich kann doch nicht bei jedem Durchlauf noch Init_ts machen, da fängt mein Prozessor an, heiß zu laufen. Ich weiß nicht, wie ich sonst sicher stellen soll, dass ich auf dem richtigen Context bin.

Vielleicht auch noch mal zu meinem Programmkonzept. Ich habe ein übergeordnetes Fenster mit einer Dateiauswahl. Die Dateien kann man dann starten und es wird ein Fenster mit Text und einer OGL-Darstellung angezeigt. (es sind nicht -wie ich zu anfang sagte- nur 2 Fenster) Ich kann nicht so einfach zwei unterschiedliche Variablen für fContextID erstellen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 18:37 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Wegen der Farbe solltest du auch im Debugger sicher stellen, dass die beiden erstellten Kontexte auch andere Farben gesetzt bekommen.

Also gerade bin ich irgendwie etwas verwirrt. Ich sage jetzt mal, wenn du deine Anwendung startest kannst du tsInit aufrufen. Und beim Beenden, dann tsQuit. Wenn du dann auf eine Datei klickst erstellst du einen Fenster. Dieses Fenster beinhaltet einen OpenGL Kontext und einen TextSuite Kontext. Jedes Fenster brauch natürlich seine eigenen Kontext. Also 2 Variablen pro Klasse. Die Kontexte erstellst du wie normal. Und im OnPaint oder was auch immer du zum Zeichnen benutzt musst du immer erst mal ActivateRenderingContext/wglMakeCurrent und tsContextBind aufrufen. Und anschließend kannst du zeichnen wie du lustig bist. Ich denke mal zum Zeichnen benutzt du keine Threads also wird die Rendermethode auch nicht von einem anderen Fenster unterbrochen. Und das war es eigentlich schon was du beim Zeichnen tun musst. Jedes Form benötigt natürlich seine eigene Kontext Variablen und diese musst du auch binden.

Beim Docken ist es halt nur Wichtig die Kontexte zu löschen und dann neu zu erstellen. Denn das Handle des Fensters hat sich geändert. Idealerweise natürlich zu erst den TextSuite Kontext entfernen, dann opengl und andersrum wieder erstellen. Also erst OpenGL und dann TextSuite


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mi Sep 15, 2010 20:35 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Okay, ich werde jetzt einen Tag Abstand zwischen mir und OpenGL bringen und mein Programm dann dahingehend ein wenig testen und umbauen. Ich glaube es sollte dann laufen.
Danke nochmals und vielleicht melde ich mich ja deswegen abermals
Gruss Jens


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Dez 30, 2010 17:07 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
Hallo Lossy,

zu dem Thema wollte ich mich noch einmal melden. Es hat etwas länger gedauert, aber dazu hatte ich bis jetzt keine Zeit. Ich glaube, dass ich das Problem erkannt habe.
Den Rendercontext mit wglMakeCurrent(DC, RC) und auch den Textsuitecontext mit fContextID), tsFontBind(fLargeFontID) hatte ich vor jedem Renderdurchlauf gesetzt. Und doch gab er mir oft bei Textsuite Fehler aus.
Bei mir ist es so, dass in meinem Programm das RenderPanel auf einem gedocktem Fenster läuft. Es konnte also sein, dass das RenderPanel geschlossen und damit Deaktiviert wurde, ohne vorher eingebunden worden zu sein. Es galt dann anscheinend noch der Kontext vom vorher gerenderten Panel. Ich habe also in der OpenGLDestroy-Procedure noch den Kontext mit wglMakeCurrent eingebunden, dasselbe habe ich mit dem TextSuite-Destroy auch gemacht. Es scheint so, als ob es keine Fehler mehr gibt und auch keine zerstörten Fonts. .. naja mal sehen.

Ich wünsche allen einen Guten Rutsch ins Neue Jahr
Jens
Code:
procedure OpenGLDestroy;
begin
  wglMakeCurrent(DC, RC); <----------

  DeactivateRenderingContext;
  DestroyRenderingContext(RC);
  ReleaseDC(Panel.Handle, DC);
  IsContex := False;
end;


Code:
procedure TextSuiteDestroy;
begin
  tsContextBind(fContextID); <----------
  tsFontBind(fLargeFontID); <----------

  tsFontDestroy(fLargeFontID);
  tsContextDestroy(fContextID);
  tsQuit;
end;


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 29 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.088s | 17 Queries | GZIP : On ]