1
\$\begingroup\$

I am currently trying to get into game development and trying to understand 3D games. I would like to learn to code from scratch without any 3D engines. Some of the things I found was libraries like SDL and graphics.h in C. How does a game actually access the screen at the lowest-level? So how would one move a square rightwards on the screen on say Windows. Is the lowest level OpenGL and Direct3D or is there lower-level ways of doing it?

\$\endgroup\$
  • \$\begingroup\$ If you want to build an engine, then I would definitely go for SDL + OpenGL and the like, so you can focus on creating the graphics, instead of messing with the creation of a window on all operating systems... \$\endgroup\$ – akaltar Aug 22 '16 at 9:36
5
\$\begingroup\$

The lowest-level practical way on modern computers is to use OpenGL/Vulkan/Mantle/Direct3D.

Technically you could write yourself a driver, replacing the ones supplied by your GPU manufacturer, because the above APIs ultimately talk to that driver at some point. This is exceedingly tedious and difficult and not worth the effort.

You could also find an old computer that runs and older operating system that would let you directly access attached video RAM and do everything in software. Or you could buy a Raspberry Pi or some other piece of DIY computing hardware and build the whole hardware and software stack yourself.

Or you could machine your own hardware components and wiring and build your own hardware stack, and then build your software stack on that...

...and so on. You can see that beyond a certain point trying to get "lower level" becomes exceedingly tedious, so stick to D3D, et cetera. D3D12 and Vulkan both provide more direct, less abstracted access to the GPU than earlier versions of D3D and than OpenGL, so you might consider those, although they are biting off quite a lot if you're a relative newbie to the field of computer graphics.


If your goal is to experience what graphics programming used to be like, though, when you did have direct access to a buffer of bytes that just represented colors... there's a couple reasonable options:

  • use D3D/OpenGL to render a single full-screen quad with a texture. Then, treat the bytes of that texture like "video RAM," so you can poke and prod them however you like. You can write sprite blitters and other sorts of old-school effects this way. Barring weird hardware-specific idiosyncrasies this can give you a pretty reasonable approximation of the old "low level" approaches to graphics.

  • get some old console hardware that's reasonably open to home-brew work. The GBA is an excellent candidate, as is the PSP. Both of these machines are fairly limited and still let you to direct hardware access tricks for graphics. Because of the specialized hardware involved, these techniques may be different than the ones you'd have seen in old DOS or Classic MacOS games.

  • build or buy an old PC and install DOS or whatnot on it. I mentioned this in the first section as a bit of a joke, but out of all those "unrealistic" options (like writing your own driver), this is actually reasonably practical to do, assuming you can tolerate working on such an old machine.

\$\endgroup\$
  • \$\begingroup\$ Ok that makes a lot of sense. Will definitely stay at the D3D/OpenGL level as it seems the most practical yet professional way. Thanks for the answer! \$\endgroup\$ – thephysicsguy Aug 20 '16 at 20:50
  • 3
    \$\begingroup\$ And using existing engine or library wouldn't be professional? \$\endgroup\$ – Mars Aug 20 '16 at 21:20
  • 1
    \$\begingroup\$ @Mars I didn't say it would not be at all. I know realistically many games use it. But at the same time, many small/big teams enjoy creating their own engines, etc. I am doing this for fun so I wanted a low-level way of doing it. \$\endgroup\$ – thephysicsguy Aug 20 '16 at 23:10
  • \$\begingroup\$ I started with DirectX. Frank Luna's book was perfect. \$\endgroup\$ – David Aug 21 '16 at 9:29
1
\$\begingroup\$

The answer depends largely on what you want to accomplish.

OpenGL has a lot of advantages, mainly that it's supported to at least some level on virtually any graphics card today without any additional libraries strictly required.

It's also pretty easy to get the basics going, but in spite of what many would say it's actually fairly high level in many respects. A huge amount is just done for you more or less like magic. I don't think a lot of developers using it even realize this is the case. Things like rasterizing, anti-aliasing, generating mip-maps, the list goes on and on.

So if you are doing this as a learning exercise and really want to go to a lower level then consider looking at creating a basic software renderer. You will still probably have to use OpenGL or DirectX but you would be using it simply to put your already created images onto the graphics card.

The flipcode archives talk about this quite a bit and are a good place to start learning the basics of how graphics work. Otherwise you will probably wind up taking a sort of magic carpet ride where you can get things going but become mystified when it comes to making truly new stuff or understanding performance issues properly.

http://flipcode.com/archives/articles.shtml

\$\endgroup\$
0
\$\begingroup\$

I am not a game developer, but I recently came across an old file from 10 years ago which was part of my undergrad Computer Science course. Since you mentioned Windows and accessing the screen at a low level, I am going to leave you with the minimal code of what I believe would work for your "moving a square to the right" example.

I am assuming you are going to use an old computer with Windows XP (or even an older one, it should include an MS-DOS terminal, I don't know anything about Windows after XP). I am assuming this old computer can run the old 'Mode 19' (or Mode13H, look it up on Wikipedia). According to wikipedia,

Mode 13h is an IBM VGA BIOS mode. It is the specific standard 256-color mode on IBM's VGA graphics hardware. It features a resolution of 320×200 pixels. It was used extensively in computer games and art/animation software of the late 1980s and early to mid-1990s

Indeed, in this minimal example I used the default VGA standard palette of 8-bit colors.

I am also assuming the special address 0xA0000000 and that you understand that if you modify beyond the 320x200=64000 positions you might corrupt your system. So either make sure this address is correct and that you don't modify beyond this limit, or that you are using an old computer that you don't mind [potentially] screwing up.

One final note: I did not try this minimal example. I just copied/modified the essential parts from my own project. I might have missed something or it may contain typos.

Another final note: I recently modified this 10-year old project to work with SDL instead of modifying the special memory address. I then used an Xcode-ios template from SDL and I successfully compiled it and installed it on my own Iphone. I am happy on the outcome and how easy it was to give this old project a new life.

#include <dos.h> // For windows, I guess
#include <conio.h> //MS-DOS console i/o 

typedef unsigned short int byte; //Definition of an unsigned short int type

//Let's say this is your 'square', it actually looks like a bomb, I took it from my own class project. 
byte bomba[7][5]=  
{
   {48,48,40,48,48},
   {48,40,40,40,48},
   {40,40,44,40,40},
   {40,44,44,44,40},
   {40,44,42,44,40},
   {40,44,44,44,40},
   {40,40,40,40,40}
};

byte backup[35]; //This will be used as a 'backup' of what is behind the bomb in the background (should you use one), so that when you move the sprite we can redraw these pixels to the screen.  

void modovideo(byte type) //this function will take you to mode 19 (or other modes if you wish to)
{
  REGS m,f;
  m.h.ah=0;
  m.h.al=type;
  int86(0x10,&m,&f); 
}

void getbackup(int bx, int by)   //this function will save the background to memory before we draw the bomb at position bx, by
{
 char far *p=(char far *)0xA0000000+bx+(320*by);

    for(int i=0;i<35;i++,p++)
        { 
          if(i%5==0 && i!=0)  //New line
              p+=(320-5);

            backup[i]=*p;                        
        }            
}


void draw(int bx, int by,byte r)   //This function will render the sprite on screen at position (bx,by), or will draw the 'backup', depending on the value of 'r'
{
    //Pointer to 0xA0000000 + the corresponding pixel position in a vectorized form (320 is the screen width)
    char far *p=(char far *)0xA0000000+bx+(320*by); 
byte m[5]; 
//7 and 5 are the dimensions of the sprite
for(int i=0;i<7;i++,p+=(320-5))  
  {    
        if(r==0) //Draws bomb
           { for(int a=0;a<5;a++,p++)
              {
        //I am using 48 as a background for the sprite (48 is a greenish color, I guess I used it so that it could literally be a 'green screen')
                if(bomba[i][a]!=48) 
                  *p=bomba[i][a];   //Assigns the value of the pixel to the correct memory address
              }
            }
        else
         {
          for(int j=0;j<5;j++)
                m[j]=backup[j+(i*5)];

            for(int b=0;b<5;b++,p++)
                if(m[b]!=48)
                  *p=m[b];  //Draws the backup pixel

         }     
   }        
}

//Main function 
void main()
{   

    modovideo(19); //Starts mode 19

    int posx=50, posy=50; //Initial position of your square 
    int dx=1, dy=0; //Constant velocity for your square
    int count=0; //Count for main loop in this minimal example 

    getbackup(posx,posy); //Gets a backup of the background


    //Main time loop
    do
    {
    delay(30); //Delay in milliseconds, up to you

    draw(posx, posy, 1); //Draws the sprite backup at previous location

    posx+=dx; //sprite moves
    posy+=dy;    

    getbackup(posx,posy); //Gets new backup (at new location)
    draw(posx,posy, 0); //Draws sprite at new location

    count++;
    }while(count<50); //We will move it 50 times in this minimal example. 
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.