test_main.c 9.8 KB

/*************************************************************

  test_main.c : Nintendo 64 Music Tools Library Sample
  (c) Copyright 1998, Software Creations (Holdings) Ltd.

  Version 3.11

  N64DD demo main source file. This demo illustrates how to
  use the library in conjunction with the N64DD unit.

**************************************************************/

/* include system header files */
#ifndef F3DEX_GBI
#define F3DEX_GBI
#endif

#include <ultra64.h>
#include <sched.h>
#include <libmus.h>
#include <leo.h>

/* include application main header file */
#include "test_rom.h"

/* include application specific header files */
#include "test_n64dd.h"
#include "test_mem.h"


// prototypes...
void    StartThread (void *arg); 
void    GameThread  (void *arg);
void    MainLoop    (void);

// macros - stack sizes...
#define BOOTSTACK_SIZE      (STACKSIZE)
#define MAINSTACK_SIZE      (STACKSIZE)
// macros - size of the DMA queue...
#define DMA_QUEUE_SIZE      200
// macros - all geometry modes...
#define GEOM_ALL    G_SHADE|G_SHADING_SMOOTH|G_CULL_BOTH|G_FOG|G_LIGHTING|G_TEXTURE_GEN|G_TEXTURE_GEN_LINEAR|G_LOD
// macros - load projection and model matrices...
#define LOAD_PROJ   (G_MTX_PROJECTION|G_MTX_LOAD|G_MTX_NOPUSH)
#define LOAD_MODEL  (G_MTX_MODELVIEW|G_MTX_LOAD|G_MTX_NOPUSH)
// macros - background colour for screen (all three components)...
#define BGCOL       0


// typedefs - graphics task message...
typedef union 
{    
    struct 
    {
        short   type;
    } gen;    
    struct 
    {
        short   type;
    } done;    
    OSScMsg      app;    
} GFXMsg;
// typedefs - graphics information...
typedef struct 
{
    OSScTask    task;
    GFXMsg      msg;  
    u16         *cfb;
} GFXInfo;


// workspace - threads...
OSThread	gameThread;
OSThread	mainThread;
// workspace - thread stacks...
u64	bootStack       [BOOTSTACK_SIZE/8];
u64 mainThreadStack [MAINSTACK_SIZE/8];
u64 scheduleStack   [OS_SC_STACKSIZE/8];
// workspace - message queues...
OSMesgQueue     PiMessageQ;
OSMesg          PiMessages[DMA_QUEUE_SIZE];
OSMesgQueue     gfxFrameMsgQ;
OSMesg          gfxFrameMsgBuf[MAX_MESGS];
OSMesgQueue     dmaMessageQ;
OSMesg          dmaMessageBuf[MAX_MESGS];
// workspace - double buffered graphic information...
GFXInfo     gInfo[2];
// workspace - scheduler...
OSSched     sc;




// Entry point...
void boot(void *arg)
{
  int i;
  char *ap;
  u32 *argp;
  u32 argbuf[16];
	
  osInitialize();    
  osCreateThread(&mainThread, 1, (void *)StartThread, NULL,
		 (void *)(mainThreadStack+MAINSTACK_SIZE/8), (OSPri)MAIN_PRIORITY);
    
  osStartThread(&mainThread);
}

// start up thread...
void StartThread(void *arg) 
{
  // start PI manager for access to cartridge...
  osCreatePiManager((OSPri) OS_PRIORITY_PIMGR, &PiMessageQ, PiMessages, DMA_QUEUE_SIZE);
   
  // create game thread and start it...
  osCreateThread(&gameThread, 6, GameThread, NULL, bootStack+BOOTSTACK_SIZE/8, (OSPri)GAME_PRIORITY);    
  osStartThread(&gameThread);   
  // suspend this thread...
  osSetThreadPri(0, 0);	
  for(;;);
}

unsigned long screen1_malloc, screen2_malloc;
unsigned short *screen1_access, *screen2_access;

unsigned long long *yield;
u64 *fifo_buffer;

// game thread...
void GameThread(void *arg)
{
   OSScClient	client;
   int mode;

   /* create DMA message queue */
   osCreateMesgQueue(&dmaMessageQ, dmaMessageBuf, MAX_MESGS);

   /* call N64DD initialisation stuff */
   DiskInitialise();

   /* initialize default scheduler using "osTvType" */
   if (osTvType==0)
      mode = OS_VI_PAL_LAN1;      /* --- PROGRAMMING CAUTION --- */
   else if (osTvType==1)          /* Applications must not use "ovTvType" to switch the TV   */
      mode = OS_VI_NTSC_LAN1;     /* system from NTSC to PAL or PAL to NTSC. A Game Pak must */
   else                           /* not be compatible with both NTSC and PAL formats.       */
      mode = OS_VI_MPAL_LAN1;     
   osCreateScheduler(&sc, (void *)(scheduleStack+OS_SC_STACKSIZE/8), SCHEDULER_PRIORITY, mode, 1);

   MemInit();
   screen1_malloc = (unsigned long)MemMalloc((320*240*2)+64);
   screen2_malloc = (unsigned long)MemMalloc((320*240*2)+64);
   /* make sure screens are on 64-byte boundary */
   screen1_access = (unsigned short *)((screen1_malloc+63)&(~63));
   screen2_access = (unsigned short *)((screen2_malloc+63)&(~63));

   yield = MemMalloc(OS_YIELD_DATA_SIZE);
   fifo_buffer = MemMalloc(FIFO_DATA_SIZE);

   gInfo[0].msg.gen.type = OS_SC_DONE_MSG;
   gInfo[0].cfb = screen1_access;
   gInfo[1].msg.gen.type = OS_SC_DONE_MSG;
   gInfo[1].cfb = screen2_access;
    
   osCreateMesgQueue(&gfxFrameMsgQ, gfxFrameMsgBuf, MAX_MESGS);
   osScAddClient(&sc, &client, &gfxFrameMsgQ);
   
   /* call main loop (never returns from this) */
   MainLoop();
}


// workspace for MainLoop...

u64         glist[2][100];
OSScTask    *end_t;
GFXMsg      *end_msg;
Vp          vp0 = 
{
        (SCREEN_XSIZE/2)*4, (SCREEN_YSIZE/2)*4, G_MAXZ/2, 0,  /* scale */
        (SCREEN_XSIZE/2)*4, (SCREEN_YSIZE/2)*4, G_MAXZ/2, 0,  /* translate */
};
Vtx         tri[]=
{
  { -64, 64,-5,0,0,0,0,0xff,0,0xff},
  {  64, 64,-5,0,0,0,0,0,0,0xff},
  {  64,-64,-5,0,0,0,0xff,0,0,0xff},
};


//==========================================================================
//
// Main Loop
//
//==========================================================================

extern unsigned char *tune_buffer;

void MainLoop(void)
{
    u64 *glistp, *glist_start;
    int i, frame, drawing_flag;
    float angle;
    u32 work;
    OSScTask    *task;    
    Mtx projection_2d, mtxwork, model_2d[2];
 
    frame = drawing_flag = 0;
    angle = 0.0;

    // initialise for 2D...
    guOrtho(&projection_2d, 0.0, 320.0, 240.0, 0.0, -200.0, 200.0, 1.0);

    // initialise music player...
    InitMusicDriver();
    // start song...
    MusStartSong(tune_buffer);

//MemShowStatus();

    // loop for ever...
    while (1)
    {
      frame ^= 1;
      // rotating triangle...
      guTranslate(&model_2d[frame], 160.0, 120.0, 0.0);
      guRotate(&mtxwork, angle, 0.0F,0.0F,1.0F);    
      guMtxCatL(&mtxwork, &model_2d[frame], &model_2d[frame]);
      angle += 1.0;
      if (angle>=360.0)
        angle-=360.0; 
      glist_start = glistp = &glist[frame][0];

      // special video tackle...
      osViSetSpecialFeatures(OS_VI_DITHER_FILTER_ON);
      osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_GAMMA_DITHER_OFF);
      // setup segments...
      gSPSegment(glistp++, 0, 0);
      gSPSegment(glistp++,  CFB_SEG, OS_K0_TO_PHYSICAL(screen1_access) );
      // set defaults...
      gSPViewport(glistp++, &vp0);
      gSPClearGeometryMode (glistp++,GEOM_ALL);
      gSPTexture           (glistp++,0, 0, 0, 0, G_OFF);
      gSPSetGeometryMode(glistp++,G_SHADE | G_SHADING_SMOOTH);

      gDPSetCycleType      (glistp++,G_CYC_1CYCLE);
      gDPPipelineMode      (glistp++,G_PM_1PRIMITIVE);
      gDPSetScissor        (glistp++,G_SC_NON_INTERLACE, 0, 0, 320, 240);
      gDPSetTextureLOD     (glistp++,G_TL_TILE);
      gDPSetTextureLUT     (glistp++,G_TT_NONE);
      gDPSetTextureDetail  (glistp++,G_TD_CLAMP);
      gDPSetTexturePersp   (glistp++,G_TP_PERSP);
      gDPSetTextureFilter  (glistp++,G_TF_BILERP);
      gDPSetTextureConvert (glistp++,G_TC_FILT);
      gDPSetCombineMode    (glistp++,G_CC_SHADE, G_CC_SHADE);
      gDPSetCombineKey     (glistp++,G_CK_NONE);
      gDPSetAlphaCompare   (glistp++,G_AC_NONE);
      gDPSetColorDither    (glistp++,G_CD_DISABLE);

      // set colour buffer address...
      gDPSetColorImage(glistp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 320, osVirtualToPhysical(frame ? screen2_access : screen1_access));
      gDPPipeSync          (glistp++);

      // clear screen...
      work = GPACK_RGBA5551(BGCOL, BGCOL, BGCOL,1);
      gDPSetCycleType      (glistp++,G_CYC_FILL);
      gDPSetFillColor(glistp++, (work<<16) | work);
      gDPFillRectangle     (glistp++,0, 0, 320-1, 240-1);
      gDPPipeSync(glistp++);

      // now setup to draw something...
      gSPMatrix(glistp++, OS_K0_TO_PHYSICAL(&projection_2d), LOAD_PROJ);
      gSPMatrix(glistp++, OS_K0_TO_PHYSICAL(&model_2d[frame]), LOAD_MODEL);
      gDPSetCycleType(glistp++, G_CYC_1CYCLE);
      gDPSetRenderMode(glistp++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
 
      // draw simple triangle...     
      gDPPipeSync(glistp++);      
      gSPVertex(glistp++,  OS_K0_TO_PHYSICAL(&tri[0]),3,0);
      gSP1Triangle(glistp++, 0, 1, 2, 0);
      gDPFullSync(glistp++);
      gSPEndDisplayList(glistp++);

      // make sure previous draw list is complete...
      if (drawing_flag)
      {
        do
        {
          osRecvMesg(&gfxFrameMsgQ, (OSMesg *)&end_msg, OS_MESG_BLOCK);
        } while (end_msg->gen.type!=OS_SC_DONE_MSG);
      }
      drawing_flag = 1;

      /* create graphic task */
      task = &gInfo[frame].task;
      task->list.t.data_ptr = (u64 *) glist_start;
      task->list.t.data_size = glistp-glist_start;
      task->list.t.type = M_GFXTASK;
      task->list.t.flags = 0x0;
      task->list.t.ucode_boot = (u64 *)rspbootTextStart;
      task->list.t.ucode_boot_size = ((int) rspbootTextEnd - (int) rspbootTextStart);
      task->list.t.ucode = (u64 *) gspF3DEX_fifoTextStart;
      task->list.t.ucode_data = (u64 *) gspF3DEX_fifoDataStart;
      task->list.t.ucode_size      = 4096;
      task->list.t.ucode_data_size = 2048;
      task->list.t.dram_stack = NULL;
      task->list.t.dram_stack_size = 0;
      task->list.t.output_buff = fifo_buffer;
      task->list.t.output_buff_size = fifo_buffer+(FIFO_DATA_SIZE/sizeof(u64));
      task->list.t.yield_data_ptr = yield;
      task->list.t.yield_data_size = OS_YIELD_DATA_SIZE;
      task->next     = 0;
      task->flags = OS_SC_NEEDS_RSP | OS_SC_NEEDS_RDP | OS_SC_LAST_TASK | OS_SC_SWAPBUFFER;
      task->msgQ     = &gfxFrameMsgQ;
      task->msg      = (OSMesg)&gInfo[frame].msg;
      task->framebuffer = (void *)gInfo[frame].cfb;

      // start task...
      osWritebackDCacheAll();
      osSendMesg(osScGetCmdQ(&sc), (OSMesg) task, OS_MESG_BLOCK);
    }
}


/* end of file */