Reputation: 3452
I´m working on a program to create a basic image editor (like paint) on DOSBOX with C using BORLAND 3.1. Right now I´m trying to implement a simple undo button. For this I created a double array to store 10 times the drawing area (which is 288*180). However, when adding the line of the array intialization, I cannot allocate memory for a double buffer I use in other functionalities of the program.
Is there any way I can get more memory in DOSBOX or another implementation that doesn´t give me this problem?
I compile my program like this:
bcc -mh paint.c
This is my code:
byte huge undo[51840][10]; // This is the array that is giving me problems
void welcome_screen(){
BITMAP fondo_inicio,normal_ptr_image,boton_inicio,boton_salir;
MOUSE mouse_welcome;
unsigned long int h;
int a[2];
byte *double_buffer;
sword new_x, new_y;
word redraw,press,release;
sword dx,dy=0;
MOUSEBITMAP *normal_pointer=NULL;
MOUSEBITMAP *mouse_new=NULL;
word last_time;
int i,done = 0;
filled=-1;
/* allocate memory for double buffer and background image SCREEN_SIZE = 320*200 */
if ((double_buffer = (byte *) malloc(SCREEN_SIZE)) == NULL)
{
printf("Not enough memory for double buffer.\n"); // ---> This is the error I get when adding the above line
exit(1);
}
Upvotes: 1
Views: 1081
Reputation: 15134
If you want to use memory above 640K, what you want to do is compile using DPMI, with a DOS extender such as CWSDMPI, and allocate memory through it. DJGPP, the DOS port of GCC, is the most modern compiler available for DOS, and is still being developed. (Edit: According to Ross Ridge, DJGPP uses extended memory automatically with the standard library calls.) Another option, which is what most commercial software at the time used, is Watcom C with DOS4G/W. This is available today as OpenWatcom and the DOS/32 extender. You will also need to configure DOSBOX to make XMS available; 16MiB was a hefty amount back in 1995.
Upvotes: 4
Reputation: 104514
Rather than keeping your undo buffer as an array of 10 full screen bitmaps, why not just preserve one screen and the 10 subsequent operations that followed on it? Then an undo is just restoring the screen buffer and then applying the 9 remembered operations that followed.
That is...
byte undo[288*180]; // one screen of memory representing what the screen looked like 10 operations ago
struct Operation undo_ops[10]; // the last 10 operations since the undo buffer was formed
int undo_ops_count; // number of elements in above array
Where "Operation" is something like this:
struct Operation
{
int x1;
int y1;
int x2;
int y2;
int size;
int extra;
int color;
enum OpCode code; // Circle, Rectangle, Line, Fill, whatever...
};
And then some pseudo-code for what an "Undo" actually does
void Undo()
{
if (undo_ops_count > 0)
{
undo_ops_count--; // forget the last operation
// restore the screen
memcpy(g_screen_buffer, undo, sizeof(undo));
// apply the last operations before the last user operation
for (int x = 0; x < undo_ops_count; x++)
{
ApplyOperation(g_screen_buffer, &undo_ops[x]); // re-draw what the user did on top of the restored screen buffer
}
RepaintScreen(g_screen_buffer);
}
}
Each user action of drawing something new gets appended to the undo_ops array. If you run out of array space for undo_ops, you merely redraw a new screen buffer and drop the oldest operation. I'll leave that as an exercise for you. Seeing how this frees up a lot more memory, I'll bet you can remember a lot more than 10 operations without running out of memory.
Upvotes: 2