Archive

Author Archive

OpenGL 4.1 Goodness

July 27th, 2010 Jerdak No comments

OpenGL made some waves w/ their recent posting of the 4.1 specifications. Most notably the ability to save and load binary shader programs via GL_ARB_get_program_binary.

According to NVIDIA, via Ars Technica:

NVIDIA says that it will release OpenGL 4.1 drivers on or before Wednesday, with AMD (ATI) releasing them shortly. As is now traditional, Apple has given no indication of when, if ever, it will update Mac OS X’s OpenGL drivers to support the new standard; the company does not have full support for OpenGL 3.0. – ars technica

Additionally it appears that OpenGL 3.3 offers some support for this feature. OpenGL 4.1 doesn’t have any hardware specific requirements.

Usage, Ripped directly from the ARB specs.:

void retrieveProgramBinary(const GLchar* vsSource, const GLchar* fsSource,
                               const char* myBinaryFileName, 
                               GLenum* binaryFormat)
    {
        GLuint        newFS, newVS;
        GLuint        newProgram;
        const GLchar* sources[1];
        GLint         success;
 
        GLint   binaryLength;
        GLvoid* binary;
        FILE*   outfile;
 
        //
        //  Create new shader/program objects and attach them together.
        //
        newVS = glCreateShader(GL_VERTEX_SHADER);
        newFS = glCreateShader(GL_FRAGMENT_SHADER);
        newProgram = glCreateProgram();
        glAttachShader(newProgram, newVS);
        glAttachShader(newProgram, newFS);
 
        //
        //  Supply GLSL source shaders, compile, and link them
        //
        sources[0] = vsSource;
        glShaderSource(newVS, 1, sources, NULL);
        glCompileShader(newVS);
 
        sources[0] = fsSource;
        glShaderSource(newFS, 1, sources, NULL);
        glCompileShader(newFS);
 
        glProgramParameteri(newProgram, PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
        glLinkProgram(newProgram);
        glGetProgramiv(newProgram, GL_LINK_STATUS, &success);
 
        if (!success)
        {
            //
            // Fallback to simpler source shaders?  Take my toys and go home?
            //
        }
 
        glUseProgram(newProgram);
 
        //
        // Perform rendering and state changes likely to be encountered.
        //
        DoRendering(newProgram);
 
        //
        //  Retrieve the binary from the program object
        //
        glGetProgramiv(newProgram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
        binary = (GLvoid*)malloc(binaryLength);
        glGetProgramBinary(newProgram, binaryLength, NULL, binaryFormat, binary);
 
        //
        //  Cache the program binary for future runs
        //
        outfile = fopen(myBinaryFileName, "wb");
        fwrite(binary, binaryLength, 1, outfile);
        fclose(outfile);
        free(binary);
 
        //
        // Clean up
        // 
        glDeleteShader(newVS);
        glDeleteShader(newFS);
        glDeleteProgram(newProgram);
    }
 
    void loadProgramBinary(const char* myBinaryFileName, GLenum binaryFormat,
                           GLuint progObj)
    {
        GLint   binaryLength;
        GLvoid* binary;
        GLint   success;
        FILE*   infile;
 
        //
        //  Read the program binary
        //
        infile = fopen(myBinaryFileName, "rb");
        fseek(infile, 0, SEEK_END);
        binaryLength = (GLint)ftell(infile);
        binary = (GLvoid*)malloc(binaryLength);
        fseek(infile, 0, SEEK_SET);
        fread(binary, binaryLength, 1, infile);
        fclose(infile);
 
        //
        //  Load the binary into the program object -- no need to link!
        //
        glProgramBinary(progObj, binaryFormat, binary, binaryLength);
        free(binary);
 
        glGetProgramiv(progObj, GL_LINK_STATUS, &success);
 
        if (!success)
        {
            //
            // Something must have changed since the program binaries
            // were cached away.  Fallback to source shader loading path,
            // and then retrieve and cache new program binaries once again.
            //
        }
    }
Categories: Uncategorized Tags:

With Love Frosty

July 19th, 2010 Jerdak No comments

A joke poster I made for Frosty after an amusing game where he spent his free time jacking my kills. It was all in good fun and it was by far one of our better games. I freely admit I still love spending an evening killing zombies with friends. I don’t know what other folks do but I can’t imagine a better way to unwind.

Categories: Uncategorized Tags:

Poor man’s A/C

June 22nd, 2010 Jerdak No comments

Lifehacker brings this interesting article about staying cool w/o the need for air conditioning (…. no thank you) but the first item on their list made me smile.

Back in college our “air conditioner” was a bucket/bag of ice sitting in front of a fan. The “peak” cooling time was when the ice had somewhat melted and the fan began blowing a tiny mist throughout the room.

Categories: Uncategorized Tags:

Cleaner Theme

June 14th, 2010 Jerdak No comments

As you can see the theme has been touched up a bit. I got tired of the tiny reading area and the dual widget columns. I believe this one is called iNova on top of which I’ve made just a couple of modifications.

Categories: Uncategorized Tags:

WinSCP Wrapper (Managed c++)

June 14th, 2010 Jerdak No comments

Here is a little code I wrote to help me access WinSCP via Managed C++.

The code is extremely simple.  A worker thread is spawned which reads from a message packet.  Even though this class uses a worker thread it is technically synchronous.  You can only run a new WinSCP command when the last one has been completed.  The basic logic is thus:  Assign Command to WinSCP -> WinSCP Runs Command Automatically -> WinSCP Returns to a MessageComplete delegate -> Assigned a Command to WinSCP

There isn’t a particular reason for my lack of true asynchronous support other than a lack of time for proper coding.  The time saved by running commands from a queue is negligible given how little I do with the data I request in my apps.  That’s also why you’ll see the beginnings of thread safety (locking) but why it isn’t complete.  Since everything has to run in a specific order there is no need to lock any variables.

The code for this project is being attached directly to this post rather than in my SVN account.

Usage:

ref class ScpRun {
public:
	ScpRun(){
		_commandList = gcnew System::Collections::Generic::List<WinScpCmd^>;
		_scp = gcnew WinScpWrapper();
		_this = this;
		_account = gcnew String("");
	};
	bool Done(){return _bDone;}
	void Run();
	void Stop(){_this->_scp->RequestStop();}
 
	///Get/Set WinSCP account name
	property String ^Account {
		String ^ get(){return _account;}
		void set(System::String ^ s){_account = s;}
	};
protected:
 
	///WinSCP message is complete
	static void ScpMessageComplete(System::Object ^sender, WinScpEventArgs ^args);
private:
 
	///WinSCP wrapper API
	WinScpWrapper ^_scp;
 
	///Command stack (each return message from WinSCP)
	System::Collections::Generic::List<WinScpCmd^> ^_commandList;
 
	///Self-referential pointer for worker thread
	private: static ScpRun ^_this;
 
	///Worker thread complete?
	bool _bDone;
 
        ///WinSCP account name
	System::String ^_account;
};

There isn’t much going on here. We create a generic WinSCP handler class. In my example we create a command stack (just a list), each successive command is sent to WinSCP when the previous one is complete.

ScpRun::Run

void ScpRun::Run(){
	_bDone = false;
	{	///Create command list
 
                //The very first call MUST be to open an account name.  I suggest setting up an easy name using WinSCP that you can reference here.
                _commandList->Add(gcnew WinScpCmd(WSC_OPEN,_account));
 
                //Next we'll add a command to print the current working directory	
		_commandList->Add(gcnew WinScpCmd(WSC_PWD,""));
 
                //Now lets dump the contents of our current directory
		_commandList->Add(gcnew WinScpCmd(WSC_LS,""));
 
                //Lastly be sure to kill your connection
		_commandList->Add(gcnew WinScpCmd(WSC_CLOSE,""));
	}
 
        //Pull the first command off our command stack and call WinSCP
	WinScpCmd ^tmp = _commandList[0];
	_commandList->RemoveAt(0);
 
        //Here we send our command to WinSCP, arguments are parsed by the class
	scp->wsc_call(tmp->Command,tmp->Arguments);
 
        //Be sure to assigned a MessageComplete callback function
	scp->WSCMessageComplete += gcnew WinScpWrapper::MessageComplete(&ScpRun::ScpMessageComplete);
 
        //Tell WinSCPWrapper it's time to start
        scp->RequestStart();
}

Again, all real simple code. We’ve added 4 commands to our command stack and we’ve sent the first off to be run. When that command is complete (successfully or not) it will push out an event to any MessageComplete handlers. I should note here that there isn’t any sort of timeout value. An assumption is made (wrongfully or not) that WinSCP will always return a value.

ScpRun::ScpMessageComplete

void ScpRun::ScpMessageComplete(System::Object ^sender, WinScpEventArgs ^args){
	//Arguments only have 2 states, success or failure.
        if(!args->_bSuccess){
		switch(args->_trigger){
			case WSC_PWD:
			case WSC_LS:
			case WSC_OPEN:
			case WSC_CLOSE:
				printf("Crap-sicle our command has failed.");
				break;
			default:
				break;
		}
		printf("[Command %s failed.]\n",args->_fullCommand);
	} else {
		switch(args->_trigger){
			case WSC_LS:{
				break;
			case WSC_PWD:
				break;
			default:
				printf("Command %s complete.\n",args->_fullCommand);
				printf("   - Value: %s.\n",args->_value);
				break;
		}
	}
 
	///If command list contains more commands, run them.  (Demo only)
	if(_this->_commandList->Count > 0){
		WinScpCmd ^tmp = _this->_commandList[0];
		_this->_commandList->RemoveAt(0);
		_this->scp->wsc_call(tmp->Command,tmp->Arguments);
	} else {
		_this->_bDone = true;
	}
}

Here we handle return messages from our WinSCP wrapper. It would be advisable to add some code here to handle an error from WSC_OPEN that tells the command stack to stop issue commands and set _bDone to true;

The only remaining action is to run our handler class:

	ScpRun ^scp = gcnew ScpRun ();
	scp->Account		= "dummy_account_name";
	scp->Run();
 
	//loop until done
	while(!scp->Done()){
		Threading::Thread::Sleep(15);
	}
	//Tell SCP to stop which in turn tells our WinSCP wrapper to kill its worker thread.
	scp->Stop();

I should mention the WinScpWrapper files. There are some lines that look like the following:

#include <GIniWrapper.h>
//gcnew String(config.getValue.....

You’ll have to remove references to and replace any calls to ‘config.getvalue’ w/ raw values. You’ll see in my get value though that the 3rd argument is actually a default value, just use these. It’s important that you use the same delimiter and cmd_ender that I use. WinSCP, as far as I can tell, doesn’t return any sort of codes. When your command is complete nothing is sent to say as much. You might be able to search for blank lines but I wasn’t sure if these would show up in other commands. Instead what I’ve done is after I issue a command to WinSCP I issue an additional command w/ ‘__END_CMD__’ as the message. WinSCP won’t know how to parse this command but it will still be written to the process handlers output. In this way we can search for valid commands between subsequent ‘winscp>’ command line tags. It’s a kludge but it works.

Categories: Coding Tags: , , , ,