C++ WriteConsoleOutput Display Issues - c++

I've started making a simple game in c++.
At this stage I have all the characters and attributes (tiles) stored in a file that is then loaded in to CHAR_INFO. Then using the WriteConsoleOutputA I can basically paint the map/world.
That all appears to work correctly and there is no display issues. However when I start to move my character around he is mucking up the tiles. It a bit hard to explain so here is a little video. http://www.youtube.com/watch?v=v5Be5qz30r8.
As you can see there is not problem with the green tiles (foreground and background are same colour). But when I go near the grey tiles it isn't working as intended.
main.cpp snippet...
int main()
{
while (0 < 1)
{
if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState(0x57))
player.Move('u');
if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState(0x53))
player.Move('d');
if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState(0x41))
player.Move('l');
if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState(0x44))
player.Move('r');
Sleep(100);
}
}
Character class snippet
void Character::Move(char d)
{
COORD oldLoc = loc;
char walkableTiles[12] = {
4, 179, 191, 192, 193, 194, 195, 196, 197, 217, 218, 255
};
//set character
switch (d)
{
case 'u' :
loc.Y--;
break;
case 'd':
loc.Y++;
break;
case 'l':
loc.X--;
break;
case 'r':
loc.X++;
break;
}
//setup the buffer and location of tiles
CHAR_INFO newTile[1];
COORD buffSize = {1,1};
COORD buffPos = {0,0};
SMALL_RECT newBuffArea = {loc.X, loc.Y, loc.X, loc.Y};
SMALL_RECT oldBuffArea = {oldLoc.X, oldLoc.Y, oldLoc.X, oldLoc.Y};
//store newTile info
ReadConsoleOutputA(outHnd, newTile, buffSize, buffPos, &newBuffArea);
//check if newTile is valid
bool valid = 0; // assume not valid
for (int i=0; i < sizeof(walkableTiles); i++)
{
if (newTile[0].Char.AsciiChar == walkableTiles[i])
valid = 1;
}
if (!valid)
{
loc = oldLoc;
return;
}
//restore oldTile information
WriteConsoleOutputA(outHnd, oldTile, buffSize, buffPos, &oldBuffArea);
//newTile becomes oldTile
oldTile[0] = newTile[0];
//get bg of newTile and set character/attributes
int bg = (newTile[0].Attributes & Blue << BG ) | (newTile[0].Attributes & Red << BG) | (newTile[0].Attributes & Green << BG) | (newTile[0].Attributes & BACKGROUND_INTENSITY);
newTile[0].Char.AsciiChar = 1;
newTile[0].Attributes = White | bg;
//place character on newTile
WriteConsoleOutputA(outHnd, newTile, buffSize, buffPos, &newBuffArea);
Apologies for the code, this is my first game.

Related

Convert Gdiplus::Region to ID2D1Geometry* for clipping

I am trying to migrate my graphics interface project from Gdiplus to Direct2D.
Currently, I have a code that calculates clipping area for an rendering object:
Graphics g(hdc);
Region regC = Rect(x, y, cx + padding[2] + padding[0], cy + padding[3] + padding[1]);
RecursRegPos(this->parent, &regC);
RecursRegClip(this->parent, &regC);
g.setClip(g);
...
inline void RecursRegClip(Object *parent, Region* reg)
{
if (parent == CARD_PARENT)
return;
if (parent->overflow != OVISIBLE)
{
Rect regC(parent->getAbsoluteX(), parent->getAbsoluteY(), parent->getCx(), parent->getCy()); // Implementation of these function is not necceassary
GraphicsPath path;
path.Reset();
GetRoundRectPath(&path, regC, parent->borderRadius[0]);
// source https://stackoverflow.com/a/71431813/15220214, but if diameter is zero, just plain rect is returned
reg->Intersect(&path);
}
RecursRegClip(parent->parent, reg);
}
inline void RecursRegPos(Object* parent, Rect* reg)
{
if (parent == CARD_PARENT)
return;
reg->X += parent->getX() + parent->padding[0];
reg->Y += parent->getY() + parent->padding[1];
if (parent->overflow == OSCROLL || parent->overflow == OSCROLLH)
{
reg->X -= parent->scrollLeft;
reg->Y -= parent->scrollTop;
}
RecursRegPos(parent->parent, reg);
}
And now I need to convert it to Direct2D. As You may notice, there is no need to create Graphics object to get complete calculated clipping region, so I it would be cool if there is way to just convert Region to ID2D1Geometry*, that, as far, as I understand from msdn article need to create clipping layer.
Also, there is probably way to convert existing code (RecursRegClip, RecursRegPos) to Direct2D, but I am facing problems, because I need to work with path, but current functions get region as an argument.
Update 1
There is Region::GetData method that returns, as I understand array of points, so maybe there is possibility to define either ID2D1PathGeometry or ID2D1GeometrySink by points?
Update 2
Oh, maybe
ID2D1GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT32 pointsCount)
is what do I need?
Unfortunately, GetData of region based on just (0,0,4,4) rectangle returns 36 mystique values:
Region reg(Rect(0, 0, 4, 4));
auto so = reg.GetDataSize();
BYTE* are = new BYTE[so];
UINT fi = 0;
reg.GetData(are, so, &fi);
wchar_t ou[1024]=L"\0";
for (int i = 0; i < fi; i++)
{
wchar_t buf[10] = L"";
_itow_s(are[i], buf, 10, 10);
wcscat_s(ou, 1024, buf);
wcscat_s(ou, 1024, L", ");
}
// ou - 28, 0, 0, 0, 188, 90, 187, 128, 2, 16, 192, 219, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 64, 0, 0, 128, 64,
I rewrote the solution completely, it seems to be working:
// zclip is ID2D1PathGeometry*
inline void Render(ID2D1HwndRenderTarget *target)
{
ID2D1RoundedRectangleGeometry* mask = nullptr;
ID2D1Layer* clip = nullptr;
if(ONE_OF_PARENTS_CLIPS_THIS || THIS_HAS_BORDER_RADIUS)
{
Region reg = Rect(x, y, cx + padding[2] + padding[0], cy + padding[3] + padding[1]);
RecursRegPos(this->parent, &reg);
D2D1_ROUNDED_RECT maskRect;
maskRect.rect.left = reg.X;
maskRect.rect.top = reg.Y;
maskRect.rect.right = reg.X + reg.Width;
maskRect.rect.bottom = reg.Y + reg.Height;
maskRect.radiusX = this->borderRadius[0];
maskRect.radiusY = this->borderRadius[1];
factory->CreateRoundedRectangleGeometry(maskRect, &mask);
RecursGeoClip(this->parent, mask);
target->CreateLayer(NULL, &clip);
if(zclip)
target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), zclip), clip);
else
target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), mask), clip);
SafeRelease(&mask);
}
// Draw stuff here
if (clip)
{
target->PopLayer();
SafeRelease(&clip);
SafeRelease(&mask);
SafeRelease(&zclip);
}
}
...
inline void RecursGeoClip(Object* parent, ID2D1Geometry* geo)
{
if (parent == CARD_PARENT)
return;
ID2D1RoundedRectangleGeometry* maskParent = nullptr;
if (parent->overflow != OVISIBLE)
{
Rect regC(parent->getAbsoluteX(), parent->getAbsoluteY(), parent->getCx(), parent->getCy());
ID2D1GeometrySink* sink = nullptr;
ID2D1PathGeometry* path = nullptr;
SafeRelease(&path);
factory->CreatePathGeometry(&path);
D2D1_ROUNDED_RECT maskRect;
maskRect.rect.left = regC.X;
maskRect.rect.top = regC.Y;
maskRect.rect.right = regC.X + regC.Width;
maskRect.rect.bottom = regC.Y + regC.Height;
maskRect.radiusX = parent->borderRadius[0];
maskRect.radiusY = parent->borderRadius[1];
path->Open(&sink);
factory->CreateRoundedRectangleGeometry(maskRect, &maskParent);
geo->CombineWithGeometry(maskParent, D2D1_COMBINE_MODE_INTERSECT, NULL, sink);
sink->Close();
SafeRelease(&sink);
SafeRelease(&this->zclip);
this->zclip = path;
RecursGeoClip(parent->parent, this->zclip);
}
else
RecursGeoClip(parent->parent, geo);
SafeRelease(&maskParent);
}
Now I can enjoy drawing one image and two rectangles in more than 60 fps, instead of 27 (in case of 200x200 image size, higher size - lower fps) with Gdi+ -_- :

changes not showing in field in ncurses

I have a ncurses program which is a login menu and I use field for username and password.
The problem is that when I type something in the fields, characters register but do not show in terminal. In other word if you execute the code blow and type something, you won't be able to see it in terminal but if you push F2, you could see that the characters were registered.
Here is my code:
test.cpp
#include <curses.h>
#include <form.h>
#include <menu.h>
#include <string>
#include <cstring>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
class WelcomeMenu {
private:
int _row; // number of rows of the terminal
int _col; // number of columns of the terminal
public:
WelcomeMenu();
~WelcomeMenu();
void welcomeBox();
void loginMenu();
void registerMenu();
};
WelcomeMenu::WelcomeMenu(){
initscr();
noecho();
cbreak();
keypad(stdscr, true);
int row, col;
getmaxyx(stdscr,row,col); /* get the number of rows and columns */
this->_row = row; this->_col = col;
loginMenu();
}
WelcomeMenu::~WelcomeMenu(){
refresh();
endwin();
}
/*
* This is useful because ncurses fill fields blanks with spaces.
*/
char* trim_whitespaces(char *str)
{
char *end;
// trim leading space
while(isspace(*str))
str++;
if(*str == 0) // all spaces?
return str;
// trim trailing space
end = str + strnlen(str, 128) - 1;
while(end > str && isspace(*end))
end--;
// write new null terminator
*(end+1) = '\0';
return str;
}
void WelcomeMenu::loginMenu(){
// erase();
FORM *form;
FIELD *fields[5];
WINDOW *win_body, *win_form;
int ch;
win_body = newwin(24, 80, 0, 0);
assert(win_body != NULL);
box(win_body, 0, 0);
win_form = derwin(win_body, 20, 78, 3, 1);
assert(win_form != NULL);
box(win_form, 0, 0);
mvwprintw(win_body, 1, 2, "Press F1 to quit and F2 to print fields content");
fields[0] = new_field(1, 10, 0, 0, 0, 0);
fields[1] = new_field(1, 40, 0, 15, 0, 0);
fields[2] = new_field(1, 10, 2, 0, 0, 0);
fields[3] = new_field(1, 40, 2, 15, 0, 0);
fields[4] = NULL;
assert(fields[0] != NULL && fields[1] != NULL && fields[2] != NULL && fields[3] != NULL);
set_field_buffer(fields[0], 0, "Username: ");
set_field_buffer(fields[1], 0, "username");
set_field_buffer(fields[2], 0, "Password: ");
set_field_buffer(fields[3], 0, "password");
set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[1], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_opts(fields[2], O_VISIBLE | O_PUBLIC | O_AUTOSKIP);
set_field_opts(fields[3], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
set_field_back(fields[1], A_UNDERLINE);
set_field_back(fields[3], A_UNDERLINE);
form = new_form(fields);
assert(form != NULL);
set_form_win(form, win_form);
set_form_sub(form, derwin(win_form, 18, 76, 1, 1));
post_form(form);
refresh();
wrefresh(win_body);
wrefresh(win_form);
while ((ch = getch()) != KEY_F(1)){
switch (ch) {
case KEY_F(2):
// Or the current field buffer won't be sync with what is displayed
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_PREV_FIELD);
move(LINES-3, 2);
for (int i = 0; fields[i]; i++) {
printw("%s", trim_whitespaces(field_buffer(fields[i], 0)));
if (field_opts(fields[i]) & O_ACTIVE)
printw("\"\t");
else
printw(": \"");
}
refresh();
pos_form_cursor(form);
break;
case KEY_DOWN:
form_driver(form, REQ_NEXT_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
form_driver(form, ch);
break;
}
}
wrefresh(win_form);
unpost_form(form);
free_form(form);
free_field(fields[0]);
free_field(fields[1]);
free_field(fields[2]);
free_field(fields[3]);
delwin(win_form);
delwin(win_body);
}
int main(){
WelcomeMenu * myConWin = new WelcomeMenu();
delete myConWin;
return 0;
}
you can compile it like: g++ -lncurses -lform test.cpp
Thank you in advance for your response
The basic problem with the example is that it does not provide for displaying the characters. In ncurses, that would be done using the form_driver function:
form_driver
Once a form has been posted (displayed), you should funnel input events
to it through form_driver. This routine has three major input cases:
o The input is a form navigation request. Navigation request codes
are constants defined in <form.h>, which are distinct from the key-
and character codes returned by wgetch(3x).
o The input is a printable character. Printable characters (which
must be positive, less than 256) are checked according to the pro-
gram's locale settings.
o The input is the KEY_MOUSE special key associated with an mouse
event.
Making your program use form_driver would involve some reorganization of the program, moving that switch-statement into a function which can be called from the form-driver.
The ncurses examples include a few using form_driver. You might want to read through the test-code, seeing how the basic loop
while (!finished) {
switch (form_driver(form, c = form_virtualize(form, w))) {
case E_OK:
MvAddStr(5, 57, field_buffer(secure, 1));
clrtoeol();
refresh();
break;
case E_UNKNOWN_COMMAND:
finished = my_form_driver(form, c);
break;
default:
beep();
break;
}
uses its form_virtualize function to read characters (or form-requests). The printable characters that you are (not) seeing are handled by form_driver which updates the current field on the form. You can manipulate the field-buffer and do other special things as done in form_virtualize, but updating fields in the form is why you would use form_driver.
You need to use echo and noecho to turn echoing on/off. You could bake that part into an input function if you'd like:
#include <memory>
struct input_context {
input_context() {
echo(); // echo typed characters
curs_set(1); // show the cursor
}
~input_context() {
curs_set(0); // hide the cursor
noecho(); // turn off echoing
}
};
std::string get_string(WINDOW* win, size_t len) {
std::unique_ptr<char[]> buf = std::make_unique<char[]>(len);
input_context dummy;
if(wgetnstr(win, buf.get(), len) != ERR) return std::string{buf.get()};
return {};
}
Note 1: You should only use new/delete (and new[]/delete[]) when all other options have been depleted. In your main, you could just replace the dynamic creation of your WelcomeMenu with an automatic variable:
int main(){
WelcomeMenu myConWin;
}
Note 2: Use nullptr, not NULL.
fields[4] = nullptr; // was NULL
Note 3: As stated by #kebs in the comments, you should use the C++ versions of the header files:
#include <cassert> // was assert.h
#include <cstdio> // was stdio.h
#include <cstdlib> // was stdlib.h

WriteConsoleOutputCharacter Drawing extra pixel thick of blank space

Ive been designing a roguelike video game in the console.
My problem is i initially draw the entire map with writeconsoleoutput at once then use writeconsoleoutputcharacter to redraw whats neccessary. But i have found that it draws an extra pixel thick on the right side.
This essentially erases one pixel off the tile on the right side.
Does anyone know a way to make it stop drawing a character and adding a 1 pixel blank space on the right side of the character.
EDIT: ONE WORKAROUND I HAVE FOUND IS TO REDRAW THE LINES THE PLAYER STEPS ON BUT IT ISNT PERFECT ONCE IN A WHILE I CAN NOTICE A FLICKER. Would be preferable to just redraw characters on an individual basis without any pixels attached on the end. or anywhere else.
The Code used to print the character
void printchar(char character, COORD location,short color)
{
const char *pointer = &character;
//short LENGTH = 1;
DWORD dwWritten = 0;
std::vector<WORD> attributes;attributes.clear();;
setAttributesChar(color,attributes);//Pushes back the color
if(attributes.size() == 1)
{ WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE),&attributes[0], attributes.size(), location, &dwWritten);
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), pointer, attributes.size(), location, &dwWritten);
}
}
void setAttributesChar(short color,std::vector<WORD> &attributes)
{
switch(color)
{
case DEFAULTCOLOR:
attributes.push_back(FOREGROUND_INTENSE_WHITE);return;
case HOVEREDCOLOR:
attributes.push_back(FOREGROUND_GREEN);return;
case RED:
attributes.push_back(FOREGROUND_RED);return;
case GOLD:
attributes.push_back(FOREGROUND_INTENSE_YELLOW);return;
case REDWHITE:
attributes.push_back(COMBINED_REDWHITE);return;
case YELLOWPURPLE:
attributes.push_back(COMBINED_YELLOWPURPLE);return;
case NPCCOLOR:
attributes.push_back(FOREGROUND_INTENSE_CYAN);return;
case PURPLE:
attributes.push_back(FOREGROUND_MAGENTA);return;
case REDPURPLE:
attributes.push_back(COMBINED_REDPURPLE);return;
case BLUE:
attributes.push_back(FOREGROUND_BLUE);return;
case BLUEPURPLE:
attributes.push_back(COMBINED_BLUEPURPLE);return;
case INTENSEGREEN:
attributes.push_back(FOREGROUND_INTENSE_GREEN);return;
case REDGREEN:
attributes.push_back(COMBINED_REDGREEN);return;
case BWHITE:
attributes.push_back(BACKGROUND_WHITE);return;
}
}
EXAMPLE:
BEFORE CHARACTER WALKS OVER ROAD: BEFORE IMAGE
AFTER CHARACTER WALKS OVER ROAD: AFTER IMAGE
EXECUTABLE LINK: EXECUTABLE
I have created a working example that you guys can compile(Assuming u use windows) to see what is occuring. In it i create a console set the size fill the screen with the asci symbol 223. then i use Writeconsoleoutchar to print a green 223 symbol. You can see the extra drawn black pixel line.
#include <windows.h>
#include <cwchar>
#include <vector>
enum COLORS{HOVEREDCOLOR};
void setAttributesChar(short color,std::vector<WORD> &attributes)
{
switch(color)
{
case HOVEREDCOLOR:
attributes.push_back(FOREGROUND_GREEN);return;
}
}
void printchar(char character, COORD location,short color)
{
const char *pointer = &character;
//short LENGTH = 1;
DWORD dwWritten = 0;
std::vector<WORD> attributes;attributes.clear();;
setAttributesChar(color,attributes);//Pushes back the color
if(attributes.size() ==1)
{ WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE),&attributes[0], attributes.size(), location, &dwWritten);
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), pointer, attributes.size(), location, &dwWritten);
}
}
#define SCREENWIDTH 1550
#define SCREENHEIGHT 850
void SETWINDOWUP(DWORD &SIZE)
{
CONSOLE_SCREEN_BUFFER_INFO info;
MoveWindow(GetConsoleWindow(),0,0,SCREENWIDTH,SCREENHEIGHT,true); //MOVE WINDOW TO 0,0 AND MAKE 1600 BY 880
::SetWindowPos(GetConsoleWindow(), HWND_TOPMOST, 0, 0, 0,0, SWP_DRAWFRAME | SWP_NOREPOSITION | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); //SET WNDOWS POSITION COMPARED TO OTHER WINDOWS IN DRAW ORDER
::SetWindowPos(GetConsoleWindow(),HWND_NOTOPMOST, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hout,&info);
COORD newBuffersize =
{
info.srWindow.Right - info.srWindow.Left + 1,
info.srWindow.Bottom - info.srWindow.Top + 1
};
SetConsoleScreenBufferSize(hout,newBuffersize);
SIZE = info.dwSize.X * info.dwSize.Y;
//EDIT REGULATED FONT SIZE
CONSOLE_FONT_INFOEX cfi;
std::wcscpy(cfi.FaceName, L"Lucida Console"); // Choose your font
cfi.FontFamily = FF_DONTCARE;
cfi.nFont = 0;
cfi.dwFontSize.X = 0;
cfi.dwFontSize.Y = 25; // Height
cfi.FontWeight = FW_BOLD;
cfi.cbSize = sizeof(cfi);
SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), false, &cfi);
}
int main()
{
Sleep(500);DWORD SIZE = 0;SETWINDOWUP(SIZE);
DWORD charswritten;COORD start = {0,0};TCHAR CHARACTER = 223;
FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),CHARACTER,SIZE,start,&charswritten);
Sleep(500);
printchar(223,{6,5},HOVEREDCOLOR);
Sleep(500);
return 0;
};

Need this to play music

Game dev class. Trying to understand what i did wrong here. Did I add the wrong thing, or do i have it at the wrong place.
my goal was to add music.
#include "allegro5/allegro.h"
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/allegro_native_dialog.h>
#include <stdio.h>
#include <string>
#include <allegro5\allegro_audio.h>
#include <allegro5\allegro_acodec.h>
#define FPS 60
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define BLACK al_map_rgb(0, 0, 0)
#define WHITE al_map_rgb(255, 255, 255)
//Prototypes
bool initializeAllegro();
//Essential Allegro pointers
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *eventQueue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_FONT *arial14;
int main()
{
ALLEGRO_BITMAP *backgroundImage; //Bitmap for the background image(star field)
int backgroundImageWidth = 0, backgroundImageHeight = 0;
bool redrawRequired = true;
//Using std:string for name, so length is not a factor
std::string userName = "";
std::string prompt1 = "Enter your Player's name below";
std::string prompt2 = "(Letters & digits only. Backspace to erase.)";
std::string prompt3 = "Press Enter to accept...";
std::string prompt4 = "Press Escape to exit...";
char keyToAdd = ' ';
bool enteringUserName = true;
bool quit = false;
//Initialize allegro, etc
if (!initializeAllegro()) return -1;
//load the arial font
arial14 = al_load_font("arial-mt-black.ttf", 14, 0);
if (!arial14)
{
return -3;
}
//test running music
al_init_acodec_addon();
ALLEGRO_SAMPLE *song = al_load_sample("hideandseek.wav");
ALLEGRO_SAMPLE_INSTANCE *songInstance = al_create_sample_instance(song);
al_set_sample_instance_playmode(songInstance, ALLEGRO_PLAYMODE_LOOP);
al_attach_sample_instance_to_mixer(songInstance, al_get_default_mixer());
//Load the background picture
if (!(backgroundImage = al_load_bitmap("starbackground.bmp")))
{
return -5;
}
//Get dimensions of the background image
backgroundImageWidth = al_get_bitmap_width(backgroundImage);
backgroundImageHeight = al_get_bitmap_height(backgroundImage);
//Set the back buffer as the drawing bitmap for the display
al_set_target_bitmap(al_get_backbuffer(display));
//Initialize the event queue
eventQueue = al_create_event_queue();
if (!eventQueue)
{
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
//Register events as arriving from these sources: display, timer, keyboard
al_register_event_source(eventQueue, al_get_display_event_source(display));
al_register_event_source(eventQueue, al_get_timer_event_source(timer));
al_register_event_source(eventQueue, al_get_keyboard_event_source());
al_flip_display();
//play song
al_play_sample_instance(songInstance);
//Start up the timer. Don't do this until just before the game is to start!
al_start_timer(timer);
//This would be a loop solely for entering the user's name, not starting the game
//Allegro keycodes are laid out as follows. (Full set of key codes is included in keycodes.h)
//Key codes for capital letters are 1 - 26 for A - Z
//Digit values are 27 - 36 for the top digits (0 - 9), and 37 - 46 for the keypad
while (!quit)
{
ALLEGRO_EVENT evt;
//Wait for one of the allegro-defined events
al_wait_for_event(eventQueue, &evt);
//An event was generated. Check for all possible event types
switch (evt.type)
{
case ALLEGRO_EVENT_KEY_CHAR:
if (evt.keyboard.keycode >= 1 && evt.keyboard.keycode <= 26) //It's a capital letter
{
//Convert to ASCII capital
keyToAdd = *al_keycode_to_name(evt.keyboard.keycode);
userName += keyToAdd;
}
else if (evt.keyboard.keycode >= 27 && evt.keyboard.keycode <= 36)
{
//Convert to digit
keyToAdd = evt.keyboard.keycode + 21;
userName += keyToAdd;
}
//Handle digits on keypad
else if (evt.keyboard.keycode >= 37 && evt.keyboard.keycode <= 46)
{
//Convert to digit
keyToAdd = evt.keyboard.keycode + 11;
userName += keyToAdd;
}
else //Handle a few other keys
{
switch(evt.keyboard.keycode)
{
case ALLEGRO_KEY_BACKSPACE:
if (userName.length() > 0)
userName = userName.substr(0, userName.length() - 1);
break;
//Enter key stops username entry
case ALLEGRO_KEY_ENTER:
case ALLEGRO_KEY_PAD_ENTER:
enteringUserName = false;
break;
case ALLEGRO_KEY_ESCAPE:
quit = true;
break;
}
}
break;
case ALLEGRO_EVENT_DISPLAY_CLOSE:
quit = true;
break;
case ALLEGRO_EVENT_TIMER:
redrawRequired = true;
break;
}//END switch evt.type
//Rerender the entire scene
if (redrawRequired && al_is_event_queue_empty(eventQueue))
{
redrawRequired = false;
al_clear_to_color(BLACK); //Just in case
//Draw background
al_draw_scaled_bitmap(backgroundImage, 0, 0, backgroundImageWidth, backgroundImageHeight,
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
//Prompt for name to be entered
al_draw_textf (arial14, WHITE, 0, 30, 0, "%s", prompt1.c_str());
al_draw_textf (arial14, WHITE, 0, 50, 0, "%s", prompt2.c_str());
if (userName.length() > 0)
{
if (enteringUserName)
{
al_draw_textf (arial14, WHITE, 0, 70, 0, "%s", userName.c_str());
al_draw_textf (arial14, WHITE, 0, 90, 0, "%s", prompt3.c_str());
}
else
{
al_draw_textf (arial14, WHITE, 0, 70, 0, "You entered your name as-->%s", userName.c_str());
}
}
al_draw_textf(arial14, WHITE, 0, 400, 0, "%s", prompt4.c_str());
al_flip_display();
}//END rendering the screen
}//END input Loop
//Release all dynamically allocated memory
al_destroy_bitmap(backgroundImage);
al_destroy_font(arial14);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(eventQueue);
//destroy songs
al_destroy_sample(song);
al_destroy_sample_instance(songInstance);
return 0;
}//END main
//Take care of Allegro initialization tasks
//Return false if any fail.
bool initializeAllegro()
{
bool success = true;
//Init basic environment
if (!al_init())
{
al_show_native_message_box(NULL, "ERROR", "Allegro failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize keyboard input
if (!al_install_keyboard())
{
al_show_native_message_box(NULL, "ERROR", "Keyboard failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize timer
timer = al_create_timer(1.0 / FPS);
if (!timer)
{
al_show_native_message_box(NULL, "ERROR", "Timer failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize display
display = al_create_display(SCREEN_WIDTH, SCREEN_HEIGHT);
if (!display)
{
al_show_native_message_box(NULL, "ERROR", "Display failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize the image mechanism
if (!al_init_image_addon())
{
al_show_native_message_box(NULL, "ERROR", "Image addon failed to initialize!", NULL, NULL, NULL);
success = false;
}
al_init_font_addon();
al_init_ttf_addon();
return success;
}//END initializeAllegro
Any wav file should work.
i get the error message -
First-chance exception at 0x0F196486
(allegro-5.0.10-monolith-md-debug.dll) in User Input Project.exe:
0xC0000005: Access violation reading location 0x00000000. Unhandled
exception at 0x0F196486 (allegro-5.0.10-monolith-md-debug.dll) in User
Input Project.exe: 0xC0000005: Access violation reading location
0x00000000.
The program '[9596] User Input Project.exe' has exited with code 0
(0x0).
I mentioned to step through things with a debugger in my comment, but the code smell here is this:
ALLEGRO_SAMPLE *song = al_load_sample("hideandseek.wav");
ALLEGRO_SAMPLE_INSTANCE *songInstance = al_create_sample_instance(song);
You should Definitely be checking for (song == NULL) before you call al_create_sample_instance()
If your path to the .WAV file is wrong or if the loading fails for any other reason, then al_load_sample() will return NULL, and you shouldn't be trying to do anything with song

Bitblt,createdibsection, image comes out corrupted

hi im trying to capture screenshot but the image comes out corrupted, can anyone see whats wrong wth the code, basically im trying to use createdibsection so i can accesss the bits directly.
heres what the resulting picture looks
http://oi47.tinypic.com/33c4zko.jpg
bool FrameData::Create(int width, int height, ImageFormat imgFormat, HWND sourceWindow)
{
if(width < 0)
return false;
srcWndDC = GetDC(sourceWindow);
hdc = CreateCompatibleDC(srcWndDC);
if(hdc == nullptr || srcWndDC == nullptr)
{
return false;
}
memset(&bmpInfo, 0, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = width;
bmpInfo.bmiHeader.biHeight = -height; // top-down
bmpInfo.bmiHeader.biPlanes = 1;
switch(imgFormat)
{
case ImageFormat::RGB16:
bmpInfo.bmiHeader.biBitCount = 16;
break;
case ImageFormat::RGB24:
bmpInfo.bmiHeader.biBitCount = 24;
break;
case ImageFormat::RGB32:
bmpInfo.bmiHeader.biBitCount = 32;
break;
default:
return false;
}
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = height * width * imgFormat;
hBitmap = CreateDIBSection(srcWndDC, &bmpInfo, DIB_RGB_COLORS, (void**)&bits, NULL, NULL);
if(hBitmap == nullptr)
{
return false;
}
return true;
}
bool FrameData::SaveFrameToFile(std::string& filename)
{
BITMAPFILEHEADER bmpFileHdr = {0};
bmpFileHdr.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHdr.bfType='MB';
bmpFileHdr.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
std::ofstream outfile;
outfile.open(filename);
if(!outfile.is_open())
{
return false;
}
outfile.write((char*)&bmpFileHdr, sizeof(BITMAPFILEHEADER));
outfile.write((char*)&bmpInfo.bmiHeader, sizeof(BITMAPINFOHEADER));
outfile.write((char*)bits, bmpInfo.bmiHeader.biSizeImage);
outfile.close();
return true;
}
thats the code, then i just use this to capture the screen
SelectObject(data.GetHDC(), data.GetHBitmap());
BitBlt(data.GetHDC(),0,0,data.GetWidth(), data.GetHeight(), data.GetSourceWindowDC(),0,0 , SRCCOPY | CAPTUREBLT);
Don't have time to check all the details of your bitmap structures initialization but try outfile.open(filename, ios_base::out + ios_base::bin); instead of outfile.open(filename);, else all your 0x0A bytes ('\n' or LineFeed) are replaced by 0x0D ('\r' or CarriageReturn) followed by 0x0A (2 bytes MS-DOS/Windows text file end-of-line sequence)!
Also I think that bmpInfo.bmiHeader.biSizeImage should be something like height * 4 * (((width * bmpInfo.bmiHeader.biBitCount) + 0x1F) / 0x20) (each row of pixels must be 32-bit aligned, resulting in up to 3 unused padding bytes at the end of each row, doesn't matter for RGB32 format).