<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}
	
.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
<<importTiddlers>>
For my own 3d object loading framework I've tried few different triangulators. And after some test decided to stick to very simple ear-cutting algorithm. Ear is a three consecutive polygon vertices forming convex triangle which didn't contain any other polygon vertices inside it. In my implementation I always choose an ear with smallest edge (it's not only looks better then choosing first found ear but also produces more fillrate-friendly triangulation - see [[this post by Humus|http://www.humus.name/index.php?page=News&ID=228]] for more info).

Basic outline of algorithm looks like this:
{{{
// calculate average polygon normal:
vec3 average_n = vec3( 0, 0, 0 );
for( i = 1; i < num_verts; ++i )
	average_n += cross( v[i] - v[0], v[i+1] - v[0] );

// then calculate ear metric for each polygon vertex:
if( dot( cross( next_vertex - this_vertex, prev_vertex - this_vertex ), average_n ) > 0 
	&& no_other_vertices_in_tri( prev_vertex, this_vertex, next_vertex ) )
{
	// valid ear
	metric = length_squared( prev_vertex - next_vertex );
}
else
{
	metric = FLT_MAX;
}

// after that 'cut' ear triangle with lowest metric and update metric for it's prev_vertex and next_vertex
// repeat cutting until number of vertices is more then 3
}}}

And as optimization don't forget to create special case versions for triangles and quads since most polygons in 3d meshes rarely have more then four vertices.
Usually, vector transformation by quaternion is derived from v' = q * v * q^^-1^^ equation or just by converting to 3*3 matrix and then by regular matrix*vector multiplication. Both approaches produce too many operations. 
In many cases simpler form is possible: most often quaternion represent only rotation and have unit length. In this case transform can be expressed as a small GLSL function:
{{{
vec3 quat_transform( vec4 q, vec3 v )
{
	return v + 2.*cross( q.xyz, cross( q.xyz, v ) + q.w*v ); 
}
}}}
There is a useful extension NV_depth_clamp on NVIDIA cards. And if you want to use it but don't want to limit yourself to running only on NVIDIA cards you'll need a way to emulate it on other hardware.
Fortunately you can do it with shader code, here is example of such depth-only writing shader.
First, we clamp vertex clip coordinate in vertex shader:
{{{
#define DEPTH_CLAMP_NEAR
#define DEPTH_CLAMP_FAR

varying float Zwindow;

void main()
{
	vec4 clip = ftransform();
	
	// assuming default [0,1] glDepthRange parameters
	Zwindow = 0.5*clip.z/clip.w + 0.5;	
#if defined DEPTH_CLAMP_NEAR && defined DEPTH_CLAMP_FAR
	// clamp to both near and far
	clip.z = clamp( clip.z, -clip.w, clip.w );
#elif defined DEPTH_CLAMP_NEAR
	// clamp only to near plane, far is clipped
	clip.z = max( clip.z, -clip.w );
#elif defined DEPTH_CLAMP_FAR
	// clamp only to far plane, near is clipped
	clip.z = min( clip.z, clip.w );
#endif
	gl_Position = clip;
}
}}}

Second, we need to recalculate correct per-fragment window depth in fragment shader:
{{{
#define DEPTH_CLAMP_NEAR
#define DEPTH_CLAMP_FAR

varying float Zwindow;

void main()
{
#if defined DEPTH_CLAMP_NEAR && defined DEPTH_CLAMP_FAR
	gl_FragDepth = clamp( Zwindow, 0., 1. );
#elif defined DEPTH_CLAMP_NEAR
	gl_FragDepth = max( Zwindow, 0. );
#elif defined DEPTH_CLAMP_FAR
	gl_FragDepth = min( Zwindow, 1. );
#endif
}
}}}

Update: Patrick Cozzi from http://blogs.agi.com/insight3d/ noted what this won't work correctly in case of perspective projection, here is his comment:
<<<
I just wanted to let you know that a small modification is required for perspective projections.  Since varying variables are interpolated in a perspective correct fashion, Zwindow isn’t want you’d expect when it gets to the fragment shader.  On shader model 4 cards, this should be easy to correct by prefixing “varying float Zwindow” with “noperspective.”  This didn’t work on my Radeon HD 4350 – probably a driver bug.  But it is still possible to undo the perspective-correct part of the interpolation.  First multiple Zwindow by w in the vertex shader:
{{{
	Zwindow = (0.5 * (clip.z / clip.w) + 0.5) * clip.w;
}}}
Then multiple by 1/w in the fragment shader, for example:
{{{
	gl_FragDepth = min(Zwindow * gl_FragCoord.w, 1.0);  // really 1/w
}}}
<<<
Some time ago, then shader hardware can handle very limited number of instructions, I was making water waves shader for [[flower screensaver|http://www.rusteddreams.net/flower.html]]. Surface movement actually was a sum of 4 sine waves of different directions, periods and amplitudes. Result of cosine function is also needed to calculate normal of resulting surface. 

So I've just plugged glsl sin() function and everything was fine until I tried to run it on GeForce 3 card there it didn't fit into available number of instructions (this card didn't support native sin and cos instructions, so glsl compiler emulated them with some math).

Water waves didn't need that much precision in calculating trig functions so I decided to replace them with some coarse approximation.

There are many cases then you don't need exact function. And waves calculation is one such example: actually, sum of sine waves is just a 'fake' in same way as sum of any other functions (compared to real water surface simulation).

So lets look at basic Hermite curve: -2x^^3^^ + 3x^^2^^, it smoothly goes from 0 to 1 and if we scale and translate it a bit we get this: -4x^^3^^/pi^^3^^ + 3x^^2^^/pi. Now we have nice sine-like curve in [-pi/2, pi/2] range. 

Almost all sine approximation code examples use conditional branching to reduce range of input parameter for use with approximating functions. You can reproduce it with few step functions and multiply-adds in shader code but there is a more clever way: see [[this article|http://realtimecollisiondetection.net/blog/?p=9]] by Christer Ericson.

{{{
#define M_PI 3.14159265

float curve( float x )
{
	const float a = -4./(M_PI*M_PI*M_PI);
	const float b = 3./M_PI;
	return x*( x*x*a + b );
}

float range_reduce( float angle )
{
	float x = mod( angle, M_PI*2. );
	x = min( x, M_PI - x );
	x = max( x, -M_PI - x );
	x = min( x, M_PI - x );
	return x;
}

float sin_like( float angle )
{
	return curve( range_reduce( angle ) );
}

float cos_like( float angle )
{
	return sin_like( angle + M_PI/2. );
}
}}}
And don't forget you can calculate 4 values 'for free' just by replacing float with vec4. 
My implementation of [[Linear-Speed Vertex Cache Optimisation|http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html]] algorithm by [[Tom Forsyth|http://www.eelpi.gotdns.org/blog.wiki.html]].

It requires [[boost|http://www.boost.org]], but all used libraries are header-only, so you only need to add it's path to your compiler includes, building isn't necessary.

Usage example:
{{{
#include "acmr.h"
#include "ls_vcache_opt.h"

{
    std::vector<unsigned short> pos_indices;
    std::vector<my_vertex> vertices;

    //...

    float acmr_before = ls_vcache_opt::acmr( &pos_indices[0], pos_indices.size()/3, 16 );
    ls_vcache_opt::optimize( &pos_indices[0], pos_indices.size()/3, vertices.size() );
    unsigned short num_verts = ls_vcache_opt::reorder_vertices( &pos_indices[0], 
        pos_indices.size()/3, vertices );
    vertices.resize( num_verts );
    float acmr_after = ls_vcache_opt::acmr( &pos_indices[0], pos_indices.size()/3, 16 );
}
}}}

[[download source code|code/ls_vcache_opt.zip]]
[[About]] [[Products|http://www.rusteddreams.net]] [[RSS Feed|index.xml]]
.button{
border: none;
}

body{
font: 0.8em Verdana, Geneva, Arial, Helvetica, sans-serif;
color: #fff;
background-color: #333;
}
#site{
width: 900px;
margin: 16px auto;
text-align: left;
}
#header{
width: 100%;
height: 80px;
background: transparent;
font-size: 7pt;
}
#siteTitle{
padding: 5px 0 0 75px;
float: left;
margin: 0;
font-family: 'NP Naipol All in One', Verdana, Helvetica, sans-serif;
font-weight: bold;
font-size: 30px;
color: #4a3509;
background: url(images/corner_tl.gif)  no-repeat top left;
}
#topMenu{
float: right;
margin: 0;
background: url(images/corner_tr.gif)  no-repeat top right;
}
#topMenu a{
float: left;
width: 75px;
padding: 5px 10px 5px 10px;
margin: 0;
font-size: 7pt;
font-weight: normal;
text-align: center;
text-transform: uppercase;
text-decoration: none;
color: #4a3509;
background: transparent;
border-bottom: 2px solid #333;
border-left: 2px solid #333;
}
#topMenu a:hover{
color: #fc0;
background-color: #333;
}

#page{
float: left;
width: 100%;
padding: 0 0 16px 0;
background-color: #666;
line-height: 1.8em;
}
#page a{
text-decoration: none;
color: #fc0;
border-bottom: 1px solid #aaa;
}
#page a:hover{
color: #ddd;
background-color: #888;
}
#page .highlight, #page .marked{
background: #a7a13B;
text-decoration: underline;
}
#sidebar{
position: static;
overflow-x: hidden;
float: right;
width: 200px;
background: #777 url(images/corner_sub_tl.gif) no-repeat top left;
margin: 16px 0 0 0;
}
#sidebarOptions, #sidebarTabs{
margin: 0.96em 0.96em 0 0.96em;
}
#sidebar a{
border: none;
}
#sidebarTabs .tabContents{
width: 100%;
padding-left: 0;
padding-right: 0;
background: #777;
color: #fff;
border: none;
border-top: 1px solid #888;
}
#sidebarTabs .tabSelected, #sidebarTabs .txtMoreTab .tabSelected{
background: #666;
border:1px solid #888;
}
#sidebarTabs .tabUnselected{
background: #777;
border:1px solid #888;
color: #bba13b;
}

#sidebarEnd{
background: #777 url(images/corner_sub_bl.gif) no-repeat bottom left;
height: 10px;
}
#displayArea{
margin: 0;
float: left;
width: 686px;
margin: 16px 0 0 0;
background: #777;
}
#tiddlersStart{
background: url(images/corner_sub_tr.gif) no-repeat top right;
height: 10px;
}
#tiddlerDisplay{
}
.tiddler{
padding:0 0.96em 0 0.96em;
font-size: 1em;
margin-bottom: 1.8em;
}
.toolbar{
font-size: 0.8em;
margin-top: 0;
float: right;
}
#page .toolbar a{
border: none;
padding: 0 0.6em 0 0.6em;
color: #777;
}
#page .selected .toolbar a{
color: #aaa;
}
.title{
font-weight: bold;
font-size: 0.8em;
text-transform: lowercase;
color: #fc0;
border-bottom: 1px solid #aaa;
margin-top: 0;
}
#page .subtitle, #page .subtitle a{
color: #aaa;
border: none;
font-size: 0.8em;
margin:0.2em;
}
#page .tagging, #page .tagged, #page .selected .tagging, #page .selected .tagged{
border: 1px solid #888;
background: #555;
}
#page .tagging .listTitle, #page .tagged .listTitle, #page .selected .tagging .listTitle, #page .selected .tagged .listTitle{
color: #aaa;
}
#page .tagging .button, #page .tagged .button, #page .selected .tagging .button, #page .selected .tagged .button{
color:	 #888;
background: #555;
border: none;
}
#page .tagging .button:hover, #page .tagged .button:hover, #page .tagging .button:active, #page .tagged .button:active{
border: none;
background:transparent;
text-decoration:underline;
color:#333;
}
#page .viewer .button, #page .editorFooter .button{
color: #fc0;
border: 1px solid #888;
background: #555;
margin: 0 0.4em;
}
#page .viewer .button:hover, #page .editorFooter .button:hover, #page .viewer .button:active, #page .viewer .highlight, #page .editorFooter .button:active, #page .editorFooter .highlight{
color: #ddd;
background: #888;
border-color: #aaa;
}
#tiddlersEnd{
background: url(images/corner_sub_br.gif) no-repeat bottom right;
height: 10px;
}

.popup{
background: #333;
border: 1px solid #444;
}
.popup li.disabled{
color: #000;
}
.popup li a, .popup li a:visited{
color: #777;
border: none;
}
.popup li a:hover{
background: #333;
color: #ccc;
border: none;
}
.popup hr{
color: #777;
background: #777;
border-bottom: 1px;
}
.listBreak div{
border-bottom: 1px solid #777;
}

#messageArea{
border: 1px solid #ccc;
background: #555;
color: #777;
font-size:90%;
}
#messageArea .button{
color: #333;
background:#ccc;
border: 1px solid #ccc;
}
#messageArea .button:hover{
color: #ccc;
background: #333;
border-color: #333;
}

.viewer table, .viewer td{
border: 1px solid #888;
font-size: 0.95em;
}
.viewer th, thead td{
background: #555;
border: 1px solid #888;
color: #fc0;
font-weight: normal;
}
.viewer pre, .viewer blockquote{
border: 1px solid #888;
background: #555;
font-size: 0.95em;
}
.viewer code{
color: #ccc; 
background:#555;
}
.viewer hr{
border-top: dashed 1px #222; 
margin: 0 1em;
}
.editor input{
border: 1px solid #ccc; 
margin-top:5px;
}
.editor textarea{
border: 1px solid #ccc;
}

#footer{
width: 100%;
float: left;
font-size: 7pt;
text-transform: lowercase;
line-height: 2.6em;
color: #4a3509;
background: transparent;
}
#footerLeft{
float: left;
width: 60%;
padding-left: 16px;
text-align: left;
background: url(images/corner_bl.gif) no-repeat bottom left;
}
#footerRight{
float: right;
width: 35%;
text-align: right;
padding-right: 16px;
background: url(images/corner_br.gif) no-repeat bottom right;
}
#footer a{
color: #4a3509;
}
#footer a:hover{
color: #666;
}
.clearer{
clear: both;
}
<div id='site'>
	<div id='header' class='header' macro='gradient horiz #fc0 #777'>
		<div id='siteTitle' refresh='content' tiddler='SiteTitle'></div>
		<span id='topMenu' refresh='content' tiddler='MainMenu'></span>
	</div>
	<div id=page>
		<div id='sidebar'>
			<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
			<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
			<div id='sidebarEnd'></div>
		</div>
		<div id='displayArea'>
			<div id='messageArea'></div>
			<div id='tiddlersStart'></div>
			<div id='tiddlerDisplay'></div>
			<div id='tiddlersEnd'></div>
		</div>
	</div>
	<div id='footer' macro='gradient horiz #fc0 #777'>
		<div id='footerLeft'>&copy; 2008 rusted dreams</div>
		<div id='footerRight' refresh='content' tiddler='SiteSubtitle'>;)</div>
	</div>
	<div class="clearer"></div>
</div>
<<search>><<closeAll>><<permaview>><<newTiddler>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
graphics programming
rusted dreams
http://blog.rusteddreams.net/
[[About]]
I'm Ryhor Spivak, author of [[rusted dreams|http://www.rusteddreams.net]] projects, and this page is a collection of my graphics programming related code snippets, algorithm ideas and some random thoughts.

If you have any comments you can mail me: grisha ~~at~~ rusteddreams ~~dot~~ net
~~'Grisha' is another way to write my name, so don't be confused then you see it in code comments or other parts of site.~~
// //''Name:'' Blog
// //''Version:'' 0.1.1
// //''Author:'' [[Anshul Nigham|http://yavin4.anshul.info]] (adapted from an earlier plugin by [[ClintChecketts|http://www.checkettsweb.com/]]) 
// //Tag support given by [[Emmanuel Frécon|http://www.sics.se/~emmanuel/]]
// //''Type:'' Plugin
// //''Description:'' Posts the most recently edited tiddlers when the TiddlyWiki is opened, similar to a blog.
// //''Syntax:'' Change the daysOrPosts and numOfDaysOrPosts variables below
// // If daysOrPosts variable is "days", tiddlers from the past numOfDaysOrPosts dates will be displayed
// // If daysOrPosts variable is "posts", the past numOfDaysOrPosts tiddlers will be displayed 
// // The restrictTag variable contains the tag that all entries should contain
// // for appearing as blog entries. Other entries will not appear, except for
// // those coming from the the defaultTiddlers. If the variable is an empty
// // string, then the behaviour is the same version 0.1 (below).

// // ''Tested against:'' Tiddlywiki 2.1.3

// // ''HOWTO:'' Simply copy this entire tiddler and paste it into a new tiddler in your own tiddlywiki.
// // Tag it with systemConfig, and also with systemTiddlers if you don't want it to appear within the blog views. Name it anything you like

var daysOrPosts = "posts";
var numOfDaysOrPosts = "10";
var restrictTag = "blogentry";

function displayTopTiddlers()
{
	if(window.location.hash) daysOrPosts = "";
	if(daysOrPosts == "posts")
	{
		var tiddlerNames = store.reverseLookup("tags","systemTiddlers",false,"modified");
		if (tiddlerNames.length < numOfDaysOrPosts)
			numOfDaysOrPosts = tiddlerNames.length;
		for(var t = tiddlerNames.length-numOfDaysOrPosts;t<=tiddlerNames.length-1;t++)
      if (restrictTag == "" || tiddlerNames[t].isTagged(restrictTag))
		story.displayTiddler("top",tiddlerNames[t].title,DEFAULT_VIEW_TEMPLATE,false,false);
	}
	if (daysOrPosts == "days"){
		var lastDay = "";
		var tiddlerNames = store.reverseLookup("tags","systemTiddlers",false,"modified");
		var t = tiddlerNames.length -1;
		var tFollower = 0;
		for(t;t>=0;t--) if(numOfDaysOrPosts >= 0){
			var theDay = tiddlerNames[t].modified.convertToYYYYMMDDHHMM().substr(0,8);
			if(theDay != lastDay){
				numOfDaysOrPosts = numOfDaysOrPosts -1;
				lastDay = theDay;
				tFollower = t;
			}
		}

		for(tFollower = tFollower+1; tFollower < tiddlerNames.length;tFollower++){
      if (restrictTag == "" || tiddlerNames[tFollower].isTagged(restrictTag))
        displayTiddler("top",tiddlerNames[tFollower].title,DEFAULT_VIEW_TEMPLATE,false,false);
		}

	}
}

window.original_restart = window.restart;
window.restart = function()
{
	window.original_restart();
	displayTopTiddlers();
}