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.
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
<!– {content-width} –> Breite des Inhaltbereichs
<!– {content} –> der eigentliche Seiteninhalt
Hier ist eine kleine Testseite zur Anschauung: der Kiosk des fiktiven Jojo
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.
Untertitel: Vorteile von Open Source Software (OSS)
Angenommen, Du gehst zu einem Auto-Händler und willst ein Auto zum täglichen Gebrauch erstehen. Der Händler macht Dir eine nagelneue Mittelklasse-Limousine schmackhaft. Kosten: einmalig 12.000,- , hinzu kommen Steuern und Versicherung. Für spätere Reparaturen oder Aufrüstungen kannst Du nur spezielle Werkstätten aufsuchen und es kostet Dich jedes mal ein halbes Vermögen. Ohne gefragt zu werden bekommst Du etlichen technischen Schnickschnack mitgeliefert, der Dir einreden soll, dass Du mit 200 Sachen Serpentinen bezwingen kannst, oder dass das Wort Aquaplaning nur für andere gültig ist. Du bist begeistert und überlegst, ob Du nicht gleich Deiner ganzen Verwandschaft solch ein tolles Auto schenken willst. Es soll ja keiner zu kurz kommen oder sich benachteiligt fühlen. Dafür wird Dir natürlich Skonto angerechnet, aber glaub ja nicht, dass Du die zusätzlichen Autos kostenlos bekommst. Der Händler argumentiert, dass Du beim Fahren nie mehr denken oder Deine körperlichen Kräfte sinnlos vergeuden musst. Du wirst mit Sitzheizung, intelligenter Klimaanlage und Multimediacenter eingelullt, und der AWA (Automatischer Weck-Assistent) wacht darüber, dass Du bei minimaler Überschreitung der Leitplanke sanft aufwachst. Falls Du nicht nur dösen willst, hast Du bei Deiner Fahrt Zeit und Ruhe, die Probleme zu lösen, die Dir am Arbeitsplatz das Leben zur Hölle machen. Diese Zeit brauchst Du auch, denn die Probleme wollen schnell und termingerecht gelöst werden, damit Du verdammt viel Geld verdienen kannst, um Deine Autos und deren Unterhalt abzubezahlen. Na ja, dieser Teufelskreis ist uns ja hinlänglich bekannt. Das mit der Zeit an sich ist jedoch auch ein Problem. Denn die technischen Raffinessen Deines neuen Autos bedürfen der monatelangen Einarbeitung anhand eines 500-seitigen Handbuches. Die Einsparung von Hebeln und Schaltern begründen die 5-fach-Belegung ein und desselben Touchsensors, dessen Bedienung im Morsecode erfolgt. Wenn Du Glück hast, und nur bei intensiver fetischhafter Neugier, wirst Du nach ca. 2 Jahren und einigen Geisterfahrten auch das letzte Feature Deines Navis ergründet haben. Und sei ehrlich, Du benötigst nur 20% der Gimmicks. Das Spannende aber kommt jetzt: Du hast einfach nicht die Kohle dafür. Was nun? Ein Kumpel von Dir hat in der dunkelsten Kaschemme der Stadt von einigen Limousinen, die vom Laster gefallen sind, gesprochen. Zwei Tage später stehst Du vor dem geilsten Fuhrpark, der Dir je in Deinen Träumen untergekommen ist. Jeden einzelnen dieser Sahneschnitten kannst Du für’n Appel und’n Ei haben. Zwar mussten die Serviceports, an die üblicherweise die elektronischen Wartungs- und Analysegeräte der Werkstätten angeschlossen werden, entfernt und einige andere kleinere Modifikationen vorgenommen werden, aber der ersten Spritztour in die City steht scheinbar nichts im Wege. City erreicht, Parklücke gefunden, Einpark-Lenk-Assistent eingeschaltet und den Hintermann unsanft auf den Gehweg geschoben. Der Abschleppdienst Deines Kumpels aus der Kaschemme berappt Dir 2500,- für das zügige Verschwinden vom Tatort. Der Fehler des Einpark-Lenk-Assistenten wird nie gefunden werden. Noch vor Eintreffen der aufgrund von Zeugenaussagen verursachten Vorladung besinnst Du Dich eines Anblicks bei besagtem Autohändler: Da stand doch noch eine italienische Limousine auf dem Hof. Ein bisschen unscheinbar und selten gesehen, aber wie Du zufällig weißt, mit einem völlig offengelegten Motorblock und gut zugänglichen Teilen. Da kannst Du wie in alten Zeiten selbst dran schrauben. Wenn Du AAS, WFS, BAS, GHD, HW, SSA oder RSE brauchst, baust Du’s einfach ein und was Du nicht brauchst, schmeißt Du raus. Ein Anruf beim Händler bestätigt: absolut kostenlos, steuerfrei und ohne Versicherungsbeiträge. Und der Clou: Du legst den Wagen einfach auf den Kopierer, und schon hast Du zwei, oder drei oder viele. Natürlich gibt es auch für diese Klasse im ganzen Land kostenpflichtige Werkstätten, wenn Du möchtest, auch mit elektronischem Wartungsgerät, jedoch kannst Du zusätzlich an den unzähligen Werkzeugverleihstationen kostenlose Werkzeuge bekommen. Und wenn Du ein Werkzeug verbesserst, kannst Du es, stolz wie Oskar, mit Deinem eingeprägten Namen dem Werkzeugverleih zurückbringen. Endlich hast Du das Gefühl, Du fährst Dein Auto und nicht Dein Auto Dich. Aber das klingt zu schön, um wahr zu sein, und Du glaubst, einer Sinnestäuschung oder einer unfassbaren Verschwörung erlegen zu sein, und so sparst Du schön weiter auf die teure Limousine.
Entdeckte ich letztens bei Recherchen nach Blender-Usern: Die Abteilung Computer Graphics der TU Braunschweig produzierte zusammen mit SYMBIZ SOUND (zwei koreanisch-deutsche Brüder aus Braunschweig) den Video-Clip „Who Cares“.