DOS ASCII Animation Lagging without constant input, Turbo C compiled - c++

Here's an oddity from the past!
I'm writing an ASCII Pong game for the command prompt (Yes yes oldschool) and I'm writing to the video memory directly (Add. 0xB8000000) so I know I'm rendering quickly (As opposed to gotoxy and then printf rendering)
My code works fine, the code compiles fine under Turbo C++ V1.01 BUT the animation lags... now hold on hold on, there's a cavaet! Under my super fast boosted turbo Dell Core 2 Duo this seems logical however when I hold a key on the keyboard the animation becomes smooth as a newly compiled baby's bottom.
I thought maybe it was because I was slowing the computer down by overloading the keyboard buffer (wtf really? come on...) but then I quickly smartened up and tried compiling for DJGPP and Tiny C Compiler to test if the results are the same. On Tiny C Compiler I found I coulnd't compile 'far' pointer types... still confused on that one but I was able to compile for DJGPP and it the animation ran smoothly!
I want to compile this and have it work for Turbo C++ but this problem has been plagueing me for the past 3 days to no resolve. Does anyone know why the Turbo C++ constant calls to my rendering method (code below) will lag in the command prompt but DJGPP will not? I don't know if I'm compiling as debug or not, I don't even know how to check if I am. I did convert the code to ASM and I saw what looked to be debugging data at the header of the source so I don't know...
Any and all comments and help will be greatly appreciated!
Here is a quick example of what I'm up against, simple to compile so please check it out:
#include<stdio.h>
#include<conio.h>
#include<dos.h>
#include<time.h>
#define bX 80
#define bY 24
#define halfX bX/2
#define halfY bY/2
#define resolution bX*bY
#define LEFT 1
#define RIGHT 2
void GameLoop();
void render();
void clearBoard();
void printBoard();
void ballLogic();
typedef struct {
int x, y;
}vertex;
vertex vertexWith(int x, int y) {
vertex retVal;
retVal.x = x;
retVal.y = y;
return retVal;
}
vertex vertexFrom(vertex from) {
vertex retVal;
retVal.x = from.x;
retVal.y = from.y;
return retVal;
}
int direction;
char far *Screen_base;
char *board;
vertex ballPos;
void main() {
Screen_base = (char far*)0xB8000000;
ballPos = vertexWith(halfX, halfY);
direction = LEFT;
board = (char *)malloc(resolution*sizeof(char));
GameLoop();
}
void GameLoop() {
char input;
clrscr();
clearBoard();
do {
if(kbhit())
input = getch();
render();
ballLogic();
delay(50);
}while(input != 'p');
clrscr();
}
void render() {
clearBoard();
board[ballPos.y*bX+ballPos.x] = 'X';
printBoard();
}
void clearBoard() {
int d;
for(d=0;d<resolution;d++)
board[d] = ' ';
}
void printBoard() {
int d;
char far *target = Screen_base+d;
for(d=0;d<resolution;d++) {
*target = board[d];
*(target+1) = LIGHTGRAY;
++target;
++target;
}
}
void ballLogic() {
vertex newPos = vertexFrom(ballPos);
if(direction == LEFT)
newPos.x--;
if(direction == RIGHT)
newPos.x++;
if(newPos.x == 0)
direction = RIGHT;
else if(newPos.x == bX)
direction = LEFT;
else
ballPos = vertexFrom(newPos);
}

First, in the code:
void printBoard() {
int d;
char far *target = Screen_base+d; // <-- right there
for(d=0;d<resolution;d++) {
you are using the variable d before it is initialized.
My assumption is that if you are running this in a DOS window, rather than booting into DOS and running it, is that kbhit is having to do more work (indirectly -- within the DOS box's provided environment) if there isn't already a keypress queued up.
This shouldn't effect your run time very much, but I suggest that in the event that there is no keypress you explicitly set the input to some constant. Also, input should really be an int, not a char.
Other suggestions:
vertexFrom doesn't really do anything.
A = vertexFrom(B);
should be able to be replaced with:
A = B;
Your macro constants that have operators in them should have parenthisis around them.
#define Foo x/2
should be:
#define Foo (x/2)
so that you never ever have to worry about operator precedence no matter what code surrounds uses of Foo.
Under 16 bit x86 PCs there are actually 4 display areas that can be switched between. If you can swap between 2 of those for your animation, and your animations should appear to happen instantaneously. It's called Double Buffering. You have one buffer that acts as the current display buffer and one that is the working buffer. Then when you are satisfied with the working buffer (and the time is right, if you are trying to update the screen at a certain rate) then you swap them. I don't remember how to do this, but the particulars shouldn't be too difficult to find. I'd suggest that you might leave the initial buffer alone and restore back to it upon exit so that the program would leave the screen in just about the state that it started in. Also, you could use the other buffer to hold debug output and then if you held down the space bar or something that buffer could be displayed.
If you don't want to go that route and the 'X' is the only thing changing then you could forgo clearing the screen and just clear the last location of the 'X'.
Isn't the screen buffer an array of 2 byte units -- one for display character, and the other for the attributes? I think so, so I would represent it as an array of:
struct screen_unit {
char ch;
unsigned char attr;
}; /* or reverse those if I've got them backwards */
This would make it less likely for you to make mistakes based on offsets.
I'd also probably read and write them to the buffer as the 16 bit value, rather than the byte, though this shouldn't make a big difference.

I figured out why it wasn't rendering right away, the timer that I created is fine the problem is that the actual clock_t is only accurate to .054547XXX or so and so I could only render at 18fps. The way I would fix this is by using a more accurate clock... which is a whole other story

Related

Update getmaxyx() return values (ncurse / C++)

So, I'm, trying to be able to correctly resize my console window using ncurse in C++. I've been able to catch when the window is resize, the problem is that I'm not 100% sure how should I proceed after that. Let's say I have this loop in my main function (after initializing ncurse and those things...):
while(ch = getch())
{
if(ch == KEY_RESIZE)
{
DoSometing();
}
}
As I said the DoSomething in that example is called. But if I try to use ncurse's functions to get the new size of the window with
getmaxyx(stdscr, yMax, xMax);
I'm get the same values (the initial values) over and over again. I guess that's because when I do initscr(), the window size is stored somewhere and that's the value that the getmaxyx function provides. I've tried to do something like call endwin() and the again initscr() to restore those values, but that doesn't seem to work, the value that getmaxyx returns is fixed.
After searching for alternative solutions, I kind of solve the problem, using some other libraries. That's an small example, which actually works as I wanted:
#include <cstdlib>
#include <ncurses.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
initscr();
noecho();
box(stdscr, 0, 0);
struct winsize w;
int ch, x, y;
while(ch = getch())
{
if(ch == KEY_RESIZE)
{
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
resize_term(w.ws_row, w.ws_col);
clear();
box(stdscr, 0, 0);
}
refresh();
}
}
The thing is I'm kind of worried about portability while using this new libraries (I'm not completely sure, because I haven't started testing yet, but I understand that ncurse programs can be port to Windows).
I would really appreciate any information about how to do this in ncurse without using any other library (if it's possible), if what I'm doing now is OK or if I should be doing it in any other way. Any hint in the right direction is what I'm looking for :)
I'm using Arch Linux (kind of noobie) and qtile as a window manager. If you need any other relevant information, just ask me. Thanks for the help!
This is causing the example to produce bogus results:
if(ch = KEY_RESIZE)
since it is always true (not a comparison, but an assignment). The "something" is not doing anything useful, because the condition is incorrect.
Change that to
if(ch == KEY_RESIZE)
and get rid of
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
resize_term(w.ws_row, w.ws_col);

My program checking for mouse click can be run just once

I have made this program in Turbo C++ wherein when the user clicks inside the square that comes on screen, the program should exit. The program works fine if I run it once. But when I run it again, it exits as soon as mouse is inside the square. It does not wait for the click. I think it is something to do with resetting the mouse.
#include<process.h>
#include<conio.h>
#include<graphics.h>
#include<dos.h>
union REGS in,out;
void main()
{
int gdriver = DETECT,gmode;
int xp,yp,cl=0;
int x,y;
initgraph(&gdriver,&gmode,"C:\\Turboc3\\BGI");
x=getmaxx()/2;
y=getmaxy()/2;
in.x.ax=4;
in.x.cx=10;
in.x.dx=10;
int86(51,&in,&out);
in.x.ax=1;
int86(51,&in,&out);
setcolor(RED);
rectangle((x-100),(y-100),x,y);
in.x.ax=3;
while(1)
{
int86(51,&in,&out);
cl=out.x.bx;
xp=out.x.cx;
yp=out.x.dx;
if(((xp>=x-100)&&(xp<=x))&&((yp>=y-100)&&(yp<=y)))
if(cl==1)
{
cl=0;
exit(1);
}
}
}
OUTPUT
P.S. I already know that Turbo C++ is an "ancient compiler" and I am well aware of the existence of other modern compilers, but I am forced to use this compiler.
Ok I have figured out the problem. When I start the program again, instead of dragging the mouse inside the square button straight away, if I click outside the square button first and then move towards the square button, the problem doesn't happen.
Basically, when the program starts for the 2nd time, the mouse starts with click=1 instead of click=0. I can't find out how to fix this though..
I've found this, dunno if that would help any. Depending what your OS you're running... or is that DosBox? It uses BGI to set graphic mode which may not work if you run it from x64 windows, should work from DosBox(at least, Turbo Pascal's version does). It is curious, that program does one dummy reading of mouse status after making cursor visible, to flush the registers. Is that the gotcha you're hit by?
#include<graphics.h>
#include<conio.h>
#include<dos.h>
union REGS i, o;
int initmouse()
{
i.x.ax = 0;
int86(0X33,&i,&o);
return ( o.x.ax );
}
void showmouseptr()
{
i.x.ax = 1;
int86(0X33,&i,&o);
}
void getmousepos(int *button, int *x, int *y)
{
i.x.ax = 3;
int86(0X33,&i,&o);
*button = o.x.bx;
*x = o.x.cx;
*y = o.x.dx;
}
main()
{
int gd = DETECT, gm, status, button, x, y;
char array[50];
initgraph(&gd,&gm,"C:\\TC\\BGI");
settextstyle(DEFAULT_FONT,0,2);
status = initmouse();
if ( status == 0 )
printf("Mouse support not available.\n");
else
{
showmouseptr();
getmousepos(&button,&x,&y);
while(!kbhit())
{
getmousepos(&button,&x,&y);
if( button == 1 )
{
button = -1;
cleardevice();
sprintf(array,"Left Button clicked x = %d y = %d",x,y);
outtext(array);
}
else if( button == 2 )
{
button = -1;
cleardevice();
sprintf(array,"Right Button clicked x = %d y = %d",x,y);
outtext(array);
}
}
}
getch();
return 0;
}
You're doing what my boss called jokingly "Computer necrophilia". Those old systems had all kind of quirks. There were reasons why programmers of old where maniacal about initializing variables. You could run into issue that if you declare a long int variable, then assigning to it a long value, then a short value, then only lower word will be set in second case - all because compiler wasn't "casting" short to long implicitly, it was just copying binary image to the same address.
I have faced the same problem recently and the cause is DOSBox, more precisely Turbo C++ IDE running in DOSBox. Try exiting the IDE and runnning your compiled program from the command line, it will work fine. Or try a virtualbox MS-DOS machine, it will work fine even from the IDE.

Cout + Float, no debug error, crash on release run

I've seen a post something like 2 hours ago about a problem i've met days ago, i'm also looking for an explanation too...
https://stackoverflow.com/questions/25281294/c-cout-float-fail-while-printf-do-the-job
I've encoutered exactly the same behavior with cout, which didn't like float at all ...
I've a seperate threaded-UserInterface, made with openGL, with a callback function attached on a button in my main thread.
class ObjectA//My class
{
private:
float light;
float surface;
float height;
public:
ObjectA();
~ObjectA();
float r_light();
float r_surface();
float r_height();
void render(int x, int y); // Not implemented when bug occured
}
ObjectA::ObjectA(void)
{
light = 0;
surface = 0;
height = 0;
}
float ObjectA::r_light()
{
return this->light;
}
void displayResult(ObjectA * a) //The callback function attached to the UserInterface-button
{
cout << a->r_light() << endl;
}
When I runned it, the program crashed hard, and I had to finish the process manually ...
The only solution i had was to replace cout by printf, but I didn't really liked that.
Anyone know why i couldn't cout this value ?
Got it, friend of mine has had the same issue.
_setmode(_fileno(stdout), _O_TEXT);
And cout go back to normal behavior. He's telling me something about a sh***y VC++ compiler and openGL old version. (Init openGl world screwed stdout in some sort of way, if i understood)

How do I accept keyboard input in a live fashion?

I am currently writing a program in c++ that is very similar to the classic "snake" program with a few changes. I am writing it so that it will update the screen five times a second, based on ctime, possibly more if it can be handled. One thing that I would like to do is make it so that the program has a variable in the .h file "currkeypressed." This variable will hold the key that the user is currently holding down and the snake head will go in that direction. Each node in the snake will be a separate object so the currkeypressed will only affect the head. Directional and locational data will be passed down the snake from node to node at each update.
My question is: how can I get the program to keep this data constantly, rather than updating only with a cin when the key is pressed or at a certain interval? I know that I can accept the ascii value for the arrow keys in some sort of for loop, but that doesn't seem to work if the key is held down and if the loop is very long it can miss a press. Does anybody know how to do this?
EDIT: I am using a Linux OS, Ubuntu to be more precise
The simplest method is to use ncurse library.
However, if you prefer "raw" linux programming, you can use select and getchar:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
fd_set readfs;
struct timeval timeout;
int res, key;
while (1) {
/* .. do something else .. */
FD_SET(0, &readfs); /* 0 is STDIN */
timeout.tv_usec = 10; /* milliseconds */
timeout.tv_sec = 0; /* seconds */
res = select(maxfd, &readfs, NULL, NULL, &timeout);
if (res) {
/* key pressed */
key = getchar();
if (key == 'A') { /* blar */ }
}
}
}
Once you are looking beyond simple line oriented or character orient input, you are into the details of the user input device. Each operating system has a particular mechanism for notifying a program of events like keydown and keyup.
To get an answer, add a tag for which programming environment you are in: MSWindows, Linux, Android, MacOS, etc.
You can use the library conio.h and you can use the function _getch() in a loop to get live input without any restriction.
#include<conio.h>
#include<iostream>
using namespace std;
int main()
{
char n='a';//Just for initialization
while(n!='e')
{
n=_getch();
}
return 0;
}
The simplest (although really not that simple) way would be to have a thread to capture the user input and then either have some kind of event driven system that can alert the head of the snake or the snake can poll for the current key.

Files reading differently in linux? C++

I'm a fairly new programmer, but I consider my google-fu quite competent and I've spent several hours searching.
I've got a simple SDL application that reads from a binary file (2 bytes as a magic number, then 5 bytes per "tile")
it then displays each tile in the buffer, the bytes decide the x,y,id,passability and such.
So it's just level loading really.
It runs fine on any windows computer (tested windows server 2008, 7/64 and 7/32)
but when I compile it on linux, it displays random tiles in random positions.
I'd be tempted to say it's reading from the wrong portion in the RAM, but I implimented the magic number so it'd return an error if the first 2 bytes were out.
I'd love to figure this out myself but it's bugging me to hell now and I can't progress much further with it unless I can program on the move (my laptop runs linux).
I'm using G++ on linux, mingw32g++ on windows.
bool loadlevel(int level_number)
{
int length;
std::string filename;
filename = "Levels/level";
filename += level_number+48;
filename += ".lvl";
std::ifstream level;
level.open(filename.c_str(),std::ios::in|std::ios::binary);
level.seekg(0,std::ios::end);
length = level.tellg();
level.seekg(0,std::ios::beg);
char buffer[length];
level.read(buffer,length);
if (buffer[0] == 0x49 && buffer[1] == 0x14)
{
char tile_buffer[BYTES_PER_TILE];
int buffer_place = 1;
while(buffer_place < length)
{
for (int i = 1;i <= BYTES_PER_TILE;i++)
{
tile_buffer[i] = buffer[buffer_place+1];
buffer_place++;
}
apply_surface(tile_buffer[1],tile_buffer[2],tiles,screen,&clip[tile_buffer[3]]);
}
}
else
{
// File is invalid
return false;
}
level.close();
return true;
}
Thanks in advance!
Your array handling is incorrect.
Array indexing in C/C++ begins from 0.
You have defined 'tile_buffer' to be an array sized 'BYTES_PER_TILE'.
If BYTES_PER_TILE was 5, your array would have elements tile_buffer[0] to tile_buffer[4].
In your inner for-loop you loop from 1 to 5 so a buffer overflow will occur.
I don't know if this is the cause of your problem but it certainly won't help matters.
This is probably not an answer, but the 1-based array handling and the unneeded copying make my head hurt.
Why not just do something along these lines?
if ((length >= 2+BYTES_PER_TILE) && (buf[0] == CONST1) && (buf[1] == CONST2)) {
for (char *tile = &buf[2]; tile < &buf[length-BYTES_PER_TILE]; tile+=BYTES_PER_TILE) {
apply_surface(tile[0],tile[1],tiles,screen,&clip[tile[2]]);
}
}