Code: Select all
/*
gory1.c - Mountain Image Generator (15 Dec 2005 - 17 Dec 2005)
Author: Alexander Shabarshin (alexander@shabarshin.com)
http://chaos.shabarshin.com
Compilation:
gcc gory1.c -o gory1 -lSDL -ljpeg -lm
Usage:
./gory1
*/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <setjmp.h>
#include <SDL/SDL.h>
#include <jpeglib.h>
#define MAXPIX 400000
int DDX = 1024;
int DDY = 768;
int quality = 90;
int black = 0x000000;
int grey = 0x808080;
int white = 0xFFFFFF;
int red = 0xFF0000;
int green = 0x00FF00;
int blue = 0x0000FF;
SDL_Surface* screen;
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
/*
* Here's the routine that will replace the standard error_exit method:
*/
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
int putpixel(int x, int y, int c)
{
int *bits;
SDL_Surface* s;
if(x<0 || x>=DDX || y<0 || y>=DDY) return 0;
s = screen;
if(SDL_MUSTLOCK(s) && SDL_LockSurface(s)<0) return 0;
bits = (int*)(&((unsigned char*)s->pixels)[y*s->pitch+x*4]);
*bits = c;
if(SDL_MUSTLOCK(s)) SDL_UnlockSurface(s);
return 1;
}
int getpixel(int x, int y)
{
int *bits,c;
SDL_Surface* s;
if(x<0 || x>=DDX || y<0 || y>=DDY) return 0;
s = screen;
if(SDL_MUSTLOCK(s) && SDL_LockSurface(s)<0) return 0;
bits = (int*)(&((unsigned char*)s->pixels)[y*s->pitch+x*4]);
c = *bits;
if(SDL_MUSTLOCK(s)) SDL_UnlockSurface(s);
return c;
}
void drawbar(int x, int y, int w, int h, int c)
{
int i,j;
for(j=y;j<y+h;j++)
{
if(j<0) continue;
if(j>=DDY) break;
for(i=x;i<x+w;i++)
{
if(i<0) continue;
if(i>=DDX) break;
putpixel(i,j,c);
}
}
}
void drawhline(int x, int y, int l, int c)
{
int i;
/* printf("drawhline(%i,%i,%i,%i)\n",x,y,l,c); */
for(i=0;i<l;i++) putpixel(x+i,y,c);
}
void drawvline(int x, int y, int l, int c)
{
int j;
/* printf("drawvline(%i,%i,%i,%i)\n",x,y,l,c); */
for(j=0;j<l;j++) putpixel(x,y+j,c);
}
void drawrect(int x, int y, int w, int h, int c)
{
drawhline(x,y,w,c);
drawhline(x,y+h-1,w,c);
drawvline(x,y,h,c);
drawvline(x+w-1,y,h,c);
}
void drawline(int x, int y, int vx, int vy, int c)
{
int ax,ay,n=0;
long xlong,ylong,xxlong,yylong,hstep,vstep,l;
if(vy==0)
{
if(vx>0) drawhline(x,y,vx,c);
else drawhline(x+vx,y,-vx,c);
return;
}
if(vx==0)
{
if(vy>0) drawvline(x,y,vy,c);
else drawvline(x,y+vy,-vy,c);
return;
}
if(vx>0) ax=vx;
else ax=-vx;
if(vy>0) ay=vy;
else ay=-vy;
if(ax<=1 && ay<=1)
{
putpixel(x,y,c);
return;
}
if(ax>ay)
l=ax<<1;
else l=ay<<1;
xlong = ((long)x)<<16;
ylong = ((long)y)<<16;
xxlong = ((long)(x+vx))<<16;
yylong = ((long)(y+vy))<<16;
hstep = (vx<<16)/l;
vstep = (vy<<16)/l;
/*
printf("\ndrawline(%i,%i,%i,%i,0x%8.8X)\n",x,y,vx,vy,c);
printf("xlong=0x%8.8X\n",xlong);
printf("ylong=0x%8.8X\n",ylong);
printf("xxlong=0x%8.8X (%i)\n",xxlong,xxlong>>16);
printf("yylong=0x%8.8X (%i)\n",yylong,yylong>>16);
printf("hstep=0x%8.8X\n",hstep);
printf("vstep=0x%8.8X\n",vstep);
*/
while(1)
{ if(n++>=1000) break;
putpixel(xlong>>16,ylong>>16,c);
xlong += hstep;
ylong += vstep;
/*
printf("%i) xlong=0x%8.8X (%i)\n",n,xlong,xlong>>16);
printf("%i) ylong=0x%8.8X (%i)\n",n,ylong,ylong>>16);
*/
if(abs((xlong&0xFFFF0000)-xxlong)<=0x10000 &&
abs((ylong&0xFFFF0000)-yylong)<=0x10000
) break;
}
}
void line(int x1, int y1, int x2, int y2, int c)
{
drawline(x1,y1,x2-x1,y2-y1,c);
}
typedef struct _pixel
{
short x,y,z;
} pixel;
typedef struct _triangle
{
short l,t,r;
} triangle;
triangle *tri;
pixel *pix;
int mtri,ntri,npix;
void drawtri(int t, int x, int y, int c)
{
int x1,x2,x3,y1,y2,y3,z1,z2,z3;
int i,k1,k2,ax[3],ay[3],xmin,ymin,xmax,ymax,yy,i1,i2,num;
float fx1,fx2,tmp,dx1,dx2;
long a1,a2,a3,a4,a5,a6,vx,vy,vz,cc;
pixel *pl,*pt,*pr;
triangle *tr;
tr = &tri[t];
pl = &pix[tr->l];
pt = &pix[tr->t];
pr = &pix[tr->r];
z1 = pl->z;
y1 = pl->y + y - z1;
x1 = pl->x + x;
z2 = pt->z;
y2 = pt->y + y - z2;
x2 = pt->x + x;
z3 = pr->z;
y3 = pr->y + y - z3;
x3 = pr->x + x;
if(c>=0)
{
line(x1,y1,x2,y2,c);
line(x2,y2,x3,y3,c);
line(x3,y3,x1,y1,c);
}
else
{
num = 3;
if(pt->y < pl->y)
{
a1 = pl->x - pt->x;
a2 = pl->y - pt->y;
a3 = pl->z - pt->z;
a4 = pr->x - pt->x;
a5 = pr->y - pt->y;
a6 = pr->z - pt->z;
ax[0] = x1;
ax[1] = x3;
ax[2] = x2;
ay[0] = y1;
ay[1] = y3;
ay[2] = y2;
}
else
{
a1 = pr->x - pt->x;
a2 = pr->y - pt->y;
a3 = pr->z - pt->z;
a4 = pl->x - pt->x;
a5 = pl->y - pt->y;
a6 = pl->z - pt->z;
ax[0] = x1;
ax[1] = x2;
ax[2] = x3;
ay[0] = y1;
ay[1] = y2;
ay[2] = y3;
}
vx = a2*a6 - a3*a5;
vy = a3*a4 - a1*a6;
vz = a1*a5 - a2*a4;
cc = acos(vx/sqrt(vx*vx+vy*vy+vz*vz))*128/3.14159;
cc = cc|(cc<<8)|(cc<<16);
xmin = 10000;
ymin = 10000;
xmax = -10000;
ymax = -10000;
for(i=0;i<num;i++)
{
if(ax[i]<xmin){xmin=ax[i];}
if(ay[i]<ymin){ymin=ay[i];k1=i;}
if(ax[i]>xmax){xmax=ax[i];}
if(ay[i]>ymax){ymax=ay[i];k2=i;}
}
yy = ay[k1];
i1 = i2 = k1;
// putpixel(ax[k1],yy,cc);
while(1)
{
if(yy==ay[k2]) break;
if(ay[i1]==yy)
{
fx1 = ax[i1];
y1 = ay[i1];
if(++i1>=num) i1=0;
tmp = ay[i1]-y1;
if(tmp==0) continue;
dx1 = (ax[i1]-fx1)/tmp;
}
if(ay[i2]==yy)
{
fx2 = ax[i2];
y2 = ay[i2];
if(--i2<0) i2=num-1;
tmp = ay[i2]-y2;
if(tmp==0) continue;
dx2 = (ax[i2]-fx2)/tmp;
}
yy++;
drawhline((int)fx1,yy,(int)(fx2-fx1+1),cc);
fx1+=dx1;
fx2+=dx2;
}
}
}
void gentri(int m,int n)
{
int i,j,hh,h2;
for(i=m;i<n;i++)
{
hh = (pix[tri[i].r].x - pix[tri[i].l].x)/3;
h2 = hh/3;
pix[npix].x = (pix[tri[i].t].x + pix[tri[i].l].x) >> 1;
pix[npix].y = (pix[tri[i].t].y + pix[tri[i].l].y) >> 1;
for(j=0;j<npix;j++)
{
if(pix[j].x==pix[npix].x && pix[j].y==pix[npix].y)
{
pix[npix].z = pix[j].z;
break;
}
}
if(j==npix)
pix[npix].z = ((pix[tri[i].t].z + pix[tri[i].l].z) >> 1) - h2 + (rand()%hh);
npix++;
pix[npix].x = (pix[tri[i].r].x + pix[tri[i].t].x) >> 1;
pix[npix].y = (pix[tri[i].r].y + pix[tri[i].t].y) >> 1;
for(j=0;j<npix;j++)
{
if(pix[j].x==pix[npix].x && pix[j].y==pix[npix].y)
{
pix[npix].z = pix[j].z;
break;
}
}
if(j==npix)
pix[npix].z = ((pix[tri[i].r].z + pix[tri[i].t].z) >> 1) - h2 + (rand()%hh);
npix++;
pix[npix].x = (pix[tri[i].r].x + pix[tri[i].l].x) >> 1;
pix[npix].y = (pix[tri[i].r].y + pix[tri[i].l].y) >> 1;
for(j=0;j<npix;j++)
{
if(pix[j].x==pix[npix].x && pix[j].y==pix[npix].y)
{
pix[npix].z = pix[j].z;
break;
}
}
if(j==npix)
pix[npix].z = ((pix[tri[i].r].z + pix[tri[i].l].z) >> 1) - h2 + (rand()%hh);
npix++;
tri[ntri].l = npix - 3;
tri[ntri].t = tri[i].t;
tri[ntri].r = npix - 2;
ntri++;
tri[ntri].l = tri[i].l;
tri[ntri].t = npix - 3;
tri[ntri].r = npix - 1;
ntri++;
tri[ntri].l = npix - 3;
tri[ntri].t = npix - 1;
tri[ntri].r = npix - 2;
ntri++;
tri[ntri].l = npix - 1;
tri[ntri].t = npix - 2;
tri[ntri].r = tri[i].r;
ntri++;
}
}
void sortri(int m,int n)
{
int i,y1,y2,l,t,r,k=1;
while(k)
{
k = 0;
for(i=m;i<n-1;i++)
{
if(pix[tri[i].t].y < pix[tri[i].l].y) y1=pix[tri[i].t].y;
else y1=pix[tri[i].l].y;
if(pix[tri[i+1].t].y < pix[tri[i+1].l].y) y2=pix[tri[i+1].t].y;
else y2=pix[tri[i+1].l].y;
if(y2<y1)
{
k = 1;
l = tri[i].l;
t = tri[i].t;
r = tri[i].r;
tri[i].l = tri[i+1].l;
tri[i].t = tri[i+1].t;
tri[i].r = tri[i+1].r;
tri[i+1].l = l;
tri[i+1].t = t;
tri[i+1].r = r;
}
}
}
}
int main(int argc,char **argv)
{
char imagefile[32];
unsigned char *keys,*image_buffer;
SDL_Color color;
SDL_Event event;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
int image_height; /* Number of rows in image */
int image_width; /* Number of columns in image */
int number = 0;
int done = 0;
int i,j,k;
int x,y,z;
int dx,dy,x0,y0,w,w2,h;
srand((unsigned int)time(NULL));
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)<0)
{
printf("Unable to initialise SDL: %s\n",SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
screen = SDL_SetVideoMode(DDX,DDY,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
if(screen==NULL)
{
printf("Unable to set video: %s\n", SDL_GetError());
exit(1);
}
dx = DDX>>1;
dy = DDY>>1;
x0 = 20;
w = dx-(x0<<1);
w2 = w>>1;
h = ((long)w2*56759)>>16;
y0 = (dy-h)>>1;
tri = (triangle*)malloc(MAXPIX*sizeof(triangle));
pix = (pixel*)malloc(MAXPIX*sizeof(pixel));
if(tri==NULL||pix==NULL) return 0;
mtri = 0;
ntri = 1;
npix = 3;
pix[0].x = x0;
pix[0].y = y0+h;
pix[0].z = 0;
pix[1].x = x0+w2;
pix[1].y = y0;
pix[1].z = 0;
pix[2].x = x0+w;
pix[2].y = y0+h;
pix[2].z = 0;
tri[0].l = 0;
tri[0].t = 1;
tri[0].r = 2;
while(1)
{
if(ntri*16>MAXPIX) break;
if(done==2) break;
drawbar(0,0,DDX,DDY,0x000000);
drawrect(0,0,dx,dy,grey);
drawrect(dx,0,dx,dy,grey);
drawrect(0,dy,dx,dy,grey);
drawrect(dx,dy,dx,dy,grey);
printf("m=%i n=%i\n",mtri,ntri);
for(i=mtri;i<ntri;i++) drawtri(i,0,0,white);
sortri(mtri,ntri);
for(i=mtri;i<ntri;i++) drawtri(i,dx,0,-1);
k = ntri;
gentri(mtri,ntri);
mtri = k;
printf("m=%i n=%i\n",mtri,ntri);
for(i=mtri;i<ntri;i++) drawtri(i,0,dy,white);
sortri(mtri,ntri);
for(i=mtri;i<ntri;i++) drawtri(i,dx,dy,-1);
k = ntri;
gentri(mtri,ntri);
mtri = k;
SDL_Flip(screen);
done = 0;
while(!done)
{while(SDL_PollEvent(&event))
{if(event.type == SDL_QUIT) done=2;
if(event.type == SDL_KEYDOWN)
{if(event.key.keysym.sym == SDLK_ESCAPE) done=2;
if(event.key.keysym.sym == SDLK_SPACE) done=1;
}
}
}
// if(done==2) break;
/* <><><><><><><><><><> JPEG <><><><><><><><><><><> */
sprintf(imagefile,"gory1_%i.jpeg",++number);
printf("Save '%s'\n",imagefile);
image_width = DDX;
image_height = DDY;
image_buffer = (unsigned char*)malloc(DDX*3);
if(image_buffer==NULL) return 0;
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
* stdio stream. You can also write your own code to do something else.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to write binary files.
*/
if ((outfile = fopen(imagefile, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", imagefile);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = image_width; /* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */ );
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
y = 0;
while (cinfo.next_scanline < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
i = 0;
for(x=0;x<DDX;x++){
k = getpixel(x,y);
image_buffer[i++] = (k>>16)&255;
image_buffer[i++] = (k>>8)&255;
image_buffer[i++] = k&255;
}
y++;
row_pointer[0] = (JSAMPLE*)image_buffer;
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
/* And we're done! */
free(image_buffer);
}
free(tri);
free(pix);
return 1;
}