Viktor Hesselbom http://www.hesselbom.net/ Blog about programming logic Magento: Why is ?SID giving me a 500 error? 26 Mar 2013 http://www.hesselbom.net/magento-why-is-sid-giving-me-a-500-error

I recently got a 500 Internal Server Error when Magento would add a ?SID=XXX to the URL. My story might be pretty specific but long story short, don't try to use sessions before it has been initiated.

In a recent Magento project we had to have multiple subdomains half-simulating stores because we needed to create dynamic stores on the spot and it could become a couple of thousand stores and creating that many Magento stores didn't play nice with the Magento admin.

And I had to know the correct values for the currently visited semi-store. For this I could've decided to load the semi-store model at every page reload and stored it in the registry but I decided to store it in a session that would update each time it noticed a new subdomain.

Now, to get correct base urls for all urls in this semi-store (when calling ->getUrl() it would default return with the base store's base url since these aren't real Magento stores) I decided to override Core_Store and specifically it's getConfig method. Inside this method, I would check in the session if this was a semi-store (and show my rewritten base url) or a regular store (just call parent::getConfig).

This worked fine for a while. Until I had to modifiy customer login to redirect to the semi-store associated with the customer. Now, this means going to a new subdomain and the way Magento handles sessions passing to a new URL (if "Use SID on Frontend" is set to "Yes") is to append a ?SID= on the URL with the customers session id. This is where I got the 500 Internal Server Error.

Why would it do this just because of a ?SID in the URL? Well, I scoured the code in Magento and let me show you by displaying some core code.

First, when creating a session Magento calls Mage_Core_Model_Session_Abstract::setSessionId() which looks like this:

public function setSessionId($id=null)

{

if (is_null($id) && $this->useSid()) {

$_queryParam = $this->getSessionIdQueryParam();

if (isset($_GET[$_queryParam]) && Mage::getSingleton('core/url')->isOwnOriginUrl()) {

$id = $_GET[$_queryParam];

}

}

$this->addHost(true);

return parent::setSessionId($id);

}

Turns out it gets an error when calling Mage::getSingleton('core/url')->isOwnOriginUrl(). Ok let's check that method out.

public function isOwnOriginUrl()

{

$storeDomains = array();

$referer = parse_url(Mage::app()->getFrontController()->getRequest()->getServer('HTTP_REFERER'), PHP_URL_HOST);

foreach (Mage::app()->getStores() as $store) {

$storeDomains[] = parse_url($store->getBaseUrl(), PHP_URL_HOST);

$storeDomains[] = parse_url($store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_LINK, true), PHP_URL_HOST);

}

$storeDomains = array_unique($storeDomains);

if (empty($referer) || in_array($referer, $storeDomains)) {

return true;

}

return false;

}

Now, take 5 minutes before proceeding and see if you can spot the problem here.

...

Did you see it? This method calls $store->getBaseUrl() which of course calls getConfig to get the base url. What do we do in that getConfig that we overwrote? Right, we try to check a session variable which in turns has to try and initiate the session which in turn eventually calls setSessionId(). We reached an infinite loop of sorts!

How can we solve it?

Well, in my case I realised that I didn't actually had to check the session for the base url in this case.

First I used the same method to check if user is currently in a semi-store as when setting the session (just comparing subdomain with real base store's base url subdomain).

Then to check current url, well duh, I just had to get the host of the current url (with the convenient $_SERVER['HTTP_HOST']) and replace the host part of the real base url and return that.

It's pretty obvious and kind of embarrasing to not think of that solution from the start but since I got this strange problem and couldn't find a solution when Googling I decided to document it anyway.

Out of interest, here's my (slightly modified) overriden Core_Store class:

class MyPackage_MyModule_Model_Core_Store extends Mage_Core_Model_Store

{

public function getConfig($path)

{

if ($path === 'web/secure/base_url' ||

$path === 'web/unsecure/base_url' ||

//$path === 'web/secure/base_link_url' || // base_link_url use base_url to create url

//$path === 'web/unsecure/base_link_url' ||

$path === 'web/secure/base_skin_url' ||

$path === 'web/unsecure/base_skin_url' ||

$path === 'web/secure/base_js_url' ||

$path === 'web/unsecure/base_js_url') {

if (Mage::helper('mymodule')->isSemiStore()) {

$return = parent::getConfig($path);

$new_host = $_SERVER['HTTP_HOST'];

$return = preg_replace('/(https?\:\/\/)([^\/]+)(\/)/', '$1' . $new_host . '$3', $return);

return $return;

}

}

else if ($path === 'real/web/secure/base_url') {

return parent::getConfig('web/secure/base_url');

}

else if ($path === 'real/web/unsecure/base_url') {

return parent::getConfig('web/unsecure/base_url');

}

return parent::getConfig($path);

}

}

Why doesn't my .gitignore ignore my file? 29 Jan 2013 http://www.hesselbom.net/why-doesnt-my-gitignore-ignore-my-file

One reason that your file, or filematch, is not ignored even though it's present in your .gitignore file could be that it's written on the first line of the .gitignore-file.

The first line is apparently reserved for a comment, or simply a blank line, so you have to start listing files starting on row 2.

Hope this little tidbit helped someone!

Magento: Override headers to not get duplicate Content-types 19 Oct 2012 http://www.hesselbom.net/magento-override-headers-to-not-get-duplicate-content-types

Today I needed to return a JSON response in a controller from my module in Magento. It need to have Content-type set to application/json in order for the Ajax library, namely prototype.js, to parse it as a JSON object.

The default Content-type in Magento is text/html. To change this you need to set a header in the response, so I did like this:

$this->getResponse()->setHeader('Content-type', 'application/json');

What this did was to add another header instead of replacing it. So now I have two Content-type headers. This worked fine in Chrome because it would read both Content-types in the javascript but in Firefox it would only read the first which would still be text/html.

To fix this, all you need to do is to set the third parameter in the setHeader method, $replace, to true. It's quite self-explanatory but what this does is replace the previous header with the new value:

$this->getResponse()->setHeader('Content-type', 'application/json', true);

It now returns just one Content-type header correctly set to application/json

Magento: Custom attributes with image upload 24 Jul 2012 http://www.hesselbom.net/magento-custom-attributes-with-image-upload

Following my previous post on creating custom category attributes, here's a short explanation on how you can choose image upload as input method instead of just plain text.

What I changed from my previous code to get this working if that first I changed the type of attribute to 'image' and set backend as 'catalog/category_attribute_backend_image', like so:

$setup->addAttribute('catalog_category', 'custom_attribute', array(
    'group' => 'Custom Tab',
    'input' => 'image',
    'type' => 'varchar',
    'label' => 'Custom Attribute',
    'backend' => 'catalog/category_attribute_backend_image',
    'visible' => 1,
    'required' => 0,
    'user_defined' => 1,
    'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
));

And that's all there is to it. Now you should have a custom attribute field where you can upload an image.

Magento: Custom attributes with selectbox 24 Jul 2012 http://www.hesselbom.net/magento-custom-attributes-with-selectbox

Following my previous post on creating custom category attributes, here's a short explanation on how you can choose a selectbox as input method instead of just plain text.

What I changed from my previous code to get this working if that first I changed the type of attribute to 'select' and added a source model, like so:

$setup->addAttribute('catalog_category', 'custom_select', array(
    'group' => 'Custom Tab',
    'input' => 'select',
    'type' => 'varchar',
    'label' => 'Custom Select',
    'visible' => 1,
    'required' => 0,
    'user_defined' => 1,
    'source' => 'mymodule/selectoptions',
    'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
));

And the code for the source model:

class Mypackage_Mymodule_Model_Selectoptions extends Mage_Eav_Model_Entity_Attribute_Source_Abstract {

    public function getAllOptions($withEmpty = true)
    {
        $options = array(
            array('label' => 'Template 1', 'value' => 'template_1'),
            array('label' => 'Template 2', 'value' => 'template_2'),
            array('label' => 'Template 3', 'value' => 'template_3'),
        );
        if ($withEmpty) {
            array_unshift($options, array('label' => '', 'value' => ''));
        }

        return $options;
    }
}

Now you should get an attribute on the category with a selectbox with the options 'Template 1', 'Template 2' and 'Template 3'

Magento: Add custom attributes and tabs to categories 20 Jul 2012 http://www.hesselbom.net/magento-custom-attributes-tabs-categories

In a recent Magento project I needed to create a custom tab in the Categories admin with some custom attributes. Turns out this is really simple.

You have to add some code to your module's mysql install/upgrade script. If you don't know what those are, read this article: http://www.magentocommerce.com/knowledge-base/entry/magento-for-dev-part-6-magento-setup-resources/

Here's what my install script looked like:

startSetup();

$setup->addAttribute('catalog_category', 'custom_attribute', array(
    'group' => 'Custom Tab',
    'input' => 'text',
    'type' => 'varchar',
    'label' => 'Custom Attribute',
    'visible' => 1,
    'required' => 0,
    'user_defined' => 1,
    'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
));

$installer->endSetup();

Now, the interesting part here is the call to addAttribute:

$setup->addAttribute('catalog_category', 'custom_attribute', array(
    'group' => 'Custom Tab',
    'input' => 'text',
    'type' => 'varchar',
    'label' => 'Custom Attribute',
    'visible' => 1,
    'required' => 0,
    'user_defined' => 1,
    'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
));

Notice how 'custom_attribute' is the database fieldname for the attribute, 'Custom Attribute' is the admin label for it, and 'Custom Tab' is the name for the tab.

If we set 'General Information' as the group the attribute would appear under that tab, but because we specify a group that doesn't exist that tab will automatically be created.

Magento: Including external stylesheet 23 Apr 2012 http://www.hesselbom.net/magento-external-stylesheet

Ever tried including an external stylesheet in Magento? If you put the following in your theme's page.xml Magento won't recognize that it's in fact an external stylesheet we're trying to include and not a local one:

<action method="addCss"><stylesheet>http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/redmond/jquery-ui.css</stylesheet></action>

So instead we have to inject text with the link-tag directly like so:

<block type="core/text" name="google.cdn.jquery.ui.css">
    <action method="setText">
        <text><![CDATA[<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/redmond/jquery-ui.css" type="text/css" rel="stylesheet" />]]></text>
    </action>
 </block>

This isn't immediately apparent so maybe my research will help someone.

Death to inline CSS! 12 Jan 2012 http://www.hesselbom.net/death-to-inline-css

Death to inline CSS!

You can't override it without using !important which is not supported by older IE-browsers.

Yet you can find them everywhere in almost every web-project.

Sad panda :(

Achtung die Javascript 30 Sep 2011 http://www.hesselbom.net/achtung-die-javascript

I'm working more and more with Javascript. I love it! I also love the possibilities that HTML5 brings. I think we will be seeing more and more games and applications using HTML5 technologies in the future and we're already seeing the development in Google+ Games. In fact, I'm working on a HTML5 application on my free time, more on that in another post.

This is why when I found out about Processing.js I was excited to try to port my clone of Achtung die Kurve.

Turns out it was easy as pie!

All I had to do was create a canvas element and let it load my Processing .pde-file. Granted, I did not expect it to be difficult but pretty cool nonetheless.

You can try it out at http://hesselboom.com/achtung-js/. The controls are the same as last time, the left and right arrow keys for one player and A and D for the second.

MySQL FUNCTION DB.count does not exist 12 Jul 2011 http://www.hesselbom.net/mysql-function-db.count-does-not-exist

I recently wanted to count the number of rows returned from a SQL query to a MySQL database. I first tried it in phpMyAdmin with a query something like this:

select count (id) from DB

This worked fine in phpMyAdmin but the "interesting" (annoying) thing is that in my live PHP code I got the error MySQL FUNCTION DB.count does not exist.

Turns out the MySQL does not like the whitespace after the function name, before the parameters. In phpMyAdmin they automatically fix this for you in your query but in your PHP code it obviously doesn't.

So that query should look like this:

select count(id) from DB

Hope this helped someone!

Google and me 26 Feb 2011 http://www.hesselbom.net/google-and-me

I love Google.

So after having a VPS with a plan of $20/month for more than two years I suddenly realised that the only thing I'm hosting on it is this blog, which gets approximately 2 visitors every other day, and an SVN server for personal projects.

This is where Google comes in. I was recommended Google App Engine by my brother (who also ported two of my games) so I started looking into it.

And it's awesome.

I decided to ditch my host and rewrite the blog in Python using App Engine. My only previous experience of Python was when hacking together an addon for Blender so the language was pretty much new to me. Python's syntax was very easy to learn though, and with the use of Google's webapp framework I was able to put this together, design and all, over the weekend.

I decided to use Disqus for comments as opposed to using the Google datastore for the comments. For one because it meant I was able to finish the blog faster but mainly because Disqus is cool.

Because of this decision it means all my previous comments were lost! No need to panic though considering I only had like 4 or 5 of them (hard to keep track of them all).

Also, I got a suggestion from a co-worker to update this blog more often with progress on current projects so I might just do that. Watch this space!

I have only one thing to say 23 Feb 2011 http://www.hesselbom.net/i-have-only-one-thing-to-say

Hello.

Collision detection 29 Jan 2011 http://www.hesselbom.net/collision-detection

Here's something I whipped up today. It's a library for checking collisions of objects. The objects are represented as either a circle, a line or a polygon.

Right now it only checks if two objects are intersecting and is not returning any information about where they are intersecting. I was thinking about adding this information before releasing it, because I'm not sure how many people would want to use it in it's current state.

In the next couple of days I'll complete it and publish the library along with some examples of use. I think it could be useful for several things.

In the meantime here's something you can play with where I demonstrate where the library is right now. Just click the buttons to create objects and drag them around. If they're red it means they're intersecting an object.

Projecting circle or point out of polygon shape 12 Dec 2010 http://www.hesselbom.net/projecting-circle-or-point-out-of-polygon-shape

This post will describe a method to project a circle (or a point) out of either a convex or a concave polygon. The example code will be written in ActionScript.

Okay, let's get started. For this I have written a simple vector class and a polygon class. They are nothing special, the vector class is like you would expect and the polygon class is simply an array of vectors. Never-the-less, if you want to look at them I have linked them, along with the complete code of what I'm discussing, at the end of this post.

First of all, if you don't know what a vector is (or what particular vector I'm talking about, since the word is used for so much) it's basically a line segment. In my vector class I store the length of the vector along with the direction.

EDIT: Actually, a vector is simply a point in a coordinate space. Woops. Sorry, I learn as I go. :)

First we create a new vector to use as the position of the circle and a polygon shape.

point = new Vector2D (0, 0);
shape = new Polygon ();
shape.addPoint (80, 20);
shape.addPoint (110, 30);
shape.addPoint (100, 60);
shape.addPoint (70, 70);
shape.addPoint (40, 40);
shape.connectLines ();

That's it for the initializing. I will leave the rendering process to you. ;)

Now, the first thing we want to check is the closest way out of the polygon. To do this we loop through the polygon's walls and check the distance between the point and each wall and return the closest. The actual method of checking the distance between a point and a line is outside of this post's scope but you can check it out in the vector class provided at the end of the post.

This is the code of what I just described:

closestDistance = null;
for each (var v:Vector2D in shape.lines)
{
	var dist:Vector2D = v.distanceToVector (point);
	if (closestDistance == null || dist.len < closestDistance.len)
		closestDistance = dist;
}

Now we have the closest distance as a vector line and can simply project the point out of the polygon by translating the point with the distance. The vx and vy of the vector class is simply the direction * length of the vector.

if (closestDistance != null)
{
	point.x -= closestDistance.vx;
	point.y -= closestDistance.vy;
}

Here's how this would look (point being at mouse and circle is the point projected by the closest distance):

As you surely noticed it now tries to project the point out of the polygon even though the point isn't inside the polygon! The obvious way to fix this is to check if the point is inside the polygon. To do this we create a vector to serve as a horizontal ray from outside the polygon to the point. Make sure that the ray always starts outside of the polygon. Then the only thing we have to do is to check how many walls in the polygon is intersecting the ray. If the amount is an odd number it means the point is inside the polygon. This method is described in detail here.

This is how it could look in code, combining with what we already have.

// Create ray to check if point is inside shape
ray = new Vector2D (0, point.y);
ray.vx = point.x;
ray.dx = 1;
isInside = false;
 
// Update closest distance and find ray collisions
closestDistance = null;
var hits:int = 0;
for each (var v:Vector2D in shape.lines)
{
	var dist:Vector2D = v.distanceToVector (point);
	if (closestDistance == null || dist.len < closestDistance.len)
		closestDistance = dist;
	if (ray.isIntersecting (v))
		hits ++;
}
 
isInside = (hits%2 == 1);
 
if (closestDistance != null)
{
	if (isInside)
	{
		point.x -= closestDistance.vx;
		point.y -= closestDistance.vy;
	}
}

Where it checks if the ray is intersecting the wall we will run into a problem if the ray is intersecting at the exact corner (vertex) of the wall because then it will record both that wall and the previous one (because it would also be at the exact opposite corner of that wall) and add two hits instead of one and thus giving us a false result. To work around this we can add a check to see if the ray's y is the same as the wall's y and if it is we don't increment hits. Remember that the x and y of the wall is the first corner and x+vx and y+vy is the second corner. Because this is not a problem at the top and bottom corners we can disregard the check if the wall is at the top or bottom. So change that part of the code to this:

if ((ray.y != v.y || ray.y == shape.lowestPos || ray.y == shape.highestPos) && ray.isIntersecting (v))
	hits ++;

Here's how this would look (the red line is the ray):

Much better!

That's it if all you want to do is to project a point out of a shape. If you want to project the complete circle outside of the shape there's not much extra work! The first thing you have to do is add the radius to the projection. All you have to do is getting the direction of the projection (closest distance, remember?) and multiply it with the circle's radius.

point.x -= radius * closestDistance.dx;
point.y -= radius * closestDistance.dy;

This works fine and dandy when the point is still inside the polygon. But if the point is outside of the polygon but the borders of the circle is still inside it won't get noticed. To fix this we only have to check if the closest distance is less than or equal to the circle's radius. And because if this is true (the circle being outside the polygon but still colliding) the distance projection would be projecting in the wrong direction and we have to add the radius with the reversed direction. Like this:

var isCircleInside:Boolean = (closestDistance.len <= radius);
 
if (closestDistance != null)
{
	if (isInside)
	{
		point.x -= closestDistance.vx;
		point.y -= closestDistance.vy;
		point.x -= radius * closestDistance.dx;
		point.y -= radius * closestDistance.dy;
	}
	else if (isCircleInside)
	{
		point.x -= closestDistance.vx;
		point.y -= closestDistance.vy;
		// Notice the inverse direction:
		point.x -= radius * -closestDistance.dx;
		point.y -= radius * -closestDistance.dy;
	}
}

This is how it would look now:

There's still a small bug left to fix. In the previous example, if you manage to place the point exactly at a line the distance between the point and closest wall will be 0 and thus the dx and dy will be 0 and the circle won't be pushed out. This is solvable by first telling the code to also store the closest wall (to which the closest distance is associated to) and calculating it's right and left normals. The right and left normals are the two vectors that are perpendicular to the vector. One with direction to the right and the other to the left. Then we use one of the normals as the new direction. But which normal to use? Maybe a little naively I just check the rotation of the wall with atan2 and if the value is positive use left normal and if negative use right normal. If anyone knows a more elegant solution, please do tell.

In any case, this is what you would change the projection part to:

if (closestDistance != null)
{
	var dx:Number = closestDistance.dx;
	var dy:Number = closestDistance.dy;
	if (dx == 0 && dy == 0)
	{
		var lx:Number = closestWall.dy;
		var ly:Number = -closestWall.dx;
		var rx:Number = -closestWall.dy;
		var ry:Number = closestWall.dx;
		if (Math.atan2 (closestWall.dy, closestWall.dx) > 0)
		{
			dx = lx;
			dy = ly;
		}
		else
		{
			dx = rx;
			dy = ry;
		}
	}
	if (isInside)
	{
		point.x -= closestDistance.vx;
		point.y -= closestDistance.vy;
		point.x -= radius * dx;
		point.y -= radius * dy;
	}
	else if (isCircleInside)
	{
		point.x -= closestDistance.vx;
		point.y -= closestDistance.vy;
		point.x -= radius * -dx;
		point.y -= radius * -dy;
	}
}

And this is the result:

And we're done! Phew. Any questions welcome.

These are the classes I used for this post:

Achtung die Processing 05 Feb 2010 http://www.hesselbom.net/achtung-die-processing

A couple of weeks ago I started looking into Processing. It's pretty interesting because you can get visual results immediately when trying it. It's not something I will continue to use because it's more geared towards people new to programming (great place to start btw!) but I quickly whipped out an easy clone of the game Acthung, die Kurve!

You can try it out at http://hesselboom.com/achtung/. This version is only for 2 players and the controls are the left and right arrow keys for one player and A and D for the second.

The source code for the game can be found here and the fonts used can be found here. As you can see it's very little code required because you don't really have to setup much, you can immediately start drawing.

I handled the hit detection by storing each pixel in a 2d boolean array and each iteration check if the new position of each snake is true in the array. And if it is, that snake should "die" and when there is only one snake left give that snake a point. It's not 100% perfect because once or twice it might miss a pixel because it doesn't necessarily move 1 pixel up or down each iteration because the new position is calculated based on rotation, but it's good enough and you rarely spot that error.

Experimenting with simulation of hard-edged shadows 04 Feb 2010 http://www.hesselbom.net/experimenting-with-simulation-of-hard-edged-shadows

For a game I'm working on we want to have 2d shadows covering parts of the screen, like in the game Nox, to create a sense of true(ish) line-of-sight. If you've never played Nox it's kind of hard to picture how the shadows work without a moving picture but here is a reference picture to get a grasp.

Nox Shadows

Nox Shadows

Basically, it projects shadows from all walls and doors, leaving open spots for windows, so the player can't see what he's not supposed to see. This, in my opinion, is a very cool idea because many bird-view 2d games have this problem, but let's not get into that, it will suffice to say that this is the reason we chose to try and simulate Nox's conveniently called 'LineSight'.

Anyway, to try to cut to the chase, here's how I started thinking it could be done.

First I create a simple wall, stored as a line segment between two points, p0 and p1. Then I want to create a shadow from that wall in the opposite direction of the focused point. In my example I will use the position of the mouse for this. Normally, you'd probably want to use the position of the player for this. So I will take the x distance and y distance between both the wall's points and the mouse, draw lines between p0 to p0' and p1 to p1', and then fill it in. The code should then look something like this (I added three walls to easier visualize the results):

class Main
{
	static function main ()
	{
		game = flash.Lib.current.graphics;
		flash.Lib.current.stage.addEventListener (flash.events.MouseEvent.MOUSE_MOVE, update);
 
		walls = new Array ();
		walls.push (new Wall ({ x : 120.0, y : 120.0 },
				      { x : 180.0, y : 180.0 }));
		walls.push (new Wall ({ x : 180.0, y : 180.0 },
				      { x : 240.0, y : 120.0 }));
		walls.push (new Wall ({ x : 180.0, y : 60.0 },
				      { x : 240.0, y : 120.0 }));
	}
 
	static function update (e)
	{
		game.clear ();
		for (w in walls) drawshadow (w, game, { x : e.stageX, y : e.stageY });
		for (w in walls) w.draw (game);
	}
 
	static function drawshadow (w : Wall, g : flash.display.Graphics, ref)
	{
		var xdist, ydist;
		g.beginFill (0);
 
		xdist = w.p0.x - ref.x;
		ydist = w.p0.y - ref.y;
		g.moveTo (w.p0.x, w.p0.y);
		g.lineTo (w.p0.x + xdist, w.p0.y + ydist);
 
		xdist = w.p1.x - ref.x;
		ydist = w.p1.y - ref.y;
		g.lineTo (w.p1.x + xdist, w.p1.y + ydist);
		g.lineTo (w.p1.x, w.p1.y);
	}
 
	static var game : flash.display.Graphics;
	static var walls : Array;
}

And the result something like this (click to set focus and then move mouse to see updates):

Now, this doesn't look like much. But how about if we multiply the distances by, say, 1000?

Now we're talking! However, this is highly unoptimized. Drawing the edges way outside where it should be drawn? Perhaps Flash Player can optimize this and only draw what needs to be drawn, but what if we were to use some other platform? Or maybe we would want to cache the shadows as bitmaps (for God knows what reason... filters?) and we will start to notice an unnecessary slowdown.

So to calculate what point each shadow segment ending should be at I calculate how far p0's x distance is from reaching it's boundary (0 if negative, width of window if positive) in percent and then multiply both x distance and y distance with that value. Then I check if the new point is outside of the vertical boundaries (0 to height of window) and if it is, recalculate percentage with y distance instead. It might sound pretty naive but it works efficiently.

Here is that written in our previous code, with just one wall to easier visualize the difference:

class Main
{
	static function main ()
	{
		game = flash.Lib.current.graphics;
		flash.Lib.current.stage.addEventListener (flash.events.MouseEvent.MOUSE_MOVE, update);
 
		walls = new Array ();
		walls.push (new Wall ({ x : 120.0, y : 120.0 },
				      { x : 180.0, y : 180.0 }));
	}
 
	static function update (e)
	{
		game.clear ();
		for (w in walls) drawshadow (w, game, { x : e.stageX, y : e.stageY });
		for (w in walls) w.draw (game);
	}
 
	static function drawshadow (w : Wall, g : flash.display.Graphics, ref)
	{
		var xdist, ydist, per : Float;
		var width = flash.Lib.current.stage.stageWidth;
		var height = flash.Lib.current.stage.stageHeight;
		g.beginFill (0);
 
		xdist = (ref.x - w.p0.x);
		ydist = (ref.y - w.p0.y);
 
		if (xdist < 0)
			per = (xdist/(w.p0.x-width));
		else
			per = (xdist/(w.p0.x-0));
 
		if (w.p0.y - (ydist/per) < 0)
 			per = (ydist/(w.p0.y-0));
 		else if (w.p0.y - (ydist/per) > height)
			per = (ydist/(w.p0.y-height));
 
		g.moveTo (w.p0.x, w.p0.y);
		g.lineTo (w.p0.x - (xdist/per), w.p0.y - (ydist/per));
 
		//p2
		xdist = (ref.x - w.p1.x);
		ydist = (ref.y - w.p1.y);
 
		if (xdist < 0)
			per = (xdist/(w.p1.x-width));
		else
			per = (xdist/(w.p1.x-0));
 
		if (w.p1.y - (ydist/per) < 0)
 			per = (ydist/(w.p1.y-0));
 		else if (w.p1.y - (ydist/per) > height)
			per = (ydist/(w.p1.y-height));
 
		g.lineTo (w.p1.x - (xdist/per), w.p1.y - (ydist/per));
		g.lineTo (w.p1.x, w.p1.y);
	}
 
	static var game : flash.display.Graphics;
	static var walls : Array;
}

Despite my dreadful explanation of the logic, the code is not very complicated as you can see. Here is what it might output:

As you can see, the points are all hitting the boundaries. My only problem now is how to fill in the corners. I actually haven't figured this out yet. I had an idea that because I know what boundary each segment point is hitting I could for instance fill in to the top left corner if one point was at the left boundary and one at the top. But this didn't really go that smoothly because sometimes one point hits the top and one the bottom, or left and right etc.

So to sum things up, the point of this article was to first of all get this off my chest and to maybe help others by seeing how I approached this. And second of all, I'm asking for help. If anyone has an idea on how I could calculate what corner(s) to fill the shadow to or maybe some other way to do shadows I'm interested to hear what you have to say.

Where has MochiAds in haXe gone? 04 Feb 2010 http://www.hesselbom.net/where-has-mochiads-in-haxe-gone

If you're looking for the post I wrote on 'Using MochiAds in haXe' in my old blog it has found a new home at http://hesselboom.com/mochi/.

I won't bother rewriting it here in the new blog because I don't want to keep changing it's URL so it will stay there until the next Titanic sinks.

Back in style! 04 Feb 2010 http://www.hesselbom.net/back-in-style

So I just recreated this blog because I felt I have some things to share and there was no real reason to close it the last time.

I also have a new design to boot! Without checking, I think it's mostly valid CSS and XHTML and all that jazz. The only mischief is probably the 'overflow-y' property, that I use in code blocks, but that is valid CSS3 so I guess you could say I'm actually ahead of CSS validators defaulting to 2.1!

So anyway, I have some thoughts I'd like to share in the future so be sure to subscribe to my feed and keep biting your nails waiting in anxiety for my next update.

In the meantime, be sure to check out Gregory Weir's website. I just found his website and he is suddenly one of my favorite game developers.