Thursday, December 17, 2009

My first PMatrix3D port to Processing.js

p.PMatrix3D = function PMatrix3D() {

this.set = function set( ) {
if ( arguments.length == 1 ) {
/*if (arguments[0] instanceof PMatrix2D) {
var src = arguments[0];
set ( src.m00, src.m01, 0, src.m02,
src.m10, src.m11, 0, src.m12,
0, 0, 1, 0,
0, 0, 0, 1 );
} else*/ if (arguments[0] instanceof PMatrix3D) {
var src = arguments[0];
set ( src.m00, src.m01, src.m02, src.m03,
src.m10, src.m11, src.m12, src.m13,
src.m20, src.m21, src.m22, src.m23,
src.m30, src.m31, src.m32, src.m33 );
} else if (arguments[0] instanceof Array) {
if (arguments[0].length == 6) {
var src = arguments[0];
set ( src[0], src[1], src[2],
src[3], src[4], src[5] );
} else if (arguments[0].length == 16) {
var src = arguments[0];
set ( src[0], src[1], src[2], src[3],
src[4], src[5], src[6], src[7],
src[8], src[9], src[10], src[11],
src[12], src[13], src[14], src[15] );
}
}
} else if ( arguments.length == 6 ) {
set ( arguments[0], arguments[1], 0, arguments[2],
arguments[3], arguments[4], 0, arguments[5],
0, 0, 1, 0,
0, 0, 0, 1 );
} else if ( arguments.length == 16 ) {
this.m00 = arguments[0]; this.m01 = arguments[1]; this.m02 = arguments[2]; this.m03 = arguments[3];
this.m10 = arguments[4]; this.m11 = arguments[5]; this.m12 = arguments[6]; this.m13 = arguments[7];
this.m20 = arguments[8]; this.m21 = arguments[9]; this.m22 = arguments[10]; this.m23 = arguments[11];
this.m30 = arguments[12]; this.m31 = arguments[13]; this.m32 = arguments[14]; this.m33 = arguments[15];
}
};

this.reset = function reset( ) {
this.set( 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 );
};

if (arguments.length == 0) {
this.reset();
} else {
this.set(arguments);
}

this.translate = function translate() {
if (arguments.length == 2) {
translate(arguments[0], arguments[1], 0);
} else if (arguments.length == 3) {
m03 += arguments[0] * m00 + arguments[1] * m01 + arguments[2] * m02;
m13 += arguments[0] * m10 + arguments[1] * m11 + arguments[2] * m12;
m23 += arguments[0] * m20 + arguments[1] * m21 + arguments[2] * m22;
m33 += arguments[0] * m30 + arguments[1] * m31 + arguments[2] * m32;
}
};

this.rotate = function rotate() {
if ( arguments.length == 1 ) {
rotateZ(arguments[0]);
} else if ( arguments.length == 4 ) {
var c = cos(arguments[0]);
var s = sin(arguments[0]);
var t = 1 - c;

apply((t * arguments[1] * arguments[1]) + c, (t * arguments[1] * arguments[2]) - (s * arguments[3]),
(t * arguments[1] * arguments[3]) + (s * arguments[2]), 0, (t * arguments[1] * arguments[2]) + (s * arguments[3]),
(t * arguments[2] * arguments[2]) + c, (t * arguments[2] * arguments[3]) - (s * arguments[1]), 0,
(t * arguments[1] * arguments[3]) - (s * arguments[2]), (t * arguments[2] * arguments[3]) + (s * arguments[1]),
(t * arguments[3] * arguments[3]) + c, 0, 0, 0, 0, 1);
}
};

this.rotateX = function rotateX(angle) {
var c = cos(angle);
var s = sin(angle);
apply(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
};

this.rotateY = function rotateY(angle) {
var c = cos(angle);
var s = sin(angle);
apply(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
};

this.rotateZ = function rotateZ(angle) {
var c = cos(angle);
var s = sin(angle);
apply(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
};

this.scale = function scale(sx, sy, sz) {
if (sx && !sy && !sz) {
sy = sz = sx;
} else if (sx && sy && !sz) {
sz = 1;
}
if (sx && sy && sz) {
m00 *= sx; m01 *= sy; m02 *= sz;
m10 *= sx; m11 *= sy; m12 *= sz;
m20 *= sx; m21 *= sy; m22 *= sz;
m30 *= sx; m31 *= sy; m32 *= sz;
}
};

this.skewX = function skewX(angle) {
var t = Math.tan(angle);
apply(1, t, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
};

this.skewY = function skewY(angle) {
var t = Math.tan(angle);
apply(1, 0, 0, 0,
t, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
};

this.apply = function apply() {
if (arguments.length == 1) {
if (arguments[0] instanceof PMatrix2D) {
apply(arguments[0].m00, arguments[0].m01, 0, arguments[0].m02,
arguments[0].m10, arguments[0].m11, 0, arguments[0].m12,
0, 0, 1, 0,
0, 0, 0, 1);
} else if (arguments[0] instanceof PMatrix3D) {
apply(arguments[0].m00, arguments[0].m01, arguments[0].m02, arguments[0].m03,
arguments[0].m10, arguments[0].m11, arguments[0].m12, arguments[0].m13,
arguments[0].m20, arguments[0].m21, arguments[0].m22, arguments[0].m23,
arguments[0].m30, arguments[0].m31, arguments[0].m32, arguments[0].m33);
}
} else if (arguments.length == 6) {
apply(arguments[0], arguments[1], 0, arguments[2],
arguments[3], arguments[4], 0, arguments[5],
0, 0, 1, 0,
0, 0, 0, 1);
} else if (arguments.length == 16) {
var n00 = arguments[0]; var n01 = arguments[1]; var n02 = arguments[2]; var n03 = arguments[3];
var n10 = arguments[4]; var n11 = arguments[5]; var n12 = arguments[6]; var n13 = arguments[7];
var n20 = arguments[8]; var n21 = arguments[9]; var n22 = arguments[10]; var n23 = arguments[11];
var n30 = arguments[12]; var n31 = arguments[13]; var n32 = arguments[14]; var n33 = arguments[15];

var r00 = m00 * n00 + m01 * n10 + m02 * n20 + m03 * n30;
var r01 = m00 * n01 + m01 * n11 + m02 * n21 + m03 * n31;
var r02 = m00 * n02 + m01 * n12 + m02 * n22 + m03 * n32;
var r03 = m00 * n03 + m01 * n13 + m02 * n23 + m03 * n33;

var r10 = m10 * n00 + m11 * n10 + m12 * n20 + m13 * n30;
var r11 = m10 * n01 + m11 * n11 + m12 * n21 + m13 * n31;
var r12 = m10 * n02 + m11 * n12 + m12 * n22 + m13 * n32;
var r13 = m10 * n03 + m11 * n13 + m12 * n23 + m13 * n33;

var r20 = m20 * n00 + m21 * n10 + m22 * n20 + m23 * n30;
var r21 = m20 * n01 + m21 * n11 + m22 * n21 + m23 * n31;
var r22 = m20 * n02 + m21 * n12 + m22 * n22 + m23 * n32;
var r23 = m20 * n03 + m21 * n13 + m22 * n23 + m23 * n33;

var r30 = m30 * n00 + m31 * n10 + m32 * n20 + m33 * n30;
var r31 = m30 * n01 + m31 * n11 + m32 * n21 + m33 * n31;
var r32 = m30 * n02 + m31 * n12 + m32 * n22 + m33 * n32;
var r33 = m30 * n03 + m31 * n13 + m32 * n23 + m33 * n33;

m00 = r00; m01 = r01; m02 = r02; m03 = r03;
m10 = r10; m11 = r11; m12 = r12; m13 = r13;
m20 = r20; m21 = r21; m22 = r22; m23 = r23;
m30 = r30; m31 = r31; m32 = r32; m33 = r33;
}
};

this.preApply = function preApply() {
apply(arguments);
};

this.mult = function mult(source, target) {
if (source != target && (source instanceof PVector || source instanceof Array)) {
var x, y, z, w;
var tx, ty, tz;
if (source instanceof PVector) {
x = source.x;
y = source.y;
z = source.z;
w = 1;
if (!target) {
target = new PVector();
}
} else if (source instanceof Array) {
x = source[0];
y = source[1];
z = source[2];
w = source[3] || 1;
if (target.length != 3 && target.length != 4) {
target = new Array();
}
}
target[source instanceof PVector ? x : 0] = m00 * x + m01 * y + m02 * z + m03 * w;
target[source instanceof PVector ? y : 1] = m10 * x + m11 * y + m12 * z + m13 * w;
target[source instanceof PVector ? z : 2] = m20 * x + m21 * y + m22 * z + m23 * w;
if (target.length == 4) {
target[3] = m30 * x + m31 * y + m32 * z + m33 * w;
}
}
return target;
};

this.multX = function multX(x, y, z, w) {
return m00 * x + m01 * y + (z ? m02 * z : 0) + (w ? m03 * w : m03);
};

this.multY = function multY(x, y, z, w) {
return m10 * x + m11 * y + (z ? m12 * z : 0) + (w ? m13 * w : m13);
};

this.multZ = function multZ(x, y, z, w) {
return m20 * x + m21 * y + (z ? m22 * z : 0) + (w ? m23 * w : m23);
};

this.multW = function multW(x, y, z, w) {
return m30 * x + m31 * y + m32 * z + (w ? m33 * w : m33);
};

this.transpose = function transpose() {
var temp;
temp = m01; m01 = m10; m10 = temp;
temp = m02; m02 = m20; m20 = temp;
temp = m03; m03 = m30; m30 = temp;
temp = m12; m12 = m21; m21 = temp;
temp = m13; m13 = m31; m31 = temp;
temp = m23; m23 = m32; m32 = temp;
};

this.invert = function invert() {
var determinant = determinant();
if (determinant == 0) {
return false;
}

// first row
var t00 = determinant3x3(m11, m12, m13, m21, m22, m23, m31, m32, m33);
var t01 = -determinant3x3(m10, m12, m13, m20, m22, m23, m30, m32, m33);
var t02 = determinant3x3(m10, m11, m13, m20, m21, m23, m30, m31, m33);
var t03 = -determinant3x3(m10, m11, m12, m20, m21, m22, m30, m31, m32);

// second row
var t10 = -determinant3x3(m01, m02, m03, m21, m22, m23, m31, m32, m33);
var t11 = determinant3x3(m00, m02, m03, m20, m22, m23, m30, m32, m33);
var t12 = -determinant3x3(m00, m01, m03, m20, m21, m23, m30, m31, m33);
var t13 = determinant3x3(m00, m01, m02, m20, m21, m22, m30, m31, m32);

// third row
var t20 = determinant3x3(m01, m02, m03, m11, m12, m13, m31, m32, m33);
var t21 = -determinant3x3(m00, m02, m03, m10, m12, m13, m30, m32, m33);
var t22 = determinant3x3(m00, m01, m03, m10, m11, m13, m30, m31, m33);
var t23 = -determinant3x3(m00, m01, m02, m10, m11, m12, m30, m31, m32);

// fourth row
var t30 = -determinant3x3(m01, m02, m03, m11, m12, m13, m21, m22, m23);
var t31 = determinant3x3(m00, m02, m03, m10, m12, m13, m20, m22, m23);
var t32 = -determinant3x3(m00, m01, m03, m10, m11, m13, m20, m21, m23);
var t33 = determinant3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22);

// transpose and divide by the determinant
m00 = t00 / determinant;
m01 = t10 / determinant;
m02 = t20 / determinant;
m03 = t30 / determinant;

m10 = t01 / determinant;
m11 = t11 / determinant;
m12 = t21 / determinant;
m13 = t31 / determinant;

m20 = t02 / determinant;
m21 = t12 / determinant;
m22 = t22 / determinant;
m23 = t32 / determinant;

m30 = t03 / determinant;
m31 = t13 / determinant;
m32 = t23 / determinant;
m33 = t33 / determinant;

return true;
}

var determinant3x3 = function determinant3x3(t00, t01, t02, t10, t11, t12, t20, t21, t22) {
return (t00 * (t11 * t22 - t12 * t21) +
t01 * (t12 * t20 - t10 * t22) +
t02 * (t10 * t21 - t11 * t20));
}

this.determinant = function determinant() {
var f = m00 * ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
- m13 * m22 * m31
- m11 * m23 * m32
- m12 * m21 * m33);
f -= m01 * ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32)
- m13 * m22 * m30
- m10 * m23 * m32
- m12 * m20 * m33);
f += m02 * ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31)
- m13 * m21 * m30
- m10 * m23 * m31
- m11 * m20 * m33);
f -= m03 * ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31)
- m12 * m21 * m30
- m10 * m22 * m31
- m11 * m20 * m32);
return f ;
}

var max = function max(a, b) {
return (a > b) ? a : b;
};

var abs = function abs(a) {
return (a < 0) ? -a : a;
};

var sin = function sin(angle) {
return Math.sin(angle);
};

var cos = function cos(angle) {
return Math.cos(angle);
};

};

0.3 Release

0.3 released.

In this release, I was planning to do rotate, translate, scale, and other features that relates to transformation of 3D stuffs. Unfortunately, I can't follow what the original Processing did for implementing these features. But at least, I found out they all rely on a PMatrix3D/PMatrix2D class to centralize codes (I guess). This PMatrix3D class is missing in Processing.js. Therefore, I decided to make PMatrix3D ready before moving forward to utilizing the class.

PMatrix3D is not listed as a feature in Processing/Processing.js reference. Therefore, I read through the original Processing's PMatrix3D class and ports the class to Processing.js

Here's the updated commit. And here's the code itself.

Wednesday, December 16, 2009

Working with Patches

Today, I am into creating a patch for FireFox. Following this exercise, I am able to make a change and do incremental builds as listed in the lab. It's just to type make in a folder that's inside the tree. But every time it returned with an error, and this time they were all the same error unlike last time I tried to build Firefox. I figured I should build it on another box because of my previous build experiences. At the moment, I only had a laptop available, and I can see the build lines flies up a lot slower than they were in the other box. I got it compiled with just 2 tries.

Now, running Nightly, every time I browse to another webpage, the console would generate a bunch of "Hello World". I just did a printf statement in a random function in a random .cpp file. Now that's something satifying =]

Creating a patch from the changes I made is an easy task. It only requires 1 command to do the work.
hg diff -p -U 8 . > patch.txt

Now to test the patch if it works, I reverted the changes by replacing the file with the backup file I made earlier. Using another command to apply the patch:
patch -p1 < patch.txt

It successfully changes the file to the one I modified.

The last command to try is backing out the patch with
patch -R -p1 < patch.txt

Again, 1 command and it worked. I liked this lab far better than the one I had before =].

Tuesday, December 15, 2009

"Simple" Firefox Build

A few days ago, I decided to build FireFox with my machine at home. Of course, I would not know where to approach this without being in an Open Source course. I thought it will be an easy task just like downloading the source and type 1 command asking Windows to compile, as described in this Simple FireFox Build tutorial.

Of course, Simple Firefox build does not equal to easy and fast. I had to install Win 7 SDK for Visual Studio which took a loooong time to install (a little less than 3GB installation file). In the mean while, I can simultaneously download the FireFox source code through the MozillaBuild package. At first, I didn't know how much time it will take to clone, I thought it was stuck and killed the process. (Stupid #1) When I clone it again, I thought it was stuck at the same place again, good thing I checked the size of the folder and realized the folder is growing. My gosh the FireFox source codes is 2GB of files. Both tasks together took over an hour to have them ready for the build! (BTW, my only ISP here, Rogers Communication Inc. has a monthly bandwidth of 60GB; there goes 10% of my monthly usage in 1 hour)

When I start to build and run the make file, another problem came. I tried couple of times to compile, and it returned an error. I did couple of searches for the error and they suggest that there should not be a space in between my build path. I was so sure that I didn't have a space in the path, but then suddenly, I remembered my username has a space in it. (yes I did read all instruction before downloading the MozillaBuild, Stupid #2).

Now, after fixing the path, the build process went a little bit further. This time, it says I'm trying to build for a newer platform than what the SDK version is capable of. I just downloaded the newest Win 7 SDK, why is this happening? All of the sudden, there's a Windows update icon poped up in the notification area, tell me that Visual Studio 2008 SP1 is ready to be installed. Oops, did I just assumed I have an updated Visual Studio? So I went ahead and applied the update. I read Win 7 SDK depends on Visual Studio 2008 SP1 and here comes Stupid #3. I didn't even think of retry the build before I uninstall/reinstall the SDK for the new VS. If it works even without this process, I could have saved an hour of time.

Finally, the build process looks good. It is bursting out alot of progress reports. Until it froze at one line. I wait and wait for it to move on, thinking that this file must be huge. I sat there and wait for 5 min, 10 min, 30 min, 1 hr, 2hr, 3hr!! Knowing that for a XP machine, it requires 2 hours to complete. I waited for 3 hours for that 1 line to complete thinking there must be something wrong. I finally gave up waiting and retried and it got stuck again but on another line. Of course, this time I retried the build right away. This happened about 10 times, and it finally finished building. It didn't cost 2 hours. More like 10 minutes. (Windows doesn't suck that much after all) Anyhow, my computer built the latest nightly, minefield v3.7alpre. Now that I think back the errors, it might be because the CPU is a new designed Athlon II x4, the processor might not be synchronizing its cores as the compiler wants it to.

Anyway, remember where I start? Simple Firefox Build. Simple it is, but it took me the whole night trying to figure out the cause of the errors that some of them could have been avoided if it's better documented. Like the size of Firefox source and the time it takes to build on different machines. Overall, this Firefox build experience is not a great one. But now, I can play around with the source.

Tuesday, November 24, 2009

Modified HashMap

var HashMap = function HashMap( map ) {
this.data = [];
this.curKey = 0;
this._size = 0;

if (arguments.length == 1) {
// copy map to data
}

this.put = function put( key, value ) {
var rv;
if (typeof key == "object") {
if(!key._HashMap_key){
key._HashMap_key = "_HashMapKey_" + this.curKey++;
}
rv = this.data[key._HashMap_key];
this.data[key._HashMap_key] = value;
} else {
rv = this.data[typeof key + key];
this.data[typeof key + key] = value;
}
this._size = rv ? this._size : this._size + 1;
return rv;
}

this.get = function get( key ) {
if (typeof key == "object") {
return this.data[key._HashMap_key];
}
return this.data[typeof key + key];
}
}

Original HashMap

HashMap = function(){
this._dict = {};
}
HashMap.prototype._shared = {id: 1};
HashMap.prototype.put = function put(key, value){
if(typeof key == "object"){
if(!key.hasOwnProperty._id){
key
.hasOwnProperty = function(key){
return Object.prototype.hasOwnProperty.call(this, key);
}
key
.hasOwnProperty._id = this._shared.id++;
}
this._dict[key.hasOwnProperty._id] = value;
}else{
this._dict[key] = value;
}
return this; // for chaining
}
HashMap.prototype.get = function get(key){
if(typeof key == "object"){
return this._dict[key.hasOwnProperty._id];
}
return this._dict[key];
}

Map Implementation

// linking the key-value-pairs is optional
// if no argument is provided, linkItems === undefined, i.e. !== false
// --> linking will be enabled
function Map(linkItems) {
this.current = undefined;
this.size = 0;

if(linkItems === false)
this.disableLinking();
}

Map.noop = function() {
return this;
};

Map.illegal = function() {
throw new Error("illegal operation for maps without linking");
};

// map initialisation from existing object
// doesn't add inherited properties if not explicitly instructed to:
// omitting foreignKeys means foreignKeys === undefined, i.e. == false
// --> inherited properties won't be added
Map.from = function(obj, foreignKeys) {
var map = new Map;

for(var prop in obj) {
if(foreignKeys || obj.hasOwnProperty(prop))
map
.put(prop, obj[prop]);
}

return map;
};

Map.prototype.disableLinking = function() {
this.link = Map.noop;
this.unlink = Map.noop;
this.disableLinking = Map.noop;
this.next = Map.illegal;
this.key = Map.illegal;
this.value = Map.illegal;
this.removeAll = Map.illegal;

return this;
};

// overwrite in Map instance if necessary
Map.prototype.hash = function(value) {
return (typeof value) + ' ' + (value instanceof Object ?
(value.__hash || (value.__hash = ++arguments.callee.current)) :
value
.toString());
};

Map.prototype.hash.current = 0;

// --- mapping functions

Map.prototype.get = function(key) {
var item = this[this.hash(key)];
return item === undefined ? undefined : item.value;
};

Map.prototype.put = function(key, value) {
var hash = this.hash(key);

if(this[hash] === undefined) {
var item = { key : key, value : value };
this[hash] = item;

this.link(item);
++this.size;
}
else this[hash].value = value;

return this;
};

Map.prototype.remove = function(key) {
var hash = this.hash(key);
var item = this[hash];

if(item !== undefined) {
--this.size;
this.unlink(item);

delete this[hash];
}

return this;
};

// only works if linked
Map.prototype.removeAll = function() {
while(this.size)
this.remove(this.key());

return this;
};

// --- linked list helper functions

Map.prototype.link = function(item) {
if(this.size == 0) {
item
.prev = item;
item
.next = item;
this.current = item;
}
else {
item
.prev = this.current.prev;
item
.prev.next = item;
item
.next = this.current;
this.current.prev = item;
}
};

Map.prototype.unlink = function(item) {
if(this.size == 0)
this.current = undefined;
else {
item
.prev.next = item.next;
item
.next.prev = item.prev;
if(item === this.current)
this.current = item.next;
}
};

// --- iterator functions - only work if map is linked

Map.prototype.next = function() {
this.current = this.current.next;
};

Map.prototype.key = function() {
return this.current.key;
};

Map.prototype.value = function() {
return this.current.value;
};

Road to Coding HashMap

For the 0.2 Release for the processing.js project, I decided I should code some more supportive classes to expand the processing.js library. I picked HashMap, because this class is missing and I still remember coding a C++ HashTable for an assignment in my previous course DSA555.

I start by reading the specifications in the processing.js references, the original processing implementation, and the Java API, to get a sense of what HashMap is supposed to do. The general idea of HashMap is very similar to HashTable, but I want to know the exact differences between them. So I did a search on Google and found this website. HashMap is actually just a new version of HashTable that accepts null keys; plus a name change. I guess I can start coding it.

Of course, I will not waste my time to come up with original codes if there's is a HashMap existed in the web. Therefore, I did a search on Google again to search for HashMap implementation on Javascript. I found this, and it's great, because the first thing I see is a Map implementation. That means I can probably take the code and do little work to use it. But it turns out that the Map class is more complicated than I thought, plus where is the missing Hash part?

I continue scrolling down and see HashMap implementation. As soon as I start tracing the codes, I realize there's no Hash anywhere in the code. Isn't it weird? Then one Javascript feature on array reappears to me: I don't even need to set a size for array in Javascript!! That means there's no need to hash the given key and insert into a limited size HashMap!! So why do I even need to write a HashMap for the processing.js library? The built-in Javascript array can do the exact same job already. That means all the above researches is wasted?

I decide that I shall code a HashMap anyways, since it is a class listed under processing.js reference. So I continue to trace the HashMap implementation. I don't really have a full understand on the usage for a few lines of codes. So I guess I can just modify some codes so that I understand the code better and see if it works the same way before I change those lines. Original version vs. Modified version.

It did, so the next will be inserting this chunk of code into processing.js. To do this, I decide to look at ArrayList, which has already been coded by someone else. Amazingly, I see uses of the keyword this, and I got freaked out since Dave have said something about it being different than what Java's keyword this. Then Dave sent me a link to show me how to use the troublesome keyword.

So, I coded this HashMap and pushed into the GitHub repository. I know it is not good codes, but I tried my best. It doesn't have codes to copy from another implementation of Map, either. But with the tests I throw to the code, it does what it is expected. I will refine the code so that it does more HashMap functions.

Saturday, November 21, 2009

0.1 Release

For my 0.1 Release for a project on Processing.js, I have coded the following functions for Processing.js:

split(str, delim), trim(str), arrayCopy(arg1, arg2, arg3, arg4, arg5), match(str, regexp), append(array, element), splitToken(str, tokens) and online().

I have tested all of the functions and made sure they work. But there's 1 issue on arrayCopy(): it does shallow copy only. In the original Processing code, it does shallow copy, too. But it seems like deep copy is more useful. This should be addressed on my 0.2 Release.

My 0.2 Release

0.2 released.

In this release, I have implemented the HashMap function.

HashMap function contains the following member functions:

put(key,value)
get(key)
remove(key)
isEmpty()
size()
clear()

containsKey(key)
containsValue(value)

Monday, September 28, 2009

Initial Project Plan for OpenSource Development

The Project

The project I will be working on is Processing.js. It is a Mozilla project in which the main purpose is to allow people to create 2D or 3D graphics on web using embedded JavaScript and Canvas.

Not many graphics designer is fluent in using programming language to create graphics on web. This project will help them easily create the visuals on web with one platform. I don't have much knowledge of JavaScript. I expect to learn a lot more about JavaScript and using it to develop an easy tool for users to use.

Project tracking

I will post my updates of the project through this blog. There will be three major release dates within the coming three months: Week of Oct 19 (0.1 Release), Nov 16 (0.2 Release) and Dec 7 (0.3 Release). I'm also expecting to continue working towards 1.0 Release in the next 4 months.

Plan for 0.1, 0.2, and 0.3 releases

0.1
I will be implementing a few functions: trim(), split(), splitTokens(), append(), arraycopy(), match() and matchAll(). This will get me started with processing.js.

0.2
I will fix the bugs in 0.1 release and implement more functions. Possibly implement the rest of Easy functions listed in task list as well as other medium/difficult functions. I would like to contribute a large portion of codes in this release.

0.3
I will fix the bugs in 0.1 and 0.2 release and will be working on the 3D features listed in task list. This will get me familar with 3D programming on web.

Learning

The main language for this project is JavaScript. But I am unfamiliar with the language. My main research will be coming from the JavaScript API and other JavaScript information page. 3D programming will also be challenging. Although I have studied in Game Programming previously, it was mostly on DirectX. So there will be quite a bit of learning OpenGL in this aspect.

Helps Needed

I am a Windows guy, and very unfamiliar with Linux and Mac OS X. The only experiences with Linux are compiling small C/C++ codes remotely to the Matrix server Seneca provides through telnet and ftp. I would appreciate some help in these areas.
I am a detail oriented type of person. Whenever I am encountered with errors or wrong outputs, I can usually pin-point the causing problem easily. I would love to help others into fixing their problems, as I can learn their codes in return.

Risks

Except for the programming language and compiling platform learning, I also have a tight schedule this semester. I am used to just finish programming codes and submit them. Only when I have spare times, I will do some decorations and comment my codes. But since I'm working with an actual project out there in the web, I need to blog about it to gain exposure in the public. This requires me to actually divide some time to talk about what I have done. Just like writing journals, except that I have never written a journal entry before. This will be challenging, as well as very rewarding. I am very excited about having an experience with the open-source community.