Autor Beitrag
dragonflyofgold
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mo 24.10.11 20:28 
Hi liebe Delphi-Forumnutzer,

ich programmiere immer mal wieder an einem Grafikframework für 3D herum. Dabei fällt ja auch jede Menge HLSL-Shadercode an. Normalerweise würde ich den Code in eine Datei stopfen diese ins Projekt legen und laden. Allerdings ist es ja ein Framework, welches in mehreren Projekten Anwendung findet. Daher müsste ich bei jedem Projekt die Datei mit hinein kopieren, was allein durch Aufwand und updaten der Datei doof wär.

Die Anwendungen sind in Delphi geschrieben nutzen allerdings HLSL-Shadercode der so aussieht:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
...
float4x4 World,View,Projection,WorldInverseTranspose;

struct VSInput
{
  float4 Position:POSITION0;
};
...

Den möchte ich nun im dem Grafikframework nutzen. Dazu muss er irgendwie als Datei, String oder Ressource rumliegen, damit ich ihn mithilfe von API-Methoden compilieren und der Grafikkarte geben kann.

Das Grafikframework ist ein Haufen .pas-Dateien und ich nutze sie in vielen Projekten. Damit es nicht so umständlich ist hab ich sie nicht jedem Projekt einzeln hinzugefügt, sondern in Delphi den Bibliothekspfad angepasst, dass automatisch da wo sie liegen gesucht wird. Das Problem ist nun wie ich an den Shadercode komme. Wenn ich den Code in eine Datei speichere, müsste ich sie in jedes Projekt hineinkopieren, damit das Programm sie laden kann. Das ist aber bei Änderungen an den Dateien hinderlich, da sie ja nur für dieses Projekt und nicht für alle geupdatet werden. Ich könnte sie in einen einzelnen Ordner legen und dann von den Projekten aus referenzieren, aber ich wollte nicht bei jedem Projekt alle Dateien hinzufügen müssen, sondern eher eine automatische Lösung wie mit dem Bibliothekspfad.
Bisher bin ich dem Speicherort entgangen indem ich in eine .pas-Datei eine Stringkonstante angelegt hab mit der Form:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
ZSHADERSTRING =
    'float4x4 World,View,Projection,WorldInverseTranspose;  ' + sLineBreak +
    '                                                       ' + sLineBreak +
    'struct VSInput                                         ' + sLineBreak +
    '{                                                      ' + sLineBreak +
    '  float4 Position : POSITION0;                         ' + sLineBreak +
    '};                                                     ' + sLineBreak + ...

Das ist aber auf Dauer sehr schwer zu handeln, da die Shader immer größer werden und hunderte Zeilen erzeugen. Zumal leidet durch die Prä- und Suffixe die Übersichtlichkeit. Der Vorteil war nur das ich mir über den Speicherort keine Gedanken machen musste, ich konnte einfach die pas in den Suchpfad einfügen unter uses einfügen und hatte meinen Shadercode.

Jetzt hab ich mich doch mal dazu durchgerungen, nach einer Alternative zu suchen.

Erst hab ich es mit {$I Shader.inc} probiert, aber damit kann man nur .pas-Dateien includieren. Ich dachte ich könnte in einen String eine externe Datei einfügen.

Dann hab ich mich wegen deinem Tipp mal mehr mit Resourcen-Dateien beschäftigt. Das geht schonmal recht gut. Ich hab eine .rc-Datei erstellt die die Shaderdateien referenziert. Jetzt muss ich nur diese rc-Datei dem jeweiligen Projekt hinzufügen und kann dann mit dem TResourceStream, den Inhalt der Datei in einen String lesen. Da habe ich jetzt nur noch zwei Probleme:

1. Wenn ich in einer referenzierten Shader-Datei eine Zeile ändere, aktualisiert Delphi nicht automatisch die erzeugte .res Datei. Ich muss sie erst löschen, damit es neu erzeugt wird, damit mein Programm die Änderung auch bekommt. Das ist das eigentliche Problem momentan. Kann ich Delphi irgendwie sagen, kompiliere immer die Res-Dateien neu oder schau nach Änderungen in den referenzierten Dateien?

2. Ich muss die rc-Datei dem Projekt hinzufügen, an sich kein großes Problem, sind ja nur nen paar Klicks, aber noch schöner wäre es man könnte sie mit {$R Shader.rc} irgendwo implizit einbinden. Was bisher nicht geht, da Delphi nur kompilierte Ressourcen-Dateien einbinden möchte. (Vll hat da ja jemand eine Idee)

Oder vielleicht hat ja jemand noch eine ganz andere Idee :) Gibt es zum Beispiel vielleicht ein Tag womit ich mehrzeilige Strings einleiten und beenden kann? Damit würde es ja auch super gehen. Aber ich hatte bisher nichts dazu gefunden.

Danke fürs Lesen! :D

dragonflyofgold

Moderiert von user profile iconNarses: Beiträge zusammengefasst

Ich habe gerade noch entdeckt das Delphi XE2, Pre und Postbuildereigenisse hat. Damit habe ich jetzt einfach mal nach jedem Buildvorgang die erzeugte .res-Datei gelöscht, wodurch sie immer neu erstellt werden muss. Allerdings erzeugt Delphi die .exe nur neu, wenn ich im Quellcode was ändere. Kann ich Delphi irgendwie dazu anhalten, diese immer neu zu erzeugen?
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 25.10.11 02:48 
Für solche Zwecke hat man in der Regel eine Unterscheidung in Suchpfade: Einmal einen Library-Pfad für Frameworks und einen Include-Pfad für Projektspezifische Sachen. Das hast Du sowohl bei C als auch bei Delphi. Bei Delphi wird das zwar etwas anders gehandhabt als es C tut, aber im Groben ist das durchaus Vergleichbar. Sprich wenn Du eine Datei "fs/subdiv/ultra.hlsl" brauchst, guckt er erst in allen Verzeichnissen, die im Include-Pfad stehen und wenn er keine passende Datei findet, im Library-Pfad. Somit kannst Du nicht nur gemeinsame Dateien wiederverwenden, sondern auch bestimmte Dateien im Zweifelsfall projektspezifisch austauschen.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 25.10.11 08:52 
Es gibt zwei passende Lösungen:
Zum Einen kannst du deinen Quelltext ja einfach mehrfach auschecken in die Unterverzeichnisse deiner Projekte.
Zum Anderen kannst du per NTFS Junction auf das Verzeichnis des Quelltextes verlinken.

Beide Vorgehensweisen haben den Vorteil, dass du einfach das Verzeichnis zippen kannst und stets alle Quelltexte dabei sind. Und du kannst alle Units fest dem Projekt hinzufügen, was es erstens auf einem anderen PC deutlich einfacher macht das zu kompilieren (ohne Einrichtung eben) und zweitens das Kompilieren deutlich schneller macht.
dragonflyofgold Threadstarter
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Di 25.10.11 12:21 
Danke euch beiden erstmal für die Antworten :)

@jaenicke:
Zitat:
Zum Einen kannst du deinen Quelltext ja einfach mehrfach auschecken in die Unterverzeichnisse deiner Projekte.

Das ist eine gute Idee, allerdings habe ich nicht nur ein Repository, sondern zwei und dann auch noch verschiedene (GIT und SVN). Im Git liegt das Framework und einige Projekte und im SVN andere Projekte. Ist etwas verquer und werd ich bestimmt mal umstellen, aber bisher solls erstmal so laufen. Danach könnt ich es bestimmt so machen.

Zitat:
Zum Anderen kannst du per NTFS Junction auf das Verzeichnis des Quelltextes verlinken.

Sind NTFS-Junctions nicht nur lokal? Wenn ich diese ins Repo hochlade, dürften die Verbindungen doch verloren gehen. Zumal ich glaube das Git auf Linux läuft und somit gar kein NTFS-Format hat.

@BenBE:
Ich hab jetzt nicht gefunden, wo ich einen Library-Pfad einstellen. Unter den Umgebungsoptionen von Delphi gibt es nur den Bibliothekspfad und den Suchpfad. Aber bei dieser Methode ist das Problem, dass ich den Shadercode nur vom Quelltext aus lade, d.h. ich bräuchte im Quelltext den Library-Pfad. Da die Exe, aber keine Ahnung mehr von der Delphiumgebung hat, könnte ich mir nur einen relativen Pfad zu dem Framework vorstellen. Das aber durch die Trennung der Repositories nicht geht, da auf den verschiedenen Rechnern sie sich ja irgendwo befinden können.

Ich hab jetzt eine Möglichkeit gefunden, was zwar nicht optimal, aber erstmal praktikabel ist:
Ich speichere meine HLSL-Dateien zentral dort, wo das Framework liegt. Alle werden in einer .rc-Datei referenziert. Diese füge ich allen meinen Projekten hinzu. Damit werden die Dateien in eine Ressourcen-Datei mit in die Exe gepackt und sind somit gut verfügbar und liegen auch bei Auslieferung nirgends im Weg. Damit die Ressourcen-Datei immer neu kompiliert wird, lösche ich sie mit einem PostBuild-Ereigniss immer von der Platte. Damit Delphi die Exe neu erzeugt, wenn ich in den Shaderdateien rumpfusche (da es das ja nicht mitbekommt und so die Exe nicht ändert), muss ich vor dem Ausführen, das Projekt mit Shift+F9 neu bauen.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 25.10.11 14:31 
Meine Lösung bezog sich auch eher darauf, wenn Du dein Framework so gebaut gehabt hättest, dass Du für das zentrale Framework teilweise Shader und in den spezifischen Projekten weitere Shader hast, das eigentliche Framework aber unabhängig von der EXE ausgeliefert werden kann. In dem Fall wäre eine Trennung wie beschrieben möglich.

Bibliothekspfad (Library Path) ist bei Delphi übrigens der Suchpfad für dcu-Dateien. Der Suchpfad (Include Path) ist für die PAS-Files/Quelltexte. Sowas ähnliches könntest Du auch in deinem Framework verwenden, um die Dateien zu organisieren.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 25.10.11 15:57 
user profile icondragonflyofgold hat folgendes geschrieben Zum zitierten Posting springen:
Das ist eine gute Idee, allerdings habe ich nicht nur ein Repository, sondern zwei und dann auch noch verschiedene (GIT und SVN). Im Git liegt das Framework und einige Projekte und im SVN andere Projekte. Ist etwas verquer und werd ich bestimmt mal umstellen, aber bisher solls erstmal so laufen. Danach könnt ich es bestimmt so machen.
Das ist doch egal, oder? Das Unterverzeichnis kennt das Projektrepository halt nicht, aber das muss es ja auch nicht. Es ist natürlich zusätzliche Arbeit, aber funktionieren sollte es schon.

user profile icondragonflyofgold hat folgendes geschrieben Zum zitierten Posting springen:
Sind NTFS-Junctions nicht nur lokal? Wenn ich diese ins Repo hochlade, dürften die Verbindungen doch verloren gehen. Zumal ich glaube das Git auf Linux läuft und somit gar kein NTFS-Format hat.
Genau darum ging es mir dabei:
Lokal ist alles korrekt hergerichtet (per Batchdatei, die die Links ggf. wiederherstellt), während auf dem Server usw. die Verknüpfungen nicht bekannt sind. Stattdessen werden da stets die Dateien des Projekts komplett eingecheckt.

Beispiel:
Projektverzeichnis: x:\projekte\abc
Komponentenquelltext: x:\components\def

Junction von x:\projekte\abc\components\def auf x:\components\def

Wenn du jetzt das Verzeichnis x:\projekte\abc zippst oder so, sind dort auch die Dateien des Unterverzeichnisses enthalten, so dass das so komplett weitergegeben werden kann.
vagtler
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 96
Erhaltene Danke: 24


Delphi 2010, C# (VS 2012), Objective-C, Java
BeitragVerfasst: Di 25.10.11 16:05 
user profile icondragonflyofgold hat folgendes geschrieben Zum zitierten Posting springen:
@jaenicke:
Zitat:
Zum Einen kannst du deinen Quelltext ja einfach mehrfach auschecken in die Unterverzeichnisse deiner Projekte.

Das ist eine gute Idee...

Nein, das ist alles andere als ein gute Idee. Dafür gibt es Externals in Subversion.

svnbook.red-bean.com...n.advanced.externals
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 25.10.11 16:23 
Und für SVV in Git gibts git-svn und Submoduls.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.