tag:blogger.com,1999:blog-77604072024-03-12T17:40:06.939-07:00The James StreamHere is where I present lessons learned, bits of code and rants related to technology.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-7760407.post-48429155547411063462014-06-28T12:34:00.002-07:002014-06-28T19:24:38.884-07:00OpenGL 4.4 and beyond on AndroidThings are changing so rapidly in mobile hardware that we are starting to enter an era where no longer will there a difference in feature sets or capabilities between what your phone can do, and what a high end PC can do. The difference will simply be how much power the chips are allowed to consume.<br />
<br />
Now, I don't want to sound like I am just blindly pushing our own chips here, but I believe Tegra K1 is an early glimpse of things to come, and probably not just from us, I expect the rest of the industry to follow eventually until developers can safely assume a relatively consistent feature set from PC down to mobile. K1 is just the first example, because the GPU core in it is <a href="http://en.wikipedia.org/wiki/Kepler_(microarchitecture)">Kepler</a>. And that is not just some marketing trickery, its actually same microarchitecture that powers crazy things like the GTX780. Over the last few years a lot of blood, sweat and tears went into making this possible. And while due to size, power and thermal constraints it <i>only</i> has 192 "cores" instead of 2304, it still smokes the competition perf wise, but more importantly its just in a completely different league when it comes to features as it is capable of full desktop class OpenGL 4.4, including geometry shaders, tessellation, compute, etc, plus extensions enabling things like <a href="https://developer.nvidia.com/content/bindless-graphics">bindless</a>!<br />
<br />
<a name='more'></a><br />
But Android only supports OpenGL ES, right? Actually, no! While the preferred and officially supported graphics API on Android today is OpenGL ES, you can already today create a "Big" OpenGL context on Android using EGL, that is, if your device supports it. This can be useful if you are porting over content from Windows/Linux/Mac/SteamOS that already has an OpenGL backend to get things up and running quickly as emulating things like clip planes, alpha test, or just the minor differences in the spec can make switching to GLES a bit of a pain. This can also serve as a great reference rendering backend to validate your port before the ES rendering path is up and running.<br />
<br />
And don't worry, you can ship GLES and BigGL side by side in the same app! Actually, its easy! Most of the important bits here are just in <a href="http://en.wikipedia.org/wiki/EGL_(API)">EGL</a>, which is the API Android exposes for OpenGL context creation. It is available through either Java or C/C++, but it is important to note this requires at least the 1.4 spec of EGL.<br />
<br />
First, before you create your context (or call any other EGL functions) its good to know which flavor of GL is supported on your current device. This can be done by simply calling "<span style="font-family: Courier New, Courier, monospace;"><a href="https://www.khronos.org/registry/egl/sdk/docs/man/html/eglBindAPI.xhtml">eglBindAPI</a>(EGL_OPENGL_API)</span>", which will switch EGL to desktop OpenGL mode and return <span style="font-family: Courier New, Courier, monospace;">EGL_TRUE</span>, or leave the state unchanged and return <span style="font-family: Courier New, Courier, monospace;">EGL_FALSE</span> if the current device doesn't support it. Because this function toggles a global state, the safest thing to do is make this the first EGL call you make and never call it again.<br />
<br />
Next comes context creation... if <span style="font-family: Courier New, Courier, monospace;">eglBindAPI</span>() failed to switch to BigGL mode then you create your ES context just as you did before, no changes necessary there, but if it succeeded, you can now <i>optionally</i> create a BigGL context! Luckily EGL makes this easy. Since we already called <span style="font-family: Courier New, Courier, monospace;">eglBindAPI(EGL_OPENGL_API)</span>, EGL is already set to BigGL mode so we only need to tweak a few things in our configuration and context attributes.<br />
<br />
First, in the configuration attributes which are passed into <span style="font-family: Courier New, Courier, monospace;"><a href="https://www.khronos.org/registry/egl/sdk/docs/man/html/eglChooseConfig.xhtml">eglChooseConfig</a></span>(), we need to make sure <span style="font-family: Courier New, Courier, monospace;">EGL_RENDERABLE_TYPE</span> is set to <span style="font-family: Courier New, Courier, monospace;">EGL_OPENGL_BIT</span> instead of <span style="font-family: Courier New, Courier, monospace;">EGL_OPENGL_ES2_BIT</span>.<br />
<br />
Second, in the attributes passed into <span style="font-family: Courier New, Courier, monospace;"><a href="https://www.khronos.org/registry/egl/sdk/docs/man/html/eglCreateContext.xhtml">eglCreateContext</a></span>() also need minor tweaking. Typically for an ES context you will set <span style="font-family: Courier New, Courier, monospace;">EGL_CONTEXT_CLIENT_VERSION</span> to 1, 2 or 3 depending on which version of OpenGL ES you want to target. For BigGL contexts this attribute isn't used, so don't set it. Infact you can actually get away with an empty attribute list on BigGL.<br />
<br />
Roughly speaking, this looks as simple as (ignoring error checking for brevity):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">if(eglBindAPI(EGL_OPENGL_API))</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> <span style="color: red;">// Create a BigGL context...</span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> EGLDisplay display = eglGetDisplay(...);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> eglInitialize(display, ...);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> const EGLint configAttrs[] =</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> EGL_SURFACE_TYPE, EGL_WINDOW_BIT,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> <span style="color: red;">// backbuffer attributes here...</span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> EGL_NONE</span><br />
<span style="font-family: Courier New, Courier, monospace;"> };</span><br />
<span style="font-family: Courier New, Courier, monospace;"> EGLConfig config;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> EGLint numConfigs = 0;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> eglChooseConfig(display, configAttrs, &</span><span style="font-family: 'Courier New', Courier, monospace;">config</span><span style="font-family: 'Courier New', Courier, monospace;">, 1, &numConfigs);</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> EGLint ctxAttrs[] =</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> {</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> EGL_NONE</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> };</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttrs);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">else</span><br />
<span style="font-family: Courier New, Courier, monospace;">{<br /><span style="color: red;"> // TODO: Fallback to old ES context creation...</span><br />}</span><br />
<br />
The final bit of the puzzle, and this is something I recommend for anyone using OpenGL or OpenGL ES no matter what platform they are on. But its especially important when toggling between APIs like this. And that is, don't implicitly link against and GL symbols! Even core functions you should use <a href="https://www.khronos.org/registry/egl/sdk/docs/man/html/eglGetProcAddress.xhtml"><span style="font-family: Courier New, Courier, monospace;">eglGetProcAddress</span></a>(), and be careful not to share function pointers between contexts. If you did something crazy like create a BigGL context and an ES context in the same application, functions like <span style="font-family: Courier New, Courier, monospace;">glDrawElements</span>(), which exist in both APIs may point to completely different implementations. This means you should only link against libEGL.so, and query all of your symbols through <span style="font-family: Courier New, Courier, monospace;">eglGetProcAddress</span>(). <b>Edit</b>: it should be noted that technically this requires "<span style="font-family: Courier New, Courier, monospace;">EGL_KHR_get_all_proc_addresses</span>" to be present for core functions to be available via <span style="font-family: Courier New, Courier, monospace;">eglGetProcAddress</span>(), but I believe this is now implemented in Android's common EGL interface so it should be driver independent, but it might not work on older versions of Android. But if you are considering supporting BigGL, you probably don't want to mess with devices old enough for this to be an issue anyways.<br />
<br />
<b>Important Note</b>: I strongly recommend that if possible, any shipping apps should also have a GLES rendering path. BigGL is useful for development, and even useful for getting at bleeding edge features, but having a GLES backend also helps Android avoid fragmentation and helps expose your app to as many users as possible.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com3tag:blogger.com,1999:blog-7760407.post-56772265410611797512014-06-27T11:00:00.001-07:002014-06-28T13:08:52.047-07:00Tegra Glass Fracture Demo<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://ytimg.googleusercontent.com/vi/YGPK__0Vnz0/0.jpg" height="266" width="320"><param name="movie" value="https://youtube.googleapis.com/v/YGPK__0Vnz0&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://youtube.googleapis.com/v/YGPK__0Vnz0&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
At <a href="https://www.youtube.com/watch?v=um6rMjwSNdU">GTC a few years back</a> I was tasked with taking a really cool GPU rigid-body + fracturing demo and making it look pretty for the keynote (something I always seem to get suckered into every year). I decided to trick it out with some fancy glass rendering, caustics, etc. Some of the techniques were invented just for the demo (how I came up with a way of using a geometry shader to do caustics probably involves a severe blow to the head I imagine). This demo ran on a high end PC with a GTX 690 in it.<br />
<br />
After that demo I started fiddling around with the idea of bringing it to Tegra. I actually rewrote everything with a keen eye on performance. Starting with Tegra 3 I was able to get the refraction/reflection actually working at around 30fps. Tegra 4 allowed me to hit 60fps and turn the shadows on (using a little mip-chain hack to achieve the penumbra). K1 though allows me to blow all that out of the water and bring the full experience of the PC version to mobile using desktop class OpenGL 4.4 feature set. And Nathan Reed took my crazy geometry shader for doing the caustics and added the even crazier use of the tessellator to make the caustics truly mind blowing and better than the original PC version.<br />
<br />
Anyways, the Tegra version of this demo didn't get a lot of attention, but we have shown it at our booth at a few trade shows, so figured it was time for the interwebs to get a taste.<br />
<br />
Continue reading for high resolution screenshots...<br />
<br />
<a name='more'></a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4ai__0V79NJFYfwRS3SsKn_q0X2G3bzJwmjo-QxDNGYXwLQwJuJPwroQCLmGNH83XaFJNQJp1sYLA7-raZg2c918Y6rlXBvz88L9PED3sGPktetdz_B848VAQ-_AIhvsKhFA/s1600/tegrafracture-monkey.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4ai__0V79NJFYfwRS3SsKn_q0X2G3bzJwmjo-QxDNGYXwLQwJuJPwroQCLmGNH83XaFJNQJp1sYLA7-raZg2c918Y6rlXBvz88L9PED3sGPktetdz_B848VAQ-_AIhvsKhFA/s1600/tegrafracture-monkey.png" height="250" width="400" /></a></div>
<br />James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com5tag:blogger.com,1999:blog-7760407.post-2243057334903943882014-06-20T21:04:00.000-07:002014-06-20T21:04:11.958-07:00Screen Space Surface Generation circa 2005<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/tPyhfFnsJQk?feature=player_embedded' frameborder='0'></iframe></div>
Early in 2005 at Ageia we were doing a lot of research into fluid dynamics using smoothed particle hydrodynamics. Because at the time we had not yet gotten chips back from the fab all of our test cases would be run in SW and then run marching cubes over them to generate a surface. We would then cache the output of marching cubes to disk and then stream it back later in real-time to give people an idea of what we thought we could do. The assumption was at the time that our hardware could generate these 3rd surfaces in real-time for tens of thousands of particles. Turns out, we could do SPH rather well, but marching cubes, not so much.<br />
<br />
When working on a cheesy little demo with John Ratcliff called "ageia carwash" I decided to try an idea that was bouncing around my head which was to render the particles as sprite that looked like the normals of a sphere, blur it a bit, then discard the post-blurred alpha below a particular threshold, apply some lighting and fake refraction in an attempt to create a GPU friendly real-time liquid surface. Personally I thought this first attempt was pretty good, but I couldn't convince everyone higher up the food chain that it was a reasonable compromise, but I was just a kid bad then and didn't push for the idea hard enough I guess :/<br />
<br />
Luckily Simon Green independently had the same idea at NVIDIA and has over time turned it into the goto method for rendering particle based liquids in real-time.<br />
<br />
Also around this time Matthias Müller, Simon Schirm and Stephan Duthaler had another novel technique called Screen Space Meshes (published in 2007, but I think they had this working much earlier than that), which did marching squares in 2D and then projected that back out into 3D. It was fast enough for real-time and could be run efficiently on our own hardware so thats the direction we went for a while, even ended up in a few games I think. But of course, eventually we ended up back at Simon's solution by the time acquisition came around.<br />
<br />
Anyways, this video was captured early in 2005 before we even added lighting in the demo and even featured our old logo.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com0tag:blogger.com,1999:blog-7760407.post-62755030029398189662014-06-20T17:27:00.001-07:002014-06-20T17:29:56.923-07:00Enabling color output with ccache+clang<div class="separator" style="clear: both; text-align: center;">
<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTzy8KzD26mJXR63VIomJpj9e2t6JPxPJvyYvBzMMKP404RTLEP5NJwlZgu1jk0ArEvNMZ0bBh2PWA11RIjczJ4Kdvv989_-pqsw6Y1TkzsQVfbXKMlo6o3_YGzqXseu2x714/s1600/clangwarnings.jpg" /></div>
Quick tip here...<br />
<br />
Typically when you compile with <a href="http://clang.llvm.org/">clang</a> you get some pretty sexy color coded error messages (as seen above). This is great and all, but if you are running through <a href="http://ccache.samba.org/">ccache</a> (which is awesome btw), then you will notice that you lose the hot color coding, which will probably make you sad. The problem isn't ccache stripping out the color coding exactly, its that clang is detecting that its not printing to a terminal that supports color (because its going through the ccache process which knows nothing about color).<br />
<br />
The fix is quite easy though, just pass "-fcolor-diagnostics" on the command-line to clang like so...<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">$(CCACHE) $(CLANG) -fcolor-diagnostics</span></blockquote>
...but what if you want to run your build through some sort of automated build system that then forwards the log to people via email or pipe it through some other system that doesn't understand color? Well I got a solution for that as well, just have your makefile check for color!<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">COLOR_DIAGNOSTICS = $(shell if [ `tput colors` -ge 8 ]; then echo -fcolor-diagnostics; fi)<br />$(CCACHE) $(CLANG) $(COLOR_DIAGNOSTICS)</span></blockquote>
In this case I check for a terminal that supports at least 8 colors.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com0tag:blogger.com,1999:blog-7760407.post-13100815394692366582014-06-20T17:05:00.004-07:002014-06-20T17:05:28.562-07:00Texture-Space Particle Fluid Dynamics<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/CajSLK1JUeY?feature=player_embedded' frameborder='0'></iframe></div>
In 2007 shortly before NVIDIA acquired Ageia I was working on an idea of running 2D SPH in UV space on arbitrary meshes. This was to do several things... 1) it allowed me to make a bunch of assumptions that would make surface generation faster and better, and 2) I could easily stain the surface that the particles were moving over which would give the feeling of greater volume and detail.<br />
<br />
It was fairly simple to implement, everything was in 2D so I used a world-space normalmap to compute which direction was up for each particle, and sampled a tangent-space normalmap to apply variable friction and modulate the staining function.<br />
<br />
This never got beyond weekend experiment status, but I did capture this video at some point to prove the concept kind of worked. Next steps would have been moving particles back and forth between 2D simulation and 3D simulation (so you could say poor water on the floor) and handle UV wrapping.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com1tag:blogger.com,1999:blog-7760407.post-16066501515103551412014-06-19T09:45:00.001-07:002014-06-20T21:27:34.467-07:00The story of "Killdozer"/"Flank"<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/97jkVgWSr2M?feature=player_embedded' frameborder='0'></iframe></div>
In 2006/2007 I had the crazy idea in my head for building a game based around super dynamic terrain. The idea was to not just "dent" the terrain like traditional deformable terrain, but to use some sort of "sleepy" fluid simulation to simulate multiple different materials like water, sand and dirt. I called this idea "project killdozer" because one of the ideas this would allow would be having bulldozers push dirt around.<br />
<br />
Then around 4 or 5 years ago Chris Lamb, Dane Johnston, and I were working on trying to make an RTS that would map equally as well on PC/Mac and Tablets in our spare time. Fundamentally that meant a Myth style RTS (no building, just combat), and a click-and-drag or touch-and-drag camera, and context aware interaction with units/items. But we eventually gave up on that particular project because our day jobs didn't allow enough time to ever really complete the vision so we moved onto something a bit simpler. We had only gotten to some basic prototyping phase of development before moving on, but I came across some video captures and thought it was time to share them. But while I didn't fully realize the "killdozer" dream before killing the project, that was where I was headed.<br />
<br />
With that said there was some pretty cool tech involved considering our target was iPad (although these videos were captured on PC).<br />
<br />
It used an engine that I have been fiddling with for the last 10 years or so as a hobby, never had really used it for much successfully though (never enough time to ship a game!), but because of that it actually had fairly mature tools and supported a wide range of platforms. I was also always totally obsessive about CPU performance so when mobile came around it really handled the transition quite easily.<br />
<br />
A layered terrain system that was deformable. This basically worked by layering different heightfields on top of each other each with different properties. Sand on top of dirt on top of bedrock, etc. This allowed the user to deform the level and change gameplay, but also allowed the level designer to place hard limits and obstacles in the environment.<br />
<br />
But probably the coolest thing was a GPU (using pixel shaders) volume conserving shallow water simulation. The idea was we wanted to plan for some cool events in the game like breaking dams to change the layout of the map in various ways during gameplay. Eventually my plan was to extend this simulation to the terrain itself, but never got around to it.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com0tag:blogger.com,1999:blog-7760407.post-28980481243010921652011-05-05T12:55:00.000-07:002011-05-05T13:06:08.504-07:00Pavlik Morozov Anti-PatternInteresting recent topic in a work skype chat...<br /><br /><blockquote><br /><span style="font-weight:bold;">[2:27:50 PM] Richard</span>: public Morozov must be what it is called in Russia because when I google that term all the results are in russian<br /><span style="font-weight:bold;">[2:28:18 PM] Richard</span>: I don't know why it is protected, the class is basically just a struct<br /><span style="font-weight:bold;">[2:28:23 PM] Feodor</span>: yes Richard, but I can tell you the story<br /><span style="font-weight:bold;">[2:28:46 PM] Feodor</span>: the story begins in the 20ies, right after the revolution in Russia<br /><span style="font-weight:bold;">[2:29:05 PM] Richard</span>: hehe<br /><span style="font-weight:bold;">[2:29:13 PM] Richard</span>: all the best C++ stories start with that line<br /><span style="font-weight:bold;">[2:35:07 PM] Feodor</span>: the boy because a central figure of the Soviet propaganda<br /><span style="font-weight:bold;">[2:30:07 PM] Feodor</span>: the socialist state required resources, first of all food to feed workers and soldiers, but the farmland was still privately owned and farmers demanded something for the food, like gold, while there was a hyperinflation of paper money<br /><span style="font-weight:bold;">[2:31:53 PM] Feodor</span>: the state decided to extract food by force, which resulted in a famine. Officially, it was disguised as a campaign against speculators who artificially drive commodities pries up<br /><span style="font-weight:bold;">[2:32:42 PM] Feodor</span>: so many people attempted to conceal some food, but the military used to kill everybody who attempted that<br /><span style="font-weight:bold;">[2:33:08 PM] Feodor</span>: so in this environment, there was a schoolboy and a young communist called Pavlik Morozov<br /><span style="font-weight:bold;">[2:33:33 PM] Feodor</span>: he knew his father concealed some flour in their farm<br /><span style="font-weight:bold;">[2:34:13 PM] Feodor</span>: and he summoned the soldiers and showed them the hiding place<br /><span style="font-weight:bold;">[2:34:19 PM] Feodor</span>: so his father was executed<br /><span style="font-weight:bold;">[2:34:37 PM] Feodor</span>: but his relatives reached him and killed the boy with an axe<br /><span style="font-weight:bold;">[2:35:07 PM] Feodor</span>: the boy because a central figure of the Soviet propaganda<br /><span style="font-weight:bold;">[2:35:24 PM] Feodor</span>: throughout the Soviet rule, his was portrayed as a hero<br /><span style="font-weight:bold;">[2:35:49 PM] Feodor</span>: and all schoolchildren were taught to praise him<br /><span style="font-weight:bold;">[2:36:15 PM] Feodor</span>: there were songs and books about him, memorials to him, there were streets named after him<br /><span style="font-weight:bold;">[2:36:30 PM] Feodor</span>: So, getting back to the 90ies<br /><span style="font-weight:bold;">[2:37:24 PM] Feodor</span>: there were lame Russian programmers who preferred to solve the problem of private methods by inheriting a class that opened them up<br /><span style="font-weight:bold;">[2:37:36 PM] Feodor</span>: and of course they remembered the story of Pavlik<br /><span style="font-weight:bold;">[2:38:15 PM] Feodor</span>: so inheriting a class to make private fields public was called "public Morozov" pattern<br /><span style="font-weight:bold;">[2:38:33 PM] Feodor</span>: because you actually make private things public, like Pavlik did<br /><span style="font-weight:bold;">[2:38:50 PM] Feodor</span>: protected, to be precise<br /></blockquote>James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com1tag:blogger.com,1999:blog-7760407.post-63402202240574927132009-10-18T17:44:00.000-07:002009-10-21T21:29:01.814-07:00Tangent Basis as a Quaternion<img style="display:block; margin:0px auto 10px; text-align:center; ;width: 400px; height: 146px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoex-99KkQvuQPTaKbH_BG_bAxGB5ROHlXkTrHdzi1aW7rxCOeJVzGoOhd6KHJw46_cYzK5ffZQNsZc0QR9m38ntvqRHxH0-hJRDRhy_7XL-GEUrEAHf-F1kLP7lZYu8wRwWA/s400/fract.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5395222806211478562" />Have not done perf testing on this much yet, but if you want to save some memory and bandwidth at the cost of a bit of maths try packing your normal+tangent basis into a quaternion instead. It might be a good option vs 8-bit normals. Can even compress the quat into 3 components too if you assume dot(q,q)=1 by negating the quaternion if w is negative which should work fine if its normalized. I suspect this could be a win for static geometry.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com0tag:blogger.com,1999:blog-7760407.post-52906698212230425952009-10-08T04:21:00.000-07:002009-10-08T16:42:37.099-07:00Color Coding Makefile Output<img style="display:block; margin:0px auto 10px; text-align:center;width: 400px; height: 142px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaZlmM2t_dS9lDfVaWHnxscPvjCbK530_rhYGYV-aTDCjGGsIcIY2blfFN-Wp2SZZxgT_JafO4TGONzo0bVL9oJLryPhX-qqJz_obDvzhbzc1wQYbzfDTNTk8bp2w0agtm6rk/s400/color_coded_make.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5390373580149303234" /><div style="text-align: left;">Quick useful tidbit... color coding makefile output...</div><div style="text-align: left;"><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo"></p><blockquote><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">NO_COLOR=\x1b[0m</p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">OK_COLOR=\x1b[32;01m</p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">ERROR_COLOR=\x1b[31;01m</p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">WARN_COLOR=\x1b[33;01m</p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; min-height: 13.0px"><br /></p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR)</p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR)</p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR)</p></blockquote></div>You can then echo out $(OK_STRING), $(ERROR_STRING) or $(WARN_STRING) depending on if errors were encountered. Errors are <span class="Apple-style-span" style="color:#FF0000;">Red</span>, Warnings are <span class="Apple-style-span" style="color:#FFFF33;">Yellow</span>, Success is <span class="Apple-style-span" style="color:#33CC00;">Green</span>. If you want to know what the goofy strings like "\x1b[32;01m" actually mean, well it really should be obvious, duh! But in case you can't decode that enigma of a color coding scheme you can <a href="http://www.cyberciti.biz/faq/bash-shell-change-the-color-of-my-shell-prompt-under-linux-or-unix/">read about it here.</a><div><br /></div><div><a href="http://www.cyberciti.biz/faq/bash-shell-change-the-color-of-my-shell-prompt-under-linux-or-unix/"></a>The only tricky bit then is just conditionally echoing the right string. Personaly I found the easiest way is to use temporary files to determine if the build was a success or had errors/warnings . But maybe there is a cleaner solution that doesn't require temp files? <div><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo"></p><blockquote><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">@$(ECHO) -n compiling debug foo.cpp...</p><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo"><br /></p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">@$(CXX) $(CFLAGS) -c foo.cpp -o $@ 2> temp.log || touch temp.errors</p><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo"><br /></p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">@if test -e temp.errors; then $(ECHO) "$(ERROR_STRING)" && $(CAT) temp.log; elif test -s temp.log; then $(ECHO) "$(WARN_STRING)" && $(CAT) temp.log; else $(ECHO) "$(OK_STRING)"; fi;</p><p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo"><br /></p> <p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo">@$(RM) -f temp.errors temp.log</p></blockquote></div>For those that don't like writing makefiles explicitly, <a href="http://sourceforge.net/projects/xpj/">XPJ</a> currently supports this color coding mechanism and leaves the OK/ERROR/WARN strings defined in the user specified platform file so you can alter the colors or disable them entirely.</div>James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com3tag:blogger.com,1999:blog-7760407.post-80509542869155937512009-10-02T16:25:00.000-07:002009-10-02T17:32:34.190-07:00Eye Candy: GTC Demos<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRsHK5xa_yoCvA71ezELbAd8nznWprnaIET0GcA0DZ03AV8PoH0QhTbOnbM1PgOD0JenZIdaNontyfw3L2qvDDiXp_Z_beIiDcdWBdsZabVZyXfwZn17cjFCJ64G99dh2U0Kg/s1600-h/destructiondemo.png" style="text-decoration: none;"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 222px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRsHK5xa_yoCvA71ezELbAd8nznWprnaIET0GcA0DZ03AV8PoH0QhTbOnbM1PgOD0JenZIdaNontyfw3L2qvDDiXp_Z_beIiDcdWBdsZabVZyXfwZn17cjFCJ64G99dh2U0Kg/s400/destructiondemo.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5388163049170167058" /></a>Here are some videos of the tech demos used during the GPU Technology Conference Keynote this year which were all simulated and rendered live in real-time. Our goal was to take the bits of tech we were each working on and produce a small demo of it to give the audience a taste. All the demos were presented in 3D Stereo and looked amazing. So, in order of appearance...<div><b><span class="Apple-style-span" style="font-weight: normal;"><br /></span></b></div><div><div><div>- <a href="http://www.youtube.com/watch?v=r17UOMZJbGs">Simon Green made an excellent demo of fluid dynamics</a>.</div></div></div><div><div>- <a href="http://www.youtube.com/watch?v=GftUpfrX9qQ">Sarah Tariq made a pretty kick ass demo showing off the turbulence</a> (sorry for the really poor video, a better one will be posted soon I am sure).</div></div><div>- <a href="http://www.youtube.com/watch?v=N1FOnpzUzZY">And I made a demo showcasing physical destruction with some comedic relief</a>.</div>James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com0tag:blogger.com,1999:blog-7760407.post-47311141315070115302009-09-04T18:10:00.000-07:002009-09-04T18:14:06.665-07:00stb_truetype: my experiments<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA81DNmwa1Z6bfg4UUmUkwhFIVL4zCdS0gen4i7KznNzLYt9mAuwWDLz_dcjnSbOz41cP45aIiOb_ies2IzqtHUO07TyAKhDsYh9843aiuUmhpVThqp34JY_HxJ_zpIu7gy_o/s1600-h/compare.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 67px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA81DNmwa1Z6bfg4UUmUkwhFIVL4zCdS0gen4i7KznNzLYt9mAuwWDLz_dcjnSbOz41cP45aIiOb_ies2IzqtHUO07TyAKhDsYh9843aiuUmhpVThqp34JY_HxJ_zpIu7gy_o/s400/compare.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5377731951666491138" /></a><br /><span style="font-style:italic;">(Blogger scaled the image down slightly so click to enlarge)</span><br /><br />Recently I discovered that <a href="http://www.nothings.org/">Sean Barrett</a> has put up on his website a nice little True Type font rasterizer. The keyword here being "little", compared to <a href="http://www.freetype.org">FreeType</a> its microscopic with less than 1600 lines of source code in a single file. FreeType on the other hand is about 6.5MB of just source code... I have worked on games with less source code! So the possibility of tossing out that much bloat is really appealing to me.<br /><br />Anyways upon finding this I quickly tossed it into my hobby project game engine to compare performance/memory/quality to FreeType with the assumption that it is probably faster, probably thrashes memory less and quality is probably roughly the same. Here are my discoveries:<br /><br /><span style="font-weight:bold;">Performance</span><br />This was a big shocker to me... FreeType was a good 3 times faster than stb_truetype at rasterizing a font of about 350 characters at height=14 pixels 8ms vs 26ms... thats almost double a single frame's budget! Granted usually you rasterize fonts once during loading and if you only have 1 or 2 fonts this is probably a non-issue, but if you have lots of fonts and supporting asian localizations this could potentially add seconds to your load time and that might be a deal breaker if you are already barely squeezing into TRC load time requirements. If you are dynamically caching fonts (like because you support rich text or something) this could be make it quite difficult to keep performance up. Luckily in my situation though I am pre-baking my fonts in my tools chain not at load time so performance isn't quite a deal breaker but I would prefer not pre-bake if performance was good enough. One thing to note is that in stb_truetype I was able to set it up to rasterize directly into locked texture memory whereas FreeType has no such API so I have to rasterize and then blit into texture memory so in a way FreeType was given a small handicap already.<br /><br /><span style="font-weight:bold;">Memory</span><br />Because I rasterize glyphs one by one the peak memory consumption for both FreeType and stb_truetype is quite low (just a few KB). But the number of allocator calls for both is quite high. Oddly enough again stb_truetype hammers on the allocator more making ~8,000 allocations versus FreeType's ~3,000 for the same font. Neither particularly makes me happy as a runtime solution. But the good news here is that while I would not want to touch FreeType's source code with a 10 foot pole, looking around in stb_truetype's source I believe I could stick in a relatively small fixed size pool and make stb_truetype run without any allocations of its own. So there is actually quite a bit of hope here.<br /><br /><span style="font-weight:bold;">Quality</span><br />Quality of stb_truetype isn't terrible but its not great either. FreeType comes off much cleaner and more closely matches the way Windows rasterize the same font. stb_truetype always comes off a bit bolder than it should be, a bit blurrier and a few artifacts like some characters being 50% transparent. Overall I think quality is probably acceptable for games and tools, but I wouldn't be shocked to have a few artists complain about it looking different than it does in Windows.<br /><br /><a href="http://digestingduck.blogspot.com">Mikko Mononen</a> brought up <a href="http://www.codinghorror.com/blog/archives/000884.html">www.codinghorror.com/blog/archives/000884.html</a>. I am not so sure yet if the differences are within the same threshold or not, but I suppose its possible the quality is no more different than OSX vs Windows (which, btw I think fonts look better in OSX).<br /><br /><span style="font-weight:bold;">Final Verdict</span><br />I am not quite ready to toss out FreeType yet, but I am awfully tempted. I think all the issues with stb_truetype can be resolved without too much effort so I fully expect to be giving FreeType the boot eventually.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com1tag:blogger.com,1999:blog-7760407.post-42347217519371033622009-09-04T14:23:00.000-07:002009-09-04T14:27:32.211-07:00So I might try this blogging thing againSo I decided I might try this blogging thing that all the cool kids are doing again, but this time instead of trying to ramble on about my day to day life which is not particularly interesting I figured I would use this as an outlet for my ramblings on technology, algorithms and random bits of code.James Dolanhttp://www.blogger.com/profile/14788855313245104425noreply@blogger.com0