Key Words
coding programming science

About
Verboten is a small town production studio with big dreams. Making music, film, software, technology, articles, essays, books, games, and more. Founded by Anthony Mountjoy.

Preeceville, Saskatchewan, Canada

editor@verboten.ca

Take Action
There are 4 levels of authority over content. Author, verified, member, and public.


Literary Agents
Enhance

Author
Edit

Verified
Promote

Verboten Publishing Ltd.

Learn To Code in C With This Cute Little Sample Program

Essential source code for any aspiring programmer trying to escape the corporate machine.

Home  |  Login

By Aesh M. Daeva

You'll need some basic programming background for this... but not much. Just the basics.

There is nothing more ravenous than a programmer. We eat our own and that's the way we like it. - Jolly Roger

You'll need some basic programming background for this...but not much. Just the basics. I demonstrate graphics, sound, vector math, memory management (the almighty pointer with malloc), structures, animation, 3D particle system, clickable 2D surface objects with collision detection, threads, keyboard and mouse inputs including the wheel. I sometimes use this program (I have a large collection of code written over 20+ years) as a start point for my other larger projects because it has everything I need to get a system up and running.

Always write your programs in generic C for desktop AND THEN port to other platforms. Trust me! I cannot emphasize this enough.

I've tried to strip it of any unnecessary distractions. It's one file, everything happens in its base directory and will compile and run as is. Feel free to change it however you like. No hiding behind API's or visual editing environments. No commercial entanglements. Even freeGlut and SDL are used in the most minimal way to provide maximum control to the coder. From this you can literally write anything you want by expanding on these principals with your own imagination.

C was invented by the late Dennis M. Ritchie. Please visit his old website at bell labs for a great history lesson.

[There are a few extra variables and some commented out remnants that I use for testing. But you don't mind cleaning up a little for your own use now do ya. Also the web formatting might mess with spacing a bit but nothing you can't handle by copying and pasting into a text editor.]

Requirements

A text editor like gEdit(my preference) and GCC which is the C compiler invented by Richard Stallman when he created open source (free software). All of which are free and available for download. You'll also need to get the include files (.h) referenced in the source.

Cute Little Stub Program
Author: Anthony Jon(Yawn) Mountjoy
Put the code in a file called verboten.c in a directory called verboten. To compile type the following on your console from the same directory. You can change the file/directory names but adjust the compile command accordingly.

gcc verboten.c -o Verboten -I"C:\Program Files\Common Files\freeglut\include" -L"C:\Program Files\Common Files\freeglut\lib" "C:\verboten\verboten.res" -lmingw32 -lSDL2main -lSDL2 -lSDL2_mixer -lpthread -lfreeglut -lopengl32 -lwinmm -lws2_32 -w -limagehlp -Wl, - subsystem,windows -mwindows

C:\verboten\verboten.res is just an icon resource so the program looks good on the desktop program tray. Made by converting a .rc file with the following command.

windres verboten.rc -O coff -o verboten.res

You'll have to provide your own .wav files for the audio. Comments italicized in bold. You'll have to remove the comments before you compile. Also I'm not going to bother distinguishing between procedures and functions or variables and constants. I'm gonna just call them all functions and variables for simplicity. I even throw in a little volatility and static for fun. ;)

The Code (All in less than 1000 lines)

The includes for basic system controls on a windows desktop.

#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <pthread.h>
#include <GL/freeglut.h>
#include <wglext.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL.h>
#include <signal.h>
#include <imagehlp.h>

We declare variables. Classic form.

double lens, speed, sx, sy, alive, totaltimepast;
int turns, cycles, mode, canedit, focus, fx, fy, slength, sxd, isaudio, cvol, swidth, sheight, nrects, mx, my,mx2, my2,onMouse, nB, hasclicked, plays;

volatile int stop, button2, canplay;

static char const * icky_global_program_name;

pthread_attr_t attr;

This is to capture exception errors that would normally crash the program...but we don't like that...so we use a signal handler to catch the errors. More useful when we're doing network stuff but it's good to know.

void windows_print_stacktrace(CONTEXT* context)

LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo)
switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
case EXCEPTION_ACCESS_VIOLATION:fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);break;
case EXCEPTION_BREAKPOINT:fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);break;
case EXCEPTION_DATATYPE_MISALIGNMENT:fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);break;
case EXCEPTION_FLT_DENORMAL_OPERAND:fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);break;
case EXCEPTION_FLT_INEXACT_RESULT:fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);break;
case EXCEPTION_FLT_INVALID_OPERATION:fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);break;
case EXCEPTION_FLT_OVERFLOW:fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);break;
case EXCEPTION_FLT_STACK_CHECK:fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);break;
case EXCEPTION_FLT_UNDERFLOW:fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);break;
case EXCEPTION_ILLEGAL_INSTRUCTION:fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);break;
case EXCEPTION_IN_PAGE_ERROR:fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);break;
case EXCEPTION_INT_OVERFLOW:fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);break;
case EXCEPTION_INVALID_DISPOSITION:fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);break;
case EXCEPTION_PRIV_INSTRUCTION:fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);break;
case EXCEPTION_SINGLE_STEP:fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);break;
case EXCEPTION_STACK_OVERFLOW:fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);break;
default:fputs("Error: Unrecognized Exception\n", stderr);break;

fflush(stderr);return EXCEPTION_EXECUTE_HANDLER;


void set_signal_handler()
SetUnhandledExceptionFilter(windows_exception_handler);

This is how you can make structures which are really just groups of variables that can be arrayed. The C version of data-basing, basically. A little more human readable than just using arrays of pure primitives with memory ranges although that works, too.

typedef struct
double x, y; double w, h, s; int members; double xdir; double ydir;
rect;

rect rects[1000];

Another example. Formatting isn't so important as you can see. Do what you like. If the code works and you understand it then there is no such thing as coding ugly. Don't let elitists tell you pretty code is important. Just code. Insecurity is a programmer's kryptonite. Don't worry about code critics; worry about making a useful program.

typedef struct
GLfloat R, G, B;
double x, y, z;
double vx, vy, vz;
double tx, ty, tz;
double ox, oy, oz;
double s,e,d,m,decay,anchored;
int loc;
sprite;

sprite swarm[100000];

typedef struct
GLfloat R, G, B;
color_t;

Some more variables.

color_t *array1d;

color_t *background;

struct timeval rNow;

struct timeval rRes;

struct timeval started;

pthread_mutex_t mutexsum, mutexsum2, mutexsum3, mutexsum4;

pthread_attr_t attr;

struct timeval tv;

Mix_Music *music = NULL; Mix_Chunk *scratch = NULL; Mix_Chunk *high = NULL; Mix_Chunk *med = NULL; Mix_Chunk *low = NULL;

Now we get into the good stuff.

Here's how to handle the keyboard.

void Keyboard(unsigned char key, int x, int y)
printf("key:%u\n",key);
switch (key)
case 103:
break;
case 115:
break;
case 93:
break;
case 91:
break;
case 109:
break;
case 96:
if(canedit==0)canedit=1;
else canedit=0;
break;
break;
case 50:
mode=1;
break;
case 49:
mode=0;
break;
case 27:
pthread_mutex_lock(&mutexsum3);
if(isaudio)
isaudio=0;
Mix_HaltMusic();
Mix_HaltChannel(-1);
Mix_FreeMusic( music );
Mix_FreeChunk( scratch );
Mix_FreeChunk( high );
Mix_FreeChunk( med );
Mix_FreeChunk( low );
//Quit SDL_mixer
Mix_CloseAudio();

int tries = 0;
//sleep(1);
pthread_mutex_unlock(&mutexsum3);
glutLeaveMainLoop();
exit(0);
break;
case 8:
break;



This is for running another program from within this one. Not used here but super useful sometimes. Just pass in the file name for the executable.
void *runsystem(void *p)
system((unsigned char*)&p[0]);
pthread_exit(0);


This is some of the real-time audio stuff.
void canPlay(int state)
if(state == GLUT_VISIBLE && canplay == 0) canplay = 1;if(isaudio)Mix_VolumeMusic((MIX_MAX_VOLUME/20)*((float)cvol/4.0));
else if(state != GLUT_VISIBLE && canplay == 1) canplay = 0;if(isaudio)Mix_VolumeMusic(0);


This is the mouse stuff. The wheel is treated as a button. The 2D Rectangles are clickable and so is the Circle on the bottom left that adds more Rectangles.
void mouseClicks(int button, int state, int x, int y)
button2 = button;
if(button2 == 3 || button2 == 4)
if(state == GLUT_UP) return;

if(button2 == 4) if(speed > 10.0) speed = speed-1.0;
if(button2 == 3) if(speed < 19.0) speed = speed+1.0;
focus = 0;


printf("Mouse click:%d\n",button2);
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
button2 = 1;

else if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
button2 = 2;

else button2 = 0;hasclicked=0;
if(hasclicked==0 && button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
hasclicked=1;
int i,j,k;
int wf = 0;
int focus2 = 0;
for(i=1;i
if(rects[i].s == speed)

for(j=0;j
for(k=0;k
// SetScreenColor(rects[i].x+j, rects[i].y+k, 0.5, 0.5, 0.5);
int t = (rects[i].x+j) + (rects[i].y+k)*swidth;
if((mx > rects[i].x && mx < rects[i].x+rects[i].w && my > rects[i].y && my < rects[i].y+rects[i].h))

focus2 = i;wf=1;fx = (mx-rects[i].x);fy = (my-rects[i].y);


rects[focus2].s = 0;

else if(hasclicked==0 && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
hasclicked=1;
if((mx > swidth-60) && (my > sheight-60))

pthread_mutex_lock(&mutexsum3);
if(isaudio)
isaudio=0;
Mix_HaltMusic();
Mix_HaltChannel(-1);
Mix_FreeMusic( music );
Mix_FreeChunk( scratch );
Mix_FreeChunk( high );
Mix_FreeChunk( med );
Mix_FreeChunk( low );
//Quit SDL_mixer
Mix_CloseAudio();

pthread_mutex_unlock(&mutexsum3);
glutLeaveMainLoop();
exit(0);
return;

else
//printf("leftclick\n");
double xd = (double)mx-25.0;
double yd = (double)my-25.0;
double D = sqrt(xd*xd + yd*yd);
if(D < 25.0)

rects[nrects].x = 100+(double)(rand()%(swidth-300));//((double)swidth/2.0);
rects[nrects].y = 100+(double)(rand()%(sheight/2));//((double)sheight/2.0);
rects[nrects].w = 10.0+(double)(rand()%190);//((double)swidth/2.0);
rects[nrects].h = 10.0+(double)(rand()%190);//((double)sheight/2.0);
rects[nrects].s = speed;
rects[nrects].members = 0;
rects[nrects].xdir = 1.0;
rects[nrects].ydir = 1.0;
nrects++;

else
int i,j,k;
int wf = 0;
for(i=1;i
if(rects[i].s == speed)

for(j=0;j
for(k=0;k
double xx = rects[i].x-sx;
double yy = rects[i].y-sy;
int t = (int)(xx+j) + (int)(yy+k)*swidth;
if((mx > (int)xx && mx < (int)(xx+rects[i].w) && my > (int)yy && my < (int)(yy+rects[i].h)))

focus = i;wf=1;fx = (mx-rects[i].x);fy = (my-rects[i].y);


if(wf == 0) focus = 0;


void mouseMoves(int x, int y)
mx = x;
my = (sheight-y);
if(focus > 0)

printf("button:%d:focus:%d\n",button2,focus);

if(button2 == 1)

if(rects[focus].s == speed)

if(mx-fx > 0.0)rects[focus].x = mx-fx;
if(my-fy > 0.0)rects[focus].y = my-fy;



This is a quick function for subtracting time
int timeval_subtract(struct timeval *result,struct timeval *x,struct timeval *y)
if (x->tv_usec < y->tv_usec)
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;

if (x->tv_usec - y->tv_usec > 1000000)
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;

result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
return x->tv_sec < y->tv_sec;


A little test function for setting a pixel in the display array. I usually prefer to access the array directly. Don't forget your order of operations.
inline void SetScreenColor(int x, int y, float red, float green, float blue)
int t = x + y*swidth;
array1d[t].R = red;
array1d[t].G = green;
array1d[t].B = blue;


A function for priming a swarm of sprites when we start the program.
void setSprite(int p)
swarm[p].d = 0.0;
swarm[p].decay = 0.0;
swarm[p].m = rand()%50;
swarm[p].anchored = 0;
swarm[p].x = swarm[p].ox;
swarm[p].y = swarm[p].oy;
swarm[p].z = swarm[p].oz;
swarm[p].tx = (-1920.0+(float)(rand()%(1920*2)));
swarm[p].ty = (-1920.0+(float)(rand()%(1920*2)));
swarm[p].tz = (-1920.0+(float)(rand()%(1920*2)));
if(swarm[p].tx+swarm[p].ty+swarm[p].tz < 0.00000000000000001)

swarm[p].tx = (-1920.0+(float)(rand()%(1920*2)));
swarm[p].ty = (-1920.0+(float)(rand()%(1920*2)));
swarm[p].tz = (-1920.0+(float)(rand()%(1920*2)));

double xd = swarm[p].tx;
double yd = swarm[p].ty;
double zd = swarm[p].tz;
double D = sqrt(xd*xd + yd*yd + zd*zd);
swarm[p].vx = xd/D;
swarm[p].vy = yd/D;
swarm[p].vz = zd/D;

swarm[p].e = 100;
swarm[p].R = 1.0;
swarm[p].G = 1.0;
swarm[p].B = 1.0;


A function for moving a sprite using algebraic vector math in 3D space between display cycles. You MUST use double type because float isn't precise enough.
void pushSprite(int p, double a)
int i;
double d = a*10.0;//*(swarm[p].s + ((swarm[p].e/100000.0)*100.0))*(1.0-(swarm[p].m/100.0));
if(d > 0.0 && swarm[p].anchored == 0)

swarm[p].x = swarm[p].x+(swarm[p].vx*(d));
swarm[p].y = swarm[p].y+(swarm[p].vy*(d));
swarm[p].z = swarm[p].z+(swarm[p].vz*(d));
swarm[p].d=swarm[p].d+d;
if(swarm[p].d > 1000.0)

swarm[p].d=0.0;
swarm[p].ox = ((float)(rand()%(1920)));
swarm[p].oy = ((float)(rand()%(1920)));
swarm[p].oz = ((float)(rand()%(1920)));
swarm[p].x = swarm[p].ox;
swarm[p].y = swarm[p].oy;
swarm[p].z = swarm[p].oz;


swarm[p].R = 1.0;
swarm[p].G = 1.0;
swarm[p].B = 1.0;


This is to count cycles and keep the display fresh.
void AnimateScene(void)cycles++;glutPostRedisplay();

Now we place the background sprites into the display array before we post the new data to the screen.
void printSwarm(double speed)
int i;
for(i=0;i
if(swarm[i].s == speed)// && swarm[i].anchored == 1

double xx = swarm[i].x-sx;
double yy = swarm[i].y-sy;
int t = ((int)xx) + ((int)yy*swidth);
if(t > 0 && t < slength)

array1d[t].R = 1.0;
array1d[t].G = 1.0;
array1d[t].B = 1.0;



Here we print the 2D objects on the foreground. We do collision here as well and when that happens the rectangles will smoothly slide out of each others way automatically.
void printSquares(double speed,double realspeed)
int i,j,k;
for(i=1;i
if(rects[i].s == speed)

if((i != focus))

if(rects[i].x+rects[i].xdir > (swidth*2.0)-rects[i].w || rects[i].x+rects[i].xdir < 0.0)

rects[i].xdir=rects[i].xdir*-1.0;

else rects[i].x=rects[i].x+rects[i].xdir;
if(rects[i].y+rects[i].ydir > sheight-rects[i].h || rects[i].y+rects[i].ydir < 0)

rects[i].ydir=rects[i].ydir*-1.0;

else rects[i].y=rects[i].y+rects[i].ydir;
int inconflict = 0;
for(j=0;j
if(j == i || (j == focus)) continue;
if(rects[j].s == speed)

if(rects[i].x < (rects[j].x+rects[j].w) && (rects[i].x+rects[i].w) > rects[j].x && rects[i].y < (rects[j].y+rects[j].h) && (rects[i].y+rects[i].h) > rects[j].y)

inconflict = j;
break;


if(inconflict > 0)

if((rects[i].w + rects[i].h) > (rects[inconflict].w + rects[inconflict].h))

if(rects[inconflict].y+(rects[inconflict].h/2) > rects[i].y+(rects[i].h/2))

if(rects[inconflict].y+1.0 < (sheight-1)-rects[inconflict].h)rects[inconflict].y=rects[inconflict].y+1.0;

else

if(rects[inconflict].y-1.0 > 1.0)rects[inconflict].y=rects[inconflict].y-1.0;

if(rects[inconflict].x+(rects[inconflict].w/2) > rects[i].x+(rects[i].w/2))

if(rects[inconflict].x+1.0 < (swidth-1)-rects[inconflict].w)rects[inconflict].x=rects[inconflict].x+1.0;

else

if(rects[inconflict].x-1.0 > 1.0)rects[inconflict].x=rects[inconflict].x-1.0;


else

if(rects[i].y+(rects[i].h/2) > rects[inconflict].y+(rects[inconflict].h/2))

if(rects[i].y+1.0 < (sheight-1)-rects[i].h)rects[i].y=rects[i].y+1.0;

else

if(rects[i].y-1.0 > 1.0)rects[i].y=rects[i].y-1.0;

if(rects[i].x+(rects[i].w/2) > rects[inconflict].x+(rects[inconflict].w/2))

if(rects[i].x+1.0 < (swidth-1)-rects[i].w)rects[i].x=rects[i].x+1.0;

else

if(rects[i].x-1.0 > 1.0)rects[i].x=rects[i].x-1.0;



if(focus != i)

double xx = rects[i].x-sx;
double yy = rects[i].y-sy;
for(j=0;j
for(k=0;k
int t = (xx+j) + (yy+k)*swidth;
if(t > 0 && t < slength)

if(xx+j > 0 && (int)(xx+j) < swidth && (int)(yy+k) > 0 && (int)(yy+k) < sheight)

if((mx > (int)xx && mx < (int)(xx+rects[i].w) && my > (int)yy && my < (int)(yy+rects[i].h)) && rects[i].s == realspeed)

array1d[t].R = 0.5+array1d[t].R*0.5;
array1d[t].G = 0.5+array1d[t].G*0.5;
array1d[t].B = 0.5+array1d[t].B*0.5;

else

if(rects[i].s == realspeed)

array1d[t].R = 0.25+array1d[t].R*0.5;
array1d[t].G = 0.25+array1d[t].G*0.5;
array1d[t].B = 0.25+array1d[t].B*0.5;

else

array1d[t].R = 0.1+array1d[t].R*0.5;
array1d[t].G = 0.1+array1d[t].G*0.5;
array1d[t].B = 0.1+array1d[t].B*0.5;



This is the core of the display cycle where we measure passage of time and apply any adjustments to objects base on that so everything appears smooth even at high resolution.

void display(void)
gettimeofday(&rNow, NULL);
timeval_subtract (&rRes,&rNow,&started);
started = rNow;
alive = (((float)rRes.tv_usec)/1000000.0);
totaltimepast = totaltimepast+alive;
if(focus > 0)
else
if(mx > 100 && mx < (int)swidth)

if(sxd==1) if((int)(sx + alive*20.0) > (swidth))sxd = 0;else sx = sx + alive*20.0;
else if(sx - alive*20.0 < 0.0)sxd = 1;else sx = sx - alive*20.0;

if(mx < 100)

sxd = 0;
if(sx - alive*20.0 < 0.0)
else sx = sx - alive*20.0;

else if(mx > (swidth-100))

sxd = 1;
if((int)(sx + alive*20.0) > (swidth))else sx = sx + alive*20.0;


int i;
for(i=0;i
if(swarm[i].s == speed)pushSprite(i,alive);


memset((unsigned char *)array1d,0,1920 * 1920 * sizeof(color_t));
int j,k;

printSwarm(speed);
printSquares(speed,speed);

if(focus > 0)

if(rects[focus].s == speed)

double xx = rects[focus].x-sx;
double yy = rects[focus].y-sy;
for(j=0;j
for(k=0;k
int t = (int)(xx+j) + (int)(yy+k)*swidth;
if(t > 0 && t < slength)

if(xx+j > 0 && (int)(xx+j) < swidth && (int)(yy+k) > 0 && (int)(yy+k) < sheight)

array1d[t].R = 1.0+array1d[t].R;
array1d[t].G = 1.0+array1d[t].G;
array1d[t].B = 1.0+array1d[t].B;


else

for(j=0;j < 300;j++)

for(k=0;k < 50;k++)

int t = (j) + (k)*swidth;
double xd = (double)j-25.0;
double yd = (double)k-25.0;
double D = sqrt(xd*xd + yd*yd);
if(D < 25.0)

array1d[t].R = 0.5;
array1d[t].G = 0.5;
array1d[t].B = 0.5;
xd = (double)mx-25.0;
yd = (double)my-25.0;
D = sqrt(xd*xd + yd*yd);
if(D < 25.0)

array1d[t].R = 1.0;
array1d[t].G = 1.0;
array1d[t].B = 1.0;


glDrawPixels(swidth, sheight, GL_RGB, GL_FLOAT, array1d);
glutSwapBuffers();


A basic thread function for whatever we might need to happen independent of the display cycle.
void *WorldTurns(void *p)

do


turns++;
//printf("Turns Cycles %d,%d\n",turns,cycles);

while(!stop);


And of course no program is possible without main. This is where the program starts and ends calling everything else. The ambient music starts playing in here and we lay the groundwork for triggered sound as well.
int main(int argc, char** argv)
lens = 50.0;speed = 10.0;
cycles = 0;mode = 0;canedit=0;
button2 = 0;
cvol = 3;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
array1d = (color_t *)malloc(1920 * 1920 * sizeof(color_t));
background = (color_t *)malloc(1920 * 1920 * sizeof(color_t));
icky_global_program_name = argv[0];
set_signal_handler();
srand ( rand()%5 );
memset((unsigned char *)background,0,1920 * 1920 * sizeof(color_t));
hasclicked = 0;
totaltimepast=0.0;
stop = 0;
mx2 = 700;
my2 = 700;
plays = 0;
canplay = 0;

srand ( time(NULL) );
int j,i;
isaudio = 1;
if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 1024 ) == -1 )

printf("Failed to open Mix_openAudio\n");
isaudio = 0;

if(isaudio)

music = Mix_LoadMUS( "song.wav" );
scratch = Mix_LoadWAV( "scratch.wav" );
high = Mix_LoadWAV( "high.wav" );
med = Mix_LoadWAV( "medium.wav" );
low = Mix_LoadWAV( "low.wav" );
if( music == NULL || ( scratch == NULL ) || ( high == NULL ) || ( med == NULL ) || ( low == NULL ) )
printf("missing music files\n");
isaudio=0;

Mix_PlayMusic( music, -1 );
Mix_VolumeMusic((MIX_MAX_VOLUME/20)*((float)cvol/4.0));

glutInit(&argc, argv);
unsigned char res[256];
memset(&res[0],'\0',256);
swidth = glutGet(GLUT_SCREEN_WIDTH);
sheight = glutGet(GLUT_SCREEN_HEIGHT);
sprintf(&res[0],"1366x768:32@60");
if(swidth == 1920)

memset(&res[0],'\0',256);
sprintf(&res[0],"1920x1080:32@60");

sxd = 1;
sx = 0.0;
sy = 0.0;
glutGameModeString( &res[0] );
if(glutGameModeGet(GLUT_GAME_MODE_POSSIBLE))

glutEnterGameMode();

else

printf("Screen resolution couldn't initalize Verboten\n");return;


swidth = glutGet(GLUT_SCREEN_WIDTH);
sheight = glutGet(GLUT_SCREEN_HEIGHT);
slength = swidth*sheight;
printf("Res: %d x %d pixels, %d x %d mm\n",glutGet(GLUT_SCREEN_WIDTH), glutGet (GLUT_SCREEN_HEIGHT), glutGet(GLUT_SCREEN_WIDTH_MM), glutGet(GLUT_SCREEN_HEIGHT_MM));
nB = 10000;
for(i=0;i
swarm[i].ox = (double)(rand()%swidth);//((double)swidth/2.0);
swarm[i].oy = ((double)sheight/2.0);
swarm[i].oz = ((double)sheight/2.0);
swarm[i].s = 10.0+(double)(rand()%20);
setSprite(i);

nrects = rand()%100;
for(i=0;i
rects[i].x = 100+(double)(rand()%(swidth-300));//((double)swidth/2.0);
rects[i].y = 100+(double)(rand()%(sheight/2));//((double)sheight/2.0);
rects[i].w = 10.0+(double)(rand()%190);//((double)swidth/2.0);
rects[i].h = 10.0+(double)(rand()%190);//((double)sheight/2.0);
rects[i].s = 10+(double)(rand()%20);
rects[i].members = 0;
rects[i].xdir = 1.0;
rects[i].ydir = 1.0;


pthread_t turnthread;
pthread_create(&turnthread, &attr, &WorldTurns, (void *)0);

glutMouseFunc(mouseClicks);
glutPassiveMotionFunc(mouseMoves);
glutMotionFunc(mouseMoves);
glutDisplayFunc(display);
glutKeyboardFunc(Keyboard);
glutIdleFunc (AnimateScene);
glutVisibilityFunc(canPlay);
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = wglGetProcAddress("wglSwapIntervalEXT");//this solves tearing issues with screen sync
wglSwapIntervalEXT(1);
glutSetWindowTitle("Recursive");
glutSetIconTitle("Recursive");
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&mutexsum,&attr);
pthread_mutex_init(&mutexsum2,&attr);
pthread_mutex_init(&mutexsum3,&attr);
pthread_mutex_init(&mutexsum4,&attr);
srand(time(NULL));

if(isaudio)

plays++;if(plays > 15)plays=0;Mix_HaltChannel( plays);Mix_Volume(plays,(MIX_MAX_VOLUME/10)*((float)cvol/4.0));Mix_PlayChannel( plays, high, 0 );

glutMainLoop();
glutLeaveGameMode();
free(array1d);
free(background);
return 0;


And that's all there is to it. Everything you need to get started is here. It's so small I don't really feel I need to go over every detail. You'll figure it out. I learned by example and so can you. I could have added a little more I suppose like how to do an HTTP request to a server, encryption, and so on but this will do for now. If you spend a day or so with this doing searches on any keywords you don't understand you'll get the hang of it.

Happy hacking!

Today's Reader List >>  |  Referral Links

It isn't easy being an independent publisher in today's economy. Our collaborators rely on your patronage to keep creating. Art is important. Literature is important. Essential even. Thank you and consider making a donation.

© Verboten Publishing Ltd. 2016-2021
Sitemap | RSS | Minds | Locals


Author
Aesh M. Daeva
Looking for the frayed edge of the Universe.
Currently worth 15 studio credits. Sign Up to earn credits reviewing member content.

Total Visits: 33 Today: 2

Related Articles
Why Artificial Intelligence Will Never, Ever Destroy The World

Game AI Isn’t True AI

Perpetual Motion Machines Aren’t Real

Coding Matters

Breaking The Monopoly With Opensource

Promoted Articles

Do you want to publish on Verboten?

Sign up for a studio account. Earn verified status by reviewing member content and soon you'll unlock access to the publishing tools.