Jump to content


Photo

Wrote This Xbox Raycaster Example Code. (here Is Both Source And Xbe)


  • Please log in to reply
8 replies to this topic

#1 miker00lz

miker00lz

    X-S Enthusiast

  • Members
  • 10 posts

Posted 24 January 2010 - 11:59 AM

if anybody is interested, i programmed this untextured raycaster for the xbox today. i think the source code is pretty easy to follow, so i'm going to paste it here along with a link to the pre-compiled XBE. the source compiles with openxdk 0.7. i'm definitely going to be adding wall/ceiling/floor textures to the engine, but i thought it would be best to post this if somebody just wanted to have a look at the basics first.

first, here's the xbe you can just copy to your xbox and run: http://rubbermallet....-untextured.xbe

and here is the source code:

CODE
#include <hal/input.h>
#include <hal/xbox.h>
#include <openxdk/debug.h>
#include "hal/fileio.h"
#include <hal/video.h>

#include "string.h"
#include "stdio.h"
#include <stdlib.h>
#include <math.h>

unsigned char *fb;
unsigned char *pb;
int width = 640;
int height = 480;
int bpp = 32; //should work with either 24 or 32 bit mode
int pixmulty;
int pixmultx;

#define mapWidth 24
#define mapHeight 24

int worldMap[mapWidth][mapHeight]=
{
  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
  {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1},
  {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};

void XPlot(int xp, int yp, BYTE r, BYTE g, BYTE b) {
    pb[(yp*pixmulty)+(xp*pixmultx)] = b;
    pb[(yp*pixmulty)+(xp*pixmultx)+1] = g;
    pb[(yp*pixmulty)+(xp*pixmultx)+2] = r;
}

void XBoxStartup(void) {
    int lastTickCount;
    int passedMilliseconds;

    pixmulty = width * (bpp / 8);
    pixmultx = bpp / 8;

        XInput_Init();

    int padnum = 0;

    debugPrint("\n\n    XCast: A simple raycaster example for the Microsoft XBOX.\n");
    debugPrint("    Written and compiled on 1/24/2010.\n");
    debugPrint("    Created by Mike Chambers [miker00lz@gmail.com]\n\n\n\n\n");
    debugPrint("    Controls: Just use the d-pad to move around the map.\n");
    debugPrint("              To reboot your XBOX, press start + back.\n\n");
    debugPrint("    Press start now to begin...");
    
    int breakloop = 0;
    while (breakloop==0) {
      //twiddle thumbs here...
      XInput_GetEvents();
      if (g_Pads[padnum].PressedButtons.usDigitalButtons & XPAD_START) breakloop = 1;
    }
    

    VIDEO_MODE current;
    current = XVideoGetMode();
    int i;
    int j;
    int vstep = 1;
    BOOL result;
    result = XVideoSetMode(width, height, bpp, 60);
    if (result==FALSE) {
      debugPrint("There was an error setting the video mode! Reboot in 5 seconds...");
      XSleep(5000);
      XReboot();
    }

    fb = XVideoGetFB(); //get pointer to beginning of xbox video memory
    pb = malloc(width*height*pixmultx); //allocate a full video buffer so we dont draw directly.
                                        //it will look sexier this way.
    int x, y;

  double posX = 22, posY = 12;  //x and y start position
  double dirX = -1, dirY = 0; //initial direction vector
  double planeX = 0, planeY = 0.66; //the 2d raycaster version of camera plane
  
  double time = 0; //time of current frame
  double oldTime = 0; //time of previous frame
  int stopcast = 0;

  while(stopcast==0) {
    lastTickCount = XGetTickCount();
    for(x = 0; x < width; x++)
    {
      //calculate ray position and direction
      double cameraX = 2 * x / (double)width - 1; //x-coordinate in camera space
      double rayPosX = posX;
      double rayPosY = posY;
      double rayDirX = dirX + planeX * cameraX;
      double rayDirY = dirY + planeY * cameraX;

      //which box of the map we're in  
      int mapX = (int)rayPosX;
      int mapY = (int)rayPosY;
      
      //length of ray from current position to next x or y-side
      double sideDistX;
      double sideDistY;
      
       //length of ray from one x or y-side to next x or y-side
      double deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
      double deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
      double perpWallDist;
      
      //what direction to step in x or y-direction (either +1 or -1)
      int stepX;
      int stepY;

      int hit = 0; //was there a wall hit?
      int side; //was a NS or a EW wall hit?

      //calculate step and initial sideDist
      if (rayDirX < 0)
      {
        stepX = -1;
        sideDistX = (rayPosX - mapX) * deltaDistX;
      }
      else
      {
        stepX = 1;
        sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX;
      }
      if (rayDirY < 0)
      {
        stepY = -1;
        sideDistY = (rayPosY - mapY) * deltaDistY;
      }
      else
      {
        stepY = 1;
        sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY;
      }

      //perform DDA
      while (hit == 0)
      {
        //jump to next map square, OR in x-direction, OR in y-direction
        if (sideDistX < sideDistY)
        {
          sideDistX += deltaDistX;
          mapX += stepX;
          side = 0;
        }
        else
        {
          sideDistY += deltaDistY;
          mapY += stepY;
          side = 1;
        }
        //Check if ray has hit a wall
        if (worldMap[mapX][mapY] > 0) hit = 1;
      }

      //Calculate distance projected on camera direction (oblique distance will give fisheye effect!)
      if (side == 0)
      perpWallDist = fabs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
      else
      perpWallDist = fabs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY);

      //Calculate height of line to draw on screen
      int lineHeight = abs((int)(height / perpWallDist));
      
      //calculate lowest and highest pixel to fill in current stripe
      int drawStart = -lineHeight / 2 + height / 2;
      if(drawStart < 0)drawStart = 0;
      int drawEnd = lineHeight / 2 + height / 2;
      if(drawEnd >= height)drawEnd = height - 1;

      //choose wall color
      BYTE cr;
      BYTE cg;
      BYTE cb;
      switch(worldMap[mapX][mapY])
      {
        case 1:
          cr = 255; //red
          cg = 0;
          cb = 0;
          break;
        case 2:
          cr = 0; //green
          cg = 255;
          cb = 0;
          break;
        case 3:
          cr = 0; //blue
          cg = 0;
          cb = 255;
          break;
        case 4:
          cr = 255; //white
          cg = 255;
          cb = 255;
          break;
        default:
          cr = 0; //yellow
          cg = 255;
          cb = 255;
      }
      
      //give x and y sides different brightness
      if (side == 1) {
        cr = (BYTE)(cr / 2);
        cg = (BYTE)(cg / 2);
        cb = (BYTE)(cb / 2);
      }

      //draw the pixels of the stripe as a vertical line
      int tmpy;
      for (tmpy=0; tmpy<drawStart; tmpy++) XPlot(x, tmpy, 100, 100, 255);
      for (tmpy=drawStart; tmpy<drawEnd; tmpy++) XPlot(x, tmpy, cr, cg, cb);
      for (tmpy=drawEnd; tmpy<height; tmpy++) XPlot(x, tmpy, 0, 100, 0);

    }
    memcpy(fb, pb, width*height*pixmultx); //do the actual copy of video buffer to screen

// NOW lets do the input functions...

    XInput_GetEvents();
    passedMilliseconds = XGetTickCount() - lastTickCount;
    lastTickCount = XGetTickCount();
    if (passedMilliseconds < 10) passedMilliseconds = 10;

    //speed modifiers
    double moveSpeed = passedMilliseconds * 0.005; //the constant value is in squares/second
    double rotSpeed = passedMilliseconds * 0.0015; //the constant value is in radians/second

      if(g_Pads[padnum].CurrentButtons.usDigitalButtons & XPAD_DPAD_UP) {
            if(worldMap[(int)(posX + dirX * moveSpeed)][(int)(posY)] == false) posX += dirX * moveSpeed;
            if(worldMap[(int)(posX)][(int)(posY + dirY * moveSpeed)] == false) posY += dirY * moveSpeed;
      }
  
      if(g_Pads[padnum].CurrentButtons.usDigitalButtons & XPAD_DPAD_DOWN) {
            if(worldMap[(int)(posX - dirX * moveSpeed)][(int)(posY)] == false) posX -= dirX * moveSpeed;
            if(worldMap[(int)(posX)][(int)(posY - dirY * moveSpeed)] == false) posY -= dirY * moveSpeed;
      }

      if(g_Pads[padnum].CurrentButtons.usDigitalButtons & XPAD_DPAD_LEFT) {
            //both camera direction and camera plane must be rotated
            double oldDirX = dirX;
            dirX = dirX * cos(rotSpeed) - dirY * sin(rotSpeed);
            dirY = oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed);
            double oldPlaneX = planeX;
            planeX = planeX * cos(rotSpeed) - planeY * sin(rotSpeed);
            planeY = oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed);
      }

      if(g_Pads[padnum].CurrentButtons.usDigitalButtons & XPAD_DPAD_RIGHT) {
            //both camera direction and camera plane must be rotated
            double oldDirX = dirX;
            dirX = dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed);
            dirY = oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed);
            double oldPlaneX = planeX;
            planeX = planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed);
            planeY = oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed);
      }

      if(g_Pads[padnum].CurrentButtons.usDigitalButtons & XPAD_START && g_Pads[padnum].CurrentButtons.usDigitalButtons & XPAD_BACK)
      {
        stopcast = 1;
        XReboot();
      }

  }
}


i'd love to get feedback on it, especially regarding optimization. i need to sit down and have a real good look at it all again and see if i can squeeze some extra speed out of it. this runs very fast, but adding textures will for sure have a big impact. i'm still a C newbie really.

i hope this isn't against the rules, but i'm going to post this in "homebrew software" too because it fits in both subforums. ph34r.gif

#2 Pulsemasta

Pulsemasta

    X-S Expert

  • Members
  • PipPipPip
  • 725 posts
  • Xbox Version:v1.1
  • 360 version:unknown

Posted 28 January 2010 - 02:24 PM

Hey. I couldnt get this running. Is there something special I have to do?

#3 openxdkman

openxdkman

    X-S Genius

  • Moderator
  • PipPipPipPip
  • 823 posts
  • Xbox Version:unk
  • 360 version:unknown

Posted 28 January 2010 - 03:11 PM

playing with pixels only with CPU is the logical path of learning graphics, so keep on the good work.

but once you are done (and disappointed by slow speed of unaccelerated complex graphics)
don't forget to check this :
http://minilgos.pers...t/changelog.txt

it's harder to learn but executes much faster...
(of course that means giving up the ray tracing concept, but don't forget
that smooth raytracing can only be achieved at the moment with some beast like 3 ps3's connected together... xbox1 is a bit too weak for that...)

Edited by openxdkman, 28 January 2010 - 03:14 PM.


#4 miker00lz

miker00lz

    X-S Enthusiast

  • Members
  • 10 posts

Posted 31 January 2010 - 07:47 AM

QUOTE(Pulsemasta @ Jan 28 2010, 07:24 AM) View Post

Hey. I couldnt get this running. Is there something special I have to do?


hmm. copying the compiled XBE over to your xbox and running it should be all you need to do. there are no external files it needs or anything like that. what happens when you try to run it?

QUOTE(openxdkman @ Jan 28 2010, 08:11 AM) View Post

playing with pixels only with CPU is the logical path of learning graphics, so keep on the good work.

but once you are done (and disappointed by slow speed of unaccelerated complex graphics)
don't forget to check this :
http://minilgos.pers...t/changelog.txt

it's harder to learn but executes much faster...
(of course that means giving up the ray tracing concept, but don't forget
that smooth raytracing can only be achieved at the moment with some beast like 3 ps3's connected together... xbox1 is a bit too weak for that...)


yep. i wasn't really planning on going much beyond a textured raycaster. maybe throw in some guns and some enemies to shoot to kill some time. if i can play wolf 3d smoothly on my old 286 i'm sure the xbox could handle this. biggrin.gif

#5 Pulsemasta

Pulsemasta

    X-S Expert

  • Members
  • PipPipPip
  • 725 posts
  • Xbox Version:v1.1
  • 360 version:unknown

Posted 31 January 2010 - 11:16 PM

hey, when I start the text comes up to press start, but when I press start nothing happens.



#6 miker00lz

miker00lz

    X-S Enthusiast

  • Members
  • 10 posts

Posted 01 February 2010 - 12:07 AM

QUOTE(Pulsemasta @ Jan 31 2010, 04:16 PM) View Post

hey, when I start the text comes up to press start, but when I press start nothing happens.


make sure the controller you're using is plugged into port 1 all the way on the left.

#7 Pulsemasta

Pulsemasta

    X-S Expert

  • Members
  • PipPipPip
  • 725 posts
  • Xbox Version:v1.1
  • 360 version:unknown

Posted 01 February 2010 - 01:54 AM

QUOTE(miker00lz @ Feb 1 2010, 12:07 AM) View Post

make sure the controller you're using is plugged into port 1 all the way on the left.


yeah it is.

could it have something to do with the type of controller? I am using a madcatz controller. not a official MS one.

#8 obcd

obcd

    X-S Hacker

  • Moderator
  • PipPipPipPipPipPip
  • 2,737 posts
  • Xbox Version:v1.0
  • 360 version:none

Posted 01 February 2010 - 12:17 PM

Very likely. For some unknown reason, programs written with the openxdk only like original M$ controllers. Some modchip setup menus suffer from the same issues.

regards.

#9 Pulsemasta

Pulsemasta

    X-S Expert

  • Members
  • PipPipPip
  • 725 posts
  • Xbox Version:v1.1
  • 360 version:unknown

Posted 11 March 2010 - 09:09 AM

Hey, I was just wondering if you were still adding to this, or working on a new project?




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users