<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0">
	<channel>
		<title>BlitzBasic Portal Worklogs - Gesammelte Synapsenkurzschlüsse</title>
		<link>https://www.blitzforum.de/worklogs/304/</link>
		<description>Worklog von Chaos Interactive</description>
		<language>de</language>
		<managingEditor>mail@blitzforum.de</managingEditor>
		<webMaster>mail@blitzforum.de</webMaster>
		<pubDate>Sat, 13 Aug 2011 23:37:11 +0200</pubDate>
		<lastBuildDate>Sat, 13 Aug 2011 23:37:11 +0200</lastBuildDate>

		<item>
			<title>2D Global Illumination</title>
			<link>https://www.blitzforum.de/worklogs/304/#3341</link>
			<guid>https://www.blitzforum.de/worklogs/304/#3341</guid>
			<author>Noobody</author>
			<description>Da ich f&amp;uuml;r ein aktuelles Sidescrolling-Projekt eine L&amp;ouml;sung f&amp;uuml;r Lightmaps in 2D-Levels suchte, experimentierte ich w&amp;auml;hrend der letzten Tage mit &lt;a href=&quot;http://en.wikipedia.org/wiki/Global_illumination&quot; target=&quot;_blank&quot;&gt;globaler Beleuchtung&lt;/a&gt; in 2D. Prinzipiell geht es darum, weiche Schatten und diffuse Beleuchtung zu berechnen, um das ganze ein wenig besser aussehen zu lassen.&lt;br /&gt;&lt;br /&gt;Der Ansatz, den ich verwendete (namentlich Light Tracing) ist sehr simpel: Man sende Strahlen von einer Lichtquelle in zuf&amp;auml;llige Richtungen, lasse sie an Schnittpunkten mit dem Level in zuf&amp;auml;llige Richtungen weiterstreuen und, wenn der Strahl terminiert, markiere seine Strahlung auf der Lightmap. Lustigerweise ist das ausw&amp;auml;hlen einer geeigneten zuf&amp;auml;lligen Richtung schwieriger als es klingt - je nach Oberfl&amp;auml;che und Lichtquelle kommen ganz andere Wahrscheinlichkeitsverteilungen zum Einsatz, damit das Endresultat nicht verf&amp;auml;lscht wird. Schlussendlich musste ich eine Art 3D-in-2D-Repr&amp;auml;sentation zuhilfe nehmen, damit das Ganze funktioniert. Das macht zwar das generieren der Strahlen um einiges chaotischer, aber es scheint immerhin zu funktionieren &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt; &lt;br /&gt;&lt;br /&gt;Das andere Problem war, effizient Schnittpunktberechnungen auszuf&amp;uuml;hren. Da ich keine Einschr&amp;auml;nkungen auf die Form der Levels setzen wollte (z.B. nur gerade Linien sind erlaubt), verwendete ich einen Sparse Voxel Quadtree, der es erlaubt, mit beliebigen Pixellandschaften effizient Schnittpunkte zu finden. Lustigerweise ist er in der Testszene sogar um einiges schneller als die naive Implementation mit Linien-Linien-Schnittpunktberechnungen, obwohl der Code mit dem Quadtree um einiges komplexer ist.&lt;br /&gt;&lt;br /&gt;Wie dem auch sei, hier ein Screenshot des Endresultats:&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://noobody.org/Data/GlobalIllum-4.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;YT-Video:&lt;br /&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=CPBdiV0JvRo&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://noobody.org/Data/GlobalIllum-YT.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Jetzt auch in HD!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Das Endresultat ist, obwohl relativ langsam, nicht ganz so schlecht herauskommen und wird vielleicht die eine oder andere Anwendung finden. Leider ist sie aber eher f&amp;uuml;r Top-Down und Indoor-Spiele geeignet als f&amp;uuml;r meinen Anwendungszweck, daher werde ich wohl etwas anderes suchen m&amp;uuml;ssen.&lt;br /&gt;&lt;br /&gt;Wer sich das ganze mal anschauen m&amp;ouml;chte, hier BMax Code und Exe f&amp;uuml;r Windows: &lt;a href=&quot;http://noobody.org/Data/2D-Global-Illumination.zip&quot; target=&quot;_blank&quot;&gt;Download&lt;/a&gt;</description>
			<pubDate>Sat, 13 Aug 2011 23:37:11 +0200</pubDate>
		</item>

		<item>
			<title>Von Intros und Mandelkugeln</title>
			<link>https://www.blitzforum.de/worklogs/304/#2917</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2917</guid>
			<author>Noobody</author>
			<description>Aus Interesse setzte ich mich gestern mal dran, eine Implementation von &lt;a href=&quot;http://en.wikipedia.org/wiki/Mandelbulb&quot; target=&quot;_blank&quot;&gt;Mandelbulbs&lt;/a&gt; zu schreiben. Eine erste Version, die das Fraktal zuerst in eine Volumentextur renderte und dann als Voxel geraytraced hatte, lief zwar relativ schnell, hatte aber eine relativ entt&amp;auml;uschende Qualit&amp;auml;t:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/Mandelbulb.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Eine zweite Version, bei der das Fraktal direkt in einem Shader geraymarched wird, sieht dann schon um einiges besser aus (Bilder anklicken f&amp;uuml;r gr&amp;ouml;ssere Version):&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.noobody.org/BBP/MandelbulbShader.png&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/MandelbulbShader_Thumb.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://www.noobody.org/BBP/MandelbulbShader_2.png&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/MandelbulbShader_Thumb_2.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Dank Orbit Traps kann sogar ein gefaktes Ambient Occlusion berechnet werden, was nochmal einiges an Rechenzeit spart. Im Bild werden im Moment n&amp;auml;mlich Beleuchtung und Schatten komplett ausgelassen, trotzdem aber sind alle Details erkennbar.&lt;br /&gt;&lt;br /&gt;Ich habe im Moment noch ein wenig Probleme mit Bildrauschen, aber sobald ich das behoben habe, steht einer kleinen Demo nichts mehr im wege (obwohl man daf&amp;uuml;r wohl eine relativ starke Grafikkarte ben&amp;ouml;tigt).&lt;br /&gt;&lt;br /&gt;Ausserdem experimentiere ich grade ein wenig mit &lt;a href=&quot;http://en.wikipedia.org/wiki/Demo_(computer_programming)&quot; target=&quot;_blank&quot;&gt;4k Intros&lt;/a&gt;, bei denen es darum geht, grafische Effekte mit Musik in einer 4kb grossen Exe unterzubringen. Das ist zwar einiges schwieriger, als ich anfangs dachte, aber auch sehr spannend, daher werde ich mal versuchen, einige meiner &amp;auml;lteren Programme in 4k unterzubringen.</description>
			<pubDate>Mon, 20 Sep 2010 06:56:27 +0200</pubDate>
		</item>

		<item>
			<title>Funktionsüberladung *britzel*</title>
			<link>https://www.blitzforum.de/worklogs/304/#2728</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2728</guid>
			<author>Noobody</author>
			<description>Nach ein wenig Umstrukturierung funktioniert nun auch die erste Version der Funktions&amp;uuml;berladung. Da der bestehende Ausdrucksparser ja sowieso schon den Datentyp eines Ausdrucks bestimmen muss, um Typen&amp;uuml;berpr&amp;uuml;fung machen zu k&amp;ouml;nnen, erwies sich das Schreiben das Algorithmus' zur Bestimmung der richtigen Variante der &amp;uuml;berladenen Funktion als relativ leicht.&lt;br /&gt;&lt;br /&gt;Folgendes Beispiel [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method Bar( A:Float )&lt;br /&gt;		Print &amp;quot;Float!&amp;quot;&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:Int )&lt;br /&gt;		Print &amp;quot;Int!&amp;quot;&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:String )&lt;br /&gt;		Print &amp;quot;String!&amp;quot;&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar( 0.5 )&lt;br /&gt;Foo.Bar( 1 )&lt;br /&gt;Foo.Bar( &amp;quot;Hello world!&amp;quot; )[/syntax]&lt;br /&gt;Wie man sieht, w&amp;auml;hlt der Precompiler automatisch die richtige &amp;uuml;berladene Variante, wenn die Parametertypen exakt &amp;uuml;bereinstimmen.&lt;br /&gt;&lt;br /&gt;Was aber, wenn die Typen nicht exakt &amp;uuml;bereinstimmen? [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method Bar( A:Float, B:String )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:TFoo, B:String )&lt;br /&gt;	EndMethod&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar( 23.0!, 42 ) 'Double l&amp;auml;sst sich unter anderem nach Float casten, Int unter anderem nach String&lt;br /&gt;                     'Double l&amp;auml;sst sich nicht nach TFoo casten&lt;br /&gt;                     '--&amp;gt; Erste Methode wird aufgerufen[/syntax]&lt;br /&gt;Wichtig ist aber, dass Funktionen, die genau zutreffen, Vorrang haben vor Funktionen, die &amp;uuml;ber Casting zutreffen w&amp;uuml;rden [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method Bar( A:Float, B:Int = 3 )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:Float )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:Int )&lt;br /&gt;	EndMethod&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar( 0.5 )  'Alle drei Methoden w&amp;uuml;rden zutreffen. Da aber Bar( float ) genau der Signatur der zweiten Methode entspricht, wird diese aufgerufen&lt;br /&gt;Foo.Bar( 1 )    'Wieder dasselbe, nur wird diesmal die dritte ausgew&amp;auml;hlt&lt;br /&gt;&lt;br /&gt;Foo.Bar( 0.5! ) 'Fehler! Keine Methode passt genau auf Bar( double ). Durch casting bzw. weglassen von optionalen Parametern treffen aber alle zu&lt;br /&gt;                '---&amp;gt; Fehlermeldung &amp;quot;Overloaded function 'Bar' is ambiguous (in line 17)&amp;quot;[/syntax]&lt;br /&gt;&lt;br /&gt;Interessantes Verhalten l&amp;auml;sst sich ausserdem feststellen, wenn man Funktionen &lt;i&gt;und&lt;/i&gt; Methoden &amp;uuml;berl&amp;auml;dt [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	'Auch wenn hier je eine Methode und eine Funktion vorliegen, d&amp;uuml;rfen sie nicht die exakt gleiche Signatur haben&lt;br /&gt;	Method Bar( A:Int, B:Int = 3 )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Function Bar( A:Int )&lt;br /&gt;	EndFunction&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar( 1 )    'Statische Funktion wird aufgerufen&lt;br /&gt;Foo.Bar( 1, 1 ) 'Methode wird aufgerufen&lt;br /&gt;TFoo.Bar( 1 )   'Statische Funktion wird aufgerufen&lt;br /&gt;&lt;br /&gt;TFoo.Bar( 0.5 ) 'Es treffen zwar beide Funktionssignaturen durch einen Cast zu, da aber von aussen nur die statische Funktion sichtbar ist, wird diese aufgerufen&lt;br /&gt;&lt;br /&gt;Foo.Bar( 0.5 )  'Fehler! Keine der beiden Funktionssignaturen trifft exakt zu, allerdings w&amp;uuml;rden beide durch einen Cast von 0.5 wieder passen. Da hier nun sowohl die statische Funktion als auch die Methode sichtbar sind, beschwert sich der Precompiler[/syntax]&lt;br /&gt;Verwirrend? Das ist es in der Tat. Aber aus Gr&amp;uuml;nden der Sauberkeit sollte man sowas auch vermeiden.&lt;br /&gt;&lt;br /&gt;Ein letztes Beispiel habe ich noch, das mit abgeleiteten Types funktioniert. Hier lassen sich wieder dieselben Verhaltensregeln beobachten [syntax=&amp;quot;bmax&amp;quot;]Type TA&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TB Extends TA&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TC Extends TB&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Type TFoo&lt;br /&gt;	Method Bar:Int( A:TA )&lt;br /&gt;	End Method&lt;br /&gt;	&lt;br /&gt;	Method Bar:Int( B:TB )&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar( New TA ) 'Die erste Methode trifft als einzige zu&lt;br /&gt;Foo.Bar( New TB ) 'Die zweite Methode trifft exakt zu. Da sich TB auch nach TA casten l&amp;auml;sst, w&amp;uuml;rde die erste Methode auch &amp;uuml;ber einen Cast erreichbar sein, aber wie immer haben exakte Treffer Vorrang vor Cast-Treffern&lt;br /&gt;&lt;br /&gt;Foo.Bar( New TC ) 'Fehler! Keine Methode trifft exakt zu, aber TC l&amp;auml;sst sich sowohl nach TA als auch nach TB casten, sprich, &amp;uuml;ber einen impliziten Cast treffen beide zu.[/syntax]&lt;br /&gt;&lt;br /&gt;Das &amp;Uuml;bersetzen ist dann weniger spektakul&amp;auml;r. Funktionsnamen werden umgewandelt, indem an den Namen noch die Parametertypen in Kurzform angeh&amp;auml;ngt werden. Der Aufruf wird auch umgewandelt, wobei das Programm per Backtracking bestimmt, von wo der Funktionszeiger herkommt. So k&amp;ouml;nnte man auch den Funktionsnamen ausklammern und so Zeug, wie folgendes Beispiel unter anderem auch zeigt [syntax=&amp;quot;bmax&amp;quot;]SuperStrict&lt;br /&gt;&lt;br /&gt;Type TA&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TB Extends TA&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TC Extends TB&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Type TFoo&lt;br /&gt;	Method Bar( A:Float )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:Int )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:String )&lt;br /&gt;	End Method&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:Float, B:String )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar( A:Int, B:Int = 3 )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar:Int( A:TA )&lt;br /&gt;	End Method&lt;br /&gt;	&lt;br /&gt;	Method Bar:Int( B:TB )&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar( 0.5 )&lt;br /&gt;Foo.Bar( 0.5, &amp;quot;Trololololo&amp;quot; )&lt;br /&gt;Foo.Bar( New TA )&lt;br /&gt;Foo.Bar( New TB )&lt;br /&gt;&lt;br /&gt;( Foo.Bar )( 42, &amp;quot;Das sowas &amp;uuml;berhaupt geht!&amp;quot; ) 'Foo.Bar liefert den (&amp;uuml;berladenen) Funktionszeiger zur&amp;uuml;ck, welcher durch die anschliessenden Klammern aufgerufen wird. Trotzdem kann der Precompiler den Ursprung des Zeigers bestimmen und den entsprechenden Bezeichner umbenennen.[/syntax]&lt;br /&gt;Das wird dann &amp;uuml;bersetzt in den folgenden Code [syntax=&amp;quot;bmax&amp;quot;]SuperStrict&lt;br /&gt;&lt;br /&gt;Type TA&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Type TB Extends TA&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Type TC Extends TB&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Type TFoo&lt;br /&gt;	Method Bar_f( A:Float )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar_i( A:Int )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar_s( A:String )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar_f_s( A:Float, B:String )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar_i_i( A:Int, B:Int = 3 )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar_ta:Int( A:TA )&lt;br /&gt;	EndMethod&lt;br /&gt;	&lt;br /&gt;	Method Bar_tb:Int( B:TB )&lt;br /&gt;	End EndMethod&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Foo.Bar_f( 0.5 )&lt;br /&gt;Foo.Bar_f_s( 0.5, &amp;quot;Trololololo&amp;quot; )&lt;br /&gt;Foo.Bar_ta( New TA )&lt;br /&gt;Foo.Bar_tb( New TB )&lt;br /&gt;&lt;br /&gt;( Foo.Bar_f_s )( 42, &amp;quot;Das sowas &amp;uuml;berhaupt geht!&amp;quot; ) 'Foo.Bar liefert den (&amp;uuml;berladenen) Funktionszeiger zur&amp;uuml;ck, welcher durch die anschliessenden Klammern aufgerufen wird. Trotzdem kann der Precompiler den Ursprung des Zeigers bestimmen und den entsprechenden Bezeichner umbenennen.[/syntax]&lt;br /&gt;Man beachte, dass der R&amp;uuml;ckgabetyp &lt;i&gt;nicht&lt;/i&gt; im Funktionsnamen steckt und daher Funktionen mit gleichen Parametertypen, aber unterschiedlichen R&amp;uuml;ckgabetypen nicht erlaubt sind. Zu bestimmen, welcher R&amp;uuml;ckgabetyp erwartet wird, ist relativ schwierig umzusetzen.&lt;br /&gt;&lt;br /&gt;Bis anhin kann man nur Funktionen und Methoden in Types &amp;uuml;berladen, dass muss ich noch mit einem kleinen Fix auch f&amp;uuml;r normale Funktionen erlauben. Ausserdem funktioniert die &amp;Uuml;berladung noch nicht, wenn ein abgeleiteter Type die Methoden seiner Basisklasse &amp;uuml;berl&amp;auml;dt - da muss noch was getan werden.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ein neues Feature ist mir eingefallen, das ich wohl auch implementieren werde - Properties. Im Prinzip geht es darum, dass man f&amp;uuml;r irgendein Field (z.B. Bar) die passenden Getter und Setter schreibt (hier also getBar und setBar) und ein Keyword namens 'property' oder so &amp;auml;hnlich setzt. Sp&amp;auml;ter kann diese Property wie ein normales Feld benutzt werden; Zuweisungen erfolgen also normal mit z.B. 'Foo.Bar = 5' und Lesezugriffe auch wie gehabt mit z.B. 'Print Foo.Bar'. Beim &amp;uuml;bersetzen aber werden Zuweisungen und Lesezugriffe durch Aufrufe der entsprechenden Setter und Getter ersetzt. Der Vorteil? Ich zitiere aus Wikipedia Zitat:&lt;div class=&quot;quotebox&quot;&gt;The field-like syntax is said to be easier to read and write than lots of method calls, yet the interposition of method calls allows for data validation, active updating (as of GUI visuals), and/or read-only 'fields'.&lt;/div&gt;&lt;br /&gt;Nachdem die Funktions&amp;uuml;berladung abgeschlossen ist, werde ich mich aber wohl eher wieder den Zeigern, expliziten Casts etc. zuwenden, damit ich &amp;uuml;berhaupt beliebigen BMax-Code vollst&amp;auml;ndig durchparsen kann.</description>
			<pubDate>Tue, 20 Jul 2010 18:21:03 +0200</pubDate>
		</item>

		<item>
			<title>Konstruktoren und Private/Public abgeschlossen</title>
			<link>https://www.blitzforum.de/worklogs/304/#2719</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2719</guid>
			<author>Noobody</author>
			<description>Die Fehler, die wie im letzten Eintrag angesprochen noch &amp;uuml;berpr&amp;uuml;ft werden mussten, sind nun auch fertig implementiert. Wer also eines der folgenden Konstrukte in seinem Code verwendet, bekommt an den mit 'Fehler!' kommentierten Stellen eine Meldung um die Ohren geschmissen [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method New()&lt;br /&gt;	End Method&lt;br /&gt;	&lt;br /&gt;	Method New( A:Int, B:Int = 3, C:Int ) 'Fehler!&lt;br /&gt;	EndMethod&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Type TBar&lt;br /&gt;	Method Constructor( A:Int, B:Int ) 'Fehler&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TFubar&lt;br /&gt;	Method New( A:Int, B:Int, C:Int )&lt;br /&gt;		Return A + B + C 'Fehler!&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TZar&lt;br /&gt;	Method New( A:Int, B:Int, C:Int )&lt;br /&gt;		If A = 4 Then Return 'Erlaubt&lt;br /&gt;		&lt;br /&gt;		Print A + B + C&lt;br /&gt;	End Method&lt;br /&gt;End Type[/syntax]&lt;br /&gt;Wie man aus dem obigen Code vielleicht erkennen kann, ist Return ohne angegebenen Wert erlaubt (und wird dann einfach in 'Return Self' &amp;uuml;bersetzt). Schliesslich sollte man ja auch aus einem Konstruktor fr&amp;uuml;hzeitig mit Return zur&amp;uuml;ckkehren k&amp;ouml;nnen, falls es n&amp;ouml;tig ist.&lt;br /&gt;&lt;br /&gt;Desweiteren baute ich heute morgen noch schnell die Private/Public-Sache vollst&amp;auml;ndig ein. Diese verhalten sich genau wie in anderen Sprachen [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;Private&lt;br /&gt;	Field A:Int, B:Int&lt;br /&gt;	Field C:String = &amp;quot;Hello, World!&amp;quot;&lt;br /&gt;	&lt;br /&gt;	Method printC()&lt;br /&gt;		Print C&lt;br /&gt;	End Method&lt;br /&gt;	&lt;br /&gt;Public&lt;br /&gt;	Field D:Int = 42&lt;br /&gt;	&lt;br /&gt;	Method getC:Int()&lt;br /&gt;		Return C&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Print Foo.getC()&lt;br /&gt;Print Foo.D&lt;br /&gt;&lt;br /&gt;Foo.printC() 'Fehler!&lt;br /&gt;&lt;br /&gt;Print Foo.A 'Fehler!&lt;br /&gt;Print Foo.B 'Fehler![/syntax]&lt;br /&gt;In einem Type darf es selbstverst&amp;auml;ndlich mehrere Private/Public-Sektionen geben, wobei Konstruktoren nur im Public-Teil stehen d&amp;uuml;rfen. Types beginnen standardm&amp;auml;ssig Public.&lt;br /&gt;&lt;br /&gt;Die &amp;Uuml;bersetzung in 'normalen' BMax-Code erfolgt nach Codekonvention, sprich ein Unterstrich vor privaten Variablen/Methoden/Funktionen. Obiger, &amp;uuml;bersetzter Code (ohne die fehlerhaften Teile, nat&amp;uuml;rlich) [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;&lt;br /&gt;	Field _A:Int, _B:Int&lt;br /&gt;	Field _C:String = &amp;quot;Hello, World!&amp;quot;&lt;br /&gt;	&lt;br /&gt;	Method _printC()&lt;br /&gt;		Print _C&lt;br /&gt;	End Method&lt;br /&gt;	&lt;br /&gt;&lt;br /&gt;	Field D:Int = 42&lt;br /&gt;	&lt;br /&gt;	Method getC:Int()&lt;br /&gt;		Return _C&lt;br /&gt;	End Method&lt;br /&gt;End EndType&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo&lt;br /&gt;&lt;br /&gt;Print Foo.getC()&lt;br /&gt;Print Foo.D[/syntax]&lt;br /&gt;Wie man sieht, werden die entsprechenden Token von Private/Public beim ausgeben einfach ignoriert. Das resultiert in einer vielleicht ein wenig un&amp;auml;sthetischen Leerzeile, aber damit wird man wohl leben m&amp;uuml;ssen.&lt;br /&gt;&lt;br /&gt;N&amp;auml;chster Stop: Funktions&amp;uuml;berladung!</description>
			<pubDate>Sun, 18 Jul 2010 12:38:59 +0200</pubDate>
		</item>

		<item>
			<title>Erste Ergebnisse</title>
			<link>https://www.blitzforum.de/worklogs/304/#2688</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2688</guid>
			<author>Noobody</author>
			<description>Da ich ja seit nun zwei Wochen im Praktikum stecke und mir nach 8 Stunden Programmierung abends der Sinn nicht mehr besonders nach noch mehr Geschreibe steht, kam der Precompiler auch nur langsam voran. Zeiger zu implementieren war mir dann auch ein wenig &amp;ouml;de, also bin ich auf der Todo-Liste schnurstracks zu den Konstruktoren gesprungen.&lt;br /&gt;&lt;br /&gt;Syntax: [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method New( A:Int, B:Int = 4, C:Int ) 'Optionale Parameter gehen nat&amp;uuml;rlich&lt;br /&gt;		Print A + C + D&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo1:TFoo = New TFoo( 3, 4, 9 )&lt;br /&gt;Local Foo2:TFoo = New TFoo( 3,,   9 ) 'Parameter auslassen funktioniert genau wie bei normalen Methoden&lt;br /&gt;&lt;br /&gt;Type TBar&lt;br /&gt;	Method New()&lt;br /&gt;		Print &amp;quot;Wenigstens noch ein leerer Konstruktor&amp;quot;&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Bar1:TBar = New TBar()&lt;br /&gt;Local Bar2:TBar = New TBar   'Da der Konstruktor keine Parameter verlangt, ist auch das hier erlaubt&lt;br /&gt;&lt;br /&gt;Type TFubar&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Fubar1:TFubar = New TFubar&lt;br /&gt;Local Fubar2:TFubar = New TFubar() 'Klammern werden auch akzeptiert, wenn im Type kein New definiert wurde[/syntax]&lt;br /&gt;Der Precompiler wandelt dann nach festgesetzten Regeln um. Das obere Beispiel wird dann in folgenden Code umgewandelt (die Kommentare habe ich nachher von Hand durch andere ersetzt - normalerweise w&amp;uuml;rden die obigen Kommentare nat&amp;uuml;rlich auch erhalten werden): [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	'New mit Parameter wird in 'Constructor' mit entsprechendem Datentyp und 'Return Self' am Ende umgewandelt&lt;br /&gt;	Method Constructor:TFoo( A:Int, B:Int = 4, C:Int )&lt;br /&gt;		Print A + C + D&lt;br /&gt;		Return Self&lt;br /&gt;	EndMethod&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Local Foo1:TFoo = New TFoo.Constructor( 3, 4, 9 ) 'Konstruktorenaufrufe werden auch passend umgewandelt&lt;br /&gt;Local Foo2:TFoo = New TFoo.Constructor( 3,,   9 )&lt;br /&gt;&lt;br /&gt;Type TBar&lt;br /&gt;	Method New() 'Um die Lesbarkeit zu erh&amp;ouml;hen, werden Konstruktoren ohne Parameter bei 'New' belassen&lt;br /&gt;		Print &amp;quot;Wenigstens noch ein leerer Konstruktor&amp;quot;&lt;br /&gt;	EndMethod&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Local Bar1:TBar = New TBar 'Klammern bei Konstruktoren ohne Parameter werden verworfen&lt;br /&gt;Local Bar2:TBar = New TBar&lt;br /&gt;&lt;br /&gt;Type TFubar&lt;br /&gt;EndType&lt;br /&gt;&lt;br /&gt;Local Fubar1:TFubar = New TFubar&lt;br /&gt;Local Fubar2:TFubar = New TFubar 'Selbes wie bei TBar[/syntax]&lt;br /&gt;&lt;br /&gt;Hier noch ein kleiner Beispielcode von Fehlern, die nun als solche erkannt werden [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method New:Int() 'Fehler!&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TBar&lt;br /&gt;	Method New( A:Int, B:Int, C:Int )&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;New TBar   'Fehler!&lt;br /&gt;New TBar() 'Fehler!&lt;br /&gt;New TBar( 1, 2 ) 'Fehler!&lt;br /&gt;'etc. etc.[/syntax]&lt;br /&gt;Dass man die Methode Constructor nicht selber definieren sollte und in New auch kein Return verwenden darf, sollte klar sein. Als Fehler erkannt wird das noch nicht, wird aber bald eingebaut.&lt;br /&gt;&lt;br /&gt;Soviel zu dem.&lt;br /&gt;&lt;br /&gt;Heutiger Ohrgasmus: &lt;a href=&quot;http://www.youtube.com/watch?v=nSJ4WintrrY&quot; target=&quot;_blank&quot;&gt;Justice&lt;/a&gt;</description>
			<pubDate>Wed, 14 Jul 2010 22:05:06 +0200</pubDate>
		</item>

		<item>
			<title>Der BMax Precompiler</title>
			<link>https://www.blitzforum.de/worklogs/304/#2618</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2618</guid>
			<author>Noobody</author>
			<description>W&amp;auml;hrend des letzten Monats habe ich an einem neuen Projekt geschraubt, welches mir schon lange im Kopf herumschwirrte: Ein BMax Precompiler.&lt;br /&gt;&lt;br /&gt;In diesem und im englischen Forum wurden schon lange W&amp;uuml;nsche ge&amp;auml;ussert, dass BMax doch ein paar Zusatzfeatures bek&amp;auml;me. Vor allem geht es dabei um echte Konstruktoren, Funktions&amp;uuml;berladung, echtes Private/Public und Operatoren&amp;uuml;berladung.&lt;br /&gt;&lt;br /&gt;Da Mark aber scheinbar ziemlich viel anderes im Kopf hat (zuerst Max3D, jetzt BMX 2), wird man wohl noch lange auf diese Features warten m&amp;uuml;ssen. Daher hatte ich mir zum Ziel gesetzt, einen Precompiler zu schreiben, der sich nahtlos zwischen BMK und BCC einf&amp;uuml;gt und 'erweiterten' BMax-Code umwandelt in 'echten' BMax-Code, der nachher vom BCC kompiliert wird.&lt;br /&gt;&lt;br /&gt;Der Hauptgedanke hinter dem Precompiler ist, dass er trotz Umwandlung einen lesbaren Code produziert, damit Debugging immer noch m&amp;ouml;glich ist und man den Vorkompilierten Code auch an andere weitergeben kann, die den Precompiler nicht besitzen. Zu diesem Zweck erh&amp;auml;lt der Precompiler die Originalformatierung zu 100% - sprich, Tabs, Leerschl&amp;auml;ge, Gross/Kleinschreibung etc. werden alle erhalten. Features, die das Originale BMax nicht beherrscht, werden so lesbar wie m&amp;ouml;glich umgewandelt.&lt;br /&gt;&lt;br /&gt;Was besonders wichtig ist, dass der Precompiler alle Syntax-Fehler, die im Code stecken k&amp;ouml;nnten, abf&amp;auml;ngt. Falls er Syntax-Fehler ignoriert und sie einfach an den BCC weiterreicht oder aufgrund inkorrekten Codes abst&amp;uuml;rzt, wird es f&amp;uuml;r den User relativ umst&amp;auml;ndlich, die entsprechenden Fehler zu finden. Das ist nat&amp;uuml;rlich eine nicht ganz leichte Aufgabe, aber im Moment kommt es recht gut voran.&lt;br /&gt;&lt;br /&gt;Wie ist denn der aktuelle Stand?&lt;br /&gt;Nun, im Moment ist das Grundger&amp;uuml;st fertig und ziemlich stabil. Die funktionierenden Teile arbeiten wie folgt:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1. Quelltext einlesen und in einen abstrakten Parsetree umwandeln. Die entfernten Whitespaces werden f&amp;uuml;r den sp&amp;auml;teren Gebrauch zwischengespeichert.&lt;br /&gt;&lt;li&gt;2. Erster Durchlauf durch den Quelltext: Frameworks, Imports und den Strict-Mode herausparsen. Von allen Types ihre Namen zwischenspeichern.&lt;br /&gt;&lt;li&gt;3. Aus allen importierten Modulen die Interface-Dateien heraussuchen und parsen: Alle Funktionen, Types, Methoden, Globale, Konstanten etc. herausparsen und zwischenspeichern.&lt;br /&gt;&lt;li&gt;4. Zweiter Durchlauf durch den Quelltext: Alle globalen Funktionen und alle Funktionen, Globalen, Fields, Konstanten und Methoden in Types herausparsen und zwischenspeichern.&lt;br /&gt;&lt;li&gt;5. Dritter und letzter Durchlauf durch den Quelltext: Den ganzen Code ablaufen und die einzelnen Anweisungen auf Korrektheit &amp;uuml;berpr&amp;uuml;fen.&lt;br /&gt;&lt;li&gt;6. Den abstrakten Parsetree mithilfe der gespeicherten Whitespaces wieder in den urspr&amp;uuml;nglichen Code umwandeln und ausgeben&lt;/ul&gt;&lt;br /&gt;Wie man feststellt, ist das ein Multi-Passcompiler mit drei Durchl&amp;auml;ufen. Ab dem ersten Durchlauf sind alle Datentypen, die vorkommen k&amp;ouml;nnen, bekannt (sprich, primitive Datentypen wie Int, Float etc. und die definierten Types). Ab dem zweiten Durchlauf sind alle Funktionen bekannt sowie alle Member der Types, auf die zugegriffen werden kann. Im schwierigsten und wichtigste Durchlauf, Nummer 3, wird dann erst der tats&amp;auml;chliche Code analysiert und auf Korrektheit gepr&amp;uuml;ft. Die einzelnen Codest&amp;uuml;cke werden dort in drei Kategorien eingeteilt:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Kontrollstruktur: If, For, While, Select, Repeat etc. Er&amp;ouml;ffnet je nach Strictmodus einen neuen Scope&lt;br /&gt;&lt;li&gt;Deklaration: Mit oder ohne Local, je nach Strictmodus. F&amp;uuml;gt die neue Variable zum aktuellen Scope hinzu&lt;br /&gt;&lt;li&gt;Statement: Funktionsaufruf mit oder ohne Klammern, Zuweisung&lt;/ul&gt;&lt;br /&gt;All das funktioniert schon alles fast vollst&amp;auml;ndig. Kontrollstrukturen sind in allen Variationen komplett eingebaut (naja, bis auf EachIn), Deklarationen sind fertig und Statements bis auf einige Ausnahmen ebenfalls.&lt;br /&gt;&lt;br /&gt;Was noch nicht implementiert ist, sind Zeiger (Sowohl Byte/Float/usw. Ptr als auch Funktionszeiger), Konstanten (Pi, Null), Typecasts und ziemlich viele Keywords wie etwa Incbin, Release, GoTo, Data etc. Als Hauptpriorit&amp;auml;t habe ich mir gesetzt, Zeiger, Typecasts und die fehlenden Konstanten zu implementieren und dann zu den Zusatzfeatures &amp;uuml;berzugehen. Die fehlenden Keywords m&amp;uuml;ssen zwar fr&amp;uuml;her oder sp&amp;auml;ter noch rein, aber da ich sie selten ben&amp;ouml;tige, schiebe ich diese langweilige Aufgabe noch ein wenig nach hinten.&lt;br /&gt;&lt;br /&gt;So ein Precompiler w&amp;auml;re nat&amp;uuml;rlich sinnlos, wenn er nicht ein paar neue Features zur Sprache hinzuf&amp;uuml;gt. Ich habe im Moment die folgenden eingeplant (in der Reihenfolge):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Echte Konstruktoren: Im Prinzip die New-Methode mit Parametern, welche man beim Erstellen zwingend angeben muss. Beispiel [syntax=&amp;quot;bmax&amp;quot;]Type TFoo&lt;br /&gt;	Method New( A:Int, B:int )&lt;br /&gt;		Print A + B&lt;br /&gt;	End Method&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Local Foo:TFoo = New TFoo( A, B )&lt;br /&gt;&lt;br /&gt;Foo = New TFoo 'Fehler![/syntax]&lt;br /&gt;Dies hat den Vorteil, dass man den Konstruktor nicht vermeiden kann wie jetzt. Zwar wird oft 'Create' als Pseudokonstruktor verwendet, welchen man aber ohne weiteres umgehen kann, indem man ihn einfacht nicht aufruft. Darum ist ein Pflichtkonstruktor mit Parametern von Vorteil&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Echtes Private/Public: Das jetzige Private/Public ist nicht zu gebrauchen, da es etwas komplett anderes tut, als man es von anderen Programmiersprachen kennt. Das sollte sich &amp;auml;ndern.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Funktions&amp;uuml;berladung: Das ist nat&amp;uuml;rlich eine etwas schwierigere Aufgabe. Der aktuelle Ausdrucksparser kann zwar mit absoluter Sicherheit den Datentyp bestimmen, der bei einem Ausdruck nach Ausf&amp;uuml;hrung herauskommt (was f&amp;uuml;r Funktions&amp;uuml;berladung zwingend ist), jedoch macht die schwache Typisierung von BMax das ganze etwas schwieriger. Folgendes Beispiel [syntax=&amp;quot;bmax]Function Add:Int( A:Int, B:Int )&lt;br /&gt;	Return A + B&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function Add:Float( A:Float, B:Float )&lt;br /&gt;	Return A + B&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Print Add( 3, 3.4 ) 'Welche Funktion soll nun aufgerufen werden? Die Parametertypen entsprechen keiner Funktion, k&amp;ouml;nnen aber ohne weiteres in die erwarteten Typen ungewandelt werden - f&amp;uuml;r beide Funktionen.[/syntax]&lt;br /&gt;In so einem Fall wird der Compiler wohl eine Fehlermeldung ausgeben m&amp;uuml;ssen, dass er sich nicht entscheiden kann - f&amp;uuml;r absolute Sicherheit wird man wohl die Parameter explizit in die Typen umcasten m&amp;uuml;ssen, die der Funktion entsprechen, die man aufrufen will.&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Leider kommt das Projekt nicht mehr so schnell voran wie am Anfang, da ich n&amp;auml;chsten Donnerstag ein Praktikum anfange und vorher noch Groovy (ein Java-Dialekt *schauder*) lernen muss, was mehr oder weniger meine ganze Zeit auffrisst. Ich hoffe aber, dass ich das Projekt noch zufriedenstellend fertigstellen kann.&lt;br /&gt;&lt;br /&gt;Was die Vertreibung angeht, halte ich mir im Hinterkopf, den Precompiler nachher f&amp;uuml;r einen kleinen Geldbetrag (5$-10$) zu vertreiben. Vorher muss sich aber noch herausstellen, ob die Leute &amp;uuml;berhaupt bereit sind, f&amp;uuml;r so ein Programm zu zahlen - hat ja keinen Wert, den ganzen Aufwand zu betreiben und nachher nur ein Exemplar an seine Mutter zu verkaufen &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt;</description>
			<pubDate>Sat, 26 Jun 2010 19:22:19 +0200</pubDate>
		</item>

		<item>
			<title>Multithreading &lt;3</title>
			<link>https://www.blitzforum.de/worklogs/304/#2433</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2433</guid>
			<author>Noobody</author>
			<description>Heute hab ich nochmal einen kleinen Test zusammengeworfen, um das neu implementierte Multithreading in der Photon Map, dem Raytracer und dem SPH-Simulator auf die Probe zu stellen. Die Anzahl Photonen pro Frame wurde verzehnfacht und die Anzahl SPH-Partikel mehr als verdoppelt, aber trotzdem renderte das Video bei der gleichen Anzahl Frames mehr als doppelt so schnell in 1h 50min. Damit werde ich mich wohl zufriedengeben, obwohl die SPH-Partikel wohl noch ein wenig optimaler auf die Threads aufgeteilt werden k&amp;ouml;nnten.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=6DUTqEXA504&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/SPH_PM_2.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Der Wasserstrom aus der R&amp;ouml;hre sieht nun hoffentlich nicht mehr nach einem 'Eisstrahl' aus wie im letzten Video &lt;img src=&quot;/forum/images/smiles/icon_wink.gif&quot; alt=&quot;Wink&quot; /&gt;&lt;br /&gt;&lt;br /&gt;Als n&amp;auml;chstes werde ich mir wohl was einfallen lassen m&amp;uuml;ssen, wie ich denn Wandpartikel m&amp;ouml;glichst effizient und h&amp;uuml;bsch auf den Bildschirm bringe, damit ich die Szene mit Hindernissen f&amp;uuml;r das Wasser aufpeppen kann.</description>
			<pubDate>Fri, 28 May 2010 01:55:10 +0200</pubDate>
		</item>

		<item>
			<title>Multithreading</title>
			<link>https://www.blitzforum.de/worklogs/304/#2426</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2426</guid>
			<author>Noobody</author>
			<description>Ich machte heute erste Versuche mit Multithreading im SPH-Code. Multithreading ist in BMax bei so vielen Objekten zwar unbrauchbar (der ver&amp;auml;nderte GC im Multithreading verlangsamt das Programm um einiges mehr, als dass ich mit mehreren Threads wieder rausholen k&amp;ouml;nnte), aber da die SPH-Berechnungen nun sowieso in C++ ablaufen, setzte ich das Multithreading mit der WinAPI um.&lt;br /&gt;&lt;br /&gt;Um die gr&amp;ouml;sste Geschwindigkeit herauszuholen, verzichtete ich komplett auf Mutexe bzw. Semaphoren, um zu verhindern, dass ein Thread auf die anderen warten muss. Stattdessen werden alle Situationen vermieden, in denen sich m&amp;ouml;glicherweise zwei Schreibprozesse &amp;uuml;berschneiden k&amp;ouml;nnten. Das bedeutet, dass das Programm eher in Kauf nimmt, etwas sp&amp;auml;ter nochmal neu berechnen zu m&amp;uuml;ssen, als die &amp;Auml;nderungen direkt zu &amp;uuml;bertragen, was in einer &amp;Uuml;berschneidung von zwei Threads f&amp;uuml;hren k&amp;ouml;nnte.&lt;br /&gt;&lt;br /&gt;Das f&amp;uuml;hrt dazu, dass es je nach Partikelanzahl eine optimale Threadanzahl gibt. Mehr Threads als die optimale Anzahl verlangsamen also das Programm, obwohl mehr Kerne ausgelastet werden &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt; Da ich im Raytracer nachher aber meistens gigantische Partikelanzahlen habe, ist die optimale Threadanzahl sowieso immer die Anzahl Kerne der CPU, also mache ich mir da keine Sorgen.&lt;br /&gt;&lt;br /&gt;Mit Multithreading ist die 3D-Version sogar Echtzeitf&amp;auml;hig, daher habe ich eine kleine Demo aus dem C++-Projekt geschn&amp;uuml;rt. Ich hoffe, es ist erlaubt, dass ich hier ein C++-Programm poste, aber der Code wird ja nachher in einem BMax-Projekt verwendet, daher wird hier hoffentlich noch ein Auge zugedr&amp;uuml;ckt.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/SPH3D_MT.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Download: &lt;/b&gt; &lt;a href=&quot;http://www.noobody.org/BBP/SPH3D_MT.rar&quot; target=&quot;_blank&quot;&gt;Link&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Die Bedienung erfolgt mit den Pfeiltasten, mit denen man den W&amp;uuml;rfel drehen kann. Da die Gravitation immer nach unten zieht, kann man so mit der Fl&amp;uuml;ssigkeit rumspielen. Am Anfang wird man nach der Anzahl Threads gefragt, die verwendet werden sollen. Dort gibt man am besten die Anzahl Kerne an, die die CPU hat, oder 4, wenn man mehr als 4 Kerne hat (4 ist die optimale Anzahl Threads bei 16'000 Partikeln).&lt;br /&gt;&lt;br /&gt;Als n&amp;auml;chstes werde ich den Raytracer vermultithreadisieren, was die Geschwindigkeit hoffentlich um einiges erh&amp;ouml;ht. Hirngespinst des Tages ist 1 FPS beim Rendern &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt; Mal sehen, ob ich das hinbekomme.</description>
			<pubDate>Wed, 26 May 2010 16:42:42 +0200</pubDate>
		</item>

		<item>
			<title>Photon Mapping Video</title>
			<link>https://www.blitzforum.de/worklogs/304/#2388</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2388</guid>
			<author>Noobody</author>
			<description>Ich habe heute einen kleinen Test zusammengeworfen, um die neuen Features zu testen. Dazugekommen sind Photon Mapping, Oberfl&amp;auml;chenspannung in 3D und jede Menge Speed (gerendert wird nun 5-7 Mal schneller als vorher). Entfernt habe ich einen sehr l&amp;auml;stigen Bug, der mich knapp eine Woche Debugging gekostet hat (die Finger schwebten manchmal bedenklich lange &amp;uuml;ber Ctrl+A, Delete und Ctrl+S).&lt;br /&gt;&lt;br /&gt;Das Video findet ihr auf Youtube:&lt;br /&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=u_xVeux5aog&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/SPH_PM.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;Photon Mapping braucht noch einiges an Kalibrierung, damit es realistisch aussieht (die Intensit&amp;auml;t schwankt immer noch ziemlich unsch&amp;ouml;n), aber ich arbeite dran.</description>
			<pubDate>Mon, 17 May 2010 23:08:21 +0200</pubDate>
		</item>

		<item>
			<title>Volume Rendering</title>
			<link>https://www.blitzforum.de/worklogs/304/#2320</link>
			<guid>https://www.blitzforum.de/worklogs/304/#2320</guid>
			<author>Noobody</author>
			<description>Da ich in den letzten Wochen vor allem an meinem BCC-Beitrag arbeitete, wurde es in diesem Worklog leider ein wenig still. Um diesen Missstand zu beheben, werde ich heute ein wenig von meinem gestern fertiggestellten GPU-Volume-Renderer berichten.&lt;br /&gt;&lt;br /&gt;Was ist denn Volume rendering schon wieder?&lt;br /&gt;Im Volume rendering geht es &amp;auml;hnlich wie beim Voxel rendering darum, ein Voxelgitter zu rendern. Der Unterschied ist aber, dass im Volume rendering nicht beim ersten Voxel gestoppt wird, der einen gewissen Transparenzwert aufweist, sondern alle Voxel von hinten nach vorn ausgewertet werden, um die kombinierte Pixelfarbe nachher auf dem Bildschirm auszugeben.&lt;br /&gt;&lt;br /&gt;Das Auswerten der Voxel erweist sich aber als ein wenig kompliziert. Volume Rendering wurde urspr&amp;uuml;nglich f&amp;uuml;r die Medizin entwickelt, um Daten aus der Computertomographie darstellen zu k&amp;ouml;nnen. Daher ist es wichtig, dass einzelne Gewebetypen herausgefiltert, w&amp;auml;hrend andere Gewebetypen ausgeblendet werden. Farbgebung und Beleuchtung spielen auch eine wichtige Rolle, um Form und Zusammensetzung des Gewebes besser zu erkennen. Ich werde die ben&amp;ouml;tigten Formeln hier mal nicht erl&amp;auml;utern - wer interessiert ist, kann sich ja mal &lt;a href=&quot;http://graphics.stanford.edu/papers/volume-cga88/volume-scanned_files/v3_document.htm&quot; target=&quot;_blank&quot;&gt;diesen Artikel hier&lt;/a&gt; durchlesen.&lt;br /&gt;&lt;br /&gt;Da es nat&amp;uuml;rlich enorm kostspielig ist, jedes Voxel durch den Klassifikations-Algo zu schicken, werden alle Werte in BMax vorausberechnet und in eine passende Textur gesteckt. Aber auch so l&amp;auml;uft das Programm enorm langsam - durchschnittlich 10 FPS bei 800x600 Pixeln. Das liegt daran, dass Normalen und Beleuchtung f&amp;uuml;r jedes Voxel berechnet werden m&amp;uuml;ssen, was bei entsprechend grossen Volumen ziemlich auf die Performance geht.&lt;br /&gt;&lt;br /&gt;Als Testmodell diente der CT-Scan einer Freundin, der mir von ihr freundlicherweise zur Verf&amp;uuml;gung gestellt wurde. Aufl&amp;ouml;sung liegt bei 512x512x256 Voxeln mit jeweils 12 Bit pro Voxel. Um den Wertebereich perfekt abzudecken, wurden zwei 4096x4096 Texturen verwendet, welche die vorausberechneten Werte dem Shader zur Verf&amp;uuml;gung zu stellen.&lt;br /&gt;&lt;br /&gt;Hier noch ein paar Aufnahmen, um einen Eindruck vom Renderer zu geben:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sch&amp;auml;del:&lt;/b&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/VolumeRendering_8.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Nebenh&amp;ouml;hlen:&lt;/b&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/VolumeRendering_6.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.noobody.org/BBP/VolumeRendering_9.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Youtube-Video:&lt;/b&gt; &lt;a href=&quot;http://www.youtube.com/watch?v=0d1riQi8s1g&quot; target=&quot;_blank&quot;&gt;Link&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;F&amp;uuml;r diejenigen, die den Voxelrenderer im vorigen Eintrag aufgrund ihrer Hardware nicht ausprobieren konnten, habe ich ein Video dessen in Aktion hochgeladen: &lt;a href=&quot;http://www.youtube.com/watch?v=CBR9GKhyRzE&quot; target=&quot;_blank&quot;&gt;Link&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ab jetzt gehts wieder zur&amp;uuml;ck ans Photon Mapping. Ein Video von Wasser mit Photon Mapping muss noch sein &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 9px;&quot;&gt;PS: Ich liebe &lt;a href=&quot;http://www.youtube.com/watch?v=jOrXiqvu-R4#t=43s&quot; target=&quot;_blank&quot;&gt;diesen Song&lt;/a&gt;. Von dem krieg ich Ohr-Orgasmen&lt;/span&gt;</description>
			<pubDate>Fri, 23 Apr 2010 19:15:32 +0200</pubDate>
		</item>


	</channel>
</rss>
