Limegarden.net Personal site of Wouter Lindenhof

8Mar/100

Broke the installation already

When I yesterday said that I don’t give Linux the 99.999% expectation to work I was not kidding. Just this morning I decided to use synergy and because I don’t want to run the command everytime I decided to add to the startup scripts, after some looking around I finally found how to do it and it was easy to understand, so I decided to give it a go. Once all the configurations were done I decided to reboot.

And then I noticed that something must have gone wrong somewhere. I simply get the console login instead of the graphical interface which I was expecting. Controlling Ubuntu from my laptop was of course also no longer possible (it was before, I have tested it). :(

So what went wrong?

Well, first of all I have been messing around with files I thought to understand (as a matter of fact I do understand them) however had I not done that the system would still have worked. Although the rule here is “If you don’t use it, it won’t break” is being applied, it is something a rule that remains true. In this case I did touch it and it did break.

Anyway I did a few more things I didn’t like so now I’m installing another Linux distribution just to see if I prefer this one.

Within a month I will get a netbook (a small laptop, that is actually too small to use) and then I intend to put some of my work on my current laptop on that. With a bit of luck I might actually set the laptops up in such a way that synergy uses thee laptops (oh and I get one monitor which I can use to increase the amount of screens to four).

Tagged as: , , , No Comments
7Mar/100

Installing Ubuntu on my old laptop

After cleaning up my room. I found one of my old laptops (which have been passed to my mother and back again) and wondered what I should do with it. It was my first laptop and although I don't intend to use it, I don't want to throw away a good laptop (well, there is a line of pixels who always have red on but that is besides the point).

Before I decided to install Ubuntu I wanted to take one last look at what my old laptop had stored on the computer. A wise thing since I came across a few old applications and some documents that all had some kind of emotional value. But more important I found my old music collection. :D

Copying my music collection from one computer to another wouldn't be such a big problem except that the library was/is around 10 GB. To give you an idea my current library is 27 GB which means I can let the music being played for almost 12 days before I encounter the first song in the playlist again. Anyway, copying from one system could be done in a few ways. One would be using an USB stick (which means I would to do it many times before everything would have been copied). The second method would be using the windows file shares to copy things over the network. Besides the fact that both devices are on wireless, the way windows copies a lot of files is not really fast.

In the end I decided to try something new: Bittorrent. Ok, I admit I have used bittorrent before but never to copy files from one device to another. Simply create a decentralized torrent, copy that to the receiving computer and run it. Besides that it worked (I tried it once before) it was rather fast. Of course once I decided to give the seeder a wire it was a whole lot faster (2.5 Mb per second instead of 500 Mb per second)

Once I copied a few of the other files using dropbox I decided to install Ubuntu. First downloading the live cd and put it on an usb using UNetbootin. The live version worked nice, so all that is left is installing.

The reason I decided for Ubuntu is because Windows XP is rather old and I have missed around with it a bit too much (somethings have been broken) and since I don't want to pay money for something I'm rarely going to use I decided to put ubuntu on it.

Although the live version run perfectly, once I tried the installed version I got a flickering screen and couldn't do anything anymore. Thank god, I'm not a complete Linux noob so after half an hour I finally fixed usplash problem (reinstall the graphics driver did the trick), but it at least demonstrates one the reason why I prefer Windows over ubuntu. When I install Windows I expect it to work 99.999% of the time. Linux on the other hand doesn't get that amount of trust from me.

Long story short. Ubuntu has been installed and I'm thinking of using it as my backup and for word processing. My good laptop is slowly becoming an software development only laptop and the occasional game laptop. However on both occasion I see it as work and there are times I simply one play around. And for that reason I use my old laptop.

Tagged as: , , No Comments
6Mar/100

Custom exceptions

Besides finishing my study I'm currently also working as a software developer. And yesterday I came across a problem which thought me how a lesson.

The project I was working is basically a custom import tool for a financial software. We get an CSV or an XML file and that is imported using the SDK of the financial software. Nothing hard except that the SDK is unfinished and various features are yet to be implemented. The majority does work, but it is like walking through a mine field and every time you move forward the application might blow up in your face :twisted:

The application is written in Visual Basic .NET (not my choice, but it does the job) and the SDK uses exceptions to notify that a certain feature is not working or when a certain object doesn't meet certain requirements when you ask it to be saved.

Because of the huge amount of data, I used reflection so that I don't have to type as much. My system also uses exceptions, and I won't be surprised if you already where this is going, but while I was debugging I came across multiple exceptions of the SDK which meant that I either had to write a workaround for it or remove the feature until the SDK does support it. When I finally fixed the majority of the errors I suddenly got hit in the face by the following exception:
[cc_text]Unable to complete save[/cc_text]

Now the SDK did provide cryptic error messages but this one was completely new and I was doing a bare bone test. I called a coworker over to see if he knew what it meant but he also didn't know what the message meant. A few minutes later he came back to me and said that the part of the SDK did work on his side and that the error must be somewhere in my code.

To cut a long story short. The exception that I got was my own and I hadn't noticed because I had already encountered so many exceptions of the SDK that I just presumed that it was again the SDK that was throwing a fit. :oops:

Once I realized that it didn't take long to solve it (I returned a true instead of false somewhere), however I was more worried about how to prevent it in the future. After some thought that also was simple.

If any of the application code would throw a fit it would throw not the standard exception which would have been:
[cc_vb]throw new Exception("Unable to complete save")[/cc_vb] but a custom type and a search and replace later we got:
[cc_vb]throw new UtilityException("Unable to complete save")[/cc_vb] so that error message would contain a special prefix by which it would be clear that it was our own code that decided to throw an exception.
[cc_vb]
Public Class UtilityException
Inherits System.Exception
Public Sub New(ByVal str As String)
MyBase.new(str)
End Sub

Public Overrides ReadOnly Property Message() As String
Get
Return "UtilityException: " & MyBase.Message
End Get
End Property
End Class
[/cc_vb]

In the future we will know when it was our own mine to blew up. A simple solution but it would have saved us a lot of time if we had done this from the start.

6Mar/100

Information about Brick3

Brick3 is the third iteration of the grand project I decided to call "Brick" and I think I have mentioned it quite a few times before, but never gone in to detail, which is the reason for this post.

I'm from the IT sector and one of the things I thought myself early is that the computer should work for me and not the other way around. In the Netherlands IT used to be called "Automation" but I'm not certain if many people still know that or try to write programs by that principle.

In the game industry we have something called procedural generation (also known as procedural content generation) which is letting the computer generate the content in game. This can be music which changes depending on the amount of danger the play can be in (adding rhythmic drumming) or textures which are generated by the computer instead of an artist. Those are all examples of generating content by the computer instead of by human.

Any process can be fully converted to logic and any logic can be programmed. A computer can be used to execute any process as long as I'm able to convert the process to logic and program that logic.
-- Wouter Lindenhof

The above quote is mine. And what I'm saying is that in time a computer should be able to replace any human, although I don't that to happen in my lifetime (and I'm young).

However the above quote is what brick3 is all about. The earlier examples were all based on the fact the design was done ahead of the actual content generation. After all the music was composed and the texture that was generated was most likely done based on an algorithm. An example for the last one but then for a mesh can be found in this blog post Donuts! (Procedural Torus in C++).

Brick3 is a bit different as it wants to let the computer do the design instead of you. It tries to generate a flat and based on requirements (you don't want a toilet in your living room) it will place the location of rooms and places the objects (lamps, light switches, paintings, trashcans et cetera). If you would use that in game like for example Grand Theft Auto you would be able to enter every house and assuming everything works correct you would have a fully designed interior while as a programmer (or artists) you hardly have to do a thing.

Anyway since a picture sometimes says more take a look the following screenshots.

This screenshot shows the minimal graphical quality I want to have. Graphics are important as they play part in deciding whether or not to buy a game. Besides that it also says a lot about the level of finish and the dedication put in the product. Although walls appear to have depth, they are flat, but using some smart programming code an illusion is created and when you look at the next screenshot I think everyone will agree that high graphical quality is a requirement for this application.

This screenshot shows the current state of the application. You will see that everything has a dummy texture and you will notice that not all walls are attached (this is because that a door is not generated and once it is does it will show a nice door frame). Both rooms have the same function and the big room that is directly in front of the camera is a test room (it is 27 by 27 by 27 meters big).

Besides the obvious issues the application is reaching its completion. There are some minor issues with placement and I need to improve the performance at some points but after that I only need to add some new models (the furniture is not procedural generated) and I will give some extra requirements and the application should design a room according to my specification.
Although I have to admit it doesn't look like much at this point, I think many people will be surprised once the end result is ready. Not only will it be able to generate fully random interiors of flats, buildings and rooms but it will do so as if it was designed by a human and only I have to do is hit one key to generate a complete new result.

2Mar/100

[DONE] Taking my time updating the website

Updating the site will take some time as I need to convert small parts of multiple posts to get it look correct. If you are using an RSS feed to keep track of the website, I'm sorry for any inconvenience it might cause.

If you find something missing or if your own links to my site, please send me a mail (or comment on this item) and I will try to fix it as soon as I can.

The good news is that wordpress is faster and easier to use than what I had before. The downside however is that all links need to be updated and some downloads won't be directly available until later.

UPDATE 2010-03-03 21:49: A quarter has now been done. It's going slower than expected as I need to correct quite a few pages and some of the links have changed so much that I lose at least a good 15 minutes to try and fix all of those. The good news is that I like wordpress, the interface is easy, although I miss the mugshot that I had on my old site ;)

UPDATE 2010-03-06 12:47: Most of the important post have been transfered and I have decided to skip the rest. From this point on no new "old posts" will be added unless I notice that someone is going to an old link. If you do need a certain article you can use the contact form to send me a notice.

Tagged as: No Comments
2Mar/106

Wavefront Obj Mesh Loader

UPDATED 2010-09-26 09:08: No longer relying upon char arrays
UPDATED 2010-03-02 11:07: There was a minor bug in the code which caused to tokens recognition to file. You won't encounter it in an obj file, but I fixed it for the good order.
UPDATED 2012-02-12 21:27: Benjamin Sommer linked to this article in which he goes in to a lot of detail: A tiny wavefront object loader - part I.

I can remember the first time I wrote my Obj Mesh loader. It took hours. Today I needed also an obj mesh loader and this time it took mere minutes (under 15 minutes at least), so I have decided to share it. Keep in mind you should most likely separate it in header and source files.


/**
 * The MIT License
 *
 * Copyright (c) 2010 Wouter Lindenhof (http://limegarden.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <string>
#include <vector>
#include <sstream>
#include <fstream>

#define TOKEN_VERTEX_POS "v"
#define TOKEN_VERTEX_NOR "vn"
#define TOKEN_VERTEX_TEX "vt"
#define TOKEN_FACE "f"

struct Vector2f{
    float x, y;
};
struct Vector3f{
    float x, y, z;
};

struct ObjMeshVertex{
    Vector3f pos;
    Vector2f texcoord;
    Vector3f normal;
};

/* This is a triangle, that we can render */
struct ObjMeshFace{
    ObjMeshVertex vertices[3];
};

/* This contains a list of triangles */
struct ObjMesh{
    std::vector<ObjMeshFace> faces;
};

/* Internal structure */
struct _ObjMeshFaceIndex{
    int pos_index[3];
    int tex_index[3];
    int nor_index[3];
};

/* Call this function to load a model, only loads triangulated meshes */
ObjMesh LoadObjMesh(std::string filename){
    ObjMesh myMesh;

    std::vector<Vector3f>           positions;
    std::vector<Vector2f>           texcoords;
    std::vector<Vector3f>           normals;
    std::vector<_ObjMeshFaceIndex>  faces;
    /**
     * Load file, parse it
     * Lines beginning with:
     * '#'  are comments can be ignored
     * 'v'  are vertices positions (3 floats that can be positive or negative)
     * 'vt' are vertices texcoords (2 floats that can be positive or negative)
     * 'vn' are vertices normals   (3 floats that can be positive or negative)
     * 'f'  are faces, 3 values that contain 3 values which are separated by / and <space>
     */

    std::ifstream filestream;
    filestream.open(filename.c_str());

	std::string line_stream;	// No longer depending on char arrays thanks to: Dale Weiler
	while(std::getline(filestream, line_stream)){
		std::stringstream str_stream(line_stream);
		std::string type_str;
        str_stream >> type_str;
        if(type_str == TOKEN_VERTEX_POS){
            Vector3f pos;
            str_stream >> pos.x >> pos.y >> pos.z;
            positions.push_back(pos);
        }else if(type_str == TOKEN_VERTEX_TEX){
            Vector2f tex;
            str_stream >> tex.x >> tex.y;
            texcoords.push_back(tex);
        }else if(type_str == TOKEN_VERTEX_NOR){
            Vector3f nor;
            str_stream >> nor.x >> nor.y >> nor.z;
            normals.push_back(nor);
        }else if(type_str == TOKEN_FACE){
            _ObjMeshFaceIndex face_index;
            char interupt;
            for(int i = 0; i < 3; ++i){
                str_stream >> face_index.pos_index[i] >> interupt
                           >> face_index.tex_index[i]  >> interupt
                           >> face_index.nor_index[i];
            }
            faces.push_back(face_index);
        }
    }
	// Explicit closing of the file
    filestream.close();

    for(size_t i = 0; i < faces.size(); ++i){
        ObjMeshFace face;
        for(size_t j = 0; j < 3; ++j){
            face.vertices[j].pos        = positions[faces[i].pos_index[j] - 1];
            face.vertices[j].texcoord   = texcoords[faces[i].tex_index[j] - 1];
            face.vertices[j].normal     = normals[faces[i].nor_index[j] - 1];
        }
        myMesh.faces.push_back(face);
    }

    return myMesh;
}