/*-------------------------------------------------------------------------*/
/*  J3W ver 6.43  3D Animation Kit                                         */
/*  j3dproc.cpp   04/04/2001                                               */
/*  Copyright (C) 1996 - 2001 Jun Mizutani <jun.mizutani@nifty.ne.jp>      */
/*                      All rights reserved.                               */
/*                                                                         */
/*   This file is part of the J3W 3D Animation Kit, and is covered under   */
/*  the terms of the GNU General Public License, version 2. This file has  */
/*  NO WARRANTY. See file COPYING for copyright details.                   */
/*                                                                         */
/*-------------------------------------------------------------------------*/

#ifdef WS
#include <stdio.h>
#else //WS
#include  <iomanip.h>
#include  <iostream.h>
#endif //WS
#include  <stdlib.h>
#include  <stdio.h>
#include  "j3dproc.h"
#include  "j3djob.h"
#ifndef WS
#include  "xkey.h"
#endif //WS
#include  "misc3d.h"

const int version1 =  6;
const int version2 = 43;

const int _RAND_MAX = 2147483647;

const double SC_FACTOR = 1000.0;

TProcess::TProcess(TJob* jp, int maxData, int StartPos,
                         cCode* code_ptr, TSpaceH3D* p_space,
                         const long *_reg, const int on)
{

    int i;
    fnew = 1;
    fwait = 0;
    pJob = jp;
    maxDataMem = maxData;
    pSpace = p_space;
    ObjNo = on;
    if (ObjNo >= 0) pObj = pSpace->get_object(ObjNo);
    else pObj = 0;
    pCode = code_ptr;
    pc = StartPos;
    rest_time = 0;
    aMessage = 0;
    DataMem = new long[maxDataMem];
    sp = maxDataMem;
    fl = 0;
    Reg[1] = 0;
    if (_reg != 0)
        for(i=2;i<16;i++) Reg[i] = _reg[i];
}

TProcess::~TProcess()
{
    delete DataMem;
}

int TProcess::CheckError(int err)
{
    if (err != 0) {
        pJob->ResetGraph();
        pJob->SendMessage(PROC_ALL, M_STOP);
#ifdef WS
#else //WS
        cout << '\n';
        cout << " # of Object  : " << dec << pSpace->count_object() << '\n';
        cout << " # of Process : " << dec << pJob->count_process() << '\n';
        cout << " Instruction(hex) : " << hex << (inst_grp*16+inst_type)
             << " reg:" << reg1*16 + reg2 << " param 16:" << param16 << '\n';
        cout << "   PC  : " << dec << pc<< '\n';
        cout << "   SP  : " << dec << sp<< '\n';
        cout << "   MES : " << dec << aMessage<< '\n';
        cout << "   RQ : " << dec << Reg[RQ]<< '\n';
        cout << "   RX : " << dec << Reg[RX]<< '\n';
        cout << "   RY : " << dec << Reg[RY]<< '\n';
        cout << "   RZ : " << dec << Reg[RZ]<< '\n';
        cout << "   RH : " << dec << Reg[RH]<< '\n';
        cout << "   RP : " << dec << Reg[RP]<< '\n';
        cout << "   RB : " << dec << Reg[RB]<< '\n';
        cout << "   R1 : " << dec << Reg[R1]<< '\n';
        cout << "   R2 : " << dec << Reg[R2]<< '\n';
        cout << "   R3 : " << dec << Reg[R3]<< '\n';
        cout << "   R4 : " << dec << Reg[R4]<< '\n';
        cout << "   R5 : " << dec << Reg[R5]<< '\n';
        cout << "   R6 : " << dec << Reg[R6]<< '\n';
        switch(err) {
            case 0x10 : cout << "Undefined inst_type in NOOP\n"; break;
            case 0x01 : cout << "Undefined inst_type in CALCURATE\n"; break;
            case 0x02 : cout << "Undefined inst_type in BRANCH\n"; break;
            case 0x03 : cout << "Undefined inst_type in CALL,RETURN\n"; break;
            case 0x30 : cout << "Stack overflow in CALL\n"; break;
            case 0x31 : cout << "Stack underflow in RETURN\n"; break;
            case 0x32 : cout << "Stack overflow in PUSH\n"; break;
            case 0x33 : cout << "Stack underflow in POP\n"; break;
            case 0x35 : cout << "Stack overflow in PUSHA\n"; break;
            case 0x36 : cout << "Stack underflow in POPA\n"; break;
            case 0x38 : cout << "Stack overflow in PUSHG\n"; break;
            case 0x39 : cout << "Stack underflow in POPG\n"; break;
            case 0x3A : cout << "Stack overflow in ENTER\n"; break;
            case 0x3B : cout << "Stack underflow in LEAVE\n"; break;
            case 0x04 : cout << "Undefined inst_type in LOAD\n"; break;
            case 0x05 : cout << "Undefined inst_type in STORE\n"; break;
            case 0x06 : cout << "Undefined inst_type in PROCESS\n"; break;
            case 0x60 : cout << "No Object exists to generate child\n"; break;
            case 0x61 : cout << "Could not generate new process\n"; break;
            case 0x67 : cout << "Could not generate new child\n"; break;
            case 0x08 : cout << "Undefined inst_type in MODE\n"; break;
            case 0x09 : cout << "Undefined inst_type in I/O\n"; break;
            case 0x0A : cout << "Undefined inst_type in MOVE,ROTEATE\n"; break;
            case 0x0B : cout << "Undefined inst_type in Bx Inst\n"; break;
            case 0x0C : cout << "Undefined inst_type in OBJECT\n"; break;
            case 0x0D : cout << "Undefined inst_type in POSITION\n"; break;
            case 0x0E : cout << "Undefined inst_type in SYSTEM I/O\n"; break;
            case 0xAA : cout << "Object used before definition MOV\n"; break;
            case 0xAB : cout << "Object used before definition ROT\n"; break;
            case 0xDD : cout << "Object used before definition\n"; break;
            case 0xDE : cout << "Object already defined\n"; break;
            case 0xF0 : cout << "Reg1 not defined in CALCURATE\n"; break;
            case 0xF1 : cout << "Divided by 0 in DIV\n"; break;
            case 0xF2 : cout << "SQRT required Positive Value\n"; break;
            case 0xFF : cout << "Undefined inst_grp\n"; break;
            case 0x13C : cout << "Register 2 required[CALLTB]\n"; break;
            case 0x13D : cout << "Register 1 required[CALLTB]\n"; break;
            case 0x140 : cout << "Register 1 required[LOD]\n"; break;
            case 0x142 : cout << "Register 2 required[LOD]\n"; break;
            case 0x143 : cout << "Register 1 required[LOD]\n"; break;
            case 0x144 : cout << "Register 1 required[LOADBP]\n"; break;
            case 0x145 : cout << "Data Memory out of range[XLOAD]\n"; break;
            case 0x146 : cout << "Data Memory out of range[LOADx]\n"; break;
            case 0x150 : cout << "Register 1,2 incorrect[LOD]\n"; break;
            case 0x152 : cout << "Register 2 required[STO]\n"; break;
            case 0x153 : cout << "Register 1 required[STO]\n"; break;
            case 0x154 : cout << "Register 1 required[STORBP]\n"; break;
            case 0x155 : cout << "Data Memory out of range[XSTORE]\n"; break;
            case 0x156 : cout << "Data Memory out of range[STORE]\n"; break;
            default : cout << "???? \n";
        }
        cout << flush;
#endif //WS
        return  1;
    } else return  0;
}

int TProcess::Run(long delta)
{
  long  inst_dword;
#ifdef WS
  short  instruction;
  short  reg_type;
#else //WS
  WORD  instruction;
  WORD  reg_type;
#endif //WS
  int  _result;
  _result = 1;

  if (aMessage != 0) {
      if (fwait) {
          fwait = 0;
          return  1;
      }
      if (aMessage == M_STOP) return  0;
      else if (aMessage == M_THROW) {
          rest_time = 0;
          aMessage = 0;
dbprintf("TProcess::Run %s:%d done3 _result=1\n",__FILE__,__LINE__);
          return  1;
      }
  }
  if (fwait){
dbprintf("TProcess::Run %s:%d done4 _result=1\n",__FILE__,__LINE__);
    return  1;
  }
//  if ((rest_time == 0) && ((pc < 0) || (pc >= pCode->Pos()))){
  if ((rest_time == 0) && ((pc < 0) || (pc > pCode->Pos()))){
dbprintf("TProcess::Run %s:%d done0 _result=0 rest_time=%d pc=%d pCode->Pos()=%d\n",__FILE__,__LINE__,rest_time,pc,pCode->Pos());
    return  0;
  }
  while ((delta > 0) && (_result != 0)) {

      if (rest_time == 0) {
          inst_dword  = pCode->fetch(pc);
          pc++;
          instruction = ((inst_dword >> 16) & 0x0000FFFF);
          param16     = (inst_dword & 0x0000FFFF);
          inst_grp    = (instruction >> 8) & 0x00FF;
          inst_type   = inst_grp & 0x000F;
          inst_grp    = inst_grp >> 4;
          reg_type    = instruction & 0x00FF;
          reg1 = reg_type & 0x000F;
          reg2 = (reg_type >> 4) & 0x000F;
          _result = execute(delta);
dbprintf("TProcess::Run %s:%d _result=%d delta\n",__FILE__,__LINE__,_result,delta);
      } else {
         _result = execute(delta);
dbprintf("TProcess::Run %s:%d _result2=%d delta\n",__FILE__,__LINE__,_result,delta);
      }
//      if ((rest_time == 0) && ((pc < 0) | (pc >= pCode->Pos()))){
      if ((rest_time == 0) && ((pc < 0) | (pc > pCode->Pos()))){
dbprintf("TProcess::Run %s:%d done1 _result=0\n",__FILE__,__LINE__);
        return 0;
      }
  }
dbprintf("TProcess::Run %s:%d done2 _result=%d\n",__FILE__,__LINE__,_result);
  return  _result;

}

void TProcess::GetOperand()
{
    if ((reg1 | reg2) == 0) {
        rest_time = (unsigned short)param16;
        rest_param = pCode->fetch(pc);
        pc++;
    } else {
        rest_time = Reg[reg1];
        rest_param = Reg[reg2];
    }
}

long TProcess::AdjustParam(long &delta, long &r_param)
{
  long param;
  if (rest_time > delta) {
      rest_time = rest_time - delta;
      param = r_param - (total_x * rest_time / total_time);
      r_param = r_param - param;
      delta = 0;
  } else {
      delta = delta - rest_time;
      param = r_param;
      r_param = 0;
      rest_time = 0;
  }
  return  param;
}
#ifdef WS
long TProcess::MoveInst(short inst_type, long param)
#else //WS
long TProcess::MoveInst(WORD inst_type, long param)
#endif //WS
{
    int err = 0;
    if (pObj == 0) return  0xAA;
    switch(inst_type) {
      case  0 : pObj->Axis.move(Vector(param, 0, 0)); break;
      case  1 : pObj->Axis.move(Vector(-param, 0, 0));break;
      case  2 : pObj->Axis.move(Vector(0, -param, 0));break;
      case  3 : pObj->Axis.move(Vector(0, param, 0)); break;
      case  4 : pObj->Axis.move(Vector(0, 0, -param));break;
      case  5 : pObj->Axis.move(Vector(0, 0, param)); break;
      case  6 : pObj->Axis.rotate(param, 0, 0);       break;
      case  7 : pObj->Axis.rotate(0, param, 0);       break;
      case  8 : pObj->Axis.rotate(0, 0, param);       break;
      default : err = 0x0A;
    }
    return  err;

}

void TProcess::RelativePos2(THObj3D *pobj1,
                     long &x,long &y,long &z,long &h,long &p,long &b)
{
    Vector  vect1, v;
    double  tx, ty, tz, w;

    if (pobj1->parent == 0) {

        vect1 = pobj1->Axis.get_origin();
        v.x = x - vect1.x;
        v.y = y - vect1.y;
        v.z = z - vect1.z;
        v = pobj1->Axis.RelativePosition(v);
    } else {

        vect1 = pobj1->GetWorldOrigin();
        v.x = x - vect1.x;
        v.y = y - vect1.y;
        v.z = z - vect1.z;
        v = pobj1->GetDirection_local(v);
    }
    x = v.x;
    y = v.y;
    z = v.z;
    tx = x;
    ty = y;
    tz = z;
    if ((x == 0) && (y == 0)) h = 0;
    else h = DEG(atan2(ty, tx));
    w = sqrt(tx * tx + ty * ty);
    if ((z == 0) && (w == 0.0)) p = 0;
    else p = DEG(atan2(-tz, w));
    b = 0;
}

int TProcess::execute(long &delta)
{
    long param, param2;
    long work1,work2;
    int  wObjNo;
    int  i;
    long _reg;
    long rx, ry, rz, rh, rp, rb;
    double t;
    int  pn,vn;
    Vector v;
    THObj3D *po;
    char wstr[34];
    char tstr[80];
    double tx, ty, tz, dx, dy, dz;

    int err = 0;
    int _result = 1;

    switch(inst_grp) {

      case 0 :
        switch(inst_type) {
          case 0 :
            if (aMessage == 0) {
                if (rest_time == 0) {
                    if ((reg1 | reg2) == 0) rest_time = (unsigned long)param16;
                    else rest_time = Reg[reg1];
                }
                if (rest_time > delta) {

                    rest_time = rest_time - delta;
                    delta = 0;
                } else {

                    delta = delta - rest_time;
                    rest_time = 0;
                }
            } else {
                rest_time = 0;
            }
            break;

        case 1 :
            delta = 0;
            break;
        case 8 :
            if (reg1!= 0) {
                fl = 0;
                Reg[reg1]++;
                if (Reg[reg1] == 0) fl = fl | f_ZERO;
                if (Reg[reg1] < 0) fl = fl | f_MINUS;
            } else err = 0xF0;
            break;
        case 9 :
            if (reg1!= 0) {
                fl = 0;
                --Reg[reg1];
                if (Reg[reg1] == 0) fl = fl | f_ZERO;
                if (Reg[reg1] < 0) fl = fl | f_MINUS;
            } else err = 0xF0;
            break;
        default : err = 0x10;
                   break;
      }
      break;

      case 1 :
        if (reg1!= 0) {
            _reg = Reg[reg1];
            if (reg2 == 0 ) param = pCode->fetch(pc++);
            else if (reg2 == 0x0F) param = DataMem[param16];
            else param = Reg[reg2];
            fl = 0;

            switch(inst_type) {
                case 0 :
                    _reg = _reg + param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 1 :
                    _reg = _reg - param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 2 :
                    _reg = _reg * param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 3 :
                    if (param!=0) {
                        _reg = _reg / param;
                        if (_reg == 0) fl |= f_ZERO;
                        if (_reg < 0) fl |= f_MINUS;
                    } else err = 0xF1;
                    break;
                case 4 :
                    _reg = _reg << param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 5 :
                    _reg = _reg >> param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 6 :
                    _reg = _reg & param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 7 :
                    _reg = _reg | param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 8 :
                    _reg = ~param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 9 :
                    if (_reg == param) fl |= f_ZERO;
                    if ((_reg - param) < 0) fl |= f_MINUS;
                    break;
                case 0xA :
                    _reg = -param;
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 0xB :
                    if (param >= 0) {
#ifdef WS
                        _reg = j3w_round(sqrt(param));
#else //WS
                        _reg = round(sqrt(param));
#endif //WS
                        if (_reg == 0) fl |= f_ZERO;
                        if (_reg < 0) fl |= f_MINUS;
                    } else err = 0xF2;
                    break;
                case 0xC :
#ifdef WS
                    _reg = j3w_round(sin(RAD(param))*10000);
#else //WS
                    _reg = round(sin(RAD(param))*10000);
#endif //WS
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 0xD :
#ifdef WS
                    _reg = j3w_round(cos(RAD(param))*10000);
#else //WS
                    _reg = round(cos(RAD(param))*10000);
#endif //WS
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 0xE :
                    if ((_reg == 0) && (param == 0)) _reg = 0;
                    else _reg = DEG(atan2(_reg, param));
                    if (_reg == 0) fl |= f_ZERO;
                    if (_reg < 0) fl |= f_MINUS;
                    break;
                case 0xF :
#if defined (WIN32) || defined (TE)
                    if (param < 0) srand(-param);
                    else _reg = long(param*double(rand())/_RAND_MAX);
#else //WIN32
                    if (param < 0) srandom(-param);
                    else _reg = long(param*double(random())/_RAND_MAX);
#endif //WIN32
                    if (_reg == 0) fl |= f_ZERO;
                    break;
                default : err = 0x01;
            }
            Reg[reg1] = _reg;
        } else err = 0xF0;
        break;

      case 2 :
        switch(inst_type) {
          case 0 : pc = param16;
                   break;
          case 1 : if ((fl & f_ZERO)!= 0) pc = param16;
                   break;
          case 2 : if ((fl & f_ZERO)== 0) pc = param16;
                   break;
          case 3 : if ((fl & (f_ZERO | f_MINUS)) == 0 ) pc = param16;
                   break;
          case 4 : if ((fl & f_MINUS)== 0) pc = param16;
                   break;
          case 5 : if ((fl & f_MINUS)!= 0) pc = param16;
                   break;
          case 6 : if ((fl & (f_ZERO | f_MINUS))!= 0) pc = param16;
                   break;
          case 7 : if ((fl & f_MINUS)!= 0) pc = param16;
                   break;
          case 8 : if ((fl & f_MINUS)== 0) pc = param16;
                   break;
          case 9 : if (--Reg[RL] != 0) pc = param16;
                   break;
          default : err = 0x02;
        }
        break;

      case 3 :
        switch(inst_type) {
          case 0 :
              DataMem[--sp] = pc;
              pc = param16;
              break;
          case 1 :
              if (sp < maxDataMem) {
                   pc = DataMem[sp++];
              } else err = 0x31;
              break;
          case 2 :
              if (sp > 0) DataMem[--sp] = Reg[reg1];
              else err = 0x32;
              break;
          case 3 :
              if (sp < maxDataMem) Reg[reg1] = DataMem[sp++];
              else err = 0x33;
              break;
          case 4 :
              for(i=RB;i>=RX;i--) Reg[i] = 0;
              break;
          case 5 :
              if ((sp - 6) >= 0)
                  for(i =RX;i<=RB;i++) DataMem[--sp] = Reg[i];
              else  err = 0x35;
              break;
          case 6 :
              if ((sp + 6) <= maxDataMem)
                  for(i=RB; i>=RX; i--) Reg[i] = DataMem[sp++];
              else  err = 0x36;
              break;
          case 7 :
              for(i=R6; i>=R1; i--) Reg[i] = 0;
              break;
          case 8 :
              if ((sp - 6) >= 0)
                  for (i=R1; i<=R6; i++) DataMem[--sp] = Reg[i];
              else  err = 0x38;
              break;
          case 9 :
              if ((sp + 6) <= maxDataMem)
                  for(i=R6;i>=R1; i--) Reg[i] = DataMem[sp++];
              else err = 0x39;
              break;
          case 0xA :
              if ((short(param16) >= 0)&&(sp > short(param16))) {
                  DataMem[--sp] = bp;
                  bp = sp;
                  sp = sp - short(param16);
              } else err = 0x3A;
              break;
          case 0xB :
              if (sp < maxDataMem) {
                     sp = bp;
                     bp = DataMem[sp++];
              } else err = 0x3B;
              break;
          case 0xC :
              if (reg1!= 0) {
                  if ((reg2 > 0) && (reg2 < 0x0F)) {
                      DataMem[--sp] = pc;
                      pc = pJob->GetCommonMem(Reg[reg1]+Reg[reg2]);
                  } else err = 0x13C;
              } else err = 0x13D;
              break;
          default : err = 0x03;
        }
        break;

      case 4 :
        switch(inst_type) {
          case 0 :
              if (((reg2 == 0x0F) && (maxDataMem <= param16)) ||
                  ((reg2 != 0x0F) && (maxDataMem <= reg1)))
                  err = 0x146;
              else if (reg1!= 0) {
                  if (reg2 == 0x0F) Reg[reg1] = DataMem[param16];
                  else if (reg2 == 0) Reg[reg1] = pCode->fetch(pc++);
                  else Reg[reg1] = Reg[reg2];
              } else err = 0x140;
              break;
          case 1 :
              if (maxDataMem <= param16) err = 0x146;
              else DataMem[param16] = pCode->fetch(pc++);
              break;
          case 2 :
              if (reg1!= 0) {
                  if ((reg2 > 0) && (reg2 < 0x0F))
                      if ((Reg[reg2] < maxDataMem) || (0 <= Reg[reg2]))
                           Reg[reg1] = DataMem[Reg[reg2]];
                      else err = 0x145;
                  else err = 0x142;
              } else err = 0x143;
              break;
          case 3 :
              if (reg1!= 0) {
                  if (reg2 == 0) param = param16;
                  else param = Reg[reg2];
                  if (reg2 < 0x0F)
                      Reg[reg1] = pJob->GetCommonMem(param);
                  else err = 0x142;
              } else err = 0x143;
              break;
          case 4 :
              if ((reg1!=0) && (reg2 == 0x00))
                 Reg[reg1] = DataMem[bp + (signed long)(param16)];
              else err = 0x144;
              break;
          default : err = 0x04;
        }
        break;

      case 5 :
        switch(inst_type) {
          case 0 :
              if( (reg1!=0) && (reg2 == 0x0F) && (maxDataMem > param16))
                  DataMem[param16] = Reg[reg1];
              else if (maxDataMem <= param16) err = 0x156;
              else err = 0x150;
              break;
          case 1 :
              if (reg1 != 0) {
                  if ((reg2 > 0) && (reg2 < 0x0F))
                      if ((Reg[reg2] < maxDataMem) || (0 <= Reg[reg2]))
                          DataMem[Reg[reg2]] = Reg[reg1];
                      else err = 0x155;
                  else err = 0x152;
              } else err = 0x153;
              break;
          case 2 :
              if (reg1!= 0) {
                  if (reg2 == 0) param = param16;
                  else param = Reg[reg2];
                  if (reg2 < 0x0F)
                      pJob->SetCommonMem(param, Reg[reg1]);
                  else err = 0x152;
              } else err = 0x153;
              break;
          case 4 :
              if ((reg1!=0) && (reg2 == 0x00))
                 DataMem[bp + (signed long)param16] = Reg[reg1];
              else err = 0x154;
              break;
          default : err = 0x05;
        }
        break;

      case 6 :
        switch(inst_type) {
          case 0 :
              param = pCode->fetch(pc++);
              if(pJob->new_process(param,param16,-1,Reg) == 0) err = 0x61;
              break;
          case 1 :
              if (pObj) {
                  pSpace->delete_object(ObjNo);
                  ObjNo = -1;
                  pObj = 0;
              }
              _result = 0;
              break;
          case 2 :
              if (aMessage == 0) {
                  delta = 0;
                  fwait = 1;
              }
              break;
          case 3 :
              pJob->SendMessage(PROC_ALL, M_STOP);
              _result = 0;
              break;
          case 4 :
              if (reg1!= 0)  _reg = Reg[reg1];
              else _reg = param16;
              if (reg2 == 0 ) param = pCode->fetch(pc++);
              else param = Reg[reg2];
              pJob->SendMessage(_reg, param);
              break;
          case 5 :
              if (reg1!= 0) {
                  Reg[reg1] = aMessage;
                  aMessage = 0;
              } else err = 0xF0;
              break;
          case 6 :
              if (reg1!= 0)  _reg = Reg[reg1];
              else _reg = param16;
              if (reg2 == 0 ) param = pCode->fetch(pc++);
              else param = Reg[reg2];
              pJob->SendMessageTo(_reg, param);
              break;
          case 7 :
              if (pObj) {
                  work1 = pCode->fetch(pc++);
                  work2 = param16;
                  param = pCode->fetch(pc++);
                  wObjNo = pSpace->append_child_object(ObjNo,param,pCode->fetch(pc++));
                  if(pJob->new_process(work1, work2, wObjNo, Reg) == 0) err = 0x67;
              } else err = 0x60;
              break;
          default : err = 0x06;
        }
        break;

      case 8 :
        switch(inst_type) {
          case 0 :
              pJob->SetGraph();
              break;
          case 1 :
              pJob->ResetGraph();
              break;
          case 2 :

              if (reg1 != 0) param16 = Reg[reg1];
               pJob->SetBackGroundColor(param16);
              break;
          case 3 :
              if (reg1 != 0) param16 = int(Reg[reg1]);
              pJob->SetZoom(param16);
              break;
          case 4 :

              if (reg1 != 0) param16 = Reg[reg1];
              if (param16 == 0) param16 = 1;
              else param16 = 2;
              pJob->SetMode(param16);
              break;
          case 8 :
              if (reg1 != 0) param16 = int(Reg[reg1]);
              if (pObj) {
                  pJob->SetLightObject(pObj, param16);
              } else err = 0xDD;
              break;
          case 9 :
              if (reg1 != 0) param16 = int(Reg[reg1]);
              pJob->SetLightType(param16);
              break;
          default : err = 0x08;
        }
        break;

      case 0x09 :
        switch(inst_type) {
          case 0 :
                   Reg[reg1] = pJob->GetKey();
                   break;
          case 1 :
                   if (reg2 == 0 ) param = param16;
                   else param = Reg[reg2];
#ifdef WS
                   Reg[reg1] = 0;
#else //WS
                   if ((GetAsyncKeyState(param)) != 0 )
                       Reg[reg1] = 1;
                   else Reg[reg1] = 0;
#endif //WS
                   break;
          case 2 :
                   pJob->GetMouse(Reg[RX],Reg[RY],Reg[RZ]);
                   break;
          case 8:
#ifdef WS
#else //WS
                   cout << long(Reg[reg1]) << flush;
#endif //WS
                   break;
          case 9:
                   if (reg1 != 0) param16 = Reg[reg1];
#ifdef WS
#else //WS
                   if (param16 == 13) {
                     cout << '\n' <<flush;
                   } else cout << char(param16) << flush;
#endif //WS
                   break;
          case 0xA:
#if BYTE_ORDER == BIG_ENDIAN
              {
                  int i = -1;
                  char s[128];
                  do {
                      i++;
                      s[i] = char(DataMem[int(Reg[reg1]) + i/4] >> (8 * (i%4)));
                  } while (s[i]!=0);
#ifdef WS
#else //WS
                   cout << s << flush;
#endif //WS
              }
#else
#ifdef WS
#else //WS
                   cout << (char *)(&DataMem[ int(Reg[reg1]) ]) << flush;
#endif //WS
#endif
                   break;
          case 0x0B:
#ifdef WS
#else //WS
                   cout << pCode->GetStr(pc) << flush;
#endif //WS
                   pc = pc + param16;
                   break;
          case 0x0C:
#ifdef MIDI_SUPPORT
                     pJob->Midi(0x90+param16, pCode->fetch(pc++));
#else
                     pc++;
#endif
                   break;
          case 0x0D:
#ifdef MIDI_SUPPORT
                     pJob->Midi(param16, pCode->fetch(pc++));
#else
                     pc++;
#endif
                   break;
          default : err = 0x09;
                   break;
        }
        break;

      case 0xA :
        if (aMessage == 0) {
            if (rest_time == 0) {
                GetOperand();
                total_time = rest_time;
                total_x = rest_param;
            }
            param = AdjustParam(delta, rest_param) ;
            err = MoveInst(inst_type, param);
        } else {
            if (rest_time == 0) GetOperand();
            rest_time = 0;
        }
        break;

      case 0xB :
        switch(inst_type) {
          case 0 :
              if (aMessage == 0) {
                  if (rest_time == 0) {
                      if ((reg1 | reg2) == 0) rest_time = (unsigned short)param16;
                      else rest_time = Reg[reg1];
                      total_time = rest_time;
                      total_x = Reg[RX];
                      total_y = Reg[RY];
                      total_z = Reg[RZ];
                      total_h = Reg[RH];
                      total_p = Reg[RP];
                      total_b = Reg[RB];
                  }
                  if (rest_time > delta) {
                      rest_time = rest_time - delta;
                      rx = Reg[RX] - (total_x * rest_time/total_time);
                      ry = Reg[RY] - (total_y * rest_time/total_time);
                      rz = Reg[RZ] - (total_z * rest_time/total_time);
                      rh = Reg[RH] - (total_h * rest_time/total_time);
                      rp = Reg[RP] - (total_p * rest_time/total_time);
                      rb = Reg[RB] - (total_b * rest_time/total_time);
                      Reg[RX] -= rx; Reg[RY] -= ry; Reg[RZ] -= rz;
                      Reg[RH] -= rh; Reg[RP] -= rp; Reg[RB] -= rb;
                      delta = 0;
                  } else {
                      delta = delta - rest_time;

                      rx = Reg[RX];  ry = Reg[RY];  rz = Reg[RZ];
                      rh = Reg[RH];  rp = Reg[RP];  rb = Reg[RB];
                      rest_param = 0;
                      rest_time = 0;
                  }
                  pObj->Axis.move(Vector(rx, ry, rz));
                  pObj->Axis.rotate(rh, rp, rb);
              } else {
                  rest_time = 0;
              }
              break;

          case 1 :
              if (aMessage == 0) {
                  if (rest_time == 0) {
                      if ((reg1 | reg2) == 0) rest_time = (unsigned short)param16;
                      else rest_time = Reg[reg1];
                      total_time = rest_time;
                      total_x = Reg[RX];
                      total_y = Reg[RY];
                      total_z = Reg[RZ];
                      qa = pObj->Axis.get_quat();
                      pObj->Axis.get_attitude(rh, rp, rb);
                      rh += Reg[RH];
                      rp += Reg[RP];
                      rb += Reg[RB];
                      EularToQuat(rh,rp,rb,qb);
                      if (! CheckShortestPath(qa, qb)) {
                            qb._0 = -qb._0;
                            qb._1 = -qb._1;
                            qb._2 = -qb._2;
                            qb._3 = -qb._3;
                      }
                  }
                  if (rest_time > delta) {
                      rest_time = rest_time - delta;
                      t = 1.0 - double(rest_time)/total_time;
                      Slerp(qa, qb, dq, t);
                      rx = Reg[RX] - (total_x * rest_time/total_time);
                      ry = Reg[RY] - (total_y * rest_time/total_time);
                      rz = Reg[RZ] - (total_z * rest_time/total_time);
                      Reg[RX] -= rx; Reg[RY] -= ry; Reg[RZ] -= rz;
                      delta = 0;
                  } else {
                      delta = delta - rest_time;

                      Slerp(qa, qb, dq, 1.0);
                      rx = Reg[RX];  ry = Reg[RY];  rz = Reg[RZ];
                      Reg[RH] = 0; Reg[RP] = 0; Reg[RB] = 0;
                      rest_time = 0;
                  }
                  pObj->Axis.move(Vector(rx, ry, rz));
                  pObj->Axis.attitudeq(dq);
              } else {
                  rest_time = 0;
              }
              break;

          case 2 :
              if (aMessage == 0) {
                  if (rest_time == 0) {
                      if ((reg1 | reg2) == 0) rest_time = (unsigned short)param16;
                      else rest_time = Reg[reg1];
                      pObj->GetScale(tx, ty, tz);
                      Reg[RX] = long(tx * Reg[RX]);
                      Reg[RY] = long(ty * Reg[RY]);
                      Reg[RZ] = long(tz * Reg[RZ]);
                  }
                  if (rest_time > delta) {
                      pObj->GetScale(tx, ty, tz);
                      dx = Reg[RX] / SC_FACTOR - tx;
                      dy = Reg[RY] / SC_FACTOR - ty;
                      dz = Reg[RZ] / SC_FACTOR - tz;

                      tx = dx * delta / rest_time + tx;
                      ty = dy * delta / rest_time + ty;
                      tz = dz * delta / rest_time + tz;
                      rest_time = rest_time - delta;
                      delta = 0;
                  } else {
                      delta = delta - rest_time;

                      tx = Reg[RX] / SC_FACTOR;
                      ty = Reg[RY] / SC_FACTOR;
                      tz = Reg[RZ] / SC_FACTOR;
                      rest_param = 0;
                      rest_time = 0;
                  }
                  pObj->SetScale(tx, ty, tz);
              } else {
                  rest_time = 0;
              }
              break;

           case 8 :
              if (pObj) {
                  if (reg1 != 0) pObj->SetGravity(Reg[reg1]);
                  else pObj->SetGravity(param16);
              }
              else err = 0xDD;
              break;
          case 9 :
              if (pObj) Reg[reg1] = pObj->GetGravity();
              else err = 0xDD;
              break;
          case 0xA :
              if (pObj)
                  pObj->SetAccele( Vector(Reg[RX], Reg[RY], Reg[RZ]));
              else err = 0xDD;
              break;
          case 0xB :
              if (pObj) {
                  Vector v = pObj->GetAccele();
                  Reg[RX] = v.x;
                  Reg[RY] = v.y;
                  Reg[RZ] = v.z;
              } else err = 0xDD;
              break;
          case 0xC :
              if (pObj) {
                  pObj->SetVelocity( Vector(Reg[RX], Reg[RY], Reg[RZ]));
                  pObj->SetAngleVelocity( Vector(Reg[RH],Reg[RP],Reg[RB]));
              } else err = 0xDD;
              break;
          case 0xD :
              if (pObj) {
                  Vector v = pObj->GetVelocity();
                  Reg[RX] = v.x;
                  Reg[RY] = v.y;
                  Reg[RZ] = v.z;
                  v = pObj->GetAngleVelocity();
                  Reg[RH] = v.x;
                  Reg[RP] = v.y;
                  Reg[RB] = v.z;
              } else err = 0xDD;
              break;
          case 0xE :
              if (pObj) pObj->SetWVelocity( Vector(Reg[RX], Reg[RY], Reg[RZ]));
              else err = 0xDD;
              break;
          case 0xF :
              if (pObj) {
                  Vector v = pObj->GetWVelocity();
                  Reg[RX] = v.x;
                  Reg[RY] = v.y;
                  Reg[RZ] = v.z;
              } else err = 0xDD;
              break;
          default : err = 0x0B;
        }
        break;

      case 0x0C :
        switch(inst_type) {
          case 0 :
              if (pObj == 0) {
                   param = pCode->fetch(pc++);
                   ObjNo = pSpace->append_object(param, pCode->fetch(pc++));
                   if (ObjNo>= 0)pObj = pSpace->get_object(ObjNo);
              } else err = 0xDE;
              break;
          case 1 :
              if (pObj) {
                  param = pCode->fetch(pc); pc++;
                  param2 = pCode->fetch(pc); pc++;
                  pObj->Polygon.Vertex.Add(
                                 Vector(param, param2, pCode->fetch(pc++)));
              } else err = 0xDD;
              break;
          case 2 :
              if (pObj) {
                  int *pindex = new int[param16];
                  for(i=0; i<param16; i++) pindex[i] = pCode->fetch(pc++);
                  pObj->Polygon.Add(param16, int(Reg[reg1]), pindex);
              } else err = 0xDD;
              break;
          case 3 :
              if (pObj) {
                  pSpace->delete_object(ObjNo);
                  ObjNo = -1;
                  pObj = 0;
              } else err = 0xDD;
              break;
          case 4 :
              if (pObj) pJob->SetEye(pObj);
              else err = 0xDD;
              break;
          case 5 :
              if (pObj) {
                  pObj->Polygon.Vertex.Add(
                                    Vector(Reg[RX], Reg[RY], Reg[RZ]));
              } else err = 0xDD;
              break;
          case 6 :
              if (pObj) {
                   if (reg1 != 0) param16 = Reg[reg1];
                   pObj->Polygon.SetReflection(param16/100.0);
              } else err = 0xDD;
              break;
          case 7 :
              if (pObj) {
                   if (reg1 != 0) param16 = Reg[reg1];
                   pObj->Polygon.SetAmbient(param16/100.0);
              } else err = 0xDD;
              break;
          case 8 :
              /* if (pObj)  pObj->ResetEyeOffset(); */
              /* else err = 0xDD;                   */
              break;
          case 9 :
              if (pObj) Reg[reg1] = pObj->Polygon.Vertex.GetCount();
              else err = 0xDD;
              break;
          case 0xA :
              if (pObj) {
                  pn = DataMem[Reg[reg1] + 1];
                  int *pindex = new int[pn];
                  for(i=0;i<pn;i++)
                     pindex[i] = DataMem[Reg[reg1] + 2 + i];
                  pObj->Polygon.Add(pn, int(DataMem[Reg[reg1]]), pindex);
              } else err = 0xDD;
              break;
          case 0xB :
              if (pObj) {
                  vn = pObj->Polygon.Vertex.GetCount();
                  for(i=0;i<vn;i++)
                      pObj->Polygon.Vertex.Transpose(i,
                                  Vector(Reg[RX],Reg[RY],Reg[RZ]));
              } else err = 0xDD;
              break;
          case 0xC :
              if (pObj) pObj->Polygon.Vertex.UpdateOffset();
              else err = 0xDD;
              break;
          case 0xD :
              if (pObj) pObj->Polygon.Vertex.ResetOffset();
              else err = 0xDD;
              break;
          case 0xE :
              if (pObj) pObj->Polygon.Vertex.SetPosition(
                                    Vector(Reg[RX],Reg[RY],Reg[RZ]));
              else err = 0xDD;
              break;
          case 0xF :
              if (pObj) pObj->Polygon.Vertex.SetPosition(Vector(0, 0, 0));
              else err = 0xDD;
              break;

          default : err = 0x0C;
        }
        break;

      case 0x0D :
        switch(inst_type) {
          case 0 :
              if (pObj) {
                   v = pObj->Axis.get_origin();
                   Reg[RX] = v.x;
                   Reg[RY] = v.y;
                   Reg[RZ] = v.z;
                   pObj->Axis.get_attitude(Reg[RH], Reg[RP], Reg[RB]);
                 } else err = 0xDD;
              break;
          case 1 :
              if (pObj) {
                   pObj->Axis.set_origin(Reg[RX], Reg[RY], Reg[RZ]);
                   pObj->Axis.attitude(Reg[RH], Reg[RP], Reg[RB]);
              } else err = 0xDD;
              break;
          case 2 :

              if (reg1 != 0) param = Reg[reg1];
              else param = param16;
              po = pJob->GetObject(param);
              if (po != 0) {
                  po->GetWorldPosition(v, Reg[RH], Reg[RP], Reg[RB]);
                  Reg[RX] = v.x;
                  Reg[RY] = v.y;
                  Reg[RZ] = v.z;

              } else Reg[reg1] = 0;
              break;
          case 3 :
              if (pObj) {

                  if (reg1 != 0) param = Reg[reg1];
                  else param = param16;
                  Reg[RX] = pJob->Distance(pObj,param,Reg[RY],Reg[RZ]);
              } else err = 0xDD;
              break;
          case 4 :
              if (pObj) {
                  if (reg1 != 0) param = Reg[reg1];
                  else param = param16;
                  pObj->Polygon.SetCenterGrav(param);
              } else err = 0xDD;
              break;
          case 5 :
              if (pObj) {

                  if (reg1 != 0) param = Reg[reg1];
                  else param = param16;
                  pJob->RelativePosition(pObj, param, Reg);
              } else err = 0xDD;
              break;
          case 6 :
              if (pObj) {

                  if (reg1 != 0) param = Reg[reg1];
                  else param = param16;
                  Reg[RB] = pJob->Look(pObj, param, Reg[RH], Reg[RP]);
              } else err = 0xDD;
              break;
          case 7 :
              if (pObj) {
                  RelativePos2(pObj, Reg[RX], Reg[RY], Reg[RZ],
                                     Reg[RH], Reg[RP], Reg[RB]);
              } else err = 0xDD;
              break;
          case 8 :
              Reg[RB] = pJob->NearestVertex(Reg[RX], Reg[RY], Reg[RZ],
                                             Reg[RP], Reg[RH]);
              break;
          case 9 :
              po = pJob->GetObject(Reg[RP]);
              Reg[RB] = -1;
              if (po != 0) {
                  po->Polygon.Vertex.Assign(Reg[RH],
                                    Vector(Reg[RX],Reg[RY],Reg[RZ]));
                  Reg[RB] = 0;
              }
              break;
          case 0xA :
              po = pJob->GetObject(Reg[RP]);
              Reg[RX] = 0; Reg[RY] = 0; Reg[RZ] = 0;
              Reg[RB] = -1;
              if (po != 0) {
                  po->Polygon.Vertex.Assign(Reg[RH], v);
                  Reg[RX] = v.x; Reg[RY] = v.y; Reg[RZ] = v.z;
                  Reg[RB] = 0;
              }
              break;
          case 0xB :
              po = pJob->GetObject(Reg[RP]);
              if (po != 0) {
                  pn = DataMem[Reg[reg1] + 1];
                  int *pindex = new int[pn];
                  for(i=0;i<pn;i++)
                      pindex[i] = DataMem[Reg[reg1] + 2 + i];
                  po->Polygon.SetPoly(pn, int(DataMem[Reg[reg1]]), pindex);
              }
              break;
          case 0xC :
              po = pJob->GetObject(Reg[RP]);
              if (po != 0) {
                  pn = po->Polygon.GetVertexCount(Reg[RH]);
                  if (pn > 0) {
                      DataMem[Reg[reg1] + 1] = pn;
                      int *pindex = new int[pn];
                      int color;
                      po->Polygon.GetPoly(pn, color, pindex);
                      DataMem[Reg[reg1]] = color;
                      for(i=0;i<pn;i++)
                           DataMem[Reg[reg1] + 2 + i] = pindex[i];
                  }
              }
              break;

          case 0xD :
              if (pObj) {
                   pObj->SetScale(Reg[RX] / SC_FACTOR, Reg[RY] / SC_FACTOR,
                                  Reg[RZ] / SC_FACTOR);
              } else err = 0xDD;
              break;

          case 0xE :
              if (pObj) {
                   pObj->GetScale(tx, ty, tz);
                   Reg[RX] = long(tx * SC_FACTOR);
                   Reg[RY] = long(ty * SC_FACTOR);
                   Reg[RZ] = long(tz * SC_FACTOR);
              } else err = 0xDD;
              break;

          default : err = 0x0D;
        }
        break;

      case 0xE :
        switch(inst_type) {
          case 0 :
              sprintf(wstr, "%ld", Reg[reg1]);
              pJob->WriteString(wstr);
          case 1 :
              wstr[0] =char(param16);
              wstr[1] =char(0);
              pJob->WriteString(wstr);
              break;
          case 2 :
#if BYTE_ORDER == BIG_ENDIAN
              {
                  int i = -1;
                  char s[128];
                  do {
                      i++;
                      s[i] = char(DataMem[int(Reg[reg1]) + i/4] >> (8 * (i%4)));
                  } while (s[i]!=0);
                  pJob->WriteString(s);
              }
#else
              pJob->WriteString((char*)(&DataMem[ int(Reg[reg1]) ]));
#endif
              break;
          case 3 :
              pJob->WriteString(pCode->GetStr(pc));
              pc = pc + param16;
              break;
          case 4 :
              if (reg1 != 0) param16 = Reg[reg1];
              pJob->StringColor(param16);
              break;
          case 5 :
              pJob->ClearString();
              break;
          case 6 :
              if (reg1 != 0) param16 = Reg[reg1];
              pJob->SetCursorPosition(param16);
              break;
          case 7 :
              Reg[reg1] = pJob->GetCursorPosition();
              break;
          case 8 :
              pJob-> GrLine(Reg[RB], Vector2D(Reg[RX], Reg[RY]),
                                    Vector2D(Reg[RH], Reg[RP]), Reg[RZ]);
              break;
          case 9 :
              if (reg1 != 0) param16 = Reg[reg1];
              pJob-> GrLineClear(param16);
              break;
          default : err = 0x0E;
        }
        break;

      case 0x0F :
        switch(inst_type) {
          case 0 :  Reg[reg1] = pJob->GetTime();
              break;
          case 1 :  Reg[reg1] = pJob->GetCount();
              break;
          case 2 :  Reg[reg1] = pJob->count_process();
              break;
          case 3 :
              for(i=0; i<param16; i++)
                  pJob->SetCommonMem(Reg[reg1]+i, pCode->fetch(pc++));
              break;
          case 4 :
              strcpy(tstr, pCode->GetStr(pc));

              Reg[RY] = pJob->WriteCommon(tstr, Reg[RX],Reg[RY]);
              pc = pc + param16;
              break;
          case 5 :
              strcpy(tstr, pCode->GetStr(pc));

              Reg[RY] = pJob->ReadCommon(tstr, Reg[RX]);
              pc = pc + param16;
              break;
          case 6 :
              pJob->Light(Reg[reg1],
                          Reg[RX], Reg[RY], Reg[RZ],
                          Reg[RH], Reg[RP], Reg[RB] );
               break;
          case 8 :
              strcpy(tstr,pCode->GetStr(pc));

              if (Reg[RY] != 0 ) {

              }
              pc = pc + param16;
              break;
          case 9 :  Reg[reg1] = pSpace->get_color();
              break;
          case 0xA :
                    Reg[reg1] = pSpace->get_shade();
              break;
          case 0xB :
                    Reg[reg1] = long(pSpace->count_vertex());
              break;
          case 0xC :
                    Reg[reg1] = long(pSpace->count_polygon());
              break;
          case 0xD :
                    pJob->Color(Reg[reg1],
                               Reg[RX], Reg[RY], Reg[RZ],
                               Reg[RH], Reg[RP],Reg[RB] );
              break;
          case 0xE :
                    pJob->ColorReset();
              break;
          case 0xF :
                    Reg[RX] = version1;
                    Reg[RY] = version2;
              break;

          default : err = 0x0F;
              break;
        }
        break;
      default : err = 0xFF;
                break;
    }

    if (CheckError(err)) _result = 0;
    return  _result;
}

