NeXTStep raster VGA Graphics mode

Started by alxmamaev, January 10, 2022, 04:12:51 PM

Previous topic - Next topic

alxmamaev

Hello there! Im interested in the computer graphics as my hobby.
I want to create a raycasting demo (like in Wolfenstein 3D) on NeXT computer.
I have no real computer, but already configured emulator (Previous).

I started my search about development on NeXT and found that main IDE is Project Builder, that's allows to compile C/CXX/Objective-C code.

I found this Book, there are telling about programming on NeXT using Objective-C. Few chapters of this book telling about graphics. But him used PostScript, that's more similar to SVG drawing in XServer, not this I want.

I want to draw true raster graphics, when I can get a pointer to the array of pixels or smth like this.
I know that it is real, because wolf3d was developed on the NeXT.

I also checked code of Wolf3D, they are using 10h interrupt to bios, for switching from text to VGA mode. This code wrote for PC-DOS, in fact the game gets full access to the display to draw it.

To make this ID Software uses kind of PC-emulator-layer in the NeXT, according to this article.
But also in this article guy tell, that they made full port of DOOM to the NeXT.
I found the screenshot of this port


I see some "VGA" in the title, that's means that the game renders using via VGA, but using only window, not the whole display.

My question is, what I should do to use VGA graphics in the NeXTStep? What the libraries.
If you can please provide the links, because it is really hard to google "NeXTStep + something", google thinks that I want to make next step in c++ graphics.

Thank you!


zombie

Not sure about "port". The NeXT version came out before the PC version. And they used NeXT to develop the levels. The alpha version was out from ID itself if I recall.

alxmamaev

Some updates. I found two books:

Black Book: Wolfenstein 3D
This book tells about how Wolf was created. And they are used IBM PC with DOS for development. They are used Borland Turbo C++. NeXT comes later, they used this only for documentation development.

But! The DOOM was developed fully on the NEXT. According to the Black Book: DOOM .

> The NeXT version came out before the PC version.
This guy from the NeXT developers tells his story. Doom on the next in fact was developed not for the next. They are used some emulation layer. And then Omni company made full port to the NeXT using original source code.

Rob Blessin Black Hole

Hello : Have you downloaded and installed the matching NeXT Develper tool rev to ie NeXTSTEP 3.3 User then install NeXTSTEP 3.3 Developer Tools . Be sure and set a password for the me account then login as root from the login panel , then install te developer tools and Y2k patches. 

https://fsck.technology/software/NeXT/NeXTSTEP%20Applications/

Here is some NeXT Developer Documentation online http://www.nextcomputers.org/NeXTfiles/Docs/NeXTStep/3.3/nd/

If you are looking for Adobe Postscript Docs ? This video gets you started... https://youtu.be/5c0De1pHJ0U

If you are interested in original printed documentation , books and manuals , I have some for sale ,

need to narrow down what you are looking for.
Rob Blessin President computerpowwow ebay  [email protected] http://www.blackholeinc.com
303-741-9998 Serving the NeXT Community  since 2/9/93

alxmamaev

Hi, thank you for the links.

Im already found the API, that's used to display Doom graphics. That is NSWindow/libinterceptor. It remains to find how to work with these APIs.

zombie

QuoteSome updates. I found two books:

Black Book: Wolfenstein 3D
This book tells about how Wolf was created. And they are used IBM PC with DOS for development. They are used Borland Turbo C++. NeXT comes later, they used this only for documentation development.

But! The DOOM was developed fully on the NEXT. According to the Black Book: DOOM .

> The NeXT version came out before the PC version.
This guy from the NeXT developers tells his story. Doom on the next in fact was developed not for the next. They are used some emulation layer. And then Omni company made full port to the NeXT using original source code.


Yea, if you read it, you'll see even during that interview, the NeXT version by ID came out first, and then later there was an 'enhanced' port done by Omni. Their enhanced port gave them an engine to make porting other games easier, which he talks about later in that interview.

QuoteIn December of 1993 Id did a public release of the Doom alpha on NEXTSTEP before the DOS version, which I'm betting encouraged many nones of people to buy NeXT boxes. But it was a nice gesture, anyways—we NeXTers really needed all the publicity we could get.

Carmack and I mailed each other about technical stuff for almost a year after that... hey, since you wrote this game on NEXTSTEP but don't want to waste your time tuning it up for that platform

So I remember this. I worked at NeXT around that time and we got the ID version of the game. I remember playing it on our network with a friend on NeXT hardware, all the way through together. Man that was a blast.

Much later, Omni did a nicer wrapper/port. But the original came out from ID. Like I said, I remember playing it.

I still have the Omni version of the port, but sadly, I think I chucked the original ID version of Doom after the 'enhanced PC portable" Omni port came out. :(

GrafZahl

QuoteHi, thank you for the links.

Im already found the API, that's used to display Doom graphics. That is NSWindow/libinterceptor. It remains to find how to work with these APIs.

Hi,

If you find more info on this I`m all ear. As far as I read and was readable in the links it is private API to circumvent any speed loss by the window compositor like NextTime was doing it, and it will be even harder to find info on that.

You may start by using official API like NXBitmapImageRep. You application code will just manage filling the byte array with likely chunky pixel data and then hand this to the NXBitmapImageRep and use it for drawing. You may keep an eye on the various formats this can be tricky. Here it uses NXColor for that but actually raw access of bytes may be much faster..

Here is an really ugly frankenstein test of an SDL Plasma sample app (I'm not 100% sure but I think its from that source: https://www.libsdl.org/projects/plasma/) with some hacky test code I tried some years ago to make it doing something on nextstep. I'm not sure it's compiling or working anymore but it may be a start.  See attached picture what it is doing (or did it's an old executable so your mileage may vary) Also it uses a timer to update the view.  Something similar (data pointer and image) was done in the Quake port by neozeed so if you look for it in the forum you'll find the link and included source code of his port.

#import <appkit/appkit.h>

#include <math.h>

#ifndef PI
#define PI    3.14159265358979323846

#endif

#define VIDEOX 320
#define VIDEOY 200

#define TABLEX VIDEOX*2
#define TABLEY VIDEOY*2
#define TONES 256

 static id menu;
 static id window;
 static id view;

@interface MyView : View
{
  DPSTimedEntry linesTimedEntry;
  NXBitmapImageRep *bitmap;
  double r[3];
  double R[6];
  unsigned char *t;
  int state;
  NXColor colors[TONES*2];
}

-updateThePlasma;

@end

@implementation MyView

static unsigned char* pData;


void do_plasma( NXBitmapImageRep *bitmap,
           double x1,
           double y1,
           double x2,
           double y2,
           double x3,
           double y3,
           unsigned char*t)
{
  unsigned int
  X1=x1*(TABLEX/2),
  Y1=y1*(TABLEY/2),
  X2=x2*(TABLEX/2),
  Y2=y2*(TABLEY/2),
  X3=x3*(TABLEX/2),
  Y3=y3*(TABLEY/2);
  unsigned int y;
  unsigned char *t1=t+X1+Y1*TABLEX, *t2=t+X2+Y2*TABLEX, *t3=t+X3+Y3*TABLEX;
  for (y=0; y<VIDEOY; y++) {
    unsigned x;
    unsigned char* tmp= pData + y * [bitmap bytesPerRow];
    unsigned int t=y*TABLEX, tmax=t+[bitmap bytesPerRow];
    for (x=0; t<tmax; t++, tmp++) {
      tmp[0]=t1[t]+t2[t]+t3[t];
    }
  }
}

void DrawIt(DPSTimedEntry te, double timeNow, void *data)
{
  [(id)data updateThePlasma];
}

-updateThePlasma
{
 int c;
 state++;
  for (c=0 ; c<TONES; c++)
  {
    colors[c] = NXConvertRGBToColor( (sin(((double)c)/TONES*6*PI+r[0]*PI*state*PI)+1)*127,
(sin(((double)c)/TONES*6*PI+r[1]*state*PI)+1)*127,                  (sin(((double)c)/TONES*6*PI+r[2]*state*PI)+1)*127 );
  }

do_plasma( self->bitmap, (sin(((double)state)*R[0])+1),
    (sin(((double)state)*R[1])+1)/2,
    (sin(((double)state)*R[2])+1)/2,
    (sin(((double)state)*R[3])+1)/2,
    (sin(((double)state)*R[4])+1)/2,
    (sin(((double)state)*R[5])+1)/2, t);

 [view display];
 NXPing();

 return self;
}

- initFrame:(const NXRect *)rect
{
  int c;

  [super initFrame:rect];

  srand(time(NULL));
  {
    for (c=0; c<3; c++)
      r[c]=((double)(rand()%1000+1))/300000;
    for (c=0; c<6; c++)
      R[c]=((double)(rand()%1000+1))/5000;
  }

  t = (unsigned char *)malloc(TABLEY*TABLEX);
  if ( t == NULL ) {
    fprintf(stderr, "Out of memory\n");
    exit(1);
  }
  {
    int y;
    for (y=0 ; y<TABLEY ; y++) {
      int x;
      for (x=0 ; x<TABLEX ; x++) {
    double tmp=(((double)((x-(TABLEX/2))*(x-(TABLEX/2))+(y-(TABLEX/2))*(y-(TABLEX/2))))
            *(PI/(TABLEX*TABLEX+TABLEY*TABLEY)));
    t[y*TABLEX+x]=(sin(sqrt(tmp)*12)+1)*TONES/6;
      }
    }
  }

bitmap = [[NXBitmapImageRep alloc]     initData:(unsigned char *)NULL
                    pixelsWide:(int)VIDEOX
                    pixelsHigh:(int)VIDEOY
                    bitsPerSample:(int)8
                    samplesPerPixel:(int)3
                    hasAlpha:(BOOL)NO
                    isPlanar:(BOOL)NO
                    colorSpace:(NXColorSpace)NX_RGBColorSpace
                     bytesPerRow:(int)VIDEOX*3
                    bitsPerPixel:(int)24];

    pData = [bitmap data];

    linesTimedEntry = DPSAddTimedEntry(0.2, &DrawIt, self, NX_BASETHRESHOLD );

    return self;
}


- free
{
    DPSRemoveTimedEntry(linesTimedEntry);

    return [super free];
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
 [view lockFocus];
     [bitmap draw];
 [view unlockFocus];
 
 return self;
}

@end



void canvas()
{
 NXRect rect;
 NXSetRect( &rect, 100.0, 100.0, VIDEOX, VIDEOY );   
 
 window = [ [ Window alloc ] initContent:(const NXRect*)&rect
                              style:(int)NX_TITLEDSTYLE
                              backing:(int)/*NX_NONRETAINED*/NX_BUFFERED
                              buttonMask:(int)NX_MINIATURIZEBUTTONMASK
                              defer:(BOOL)NO ];
                             
 menu = [ [ Menu alloc ] initTitle:"Plasma" ];
 [menu sizeToFit ];

 [menu addItem: "Hide"
         action: @selector(hide:)
         keyEquivalent: 'h'];

 [menu addItem: "Quit"
         action: @selector(terminate:)
         keyEquivalent: 'q'];
        
 [NXApp setMainMenu: menu];
 
 [window setTitle: "Plasma"];
 [window display];
 

 NXSetRect( &rect, 0.0, 0.0, VIDEOX, VIDEOY );   
 view = [ [ MyView alloc ]initFrame: &rect ];
 [view setOpaque: YES];
 
 [window setContentView: view];
 [window makeKeyAndOrderFront:0];
}

void main()
{
    NXApp = [Application new];
   
    canvas();
       
    [NXApp run];

    [NXApp free];
}