Was braucht man in Blender, um ein 3D-Häuschen zu modellieren?
Anfangen kann man mit einer Wand mit Löchern drin, dann eine Bodenplatte oder Geschossplatte mit Öffnungen. Fenster und Türen sind anschließend dran. Eine Treppe verbindet die Ebenen. Den oberen Abschluss bildet eine Sparrendachkonstruktion. Drumherum gibt’s Grasland.
Richtig Architektur kann man damit nicht betreiben, aber man hat vielleicht einen Einstiegspunkt.
Das habe ich nun mit parametrisierten Bauteilen realisiert:
Habe in Blender erst jetzt die Geometry Nodes entdeckt. Das bietet die Möglichkeit, fantastische Objekte zu bauen. Seit meinen AutoCad-Zeiten vor 25 Jahren schwebte mir vor, ein Fenster-Element (also Fenster wie Fenster und nicht wie Windows) zu bauen, bei dem die Parameter Außenmaße, Rahmenbreite und -dicke und noch ein paar andere Werte einzugeben sind, und schwupps ist das Element gezeichnet. In Blender geht das nun ziemlich einfach. Ob es sich um ein Fenster oder eine Tür handelt, wird durch das Vorhandensein des unteren Rahmenelements im Blendrahmen entschieden.
Letztes Jahr hatte ich eine Fahrrad-Rallye zum Braunschweiger Ringgleis veranstaltet. Da ich der Meinung bin, dass sich solch eine Veranstaltung geradezu anbietet, per Software unterstützt zu werden, schrieb ich die R-Rallye:
R-Rallye mobile view
Die App ist eine Browser-Anwendung, voll funktionsfähig und für mobile Nutzung optimiert. Ein großer Teil der Aufgaben ist jedoch leider inzwischen veraltet, da sich die lokalen Gegebenheiten (z.B. Graffitis) geändert haben. Wenn ich mal wieder Zeit habe, werde ich die Aufgaben aktualisieren. Dabei unterstützt mich der Task-Editor. (Bei aktualisierten Aufgaben und Antworten wird der Task-Editor von hier natürlich nicht mehr erreichbar sein)
Hier eine kleine Übersicht über die Funktionsweise und die Bestandteile des ‚Webhostings‘. Also: wie veröffentliche ich eine eigene Website? Und zwar ohne mich bei Webbaukasten-Anbietern registrieren zu müssen und damit in den meisten Fällen im Netz eines Anbieters gefangen zu sein. Guckstu:
Wenn du eine Website erstellen willst, brauchst du einen Webhoster. Bei diesem bestellst du ein (kostenpflichtiges) Hostingpaket mit Wunschdomain („irgendeinentollenseitennamen.de“) und bekommst damit als Eigentümer Zugang zur Domain-Verwaltung und zum Webspace. Mithilfe eines FTP-Programms (z.B. FileZilla) und den vom Webhoster mitgeteilten Zugangsdaten machst du den Datei-Upload in deinen Webspace. Wenn du WordPress verwenden willst, lädst du dir die zip-Datei von wordpress.org herunter und packst den Inhalt des Unterordners ‚wordpress‘ auf den Webspace. Mittels der Domain-Verwaltung sagst du dem System, welcher Ordner des Webspace der Domain zugeordnet werden soll. Für WordPress (und andere CMS) benötigst du eine Datenbank, die über die Domain-Verwaltung eingerichtet werden kann. Nun kann die Designverwaltung aufgerufen werden (bei WordPress initial aufzurufen mit der domain und im Folgenden mit domain/wp-login) und der Spaß beginnt.
Die vorangegangenen Schritte sind im Allgemeinen nur einmalig auszuführen. Alles Folgende passiert innerhalb der Designverwaltung (z.B. innerhalb von WordPress).
Zu WordPress:
Worpress ist historisch gesehen eine Software , um Web-Blogs zu erstellen. Aus diesem Grunde unterscheidet die Admin-Oberfläche zwischen ‚Beiträgen‘ und ‚Seiten‘. Standardmäßig gibt es immer eine Blogseite, auf der die Beiträge gesammelt werden, und alle anderen Seiten, die üblicherweise auch im Menü zu finden sind. Ausgangspunkt für das Layout sind die ‚Themes‘. Einige sind bereits in der Installationsversion mitgeliefert, andere lassen sich (oftmals kostenpflichtig) nachinstallieren. Die Themes haben spezifische Einstellungsmöglichkeiten, die über den ‚Design -> Customizer‘ aufzurufen sind. Du solltest dir auf jeden Fall Zeit nehmen, um ein wenig rumzuexperimentieren. Das englischsprachige Manual https://codex.wordpress.org hilft auf jeden Fall.
Hier noch ein Hinweis zu den Sternchen * in der Grafik: alle Zugangsdaten sollten in deinem Passwortcontainer hinterlegt werden, z.B. KeePass.
Nach einigen Forschungsaufwendungen ist mein DAW-Setup nun vorerst beendet. Besonderheit dabei ist die ausschließliche Nutzung von Open-Source-Software und damit ein überschaubarer Kostenrahmen. Wenn ich mich ranhalte, lerne ich vielleicht demnächst auch ein wenig Klavierspielen und verbessere meine Gitarrenskills weiter. Im Moment jedoch ist es viel aufregender, die funktionierende Gesamtkonfiguration auszuprobieren durch Ausloten der runtergeladenen Soundfonts, rauszufinden, wie Drums gemacht werden und mit welchen Effekten die E-Gitarre versehen werden kann.
Das Setup:
Hardware
Rechner ist bestückt mit einem Quadcore-Prozessor mit 3,6 GHz und 8 GB RAM.
Betriebssystem Ubuntu 18.04.01 (Bionic) mit folgender Zusatzeinstellung: Eintrag in /etc/security/limits.conf:
@audio - rtprio 95
@audio - memlock unlimited
Außerdem muss der aktuelle user (Benutzername) der Gruppe audio zugewiesen werden:
sudo usermod -a -G audio Benutzername
meine Instrumente, die einen „elektrischen Anschluß“ haben:
Als zusätzliche und fast wichtigste Hardwarekomponente kam als letztes ein Audio-Interface von Steinberg (UR22mkII) hinzu. Denn nur mit so einer externen Soundkarte gibt’s keine Probleme mit Brummen, Rauschen, Frequenzgang, Pegel, Impedanz und Latenzen. Das von mir gewählte Modell funktioniert out of the box. Ubuntu 18.04 findet sowohl die Audio-Ein- und Ausgänge als auch den MIDI-Port ohne zusätzliche Software. Der UR22 ist wie gemacht für meinen kleinen Instrumentenpool.
Software
qjackctl: dies ist das Frontend für den JACK-Server. JACK ist das System der Audio- und Midi-Signalverarbeitung unter Linux. Viele (wenn nicht gar die meisten) Audio- und Midi-Programme unter Linux unterstützen das JACK-Konzept. JACK ist der Dirigent der Audio-Programme und regelt die Signalwege und „timing-tasks“ und sollte deswegen immer als erstes gestartet werden. Meine JACK-Einstellungen: Abtastrate: 44100, Frames/Periode: 256 ergibt eine Latenz von 11,6 ms, ohne dass JACK in xruns läuft.
pulseaudio-module-jack: weil es auch Standardprogramme gibt (wie z.B. Browser), die den pulseaudio-Soundserver unterstützen, gibt es diese „Bridge“, die es z.B. ermöglicht, Audio-Signale aus Video-Portalen mit Effekten zu versehen und in eine Audiospur zu leiten.
Ardour: das Schweizer Taschenmesser für die Musikproduktion unter Linux. Audio- und Midi-Spuren in unbegrenzter Anzahl, Einfügen von Effektgeräten und Klangerzeuger in Form von (LV2-)Plugins.
Guitarix: der konfigurierbare Guitar-Amp für jeden Geschmack mit allen Effekten, die man so braucht. Plus Stimmgerät. Und für den schnellen Rhythmus sogar eine kleine „Hobby“-Drum-Engine.
Drumgizmo mit DRSKit: echte hochqualitative Drum-Samples (4,3 GB) zum Einbinden in Ardour. Wer noch mehr Drums will, verwendet Hydrogen.
calf-Plugins: Sammlung von spannenden LV2-Instrumenten, -Effekten, -Filtern und -Tools. Einmal installiert stehen sie sofort zum Einfügen in Audio- oder Midi-Spuren zur Verfügung.
X42-plugins: Sammlung von interessanten Plugins. Insbesondere reizte mich die darin enthaltene MIDI Filter Collection, und darin der MIDI Keysplit, der es ermöglicht, den Tastaturbereich des Midi-Keyboards in zwei oder mehrere Bereiche zu teilen: linke Hand Bass-Linie oder Drums, rechte Hand Harfe oder ähnliches.
Soundfonts: für das mit Ardour mitgelieferte Instrument a-fluid Synth gibt es Unmengen an Soundfonts zum Download (Dateien mit der Endung .sf2). Da hab ich auch eins der besten Pianos gefunden.
Wenn dann irgendwann tatsächlich vorzeigbare Ergebnisse vorliegen, werden sie hier vorgezeigt :).
Es war schon immer ein Problem: Was passiert, wenn ein Raumschiff zu einem unbekannten Ziel gebeamt wird? Ist an dem neuen Ort überhaupt Platz für das gebeamte Objekt? Bei dem nun folgenden Objekt hat man das Gefühl „mh, ja, das ist ja gerade noch mal gut gegangen“.
Nee, im Ernst, das ist schon ein heftig cooles Kleinod, was die om-architekten da gezaubert haben, und mußte deswegen auch unters blender-threejs-Messer.
Und schon wieder Blender. Yes, it rocks ! Route 66, Woodstock, Jimi Hendrix und ich im zarten Alter von 13 zeichnete meine Geraldine: die Materialisierung von Freiheit und Abenteuer.
… und 40 Jahre später wurde die flache 2D-Zeichnung endlich zur dritten Dimension erhoben:
Das Objekt meiner Betrachtung ist das Haus meiner Mutter. Die Idee ist, ein minimiertes Gebäudemodell in blender zu bauen, eine perspektivkorrigierte Fototextur aufzubringen und zu hoffen, dass die Unzulänglichkeiten nicht so dominierend sind. Mein Ziel ist es, die Kubatur und „Atmosphäre“ eines Gebäudes rüberzubringen.
Original und „Fälschung“:
Das Blender-Export-Addon von MrDoob und ein wenig threejs-Script bescherte mir das. Das ist mit sehr wenig Aufwand (aus der Hüfte geschossene Fotos und ein Low-Poly-Model) schnell gemacht und erfüllt zumindest meine Erwartung. Dieses Model besteht aus nur 42 (!) Vertices.
Es gibt ja eine ziemlich große Gemeinde von Kartonmodellbauern. Dementsprechend komplexe und aufwendige Kartonmodelle gibt es: z.B. die gesamte Insel Mont-Saint-Michel oder die Sagrada Família. Ich beschränke mich als blutiger Anfänger auf einen einfacheren Kartonbogen, den es beim AGK gibt: es handelt sich um den Kartonbogen eines französischen Verlages eines deutschen Arbeiterhauses aus dem Jahre 1902.
Die meisten Leute, die sich mit diesem Metier beschäftigen, stellen sich die Frage, wie man aus einem 3D-Modell einen Modellbaubogen erstellt. (In der Tat gibt es dazu sogar ein Blender-Plugin). Hier jedoch gehts andersherum: man nehme einen Modellbaubogen und benutze blender als virtuellen Cutter und Klebstoff. Ein Filmchen demonstriert, was ich meine.
Mein Gesellenstück
Schön, wie sich vergangene Projekte eignen, mit neuen Mitteln verarbeitet zu werden. Mein Gesellenstück als Tischler entstand 1987:
Da stand ich nun im Garten meiner Mutter, stellte mich genau in die Mitte, und schoss 42 Bilder mit meiner Digicam, indem ich mich um meine eigene Achse drehte. Irgendwo in meinem Hinterkopf hatte ich zwar das Parallaxenproblem, aber ich dachte: die Software gleicht das schon aus. Denkste ! Zwei Bilder, die sich überlappen, aber von leicht unterschiedlichen Standorten aufgenommen, können partout nicht miteinander kombiniert werden, ohne dass es merkwürdige Phänomene gibt (s. Panorama). Ich denke, es wird Zeit, ein ordentliches Stativ mit Panoramakopf zu besorgen.
(Panorama erstellt mit Hugin, Panoramaplayer mit three.js von MrDoob)
An den großen Contentmanagement-Systemen hat mich immer der enorme Umfang genervt. Da werden Unmengen an MBs auf den Webserver geladen und diejenigen, die im Alltag die Inhaltspflege übernehmen sollen, müssen aufwendig angelernt werden. Mal ehrlich: es ist fast einfacher, HTML, CSS und JavaScript von der Pike auf zu erlernen als die Redaktionsoberfäche von Typo3 (oder WordPress 😉 ) zu bedienen. Das hat mich dazu animiert, das onefile_cms zu schreiben. Eine einzige kleine PHP-Script-Datei und ein HTML-Template mit nur 5 Variablen sind die Zutaten. Natürlich kann damit kein Enterprise-Portal entwickelt werden, aber für eine mehrseitige kleine Homepage mit 1-stufigem Menü reicht’s.
<?php
// onefile_cms by G. Drinkmann Ver 0.12 (29.05.2013)
// Contentmanagement-System mit Wiki-Dialekt zur Contentbearbeitung
// Dieser Quelltext kann völlig frei verwendet werden
error_reporting(E_ALL);
// ############################ HTML-Template ##########################################
// das Template sollte folgendes enthalten:
// Variablen im Template:
// <!-- {sitetitle} -->
// wird ersetzt durch Homepage-Titel
// <!-- {menutitle} -->
// der Menüname der angezeigten Seite
// <!-- {ul-menu} -->
// Menü als automatisch erzeugte ul-Liste (CSS s.u.)
// <!-- {content-width} -->
// wird ersetzt durch Content-Breite
// <!-- {content} -->
// der eigentliche Seiteninhalt aus der Redaktionsseite
// CSS:
// #menu id des ul-Elements
// #menu li z.B.{display:inline; list-style:none;}
// #menu a.menunormal class-Attribut des a-Elements im Menü
// #menu a.menucurrent class-Attribut des aktiven a-Elements im Menü
// img.Lfloat class-Attribut von linksbündig formatierten Bildern mit Text-Umlauf
// img.Rfloat class-Attribut von rechtsbündig formatierten Bildern mit Text-Umlauf
// Konvention:
// Namen der Bilder des Templates sollten mit "ONEFILECMS_" beginnen
// ------- HTML-Template-Datei ---------------------
$ggtplfile = "tpl1.html";
// ############################ Script-Variablen #######################################
// ------- Homepage-Titel --------------------------------------------------------------
$ggsitetitel = "Kiosk JOJO";
// ------- md5-Passwort (zu erstellen bei z.B. http://www.functions-online.com/md5.html)
$ggpass = "e6b3cd51a7afb493493d0c4a0bb0c8b2"; // jo33jo (bitte comment löschen)
// ------- Edit-URL-Parameter (m=) zum Aufruf der Redaktionsseite ----------------------
$ggeditpara = "edit"; // ohne Leer- oder Sonderzeichen !
// ------- Template ist XHTML ----------------------------------------------------------
$ggisxhtml = false;
// ------- Content-Breite --------------------------------------------------------------
$ggcontwidth = "750px";
// ############################ ab hier Chefsache !! ###################################
$ggcontfile = "content1file.txt";
$ggxsl = ($ggisxhtml) ? " /" : "";
function ggerror($ggmsg) {
global $ggcontent, $ggsitetitel, $ggxsl;
$ggcontent[0]['mtitle'] = "FEHLER";
$ggcontent[0]['read'] = "<i>".$ggmsg."</i><br".$ggxsl."><br".$ggxsl.">Die Seite \"".$ggsitetitel."\" ist momentan nicht verfügbar.<br".$ggxsl.">Versuchen Sie es bitte später nocheinmal.<br".$ggxsl.">Danke !";
}
if (isset($_GET['m'])) { // Check des GET-Parameter
if ($_GET['m'] === $ggeditpara) $ggpar = "e";
else $ggpar = intval($_GET['m']);
} else $ggpar = 0;
if ($ggpar === "e") { // Seite editieren
if (md5($_POST['pass']) === $ggpass && isset($_POST['content'])) {
file_put_contents("./".$ggcontfile, urldecode($_POST['content']));
if (isset($_FILES['pic'])) {
if (preg_match("/\.(jpg|gif|png)$/i", $_FILES['pic']['name']) || ($ggtplfile === $_FILES['pic']['name'])) {
move_uploaded_file($_FILES['pic']['tmp_name'], "./".$_FILES['pic']['name']);
}
}
if (isset($_POST['delimg'])) {
for ($i=0; $i<count($_POST['delimg']); $i++) {
@unlink("./".urldecode($_POST['delimg'][$i]));
}
}
}
if (file_exists("./".$ggcontfile)) {
$ggfstr = file_get_contents("./".$ggcontfile);
} else $ggfstr = utf8_encode("; Bitte mit Inhalt füllen");
$ggpiclis = ""; // vorhandene Bilder listen
if ($gghandle = opendir('.')) {
while (false !== ($ggfile = readdir($gghandle))) {
if (preg_match("/\.(jpg|gif|png)$/i", $ggfile) && (!preg_match("/^ONEFILECMS_/", $ggfile))) {
$ggpiclis .= "{{".$ggfile."}}<input type='checkbox' name='delimg[]' value='".$ggfile."' title='Bild löschen'><img onmouseover='document.getElementById(\"preview\").src = this.src; document.getElementById(\"preview\").className=\"gvisible\"' onmouseout='document.getElementById(\"preview\").className=\"ghidden\"' class='pici' src='".$ggfile."'> ";
}
}
closedir($gghandle);
}
if (!$ggpiclis) $ggpiclis = "<i>Keine</i>";
$ggaction = $_SERVER['PHP_SELF']."?m=".$ggeditpara;
$ggeditsite = <<<EOTE
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>{$ggsitetitel} editieren</title>
<style type="text/css">
* {font-family:arial}
img.pici {border:0;padding:0;margin:0;height:18px}
img.gvisible {visibility:visible}
img.ghidden {visibility:hidden}
</style>
</head>
<body style="background-color:#ebebeb">
<h2>Website <a href="{$_SERVER['PHP_SELF']}" style="color:red" target="_blank"><i>{$ggsitetitel}</i></a> editieren (Inhalts-Breite <span style="color:red">{$ggcontwidth}</span>):</h2>
<p style="font-size:10px">Zeile mit ; am Anfang = Kommentar<br>
M--- am Anfang der Zeile = neuer Menütitel<br>
HTML-Tags werden ausgeführt<br>
== am Anfang der Zeile = große Überschrift<br>
=== am Anfang der Zeile = kleinere Überschrift<br>
| am Anfang der Zeile = Tabelle (weitere Zellen mit | trennen)<br>
* am Anfang der Zeile = Liste<br>
{{*.jpg oder gif oder png}} = Bild in Originalgröße<br>
{{*.jpg oder gif oder png|L oder R}} = Bild links bzw. rechts mit Text-Umlauf<br>
[[Menüindex|Linktext oder -bild]] = interner Link (Index beginnt bei 0)<br>
[[Linkadresse|Linktext oder -bild]] = externer Link<br>
**Wörter** = Fett<br>
//Wörter// = Kursiv<br>
---- = horizontale Linie<br>
((x)) am Anfang = Text-Umlauf (Float) beenden</p>
<form name="f1" action="{$ggaction}" method="post" enctype="multipart/form-data">
<p><b>Inhalt</b><br>
<textarea name="content" style="width: 600px; height: 300px; font-size: 12pt">{$ggfstr}</textarea></p>
<p id="piclist"><b>Hochgeladene Bilder:</b><br>
{$ggpiclis}</p>
<p><b>Datei hochladen:</b> jpg, gif, png oder Template <i>{$ggtplfile}</i><br>
<input type="file" name="pic" size="61"></p>
<p>Passwort <input type="password" onkeydown="document.getElementsByName('OK')[0].disabled=false" name="pass" style="width: 200px;">
<input style="font-weight:bold" type="submit" name="OK" value="Seite speichern" disabled="disabled"></p>
</form>
<img class="ghidden" id="preview" src="nixda" style="position:absolute; left:3px; top:3px; border:solid #808080 30px;">
</body>
</html>
EOTE;
echo $ggeditsite;
} else { // normaler Seitenaufruf
if (file_exists("./".$ggtplfile)) {
$ggsitestr = file_get_contents("./".$ggtplfile);
} else die("TEMPLATE NICHT VORHANDEN !");
$ggcontent = array(); // Initialisierung des Content-Array
$ggcount=-1;
if (file_exists("./".$ggcontfile)) { // Steuerdatei ins Content-Array einlesen
$ggf = fopen("./".$ggcontfile, 'rb');
while (!feof($ggf)) {
$ggtmp = rtrim(fgets($ggf));
if (substr(ltrim($ggtmp),0,4)==="M---") {
$ggcount++;
$ggcontent[$ggcount]['mtitle'] = ltrim(substr(ltrim($ggtmp),4));
$ggcontent[$ggcount]['mtitleclass'] = "menunormal";
$ggcontent[$ggcount]['read'] = "";
} elseif (substr(ltrim($ggtmp),0,1)!==";") {
$ggcontent[$ggcount]['read'] .= $ggtmp."<brbr>";
}
}
fclose($ggf);
if ($ggcount === -1) ggerror("Fehler: Kein Menü in Steuer-Datei eingetragen");
} else ggerror("Fehler: Steuer-Datei nicht vorhanden");
if ($ggpar>$ggcount) $ggpar = 0;
$ggcontent[$ggpar]['mtitleclass'] = "menucurrent";
$ggsitestr = str_replace("<!-- {sitetitle} -->", $ggsitetitel, $ggsitestr);
$ggsitestr = str_replace("<!-- {menutitle} -->", $ggcontent[$ggpar]['mtitle'], $ggsitestr);
$ggsitestr = str_replace("<!-- {content-width} -->", $ggcontwidth, $ggsitestr);
// --- Menü zusammenbauen ---
$ggmenustr = "<ul id=\"menu\">\n";
for ($i=0; $i<count($ggcontent); $i++) {
$ggmenustr .= "<li><a href=\"".$_SERVER['PHP_SELF']."?m=".$i."\" class=\"".$ggcontent[$i]['mtitleclass']."\" target=\"_self\">".$ggcontent[$i]['mtitle']."</a></li>\n";
}
$ggmenustr .= "</ul>\n";
$ggsitestr = str_replace("<!-- {ul-menu} -->", $ggmenustr, $ggsitestr);
// --- Content zusammenbauen ---
$ggcont = $ggcontent[$ggpar]['read'];
$ggcont = explode("<brbr>",$ggcont);
$ggcontstr = "";
$istab = 0; // Tabelle
$isul = false; // Bullet-Liste
$ggcleardiv = "<div style='clear:both;visibility:hidden;width:0;height:0;margin:0;padding:0;border:0;'></div>\n";
for ($i=0; $i<count($ggcont); $i++) {
if (substr(ltrim($ggcont[$i]),0,5)==="((x))") {
$ggisclear = " style='clear:both'";
$ggcont[$i] = substr(ltrim($ggcont[$i]),5);
} else $ggisclear = "";
if (substr(ltrim($ggcont[$i]),0,1)==="|") {
$ggtra = explode("|",substr(ltrim($ggcont[$i]),1));
if (!$istab) {
$ggcontstr .= "<table".$ggisclear.">\n";
} elseif ($istab !== count($ggtra)) {
$ggcontstr .= "</table>\n<table".$ggisclear.">\n";
}
$istab = count($ggtra);
$ggcontstr .= "<tr>";
for ($j=0; $j<$istab; $j++) {
$ggcontstr .= "<td>".trim($ggtra[$j])."</td>";
}
$ggcontstr .= "</tr>";
} else {
if ($istab) $ggcontstr .= "</table>\n";
$istab = 0;
if ((substr(ltrim($ggcont[$i]),0,1)==="*") && (substr(ltrim($ggcont[$i]),1,1)!=="*")) {
if (!$isul) $ggcontstr .= "<ul".$ggisclear.">\n";
$isul = true;
$ggcontstr .= "<li>".trim(substr(ltrim($ggcont[$i]),1))."</li>";
} else {
if ($isul) $ggcontstr .= "</ul>\n";
$isul = false;
if (substr(ltrim($ggcont[$i]),0,3)==="===") {
$ggcontstr .= "<h2".$ggisclear.">".substr(ltrim($ggcont[$i]),3)."</h2>";
} elseif (substr(ltrim($ggcont[$i]),0,2)==="==") {
$ggcontstr .= "<h1".$ggisclear.">".substr(ltrim($ggcont[$i]),2)."</h1>";
} elseif (trim($ggcont[$i])==="----") {
$ggcontstr .= "<hr".$ggisclear.">";
} elseif ($ggisclear) {
$ggcontstr .= $ggcleardiv.$ggcont[$i]."<br".$ggxsl.">";
} else $ggcontstr .= $ggcont[$i]."<br".$ggxsl.">";
}
}
$ggcontstr .= "\n";
}
$ggcontstr = preg_replace("/{{(\S.*\.(jpg|JPG|gif|GIF|png|PNG))\|L}}/", "<img src=\"$1\" style=\"float:left\" class=\"Lfloat\"".$ggx.">", $ggcontstr); // Bilder mit float links
$ggcontstr = preg_replace("/{{(\S.*\.(jpg|JPG|gif|GIF|png|PNG))\|R}}/", "<img src=\"$1\" style=\"float:right\" class=\"Rfloat\"".$ggx.">", $ggcontstr); // Bilder mit float rechts
$ggcontstr = preg_replace("/{{(\S.*\.(jpg|gif|png))}}/i", "<img src=\"$1\"".$ggx.">", $ggcontstr); // Bilder
$ggcontstr = preg_replace("/\[\[(\d+)\|(\S.*\S|\S)]]/", "<a href=\"".$_SERVER['PHP_SELF']."?m=$1\" target=\"_self\">$2</a>", $ggcontstr); // interne Links
$ggcontstr = preg_replace("/\[\[(\S+)\|(\S.*\S|\S)]]/", "<a href=\"$1\" target=\"_blank\" title=\"Link in neuem Fenster\">$2</a>", $ggcontstr); // externe Links
$ggcontstr = preg_replace("/ /", " ", $ggcontstr); // Leerzeichen
$ggcontstr = preg_replace("/ (\S)/", " $1", $ggcontstr);
$ggcontstr = preg_replace("/\*\*(\S.*\S|\S)\*\*/", "<strong>$1</strong>", $ggcontstr); // Fett
$ggcontstr = preg_replace("#//(\S.*\S|\S)//#", "<em>$1</em>", $ggcontstr); // Kursiv
$ggsitestr = str_replace("<!-- {content} -->", $ggcontstr, $ggsitestr);
$ggsitestr .= $ggcleardiv;
echo $ggsitestr;
}
?>
Also, man nehme den Quelltext, erstelle daraus eine Datei names index.php, fülle die Variablen aus, erstelle eine Template-Datei (mit dem Namen wie bei den Variablen angegeben) und lade beide Dateien (inklusive der zum Template gehörigen Bilder) auf den Webserver. Die index.php-Datei beinhaltet beides: die Maschinerie der eigentlichen Website für den Betrachter und die der Redaktion. Die Redaktionsseite wird über den Link <DeineURL>/index.php?m=<Variable URL-Parameter> aufgerufen. Ok, es sind mehr als nur eine Datei im Spiel, doch das eigentliche Programm besteht in der Tat nur aus dieser einen PHP-Datei.
Das Template sollte eine ganz normale HTML-Seite sein. Die Namen der Templatebilder sollten mit „ONEFILECMS_“ beginnen. Folgende Variablen können in diesem Template plaziert sein:
<!– {sitetitle} –> der Homepagetitel
<!– {menutitle} –> der Menüname der angezeigten Seite
<!– {ul-menu} –> Seiten-Menü als automatisch erzeugte ul-Liste
Das zugehörige Template ist die Datei tpl1.html. Im Quelltext dieser Seite sind die Variablen sichtbar.
Jojo’s Kiosk kann mit der Edit-Seite bearbeitet werden.
Dabei wird zur leicht erlernbaren Bearbeitung ein Wiki-Dialekt angewendet. Hat Ähnlichkeit mit Creole. Zum Speichern wird JEDESMAL das Paßwort abgefragt. Das ist ein wenig lästig, aber sicher.