<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>kometbomb &#187; Programming</title> <atom:link href="http://kometbomb.net/category/programming/feed/" rel="self" type="application/rss+xml" /><link>http://kometbomb.net</link> <description>Journal of my adventures in Programming, the Internet and Life.</description> <lastBuildDate>Wed, 16 Jun 2010 14:56:50 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.0.1</generator> <item><title>An Alternative to XML</title><link>http://kometbomb.net/2010/02/28/libconfig/</link> <comments>http://kometbomb.net/2010/02/28/libconfig/#comments</comments> <pubDate>Sun, 28 Feb 2010 15:42:06 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[Webfinds]]></category> <category><![CDATA[API]]></category> <category><![CDATA[C]]></category> <category><![CDATA[Libraries]]></category> <category><![CDATA[XML]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=701</guid> <description><![CDATA[XML can be overkill or simply cumbersome to edit manually for example when used in configuration files. Or, it may simply be unavailable for the preferred platform. Here's a great alternative.]]></description> <content:encoded><![CDATA[<p>My new weapon of choice. <strong><a
href="http://www.hyperrealm.com/libconfig/">libconfig</a></strong> is a configuration file parser that supports arrays, named and typed members, selection by path (e.g. <tt>cfg.users.[3].name</tt>) and more. That is, it has basically all the useful (as in 80% of cases) features of XML and none of the bad. There&#8217;s a minimal but well defined structure that will work for most situations and that can be used to enforce e.g. all array items having to be of the same type. There&#8217;s no overkill markup so it&#8217;s easy to read and write by humans. The library can also write the settings tree into a text file.</p><p>The configuration files look like this:</p><pre class="brush: plain;">screen = { width = 300; height = 200; }
users = ( { name = &quot;Torgo&quot;; items = [ &quot;Item 1&quot;, &quot;Item 2&quot; ]; } );</pre><p>And in C you would do something like this:</p><pre class="brush: cpp;">int screen_height = 100;
const char *name;
config_init(&amp;cfg);
config_read_file(&amp;cfg, &quot;config&quot;);
if (!config_lookup_int(&amp;cfg, &quot;screen.height&quot;, &amp;screen_height))
  puts(&quot;Using default screen height&quot;);
if (config_lookup_string(&amp;cfg, &quot;users.[0].name&quot;, &amp;name))
  puts(name);
config_destroy(&amp;cfg);</pre><p>You can also iterate the setting tree without the path for easier array or tree traversal. In all, I would say it involves less work compared to any XML library, especially in C. I like to think it&#8217;s a good example of software designed by the same guy who also uses it and not by some external committee.</p><ul><li><a
href="http://www.hyperrealm.com/libconfig/">Homepage</a></li><li><a
href="http://www.hyperrealm.com/libconfig/test.cfg.txt">An example config file</a></li></ul><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2008/03/21/a-tiny-xml-parser/" title="A Tiny XML Parser">A Tiny XML Parser</a></li><li><a
href="http://kometbomb.net/2009/09/22/introducing-my-latest-projects/" title="Introducing My Latest Projects">Introducing My Latest Projects</a></li><li><a
href="http://kometbomb.net/2008/02/24/google-chart-api-is-pretty-cool/" title="Google Chart API is pretty cool">Google Chart API is pretty cool</a></li><li><a
href="http://kometbomb.net/2007/11/07/what-exactly-does-gcc-optimize/" title="What exactly does GCC optimize?">What exactly does GCC optimize?</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/" title="Creating a Simple GUI from Scratch">Creating a Simple GUI from Scratch</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2010/02/28/libconfig/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Creating a Simple GUI from Scratch</title><link>http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/</link> <comments>http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#comments</comments> <pubDate>Thu, 31 Dec 2009 14:27:20 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[C]]></category> <category><![CDATA[GUI]]></category> <category><![CDATA[SDL]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=695</guid> <description><![CDATA[More often than not, the biggest obstacle for a programmer is adding a GUI to a otherwisely ready application. This probably is because you generally can create a program that inputs and outputs text with a few lines of code in any language. ]]></description> <content:encoded><![CDATA[<div
class="toc"><ol><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-introduction">Introduction</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-how-to-do-it">How to do it</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-solutions-to-common-problems">Solutions to common problems</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-faq">FAQ</a><ol><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-i-absolutely-need-a-separate-window">I absolutely need a separate window</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-is-this-reusable">Is this reusable?</a></li></ol></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/#toc-conclusion">Conclusion</a></li></ol></div><h3 id="toc-introduction">Introduction</h3><p>More often than not, the biggest obstacle for a programmer is adding a GUI to a otherwisely ready application. This probably is because you generally can create a program that inputs and outputs text with a few lines of code in any language. However, if you don&#8217;t count <tt>MessageBox()</tt> and other similar helper APIs that are available in most windowing systems and that are as simple to use as <tt>gets()</tt> and <tt>printf()</tt>, it&#8217;s a unnecessarily big step to change a command line program into a program that outputs the exact same text but with complex command line arguments replaced by a few buttons and a window with the outputted text.</p><p>However, if you are developing a program that already draws something on the screen, it&#8217;s really easy to add simple mouse interactivity. This is especially true if you are using SDL (even if it&#8217;s <em>extremely</em> bare bones in these things!) and already use <tt>SDL_rect</tt> (your standard rectangle) to draw things. You can simply change the draw routine so that it takes one more argument which would be the <tt>SDL_event</tt> struct you&#8217;re already using to check for a quit message and so on. Then for every object you are drawing on screen, check if the event if a mouse button down event and that the coordinates are inside the rectangle that will be drawn. This eliminates completely the need for having to plan a separate system that interprets the mouse events. It&#8217;s sort of piggybacking on the existing code with minimal changes to the existing code.</p><p>Now, you might already think that is way too simplistic and lazy but think again. Not many programs need a more complex GUI with multiple movable windows and so on. If you really do need that, then be my guest and create a exhaustive windowing system or take the time to learn an existing system. But it is still overhead and you have to do comparatively a lot of work before any real results. At least I hate that kind of mental overhead. And while this whole idea of combining the drawing and the event processing sounds like a bit of a hack, it really isn&#8217;t a &#8220;hack&#8221; as in patching something you will probably have to replace with a better solution later. It&#8217;s just a different way of doing almost the same thing. With <em>less overhead</em>.</p><p>I have used this approach in <a
href="http://code.google.com/p/klystrack/">my latest project</a> and from direct experience I know it is possible to create scrollbars, scrolling text fields, text input fields, message boxes and pretty much anything I have needed. And it&#8217;s not too much code either even if you have to create absolutely everything from nothing. In other words I do not feel limited or burdened.</p><h3 id="toc-how-to-do-it">How to do it</h3><p>As explained above, you most likely are drawing to a specific region on the screen for every object you need to check for mouse clicks. It is not necessary to have any kind of array where those regions are. You need to make sure that for every mouse click event runs the draw loop once and that the mouse click event gets passed to the draw routine. Then check if the coordinates are inside the draw region.</p><p>This is where the part starts that it admittedly gets a bit hacky: if a button is pressed, the event that the button triggers will be run in the middle of the draw loop (unless you somehow buffer the events). In most cases this doesn&#8217;t matter at all but it could be that what is on the screen is not exactly how it really is; you might have two selected items for a duration of one frame and so on. For the most part this doesn&#8217;t matter since you are getting results with very little overhead.</p><p>Consider this example.</p><pre class="brush: cpp;">void draw_stuff()
{
  SDL_Rect position = {10, 10, 40, 40};

  SDL_BlitRect(button_gfx, NULL, screen, &amp;position);
}

void draw_stuff_and_check_events(SDL_Event *event)
{
  SDL_Rect position = {10, 10, 40, 40};

  if (event-&gt;type == SDL_MOUSEBUTTONDOWN
   &amp;&amp; event-&gt;button.x &gt;= position.x
   &amp;&amp; event-&gt;button.y &gt;= position.y
   &amp;&amp; event-&gt;button.x &lt; position.x + position.w
   &amp;&amp; event-&gt;button.y &lt; position.y + position.h)
     button_event();

  SDL_BlitRect(button_gfx, NULL, screen, &amp;position);
}

void event_loop()
{
  SDL_Event event;

  while (SDL_PollEvent(&amp;event))
  {
    if (event.type == SDL_QUIT) break;

    draw_stuff(&amp;event);
  }
}</pre><p>From the above example, the benefits of this approach are obvious. The event checking can simply be injected anywhere in the code as long as you have the event and a region.</p><h3 id="toc-solutions-to-common-problems">Solutions to common problems</h3><p>One downside in this is that if you draw multiple overlapping regions, the region drawn last will be the one that is visible on the screen but the click is handled by the first region. Our event checking sees the regions from the other side of the screen. In such cases you can first iterate the regions in reverse order checking the event and then draw them in the correct order. An example in the mentioned project is the menu, submenus often overlap the parent menu; I solved that by first going through the menus in the order the user sees them and then drawing them back to front.</p><p>Dragging items is easy: simply check for mouse motion events and if the button is held down and the mouse is moved, just adjust the position of the matching region. You do not need any special &#8220;drag starts now&#8221; and &#8220;drag ends now, update objects&#8221; phases. However, this simplistic method is subject to the previous issue if you move a region over one that seems to be under it. You can also simply record the clicked object when the mouse button is pressed and make the motion events match only the selected region.</p><h3 id="toc-faq">FAQ</h3><h4 id="toc-i-absolutely-need-a-separate-window">I absolutely need a separate window</h4><p>This is possible as long as the window can be modal (like a message or open file dialog that takes over from the window behind it). You simply jump to another event loop until the new window is closed, much like it&#8217;s done in the Windows API with <tt>GetOpenFileName()</tt> or the <tt>MessageBox()</tt> mentioned earlier. Then it&#8217;s just a matter of drawing the new window and checking for the events normally.</p><h4 id="toc-is-this-reusable">Is this reusable?</h4><p>Of course. You could create a small library that has basic functionality and helper functions. <a
href="http://code.google.com/p/klystron/source/browse/#svn/trunk/src/gui">A practical example can be seen here</a>.</p><p>Even if you can use the event checking straight in the source code, you can still define the regions in an array and link to relevant event handlers.</p><h3 id="toc-conclusion">Conclusion</h3><p>Combining the drawing and the event processing code can save time in the short term. Many common GUI elements are perfectly possible to replicate. The idea described above should be considered if a project needs mouse interaction and external libraries are not available, the conversion of existing code seems expensive or the learning curve is too steep compared to the future benefits. Nonetheless, in borderline cases, it can be well worth prototyping due to the minimal overhead and developing considerations.</p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2010/02/28/libconfig/" title="An Alternative to XML">An Alternative to XML</a></li><li><a
href="http://kometbomb.net/2009/09/22/introducing-my-latest-projects/" title="Introducing My Latest Projects">Introducing My Latest Projects</a></li><li><a
href="http://kometbomb.net/2009/07/19/opengl-static-arrays-and-glmaterialfv/" title="OpenGL, Static Arrays and glMaterialfv">OpenGL, Static Arrays and glMaterialfv</a></li><li><a
href="http://kometbomb.net/2008/08/19/out-of-memory/" title="Out of Memory?">Out of Memory?</a></li><li><a
href="http://kometbomb.net/2008/04/22/blog-experiment-desaturating-and-resizing-images/" title="Blog Experiment: Desaturating and resizing images">Blog Experiment: Desaturating and resizing images</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Plenty of Room, Part II</title><link>http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/</link> <comments>http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/#comments</comments> <pubDate>Mon, 09 Nov 2009 16:47:17 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[256B]]></category> <category><![CDATA[Algorithms]]></category> <category><![CDATA[Assembly]]></category> <category><![CDATA[Demoscene]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[Source code]]></category> <category><![CDATA[Tutorial]]></category> <category><![CDATA[Video]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=128</guid> <description><![CDATA[As stated earlier, tiny intros written in assembly language fascinate me. I have written a few in x86 assembly language, here's one of them. I have tried to make the inner workings of the program as accessible -- or, at least as thought-provoking -- as possible even if assembly wasn't their weapon of choice. ]]></description> <content:encoded><![CDATA[<p
style="border:1px #eee solid;padding:2px;background-color:#f8f8f8;font-size:11px">This is the second part of the epic (<del
datetime="2009-11-09T13:46:36+00:00">two</del> three-part) series of articles about tiny intros, <a
href="http://kometbomb.net/2007/10/22/theres-plenty-of-room-at-the-bottom/">the previous part was an essay about 256-byte intros in general</a>.</p><p><em><strong>Ed. note:</strong> Since this article seems to take forever to finish, here&#8217;s the first half of it. The (hopefully) final part will detail more of the specifics.</em></p><p><img
src="http://kometbomb.net/wp-content/uploads/2009/11/rubba.png" alt="rubba" title="rubba" width="320" height="199" class="alignright size-full wp-image-649 iradius8" /> As stated earlier, tiny intros written in assembly language fascinate me. I have written a few in x86 assembly language, here&#8217;s one of them. I have tried to make the inner workings of the program as accessible &#8212; or, at least as thought-provoking &#8212; as possible even if assembly wasn&#8217;t their weapon of choice.</p><p>I&#8217;ve included the original DOS intro (you can use <a
href="http://dosbox.sourceforge.net/">DOSBox</a> to run it, it should also work on Windows XP) and a Win32 port of it, written in C while trying to keep the original structure intact. I&#8217;ll also try to explain the general idea of the effect in pseudocode where syntax can be an obstacle. The archive <a
href='http://kometbomb.net/wp-content/uploads/2009/11/rubba_c.zip'>rubba_c.zip</a> contains the source code, <kbd>rubba_b.exe</kbd> which is the compiled Win32 executable and <kbd>RUBBA.COM</kbd> which is the 16-bit MS-DOS executable. To compile the C program, you need the <a
href="http://sourceforge.net/projects/tinyptc/">TinyPTC library</a> (like SDL but even more bare-bones).</p><p>I won&#8217;t go into details about x86 assembly language, I suggest anyone interested first reads an introduction and <a
href="http://homepage.mac.com/randyhyde/webster.cs.ucr.edu/index.html">learns some of the basics</a>. However, I&#8217;ll try to make the code look interesting, explain some weird or obfuscated code and probably show some basic size optimization tricks.</p><div
class="toc"><ol><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/#toc-the-effect">The Effect</a></li><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/#toc-the-code">The Code</a><ol><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/#toc-initialization">Initialization</a></li><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/#toc-the-main-loop">The Main Loop</a><ol><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/#toc-self-modifying-code">Self Modifying Code</a></li></ol></li></ol></li></ol></div><h3 id="toc-the-effect">The Effect</h3><p>The intro, called <b>rubba_b</b>, shows one effect: a twisting bar drawn using primitive light-shaded texture mapping. The color palette and the texture are generated run-time. The texturing is done using linear interpolation and no vector math is used even if the bar looks like it is rotated. The lighting is an extremely simple approximation of the light source being exactly where the camera is located. That is, the length of the textured line directly determines the light.</p><p>If looked from above, the bar will be a tower of squares. If one of the squares is rotated around the center, the corners will move in a circular pattern. So, the X coordinate will be equal to <tt>cos(corner_number*(360 degrees/4)+square_rotation)</tt>, the Z coordinate (why Z? Because it goes towards the screen) is equal to the sine but it can be discarded because we will not need it for perspective calculation. Remember, we&#8217;re short on bytes.</p><p>We then modulate the bar rotation for each square in the tower. If the amount of rotation changes when moving up or down the tower, the bar will twist. If the rotation stays the same for each square, the bar will rotate uniformly and look uninteresting.</p><p>The textured horizontal line is drawn from each corner to the next corner, from left to right. If the line would be drawn from right to left, we know it isn&#8217;t facing towards the camera, another line facing the camera will be drawn over it and we simply skip the line. The color value fetched from the texture is multiplied by the line length which makes short lines darker.</p><p>Still with me?</p><h3 id="toc-the-code">The Code</h3><h4 id="toc-initialization">Initialization</h4><p>First things first. We need to set the video mode before we continue. In the Win32 version we simply open a TinyPTC window, in the original version we need to tell BIOS to go in a nice 320x200x8 video mode (the <em>de facto</em> video mode back in the day).</p><table><tr><td><strong>C</strong></td><td><strong>asm</strong></td></tr><tr><td><pre><code>ptc_open("rubba_b",320,200)</code></pre></td><td><pre><code>mov al,13h
int 10h</code></pre></td></tr></table><p>In the above code, the Win32 part is self-explanatory. The assembly bit probably needs some clarification: we put  the number <strong>13h</strong> (hex) in the 8-bit register <strong>al</strong> and we request for interrupt <strong>10h</strong>. This is the BIOS video interrupt and since register <strong>ax</strong> (which consists of <strong>al</strong> &#8211; &#8220;low&#8221; &#8211; and <strong>ah</strong> &#8211; &#8220;high&#8221;) equals to <strong>0013h</strong> (when the program starts, <strong>ax</strong> is always zeroed), BIOS will call the routine for changing the video mode (<strong>ah</strong>=<strong>00h</strong>) to <strong>13h</strong>.</p><p>If above sounds complicated, don&#8217;t worry. It&#8217;s just a matter of memorization &#8211; similar to how you would memorize the function name for changing the video mode.</p><p>The next thing we need is some space for the texture, the sine table and the double buffer. In the Win32 version this is obvious, we just add a few arrays (although since TinyPTC only supports 32-bit video modes, we will also have an array for the palette). Again, in the assembly version we won&#8217;t use any fancy way to reserve memory to save some precious bytes: we simply decide certain areas of the memory will be used for whatever we want. The benefits of no memory protection and single tasking. ;)</p><table><tr><td><strong>C</strong></td><td><strong>asm</strong></td></tr><tr><td><pre><code>short int sinetab[SINETAB];
unsigned char palette[256*4];
unsigned char texture[256*256];
unsigned char screen[320*200];</code></pre></td><td><pre><code>mov dh,80h
mov gs,dx
mov dh,70h
mov es,dx
mov dh,60h
mov fs,dx</code></pre></td></tr></table><p>The assembly version basically sets the register <strong>dx</strong> to <strong>60xxh-80xxh</strong> (we set only the high byte, i.e. <strong>dh</strong> to save bytes, thus the low byte of <strong>dx</strong> is undefined &#8211; it won&#8217;t matter) and puts the value into various segment registers (<strong>es-gs</strong>).</p><p>This makes it so that if we use the different segment registers, we can access each of the three 64 kilobyte segments as a 64 kilobyte array. E.g. the sine is in <strong>gs</strong>, thus <tt>mov ax,[gs:2]</tt> would move the second word in the sine table in <strong>ax</strong>. In C, the equivalent would be <tt>short int value=sinetab[1]</tt> (note how the C compiler knows the fact that a word is 2 bytes but in assembly you have to take care of that yourself &#8211; all memory accesses are always by the exact location, not the array element!).</p><p>All this is because in 16-bit memory accessing you can see only 64 kilobytes at one time. You can&#8217;t have a 128 KB array, nor can you have two 64 K arrays in the same segment. It&#8217;s something comparable to having a flashlight and a big sheet of paper in a dark room; you can move the light to show different areas but you will never see more than what there is in the spotlight.</p><p>The next two parts calculate the sine table (back in the day you simply could not do trigonometric stuff real-time, even in hardware &#8212; although in the intro it&#8217;s there just for show) and set the palette. This is pretty straight-forward stuff across the two versions. The only difference is that in the Windows version we have to remember the palette has 8-bit color components and the original has 6-bit components (0..255 ~ 0..63). And of course, the Windows version simply puts the values in a palette look-up table (because 32-bit video mode doesn&#8217;t use a palette) and the original actually sets the video mode colors.</p><p>I won&#8217;t reiterate the source code for the sine table and palette change here, I think you should be able to figure it out by comparing the source code. But in theory, here&#8217;s how to change a color: first, write the color index in port <strong>3C8h</strong>, then write the three color components in port <strong>3C9h</strong> (hint: <strong>dx</strong> first contains <strong>3C8h</strong> and it&#8217;s incremented to <strong>3C9h</strong> to save bytes).</p><p>The sine routine increases the angle (<b>st0</b> the topmost register on the FPU) by <strong>2*PI/32768</strong> (a full circle is 2*PI, the sine table has 32768 elements). You probably should check some FPU tutorial, arithmetic on the 8087 is pretty interesting due to the stack-based architecture. For example, you first push in two numbers and then do an add, which (in most cases) pops out the two values and pushes in the result.</p><p>The texture generation bit is interesting. It also was annoying to port to C thanks to the fact you have to emulate how some instructions work &#8211; there are no accurate analogies in the C standard. A big thanks goes to <strong>baze</strong> whose code I originally cannibalized for this (I think). To be honest the conversion doesn&#8217;t work 100 % accurately but does still produce a nice texture.</p><p>The algorithm uses addition, bitwise operations and other simple things to achieve complexity thanks to how processors do arithmetics. Mainly, the results from an earlier calculation is carried over to the next calculation &#8212; when an addition or a subtraction overflows, i.e. the result is too large or too small to fit in a register, the processor lets the result wrap over but sets the <strong>carry flag</strong>.</p><p>This is quite similar to how you would carry numbers when calculating with a pen and a paper. The flag affects the results unpredictably because it&#8217;s used across quite different operations; usually you would just use to to add big numbers together as in the pen and paper example.</p><h4 id="toc-the-main-loop">The Main Loop</h4><p>Here is the meat of the code. The C version has many variables that are named after registers in order to see the connection with the original code. Sometimes, as with the 8-bit registers, some code doesn&#8217;t work exactly as in the original because you can&#8217;t do things similarly in C. E.g. you can&#8217;t have two variables that also are a part of one big register similarly how <strong>al</strong> and <strong>ah</strong> form <strong>ax</strong> (well, you can with pointers or unions but that is besides the point, kind of).</p><h5 id="toc-self-modifying-code">Self Modifying Code</h5><p>I use self modifying code (SMC) in a few places because it produces faster and also much simpler code. For example, if you have a variable that is changed in a few places but used by one instruction only (and the instruction performs arithmetic or otherwise accepts a constant parameter), it&#8217;s much faster to store the variable where the constant for the instruction would be. That way you don&#8217;t have to read the variable in a register and then use the register to do something.</p><p>E.g. Let&#8217;s multiply <strong>cx</strong> by the variable <strong>foo</strong>:</p><table><tr><td><strong>Original</strong></td><td><strong>SMC</strong></td></tr><tr><td><pre><code>  push ax ; save ax
  mov ax,[foo] ; move variable foo in ax
  imul cx,ax ; multiply cx by ax
  pop ax  ; restore ax
  ...
  mov ax,123   ; set foo ...
  mov [foo],ax ; ... to 123
  ...
foo: dw 0</code>
</pre></td><td><pre><code>  imul cx,123
foo equ $-2
  ...
  mov ax,123   ; set foo ...
  mov [foo],ax ; ... to 123</code></pre></td></tr></table><p>We can exploit the fact <strong>imul</strong> (signed multiplication) accepts constant multipliers. If you looked at the code with a hex editor, you&#8217;d see 123 next to the opcode. You can change the constant run-time and you do that exactly like you would change a variable: if you just define <b>foo</b> as the address where the constant is (the above code defines it as the last two bytes (i.e. word) of the previous instruction: in NASM, <strong>$</strong> is the current location and <strong>$-2</strong> equals the address of the previous word).</p><p><strong><em>To be concluded&#8230;</em></strong></p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2009/09/08/you-can-stop-programming-now/" title="You Can Stop Programming Now">You Can Stop Programming Now</a></li><li><a
href="http://kometbomb.net/2007/10/22/theres-plenty-of-room-at-the-bottom/" title="There&#8217;s Plenty of Room at the Bottom">There&#8217;s Plenty of Room at the Bottom</a></li><li><a
href="http://kometbomb.net/2007/09/04/image-retargeting/" title="Image retargeting">Image retargeting</a></li><li><a
href="http://kometbomb.net/2007/07/17/nanopond-screensaver/" title="Nanopond Screensaver">Nanopond Screensaver</a></li><li><a
href="http://kometbomb.net/2009/09/22/introducing-my-latest-projects/" title="Introducing My Latest Projects">Introducing My Latest Projects</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Introducing My Latest Projects</title><link>http://kometbomb.net/2009/09/22/introducing-my-latest-projects/</link> <comments>http://kometbomb.net/2009/09/22/introducing-my-latest-projects/#comments</comments> <pubDate>Mon, 21 Sep 2009 22:34:30 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Games]]></category> <category><![CDATA[Nonsense]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[API]]></category> <category><![CDATA[Game programming]]></category> <category><![CDATA[Retro gaming]]></category> <category><![CDATA[SDL]]></category> <category><![CDATA[Source code]]></category> <category><![CDATA[Video]]></category> <category><![CDATA[Video games]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=611</guid> <description><![CDATA[<em>... Or, How to Procrastinate Productively.</em> <a
href="http://kometbomb.net/wp-content/uploads/2009/09/klystrack3.png"><img
src="http://kometbomb.net/wp-content/uploads/2009/09/klystrack3-250x187.png" alt="klystrack3" title="klystrack3" width="192" height="144" class="alignright size-thumbnail wp-image-628" style="width:192px;height:144px" /></a>I decided to make one of my current projects open source and post them on Google Code just for fun. The project is a toolchain that I'm using to remake <em>Thrust</em>. In reality, I decided to divide the project into two separate projects: <a
href="http://code.google.com/p/klystron/">the actual game engine</a> and related tools, and <a
href="http://code.google.com/p/klystrack/">a music editor</a> that uses the engine. ]]></description> <content:encoded><![CDATA[<p><em>&#8230; Or, How to Procrastinate Productively.</em></p><p><a
href="http://kometbomb.net/wp-content/uploads/2009/09/klystrack3.png"><img
src="http://kometbomb.net/wp-content/uploads/2009/09/klystrack3-250x187.png" alt="klystrack3" title="klystrack3" width="250" height="187" class="alignright size-thumbnail wp-image-628" /></a></p><p>I decided to make one of my current projects open source and post them on Google Code just for fun. The project is a tool chain that I&#8217;m using to remake <em>Thrust</em>. In reality, I decided to divide the project into two separate projects: <a
href="http://code.google.com/p/klystron/">the actual game engine</a> (called <em>klystron</em>) and related tools, and <a
href="http://code.google.com/p/klystrack/">a music editor</a> that uses the engine.</p><p>Here are two videos I made a while ago that demonstrate the engine. The first is the music editor (called <em>klystrack</em>) &#8212; it&#8217;s much less ugly at the moment but the sound synthesis is the same, and that&#8217;s what matters:</p><p
class="aligncenter" style="text-align:center"><object
width="480" height="385"><param
name="movie" value="http://www.youtube.com/v/mJewnkOW42I&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0xe1600f&#038;color2=0xfebd01"></param><param
name="allowFullScreen" value="true"></param><param
name="allowscriptaccess" value="always"></param><embed
src="http://www.youtube.com/v/mJewnkOW42I&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0xe1600f&#038;color2=0xfebd01" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></p><p>The sound engine (&#8220;Cyd&#8221;) is basically a very simple software synthesizer with capabilities comparable to the SID or any 8-bit machine from the 80s. The editor is a fairly standard tracker, much like <a
href="http://en.wikipedia.org/wiki/GoatTracker">GoatTracker</a>.</p><p>The graphics half of the engine is basically a wrapper around a quite fast collision detection system (pixel-accurate, or it wouldn&#8217;t be much good for a thrustlike) built on <a
href="http://www.libsdl.org">SDL</a>. It also does background collisions and drawing as well. As you may have guessed, the whole point is to provide a limited but still helpful set of routines that are useful for creating 2D games not unlike what video games were in 1991.</p><p>And, here&#8217;s a proof I&#8217;m actually working on the actual game (the sound effects are created in real time by the sound engine):</p><p
class="aligncenter" style="text-align:center"><object
width="640" height="505"><param
name="movie" value="http://www.youtube.com/v/Yt1LtVSv5gw&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0xe1600f&#038;color2=0xfebd01"></param><param
name="allowFullScreen" value="true"></param><param
name="allowscriptaccess" value="always"></param><embed
src="http://www.youtube.com/v/Yt1LtVSv5gw&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0xe1600f&#038;color2=0xfebd01" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></p><p>A note on <a
href="http://code.google.com/">Google Code</a>: it&#8217;s rather nice. It provides the standard open source development stuff like source control an such but I really like how clean and hassle-free it is. Adding a project takes a minute and after that it&#8217;s simply coding and some quick documentation on the project wiki. The project wiki is good example of how simple but elegant the system is: the wiki pages actually exists inside the source control as files, just like your source code.</p><p>Go check Google Code out and while you&#8217;re at it, contribute on my projects. :)</p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/" title="Collision Detection with Occlusion Queries Redux">Collision Detection with Occlusion Queries Redux</a></li><li><a
href="http://kometbomb.net/2008/06/18/thrustlikes/" title="Thrustlikes">Thrustlikes</a></li><li><a
href="http://kometbomb.net/2008/04/10/rom-check-fail/" title="ROM CHECK FAIL">ROM CHECK FAIL</a></li><li><a
href="http://kometbomb.net/2008/03/24/show-me-yours-and-ill-show-you-mine/" title="Show Me Yours and I&#8217;ll Show You Mine">Show Me Yours and I&#8217;ll Show You Mine</a></li><li><a
href="http://kometbomb.net/2008/03/09/dev-stories-from-the-past/" title="Dev Stories from the Past">Dev Stories from the Past</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2009/09/22/introducing-my-latest-projects/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>You Can Stop Programming Now</title><link>http://kometbomb.net/2009/09/08/you-can-stop-programming-now/</link> <comments>http://kometbomb.net/2009/09/08/you-can-stop-programming-now/#comments</comments> <pubDate>Tue, 08 Sep 2009 10:36:26 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[256B]]></category> <category><![CDATA[Assembly]]></category> <category><![CDATA[Demoscene]]></category> <category><![CDATA[Raytracing]]></category> <category><![CDATA[Video]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=585</guid> <description><![CDATA[I'll be deleting all my own source code since perfection has finally been achieved and there is no need for programmers anymore.]]></description> <content:encoded><![CDATA[<p
class="aligncenter" style="text-align:center"><object
width="640" height="505"><param
name="movie" value="http://www.youtube.com/v/3vzcMdkvPPg&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0xe1600f&#038;color2=0xfebd01"></param><param
name="allowFullScreen" value="true"></param><param
name="allowscriptaccess" value="always"></param><embed
src="http://www.youtube.com/v/3vzcMdkvPPg&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0xe1600f&#038;color2=0xfebd01" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></p><p>The above is <em>puls</em>, a <a
href="http://kometbomb.net/2007/10/22/theres-plenty-of-room-at-the-bottom/">256-byte intro</a> by <a
href="http://rrrola.wz.cz/">Řrřola</a>. It&#8217;s basically a raytracer with screen space ambient occlusion (which makes it so much realistic and cooler). While <a
href="http://www.pouet.net/prod.php?which=3397"><em>tube</em></a> &#8212; which I think was the best 256-byte intro until now (when design and code are judged together) &#8212; also did raytracing of a cylinders, and after that many other intros did similar tracing of more complex surfaces, <em>puls</em> simply crushes all of them with objects that are formed by multiple plane surfaces (e.g. a cube would be a combination of six intersecting planes), a very nice color palette and that delicious ambient occlusion.</p><blockquote
cite="http://pouet.net/prod.php?which=53816&#038;howmanycomments=25&#038;page=9"><p>Thinking it out in C and sketching it out in asm took about a week, byte crunching took another one&#8230; that&#8217;s like forty hours of full focus and eighty of playing.</p></blockquote><p>It&#8217;s also really, really slow which is the only minus especially because you can&#8217;t run 16-bit executables on Windows 7, so you have to use <a
href="http://www.dosbox.com/">DOSBox</a> to watch it (or, use a <a
href="http://www.kolumbus.fi/xtmb/goatsefloppy/#custom">boot floppy</a> to run it or something). <ins
datetime="2009-09-08T14:09:45+00:00">There&#8217;s now a Windows port including a screensaver, <a
href="http://pouet.net/prod.php?which=53816">see the Pouet.net page for more</a></ins>. A big thank you to nordak5 who was kind enough to upload a video on Youtube.</p><p>Řrřola has also included source code with <a
href="http://rrrola.wz.cz/downloads.html">the binary that you can find over here</a>. That said, I&#8217;ll be deleting all my own source code since perfection has finally been achieved and there is no need for programmers anymore.</p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/" title="Plenty of Room, Part II">Plenty of Room, Part II</a></li><li><a
href="http://kometbomb.net/2007/10/22/theres-plenty-of-room-at-the-bottom/" title="There&#8217;s Plenty of Room at the Bottom">There&#8217;s Plenty of Room at the Bottom</a></li><li><a
href="http://kometbomb.net/2009/09/22/introducing-my-latest-projects/" title="Introducing My Latest Projects">Introducing My Latest Projects</a></li><li><a
href="http://kometbomb.net/2008/03/28/playstation-3-vs-atari-vcs/" title="Playstation 3 vs. Atari VCS">Playstation 3 vs. Atari VCS</a></li><li><a
href="http://kometbomb.net/2008/03/25/some-cool-demoscene-stuff/" title="Some Cool Demoscene Stuff">Some Cool Demoscene Stuff</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2009/09/08/you-can-stop-programming-now/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Retargeting Images Using Parallax</title><link>http://kometbomb.net/2009/09/02/retargeting-images-paralla/</link> <comments>http://kometbomb.net/2009/09/02/retargeting-images-paralla/#comments</comments> <pubDate>Wed, 02 Sep 2009 10:10:41 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[Algorithms]]></category> <category><![CDATA[Image retargeting]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=553</guid> <description><![CDATA[I came up with a neat way to retarget images using a mesh that is transformed by rotating and doing an ortographic (non-perspective) projection. This is generally quite interesting since it can be done using a mesh and simple transformations and so can be done almost completely on the GPU. Even using a mesh can [...]]]></description> <content:encoded><![CDATA[<p></p><p>I came up with a neat way to <a
href="http://www.youtube.com/watch?v=qadw0BRKeMk">retarget images</a> using a mesh that is transformed by rotating and doing an ortographic (non-perspective) projection. This is generally quite interesting since it can be done using a mesh and simple transformations and so can be done almost completely on the GPU. Even using a mesh can be avoided if one uses a height map à la <a
href="http://en.wikipedia.org/wiki/Parallax_mapping">parallax mapping</a> to alter the texture coordinates so just one quad needs to be drawn (with a suitable fragment shader, of course).</p><p>The idea is simply to have areas of images at a slope depending of how much the areas should be resized when retargeting. The slope angle depends of from what angle the source image is viewed to get the retargeting effect since the idea is to eliminate the viewing angle using the slope.</p><p>Here&#8217;s a more detailed explanation:</p><ol><li><p>Create an energy map of the source image, areas of interest have high energy</p></li><li><p>Traverse the energy map horizontally accumulating the energy value of the current pixel and the accumulated sum from the previous pixel</p></li><li><p>Repeat the previous step vertically using the accumulated map from the previous step. The accumulated energy map now &#8220;grows&#8221; from the upper left corner to the lower right corner. You may need a lot of precision for the map</p></li><li><p>Create a mesh with the x and y coordinates of each vertex encoding the coordinates of the source image (and thus also the texture coordinates) and the z coordinate encoding the accumulated energy. The idea is to have all areas of interest at a steep slope and other areas with little or no slope</p></li><li><p>Draw the mesh with ortographic projection, using depth testing and textured with the source image</p></li><li><p>Rotate the mesh around the Y axis to retarget image horizontally and around the X axis to retarget image vertically</p></li></ol><p>Here is a one-dimensional example (sorry for the awful images):</p><div
id="attachment_554" class="wp-caption aligncenter" style="width: 339px"><a
href="http://kometbomb.net/wp-content/uploads/2009/09/red-dots.png"><img
src="http://kometbomb.net/wp-content/uploads/2009/09/red-dots.png" alt="Source image" title="red-dots" width="329" height="79" class="size-full wp-image-554" /></a><p
class="wp-caption-text">Source image</p></div><p>The red dots represent areas of interest, such as sharp edges that we don&#8217;t want to resize as much as we want to resize the areas between the details. We then elevate our line for every red dot:</p><div
id="attachment_554" class="wp-caption aligncenter" style="width: 339px"><a
href="http://kometbomb.net/wp-content/uploads/2009/09/red-dots1.png"><img
src="http://kometbomb.net/wp-content/uploads/2009/09/red-dots1.png" alt="red-dots" title="red-dots" width="302" height="132" class="aligncenter size-full wp-image-555" /></a><p
class="wp-caption-text">Elevated mesh</p></div><p>Imagine the above example as something you would do for every row and column of a two-dimensional image. Now, when the viewer views the mesh (which is drawn without perspective) he or she sees the original image:</p><div
id="attachment_554" class="wp-caption aligncenter" style="width: 339px"><a
href="http://kometbomb.net/wp-content/uploads/2009/09/red-dots3.png"><img
src="http://kometbomb.net/wp-content/uploads/2009/09/red-dots3.png" alt="red-dots3" title="red-dots3" width="328" height="336" class="aligncenter size-full wp-image-556" /></a><p
class="wp-caption-text">Viewing the mesh from zero angle</p></div><p>However, if the viewing angle is changed, the red dots don&#8217;t move in relation to each other as much as the areas that are not elevated when they are projected on the view plane. Consider the below example:</p><div
id="attachment_554" class="wp-caption aligncenter" style="width: 339px"><a
href="http://kometbomb.net/wp-content/uploads/2009/09/red-dots31.png"><img
src="http://kometbomb.net/wp-content/uploads/2009/09/red-dots31.png" alt="red-dots3" title="red-dots3" width="300" height="203" class="aligncenter size-full wp-image-557" /></a><p
class="wp-caption-text">Viewing the mesh from an angle (gray line is the projected mesh)</p></div><p>Note how the unelevated line segments will seem shorter from the viewer&#8217;s perspective while the distance between the red dots is closer to the original distance. The blue dots in the above image show how areas that have little energy and so are not on a slope, thus will be move more compared to the red dots.</p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2007/09/04/image-retargeting/" title="Image retargeting">Image retargeting</a></li><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/" title="Plenty of Room, Part II">Plenty of Room, Part II</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/" title="Collision Detection with Occlusion Queries Redux">Collision Detection with Occlusion Queries Redux</a></li><li><a
href="http://kometbomb.net/2008/02/20/lets-make-a-planet/" title="Let&#8217;s make a planet">Let&#8217;s make a planet</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2009/09/02/retargeting-images-paralla/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>OpenGL, Static Arrays and glMaterialfv</title><link>http://kometbomb.net/2009/07/19/opengl-static-arrays-and-glmaterialfv/</link> <comments>http://kometbomb.net/2009/07/19/opengl-static-arrays-and-glmaterialfv/#comments</comments> <pubDate>Sun, 19 Jul 2009 20:09:27 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[C]]></category> <category><![CDATA[GCC]]></category> <category><![CDATA[OpenGL]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=505</guid> <description><![CDATA[I stumbled upon weird behavior of OpenGL: I was setting material properties with <tt>glMaterialfv</tt> and for some reason this did not change the parameters if done multiple times in succession. I.e. when I drew two versions of the same object on the screen side by side with different material parameters, they both looked the same.]]></description> <content:encoded><![CDATA[<p>I stumbled upon weird behavior of OpenGL (OGL 1.4, Catalyst 8.612, GCC if that matters): I was setting material properties with <tt><a
href="http://www.opengl.org/sdk/docs/man/xhtml/glMaterial.xml">glMaterialfv</a></tt> and for some reason this did not change the parameters if done multiple times in succession. I.e. when I drew two versions of the same object on the screen side by side with different material parameters, they both looked the same.</p><p>The reason seems to be I was using a static array to store the parameters like this:</p><pre><code>void set_params(const Color&amp; diffuse)
{
  static float d[4] = {diffuse.r, diffuse.g, diffuse.b, diffuse.a};
  glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
}</code></pre><p>The only explanation I can think of is OpenGL doesn&#8217;t copy or use the values before <tt>glMaterialfv</tt> returns but instead reads them later, at which time there could be different values in the array (because it&#8217;s declared static) set for some other object being drawn. But that doesn&#8217;t explain why it can read the array (which AFAIK will be located on stack) later because the address to the then-valid location on the stack most likely won&#8217;t point to the parameters. Maybe the driver assumes anything that&#8217;s not on the stack can be used later and stuff located on stack will be copied. Who knows?</p><p>In any case, not declaring the array as static fixed the problem.</p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2010/02/28/libconfig/" title="An Alternative to XML">An Alternative to XML</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/" title="Creating a Simple GUI from Scratch">Creating a Simple GUI from Scratch</a></li><li><a
href="http://kometbomb.net/2008/08/19/out-of-memory/" title="Out of Memory?">Out of Memory?</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/" title="Collision Detection with Occlusion Queries Redux">Collision Detection with Occlusion Queries Redux</a></li><li><a
href="http://kometbomb.net/2008/03/21/a-tiny-xml-parser/" title="A Tiny XML Parser">A Tiny XML Parser</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2009/07/19/opengl-static-arrays-and-glmaterialfv/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Out of Memory?</title><link>http://kometbomb.net/2008/08/19/out-of-memory/</link> <comments>http://kometbomb.net/2008/08/19/out-of-memory/#comments</comments> <pubDate>Tue, 19 Aug 2008 20:07:34 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[C]]></category> <category><![CDATA[Memory]]></category> <category><![CDATA[Windows]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=375</guid> <description><![CDATA[It&#8217;s a common practice not to check what malloc() or new returns, since in an ideal world you will never run out of memory and so allocating memory will never fail. With a reasonably sized page file that is mostly true. When using a page file, this wouldn&#8217;t be a problem since if there is [...]]]></description> <content:encoded><![CDATA[<p>It&#8217;s a common practice not to check what <tt>malloc()</tt> or <tt>new</tt> returns, since in an ideal world you will never run out of memory and so allocating memory will never fail. With a reasonably sized <a
href="http://en.wikipedia.org/wiki/Paging" title="Paging" rel="wikipedia" class="zem_slink">page file</a> that is mostly true. When using a page file, this wouldn&#8217;t be a problem since if there is free space on the drive the page file is located, <a
href="http://en.wikipedia.org/wiki/Virtual_memory" title="Virtual memory" rel="wikipedia" class="zem_slink">virtual memory</a> space can be temporarily enlarged (and a message pops up mentioning that) and the application that tried to allocate memory got what it asked.</p><p>However, since I upgraded to the maximum amount of memory Windows XP supports, and switched memory paging completely off, I&#8217;ve noticed some programs will silently fail when the system runs out of memory. And this isn&#8217;t that uncommon since I develop software and the crap programmer I am, silly mistakes are and always will be made that cause huge memory usage (and there&#8217;s also the rest of the software running on the computer). I have noticed at least Firefox simply disappears, while some software die with an error message.</p><p>For a game this wouldn&#8217;t be an issue (or a web browser even) but there are tons of programs downloading stuff or just hanging there that you&#8217;ll never notice missing. But it&#8217;s annoying to notice everything isn&#8217;t as you left it.</p><p>So, in case you haven&#8217;t thought of allocation failing, you probably should do something about it. When there&#8217;s no free memory left, even a <tt>malloc(sizeof(char))</tt> will invariably fail. A lazy way out would be wrapping the allocation with something that checks if the allocation succeeded and if not, displaying a message box will halt the program until the user does something (kills the offending app reserving all that memory or frees some disk space for the page file) and then clicks &#8220;Retry&#8221; and then the wrapper simply tries to allocate again. In C++, the <tt>new</tt> operator can be overloaded.</p><p>Just my 2 cents (Euro).</p><h3 id="toc-example-code">Example code</h3><h4 id="toc-c">C</h4><pre><code>void * my_alloc(size_t bytes)
{
  if (NULL == (ptr = malloc(bytes)))
  {
    // malloc failed, do something about it!
  }
  return ptr;
}</code></pre><h4 id="toc-c1">C++</h4><p>This uses the function from above C code.</p><pre><code>void * operator new(size_t bytes)
{
  return my_malloc(bytes);
}</code></pre><div
style="margin-top: 10px; height: 15px;" class="zemanta-pixie"><a
class="zemanta-pixie-a" href="http://reblog.zemanta.com/zemified/91884b1b-4ef2-46ee-8343-cc6bb32f1031/" title="Zemified by Zemanta"><img
style="border: medium none ; float: right;" class="zemanta-pixie-img" src="http://img.zemanta.com/reblog_e.png?x-id=91884b1b-4ef2-46ee-8343-cc6bb32f1031" alt="Reblog this post [with Zemanta]" /></a></div><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2010/02/28/libconfig/" title="An Alternative to XML">An Alternative to XML</a></li><li><a
href="http://kometbomb.net/2009/12/31/creating-a-simple-gui-from-scratch/" title="Creating a Simple GUI from Scratch">Creating a Simple GUI from Scratch</a></li><li><a
href="http://kometbomb.net/2009/07/19/opengl-static-arrays-and-glmaterialfv/" title="OpenGL, Static Arrays and glMaterialfv">OpenGL, Static Arrays and glMaterialfv</a></li><li><a
href="http://kometbomb.net/2008/08/05/introducing-calculon/" title="Introducing Calculon">Introducing Calculon</a></li><li><a
href="http://kometbomb.net/2008/03/21/a-tiny-xml-parser/" title="A Tiny XML Parser">A Tiny XML Parser</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2008/08/19/out-of-memory/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Collision Detection with Occlusion Queries Redux</title><link>http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/</link> <comments>http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#comments</comments> <pubDate>Wed, 23 Jul 2008 15:37:41 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Games]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Algorithms]]></category> <category><![CDATA[Collision detection]]></category> <category><![CDATA[Game programming]]></category> <category><![CDATA[OpenGL]]></category> <category><![CDATA[Source code]]></category> <category><![CDATA[Video games]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=317</guid> <description><![CDATA[Here we describe a method for checking collisions between arbitrary objects drawn by the GPU. The objects are not limited to any shape, complexity or orientation. The objects that are checked for collisions can be the same objects that are drawn on the screen. The algorithm is pixel perfect but without further refining is limited to 2D collisions.]]></description> <content:encoded><![CDATA[<div
class="toc"><ol><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-introduction">Introduction</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-description">Description</a><ol><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-determining-objects-that-need-to-be-tested">Determining objects that need to be tested</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-drawing-objects">Drawing objects</a><ol><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-sprites">Sprites</a></li></ol></li></ol></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-optimizations">Optimizations</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-caveats">Caveats</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-appendix-a-source-code-for-opengl">Appendix A. Source code for OpenGL</a></li><li><a
href="http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/#toc-links">Links</a></li></ol></div><h3 id="toc-introduction">Introduction</h3><p>Here we describe a method for checking collisions between arbitrary objects drawn by the GPU. The objects are not limited to any shape, complexity or orientation. The objects that are checked for collisions can be the same objects that are drawn on the screen. The algorithm is pixel perfect but without further refining is limited to 2D collisions.</p><h3 id="toc-description">Description</h3><p>The algorithm can be divided in three separate steps:</p><ol><li><p>Determine which objects need testing</p></li><li><p>Set up the GPU buffers and draw the first object so the stencil buffer is set</p></li><li><p>Make an occlusion query using the and using the stencil from the previous buffer</p></li></ol><p>If the occlusion query returns any pixels were drawn, the two objects overlap.</p><h4 id="toc-determining-objects-that-need-to-be-tested">Determining objects that need to be tested</h4><div
class="alignright" style="font-size:12px"><a
href="http://kometbomb.net/wp-content/uploads/2008/07/col1.png"><img
alt="Figure 1." src="http://kometbomb.net/wp-content/uploads/2008/07/col1thumb.png" style="border:0"></a><br/>Figure 1.</div><p> To speed up the algorithm, we need to eliminate object pairs that can&#8217;t overlap. This can be done by projecting the object bounding volumes in screen space. Then, we can quickly check which 2D polygons overlap and do further checking. Choosing the shape of the bounding volumes/polygons is not relevant. In this document we will use rectangles for the simplicity.</p><p>The example case in figure 1 shows two colliding objects (overlapping bounding rectangles shown red), one near hit (green overlap) and one object with no collisions or bounding rectangle overlap. To determine the collisions (and non-collisions) we need checks for every bounding rectangle (15 checks) and two checks using the GPU<sup
class='footnote'><a
href='#fn-317-1' id='fnref-317-1'>1</a></sup>. Without the use of the bounding rectangles, we would need 13 more checks on the GPU.</p><p>The bounding rectangles in the example can be generated by finding the maximum and minimum coordinates and using them as the corner points of the rectangle. Since the algorithm finds collisions as seen from the camera, we need first project the object coordinates (or the object bounding volume coordinates) on the screen and find the minima and maxima using those coordinates. Most 3D frameworks provide functions for projecting a 3D point to screen coordinates using the same transformations as seen on screen<sup
class='footnote'><a
href='#fn-317-2' id='fnref-317-2'>2</a></sup>.</p><h4 id="toc-drawing-objects">Drawing objects</h4><p>Before we start drawing the objects on the graphics buffer, we need to clear the stencil buffer. After that, the GPU should be set to draw only to the stencil buffer, that is we don&#8217;t need the color buffer or depth buffer to be updated.</p><p>Now, the first object can be drawn. After that, we will draw the second object. Before we start we need to set up the occlusion query to count the drawn pixels. We also need to use the stencil buffer created in the previous step and set the GPU to draw only if the stencil buffer is non-zero. We don&#8217;t need to update any buffers at this point.</p><p>After the second object is drawn, the pixel count returned by the occlusion query tells how many pixels overlap. For most purposes, we can assume a non-zero value means the two objects collide<sup
class='footnote'><a
href='#fn-317-3' id='fnref-317-3'>3</a></sup>.</p><p><center><br
/><table><tr><td><img
src="http://kometbomb.net/wp-content/uploads/2008/07/col4.png" width="144" height="96" /><br/>Figure 2.</td><td><img
src="http://kometbomb.net/wp-content/uploads/2008/07/col5.png" width="144" height="96" /><br/>Figure 3.</td><td><img
src="http://kometbomb.net/wp-content/uploads/2008/07/col6.png" width="144" height="96" /><br/>Figure 4.</td></tr></table><p></center></p><p>Consider the above example. Figure 2 shows two objects as seen on screen. Figure 3 shows the stencil derived by drawing only the green (right) object. Figure 4 shows what will be drawn of the red (left) object if we limit the rendering to drawing on the stencil (the occlusion query will tell us six  pixels were drawn).</p><h5 id="toc-sprites">Sprites</h5><p>For sprite objects that consist of only one quad and an alpha blended texture with transparent area representing the area that cannot collide with anything, the same result can be achieved by setting the alpha testing to discard pixels below a certain tolerance. This will then avoid updating the stencil buffer on the whole area of the quad.</p><h3 id="toc-optimizations">Optimizations</h3><p>The stencil buffer can be created to contain the collision area of e.g. every enemy currently on the screen and then testing with the player object. This avoids the necessity to test between every object individually, which can be costly since the occlusion query has to finish before the next query can start. If the objects on the screen can be grouped to a handful of categories, such as the player, the enemies, player bullets and so on, multiple objects can be tested simultaneously where it is not important to know exactly which two objects collided (e.g. when deciding whether to kill the player which in a shooter game generally is because the player collides with the background, an enemy bullet or an enemy &#8212; all of which would be drawn in the same stencil buffer).</p><p>Ideally, the above can be done so that every object group has its own stencil buffer. This then makes it possible to create the stencil and start the queries in their respective buffers, do something useful while they execute and then query for the occlusion query results.</p><h3 id="toc-caveats">Caveats</h3><p>Most of all, doing collision detection with occlusion queries is admittedly a curiosity. There are many, many ways to do collisions faster and most likely with less technicalities. Using a simple rectangle (a cube or a sphere in 3D applications) to test collisions between complex objects has been used since the first video games and it still provides acceptable accuracy. Indeed, some games even use an extremely small collision area (e.g. a single pixel) to test collisions with larger objects with great success. Additionally, the algorithm is potentially a bottleneck, especially when triple buffering etc. are used since occlusion queries generally are started after the previous frame is drawn and then read when the next frame is drawn (i.e. it&#8217;s asyncronous). This limits either the algorithm accuracy for real time (frame accuracy) or the framerate since we may have to wait for the query to finish for a relatively long time.</p><p>A serious consideration is to use the occlusion query algorithm to test between a complex object, e.g. with a large end of level boss with a complex, changing shape and use a simpler geometry based algoritm to test between hundreds of bullets. A hybrid algorithm could even first make an occlusion query to know which objects collide and then use a different algorithm to find out more about the collision.</p><p>This is inherently a 2D algorithm. The GPU sees any situations in which two objects overlap as a collision, as seen from the location of the camera. This if fine for side-scrollers et cetera, which also benefit from pixel perfect (fair, predictable) collisions, and other situations in which all the objects to be tested are on the same plane. Multiple depth levels (e.g. foreground objects never collide with background items) improve the situation and so does drawing only the parts of the objects that are between specified depth levels<sup
class='footnote'><a
href='#fn-317-4' id='fnref-317-4'>4</a></sup>.</p><p>Another possible problem is that the screen resolution may be different between systems, which makes the algorithm have different levels of accuracy. This can be avoided by doing the checks in a fixed resolution. Limiting the collision buffer resolution also improves the algorithm speed in cases the GPU fillrate is a bottleneck.</p><p>Finally, some older systems may not support occlusion queries or stencil buffers. As of 2008, this is increasingly rare but should be taken into consideration.</p><h3 id="toc-appendix-a-source-code-for-opengl">Appendix A. Source code for OpenGL</h3><p>The following is source code extracted from a proof of a concept/prototype game written in C++ using OpenGL. The source code should be self explanatory.</p><p>The following builds the bounding rectangle for a object:</p><pre><code>BoundBox box=object-&gt;GetBoundingBox();

object-&gt;DoObjectTranslations();

glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
glGetIntegerv(GL_VIEWPORT, viewport);

for (int i=0;i&lt;8;i++)
{
    GLdouble screenX, screenY, screenZ;

    vec3 c=box.Corner(i);

    gluProject(c.x(), c.y(), c.z(),
        modelViewMatrix, projectionMatrix, viewport,
        &amp;screenX, &amp;screenY, &amp;screenZ);

    maxX=max((int)screenX,maxY);
    maxY=max((int)screenY,maxY);
    minX=min((int)screenX,minX);
    minY=min((int)screenY,minY);
}

rect = Rect(minX,minY,maxX-minX, maxY-minY);</code></pre><p>The following can be used to set the rendering mode before drawing the object on the screen, on the stencil buffer or when making the occlusion query (note how we disable most of the rendering when drawing something that will not be visible to the player, also notice how the stencil buffer is cleared if we enable stencil drawing mode &#8212; using scissor makes this efficient):</p><pre><code>void GfxManager::SetRenderMode(RenderMode mode) {
  if (mode==STENCIL) {
    glDepthFunc(GL_ALWAYS);
    glDisable(GL_LIGHTING);
    glClear(GL_STENCIL_BUFFER_BIT);
    glEnable(GL_STENCIL_TEST);
    glDisable(GL_DEPTH_TEST);
    glStencilFunc(GL_ALWAYS, 1, 1);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
    glColorMask(0,0,0,0);
  } else if (mode==OCCLUSION) {
    glDepthFunc(GL_ALWAYS);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
    glEnable(GL_SCISSOR_TEST);
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_EQUAL, 1, 1);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glColorMask(0,0,0,0);
    glBeginQueryARB(GL_SAMPLES_PASSED_ARB, m_OccId);
  } else {
    // Set normal rendering mode here (enable lighting etc.)
  }
}</code></pre><p>Similarly, the following is used to end drawing (specifically to end the collision testing, at which the function returns the number of pixels drawn)&#8230;</p><pre><code>int GfxManager::FinishRenderMode(RenderMode mode) {
  if (mode==OCCLUSION) {
    glEndQueryARB( GL_SAMPLES_PASSED_ARB );
    GLuint occ=0;
    glGetQueryObjectuivARB( m_OccId, GL_QUERY_RESULT_ARB, &amp;occ);
    return (int)occ;
  } else {
    return 0;
  }
}</code></pre><p>&#8230; using something like this:</p><pre><code>int GfxManager::DrawObject(int oid,vec3 pos,vec3 rot,RenderMode mode) {
  SetRenderMode(mode);
  Draw3DObject(oid, pos, rot);
  return FinishRenderMode(mode);
}</code></pre><p>This is from the main loop, it simply goes through all objects in the game. Notice how we first prepare the collision checking for the first object to be tested (i.e. create the stencil as in step 2 of the algorithm).</p><pre><code>for (unsigned int a=0;a&lt;m_Objects.size();a++) {
  m_Objects[a]-&gt;PrepareCollide();
  for (unsigned int b=a+1;b&lt;m_Objects.size();b++) {
    if (m_Objects[a]-&gt;TestCollide(m_Objects[b])) {
      // We have a collision
    }
  }
  m_Objects[a]-&gt;FinishCollide();
}</code></pre><p>Note that DrawObject is the same method as we use to draw the visible object on the screen. The only thing that differs is that the drawing mode is set to stencil or occlusion query. Also worth noting is how we use the rectangle to set the scissor to further reduce the workload.</p><pre><code>void GfxObject::PrepareCollide() {
  GetGfxManager()-&gt;SetScissor(this-&gt;GetBoundingRect());
  GetGfxManager()-&gt;DrawObject(m_GfxId,GetPosition(),GetRotation(),STENCIL);
}

void GfxObject::FinishCollide() {
  // We simply reset the scissor
  GetGfxManager()-&gt;SetScissor();
}

int GfxObject::DrawCollide() {
  // We could set the scissor here to even smaller area, the overlapping area
  return GetGfxManager()-&gt;DrawObject(m_GfxId,GetPosition(),GetRotation(),OCCLUSION);
}

bool GfxObject::TestCollide(Object *obj) {
  Rect a=GetBoundingRect();
  Rect b=obj-&gt;GetBoundingRect();

  // No need for further collision testing if the rectangles
  // don't overlap
  if (!a.TestCollide(b)) return false;

  // We have a collision if any pixels were drawn
  return obj-&gt;DrawCollide() &gt; 0;
}</code></pre><h3 id="toc-links">Links</h3><ul><li><a
href="http://blogs.msdn.com/shawnhar/archive/2008/12/31/pixel-perfect-collision-detection-using-gpu-occlusion-queries.aspx">Shawn Hargreaves Blog: Pixel perfect collision detection using GPU occlusion queries</a> &#8211; seems to be exactly the same idea but this time using XNA</li></ul><div
class='footnotes'><div
class='footnotedivider'></div><ol><li
id='fn-317-1'> To speed up the checks done on the GPU, we can set the scissor rectangle to the overlapping area. This helps in cases in which the overlapping area is small compared to the complete area of the object. <span
class='footnotereverse'><a
href='#fnref-317-1'>&#8617;</a></span></li><li
id='fn-317-2'>OpenGL has <a
href="http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/project.html">gluProject()</a>, DirectX has <a
href="http://msdn.microsoft.com/en-us/library/bb205516(VS.85).aspx">D3DXVecProject()</a> <span
class='footnotereverse'><a
href='#fnref-317-2'>&#8617;</a></span></li><li
id='fn-317-3'>It may be useful to consider a larger tolerance for fairness&#8217; sake <span
class='footnotereverse'><a
href='#fnref-317-3'>&#8617;</a></span></li><li
id='fn-317-4'>E.g. setting the near and far clipping planes to the distance of the second object (assuming it won&#8217;t be a problem that the clipping results in objects that have a hole) <span
class='footnotereverse'><a
href='#fnref-317-4'>&#8617;</a></span></li></ol></div><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2009/09/22/introducing-my-latest-projects/" title="Introducing My Latest Projects">Introducing My Latest Projects</a></li><li><a
href="http://kometbomb.net/2009/11/09/plenty-of-room-part-ii/" title="Plenty of Room, Part II">Plenty of Room, Part II</a></li><li><a
href="http://kometbomb.net/2008/03/24/show-me-yours-and-ill-show-you-mine/" title="Show Me Yours and I&#8217;ll Show You Mine">Show Me Yours and I&#8217;ll Show You Mine</a></li><li><a
href="http://kometbomb.net/2007/09/04/image-retargeting/" title="Image retargeting">Image retargeting</a></li><li><a
href="http://kometbomb.net/2010/03/10/the-last-arcadian/" title="Review: The Last Arcadian">Review: The Last Arcadian</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2008/07/23/collision-detection-with-occlusion-queries-redux/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Blog Experiment: More SQL and Text Matching</title><link>http://kometbomb.net/2008/04/25/more-sql-and-text-matching/</link> <comments>http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#comments</comments> <pubDate>Fri, 25 Apr 2008 11:11:52 +0000</pubDate> <dc:creator>kometbomb</dc:creator> <category><![CDATA[Programming]]></category> <category><![CDATA[TGBE]]></category> <category><![CDATA[Search algorithms]]></category> <category><![CDATA[SQL]]></category><guid
isPermaLink="false">http://kometbomb.net/?p=264</guid> <description><![CDATA[In Viewer2, there is a feature that allows fast text searches on huge databases with tens of thousands of filenames. Here's how I did it.]]></description> <content:encoded><![CDATA[<p><p
class="blogexperiment_disclaimer">This post is a part of a blogging experiment on writing posts based on common search queries from which this site receives traffic. <a
href="/04/18/a-blogging-experiment/">Read the original post for more information</a> on this experiment. <a
href="/category/tgbe/">See all posts</a> in this series.</p></p><p>In <a
href="/projects/viewer2/">Viewer2</a>, there is a feature that allows fast text searches on huge databases with tens of thousands of filenames (and associated photo captions and other meta data). Here&#8217;s how I did it.</p><div
class="toc"><ol><li><a
href="http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#toc-the-simple-approach">The simple approach</a></li><li><a
href="http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#toc-using-a-token-based-approach">Using a token-based approach</a><ol><li><a
href="http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#toc-searching-using-tokens">Searching using tokens</a></li><li><a
href="http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#toc-evaluation-order">Evaluation order</a></li><li><a
href="http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#toc-further-ideas">Further ideas</a></li></ol></li><li><a
href="http://kometbomb.net/2008/04/25/more-sql-and-text-matching/#toc-notes">Notes</a></li></ol></div><h3 id="toc-the-simple-approach">The simple approach</h3><p>The easiest way to find all filenames (the following article talks about filenames but you can use this to search for <em>any</em> text) matching <strong>$query</strong> (the string we are looking for) can be done a bit like this:</p><pre><code>SELECT `filename` FROM `files` WHERE `filename` LIKE '%$query%'</code></pre><p>Similarly, you could perform for multi-word searches by adding one test for each word you have extracted from the query string. And, you can very easily extend the syntax to include exclusions. Below is the equivalent SQL query for the query string <kbd>[kitten -jpg]</kbd> (filenames with the text &#8216;kitten&#8217; but not the string &#8216;jpg&#8217;):</p><pre><code>SELECT `filename`
  FROM `files`
  WHERE `filename` LIKE '%kitten%'
    AND `filename` NOT LIKE '%jpg%'</code></pre><p>The above works well but it can be very, very slow because it has to go through all entries in the table <kbd>files</kbd> to find matching rows. Speed can be improved by having queries like <kbd>LIKE 'word%'</kbd> but this limits the searches and in the end doesn&#8217;t give too much extra speed.</p><p>And if you are performing fuzzy searches&#8230;</p><p></p><h3 id="toc-using-a-token-based-approach">Using a token-based approach</h3><p>A lot of speed can be gained by splitting the filenames and the searched text into tokens and then performing the search using the tokens. I ended up using the following structure (<a
href="http://www.sqlite.org">SQLite</a> syntax):</p><pre><code>CREATE TABLE `files` (
  `file_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `filename` TEXT
);

CREATE TABLE `tokens` (
  `token_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `word` TEXT UNIQUE
);

CREATE TABLE `link_file_token` (
  `token_id` INT, -- Foreign key to the table `tokens`
  `file_id` INT   -- Foreign key to the table `files`
);</code></pre><p>The idea is that each word in the filename can be represented with a single index to the <kbd>`tokens`</kbd> table. Thus, you can also search by a single integer instead of text comparison. You have to compare text only when generating the tokens (which is extremely helpful if you are using a comparatively expensive comparison).</p><p>First, when you insert the a file in the files table, you split the filename into words and link the file and the tokens (which may already exist in the `tokens` table). Later, when you need to perform a search, you do the same but use the generated tokens to search matching links.</p><p>The filename &#8216;<kbd>Cute kitten picture.jpg</kbd>&#8216; can be split in four tokens which results to four links between the token table and the file table. I also split words when the case between characters changes (splits filenames like &#8216;<kbd>CuteKittenPicture.jpg</kbd>&#8216;) but this is up to you. In my implementation the tokens are also case-insensitive.</p><p></p><h4 id="toc-searching-using-tokens">Searching using tokens</h4><p>Here is a simple example query that finds matching files using the approach described above:</p><pre><code>SELECT `filename`
  FROM `files`
  JOIN `link_file_token` USING `file_id`
  WHERE `token_id` IN (
    SELECT `token_id`
    FROM `tokens`
    WHERE `word` LIKE '%$query%'
  )</code></pre><p>The subquery first finds all <kbd>`token_id`</kbd>&#8216;s that match the query and then the main SELECT finds all filenames that have that <kbd>`token_id`</kbd> linked to them. Obviously, this restricts the query to simple OR queries. This is because the text matching is done in one word scope instead of a longer string (using the above filename as an example, a single word can&#8217;t match both &#8216;cat&#8217; and &#8216;cute&#8217;).</p><p>Here is how you would do a query like <kbd>[cat OR dog]</kbd>:</p><pre><code>SELECT `filename`
  FROM `files`
  JOIN `link_file_token` USING `file_id`
  WHERE `token_id` IN (
    SELECT `token_id`
    FROM `tokens`
    WHERE `word` LIKE '%cat%' OR `word` LIKE '%dog%'
  )</code></pre><p>To perform an AND in the search query you need a query like this:</p><pre><code>SELECT `filename`
  FROM `files`
  JOIN `link_file_token` ON `files`.`file_id` = `link_file_token`.`file_id`
    AND `token_id` IN (
      SELECT `token_id`
      FROM `tokens`
      WHERE `word` LIKE '%kitten%'
    )
  JOIN `link_file_token` ON `files`.`file_id` = `link_file_token`.`file_id`
    AND `token_id` IN (
      SELECT `token_id`
      FROM `tokens`
      WHERE `word` LIKE '%cute%'
    )</code></pre><p>In the above example, using a natural <a
href="http://en.wikipedia.org/wiki/Join_%28SQL%29">JOIN</a> handles the removal of all rows that only match one of the two searched words. Don&#8217;t forget that you can do the same in many ways. For example, you can use <strong>INTERSECT</strong> (do mind though that if you intersect two result lists of strings, it might be much more resource demanding than intersecting two result lists of integers).</p><h4 id="toc-evaluation-order">Evaluation order</h4><p>Keep in mind that if you combine the above AND and OR queries (by adding a <kdb>OR `word` LIKE&#8230;</kbd> for each OR'd word), it will not work as expected. <a
href="http://www.csa.com/help/Search_Tools/boolean_operators.html">Boolean algebra</a> states the correct order to evaluate the two operators is AND first and then OR (the relation is similar to multiplication and addition, which may help you remember that). Above, it will work the opposite, the OR is evaluated before the AND.</p><p>If you restructure the query so that it, for example, returns indexes to the files table, you can implement correct evaluation order by adding a <strong><a
href="http://www.w3schools.com/sql/sql_union.asp">UNION</a></strong> for each OR term. In effect, you first use the above query to find each pair of terms AND'd and then combine all those queries with UNION.</p><p>For the query <kbd>[cat cute OR dog drooly]</kbd>, the resulting SQL query will look something like this:</p><pre><code>SELECT `filename` FROM `files` JOIN ... -- cat AND cute
UNION
SELECT `filename` FROM `files` JOIN ... -- dog AND drooly</code></pre><h4 id="toc-further-ideas">Further ideas</h4><p>To implement a NEAR operator, or when it is important that the searched words are in a certain order (in short strings like filenames it's usually not at all necessary), you could add a field in the file-token links that tell the index of the word in the original string. When you have searched for the results using the above method, you then score the results based on the distance between the tokens.</p><p>E.g. if you are looking for <kbd>[cute kitten]</kbd>, and a result has the text 'Here is a cute dog. It is not a kitten', the indexes for the words 'cute' and 'kitten' will be 4 and 10. Thus, the result should have a worse score than some other piece of text with the exact word order.</p><p></p><h3 id="toc-notes">Notes</h3><p>In Viewer2, the exact implementation doesn't use subqueries like described above. Instead, I first generate a longer query that has the needed `token_id`'s and other stuff filled in (a comma separated list of integers in place of the SELECT subquery). You might consider this to gain some more speed but do experiment before you optimize.</p><p>Take note that even <a
href="http://www.sqlite.org/cvstrac/wiki?p=FullTextIndex">SQLite has a similar feature called FTS2</a>. In theory, it should provide most if not all of the above. My example is still useful if you need more control over how the text is tokenized and compared (and I think in the case of FTS2 enabling full text searching requires double the storage, if you don't want to store all the text data in the full text search table).</p><p>As always, research before you start doing something you think someone probably already did.</p><h3  class="related_post_title">You might also like...</h3><ul
class="related_post"><li><a
href="http://kometbomb.net/2008/04/20/blog-experiment-comparing-text-and-sql/" title="Blog Experiment: Comparing text and SQL">Blog Experiment: Comparing text and SQL</a></li><li><a
href="http://kometbomb.net/2007/11/11/compare-text-files-in-sql/" title="Compare text files in SQL">Compare text files in SQL</a></li></ul>]]></content:encoded> <wfw:commentRss>http://kometbomb.net/2008/04/25/more-sql-and-text-matching/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced)

Served from: kometbomb.net @ 2010-09-03 12:10:14 -->