summaryrefslogtreecommitdiff
path: root/osframework/source/demos/Demo4
diff options
context:
space:
mode:
Diffstat (limited to 'osframework/source/demos/Demo4')
-rw-r--r--osframework/source/demos/Demo4/Board.cpp488
-rw-r--r--osframework/source/demos/Demo4/Board.h331
-rw-r--r--osframework/source/demos/Demo4/Demo4 VS2005 WideString.vcproj251
-rw-r--r--osframework/source/demos/Demo4/Demo4 VS2005.vcproj251
-rw-r--r--osframework/source/demos/Demo4/Demo4 WideString.vcproj158
-rw-r--r--osframework/source/demos/Demo4/Demo4.dsp136
-rw-r--r--osframework/source/demos/Demo4/Demo4.vcproj158
-rw-r--r--osframework/source/demos/Demo4/GameApp.cpp395
-rw-r--r--osframework/source/demos/Demo4/GameApp.h122
-rw-r--r--osframework/source/demos/Demo4/TitleScreen.cpp210
-rw-r--r--osframework/source/demos/Demo4/TitleScreen.h127
-rw-r--r--osframework/source/demos/Demo4/main.cpp47
12 files changed, 2674 insertions, 0 deletions
diff --git a/osframework/source/demos/Demo4/Board.cpp b/osframework/source/demos/Demo4/Board.cpp
new file mode 100644
index 0000000..477c0c4
--- /dev/null
+++ b/osframework/source/demos/Demo4/Board.cpp
@@ -0,0 +1,488 @@
+#include "Board.h"
+#include "GameApp.h"
+
+// Contains all the resources from the resources.xml file in our
+// properties directory. See that file for more information.
+#include "Res.h"
+
+// You should remember these files from the previous demos
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Color.h"
+#include "SexyAppFramework/Rect.h"
+#include "SexyAppFramework/ButtonWidget.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/ImageFont.h"
+
+// The following are needed for some new widgets we're going to learn about:
+#include "SexyAppFramework/EditWidget.h"
+#include "SexyAppFramework/Checkbox.h"
+#include "SexyAppFramework/ListWidget.h"
+#include "SexyAppFramework/ScrollbarWidget.h"
+#include "SexyAppFramework/ScrollListener.h"
+
+// As part of our pitch shifted sound example, we'll need to
+// access the sound manager in our GameApp class as well as
+// individual sound instances:
+#include "SexyAppFramework/SoundManager.h"
+#include "SexyAppFramework/SoundInstance.h"
+
+// Used for file I/O:
+#include "SexyAppFramework/Buffer.h"
+
+// The SexyAppFramework resides in the "Sexy" namespace. As a convenience,
+// you'll see in all the .cpp files "using namespace Sexy" to avoid
+// having to prefix everything with Sexy::
+using namespace Sexy;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::Board(GameApp* theApp)
+{
+ mApp = theApp;
+
+
+ mButton1 = NULL;
+ mButton2 = NULL;
+ mEditWidget = NULL;
+ mCheckboxWidget = NULL;
+ mListWidget = NULL;
+ mScrollbarWidget = NULL;
+
+ mMotionX = mUpdateFMotionX = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+ delete mButton1;
+ delete mButton2;
+ delete mEditWidget;
+ delete mCheckboxWidget;
+ delete mListWidget;
+ delete mScrollbarWidget;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+
+ Widget::Update();
+
+ // As an example to illustrate the difference between smooth motion via UpdateF
+ // and the traditional motion via Update, we'll udpate the two MotionX variables
+ // separately.
+ if ((mMotionX += 5.0f) >= mWidth)
+ mMotionX = (float) -IMAGE_ROBOTROBOT->GetWidth();
+
+ MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::UpdateF(float theFrac)
+{
+ // This is very similar to Update, except that since this function
+ // gets called a different number of times depending on the refresh
+ // rate of the monitor, "theFrac" can be a variable number, and we
+ // need to multiply our normal motion change of 5.0 pixels per
+ // update by "theFrac" to get our smooth motion. See the header
+ // comment for this function in Board.h for more details.
+ if ((mUpdateFMotionX += 5.0f * theFrac) >= mWidth)
+ mUpdateFMotionX = (float) -IMAGE_ROBOTROBOT->GetWidth();
+
+ // No need to MarkDirty: We're doing it in Board::Update already.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ // Clear the screen to black
+ g->SetColor(Color(0, 0, 0));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // Draw the image first using the standard method, with the coordinate
+ // updated via Board::Update as an example of non-smooth motion.
+ // Let's also print some text too.
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color(255, 255, 255));
+ g->DrawString(_S("Non smooth motion is jerky"), 10, 100);
+
+ // What's this? A new DrawImage function? Yes. Believe it. It is true.
+ // DrawImageF is just like it's best friend, DrawImage except that
+ // it takes floating point values instead of integer ones. This is
+ // slower than DrawImage, as the resulting image is anti-aliased to
+ // give the illusion of moving at sub-pixel increments. A common
+ // optimization technique at PopCap is to use DrawImageF
+ // for motion when the user has a supported 3D card and DrawImage if
+ // the user has to run in software mode.
+ g->DrawImageF(IMAGE_ROBOTROBOT, mMotionX, 120.0f);
+
+ // Now let's draw the image but using the smooth motion amounts:
+ g->DrawString(_S("Smooth motion is silky smoothness"), 10, 200);
+ g->DrawImageF(IMAGE_ROBOTROBOT, mUpdateFMotionX, 220.0f);
+
+ // Let's draw the currently selected list item:
+ g->DrawString(mText, mListWidget->mX, mListWidget->mY + mListWidget->mHeight + 20);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::AddedToManager(WidgetManager* theWidgetManager)
+{
+ // At this point, the Board class has already been added to the
+ // widget manager. We should call our parent class' method
+ // so that it can be sure to perform any needed tasks, first.
+ Widget::AddedToManager(theWidgetManager);
+
+ // You should remember how to create buttons from Demo3. If not,
+ // go back and review. We're going to make two buttons which we'll use
+ // to do some sound playing when clicked.
+ mButton1 = new ButtonWidget(1, this);
+ mButton1->Resize(5, 5, 100, 50);
+ mButton1->SetFont(FONT_DEFAULT);
+ mButton1->mLabel = _S("Sound Left");
+ theWidgetManager->AddWidget(mButton1);
+
+ mButton2 = new ButtonWidget(2, this);
+ mButton2->Resize(106, 5, 100, 50);
+ mButton2->SetFont(FONT_DEFAULT);
+ mButton2->mLabel = _S("Sound Right");
+ theWidgetManager->AddWidget(mButton2);
+
+ // Let's set up our edit widget, shall we? The constructor is
+ // just like it is with all widgets that emit messages: first parameter
+ // is the ID to use, second is the class that will listen to its events.
+ // We're reusing some IDs here because an edit widget isn't a button
+ // widget and thus the IDs won't be confused. In your app however, you
+ // will most likely just want to use unique enums or numbers to assign
+ // to each specific widget.
+ mEditWidget = new EditWidget(1, this);
+
+ // We can't type in text if we don't have a font! Set one:
+ mEditWidget->SetFont(FONT_DEFAULT);
+
+ // Let's also set a maximum number of characters allowed.
+ // How about 15:
+ mEditWidget->mMaxChars = 15;
+
+ // If we wanted to emulate a password edit box, we could set
+ // mEditWidget->mPasswordChar. Any character typed in would
+ // then be visually replaced by mPasswordChar. We don't
+ // want to do that in this demo though.
+
+ mEditWidget->Resize(10, 300, 100, 15);
+ theWidgetManager->AddWidget(mEditWidget);
+
+ // Let's create a checkbox now. The checkbox widget does NOT
+ // have any default drawing methods, unlike the other widgets.
+ // You have to specify two images when creating a new one:
+ // an unchecked and a checked image. There is another option though:
+ // at PopCap it's common to place both the checked and unchecked image
+ // into one image file. Observe how we handle this mind warp:
+ mCheckboxWidget = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, 1, this);
+
+ // No way! The check AND unchecked images are the same! Yes. Indeed.
+ // But we're not done. Now, we need to tell the checkbox that
+ // it has to use a different part of the image for checked and a different
+ // part for unchecked. This is just like drawing a chunk of an image
+ // by specifying a Rect. For this particular image, the first cel
+ // contains the unchecked state and the second contains the checked one:
+ int checkWidth = IMAGE_CHECKBOX->GetWidth() / 2;
+ mCheckboxWidget->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ mCheckboxWidget->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+
+ // Now add it and resize it
+ mCheckboxWidget->Resize(200, 300, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ theWidgetManager->AddWidget(mCheckboxWidget);
+
+ // Let's create our list box. The first parameter is the id, second
+ // is the font to use, and third is who's going to listen to its events:
+ mListWidget = new ListWidget(1, FONT_DEFAULT, this);
+
+ // This next line instructs the list box to draw an outline around itself
+ mListWidget->mDrawOutline = true;
+
+ // Now we need to set up the colors to use for the listbox. We create
+ // a 2D array containing RGB values, which we pass via SetColors.
+ // An explanation of each of the colors is below:
+ int listWidgetColors[][3] =
+ {
+ {255, 255, 255}, //Background color
+ {255, 0, 0}, //Outline color
+ {0, 0, 0}, //Plain text not hilited
+ {0, 0, 255}, //Text color when mouse is over text
+ {128, 128, 128}, //Color of the bar displayed when an item is selected
+ {190, 0, 80} //Color of the text if it has the bar behind it and mouse is not over it
+ };
+
+ // Now we set the colors, and tell it that we're setting 6 of them
+ mListWidget->SetColors(listWidgetColors, 6);
+
+ // Let's create a scrollbar for the list widget.
+ // The list widget is already a scrollbar listener, so we will
+ // specify it as the widget responsible for dealing with the
+ // scrollbar's messages.
+ mScrollbarWidget = new ScrollbarWidget(1, mListWidget);
+
+ // We also need to let the list widget know that it actually has a scrollbar.
+ // That way, it will automatically resize it as items are added/removed.
+ // IMPORTANT: You should do this before resizing the widgets.
+ mListWidget->mScrollbar = mScrollbarWidget;
+
+ // Now resize the list widget
+ mListWidget->Resize(300, 300, 100, 100);
+
+
+ // Let's resize the scrollbar to the right of the list box. Instead of using
+ // Resize(...), we use ResizeScrollbar to indicate that the entire scrollbar,
+ // arrows and thumb included, are to be evenly resized. This will appropriately
+ // scale all the items in the scrollbar.
+ mScrollbarWidget->ResizeScrollbar(mListWidget->mX + mListWidget->mWidth,
+ mListWidget->mY,
+ 25, // an arbitrary width for the bar itself
+ mListWidget->mHeight);
+
+ // Let's make the scrollbar invisible until there are enough items in the list box
+ // to make them all not fit
+ mScrollbarWidget->SetInvisIfNoScroll(true);
+
+ theWidgetManager->AddWidget(mListWidget);
+ theWidgetManager->AddWidget(mScrollbarWidget);
+
+ // If you check out Board::EditWidgetText you'll see that we write out the
+ // contents of the list box to disk every time something is added to it, or
+ // it is cleared. For files that were created from a buffer, we can read
+ // the data back into a buffer for ease of use.
+ //
+ // IMPORTANT: You can NOT load files into a buffer if they were not
+ // created from a buffer in the first place. Thus, loading a random
+ // text or binary file is not a good idea, since the buffer will
+ // have no way to identify the datatypes beyond just a standard byte.
+ // Plase read Board::EditWidgetText for an explanation of writing
+ // with buffers.
+ //
+ // Let's load in the contents of that file, if it exists,
+ // and repopulate the list box with it. The first step is to create
+ // a Buffer object. The Buffer object will contain all the data
+ // in the file:
+ Buffer buffer;
+
+ // Check if the file exists:
+ if (mApp->FileExists("list_items.dat"))
+ {
+ // Read in all the data from the file. It will be stored in a format
+ // unique to the Buffer object:
+ if (!mApp->ReadBufferFromFile("list_items.dat", &buffer))
+ {
+ // error, the file was corrupted or some other error occurred
+ mApp->Popup("Could not read contents of list_items.txt");
+ }
+
+ // In Board::EditWidgetText we wrote out all the strings
+ // via buffer.WriteString. The order in which data is written
+ // to the buffer is the order in which it is read. Thus, if
+ // you wrote out 2 integers, a string, and 10 booleans, when
+ // reading from the buffer you'd first ask for the 2 integers,
+ // then the string, then the 10 booleans. This is important:
+ // the order DOES matter. If you asked to read a string when
+ // a long was actually the next element in the file, you'd
+ // get an error. Buffers are very useful for userprofiles or
+ // data files like that where you can guarantee an explicit
+ // file format.
+
+ while (!buffer.AtEnd())
+ mListWidget->AddLine(StringToSexyStringFast(buffer.ReadString()), true);
+ }
+
+ // If you read Board::ListClicked, you'll see that we
+ // wrote the last selected item from the list box to the registry.
+ // Let's read that value in, if it exists, and set the mText
+ // variable to it so that it displays on screen. We use the
+ // RegsitryRead... functions to grab values from the regsitry.
+ // The values are assumed to be in the registry location that you
+ // set by setting the mRegKey variable in GameApp's constructor.
+ // The functions return false if there was an error reading the
+ // key or the key doesn't exist:
+ mApp->RegistryReadString("ListItem", &SexyStringToStringFast(mText));
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::RemovedFromManager(WidgetManager* theWidgetManager)
+{
+ // This is called after we've been removed from the widget manager.
+ // Again, we should let our base class do anything it needs to, first.
+ Widget::RemovedFromManager(theWidgetManager);
+
+ // We should now also remove any widgets we are responsible for.
+ theWidgetManager->RemoveWidget(mButton1);
+ theWidgetManager->RemoveWidget(mButton2);
+ theWidgetManager->RemoveWidget(mEditWidget);
+ theWidgetManager->RemoveWidget(mCheckboxWidget);
+ theWidgetManager->RemoveWidget(mListWidget);
+ theWidgetManager->RemoveWidget(mScrollbarWidget);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::ButtonDepress(int theId)
+{
+ if (theId == 1)
+ {
+ // Our "left" button was clicked. Let's play a sound
+ // in the left speaker with a slight pitch shift.
+ // In order to play a pitch shifted sample, we have to do more
+ // than just say "PlaySample." We have to get a pointer to the sound
+ // instance that represents our sound effect. We do that by asking the
+ // app's sound manager to return us a sound instance, and we tell it
+ // the ID of the sound file that we want. Let's do that now,
+ // using the sound "SOUND_MUTATOR" which we set up in properties/resources.xml:
+ SoundInstance* sample = mApp->mSoundManager->GetSoundInstance(SOUND_MUTATOR);
+
+ // It's good to make sure the sample isn't NULL. It would be NULL if you
+ // specified an invalid sound id.
+ if (sample != NULL)
+ {
+ //Now we actually adjust the pitch. Specify the number of
+ //steps to raise (positive) or lower (negative) the original sound by.
+ //We'll just arbitrarily choose 13.
+ sample->AdjustPitch(13);
+
+ //Let's make it play on the left speaker only. We set a panning value
+ //in decibels, which for DirectX range from -10000 to +10000, where
+ //-10000 is fully left and +10000 is fully right:
+ sample->SetPan(-10000);
+
+ // Now we have the sample play. This is again slightly different than
+ // our PlaySample from previous demos. The first parameter indicates
+ // whether or not we want the sample to loop (in this case, no), and
+ // the second indicates whether the memory taken up by this special
+ // sound instance pointer should be reclaimed when the sample is done
+ // playing. If true, then the pointer will be invalid once its
+ // done playing, sine the memory will be reclaimed. If false, the
+ // memory won't be reclaimed and you'll have to do it yourself.
+ sample->Play(false, true);
+ }
+ }
+ else if (theId == 2)
+ {
+ // Let's do the same as we did for the left button, except make it
+ // play on the right speaker and pitch shift it down
+ SoundInstance* sample = mApp->mSoundManager->GetSoundInstance(SOUND_MUTATOR);
+ if (sample != NULL)
+ {
+ sample->AdjustPitch(-5);
+ sample->SetPan(10000);
+ sample->Play(false, true);
+ }
+ }
+
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::EditWidgetText(int theId, const std::string& theString)
+{
+ // This is called when enter is pressed. Let's add the string
+ // to the list box and tell it to sort it alphabetically, if the string
+ // isn't blank.
+
+ if (theString.length() > 0)
+ {
+ // Let's also clear everything out of the list box if the user types
+ // in the word "CLEAR". StringToUpper is found in Common.h and returns
+ // the uppercase version of the string.
+ if (StringToUpper(theString) == "CLEAR")
+ mListWidget->RemoveAll();
+ else
+ mListWidget->AddLine(StringToSexyStringFast(theString), true);
+
+ // Now clear the edit box
+ mEditWidget->SetText(_S(""));
+
+ // As an example of saving data to files, let's write out the contents
+ // of the list box. Instead of using the C or C++ way of
+ // file I/O, we use buffers. As you'll see in a later demo,
+ // buffers are useful for the demo playback system and are a powerful
+ // feature of the framework. Plus, they make file I/O easy. The first
+ // step is to make a buffer:
+ Buffer buffer;
+
+ // And now all we do is say WriteString. There are other methods
+ // for writing other data types too:
+ for (unsigned int i = 0; i < mListWidget->mLines.size(); i++)
+ buffer.WriteString(SexyStringToStringFast(mListWidget->mLines.at(i)));
+
+ // Now we need to write the buffer to disk. GameApp can help us out with
+ // that. This data is saved in a special binary format that allows
+ // us to read the data easily back into another buffer later.
+ mApp->WriteBufferToFile("list_items.dat", &buffer);
+
+ // That's it!
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+bool Board::AllowChar(int theId, char theChar)
+{
+ // As an example of denying input, let's prevent the user
+ // from typing in the following: :-+.@#$%^&*()
+ switch (theChar)
+ {
+ case ':':
+ case '-':
+ case '+':
+ case '.':
+ case '@':
+ case '#':
+ case '$':
+ case '%':
+ case '^':
+ case '&':
+ case '*':
+ case '(':
+ case ')':
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::ListClicked(int theId, int theIdx, int theClickCount)
+{
+ if (theId == 1)
+ {
+ // Actually select the index. This is done to allow us to
+ // block the selection, if we chose to.
+ mListWidget->SetSelect(theIdx);
+
+ // And update the text that's displaying on screen...
+ // The strings are stored in the list widget's mLines variable
+ // and the one clicked can be indexed via theIdx.
+ mText = mListWidget->mLines[theIdx];
+
+ // As an example of writing to the registry, let's write this value
+ // and later on load it in when we restart the app. You'll notice
+ // a bunch of RegistryWrite... functions in SexyAppBase. Each one
+ // of these takes as first argument the name of the value to
+ // add to the registry. The second argument is the actual data
+ // to store in that value. The value is saved under the registry
+ // location that you set in GameApp's constructor when you
+ // set the mRegKey variable. The function returns false
+ // if there was an error, such as a lack of permission:
+ if (!mApp->RegistryWriteString("ListItem", SexyStringToStringFast(mText)))
+ mApp->Popup("Couldn't save \"ListItem\" to registry");
+ }
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo4/Board.h b/osframework/source/demos/Demo4/Board.h
new file mode 100644
index 0000000..6a4ce3f
--- /dev/null
+++ b/osframework/source/demos/Demo4/Board.h
@@ -0,0 +1,331 @@
+#ifndef __BOARD_H__
+#define __BOARD_H__
+
+//////////////////////////////////////////////////////////////////////////
+// Board.h
+//
+// This is the third class to look at in this particular demo
+// (after main.cpp and GameApp.h/.cpp). The Board class is where most of
+// your actual game programming will go. It is here that we will do
+// all our game drawing, updating, and input processing. Of course, in
+// a larger application, you would probably do drawing and updating in
+// multiple files, but you would still most likely use something similar
+// to a Board class as the master game logic class.
+//
+// The reason that the Board class is a widget is because when a widget
+// is added to the GameApp's WidgetManager, it will automatically have its
+// Update and Draw methods called, and it will automatically receive input
+// at the appropriate times. Furthermore, by making it a widget and adding
+// it to the WidgetManager, the game logic loop, Update(), will be guaranteed
+// to run at a standard 100FPS on all machines. This is extremely important
+// as you always want your logic code to run at the same speed, but want
+// the drawing code to run as fast as possible. That way on faster machines
+// your program doesn't run its logic faster than on a slower machine.
+//
+// You can think of the Board as a canvas upon which we do all our
+// drawing, and a central hub where if we need to, we instruct other
+// classes where and when to draw to.
+//////////////////////////////////////////////////////////////////////////
+
+#include "SexyAppFramework/Widget.h"
+#include "SexyAppFramework/ButtonListener.h"
+
+// Because we're going to be learning about some new widgets, we
+// need to include some more listener classes so we can respond to each one.
+#include "SexyAppFramework/EditListener.h"
+#include "SexyAppFramework/CheckboxListener.h"
+#include "SexyAppFramework/ListListener.h"
+
+
+
+// We place all our classes inside the "Sexy" namespace to avoid name collisions
+// with other libraries that might be added.
+namespace Sexy
+{
+
+
+// Forward declare the graphics class. You will see the graphics class used
+// and explained in Board.cpp: it is the main object used to draw all
+// images, fonts, etc.
+class Graphics;
+
+// We maintain a pointer to the main game application in the Board class.
+// The main game app contains functions that are often times needed
+// by the Board class, such as registry reading/writing, file reading/writing,
+// etc.
+class GameApp;
+
+// forward declare the widgets we're going to use in this demo:
+class ButtonWidget;
+class EditWidget;
+class Checkbox;
+class ListWidget;
+class ScrollbarWidget;
+
+// In this demo, we're going to do some more advanced things like
+// handle the two cases where Board is added and removed from the
+// WidgetManager.
+class WidgetManager;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+class Board : public Widget, public ButtonListener,
+ public EditListener, public CheckboxListener,
+ public ListListener
+{
+
+ private:
+
+ GameApp* mApp;
+ ButtonWidget* mButton1; // We'll use these buttons for sound playing
+ ButtonWidget* mButton2;
+
+ // These are explained in the C++ code, they are the new widgets we're learning about.
+ EditWidget* mEditWidget;
+ Checkbox* mCheckboxWidget;
+ ListWidget* mListWidget;
+ ScrollbarWidget* mScrollbarWidget;
+
+ SexyString mText; // When we press enter on the edit box, we'll set this string and print it
+
+ // Both are floats to ensure that the only difference in the movement demo
+ // is the fact that one is updated in UpdateF and the other is in Update.
+ float mMotionX; // For our movement example, this is the X coordinate of the image as it moves rightward
+ float mUpdateFMotionX;// Same as above, but only modified in UpdateF, to illustrate the difference in motion
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Board
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ Board(GameApp* theApp);
+
+ virtual ~Board();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: EditWidgetText
+ // Parameters:
+ // theId - Integer ID of the edit widget sending this message
+ // theString - The contents of the edit widget
+ //
+ // Returns: none
+ //
+ // Purpose: Called whenever the return/enter key is pressed on
+ // an edit widget.
+ //////////////////////////////////////////////////////////////////////////
+ void EditWidgetText(int theId, const std::string& theString);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: AllowChar
+ // Parameters:
+ // theId - Integer ID of the edit widget sending this message
+ // theChar - Character just typed in
+ //
+ // Returns:
+ // true - Indicates that the character is acceptible
+ // false - Indicates that the character is invalid
+ //
+ // Purpose: Whenever an ASCII character is typed into the edit box,
+ // this method is called first. If the method returns true, then the
+ // character just typed is accepted and appended to the current edit widget
+ // string. If it returns false, the character is rejected and is not added.
+ //////////////////////////////////////////////////////////////////////////
+ bool AllowChar(int theId, char theChar);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: CheckboxChecked
+ // Parameters:
+ // theId - Integer ID of the checkbox widget sending this message
+ // checked - Boolean indicating if the widget is checked or not
+ //
+ // Returns: none
+ //
+ // Purpose: Whenever a checkbox widget is checked or unchecked, this
+ // method is called. We're not actually going to do anything with this,
+ // we're just listing it here as an example of how you'd implement a
+ // function to respond to that event.
+ //////////////////////////////////////////////////////////////////////////
+ void CheckboxChecked(int theId, bool checked) {;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ListClicked
+ // Parameters:
+ // theId - Integer ID of the listbox widget sending this message
+ // theIdx - Integer indicating the index of the item selected in the list
+ // theClickCount - An integer indicating which mouse button
+ // was pressed. One of the following:
+ // 1: Left button
+ // 2: Double-left-click
+ // 3: Middle button
+ // -1: Right button
+ // -2: Double-right-click
+ //
+ // Returns: none
+ //
+ // Purpose: Called any time a list widget is clicked on. The list
+ // widget by default doesn't automatically select the item you clicked on,
+ // it instead calls this method and in here you manually select the item.
+ // This is to allow you to prevent the selection of certain items, such as
+ // disabled items, etc.
+ //////////////////////////////////////////////////////////////////////////
+ void ListClicked(int theId, int theIdx, int theClickCount);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Draw
+ // Parameters:
+ // g - Graphics object used to draw all images and fonts to the screen.
+ //
+ // Returns: none
+ //
+ // Purpose: Called automatically by GameApp's WidgetManager, this function
+ // is the main method that is responsible for all graphical and textual
+ // displaying.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Draw(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Update
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called automatically by GameApp's WidgetManager, this method
+ // is GUARANTEED to be called 100 times per second (100FPS) and is where
+ // all main game logic is performed. Of course, if you had a larger more
+ // complex game, you'd most likely divide your logic between several
+ // other files, but this is commonly the central place where all game
+ // logic begins and is executed.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Update();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: UpdateF
+ // Parameters:
+ // theFrac - The number of updates this time slice represents.
+ //
+ // Returns: none
+ //
+ // Purpose:
+ // There has been a fundamental temporal aliasing issue in the previous
+ // demos because games run at a 100 Hz Update rate while the user's monitor
+ // is refreshing at some other rate, generally between 60 and 85 Hz. The fixed
+ // 100 Hz Update rate is convenient because it allows game logic to proceed
+ // independantly from the refresh rate, but in some cases it's worth the extra
+ // trouble of updating at a variable rate in order to provide smoother animation,
+ // as in the case of a scrolling background, a shark with words written on it,
+ // or an Arkanoid ball.
+ //
+ // To illustrate the aliasing problem, imagine a ball that is supposed to move
+ // 200 pixels per second, running on a 75 Hz monitor. The update rate of the
+ // game is 100 Hz, so that means that we will add 2 pixels to the ball position
+ // every update, and there will be 1.33 updates per monitor refresh (on average).
+ // That means that that 2 out of every 3 monitor refreshes will show the ball
+ // moving 2 pixels, and and the third will show it moving 4 pixels. That isn't
+ // smooth motion. The correct solution would be for the ball to move 2.67
+ // pixels every monitor refresh. But how do we do that?
+ //
+ // To support smooth motion, we use UpdateF. Widget::UpdateF is similar to
+ // Widget::Update, but Widget::UpdateF gets a float passed into it that
+ // represents how many Update's this time slice represents. In the 75 Hz
+ // example, UpdateF would always be called with 1.33. Update has certainly
+ // not been made obsolete, however, and you can choose which
+ // parts of your game logic should be in Update and which should be in
+ // UpdateF. To facilitate cooperation and good behavior between the two
+ // update methods, there are some rules they follow: Updating always occurs
+ // in blocks, with one or two Update calls followed immediately with an
+ // UpdateF call. This means that the application will never get the chance
+ // to draw or process input between an Update and a Draw without calling
+ // UpdateF in the middle. Therefore, you can assume that focus won't be
+ // lost, nor will input change between an Update and an UpdateF, and you'll
+ // know that you'll have a chance to finalize your state in UpdateF so things
+ // can be left dangling (whatever that means for your app) after Update.
+ // You are also guaranteed that the value passed in to UpdateF will be between
+ // 1.67 (for a 60 Hz monitor) and 1.0 (for a 100 Hz monitor). Even if the
+ // monitor is 60 Hz but the computer is only fast enough to draw at 30 FPS
+ // you will get two Update blocks in a row before the draw, so it will still
+ // appear to your app as if you are updating at 60 Hz.
+ //
+ // IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT
+ //
+ // In order to fully use this, you need to set up a few things.
+ // Set GameApp::mVSyncUpdates to true, override UpdateF(float theFrac),
+ // and move some code from Update that used to look like
+ // this: "mPos += 1.5;", changing it to "mPos += 1.5 * theFrac;".
+ // Check out the C++ code for an example of motion using both Update and
+ // UpdateF.
+ //
+ // IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT
+ //
+ // Because UpdateF is called a variable number of times per second,
+ // you do NOT want to put game logic in it that needs to remain framerate
+ // independant. Use UpdateF ONLY for movement related operations, and not
+ // for your main game code.
+ //
+ // If you really want to avoid shearing in windowed mode, you can
+ // set GameApp::mWaitForVSync to true and set GameApp::mSoftVSyncWait
+ // to false. NOTE: This winds up doing some busy waiting and consumes
+ // more processor time.
+ // IMPORTANT: YOU MUST ALSO DELETE THE FOLLOWING REGISTRY KEY:
+ // Whereever your registry settings are stored
+ // (HKEY_LOCAL_MACHINE\SOFTWARE\SexyAppFramework\Demo4 for this case),
+ // you must delete the key "WaitForVSync". This is VERY important, and it
+ // won't work otherwise.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void UpdateF(float theFrac);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ButtonDepress
+ // Parameters:
+ // theId - Integer ID of the button that was clicked
+ //
+ // Returns: none
+ //
+ // Purpose: This method is called by the WidgetManager when a button widget
+ // is first pressed and THEN released. You can use ButtonPress if you want
+ // to know when the button is first pressed (before it is released).
+ // theId is the integer ID that was assigned to the button when it was
+ // first created.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void ButtonDepress(int theId);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: AddedToManager
+ // Parameters:
+ // theWidgetManager - Pointer to the main widget manager from
+ // GameApp.
+ //
+ // Returns: none
+ //
+ // Purpose: This function is automatically called by the widget manager
+ // which also passes a pointer to itself, when the Board class is
+ // added to its list of widgets. Every widget gets this function
+ // called when it is first added. It useful to use this function to
+ // set up any other widgets that the class might contain, such as buttons.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void AddedToManager(WidgetManager* theWidgetManager);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: RemovedFromManager
+ // Parameters:
+ // theWidgetManager - Pointer to the main widget manager from
+ // GameApp.
+ //
+ // Returns: none
+ //
+ // Purpose: This function is automatically called by the widget manager
+ // which also passes a pointer to itself, when the Board class is
+ // removed from its list of widgets. Every widget gets this function
+ // called when it is finally removed. It useful to use this function to
+ // also remove any widgets that were added and created in AddedToManager.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void RemovedFromManager(WidgetManager* theWidgetManager);
+
+};
+
+
+}
+
+#endif // __BOARD_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo4/Demo4 VS2005 WideString.vcproj b/osframework/source/demos/Demo4/Demo4 VS2005 WideString.vcproj
new file mode 100644
index 0000000..7c674c7
--- /dev/null
+++ b/osframework/source/demos/Demo4/Demo4 VS2005 WideString.vcproj
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo4"
+ ProjectGUID="{11091E68-2497-4470-9719-8ED84CECF827}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="DebugVS2005"
+ IntermediateDirectory="DebugVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USE_WIDE_STRING"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="true"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib gdi32.lib advapi32.lib shell32.lib"
+ OutputFile="$(OutDir)/../../Demo4_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo4.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo4.map"
+ MapExports="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="ReleaseVS2005"
+ IntermediateDirectory="ReleaseVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="true"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ ForceConformanceInForLoopScope="true"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib gdi32.lib advapi32.lib shell32.lib"
+ OutputFile="$(OutDir)/../../Demo4.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+ >
+ <File
+ RelativePath="Board.cpp"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.cpp"
+ >
+ </File>
+ <File
+ RelativePath="TitleScreen.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.h"
+ >
+ </File>
+ <File
+ RelativePath="TitleScreen.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/Demo4/Demo4 VS2005.vcproj b/osframework/source/demos/Demo4/Demo4 VS2005.vcproj
new file mode 100644
index 0000000..50330d3
--- /dev/null
+++ b/osframework/source/demos/Demo4/Demo4 VS2005.vcproj
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo4"
+ ProjectGUID="{11091E68-2497-4470-9719-8ED84CECF827}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="DebugVS2005"
+ IntermediateDirectory="DebugVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="true"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib gdi32.lib advapi32.lib shell32.lib"
+ OutputFile="$(OutDir)/../../Demo4_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo4.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo4.map"
+ MapExports="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="ReleaseVS2005"
+ IntermediateDirectory="ReleaseVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="true"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ ForceConformanceInForLoopScope="true"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib gdi32.lib advapi32.lib shell32.lib"
+ OutputFile="$(OutDir)/../../Demo4.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+ >
+ <File
+ RelativePath="Board.cpp"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.cpp"
+ >
+ </File>
+ <File
+ RelativePath="TitleScreen.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.h"
+ >
+ </File>
+ <File
+ RelativePath="TitleScreen.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/Demo4/Demo4 WideString.vcproj b/osframework/source/demos/Demo4/Demo4 WideString.vcproj
new file mode 100644
index 0000000..47a8f04
--- /dev/null
+++ b/osframework/source/demos/Demo4/Demo4 WideString.vcproj
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo4"
+ ProjectGUID="{11091E68-2497-4470-9719-8ED84CECF827}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USE_WIDE_STRING"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="0"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo4_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo4.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo4.map"
+ MapExports="TRUE"
+ MapLines="TRUE"
+ SubSystem="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo4.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+ <File
+ RelativePath="Board.cpp">
+ </File>
+ <File
+ RelativePath="GameApp.cpp">
+ </File>
+ <File
+ RelativePath="..\Res.cpp">
+ </File>
+ <File
+ RelativePath="TitleScreen.cpp">
+ </File>
+ <File
+ RelativePath="main.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc">
+ <File
+ RelativePath="Board.h">
+ </File>
+ <File
+ RelativePath="GameApp.h">
+ </File>
+ <File
+ RelativePath="..\Res.h">
+ </File>
+ <File
+ RelativePath="TitleScreen.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/Demo4/Demo4.dsp b/osframework/source/demos/Demo4/Demo4.dsp
new file mode 100644
index 0000000..0177067
--- /dev/null
+++ b/osframework/source/demos/Demo4/Demo4.dsp
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="Demo4" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=Demo4 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Demo4.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Demo4.mak" CFG="Demo4 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Demo4 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Demo4 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Demo4 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Demo4___Win32_Release"
+# PROP BASE Intermediate_Dir "Demo4___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I ".." /I "..\.." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 winmm.lib wsock32.lib gdi32.lib advapi32.lib shell32.lib /nologo /subsystem:windows /machine:I386 /out:"..\Demo4.exe"
+
+!ELSEIF "$(CFG)" == "Demo4 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Demo4___Win32_Debug"
+# PROP BASE Intermediate_Dir "Demo4___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /GR /GX /Zi /Od /I ".." /I "..\.." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 winmm.lib wsock32.lib gdi32.lib advapi32.lib shell32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /out:"..\Demo4_debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Demo4 - Win32 Release"
+# Name "Demo4 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\Board.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\GameApp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Res.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TitleScreen.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\Board.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\GameApp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TitleScreen.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/osframework/source/demos/Demo4/Demo4.vcproj b/osframework/source/demos/Demo4/Demo4.vcproj
new file mode 100644
index 0000000..bf5c38c
--- /dev/null
+++ b/osframework/source/demos/Demo4/Demo4.vcproj
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo4"
+ ProjectGUID="{11091E68-2497-4470-9719-8ED84CECF827}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="0"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo4_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo4.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo4.map"
+ MapExports="TRUE"
+ MapLines="TRUE"
+ SubSystem="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo4.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+ <File
+ RelativePath="Board.cpp">
+ </File>
+ <File
+ RelativePath="GameApp.cpp">
+ </File>
+ <File
+ RelativePath="..\Res.cpp">
+ </File>
+ <File
+ RelativePath="TitleScreen.cpp">
+ </File>
+ <File
+ RelativePath="main.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc">
+ <File
+ RelativePath="Board.h">
+ </File>
+ <File
+ RelativePath="GameApp.h">
+ </File>
+ <File
+ RelativePath="..\Res.h">
+ </File>
+ <File
+ RelativePath="TitleScreen.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/Demo4/GameApp.cpp b/osframework/source/demos/Demo4/GameApp.cpp
new file mode 100644
index 0000000..2d8044f
--- /dev/null
+++ b/osframework/source/demos/Demo4/GameApp.cpp
@@ -0,0 +1,395 @@
+#include "GameApp.h"
+#include "TitleScreen.h"
+#include "Board.h"
+#include "SexyAppFramework/WidgetManager.h"
+
+// We will be accessing the resource manager in this demo, so include it's header
+#include "SexyAppFramework/ResourceManager.h"
+
+// Required for playing music
+#include "SexyAppFramework/BassMusicInterface.h"
+
+// Contains all the resources from the resources.xml file in our
+// properties directory. See that file for more information.
+#include "Res.h"
+
+// The SexyAppFramework resides in the "Sexy" namespace. As a convenience,
+// you'll see in all the .cpp files "using namespace Sexy" to avoid
+// having to prefix everything with Sexy::
+using namespace Sexy;
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+GameApp::GameApp()
+{
+ // mProdName is used for internal purposes to indicate the game that we're working on
+ mProdName = "Demo 4";
+
+ // For internal uses, indicates the current product version
+ mProductVersion = "1.0";
+
+ // This is the text that appears in the title bar of the application window
+ mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion);
+
+ // Indicates the registry location where all registry keys will be read from
+ // and written to. This is stored under the HKEY_CURRENT_USER tree on
+ // Windows systems.
+ mRegKey = "PopCap\\SexyAppFramework\\Demo4";
+
+ // Set the application width/height in terms of pixels here. Let's
+ // use a different resolution from Demo 1 just for fun.
+ mWidth = 800;
+ mHeight = 600;
+
+ // By setting this to true, the framework will automatically check to see
+ // if hardware acceleration can be turned on. This doesn't guarantee that it
+ // WILL be turned on, however. Some cards just aren't compatible or have
+ // known issues. Also, cards with less than 8MB of video RAM aren't supported.
+ // There are ways to override the 3D enabled settings, which we will discuss
+ // in a later demo. As a side note, if you want to see if you app is
+ // running with 3D acceleration, first enable debug keys by pressing
+ // CTRL-ALT-D and then press F9. To toggle 3D on/off, press F8. That is just
+ // for testing purposes.
+ mAutoEnable3D = true;
+
+ mBoard = NULL;
+ mTitleScreen = NULL;
+
+ // See Board::UpdateF for a very lengthy explanation of this and smooth motion
+ mVSyncUpdates = true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+GameApp::~GameApp()
+{
+ // Remove our "Board" class which was, in this particular demo,
+ // responsible for all our game drawing and updating.
+ // All widgets MUST be removed from the widget manager before deletion.
+ // More information on the basics of widgets can be found in the Board
+ // class file. If you tried to delete the Board widget before removing
+ // it, you will get an assert. Because our board might not have been
+ // added (if you shut down the app before closing the loading screen),
+ // only remove it if it isn't null.
+ if (mBoard != NULL)
+ mWidgetManager->RemoveWidget(mBoard);
+
+ // Take a look at TitleScreen::ButtonDepress if you haven't already.
+ // It explains a function called SafeDeleteWidget. Notice that we're
+ // directly deleting the widget here: that is because when our app's
+ // destructor is called, it's at the very end of the shutdown sequence
+ // and the safe delete widget list will NOT be processed. Thus we
+ // have to delete the memory manually.
+ delete mBoard;
+
+
+ // If you shut down the app before closing the loading screen, then
+ // it will need to be removed here. The rational for the next two
+ // steps is the same as for Board:
+ if (mTitleScreen != NULL)
+ mWidgetManager->RemoveWidget(mTitleScreen);
+ delete mTitleScreen;
+
+ // We should also free up all the resources that we loaded
+ // for ALL the resource groups. Deleting a group that was
+ // already deleted doesn't do anything, it's ignored.
+ mResourceManager->DeleteResources("Init");
+ mResourceManager->DeleteResources("TitleScreen");
+ mResourceManager->DeleteResources("Game");
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::Init()
+{
+ // Let the parent class perform any needed initializations first.
+ // This should always be done.
+ SexyAppBase::Init();
+
+ // We need to tell the resource manager to read in all the groups
+ // and information from that main group we made, called ResourceManifest,
+ // in the file "properties/resources.xml". The path/filename are
+ // by default set up to load that file, so you must name it exactly as such.
+ // This doesn't load any resources: it just parses the data and sets
+ // things up for loading.
+ LoadResourceManifest();
+
+ // Next, we want to load our absolutely necessary files that have to
+ // be loaded before anything else can run. You'll notice in the resources.xml
+ // file that we created a group called Init that contains these resources.
+ // You may call it whatever you like. Let's load those resources now.
+ // We do that by calling the LoadResources method of our mResourceManager
+ // variable and specifying in quotes the name of the resource group to
+ // load. This string is case sensitive.
+ if (!mResourceManager->LoadResources("Init"))
+ {
+ mLoadingFailed = true;
+ // This will display an informative error message indicating exactly
+ // what went wrong in the resource loading process.
+ ShowResourceError(true);
+ return;
+ }
+
+ // Now we've loaded the resources, but we need to extract them.
+ // Extraction is the phase that converts sound files to raw WAV
+ // files, and sets up and initializes fonts and palletizes images.
+ // The ResourceGen.exe program, when it generates C++ code for our
+ // resources, also creates a function for EVERY resource group of the
+ // form: Extract<GROUP>Resources, where <GROUP> is the exact name
+ // of the resource group you made. In our case, we made an "Init"
+ // group, so we have an ExtractInitResources method. You pass to it
+ // the pointer to the resource manager. Because an error can occur
+ // during this step, you should make sure to check for it.
+ if (!ExtractInitResources(mResourceManager))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ // We also need to load our title screen graphics in, since you can't
+ // display the title screen without any graphics. For an explanation of why
+ // we placed this in a separate group from Init, see properties/resources.xml.
+ // This code works exactly like the above did for the Init group.
+ if (!mResourceManager->LoadResources("TitleScreen"))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ if (!ExtractTitleScreenResources(mResourceManager))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ // Now let's create and add our title screen to the widget manager
+ mTitleScreen = new TitleScreen(this);
+ mTitleScreen->Resize(0, 0, mWidth, mHeight);
+
+ // Let's let the title screen initialize it's widgets and data
+ // before adding it to the widget manager:
+ mTitleScreen->Init();
+
+ mWidgetManager->AddWidget(mTitleScreen);
+
+ // Let's also load in some music to play. We use the mMusicInterface
+ // member for all our music needs, which requires the BassMusicInterface.h
+ // header to be loaded, since we use the library BASS to play our music.
+ // We can load in WAV, OGG, or MP3 files. BASS also supports a number
+ // of tracker formats, such as .it, .xm, .mod, etc. It also supports
+ // a format called MO3, which is a compressed version of a tracker
+ // file. For this example, we will use the MO3 from AstroPop.
+ // Why? Cause it's ours and we won't get sued for using it.
+ // We load our file manually, we do not use the resource manager for this.
+ // The first parameter is the ID to associate the song with. Just as sounds
+ // have IDs, so do music tracks.
+ mMusicInterface->LoadMusic(0, "music/music.mo3");
+
+ // Let's load another copy of the file. Why? In order to fade from one
+ // track to another, we need two instances of the track on different
+ // channels. Let's load it again and give it a different ID, 1.
+ mMusicInterface->LoadMusic(1, "music/music.mo3");
+
+ // Now we need to start playing a track. Because we are using an MO3
+ // and because the original format was a .it (Impulse Tracker) file,
+ // there are actually multiple songs inside of it, differentiated
+ // by various offsets. If you were just playing a single MP3 or OGG
+ // or WAV file instead of a tracker file, you would ignore this
+ // and use the default offset of 0 for the start of the song.
+ // Because the person that made the song file was nice and
+ // told us which offsets equated to which song pieces, I already
+ // know the magic offset numbers. In this particular case, the
+ // song for the intro screen is at offset 0, and the song
+ // for the main game music is at offset 9. Our music artist
+ // also was kind enough to put in tracker looping commands,
+ // so you'll notice that the songs play over and over. A discussion
+ // of tracker file formats is beyond the scope of this. Again,
+ // if you are just playing a WAV/OGG/MP3, you use offset 0 (the default)
+ // to indicate that you want to start playing from the start of the song.
+ //
+ // You can use PlayMusic to instantly play the track, or, like below,
+ // you can use FadeIn to smoothly fade the song in. The first parameter
+ // for both methods is the channel or song id that was used when the
+ // track was first loaded (In our case, either 0 or 1 works). For both,
+ // the second parameter is the offset to start playing at. Again, I just
+ // happen to know that the intro song is at offset 0. For FadeIn, the
+ // third parameter is how quickly to fade in, out of 1.0. The last parameter
+ // for both indicates whether or not you want to loop. This is kind of weird,
+ // but specify "false" to loop and "true" to not loop.
+ mMusicInterface->FadeIn(0, 0, 0.002, false);
+
+ // We'll cover changing the music and sound volumes in a later demo.
+
+ // Next, we need to know how many resources there are to load.
+ // This is necessary so we can display our progress bar on the title screen
+ // and make it be the appropriate length. There's a variable in SexyAppBase
+ // called mNumLoadingThreadTasks which holds the number of resources to
+ // load in the LoadingThreadProc function. You get the number of resources
+ // in a given group with a call to the resource manager's GetNumResources function
+ // for each of your groups that you are going to load:
+ mNumLoadingThreadTasks = mResourceManager->GetNumResources("Game");
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadProc()
+{
+ // This time, things are different. We aren't manually loading
+ // our fonts, sounds, and images. The resource manager is doing
+ // it for us. For each of the groups that we want to load,
+ // we first have to instruct the resource manager to begin the
+ // loading phase and initialize its internal variables.
+ // We do that with the StartLoadResources method and pass in the
+ // exact string name of the group to begin loading:
+ mResourceManager->StartLoadResources("Game");
+
+ // Now we need to load each individual resource. We will loop,
+ // calling LoadNextResource at the start. When it returns false,
+ // there are no more resources to load for the current group.
+ // LoadNextResource knows what group to load from because
+ // of the call to StartLoadResources above:
+ while (mResourceManager->LoadNextResource())
+ {
+ // The SexyAppBase variable, mCompletedLoadingThreadTasks, indicates the
+ // total number of resources that have so far been loaded. This is used
+ // to tell our loading screen the % progress we've made. See TitleScreen::Draw
+ // for an example of how this is used. We need to increment this value
+ // ourselves everytime we load a resource:
+ mCompletedLoadingThreadTasks++;
+
+ // If there was an error loading our resource, the resource manager
+ // will tell us to shut down by setting mShutdown to true. If that
+ // happened, immediately abort and return:
+ if (mShutdown)
+ return;
+
+ // Remember in demos 1-3 how we had the Board class call MarkDirty
+ // every update? Well, the title screen doesn't need to be such a hog.
+ // The title screen only needs to repaint when its progress bar changes
+ // size. The progress bar only changes size when a resource gets loaded.
+ // Because the game app is the only one that knows when this happens,
+ // the game app will be the one to tell the title screen that it's a
+ // dirty, dirty widget and that it needs a good and proper repainting.
+ // You COULD make an update method for the title screen and mark dirty
+ // every frame. But because this consumes more CPU time, it will take
+ // longer to load our resources. And since you want the loading time
+ // to be as quick as possible, you should only repaint when you need to.
+ mTitleScreen->MarkDirty();
+ }
+
+ // Just like in our Init function, after loading resources we
+ // need to extract them. Let's do that. Let's also ask the resource
+ // manager if an error occurred in the above loop that we
+ // didn't yet catch. We do that with the HadError method:
+ if (mResourceManager->HadError() || !ExtractGameResources(mResourceManager))
+ {
+ ShowResourceError(false);
+ mLoadingFailed = true;
+
+ return;
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadCompleted()
+{
+ // Let the base app class also know that we have completed
+ SexyAppBase::LoadingThreadCompleted();
+
+ // When we're actually loading resources, we'll set the
+ // mLoadingFailed variable to "true" if there were any problems
+ // encountered along the way. If that is the case, just return
+ // because we won't want the user to get to the main menu or any
+ // other part of the game. We will want them to exit out.
+ if (mLoadingFailed)
+ return;
+
+
+ // We aren't going to make and add the Board class here like we
+ // did in the previous demos. Instead, since we are done loading
+ // everything, we're going to tell the title screen that
+ // we're done and that it should unhide the continue link and let
+ // the user enter the game.
+ mTitleScreen->LoadingComplete();
+
+ // Remember: since we didn't give our title screen an Update method,
+ // this class is responsible for telling it when to repaint. If we
+ // don't mark it dirty, you won't see the hyperlink widget
+ // appear. So mark it dirty now:
+ mTitleScreen->MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::TitleScreenIsFinished()
+{
+ // This function is called by the title screen when the user clicks
+ // on the hyperlink widget to continue. At this point, the title screen
+ // has already removed itself and its widgets and we should set up our
+ // Board class and begin the game. Let's also set our title screen
+ // pointer to NULL, since it will be safely deleted automatically at a
+ // later point, and we don't want to delete it twice.
+ mTitleScreen = NULL;
+ mBoard = new Board(this);
+
+ // Now that the title screen is done, we don't need its resources
+ // wasting memory. Let's delete all of its resources. We do that
+ // by calling DeleteResources and specifying the exact name of the
+ // resource group we want to free up:
+ mResourceManager->DeleteResources("TitleScreen");
+
+ // This is a very important step: Because the Board class is a widget
+ // (see Board.h/.cpp for more details) we need to tell it what
+ // dimensions it has and where to place it.
+ // By default a widget is invisible because its
+ // width/height are 0, 0. Since the Board class is our main
+ // drawing area and game logic class, we want to make it the
+ // same size as the application. For this particular demo, that means
+ // 800x600. We will use mWidth and mHeight though, as those were
+ // already set to the proper resolution in GameApp::Init().
+ mBoard->Resize(0, 0, mWidth, mHeight);
+
+ // Also an important step is to add the newly created Board widget to
+ // the widget manager so that it will automatically have its update, draw,
+ // and input processing methods called.
+ mWidgetManager->AddWidget(mBoard);
+
+ // Let's fade out the intro song and fade in the main game music.
+ // FadeOut works just like FadeIn did in Init() but with some
+ // slightly different parameters. The first, is like with FadeIn and
+ // PlayMusic, the channel or song id that you want to mess with.
+ // The second indicates that the song fading out should stop when
+ // done, if it is true. The final parameter indicates how fast
+ // to fade out, and is from 0 to 1.
+ mMusicInterface->FadeOut(0, true, 0.004);
+
+ // Let's fade in the main game music. This is the same as in Init.
+ // The only difference is we're using 1 instead of 0 for our song id.
+ // Why? Well, channel/song id 0 is being used to fade out the
+ // previously playing track, we can't use it to also fade in.
+ // That's why we loaded another copy of the song into channel 1.
+ // Again, as explained in Init, I happen to know that offset 9
+ // is the start of the main game music.
+ mMusicInterface->FadeIn(1, 9, 0.002, false);
+
+ // We'll cover changing the music and sound volumes in a later demo.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::HandleCmdLineParam(const std::string& theParamName, const std::string& theParamValue)
+{
+ // If you wanted to, in here you could examine command line parameters and their values.
+ // We actually don't care to, in this. The purpose was to show you how you'd do it,
+ // and this function is the one you use to read those values. We'll just print the
+ // parameters out for now:
+ OutputDebugString(StrFormat("theParamName = \"%s\", theParamValue = \"%s\"",
+ theParamName.c_str(), theParamValue.c_str()).c_str());
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo4/GameApp.h b/osframework/source/demos/Demo4/GameApp.h
new file mode 100644
index 0000000..3b038f1
--- /dev/null
+++ b/osframework/source/demos/Demo4/GameApp.h
@@ -0,0 +1,122 @@
+#ifndef __GAMEAPP_H__
+#define __GAMEAPP_H__
+
+//////////////////////////////////////////////////////////////////////////
+// GameApp.h
+//
+// This is what drives the whole game. In here, you derive your class
+// from SexyAppBase and implement common game tasks, such as
+// responding to widgets (covered later), initializing and loading
+// resources, setting up the various game screens, etc.
+// All applications at minimum must have a class that derives from
+// SexyAppBase.
+//
+// The GameApp class is used to do such things as create the main
+// menu screen, create the main game class (where all drawing/updating/
+// interaction takes place), etc.
+//////////////////////////////////////////////////////////////////////////
+
+#include "SexyAppFramework/SexyAppBase.h"
+
+// We place all our classes inside the "Sexy" namespace to avoid name collisions
+// with other libraries that might be added.
+namespace Sexy
+{
+
+ // The GameApp class will be responsible for creating a class by the name
+ // of "Board", which we will use to do all the game's drawing, input processing,
+ // etc. Board is the second most important class and is where almost all of your
+ // game logic code will originate from. It is a widget, which allows for
+ // easy and automatic invocation of its update, drawing, and input processing
+ // functions. See the "Board" class for more details.
+ class Board;
+
+ // We're going to be responsible for creating and adding the title screen widget
+ class TitleScreen;
+
+class GameApp : public SexyAppBase
+{
+
+ private:
+
+ Board* mBoard;
+ TitleScreen* mTitleScreen;
+
+ public:
+
+ GameApp();
+ virtual ~GameApp();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Init
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Initializes the application. Sets the resolution, overrides
+ // any default settings, and if there is a loader/intro screen (not in this demo)
+ // creates it and displays it. The framework will then automatically
+ // call the LoadingThreadProc() method after this method returns.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Init();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: LoadingThreadProc
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Loads all resources in a separate thread. If there is a
+ // loader/intro screen (not in this demo), would also update the
+ // loader progress indicator. When the function returns, the
+ // LoadingThreadCompleted() method is automatically called.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void LoadingThreadProc();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: LoadingThreadCompleted
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called when LoadingThreadProc is complete and all resources
+ // have been loaded. It is in this function that you would then set up
+ // your main menu or similar screen. For this particular demo however,
+ // we will go straight to the main game class, "Board".
+ //////////////////////////////////////////////////////////////////////////
+ virtual void LoadingThreadCompleted();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: TitleScreenIsFinished
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called by the TitleScreen widget when it is about to close
+ // down, this indicates that we should now add the board widget and
+ // start the game.
+ //////////////////////////////////////////////////////////////////////////
+ void TitleScreenIsFinished();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: HandleCmdLineParam
+ // Parameters:
+ // theParamName - The name of the parameter, will be of the form
+ // "-paramname". Note the "-" prefix.
+ // theParamValue - The parameter associated with the param name,
+ // or "" if none.
+ //
+ // Returns: none
+ //
+ // Purpose: This function lets you parse command line parameters and
+ // their associated values. Command line parameters are of the form:
+ // -paramname or -paramname="some value"
+ // Example:
+ // Demo4.exe -debug -printmsg="A test message" results in:
+ //
+ // theParamName = "-debug", theParamValue = ""
+ // theParamName = "-printmsg", theParamValue = "A test message"
+ //////////////////////////////////////////////////////////////////////////
+ virtual void HandleCmdLineParam(const std::string& theParamName, const std::string& theParamValue);
+};
+
+}
+
+
+#endif // __GAMEAPP_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo4/TitleScreen.cpp b/osframework/source/demos/Demo4/TitleScreen.cpp
new file mode 100644
index 0000000..2c85732
--- /dev/null
+++ b/osframework/source/demos/Demo4/TitleScreen.cpp
@@ -0,0 +1,210 @@
+#include "TitleScreen.h"
+
+#include "GameApp.h"
+
+// Contains all the resources from the resources.xml file in our
+// properties directory. See that file for more information.
+#include "Res.h"
+
+// Now that we're on our 4th demo, the reason for including the headers
+// below should be apparent. If you forgot, review demos 1-3.
+#include "SexyAppFramework/Font.h"
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Image.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/Rect.h"
+
+// A new class: the HyperlinkWidget. It acts and resembles a standard
+// WWW hyperlink.
+#include "SexyAppFramework/HyperlinkWidget.h"
+
+using namespace Sexy;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+TitleScreen::TitleScreen(GameApp *pApp)
+{
+ mApp = pApp;
+ mContinueLink = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+TitleScreen::~TitleScreen()
+{
+ delete mContinueLink;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::Init(void)
+{
+ // A hyperlink widget is basically the same thing as a button widget
+ // but with some slight differences. It is meant to emulate the look
+ // and feel of an internet hyperlink. We create the widget the
+ // same way we created a button widget in Demo3, specifying that
+ // this class is to listen to the widget events.
+ mContinueLink = new HyperlinkWidget(1, this);
+
+ // We need to set the font to use. In previous demos, we had
+ // a variable inside of GameApp that held the font. Now that we're
+ // using the resource manager, we'll use the main (and only) one
+ // that we declared from there. Remember how we named it FONT_DEFAULT?
+ // Well, you can use that name exactly now to reference it.
+ mContinueLink->SetFont(FONT_DEFAULT);
+
+ // Like the button widget, we can set the text to display:
+ mContinueLink->mLabel = _S("CLICK TO CONTINUE");
+
+ // And like the button widget, we can set the default and over colors.
+ // We don't use the SetColor method though, we just directly
+ // set mColor and mOverColor:
+ mContinueLink->mColor = Color(255, 255, 255);
+ mContinueLink->mOverColor = Color(0, 255, 0);
+ mContinueLink->mUnderlineSize = 1;
+
+
+ // We're not going to place the widget just yet. Why? Well,
+ // the TitleScreen hasn't been added to the widget manager.
+ // We'll wait until the AddedToManager method is called before
+ // adding it, just like in Demo3.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::AddedToManager(WidgetManager *theWidgetManager)
+{
+ Widget::AddedToManager(theWidgetManager);
+
+ // Just like with the button widget from Demo3, we're going to add our
+ // hyperlink widget in this method. However, we want the link to be
+ // invisible at first. Why? Well, while we're loading our resources,
+ // we don't want the user to be able to just start the game. We want
+ // them to wait until it's all loaded and ready to go. Once everything
+ // is loaded, then we'll make it visible and let them click to play.
+ // We do that with the SetVisible command:
+ mContinueLink->SetVisible(false);
+
+ // Just making it invisible isn't enough. Technically the user could
+ // still click on it even though they can't see it. We have to
+ // disable the widget to prevent it from receiving input:
+ mContinueLink->SetDisabled(true);
+
+ // Let's resize it to be at the bottom of the screen, and to be exactly
+ // the width/height of the lable that we set. Again, we use our friend
+ // the Resize function. However, note that we're setting the height to
+ // be a bit larger than that of the string. That's because the underline
+ // part of the hyperlink widget (whose thickness can be controlled via mUnderlineSize)
+ // draws a little below the string. If you didn't make the height a little
+ // larger, the line would be clipped and thus wouldn't be visible. Clipping
+ // is discussed in the next demo.
+ int labelWidth = FONT_DEFAULT->StringWidth(mContinueLink->mLabel);
+ int labelHeight = FONT_DEFAULT->GetHeight();
+ mContinueLink->Resize( mWidth / 2 - labelWidth / 2,
+ mHeight - labelHeight - 40,
+ labelWidth,
+ labelHeight+4);
+
+ // Almost done. Let's make it so that when the user mouses over the widget,
+ // that the cursor changes from the standard Windows arrow to a hand icon.
+ // We do that by setting the variable mDoFinger to true. This instructs the
+ // WidgetManager to chagne the cursor to the hand/finger icon when the mouse
+ // is inside the widget's bounds, and to reset it back to the arrow when it
+ // is not. Note that ALL widgets have this functionality.
+ mContinueLink->mDoFinger = true;
+
+ // And finally, we add the widget just like we added the button widget
+ // from demo 3 and the Board widget.
+ theWidgetManager->AddWidget(mContinueLink);
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::RemovedFromManager(WidgetManager *theWidgetManager)
+{
+ // This is just like what we did in Board in Demo3.
+ // Let our parent class know about the removal, and get rid
+ // of our hyperlink widget.
+ Widget::RemovedFromManager(theWidgetManager);
+ theWidgetManager->RemoveWidget(mContinueLink);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::Draw(Graphics *g)
+{
+ // Instead of having to say Color(0, 0, 0) or Color(255, 255, 255)
+ // for black/white, you can use Color::Black and Color::White.
+ g->SetColor(Color::Black);
+ g->FillRect(0, 0, mWidth, mHeight);
+
+
+ // We want to draw our loader bar to indicate the progress made in
+ // loading all our resources. As you recalll, GameApp::LoadingThreadProc is
+ // the thread that is actually loading everything. The app has a function,
+ // GetLoadingThreadProgress, that returns a value from 0.0 to 1.0 indicating
+ // the % complete it is. We will multiply this % complete by the width
+ // of our progress bar, so that we give the illusion of a growing bar.
+ int loaderBarWidth = IMAGE_LOADER_BAR->GetWidth();
+ int drawWidth = (int)(mApp->GetLoadingThreadProgress() * loaderBarWidth);
+ if (drawWidth > 0)
+ {
+ // As you may recall from Demo3 where we drew the frames of animation
+ // for the lightning image, the DrawImage call can take a source rectangle
+ // which indicates what chunk of the original image we want to draw.
+ // In our case, we want to start from from the upper left corner of
+ // the loader bar, but we only want to draw "drawWidth" wide. This will
+ // give the illusion that the progress bar is expanding as the resources
+ // are loaded in.
+ g->DrawImage(IMAGE_LOADER_BAR, mWidth / 2 - loaderBarWidth / 2,
+ 400,
+ Rect(0, 0, drawWidth, IMAGE_LOADER_BAR->GetHeight()));
+ }
+
+ // If our hyperlink widget is false, let's instead draw some
+ // "Loading" text (er, actually in this case it's an image) where
+ // it is located.
+ if (mContinueLink->mVisible == false)
+ g->DrawImage(IMAGE_LOADER_LOADINGTXT, mContinueLink->mX, mContinueLink->mY - 20);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::LoadingComplete()
+{
+ // Since the app told us that we're done loading all our resources,
+ // let's unhide and enable our continue link so the user can start
+ // playing.
+ mContinueLink->SetVisible(true);
+ mContinueLink->SetDisabled(false);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::ButtonDepress(int theId)
+{
+ if (theId == 1)
+ {
+ // Our hyperlink widget was pressed. We want to remove ourselves
+ // and the hyperlink widget, and tell the app to display the
+ // main board and get the game started.
+ // You might be thinking, "If I delete the title screen and
+ // hyperlink, won't I crash the program?" Yes, you will. That's
+ // why we aren't going to delete them using "delete". We're going
+ // to use SexyAppBase's SafeDeleteWidget method. This places the
+ // widget in a queue that is processed after all widgets and data
+ // get processed, and is then deleted at a time that is safe
+ // and appropriate. We still have to remove ourself and the
+ // hyperlink widget from the WidgetManager. We can easily access
+ // the WidgetManager, as it is a public variable in our game app.
+ mApp->mWidgetManager->RemoveWidget(this);
+ mApp->mWidgetManager->RemoveWidget(mContinueLink);
+ mApp->SafeDeleteWidget(this);
+ mApp->SafeDeleteWidget(mContinueLink);
+ mContinueLink = NULL;
+
+ // Now let's tell the game app that it's ok to add the board widget:
+ mApp->TitleScreenIsFinished();
+ }
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo4/TitleScreen.h b/osframework/source/demos/Demo4/TitleScreen.h
new file mode 100644
index 0000000..6d935cb
--- /dev/null
+++ b/osframework/source/demos/Demo4/TitleScreen.h
@@ -0,0 +1,127 @@
+#ifndef __TITLE_SCREEN_H__
+#define __TITLE_SCREEN_H__
+
+#include "SexyAppFramework/Widget.h"
+#include "SexyAppFramework/ButtonListener.h"
+
+namespace Sexy
+{
+
+class GameApp;
+class Graphics;
+class WidgetManager;
+
+// A new widget that we'll be learning about. It's explained in the .CPP code.
+class HyperlinkWidget;
+
+
+// If you forgot about the ButtonListener class, you should review Demo3.
+// The hyperlink widget is essentially the same thing as a button widget,
+// and emits the same messages that a button does. Thus, to act on its
+// messages we derive from the ButtonListener class.
+class TitleScreen : public Widget, public ButtonListener
+{
+
+private:
+
+ GameApp* mApp;
+ HyperlinkWidget* mContinueLink;
+
+public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: TitleScreen
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ TitleScreen(GameApp* pApp);
+
+ virtual ~TitleScreen();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Init
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called BEFORE the title screen is added to the widget manager
+ // by GameApp. This initializes some things like the images used for
+ // our hyperlink widget.
+ //////////////////////////////////////////////////////////////////////////
+ void Init(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: AddedToManager
+ // Parameters:
+ // theWidgetManager - Pointer to the main widget manager from
+ // GameApp.
+ //
+ // Returns: none
+ //
+ // Purpose: This function is automatically called by the widget manager
+ // which also passes a pointer to itself, when the TitleScreen class is
+ // added to its list of widgets. Every widget gets this function
+ // called when it is first added. It useful to use this function to
+ // set up any other widgets that the class might contain, such as buttons.
+ //////////////////////////////////////////////////////////////////////////
+ void AddedToManager(WidgetManager* theWidgetManager);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: RemovedFromManager
+ // Parameters:
+ // theWidgetManager - Pointer to the main widget manager from
+ // GameApp.
+ //
+ // Returns: none
+ //
+ // Purpose: This function is automatically called by the widget manager
+ // which also passes a pointer to itself, when the TitleScreen class is
+ // removed from its list of widgets. Every widget gets this function
+ // called when it is finally removed. It useful to use this function to
+ // also remove any widgets that were added and created in AddedToManager.
+ //////////////////////////////////////////////////////////////////////////
+ void RemovedFromManager(WidgetManager* theWidgetManager);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ButtonDepress
+ // Parameters:
+ // theId - Integer ID of the button that was clicked
+ //
+ // Returns: none
+ //
+ // Purpose: This method is called by the WidgetManager when a button widget
+ // is first pressed and THEN released. You can use ButtonPress if you want
+ // to know when the button is first pressed (before it is released).
+ // theId is the integer ID that was assigned to the button when it was
+ // first created.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void ButtonDepress(int theId);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Draw
+ // Parameters:
+ // g - Graphics object used to draw all images and fonts to the screen.
+ //
+ // Returns: none
+ //
+ // Purpose: Called automatically by GameApp's WidgetManager. This is where
+ // we'll do all our display routines for the loading screen.
+ //////////////////////////////////////////////////////////////////////////
+ void Draw(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: LoadingComplete
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called manually by GameApp when we are done loading all
+ // resources, to let the title screen know that it should unhide and
+ // enable the continue link, so the user can start playing the game.
+ //////////////////////////////////////////////////////////////////////////
+ void LoadingComplete();
+};
+
+}
+
+#endif //__TITLE_SCREEN_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo4/main.cpp b/osframework/source/demos/Demo4/main.cpp
new file mode 100644
index 0000000..2d0bd68
--- /dev/null
+++ b/osframework/source/demos/Demo4/main.cpp
@@ -0,0 +1,47 @@
+//////////////////////////////////////////////////////////////////////////
+// main.cpp
+//
+// This is the starting point for all new projects. This file's purpose is
+// pretty small, but important. In here we create our application, initialize
+// it, and begin processing all the game code.
+//
+// This demo will teach you:
+// * Using the resource manager
+// * Title screen with progress bar
+// * Loading/playing music
+// * Playing sounds with pitch and panning values changed
+// * smooth motion with UpdateF
+// * Reading/writing to files/registry
+// * Getting command line switches
+// * Widgets: Hyperlink widget, edit widget, checkbox, list, scrollbars, safedeletewidget
+//////////////////////////////////////////////////////////////////////////
+
+#include "GameApp.h"
+
+// The SexyAppFramework resides in the "Sexy" namespace. As a convenience,
+// you'll see in all the .cpp files "using namespace Sexy" to avoid
+// having to prefix everything with Sexy::
+using namespace Sexy;
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+
+ // Make sure to set this. Some classes, like the exception handler and custom cursors
+ // will need to use it.
+ gHInstance = hInstance;
+
+ // Create and initialize our game application.
+ GameApp* anApp = new GameApp();
+ anApp->Init();
+
+ // Starts the entire application: sets up the resource loading thread and
+ // custom cursor thread, and enters the game loop where the application
+ // will remain until it is shut down. You will most likely not need to
+ // override this function.
+ anApp->Start();
+
+
+ delete anApp;
+
+ return 0;
+}