fc349e2cf1/vm/graphical/devices.c

User picture

Commiter: Charles Childers

Author: Charles Childers

Revision: fc349e2cf1


File Size: 13.9 KB

(March 08, 2010 02:15 UTC) About 2 years ago

no core words in 32-128 address range; all C implementations updated with implicit calls

 
Show/hide line numbers
/******************************************************
 * Ngaro
 * Copyright (C) 2008 - 2010, Charles Childers
 ******************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#include "functions.h"
#include "vm.h"
#include "SDL_ColorDef.h"

#include "SDL.h"
#include "SDL_keysym.h"

/* From vm.c */
extern VM_STATE vm;


typedef struct {
  SDL_Surface *screen;
  SDL_Surface *font;
} DEVICES;

DEVICES io;
int tx, ty, mousex, mousey, mouseb;
int color, gx, gy, gh, gw, scratch;

int black, darkblue, darkgreen, darkcyan, darkred;
int purple, brown, darkgray, gray, blue, green;
int cyan, red, magenta, yellow, white;

void video_color(int c)
{
  switch (c)
  {
    case 0:
      color = black;
      break;
    case 1:
      color = darkblue;
      break;
    case 2:
      color = darkgreen;
      break;
    case 3:
      color = darkcyan;
      break;
    case 4:
      color = darkred;
      break;
    case 5:
      color = purple;
      break;
    case 6:
      color = brown;
      break;
    case 7:
      color = darkgray;
      break;
    case 8:
      color = gray;
      break;
    case 9:
      color = blue;
      break;
    case 10:
      color = green;
      break;
    case 11:
      color = cyan;
      break;
    case 12:
      color = red;
      break;
    case 13:
      color = magenta;
      break;
    case 14:
      color = yellow;
      break;
    case 15:
      color = white;
      break;
    default:
      color = black;
  }
}

void video_pixel(int x, int y)
{
  vm.image[VIDEO_BASE+(x + y * VIDEO_WIDTH)] = color;
}


void line(int x1, int y1, int x2, int y2)
{
  float error, m;
  int x, y;
  x = x1;
  y = y1;
  if (x1 == x2)
  {
    while (y != y2)
    {
      if (y2 - y1 > 0)
         y++;
      else
         y--;
      video_pixel(x,y);
    }
  }
  else
  {
    m = (float)(y2 - y1) / (x2 - x1);
    error = 0;
    video_pixel(x, y);
    while (x != x2)
    {
      error += m;
      if (error > .5)
      {
        if (x2 - x1 > 0)
          y++;
        else
          y--;
        --error;
      }
      if (x2 - x1 > 0)
        x++;
      else
        x--;
      video_pixel(x, y);
    }
  }
}


int equ(float x, float y, int r)
{
  int res = 0;
  if (pow(x, 2) + pow(y, 2) - pow(r, 2) == 0)
    res = 0;
  else if (pow(x, 2) + pow(y, 2) - pow(r, 2) < 0)
    res = -1;
  else if (pow(x, 2) + pow(y, 2) - pow(r, 2) > 0)
    res = 1;
  return res;
}

void setOthers(int x, int y, int xCenter, int yCenter)
{
  video_pixel(xCenter+x, yCenter+y);
  video_pixel(xCenter-x, yCenter+y);
  video_pixel(xCenter+x, yCenter-y);
  video_pixel(xCenter-x, yCenter-y);
  video_pixel(xCenter+y, yCenter+x);
  video_pixel(xCenter-y, yCenter+x);
  video_pixel(xCenter+y, yCenter-x);
  video_pixel(xCenter-y, yCenter-x);
}

void video_circle(int xCenter, int yCenter, int radius)
{
  int x = 0, y = radius;
  setOthers(x, y, xCenter, yCenter);
  while (x < y)
  {
    x++;
    if (equ(x, y - (float) 1 / 2, radius) >= 0)
      y--;
    setOthers(x, y, xCenter, yCenter);
  }
}


/******************************************************
 *|F| void draw_character(int x, int y, int character)
 ******************************************************/
void drawcharacter(int x, int y, int character)
{
  int i, j, screenofs, charofs;

  /* The Ngaro font does not have the first 33    */
  /* characters, so if the requested character is */
  /* less than this, ignore the request           */
  if (character <= 32)
    return;

  character -= 33;

  /* Render the character to the framebuffer*/
  for (i = 0; i < io.font->w; i++)
  {
    screenofs = x + (y + i) * io.screen->pitch;
    charofs = (i + character * io.font->w) * io.font->pitch;
    for (j = 0; j < io.font->w; j++)
    {
      vm.image[screenofs+VIDEO_BASE] = (int)((char *)io.font->pixels)[charofs];
      screenofs++;
      charofs++;
    }
  }
}



/******************************************************
 *|F| int handle_devices(void *unused)
 ******************************************************/
int handle_devices(void *unused)
{
  SDL_Event event;
  int c;

  while (vm.ports[0] == 0)
  {
    if (SDL_PollEvent(&event) != 0)
    {
      switch(event.type)
      {
        case SDL_KEYDOWN:
             vm.ports[1] = (int)event.key.keysym.unicode;
             if (event.key.keysym.sym == SDLK_BACKSPACE)
               vm.ports[1] = 8;
             vm.ports[0] = 1;
             break;
        case SDL_KEYUP:
             break;
        case SDL_MOUSEMOTION:
             mousex = event.motion.x;
             mousey = event.motion.y;
             break;
        case SDL_MOUSEBUTTONDOWN:
             mouseb = 1;
             break;
        case SDL_MOUSEBUTTONUP:
             mouseb = 0;
             break;
        case SDL_QUIT:
             vm.ip = IMAGE_SIZE;
             vm.ports[0] = 1;
             break;
      }
    }
    if (vm.ports[2] == 1)
    {
      c = TOS; DROP
      if (c >= 0)
      {
        drawcharacter(tx, ty, c);
        tx += 9;
        if (c == 8)
        {
          tx -= 16;
          drawcharacter(tx, ty, '_');
        }
        if (c == 10)
        {
          tx  = 0;
          ty += 12;
        }
        if (tx > VIDEO_WIDTH - 9)
        {
          tx  = 0;
          ty += 12;
        }
        if (ty > VIDEO_HEIGHT - 12)
        {
          /* Scroll Up */
          gw = 0;
          for (gx = VIDEO_WIDTH * 12; gx < (VIDEO_WIDTH * VIDEO_HEIGHT) - 12; gx++)
          {
            vm.image[VIDEO_BASE + gw] = vm.image[VIDEO_BASE + gx];
            gw++;
          }

          ty = VIDEO_HEIGHT - 12;

          /* Clear bottom line */
          scratch = color;
          color = black;
          gw = VIDEO_WIDTH;     gh = 12;
          gy = ty;              gx = 0;
          for (; gw > 0; gw--)
          {
            line(gx, gy, gx + gw, gy);
            line(gx + gw, gy, gx + gw, gy + gh);
            line(gx + gw, gy + gh, gx, gy + gh);
            line(gx, gy + gh, gx, gy);
          }
          color = scratch;
          vm.ports[3] = 0;
        }
      }
      else
        clear_display();
      vm.ports[2] = 0;
      vm.ports[0] = 1;
    }
    if (vm.ports[4] == 1)
    {
      vm_save_image(vm.filename);
      vm.ports[4] = 0;
      vm.ports[0] = 1;
    }
    if (vm.ports[4] == 2)
    {
      vm.ports[4] = 0;
      vm.ports[0] = 1;
    }

    /* Create file handle */
    if (vm.ports[4] == -1) {
      char *modes[] = { "r", "r+", "w", "w+", "a", "a+" };
      int mode = TOS; DROP;
      int i, address = TOS; DROP;
      char filename[256];
      for (i = 0; i < 256; i++)
      {
        filename[i] = vm.image[address+i];
        if (! filename[i]) break;
      }
      FILE *handle = fopen(filename, modes[mode]);
      vm.ports[4] = (int)handle;
      vm.ports[0] = 1;
    }

    /* Read a char; response indicates success/failure */
    if (vm.ports[4] == -2) {
      int cell = TOS; DROP;
      FILE *handle = (FILE *) TOS; DROP;
      int c = fgetc(handle);
      vm.image[cell] = c;
      if   ( c == EOF ) vm.ports[4] =  0;
      else              vm.ports[4] = -1;
      vm.ports[0] = 1;
    }

    /* Write a char; response indicates success/failure */
    if (vm.ports[4] == -3) {
      FILE *handle = (FILE *) TOS; DROP;
      int c = TOS; DROP;
      int r = fputc(c, handle);
      if   ( r == EOF ) vm.ports[4] =  0;
      else              vm.ports[4] = -1;
      vm.ports[0] = 1;
    }

    /* Close handle */
    if (vm.ports[4] == -4) {
      FILE *handle = (FILE *)TOS; DROP;
      fclose(handle);
      vm.ports[4] = 1;
      vm.ports[0] = 1;
    }

    /* Getpos */
    if (vm.ports[4] == -5) {
      FILE *handle = (FILE *)TOS; DROP;
      int pos = (int) ftell(handle);
      vm.ports[4] = pos;
      vm.ports[0] = 1;
    }

    /* Seek */
    if (vm.ports[4] == -6) {
      FILE *handle = (FILE *) TOS; DROP;
      int pos = TOS; DROP;
      int r = fseek(handle, pos, SEEK_SET);
      if   ( r == 0 ) vm.ports[4] = -1;
      else            vm.ports[4] =  0;
      vm.ports[0] = 1;
    }

    /* File size */
    if (vm.ports[4] == -7) {
      FILE *handle = (FILE *) TOS; DROP;
      int current = ftell(handle);
      int r = fseek(handle, 0, SEEK_END);
      int size = ftell(handle);
      fseek(handle, current, SEEK_SET);
      if   ( r == 0 ) vm.ports[4] = size;
      else            vm.ports[4] = 0;
      vm.ports[0] = 1;
    }

    /* Capabilities */
    if (vm.ports[5] == -1)
    {
      vm.ports[5] = IMAGE_SIZE;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -2)
    {
      vm.ports[5] = -1;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -3)
    {
      vm.ports[5] = VIDEO_WIDTH;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -4)
    {
      vm.ports[5] = VIDEO_HEIGHT;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -5)
    {
      vm.ports[5] = vm.sp;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -6)
    {
      vm.ports[5] = vm.rsp;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -7)
    {
      vm.ports[5] = -1;
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -8)
    {
      vm.ports[5] = time(NULL);
      vm.ports[0] = 1;
    }
    if (vm.ports[5] == -9)
    {
      vm.ports[5] = 0;
      vm.ports[0] = 1;
      vm.ip = IMAGE_SIZE;
    }

    if (vm.ports[6] == 1)
    {
      video_color(TOS); DROP;
      vm.ports[6] = 0;
      vm.ports[0] = 1;
    }
    if (vm.ports[6] == 2)
    {
      gy = TOS; DROP;
      gx = TOS; DROP;
      video_pixel(gx, gy);
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }
    if (vm.ports[6] == 3)
    {
      gw = TOS; DROP;
      gh = TOS; DROP;
      gy = TOS; DROP;
      gx = TOS; DROP;
      line(gx, gy, gx + gw, gy);
      line(gx + gw, gy, gx + gw, gy + gh);
      line(gx + gw, gy + gh, gx, gy + gh);
      line(gx, gy + gh, gx, gy);
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }
    if (vm.ports[6] == 4)
    {
      gw = TOS; DROP;
      gh = TOS; DROP;
      gy = TOS; DROP;
      gx = TOS; DROP;
      for (; gw > 0; gw--)
      {
        line(gx, gy, gx + gw, gy);
        line(gx + gw, gy, gx + gw, gy + gh);
        line(gx + gw, gy + gh, gx, gy + gh);
        line(gx, gy + gh, gx, gy);
      }
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }
    if (vm.ports[6] == 5)
    {
      gh = TOS; DROP;
      gy = TOS; DROP;
      gx = TOS; DROP;
      line(gx, gy, gx, gy + gh);
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }
    if (vm.ports[6] == 6)
    {
      gw = TOS; DROP;
      gy = TOS; DROP;
      gx = TOS; DROP;
      line(gx, gy, gx + gw, gy);
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }
    if (vm.ports[6] == 7)
    {
      gw = TOS; DROP;
      gy = TOS; DROP;
      gx = TOS; DROP;
      video_circle(gx, gy, gw);
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }
    if (vm.ports[6] == 8)
    {
      gw = TOS; DROP;
      gy = TOS; DROP;
      gx = TOS; DROP;
      for (; gw > 0; gw--)
        video_circle(gx, gy, gw);
      vm.ports[6] = 0;
      vm.ports[0] = 1;
      vm.ports[3] = 0;
    }


    if (vm.ports[7] == 1)
    {
      vm.sp++; vm.data[vm.sp] = mousex;
      vm.sp++; vm.data[vm.sp] = mousey;
      vm.ports[7] = 0;
      vm.ports[0] = 1;
    }
    if (vm.ports[7] == 2)
    {
      vm.sp++; vm.data[vm.sp] = mouseb;
      vm.ports[7] = 0;
      vm.ports[0] = 1;
    }
  }
  return 0;
}



/******************************************************
 *|F| void init_devices()
 ******************************************************/
void init_devices()
{
  SDL_Surface *temp;

  tx = 0;
  ty = 0;

  if (SDL_Init(SDL_INIT_VIDEO) < 0)
  {
    fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
    exit(1);
  }

  /* This causes each key value returned to be unique. */
  SDL_EnableUNICODE(1);

  /* We use an 8-bit display mode. */
  io.screen = SDL_SetVideoMode(VIDEO_WIDTH, VIDEO_HEIGHT, 8, SDL_SWSURFACE);
  SDL_WM_SetCaption("Ngaro", "Ngaro");

  /* Try to load the font. We look in the current directory and in */
  /* /usr/share/ngaro. If we can't find it, report an error and exit. */
  temp = SDL_LoadBMP("font.bmp");
  if (temp == 0)
    temp = SDL_LoadBMP("/usr/share/ngaro/font.bmp");
  if (temp == 0)
  {
    fprintf(stderr, "FATAL: Unable to locate font.bmp!\n");
    exit(1);
  }

  io.font = SDL_ConvertSurface(temp, io.screen->format, SDL_SWSURFACE);
  SDL_FreeSurface(temp);

  /* Map Colors */
  black     = RGB_black(io.screen);
  darkblue  = RGB_darkblue(io.screen);
  darkgreen = RGB_darkgreen(io.screen);
  darkcyan  = RGB_darkcyan(io.screen);
  darkred   = RGB_darkred(io.screen);
  purple    = RGB_purple(io.screen);
  brown     = RGB_brown(io.screen);
  darkgray  = RGB_darkgray(io.screen);
  gray      = RGB_gray(io.screen);
  blue      = RGB_blue(io.screen);
  green     = RGB_green(io.screen);
  cyan      = RGB_cyan(io.screen);
  red       = RGB_red(io.screen);
  magenta   = RGB_magenta(io.screen);
  yellow    = RGB_yellow(io.screen);
  white     = RGB_white(io.screen);
}



/******************************************************
 *|F| void cleanup_devices()
 ******************************************************/
void cleanup_devices()
{
}


/******************************************************
 *|F| void drawpixel(int x, int color)
 ******************************************************/
void drawpixel(int x, int color)
{
  unsigned char *ptr = (unsigned char*)io.screen->pixels;
  ptr[x] = (char)color;
}



/******************************************************
 *|F| int update_display(void *unused)
 ******************************************************/
int update_display(void *unused)
{
  int i;
  if (vm.ports[3] == 0)
  {
    for (i = VIDEO_BASE; i < (VIDEO_BASE+(VIDEO_WIDTH*VIDEO_HEIGHT)); i++)
       drawpixel(i-VIDEO_BASE, vm.image[i]);
    SDL_Flip(io.screen);
    vm.ports[3] = 1;
  }
  return 0;
}


/******************************************************
 *|F| void clear_display()
 ******************************************************/
void clear_display()
{
  int i;

  for (i = VIDEO_BASE; i < (VIDEO_BASE+(VIDEO_WIDTH*VIDEO_HEIGHT)); i++)
    vm.image[i] = 0;

  tx = 0; ty = 0;

  vm.ports[3] = 0;
}