c++ draw images on bitmap and save - c++

//background feel free to skip
I am creating a animated clock for my Windows desktop background. Basically I create a bmp image with code using pre-drawn images (the numbers of the clock) then a save the bmp image and set the desktop background to that image. I tried using c# and .Net but inorder to set the desktop background I have to call a WinApi function (SystemParametersInfo). Calling this function from c# takes almost a second. Too long for an animation.
So now I want to do the same except in c++, I hope calling SystemParametersInfo will be faster from unmanaged code. EDIT:I used c# to create the bmp and c++ to set the desktop background and it is faster
//the question
I created a Win32 console project using Visual Studio 2012, and I managed to embed the pre-drawn images as resources. Now I need to combine the images onto a single bitmap and save it to the hdd. It has been four years since I last programmed in c++ so I have no idea how to draw a image and save it.
The code I found when googling all have to do painting to the screen, which I obviously don't want to do.
So how do create a bitmap, draw a resource image (also a bitmap) on it, and save it all in c++?
Thanks for any assistance.

This question is more about Windows API than about C++.
If you want to use Windows API, refer to GDI+:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms533798.aspx
.NET Framework wraps GDI+, so classes may be familiar for you just in C++ and not in C# with manual memory management, etc.
There are also some other libraries that can manipulate images. Personally me like GD, a C-style images manipulation library with many languages bindings.
https://bitbucket.org/libgd/gd-libgd/downloads
However, as always with Open Source, you will have to build it youself togeather with dependencies. So, probably GDI+ is the best.

As it turns out Win32 (c++) code is quick at changing the desktop background (under 20ms on i5 3.2ghz), where as the managed C# code takes anywhere from 500 to 3000ms. However, the unmanaged c++ code takes forever to draw the image (300 to 1500ms). So what I did was make two programs that work together. The managed C# program creates the image (under 20ms) and then saves it. The unmanaged c++ sets the saved image as the desktop background.
C#
static void Main(string[] args)
{
//the images positions where calculated manually and hard coded
//first image positoon
//X:532
//Y:335
Bitmap TheImage = new Bitmap(1366, 768);
Graphics G = Graphics.FromImage(TheImage);
DateTime DTNow = DateTime.Now;
while (true)
{
//get the time
DTNow = DateTime.Now;
//draw the canvas
G.DrawImage(Resources.canvas, 0, 0,1366,768);
//draw the first image of the hour
G.DrawImage(GetImage(DTNow.Hour,0),532,330,174,217);
//draw the second image of the hour
G.DrawImage(GetImage(DTNow.Hour, 1), 711, 330, 174, 217);
//draw the colon
if (DTNow.Second % 2 == 0) G.DrawImage(Resources.aColon, 890, 365,57,147);
//draw the first digit of the minute
G.DrawImage(GetImage(DTNow.Minute, 0), 952, 330, 174, 217);
//draw the second digit of the minute
G.DrawImage(GetImage(DTNow.Minute, 1), 1131, 330, 174, 217);
//save the file
try
{
File.Delete("C:\\background.bmp");
TheImage.Save("C:\\background.bmp", ImageFormat.Bmp);
}
catch
{
}
//calculate sleep time and sleep until next second
DTNow = DateTime.Now.AddSeconds(1);
DateTime NextSecond = new DateTime(DTNow.Year,DTNow.Month,DTNow.Day, DTNow.Hour,DTNow.Minute, DTNow.Second,500);
DTNow = DateTime.Now;
System.Threading.Thread.Sleep((int)NextSecond.Subtract(DTNow).TotalMilliseconds);
}
}
static Bitmap GetImage(int Number, int Index)
{
string NS = Number.ToString();
if (NS.Length < 2) NS = "0" + NS;
char[] digits = NS.ToCharArray();
switch (digits[Index])
{
case '1': { return Resources.a1; }
case '2': { return Resources.a2; }
case '3': { return Resources.a3; }
case '4': { return Resources.a4; }
case '5': { return Resources.a5; }
case '6': { return Resources.a6;}
case '7': { return Resources.a7;}
case '8': { return Resources.a8;}
case '9': { return Resources.a9; }
default: { return Resources.a0; }
}
}
}
c++
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char*, int nShowCmd)
{
while(true){
SystemParametersInfo(SPI_SETDESKWALLPAPER,0, L"C:\background.bmp", SPIF_UPDATEINIFILE);
int MS = (int)(((long)floor((long)clock()/(long)CLOCKS_PER_SEC)*1000l+1000l)-((long)clock()));
if(MS<=1000 && MS>0){
std::this_thread::sleep_for(std::chrono::milliseconds(MS));
}
else
{
}
}
return 0;
}

Related

Multiple key presses detected on SFML, can't solve it in any other way and works differently on different machines

this is my first post here.
I am trying to solve a problem I am having with my SFML project where I am using multiple clients, that communicate through texts that can be typed in the rendered window and then sent to the other sockets using a selector.
My problem is that everytime i press one button of the keyboard, the window detects like 3 or 4, and if I try it on another machine, the behaviour changes.
I tried almost every solution, including the setKeyRepeatEnabled(false);
This is the update function
void Client::Update(Input* input,sf::Event& Ev, sf::Font& font, sf::RenderWindow& window)
{
if (input->isKeyDown(sf::Keyboard::Return))
{
sf::Packet packet;
packet << id + ": " + text;
socket.send(packet);
sf::Text displayText(text, font, 20);
displayText.setFillColor(sf::Color::Red);
chat.push_back(displayText);
text = "";
input->setKeyUp(sf::Keyboard::Return);
}
else if (input->isKeyDown(sf::Keyboard::Backspace))
{
if (text.size() > 0)
text.pop_back();
}
else if (input->isKeyDown(sf::Keyboard::Space))
{
text += ' ';
}
else if (Ev.type == sf::Event::TextEntered)
{
text += Ev.text.unicode;
return;
}
//sf::Event::TextEntered
//text += Ev.text.unicode;
}
This is the render one.
void Client::Render(sf::Font& font, sf::RenderWindow& window)
{
sf::Packet packet;
socket.receive(packet);
std::string temptext;
if (packet >> temptext)
{
sf::Text displayText(temptext, font, 20);
displayText.setFillColor(sf::Color::Blue);
chat.push_back(displayText);
}
int i = 0;
for (i; i < chat.size(); i++)
{
chat[i].setPosition(0, i * 20);
window.draw(chat[i]);
}
sf::Text drawText(text, font, 20);
drawText.setFillColor(sf::Color::Red);
drawText.setPosition(0, i * 20);
window.draw(drawText);
}
I don't recognize the isKeyDown function as part of SFML, so I assume you either is something you implemented or is part of a previous version of SFML (being the current 2.5.1).
There are three ways to detect input from keyboard in SFML.
sf::Keyboard::isKeyPressed: looks like this is the one you are using. It will be true every cycle that the key is pressed. You definetly don't want this. The window.setKeyRepeatEnabled(false) will obviously not work because you don't get the input through the window, but directly from the keyboard.
sf::Event::KeyPressed and sf::Event::KeyReleased events: for this, window.setKeyRepeatEnabled(false) will work, but still it's not the recommended way to deal with text input, as it would require a lot of juggling by your side to handle key combinations (accents, uppa.
sf::Event::TextEntered event: now, this is the best and recommended way to handle typing. Check the tutorial to see how to use it.

Xbox Live leaderboard in UWP game returns with error 404

When trying to retrieve a leaderboard from Xbox Live, the stat event type get_leaderboard_complete returns the error code 404. I'm using Xbox Live in a UWP game in the Creators Program.
I'm am able to set and retrieve the stat for the user. This part works without issue:
xbox_live_result<stat_value> serverStat = m_statsManager->get_stat(m_user, L"score");
auto result = serverStat.payload();
if (result.as_integer() < score) {
setStatForUser(m_user, L"score", score);
}
My code is adopted from the leaderboard example in the Xbox Live Samples. So to retrieve my leaderboard I'm calling getLeaderboard(m_user, L"score"); and every frame I'm calling statsManager->do_work();.
// Process events from the stats manager
// This should be called each frame update
auto statsEvents = m_statsManager->do_work();
std::wstring text;
for (const auto& evt : statsEvents)
{
switch (evt.event_type())
{
case stat_event_type::local_user_added:
text = L"local_user_added";
break;
case stat_event_type::local_user_removed:
text = L"local_user_removed";
break;
case stat_event_type::stat_update_complete:
text = L"stat_update_complete";
break;
case stat_event_type::get_leaderboard_complete:
text = L"get_leaderboard_complete";
auto getLeaderboardCompleteArgs = std::dynamic_pointer_cast<leaderboard_result_event_args>(evt.event_args());
processLeaderboards(evt.local_user(), getLeaderboardCompleteArgs->result());
break;
}
stringstream_t source;
source << _T("StatsManager event: ");
source << text;
source << _T(".");
log("%S", source.str().c_str());
}
Because I'm able to set and retrieve the stat without issue, I wonder if maybe it's an issue with the Xbox Live backend? However, I'm not very familiar with the xbox live 2017 data platform, and I may be calling something incorrectly.
I discovered a solution:
Create a new stat/leaderboard in Dev Center.
Press the “Test” button. This is important because it publishes the service configuration.
I’m unsure why the original stat didn’t work. Perhaps because I used the word “score” as the statID.

How do I put a subwindow within a subwindow?

I am using NCurses to try and get the desired output:
However with the following code:
int main(void)
{
WINDOW *white_space,*red_space,*blue_box;
int maxx,maxy;
initscr();
start_color();
init_pair(1,COLOR_WHITE,COLOR_BLUE);
init_pair(2,COLOR_RED,COLOR_WHITE);
init_pair(3,COLOR_BLACK,COLOR_GREEN);
init_pair(4,COLOR_RED,COLOR_RED);
white_space = subwin(stdscr,10,76,6,2);
red_space = subwin(stdscr,1,80,23,0);
getmaxyx(white_space,maxy,maxx);
blue_box = subwin(white_space,maxy-1,maxx-1,8,20);
if(white_space == NULL)
{
addstr("Unable to create subwindow\n");
endwin();
return 1;
}
bkgd(COLOR_PAIR(1));
addstr("Master window");
wbkgd(white_space,COLOR_PAIR(2));
mvwprintw(white_space, 0, 0, "%46s", "White space");
wbkgd(blue_box,COLOR_PAIR(4));
wbkgd(red_space,COLOR_PAIR(3));
waddstr(red_space,"Alert area");
wrefresh(white_space);
wrefresh(stdscr);
refresh();
getch();
endwin();
return 0;
}
I get the following output:
Is it possible to create a subwindow within a subwindow?
Thanks
ncurses (any non-buggy version of curses) supports subwindows, as noted in the manual.
In the given example, there are a few problems noticed:
white_space = subwin(stdscr,10,76,6,2);
red_space = subwin(stdscr,1,80,23,0);
getmaxyx(white_space,maxy,maxx);
blue_box = subwin(white_space,maxy-1,maxx-1,8,20);
For instance:
the initial size given to white_space does not take into account the actual screen-size (which could be narrower than 80 columns)
the size asked for blue_box is only slightly smaller than white_space, but starts far enough to the right that the window could not (in 80 columns) be shown. If so, no window is created.
There are several programs in ncurses-examples using subwin and the related derwin, which may be useful for comparison.

SFML help (Using the Sleep function in <Windows.h>)

I need some help with my SFML/C++ code in Visual C++ 2010 Express Edition. I am trying to get my text (livesLeft) to "You Win!" Before the program sleeps. This is making the player know that he won. But instead, the program goes right to sleep and changes the text right as it is closing, so you only see it change for a few milliseconds. I can't even read it.
bool play = true;
bool win = false;
bool touchFinish = false;
int lives = 3;
sf::Font arial;
if(arial.loadFromFile("Fonts/arial.ttf") == 0)
{
return 1;
}
sf::Text livesLeft;
livesLeft.setFont(arial);
livesLeft.setCharacterSize(30);
livesLeft.setString("Lives: ");
livesLeft.setPosition(0, 0);
livesLeft.setColor(sf::Color::White);
sf::RectangleShape finish;
finish.setSize(sf::Vector2f(200, 600));
finish.setPosition(700, 0);
finish.setFillColor(sf::Color::Green);
Those are my variables in use and this is my code where I'm trying to change the text:
if(player.getGlobalBounds().intersects(finish.getGlobalBounds()))
{
livesLeft.setString("You Win!");
touchFinish = true;
}
if(touchFinish)
{
win = true;
}
if(win)
{
Sleep(5000);
play = false;
}
I also forgot to add in that I do have the rendering at the end:
window.clear();
window.draw(livesLeft);
window.draw(finish);
window.draw(player);
window.draw(obs1);
window.draw(obs2);
window.draw(obs3);
window.draw(obs4);
window.draw(obs5);
window.draw(obs6);
window.draw(obs7);
window.draw(obs8);
window.draw(obs9);
window.draw(obs10);
window.draw(obs11);
window.draw(obs12);
window.draw(obs13);
window.display();
This is most likely due to the fact that you aren't calling the display method for you window. Telling the text to change simply prepares the next framebuffer to display the new text, but because you never tell the window to update its display before sleeping, it never displays the new framebuffer.
Here is a quick example of a simple program using SFML. Notice the window.display() method at the end of the main game loop.
You effectively want to be doing this:
if(win)
{
window.display();
Sleep(5000);
play = false;
}
The reason why you need to update the display before hand again is because Sleep(5000); blocks the thread, essentially meaning that it sits at that call for 5000ms. Also, if you want to keep the previous items on the screen, you'll want to redraw those before window.display(); as well, since these won't be in the next framebuffer.

Changing color of a specific character in an item in CListCtrl in MFC

I have a CListCtrl and I need to change the color of A SPECIFIC character/set of characters (which I choose by comparison) from the text of every cell in the list.
I know how to change the color of the entire text of the cell when I find the character/set of characters (by using 'strstr' command), but I can't find an example which shows how to change ONLY the character/set of characters.
Here is a sample of my code:
void Agenda::OnCustomdrawMyList( NMHDR* pNMHDR, LRESULT* pResult )
{
NMLVCUSTOMDRAW* pLVCD = (NMLVCUSTOMDRAW*)pNMHDR;
*pResult = CDRF_DODEFAULT;
if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
{
*pResult = CDRF_NOTIFYITEMDRAW;
return;
}else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
{
*pResult = CDRF_NOTIFYSUBITEMDRAW;
return;
}else if ( (CDDS_SUBITEM | CDDS_ITEMPREPAINT) == pLVCD->nmcd.dwDrawStage )
{
// So right now I am in the stage where a SUBITEM is PREPAINTED
int nItem = pLVCD->nmcd.dwItemSpec;
int nSubItem = pLVCD->iSubItem;
char a[100];
listControl.GetItemText(nItem,nSubItem,a,100);
COLORREF textColorFound, textColorDefault;
textColorDefault = RGB(0,0,0);
pLVCD->clrText = textColorDefault;
char* startingFrom;
if( (startingFrom = strstr(a,filterText)) != NULL ) {
// Could I set a pointer here or something like that so
// the coloring could start only from 'startingFrom'
// and stop at 'strlen(filterText)' characters?
textColorFound = RGB(205,92,92);
pLVCD->clrText = textColorFound;
}
*pResult = CDRF_DODEFAULT;
}
}
listControl is the variable for my CListCtrl
the other things are pretty self-explanatory
No, you cannot do this. What you will have to do is custom-draw the text in question. This will be tricky because you will have to do it with two different calls, between which you will have to manually adjust the color and the drawing location to account for the intercharacter spacing etc. And you better hope that you don't need to do multi-line output.
Take a look at the article Neat Stuff to Do in List Controls Using Custom Draw by Michael Dunn on CodeProject to get some ideas on how to proceed.
Alternatively, if you can use the Toolkit Pro toolkit from CodeJock you can leverage their "XAML" support (I use quotes because it's not really XAML, but their own implementation of a subset of XAML) and let them do all the hard work.
Digging on the same issue; But I wouldn't go so far as modifying/adding to the default Windows behaviour for painting strings... apparently that would be the endpoint of having it owner-drawn.(aici am murit si eu :).