Subject: The essential non-weirdness of Son'ys Playstation PS2

From: [email-masked] (Dan Kolis)
Date: Thu, 2 Jan 2003 16:54:58 -0500

Hi,

I happen to have an aquaintance who taught a course in California on writing
video games. This code fragment example is *hard* to find and *harder* to
believe. 

With the Playstation PS2 selling 27 boxes a minute worldwide... and game
consoles selling 5+ billion $ a year, the box is actually *easy* to program! 

The below is 100% of the source to make some stars fly by. The point is how
totally ordinary this all is. Compiled under Linux with free compilers, yet!

Sony has done a good job of making the last step of making a PS2 compliant
CD very difficult. But, fooling the box for testing is reasonably easy. And
they are not unreasonable about the publishing rights, etc.

The below seems completely accessable. A few weird libraries in the includes
and that's it!
 
I don't know if you find this as unexpected as I do. I visualized it would
take a dozen $100K programs glued together by weirdo "good luck" code to run. 

Don't forget this $250 computer has 15 times the throughput of a Pentium at
1 GHz. And an audiance that would crawl over broken glass to play.

I think the audience on this email reflector might find this interesting.
Hope I'm right on that...

The author is on the CC line and the leading comments. Thanks for WWW access
to this code!

Regards to all,
Dan Kolis

// lilplasma.c
// my non-vpu-using first attempt at PS2 graphics.
// inefficient, but pretty!
//
// - [email-masked]
// (or) [email-masked]

// to compile:
// cc -o lilplasma lilplasma.c -lps2dev -lm

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <linux/ps2/dev.h>
#include <ps2gs.h>
#include <ps2dma.h>
#include <math.h>

static int gsFd = 0;
static ps2_gs_gparam *gsParam;
static ps2_gs_dbuff gsDb;
static ps2_gs_finish gsFinish;

typedef struct {
  ps2_giftag     tag;
  ps2_gsreg_rgbaq rgb0;
  ps2_gsreg_addr rgb0Addr;
  ps2_gsreg_xyz  xyz0;
  ps2_gsreg_addr xyz0Addr;
  ps2_gsreg_rgbaq rgb1;
  ps2_gsreg_addr rgb1Addr;
  ps2_gsreg_xyz  xyz1;
  ps2_gsreg_addr xyz1Addr;
  ps2_gsreg_rgbaq rgb2;
  ps2_gsreg_addr rgb2Addr;
  ps2_gsreg_xyz  xyz2;
  ps2_gsreg_addr xyz2Addr;
} TriPacket __attribute__((aligned(16)));

static TriPacket triPacket;

static int costa[256];
static int t;

void cleanup()
{
  if (gsFd > 0) { ps2_gs_close(); }
}

void draw();
void renderinit();

int main( int argc, char *argv[] )
{
  int frame, field;
  signal( SIGINT, exit );
  atexit( cleanup );

  //triPacket = memalign( 128, 128 ); 

  gsFd = ps2_gs_open(-1);
  assert( gsFd > 0 );
  gsParam = ps2_gs_get_gparam();
  ps2_gs_vc_graphicsmode();

  ps2_gs_reset( 0, PS2_GS_INTERLACE, PS2_GS_VESA, PS2_GS_FRAME,
PS2_GS_640x480, PS2_GS_60Hz );

  ps2_gs_set_dbuff( &gsDb, PS2_GS_PSMCT32,
    gsParam->width, gsParam->height,
    PS2_GS_TEST_ZTST_NEVER, PS2_GS_PSMZ16S, 0 );

  *(__u64 *)&gsDb.clear0.rgbaq =
    PS2_GS_SETREG_RGBAQ( 0,0,0, 0x80, 0x3f800000 );

  *(__u64 *)&gsDb.clear1.rgbaq =
    PS2_GS_SETREG_RGBAQ( 0,0,0, 0x80, 0x3f800000 );

  //ps2_gs_put_drawenv( &gsDb.giftag1 );

  ps2_gs_set_finish( &gsFinish );
  ps2_gs_wait_finish( &gsFinish );

  ps2_gs_start_display(1);

  field = 0;
  frame = !ps2_gs_sync_v( 0 );
  renderinit();
  while(1) {
    ps2_gs_set_half_offset( frame ? &gsDb.draw1 : &gsDb.draw0, field );
    ps2_gs_swap_dbuff( &gsDb, field );
    draw();
    ps2_gs_wait_finish( &gsFinish );
    frame = !ps2_gs_sync_v( 0 );
    field = field ^ 1;
  }

  return 0;
}
  
void renderinit( )
{
  triPacket.tag.NLOOP = 6;
  triPacket.tag.EOP   = 1;
  triPacket.tag.PRE   = 1;
  triPacket.tag.FLG   = PS2_GIFTAG_FLG_PACKED;
  triPacket.tag.NREG  = 1;
  triPacket.tag.REGS0 = PS2_GIFTAG_REGS_AD;
  triPacket.tag.PRIM  =
    PS2_GS_SETREG_PRIM(
       PS2_GS_PRIM_PRIM_TRIANGLE,
       PS2_GS_PRIM_IIP_GOURAUD,
       PS2_GS_PRIM_TME_OFF,
       PS2_GS_PRIM_FGE_OFF,
       PS2_GS_PRIM_ABE_OFF,      
       PS2_GS_PRIM_AA1_OFF,
       PS2_GS_PRIM_FST_STQ,
       PS2_GS_PRIM_CTXT_CONTEXT1,
       PS2_GS_PRIM_FIX_NOFIXDDA );
  triPacket.rgb0Addr = PS2_GS_RGBAQ;
  triPacket.rgb1Addr = PS2_GS_RGBAQ;
  triPacket.rgb2Addr = PS2_GS_RGBAQ;
  triPacket.xyz0Addr = PS2_GS_XYZF2;
  triPacket.xyz1Addr = PS2_GS_XYZF2;
  triPacket.xyz2Addr = PS2_GS_XYZF2;
  triPacket.xyz0.Z = 0xFFFFFF;
  triPacket.xyz1.Z = 0xFFFFFF;
  triPacket.xyz2.Z = 0xFFFFFF;

  {
    int x;
    for (x = 0; x < 256; x++) {
      costa[x] = (int)(32767.0f * cos((float)x * 3.14159f * 2.0f / 256.0f));
    }
  }
}

void triangle( unsigned char r0,
       unsigned char g0,
       unsigned char b0,
       int x0, int y0,
       unsigned char r1,
       unsigned char g1,
       unsigned char b1,
       int x1, int y1,
       unsigned char r2,
       unsigned char g2,
       unsigned char b2,
       int x2, int y2 )
{
  triPacket.rgb0.R = r0;
  triPacket.rgb0.G = g0;
  triPacket.rgb0.B = b0;
  triPacket.rgb1.R = r1;
  triPacket.rgb1.G = g1;
  triPacket.rgb1.B = b1;
  triPacket.rgb2.R = r2;
  triPacket.rgb2.G = g2;
  triPacket.rgb2.B = b2;

  triPacket.xyz0.X = (gsParam->center_x + x0) << 4;
  triPacket.xyz0.Y = (gsParam->center_y + y0) << 4;
  triPacket.xyz1.X = (gsParam->center_x + x1) << 4;
  triPacket.xyz1.Y = (gsParam->center_y + y1) << 4;
  triPacket.xyz2.X = (gsParam->center_x + x2) << 4;
  triPacket.xyz2.Y = (gsParam->center_y + y2) << 4;

  ps2_gs_put_drawenv( &(triPacket.tag) );
}

void draw()
{
  unsigned char r[64][48];
  unsigned char g[64][48];
  unsigned char b[64][48];
  int x, y;

  t++;

  for (x = 0; x < 17; x++) {
    for (y = 0; y < 13; y++) {
      r[x][y] = (((int)costa[(x * 22 + t * 8) & 255] +
          (int)costa[(y * 19 + t * 6) & 255] +
  (int)costa[((x + x + y) * 9 + t * 4) & 255] +
  (int)costa[((x + x + x + y) * 10 + t * 2) & 255] 
  ) >> 10) + 128;

      g[x][y] = (((int)costa[((x + y + y) * 18 + t * 3) & 255] +
  (int)costa[(y * 32 + t * 9) & 255] +
          (int)costa[(x * 17 - t * 4) & 255] +
  (int)costa[((x + y) * 12 + t * 5) & 255] 
  ) >> 10) + 128;

      b[x][y] = (((int)costa[((x + x + y) * 18 + t * 2) & 255] +
  (int)costa[((y + x) * 8 + t * 7) & 255] +
          (int)costa[(x * 10 - t * 3) & 255] +
          (int)costa[(y * 23 + t * 5) & 255]
  ) >> 10) + 128;
    }
  }

  for (x = 0; x < 16; x++) {
    for (y = 0; y < 12; y++) {
      triangle( r[x][y], g[x][y], b[x][y],
(x - 8) * 40 , (y - 6) * 40,
r[x+1][y], g[x+1][y], b[x+1][y],
(x - 8 + 1) * 40 , (y - 6) * 40,
r[x][y+1], g[x][y+1], b[x][y+1],
(x - 8) * 40 ,  (y - 6+1) * 40 );

      triangle( r[x+1][y], g[x+1][y], b[x+1][y],
(x - 8+1) * 40 , (y - 6) * 40,
r[x+1][y+1], g[x+1][y+1], b[x+1][y+1],
(x - 8+1) * 40 , (y - 6+1) * 40,
r[x][y+1], g[x][y+1], b[x][y+1],
(x - 8)   * 40,  (y - 6+1) * 40 );
    }
  }
}

Document end
02 Jan 2003

Dan Kolis - Lindsay Electronics Ltd [email-masked]
50 Mary Street West, Lindsay Ontario Canada K9V 2S7
(705) 324-2196               (705) 324-5474 Fax
An ISO 9001 Company; SCTE Member ISM-127194
/Document end