topical media & game development

talk show tell print

hush-src-multi-GamePlayer-CustomUILayer.cpp / cpp



  //------------------------------------------------------------------------------
  // File: CustomUILayer.cpp
  //
  // Desc: DirectShow sample code - MultiVMR9 GamePlayer
  //
  // Copyright (c) Microsoft Corporation.  All rights reserved.
  //------------------------------------------------------------------------------
  
  include <stdafx.h>
  include <CustomMixer.h>
  include <CustomUILayer.h>
  include <GamePlayer.h>
  include <resource.h>
  
  //#include "scene/scene.h"
  include <vip.h>
  extern vip* VP;
  
  extern IDirect3DTexture9* gCaptureTexture;
  extern CGamePlayerSession* g_pSession;
  
  static int vip_on = 1;
  
  static int moving = 0;
  static int xPos = 0;
  static int yPos = 0;
  static int bmode = 0;
  
  
****************************Public*Routine******************************\ CGameUILayer constructor \*************************************************************************

  
  CGameUILayer::CGameUILayer(LPUNKNOWN pUnk, HRESULT *phr)
      : CUnknown(NAME("GameUILayer for MultiVMR9"), pUnk)
      , m_bInitialized( FALSE )
      , m_bViewing( TRUE )
      , m_pOwner( NULL )
      , m_pTextureButtonResume( NULL )
      , m_pTextureButtonView( NULL )
      , m_pMixer( NULL )
  {
      // initialize vertices here
      m_V[0].Pos.x = 300.f;   m_V[0].Pos.y =  -200.f; m_V[0].Pos.z = 0.f;
      m_V[1].Pos.x = 364.f;   m_V[1].Pos.y =  -200.f; m_V[1].Pos.z = 0.f;
      m_V[2].Pos.x = 300.f;   m_V[2].Pos.y =  -264.f; m_V[2].Pos.z = 0.f;
      m_V[3].Pos.x = 364.f;   m_V[3].Pos.y =  -264.f; m_V[3].Pos.z = 0.f;
  
      m_V[0].tu = 0.f;    m_V[0].tv = 0.f;
      m_V[1].tu = 1.f;    m_V[1].tv = 0.f;
      m_V[2].tu = 0.f;    m_V[2].tv = 1.f;
      m_V[3].tu = 1.f;    m_V[3].tv = 1.f;
  }
  
  
****************************Public*Routine******************************\ ~CGameUILayer destructor \*************************************************************************

  
  CGameUILayer::~CGameUILayer()
  {
      CAutoLock Lock(&m_ObjectLock);
      RELEASE( m_pOwner );
      RELEASE( m_pTextureButtonResume );
      RELEASE( m_pTextureButtonView );
      RELEASE( m_pMixer );
  }
  
  
/////////////////// IUnknown
///////////////////////////////////


****************************Public*Routine******************************\ CreateInstance \*************************************************************************

  
  CUnknown* CGameUILayer::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
  {
      return new CGameUILayer(pUnk, phr);
  }
  
  
****************************Public*Routine******************************\ NonDelegatingQueryInterface \*************************************************************************

  
  STDMETHODIMP
  CGameUILayer::NonDelegatingQueryInterface(
      REFIID riid,
      void ** ppv)
  {
      HRESULT hr = E_NOINTERFACE;
      *ppv = NULL;
  
      if (riid == IID_IMultiVMR9UILayer) 
      {
          hr = GetInterface((IMultiVMR9UILayer *)this, ppv);
      }
      else 
      {
          hr = CUnknown::NonDelegatingQueryInterface(riid,ppv);
      }
      return hr;
  }
  
  
////////////////////// IMultiVMR9UILayer
//////////////////////////


****************************Public*Routine******************************\ SetRenderEngineOwner \*************************************************************************

  
  STDMETHODIMP
  CGameUILayer::SetRenderEngineOwner(
          IMultiVMR9RenderEngine* pRenderEngine)
  {
      HRESULT hr = S_OK;
      CAutoLock Lock(&m_ObjectLock);
  
      try
      {
          RELEASE( m_pOwner );
          if( pRenderEngine )
          {
              m_pOwner = pRenderEngine;
              m_pOwner->AddRef();
          }
      }
      catch( HRESULT hr1)
      {
          hr = hr1;
      }
      return hr;
  }
  
  
****************************Public*Routine******************************\ GetRenderEngineOwner \*************************************************************************

  
  STDMETHODIMP
  CGameUILayer::GetRenderEngineOwner(
          IMultiVMR9RenderEngine** ppRenderEngine)
  {
      if( !ppRenderEngine )
      {
          return E_POINTER;
      }
      if( !m_pOwner )
      {
          return VFW_E_NOT_FOUND;
      }
  
      *ppRenderEngine = m_pOwner;
      (*ppRenderEngine)->AddRef();
  
      return S_OK;
  }
  
  
****************************Public*Routine*****************************\ Initialize \*************************************************************************

  
  STDMETHODIMP
  CGameUILayer::Initialize(
                         IDirect3DDevice9 *pDevice)
  {
      HRESULT hr = S_OK;
  
      // load buttons from resources
      if( m_bInitialized )
      {
          return VFW_E_WRONG_STATE;
      }
      if( !pDevice )
      {
          return E_POINTER;
      }
  
      try
      {
          CHECK_HR(
              hr = D3DXCreateTextureFromResource( pDevice,
                                                  NULL,
                                                  MAKEINTRESOURCE( IDB_UIBTN_RESUME ),
                                                  &m_pTextureButtonView ),
          DbgMsg("CGameUILayer::Initialize: failed to load texture for the button, hr = 0x%08x", hr));
  
          CHECK_HR(
              hr = D3DXCreateTextureFromResource( pDevice,
                                                  NULL,
                                                  MAKEINTRESOURCE( IDB_UIBTN_VIEW ),
                                                  &m_pTextureButtonResume ),
          DbgMsg("CGameUILayer::Initialize: failed to load texture for the button, hr = 0x%08x", hr));
      }
      catch( HRESULT hr1 )
      {
          hr = hr1;
      }
      return hr;
  }
  
  
****************************Public*Routine*****************************\ BeginDeviceLoss \*************************************************************************

  
  STDMETHODIMP CGameUILayer::BeginDeviceLoss(void)
  {
          HRESULT hr = S_OK;
          m_bInitialized = FALSE;
          RELEASE( m_pTextureButtonResume );
          RELEASE( m_pTextureButtonView );
          return S_OK;
  }
  
  
****************************Public*Routine*****************************\ EndDeviceLoss \*************************************************************************

  
  STDMETHODIMP CGameUILayer::EndDeviceLoss(IDirect3DDevice9* pDevice)
  {
          HRESULT hr = S_OK;
          if( !pDevice )
                  return E_POINTER;
          hr = Initialize( pDevice );
          return hr;
  }
  
  
****************************Public*Routine*****************************\ Render \*************************************************************************

  
  STDMETHODIMP
  CGameUILayer::Render(
                       IDirect3DDevice9 *pDevice)
  {
      HRESULT hr = S_OK;
  
          //return hr;
  
      IDirect3DStateBlock9 *pState = NULL;
      D3DMATRIX matW;
      D3DXMATRIX matW1, matW2;
  
      if( !pDevice )
      {
          return E_POINTER;
      }
  
          
      try
      {
          CHECK_HR(
              hr = pDevice->BeginStateBlock(),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pDevice->EndStateBlock(&pState),
              DbgMsg(""));
  
                  if (1) { //XX
      pDevice->SetRenderState( D3DRS_ZENABLE,  D3DZB_TRUE );
      pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
    
      pDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE );
          }
  
          if (1) { //XX
                          hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
      hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
      hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
      hr = pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
                  }
          //scene::fx("walk",0);
  
          //scene::tx(1,scene::tx("camera"));
          
          if (vip_on && VP->_main() && scene::ds("video:overlay")) {
                  
                  VP->_main()->render(pDevice,gCaptureTexture);
          }
  
          pDevice->GetTransform( D3DTS_WORLD, &matW);
          D3DXMatrixIdentity( &matW1);
                  D3DXMatrixIdentity( &matW2);
  
                  matW2._41 = -0.5;
  
                  
          pDevice->SetTransform( D3DTS_WORLD, &matW1);
                  if (1) { //XX
          pDevice->SetRenderState( D3DRS_ZENABLE,  D3DZB_FALSE );
          pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
          pDevice->SetRenderState( D3DRS_SRCBLEND,    D3DBLEND_SRCALPHA );
          pDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
          pDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
          pDevice->SetRenderState( D3DRS_ALPHAREF,         0x06 );
          pDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
                  }
  
                  if (1) { //XX
          CHECK_HR(
              hr = pDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID ),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ),
              DbgMsg(""));
                  }
  
                  if (1) { //XX
                          hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
      hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
      hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
      hr = pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
                  }
        
          if( m_bViewing )
          {
                          if( m_pTextureButtonResume )
                          {
                                  CHECK_HR(
                                          hr = pDevice->SetTexture(0, m_pTextureButtonResume),
                                          DbgMsg(""));
                          }
          }
          else
          {
                          if( m_pTextureButtonView )
                          {
                                  CHECK_HR(
                                          hr = pDevice->SetTexture(0, m_pTextureButtonView),
                                          DbgMsg(""));
                          }
          }
  // AE
                  
                  if (!scene::ds("nopreview") && !scene::ds("hide:0"))
                  for (int i = 1; i <= 9; i++) {
                          if (!scene::ds(scene::fm("hide:\%d",i)) && scene::tx(i)) {
                  matW1._41 = -(i-1) * 80;
          pDevice->SetTransform( D3DTS_WORLD, &matW1);
                  if (scene::tx(i)) pDevice->SetTexture( 0, scene::tx(i) );
  
          CHECK_HR(
              hr = pDevice->SetFVF( m_FVFUILayer ),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pDevice->DrawPrimitiveUP(  D3DPT_TRIANGLESTRIP,
                                              2,
                                              (LPVOID)(m_V),
                                              sizeof(m_V[0])),
              DbgMsg(""));
          
                  }
                  }
  
          pDevice->SetTransform( D3DTS_WORLD, &matW);
  
          CHECK_HR(
              hr = pDevice->SetTexture(0, NULL),
              DbgMsg(""));
  
          CHECK_HR(
              hr = pState->Apply(),
              DbgMsg(""));
      }
      catch( HRESULT hr1 )
      {
                  if( D3DERR_DEVICELOST == hr1 && m_pOwner )
                  {
                          hr = m_pOwner->ProcessLostDevice();
                  }
                  else
                  {
                          hr = hr1;
                  }
      }
          if (1) { //XX
      pDevice->SetRenderState( D3DRS_ZENABLE,  D3DZB_TRUE );
      pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
    
      pDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE );
          }
          //scene::fx("walk",0);
  
          //scene::tx(1,scene::tx("camera"));
          
          if (!scene::ds("video:overlay") && vip_on && VP->_main()) {
                  
                  VP->_main()->render(pDevice,gCaptureTexture);
          }
  
          //scene::tx(1,scene::tx("camera"));
  
          if (1) { //XX
      pDevice->SetRenderState( D3DRS_ZENABLE,  D3DZB_FALSE);
      pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
      pDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
          }
          /*
          pDevice->SetRenderState( D3DRS_ZENABLE,  D3DZB_TRUE );
      pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
      pDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE );
  */        
          pDevice->GetTransform( D3DTS_WORLD, &matW);
  
          static int once = 0;
          int flip = scene::ds("flip"); //VP->_main()->iopt("flip");
          if (flip != 0 ) {
          once++;
      //VP->_main()->opt("flip","0");
          scene::ds("flip",0);
          hr = m_pMixer->Animate( !m_bViewing );
                          if( S_OK == hr )
                          {
                              m_bViewing = !m_bViewing;
                          }
          }
  
      RELEASE( pState );
      return hr;
  }
  
  
****************************Public*Routine*****************************\ ProcessMessage \*************************************************************************

  
  
  static void _handle(char* s1, char* s2) {        VP->handle(s1,s2); }
  
  STDMETHODIMP
  CGameUILayer::ProcessMessage(
          UINT msg, 
          UINT wParam, 
          LONG lParam
          )
  {
      switch( msg )
      {
                  case WM_KEYUP:
                          if (wParam == VK_CONTROL) { VP->ctrl(0);  } //scene::_ctrl = 0; }
                          else if (wParam == VK_SHIFT) { VP->shift(0);  } //scene::_shift = 0; }
                          else if (wParam == VK_UP) _handle("stop","up");
                          else if (wParam == VK_LEFT) _handle("stop","left");
                          else if (wParam == VK_RIGHT) _handle("stop","right");
                          else if (wParam == VK_DOWN) _handle("stop","down");
                          break;
                  case WM_KEYDOWN:
                          if (wParam == VK_ESCAPE) {
                                  //::DestroyWindow(hWnd);
                                  //return 0;
                                  //exit(0); break;;
  
                  //delete g_pSession;
                                  //g_pSession = 0;
                                  //::KillTimer( GetSafeHwnd(), 0);
  
                                  _handle("key","escape");
                          }
                          else if (wParam == VK_SPACE) 
                                  //MessageBox(0,"space","odyssee",MB_OK);
                                  _handle("key","space");
                          else if (wParam == VK_TAB) {
                                  //MessageBox(0,"tab","odyssee",MB_OK);
                                    _handle("key","tab");
                                    //doit();
                          }
                          else if (wParam == VK_RETURN) _handle("key","return");
  
                          else if (wParam == VK_BACK) _handle("key","back");
  
                          else if (wParam == VK_CONTROL) { VP->ctrl(1); } //scene::_ctrl = 1; }
                          else if (wParam == VK_SHIFT) { //_handle("key","shift"); //
                          VP->shift(1);
                          
                              if (VP->ctrl() && VP->shift()) {
                          if (vip_on) vip_on = 0;
                          else vip_on = 1;
                      }
                          } //scene::_shift = 1; }
  
                          else if (wParam == VK_UP) _handle("arrow","up");
                          else if (wParam == VK_LEFT) _handle("arrow","left");
                          else if (wParam == VK_RIGHT) _handle("arrow","right");
                          else if (wParam == VK_DOWN) _handle("arrow","down");
  
                          else {
                             char buf[64];
                             int x = wParam; char c ='-';
                             if (x > 47 && x < 48+10) c = '0' + x - 48;
                             else if (x > 64 && x < 65+26 ) c = 'a' + x - 65;
                             if (c != '-') sprintf(buf,"\%c",c);
                             else sprintf(buf,"%3d",wParam);
                                _handle("key",buf);
                          }
                          break;
                  case WM_MOUSEMOVE: 
                          if (1) { 
                              bmode = 1;
                              moving = 1; 
                                  xPos = GET_X_LPARAM(lParam); 
                  yPos = GET_Y_LPARAM(lParam); 
                                  VP->x(xPos);
                                  VP->y(yPos);
                                  //scene::ds("mouse:x",xPos);
                                  //scene::ds("mouse:y",yPos);
                                  //moving = 0; 
                                  }
                                  if (0)  
                                         break;;
          case WM_LBUTTONUP: 
              {
                                  if (bmode == 1) moving = 1;
                                  else moving = 0;
                                  bmode = 0;
                  HRESULT hr = S_OK;
                  xPos = GET_X_LPARAM(lParam); 
                  yPos = GET_Y_LPARAM(lParam); 
  
                                  VP->x(xPos);
                                  VP->y(yPos);
  
                                  //scene::ds("mouse:x",xPos);
                                  //scene::ds("mouse:y",yPos);
  
                                  //if (!moving && scene::ds("track:button")) _handle("lbutton","down");
  
                  if( m_pMixer )
                  {
                                          
                                          if (yPos < 50) {
                                                  int b = 0;
                                              int cb = 27;
                          int cw = VP->width() / 30;
                                                  for (int i = 1; i <= 35; i++) {
                                                          if (xPos < (VP->width() - ((i-1) * cw))) {
                                                                  b = 1; cb--;
                                                          }
                                                  }
                                      if (b) {
                                                          if (cb <= 0) VP->cmd("space");
                                                          //scene::cm("button:command","space");
                                                          else if (cb <= 26) VP->cmd(scene::fm("\%c",'a'+(cb-1)));
                                                          //scene::cm("button:command",scene::fm("\%c",'a'+(cb-1)));
                                                          //else if (cb <= 26) scene::cm("button:command","space");
                                                          else VP->cmd("space");
                                                          //scene::cm("button:command","space");
                                                          if (!moving) _handle("command","button");
                                                          //if (!moving) _handle("command",scene::cm("button:command"));
                                              }
                                      
                                              moving = 0;
  
                                          } else if ((yPos > (VP->height() - 150)) )// && yPos <600 )
                                          {
                                          int b = 0;
                                          int cb = 0;
                                          //scene::ds("flip",1);
                                          //scene::ds("focus",0); 
  
                                          if (1) {
                                          int xw = VP->width();
                                          int dw = VP->width() / 9.75; //105;
                                          //if (yPos > (VP->height() - 200)) {
                                          
                                          for (int i = 1; i <= 10; i++) {
                                                          if (xPos < (xw - ((i-1) * dw))) {
                                                                  //if (scene::tx(i)) scene::ds("focus",i); 
                                                                  b = 1;
                                                                  cb = i;
                                                          }
                                          }}
                                                  
                                          if (b) {
                                                  if (cb == 10) cb = 0;
                                                  //scene::cm("button:command",scene::fm("\%d",cb));
                                                  VP->cmd(scene::fm("\%d",cb));
                                                  if ( !moving && (!scene::ds("in:dossier")
                                                          || scene::ds("neutral") || scene::ds("select")) 
                                                          && (cb == 0 || scene::tx(cb)) ) {
                                                          scene::ds("focus",cb); 
                                                      scene::ds("flip",1);
                                                          //scene::ds("select",0);
                                                  } else
                                                  //if (!moving) _handle("command",scene::cm("button:command"));
                                                  if (!moving) _handle("command","button");
                                          }
                                           
                          /*
                                                  hr = m_pMixer->Animate( !m_bViewing );
                          if( S_OK == hr )
                          {
                              m_bViewing = !m_bViewing;
                          }*/
                                              moving = 0;
                                          } else {
                                                  int xd = VP->width() / 9;
                                                  int yd = (VP->height() - 200) / 3;
                          int y31 = 50; int y32 = y31 + yd; int y33 = y32 + yd; 
                                                  int y34 = VP->height()-150;
                                                  int y21 = 50; int y22 = y21 + 1.5 * yd; int y23 = y34;
                                                  int x0 = 0; int x1 = xd; int x2 = x1 + 2 * xd;
                                                  int x3 = x2 + 3 * xd; int x4 = x3 + 2 * xd; int x5 = VP->width();
  
                                                  if ( (xPos > x0) && (xPos < x1) ) {
                                                          if ((yPos > y31) && (yPos < y32)) {
                                                                  VP->cmd("tab");
                                                                  //scene::cm("button:command","tab");
                                                          } else if ((yPos > y32) && (yPos < y33)) {
                                                                  //scene::cm("button:command","shift");
                                                                  VP->cmd("shift");
                              } else if ((yPos > y33) && (yPos < y34)) {
                                                                  //scene::cm("button:command","control");
                                                                  VP->cmd("control");
                                                          }
                                                  } else if ( (xPos > x1) && (xPos < x2) ) {
                                                          if ((yPos > y21) && (yPos < y22)) {
                                                                  scene::cm("button:command","meta");
                                                                  VP->cmd("meta");
                                                          } else if ((yPos > y22) && (yPos < y23)) {
                                                                  //scene::cm("button:command","effect");
                                                                  VP->cmd("objects");
                                                          }
                                                  } else if ( (xPos > x2) && (xPos < x3) ) {
                                                          if (0) {
                                                          if ((yPos > y21) && (yPos < y22)) {
                                                                  //scene::cm("button:command","neutral");
                                                                  VP->cmd("neutral");
                                                          } else if ((yPos > y22) && (yPos < y23)) {
                                                                  //scene::cm("button:command","space");
                                                                  VP->cmd("space");
                                                          }
                                                          } else {
  
                                                          if ((yPos > y31) && (yPos < y32)) {
                                                                  //scene::cm("button:command","neutral");
                                                                  VP->cmd("neutral");
                                                          } else if ((yPos > y32) && (yPos < y33)) {
                                                                  //scene::cm("button:command","space");
                                                                  VP->cmd("space");
                              } else if ((yPos > y33) && (yPos < y34)) {
                                                                  //scene::cm("button:command","select");
                                                                  VP->cmd("select");
                                                          }
                                                          }
                                                  } else if ( (xPos > x3) && (xPos < x4) ) {
                                                          if ((yPos > y21) && (yPos < y22)) {
                                                                  //scene::cm("button:command","command");
                                                                  VP->cmd("command");
                                                          } else if ((yPos > y22) && (yPos < y23)) {
                                                                  //scene::cm("button:command","exec");
                                                                  VP->cmd("effects");
                                                          }
                                                  } else if ( (xPos > x4) && (xPos < x5) ) {
                                                          if ((yPos > y31) && (yPos < y32)) {
                                                                  //scene::cm("button:command","back");
                                                                  VP->cmd("back");
                                                          } else if ((yPos > y32) && (yPos < y33)) {
                                                                  //scene::cm("button:command","return");
                                                                  VP->cmd("return");
                              } else if ((yPos > y33) && (yPos < y34)) {
                                                                  //scene::cm("button:command","choice");
                                                                  VP->cmd("choice");
                                                          }
  
                                                  }
                                                  if (!moving) _handle("command","button");
                                                          //_handle("command",scene::cm("button:command")); 
                          moving = 0;
  
                                          }
                     
                  }
                                  
              }
                          moving = 0;
              break;
                          
      }
  
      return S_OK;
  }
  
  
****************************Public*Routine*****************************\ SetMixer \*************************************************************************

  
  HRESULT CGameUILayer::SetMixer( CGameMixer* pMixer )
  {
      RELEASE( m_pMixer );
  
      if( pMixer )
      {
          m_pMixer = pMixer;
          m_pMixer->AddRef();
      }
  
      return S_OK;
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.