|
25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more... |
Home Projects Up Sitemap Search Blog Forum+Chat About Us Privacy Terms of Use Feedback FAQ Images Services Ads Donate Humor |
|
|
.PIC graphics experiments: display, edit, transform, rotateBorland C++ 4.0 for MSDOS experiments with graphics files in .PIC format. They are crude attempts at animation, rotation, etc. These are C++ conversions of the DeSmet C programs in the vintage computing section. They were developed on a Heathkit H-100 computer, on which their development was more interesting than they are on a modern PC. Click here to download picfiles.zip (24 KB). The zip file contains the following files. All the programs are also listed on this page.
|
|
/* dispic.cpp 12-18-96
Copyright (C)1996 Steven Whitney.
Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
Retrieves and displays a single .PIC file. (This was previously called dispsing.c)
Supply input file name on command line.
*/
#include <graphics.h>
#include "c:\bcs\my.h"
#pragma hdrstop
#include "c:\bcs\mylib.cpp"
//////////////////////////////////////////////////////////////////////////////
int main(int argc,char **argv)
{
cerr << "Usage: DISPIC filename.ext [pause]" << endl;
cerr << "Displays a graphics file saved in .PIC format." << endl;
cerr << "If [pause] is nonblank, title displays only after a key is pressed." << endl;
cerr << "While drawing, ESC stops loading the file," << endl;
cerr << "or ^C stops loading and also stops any running batch file." << endl;
if(argc < 2)
return(1);
initgraf();
picload(argv[1]);
if(argc > 2) // wait, to allow screen capture without title, for example
getch();
setfillstyle(SOLID_FILL,BLACK); // clear a text box
int boxtop = getmaxy()-textheight("H"); // so file name shows up
bar(0,boxtop,textwidth(argv[1]),getmaxy());
setcolor(WHITE);
outtextxy(0,boxtop,argv[1]);
getch(); // wait for a character to quit
closegraph();
return(0);
}
/* animapic.cpp 3-10-96
Copyright (C)1993-96 Steven Whitney.
Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
Retrieves and displays consecutive .PIC files without a pause between.
This worked quite well on the Heathkit H-100 computer with its optimized zedload() function,
but picload() used here is too slow to be effective.
*/
#include <graphics.h>
#include "c:\bcs\my.h"
#pragma hdrstop
#include "c:\bcs\mylib.cpp"
//////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
cout << "Usage: ANIMAPIC filename.ext\n";
cout << "Displays .PIC files to the screen consecutively, with no pauses.\n";
cout << "filename.ext must contain list of files to display, one per line.\n";
if(argc < 2)
return(1);
ifstream masterfile(argv[1]);
if(!masterfile)
cout << "File not found.\n";
else
{
initgraf();
string filename;
while(getline(masterfile,filename,'\n'))
picload(filename.c_str()); // load new page
closegraph();
}
return(0);
}
/* EDITPIC.CPP 6-25-97
Copyright (C)1993-97 Steven Whitney.
Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
GRAPHICS SCREEN EDITOR for .PIC files.
This is a Borland C++ 4.0 MSDOS conversion of the graphics editor I wrote
for the Heathkit H-100 computer. Not all features have been converted, but it is functional
enough to create environments for a graphics robot if the robot.cpp project ever goes to a
graphical rather than text environment.
TO DO:
6-25-97, misc. tinkering was done; untested.
must determine how many scan lines is 1 line of text & use exactly that, not 16.
important only for getting text, case 't'.
try saving entire screen to an array (for multiple pages) (large model, 300k+)
add color at (x,y) to status line display
------------------
NOTES:
--This isn't much use anymore. If you really need a .pic file, create it as a .bmp
and then use SDib to save it as .pic.
*/
#define USEPAINT 0 // can't enable it until converted (low priority)
#include <math.h>
#include <graphics.h>
#include "c:\bcs\my.h"
#pragma hdrstop
#include "c:\bcs\mylib.cpp"
#if(USEPAINT)
#include <c:\bcs\paint.c>
#endif
//////////////////////////////////////////////////////////////////////////////
// GLOBAL DATA
char gbuf[640 * 17]; // HOLDS GRAPHICS CONTENTS OF line 1 (top 16 scan lines + safety)
struct areadesc // DESCRIPTION OF AREA OF SCREEN STORED TO BUFFER
{
char *address; // POINTER TO START OF ALLOCATED CHAR ARRAY
int xspan; // X AXIS (WIDTH), IN PIXELS
int yspan; // Y AXIS (HEIGHT), IN PIXELS
} area;
//----------------------------------------------------------------------------
// save graphics contents of line 1 to buffer so line can be used for text
void saveline1()
{
char *bufptr = gbuf; // set secondary buf pointer
for(int y = 0 ; y < 16 ; y++) // top scan lines
for(int x = 0 ; x < 640 ; x++)
*(bufptr++) = (char)getpixel(x,y); // save the (int) color as a char
}
//----------------------------------------------------------------------------
// restore line 1 graphics contents previously saved with saveline1()
void putline1()
{
char *bufptr = gbuf; // set secondary buf pointer
for(int y = 0 ; y < 16 ; y++) // top scan lines
for(int x = 0 ; x < 640 ; x++)
putpixel(x,y,*(bufptr++));
}
//----------------------------------------------------------------------------
// erase line 1 so text will show up, and pre-position cursor at upper left
void eraseline1(int backgroundcolor = BLACK)
{
setfillstyle(SOLID_FILL,backgroundcolor);
bar(0,0,639,15);
gotoxy(1,1); // seems to work in graphics mode
}
//----------------------------------------------------------------------------
// GETS INPUT FILE NAME FROM USER
void inpnam(char *fnam)
{
printf("File name (include .PIC) (CR=quit): "); // CURSOR ON
scanf("%50s",fnam);
strupr(fnam); // TO UPPER FOR LATER DISPLAY
}
//----------------------------------------------------------------------------
// SAVES AREA OF SCREEN TO MEMORY FOR RELOCATION
// EACH PIXEL's color value IS SAVED AS A BYTE (used as a short int) IN A CHAR ARRAY.
// WASTEFUL OF MEMORY, BUT IT WORKS
// RETURNS TRUE IF SUCCEED, FALSE IF OFFSCREEN OR TOO LARGE TO STORE
int getarea(int x1, int y1, int x2, int y2)
{
int i, j; // COUNTERS
char *p; // POINTER INTO ALLOCATED ARRAY
if((x1 < 0) || (x1 > 639) || (x2 < 0) || (x2 > 639)) return(FALSE);
if((y1 < 0) || (y1 > 479) || (y2 < 0) || (y2 > 479)) return(FALSE);
if(area.address) // IF BUFFER ALREADY IN USE,
free(area.address); // FREE IT FOR REUSE
if(y1 > y2) {i = y1; y1 = y2; y2 = i;} // Y1 = LOW, Y2 = HIGH
if(x1 > x2) {i = x1; x1 = x2; x2 = i;} // X1 = LOW, X2 = HIGH
area.yspan = y2 - y1 + 1; // AREA HEIGHT
area.xspan = x2 - x1 + 1; // AREA WIDTH
if(((long)(area.xspan) * (long)(area.yspan)) > 65535L)
return(FALSE);
if(!(area.address = (char *)malloc(area.yspan * area.xspan)))
return(FALSE);
p = area.address;
for(i = y1 ; i <= y2 ; i++)
for(j = x1 ; j <= x2 ; j++)
*(p++) = (char)getpixel(j,i);
return(TRUE);
}
//----------------------------------------------------------------------------
// COPIES AREA FROM MEMORY TO SCREEN DISPLAY
// returns TRUE if successful, FALSE if not
// 12-25-93 ok if area runs off screen edges
int putarea(int x0, int y0) // UPPER LEFT CORNER OF WHERE TO PLACE AREA
{ // not used yet with borland
char *p = area.address;
if(!p) // NOTHING THERE TO PUT
return(FALSE);
int highx = x0 + area.xspan;
int highy = y0 + area.yspan;
for(int y = y0 ; y < highy ; y++)
for(int x = x0 ; x < highx ; x++)
putpixel(x,y,(int)(*(p++)));
return(TRUE);
}
//----------------------------------------------------------------------------
// writes graphics area to disk in format:
// width,height\n, then a series of (width*height) chars:
// color at x1,y1, color at x2,y1, etc. (x varies fastest)
// chars are numeric 0-7, could easily be ascii '0'-'7'
// undecided which is best. text editor could edit ascii file
// returns TRUE if successful, FALSE if not
int writearea(char *filename)
{
char *p = area.address; // 2nd pointer to area chars
if(!p) // NOTHING THERE TO write
return(FALSE);
ofstream outfile(filename,ios::binary); // binary, must only write \n, not /r/n
outfile << area.xspan << "," << area.yspan << endl;
unsigned charcount = (area.xspan) * (area.yspan); // limits file size to 65535, 1 fwrite chunk
outfile.write(p,charcount);
return(TRUE);
}
//----------------------------------------------------------------------------
// reads graphics area from disk
// returns TRUE if succeed, FALSE if fail
int readarea(char *filename)
{
if(area.address) // IF BUFFER ALREADY IN USE,
free(area.address); // FREE IT FOR REUSE
int width, height;
ifstream infile(filename,ios::binary);
if(!infile)
return(FALSE);
infile >> width;
infile.ignore(1); // the comma
infile >> height;
infile.ignore(1); // the \n
area.xspan = width;
area.yspan = height;
if(((long)(area.xspan) * (long)(area.yspan)) > 65535L)
return(FALSE);
unsigned i = (area.xspan) * (area.yspan);
if(!(area.address = (char *)malloc(i)))
return(FALSE);
infile.read(area.address,i);
return(TRUE);
}
//----------------------------------------------------------------------------
// blinks the "+" cursor on/off
void curblink(int x, int y)
{
// there is no XOR mode for putpixel()
// must create the "+" shape, then use putimage() getimage
// or use a single dot for the cursor, using XOR or an equivalent so it always shows up
static int oldcolor = 0;
static int state = OFF;
state = !state;
if(state) // if we're turning the cursor ON
{
oldcolor = getpixel(x,y); // save previous color
putpixel(x,y,oldcolor ? BLACK : WHITE); // and place the cursor as a (negative) dot
}
else // if we're turning the cursor OFF,
putpixel(x,y,oldcolor); // restore the previous color
}
//----------------------------------------------------------------------------
// displays help screen
void drawhelp()
{
printf("Keypad: 1-4,6-9 Move Cursor INS double cursor step \n");
printf(" 5 Toggle Draw/Move DEL 1/2 cursor step \n");
printf(" ^5 center screen CTL-ARROWS move 1 dot U (Undo)=Load SCREEN.PIC\n");
printf(" SHIFT-HOME top left SHIFT+1379 to edges # Toggle AUTOZEDSAVE\n");
printf("\n");
printf("Keyboard: 0-9 Set Color = GOTO new xy H HELP Q QUIT program\n");
printf("B BOX xy - x1y1 ! AREA SAVE S STATUS of variables\n");
printf("F FILL box xy - x1y1 @ AREA PUT F2 PUT Mode ESC SAVE xy as x1y1\n");
printf("L LINE xy - x1y1 | Set Paint BORDER G GET disk file\n");
printf("C CIRCLE x1y1 to xy P PAINT area Z .PIC screen save\n");
printf("\n");
printf("F1 Save X for OVAL - Darken by 1 color \n");
printf("ESC Save Y for OVAL + Lighten by 1 color \n");
printf("O Draw OVAL E Enhance contrast * Clear screen\n");
printf(" \n");
printf("\n");
printf("^T Change TEXT fore/back colors \n");
printf("T Enter TEXT to SAVE buffer\n");
printf("F3 Save graphics area to disk F4 Read graphics area from disk\n");
printf("\n");
printf("0:BLACK 1:LIGHTBLUE 2:LIGHTRED 3:LIGHTMAGENTA 4:LIGHTGREEN 5:LIGHTCYAN\n");
printf("6:YELLOW 7:WHITE 8:BROWN 9:LIGHTGRAY");
printf("\n");
printf("Press any key to return to edit screen...");
}
//----------------------------------------------------------------------------
#if(USEPAINT)
//----------------------------------------------------------------------------
// execute paint command. IF paint FAILS, IT JUST LEAVES SOME UNPAINTED
void dopaint(int x, int y, char *border)
{
int ch;
char buf[40];
static char paintcolors[40]; // colors to paint with
static int tile = TRUE; // whether to use regular paint tiling
// if false, random spray painting is used
saveline1();
do
{
eraseline1();
printf("Paint color(s) to use or CR for <%s>: ",paintcolors);
gets(buf);
if(strlen(buf))
strcpy(paintcolors,buf);
}
while(!strlen(paintcolors)); // there must be something in paintcolors
eraseline1();
printf("<T>ile or <S>pray, CR for %s: ",tile?"<TILE>":"<SPRAY>");
ch = tolower((char)getche());
if(ch == 't') tile = TRUE;
if(ch == 's') tile = FALSE;
putline1();
if(!paint(x,y,paintcolors,border,tile))
putline1(); // overwrite paint's error msg
}
//----------------------------------------------------------------------------
#endif
//----------------------------------------------------------------------------
// handles contrast commands: +, -, enhance
void adjustcolor(int x, int y, int x1, int y1, int mode)
{
int i, j, colorfound;
switch(mode)
{
case '-': // REDUCE ALL COLORS BY 1
for(j = y1 ; j <= y ; j++)
{
for(i = x1 ; i <= x ; i++)
{
colorfound = getpixel(i,j);
putpixel(i,j,max(colorfound-1,0));
}
if(csts())
if(tolower(ci()) == 3)
break;
}
break;
case '+': // INCREASE ALL COLORS BY 1
for(j = y1 ; j <= y ; j++)
{
for(i = x1 ; i <= x ; i++)
{
colorfound = getpixel(i,j);
putpixel(i,j,min(colorfound+1,getmaxcolor()));
}
if(csts())
if(tolower(ci()) == 3)
break;
}
break;
case 'e': // ENHANCE CONTRAST
for(j = y1 ; j <= y ; j++)
{
for(i = x1 ; i <= x ; i++)
{
colorfound = getpixel(i,j);
if(colorfound > 4) // LEAVES GREEN UNCHANGED
putpixel(i,j,min(colorfound+1,7));
else
if(colorfound < 4)
putpixel(i,j,max(colorfound-1,0));
}
if(csts())
if(tolower(ci()) == 3)
break;
}
break;
} // end switch
} // end adjustcolor
//----------------------------------------------------------------------------
// adjust xstep, ystep
void setsteps(int *xstep, int *ystep)
{
char buf[20];
saveline1();
eraseline1();
printf("Enter XSTEP YSTEP or CR for no change: ");
gets(buf);
if(strlen(buf))
{
sscanf(buf,"%d %d",xstep,ystep); // already pointers
// *ystep = (int)((double)(*ystep) * 0.48046875 + .5); // factor maybe H100 specific
}
putline1();
}
//----------------------------------------------------------------------------
// main()
int main(int argc, char **argv)
{
int ch, ch2; // USER INPUT
char fnam[51]; // HOLDS FILE NAMES
int foreground, background; // FOREGROUND, BACKGROUND TEXT COLORS
char border[40]; // BORDER string FOR PAINT COMMAND
int i, j, k; // COUNTERS
int x, y; // COORDINATES OF CURRENT CURSOR LOCATION
int x1, y1; // 1ST SET OF SAVED COORDINATES
int x2, y2; // USED FOR DRAWING AFTER CURSOR MOVEMENT
int x3, y3; // USED FOR DRAWING OVALS
int draw = FALSE; // MODE: CURSOR DRAWS OR JUST MOVES
int autosave = FALSE; // WHETHER TO ZEDSAVE() BEFORE EACH ACTION
// (ALLOWS ANY CHANGE TO BE UNDONE)
int xstep, ystep; // DISTANCE CURSOR MOVES WITH EACH STEP
int color = 15; // COLOR TO DRAW IN
int psetmode = 'p'; // X,P,O = PSET MODE, not used
int radius; // RADIUS OF CIRCLE TO DRAW
double xrange, yrange; // USED IN DRAWING CIRCLE
int grmode; // graphics mode, VGAHI
drawhelp(); // CREATE HELP SCREEN
getch(); // THIS IS THE 'ANY CHAR' DRAWHELP ASKS FOR
grmode = initgraf();
x1 = y1 = x2 = y2 = x3 = y3 = 0;
strcpy(border,"0"); // initial border is black
area.address = 0; // 0 INDICATES THAT IT HASN'T BEEN USED YET
xstep = 16;
ystep = 16; // on VGAHI, works fine when equal
// ystep = (int)((double)xstep * 0.48046875 + .5); // H100 specific: adjust to same length
x = getmaxx()/2;
y = getmaxy()/2;
setcolor(color);
setfillstyle(SOLID_FILL,color);
if(argc > 1) // EDIT FILENAME NOW ALLOWED
picload(argv[1]);
curblink(x,y); // turn cursor ON
while(1) // DO FOREVER. EXIT IS IN LOOP
{
ch = ci(); // wait for user input, ci() returns lowercase
curblink(x,y); // turn cursor off during any activity
if((autosave) && (ch != 'u')) // ALLOW LAST ACTION TO BE UNDONE
if(!picsave("screen.pic"))
printf("\007"); // WARN OF FAILURE
switch(ch)
{
// the lines previously were drawn from one coordinate +/- 1, depending on draw direction.
// Removed by mistake. It prevented the cursor from being overwritten.
// 12/24/2006 I think that note meant that the +/-1 calculation should be restored here.
// Refer to the H-100 version.
// KEYPAD (numlock off) USED AS ARROW KEYS
case(UP): // 8 up
case 18: // ^R
x2 = x; y2 = y;
y -= ystep;
if(draw)
line(x,y,x2,y2);
break;
case(DOWN): // 2 down
case 3: // ^C
x2 = x; y2 = y;
y += ystep;
if(draw)
line(x,y,x2,y2);
break;
case(RIGHT): // 6 right
case 6: // ^F
x2 = x; y2 = y;
x += xstep;
if(draw)
line(x,y,x2,y2);
break;
case(LEFT): // 4 left
case 1: // ^A
x2 = x; y2 = y;
x -= xstep;
if(draw)
line(x,y,x2,y2);
break;
case(PGDN): // 3 down-right
x2 = x; y2 = y;
x += xstep;
y += ystep;
if(draw)
line(x,y,x2,y2);
break;
case(HOME): // 7 up-left
x2 = x; y2 = y;
x -= xstep;
y -= ystep;
if(draw)
line(x,y,x2,y2);
break;
case(PGUP): // 9 up-right
x2 = x; y2 = y;
x += xstep;
y -= ystep;
if(draw)
line(x,y,x2,y2);
break;
case(END): // 1 down-left
x2 = x; y2 = y;
x -= xstep;
y += ystep;
if(draw)
line(x,y,x2,y2);
break;
// CONTROL-ARROW KEYS STEP 1 DOT
// BUT DON'T CHANGE THE STEP
case(CUP): // UP
case 5: // ^E
x2 = x; y2 = y;
y--;
if(draw)
putpixel(x,y,color);
break;
case(CDOWN): // DOWN
case 24: // ^X
x2 = x; y2 = y;
y++;
if(draw)
putpixel(x,y,color);
break;
case(CRIGHT): // RIGHT
case 4: // ^D
x2 = x; y2 = y;
x++;
if(draw)
putpixel(x,y,color);
break;
case(CLEFT): // LEFT
case 19: // ^S
x2 = x; y2 = y;
x--;
if(draw)
putpixel(x,y,color);
break;
// These would be a good use for the center keypad,
// but it isn't supported by ci() at this time. See my.h.
// control- ARROWS MOVE TO SCREEN EDGES
case(CHOME): // CENTER LEFT EDGE
x2 = x; y2 = y;
x = 0; y = getmaxy()/2;
if(draw)
line(x,y,x2,y2);
break;
case(CPGUP): // CENTER RIGHT EDGE
x2 = x; y2 = y;
x = getmaxx(); y = getmaxy()/2;
if(draw)
line(x,y,x2,y2);
break;
case(CEND): // CENTER BOTTOM EDGE
x2 = x; y2 = y;
x = getmaxx()/2; y = getmaxy();
if(draw)
line(x,y,x2,y2);
break;
case(CPGDN): // CENTER TOP EDGE
x2 = x; y2 = y;
x = getmaxx()/2; y = 0;
if(draw)
line(x,y,x2,y2);
break;
case(INS): // KEYPAD PERIOD DOUBLES STEPs
xstep *= 2;
ystep *= 2;
break;
case(DEL): // KEYPAD MINUS HALVES STEPs
xstep = max(((xstep + 1)/ 2),1); // rounded
ystep = max(((ystep + 1)/ 2),1);
break;
case(13): // specify xstep, ystep
setsteps(&xstep,&ystep);
break;
case(CFIVE): // control-FIVE GOES TO CENTER OF SCREEN
x2 = x; y2 = y;
x = getmaxx()/2; y = getmaxy()/2;
if(draw)
line(x,y,x2,y2);
break;
// KEYBOARD NUMBERS CHANGE COLOR
// should be changed to allow colors up to 15.
// current lazy way: redefine so only most useful colors are available:
// also uses the old H100 color numbers
case '0': setcolor(color = BLACK); setfillstyle(SOLID_FILL,color); break;
case '1': setcolor(color = LIGHTBLUE); setfillstyle(SOLID_FILL,color); break;
case '2': setcolor(color = LIGHTRED); setfillstyle(SOLID_FILL,color); break;
case '3': setcolor(color = LIGHTMAGENTA); setfillstyle(SOLID_FILL,color); break;
case '4': setcolor(color = LIGHTGREEN); setfillstyle(SOLID_FILL,color); break;
case '5': setcolor(color = LIGHTCYAN); setfillstyle(SOLID_FILL,color); break;
case '6': setcolor(color = YELLOW); setfillstyle(SOLID_FILL,color); break;
case '7': setcolor(color = WHITE); setfillstyle(SOLID_FILL,color); break;
case '8': setcolor(color = BROWN); setfillstyle(SOLID_FILL,color); break;
case '9': setcolor(color = LIGHTGRAY); setfillstyle(SOLID_FILL,color); break;
// maybe change this to goto x1,y1
case '=': // = EQUALS MEANS GOTO X Y
saveline1(); // seldom used
x2 = x; y2 = y;
do
{
eraseline1();
printf("GOTO: Enter x y (space between): ");
}
while(scanf("%d %d",&x,&y) != 2);
putline1();
if(draw)
line(x,y,x2,y2);
break;
case 27: // ESCAPE: SAVE COORDINATES
x1 = x;
y1 = y;
break;
case 'l': // DRAW LINE FROM SAVED POINT
line(x1,y1,x,y); // TO CURSOR
break;
case 'b': // DRAW A BOX
rectangle(x1,y1,x,y);
break;
case 'f': // FILL A BOX WITH A COLOR
bar(x1,y1,x,y);
break;
case 'c': // DRAW CIRCLE CENTERED AT CURSOR
xrange = (double)(x1 - x); // RADIUS = CURSOR TO X1Y1
yrange = (double)(y1 - y);
// yrange = 2.081300813 * (double)(y1 - y); // 1./.48046875 old H100 scaling?
radius = (int)(sqrt(xrange * xrange + yrange * yrange) + .5);
circle(x,y,radius);
break;
case 'o': // DRAW OVAL
xrange = (double)(abs(x3 - x));
yrange = (double)(abs(y1 - y));
ellipse(x,y,0,360,(int)xrange,(int)yrange);
break;
case(F1): // FUNCTION KEY F1 SAVES X3Y3
x3 = x; y3 = y;
break;
case(FIVE): // KEYPAD 5 TOGGLES DRAW/MOVE MODE
draw = !draw;
break;
// case '#': // POUND SIGN TOGGLES AUTOSAVE
// autosave = !autosave;
// break;
case('h'): // DISPLAY HELP PAGE
picsave("screen.pic"); // hopefully faster
restorecrtmode();
drawhelp(); // IF ERASED, REDRAW SCREEN
getch();
setgraphmode(grmode);
picload("screen.pic");
break;
case 's': // STATUS DISPLAY
saveline1();
eraseline1();
printf("x%d y%d x1=%d y1=%d mode:%c pset:%c save:%c c:%d bor:%s steps:x%d y%d",
x,y,x1,y1,(draw?'D':'M'),toupper(psetmode),(autosave?'T':'F'),
color,border,xstep,ystep);
getch();
putline1();
break;
case 'z': // ZEDSAVE
picsave("screen.pic");
break;
case 'g': // GET A DISK FILE
eraseline1();
printf("File to load (include .PIC) (CR aborts): ");
gets(fnam);
if(strlen(fnam))
picload(fnam);
break;
case 'u': // "UNDO" WORKS ONLY IF
picload("SCREEN.pic"); // SHIFT-KEYPAD 8 IS USED
break; // FREQUENTLY
case '!': // AREA SAVE
if(!getarea(x1,y1,x,y))
{
saveline1();
eraseline1();
printf("\007SAVE FAILED - X or Y off screen or area too big");
getch();
putline1();
}
break;
case '@': // AREA PUT
putarea(x,y);
break;
case(0x14): // CONTROL-T CHANGE TEXT COLOR
saveline1();
do
{
eraseline1();
printf("Enter foreground background (space between): ");
}
while(scanf("%d %d",&foreground,&background) != 2);
putline1();
break;
case 't': // ENTER TEXT LINE
saveline1();
eraseline1();
gets(fnam); // just uses fnam as convenient buffer
getarea(0,0,639,15); // SAVE first 16 SCAN LINES
putline1();
break;
case '|': // SET PAINT BORDER
saveline1();
eraseline1();
// redo to require spaces between (colors can be 2 digits)
printf("Enter border color(s) 0-9 or E(xcept), no spaces: ");
scanf("%s",border);
border[16] = '\0'; // terminate in case too long
strlwr(border); // won't affect digits
putline1(); // must put before reading point!
if(strchr(border,'e')) // all colors are border
{ // except color at cursor loc.
k = 0; // pointer into border[]
i = getpixel(x,y); // read current point
for(j = 0 ; j < 10 ; j++) // for all colors
if(j != i) // if it isn't same as current pixel,
border[k++] = (char)(j + 0x30); // it's a border color
border[k] = '\0'; // terminate
}
break;
#if(USEPAINT)
case 'p': // PAINT AN AREA (only works in pset mode)
dopaint(x,y,border);
break;
#endif
case '*': // CLEAR SCREEN
clearviewport();
break;
case '-': // DARKEN IMAGE
case '+': // LIGHTEN IMAGE
case 'e': // enhance contrast
adjustcolor(x,y,x1,y1,ch);
break;
case 'q':
saveline1();
eraseline1();
printf("Press ESC to exit "); // ALLOW USER TO CHANGE MIND
ch2 = getch();
if(ch2 == 27)
{
closegraph();
return(0);
}
putline1();
break;
case(F2): // CHANGE X,O,P PUTAREA() MODE
saveline1();
eraseline1();
do
{
printf("PUT mode (p,x,o): ");
psetmode = tolower(getche());
}
while(!strchr("xpo",psetmode));
putline1();
break;
case(F3): // save graphics area to disk
saveline1();
eraseline1();
printf("Filename for area save (c/r aborts): ");
gets(fnam);
if(strlen(fnam))
writearea(fnam);
putline1();
break;
case(F4): // read graphics area from disk
saveline1();
eraseline1();
printf("Filename containing graphics area (c/r aborts): ");
gets(fnam);
if(strlen(fnam))
readarea(fnam);
putline1();
break;
} // END SWITCH
curblink(x,y); // cursor back on while idle
} // END WHILE
} // END MAIN
/* picxfrm.cpp 3-10-96
Copyright (C)1996 Steven Whitney.
Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
Allows various transformations to .pic files.
It is a combination of previous programs: inverpic, upsidown, smoothe
These all seem to work fine, though not thoroughly tested.
About twice as fast as previous version.
This program is obsolete. Everything it does can be done by class SDib, used in Winbrot.
*/
#include "c:\bcs\my.h"
#include "c:\bcs\mylib.cpp"
extern unsigned _stklen = 64000U;
//----------------------------------------------------------------------------
// smoothe. reduces jaggedness of .pic file by converting its values to
// n-item moving averages. Only smoothes horizontally, not vertically,
// and the leftmost N points of each line are not true N-item moving averages.
void smoothe(string& filename)
{
int maxx, maxy; // screen dimensions of the .pic file
int n = 30; // number of items to average
string buf;
ifstream infile(filename.c_str(),ios::binary); // existence already checked in main
infile >> maxx; // get x, y size of file
infile.ignore(); // the comma
infile >> maxy;
infile.ignore(); // the \n
ofstream outfile("movavg.pic",ios::binary);
outfile << maxx << "," << maxy << endl; // binary: \n only writes linefeed
cout << "Enter number of items to average <CR for 30>: ";
getline(cin,buf,'\n');
if(buf.length())
n = max(atoi(buf.c_str()),1); // disallow 0 or negative due to error
char linebuf[3000]; // read/write line of chars
int values[3000]; // ints for computing moving averages
// must be big enough to hold one x-axis line
long sum, movavg;
while(infile.read(linebuf,maxx))
{
sum = 0L;
for(int i = 0 ; i < maxx ; i++)
{
values[i] = (int)(linebuf[i]); // convert char to int
sum += (long)values[i]; // compute running total
if(i >= n) // after 30 items,
sum -= (long)values[i - n]; // take item (i-30) out of sum
movavg = sum / (long)(min(i+1,n)); // 1 to N, and after that, N
linebuf[i] = (char)movavg; // put movavg back into buffer
}
outfile.write(linebuf,maxx); // write the modified line
}
filename = "MOVAVG.PIC"; // default filename for after return
}
//----------------------------------------------------------------------------
// upsidown. rewrites lines from a .pic file in reverse order to a new file
// last line becomes the first line in the new file, etc.
void upsidown(string& filename)
{
char buf[3000]; // must be big enough to hold one x-axis line
int maxx, maxy;
ifstream infile(filename.c_str(),ios::binary); // existence already checked in main
infile >> maxx; // get x, y size of file
infile.ignore(); // the comma
infile >> maxy;
infile.ignore(); // the \n
ofstream outfile("upsidown.pic",ios::binary);
outfile << maxx << "," << maxy << endl; // binary: \n only writes linefeed
infile.seekg(0,istream::end); // start at end of file
for(int fline = 0 ; fline < maxy ; fline++)
{
infile.seekg(-maxx,istream::cur); // back up one line
infile.read(buf,maxx); // read the bytes
infile.seekg(-maxx,istream::cur); // back up to where we were
outfile.write(buf,maxx);
}
filename = "UPSIDOWN.PIC";
}
//----------------------------------------------------------------------------
// inverpic. inverts values from a .pic file.
// range of 0->255 becomes 255->0, so mountains become valleys & vice versa.
void inverpic(string& filename)
{
int maxx, maxy;
char ch;
ifstream infile(filename.c_str(),ios::binary); // existence already checked in main
infile >> maxx; // get x, y size of file
infile.ignore(); // the comma
infile >> maxy;
infile.ignore(); // the \n
ofstream outfile("inverted.pic",ios::binary);
outfile << maxx << "," << maxy << endl; // binary: \n only writes linefeed
while(infile.get(ch))
outfile.put((unsigned char)(255 - ch));
filename = "INVERTED.PIC";
}
//----------------------------------------------------------------------------
// main()
int main(int argc, char** argv)
{
int ch;
string filename("INFILE.PIC");
ifstream infile;
if(argc > 1)
filename = argv[1];
cout << "Usage: PICXFRM infile.ext\n";
cout << "This program allows you to transform .PIC files in various ways.\n";
cout << "You can do multiple transformations in one session: After each\n";
cout << "transformation, you are given the name of the output file.\n";
cout << "To do another, just use that as the input file name.\n\n";
while(1)
{
do
{
cout << "\nYou can transform a .PIC file as follows:\n";
cout << "Q- <Q>uit\n";
cout << "S- <S>moothe jaggedness by converting values to n-item moving averages\n";
cout << "U- Turn <U>pside-down, so last line becomes the first, etc.\n";
cout << "C- Invert <C>ontours so mountains become valleys & vice versa\n";
cout << "\nEnter choice (Q,S,U,C): ";
ch = tolower(getche());
cout << endl;
}
while(!strchr("qsuc",ch));
if(ch == 'q')
return(0);
do
{
filename.to_upper();
string oldfilename(filename);
cout << "Enter input file name (or CR for " << filename << "): ";
getline(cin,filename,'\n');
if(!filename.length())
filename = oldfilename;
infile.open(filename.c_str());
}
while(!infile);
infile.close();
switch(ch) // the functions change filename to allow chaining commands
{
case 's':
smoothe(filename);
break;
case 'u':
upsidown(filename);
break;
case 'c':
inverpic(filename);
break;
}
cout << "Output file is called: " << filename << endl;
} // end while(1)
} // end main()
/* rotpic.cpp 6-27-97
Copyright (C)1994-97 Steven Whitney.
Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
Loads, displays, and rotates a .PIC format file.
Keep this mainly for preservation of the calculation routines.
-----
TO DO:
reduce magnification factor to 1:1 to eliminate side-on view gaps.
see wshowfs STransform for possible applicability here
-----
NOTES:
--slow, probably because it reads from the file for each redraw.
tested with mt.pic, there's an extra green dot in the display, because mt.pic was
saved in text format and has an extra CR.
--the coloring scheme also needs to be separated from the "elevation",
which will require a different file format. try:
(x size),(y size)\n
z,color,z,color...
or just use my old .col files or .map files
--i think some of the angles are still backwards. once they're fixed,
it should be possible to recombine the rotation into one function, since
the rotations will always be done in the same order. remember that the
order determines what the shape's final position will be.
I think rotate.cpp was the attempt to combine into 1 function, and it works ok;
or else this was an offshoot of rotate when it wasn't working.
--This isn't worth any further work. corelDRAW has features
that will do much of this, and corelCHART has even more, including 3D
scatter plots AND 3D connected point area plots, for fractally
generated landscapes. (but it won't handle a large points database).
*/
#include <graphics.h>
#include <math.h>
#pragma hdrstop
#include "c:\bcs\my.h"
#include "c:\bcs\mylib.cpp"
/////////////////////////////////////////////////////////////////////////////
// global variables
//----------------------------------------------------------------------------
Trigtable t;
int maxx, maxy, maxz;
int x0, y0; // screen origin
string filename;
//---------------------------------------------------------------------------
// rotate around x axis
void rotx(int deg)
{
char ch;
double x, y, z;
double plotx, ploty, plotz;
int color;
ifstream infile(filename.c_str(),ios::binary); // if picload() was ok in main(), so's this
infile >> maxx; // get x, y size of file
infile.ignore(); // the comma
infile >> maxy;
infile.ignore(); // the \n
int charcount = -1;
while(infile.get(ch))
{
color = (int)ch; // point retains original color, for now
z = (double)ch;
charcount++;
x = charcount % maxx; // original 0->maxx value
y = charcount / maxx;
x -= maxx/2; // renormalize around midpoints
y -= maxy/2;
z -= maxz/2;
z *= 8; // magnification factor because starts at only 0-7
// plotz = (z * t.cosines[deg]) + (y * -t.sines[deg]); don't need it
ploty = (z * t.sines[deg]) + (y * t.cosines[deg]);
// x doesn't change with this rotation.
// since z can't be plotted, should project it onto (x,y) plane,
// making sure that only the frontmost (highest z value) point
// sets the pixel at x,y, but that's prohibitively expensive in time
// and memory. when the test below is eliminated, some views will
// always be messed up, but it will also always be possible to further
// rotate until you get the correct picture of the angle you want
// that is if it's wrong, rotate 180 degrees and it will be right
plotx = x + x0; // renormalize around screen center
ploty = ploty + y0;
// if pixel not already set, ok to plot the point
// but it works better without the test
// if(pset(plotx,ploty,'s',0) == 0)
putpixel((int)plotx, (int)ploty, color);
}
}
//---------------------------------------------------------------------------
// rotate around y axis
void roty(int deg)
{
char ch;
double x, y, z;
double plotx, ploty, plotz;
int color;
ifstream infile(filename.c_str(),ios::binary); // if picload() ok in main(), so's this
infile >> maxx; // get x, y size of file
infile.ignore(); // the comma
infile >> maxy;
infile.ignore(); // the \n
int charcount = -1;
while(infile.get(ch))
{
color = (int)ch; // point retains original color, for now
z = (double)ch;
charcount++;
x = charcount % maxx; // original 0->maxx value
y = charcount / maxx;
x -= maxx/2; // renormalize around midpoints
y -= maxy/2;
z -= maxz/2;
z *= 12; // magnification factor because starts at only 0-7
// plotz = (z * t.cosines[deg]) + (x * -t.sines[deg]); don't need
plotx = (z * t.sines[deg]) + (x * t.cosines[deg]);
plotx += x0; // renormalize around screen center
ploty = y + y0;
// if pixel not already set, ok to plot the point
// it works better without the test
// if(pset(plotx,ploty,'s',0) == 0)
putpixel((int)plotx, (int)ploty, color);
}
}
//---------------------------------------------------------------------------
// rotate around z axis
void rotz(int deg)
{
char ch;
double x, y, z;
double plotx, ploty;
int color;
ifstream infile(filename.c_str(),ios::binary); // if picload() ok in main(), so's this
infile >> maxx; // get x, y size of file
infile.ignore(); // the comma
infile >> maxy;
infile.ignore(); // the \n
int charcount = -1;
while(infile.get(ch))
{
color = (int)ch; // only valid with edit() format, for now
z = (double)ch;
charcount++;
x = charcount % maxx; // original 0->maxx value
y = charcount / maxx;
x -= maxx/2; // renormalize around midpoint
y -= maxy/2;
plotx = (x * t.cosines[deg]) + (y * -t.sines[deg]);
ploty = (x * t.sines[deg]) + (y * t.cosines[deg]);
plotx += x0; // renormalize around screen center
ploty = ploty/2 + y0; // no aspect ratio adjustment yet
putpixel((int)plotx, (int)ploty, color); // plot the point
}
}
//---------------------------------------------------------------------------
// main()
int main(int argc, char **argv)
{
char usrcmd;
int xrot, yrot, zrot;
cout << "Usage: ROTPIC filename.PIC\n";
if(argc < 2)
return(1);
initgraf();
x0 = getmaxx()/2;
y0 = getmaxy()/2;
filename = argv[1];
maxz = picload(filename.c_str());
xrot = yrot = zrot = 0;
int page = 0;
while(1)
{
usrcmd = tolower(getch());
if(page == 0)
page = 1;
else
page = 0;
// setactivepage(page);
clearviewport();
switch(usrcmd) // NUMLOCK must be ON. Numbers accepted only.
{
case '8': // rotate around x 15 more degrees
xrot -= 15; // must calc angle backwards, don't know why
if(xrot < 0)
xrot += 360;
rotx(xrot);
break;
case '2': // rotate around x 15 fewer degrees
xrot = (xrot + 15) % 360; // backwards, don't know why
rotx(xrot);
break;
case '4': // rotate around y +15 degrees
yrot = (yrot + 15) % 360;
roty(yrot);
break;
case '6': // rotate around y -15 degrees
yrot -= 15;
if(yrot < 0)
yrot += 360;
roty(yrot);
break;
case '7': // rotate around z -15 degrees
zrot -= 15;
if(zrot < 0)
zrot += 360;
rotz(zrot);
break;
case '9': // rotate around z +15 degrees
zrot = (zrot + 15) % 360;
rotz(zrot);
break;
case 27:
case 'q':
closegraph();
exit(0);
} // end switch
// setvisualpage(page);
} // end while(1)
} // end main
/* rotate.cpp 6-27-97
Copyright (C)1994-97 Steven Whitney.
Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.
Initially published by http://25yearsofprogramming.com.
Rotates an object in space randomly until user stops.
-----
TO DO
see wshowfs STransform for possible applicability here
try going back to previous version, with shape's points actually being
changed; use doubles for point coordinates; see if rounding problem goes away.
if still a problem, try doubles for the angles and trig tables, too.
the shape should be an object, and rotation something it can do to itself.
The effect is very good, but the shape also grows and shrinks mysteriously
as though it's moving closer and farther away, too, which I don't think
was intended.
-----
NOTES:
--set up shape as desired, then determine its (x,y,z) center, then
renormalize all its points relative to the center. this works:
the shape rotates around its center of rotation.
--in this version, the points defining the shape never actually change.
rather, the shape is rotated to increasing angles. this works.
a previous version recalculated the defining points with each angle
change, and (probably) rounding errors caused the shape to
shrink with successive redraws.
--using doubles for trig table and coordinates isn't much slower.
*/
#include <graphics.h>
#include <math.h>
#include <classlib\arrays.h>
#pragma hdrstop
#include "c:\bcs\my.h"
#include "c:\bcs\mylib.cpp"
//////////////////////////////////////////////////////////////////////////////
// a point in 3-dimensional space.
struct Point3d
{
Point3d() {}
Point3d(double a, double b, double c) : x(a), y(b), z(c) {}
BOOL operator == (const Point3d& other)
{ return((x == other.x) && (y == other.y) && (z == other.z)); }
double x;
double y;
double z;
};
//////////////////////////////////////////////////////////////////////////////
// global variables
TArrayAsVector<Point3d> a(5,0,5); // a collection of points (a shape)
Trigtable t;
int x0, y0; // screen origin
//////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------
// draw the shape, rotated as requested
// assume +z is in front of screen and -z is in back of screen
// so +rotation around z is clockwise from the viewpoint of +z
// and rotation around other axes is likewise from the "+" viewpoint
void draw(int xdeg, int ydeg, int zdeg, int color) // degrees rotation around given axis
{
double x[4], y[4]; // no z because it's a projection,
double lastx = 0., lasty = 0.; // z affects result, but can't be plotted
setcolor(color);
for(int i = 0 ; i < a.GetItemsInContainer() ; i++)
{
// these probably aren't right, but they produce the effect
x[i] = ((a[i].x * t.cosines[zdeg]) + (a[i].y * -t.sines[zdeg])) * t.cosines[ydeg];
y[i] = ((a[i].x * t.sines[zdeg]) + (a[i].y * t.cosines[zdeg])) * t.sines[xdeg];
// draw connecting lines - but it's still flat because z isn't used
// line(x0, y0, x0 + x[i], y0 + y[i]/2);
// why y[i]/2 , and why NOT x[i]/2 ??
if(i)
line(x0 + (int)lastx, y0 + (int)(lasty/2.), x0 + (int)x[i], y0 + (int)(y[i]/2.));
lastx = x[i];
lasty = y[i];
}
// draw the last line to close the figure
line(x0 + (int)lastx, y0 + (int)(lasty/2.), x0 + (int)x[0], y0 + (int)(y[0]/2.));
}
//----------------------------------------------------------------------------
// main()
int main(int argc, char **argv)
{
randomize();
initgraf(); // vgahi is default
x0 = getmaxx() / 2;
y0 = getmaxy() / 2;
a.Add(Point3d(160.,-160.,0.)); // make a triangle
a.Add(Point3d(160.,160.,0.));
a.Add(Point3d(-160.,0.,0.));
int xrot = random(360);
int yrot = random(360);
int zrot = random(360);
while(1)
{
if(argc == 1) // nothing on command line means clear screen
clearviewport();
xrot = (xrot + random(2)) % 360;
yrot = (yrot + random(2)) % 360;
zrot = (zrot + random(2)) % 360;
draw(xrot,yrot,zrot,LIGHTGREEN);
if(kbhit())
if(getch() == 27)
break;
}
closegraph();
return(0);
}
|
|
|
|
|
|