Wednesday, December 28, 2016

Unit test my code

Now is the time for serious thing - unit testing. To make sure I'm doing the right thing with my code. Frankly speaking, implementing unit test in C++ is my first time. Not even heard of it in the past. Wasting a lot of my time discovering C++ unit test framework, surprisingly, Boost's test framework was quite user friendly.

To adopt this thing into my project, I've come an idea that is suited for my test case. The idea like this, for each test case, 2 folders will be created to mimic the source location and destination location. Thus I have a class named PrepareFile for this purpose, the constructor will invoke when each test case begins, and the destructor will invoke when the test case has ended:
class PrepareFile
{
public:
    PrepareFile() {
        create_directory("path_A");
        create_directory("path_B");

        BOOST_TEST_MESSAGE("Creating test folder");
    }
    ~PrepareFile() {
        remove_all("path_A");
        remove_all("path_B");

        BOOST_TEST_MESSAGE("Removing test folder");
    }
};

/*  Test case: Cap_T1
 *  Test scenario: path_A has one file
 *  Test result: one file is captured in index file
 */
BOOST_FIXTURE_TEST_CASE(Cap_T1, PrepareFile)
{
    ...
}

/*  Test case: Cap_T2
 *  Test scenario: path_A has one file, path_B has one file.
 *  Test result: files in both paths has captured in index file.
 */
BOOST_FIXTURE_TEST_CASE(Cap_T2, PrepareFile)
{
    ...
}
I like this test framework structure because it could provide me a clean test environment. Anyhow, this is just a tiny test in my code, SIT effort is still required.

Saturday, December 24, 2016

Generate WSDL file with wsgen

Today I'm running a Web Service experiment again. But I just feel that I'm making a tutorial right now. No way, this is just a finding on my silly mistake though. Assuming I have the following code setup:
package org.huahsin.main.bo;

...

@WebService(targetNamespace = "http://main.huahsin.org/")
public interface IPersonService {

 @WebMethod
 public String getPerson(String name);
}


package org.huahsin.main;

...

@WebService(serviceName = "PersonService", 
   endpointInterface = "org.huahsin.main.bo.IPersonService",
   portName = "PersonServicePort")
public class PersonService implements IPersonService {

 @Override
 public String getPerson(String name) {
  return "Hello World " + name;
 }

}
Take good care of the endpointInterface, I mess up this name with the implementation class name, that suppose belong to an Interface. Next is to fire up the WSDL through HTTP. Previously I was using this trick to make a WSDL file:
public class PersonClient {

 public static void main(String[] args) {
  Endpoint.publish("http://localhost:8080/ws", new PersonService());
 }
}
And then hit the URL http://localhost:8080/ws?wsdl in the browser, copy the content in the WSDL file. Actually wsgen has already covered the WSDL file generation with -wsdl as shown following command:

wsgen -keep -wsdl -cp ./WebContent/WEB-INF/classes org.huahsin.main.PersonService

There will be some minor modification on the REPLACE_WITH_ACTUAL_URL after WSDL file is generated:
  <service name="PersonService">
    <port binding="tns:PersonServicePortBinding" name="PersonServicePort">
      <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
    </port>
  </service>
Just replace any URL as you like, make sure the IP and port are accessible, it is very useful to determine what are the service available currently deployed.

* Do take note that when I deploy this code into WebSphere Liberty Profile (v8.5.5.8 as of this writing) with CXF runtime bundle with my code, it causes conflict error. According to the documentation, I should not enable jaxws-2.2 feature.
If you application provides its own copy of CXF JAR files as the application libraries, for example, in the WEB-INF/lib directory of a web application, you cannot enable the jaxws-2.2 feature in the server.xml file.

Thursday, December 22, 2016

New use case identified.

The experiment in my test lab was so successful. Feeling good? Not too early. Things always not working when put into real environment. Just like the use case diagram below.
Figure 1: Files are captured into index file
Notice that the files are captured into a file (index file) but not a destination. There are 2 problems I need to solve when I draft this design:
  1. to let the program know there are some files has been removed and thus the copy in destination must remove as well. 
  2. file exist in destination path but not in source path are consider orphan file. I'm trying to prevent these orphan file being removed from destination path.
Here are the requirements during the capturing process:
  • First scan will be done on the destination location.
  • Next scan will be done on the origin location.
  • If the file shown in origin location, but missing in a destination location, put a plus sign to indicate this file need to be added in. During the sync process, the file will be copied to the destination.
  • If the file was missing in origin location, but shown in the destination location, put a minus sign to indicate the file need to be removed. During the sync process, the file will be removed from the destination.
This was a real damn hard work logic. First thing first, I'll load up the content of index files into memory called fileContent through the constructor, this is the only chance I can load them up into memory when the FilePath object got intialized.
void FilePath::captureExistingFile()
{
    std::ifstream indexFile(indexFilePath, ios_base::in);
    string line = "";
    while( std::getline(indexFile, line) ) {
        fileContent.insert(line);
    }
    indexFile.close();
}


class FilePath
{
...
...

private:
    set<string> fileContent;
    path rootPath;
    std::ofstream indexFile;
};

FilePath::FilePath(path thePath)
    : rootPath(thePath), searchDone(false)
{
    ...

    // capture the index file content into memory
    indexFilePath = rootPath + string(1, path::preferred_separator) + ((seperatorPos > 0) ? filename : converterX.to_bytes(thePath.wstring())) + ".i";

    if( exists(indexFilePath) ) {
        captureExistingFile();
        bFileExist = true;
    }

    indexFile.open(indexFilePath, ios_base::in | ios_base::out | ios_base::app);
}
That is for the requirement 1 and 2. To handle the requirement plus and minus flag, here is the work around:
void FilePath::captureFiles(path searchPath)
{
    bool bPlus = false, bMinus = false;
    vector<path> pathList;

    if (rootPath.size() == 0) {
        rootPath = searchPath;
    }

    if( exists(searchPath) ) {
        // capture the paths/files list under the source

        ...

        // scan through path and those files sit in that path
        // scan for files in sub directory if there is any sub directory in that path
        for(vector<path>::const_iterator it(pathList.begin()); it != pathList.end(); ++it) {

            ...

            file = file.substr(thePath.length() + 1, file.length());

            // remove the files when index file content is larger than actual path
            if( fileContent.size() > pathList.size() - 1 ) {
                set<string>::iterator result = std::find(std::begin(fileContent), std::end(fileContent), file);
                if( result != std::end(fileContent) ) {
                    fileContent.erase(file);
                    bMinus = true;
                }
            }
            // new file has arrive when index file does exists
            // this block wouldn't execute if the path has never been scan before
            else if( fileContent.size() != 0 ){
                set<string>::iterator result = std::find(std::begin(fileContent), std::end(fileContent), file);
                if( result == std::end(fileContent) ) {
                    bPlus = true;
                    fileContent.insert(file);
                }
                else {
                    continue;
                }
            }

            ...

            // it is a file
            else {
                fileSet.insert(file);

                string filename(file.begin(), file.end());

                if( bPlus ) {
                    bPlus = false;
                    indexFile << "+" << filename << endl;
                }
                else if( !bMinus ) {
                    bMinus = false;
                    indexFile << filename << endl;
                }
            }
        }
    }

    indexFile.close();

    // there are some files has been remove
    // replace the content of index file
    if( bFileExist && bMinus ) {
        indexFile.open(indexFilePath, ios_base::out | ios_base::trunc);
        for( set<string>::iterator it=fileSet.begin(); it != fileSet.end(); it++ ) {
            indexFile << *it << endl;
        }

        for( set<string>::iterator it=fileContent.begin(); it != fileContent.end(); it++ ) {
            indexFile << "-" << *it << endl;
        }
    }

}
Sometimes I can't even remember my work after a few years not looking on my code, duh~

Sunday, December 18, 2016

The searching mechanism is ready

The fun part of this program, file searching, is created. This module was dominated by boost::filesystem. I start off with some experiment on this module. Then slowly evolve piece by piece from my test lab, and now it has graduate become a man that took up the responsible on file searching. This is the attribute of the object:
class FilePath
{
public:
    FilePath();
    FilePath(path thePath);

    void captureFiles(path searchPath);
    set<wstring> getFileSet() { return fileSet; }


private:
    bool checkPathExists(path workingPath);


private:

    set<wstring> fileSet;
    path rootPath;
    bool searchDone = false;
    void clearFileSet() { fileSet.clear(); }
};
Each of this object will be responsible on each path. Only one and no more! The strongest power, captureFiles() is the most important function this object could ever had. It searches for files, and capture them into memory (cool huh?):
void FilePath::captureFiles(path searchPath)
{
    vector<path> pathList;

    if( rootPath.wstring().length() == 0 )
        rootPath = searchPath;

    if( exists(searchPath) ) {
        // capture the paths/files list under the source
        copy(directory_iterator(searchPath), directory_iterator(), back_inserter(pathList));

        // scan through each path/file to categorize them either path or file
        for(vector<path>::const_iterator it(pathList.begin()); it != pathList.end(); ++it) {
            wstring file = (*it).wstring();
            wstring thePath = rootPath.wstring();
            file = file.substr(thePath.length() + 1, file.length());

            // it is a directory
            if( is_directory(status(*it)) ) {
                captureFiles(*it);
            }
            // it is a file
            else {
                fileSet.insert(file);
            }
        }
    }

    searchDone = true;
}
The key of this object is the rootPath. When this object is summoned, one must not forget is to tell which path to go, just as shown below:
FilePath::FilePath(path thePath)
    :rootPath(thePath), searchDone(false)
{
}
If the key was missing during initialization, this object might behave abnormally.

Sunday, December 11, 2016

Going deep to the backup plan

To start off the backup plan, I will need Qt and Boost. Before this, I'm a fan of MFC, everything I did is for Windows (only). But now I was using Windows and Linux together, thus I think Qt would be my best support on UI work for cross platform environment. Boost contains many flavor type of algorithm that could ease up my development effort.

I start off this project with unit test. I am a true fan of Test Driven Development methodology. I've been using this methodology for years, and it proves the lesser defects report from the tester. So I believe that a quality product comes from quality code. A quality code depends on how well you design the code. And unit test would be the quality controller on my code.

Sometimes I do use unit tests code as my code documentation for other developers, this may not true for others, but I just so lazy to prepare functional documentation.

Well, that's all for the plan. Wish me luck!

Monday, December 5, 2016

I need a backup plan

In the year of 2016, I was planning to write more code about game development but struggling where could I get start. Well, I start off making the fundamental stuff and end up making a tutorial on game development quick start guide. No! This isn't my objective. I want to make a real person of myself while I'm coding on a game. Somehow in one day, my hard disk failed to boot up and all my hard work effort are gone. The most unlucky thing was I don't have a "real" backup plan, thus restoring my files has turn into nightmare. I spend few months doing the recovery until now, there are still missing parts.

In the past few months while doing my recovery job and also trying my best to recover the code, I started to realize on the disaster recovery plan. I put this at the top and highest priority in my working queue. And I have come up a draft plan for the design. Since my backup files are scattered around in different computers and the external medium, I would need a tool to consolidate all my backup files in one place. And also house keeping the backup files is a must to maintain storage capacity.

The high level design would be something like this: as for now, the backup files are currently scattered around in different computer. There will be relocated to a central storage and I'm pretty sure there must be the same files locate in others PC as well, thus I need to have the central storage setup.

Figure 1: When all PCs come online

After that all files on other computers will be synced up together. Well, that's about the plan. If I want to automate the process, how complicate will it be?

Thursday, March 24, 2016

Why default GL library crash with string declaration on Linux?

How can this simple OpenGL program can throw a segmentation fault?
#include "GL/glew.h"
#include "GL/freeglut.h"
#include <iostream>


std::string a;

int main(int argc, char **argv)
{
   return 0;
}

I don't think this is a joke. Even if I omit the string, the program will still running fine with cout. Am I wrongly setup the IDE? Things were settled until I found this bug report, this could be a serious problem. I run the ldd check and find it there isn't any linkage to pthread.

kokhoe@KOKHOE:~/workspacec/OpenGL1/Debug$ ldd OpenGL1
 linux-vdso.so.1 =>  (0x00007ffe14f5e000)
 libglut.so.3 => /usr/lib/x86_64-linux-gnu/libglut.so.3 (0x00007f9b24659000)
 libGL.so.1 => /usr/lib/nvidia-352/libGL.so.1 (0x00007f9b24329000)
 libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9b24025000)
 libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9b23e0f000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9b23a4a000)
 libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f9b23715000)
 libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9b2340f000)
 libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f9b231ff000)
 libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f9b22ff9000)
 libnvidia-tls.so.352.63 => /usr/lib/nvidia-352/tls/libnvidia-tls.so.352.63 (0x00007f9b22df6000)
 libnvidia-glcore.so.352.63 => /usr/lib/nvidia-352/libnvidia-glcore.so.352.63 (0x00007f9b20363000)
 libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f9b20151000)
 libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9b1ff4d000)
 /lib64/ld-linux-x86-64.so.2 (0x00007f9b248a3000)
 libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f9b1fd2e000)
 libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f9b1fb2a000)
 libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f9b1f924000)

But interestingly, I see there is a link with nVidia driver. I then find out there is another libGL did installed in /usr/lib/nvidia-352. If I link my program with this GL library, everything would go fine.

Hmmm... Could it be the permanent workaround for this problem?

Saturday, February 27, 2016

I forget to install NVIDIA driver

What!! The supported OpenGL shader language version is only 1.3? I was shocked when I am first seeing this.

I'm just feeling bored from my daily coding routine, thus thinking to try out something new to get some new inspiration. I grab the piece from learnopengl.com hoping to get some sparkling idea:
const GLchar* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "void main()\n"
    "{\n"
    "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
    "}\0";

int main(int argc, char **argv)
{
    ...

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // Check for compile time errors
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    ...
}

But what's surprising me is that the program failed to run even though I have NVIDIA GT 610 installed. What even surprising me when I issue the following command:
kokhoe@KOKHOE:~$ lspci -vnn | grep -i VGA -A 12
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GF119 [GeForce GT 610] [10de:104a] (rev a1) (prog-if 00 [VGA controller])
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]
 Flags: bus master, fast devsel, latency 0, IRQ 45
 Memory at f6000000 (32-bit, non-prefetchable) [size=16M]
 Memory at e8000000 (64-bit, prefetchable) [size=128M]
 Memory at f0000000 (64-bit, prefetchable) [size=32M]
 I/O ports at e000 [size=128]
 Expansion ROM at f7000000 [disabled] [size=512K]
 Capabilities: <access denied="">
 Kernel driver in use: nouveau

01:00.1 Audio device [0403]: NVIDIA Corporation GF119 HDMI Audio Controller [10de:0e08] (rev a1)
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]

Notice that the Kernel driver in use is showing nouveau?! That means I have not yet install the driver since the first day I got the NVIDIA card. To fix this error, I installed the driver (see here to see how I do the installation), make a final verification:
kokhoe@KOKHOE:~$ lspci -vnn | grep -i VGA -A 12
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GF119 [GeForce GT 610] [10de:104a] (rev a1) (prog-if 00 [VGA controller])
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]
 Flags: bus master, fast devsel, latency 0, IRQ 46
 Memory at f6000000 (32-bit, non-prefetchable) [size=16M]
 Memory at e8000000 (64-bit, prefetchable) [size=128M]
 Memory at f0000000 (64-bit, prefetchable) [size=32M]
 I/O ports at e000 [size=128]
 [virtual] Expansion ROM at f7000000 [disabled] [size=512K]
 Capabilities: <access denied="">
 Kernel driver in use: nvidia

01:00.1 Audio device [0403]: NVIDIA Corporation GF119 HDMI Audio Controller [10de:0e08] (rev a1)
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]

Ah ha~ now it shows nvidia is the current driver in use. Before I run the program, I just want to make sure the supported shader language is 3.3.
kokhoe@KOKHOE:~$ glxinfo | grep 'version'
server glx version string: 1.4
client glx version string: 1.4
GLX version: 1.4
OpenGL core profile version string: 4.3.0 NVIDIA 352.63
OpenGL core profile shading language version string: 4.30 NVIDIA via Cg compiler
OpenGL version string: 4.5.0 NVIDIA 352.63
OpenGL shading language version string: 4.50 NVIDIA
Now my OpenGL info shows me version 4.5, it is far more advance than the expected version. This shouldn't be a problem with my program.

Monday, February 15, 2016

Does Flyweigh pattern really help in memory management?

In a game architecture design, memory allocator is one of the core modules sit in the game system. I’m so wondering how could I implement this module and why do I need this? After reading many articles from the experts, understand that this is a crucial part of game performance when there are thousands of game objects being spawned at a time. Due to the slow performance of the new/delete operator, it is advisable to implement a very own or game specific memory allocator. But how could I do it?

Forget about those big games adopting very advance features of memory allocator. I should focus on my game since my game is categorized as a casual game. So the most basic need for me would be:
  1. Able to allocate from OS and release memory back to the OS.
  2. The memory pool should be expandable and return the memory back into the pool.
  3. The memory pool should not release the memory back to OS until the game exit.
For this purpose, I’m borrowing the idea of Flyweigh pattern, the idea of this pattern is to minimize the memory usage by sharing as much data as possible with other similar objects. First thing first, I define a default pool size of 10 whenever a new memory pool was created:
template <typename T>
class GameObjectPool
{
private:
 static const int POOL_SIZE = 10;

 T *freshPiece; 
}
Notice the use of template for this class, it is to allow the game to be able to allocate different kinds of game object (eg. particle, sprite) in the pool. freshPiece will be responsible for holding the available memory chunk for the game object. When the pool is first constructed, freshPiece was empty. There isn't any game object hold by freshPiece. Thus, the pool will first acquire some memory from the OS. This was done in the constructor:
template <typename T>
class GameObjectPool
{
public:
 GameObjectPool () {
  fillUpMemory();
 }
 ...
private:
 void fillUpMemory() {
  T *curObj = new T();
  freshPiece = curObj;

  for (int i = 0; i < POOL_SIZE - 1; i++) {
   curObj->setNext(new T());
   curObj = curObj->getNext();
  }

  curObj->setNext(nullptr);
 }

}
Once the game was finished, the memory is released back to the OS:
template <typename T>
class GameObjectPool
{
public:
 ~GameObjectPool() { 
  Particle *curObj = freshPiece;

  if (freshPiece != nullptr) {
   for (; curObj; curObj = freshPiece) {
    freshPiece = freshPiece->getNext();
    delete curObj;
   }
  }
 }
}
During the game runtime, the game object will acquire the memory from the pool instead of using the new keyword:
template <typename T>
class GameObjectPool
{
public:
 inline T *create() {
  if (freshPiece == nullptr)
   fillUpMemory();

  T *curObj = freshPiece;
  freshPiece = freshPiece->getNext();

  return curObj;
 }

}
Once the game object has done his job, the memory will release back to the pool. Same thing as acquiring the memory, no delete keyword is used:
template <typename T>
class GameObjectPool
{
public:
 inline void release(T* obj) {
  obj->setNext(freshPiece);
  freshPiece = obj;
 }
}
Notice the POOL_SIZE I pre-code it to 10, this is due to my laziness. I let the pool automatically allocate the predefined pool size if it exceeds the available pool size. May be in the future, I will need a more elegant way to adjust the pool size as shown below:
template <typename T>
class GameObjectPool
{
public:
GameObjectPool() {
  fillUpMemory();
 }

 GameObjectPool(int poolSize) : mPoolSize(poolSize) {
  fillUpMemory();
 }

...

private:
 void expandPoolSize() {
  T *curObj = new T();
  particleHead = curObj;

  for (int i = 0; i < mPoolSize - 1; i++) {
   curObj->setNext(new T());
   curObj = curObj->getNext();
  }

  curObj->setNext(nullptr);
 }

private:
 int mPoolSize = 10;

 T *freshPiece; 
}
Well, this is my very first version that meets the most basic fundamental of my game.