summaryrefslogtreecommitdiff
path: root/osframework/source/demos
diff options
context:
space:
mode:
Diffstat (limited to 'osframework/source/demos')
-rw-r--r--osframework/source/demos/Demo1/Board.cpp166
-rw-r--r--osframework/source/demos/Demo1/Board.h106
-rw-r--r--osframework/source/demos/Demo1/Demo1 VS2005 WideString.vcproj237
-rw-r--r--osframework/source/demos/Demo1/Demo1 VS2005.vcproj237
-rw-r--r--osframework/source/demos/Demo1/Demo1 WideString.vcproj149
-rw-r--r--osframework/source/demos/Demo1/Demo1.dsp126
-rw-r--r--osframework/source/demos/Demo1/Demo1.vcproj149
-rw-r--r--osframework/source/demos/Demo1/GameApp.cpp114
-rw-r--r--osframework/source/demos/Demo1/GameApp.h88
-rw-r--r--osframework/source/demos/Demo1/main.cpp46
-rw-r--r--osframework/source/demos/Demo2/Board.cpp305
-rw-r--r--osframework/source/demos/Demo2/Board.h108
-rw-r--r--osframework/source/demos/Demo2/Demo2 VS2005 WideString.vcproj237
-rw-r--r--osframework/source/demos/Demo2/Demo2 VS2005.vcproj237
-rw-r--r--osframework/source/demos/Demo2/Demo2 WideString.vcproj149
-rw-r--r--osframework/source/demos/Demo2/Demo2.dsp125
-rw-r--r--osframework/source/demos/Demo2/Demo2.vcproj149
-rw-r--r--osframework/source/demos/Demo2/GameApp.cpp306
-rw-r--r--osframework/source/demos/Demo2/GameApp.h105
-rw-r--r--osframework/source/demos/Demo2/main.cpp46
-rw-r--r--osframework/source/demos/Demo3/Board.cpp389
-rw-r--r--osframework/source/demos/Demo3/Board.h267
-rw-r--r--osframework/source/demos/Demo3/Demo3 VS2005 WideString.vcproj237
-rw-r--r--osframework/source/demos/Demo3/Demo3 VS2005.vcproj237
-rw-r--r--osframework/source/demos/Demo3/Demo3 WideString.vcproj149
-rw-r--r--osframework/source/demos/Demo3/Demo3.dsp125
-rw-r--r--osframework/source/demos/Demo3/Demo3.vcproj149
-rw-r--r--osframework/source/demos/Demo3/GameApp.cpp301
-rw-r--r--osframework/source/demos/Demo3/GameApp.h108
-rw-r--r--osframework/source/demos/Demo3/main.cpp45
-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
-rw-r--r--osframework/source/demos/Demo5/Board.cpp306
-rw-r--r--osframework/source/demos/Demo5/Board.h205
-rw-r--r--osframework/source/demos/Demo5/Demo5 VS2005 WideString.vcproj258
-rw-r--r--osframework/source/demos/Demo5/Demo5 VS2005.vcproj258
-rw-r--r--osframework/source/demos/Demo5/Demo5 WideString.vcproj162
-rw-r--r--osframework/source/demos/Demo5/Demo5.dsp150
-rw-r--r--osframework/source/demos/Demo5/Demo5.vcproj162
-rw-r--r--osframework/source/demos/Demo5/DemoDialog.cpp414
-rw-r--r--osframework/source/demos/Demo5/DemoDialog.h209
-rw-r--r--osframework/source/demos/Demo5/GameApp.cpp427
-rw-r--r--osframework/source/demos/Demo5/GameApp.h173
-rw-r--r--osframework/source/demos/Demo5/TitleScreen.cpp205
-rw-r--r--osframework/source/demos/Demo5/TitleScreen.h125
-rw-r--r--osframework/source/demos/Demo5/main.cpp50
-rw-r--r--osframework/source/demos/Hun-garr/Board.cpp2189
-rw-r--r--osframework/source/demos/Hun-garr/Board.h739
-rw-r--r--osframework/source/demos/Hun-garr/GameApp.cpp279
-rw-r--r--osframework/source/demos/Hun-garr/GameApp.h171
-rw-r--r--osframework/source/demos/Hun-garr/GameOverEffect.cpp452
-rw-r--r--osframework/source/demos/Hun-garr/GameOverEffect.h204
-rw-r--r--osframework/source/demos/Hun-garr/Hun-garr VS2005 WideString.vcproj276
-rw-r--r--osframework/source/demos/Hun-garr/Hun-garr VS2005.vcproj276
-rw-r--r--osframework/source/demos/Hun-garr/Hun-garr WideString.vcproj176
-rw-r--r--osframework/source/demos/Hun-garr/Hun-garr.vcproj176
-rw-r--r--osframework/source/demos/Hun-garr/Hungarr.dsp166
-rw-r--r--osframework/source/demos/Hun-garr/LevelupEffect.cpp438
-rw-r--r--osframework/source/demos/Hun-garr/LevelupEffect.h191
-rw-r--r--osframework/source/demos/Hun-garr/OptionsDialog.cpp273
-rw-r--r--osframework/source/demos/Hun-garr/OptionsDialog.h110
-rw-r--r--osframework/source/demos/Hun-garr/TitleScreen.cpp150
-rw-r--r--osframework/source/demos/Hun-garr/TitleScreen.h121
-rw-r--r--osframework/source/demos/Hun-garr/main.cpp41
-rw-r--r--osframework/source/demos/Res.cpp378
-rw-r--r--osframework/source/demos/Res.h147
-rw-r--r--osframework/source/demos/V12Demo/.#Board.cpp.1.7442
-rw-r--r--osframework/source/demos/V12Demo/.#Board.cpp.1.8442
-rw-r--r--osframework/source/demos/V12Demo/Board.cpp439
-rw-r--r--osframework/source/demos/V12Demo/Board.h87
-rw-r--r--osframework/source/demos/V12Demo/DemoWidget.cpp101
-rw-r--r--osframework/source/demos/V12Demo/DemoWidget.h38
-rw-r--r--osframework/source/demos/V12Demo/V12Demo VS2005 WideString.vcproj234
-rw-r--r--osframework/source/demos/V12Demo/V12Demo VS2005.vcproj234
-rw-r--r--osframework/source/demos/V12Demo/V12Demo WideString.vcproj143
-rw-r--r--osframework/source/demos/V12Demo/V12Demo.dsp141
-rw-r--r--osframework/source/demos/V12Demo/V12Demo.vcproj143
-rw-r--r--osframework/source/demos/V12Demo/V12DemoApp.cpp116
-rw-r--r--osframework/source/demos/V12Demo/V12DemoApp.h79
-rw-r--r--osframework/source/demos/V12Demo/main.cpp65
-rw-r--r--osframework/source/demos/XMLDemo/Board.cpp50
-rw-r--r--osframework/source/demos/XMLDemo/Board.h29
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemo VS2005 WideString.vcproj228
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemo VS2005.vcproj228
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemo WideString.vcproj139
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemo.dsp133
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemo.vcproj139
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemoApp.cpp217
-rw-r--r--osframework/source/demos/XMLDemo/XMLDemoApp.h83
-rw-r--r--osframework/source/demos/XMLDemo/main.cpp34
-rw-r--r--osframework/source/demos/bass.dllbin0 -> 92216 bytes
-rw-r--r--osframework/source/demos/demos.txt199
-rw-r--r--osframework/source/demos/fonts/ArmorPiercing22.txt67
-rw-r--r--osframework/source/demos/fonts/ContinuumBold12.txt100
-rw-r--r--osframework/source/demos/fonts/Kiloton9.txt56
-rw-r--r--osframework/source/demos/fonts/_ArmorPiercing22.pngbin0 -> 8303 bytes
-rw-r--r--osframework/source/demos/fonts/_ContinuumBold12.gifbin0 -> 8027 bytes
-rw-r--r--osframework/source/demos/fonts/_Kiloton9.pngbin0 -> 1033 bytes
-rw-r--r--osframework/source/demos/fonts/_supernova20.pngbin0 -> 2413 bytes
-rw-r--r--osframework/source/demos/fonts/supernova20.txt28
-rw-r--r--osframework/source/demos/images/atomicexplosion.jpgbin0 -> 20265 bytes
-rw-r--r--osframework/source/demos/images/atomicexplosion_.jpgbin0 -> 16883 bytes
-rw-r--r--osframework/source/demos/images/beam_opaque.jpgbin0 -> 573 bytes
-rw-r--r--osframework/source/demos/images/beam_opaque_.gifbin0 -> 1382 bytes
-rw-r--r--osframework/source/demos/images/bomb_radial_death.jpgbin0 -> 25696 bytes
-rw-r--r--osframework/source/demos/images/bomb_radial_death_.jpgbin0 -> 18025 bytes
-rw-r--r--osframework/source/demos/images/btn_down.gifbin0 -> 881 bytes
-rw-r--r--osframework/source/demos/images/btn_down_.gifbin0 -> 284 bytes
-rw-r--r--osframework/source/demos/images/btn_over.gifbin0 -> 881 bytes
-rw-r--r--osframework/source/demos/images/btn_over_.gifbin0 -> 284 bytes
-rw-r--r--osframework/source/demos/images/btn_up.gifbin0 -> 881 bytes
-rw-r--r--osframework/source/demos/images/btn_up_.gifbin0 -> 268 bytes
-rw-r--r--osframework/source/demos/images/checkbox.gifbin0 -> 933 bytes
-rw-r--r--osframework/source/demos/images/checkbox_.gifbin0 -> 217 bytes
-rw-r--r--osframework/source/demos/images/custom_dragging.gifbin0 -> 1134 bytes
-rw-r--r--osframework/source/demos/images/custom_dragging_.gifbin0 -> 485 bytes
-rw-r--r--osframework/source/demos/images/custom_hand.gifbin0 -> 501 bytes
-rw-r--r--osframework/source/demos/images/custom_hand_.gifbin0 -> 533 bytes
-rw-r--r--osframework/source/demos/images/custom_pointer.gifbin0 -> 1131 bytes
-rw-r--r--osframework/source/demos/images/custom_pointer_.gifbin0 -> 1566 bytes
-rw-r--r--osframework/source/demos/images/custom_text.gifbin0 -> 956 bytes
-rw-r--r--osframework/source/demos/images/dialog.gifbin0 -> 8246 bytes
-rw-r--r--osframework/source/demos/images/dialog_.gifbin0 -> 2394 bytes
-rw-r--r--osframework/source/demos/images/dialog_btn.gifbin0 -> 1667 bytes
-rw-r--r--osframework/source/demos/images/dialog_btn_.gifbin0 -> 849 bytes
-rw-r--r--osframework/source/demos/images/hungarr_logo.jpgbin0 -> 8008 bytes
-rw-r--r--osframework/source/demos/images/hungarr_logo_.gifbin0 -> 2347 bytes
-rw-r--r--osframework/source/demos/images/layer0.jpgbin0 -> 18797 bytes
-rw-r--r--osframework/source/demos/images/layer1.pngbin0 -> 34715 bytes
-rw-r--r--osframework/source/demos/images/layer2.pngbin0 -> 157474 bytes
-rw-r--r--osframework/source/demos/images/lightning.gifbin0 -> 77377 bytes
-rw-r--r--osframework/source/demos/images/lightning_.gifbin0 -> 32157 bytes
-rw-r--r--osframework/source/demos/images/loader_bar.jpgbin0 -> 4569 bytes
-rw-r--r--osframework/source/demos/images/loader_loading.gifbin0 -> 1596 bytes
-rw-r--r--osframework/source/demos/images/loader_loading_.gifbin0 -> 2547 bytes
-rw-r--r--osframework/source/demos/images/moon.gifbin0 -> 3895 bytes
-rw-r--r--osframework/source/demos/images/moon_.gifbin0 -> 621 bytes
-rw-r--r--osframework/source/demos/images/particle_lightning.jpgbin0 -> 5691 bytes
-rw-r--r--osframework/source/demos/images/planets_small.jpgbin0 -> 6302 bytes
-rw-r--r--osframework/source/demos/images/planets_small_.gifbin0 -> 3567 bytes
-rw-r--r--osframework/source/demos/images/robotrobot.gifbin0 -> 1131 bytes
-rw-r--r--osframework/source/demos/images/slider.gifbin0 -> 236 bytes
-rw-r--r--osframework/source/demos/images/slider_thumb.gifbin0 -> 242 bytes
-rw-r--r--osframework/source/demos/images/spark.jpgbin0 -> 927 bytes
-rw-r--r--osframework/source/demos/images/turbot_worry.gifbin0 -> 8085 bytes
-rw-r--r--osframework/source/demos/images/turbot_worry_.gifbin0 -> 2901 bytes
-rw-r--r--osframework/source/demos/images/unicron_baby.JPGbin0 -> 9522 bytes
-rw-r--r--osframework/source/demos/images/unicron_baby_.GIFbin0 -> 1197 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_down.jpgbin0 -> 17908 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_down_.gifbin0 -> 2133 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_left.jpgbin0 -> 16527 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_left_.gifbin0 -> 1562 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_right.jpgbin0 -> 4450 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_right_.gifbin0 -> 1564 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_up.jpgbin0 -> 5214 bytes
-rw-r--r--osframework/source/demos/images/unicron_beam_up_.gifbin0 -> 1867 bytes
-rw-r--r--osframework/source/demos/images/unicron_horiz.jpgbin0 -> 9352 bytes
-rw-r--r--osframework/source/demos/images/unicron_horiz_.gifbin0 -> 1874 bytes
-rw-r--r--osframework/source/demos/images/unicron_vert.jpgbin0 -> 9336 bytes
-rw-r--r--osframework/source/demos/images/unicron_vert_.gifbin0 -> 1905 bytes
-rw-r--r--osframework/source/demos/music/hungarr.oggbin0 -> 2467571 bytes
-rw-r--r--osframework/source/demos/music/music.mo3bin0 -> 343576 bytes
-rw-r--r--osframework/source/demos/osfd VS2005.sln91
-rw-r--r--osframework/source/demos/osfd WideString VS2005.sln91
-rw-r--r--osframework/source/demos/osfd WideString.sln80
-rw-r--r--osframework/source/demos/osfd.dsw149
-rw-r--r--osframework/source/demos/osfd.sln80
-rw-r--r--osframework/source/demos/properties/demo.xml38
-rw-r--r--osframework/source/demos/properties/resources.xml145
-rw-r--r--osframework/source/demos/sounds/bad2.oggbin0 -> 7999 bytes
-rw-r--r--osframework/source/demos/sounds/click2.oggbin0 -> 13500 bytes
-rw-r--r--osframework/source/demos/sounds/electro_start.oggbin0 -> 38895 bytes
-rw-r--r--osframework/source/demos/sounds/explosion.oggbin0 -> 19920 bytes
-rw-r--r--osframework/source/demos/sounds/killall_explode.oggbin0 -> 26950 bytes
-rw-r--r--osframework/source/demos/sounds/lament.oggbin0 -> 124400 bytes
-rw-r--r--osframework/source/demos/sounds/laserpowerup.oggbin0 -> 9587 bytes
-rw-r--r--osframework/source/demos/sounds/level_up.oggbin0 -> 29787 bytes
-rw-r--r--osframework/source/demos/sounds/level_up2.oggbin0 -> 16021 bytes
-rw-r--r--osframework/source/demos/sounds/magzap1.oggbin0 -> 7845 bytes
-rw-r--r--osframework/source/demos/sounds/metal_loop.wavbin0 -> 39290 bytes
-rw-r--r--osframework/source/demos/sounds/mouseover.oggbin0 -> 9903 bytes
-rw-r--r--osframework/source/demos/sounds/mutator.oggbin0 -> 13623 bytes
-rw-r--r--osframework/source/demos/sounds/planet.oggbin0 -> 11778 bytes
-rw-r--r--osframework/source/demos/sounds/robotlaser.oggbin0 -> 7547 bytes
-rw-r--r--osframework/source/demos/sounds/shorting.oggbin0 -> 17175 bytes
-rw-r--r--osframework/source/demos/sounds/slowdown1.oggbin0 -> 25757 bytes
-rw-r--r--osframework/source/demos/sounds/timer.oggbin0 -> 4171 bytes
-rw-r--r--osframework/source/demos/sounds/whirlpool1.oggbin0 -> 102612 bytes
198 files changed, 23031 insertions, 0 deletions
diff --git a/osframework/source/demos/Demo1/Board.cpp b/osframework/source/demos/Demo1/Board.cpp
new file mode 100644
index 0000000..77354de
--- /dev/null
+++ b/osframework/source/demos/Demo1/Board.cpp
@@ -0,0 +1,166 @@
+#include "Board.h"
+#include "SexyAppFramework/Graphics.h"
+
+// See the Draw method for more information on using the Color class.
+#include "SexyAppFramework/Color.h"
+
+// A generic X, Y point template. See Draw() below for usage info.
+#include "SexyAppFramework/Point.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;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+ // Let the parent class update as well. This will increment
+ // the variable mUpdateCnt which is an integer that indicates
+ // how many times the Update() method has been called. Since our
+ // Board class is updated 100 times per second, this variable will
+ // increment 100 times per second. As you will see in later demos,
+ // we will use this variable for animation since its value represents
+ // hundredths of a second, which is for almost all games a good
+ // enough timer value and doesn't rely on the system clock function
+ // call.
+ Widget::Update();
+
+
+ // For this and most of the other demos, you will see the function
+ // below called every Update() call. MarkDirty() tells the widget
+ // manager that something has changed graphically in the widget and
+ // that it needs to be repainted. All widgets follow this convention.
+ // In general, if you don't need
+ // to update your drawing every time you call the Update method
+ // (the most common case is when the game is paused) you should
+ // NOT mark dirty. Why? If you aren't marking dirty every frame,
+ // then you aren't drawing every frame and thus you use less CPU
+ // time. Because people like to multitask, or they may be on a laptop
+ // with limited battery life, using less CPU time lets people do
+ // other things besides play your game. Of course, everyone
+ // will want to play your game at all times, but it's good to be
+ // nice to those rare people that might want to read email or
+ // do other things at the same time.
+ // In this particular demo, we
+ // won't be nice, as the purpose is to bring you up to speed as
+ // quickly as possible, and so we'll dispense with optimizations
+ // for now, so you can concentrate on other core issues first.
+ // In general, this is the last method called in the Update
+ // function, but that is not necessary. In fact, the MarkDirty
+ // function can be called anywhere, in any method (although
+ // calling it in the Draw method doesn't make sense since it is
+ // already drawing) and even multiple times. Calling it multiple
+ // times does not do anything: only the first call makes a difference.
+ MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ // And now for the good stuff! The Graphics object, "g", is
+ // automatically created and passed to this method by the
+ // WidgetManager and can be thought of as the main screen
+ // bitmap/canvas upon which all drawing will be done. This object
+ // is double buffered automatically so you don't need to worry
+ // about those details. All you need to do is instruct the object
+ // that you would like to draw something to it, and when the
+ // WidgetManager gets done letting all widgets draw to the
+ // Graphics object, it will then blit everything to the screen
+ // at once.
+
+ // First, let's start by drawing some geometric primitives. By
+ // default, the drawing color is black. We will change it later
+ // on. The first command clears the screen by drawing a
+ // black rectangle (black due to the default color) that is
+ // located at coordinate 0, 0 and is the same size as our
+ // Board widget, which is the same size as the application and
+ // thus is the same size of the game window.
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // You may notice that there's another form of FillRect, one that
+ // takes a Rect object as its sole parameter. That does the
+ // same thing as the above function, but sometimes its more useful
+ // to draw using a Rect object.
+
+ // Now let's learn how to change the color of the shapes we're drawing.
+ // Call the "SetColor" method to change the current drawing color.
+ // The parameter is a Color object which can take 3 or 4 parameters.
+ // If you call it with only 3 parameters, the 4th one, which is the
+ // alpha value, is set to 255 for fully opaque. The first three are
+ // in order, red, green, and blue. They range from 0 to 255.
+
+ g->SetColor(Color(255, 128, 64)); // some ugly orangish color
+
+ // Let's draw a smaller rectangle with its upper left corner
+ // in the center of the screen.
+ g->FillRect(mWidth / 2, mHeight / 2, 50, 50);
+
+ // Now let's continue with some other primitives. How about
+ // drawing a few lines? We'll use a few other colors too.
+
+ g->SetColor(Color(255, 0, 0)); // red
+
+ // Parameter order is X1, Y1, X2, Y2
+ g->DrawLine(0, 0, 200, 150);
+
+ g->SetColor(Color(0, 255, 0)); // green
+ g->DrawLine(mWidth, 0, mWidth - 200, 150);
+
+ g->SetColor(Color(0, 0, 255)); // blue
+ g->DrawLine(0, mHeight, 200, mHeight - 150);
+
+ g->SetColor(Color(255, 255, 255)); // white
+ g->DrawLine(mWidth, mHeight, mWidth - 200, mHeight - 150);
+
+ // Let's draw another rectangle, with vertices where each of
+ // the previous 4 lines were. This time, however, let's not
+ // fill it in and just draw its outline instead. We
+ // accomplish that with the DrawRect function, which doesn't
+ // fill in the center.
+ g->SetColor(Color(255, 0, 255)); // purple
+ g->DrawRect(200, 150, (mWidth - 200) - 200, (mHeight - 150) - 150);
+
+ // Tired of drawing lines and quads? How about drawing a triangle
+ // instad? To do that, we use the generic PolyFill function which
+ // draws a closed polygon with any number of points, >= 2.
+ // We pass this function an array containing these points. We'll
+ // create such an array right now, although in reality you'd
+ // probably make this a constant instead of creating it every time.
+ // We'll make use of the Point template which will use the int type
+ // to specify the X, Y coordinates of each point in our triangle.
+ // It is assumed that the last point connects to the first point.
+ Point trianglePoints[3];
+ trianglePoints[0] = Point(30, 30);
+ trianglePoints[1] = Point(30, 60);
+ trianglePoints[2] = Point(60, 45);
+ g->SetColor(Color(255, 255, 0)); // yellow
+ g->PolyFill(trianglePoints, 3);
+
+ // And how about a pentagram as well?
+ g->SetColor(Color(0, 255, 255)); // cyan
+ Point pentaPoints[5];
+ pentaPoints[0] = Point(200, 0);
+ pentaPoints[1] = Point(150, 40);
+ pentaPoints[2] = Point(150, 80);
+ pentaPoints[3] = Point(250, 80);
+ pentaPoints[4] = Point(250, 40);
+ g->PolyFill(pentaPoints, 5);
+
+
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo1/Board.h b/osframework/source/demos/Demo1/Board.h
new file mode 100644
index 0000000..c4240a9
--- /dev/null
+++ b/osframework/source/demos/Demo1/Board.h
@@ -0,0 +1,106 @@
+#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.
+//////////////////////////////////////////////////////////////////////////
+
+// This file must be included so that we can derive our Board class from it
+#include "SexyAppFramework/Widget.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;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+class Board : public Widget
+{
+
+ private:
+
+ GameApp* mApp;
+
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Board
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ Board(GameApp* theApp);
+
+ virtual ~Board();
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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();
+
+};
+
+
+}
+
+#endif // __BOARD_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo1/Demo1 VS2005 WideString.vcproj b/osframework/source/demos/Demo1/Demo1 VS2005 WideString.vcproj
new file mode 100644
index 0000000..ead39c9
--- /dev/null
+++ b/osframework/source/demos/Demo1/Demo1 VS2005 WideString.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo1"
+ ProjectGUID="{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+ 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)/../../Demo1_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo1.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo1.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="false"
+ 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)/../../Demo1.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="Demo1_release.map"
+ 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>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.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/Demo1/Demo1 VS2005.vcproj b/osframework/source/demos/Demo1/Demo1 VS2005.vcproj
new file mode 100644
index 0000000..d4d9779
--- /dev/null
+++ b/osframework/source/demos/Demo1/Demo1 VS2005.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo1"
+ ProjectGUID="{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+ 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)/../../Demo1_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo1.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo1.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="false"
+ 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)/../../Demo1.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="Demo1_release.map"
+ 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>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.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/Demo1/Demo1 WideString.vcproj b/osframework/source/demos/Demo1/Demo1 WideString.vcproj
new file mode 100644
index 0000000..48d9851
--- /dev/null
+++ b/osframework/source/demos/Demo1/Demo1 WideString.vcproj
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo1"
+ ProjectGUID="{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+ 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)/../../Demo1_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo1.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo1.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="FALSE"
+ 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)/../../Demo1.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo1_release.map"
+ MapLines="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="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>
+ </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/Demo1/Demo1.dsp b/osframework/source/demos/Demo1/Demo1.dsp
new file mode 100644
index 0000000..d0976be
--- /dev/null
+++ b/osframework/source/demos/Demo1/Demo1.dsp
@@ -0,0 +1,126 @@
+# Microsoft Developer Studio Project File - Name="Demo1" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=DEMO1 - 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 "Demo1.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 "Demo1.mak" CFG="DEMO1 - WIN32 DEBUG"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Demo1 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Demo1 - 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)" == "Demo1 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Demo1___Win32_Release"
+# PROP BASE Intermediate_Dir "Demo1___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 /FD /c
+# SUBTRACT CPP /YX
+# 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:"..\Demo1.exe"
+# SUBTRACT LINK32 /map
+
+!ELSEIF "$(CFG)" == "Demo1 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Demo1___Win32_Debug"
+# PROP BASE Intermediate_Dir "Demo1___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 /map /debug /machine:I386 /out:"..\Demo1_debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Demo1 - Win32 Release"
+# Name "Demo1 - 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
+# 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
+# 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/Demo1/Demo1.vcproj b/osframework/source/demos/Demo1/Demo1.vcproj
new file mode 100644
index 0000000..afa01a7
--- /dev/null
+++ b/osframework/source/demos/Demo1/Demo1.vcproj
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo1"
+ ProjectGUID="{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+ 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)/../../Demo1_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo1.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo1.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="FALSE"
+ 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)/../../Demo1.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo1_release.map"
+ MapLines="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="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>
+ </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/Demo1/GameApp.cpp b/osframework/source/demos/Demo1/GameApp.cpp
new file mode 100644
index 0000000..b4a8549
--- /dev/null
+++ b/osframework/source/demos/Demo1/GameApp.cpp
@@ -0,0 +1,114 @@
+#include "GameApp.h"
+#include "Board.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/Common.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 1";
+
+ // 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\\Demo1";
+
+ // Set the application width/height in terms of pixels here.
+ mWidth = 640;
+ mHeight = 480;
+
+ mBoard = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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.
+ mWidgetManager->RemoveWidget(mBoard);
+ delete mBoard;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::Init()
+{
+ // Let the parent class perform any needed initializations first.
+ // This should always be done.
+ SexyAppBase::Init();
+
+ // In later demos, you will see more done with this function.
+ // For now, we have nothing else to initialize, so we are done.
+ // Once complete, the LoadingThreadProc function will automatically
+ // start and we will begin loading all our needed resources.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadProc()
+{
+ // In this particular demo, there are no resources that we
+ // need to load. In every game and in all subsequent demos, however,
+ // there will be things we need to load. Besides loading data,
+ // this thread can also update the progress indicator for the loading
+ // screen, which you will see in later demos.
+ // Once complete, the LoadingThreadCompleted function will be called.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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;
+
+ // Now that we're done loading everything we need (which wasn't
+ // anything in this particular demo), we need to get the main
+ // game screen up and running: That is our "Board" class, and
+ // it will handle all the drawing, updating, and input processing
+ // for most of the game.
+ mBoard = new Board(this);
+
+ // 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
+ // 640x480. 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);
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo1/GameApp.h b/osframework/source/demos/Demo1/GameApp.h
new file mode 100644
index 0000000..ce68822
--- /dev/null
+++ b/osframework/source/demos/Demo1/GameApp.h
@@ -0,0 +1,88 @@
+#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;
+
+class GameApp : public SexyAppBase
+{
+
+ private:
+
+ Board* mBoard;
+
+
+ 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();
+
+};
+
+}
+
+
+#endif // __GAMEAPP_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo1/main.cpp b/osframework/source/demos/Demo1/main.cpp
new file mode 100644
index 0000000..bfb8175
--- /dev/null
+++ b/osframework/source/demos/Demo1/main.cpp
@@ -0,0 +1,46 @@
+//////////////////////////////////////////////////////////////////////////
+// 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:
+// * Setting app width/height
+// * Drawing primitives
+// * Changing colors
+// * Widget basics: Adding, removing, drawing, updating
+// * Standardized game logic frame rate
+// * Intro to the Init and resource loading methods
+// * Introduction to the structure and organization of a SexyAppBase game
+//////////////////////////////////////////////////////////////////////////
+
+#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;
+}
diff --git a/osframework/source/demos/Demo2/Board.cpp b/osframework/source/demos/Demo2/Board.cpp
new file mode 100644
index 0000000..4bc7f4a
--- /dev/null
+++ b/osframework/source/demos/Demo2/Board.cpp
@@ -0,0 +1,305 @@
+#include "Board.h"
+#include "GameApp.h"
+#include "SexyAppFramework/Graphics.h"
+
+// See the Draw method for more information on using the Color class.
+#include "SexyAppFramework/Color.h"
+
+// Why are we including ImageFont.h and not Font.h? Font.h is just a generic
+// base class. ImageFont creates fonts from an image that contains all the
+// text characters as well as a text file that indicates character widths
+// and kerning information, as well as some more advanced features not used
+// in this tutorial such as font layers, etc.
+#include "SexyAppFramework/ImageFont.h"
+
+// The Image.h file just declares basic functions. All images are either of
+// the DDImage or MemoryImage type. For this demo, we will use DDImage
+// types, as they are the type returned by the image loading code.
+// A DDImage is actually derived from MemoryImage, so where an Image or
+// MemoryImage is required, a DDImage will suffice as well. A DDImage
+// contains optimized code for use with DirectX 7+.
+#include "SexyAppFramework/DDImage.h"
+
+// The Rectangle template, used to specify X, Y, Width, Height
+#include "SexyAppFramework/Rect.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;
+
+ // Start by fully glowing and making the pulse decrease
+ mPulseAmt = 255;
+ mIncPulse = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+ // Let the parent class update as well. This will increment
+ // the variable mUpdateCnt which is an integer that indicates
+ // how many times the Update() method has been called. Since our
+ // Board class is updated 100 times per second, this variable will
+ // increment 100 times per second. As you will see in later demos,
+ // we will use this variable for animation since its value represents
+ // hundredths of a second, which is for almost all games a good
+ // enough timer value and doesn't rely on the system clock function
+ // call.
+ Widget::Update();
+
+ // Every frame (100 times per second) let's change the pulse amount by
+ // 1. When we reach either 0 or 255 (the lower/upper bounds of
+ // a color value) we'll reverse the pulsing direction. See the Draw()
+ // method for its usage: we're going to draw an image with varying intenstiy
+ // over time.
+ if (mIncPulse)
+ {
+ if (++mPulseAmt >= 255)
+ {
+ mIncPulse = false;
+ mPulseAmt = 255;
+ }
+ }
+ else
+ {
+ if (--mPulseAmt <= 0)
+ {
+ mIncPulse = true;
+ mPulseAmt = 0;
+ }
+ }
+
+ // Let's play the timer sound effect once every 2 second.
+ // Since this method is called 100 times per second, just mod
+ // mUpdateCnt by 200. We do that by calling GameApp's PlaySample()
+ // method and specifying the integral ID of the sound to play. This
+ // ID is the same as we used when loading the sound in GameApp::LoadingThreadProc()
+ if (mUpdateCnt % 200 == 0)
+ mApp->PlaySample(1);
+
+ // What about playing a sound but making it play on either the left or
+ // right speaker? And what about pitch shifting? These are all possible,
+ // but we won't learn about them until a later demo.
+
+
+
+ // For this and most of the other demos, you will see the function
+ // below called every Update() call. MarkDirty() tells the widget
+ // manager that something has changed graphically in the widget and
+ // that it needs to be repainted. All widgets follow this convention.
+ // In general, if you don't need
+ // to update your drawing every time you call the Update method
+ // (the most common case is when the game is paused) you should
+ // NOT mark dirty. Why? If you aren't marking dirty every frame,
+ // then you aren't drawing every frame and thus you use less CPU
+ // time. Because people like to multitask, or they may be on a laptop
+ // with limited battery life, using less CPU time lets people do
+ // other things besides play your game. Of course, everyone
+ // will want to play your game at all times, but it's good to be
+ // nice to those rare people that might want to read email or
+ // do other things at the same time.
+ // In this particular demo, we
+ // won't be nice, as the purpose is to bring you up to speed as
+ // quickly as possible, and so we'll dispense with optimizations
+ // for now, so you can concentrate on other core issues first.
+ // In general, this is the last method called in the Update
+ // function, but that is not necessary. In fact, the MarkDirty
+ // function can be called anywhere, in any method (although
+ // calling it in the Draw method doesn't make sense since it is
+ // already drawing) and even multiple times. Calling it multiple
+ // times does not do anything: only the first call makes a difference.
+ MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ // And now for the good stuff! The Graphics object, "g", is
+ // automatically created and passed to this method by the
+ // WidgetManager and can be thought of as the main screen
+ // bitmap/canvas upon which all drawing will be done. This object
+ // is double buffered automatically so you don't need to worry
+ // about those details. All you need to do is instruct the object
+ // that you would like to draw something to it, and when the
+ // WidgetManager gets done letting all widgets draw to the
+ // Graphics object, it will then blit everything to the screen
+ // at once.
+
+ // First, let's start by clearing the screen to black.
+ // As you'll recall from Demo1, we set the color with SetColor
+ // and pass in a Color object that contains either 3 or 4 parameters,
+ // that represent the r,g,b,a values (alpha is 255 if only 3 specified).
+ g->SetColor(Color(0, 0, 0));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // Now let's print some text. In order to do so, we need to instruct the
+ // graphics object as to which font we want to use. We do that with
+ // the SetFont method. Then we call the DrawString method and pass in
+ // a normal string and give it an X, Y to draw at. But wait! If we just
+ // draw a string right now, we won't see it. Can you guess why?
+ // The graphics object is still using the color, white, which we
+ // set a few lines above. Thus, when it goes to draw the string,
+ // it will draw it in white. How do you change the text color?
+ // Easy: it's just like you learned for drawing those primitives:
+ // just use SetColor and you're done! It doesn't matter whether you
+ // set the color before or after you set the font, fyi.
+ g->SetColor(Color(255, 0, 0));
+ g->SetFont(mApp->mTextFont);
+ g->DrawString(_S("Woo! Text! Ya!"), 10, 10);
+
+ // Wait a minute, didn't we say to draw at a Y value of 10? Then why does it
+ // appear to be drawing at about 0? That's because the text is offset
+ // by the ascent of the font. A discussion of font terms is beyond the
+ // scope of this demo, but basically just remember that if you want to
+ // display the text at the exact Y coordinate, that you should add
+ // the value of the font's ascent. You can get the ascent by calling
+ // GetAscent() on the font in question. I'm going to use the same
+ // Y value of 10 just to show you the slight difference using GetAscent makes.
+ g->SetColor(Color(55, 90, 255));
+ // We already set the font, no need to set it again unless we want a new one
+ g->DrawString(_S("I like Techno and Drum n' Bass"), 170, 10 + mApp->mTextFont->GetAscent());
+
+ // And to help you out visually, let's draw a line at Y coordinate 10:
+ g->SetColor(Color(255, 255, 255));
+ g->DrawLine(0, 10, mWidth, 10);
+
+ // Just for fun, let's change the font. This font, as you can see from its image,
+ // only contains digits and a few symbols. As an example, I will draw a string
+ // containing only those characters as well as a string containing characters that
+ // the font can't represent to show you what would happen.
+ g->SetFont(mApp->mNumberFont);
+ g->SetColor(Color(255, 255, 0));
+ g->DrawString(_S("+200"), 10, 40);
+ g->DrawString(_S("+200 pts"), 10, 60);
+
+ // You can also get the width of a string in pixels for any given font. In addition, you
+ // can use a printf style function, StrFormat, which is defined in Common.h, to
+ // format strings. You might want to look at Common.h for some...common...and handy functions.
+ g->SetColor(Color(0, 255, 255));
+ SexyString myString = StrFormat(_S("You got %d points!"), 147);
+ g->SetFont(mApp->mTextFont);
+ g->DrawString(myString, 10, 80);
+ g->SetColor(Color(0, 255, 0));
+ g->DrawString(_S(" I am to the right of that previous string."), 10 + mApp->mTextFont->StringWidth(myString), 80);
+
+
+ // What about some other common text functions, like justifying and word wrapping?
+ // Not a problem. The Widget class contains some useful features.
+ // For justification, the easiest is to use the WriteString method.
+ // The valid justification values are:
+ // -1: Left justified (same as DrawString)
+ // 0: Centered
+ // 1: Right justified
+ //
+ // For centered/right justified, you can also specify a width indicating the size of the region you
+ // are printing in. The sole purpose of that is to control the centering/right aligning.
+ g->SetColor(Color(255, 255, 255));
+ WriteString(g, _S("Left justified at X of 200"), 200, 95, -1, -1);
+ WriteString(g, _S("Centered using app width"), 0, 110, mWidth, 0);
+ WriteString(g, _S("Centered using width of 200, X of 200"), 200, 125, 200, 0);
+
+ // And now for a word wrapping example. With this function, you specify a rectangular region
+ // that represents the "box" in which you want the text to be displayed. You can also
+ // set the line spacing, or use -1 for the default font height, and you can also set
+ // the justification using the same values as for WriteString. We'll also draw the "box" using
+ // the DrawRect function, for illustrative purposes. You may notice that I didn't offset the
+ // Y coordinate of the text by the font's ascent: that's because WriteWordWrapped automatically
+ // does that for you.
+ g->SetColor(Color(255, 255, 255));
+ g->DrawRect(30, 140, 200, 400);
+ g->SetColor(Color(0, 255, 0));
+ WriteWordWrapped(g, Rect(30, 140, 200, 400), _S("This is some text that is wrapped inside of the rectangle \
+ at X of 30, Y of 140, width of 200, height of 400. It has \
+ been wrapped using the default left justification and the \
+ default line spacing."), -1, -1);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Enough talk, let's draw images!
+ // The simplest way to draw an image is with, coincidentally, the DrawImage method.
+ // Just specify the image and the X, Y to draw at and boom! It's done.
+ g->DrawImage(mApp->mTurbotImg, 230, 140);
+
+ // What about changing the color of an image? This is called colorization, and it works just like
+ // all the previous examples: You call SetColor with the color you want. But wait! There's
+ // an extra step: Because colorizing an image on the fly is slower than normal drawing, you have
+ // to explicity tell the graphics object that you want to enable it. This is done by calling the
+ // SetColorizeImages method of the Graphics class with a parameter value of "true".
+ // IMPORTANT: You should call SetColorizeImages again but with a parameter of "false" when you
+ // are done drawing your colorized image! Otherwise all subsequent image drawing calls will
+ // be colorized using the most recent value from SetColor. You may call SetColor either before
+ // or after SetColorizeImages, it doesn't matter. For this example, we'll draw an image normally
+ // and then colorized. We'll also use the GetHeight() method to draw this image just below the
+ // previous one.
+ g->DrawImage(mApp->mOpaqueBeamImg, 230, 140 + mApp->mTurbotImg->GetHeight());
+
+ g->SetColor(Color(255, 0, 0));
+ g->SetColorizeImages(true);
+ g->DrawImage(mApp->mOpaqueBeamImg, 230 + mApp->mOpaqueBeamImg->GetWidth(), 140 + mApp->mTurbotImg->GetHeight());
+ g->SetColorizeImages(false);
+
+ // You may have noticed that part of the previous two images was drawn offscreen. The graphics object by
+ // default sets a clipping region to the size of the widget, and anything drawn outside of it
+ // is clipped, or not drawn. You'll see some more advanced uses of clipping and widgets in a later demo.
+
+ // There's another cool effect you can do to images: Drawing additively instead of normally.
+ // Additive drawing is just what the name implies: when you draw the image, instead of
+ // drawing using the exact RGBA values of the image, it actually combines them with whatever
+ // pixel values there are in the location in which it is placed. One common use of this is
+ // to draw the same image, but brighter: To do so, you'd just draw the image normally first,
+ // then draw the same image on top of it but additively. Let's try an example and draw
+ // our first image, mApp->mTurbotImg, additively to get a bright effect.
+ g->DrawImage(mApp->mTurbotImg, 230 + mApp->mTurbotImg->GetWidth(), 140);
+
+ // Enable additive drawing with the call below. IMPORTANT: You should set the
+ // drawmode back to Graphics::DRAWMODE_NORMAL when done, so that other images
+ // don't get drawn additively. Additive drawing is slower than colorization,
+ // so keep that in mind if you are concerned about your game's performance.
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->DrawImage(mApp->mTurbotImg, 230 + mApp->mTurbotImg->GetWidth(), 140);
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+
+ // You can even draw an image colorized and additively. This is comonly used to
+ // implement a pulsing sort of effect. Let's do just that: the variable,
+ // mPulseAmt, is updated in our Update method and controls the RGB value
+ // that we'll use to make our image pulse. Again, be sure to set things back
+ // to normal when you are done. Also, it matters not in which order the
+ // SetDrawMode, SetColor, and SetColorizeImages calls are made.
+ g->DrawImage(mApp->mTurbotImg, 230 + mApp->mTurbotImg->GetWidth() * 2, 140);
+
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColor(Color(mPulseAmt, mPulseAmt, mPulseAmt));
+ g->SetColorizeImages(true);
+ g->DrawImage(mApp->mTurbotImg, 230 + mApp->mTurbotImg->GetWidth() * 2, 140);
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ g->SetColorizeImages(false);
+
+ // And finally, let's just have a simple example of alpha blending. We'll
+ // Draw our first image, a picture of a moon, normally, and draw
+ // our friend Turbot at reduced opacity on top of it. The result is you can
+ // see through turbot to the moon below. Notice that we set the color
+ // for turbot to r=255, g=255, b=255, alpha=128: This results in the
+ // RGB values not being changed, only the alpha. Using a value of 255 for
+ // a colorization amount basically means that the color component will not
+ // be altered.
+ g->DrawImage(mApp->mMoonImg, 400, 300);
+ g->SetColor(Color(255, 255, 255, 60));
+ g->SetColorizeImages(true);
+ g->DrawImage(mApp->mTurbotImg, 400, 300);
+ g->SetColorizeImages(false);
+
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo2/Board.h b/osframework/source/demos/Demo2/Board.h
new file mode 100644
index 0000000..04d84cd
--- /dev/null
+++ b/osframework/source/demos/Demo2/Board.h
@@ -0,0 +1,108 @@
+#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.
+//////////////////////////////////////////////////////////////////////////
+
+// This file must be included so that we can derive our Board class from it
+#include "SexyAppFramework/Widget.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;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+class Board : public Widget
+{
+
+ private:
+
+ GameApp* mApp;
+ int mPulseAmt; // See Draw(): used to make an image pulse over time
+ bool mIncPulse; // If true, then we're increasing the pulse value, otherwise, decreasing
+
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Board
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ Board(GameApp* theApp);
+
+ virtual ~Board();
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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();
+
+};
+
+
+}
+
+#endif // __BOARD_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo2/Demo2 VS2005 WideString.vcproj b/osframework/source/demos/Demo2/Demo2 VS2005 WideString.vcproj
new file mode 100644
index 0000000..945028a
--- /dev/null
+++ b/osframework/source/demos/Demo2/Demo2 VS2005 WideString.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo2"
+ ProjectGUID="{3729E951-A2F8-4516-BFF8-312040890EA4}"
+ 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)/../../Demo2_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo2.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo2.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="false"
+ 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)/../../Demo2.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="Demo2_release.map"
+ 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>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.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/Demo2/Demo2 VS2005.vcproj b/osframework/source/demos/Demo2/Demo2 VS2005.vcproj
new file mode 100644
index 0000000..9944517
--- /dev/null
+++ b/osframework/source/demos/Demo2/Demo2 VS2005.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo2"
+ ProjectGUID="{3729E951-A2F8-4516-BFF8-312040890EA4}"
+ 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)/../../Demo2_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo2.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo2.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="false"
+ 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)/../../Demo2.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="Demo2_release.map"
+ 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>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.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/Demo2/Demo2 WideString.vcproj b/osframework/source/demos/Demo2/Demo2 WideString.vcproj
new file mode 100644
index 0000000..42e76ec
--- /dev/null
+++ b/osframework/source/demos/Demo2/Demo2 WideString.vcproj
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo2"
+ ProjectGUID="{3729E951-A2F8-4516-BFF8-312040890EA4}"
+ 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)/../../Demo2_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo2.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo2.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="FALSE"
+ 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)/../../Demo2.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo2_release.map"
+ MapLines="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="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>
+ </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/Demo2/Demo2.dsp b/osframework/source/demos/Demo2/Demo2.dsp
new file mode 100644
index 0000000..67ce42b
--- /dev/null
+++ b/osframework/source/demos/Demo2/Demo2.dsp
@@ -0,0 +1,125 @@
+# Microsoft Developer Studio Project File - Name="Demo2" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=Demo2 - 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 "Demo2.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 "Demo2.mak" CFG="Demo2 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Demo2 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Demo2 - 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)" == "Demo2 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Demo2___Win32_Release"
+# PROP BASE Intermediate_Dir "Demo2___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 /FD /c
+# SUBTRACT CPP /YX
+# 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:"..\Demo2.exe"
+
+!ELSEIF "$(CFG)" == "Demo2 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Demo2___Win32_Debug"
+# PROP BASE Intermediate_Dir "Demo2___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 /map /debug /machine:I386 /out:"..\Demo2_debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Demo2 - Win32 Release"
+# Name "Demo2 - 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
+# 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
+# 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/Demo2/Demo2.vcproj b/osframework/source/demos/Demo2/Demo2.vcproj
new file mode 100644
index 0000000..a85e4ce
--- /dev/null
+++ b/osframework/source/demos/Demo2/Demo2.vcproj
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo2"
+ ProjectGUID="{3729E951-A2F8-4516-BFF8-312040890EA4}"
+ 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)/../../Demo2_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo2.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo2.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="FALSE"
+ 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)/../../Demo2.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo2_release.map"
+ MapLines="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="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>
+ </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/Demo2/GameApp.cpp b/osframework/source/demos/Demo2/GameApp.cpp
new file mode 100644
index 0000000..5b8ca83
--- /dev/null
+++ b/osframework/source/demos/Demo2/GameApp.cpp
@@ -0,0 +1,306 @@
+#include "GameApp.h"
+#include "Board.h"
+#include "SexyAppFramework/WidgetManager.h"
+
+// Why are we including ImageFont.h and not Font.h? Font.h is just a generic
+// base class. ImageFont creates fonts from an image that contains all the
+// text characters as well as a text file that indicates character widths
+// and kerning information, as well as some more advanced features not used
+// in this tutorial such as font layers, etc.
+#include "SexyAppFramework/ImageFont.h"
+
+// The Image.h file just declares basic functions. All images are either of
+// the DDImage or MemoryImage type. For this demo, we will use DDImage
+// types, as they are the type returned by the image loading code.
+// A DDImage is actually derived from MemoryImage, so where an Image or
+// MemoryImage is required, a DDImage will suffice as well. A DDImage
+// contains optimized code for use with DirectX 7+.
+#include "SexyAppFramework/DDImage.h"
+
+// This will let us load sounds
+#include "SexyAppFramework/SoundManager.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 2";
+
+ // 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\\Demo2";
+
+ // 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;
+
+ mBoard = NULL;
+
+ mTextFont = NULL;
+ mNumberFont = NULL;
+ mTurbotImg = NULL;
+ mMoonImg = NULL;
+ mOpaqueBeamImg = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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.
+ mWidgetManager->RemoveWidget(mBoard);
+ delete mBoard;
+
+ // We need to clean up after ourselves and delete the image and
+ // font information.
+ delete mTextFont;
+ delete mNumberFont;
+ delete mTurbotImg;
+ delete mMoonImg;
+ delete mOpaqueBeamImg;
+
+ // We need to release the memory allocated to our sounds too.
+ // This call frees up the memory for ALL sound effects.
+ mSoundManager->ReleaseSounds();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::Init()
+{
+ // Let the parent class perform any needed initializations first.
+ // This should always be done.
+ SexyAppBase::Init();
+
+ // In later demos, you will see more done with this function.
+ // For now, we have nothing else to initialize, so we are done.
+ // Once complete, the LoadingThreadProc function will automatically
+ // start and we will begin loading all our needed resources.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadProc()
+{
+ // This time, we have things to load. Let's load in our two fonts
+ // and our three images.
+ // Besides loading data,
+ // this thread can also update the progress indicator for the loading
+ // screen, which you will see in later demos.
+ // Once complete, the LoadingThreadCompleted function will be called.
+
+ // Loading images is easy: you don't have to specify the image type.
+ // Depending on the file extension, the appropriate image decoder
+ // will be used. The following image types are supported:
+ // Targa (.tga), JPEG (.jpg), PNG (.png), GIF (.gif). You do NOT have
+ // to specify the extension when loading the file if you don't want to.
+ // In this case, all of the above extensions will be looked for.
+ // A discussion of image formats is beyond the scope of this tutorial.
+ // There is some important information to know about images.
+ // You will notice in the "images" directory that for each image,
+ // there is a black and white image with the same name but with
+ // an underscore ("_") at the end of it. By default, when you load
+ // and image, the code automatically looks for the presence of
+ // that file to use for the alpha information. Some file formats
+ // have the alpha channel built into them, like PNG files. But
+ // others, like JPEG or GIF files, do not. The purpose of the alpha
+ // file is of course to generate an image that doesn't have jagged
+ // lines, or to control the opacity of various parts of the image.
+ // As a side not, the alpha image file may also begin with the
+ // underscore instead of ending with it, it matters not, and again,
+ // is automatically loaded in by the image loading code.
+ // You need to clean up the memory allocated by these functions yourself.
+ mOpaqueBeamImg = (DDImage*) GetImage("images/beam_opaque");
+
+ // If the file was not found or couldn't be loaded (i.e. due to an
+ // incompatible file format) the returned value will be NULL.
+ // You should always check this, and if it occurs, display an error
+ // message, then set mLoadingFailed to true, and then immediately return.
+ if (mOpaqueBeamImg == NULL)
+ {
+
+ // The PopUp method displays a standard Windows message box.
+ // If in full screen mode, this will appropriately handle things such
+ // that the GDI surface is properly rendered and the dialog box appears
+ // as expected.
+ Popup("There was an error loading the file: images/beam_opaque");
+ mLoadingFailed = true;
+
+ return;
+ }
+
+ // Now load the other two images
+ mMoonImg = (DDImage*) GetImage("images/moon");
+ if (mMoonImg == NULL)
+ {
+ Popup("There was an error loading the file: images/moon");
+ mLoadingFailed = true;
+ return;
+ }
+
+ mTurbotImg = (DDImage*) GetImage("images/turbot_worry");
+ if (mTurbotImg == NULL)
+ {
+ Popup("There was an error loading the file: images/turbot_worry");
+ mLoadingFailed = true;
+ return;
+ }
+
+ // So we've loaded the images, that's all there is right? Wrong.
+ // If possible, we should try to palletize the images. An image that
+ // contains 255 or fewer colors can be palletized. This results in
+ // a memory savings of about 4x and doesn't affect the image quality
+ // at all. It's the same principals that the GIF format uses: instead
+ // of representing each red, green, blue, alpha value as a separate
+ // quantity (1 byte each, 4 bytes in total per pixel), we represent
+ // the actual combined RGBA value as a single number, from 0-255.
+ // This number is an index into a lookup table. Thus, every time
+ // the value (200,43,11,128), for example, is used, instead of
+ // representing that value as a 4 byte value every time it
+ // appears, we'd represent it with a 1 byte index into a lookup
+ // table that contained the above RGBA value. Don't worry, you
+ // don't have to really know or care about any of that if you
+ // didn't understand it. What you need to know is that by calling the
+ // Palletize() method on an image, you potentially can reduce the
+ // amount of RAM it consumes by 4 times. The Palletize method
+ // returns a boolean indicating if it could or couldn't be palletized.
+ ((DDImage*)mOpaqueBeamImg)->Palletize();
+ ((DDImage*)mMoonImg)->Palletize();
+ ((DDImage*)mTurbotImg)->Palletize();
+
+ // Now let's load and create some fonts. A font consists of an
+ // image and a text file. The image works on the same principles
+ // as a normal image file (like the ones above) works on. Except
+ // that with fonts, there is only 1 image, the alpha image.
+ // Thus, you will see in the "fonts" directory two images that
+ // begin with the underscore prefix. If there isn't a file
+ // of the same name without an underscore, then it is assumed that
+ // the file is of the same dimensions as the underscore file and that
+ // it is to be all white and fully opaque. This is done with fonts because
+ // it's common to want to change the color of the font, and to change
+ // the color, the base, original image color, should be white and
+ // fully opaque. More information on colorizing fonts and images can
+ // be found in Board.cpp, but for now know that the image in the fonts
+ // directory contains the alpha information for your font, and that it
+ // is assumed that the "main" image is pure white.
+ // The other file in the directory is a text file, commonly with the
+ // same name as the image, but without the underscore character, but
+ // not always. The file will define the name of the image to load.
+ // This file defines the characters, their widths, their offsets
+ // within the image, the point size, and any layers (which are not
+ // used or discussed in this demo). This is the data file and is
+ // how the font knows how to take a string and convert it into
+ // the proper images representing each character. A font is really
+ // just an image but with an extra data file that tells the program
+ // how to map strings to their image representation.
+ // You load a font by specifying the text data file.
+ mTextFont = new ImageFont(this, "fonts/Kiloton9.txt");
+
+ // We need to check to see if the font was properly initialized.
+ // If it wasn't, then an error occurred and we need to abort.
+ if (!mTextFont->mFontData->mInitialized)
+ {
+ delete mTextFont;
+ Popup("There was an error loading fonts/Kiloton9.txt");
+ mLoadingFailed = true;
+ return;
+ }
+
+ mNumberFont = new ImageFont(this, "fonts/supernova20.txt");
+ if (!mNumberFont->mFontData->mInitialized)
+ {
+ delete mNumberFont;
+ Popup("There was an error loading fonts/supernova20.txt");
+ mLoadingFailed = true;
+ return;
+ }
+
+ // Let's load some sounds. You assign a unique unsigned integer ID to each
+ // sound. It is with this ID that you indicate which sound you
+ // want to play. Valid types of sounds to load are:
+ // WAV, OGG, AU, and if you have FMod and enable FMod: MP3. Although
+ // you should probably not use MP3 due to patent/copyright issues
+ // unless of course that either doesn't bother you or you happen
+ // to have the legal right to do so. Like images, you don't have
+ // to specify the file extension. LoadSound returns a boolean
+ // indicating success or failure.
+ if (!mSoundManager->LoadSound(1, "sounds/timer"))
+ {
+ Popup("There was an error loading sounds/timer");
+ mLoadingFailed = true;
+ return;
+ }
+
+ if (!mSoundManager->LoadSound(2, "sounds/mutator"))
+ {
+ Popup("There was an error loading sounds/mutator");
+ 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;
+
+ // Now that we're done loading everything we need (which wasn't
+ // anything in this particular demo), we need to get the main
+ // game screen up and running: That is our "Board" class, and
+ // it will handle all the drawing, updating, and input processing
+ // for most of the game.
+ mBoard = new Board(this);
+
+ // 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);
+
+ // And just to test out our sound playing abilities, let's play the
+ // mutator sound to indicate that we're done loading.
+ // We do that by calling GameApp's PlaySample()
+ // method and specifying the integral ID of the sound to play. This
+ // ID is the same as we used when loading the sound in GameApp::LoadingThreadProc()
+ PlaySample(2);
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo2/GameApp.h b/osframework/source/demos/Demo2/GameApp.h
new file mode 100644
index 0000000..7a60300
--- /dev/null
+++ b/osframework/source/demos/Demo2/GameApp.h
@@ -0,0 +1,105 @@
+#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;
+
+ // Alright, fonts and images! You'll learn more about these in GameApp.cpp
+ // so check there for more info.
+ class ImageFont;
+ class Image;
+
+class GameApp : public SexyAppBase
+{
+
+ private:
+
+ Board* mBoard;
+
+ public:
+
+ // These are the fonts and images we'll be using for this demo. See
+ // GameApp.cpp for full information on fonts and images. We're going to
+ // make them public for easy accessing, since the point of this tutorial
+ // is to quickly get you up to speed on using the framework.
+ ImageFont* mTextFont;
+ ImageFont* mNumberFont;
+ Image* mOpaqueBeamImg;
+ Image* mMoonImg;
+ Image* mTurbotImg;
+
+
+ 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();
+
+};
+
+}
+
+
+#endif // __GAMEAPP_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo2/main.cpp b/osframework/source/demos/Demo2/main.cpp
new file mode 100644
index 0000000..36f0c9e
--- /dev/null
+++ b/osframework/source/demos/Demo2/main.cpp
@@ -0,0 +1,46 @@
+//////////////////////////////////////////////////////////////////////////
+// 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:
+// * Loading and displaying fonts
+// * Loading and displaying images
+// * Colorizing images
+// * Additive drawing
+// * Palletizing images to use less RAM (when possible)
+// * Loading/playing sounds
+// * Widget introduction: buttons, listeners, events, adding/removing
+//////////////////////////////////////////////////////////////////////////
+
+#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;
+}
diff --git a/osframework/source/demos/Demo3/Board.cpp b/osframework/source/demos/Demo3/Board.cpp
new file mode 100644
index 0000000..e4c868f
--- /dev/null
+++ b/osframework/source/demos/Demo3/Board.cpp
@@ -0,0 +1,389 @@
+#include "Board.h"
+#include "GameApp.h"
+#include "SexyAppFramework/Graphics.h"
+
+// See the Draw method for more information on using the Color class.
+#include "SexyAppFramework/Color.h"
+
+// The Image.h file just declares basic functions. All images are either of
+// the DDImage or MemoryImage type. For this demo, we will use DDImage
+// types, as they are the type returned by the image loading code.
+// A DDImage is actually derived from MemoryImage, so where an Image or
+// MemoryImage is required, a DDImage will suffice as well. A DDImage
+// contains optimized code for use with DirectX 7+.
+#include "SexyAppFramework/DDImage.h"
+
+// The Rectangle template, used to specify X, Y, Width, Height
+#include "SexyAppFramework/Rect.h"
+
+// We're going to be making a button in this demo so we need to
+// include this file.
+#include "SexyAppFramework/ButtonWidget.h"
+
+// We're going to add our own button widget, which requires knowing about the
+// WidgetManager.
+#include "SexyAppFramework/WidgetManager.h"
+
+#include "SexyAppFramework/ImageFont.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;
+
+ // Start off drawing the first frame of mLightningImg
+ mAnimFrame = 0;
+
+ mButton = NULL;
+
+ mMouseX = mMouseY = 0;
+ mLeftDown = mRightDown = mMiddleDown = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+ delete mButton;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+ // Let the parent class update as well. This will increment
+ // the variable mUpdateCnt which is an integer that indicates
+ // how many times the Update() method has been called. Since our
+ // Board class is updated 100 times per second, this variable will
+ // increment 100 times per second. As you will see in later demos,
+ // we will use this variable for animation since its value represents
+ // hundredths of a second, which is for almost all games a good
+ // enough timer value and doesn't rely on the system clock function
+ // call.
+ Widget::Update();
+
+ // Let's update our animation frame every 5 update ticks. This
+ // is equivalent to 20 times per second.
+ if (mUpdateCnt % 5 == 0)
+ {
+ // In GameApp we specified how many rows and columns this image
+ // had. Thus, if our current frame of animation exceeds the number
+ // of frames that we have, we should reset the animation frame back
+ // to 0.
+ if (++mAnimFrame >= mApp->mLightningImg->mNumRows)
+ mAnimFrame = 0;
+ }
+
+
+
+ // For this and most of the other demos, you will see the function
+ // below called every Update() call. MarkDirty() tells the widget
+ // manager that something has changed graphically in the widget and
+ // that it needs to be repainted. All widgets follow this convention.
+ // In general, if you don't need
+ // to update your drawing every time you call the Update method
+ // (the most common case is when the game is paused) you should
+ // NOT mark dirty. Why? If you aren't marking dirty every frame,
+ // then you aren't drawing every frame and thus you use less CPU
+ // time. Because people like to multitask, or they may be on a laptop
+ // with limited battery life, using less CPU time lets people do
+ // other things besides play your game. Of course, everyone
+ // will want to play your game at all times, but it's good to be
+ // nice to those rare people that might want to read email or
+ // do other things at the same time.
+ // In this particular demo, we
+ // won't be nice, as the purpose is to bring you up to speed as
+ // quickly as possible, and so we'll dispense with optimizations
+ // for now, so you can concentrate on other core issues first.
+ // In general, this is the last method called in the Update
+ // function, but that is not necessary. In fact, the MarkDirty
+ // function can be called anywhere, in any method (although
+ // calling it in the Draw method doesn't make sense since it is
+ // already drawing) and even multiple times. Calling it multiple
+ // times does not do anything: only the first call makes a difference.
+ MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ // The Graphics object, "g", is
+ // automatically created and passed to this method by the
+ // WidgetManager and can be thought of as the main screen
+ // bitmap/canvas upon which all drawing will be done. This object
+ // is double buffered automatically so you don't need to worry
+ // about those details. All you need to do is instruct the object
+ // that you would like to draw something to it, and when the
+ // WidgetManager gets done letting all widgets draw to the
+ // Graphics object, it will then blit everything to the screen
+ // at once.
+
+ // First, let's start by clearing the screen to black.
+ // As you'll recall from Demo1, we set the color with SetColor
+ // and pass in a Color object that contains either 3 or 4 parameters,
+ // that represent the r,g,b,a values (alpha is 255 if only 3 specified).
+ g->SetColor(Color(0, 0, 0));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // Now let's try drawing a stretched image. We'll draw the original image
+ // stretched to twice its size. Drawing a stretched image is exactly like
+ // drawing a normal image, except that you have two extra parameters:
+ // the stretched width and height. You can use this to draw a shrunk version
+ // of the image as well (which we'll do second)
+ g->DrawImage(mApp->mTurbotImg, 0, 0, mApp->mTurbotImg->GetWidth() * 2, mApp->mTurbotImg->GetHeight() * 2);
+ g->DrawImage(mApp->mTurbotImg, 0, 275, mApp->mTurbotImg->GetWidth() / 2, mApp->mTurbotImg->GetHeight() / 2);
+
+ // The default stretching algorithm (the one used in the two examples above) uses
+ // the slow stretching method. The slow stretching method anti-aliases the resulting
+ // image to give a smoother, less pixelated look. While this tends to look a lot
+ // nicer, it also requires more processing power. Thus, if you either don't need
+ // or don't care about the anti-aliasing, you can instruct the graphics object
+ // to use fast stretching. Just remember: unless you turn fast stretching off when
+ // done, it will remain on. Let's give it a try by drawing the same image
+ // stretched twice as large using fast stretching.
+ g->SetFastStretch(true);
+ g->DrawImage(mApp->mTurbotImg, 275, 0, mApp->mTurbotImg->GetWidth() * 2, mApp->mTurbotImg->GetHeight() * 2);
+ g->SetFastStretch(false);
+
+ // A good use of fast/non fast stretching is to enable the slower stretching method
+ // for users with a supported 3D card and to disable it for users that have
+ // to run in software mode. You'll learn more about determining if a user is in
+ // 3D mode or not in a later demo, but keep this simple optimization in mind
+ // when creating drawing code for your games.
+
+ // Another cool thing we can do is to draw an image mirrored. This is exactly
+ // like using the DrawImage command except that you use DrawImageMirror
+ // instead. The optional fourth argument is just a convenience switch: if it's false,
+ // it will draw the image normally. In 3D mode, this is just as fast as a normal draw.
+ g->DrawImageMirror(mApp->mTurbotImg, 75, 275);
+
+ // But what if you want to draw the image mirrored AND stretched? It's a little different,
+ // but still easy. The first parameter, like usual, is the image you want to draw.
+ // The second parameter is a Rect which indicates the destination region you want to draw
+ // the image to: The XY of the Rect is just what you think it is, it's the pixel coordinate
+ // the image should be drawn at. The Width, Height of the Rect however is how you accomplish
+ // the stretching/shrinking. Specify a different width/height from the original image size
+ // and you've just accomplished resizing the original image! Note that we have a third
+ // parameter, also a Rect. This is the source rectangle, and indicates the region of
+ // image you wish to draw. As you'll see in our animation example, you don't have to
+ // always draw the entire image. You can specify a rectangular region of the source image
+ // that you wish to draw, which is useful for large strips of animation (more below).
+ // For our current case, however, we want to draw the entire image. So we specify that
+ // we should draw from the top left (0,0) coordinate of the source image and we should
+ // use it's full width/height. Again, just like with DrawImage, you can use the
+ // SetFastStretch call to set whether you want the nice, slow, smooth scaling, or the quick
+ // and efficient exact scaling. In 3D mode, this is just as fast as a normal stretched draw.
+ g->DrawImageMirror(mApp->mTurbotImg,
+ Rect(200, 275, mApp->mTurbotImg->GetWidth() * 2, mApp->mTurbotImg->GetHeight() * 2),
+ Rect(0, 0, mApp->mTurbotImg->GetWidth(), mApp->mTurbotImg->GetHeight()));
+
+
+ // Remember that black and white image we made in GameApp::LoadingThreadCompleted?
+ // How about we draw it now so you can see what the result looks like:
+ g->DrawImage(mApp->mAlteredImg, 500, 0);
+
+ // And now for the exciting part: animation! As you can see in ::Update, we
+ // increment the animation frame every 5 update ticks. We don't want to use
+ // DrawImage because that will render the entire image. Instead, we only
+ // want to draw a particular cel. We do that with the DrawImageCel function,
+ // specifying the row or column to draw like so:
+ g->DrawImageCel(mApp->mLightningImg, 0, 540, mAnimFrame);
+
+ // If your animation strips contain both multiple rows AND columns,
+ // you will need to use one of the alternate forms of DrawImageCel.
+ // DrawImageCel is really just a convenience wrapper around DrawImage.
+ // As you may have seen, you can tell DrawImage to draw just a particular
+ // rectangular region of the image. Here is the equivalent function
+ // call that we could have used in place of DrawImageCel above:
+ //g->DrawImage(mApp->mLightningImg,
+ //Rect(0, 540, mApp->mLightningImg->GetWidth(), mApp->mLightningImg->GetCelHeight()),
+ //Rect(0, mApp->mLightningImg->GetCelHeight() * mAnimFrame, mApp->mLightningImg->GetWidth(), mApp->mLightningImg->GetCelHeight()));
+ //
+ // As you can see, DrawImageCel is a lot quicker to type.
+
+ // Let's also display the current mouse XY and which button(s) are held down.
+ // You should recall how to set fonts and change their colors from Demo2.
+ // You will notice that the X, Y is not updated when the cursor moves over
+ // the button that we added. This can be explained by reading the comments
+ // for the MouseMove/MouseDrag/MouseDown/MouseUp methods.
+ g->SetFont(mApp->mFont);
+ g->SetColor(Color(255, 255, 255));
+ g->DrawString(StrFormat(_S("X, Y is %d, %d"), mMouseX, mMouseY), 630, 20);
+
+ SexyString buttonStr;
+ if (mLeftDown)
+ buttonStr += _S("Left button is down. ");
+ if (mRightDown)
+ buttonStr += _S("Right button is down. ");
+ if (mMiddleDown)
+ buttonStr += _S("Middle button is down. ");
+
+ WriteWordWrapped(g, Rect(630, 40, mWidth - 630, 300), buttonStr, -1, -1);
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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);
+
+ // Now let's create our first widget: a button. We do that by
+ // telling the button what integer ID it should be identified with,
+ // and by passing it a pointer to a button listener. Widgets have
+ // "listeners" which respond to their particular events. Any class
+ // can be a listener. For this particular demo, it is convenient for the
+ // Board class to be the listener, but it is also common to use GameApp
+ // as the main listener for all application buttons. The choice is up
+ // to you and your needs.
+ mButton = new ButtonWidget(1, this);
+
+ // Remember how we had to position and size the Board class when we first
+ // created it? A button is no different, it too is a widget. Let's
+ // place this button on screen and set it's size now:
+ mButton->Resize(675, 500, 100, 50);
+
+ // Because a button can have a label on it, we should set the font to use:
+ mButton->SetFont(mApp->mFont);
+
+ // And just what should that label be? How about the word "Off".
+ // We'll make it so that when it's clicked, it changes to "On" and
+ // back to "Off" again.
+ mButton->mLabel = _S("Off");
+
+ // We can also change some colors, like the label color and the color
+ // the label gets when moused over using the constants below:
+ mButton->SetColor(ButtonWidget::COLOR_LABEL, Color(0, 0, 0));
+ mButton->SetColor(ButtonWidget::COLOR_LABEL_HILITE, Color(0, 255, 0));
+
+ // And finally, just like with the Board class, we have to add it
+ // if we want to do anything with it.
+ theWidgetManager->AddWidget(mButton);
+
+ // If you want, you can also control the placement of the button.
+ // You can put it in front of another widget, behind another widget,
+ // at the top of the drawing order, or at the bottom of the
+ // drawing order. You accomplish that with the WidgetManager's
+ // PutInFront, PutBehind, BringToFront, BringToBack methods, respectively.
+
+ // But wait, what does this button look like? If you don't specify an
+ // image to use, the default Windows widget look will be used. We'll cover
+ // images and widgets in a later demo.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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. In
+ // our current case, we made a button in AddedToManager. Let's remove
+ // it now:
+ theWidgetManager->RemoveWidget(mButton);
+
+ // We'll delete it in our destructor.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::ButtonDepress(int theId)
+{
+ // Because we told our button that we, the Board class, are
+ // going to listen for its particular events, this method will
+ // thus be called when our button has any events it wants us
+ // to know about. In our current case, we only want to know when
+ // the button is clicked, but you could also respond to a few others.
+ // Let's change the label on our button whenever it is clicked, from
+ // "Off" to "On" and back again.
+ if (theId == 1)
+ {
+ // We assigned ID of 1 to our button. You'd ideally want to use
+ // a constant, but since this is a demo and there's only 1 button,
+ // we're going to just use a literal instead. When a button
+ // causes an action, it calls the appropriate listener function and
+ // let's the listener know who it is via the ID parameter.
+ if (mButton->mLabel == _S("Off"))
+ mButton->mLabel = _S("On");
+ else
+ mButton->mLabel = _S("Off");
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseMove(int x, int y)
+{
+ // This is called because the mouse cursor changed position and
+ // the Board class was the widget closest to the cursor.
+ // We're going to keep track of the XY coordinate whenever we
+ // get this message for the sake of this demo.
+ mMouseX = x;
+ mMouseY = y;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseDrag(int x, int y)
+{
+ // This is called because the mouse cursor changed position while
+ // a button was down (a drag) and
+ // the Board class was the widget closest to the cursor.
+ // We're going to keep track of the XY coordinate whenever we
+ // get this message for the sake of this demo.
+ // Note that MouseDrag is called instead of MouseMove under
+ // this condition.
+ mMouseX = x;
+ mMouseY = y;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseDown(int x, int y, int theClickCount)
+{
+ // Let the parent class know about this and perform any actions
+ // it needs to.
+ Widget::MouseDown(x, y, theClickCount);
+
+ // Let's just keep track of which button is currently held down.
+ if (theClickCount == 3)
+ mMiddleDown = true;
+ else if (theClickCount > 0)
+ mLeftDown = true;
+ else if (theClickCount < 0)
+ mRightDown = true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseUp(int x, int y, int theClickCount)
+{
+ // Let the parent class know about this and perform any actions
+ // it needs to.
+ Widget::MouseUp(x, y, theClickCount);
+
+ //You can actually tell if the left, right,
+ // or middle buttons are currently held down by calling one of these
+ // WidgetManager methods: IsLeftButtonDown, IsRightButtonDown,
+ // IsMiddleButtonDown. However, we're going to keep track of this
+ // manually just to illustrate a point.
+ if (theClickCount == 3)
+ mMiddleDown = false;
+ else if (theClickCount > 0)
+ mLeftDown = false;
+ else if (theClickCount < 0)
+ mRightDown = false;
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo3/Board.h b/osframework/source/demos/Demo3/Board.h
new file mode 100644
index 0000000..3f582eb
--- /dev/null
+++ b/osframework/source/demos/Demo3/Board.h
@@ -0,0 +1,267 @@
+#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.
+//////////////////////////////////////////////////////////////////////////
+
+// This file must be included so that we can derive our Board class from it
+#include "SexyAppFramework/Widget.h"
+
+// You'll learn about responding to button events in this demo.
+// Any class that wants to respond to them must derive from ButtonListener.
+#include "SexyAppFramework/ButtonListener.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;
+
+// We're going to make a modified copy of GameApp::mTurbotImg, so we'll
+// need to forward declare the DDImage class. See Board::CreateMirroredStretchedImg.
+class DDImage;
+
+// We're going to create a button in this demo and respond to its
+// click event.
+class ButtonWidget;
+
+// 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
+{
+
+ private:
+
+ GameApp* mApp;
+ ButtonWidget* mButton; // The button that we're going to create in this demo
+ int mAnimFrame; // The current frame of animation we're on for the mLightningImg image.
+ int mMouseX, mMouseY; // As an example, we'll keep track of the mouse cursor position and display it on screen
+
+ // We'll also keep track of which button is down
+ bool mLeftDown;
+ bool mRightDown;
+ bool mMiddleDown;
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Board
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ Board(GameApp* theApp);
+
+ virtual ~Board();
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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: 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);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseMove
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime the
+ // mouse moves. The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored (you'll learn about how
+ // to bypass that in a later demo).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseMove(int x, int y);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseDrag
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime the
+ // mouse moves AND a button is held down. This is the same thing as
+ // MouseMove except that it represents a drag operation. When dragging,
+ // MouseDrag will be called INSTEAD OF MouseMove.
+ // The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored (you'll learn about how
+ // to bypass that in a later demo).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseDrag(int x, int y);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseDown
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ // 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
+ //
+ // IMPORTANT: Because you can't have a double click with a
+ // single click, you will receive BOTH a left (or right) button as well
+ // as a double left (or right) button message whenever you double-click.
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime
+ // a mouse button is in the down state.
+ // The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored (you'll learn about how
+ // to bypass that in a later demo).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseDown(int x, int y, int theClickCount);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseUp
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ // 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
+ //
+ // IMPORTANT: Because you can't have a double click with a
+ // single click, you will receive BOTH a left (or right) button as well
+ // as a double left (or right) button message whenever you double-click.
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime
+ // a mouse button is in the up state after previously being in the down state.
+ // The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored (you'll learn about how
+ // to bypass that in a later demo).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseUp(int x, int y, int theClickCount);
+};
+
+
+}
+
+#endif // __BOARD_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo3/Demo3 VS2005 WideString.vcproj b/osframework/source/demos/Demo3/Demo3 VS2005 WideString.vcproj
new file mode 100644
index 0000000..058601e
--- /dev/null
+++ b/osframework/source/demos/Demo3/Demo3 VS2005 WideString.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo3"
+ ProjectGUID="{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+ 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)/../../Demo3_debug.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo3.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo3.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)/../../Demo3.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="Demo3_release.map"
+ 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>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.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/Demo3/Demo3 VS2005.vcproj b/osframework/source/demos/Demo3/Demo3 VS2005.vcproj
new file mode 100644
index 0000000..3c9a3f4
--- /dev/null
+++ b/osframework/source/demos/Demo3/Demo3 VS2005.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo3"
+ ProjectGUID="{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+ 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)/../../Demo3_debug.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo3.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo3.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)/../../Demo3.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ GenerateMapFile="true"
+ MapFileName="Demo3_release.map"
+ 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>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="GameApp.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/Demo3/Demo3 WideString.vcproj b/osframework/source/demos/Demo3/Demo3 WideString.vcproj
new file mode 100644
index 0000000..40f4dc6
--- /dev/null
+++ b/osframework/source/demos/Demo3/Demo3 WideString.vcproj
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo3"
+ ProjectGUID="{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+ 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)/../../Demo3_debug.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo3.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo3.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)/../../Demo3.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo3_release.map"
+ MapLines="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="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>
+ </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/Demo3/Demo3.dsp b/osframework/source/demos/Demo3/Demo3.dsp
new file mode 100644
index 0000000..2ed91d7
--- /dev/null
+++ b/osframework/source/demos/Demo3/Demo3.dsp
@@ -0,0 +1,125 @@
+# Microsoft Developer Studio Project File - Name="Demo3" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=Demo3 - 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 "Demo3.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 "Demo3.mak" CFG="Demo3 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Demo3 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Demo3 - 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)" == "Demo3 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Demo3___Win32_Release"
+# PROP BASE Intermediate_Dir "Demo3___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 /FD /c
+# SUBTRACT CPP /YX
+# 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:"..\Demo3.exe"
+
+!ELSEIF "$(CFG)" == "Demo3 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Demo3___Win32_Debug"
+# PROP BASE Intermediate_Dir "Demo3___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 /map /debug /machine:I386 /out:"..\Demo3_debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Demo3 - Win32 Release"
+# Name "Demo3 - 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
+# 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
+# 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/Demo3/Demo3.vcproj b/osframework/source/demos/Demo3/Demo3.vcproj
new file mode 100644
index 0000000..925100a
--- /dev/null
+++ b/osframework/source/demos/Demo3/Demo3.vcproj
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo3"
+ ProjectGUID="{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+ 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)/../../Demo3_debug.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo3.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo3.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)/../../Demo3.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo3_release.map"
+ MapLines="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="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>
+ </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/Demo3/GameApp.cpp b/osframework/source/demos/Demo3/GameApp.cpp
new file mode 100644
index 0000000..ef9767a
--- /dev/null
+++ b/osframework/source/demos/Demo3/GameApp.cpp
@@ -0,0 +1,301 @@
+#include "GameApp.h"
+#include "Board.h"
+#include "SexyAppFramework/WidgetManager.h"
+
+
+// The Image.h file just declares basic functions. All images are either of
+// the DDImage or MemoryImage type. For this demo, we will use DDImage
+// types, as they are the type returned by the image loading code.
+// A DDImage is actually derived from MemoryImage, so where an Image or
+// MemoryImage is required, a DDImage will suffice as well. A DDImage
+// contains optimized code for use with DirectX 7+.
+#include "SexyAppFramework/DDImage.h"
+
+// We're going to create a font for Board's button widget's label
+#include "SexyAppFramework/ImageFont.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 3";
+
+ // 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\\Demo3";
+
+ // 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.
+ //
+ // When 3D mode is on, the standard drawing routines will automatically use
+ // their hardware rendering versions, which in truns makes the game run faster.
+ // You do not need to do anything different when drawing in 2D or 3D mode.
+ // Although if 3D mode is disabled, you will most likely want to do less
+ // drawing intensive operations like additive drawing, colorization,
+ // real-time flipping/mirroring, etc.
+ mAutoEnable3D = true;
+
+ mBoard = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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.
+ mWidgetManager->RemoveWidget(mBoard);
+ delete mBoard;
+
+ // We need to clean up after ourselves and delete the image and
+ // font information.
+ delete mTurbotImg;
+ delete mLightningImg;
+ delete mAlteredImg;
+ delete mFont;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::Init()
+{
+ // Let the parent class perform any needed initializations first.
+ // This should always be done.
+ SexyAppBase::Init();
+
+ // In later demos, you will see more done with this function.
+ // For now, we have nothing else to initialize, so we are done.
+ // Once complete, the LoadingThreadProc function will automatically
+ // start and we will begin loading all our needed resources.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadProc()
+{
+ // This time, we have things to load. Let's load in our two fonts
+ // and our three images.
+ // Besides loading data,
+ // this thread can also update the progress indicator for the loading
+ // screen, which you will see in later demos.
+ // Once complete, the LoadingThreadCompleted function will be called.
+
+ // Loading images is easy: you don't have to specify the image type.
+ // Depending on the file extension, the appropriate image decoder
+ // will be used. The following image types are supported:
+ // Targa (.tga), JPEG (.jpg), PNG (.png), GIF (.gif). You do NOT have
+ // to specify the extension when loading the file if you don't want to.
+ // In this case, all of the above extensions will be looked for.
+ // A discussion of image formats is beyond the scope of this tutorial.
+ // There is some important information to know about images.
+ // You will notice in the "images" directory that for each image,
+ // there is a black and white image with the same name but with
+ // an underscore ("_") at the end of it. By default, when you load
+ // and image, the code automatically looks for the presence of
+ // that file to use for the alpha information. Some file formats
+ // have the alpha channel built into them, like PNG files. But
+ // others, like JPEG or GIF files, do not. The purpose of the alpha
+ // file is of course to generate an image that doesn't have jagged
+ // lines, or to control the opacity of various parts of the image.
+ // As a side not, the alpha image file may also begin with the
+ // underscore instead of ending with it, it matters not, and again,
+ // is automatically loaded in by the image loading code.
+ // You need to clean up the memory allocated by these functions yourself.
+ mTurbotImg = (DDImage*) GetImage("images/turbot_worry");
+
+ // If the file was not found or couldn't be loaded (i.e. due to an
+ // incompatible file format) the returned value will be NULL.
+ // You should always check this, and if it occurs, display an error
+ // message, then set mLoadingFailed to true, and then immediately return.
+ if (mTurbotImg == NULL)
+ {
+ mLoadingFailed = true;
+
+ // The PopUp method displays a standard Windows message box.
+ // If in full screen mode, this will appropriately handle things such
+ // that the GDI surface is properly rendered and the dialog box appears
+ // as expected.
+ Popup("There was an error loading the file: images/turbot_worry");
+
+ return;
+ }
+
+ mLightningImg = (DDImage*) GetImage("images/lightning");
+ if (mLightningImg == NULL)
+ {
+ mLoadingFailed = true;
+ Popup("There was an error loading the file: images/lightning");
+ return;
+ }
+
+ // There's something different about mLightningImg. If you look at the
+ // image in the iamges directory, you'll notice that it has multiple frames
+ // arranged in rows. This is an animation strip and is the main way that we
+ // accomplish animation. Rather than putting each frame in a separate file,
+ // we place it in one file and make each frame have the same width/height.
+ // When loading, the image loader has no idea that we even want to consider
+ // the image as being made of multiple frames. So we have to manually tell
+ // it how many rows and/or columns it has. In this case, there is only 1
+ // column, but there are 8 rows. We set this via mNumRows and mNumCols.
+ // You'll see why this is important in the Board class.
+ mLightningImg->mNumRows = 8;
+ mLightningImg->mNumCols = 1;
+
+
+ // So we've loaded the images, that's all there is right? Wrong.
+ // If possible, we should try to palletize the images. An image that
+ // contains 255 or fewer colors can be palletized. This results in
+ // a memory savings of about 4x and doesn't affect the image quality
+ // at all. It's the same principals that the GIF format uses: instead
+ // of representing each red, green, blue, alpha value as a separate
+ // quantity (1 byte each, 4 bytes in total per pixel), we represent
+ // the actual combined RGBA value as a single number, from 0-255.
+ // This number is an index into a lookup table. Thus, every time
+ // the value (200,43,11,128), for example, is used, instead of
+ // representing that value as a 4 byte value every time it
+ // appears, we'd represent it with a 1 byte index into a lookup
+ // table that contained the above RGBA value. Don't worry, you
+ // don't have to really know or care about any of that if you
+ // didn't understand it. What you need to know is that by calling the
+ // Palletize() method on an image, you potentially can reduce the
+ // amount of RAM it consumes by 4 times. The Palletize method
+ // returns a boolean indicating if it could or couldn't be palletized.
+ mLightningImg->Palletize();
+ mTurbotImg->Palletize();
+
+ // This is the same as in Demo2. Check the comments there
+ // if you've forgotten how to load and initialize a font.
+ mFont = new ImageFont(this, "fonts/Kiloton9.txt");
+
+ // We need to check to see if the font was properly initialized.
+ // If it wasn't, then an error occurred and we need to abort.
+ if (!mFont->mFontData->mInitialized)
+ {
+ delete mFont;
+ mLoadingFailed = true;
+ Popup("There was an error loading fonts/Kiloton9.txt");
+ 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;
+
+ // Now that we're done loading everything we need (which wasn't
+ // anything in this particular demo), we need to get the main
+ // game screen up and running: That is our "Board" class, and
+ // it will handle all the drawing, updating, and input processing
+ // for most of the game.
+ mBoard = new Board(this);
+
+ // 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);
+
+
+ // As part of a new topic in this demo, we're also going to modify the image
+ // data for mTurbotImg and make a grayscale version of it. I'll explain
+ // each step of the way:
+
+ // 1. Let's make a copy of the image so we don't ruin the original.
+ // We should make sure to delete this when we're done.
+ mAlteredImg = (DDImage*) CopyImage(mTurbotImg);
+
+ // 2. Now we need to get the pixel data. The pixel data is stored as
+ // an unsigned long array, where each entry represents the RGBA value.
+ // The data is actually stored in ARGB format, where alpha is
+ // the leftmost byte and blue is the rightmost byte.
+ unsigned long* bits = mAlteredImg->GetBits();
+
+ // 3. Now we will loop over each pixel in the image. The size of the bits array
+ // is simply the width times the height.
+ for (int i = 0; i < mAlteredImg->GetWidth() * mAlteredImg->GetHeight(); i++)
+ {
+ // 4. Get the ARGB color value for this pixel
+ unsigned long c = bits[i];
+
+ // 5. To illustrate the ARGB storage format, we will assign each
+ // component to a variable, although we're actually only going to care
+ // about the RGB values, for this particular example. The 4 lines below
+ // extract out the individual ARGB values.
+ unsigned char alpha = (unsigned char) (c >> 24);
+ unsigned char red = (unsigned char) ((c >> 16) & 0xFF);
+ unsigned char green = (unsigned char) ((c >> 8) & 0xFF);
+ unsigned char blue = (unsigned char) (c & 0xFF);
+
+ // 6. Just like the Color class, the ARGB values are from 0-255.
+ // Let's alter these to produce a grayscale image using one of many
+ // conversion methods. This method uses 30% of the red value,
+ // 59% of the green value, and 11% of the blue value:
+ unsigned long gray = (unsigned long) ((float)red * 0.30f + (float)green * 0.59f + (float)blue * 0.11f);
+
+ // 7. Now we need to put the pixel data back into the image's data.
+ // We do the opposite of how we extracted the ARGB values above and
+ // use a left shift instead of a right shift:
+
+ // alpha red green blue
+ bits[i] = (alpha << 24) | (gray << 16) | (gray << 8) | gray;
+ }
+
+ // The image won't use this modified data until we inform it that we've
+ // done some messing around with it. We do that with the BitsChanged()
+ // function call. After that, we're all done! Pretty simple. It just
+ // depends on what you want to actually do with the RGBA data. Extracting
+ // the information and putting it back is as simple as a few shifts.
+ mAlteredImg->BitsChanged();
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo3/GameApp.h b/osframework/source/demos/Demo3/GameApp.h
new file mode 100644
index 0000000..25901e6
--- /dev/null
+++ b/osframework/source/demos/Demo3/GameApp.h
@@ -0,0 +1,108 @@
+#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;
+
+ // You'll learn more about images in GameApp.cpp and Demo2,
+ // so check there for more info. You'll notice we're using DDImage instead
+ // of Image, like we did in Demo 2. That's for convenience only, so that
+ // we don't have to type cast the image every time we want to work with it.
+ class DDImage;
+
+ // We'll need a font for the label on our button (see Board for more info on buttons)
+ class ImageFont;
+
+class GameApp : public SexyAppBase
+{
+
+ private:
+
+ Board* mBoard;
+
+ public:
+
+ // These are the images we'll be using for this demo. See
+ // GameApp.cpp for full information. We're going to
+ // make them public for easy accessing, since the point of this tutorial
+ // is to quickly get you up to speed on using the framework.
+ DDImage* mTurbotImg;
+ DDImage* mLightningImg;
+ DDImage* mAlteredImg; // Used in our example of modifying the image bits to make an altered version of an image.
+
+ ImageFont* mFont; // The font we'll use for the label on our button in Board
+
+ 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();
+
+};
+
+}
+
+
+#endif // __GAMEAPP_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo3/main.cpp b/osframework/source/demos/Demo3/main.cpp
new file mode 100644
index 0000000..8b33e44
--- /dev/null
+++ b/osframework/source/demos/Demo3/main.cpp
@@ -0,0 +1,45 @@
+//////////////////////////////////////////////////////////////////////////
+// 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:
+// * Automatically detecting and enabling 3D mode
+// * Modifying image data/bits
+// * Stretching images
+// * Mirroring/flipping images
+// * Animation using image strips
+// * Widgets: buttons, listeners, basic events, mouse move/down/up/drag
+//////////////////////////////////////////////////////////////////////////
+
+#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;
+}
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;
+}
diff --git a/osframework/source/demos/Demo5/Board.cpp b/osframework/source/demos/Demo5/Board.cpp
new file mode 100644
index 0000000..c2a3cfd
--- /dev/null
+++ b/osframework/source/demos/Demo5/Board.cpp
@@ -0,0 +1,306 @@
+#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"
+#include "SexyAppFramework/Image.h"
+
+// Our example dialog box
+#include "DemoDialog.h"
+
+// And for our performance profiling example, we first have to define SEXY_PERF_ENABLED
+// before including PerfTimer.h:
+#define SEXY_PERF_ENABLED
+#include "SexyAppFramework/PerfTimer.h"
+
+// Lastly, for our example of how to catch memory leaks, we first
+// enable leak detection with a #define in EACH of the files we want
+// to find leaks in, then include the memory management file.
+// IT IS VERY IMPORTANT THAT THIS DEFINE AND INCLUDE BE DONE AFTER ALL
+// OTHER FILE INCLUDES OR ELSE IT WILL CAUSE LINKER AND COMPILER ERRORS!
+// Memory leaks will automatically be dumped to "mem_leaks.txt" when
+// the app is closed.
+#define SEXY_MEMTRACE
+#include "SexyAppFramework/memmgr.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;
+
+
+ mButton = NULL;
+
+ // Set up our parallaxing layers
+ for (int i = 0; i < 3; i++)
+ {
+ mLayer[i].mX = 0;
+
+ // Get the image for this layer. You'll notice in our resource
+ // file that we named the layers IMAGE_BG0, IMAGE_BG1, IMAGE_BG2.
+ // Instead of having to manually type in the layer names for each one,
+ // we can use some convenience routines from our generated Res.h/.cpp
+ // resource files. First step: make a string of the ID of the image we want
+ // to access:
+ std::string imageStringID = StrFormat("IMAGE_BG%d", i);
+
+ // what we need to do now is get the integer ID for our resource
+ // that has the same name as imageStringID.
+ int id = GetIdByStringId(imageStringID.c_str());
+
+ // Now that we have the integer ID, we can request the actual
+ // image data with it. We do that with GetImageById:
+ mLayer[i].mImage = GetImageById(id);
+
+ // Set the Y coordinate of the background layer so that it's
+ // base is at the bottom of the screen. Because the Board hasn't
+ // been resized or added to the manager yet, it's own mHeight and
+ // mWidth are at the default of 0, 0. But not to worry, we set the
+ // overall game's width/height in GameApp's constructor, so we
+ // can just use those variables instead:
+ mLayer[i].mY = (float)(mApp->mHeight - mLayer[i].mImage->GetHeight());
+ }
+
+ // We will ON PURPOSE leak memory as an example of how to track
+ // such things in your program. Review the comments at the top of this
+ // file about memory leak detection:
+ int* aLeakedInteger = new int;
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+ delete mButton;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+
+ // As an example of how to profile things, we're going to profile
+ // the update and draw functions. Clearly, profiling this almost
+ // empty function isn't too useful, but the point is to show you
+ // HOW to profile multiple things and how to view the results.
+ // You tell the profiler that you want it to begin with the
+ // statement below, passing in a string indicating WHAT you're
+ // profiling. The string can be anything. Enabled debug keys by
+ // pressing CTRL-ALT-D and then press F2 to enabled/disable profiling.
+ SEXY_PERF_BEGIN("Start_Of_Update");
+
+ Widget::Update();
+
+
+ MarkDirty();
+
+ // And you mark the end of a profiling section with
+ // SEXY_PER_END, passing in the same string you passed to
+ // SEXY_PERF_BEGIN.
+ SEXY_PERF_END("Start_Of_Update");
+
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::KeyDown(KeyCode theKey)
+{
+ // If the user presses the right or left arrow keys, let's
+ // scroll the layers:
+ if (theKey == KEYCODE_RIGHT)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // When the X coordinate has moved leftward (negative) by
+ // the image's width or more, we reset the X coordinate back to
+ // 0. Since we tile an image to the left and right of
+ // this center image, the user won't see the snapping back to 0.
+ mLayer[i].mX -= 1.0f * (i + 1);
+ if (mLayer[i].mX <= -mLayer[i].mImage->GetWidth())
+ mLayer[i].mX = 0;
+ }
+ }
+ else if (theKey == KEYCODE_LEFT)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // This is the opposite of above, but notice that we're checking
+ // to see if the X coordinate is >= the width of the image, and not the
+ // width of the application. That's because some of the layers are wider
+ // than the screen: 960 wide, when the game is 640 wide. If we checked
+ // against the game width instead, we'd get this odd flicker appearing
+ // because the tiling would be off. You can try it and see the effect.
+ mLayer[i].mX += 1.0f * (i + 1);
+ if (mLayer[i].mX >= mLayer[i].mImage->GetWidth())
+ mLayer[i].mX = 0;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ // As an example of how to profile things, we're going to profile
+ // the update and draw functions.
+ // You tell the profiler that you want it to begin with the
+ // statement below, passing in a string indicating WHAT you're
+ // profiling. The string can be anything. Enabled debug keys by
+ // pressing CTRL-ALT-D and then press F2 to enabled/disable profiling.
+ SEXY_PERF_BEGIN("Start_Of_Draw");
+
+ // Clear the screen to black
+ g->SetColor(Color(0, 0, 0));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+
+ for (int i = 0; i < 3; i++)
+ {
+ int imgWidth = mLayer[i].mImage->GetWidth();
+
+
+ // Let's learn about Graphics translation. Normally, you draw your image
+ // at a given XY by passing the coordinates to DrawImage. As an alternative,
+ // you can "translate" the Graphics object (change its XY drawing offset)
+ // and then just draw your image at 0, 0. Think of the Graphics object by
+ // default as always being at 0, 0. By translating it, you move that
+ // to whereever you like. The usefulness is in saving extra typing,
+ // as well as some other features that come into play when scrolling
+ // large worlds with many objects. For each of the background layers,
+ // let's move the graphics object to its base XY location:
+ g->TranslateF(mLayer[i].mX, mLayer[i].mY);
+
+ // Something else to know about translation is that it is the method
+ // used when drawing widgets. For every widget, the Graphics object
+ // is translated to its own X, Y coordinate. Thus, when drawing
+ // in the widget's class, you should always draw as if the top left
+ // corner of the widget itself was 0, 0. Since all along we've been making
+ // our Board widget the size of the screen, this hasn't been something we've
+ // had to care about. But as you'll see in the dialog box example, it's something
+ // we have to take into consideration. Normally, you can't draw outside the
+ // X, Y, width, height of a widget. However, as you'll also see, you can
+ // change that to allow drawing anywhere you want.
+
+ // Remember how in previous demos we mentioned that it's common to use the
+ // smoother DrawImageF functions instead of DrawImage if the user has 3D
+ // acceleration enabled? Let's do that know. We can check if hardware acceleration
+ // is on or not with a call to SexyAppBase's Is3DAccelerated:
+ if (mApp->Is3DAccelerated())
+ {
+ // Because we translated the graphics object, we can just draw our layers
+ // offset by the image width. Had we not translated the graphics object, here
+ // is the code we would have had to use instead:
+ // g->DrawImageF(mLayer[i].mImage, mLayer[i].mX - imgWidth, mLayer[i].mY);
+ // g->DrawImageF(mLayer[i].mImage, mLayer[i].mX, mLayer[i].mY);
+ // g->DrawImageF(mLayer[i].mImage, mLayer[i].mX + imgWidth, mLayer[i].mY);
+
+ g->DrawImageF(mLayer[i].mImage, (float)-imgWidth, 0.0f);
+ g->DrawImageF(mLayer[i].mImage, 0.0f, 0.0f);
+ g->DrawImageF(mLayer[i].mImage, (float)imgWidth, 0.0f);
+ }
+ else
+ {
+ // non-hardware accelerated
+ g->DrawImage(mLayer[i].mImage, -imgWidth, 0);
+ g->DrawImage(mLayer[i].mImage, 0, 0);
+ g->DrawImage(mLayer[i].mImage, imgWidth, 0);
+ }
+
+ // You should remember to put the Graphics object back to where it was
+ // before you translated it, otherwise all subsequent drawing commands will
+ // be offset by that amount.
+ g->TranslateF(-mLayer[i].mX, -mLayer[i].mY);
+ }
+
+ // And you mark the end of a profiling section with
+ // SEXY_PER_END, passing in the same string you passed to
+ // SEXY_PERF_BEGIN.
+ SEXY_PERF_END("Start_Of_Draw");
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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.
+ mButton = new ButtonWidget(Board::OPTIONS_BUTTON_ID, this);
+ mButton->SetFont(FONT_DEFAULT);
+ mButton->mLabel = _S("Click Me!");
+
+ // This time, let's use some images for our button.
+ // mOverImage is the image to use when the mouse cursor is over the button.
+ // mDownImage is the image to use when a mouse button is held down on it
+ // mButtonImage is the default image to use
+ // If we wanted to, we could specify a disabled image as well.
+ mButton->mOverImage = IMAGE_BUTTON_OVER;
+ mButton->mDownImage = IMAGE_BUTTON_DOWN;
+ mButton->mButtonImage = IMAGE_BUTTON_NORMAL;
+ mButton->mDoFinger = true;
+ mButton->Resize(56, 5, IMAGE_BUTTON_NORMAL->GetWidth(), IMAGE_BUTTON_NORMAL->GetHeight());
+
+ theWidgetManager->AddWidget(mButton);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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(mButton);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::ButtonDepress(int theId)
+{
+ // As another PURPOSEFUL example of detecting memory leaks, let's
+ // cause a leak here as well so you can see how the leak detection works.
+ // Again, this is on purpose to illustrate a point.
+ struct ParallaxLayer* aLeakedParallaxLayer = new struct ParallaxLayer;
+
+ if (theId == Board::OPTIONS_BUTTON_ID)
+ {
+ // Let's open our options dialog box. Everything works the same
+ // except that instead of using the WidgetManager's AddWidget function,
+ // we use a special AddDialog method. The first parameter is the ID
+ // of the dialog box, the second is the dialog box itself.
+ // In this case, we don't need to maintain a pointer to the dialog box
+ // to delete later. It will automatically be cleaned up when the
+ // dialog box is closed via the KillDialog command (see DemoDialog).
+ DemoDialog* dlg = new DemoDialog("Header", "Hello! I am a dialog box.");
+ dlg->Resize(50, 50, 300, 400);
+ mApp->AddDialog(DemoDialog::DIALOG_ID, dlg);
+ }
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo5/Board.h b/osframework/source/demos/Demo5/Board.h
new file mode 100644
index 0000000..ae8519e
--- /dev/null
+++ b/osframework/source/demos/Demo5/Board.h
@@ -0,0 +1,205 @@
+#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
+{
+
+
+
+class Graphics;
+class GameApp;
+class ButtonWidget;
+class WidgetManager;
+class Image;
+
+struct ParallaxLayer
+{
+ float mX;
+ float mY;
+ Image* mImage;
+};
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+class Board : public Widget, public ButtonListener
+{
+
+ private:
+
+ GameApp* mApp;
+ ButtonWidget* mButton;
+
+ // And in this demo, we're going to do some parallax scrolling whenever
+ // the arrow keys are pressed.
+ struct ParallaxLayer mLayer[3];
+
+ public:
+
+ // And let's finally use some enums for our widgets
+ enum
+ {
+ OPTIONS_BUTTON_ID
+ };
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Board
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ Board(GameApp* theApp);
+
+ virtual ~Board();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: KeyDown
+ // Parameters:
+ // theKey - A KEYCODE_ value from Keycodes.h that represents the
+ // key pressed.
+ //
+ // Returns: none
+ //
+ // Purpose: When a key is pressed, this method is called. This method
+ // differs from KeyChar (described below) in that you can detect non-ASCII
+ // keys with it, as well as ASCII.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void KeyDown(KeyCode theKey);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: KeyChar
+ // Parameters:
+ // theChar - The ASCII character that was pressed.
+ //
+ // Returns: none.
+ //
+ // Purpose: Unlike KeyDown, this method only takes ASCII characters
+ // as input. It's common to use KeyChar for your normal ASCII processing
+ // needs, and KeyDown for your extended keyboard key needs. We're not
+ // actually going to do anything with KeyChar in this code. It's displayed
+ // here though to illustrate the differences between KeyDown and to
+ // help explain its usage.
+ //////////////////////////////////////////////////////////////////////////
+ //virtual void KeyChar(char theChar);
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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: 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/Demo5/Demo5 VS2005 WideString.vcproj b/osframework/source/demos/Demo5/Demo5 VS2005 WideString.vcproj
new file mode 100644
index 0000000..639a511
--- /dev/null
+++ b/osframework/source/demos/Demo5/Demo5 VS2005 WideString.vcproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo5"
+ ProjectGUID="{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+ 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)/../../Demo5_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo5.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo5.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"
+ 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)/../../Demo5.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="DemoDialog.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="DemoDialog.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/Demo5/Demo5 VS2005.vcproj b/osframework/source/demos/Demo5/Demo5 VS2005.vcproj
new file mode 100644
index 0000000..bca9888
--- /dev/null
+++ b/osframework/source/demos/Demo5/Demo5 VS2005.vcproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Demo5"
+ ProjectGUID="{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+ 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)/../../Demo5_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Demo5.pdb"
+ GenerateMapFile="true"
+ MapFileName="Demo5.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"
+ 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)/../../Demo5.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="DemoDialog.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="DemoDialog.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/Demo5/Demo5 WideString.vcproj b/osframework/source/demos/Demo5/Demo5 WideString.vcproj
new file mode 100644
index 0000000..cb53cc1
--- /dev/null
+++ b/osframework/source/demos/Demo5/Demo5 WideString.vcproj
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo5"
+ ProjectGUID="{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+ 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)/../../Demo5_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo5.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo5.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"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="0"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo5.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="DemoDialog.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="DemoDialog.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/Demo5/Demo5.dsp b/osframework/source/demos/Demo5/Demo5.dsp
new file mode 100644
index 0000000..1e06a9a
--- /dev/null
+++ b/osframework/source/demos/Demo5/Demo5.dsp
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="Demo5" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=Demo5 - 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 "Demo5.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 "Demo5.mak" CFG="Demo5 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Demo5 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Demo5 - 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)" == "Demo5 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Demo5___Win32_Release"
+# PROP BASE Intermediate_Dir "Demo5___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 /FD /c
+# SUBTRACT CPP /YX
+# 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:"..\Demo5.exe"
+
+!ELSEIF "$(CFG)" == "Demo5 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Demo5___Win32_Debug"
+# PROP BASE Intermediate_Dir "Demo5___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:"..\Demo5_debug.exe" /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "Demo5 - Win32 Release"
+# Name "Demo5 - 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=.\DemoDialog.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=.\DemoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\GameApp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Res.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/Demo5/Demo5.vcproj b/osframework/source/demos/Demo5/Demo5.vcproj
new file mode 100644
index 0000000..e01d522
--- /dev/null
+++ b/osframework/source/demos/Demo5/Demo5.vcproj
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Demo5"
+ ProjectGUID="{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+ 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="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo5_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Demo5.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Demo5.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"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="0"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../Demo5.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="DemoDialog.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="DemoDialog.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/Demo5/DemoDialog.cpp b/osframework/source/demos/Demo5/DemoDialog.cpp
new file mode 100644
index 0000000..38d4f53
--- /dev/null
+++ b/osframework/source/demos/Demo5/DemoDialog.cpp
@@ -0,0 +1,414 @@
+#include "DemoDialog.h"
+#include "Res.h"
+#include "GameApp.h"
+#include "SexyAppFramework/SexyAppBase.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/Font.h"
+#include "SexyAppFramework/DialogButton.h"
+#include "SexyAppFramework/Checkbox.h"
+
+// We're going to use a slider widget to control sound/music volume
+#include "SexyAppFramework/Slider.h"
+
+using namespace Sexy;
+
+
+//////////////////////////////////////////////////////////////////////////
+// Let's do a little explanation of the parent Dialog class, shall we?
+// The first parameter we pass it is an image to use for the dialog box.
+//
+// This image has to have the property that its width and height be
+// divisible by 3. Why? For stretching/tiling, in case you want the
+// dialog box to be bigger than the actual image. The image can
+// be thought of as being divided into regions. The 4 corners
+// are drawn normally, and the remaining chunks (which comprise a third
+// of the image height or the image width) are tiled to allow for
+// the stretching of the dialog box.
+//
+// The image for the dialog button works the same way and must have
+// the same properties. Dialogs use a DialogButton class which is exactly
+// the same as a normal button class, except that they support tiling
+// the image if it is stretched larger than the original image is.
+//
+// The third parameter is the ID to use for the dialog box.
+//
+// The fourth indicates if the dialog is modal. If it is, then only the
+// dialog box and any widget above it (like its buttons) will receive
+// keyboard and mouse input. This is just like in Windows when a file
+// dialog appears and you can't click on the window of the application
+// below it.
+//
+// The fifth parameter is the header to use for the dialog box.
+//
+// The sixth parameter is the text to display in the body of the dialog
+// box. You can use the newline (\n) character for line breaks.
+//
+// The seventh parameter is optional, and is only used if the eigth
+// parameter is Dialog::BUTTONS_FOOTER. This is the text to display on
+// the footer (bottom) dialog button.
+//
+// The eigth parameter indicates what type of buttons are to display.
+// You can use BUTTONS_YES_NO or BUTTONS_OK_CANCEL for the standard
+// "Yes", "No" or "OK", "Cancel" options, BUTTONS_NONE for no buttons,
+// or BUTTONS_FOOTER for a single button that runs along the bottom.
+// Of course, you can change the labels on any of the buttons if you
+// like.
+//
+// The YES/OK/FOOTER buttons have a value of 2000 + the dialog's ID.
+// The NO/CANCEL buttons have a value of 3000 + the dialog's ID.
+//////////////////////////////////////////////////////////////////////////
+DemoDialog::DemoDialog(std::string theHeader, std::string theBody) :
+Dialog(IMAGE_DIALOG_BOX, IMAGE_DIALOG_BUTTON, DemoDialog::DIALOG_ID, true, StringToSexyStringFast(theHeader), StringToSexyStringFast(theBody), _S("CLOSE"), Dialog::BUTTONS_FOOTER)
+{
+ // We can set the rectangular region in which all text/buttons are to go
+ // by changing the mContentInsets variable. The first parameter
+ // is the distance from the left side of the dialog box, the second
+ // is the distance from the top, third is distance from the right,
+ // and fourth is distance from the bottom in which content
+ // can be placed.
+ mContentInsets = Insets(23, 20, 23, 20);
+
+ // We can then set a value for how many pixels below the inset top
+ // the text body should go:
+ mSpaceAfterHeader = 30;
+
+ // Let's also set the fonts to use for the header and the text. We should
+ // use the SetXXXFont functions instead of directly modifying the font because
+ // the dialog class makes a copy of the font and then deletes it in its destructor.
+ // This is due to backwards compatibility with our old Java framework.
+ SetHeaderFont(FONT_DEFAULT);
+ SetLinesFont(FONT_DEFAULT);
+ SetButtonFont(FONT_DEFAULT);
+
+ // We can also change the color of the text
+ SetColor(COLOR_HEADER, Color::Black);
+ SetColor(COLOR_LINES, Color::Black);
+
+ // Now let's create some sliders to control the music and sound volume with.
+ // The first parameter is the image to use for the track of the slider. The
+ // second is the image to use for the little movable "thumb" icon.
+ // The third is the ID and the fourth is the widget who wants to listen to
+ // the slider.
+ mMusicVolumeSlider = new Slider(IMAGE_SLIDER_TRACK, IMAGE_SLIDER_THUMB, DemoDialog::MUSIC_SLIDER_ID, this);
+
+ // Let's set the value of the music slider to what the current volume is.
+ // SexyAppBase has a GetMusicVolume function that returns this amount.
+ // But wait, we didn't get a SexyAppBase pointer passed into the constructor!
+ // Don't worry. gSexyAppBase is externed in SexyAppBase.h and we can use that instead.
+ mMusicVolumeSlider->SetValue(gSexyAppBase->GetMusicVolume());
+
+ mSfxVolumeSlider = new Slider(IMAGE_SLIDER_TRACK, IMAGE_SLIDER_THUMB, DemoDialog::SFX_SLIDER_ID, this);
+
+ // Let's set the sound volume to the current volume, just like we did with the music slider
+ mSfxVolumeSlider->SetValue(gSexyAppBase->GetSfxVolume());
+
+ // Let's make a button to show off how to use random numbers
+ mRandomBtn = new DialogButton(IMAGE_DIALOG_BUTTON, DemoDialog::RANDOM_BTN_ID, this);
+ mRandomBtn->mLabel = _S("Random #");
+ mRandomBtn->SetFont(FONT_DEFAULT);
+
+ // To illustrate the mClip example, we'll use a button to toggle it.
+ mClipBtn = new DialogButton(IMAGE_DIALOG_BUTTON, DemoDialog::CLIP_BTN_ID, this);
+ mClipBtn->mLabel = _S("Clipping");
+ mClipBtn->SetFont(FONT_DEFAULT);
+
+ m3DCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, DemoDialog::HARDWARE_CHECKBOX_ID, this);
+ mFSCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, DemoDialog::FS_CHECKBOX_ID, this);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+DemoDialog::~DemoDialog()
+{
+ delete mMusicVolumeSlider;
+ delete mSfxVolumeSlider;
+ delete mRandomBtn;
+ delete mClipBtn;
+ delete m3DCheckbox;
+ delete mFSCheckbox;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::Draw(Graphics* g)
+{
+ Dialog::Draw(g);
+
+ // Let's draw some labels for the sliders
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color::Black);
+
+ // We draw the X/Y at the slider's X/Y but we subtract off the dialog box's
+ // X/Y's from that. Why? The slider's XY's are in absolute screen coordinates,
+ // as are the dialog boxes. But as you may recall from Board::Draw(), where
+ // we explain graphics translation, once we get inside the draw loop of a
+ // widget, the graphics object is already moved (translated) to the widget's
+ // coordinates. Thus, in using the Graphics object, g, (0, 0) is located
+ // at the top left corner of the widget (our dialog box). So we
+ // just take the difference between the widget locations to produce the
+ // actual location we want to drawour text at:
+ g->DrawString(_S("Music volume:"), mMusicVolumeSlider->mX - mX,
+ mMusicVolumeSlider->mY - mY - mMusicVolumeSlider->mHeight);
+
+ g->DrawString(_S("Sound volume:"), mSfxVolumeSlider->mX - mX,
+ mSfxVolumeSlider->mY - mY - mSfxVolumeSlider->mHeight);
+
+ // Do the same for the checkboxes:
+ g->DrawString(_S("3D Mode:"), m3DCheckbox->mX - mX, m3DCheckbox->mY - mY - m3DCheckbox->mHeight + 20);
+ g->DrawString(_S("Full Screen:"), mFSCheckbox->mX - mX, mFSCheckbox->mY - mY - mFSCheckbox->mHeight + 20);
+
+ // As an example of clipping and how to disable it, let's draw
+ // a box and some text outside of the X/Y/Width/Height of this
+ // dialog box. You'll notice that when mClip is true (default),
+ // that anything drawn outside the bounds of the widget is clipped, or
+ // ignored. When mClip is false, no clipping is performed and we
+ // can draw anywhere.
+
+ g->SetColor(Color(255, 0, 0, 128));
+ // Draw a box in the bottom right
+ g->FillRect(mWidth, mHeight, 100, 100);
+ // Draw one in the top left
+ g->FillRect(-100, -100, 100, 100);
+ g->SetColor(Color::Black);
+ g->DrawString(_S("Top left"), -90, -20);
+ g->DrawString(_S("Bottom right"), mWidth + 10, mHeight + 20);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::Update()
+{
+ Dialog::Update();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::AddedToManager(WidgetManager* theWidgetManager)
+{
+ Dialog::AddedToManager(theWidgetManager);
+ theWidgetManager->AddWidget(mMusicVolumeSlider);
+ theWidgetManager->AddWidget(mSfxVolumeSlider);
+ theWidgetManager->AddWidget(mRandomBtn);
+ theWidgetManager->AddWidget(mClipBtn);
+
+ int checkWidth = IMAGE_CHECKBOX->GetWidth() / 2;
+ m3DCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ m3DCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+
+ mFSCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ mFSCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+
+ // Let's set the initial checked state of the 3d checkbox to true if the
+ // user has 3D support enabled. We determine that via a call to Is3DAccelerated
+ m3DCheckbox->mChecked = gSexyAppBase->Is3DAccelerated();
+
+ // We can check if the app is fullscreen by examining the mIsWindowed variable:
+ mFSCheckbox->mChecked = !gSexyAppBase->mIsWindowed;
+
+ theWidgetManager->AddWidget(m3DCheckbox);
+ theWidgetManager->AddWidget(mFSCheckbox);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::RemovedFromManager(WidgetManager* theWidgetManager)
+{
+ Dialog::RemovedFromManager(theWidgetManager);
+ theWidgetManager->RemoveWidget(mMusicVolumeSlider);
+ theWidgetManager->RemoveWidget(mSfxVolumeSlider);
+ theWidgetManager->RemoveWidget(mRandomBtn);
+ theWidgetManager->RemoveWidget(mClipBtn);
+ theWidgetManager->RemoveWidget(m3DCheckbox);
+ theWidgetManager->RemoveWidget(mFSCheckbox);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::Resize(int theX, int theY, int theWidth, int theHeight)
+{
+ Dialog::Resize(theX, theY, theWidth, theHeight);
+
+ // Layout the music slider so that it's left aligned with the
+ // boundary we set for the content insets. We'll make the slider fill the width
+ // of the content region (it'll be stretched if the base image isn't
+ // wide enough) too.
+ mMusicVolumeSlider->Resize(theX + mContentInsets.mLeft,
+ theY + 140,
+ mWidth - mContentInsets.mLeft - mContentInsets.mRight,
+ IMAGE_SLIDER_THUMB->GetHeight());
+
+ // Let's align the sound effect slider in the same way but using a different method.
+ // We know that we want the SFX slider to have the same X, width, and height, and
+ // to be just a few pixels below the music slider. Instead of having to mess around
+ // with the settings like we did above, we can use the layout (LAY_) flags instead.
+ // The first parameter is an ORed list of layout parameters and should be
+ // pretty self explanatory. You can find more in Widget.h.
+ // The second parameter is the widget to use as the reference.
+ // The rest are any extra padding to use for left/top/width/height related
+ // layout flags. As you can see, we wanted 60 pixels added to the top of
+ // our sound effect slider.
+ mSfxVolumeSlider->Layout(LAY_SameLeft | LAY_Below | LAY_SameWidth | LAY_SameHeight,
+ mMusicVolumeSlider, 0, 40, 0, 0);
+
+ // Place the button that will show off random number generation under the sound effect
+ // slider. But let's only make it take up 1/2 of the width of the slider
+ // and be only as tall as the original button image:
+ mRandomBtn->Layout(LAY_SameLeft | LAY_SameTop, mSfxVolumeSlider, 0, 40, 0, 0);
+ mRandomBtn->Resize(mRandomBtn->mX, mRandomBtn->mY,
+ mSfxVolumeSlider->mWidth / 2, IMAGE_DIALOG_BUTTON->mHeight);
+
+ // And let's place the clipping toggle button to its right
+ mClipBtn->Layout(LAY_Right | LAY_SameTop | LAY_SameWidth | LAY_SameHeight,
+ mRandomBtn, 0, 0, 0, 0);
+
+ // Place the 3D checkbox under the random button:
+ m3DCheckbox->Layout(LAY_SameLeft | LAY_Below, mRandomBtn, 0, 40, 0, 0);
+ m3DCheckbox->Resize(m3DCheckbox->mX, m3DCheckbox->mY,
+ IMAGE_CHECKBOX->mWidth / 2, IMAGE_CHECKBOX->mHeight);
+
+ // And the fullscreen box to the right of the 3d one. Except, let's use
+ // the mClipBtn's X coordinate to align with:
+ mFSCheckbox->Layout(LAY_SameTop | LAY_SameWidth | LAY_SameHeight, m3DCheckbox);
+ mFSCheckbox->Layout(LAY_SameLeft, mClipBtn);
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::SliderVal(int theId, double theVal)
+{
+ if (theId == DemoDialog::MUSIC_SLIDER_ID)
+ {
+ // Let's set the music volume to whatever the slider position is
+ gSexyAppBase->SetMusicVolume(theVal);
+ }
+ else if (theId == DemoDialog::SFX_SLIDER_ID)
+ {
+ // Set the sound value
+ gSexyAppBase->SetSfxVolume(theVal);
+
+ // A good idea is to play a "ding" or some similar sound when
+ // the thumb is released, to indicate to the user what the current
+ // sound volume is (since sounds might not be continuously playing,
+ // unlike the music). We check for this by seeing if the mDragging
+ // variable is true or not.
+ if (!mSfxVolumeSlider->mDragging)
+ gSexyAppBase->PlaySample(SOUND_TIMER);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::ButtonDepress(int theId)
+{
+ Dialog::ButtonDepress(theId);
+
+ if (theId == mRandomBtn->mId)
+ {
+ // Let's get a random integer. The Rand() function is declared
+ // in Common.h and returns a value from 0 to SEXY_RAND_MAX (2,147,483,647)
+ int r = Rand();
+
+ // Now let's change the text of the dialog box:
+ mDialogLines = StrFormat(_S("Random number: %d"), r);
+ }
+ else if (theId == mClipBtn->mId)
+ {
+ // Toggle mClip. If mClip is off, we can draw outside the X/Y/width/height of
+ // our dialog box.
+ mClip = !mClip;
+ if (mClip)
+ mClipBtn->mLabel = _S("Clipping");
+ else
+ mClipBtn->mLabel = _S("No clipping");
+ }
+ // Previously, before framework 1.2, the line below looked like:
+ // else if (theId == 2000 + mId)
+ // With the 1.2 changes, there's just 1 slight incompatibility.
+ // If the DialogListener for a dialog your app (by default), and
+ // you don't implement your own DialogButton(De)press method (see V12Demo for
+ // more info on this), and instead are trapping button presses within ButtonDepress
+ // inside the dialog itself, then instead of the button ID being 2000 or 3000 + mId,
+ // it's just ID_YES/ID_OK for ok/cancel/1-button dialog, and ID_NO/ID_CANCEL for no/cancel 2nd button.
+ // Hence we changed our check to look for ID_YES, which is our default single close button at the bottom of this
+ // dialog.
+ else if (theId == ID_YES)
+ {
+ // Close button pressed. Tell the app to remove ourselves. This
+ // will automatically safe delete the dialog at a later time.
+ // Let's apply the 3D and fullscreen mode settings first though.
+ // We call SwitchScreenMode. The first parameter is whether or not to run
+ // windowed (false means fullscreen), the second is whether or not to do 3d.
+ gSexyAppBase->SwitchScreenMode(!mFSCheckbox->mChecked, m3DCheckbox->mChecked);
+
+ gSexyAppBase->KillDialog(this);
+
+ // Set focus back to the board
+ ((GameApp*)gSexyAppBase)->SetFocusToBoard();
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoDialog::CheckboxChecked(int theId, bool checked)
+{
+ // We'll wait until the dialog box is closed before actually applying any effects,
+ // since it's rather jarring if as soon as a user clicks the 3d or fullscreen
+ // toggle buttons to change right then and there.
+
+ if (theId == m3DCheckbox->mId)
+ {
+ if (checked)
+ {
+ // Turn on 3D acceleration. But we need to check if the user is
+ // even allowed to have it on. Some cards are just not compatible
+ // with the framework (less than 8MB RAM for instance):
+ if (!gSexyAppBase->Is3DAccelerationSupported())
+ {
+ // It's not supported. Don't let the checkbox get checked.
+ // Display an error dialog to the user to let them know why this happened.
+ // The reason we don't use a Popup or Windows-based message box here is because
+ // if the user was in full screen mode, they might not see the error message. Using
+ // a game dialog box is the safest way to warn them.
+ m3DCheckbox->SetChecked(false);
+ gSexyAppBase->DoDialog(DemoDialog::MESSAGE_BOX_ID, true, _S("Not Supported"),
+ _S("Hardware acceleration can not be enabled on this computer. \nYour\
+ video card does not meet the minimum requirements for this game."),
+ _S("OK"), Dialog::BUTTONS_FOOTER);
+ }
+ else if(!gSexyAppBase->Is3DAccelerationRecommended())
+ {
+ // We can also check if 3D acceleration is not recommended for this computer
+ // with a call to Is3DAccelerationRecommended. This allows the user to override
+ // the default setting, but with a warning that it might not work or might cause
+ // problems. Some cards fail the detection process but wind up being OK to use.
+ gSexyAppBase->DoDialog(DemoDialog::MESSAGE_BOX_ID, true, _S("Warning"),
+ _S("Your video card may not fully support this feature.\n\
+ If you experience slower performance, please disable Hardware Acceleration."),
+ _S("OK"), Dialog::BUTTONS_FOOTER);
+ }
+
+ }
+ }
+ else if (theId == mFSCheckbox->mId)
+ {
+ // Believe it or not, some people are not allowed to play in windowed mode.
+ // You can only run in windowed mode if your desktop is 16 or 32 bit, and
+ // if the resolution of their desktop is GREATER THAN the resolution of the
+ // game. It doesn't make sense to run a 800x600 game windowed when your desktop
+ // is 800x600 or less.
+ // We can determine if the user is not allowed to run in windowed mode by
+ // checking the value of SexyAppBase's mForceFullScreen variable.
+ if (gSexyAppBase->mForceFullscreen && !checked)
+ {
+ gSexyAppBase->DoDialog(DemoDialog::MESSAGE_BOX_ID, true, _S("No Windowed Mode"),
+ _S("Windowed mode is only available if your desktop is running in\n\
+ either 16 bit or 32 bit color mode, which it is not."), _S("OK"), Dialog::BUTTONS_FOOTER);
+
+ // re-check the box to indicate that fullscreen is still the selected mode:
+ mFSCheckbox->SetChecked(true);
+ }
+ }
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo5/DemoDialog.h b/osframework/source/demos/Demo5/DemoDialog.h
new file mode 100644
index 0000000..89fc43b
--- /dev/null
+++ b/osframework/source/demos/Demo5/DemoDialog.h
@@ -0,0 +1,209 @@
+//////////////////////////////////////////////////////////////////////////
+// DemoDialog.h
+//
+// This class demonstrates how to create a customized dialog box.
+// Most games will want to use custom implementations of the dialog
+// class if they want to go beyond the simple yes/no/ok ones.
+//
+// Basically, all we want to do is implement custom drawing and updating
+// code, as well as do some little things when we get added/removed from
+// the widget manager and handle button presses slightly differently.
+//
+// IMPORTANT: Make sure to read the comments in the .CPP file for the
+// Dialog constructor as they contain important information.
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef __DEMO_DIALOG_H__
+#define __DEMO_DIALOG_H__
+
+#include "SexyAppFramework/Dialog.h"
+
+// This lets us receive slider events
+#include "SexyAppFramework/SliderListener.h"
+
+#include "SexyAppFramework/CheckboxListener.h"
+
+namespace Sexy
+{
+
+ class Graphics;
+
+ // We're going to use slider widgets to control audio volume
+ class Slider;
+
+ // This is the same as a normal button, but it automatically tiles
+ // the butotn image if we make the widget too large
+ class DialogButton;
+
+ class Checkbox;
+
+class DemoDialog : public Dialog, public SliderListener, public CheckboxListener
+{
+
+ protected:
+
+ Slider* mMusicVolumeSlider;
+ Slider* mSfxVolumeSlider;
+ DialogButton* mRandomBtn; // Click this for a random number
+ DialogButton* mClipBtn; // Click this to toggle clipping
+
+
+ public:
+
+ // Alright, fine, we'll use some constants for our widgets!
+ enum
+ {
+ MUSIC_SLIDER_ID,
+ SFX_SLIDER_ID,
+ RANDOM_BTN_ID,
+ CLIP_BTN_ID,
+ FS_CHECKBOX_ID,
+ HARDWARE_CHECKBOX_ID,
+ MESSAGE_BOX_ID,
+ DIALOG_ID
+ };
+
+ // For ease of accessing, we're going to make our checkboxes public,
+ // as the GameApp class will need to query their states as well as
+ // possibly alter the FSCheckbox's state.
+ Checkbox* m3DCheckbox; // Toggle 3D enhanced mode
+ Checkbox* mFSCheckbox; // Toggle fullscreen mode
+
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DemoDialog
+ // Parameters:
+ // theHeader - A string to use for the dialog box header
+ // theBody - A string to use for the body of the text. May use
+ // \n characters to denote new line.
+ //
+ // Returns: none
+ //
+ // Purpose: Creates a new dialog box. You can specify a custom header
+ // and content with the two parameters.
+ //////////////////////////////////////////////////////////////////////////
+ DemoDialog(std::string theHeader, std::string theBody);
+ virtual ~DemoDialog();
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Update();
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Resize
+ // Parameters:
+ // theX - X coordinate to place the dialog at
+ // theY - Y coordinate to place the dialog at
+ // theWidth - Width of the dialog box
+ // theHeight - Height of the dialog box
+ //
+ // Returns: none
+ //
+ // Purpose: Resizes and places the dialog box. We'll also
+ // make sure to position any widgets appropriately based on the new
+ // dimensions.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Resize(int theX, int theY, int theWidth, int theHeight);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: SliderVal
+ // Parameters:
+ // theId - ID of the slider object that generated this message
+ // theVal - The value of the slider, i.e. where the thumb image
+ // is located. Leftmost is 0, rightmost is mVal in the slider widget.
+ //
+ // Returns: none
+ //
+ // Purpose: Whenever the thumb image on a slider is moved, this event is
+ // generated. The value passed in ranges from 0 to the maximum value on
+ // the slider, which is set in the slider's mVal variable.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void SliderVal(int theId, double theVal);
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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.
+ //////////////////////////////////////////////////////////////////////////
+ void CheckboxChecked(int theId, bool checked);
+};
+
+
+}
+
+
+#endif \ No newline at end of file
diff --git a/osframework/source/demos/Demo5/GameApp.cpp b/osframework/source/demos/Demo5/GameApp.cpp
new file mode 100644
index 0000000..c792683
--- /dev/null
+++ b/osframework/source/demos/Demo5/GameApp.cpp
@@ -0,0 +1,427 @@
+#include "GameApp.h"
+#include "TitleScreen.h"
+#include "Board.h"
+#include "DemoDialog.h"
+#include "SexyAppFramework/WidgetManager.h"
+
+#include "SexyAppFramework/Checkbox.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"
+
+#include "SexyAppFramework/Dialog.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 5";
+
+ // 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\\Demo5";
+
+ // Set the application width/height in terms of pixels here.
+ mWidth = 640;
+ mHeight = 480;
+
+ // 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 F8. To toggle 3D on/off, press shift-F8. That is just
+ // for testing purposes.
+ mAutoEnable3D = true;
+
+ mBoard = NULL;
+ mTitleScreen = NULL;
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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()
+{
+ // 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 true,
+ // 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()
+{
+ 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");
+
+ mBoard->Resize(0, 0, mWidth, mHeight);
+ mWidgetManager->AddWidget(mBoard);
+
+ // This is a new step: We're going to tell the WidgetManager
+ // that keyboard input and mouse wheel notifications should go to
+ // the board object. This way, we'll be able to respond to keypresses:
+ mWidgetManager->SetFocus(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 our options dialog.
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Dialog* GameApp::NewDialog(int theDialogId, bool isModal, const std::string& theDialogHeader,
+ const std::string& theDialogLines, const std::string& theDialogFooter, int theButtonMode)
+{
+ // Rather than dupliate a lengthy explanation, check out the top of DemoDialog.cpp for a complete description
+ // of what all the parameters and functions are.
+ Dialog* d = new Dialog(IMAGE_DIALOG_BOX, IMAGE_DIALOG_BUTTON, theDialogId, isModal,
+ StringToSexyStringFast(theDialogHeader), StringToSexyStringFast(theDialogLines), StringToSexyStringFast(theDialogFooter), theButtonMode);
+
+ d->SetButtonFont(FONT_DEFAULT);
+ d->SetLinesFont(FONT_DEFAULT);
+ d->SetHeaderFont(FONT_DEFAULT);
+
+ d->SetColor(Dialog::COLOR_HEADER, Color::Black);
+ d->SetColor(Dialog::COLOR_LINES, Color::Black);
+
+ d->mSpaceAfterHeader = 30;
+ d->Resize(100, 100, 300, 250);
+
+ return d;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::SwitchScreenMode(bool wantWindowed, bool is3d)
+{
+ // Let the app handle the actual details of this call...
+ SexyAppBase::SwitchScreenMode(wantWindowed, is3d);
+
+ // We can see if the options dialog is up with a call to
+ // GetDialog. You pass GetDialog the unique ID of the dialog box,
+ // and if it exists it is returned to you, otherwise NULL is returned.
+ DemoDialog* d = (DemoDialog*) GetDialog(DemoDialog::DIALOG_ID);
+
+ // Set the checkbox state to our windowed state
+ if ((d != NULL) && (d->mFSCheckbox != NULL))
+ d->mFSCheckbox->SetChecked(!wantWindowed);
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::ButtonPress(int theId)
+{
+ if (theId == DemoDialog::MESSAGE_BOX_ID + 2000)
+ KillDialog(theId - 2000);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::SetFocusToBoard()
+{
+ if (mBoard != NULL)
+ mWidgetManager->SetFocus(mBoard);
+} \ No newline at end of file
diff --git a/osframework/source/demos/Demo5/GameApp.h b/osframework/source/demos/Demo5/GameApp.h
new file mode 100644
index 0000000..629055a
--- /dev/null
+++ b/osframework/source/demos/Demo5/GameApp.h
@@ -0,0 +1,173 @@
+#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;
+
+ // We're going to learn about making and using dialog boxes in this demo
+ class Dialog;
+
+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: NewDialog
+ // Parameters:
+ // theDialogId - Unique ID to give this dialog box
+ // isModal - If true, only itself and widgets above it receive
+ // input events.
+ // theDialogHeader - String to display in the header part of the dialog box
+ // theDialogLines - String to use for the body of the dialog. May use
+ // \n characters to indicate new lines.
+ // theDialogFooter - If the button mode is BUTTONS_FOOTER, this is the text
+ // to use for the button, otherwise ignored.
+ // theButtonMode - One of 3 settings: Dialog::BUTTONS_YES_NO creates two
+ // "Yes" "No" buttons, Dialog::BUTTONS_OK_CANCEL creates two
+ // "OK" "Cancel" buttons, Dialog::BUTTONS_FOOTER creates one
+ // button with the text from theDialogFooter.
+ //
+ // Returns: A new dialog pointer for use by SexyAppBase's DoDialog method.
+ //
+ // Purpose: SexyAppBase contains a convenience function, DoDialog, that relies on
+ // this overriden function. DoDialog calls NewDialog which instructs it how to make
+ // a dialog box. You should use DoDialog to create and add your dialog boxes.
+ // The reason for this function is to allow for customized dialog boxes and to avoid
+ // having to have a gigantic function with every possible parameter to pass to the Dialog's
+ // constructor.
+ //////////////////////////////////////////////////////////////////////////
+ virtual Dialog* NewDialog(int theDialogId, bool isModal, const std::string& theDialogHeader,
+ const std::string& theDialogLines, const std::string& theDialogFooter, int theButtonMode);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: SwitchScreenMode
+ // Parameters:
+ // wantWindowed - True indicates that the game should be in windowed mode
+ // is3d - True indicates that 3D acceleration should be turned on
+ //
+ // Returns: none
+ //
+ // Purpose: Take a look at DemoDialog. In it, you can toggle whether or not
+ // the game is fullscreen. What if though, the user presses ALT-ENTER to force
+ // the game to be windowed/fullscreen while that dialog is up? The fullscreen
+ // checkbox should update to reflect the current windowed state. It's a little
+ // thing to do but if you don't wind up doing it, it can be a bit wonky
+ // for the user if the checkbox state gets out of sync with the resolution and
+ // could wind up irritating them.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void SwitchScreenMode(bool wantWindowed, bool is3d);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ButtonPress:
+ // Parameters:
+ // theId - ID of the button pressed
+ //
+ // Returns: none
+ //
+ // Purpose: Called when the button is pressed, but before the mouse is
+ // released (which would instead generate a ButtonDepress event).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void ButtonPress(int theId);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: SetFocusToBoard
+ //
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: When a dialog box closes, this is called to set keyboard focus
+ // to the board widget.
+ //////////////////////////////////////////////////////////////////////////
+ void SetFocusToBoard();
+};
+
+}
+
+
+#endif // __GAMEAPP_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Demo5/TitleScreen.cpp b/osframework/source/demos/Demo5/TitleScreen.cpp
new file mode 100644
index 0000000..49caebd
--- /dev/null
+++ b/osframework/source/demos/Demo5/TitleScreen.cpp
@@ -0,0 +1,205 @@
+#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"
+
+
+#include "SexyAppFramework/Font.h"
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Image.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/Rect.h"
+#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.
+ 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() * (double)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 - 10, mContinueLink->mY - 80);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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/Demo5/TitleScreen.h b/osframework/source/demos/Demo5/TitleScreen.h
new file mode 100644
index 0000000..c55776d
--- /dev/null
+++ b/osframework/source/demos/Demo5/TitleScreen.h
@@ -0,0 +1,125 @@
+#ifndef __TITLE_SCREEN_H__
+#define __TITLE_SCREEN_H__
+
+#include "SexyAppFramework/Widget.h"
+#include "SexyAppFramework/ButtonListener.h"
+
+namespace Sexy
+{
+
+class GameApp;
+class Graphics;
+class WidgetManager;
+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/Demo5/main.cpp b/osframework/source/demos/Demo5/main.cpp
new file mode 100644
index 0000000..812e585
--- /dev/null
+++ b/osframework/source/demos/Demo5/main.cpp
@@ -0,0 +1,50 @@
+//////////////////////////////////////////////////////////////////////////
+// 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:
+// * Drawing differently if 3D or 2D
+// * Using Translate instead of using XYs
+// * Keyboard input, setting focus
+// * Widgets: Dialog box, sliders, an options dialog box
+// * Advanced widget topics: mClip, using Layout_ flags, using images
+// * Making an options dialog box and controlling fullscreen, volumes,
+// 3D settings.
+// * Parallax scrolling
+// * Random numbers
+// * Catching memory leaks
+// * Profiling
+//////////////////////////////////////////////////////////////////////////
+
+#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;
+}
diff --git a/osframework/source/demos/Hun-garr/Board.cpp b/osframework/source/demos/Hun-garr/Board.cpp
new file mode 100644
index 0000000..09594f1
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Board.cpp
@@ -0,0 +1,2189 @@
+#pragma warning(disable:4244)
+#pragma warning(disable:4018)
+#include "Board.h"
+#include "GameApp.h"
+#include "Res.h"
+#include "LevelupEffect.h"
+#include "GameOverEffect.h"
+#include "OptionsDialog.h"
+
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Color.h"
+#include "SexyAppFramework/Rect.h"
+#include "SexyAppFramework/ButtonWidget.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/ImageFont.h"
+#include "SexyAppFramework/SoundManager.h"
+#include "SexyAppFramework/SoundInstance.h"
+#include "SexyAppFramework/Buffer.h"
+#include "SexyAppFramework/MusicInterface.h"
+
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+// VC6 workaround
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+using namespace Sexy;
+
+// How much faster the beam gets when you eat a planet
+const float BEAM_INC_SPEED = 0.05f;
+
+// Fastest the beam can go
+const float MAX_BEAM_SPEED = 2.5f;
+
+// Table of random planet names
+const int NUM_PLANET_NAMES = 28;
+const SexyString PLANET_NAME[] =
+{_S("Deev-z"), _S("SEN-Hen"), _S("Wallach IX"), _S("Salusa Secundus"), _S("Ridiculous Prime"), _S("Architekt V"),
+_S("Robot Republica"), _S("Ix"), _S("XOLDOG4000"), _S("Kliprok"), _S("TR-909"), _S("TR-808"), _S("TB-303"),
+_S("DTR011"), _S("dTech"), _S("Rotwang"), _S("Sukhtek"), _S("Romulox"), _S("Dob Reevz"), _S("Skull XII"),
+_S("Beefy Prime"), _S("Haas"), _S("Reifenrath"), _S("Gehner Subulon"), _S("ACE-DOGG"), _S("Charolastra"), _S("Nixd"), _S("BASS")};
+
+// Table of random planet exports:
+const int NUM_PLANET_EXPORTS = 23;
+const SexyString PLANET_EXPORTS[] =
+{_S("Happiness"), _S("Donkeys"), _S("Rabies"), _S("AstroPop"), _S("Idiocy"), _S("Minimal Techno"),
+_S("Citizens"), _S("Pain-relieving Pants"), _S("The Quad-Laser"), _S("Septic Systems"), _S("Video Games"),
+_S("Robots"), _S("Plaid"), _S("Octagons"), _S("Gingivitis"), _S("Recognizers"), _S("Electro"), _S("Sauce"),
+_S("Kindness"), _S("Bison"), _S("Saline"), _S("Cholera"), _S("TyperShark")};
+
+
+//////////////////////////////////////////////////////////////////////////
+// Inline functions
+//////////////////////////////////////////////////////////////////////////
+
+// Given an X coordinate, returns the grid column it maps to
+inline int GetCol(float x)
+{
+ return (int) ((x - GRID_START_X) / GRID_PIX_SIZE);
+}
+
+// Given a Y coordinate, returns the grid row it maps to
+inline int GetRow(float y)
+{
+ return (int) ((y - GRID_START_Y) / GRID_PIX_SIZE);
+}
+
+// Given a grid column, returns the X pixel of the left edge of it
+inline float GetColPix(int col)
+{
+ return col * GRID_PIX_SIZE + GRID_START_X;
+}
+
+// Given a grid row, returns the Y pixel of the top edge of it
+inline float GetRowPix(int row)
+{
+ return row * GRID_PIX_SIZE + GRID_START_Y;
+}
+
+// Given an X coordinate, adjusts it so that it is aligned
+// with the left edge of the grid square it's over
+inline float GetAlignedX(float x)
+{
+ return (float)GetCol(x) * GRID_PIX_SIZE + GRID_START_X;
+}
+
+// Given a Y coordinate, adjusts it so that it is aligned
+// with the top edge of the grid square it's over
+inline float GetAlignedY(float y)
+{
+ return (float)GetRow(y) * GRID_PIX_SIZE + GRID_START_Y;
+}
+
+// Checks to see if the Y coordinate is in the grid's bounds.
+// Needs to know if Hun-garr is oriented vertically or not
+inline bool YCoordInBounds(float y, bool vertical)
+{
+ int h = IMAGE_HUNGARR_HORIZ->GetHeight() / 2;
+
+ if ( (vertical && (y > GRID_START_Y + h) && (y < GRID_END_Y - h)) ||
+ (!vertical && (y > GRID_START_Y + 7) && (y < GRID_END_Y - 4)) )
+ return true;
+
+ return false;
+}
+
+// Checks to see if the X coordinate is in the grid's bounds
+inline bool XCoordInBounds(float x)
+{
+ if ((x > GRID_START_X + 9) && (x < GRID_END_X - 2))
+ return true;
+
+ return false;
+}
+
+// Checks to see if the column number points to a valid grid column
+inline bool ValidCol(int col)
+{
+ return ((col >= 0) && (col < GRID_WIDTH));
+}
+
+// Checks to see if the row number points to a valid grid row
+inline bool ValidRow(int row)
+{
+ return ((row >= 0) && (row < GRID_HEIGHT));
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::Board(GameApp* theApp)
+{
+ mApp = theApp;
+ mHungarrIsVertical = true;
+ mLineSpeed = 1.0f;
+
+ mNumPlanetsEaten = 0;
+ mPercentComplete = 0;
+
+ mBorderHue = 0;
+ mFlashCount = 0;
+ mLives = 3;
+ mLevel = 1;
+ mScore = 0;
+ mBeamPulseAmt = 30;
+ mBeamPulseVal = 128;
+
+ // Put Hun-garr in a valid spot
+ UpdateHungarrPosition(GetColPix(4), GetRowPix(4));
+
+ // Create a 2D array to hold the grid fill state that's of size
+ // GRID_WIDTH x GRID_HEIGHT
+ mGridState = new GridTile* [GRID_HEIGHT];
+
+ //vc6 workaround:
+ int i;
+ for (i = 0; i < GRID_HEIGHT; i++)
+ mGridState[i] = new GridTile[GRID_WIDTH];
+
+ mFillDirection = FILL_LEFT;
+ mFillSpeed = 20.0f;
+ mPlanetSpeed = 1.5f;
+ mPopulationEaten = mTotalPopulationEaten = 0;
+ mPauseLevel = 0;
+
+ // Create our starfield
+ for (i = 0; i < MAX_STARS; i++)
+ {
+ Star s;
+ s.mX = Rand() % mApp->mWidth;
+ s.mY = Rand() % mApp->mHeight;
+
+ int r = Rand() % 3;
+ switch (r)
+ {
+ case 0: s.mSpeed = 0.5f; s.mColor = Color(200, 200, 200, 128); break;
+ case 1: s.mSpeed = 0.25f; s.mColor = Color(100, 100, 100, 128); break;
+ case 2: s.mSpeed = 0.1f; s.mColor = Color(50, 50, 50, 128); break;
+ }
+
+ mStarField[i] = s;
+ }
+
+ mLevelupEffect = new LevelupEffect();
+ mGameOverEffect = new GameOverEffect();
+ mOptionsBtn = NULL;
+
+
+ // The shorting out, electrical sound of the beams moving. We use a SoundInstance pointer
+ // because we want to loop the sound while the beam is moving, and stop it when done.
+ // This is easiest done manually.
+ mShortSound = mApp->mSoundManager->GetSoundInstance(SOUND_BEAM_MOVING);
+
+ InitLevel(1);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+ // Frees up the memory allocated to our manual SoundInstance pointer. Required.
+ mShortSound->Release();
+
+ for (int i = GRID_HEIGHT; i > 0; --i)
+ delete[] mGridState[i - 1];
+ delete[] mGridState;
+
+ delete mLevelupEffect;
+ delete mGameOverEffect;
+ delete mOptionsBtn;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+ // If paused, return and don't markdirty, whcih prevents drawing
+ // and the stealing of CPU cycles
+ if (mPauseLevel > 0)
+ return;
+
+ Widget::Update();
+
+
+ // HSL is an alternative to specifying an RGB color format.
+ // Using HSL lets us easily do the hyper blinking crazy weird
+ // flashing effect commonly found in old games, such as Robotron.
+ // Below, we increment the value by 6 per update. The &0xFF is an
+ // easy way to clamp the value between 0 and 255 instead of having to
+ // do a separate if (mHue > 255) mHue -= 255. This lets the value
+ // rollover and keep cycling.
+ if (--mFlashCount > 0)
+ mBorderHue = (mBorderHue + 6) % 0xFF;
+
+ if (mGameOverEffect->IsActive())
+ {
+ mGameOverEffect->Update();
+
+ // If the game over effect is in the proper state, we will
+ // be able to initialize the first level so that when it fades out,
+ // the level will appear underneath it.
+ if (mGameOverEffect->CanInitFirstLevel())
+ {
+ //Reset the critical variables:
+ mBorderHue = 0;
+ mFlashCount = 0;
+ mLives = 3;
+ mLevel = 1;
+ mScore = 0;
+ mFillDirection = FILL_LEFT;
+ mFillSpeed = 20.0f;
+ mPlanetSpeed = 1.5f;
+ mPopulationEaten = mTotalPopulationEaten = 0;
+ mPauseLevel = 0;
+ mLineSpeed = 1.0f;
+ mPlanetIdxCount.clear();
+ mExportIdxCount.clear();
+ mOptionsBtn->SetVisible(true);
+ mApp->mMusicInterface->FadeIn(0);
+ InitLevel(1);
+ }
+ }
+
+ // Make the beams that the player emits pulse with intensity
+ mBeamPulseVal += mBeamPulseAmt;
+ if (mBeamPulseVal >= 255)
+ {
+ mBeamPulseVal = 255;
+ mBeamPulseAmt = -mBeamPulseAmt;
+ }
+ else if (mBeamPulseVal <= 0)
+ {
+ mBeamPulseVal = 0;
+ mBeamPulseAmt = -mBeamPulseAmt;
+ }
+
+ MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::UpdateF(float theFrac)
+{
+ if (mPauseLevel > 0)
+ return;
+
+ if (mFilling)
+ {
+ // If the beams have been released, update the filling of the grid
+ float amt = mFillSpeed * theFrac;
+
+ if (mFillDirection == FILL_RIGHT)
+ FillRight(amt);
+ else if (mFillDirection == FILL_LEFT)
+ FillLeft(amt);
+ else if (mFillDirection == FILL_UP)
+ FillUp(amt);
+ else if (mFillDirection == FILL_DOWN)
+ FillDown(amt);
+
+ // Check what % full the filled regions are if it's done filling
+ if (!mFilling)
+ UpdatePercentComplete();
+
+ }
+
+ // Make the bonus text float upwards and fade it out over time.
+ std::vector<BonusText>::iterator it = mBonusText.begin();
+ while (it != mBonusText.end())
+ {
+ BonusText* bt = &*it;
+ bt->mY -= 1.00f * theFrac;
+ bt->mHue = (bt->mHue + 5) % 0xFF;
+
+ if (--bt->mAlpha <= 0)
+ {
+ //Totally faded out, remove it
+ it = mBonusText.erase(it);
+ }
+ else
+ ++it;
+ }
+
+
+ // Move the starfield. If a start gets beyond the screen,
+ // randomly place it offscreen again
+ int i;
+ for (i = 0; i < MAX_STARS; i++)
+ {
+ Star* s = &mStarField[i];
+ s->mX += s->mSpeed;
+ if (s->mX > mWidth)
+ {
+ s->mX = -5;
+ s->mY = Rand() % mHeight;
+ }
+ }
+
+ if ((!mMovingLine1.mDone || !mMovingLine2.mDone) && !mGameOverEffect->IsActive())
+ MoveLines(theFrac);
+
+
+ // If we're allowed to show the planets and the game isn't paused and the game
+ // over effect isn't playing, then we can move the planets around
+ if ((!mLevelupEffect->HidePlanets() || (mPauseLevel > 0)) && !mGameOverEffect->IsActive())
+ {
+ // Move the planets
+ int w = IMAGE_PLANETS->GetCelWidth();
+ int h = IMAGE_PLANETS->GetCelHeight();
+
+ // Instead of playing the explosion sound every time a planet gets destroyed, we'll
+ // only play it once. That way, if you destroy more than 1 planet in one go, you won't
+ // hear the same sound played multipled times at once, which would result in this loud,
+ // hideous, flanging sound.
+ bool playSound = false;
+ for (int i = 0; i < mPlanets.size(); i++)
+ {
+ Planet* p = &mPlanets[i];
+
+ // Again, the timer is used solely for incrementing the animation frames
+ ++p->mTimer;
+
+ if (!p->mExploding)
+ {
+ if (MovePlanet(p, theFrac))
+ playSound = true; // Returns true if the planet is to explode
+ }
+ else
+ {
+ if ((p->mTimer % p->mExplodeSpeed) == 0)
+ {
+ if (++p->mExplodeFrame >= IMAGE_BOMB_RADIAL_DEATH->mNumCols)
+ {
+ mPlanets.erase(mPlanets.begin() + i);
+ --i;
+ }
+ }
+ }
+ }
+
+ if (playSound)
+ mApp->PlaySample(SOUND_PLANET);
+ }
+
+ // update and move the particles. When they have reached
+ // their last frame, remove them.
+ for (i = 0; i < mParticles.size(); i++)
+ {
+ Particle* p = &mParticles[i];
+ ++p->mTimer;
+
+ p->mX += p->mVX * theFrac;
+ p->mY += p->mVY * theFrac;
+ p->mVY += 0.1f;
+ if (p->mTimer % 6 == 0)
+ {
+ if (++p->mFrame >= IMAGE_PARTICLE_LIGHTNING->mNumCols)
+ {
+ mParticles.erase(mParticles.begin() + i);
+ --i;
+ }
+ }
+ }
+
+ if (mLevelupEffect->IsActive())
+ {
+ mLevelupEffect->Update(theFrac);
+
+ // If the proper state is reached in the level up effect, then we can begin
+ // setting up the next level.
+ if (mLevelupEffect->StartNextLevel())
+ {
+ // Just finished, start the next level
+ mOptionsBtn->SetVisible(true);
+ InitLevel(mLevel + 1);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::FillRight(float amt)
+{
+ bool change = true;
+
+ // Fill the entire line, moving rightward
+ for (int y = mFillRegion.mTop; y <= mFillRegion.mBottom; y++)
+ {
+ GridTile* gt = &mGridState[y][mFillRegion.mLeft];
+
+ // We only want to fill those pieces that are in the GRID_FILLING state
+ if (gt->mFillState == GRID_FILLING)
+ {
+ // This piece is filling up, expand its width
+ gt->mFillRect.mWidth += amt;
+
+ // If the width exceeds that of the grid piece, overflow the result
+ // into the tile next to it so that the filling appears continuous.
+ if (gt->mFillRect.mWidth >= GRID_PIX_SIZE)
+ {
+ float overflow = gt->mFillRect.mWidth - GRID_PIX_SIZE;
+ gt->mFillState = GRID_FILLED;
+
+ gt->mFillRect.mWidth = GRID_PIX_SIZE;
+
+ //overflow into next column, if the next column is within our
+ //fill region and if the piece is in the normal tile state.
+ if (mFillRegion.mLeft + 1 <= mFillRegion.mRight)
+ if (mGridState[y][mFillRegion.mLeft + 1].mFillState == GRID_NORMAL)
+ mGridState[y][mFillRegion.mLeft + 1].mFillRect.mWidth += overflow;
+ }
+ else
+ change = false;
+ }
+ }
+
+ //if "change" is true, then move one column right and begin filling in that column next
+ //time this function is called. If there are no more columns to fill, we're done.
+
+ if (change && (++mFillRegion.mLeft > mFillRegion.mRight))
+ mFilling = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::FillLeft(float amt)
+{
+ float leftX = GetColPix(mFillRegion.mRight);
+ bool change = true;
+
+ //This algorithm works just like FillRight except that it's filling
+ //from the right side of the grid piece instead of the left, so there's
+ //a couple extra calculations.
+
+ for (int y = mFillRegion.mTop; y <= mFillRegion.mBottom; y++)
+ {
+ GridTile* gt = &mGridState[y][mFillRegion.mRight];
+
+ if (gt->mFillState == GRID_FILLING)
+ {
+ gt->mFillRect.mWidth += amt;
+ gt->mFillRect.mX -= amt;
+
+ if ((gt->mFillRect.mWidth >= GRID_PIX_SIZE) || (gt->mFillRect.mX < leftX))
+ {
+ float overflow = gt->mFillRect.mWidth - GRID_PIX_SIZE;
+ gt->mFillState = GRID_FILLED;
+
+ gt->mFillRect.mWidth = GRID_PIX_SIZE;
+ gt->mFillRect.mX = leftX;
+
+ //overflow into next column
+ if (mFillRegion.mRight - 1 >= mFillRegion.mLeft)
+ {
+ if (mGridState[y][mFillRegion.mRight - 1].mFillState == GRID_NORMAL)
+ {
+ mGridState[y][mFillRegion.mRight - 1].mFillRect.mWidth += overflow;
+ mGridState[y][mFillRegion.mRight - 1].mFillRect.mX -= overflow;
+ }
+ }
+ }
+ else
+ change = false;
+ }
+ }
+
+ if (change && (--mFillRegion.mRight < mFillRegion.mLeft))
+ mFilling = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::FillUp(float amt)
+{
+ bool change = true;
+ float topY = GetRowPix(mFillRegion.mBottom);
+
+ //This algorithm works just like FillRight except that it's filling
+ //from the bottom side of the grid piece instead of the left, so there's
+ //a couple extra calculations.
+
+ for (int x = mFillRegion.mLeft; x <= mFillRegion.mRight; x++)
+ {
+ GridTile* gt = &mGridState[mFillRegion.mBottom][x];
+
+ if (gt->mFillState == GRID_FILLING)
+ {
+ gt->mFillRect.mHeight += amt;
+ gt->mFillRect.mY -= amt;
+
+ if ((gt->mFillRect.mHeight >= GRID_PIX_SIZE) || (gt->mFillRect.mY < topY))
+ {
+ float overflow = gt->mFillRect.mHeight - GRID_PIX_SIZE;
+ gt->mFillState = GRID_FILLED;
+
+ gt->mFillRect.mHeight = GRID_PIX_SIZE;
+ gt->mFillRect.mY = topY;
+
+ //overflow into next row
+ if (mFillRegion.mBottom - 1 > mFillRegion.mTop)
+ {
+ if (mGridState[mFillRegion.mBottom - 1][x].mFillState == GRID_NORMAL)
+ {
+ mGridState[mFillRegion.mBottom - 1][x].mFillRect.mHeight += overflow;
+ mGridState[mFillRegion.mBottom - 1][x].mFillRect.mY -= overflow;
+ }
+ }
+ }
+ else
+ change = false;
+ }
+ }
+
+ if (change && (--mFillRegion.mBottom < mFillRegion.mTop))
+ mFilling = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::FillDown(float amt)
+{
+ bool change = true;
+
+ //This algorithm works just like FillRight except that it's filling
+ //from the top side of the grid piece instead of the left.
+
+ for (int x = mFillRegion.mLeft; x <= mFillRegion.mRight; x++)
+ {
+ GridTile* gt = &mGridState[mFillRegion.mTop][x];
+
+ if (gt->mFillState == GRID_FILLING)
+ {
+ gt->mFillRect.mHeight += amt;
+
+ if (gt->mFillRect.mHeight >= GRID_PIX_SIZE)
+ {
+ float overflow = gt->mFillRect.mHeight - GRID_PIX_SIZE;
+ gt->mFillState = GRID_FILLED;
+
+ gt->mFillRect.mHeight = GRID_PIX_SIZE;
+
+ //overflow into next row
+ if (mFillRegion.mTop + 1 <= mFillRegion.mBottom)
+ if (mGridState[mFillRegion.mTop + 1][x].mFillState == GRID_NORMAL)
+ mGridState[mFillRegion.mTop + 1][x].mFillRect.mHeight += overflow;
+ }
+ else
+ change = false;
+ }
+ }
+
+ if (change && (++mFillRegion.mTop > mFillRegion.mBottom))
+ mFilling = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MoveLines(float theFrac)
+{
+
+ // Move the lines, differently depending on if they are oriented verticall
+ // or horizontally. When a line reaches its target, it is done, and planets
+ // can bounce off of it. When both lines are done, we will calculate the region
+ // to fill.
+
+ int numDone = 0;
+ if (!mMovingLine1.mDone)
+ {
+ float amt = -mLineSpeed * theFrac;
+
+ if (mMovingLine1.mIsVertical)
+ {
+ mMovingLine1.mY += amt;
+ mMovingLine1.mHeight += fabsf(amt);
+
+ if (mMovingLine1.mY <= mMovingLine1.mTargetY)
+ {
+ mMovingLine1.mY = mMovingLine1.mTargetY;
+ mMovingLine1.mDone = true;
+ ++numDone;
+ }
+ }
+ else
+ {
+ mMovingLine1.mX += amt;
+ mMovingLine1.mWidth += fabsf(amt);
+
+ if (mMovingLine1.mX <= mMovingLine1.mTargetX)
+ {
+ mMovingLine1.mX = mMovingLine1.mTargetX;
+ mMovingLine1.mDone = true;
+ ++numDone;
+ }
+ }
+ }
+
+ if (!mMovingLine2.mDone)
+ {
+ float amt = mLineSpeed * theFrac;
+
+ if (mMovingLine2.mIsVertical)
+ {
+ mMovingLine2.mHeight += amt;
+
+ if (mMovingLine2.mY + mMovingLine2.mHeight >= mMovingLine2.mTargetY)
+ {
+ mMovingLine2.mHeight = mMovingLine2.mTargetY - mMovingLine2.mY;
+ mMovingLine2.mDone = true;
+ ++numDone;
+ }
+ }
+ else
+ {
+ mMovingLine2.mWidth += amt;
+
+ if (mMovingLine2.mX + mMovingLine2.mWidth >= mMovingLine2.mTargetX)
+ {
+ mMovingLine2.mWidth = mMovingLine2.mTargetX - mMovingLine2.mX;
+ mMovingLine2.mDone = true;
+ ++numDone;
+ }
+ }
+ }
+
+ // While at least one of the lines is still moving, make a bunch of sparks shower off
+ // the edge of them. In non-3d mode, we'll only emit half the sparks to reduce the CPU time consumed.
+ if (!mMovingLine2.mDone || !mMovingLine1.mDone)
+ {
+ int modVal = gSexyAppBase->Is3DAccelerated() ? 2 : 4;
+ if (mUpdateCnt % modVal == 0)
+ EmitSparks();
+ }
+
+ // If both are done at the same time, or both are done but perhaps one completed earlier than the other,
+ // then it's time to compute the fill region.
+ if ((numDone == 2) || ((numDone == 1) && mMovingLine1.mDone && mMovingLine2.mDone))
+ {
+ mFilling = true;
+
+ CalculateFillRegions();
+ }
+
+ // Quit playing the electrical shorting out sound when both lines are broken or
+ // done or any combination of the two.
+ if ((mMovingLine1.mDone && mMovingLine2.mDone) ||
+ (mMovingLine1.mBroken && mMovingLine2.mDone) ||
+ (mMovingLine2.mBroken && mMovingLine1.mDone))
+ mShortSound->Stop();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ g->SetColor(Color::Black);
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ int incAmt = gSexyAppBase->Is3DAccelerated() ? 1 : 2;
+
+ // Draw less starts if not in 3D mode to reduce CPU usage, since they aren't a critical feature
+ for (int i = 0; i < MAX_STARS; i += incAmt)
+ {
+ Star* s = &mStarField[i];
+ g->SetColor(s->mColor);
+ g->FillRect(s->mX, s->mY, 1, 1);
+ }
+
+ // We don't draw the other game elements under certain conditions, like
+ // if the level up and game over effects are in a few particular states.
+ if (!mLevelupEffect->HideBoard() && !mGameOverEffect->HideBoard())
+ {
+ DrawGrid(g);
+ DrawUI(g);
+
+ // To prevent cheating, don't draw planets if the game is paused.
+ // Also don't show them during certain points of the level up effect
+ if (!mLevelupEffect->HidePlanets() || (mPauseLevel > 0))
+ DrawPlanets(g);
+
+ if (!mGameOverEffect->IsActive())
+ DrawMovingBeams(g);
+
+ DrawHungarr(g);
+ }
+
+ if (mLevelupEffect->IsActive())
+ mLevelupEffect->Draw(g);
+
+ if (mGameOverEffect->IsActive())
+ mGameOverEffect->Draw(g);
+
+ if (mPauseLevel > 0)
+ {
+ // Paused: draw an overlay
+ g->SetColor(Color(0, 0, 0, 128));
+ g->FillRect(0, 0, mWidth, mHeight);
+ g->SetColor(Color::White);
+ g->SetFont(FONT_HUNGARR);
+ g->DrawString(_S("PAUSED"), mWidth / 2 - FONT_HUNGARR->StringWidth(_S("PAUSED")) / 2, mHeight / 2);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawGrid(Graphics* g)
+{
+ // Draw an outline around the whole grid region. See LevelUpEffect.cpp or
+ // GameOverEffect.cpp for full details on using HSL instead of RGB for color and
+ // why it's useful.
+ if (mFlashCount > 0)
+ g->SetColor(mApp->HSLToRGB(mBorderHue, 255, 128) & 0xFFFFFFFF);
+ else
+ g->SetColor(Color(255, 0, 0, 64));
+
+ // grid outline:
+ g->FillRect(0, GRID_START_Y, GRID_START_X, mHeight - GRID_START_Y);
+ g->FillRect(0, GRID_START_Y - GRID_PIX_SIZE, mWidth, GRID_PIX_SIZE);
+ g->FillRect(GRID_END_X, GRID_START_Y, mWidth - GRID_END_X, mHeight - GRID_START_Y);
+ g->FillRect(GRID_START_X, GRID_END_Y, GRID_END_X - GRID_START_X, mHeight - GRID_END_Y);
+
+
+ // To make a weird pattern, a few of the grid pieces will be more brightly
+ // colored than the others, if they are in the normal state.
+ bool startBright = true;
+ for (int y = 0; y < GRID_HEIGHT; y++)
+ {
+ int drawY = GetRowPix(y);
+
+ for (int x = 0; x < GRID_WIDTH; x++)
+ {
+ int drawX = GetColPix(x);
+ int state = mGridState[y][x].mFillState;
+ if (state == GRID_FILLING)
+ {
+ // The grid piece is in the process of filling up. Draw a different colored rectangle for the
+ // filled in part, and then draw the rest normally.
+ FRect* fr = &mGridState[y][x].mFillRect;
+ Rect normalRect;
+
+ if (mFillDirection == FILL_RIGHT)
+ normalRect = Rect(fr->mX + fr->mWidth, drawY, GRID_PIX_SIZE - fr->mWidth + 1, GRID_PIX_SIZE);
+ else if (mFillDirection == FILL_LEFT)
+ normalRect = Rect(drawX, drawY, GRID_PIX_SIZE - fr->mWidth, GRID_PIX_SIZE);
+ else if (mFillDirection == FILL_UP)
+ normalRect = Rect(drawX, drawY, GRID_PIX_SIZE, GRID_PIX_SIZE - fr->mHeight);
+ else
+ normalRect = Rect(drawX, fr->mY + fr->mHeight, GRID_PIX_SIZE, GRID_PIX_SIZE - fr->mHeight + 1);
+
+
+ if ((normalRect.mWidth > 0) && (normalRect.mHeight > 0))
+ {
+ g->SetColor(Color(255, 255, 0, startBright && (x % 2 == 0) ? 128 : 64));
+ g->FillRect(normalRect);
+ g->SetColor(Color(0, 0, 0));
+ g->DrawRect(normalRect);
+ }
+
+ g->SetColor(Color(255, 255, 0, 100));
+ FillRectF(g, *fr);
+ }
+ else if (state == GRID_NORMAL)
+ {
+ // Just draw the grid piece normally, with a black outline around it.
+
+ g->SetColor(Color(255, 255, 0, startBright && (x % 3 == 0) ? 64 : 32));
+ g->FillRect(drawX, drawY, GRID_PIX_SIZE, GRID_PIX_SIZE);
+ g->SetColor(Color(0, 0, 0));
+ g->DrawRect(drawX, drawY, GRID_PIX_SIZE, GRID_PIX_SIZE);
+ }
+ else
+ {
+ // The piece is completely filled in, just fill the whole rectangle
+ g->SetColor(Color(255, 255, 0, 100));
+ FillRectF(g, mGridState[y][x].mFillRect);
+ }
+ }
+
+ startBright = !startBright;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawUI(Graphics* g)
+{
+ int ascent = FONT_HUNGARR->GetAscent();
+ int height = FONT_HUNGARR->GetHeight();
+
+ g->SetFont(FONT_HUNGARR);
+ SexyString s;
+ int rightX = FONT_HUNGARR->StringWidth(_S("POPULATION CONSUMED: ")) + 5;
+
+ int strWidth;
+ s = _S("WORLDS DEVOURED: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->SetColor(Color(255, 255, 255, 128));
+ g->DrawString(s, rightX - strWidth, ascent);
+ g->SetColor(Color(255, 0, 0, 200));
+ g->DrawString(StrFormat(_S("%d"), mNumPlanetsEaten), rightX - 5, ascent);
+
+ s = _S("POPULATION CONSUMED: ");
+ g->SetColor(Color(255, 255, 255, 128));
+ g->DrawString(s, 5, height * 2);
+ g->SetColor(Color(255, 0, 0, 200));
+ g->DrawString(CommaSeperate(mPopulationEaten), rightX - 5, height * 2);
+
+ s = _S("SCORE: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->SetColor(Color(255, 255, 255, 128));
+ g->DrawString(s, rightX - strWidth, height * 3);
+ g->SetColor(Color(255, 255, 0, 200));
+ g->DrawString(StrFormat(_S("%s"), CommaSeperate(mScore).c_str()), rightX - 5, height * 3);
+
+
+
+ int x = 380;
+ s = _S("SYSTEMS SUBJUGATED: ");
+ g->SetColor(Color(255, 255, 255, 128));
+ g->DrawString(s, x, ascent);
+ g->SetColor(Color(255, 0, 0, 200));
+ g->DrawString(StrFormat(_S("%d%%"), mPercentComplete), x + FONT_HUNGARR->StringWidth(s), ascent);
+
+ s = _S("LIVES: ");
+ g->SetColor(Color(255, 255, 255, 128));
+ g->DrawString(s, x, height * 2);
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawImage(IMAGE_HUNGARR_SMALL, strWidth + x, ascent);
+ g->SetColor(Color(255, 0, 0, 200));
+ g->DrawString(StrFormat(_S("x%d"), mLives), x + 10 + strWidth + IMAGE_HUNGARR_SMALL->GetWidth(), height * 2);
+
+ s = _S("LEVEL: ");
+ g->SetColor(Color(255, 255, 255, 128));
+ g->DrawString(s, x, height * 3);
+ g->SetColor(Color(255, 255, 0, 200));
+ g->DrawString(StrFormat(_S("%d"), mLevel), x + FONT_HUNGARR->StringWidth(s), height * 3);
+
+ for (int i = 0; i < mBonusText.size(); i++)
+ {
+ BonusText* bt = &mBonusText[i];
+ g->SetColor( (mApp->HSLToRGB(bt->mHue, 255, 128) & 0xFFFFFF) | (bt->mAlpha << 24) );
+ g->DrawString(bt->mText, bt->mX, bt->mY);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Beam1DrawHelper(Graphics* g)
+{
+ // In 3D mode we'll use the DrawImageF versions since they look nicer and
+ // perform anti-aliasing, and make floating point movement appear smoother.
+ // Since they are more taxing, we'll use the default integer routines if hardware
+ // mode is not available.
+
+ // The offsets you see were taken from the actual image itself. You'll notice
+ // that the image has a lot of blank space around the actual beam, so we move things
+ // around a bit to get a nice aligned look. You'd either just play around with these
+ // numbers till it looked right, or your artist would inform you.
+ if (mMovingLine1.mIsVertical)
+ {
+ if (gSexyAppBase->Is3DAccelerated())
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_UP, mMovingLine1.mX - 8, mMovingLine1.mY,
+ Rect(0, 0, IMAGE_HUNGARR_BEAM_UP->GetWidth(), mMovingLine1.mHeight));
+ }
+ else
+ {
+ g->DrawImage(IMAGE_HUNGARR_BEAM_UP, mMovingLine1.mX - 8, mMovingLine1.mY,
+ Rect(0, 0, IMAGE_HUNGARR_BEAM_UP->GetWidth(), mMovingLine1.mHeight));
+ }
+ }
+ else
+ {
+ if (gSexyAppBase->Is3DAccelerated())
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_LEFT, mMovingLine1.mX, mMovingLine1.mY - 8,
+ Rect(0, 0, mMovingLine1.mWidth, IMAGE_HUNGARR_BEAM_LEFT->GetHeight()));
+ }
+ else
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_LEFT, mMovingLine1.mX, mMovingLine1.mY - 8,
+ Rect(0, 0, mMovingLine1.mWidth, IMAGE_HUNGARR_BEAM_LEFT->GetHeight()));
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Beam2DrawHelper(Graphics* g)
+{
+ // In 3D mode we'll use the DrawImageF versions since they look nicer and
+ // perform anti-aliasing, and make floating point movement appear smoother.
+ // Since they are more taxing, we'll use the default integer routines if hardware
+ // mode is not available.
+
+ // The offsets you see were taken from the actual image itself. You'll notice
+ // that the image has a lot of blank space around the actual beam, so we move things
+ // around a bit to get a nice aligned look. You'd either just play around with these
+ // numbers till it looked right, or your artist would inform you.
+
+ if (mMovingLine2.mIsVertical)
+ {
+ if (gSexyAppBase->Is3DAccelerated())
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_DOWN, mMovingLine2.mX - 8, mMovingLine2.mY - 1,
+ Rect(0, IMAGE_HUNGARR_BEAM_DOWN->GetHeight() - mMovingLine2.mHeight,
+ IMAGE_HUNGARR_BEAM_DOWN->GetWidth(), mMovingLine2.mHeight));
+ }
+ else
+ {
+ g->DrawImage(IMAGE_HUNGARR_BEAM_DOWN, mMovingLine2.mX - 8, mMovingLine2.mY - 1,
+ Rect(0, IMAGE_HUNGARR_BEAM_DOWN->GetHeight() - mMovingLine2.mHeight,
+ IMAGE_HUNGARR_BEAM_DOWN->GetWidth(), mMovingLine2.mHeight));
+ }
+ }
+ else
+ {
+ if (gSexyAppBase->Is3DAccelerated())
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_RIGHT, mMovingLine2.mX - 1, mMovingLine2.mY - 8,
+ Rect(IMAGE_HUNGARR_BEAM_RIGHT->GetWidth() - mMovingLine2.mWidth, 0,
+ mMovingLine2.mWidth, IMAGE_HUNGARR_BEAM_RIGHT->GetHeight()));
+ }
+ else
+ {
+ g->DrawImage(IMAGE_HUNGARR_BEAM_RIGHT, mMovingLine2.mX - 1, mMovingLine2.mY - 8,
+ Rect(IMAGE_HUNGARR_BEAM_RIGHT->GetWidth() - mMovingLine2.mWidth, 0,
+ mMovingLine2.mWidth, IMAGE_HUNGARR_BEAM_RIGHT->GetHeight()));
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawMovingBeams(Graphics* g)
+{
+ // If the beams are moving, then draw them. Make them pulse too. You make a
+ // pulsing effect like we did in the previous demos: draw the image a second time on
+ // top of the original additively, and colorize the image, setting the RGB values to
+ // a different intensity. The result is an image that gets brighter and dimmer over time.
+ if (!mMovingLine1.mBroken && (!mMovingLine1.mDone || mFilling || !mMovingLine2.mDone))
+ {
+ Beam1DrawHelper(g);
+
+ if (!mMovingLine1.mDone)
+ {
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+ g->SetColor(Color(mBeamPulseVal, mBeamPulseVal, mBeamPulseVal));
+ Beam1DrawHelper(g);
+ g->SetColorizeImages(false);
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ }
+
+ }
+
+ if (!mMovingLine2.mDone || mFilling || !mMovingLine1.mDone)
+ {
+ Beam2DrawHelper(g);
+
+ if (!mMovingLine2.mDone)
+ {
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+ g->SetColor(Color(mBeamPulseVal, mBeamPulseVal, mBeamPulseVal));
+ Beam2DrawHelper(g);
+ g->SetColorizeImages(false);
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ }
+ }
+
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ for (int i = 0; i < mParticles.size(); i++)
+ {
+ Particle* p = &mParticles[i];
+ g->DrawImageCel(IMAGE_PARTICLE_LIGHTNING, p->mX, p->mY, p->mFrame);
+ }
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawPlanets(Graphics* g)
+{
+ // If the user has 3d, we'll rotate the planets using the floating point
+ // smooth rotation function. If they don't, we'll avoid rotating at all to
+ // save on CPU cycles and keep the framerate up.
+ int w = IMAGE_PLANETS->GetCelWidth();
+ int h = IMAGE_PLANETS->GetCelHeight();
+ for (int i = 0; i < mPlanets.size(); i++)
+ {
+ Planet* p = &mPlanets[i];
+ if (p->mExploding)
+ {
+ g->DrawImageCel(IMAGE_BOMB_RADIAL_DEATH,
+ p->mX - (IMAGE_BOMB_RADIAL_DEATH->GetCelWidth() / 2 + w / 2),
+ p->mY - (IMAGE_BOMB_RADIAL_DEATH->GetCelHeight() / 2 + h / 2),
+ p->mExplodeFrame);
+ }
+ else
+ {
+ Rect r = Rect(p->mImgCol * w, 0, w, IMAGE_PLANETS->GetCelHeight());
+
+ if (gSexyAppBase->Is3DAccelerated())
+ g->DrawImageRotatedF(IMAGE_PLANETS, p->mX, p->mY, p->mRotationAngle, &r);
+ else
+ g->DrawImage(IMAGE_PLANETS, p->mX, p->mY, r);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawHungarrVertBeamsHelper(Graphics* g)
+{
+ // This draws the two little static beams that are always attached to
+ // Hun-garr's bitmap. If the user has hardware acceleration, we'll
+ // draw the beams pulsating. If not, we'll skip it since it's time consuming
+ // and doesn't hurt the game any. It'd be worse to drop the framrate by a few FPS
+ // for this effect.
+
+ int h = IMAGE_HUNGARR_VERT->GetHeight() / 2;
+
+ if (gSexyAppBase->Is3DAccelerated())
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_UP, mLine1X, mLine1Y,
+ Rect(0, 0, IMAGE_HUNGARR_BEAM_UP->GetWidth(), h));
+
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_DOWN, mLine2X, mLine2Y,
+ Rect(0, IMAGE_HUNGARR_BEAM_DOWN->GetHeight() - h, IMAGE_HUNGARR_BEAM_DOWN->GetWidth(), h));
+
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+
+ g->SetColor(Color(255, 255, 255, mBeamPulseVal));
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_UP, mLine1X, mLine1Y,
+ Rect(0, 0, IMAGE_HUNGARR_BEAM_UP->GetWidth(), h));
+
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_DOWN, mLine2X, mLine2Y,
+ Rect(0, IMAGE_HUNGARR_BEAM_DOWN->GetHeight() - h, IMAGE_HUNGARR_BEAM_DOWN->GetWidth(), h));
+
+
+ g->SetColorizeImages(false);
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ }
+ else
+ {
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->DrawImage(IMAGE_HUNGARR_BEAM_UP, mLine1X, mLine1Y,
+ Rect(0, 0, IMAGE_HUNGARR_BEAM_UP->GetWidth(), h));
+
+ g->DrawImage(IMAGE_HUNGARR_BEAM_DOWN, mLine2X, mLine2Y,
+ Rect(0, IMAGE_HUNGARR_BEAM_DOWN->GetHeight() - h, IMAGE_HUNGARR_BEAM_DOWN->GetWidth(), h));
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawHungarrHorizBeamsHelper(Graphics* g)
+{
+ // This draws the two little static beams that are always attached to
+ // Hun-garr's bitmap. If the user has hardware acceleration, we'll
+ // draw the beams pulsating. If not, we'll skip it since it's time consuming
+ // and doesn't hurt the game any. It'd be worse to drop the framrate by a few FPS
+ // for this effect.
+
+ int w = IMAGE_HUNGARR_HORIZ->GetWidth() / 2;
+
+ if (gSexyAppBase->Is3DAccelerated())
+ {
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_LEFT, mLine1X, mLine1Y,
+ Rect(0, 0, w, IMAGE_HUNGARR_BEAM_LEFT->GetHeight()));
+
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_RIGHT, mLine2X, mLine2Y,
+ Rect(IMAGE_HUNGARR_BEAM_RIGHT->GetWidth() - w, 0, w, IMAGE_HUNGARR_BEAM_RIGHT->GetHeight()));
+
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+
+ g->SetColor(Color(255, 255, 255, mBeamPulseVal));
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_LEFT, mLine1X, mLine1Y,
+ Rect(0, 0, w, IMAGE_HUNGARR_BEAM_LEFT->GetHeight()));
+
+ g->DrawImageF(IMAGE_HUNGARR_BEAM_RIGHT, mLine2X, mLine2Y,
+ Rect(IMAGE_HUNGARR_BEAM_RIGHT->GetWidth() - w, 0, w, IMAGE_HUNGARR_BEAM_RIGHT->GetHeight()));
+
+ g->SetColorizeImages(false);
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ }
+ else
+ {
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+
+ g->DrawImage(IMAGE_HUNGARR_BEAM_LEFT, mLine1X, mLine1Y,
+ Rect(0, 0, w, IMAGE_HUNGARR_BEAM_LEFT->GetHeight()));
+
+ g->DrawImage(IMAGE_HUNGARR_BEAM_RIGHT, mLine2X, mLine2Y,
+ Rect(IMAGE_HUNGARR_BEAM_RIGHT->GetWidth() - w, 0, w, IMAGE_HUNGARR_BEAM_RIGHT->GetHeight()));
+
+ g->SetDrawMode(Graphics::DRAWMODE_NORMAL);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::DrawHungarr(Graphics* g)
+{
+ // again, we use the floating point functions instead of the integer ones
+ // if the user has a 3d card.
+
+ bool is3d = gSexyAppBase->Is3DAccelerated();
+
+ if (mHungarrIsVertical)
+ {
+ DrawHungarrVertBeamsHelper(g);
+
+ if (is3d)
+ g->DrawImageF(IMAGE_HUNGARR_VERT, mHungarrX, mHungarrY);
+ else
+ g->DrawImage(IMAGE_HUNGARR_VERT, mHungarrX, mHungarrY);
+ }
+ else
+ {
+ DrawHungarrHorizBeamsHelper(g);
+
+ if (is3d)
+ g->DrawImageF(IMAGE_HUNGARR_HORIZ, mHungarrX, mHungarrY);
+ else
+ g->DrawImage(IMAGE_HUNGARR_HORIZ, mHungarrX, mHungarrY);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::AddedToManager(WidgetManager* theWidgetManager)
+{
+ Widget::AddedToManager(theWidgetManager);
+
+
+ mOptionsBtn = new ButtonWidget(1, this);
+ mOptionsBtn->SetFont(FONT_DEFAULT);
+ mOptionsBtn->mLabel = _S("Options");
+ mOptionsBtn->SetColor(ButtonWidget::COLOR_LABEL, Color::White);
+ mOptionsBtn->SetColor(ButtonWidget::COLOR_LABEL_HILITE, Color::White);
+
+ mOptionsBtn->mOverImage = IMAGE_BUTTON_OVER;
+ mOptionsBtn->mDownImage = IMAGE_BUTTON_DOWN;
+ mOptionsBtn->mButtonImage = IMAGE_BUTTON_NORMAL;
+ mOptionsBtn->mDoFinger = true;
+ mOptionsBtn->Resize(gSexyAppBase->mWidth - IMAGE_BUTTON_NORMAL->GetWidth() - 10, FONT_HUNGARR->GetHeight() * 3 - 20,
+ IMAGE_BUTTON_NORMAL->GetWidth(), IMAGE_BUTTON_NORMAL->GetHeight());
+
+ theWidgetManager->AddWidget(mOptionsBtn);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::RemovedFromManager(WidgetManager* theWidgetManager)
+{
+ Widget::RemovedFromManager(theWidgetManager);
+
+ theWidgetManager->RemoveWidget(mOptionsBtn);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::ButtonDepress(int theId)
+{
+ // Play a sound whenever the options button is depressed/sad.
+ if (theId == mOptionsBtn->mId)
+ {
+ // Stop the shorting sound if it's playing, otherwise it's annoying
+ mShortSound->Stop();
+
+ mApp->PlaySample(SOUND_BUTTON);
+ Pause(true);
+ OptionsDialog* od = new OptionsDialog(this);
+ od->Resize(mWidth / 2 - 200, mHeight / 2 - 175, 400, 350);
+ mApp->AddDialog(OptionsDialog::DIALOG_ID, od);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseMove(int x, int y)
+{
+ UpdateHungarrPosition(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseDrag(int x, int y)
+{
+ UpdateHungarrPosition(x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::MouseDown(int x, int y, int theClickCount)
+{
+ // if the level up effect is displaying stats, or the game over effect is too,
+ // and the user clicked, then start the next phase
+ if (mLevelupEffect->ShowingStats())
+ mLevelupEffect->DoneViewingStats();
+
+ if (mGameOverEffect->CanStartNewGame())
+ mGameOverEffect->DoneViewingStats();
+
+ // ignore mouse clicks when paused or an effect is on screen and the user has no reason to click
+ if (mLevelupEffect->IsActive() || (mPauseLevel > 0) || (mGameOverEffect->IsActive() && !mGameOverEffect->CanStartNewGame()))
+ return;
+
+ // On a right click, if the click was within the grid bounds, switch hungarr's orientation
+ if ((theClickCount < 0) && XCoordInBounds(x) && YCoordInBounds(y, mHungarrIsVertical))
+ mHungarrIsVertical = !mHungarrIsVertical;
+ else if ((theClickCount > 0) && mMovingLine1.mDone && mMovingLine2.mDone && !mFilling)
+ {
+ //left click, and there's no lines moving: drop two new lines
+
+ // Make sure the user didn't click on a planet which would instantly kill them
+ FRect hungarrRect = FRect(mHungarrX, mHungarrY, IMAGE_HUNGARR_HORIZ->mWidth, IMAGE_HUNGARR_HORIZ->mHeight);
+ for (int i = 0; i < mPlanets.size(); i++)
+ {
+ Planet* p = &mPlanets[i];
+ FRect planetRect = FRect(p->mX, p->mY, IMAGE_PLANETS->GetCelWidth(), IMAGE_PLANETS->GetCelHeight());
+ if (planetRect.Intersects(hungarrRect))
+ return;
+ }
+
+ mApp->PlaySample(SOUND_MAGZAP);
+
+ // start the electrical shorting sound
+ mShortSound->Play(true, false);
+
+ mMovingLine1.mDone = mMovingLine2.mDone = false;
+ mMovingLine1.mBroken = mMovingLine2.mBroken = false;
+ int midX = IMAGE_HUNGARR_HORIZ->GetWidth() / 2;
+ int midY = IMAGE_HUNGARR_HORIZ->GetHeight() / 2;
+
+ //Align the XYs of the lines to the grid, and set the target coordinates to the
+ //closest normal state tile.
+ if (mHungarrIsVertical)
+ {
+ mMovingLine1.mIsVertical = mMovingLine2.mIsVertical = true;
+ mMovingLine1.mX = mMovingLine2.mX = GetAlignedX(mHungarrX + midX);
+ mMovingLine1.mY = mMovingLine2.mY = GetAlignedY(mHungarrY + midY);
+ mMovingLine1.mHeight = 1;
+ mMovingLine2.mHeight = 13;
+ mMovingLine1.mWidth = mMovingLine2.mWidth = GRID_PIX_SIZE;
+ mMovingLine1.mTargetY = mMovingLine2.mTargetY = mMovingLine1.mY;
+ mMovingLine1.mTargetX = mMovingLine2.mTargetX = mMovingLine1.mX;
+
+ // Make sure the target coords end at a tile that's normal. If not, keep moving them
+ int row = GetRow(mMovingLine1.mTargetY);
+ int col = GetCol(mMovingLine1.mTargetX);
+
+ // Tile immediately below is not valid
+ if (mGridState[row][col].mFillState != GRID_NORMAL)
+ return;
+
+ while ((row >= 0) && (mGridState[row][col].mFillState == GRID_NORMAL))
+ {
+ mMovingLine1.mTargetY -= GRID_PIX_SIZE;
+ --row;
+ }
+
+ // Make it end on the last valid tile. The loop above makes it leave
+ // on an invalid tile
+ mMovingLine1.mTargetY += GRID_PIX_SIZE;
+
+ row = GetRow(mMovingLine2.mTargetY);
+ col = GetCol(mMovingLine2.mTargetX);
+
+ while ((row < GRID_HEIGHT) && (mGridState[row][col].mFillState == GRID_NORMAL))
+ {
+ mMovingLine2.mTargetY += GRID_PIX_SIZE;
+ ++row;
+ }
+
+ if (mMovingLine1.mTargetY > mMovingLine2.mTargetY)
+ mMovingLine1.mDone = mMovingLine2.mDone = true;
+ }
+ else
+ {
+ mMovingLine1.mIsVertical = mMovingLine2.mIsVertical = false;
+ mMovingLine1.mX = mMovingLine2.mX = GetAlignedX(mHungarrX + midX);
+ mMovingLine1.mY = mMovingLine2.mY = GetAlignedY(mHungarrY + midY);
+ mMovingLine1.mWidth = 1;
+ mMovingLine2.mWidth = 13;
+ mMovingLine1.mHeight = mMovingLine2.mHeight = GRID_PIX_SIZE;
+ mMovingLine1.mTargetX = mMovingLine2.mTargetX = mMovingLine1.mX;
+ mMovingLine1.mTargetY = mMovingLine2.mTargetY = mMovingLine1.mY;
+
+ // Make sure the target coords end at a tile that's normal. If not, keep moving them
+ int row = GetRow(mMovingLine1.mTargetY);
+ int col = GetCol(mMovingLine1.mTargetX);
+
+ // Tile immediately below is not valid...?
+ if (mGridState[row][col].mFillState != GRID_NORMAL)
+ return;
+
+ while ((col >= 0) && (mGridState[row][col].mFillState == GRID_NORMAL))
+ {
+ mMovingLine1.mTargetX -= GRID_PIX_SIZE;
+ --col;
+ }
+
+ // Make it end on the last valid tile. The loop above makes it leave
+ // on an invalid tile
+ mMovingLine1.mTargetX += GRID_PIX_SIZE;
+
+
+ row = GetRow(mMovingLine2.mTargetY);
+ col = GetCol(mMovingLine2.mTargetX);
+
+ while ((col < GRID_WIDTH) && (mGridState[row][col].mFillState == GRID_NORMAL))
+ {
+ mMovingLine2.mTargetX += GRID_PIX_SIZE;
+ ++col;
+ }
+
+
+ if (mMovingLine1.mTargetX > mMovingLine2.mTargetX)
+ mMovingLine1.mDone = mMovingLine2.mDone = true;
+ }
+ }
+
+ UpdateHungarrPosition(x, y);
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::UpdateHungarrPosition(int x, int y)
+{
+ // Place the Hun-garr bitmap and the two lines that stick out of him
+ // so that Hun-garr is centered on the mouse cursor
+ int midX = IMAGE_HUNGARR_HORIZ->GetWidth() / 2;
+ int midY = IMAGE_HUNGARR_HORIZ->GetHeight() / 2;
+
+ if (YCoordInBounds(y, mHungarrIsVertical))
+ {
+ mHungarrY = y - midY;
+ mLine1Y = mHungarrY + (!mHungarrIsVertical ? 7 : -12);
+ mLine2Y = mHungarrY + (!mHungarrIsVertical ? 7 : 35);
+ }
+
+ if (XCoordInBounds(x))
+ {
+ mHungarrX = x - midX;
+ mLine1X = mHungarrX + (!mHungarrIsVertical ? -13 : 8);
+ mLine2X = mHungarrX + (!mHungarrIsVertical ? 36 : 9);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::CalculateFillRegions(void)
+{
+ int topRow, botRow, leftCol, rightCol;
+
+ // The basic idea is this: Find the CLOSEST edge to where the user clicks that
+ // meets the following conditions:
+ // 1. If Hun-garr is vertical, the edge must be as tall as the column created
+ // by the two emitted lines (or more) and every grid piece must be normal
+ // 2. If Hun-garr is horizontal, the edge must be as wide as the row created by
+ // the two emitted lines (or more) and every grid piece must be normal
+ // 3. If either of the lines were broken, we instead just fill in the single
+ // line made by the non-broken line (the code won't execute if both are broken)
+
+
+ if (mMovingLine1.mIsVertical)
+ {
+ topRow = GetRow(mMovingLine1.mTargetY);
+ int col1 = GetCol(mMovingLine1.mTargetX);
+ botRow = GetRow(mMovingLine2.mTargetY);
+
+ if ((mMovingLine1.mBroken && !mMovingLine2.mBroken) ||
+ (!mMovingLine1.mBroken && mMovingLine2.mBroken))
+ {
+ leftCol = col1;
+ rightCol = col1 + 1;
+ mFillDirection = FILL_RIGHT;
+ topRow = mMovingLine1.mBroken ? GetRow(mMovingLine2.mY) : topRow;
+ botRow = mMovingLine1.mBroken ? botRow : GetRow(mMovingLine2.mY);
+ }
+ else
+ {
+ int rightEdge, leftEdge;
+ GetVerticalFillValues(col1, topRow, botRow, 1, &rightEdge);
+ GetVerticalFillValues(col1, topRow, botRow, -1, &leftEdge);
+
+ if ((rightEdge - col1) <= (col1 - leftEdge))
+ {
+ leftCol = col1;
+ rightCol = rightEdge + 1;
+ mFillDirection = FILL_RIGHT;
+ }
+ else
+ {
+ leftCol = leftEdge;
+ rightCol = col1 + 1;
+ mFillDirection = FILL_LEFT;
+ }
+ }
+
+ }
+ else
+ {
+ leftCol = GetCol(mMovingLine1.mTargetX);
+ rightCol = GetCol(mMovingLine2.mTargetX);
+ int row1 = GetRow(mMovingLine1.mTargetY);
+
+ if ((mMovingLine1.mBroken && !mMovingLine2.mBroken) ||
+ (!mMovingLine1.mBroken && mMovingLine2.mBroken))
+ {
+ leftCol = mMovingLine1.mBroken ? GetCol(mMovingLine2.mX) : leftCol;
+ rightCol = mMovingLine1.mBroken ? rightCol : GetCol(mMovingLine2.mX);
+ topRow = row1;
+ botRow = row1 + 1;
+ mFillDirection = FILL_DOWN;
+ }
+ else
+ {
+ int topEdge, botEdge;
+ GetHorizontalFillValues(row1, leftCol, rightCol, -1, &topEdge);
+ GetHorizontalFillValues(row1, leftCol, rightCol, 1, &botEdge);
+
+ if ((botEdge - row1) <= (row1 - topEdge))
+ {
+ topRow = row1;
+ botRow = botEdge + 1;
+ mFillDirection = FILL_DOWN;
+ }
+ else
+ {
+ topRow = topEdge;
+ botRow = row1 + 1;
+ mFillDirection = FILL_UP;
+ }
+ }
+
+ }
+
+ //Make a rectangular fill region: every block in it will eventually be filled.
+ // Then, for all grid pieces in that region, if they are in the normal state,
+ // set them to the filling state and initialize their mFillRect's
+ mFillRegion.mLeft = leftCol;
+ mFillRegion.mRight = rightCol - 1;
+ mFillRegion.mTop = topRow;
+ mFillRegion.mBottom = botRow - 1;
+
+ for (int y = topRow; y < botRow; y++)
+ {
+ for (int x = leftCol; x < rightCol; x++)
+ {
+ if (mGridState[y][x].mFillState == GRID_NORMAL)
+ {
+ mGridState[y][x].mFillState = GRID_FILLING;
+
+ switch (mFillDirection)
+ {
+ case FILL_RIGHT:
+ mGridState[y][x].mFillRect =
+ FRect(GetColPix(x), GetRowPix(y), 0, GRID_PIX_SIZE);
+ break;
+
+ case FILL_LEFT:
+ mGridState[y][x].mFillRect =
+ FRect(GetColPix(x + 1), GetRowPix(y), 0, GRID_PIX_SIZE);
+ break;
+
+ case FILL_UP:
+ mGridState[y][x].mFillRect =
+ FRect(GetColPix(x), GetRowPix(y + 1), GRID_PIX_SIZE, 0);
+ break;
+
+ case FILL_DOWN:
+ mGridState[y][x].mFillRect =
+ FRect(GetColPix(x), GetRowPix(y), GRID_PIX_SIZE, 0);
+ break;
+ }
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::FillRectF(Graphics* g, FRect fr)
+{
+ Rect r = Rect((int)fr.mX, (int)fr.mY, (int)fr.mWidth, (int)fr.mHeight);
+ g->FillRect(r);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::GetVerticalFillValues(int startCol, int topRow, int botRow, int dir, int* edge)
+{
+ // If dir == -1, left, if 1, right
+ // See function header for algorithm description
+
+ bool done = false;
+ int col = startCol;
+
+ while (!done)
+ {
+ bool found = true;
+ for (int y = topRow; y < botRow; y++)
+ {
+ if (mGridState[y][col].mFillState != GRID_FILLED)
+ {
+ found = false;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ if ( ((dir > 0) && (++col >= GRID_WIDTH)) ||
+ ((dir < 0) && (--col < 0)) )
+ {
+ done = true;
+ *edge = col + (dir > 0 ? -1 : 1);
+ }
+ }
+ else
+ {
+ *edge = col;
+ done = true;
+ }
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::GetHorizontalFillValues(int startRow, int leftCol, int rightCol, int dir, int* edge)
+{
+ // If dir == -1, up, if 1, down
+ // See function header for algorithm description
+
+ bool done = false;
+ int row = startRow;
+
+ while (!done)
+ {
+
+ bool found = true;
+ for (int x = leftCol; x < rightCol; x++)
+ {
+ if (mGridState[row][x].mFillState != GRID_FILLED)
+ {
+ found = false;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ if ( ((dir > 0) && (++row >= GRID_HEIGHT)) ||
+ ((dir < 0) && (--row < 0)) )
+ {
+ done = true;
+ *edge = row + (dir > 0 ? -1 : 1);
+ }
+ }
+ else
+ {
+ *edge = row;
+ done = true;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::InitLevel(int level)
+{
+ mLives += level - mLevel;
+
+ mPopulationEaten = 0;
+ mPlanetSpeed += 0.15f;
+ mLevel = level;
+ mPlanets.clear();
+ mFlashCount = 0;
+ mPercentComplete = 0;
+ mPlanetsEaten.clear();
+ mBonusText.clear();
+ mParticles.clear();
+
+ mFilling = false;
+
+ // reset the grid state
+ int i;
+ for (i = 0; i < GRID_HEIGHT; i++)
+ {
+ for (int x = 0; x < GRID_WIDTH; x++)
+ {
+ mGridState[i][x].mFillRect = FRect(x * GRID_PIX_SIZE, GRID_START_Y + i * GRID_PIX_SIZE, 0, 0);
+ mGridState[i][x].mFillState = GRID_NORMAL;
+ }
+ }
+
+ // Start with 2 planets. Then add 1 every other level
+ int numPlanets = 2 + (mLevel / 2);
+ for (i = 0; i < numPlanets; i++)
+ {
+ Planet p;
+
+ // Choose a random name and export
+ p.mNameIdx = Rand() % NUM_PLANET_NAMES;
+ p.mExportIdx = Rand() % NUM_PLANET_EXPORTS;
+
+ // a random number I made up for the population. Increases by a random amount each level.
+ p.mPopulation = (mLevel * 133602) + 748819;
+
+ // Position it randomly within the confines of the grid
+ p.mX = GRID_START_X + 20 + (Rand() % (GRID_END_X - GRID_START_X - 20));
+ p.mY = GRID_START_Y + 20 + (Rand() % (GRID_END_Y - GRID_START_Y - 20));
+
+ // Get a random angle for the planet to travel in. It's easier to do RAND on
+ // degrees, so convert them to radians after choosing an angle
+ float a = (Rand() % 360) * M_PI / 180.0f;
+ p.mVX = mPlanetSpeed * cosf(a);
+ p.mVY = -mPlanetSpeed * sinf(a);
+
+ // don't let the speed be too close to 0 though, it's lame if the planet
+ // bounces just straight vertically or horizontally
+ if ((p.mVX >= -0.1) && (p.mVX <= 0.1))
+ p.mVX = 0.3f;
+
+ if ((p.mVY >= -0.1) && (p.mVY <= 0.1))
+ p.mVY = 0.3f;
+
+ // Set a random initial rotation angle and speed to rotate at.
+ // All angle manipulation is in radians.
+ p.mRotationAngle = (Rand() % 360) * M_PI / 180.0f;
+ p.mRotateSpeed = (float)(Rand() % 100) / 1000.0f;
+
+ // Choose a random image. There's 11 images, each is just 1 frame.
+ p.mImgCol = Rand() % IMAGE_PLANETS->mNumCols;
+
+ mPlanets.push_back(p);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+bool Board::MovePlanet(Planet* p, float theFrac)
+{
+ // This is a pretty simple collision detection routine and is good enough for this
+ // game. It's also a lot easier to understand than other more accurate but more
+ // complex methods. The basic idea is to check the two blocks in the direction of
+ // travel to see if they are solid or not, and if so, we reverse course, and
+ // don't move the planet to that new coordinate.
+
+ int w = IMAGE_PLANETS->GetCelWidth();
+ int h = IMAGE_PLANETS->GetCelHeight();
+ bool playSample = false;
+
+ // Update rotation
+ p->mRotationAngle += p->mRotateSpeed;
+
+ // Don't move it yet...compute where it WOULD be if the move was valid
+ float newx = p->mX + p->mVX * theFrac;
+ float newy = p->mY + p->mVY * theFrac;
+
+ // If moving right, we'll check the grid piece right of the
+ // planet to see if we hit it. Otherwise, we'll just use the grid piece that maps to
+ // where the new X coordinate is:
+ float checkx = p->mVX > 0 ? newx + GRID_PIX_SIZE : newx;
+ int col = GetCol(checkx);
+
+ // We're going to check both the current row and row below it:
+ int row = GetRow(p->mY);
+ int nextrow = ValidRow(row + 1) ? row + 1 : row;
+
+ if (ValidCol(col) && ValidRow(row))
+ {
+ int state1 = mGridState[row][col].mFillState;
+ int state2 = mGridState[nextrow][col].mFillState;
+
+ if ((state1 == GRID_NORMAL) && (state2 == GRID_NORMAL) && (newx > GRID_START_X))
+ p->mX = newx; // valid grid space
+ else if (((state1 == GRID_FILLING) || (state2 == GRID_FILLING)) && (newx > GRID_START_X))
+ {
+ // planet entered a grid space that is in the process of being filled, so make it explode
+ p->mExploding = true;
+ GivePlanetBonus(p);
+ return true;
+ }
+ else
+ {
+ // planet hit a filled in space, reverse the X velocity
+ playSample = true;
+ p->mVX = -p->mVX;
+ }
+ }
+ else
+ {
+ // Not valid cases would be if the planet hit the edges of the board, where there
+ // aren't any grid tiles. If so, just bounce it off the wall.
+ playSample = true;
+ p->mVX = -p->mVX;
+ }
+
+
+ // Now for the Y direction. The principal is the same as above.
+ int checky = p->mVY > 0 ? newy + GRID_PIX_SIZE : newy;
+ row = GetRow(checky);
+ col = GetCol(p->mX);
+ int nextcol = ValidCol(col + 1) ? col + 1 : col;
+
+ if (ValidCol(col) && ValidRow(row))
+ {
+ int state1 = mGridState[row][col].mFillState;
+ int state2 = mGridState[row][nextcol].mFillState;
+
+ if ((state1 == GRID_NORMAL) && (state2 == GRID_NORMAL) && (newy > GRID_START_Y))
+ p->mY = newy;
+ else if (((state1 == GRID_FILLING) || (state2 == GRID_FILLING)) && (newy > GRID_START_Y))
+ {
+ p->mExploding = true;
+ GivePlanetBonus(p);
+ return true;
+ }
+ else
+ {
+ playSample = true;
+ p->mVY = -p->mVY;
+ }
+ }
+ else
+ {
+ p->mVY = -p->mVY;
+ playSample = true;
+ }
+
+ // When a planet hits a wall/filled in grid piece, bounce it and play a sound
+ if (playSample)
+ mApp->PlaySample(SOUND_PLANET_HIT);
+
+ CheckPlanetBeamCollision(p);
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::CheckPlanetBeamCollision(Planet* p)
+{
+ // We're just going to do a rectangular collision check on each of the beams
+ // and the given planet. Because the visible "beam" part of the image is smaller
+ // than the image width/height, and the same goes for the planet too, you'll notice
+ // that offsets are used to constrain the collision rectangles to make a more fair algorithm.
+ FRect pr = FRect(p->mX + 4, p->mY + 4, 11, 11);
+
+ FRect beam1Rect;
+
+ if (!mMovingLine1.mIsVertical)
+ beam1Rect = FRect(mMovingLine1.mX + 7, mMovingLine1.mY + 12, mMovingLine1.mWidth - 12, 8);
+ else
+ beam1Rect = FRect(mMovingLine1.mX + 12, mMovingLine1.mY + 10, 9, mMovingLine1.mHeight);
+
+ // Only allow the user to lose 1 life max: if both beams break you don't lose 2. If the beam breaks,
+ // set a flag and set its target to be its current location (indicating that it's done moving)
+ if (pr.Intersects(beam1Rect))
+ {
+ if (!mMovingLine1.mDone)
+ {
+ mMovingLine1.mBroken = true;
+ mApp->PlaySample(SOUND_BEAM_HIT);
+
+ if (!mMovingLine2.mBroken)
+ LostLife();
+
+ if (!mMovingLine1.mIsVertical)
+ mMovingLine1.mTargetX = mMovingLine1.mX = mMovingLine1.mX + mMovingLine1.mWidth;
+ else
+ mMovingLine1.mTargetY = mMovingLine1.mY = mMovingLine1.mY + mMovingLine1.mHeight;
+ }
+ else if (!mMovingLine1.mBroken && mMovingLine1.mDone && !mMovingLine2.mDone)
+ {
+ // bounce off of it
+ if (mMovingLine1.mIsVertical)
+ {
+ p->mVX *= -1.0f;
+ p->mX += p->mVX;
+ }
+ else
+ {
+ p->mVY *= -1.0f;
+ p->mY += p->mVY;
+ }
+ }
+ }
+
+ FRect beam2Rect;
+
+ if (!mMovingLine2.mIsVertical)
+ beam2Rect = FRect(mMovingLine2.mX, mMovingLine2.mY + 12, mMovingLine2.mWidth - 7, 8);
+ else
+ beam2Rect = FRect(mMovingLine2.mX + 12, mMovingLine2.mY, 9, mMovingLine2.mHeight);
+
+ if (pr.Intersects(beam2Rect))
+ {
+ if (!mMovingLine2.mDone)
+ {
+ mMovingLine2.mBroken = true;
+ mApp->PlaySample(SOUND_BEAM_HIT);
+
+ if (!mMovingLine1.mBroken)
+ LostLife();
+
+ if (!mMovingLine2.mIsVertical)
+ mMovingLine2.mTargetX = mMovingLine2.mX;
+ else
+ mMovingLine2.mTargetY = mMovingLine2.mY;
+ }
+ else if (!mMovingLine2.mBroken && mMovingLine2.mDone && !mMovingLine1.mDone)
+ {
+ // bounce off of it
+ if (mMovingLine2.mIsVertical)
+ {
+ p->mVX *= -1.0f;
+ p->mX += p->mVX;
+ }
+ else
+ {
+ p->mVY *= -1.0f;
+ p->mY += p->mVY;
+ }
+ }
+ }
+
+ if ((mMovingLine1.mDone && mMovingLine2.mDone) ||
+ (mMovingLine1.mBroken && mMovingLine2.mDone) ||
+ (mMovingLine2.mBroken && mMovingLine1.mDone))
+ mShortSound->Stop();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Pause(bool p)
+{
+ if (p)
+ {
+ // Since when we're paused we don't update each frame, call
+ // MarkDirty here so that we ensure the "PAUSED" overlay appears
+ MarkDirty();
+ ++mPauseLevel;
+
+ // Don't play the looping circuit sound
+ mShortSound->Stop();
+ }
+ else
+ {
+ if (--mPauseLevel == 0)
+ {
+ // If any of the lines are moving, re-play the shorting sound
+ if (!mMovingLine1.mDone || !mMovingLine2.mDone)
+ mShortSound->Play(true, false);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::KeyChar(char theChar)
+{
+ if (theChar == ' ')
+ Pause(mPauseLevel == 0);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::GivePlanetBonus(Planet* p)
+{
+ mTotalPopulationEaten += p->mPopulation;
+ mPopulationEaten += p->mPopulation;
+ mLineSpeed += BEAM_INC_SPEED;
+ if (mLineSpeed > MAX_BEAM_SPEED)
+ mLineSpeed = MAX_BEAM_SPEED;
+
+ ++mNumPlanetsEaten;
+
+ SexyString pName = PLANET_NAME[p->mNameIdx];
+ SexyString pExport = PLANET_EXPORTS[p->mExportIdx];
+ int points = mLevel * 1000;
+ AddBonusText(StrFormat(_S("%s: +%d"), pName.c_str(), points), p->mX, p->mY);
+ mScore += points;
+
+ mPlanetsEaten.push_back(pName);
+ mPlanetsEaten.push_back(pExport.c_str());
+ mPlanetsEaten.push_back(CommaSeperate(p->mPopulation));
+
+ std::map<int, int>::iterator it = mPlanetIdxCount.find(p->mNameIdx);
+ if (it == mPlanetIdxCount.end())
+ mPlanetIdxCount[p->mNameIdx] = 1;
+ else
+ ++it->second;
+
+ it = mExportIdxCount.find(p->mExportIdx);
+ if (it == mExportIdxCount.end())
+ mExportIdxCount[p->mExportIdx] = 1;
+ else
+ ++it->second;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::UpdatePercentComplete(void)
+{
+ if (mGameOverEffect->IsActive())
+ return;
+
+ int total = GRID_WIDTH * GRID_HEIGHT;
+ int actual = 0;
+
+ for (int y = 0; y < GRID_HEIGHT; y++)
+ for (int x = 0; x < GRID_WIDTH; x++)
+ if (mGridState[y][x].mFillState == GRID_FILLED)
+ ++actual;
+
+ int newAmount = (int) (((float)actual / (float)total) * 100.0f);
+
+ int pctCleared = newAmount - mPercentComplete;
+
+ // Make the edges of the grid flash the larger the filled region was, but not
+ // for more than 3 seconds.
+ mFlashCount = pctCleared * 10;
+ if (mFlashCount > 300)
+ mFlashCount = 300;
+
+ // Points are exponential, so the larger a fill region, the much larger the score
+ int points = pctCleared * pctCleared * 20;
+ mScore += points;
+ if (points > 0)
+ {
+ mApp->PlaySample(SOUND_REGION_FILLED);
+ AddBonusText(StrFormat(_S("+%d"), points));
+ }
+
+ mPercentComplete = newAmount;
+
+ if (mPercentComplete >= LEVELUP_PERCENT)
+ {
+ // Time to level up, set up the stats
+ LevelupStats ls;
+ ls.mLevelCompleted = mLevel;
+ ls.mPercentComplete = mPercentComplete;
+ ls.mPopulationEaten = mPopulationEaten;
+ ls.mPlanetsEaten = mPlanetsEaten;
+
+ // Award a bonus for extra region filling action
+ if (mPercentComplete >= COMPLETION_BONUS_PCT)
+ mScore += COMPLETION_BONUS * mLevel;
+
+ mOptionsBtn->SetVisible(false);
+ mLevelupEffect->Activate(ls);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::AddBonusText(SexyString t)
+{
+ AddBonusText(t, mWidth / 2 - FONT_HUNGARR->StringWidth(t) / 2,
+ (mHeight - GRID_START_Y) / 2 - FONT_HUNGARR->GetHeight() / 2);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::AddBonusText(SexyString t, float x, float y)
+{
+ BonusText bt;
+ bt.mText = t;
+ bt.mX = x;
+ bt.mY = y;
+
+ mBonusText.push_back(bt);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::LostLife(void)
+{
+
+ if (--mLives <= 0)
+ {
+ mLives = 0;
+
+ // Game over. Set up the stats:
+ mOptionsBtn->SetVisible(false);
+ EndGameStats es;
+ es.mLevel = mLevel;
+ es.mNumPlanetsEaten = mNumPlanetsEaten;
+ es.mPopulationConsumed = mTotalPopulationEaten;
+ es.mScore = mScore;
+
+ // Find which planet and export were consumed the most:
+ int idx = -1;
+ int count = 0;
+ int i;
+ for (i = 0; i < NUM_PLANET_NAMES; i++)
+ {
+ std::map<int, int>::iterator it = mPlanetIdxCount.find(i);
+ if (it != mPlanetIdxCount.end())
+ {
+ if (it->second > count)
+ {
+ count = it->second;
+ idx = i;
+ }
+ }
+ }
+
+ if (idx != -1)
+ es.mFavoritePlanet = PLANET_NAME[idx];
+ else
+ es.mFavoritePlanet = _S("N/A");
+
+ idx = -1;
+ count = 0;
+ for (i = 0; i < NUM_PLANET_EXPORTS; i++)
+ {
+ std::map<int, int>::iterator it = mExportIdxCount.find(i);
+ if (it != mExportIdxCount.end())
+ {
+ if (it->second > count)
+ {
+ count = it->second;
+ idx = i;
+ }
+ }
+ }
+
+ if (idx != -1)
+ es.mFavoriteExport = PLANET_EXPORTS[idx];
+ else
+ es.mFavoriteExport = _S("N/A");
+
+ // Fade out the music
+ mApp->mMusicInterface->FadeOut(0, true);
+
+ mShortSound->Stop();
+
+ mGameOverEffect->Activate(es);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::EmitSparks(void)
+{
+ // This basically emits sparks between various angles, depending on
+ // the orientation of the line. The angle values I had to play around with
+ // until I found ones that I liked, and there's no magic secret formula for
+ // coming up with them, unless you just know how to guess well. Again,
+ // the Rand() function is easier dealt with using degrees, so we convert them
+ // to radians after choosing an angle. Then, using some basic math, we compute
+ // the separate XY velocities for the projectiles. In some cases, projectiles use
+ // diferent velocities, and again, that was just due to trying to get the nicest look
+ // and involved some playing around with to figure out. The offsets are to make the sparks
+ // appear to come out of the bulbous part of the line.
+ if (!mMovingLine1.mDone && !mMovingLine1.mBroken)
+ {
+ if (mMovingLine1.mIsVertical)
+ {
+ // between 90 and 180 degrees for left side emission
+ float angle = (90 + (Rand() % 90)) * M_PI / 180.0f;
+ float vx = cosf(angle) * 2.0f;
+ float vy = -sinf(angle) * 2.0f;
+ mParticles.push_back(Particle(mMovingLine1.mX + 5, mMovingLine1.mY + 8, vx, vy));
+
+ // between 0 and 90 degrees for right side emission
+ angle = (Rand() % 90) * M_PI / 180.0f;
+ vx = cosf(angle) * 2.0f;
+ vy = -sinf(angle) * 2.0f;
+ mParticles.push_back(Particle(mMovingLine1.mX + 5, mMovingLine1.mY + 8, vx, vy));
+ }
+ else
+ {
+ // between 280 and 320 degrees for bottom side emission
+ float angle = (280 + (Rand() % 40)) * M_PI / 180.0f;
+ float vx = cosf(angle) * 4.0f;
+ float vy = -sinf(angle) * 2.0f;
+ mParticles.push_back(Particle(mMovingLine1.mX + 5, mMovingLine1.mY + 8, vx, vy));
+
+ // between 50 and 90 degrees for top side emission
+ angle = (50 + (Rand() % 40)) * M_PI / 180.0f;
+ vx = cosf(angle) * 4.0f;
+ vy = -sinf(angle) * 3.0f;
+ mParticles.push_back(Particle(mMovingLine1.mX + 5, mMovingLine1.mY + 8, vx, vy));
+ }
+ }
+
+ if (!mMovingLine2.mDone && !mMovingLine2.mBroken)
+ {
+ if (mMovingLine2.mIsVertical)
+ {
+ // between 50 and 90 degrees for left side emission
+ float angle = (50 + (Rand() % 40)) * M_PI / 180.0f;
+ float vx = cosf(angle) * 3.0f;
+ float vy = -sinf(angle) * 4.0f;
+ mParticles.push_back(Particle(mMovingLine2.mX + 1, mMovingLine2.mY + mMovingLine2.mHeight - 17, vx, vy));
+
+ // between 120 and 160 degrees for right side emission
+ angle = (120 + (Rand() % 40)) * M_PI / 180.0f;
+ vx = cosf(angle) * 2.0f;
+ vy = -sinf(angle) * 4.0f;
+ mParticles.push_back(Particle(mMovingLine2.mX + 1, mMovingLine2.mY + mMovingLine2.mHeight - 17, vx, vy));
+ }
+ else
+ {
+ // between 90 and 140 degrees for top side emission
+ float angle = (90 + (Rand() % 50)) * M_PI / 180.0f;
+ float vx = cosf(angle) * 4.0f;
+ float vy = -sinf(angle) * 3.0f;
+ mParticles.push_back(Particle(mMovingLine2.mX + mMovingLine2.mWidth - 20, mMovingLine2.mY + 2, vx, vy));
+
+ // between 220 and 260 degrees for bottom side emission
+ angle = (220 + (Rand() % 40)) * M_PI / 180.0f;
+ vx = cosf(angle) * 4.0f;
+ vy = -sinf(angle) * 4.0f;
+ mParticles.push_back(Particle(mMovingLine2.mX + mMovingLine2.mWidth - 20, mMovingLine2.mY + 2, vx, vy));
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::OptionsDialogDone()
+{
+ // If any of the lines are moving, re-play the shorting sound
+ if (!mMovingLine1.mDone || !mMovingLine2.mDone)
+ mShortSound->Play(true, false);
+
+ Pause(false);
+
+ // Give focus back to the board so that it processes keyboard input
+ mApp->mWidgetManager->SetFocus(this);
+}
+ \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/Board.h b/osframework/source/demos/Hun-garr/Board.h
new file mode 100644
index 0000000..e627c80
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Board.h
@@ -0,0 +1,739 @@
+#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"
+#include "SexyAppFramework/Rect.h"
+
+namespace Sexy
+{
+
+
+class Graphics;
+class GameApp;
+class ButtonWidget;
+class WidgetManager;
+class LevelupEffect;
+class GameOverEffect;
+class SoundInstance;
+
+// Each grid piece is this many pixels wide/tall
+const int GRID_PIX_SIZE = 16;
+
+// Starting/ending Y coordinate of the grid (above it is the status display)
+const int GRID_START_Y = 128;
+const int GRID_END_Y = 480 - GRID_PIX_SIZE;
+
+// Starting/ending X coordinate of the grid
+const int GRID_START_X = GRID_PIX_SIZE;
+const int GRID_END_X = 640 - GRID_PIX_SIZE;
+
+// Total number of grid tiles wide/tall
+const int GRID_WIDTH = (GRID_END_X - GRID_START_X) / GRID_PIX_SIZE;
+const int GRID_HEIGHT = (GRID_END_Y - GRID_START_Y) / GRID_PIX_SIZE;
+
+// >= this percent begins the next level
+const int LEVELUP_PERCENT = 80;
+
+// >= this percent gives a bonus
+const int COMPLETION_BONUS_PCT = 85;
+
+// Bonus for >= COMPLETION_BONUS_PCT
+const int COMPLETION_BONUS = 20000;
+
+//////////////////////////////////////////////////////////////////////////
+// Represents one segment of the two expanding lines that emit
+// from the cursor when the left mouse button is pressed on a valid
+// grid region.
+//////////////////////////////////////////////////////////////////////////
+struct ExpandingLine
+{
+ bool mIsVertical; // Orientation of the line
+
+ // When the line reaches its target, that particular segment is done and planets can bounce off it.
+ // If a planet hits it before its done, it will break and you will lose a life
+ bool mDone;
+ bool mBroken; // Indicates if the line broke and thus the player lost a life.
+ float mX;
+ float mY;
+ float mWidth;
+ float mHeight;
+ float mTargetX; // XY coordinate the line is trying to reach
+ float mTargetY;
+
+ ExpandingLine() {mIsVertical = mDone = true; mBroken = false; mX = mY = mWidth = mHeight = mTargetX = mTargetY = 0;}
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Represents one of the little grid squares on the board.
+// Each square can have 1 of 3 states. See the Board class for the states.
+//////////////////////////////////////////////////////////////////////////
+struct GridTile
+{
+ int mFillState;
+
+ // A rectangle, used when the grid space is being filled in. This indicates
+ // the actual region that is currently filled. The unfilled region is drawn
+ // normally. Regions expand over time, and don't instantly fill up.
+ FRect mFillRect;
+
+ GridTile() {mFillState = 0;}
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Represents one of the bouncing balls ("Planets" I suppose). For
+// fun, planets get a random name and export, which the player, "Hun-Garr",
+// eats. If a planet is inside a region as it fills, the planet will be
+// destroyed. Each planet destroyed makes the player's beams move faster,
+// up to a point.
+//////////////////////////////////////////////////////////////////////////
+struct Planet
+{
+ unsigned int mPopulation; // A fun little stat, indicates how many people live on the planet
+ int mImgCol; // There are 11 planets, this is the column indicating the planet image to draw
+ int mExplodeFrame; // When it's dying, this keeps track of the current frame of animation
+ int mExplodeSpeed; // How fast the death animation runs
+ int mNameIdx, mExportIdx; // Index into the two tables that contain planet names and export lists
+ int mTimer; // Counter used for animation timing
+ float mX, mY;
+ float mVX, mVY; // X/Y speed
+ float mRotationAngle; // In 3D mode, the planets rotate. This is the present angle
+ float mRotateSpeed; // How fast he planet rotates, in 3D mode
+ bool mExploding; // If true, the planet is dying and going through its explosion state
+
+ Planet() {mPopulation = mImgCol = mExportIdx = mNameIdx = mTimer = 0;
+ mX = mY = mVX = mVY = mRotationAngle = mRotateSpeed = 0;
+ mExplodeSpeed = 8; mExplodeFrame = 0; mExploding = false;}
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// Used for the 3 layer star field effect.
+//////////////////////////////////////////////////////////////////////////
+struct Star
+{
+ float mX, mY;
+ float mSpeed; // How fast the star is moving rightward
+ Color mColor; // Color, for some depth perception trickery
+};
+
+//////////////////////////////////////////////////////////////////////////
+// The flashy bonus text that floats up when you get points
+//////////////////////////////////////////////////////////////////////////
+struct BonusText
+{
+ int mHue; // See the .CPP file for info on using hue/saturation/luminance values
+ int mAlpha; // How faded out the text is
+ float mX, mY;
+ SexyString mText;
+
+ BonusText() {mAlpha = 255; mHue = 0; mX = mY = 0;}
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Used for the particle effects that fly off of the moving beams
+//////////////////////////////////////////////////////////////////////////
+struct Particle
+{
+ float mX, mY;
+ float mVX, mVY; // X/Y speed
+ int mFrame; // Which frame of animation it's on
+ int mTimer; // Used to control the animation
+
+ Particle(float x, float y, float vx, float vy)
+ {mX = x, mY = y; mVX = vx; mVY = vy; mFrame = 0; mTimer = 0;}
+};
+
+
+#define MAX_STARS 300
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+class Board : public Widget, public ButtonListener
+{
+
+ private:
+
+ // The direction that the grid is being filled in
+ enum
+ {
+ FILL_LEFT,
+ FILL_RIGHT,
+ FILL_UP,
+ FILL_DOWN
+ };
+
+ // The possible states for each little grid cube
+ enum
+ {
+ GRID_NORMAL, // Drawn regularly, not filled in
+ GRID_FILLING, // In the process of being filled in, will partially draw filled and normal
+ GRID_FILLED // Totally filled in, piece now acts as a wall and draws differently
+ };
+
+ // For the stats at the end of the game that display the planet and export you ate the most,
+ // we keep track of them in the maps below. The key is the index from the PLANET_NAME or
+ // PLANET_EXPORTS table, and the value is the number of times it has been consumed. Reset on death
+ std::map<int, int> mPlanetIdxCount;
+ std::map<int, int> mExportIdxCount;
+ std::vector<BonusText> mBonusText;
+ std::vector<Planet> mPlanets; // A list of all the planets bouncing on the level
+
+ // When a planet is eaten, we dump its name, export, and population (comma delimited) in that
+ // order into this list, which will be passed to the level up class for a stats summary of
+ // the past level.
+ std::vector<SexyString> mPlanetsEaten;
+ std::vector<Particle> mParticles;
+
+ GameApp* mApp;
+
+ // The two beams that the player emits with a left click. Line 1 is ALWAYS either
+ // up or left, and line 2 is ALWAYS either down or right.
+ ExpandingLine mMovingLine1, mMovingLine2;
+ GridTile** mGridState; // 2D array of all the grid tiles
+ Insets mFillRegion; // Indicates the rectangular region being filled.
+ Star mStarField[MAX_STARS];
+ LevelupEffect* mLevelupEffect;
+ GameOverEffect* mGameOverEffect;
+ ButtonWidget* mOptionsBtn;
+
+ // The shorting out, electrical sound of the beams moving. We use a SoundInstance pointer
+ // because we want to loop the sound while the beam is moving, and stop it when done.
+ // This is easiest done manually.
+ SoundInstance* mShortSound;
+
+ bool mHungarrIsVertical; // Orientation of the player: will the lines come out vertical or horizontal?
+ bool mFilling; // Is the grid currently being filled?
+
+ int mFillDirection; // One of the FILL_ enums
+ int mHungarrX, mHungarrY; // XY of the IMAGE of the player, not exactly where the beams go though
+ int mLevel;
+ int mPopulationEaten; // Number of people eaten this level
+ int mTotalPopulationEaten; // Total number of people eaten this game
+ int mNumPlanetsEaten; // Total number of planets eaten this game
+ int mPercentComplete; // What % filled the grid is
+
+ // Indicates the number of times the game has been asked to pause. When unpausing, we decrement
+ // this value. Not really needed in this game, but in general a good idea, as every time a dialog
+ // box pops up or the app loses focus or anything like that, you'll want to only fully unpause
+ // everything when ALL the elements that requested a pause are complete, and not just one of them.
+ int mPauseLevel;
+ int mBorderHue; // HSL value of the border for a flashing effect. See .CPP for more info
+ int mFlashCount; // How long the border will flash for
+ int mLives;
+ int mScore;
+ int mBeamPulseVal; // Current intensity for the pulsing effect of the moving beams
+ int mBeamPulseAmt; // Current amount to inc/dec the intensity by for a pulsing effect
+
+ float mLine1X, mLine1Y; // XYs of the two lines that are drawn underneath Hun-garr. These
+ float mLine2X, mLine2Y; // are always drawn and are not the same as the moving line positions.
+ float mLineSpeed; // Gets faster with each planet destroyed
+ float mFillSpeed; // How quickly to fill in the grid
+
+ // Current max rate the planets can move at. Used with the planet's angle of motion to determine separate
+ // XY movement values. This increases with each level.
+ float mPlanetSpeed;
+
+ private:
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: UpdateHungarrPosition
+ // Parameters:
+ // x, y - Pixel location of the Windows cursor
+ //
+ // Purpose: Given a pixel location of the pointer, if it is within the
+ // valid bounds of the grid region, will update the XY to draw the
+ // Hun-garr bitmap at, as well as the little pulsing beams that are attached.
+ //////////////////////////////////////////////////////////////////////////
+ void UpdateHungarrPosition(int x, int y);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: UpdatePercentComplete
+ //
+ // Purpose: After the lines are done moving, this is called to see how
+ // full the grid is, and potentially take the player to the next level.
+ //////////////////////////////////////////////////////////////////////////
+ void UpdatePercentComplete(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawMovingBeams
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Helper function, draws the beams as they move across the grid.
+ //////////////////////////////////////////////////////////////////////////
+ void DrawMovingBeams(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Beam1DrawHelper
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Convenience function for DrawMovingBeams to avoid copy/pasting
+ //////////////////////////////////////////////////////////////////////////
+ void Beam1DrawHelper(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Beam2DrawHelper
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Convenience function for DrawMovingBeams to avoid copy/pasting
+ //////////////////////////////////////////////////////////////////////////
+ void Beam2DrawHelper(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawGrid
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Draws all the little rectangles that make up the grid.
+ //////////////////////////////////////////////////////////////////////////
+ void DrawGrid(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawPlanets
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Draws all the planets, convenience function
+ //////////////////////////////////////////////////////////////////////////
+ void DrawPlanets(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawGrid
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Draws the player bitmap and the two pulsing lines that are
+ // attached.
+ //////////////////////////////////////////////////////////////////////////
+ void DrawHungarr(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawHungarrVertBeamsHelper
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Helper function for DrawGrid to avoid copy/pasting
+ //////////////////////////////////////////////////////////////////////////
+ void DrawHungarrVertBeamsHelper(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawHungarrHorizBeamsHelper
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Helper function for DrawGrid to avoid copy/pasting
+ //////////////////////////////////////////////////////////////////////////
+ void DrawHungarrHorizBeamsHelper(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawUI
+ // Parameters:
+ // g - Graphics object to draw to
+ //
+ // Purpose: Draws the interface elements of the game, such as the stats.
+ //////////////////////////////////////////////////////////////////////////
+ void DrawUI(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: FillRectF
+ // Parameters:
+ // g - Graphics object to draw to
+ // fr - FRect to draw
+ //
+ // Purpose: Convenience function, since you can't pass an FRect to DrawRect.
+ // Just converts the FRect to a normal Rect. We use FRects though for
+ // more precise motion control.
+ //////////////////////////////////////////////////////////////////////////
+ void FillRectF(Graphics* g, FRect fr);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: FillLeft
+ // Parameters:
+ // amt - How many pixels to fill
+ //
+ // Purpose: Updates the filling of the grid if it's moving leftward.
+ //////////////////////////////////////////////////////////////////////////
+ void FillLeft(float amt);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: FillRight
+ // Parameters:
+ // amt - How many pixels to fill
+ //
+ // Purpose: Updates the filling of the grid if it's moving rightward.
+ //////////////////////////////////////////////////////////////////////////
+ void FillRight(float amt);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: FillUp
+ // Parameters:
+ // amt - How many pixels to fill
+ //
+ // Purpose: Updates the filling of the grid if it's moving upward.
+ //////////////////////////////////////////////////////////////////////////
+ void FillUp(float amt);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: FillDown
+ // Parameters:
+ // amt - How many pixels to fill
+ //
+ // Purpose: Updates the filling of the grid if it's moving downward.
+ //////////////////////////////////////////////////////////////////////////
+ void FillDown(float amt);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: CalculateFillRegions
+ //
+ // Purpose: Determines which areas need to be filled, once the grid lines
+ // are done moving.
+ //////////////////////////////////////////////////////////////////////////
+ void CalculateFillRegions(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: GetVerticalFillValues
+ // Parameters:
+ // startCol - Column in which the beams were released
+ // topRow - The row that the top line reached
+ // botRow - The row the the bottom line reached
+ // dir - 1 to compute the target fill line in the rightward direction,
+ // -1 to compute it in the leftward direction.
+ // edge - Set to the column that the filling should proceed towards
+ //
+ // Purpose: Given a direction to look in, finds a column to fill to.
+ // The column selected is the first column found where EVERY grid piece
+ // in it, from topRow to botRow, is in the normal grid state. If one is
+ // not found, the farthest grid edge is used. Partially filled lines are
+ // bypassed. This is used to get the CLOSEST edge to fill to for both of
+ // the possible directions: the edge that is closest to the player is
+ // selected and filling will proceed in that direction.
+ //////////////////////////////////////////////////////////////////////////
+ void GetVerticalFillValues(int startCol, int topRow, int botRow, int dir, int* edge);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: GetHorizontalFillValues
+ // Parameters:
+ // startRow - Row in which the beams were released
+ // leftCol - The column that the left line reached
+ // rightCol - The column the the right line reached
+ // dir - 1 to compute the target fill line in the downward direction,
+ // -1 to compute it in the upward direction.
+ // edge - Set to the column that the filling should proceed towards
+ //
+ // Purpose: Given a direction to look in, finds a row to fill to.
+ // The row selected is the first row found where EVERY grid piece
+ // in it, from leftCol to rightCol, is in the normal grid state. If one is
+ // not found, the farthest grid edge is used. Partially filled lines are
+ // bypassed. This is used to get the CLOSEST edge to fill to for both of
+ // the possible directions: the edge that is closest to the player is
+ // selected and filling will proceed in that direction.
+ //////////////////////////////////////////////////////////////////////////
+ void GetHorizontalFillValues(int startRow, int leftCol, int rightCol, int dir, int* edge);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MoveLines
+ // Parameters:
+ // theFrac - Value from UpdateF, used for smooth motion
+ //
+ // Purpose: Handles the moving of the lines once released.
+ //////////////////////////////////////////////////////////////////////////
+ void MoveLines(float theFrac);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MovePlanet
+ // Parameters:
+ // theFrac - Value from UpdateF, used for smooth motion
+ //
+ // Returns: true or false indicating if the planet blew up or not.
+ //
+ // Purpose: Handles the moving/bouncing of the planets
+ //////////////////////////////////////////////////////////////////////////
+ bool MovePlanet(Planet* p, float theFrac);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: CheckPlanetBeamCollision
+ // Parameters:
+ // p - A planet to check for collision
+ //
+ // Purpose: Called by MoveLines, checks to see if the given planet
+ // collided with either of the beams. If a beam is still moving,
+ // it will break and the player will lose a life (only 1 life can
+ // be lost though, even if both are broken you don't lose 2 lives).
+ // If the beam is not moving, the planet will bounce off of it.
+ //////////////////////////////////////////////////////////////////////////
+ void CheckPlanetBeamCollision(Planet* p);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: InitLevel
+ // Parameters:
+ // level - The level to set up
+ //
+ // Purpose: Initializes the next level
+ //////////////////////////////////////////////////////////////////////////
+ void InitLevel(int level);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: GivePlanetBonus
+ // Parameters:
+ // p - The planet that was destroyed
+ //
+ // Purpose: Awards bonuses for destroying a planet and emits bonus text.
+ //////////////////////////////////////////////////////////////////////////
+ void GivePlanetBonus(Planet* p);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: AddBonusText
+ // Parameters:
+ // t - The text to add
+ //
+ // Purpose: Adds floating bonus text to the center of the screen
+ //////////////////////////////////////////////////////////////////////////
+ void AddBonusText(SexyString t);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: AddBonusText
+ // Parameters:
+ // t - The text to add
+ // x, y - Coordinates to add the text at
+ //
+ // Purpose: Allows exact placement of the bonus text
+ //////////////////////////////////////////////////////////////////////////
+ void AddBonusText(SexyString t, float x, float y);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: LostLife
+ //
+ // Purpose: Convenience function, used to decrement the player's
+ // life and if it reaches 0, to start the end game sequence.
+ //////////////////////////////////////////////////////////////////////////
+ void LostLife(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: EmitSparks
+ //
+ // Purpose: Every frame, sends out more sparks from the edges of
+ // the two beams if they are moving.
+ //////////////////////////////////////////////////////////////////////////
+ void EmitSparks(void);
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Board
+ // Parameters:
+ // theApp - Pointer to the main application class
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ Board(GameApp* theApp);
+
+ virtual ~Board();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: KeyChar
+ // Parameters:
+ // theChar - The ASCII character pressed
+ //
+ // Purpose: Called by the WidgetManager if a key is pressed and the Board
+ // has focus. Used to see if space was pressed, to toggle pause state.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void KeyChar(char theChar);
+
+ //////////////////////////////////////////////////////////////////////////
+ // 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: Like Update, but allows for smooth motion. See previous
+ // demos or the doc for a lengthy explanation.
+ //////////////////////////////////////////////////////////////////////////
+ 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);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseMove
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime the
+ // mouse moves. The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseMove(int x, int y);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseDown
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ // 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
+ //
+ // IMPORTANT: Because you can't have a double click with a
+ // single click, you will receive BOTH a left (or right) button as well
+ // as a double left (or right) button message whenever you double-click.
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime
+ // a mouse button is in the down state.
+ // The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseDown(int x, int y, int theClickCount);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: MouseDrag
+ // Parameters:
+ // x - X coordinate relative to the application of the mouse
+ // y - Y coordinate relative to the application of the mouse
+ //
+ // Returns: none
+ //
+ // Purpose: Called by the WidgetManager automatically anytime the
+ // mouse moves AND a button is held down. This is the same thing as
+ // MouseMove except that it represents a drag operation. When dragging,
+ // MouseDrag will be called INSTEAD OF MouseMove.
+ // The topmost widget (i.e. the widget most immediately
+ // under the cursor) is the one who gets the function call, and any
+ // widgets underneath by default are ignored.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void MouseDrag(int x, int y);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Pause
+ // Parameters:
+ // p - Boolean indicating pause or unpause
+ //
+ // Purpose: Pauses/unpauses the game
+ //////////////////////////////////////////////////////////////////////////
+ void Pause(bool p);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: OptionsDialogDone
+ //
+ // Purpose: Called by the options dialog box when it closes, so the board
+ // can perform some misc tasks.
+ //////////////////////////////////////////////////////////////////////////
+ void OptionsDialogDone();
+};
+
+
+}
+
+#endif // __BOARD_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/GameApp.cpp b/osframework/source/demos/Hun-garr/GameApp.cpp
new file mode 100644
index 0000000..0c5a3c5
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/GameApp.cpp
@@ -0,0 +1,279 @@
+#include "GameApp.h"
+#include "TitleScreen.h"
+#include "Board.h"
+#include "OptionsDialog.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/ResourceManager.h"
+#include "SexyAppFramework/BassMusicInterface.h"
+#include "SexyAppFramework/Dialog.h"
+#include "Res.h"
+
+using namespace Sexy;
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+GameApp::GameApp()
+{
+ mProdName = "Hun-garr Needs Planets!";
+ mProductVersion = "1.0";
+ mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion);
+ mRegKey = "PopCap\\SexyAppFramework\\Hungarr";
+
+ mWidth = 640;
+ mHeight = 480;
+
+ mDebugKeysEnabled = true;
+
+ // 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;
+
+ // Enable smooth motion via UpdateF
+ mVSyncUpdates = true;
+
+ // Because it's annoying to hear the sound of the planets hitting a wall too many
+ // times in a second, we'll limit how many can occur.
+ mLastPlanetHitSoundTime = -30;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+GameApp::~GameApp()
+{
+ if (mBoard != NULL)
+ mWidgetManager->RemoveWidget(mBoard);
+
+ delete mBoard;
+
+ if (mTitleScreen != NULL)
+ mWidgetManager->RemoveWidget(mTitleScreen);
+ delete mTitleScreen;
+
+ // Using "" deletes ALL resources
+ mResourceManager->DeleteResources("");
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::Init()
+{
+
+ SexyAppBase::Init();
+
+ LoadResourceManifest();
+ if (!mResourceManager->LoadResources("Init"))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ if (!ExtractInitResources(mResourceManager))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ // To use custom cursors, you have to specify an image resource
+ // to use. The CURSOR_ defines indicate which cursor type you
+ // want to assign the image to.
+ // CURSOR_POINTER is the normal Windows pointer.
+ // CURSOR_HAND is used when mousing over widgets (if mDoFinger is true).
+ // CURSOR_DRAGGING is used when a drag operation is happening.
+ // CURSOR_TEXT is the icon used when entering text in an edit box.
+ SetCursorImage(CURSOR_POINTER, IMAGE_CUSTOM_POINTER);
+ SetCursorImage(CURSOR_HAND, IMAGE_CUSTOM_HAND);
+ SetCursorImage(CURSOR_DRAGGING, IMAGE_CUSTOM_DRAGGING);
+ SetCursorImage(CURSOR_TEXT, IMAGE_CUSTOM_TEXT);
+
+ 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);
+
+ // This example just uses 1 standard OGG file instead of a tracker file.
+ // Since we aren't cross fading at all, we'll only load it once.
+ mMusicInterface->LoadMusic(0, "music/hungarr.ogg");
+ mMusicInterface->FadeIn(0, 0, 0.002, false);
+
+ mNumLoadingThreadTasks = mResourceManager->GetNumResources("Game") +
+ mResourceManager->GetNumResources("Hungarr");
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadProc()
+{
+
+ mResourceManager->StartLoadResources("Game");
+
+ while (mResourceManager->LoadNextResource())
+ {
+ mCompletedLoadingThreadTasks++;
+ if (mShutdown)
+ return;
+
+ mTitleScreen->MarkDirty();
+ }
+
+ if (mResourceManager->HadError() || !ExtractGameResources(mResourceManager))
+ {
+ ShowResourceError(false);
+ mLoadingFailed = true;
+
+ return;
+ }
+
+ mResourceManager->StartLoadResources("Hungarr");
+
+ while (mResourceManager->LoadNextResource())
+ {
+ mCompletedLoadingThreadTasks++;
+ if (mShutdown)
+ return;
+
+ mTitleScreen->MarkDirty();
+ }
+
+ if (mResourceManager->HadError() || !ExtractHungarrResources(mResourceManager))
+ {
+ ShowResourceError(false);
+ mLoadingFailed = true;
+
+ return;
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LoadingThreadCompleted()
+{
+ // Let the base app class also know that we have completed
+ SexyAppBase::LoadingThreadCompleted();
+
+ if (mLoadingFailed)
+ return;
+
+ mTitleScreen->LoadingComplete();
+
+ mTitleScreen->MarkDirty();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::TitleScreenIsFinished()
+{
+
+ mTitleScreen = NULL;
+ mBoard = new Board(this);
+ mResourceManager->DeleteResources("TitleScreen");
+
+
+ mBoard->Resize(0, 0, mWidth, mHeight);
+ mWidgetManager->AddWidget(mBoard);
+ mWidgetManager->SetFocus(mBoard);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Dialog* GameApp::NewDialog(int theDialogId, bool isModal, const std::string& theDialogHeader,
+ const std::string& theDialogLines, const std::string& theDialogFooter, int theButtonMode)
+{
+ // Rather than dupliate a lengthy explanation, check out the top of DemoDialog.cpp for a complete description
+ // of what all the parameters and functions are, in Demo5.
+ Dialog* d = new Dialog(IMAGE_DIALOG_BOX, IMAGE_DIALOG_BUTTON, theDialogId, isModal,
+ StringToSexyStringFast(theDialogHeader), StringToSexyStringFast(theDialogLines), StringToSexyStringFast(theDialogFooter), theButtonMode);
+
+ d->SetButtonFont(FONT_DEFAULT);
+ d->SetLinesFont(FONT_DEFAULT);
+ d->SetHeaderFont(FONT_DEFAULT);
+
+ d->SetColor(Dialog::COLOR_HEADER, Color::Black);
+ d->SetColor(Dialog::COLOR_LINES, Color::Black);
+
+ d->mSpaceAfterHeader = 30;
+ d->Resize(100, 100, 300, 250);
+
+ return d;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::LostFocus()
+{
+ SexyAppBase::LostFocus();
+
+ // When losing focus, we should pause the game board
+ if (mBoard)
+ mBoard->Pause(true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::GotFocus()
+{
+ SexyAppBase::GotFocus();
+
+ if (mBoard)
+ mBoard->Pause(false);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::ButtonPress(int theId)
+{
+ if (theId == OptionsDialog::MESSAGE_BOX_ID + 2000)
+ KillDialog(theId - 2000);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameApp::PlaySample(int theSoundNum)
+{
+ // If playing the sound for when a planet hits a wall, only let it
+ // play if it hasn't played the sound for at least 30 update frames
+ // (30 hundredths of a second).
+ if (theSoundNum == SOUND_PLANET_HIT)
+ {
+ if (mUpdateCount - mLastPlanetHitSoundTime > 30)
+ {
+ mLastPlanetHitSoundTime = mUpdateCount;
+ SexyAppBase::PlaySample(theSoundNum);
+ }
+ }
+ else
+ SexyAppBase::PlaySample(theSoundNum);
+}
diff --git a/osframework/source/demos/Hun-garr/GameApp.h b/osframework/source/demos/Hun-garr/GameApp.h
new file mode 100644
index 0000000..66676d3
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/GameApp.h
@@ -0,0 +1,171 @@
+#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.
+//
+// IMPORTANT: Comments for topics covered in the previous demos will
+// be kept to a minimum and removed in most cases. You should read through
+// the previous demos to familiarize yourself with anything you don't
+// understand. All functions, variables, and concepts are explained
+// either in this demo, or in previous ones if they've already been covered.
+//////////////////////////////////////////////////////////////////////////
+
+#include "SexyAppFramework/SexyAppBase.h"
+
+
+namespace Sexy
+{
+
+ class Board;
+ class TitleScreen;
+
+class GameApp : public SexyAppBase
+{
+
+ private:
+
+ Board* mBoard;
+ TitleScreen* mTitleScreen;
+
+ // Because it's annoying to hear the sound of the planets hitting a wall too many
+ // times in a second, we'll limit how many can occur.
+ int mLastPlanetHitSoundTime;
+
+ 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: NewDialog
+ // Parameters:
+ // theDialogId - Unique ID to give this dialog box
+ // isModal - If true, only itself and widgets above it receive
+ // input events.
+ // theDialogHeader - String to display in the header part of the dialog box
+ // theDialogLines - String to use for the body of the dialog. May use
+ // \n characters to indicate new lines.
+ // theDialogFooter - If the button mode is BUTTONS_FOOTER, this is the text
+ // to use for the button, otherwise ignored.
+ // theButtonMode - One of 3 settings: Dialog::BUTTONS_YES_NO creates two
+ // "Yes" "No" buttons, Dialog::BUTTONS_OK_CANCEL creates two
+ // "OK" "Cancel" buttons, Dialog::BUTTONS_FOOTER creates one
+ // button with the text from theDialogFooter.
+ //
+ // Returns: A new dialog pointer for use by SexyAppBase's DoDialog method.
+ //
+ // Purpose: SexyAppBase contains a convenience function, DoDialog, that relies on
+ // this overriden function. DoDialog calls NewDialog which instructs it how to make
+ // a dialog box. You should use DoDialog to create and add your dialog boxes.
+ // The reason for this function is to allow for customized dialog boxes and to avoid
+ // having to have a gigantic function with every possible parameter to pass to the Dialog's
+ // constructor.
+ //////////////////////////////////////////////////////////////////////////
+ virtual Dialog* NewDialog(int theDialogId, bool isModal, const std::string& theDialogHeader,
+ const std::string& theDialogLines, const std::string& theDialogFooter, int theButtonMode);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: LostFocus
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called when the game itself loses focus, such as the user switch
+ // to another application.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void LostFocus(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: GotFocus
+ // Parameters: none
+ // Returns: none
+ //
+ // Purpose: Called when the app regains focus after losing it.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void GotFocus(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ButtonPress:
+ // Parameters:
+ // theId - ID of the button pressed
+ //
+ // Returns: none
+ //
+ // Purpose: Called when the button is pressed, but before the mouse is
+ // released (which would instead generate a ButtonDepress event).
+ //////////////////////////////////////////////////////////////////////////
+ virtual void ButtonPress(int theId);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: PlaySample
+ // Parameters:
+ // theSoundNum - The sound ID to play
+ // Returns: none
+ //
+ // Purpose: Plays the sample at normal pitch with no panning.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void PlaySample(int theSoundNum);
+};
+
+}
+
+
+#endif // __GAMEAPP_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/GameOverEffect.cpp b/osframework/source/demos/Hun-garr/GameOverEffect.cpp
new file mode 100644
index 0000000..4845813
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/GameOverEffect.cpp
@@ -0,0 +1,452 @@
+#pragma warning(disable:4244)
+#pragma warning(disable:4018)
+
+#include "GameOverEffect.h"
+#include "Res.h"
+#include "Board.h"
+#include "SexyAppFramework/SexyAppBase.h"
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Font.h"
+#include "SexyAppFramework/Image.h"
+
+using namespace Sexy;
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+GameOverEffect::GameOverEffect()
+{
+ Init();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameOverEffect::Init()
+{
+ mState = GameOverEffect::RED_FADE_IN;
+ mAlpha = 0;
+ mRed = 200;
+ mRedHoldCount = 100;
+ mRedChange = 4;
+ mActive = false;
+ mUpdateCnt = 0;
+ mHue = 0;
+ mCanInitFirstLevel = false;
+ mFadeOut = false;
+ mExplosion.clear();
+
+ mText.clear();
+ mText.push_back(Letter(_S("G")));
+ mText.push_back(Letter(_S("A")));
+ mText.push_back(Letter(_S("M")));
+ mText.push_back(Letter(_S("E")));
+ mText.push_back(Letter(_S(" O")));
+ mText.push_back(Letter(_S("V")));
+ mText.push_back(Letter(_S("E")));
+ mText.push_back(Letter(_S("R")));
+
+ mLines.clear();
+
+ // Make as many lines as the screen is wide, and stagger them by a
+ // random time up to 2 seconds, with speeds between 5 and 10 pixels per update.
+ for (int i = 0; i < gSexyAppBase->mWidth; i++)
+ mLines.push_back(DrippyLine((Rand() % 5) + 5, i, Rand() % 200));
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameOverEffect::Update(void)
+{
+ ++mUpdateCnt;
+
+ // HSL is an alternative to specifying an RGB color format.
+ // Using HSL lets us easily do the hyper blinking crazy weird
+ // flashing effect commonly found in old games, such as Robotron.
+ // Below, we increment the value by 7 per update. The &0xFF is an
+ // easy way to clamp the value between 0 and 255 instead of having to
+ // do a separate if (mHue > 255) mHue -= 255. This lets the value
+ // rollover and keep cycling.
+ mHue = (mHue + 7) & 0xFF;
+
+ if (!mFadeOut)
+ {
+ // 10 times per second we create a new planet explosion animation and place it at a random
+ // position within the grid's area.
+ if (mUpdateCnt % 10 == 0)
+ {
+ Explosion e;
+ e.mFrame = 0;
+ e.mX = GRID_START_X + (Rand() % (GRID_END_X - GRID_START_X - IMAGE_ATOMIC_EXPLOSION->GetCelWidth()));
+ e.mY = GRID_START_Y + (Rand() % (GRID_END_Y - GRID_START_Y - IMAGE_ATOMIC_EXPLOSION->GetCelHeight()));
+
+ mExplosion.push_back(e);
+ }
+
+ // Play a sound of a planet exploding ever 4th new planet. If we did this every single
+ // planet, then 10 times per second you'd hear it, and trust me, it's really irritating.
+ if ((mState == RED_FADE_IN) || (mState == RED_HOLD))
+ if (mUpdateCnt % 40 == 0)
+ gSexyAppBase->PlaySample(SOUND_EXPLOSION);
+
+ // Update each explosion animation. When it's done, remove it.
+ for (int i = 0; i < mExplosion.size(); i++)
+ {
+ Explosion* e = &mExplosion[i];
+
+ // The animation runs at 20FPS, so every 5 updates step the frame.
+ if (mUpdateCnt % 5 == 0)
+ {
+ if (++e->mFrame >+ IMAGE_ATOMIC_EXPLOSION->GetCelWidth())
+ {
+ mExplosion.erase(mExplosion.begin() + i);
+ --i;
+ }
+ }
+ }
+ }
+
+ if (mState == GameOverEffect::RED_FADE_IN)
+ {
+ // Slowly make the red effect become fully opaque to cover
+ // the screen, while at the same time making the red value
+ // pulse between 200 and 255.
+ if (++mAlpha >= 255)
+ {
+ mState = GameOverEffect::RED_HOLD;
+ mAlpha = 255;
+ }
+ else
+ PulseRed();
+ }
+ else if (mState == GameOverEffect::RED_HOLD)
+ {
+ // Hold for 1 second, the red pulsing effect for dramatic fun
+ if (--mRedHoldCount <= 0)
+ {
+ mState = GameOverEffect::SHOWING_LETTERS;
+ mUpdateCnt = 0;
+ gSexyAppBase->PlaySample(SOUND_GAME_OVER_TEXT);
+ }
+ else
+ PulseRed();
+ }
+ else if (mState == GameOverEffect::SHOWING_LETTERS)
+ {
+ // Start showing the GAME OVER letters. Fade out that fully
+ // red screen, but still let it pulse while we do so.
+ if (mAlpha > 0)
+ {
+ PulseRed();
+ mAlpha -= 2;
+ }
+
+ // Increase the red value on each letter by 2 per update.
+ // Once one letter has a red value of 50, let the next letter
+ // after it begin to fade in. Stop looping if a letter has less
+ // than 50 for its red value.
+ bool done = true;
+ for (int i = 0; i < mText.size(); i++)
+ {
+ Letter* l = &mText[i];
+
+ if (l->mRed < 254)
+ {
+ done = false;
+ l->mRed += 2;
+ }
+
+ if (l->mRed < 50)
+ {
+ done = false;
+ break;
+ }
+ }
+
+ if (done)
+ mState = GameOverEffect::FADING_LETTERS;
+ }
+ else if (mState == GameOverEffect::FADING_LETTERS)
+ {
+ // Now make the lettesr fade out, starting with
+ // the last letter. When a letter's red value drops
+ // below 205, allow the letter before it to also begin
+ // decreasing.
+ bool done = true;
+ for (int i = (int)mText.size() - 1; i >= 0; i--)
+ {
+ Letter* l = &mText[i];
+
+ if (l->mRed > 1)
+ {
+ done = false;
+ l->mRed -= 2;
+ }
+
+ if (l->mRed > 205)
+ {
+ done = false;
+ break;
+ }
+ }
+
+ if (done)
+ {
+ mAlpha = 0;
+ mState = GameOverEffect::SHOWING_STATS;
+ gSexyAppBase->PlaySample(SOUND_GAME_OVER_STATS);
+ }
+
+ }
+ else if ((mState == GameOverEffect::DRIP_OUT) && !mFadeOut)
+ {
+ // move the drippy lines, but we aren't fading the screen out yet.
+ bool alldone = true;
+ for (int i = 0; i < mLines.size(); i++)
+ {
+ // Once a line's starting delay has passed, it moves downward.
+ // Once it reaches the bottom of the screen, it begins to then
+ // move back upward. When all lines have moved upward, and thus the
+ // whole screen is totally opaque, we can begin the fade out sequence.
+ DrippyLine* dl = &mLines[i];
+ if (dl->mDelay > 0)
+ {
+ alldone = false;
+ --dl->mDelay;
+ }
+ else if (!dl->mDripUp)
+ {
+ alldone = false;
+ dl->mHeight += dl->mSpeed;
+ if (dl->mHeight >= gSexyAppBase->mHeight)
+ {
+ dl->mHeight = 0;
+ dl->mSpeed = 10;
+ dl->mDripUp = true;
+ }
+ }
+ else if (dl->mDripUp && (dl->mHeight < gSexyAppBase->mHeight))
+ {
+ dl->mHeight += dl->mSpeed;
+ if (dl->mHeight >= gSexyAppBase->mHeight)
+ dl->mHeight = gSexyAppBase->mHeight;
+ else
+ alldone = false;
+ }
+
+ }
+
+ if (alldone)
+ {
+ // Now that the screen is fully covered, allow the board to set up the first level
+ mCanInitFirstLevel = true;
+ mFadeOut = true;
+ mAlpha = 255;
+ }
+ }
+ else if ((mState == GameOverEffect::DRIP_OUT) && mFadeOut)
+ {
+ if (--mAlpha <= 0)
+ mActive = false;
+ }
+}
+
+///
+//////////////////////////////////////////////////////////////////////////
+void GameOverEffect::PulseRed()
+{
+ mRed += mRedChange;
+ if (mRed >= 255)
+ {
+ mRed = 255;
+ mRedChange = -mRedChange;
+ }
+ else if (mRed <= 200)
+ {
+ mRed = 200;
+ mRedChange = -mRedChange;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameOverEffect::Draw(Graphics* g)
+{
+ // Draw explosions for every state except the final fade out
+ if (!mFadeOut)
+ {
+ for (int i = 0; i < mExplosion.size(); i++)
+ {
+ Explosion* e = &mExplosion[i];
+ g->DrawImageCel(IMAGE_ATOMIC_EXPLOSION, e->mX, e->mY, e->mFrame);
+ }
+ }
+
+ if ((mState == GameOverEffect::RED_FADE_IN) || (mState == GameOverEffect::RED_HOLD))
+ {
+ g->SetColor(Color(mRed, 0, 0, mAlpha));
+ g->FillRect(0, 0, gSexyAppBase->mWidth, gSexyAppBase->mHeight);
+ }
+ else if ((mState == GameOverEffect::SHOWING_LETTERS) || (mState == GameOverEffect::FADING_LETTERS))
+ {
+ g->SetFont(FONT_HUNGARR);
+ int x = gSexyAppBase->mWidth / 2 - FONT_HUNGARR->StringWidth(_S("GAME OVER")) / 2;
+ int y = gSexyAppBase->mHeight / 2;
+
+ for (int i = 0; i < mText.size(); i++)
+ {
+ Letter* l = &mText[i];
+ if (l->mRed > 0)
+ {
+ g->SetColor(Color(l->mRed, 0, 0));
+ g->DrawString(l->mChar, x, y);
+ x += FONT_HUNGARR->StringWidth(l->mChar);
+ }
+ }
+
+ if (mAlpha > 0)
+ {
+ g->SetColor(Color(mRed, 0, 0, mAlpha));
+ g->FillRect(0, 0, gSexyAppBase->mWidth, gSexyAppBase->mHeight);
+ }
+ }
+ else if (mState == GameOverEffect::SHOWING_STATS)
+ {
+ g->DrawImage(IMAGE_HUNGARR_LOGO, gSexyAppBase->mWidth / 2 - IMAGE_HUNGARR_LOGO->mWidth / 2, 10);
+
+ g->SetFont(FONT_HUNGARR);
+ g->SetColor(Color::White);
+ int rightX = gSexyAppBase->mWidth / 2;
+ int y = 100;
+ SexyString s;
+ int strWidth;
+
+ s = _S("FINAL SCORE: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(255, 0, 0));
+ g->DrawString(CommaSeperate(mStats.mScore), rightX, y);
+
+ g->SetColor(Color::White);
+ y += FONT_HUNGARR->GetHeight();
+ s = _S("LEVEL REACHED: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(255, 0, 0));
+ g->DrawString(StrFormat(_S("%d"), mStats.mLevel), rightX, y);
+
+ g->SetColor(Color::White);
+ y += FONT_HUNGARR->GetHeight();
+ s = _S("TOTAL PLANETS EATEN: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(255, 255, 0));
+ g->DrawString(StrFormat(_S("%d"), mStats.mNumPlanetsEaten), rightX, y);
+
+ g->SetColor(Color::White);
+ y += FONT_HUNGARR->GetHeight();
+ s = _S("TOTAL PEOPLE EATEN: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(255, 255, 0));
+ g->DrawString(CommaSeperate(mStats.mPopulationConsumed), rightX, y);
+
+ g->SetColor(Color::White);
+ y += FONT_HUNGARR->GetHeight();
+ s = _S("TASTIEST PLANET: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(0, 255, 0));
+ g->DrawString(mStats.mFavoritePlanet, rightX, y);
+
+
+ g->SetColor(Color::White);
+ y += FONT_HUNGARR->GetHeight();
+ s = _S("EXPORT EATEN MOST: ");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(0, 255, 0));
+ g->DrawString(mStats.mFavoriteExport, rightX, y);
+ }
+ else if (mState == GameOverEffect::DRIP_OUT)
+ {
+ if (!mFadeOut)
+ {
+ // This is how we convert an HSL value to an RGB value, which we have to
+ // do to specify the color for the graphics object. The function HSLToRGB
+ // takes as parameters: hue, saturation, luminance. We want to leave the
+ // saturation at max and luminance at half for our particular example.
+ // The returned value is ANDed with 0xFFFFFFFF to clamp the values for
+ // the alpha, red, green, and blue to the valid region of 0 to 255.
+ Color hue = gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFFFF;
+ for (int i = 0; i < mLines.size(); i++)
+ {
+ DrippyLine* dl = &mLines[i];
+ if (!dl->mDripUp && (dl->mDelay == 0))
+ {
+ // Draw a black line, with its bottommost pixel using the HSL color
+ g->SetColor(Color(0, 0, 0));
+ g->DrawRect(Rect(dl->mX, 0, 1, dl->mHeight - 1));
+ g->SetColor(hue);
+ g->DrawRect(Rect(dl->mX, dl->mHeight, 1, 1));
+ }
+ else if (dl->mDelay == 0)
+ {
+ // Moving up, draw the line in HSL and the rest in black
+ if (dl->mHeight < gSexyAppBase->mHeight)
+ {
+ g->SetColor(Color(0, 0, 0));
+ g->DrawRect(Rect(dl->mX, 0, 1, gSexyAppBase->mHeight - dl->mHeight));
+ }
+
+ g->SetColor(hue);
+ g->DrawRect(Rect(dl->mX, gSexyAppBase->mHeight - dl->mHeight, 1, dl->mHeight));
+ }
+ }
+ }
+ else
+ {
+ // We AND the color with 0xFFFFFF instead of 0xFFFFFFFF. Then, we OR it with the alpha value
+ // that we're fading out with shifted left 24 bits.
+ // This then sticks the alpha value, which changes over time,
+ // into our HSL color. As you may recall from previous demos, the actual color
+ // structure is 32 bit, and looks like this in binary form:
+ // AAAA RRRR GGGG BBBB Where A,R,G,B are alpha, red, green, blue.
+ Color hue = (gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFF) | (mAlpha << 24);
+ g->SetColor(hue);
+ g->FillRect(0, 0, gSexyAppBase->mWidth, gSexyAppBase->mHeight);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+bool GameOverEffect::CanInitFirstLevel(void)
+{
+ if (mCanInitFirstLevel)
+ {
+ mCanInitFirstLevel = false;
+ return true;
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+bool GameOverEffect::HideBoard()
+{
+ return (mState == GameOverEffect::SHOWING_LETTERS) ||
+ (mState == GameOverEffect::RED_HOLD) ||
+ (mState == GameOverEffect::FADING_LETTERS) ||
+ (mState == GameOverEffect::SHOWING_STATS) ||
+ ((mState == GameOverEffect::DRIP_OUT) && !mFadeOut);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void GameOverEffect::DoneViewingStats()
+{
+ mState = DRIP_OUT;
+ gSexyAppBase->PlaySample(SOUND_GAME_OVER_CLICK);
+ gSexyAppBase->PlaySample(SOUND_GAME_OVER_RESTART);
+} \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/GameOverEffect.h b/osframework/source/demos/Hun-garr/GameOverEffect.h
new file mode 100644
index 0000000..47431f5
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/GameOverEffect.h
@@ -0,0 +1,204 @@
+//////////////////////////////////////////////////////////////////////////
+// GameOverEffect.h
+//
+// Handles the entire sequence when the user dies.
+//////////////////////////////////////////////////////////////////////////
+#ifndef __GAME_OVER_EFFECT_H__
+#define __GAME_OVER_EFFECT_H__
+
+#include "SexyAppFramework/Common.h"
+
+namespace Sexy
+{
+
+ class Graphics;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Represents an exploding planet at a given XY, drawing the given
+ // frame number.
+ //////////////////////////////////////////////////////////////////////////
+ struct Explosion
+ {
+ int mX, mY;
+ int mFrame;
+ };
+
+ //////////////////////////////////////////////////////////////////////////
+ // Used to spell out "GAME OVER". Each letter, beginning with G,
+ // slowly goes from black to full red. Once all letters are spelled,
+ // the process reverses, making it fade back to black.
+ //////////////////////////////////////////////////////////////////////////
+ struct Letter
+ {
+ int mRed;
+ SexyString mChar;
+
+ Letter(SexyString c) {mChar = c; mRed = 0;}
+ };
+
+ //////////////////////////////////////////////////////////////////////////
+ // Stats that summarize the user's entire game.
+ //////////////////////////////////////////////////////////////////////////
+ struct EndGameStats
+ {
+ SexyString mFavoritePlanet; // We keep track of the planet
+ SexyString mFavoriteExport; // and export eaten most.
+ int mScore;
+ int mLevel;
+ int mNumPlanetsEaten;
+ int mPopulationConsumed;
+ };
+
+ //////////////////////////////////////////////////////////////////////////
+ // The transition to the start of the new game is done by these 1 pixel
+ // wide weird lines that drip from the top of the screen. Each line, as it
+ // drips, draws a black line but the bottommost pixel of the line blinks
+ // using our over-used HSL color effect (see LevelUpEffect for more HSL details).
+ // Once it hits the bottom, it drips upward, this time drawing the whole line
+ // with the HSL color, until the entire screen is flashing and pulsing crazily.
+ // The lines are delayed by a random time interval to make it look more ... drippy.
+ //////////////////////////////////////////////////////////////////////////
+ struct DrippyLine
+ {
+ int mSpeed; // Pixles per update the lines moves, < 0 for upward.
+ int mX;
+ int mDelay; // How long to wait before dripping down
+ int mHeight; // How far it has dripped so far
+ bool mDripUp; // Dripping upward or downward?
+
+ DrippyLine(float s, int x, int d)
+ {mSpeed = s; mX = x; mDelay = d; mHeight = 0; mDripUp = false;}
+ };
+
+class GameOverEffect
+{
+
+ private:
+
+ // The states used for this effect
+ enum
+ {
+ RED_FADE_IN, // The pulsating, red fade in that obscures the whole screen
+ RED_HOLD, // We hold the fully opaque, red screen for a short interval for dramatic effect
+ SHOWING_LETTERS, // Displaying the GAME OVER letters in dramatic style
+ FADING_LETTERS, // Making them fade out
+ SHOWING_STATS, // Displaying the user's game performance statistics
+ DRIP_OUT // Doing the weird drippy effect that takes the user to a new game.
+ };
+
+ // The whole time this effect is going on, we make these planet explosion animations trigger
+ // randomly around the screen, again for dramatic but fun uselessness.
+ std::vector<Explosion> mExplosion;
+ std::vector<Letter> mText; // The letters "GAME OVER"
+ std::vector<DrippyLine> mLines; // Each of the drippy lines
+ EndGameStats mStats;
+ int mState;
+ int mAlpha; // Used for fading the screen in/out
+ int mRed; // The red value during the RED_ states pulses between 200 and 255.
+ int mRedChange; // How fast (and which direction) the red pulsing is going
+ int mUpdateCnt; // Since this isn't a widget, we'll manually track the number of times the update method is called
+ int mHue; // For hue/saturation/luminence crazy weird flashing effect
+ int mRedHoldCount; // Counter for the RED_HOLD state, when it drops to 0 we switch to SHOWING_LETTERS
+ bool mFadeOut; // Indicates if the lines are done dripping and we're doing the final fade out
+ bool mActive; // Indicates if the game over sequence is running or not
+ bool mCanInitFirstLevel; // When true, indicates that the board should set up the first level so that it'll be there when we fade out
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Init
+ //
+ // Purpose: Sets up and initializes/resets all variables.
+ //////////////////////////////////////////////////////////////////////////
+ void Init();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: PulseRed
+ //
+ // Purpose: Convenience function that handles the pulsing of the red
+ // value between 200 and 255.
+ //////////////////////////////////////////////////////////////////////////
+ void PulseRed();
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // GameOverEffect
+ //////////////////////////////////////////////////////////////////////////
+ GameOverEffect();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Draw
+ //////////////////////////////////////////////////////////////////////////
+ void Draw(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Update
+ //////////////////////////////////////////////////////////////////////////
+ void Update(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: CanInitFirstLevel
+ // Returns: true or false, indicating if the first level can be setup for
+ // restarting.
+ //
+ // Purpose: Called by the Board's Update method, this returns true
+ // when the board should initialize the first level, so that when the
+ // game over effect fades out, the level will appear underneath it.
+ // When the function returns true, it automatically sets internal variables
+ // so that the next time the function is called, it will return false,
+ // preventing the Board from accidentally initializing the first level
+ // multiple times. After the next call to Activate, it is allowed to
+ // return true again.
+ //
+ // Once the screen is totally filled after closing the stats display,
+ // the Board is allowed to init the first level.
+ //////////////////////////////////////////////////////////////////////////
+ bool CanInitFirstLevel(void);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: CanStartNewGame
+ //
+ // Purpose: Returns true or false indicating if the user is allowed
+ // to click to start a new game. This can only happen when the user
+ // is viewing the stats and all other states have completed.
+ // This will trigger the effects that transition to the start of a
+ // new game.
+ //////////////////////////////////////////////////////////////////////////
+ bool CanStartNewGame() {return mState == SHOWING_STATS;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: HideBoard
+ // Returns: true or false indicating whether or not the board should
+ // hide all of its display stuff, except for the starfield which always
+ // displays.
+ //////////////////////////////////////////////////////////////////////////
+ bool HideBoard();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: IsActive
+ // Returns: true or false indicating if the sequence is running or not
+ //////////////////////////////////////////////////////////////////////////
+ bool IsActive() {return mActive;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Activate
+ // Parameters:
+ // ls - A stat structure containing the info for the past level
+ //
+ // Purpose: Begins the game over sequence
+ //////////////////////////////////////////////////////////////////////////
+ void Activate(EndGameStats es) {Init(); mActive = true; mStats = es;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DoneViewingStats
+ //
+ // Purpose: Called by Board when the user clicks the mouse button,
+ // indicating that they want the stats screen to go away and have the
+ // game restart.
+ //////////////////////////////////////////////////////////////////////////
+ void DoneViewingStats();
+};
+
+
+}
+
+#endif // __GAME_OVER_EFFECT_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/Hun-garr VS2005 WideString.vcproj b/osframework/source/demos/Hun-garr/Hun-garr VS2005 WideString.vcproj
new file mode 100644
index 0000000..a4403b1
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Hun-garr VS2005 WideString.vcproj
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Hun-garr"
+ ProjectGUID="{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+ 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)/../../Hun-garr.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Hun-garr.pdb"
+ GenerateMapFile="true"
+ MapFileName="Hun-garr.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"
+ 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)/../../Hun-garr.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="GameOverEffect.cpp"
+ >
+ </File>
+ <File
+ RelativePath="LevelupEffect.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="OptionsDialog.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="GameOverEffect.h"
+ >
+ </File>
+ <File
+ RelativePath="LevelupEffect.h"
+ >
+ </File>
+ <File
+ RelativePath="OptionsDialog.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/Hun-garr/Hun-garr VS2005.vcproj b/osframework/source/demos/Hun-garr/Hun-garr VS2005.vcproj
new file mode 100644
index 0000000..133c302
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Hun-garr VS2005.vcproj
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Hun-garr"
+ ProjectGUID="{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+ 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)/../../Hun-garr.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/Hun-garr.pdb"
+ GenerateMapFile="true"
+ MapFileName="Hun-garr.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"
+ 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)/../../Hun-garr.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="GameOverEffect.cpp"
+ >
+ </File>
+ <File
+ RelativePath="LevelupEffect.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="OptionsDialog.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="GameOverEffect.h"
+ >
+ </File>
+ <File
+ RelativePath="LevelupEffect.h"
+ >
+ </File>
+ <File
+ RelativePath="OptionsDialog.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/Hun-garr/Hun-garr WideString.vcproj b/osframework/source/demos/Hun-garr/Hun-garr WideString.vcproj
new file mode 100644
index 0000000..b35508f
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Hun-garr WideString.vcproj
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Hun-garr"
+ ProjectGUID="{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+ 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)/../../Hun-garr.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Hun-garr.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Hun-garr.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"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ 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)/../../Hun-garr.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="GameOverEffect.cpp">
+ </File>
+ <File
+ RelativePath="LevelupEffect.cpp">
+ </File>
+ <File
+ RelativePath="OptionsDialog.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="GameOverEffect.h">
+ </File>
+ <File
+ RelativePath="LevelupEffect.h">
+ </File>
+ <File
+ RelativePath="OptionsDialog.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/Hun-garr/Hun-garr.vcproj b/osframework/source/demos/Hun-garr/Hun-garr.vcproj
new file mode 100644
index 0000000..d3ce2d8
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Hun-garr.vcproj
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Hun-garr"
+ ProjectGUID="{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+ 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)/../../Hun-garr.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/Hun-garr.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="Hun-garr.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"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="..;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ 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)/../../Hun-garr.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="GameOverEffect.cpp">
+ </File>
+ <File
+ RelativePath="LevelupEffect.cpp">
+ </File>
+ <File
+ RelativePath="OptionsDialog.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="GameOverEffect.h">
+ </File>
+ <File
+ RelativePath="LevelupEffect.h">
+ </File>
+ <File
+ RelativePath="OptionsDialog.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/Hun-garr/Hungarr.dsp b/osframework/source/demos/Hun-garr/Hungarr.dsp
new file mode 100644
index 0000000..69b60c8
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/Hungarr.dsp
@@ -0,0 +1,166 @@
+# Microsoft Developer Studio Project File - Name="Hungarr" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=Hungarr - 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 "Hungarr.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 "Hungarr.mak" CFG="Hungarr - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Hungarr - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "Hungarr - 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)" == "Hungarr - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Hungarr___Win32_Release"
+# PROP BASE Intermediate_Dir "Hungarr___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 /FD /c
+# SUBTRACT CPP /YX
+# 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:"..\Hun-garr.exe"
+
+!ELSEIF "$(CFG)" == "Hungarr - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Hungarr___Win32_Debug"
+# PROP BASE Intermediate_Dir "Hungarr___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:"..\Hun-garr_debug.exe" /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "Hungarr - Win32 Release"
+# Name "Hungarr - 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=.\GameOverEffect.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LevelupEffect.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.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=.\GameOverEffect.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LevelupEffect.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Res.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/Hun-garr/LevelupEffect.cpp b/osframework/source/demos/Hun-garr/LevelupEffect.cpp
new file mode 100644
index 0000000..7c728a0
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/LevelupEffect.cpp
@@ -0,0 +1,438 @@
+#pragma warning(disable:4244)
+#pragma warning(disable:4018)
+
+
+#include "LevelupEffect.h"
+#include "Board.h"
+#include "Res.h"
+#include "SexyAppFramework/SexyAppBase.h"
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Font.h"
+
+using namespace Sexy;
+
+const int STRIP_WIDTH = 20;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+LevelupEffect::LevelupEffect()
+{
+ Init();
+ mActive = false;
+ mCoverWidth = 0;
+ mStripSizeChange = 60;
+ mStripHeight = 0;
+ mFadeOutAlpha = 255;
+ mStartNextLevel = false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void LevelupEffect::Init()
+{
+ mText.clear();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Each letter, starting with the 'L' in "LEVEL UP!", will drop, delayed
+ // by a height of FONT_HUNGARR->GetHeight() pixels. Each letter will initially
+ // drop at a rate of 5 pixels per update (500 pixels per second). Once they
+ // reach their target Y coordinate (300), the speed will decrease and reverse
+ // to make the letters bounce upward. Gravity is applied each frame, so eventually
+ // the letters return back to Y of 300, where the speed is again decreased and
+ // reversed until it drops below the threshhold speed of 0.1 pixels per update.
+ //////////////////////////////////////////////////////////////////////////
+
+ float x = (GRID_END_X - GRID_START_X) / 2 - FONT_HUNGARR->StringWidth(_S("LEVEL UP!")) / 2;
+ float y = FONT_HUNGARR->GetHeight();
+ float startingY = y;
+ float ydec = y;
+ float speed = 5.0f;
+
+ mText.push_back(BouncyChar(_S("L"), x, y, speed));
+
+ x += FONT_HUNGARR->StringWidth(_S("L"));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("E"), x, y, speed));
+
+ x += FONT_HUNGARR->StringWidth(_S("E"));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("V"), x, y, speed));
+
+ x += FONT_HUNGARR->StringWidth(_S("V"));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("E"), x, y, speed));
+
+ x += FONT_HUNGARR->StringWidth(_S("E"));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("L"), x, y, speed));
+
+
+
+ x += FONT_HUNGARR->StringWidth(_S("L "));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("U"), x, y, speed));
+
+ x += FONT_HUNGARR->StringWidth(_S("U"));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("P"), x, y, speed));
+
+ x += FONT_HUNGARR->StringWidth(_S("P"));
+ y -= ydec;
+ mText.push_back(BouncyChar(_S("!"), x, y, speed));
+
+ mDone = false;
+ mHue = 0;
+ mCurtainX = 0;
+ mState = LevelupEffect::LEVELUP_TEXT;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void LevelupEffect::Activate(LevelupStats ls)
+{
+ Init();
+ mActive = true;
+ mStats = ls;
+
+ gSexyAppBase->PlaySample(SOUND_LEVEL_UP1);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void LevelupEffect::Update(float theFrac)
+{
+
+ // HSL is an alternative to specifying an RGB color format.
+ // Using HSL lets us easily do the hyper blinking crazy weird
+ // flashing effect commonly found in old games, such as Robotron.
+ // Below, we increment the value by 7 per update. The &0xFF is an
+ // easy way to clamp the value between 0 and 255 instead of having to
+ // do a separate if (mHue > 255) mHue -= 255. This lets the value
+ // rollover and keep cycling.
+ mHue = (mHue + 7) & 0xFF;
+
+ if (mState == LevelupEffect::LEVELUP_TEXT)
+ {
+ // Move all the letters, applying 0.15 pixels per update of
+ // "gravity" to pull the letters down. Once reaching Y of 300,
+ // the speed of the letters decreases by 0.75 and is reversed, making
+ // them "bounce" in the up direction. Once this bounce speed drops below 0.1
+ // pixels per update, the letter is done bouncing. When all letters are done bouncing,
+ // switch to the next state.
+ bool allDone = true;
+ for (int i = 0; i < mText.size(); i++)
+ {
+ BouncyChar* c = &mText[i];
+
+ if (c->mDone)
+ continue;
+
+ c->mY += c->mBounceSpeed;
+
+ c->mBounceSpeed += 0.15f;
+
+ if (c->mY >= 300)
+ {
+ c->mY = 300;
+
+ c->mOldBounceSpeed -= 0.750f;
+ if (c->mOldBounceSpeed <= 0.1f)
+ {
+ c->mDone = true;
+ c->mOldBounceSpeed = 0;
+ }
+ else
+ {
+ allDone = false;
+ c->mBounceSpeed = -c->mOldBounceSpeed;
+ }
+ }
+ else
+ allDone = false;
+ }
+
+ if (allDone)
+ mState = LevelupEffect::CURTAIN_IN;
+ }
+ else if (mState == LevelupEffect::CURTAIN_IN)
+ {
+ // Moves the black rectangles ("curtains") inward to cover up the
+ // previous level. We only move the left one. The right one is logically
+ // just the same width but starting from the right of the screen instead
+ // of the left. The curtain moves 25 pixels per update. Once it reaches
+ // the center (and thus fully covers the screen), we switch to the next state.
+ if ((mCurtainX += 25) >= gSexyAppBase->mWidth / 2)
+ {
+ mCurtainX = gSexyAppBase->mWidth / 2;
+ mState = LevelupEffect::CURTAIN_OUT;
+ gSexyAppBase->PlaySample(SOUND_LEVEL_UP2);
+ }
+ }
+ else if (mState == LevelupEffect::CURTAIN_OUT)
+ {
+ // Now the curtain is red and slowly moves back out to reveal the
+ // stats below it. This works just like above.
+ if ((mCurtainX -= 2) <= 0)
+ mState = LevelupEffect::SHOWING_STATS;
+ }
+ else if (mState == LevelupEffect::COVERING_STATS)
+ {
+ // This state begins when the user clicks the mouse to dismiss the
+ // stats screen. We then make these strips quickly appear. Imagine
+ // rectangles of width 20 coming in from the left and right of the screen.
+ // The left one starts comign from the top left of the screen, the right
+ // from the bottom right. These strips quickly expand to be screen height in size
+ // and then move closer inward (by their width of 20) and reverse the direction
+ // that they come in at. Once the strips have traveled to the center of the screen,
+ // it's fully covered and we then move to the next state. After a strip becomes
+ // the height of the screen, we update mCoverWidth, which is just simply the width
+ // of the region fully filled in. Again, like with the curtain effects, we only
+ // keep track of the left side, since the right moves the same amount and it's
+ // easy to compute the right's offsets.
+ if (mStripSizeChange > 0)
+ {
+ // Left strip is moving downward from Y of 0, right is moving up
+ // from Y of app height
+ if ((mStripHeight += mStripSizeChange) >= gSexyAppBase->mHeight)
+ {
+ // Left strip and right strip are now the height of the screen.
+ // Reverse the direction they come in at and reset their heights.
+ // Then, increment the width of the fully covered region by the
+ // size of one of the strip's width.
+ mStripSizeChange = -mStripSizeChange;
+ mStripHeight = 0;
+ if ((mCoverWidth += STRIP_WIDTH) >= gSexyAppBase->mWidth / 2)
+ {
+ // The screen is fully covered. Fade out.
+ mStartNextLevel = true;
+ mState = LevelupEffect::FADE_OUT_STATS;
+ }
+ }
+ }
+ else
+ {
+ if ((mStripHeight -= mStripSizeChange) >= gSexyAppBase->mHeight)
+ {
+ mStripSizeChange = -mStripSizeChange;
+ mStripHeight = 0;
+ if ((mCoverWidth += STRIP_WIDTH) >= gSexyAppBase->mWidth / 2)
+ {
+ mStartNextLevel = true;
+ mState = LevelupEffect::FADE_OUT_STATS;
+ }
+ }
+ }
+ }
+ else if (mState == LevelupEffect::FADE_OUT_STATS)
+ {
+ //Fade the screen out, with the next level appearing below it.
+ if ((mFadeOutAlpha -= 2) <= 0)
+ {
+ mDone = true;
+ mActive = false;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void LevelupEffect::Draw(Graphics* g)
+{
+ g->SetFont(FONT_HUNGARR);
+ if (mState == LevelupEffect::LEVELUP_TEXT)
+ {
+ // This is how we convert an HSL value to an RGB value, which we have to
+ // do to specify the color for the graphics object. The function HSLToRGB
+ // takes as parameters: hue, saturation, luminance. We want to leave the
+ // saturation at max and luminance at half for our particular example.
+ // The returned value is ANDed with 0xFFFFFFFF to clamp the values for
+ // the alpha, red, green, and blue to the valid region of 0 to 255.
+ g->SetColor( (gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFFFF) );
+ for (int i = 0; i < mText.size(); i++)
+ {
+ BouncyChar* c = &mText[i];
+ g->DrawString(c->mChar, c->mX, c->mY);
+ }
+ }
+ else if (mState == LevelupEffect::CURTAIN_IN)
+ {
+ // The righ tcurtain is just the same width as the left, but starts from the right
+ // side instead of X of 0.
+ g->SetColor(Color(0, 0, 0));
+ g->FillRect(0, 0, mCurtainX, gSexyAppBase->mHeight);
+ g->FillRect(gSexyAppBase->mWidth - mCurtainX, 0, mCurtainX, gSexyAppBase->mHeight);
+ }
+ else if ((mState == LevelupEffect::SHOWING_STATS) || (mState == LevelupEffect::CURTAIN_OUT) ||
+ (mState == LevelupEffect::COVERING_STATS))
+ {
+ // When just showing the stats normally, fading out the red curtain (to reveal the stats
+ // beneath it), or covering up the stats with the effect triggered when the user clicks
+ // to begin the next level, we display info on the user's performance from the last level.
+ int y = 50;
+ g->SetColor(gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFFFF);
+ SexyString s = StrFormat(_S("LEVEL %d COMPLETE!"), mStats.mLevelCompleted);
+ g->DrawString(s, gSexyAppBase->mWidth / 2 - FONT_HUNGARR->StringWidth(s) / 2, y);
+
+ g->SetColor(Color::White);
+ s = _S("POPULATION CONSUMED:");
+ int strWidth = FONT_HUNGARR->StringWidth(s);
+
+ int rightX = strWidth + 100;
+ y += 50;
+ g->DrawString(s, 100, y);
+ g->SetColor(Color(255, 0, 0));
+ g->DrawString(CommaSeperate(mStats.mPopulationEaten), rightX + 5, y);
+
+ y += FONT_HUNGARR->GetHeight();
+ g->SetColor(Color::White);
+ s = _S("SYSTEMS SUBJUGATED:");
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(255, 0, 0));
+ g->DrawString(StrFormat(_S("%d%%"), mStats.mPercentComplete), rightX + 5, y);
+
+ y += FONT_HUNGARR->GetHeight();
+ if (mStats.mPercentComplete >= COMPLETION_BONUS_PCT)
+ {
+ s = StrFormat(_S("%d%%+ BONUS:"), COMPLETION_BONUS_PCT);
+ g->SetColor(Color::White);
+ strWidth = FONT_HUNGARR->StringWidth(s);
+ g->DrawString(s, rightX - strWidth, y);
+ g->SetColor(Color(255, 0, 0));
+ g->DrawString(StrFormat(_S("%d"), COMPLETION_BONUS * mStats.mLevelCompleted),
+ rightX + 5, y);
+ }
+
+ if (mStats.mPlanetsEaten.size() > 0)
+ {
+ y += 50;
+ int third = gSexyAppBase->mWidth / 3;
+ g->SetColor(Color(255, 255, 0));
+
+ s = _S("PLANET EATEN:");
+ g->DrawString(s, third / 2 - FONT_HUNGARR->StringWidth(s) / 2, y);
+ s = _S("EXPORTS:");
+ g->DrawString(s, third + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
+ s = _S("POPULATION:");
+ g->DrawString(s, third*2 + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
+
+ y += FONT_HUNGARR->GetHeight();
+
+ // If the user ate too many planets to fit on screen, we'll just display "..."
+ // to indicate that they ate a bunch but we just can't fit it all on screen.
+ // In reality, it'd be best to either ensure that all the planets fit on screen,
+ // or that there's some sort of scrolling mechanism to allow the user to view all their
+ // stats.
+ bool drawDotDotDot = false;
+ for (int i = 0; i < mStats.mPlanetsEaten.size(); i += 3)
+ {
+ if (y >= gSexyAppBase->mHeight - FONT_HUNGARR->GetHeight() * 2)
+ {
+ drawDotDotDot = true;
+ break;
+ }
+
+ g->SetColor(Color(255, 255, 255));
+ s = mStats.mPlanetsEaten[i];
+ g->DrawString(s, third / 2 - FONT_HUNGARR->StringWidth(s) / 2, y);
+
+ g->SetColor(Color(128, 255, 0));
+ s = mStats.mPlanetsEaten[i+1];
+ g->DrawString(s, third + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
+
+ g->SetColor(Color(255, 128, 0));
+ s = mStats.mPlanetsEaten[i+2];
+ g->DrawString(s, third*2 + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
+
+ y += FONT_HUNGARR->GetHeight();
+
+ }
+
+ if (drawDotDotDot)
+ {
+ g->SetColor(Color::White);
+ g->DrawString(_S("..."), 5, y);
+ }
+ }
+
+ g->SetColor(Color::White);
+ s = _S("CLICK TO CONTINUE");
+ g->DrawString(s, gSexyAppBase->mWidth / 2 - FONT_HUNGARR->StringWidth(s) / 2, gSexyAppBase->mHeight - 20);
+ }
+
+ if (mState == LevelupEffect::CURTAIN_OUT)
+ {
+ // Draw a red curtain, whose alpha decreases as it withdrawls more.
+ // This lets the stats display underneath the curtain while it moves.
+ int alpha = mCurtainX > 255 ? 255 : mCurtainX;
+ g->SetColor(Color(255, 0, 0, alpha));
+ g->FillRect(0, 0, mCurtainX, gSexyAppBase->mHeight);
+ g->FillRect(gSexyAppBase->mWidth - mCurtainX, 0, mCurtainX, gSexyAppBase->mHeight);
+ }
+
+ if ((mState == LevelupEffect::COVERING_STATS) || (mState == LevelupEffect::FADE_OUT_STATS))
+ {
+ // Both the states where we cover up the stats and fade them out are controlled here,
+ // since they are functionally the same. Again, with the HSL we do the usual HSLToRGB
+ // stuff. However, since the FADE_OUT_STATS state actually fades out the screen and
+ // has an alpha value that decreases over time (mFadeOutAlpha), instead of always
+ // setting the alpha to 255, we need to set the alpha to mFadeOutAlpha. To do this,
+ // we AND with 0xFFFFFF instead of 0xFFFFFFFF. Then, we OR it with the alpha value
+ // shifted left 24 bits. This then sticks the alpha value, which changes over time,
+ // into our HSL color. As you may recall from previous demos, the actual color
+ // structure is 32 bit, and looks like this in binary form:
+ // AAAA RRRR GGGG BBBB Where A,R,G,B are alpha, red, green, blue.
+ //
+ // We draw the totally filled in regions separately, since they're easy.
+ // The strips then are drawn differently depending on if they are moving up or down.
+ // The left and right ones move oppositely.
+ g->SetColor( (gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFF) | (mFadeOutAlpha << 24) );
+ g->FillRect(0, 0, mCoverWidth, gSexyAppBase->mHeight);
+ g->FillRect(gSexyAppBase->mWidth - mCoverWidth, 0, mCoverWidth, gSexyAppBase->mHeight);
+
+ if (mStripSizeChange > 0)
+ {
+ g->FillRect(mCoverWidth, 0, STRIP_WIDTH, mStripHeight);
+ g->FillRect(gSexyAppBase->mWidth - mCoverWidth - STRIP_WIDTH,
+ gSexyAppBase->mHeight - mStripHeight,
+ STRIP_WIDTH,
+ mStripHeight);
+ }
+ else
+ {
+ g->FillRect(mCoverWidth, gSexyAppBase->mHeight - mStripHeight, STRIP_WIDTH, mStripHeight);
+ g->FillRect(gSexyAppBase->mWidth - mCoverWidth - STRIP_WIDTH, 0, STRIP_WIDTH, mStripHeight);
+ }
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void LevelupEffect::DoneViewingStats()
+{
+ // The user clicked to dismiss the stats screen. Cover it up
+ // and begin the transition to the next level.
+ mState = LevelupEffect::COVERING_STATS;
+ mCoverWidth = 0;
+ mStripSizeChange = 90;
+ mStripHeight = 0;
+ mFadeOutAlpha = 255;
+ mStartNextLevel = false;
+ gSexyAppBase->PlaySample(SOUND_LEVEL_UP3);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+bool LevelupEffect::StartNextLevel()
+{
+ // See function header for a complete description
+ if (mStartNextLevel)
+ {
+ mStartNextLevel = false;
+ gSexyAppBase->PlaySample(SOUND_LEVEL_UP4);
+ return true;
+ }
+
+ return false;
+} \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/LevelupEffect.h b/osframework/source/demos/Hun-garr/LevelupEffect.h
new file mode 100644
index 0000000..390dc0b
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/LevelupEffect.h
@@ -0,0 +1,191 @@
+//////////////////////////////////////////////////////////////////////////
+// LevelupEffect.h
+//
+// Does the level up effect, from the bouncing "LEVEL UP!" text to
+// the stats display and weird transition effects.
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef __LEVELUP_EFFECT_H__
+#define __LEVELUP_EFFECT_H__
+
+#include "SexyAppFramework/Common.h"
+#include "SexyAppFramework/Rect.h"
+
+namespace Sexy
+{
+
+ class Graphics;
+
+
+//////////////////////////////////////////////////////////////////////////
+// Represents a letter that bounces, used for the "LEVEL UP!" text.
+//////////////////////////////////////////////////////////////////////////
+struct BouncyChar
+{
+ SexyString mChar; // The character bouncing
+ bool mDone; // Completed bouncing yet?
+ float mX, mY;
+ float mBounceSpeed; // How fast up or down it's bouncing, affected by "gravity"
+ float mOldBounceSpeed; // The base value that mBounceSpeed started at. Gets reduced over time.
+
+ BouncyChar(SexyString t, float x, float y, float s)
+ {mChar = t; mX = x; mY = y; mBounceSpeed = mOldBounceSpeed = s; mDone = false;}
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Contains stat info to display after completing a level.
+//////////////////////////////////////////////////////////////////////////
+struct LevelupStats
+{
+ int mPopulationEaten;
+ int mPercentComplete;
+ int mLevelCompleted;
+
+ // Always 3 strings per planet:
+ // Planet name, exports, population (comma delimited)
+ std::vector<SexyString> mPlanetsEaten;
+
+};
+
+class LevelupEffect
+{
+
+ private:
+
+ // States that the level up effect goes through
+ enum
+ {
+ LEVELUP_TEXT, // Displaying the bouncy LEVEL UP! text
+ CURTAIN_IN, // Moving the black "curtain" inward to cover up the level
+ CURTAIN_OUT, // Moving the red "curtain" out after above to reveal the stats
+ SHOWING_STATS, // Displaying level stats
+ COVERING_STATS, // Doing the weird transitionary cover-up screen after clicking to continue
+ FADE_OUT_STATS // Fading out the above screen
+ };
+
+ std::vector<BouncyChar> mText; // The letters that spell LEVEL UP!, as BouncyChar structures
+ LevelupStats mStats; // Stat info to display
+ bool mActive; // If true, means we're doing the level up sequence
+ bool mDone; // If done, means all finished and the next level can actually begin
+ bool mStartNextLevel; // When true, indicates that the board should set up the next level so that it'll be there when we fade out
+
+ int mHue; // For hue/saturation/luminence crazy weird flashing effect
+ int mCurtainX; // X location of the black/red curtain edge (for the left curtain, the right is the same size)
+ int mState; // One of the above nums
+
+ // When doing the COVERING_STATS phase, this is how wide 1/2 of the filled in part of the screen is. The other half
+ // is the same size.
+ int mCoverWidth;
+ int mStripHeight; // For the above, we make strips quickly appear, alternating up/down filling
+
+ // Indicates whether the strips are increasing Y (so strip comes from top) or decreasing
+ // (so strip comes from bottom)
+ int mStripSizeChange;
+ int mFadeOutAlpha; // Alpha amount for the final fade out effect
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Init
+ //
+ // Purpose: Sets up and initializes/resets all variables.
+ //////////////////////////////////////////////////////////////////////////
+ void Init();
+
+ public:
+
+ LevelupEffect();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Update
+ // Parameters:
+ // theFrac - Value from Board::UpdateF, used for smooth motion
+ //
+ //////////////////////////////////////////////////////////////////////////
+ void Update(float theFrac);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Draw
+ //////////////////////////////////////////////////////////////////////////
+ void Draw(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: Activate
+ // Parameters:
+ // ls - A stat structure containing the info for the past level
+ //
+ // Purpose: Begins the level up sequence
+ //////////////////////////////////////////////////////////////////////////
+ void Activate(LevelupStats ls);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DoneViewingStats
+ //
+ // Purpose: Called by Board when the user clicks the mouse button,
+ // indicating that they want the stats screen to go away and have the
+ // next level begin.
+ //////////////////////////////////////////////////////////////////////////
+ void DoneViewingStats();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: StartNextLevel
+ // Returns: true or false, indicating if the next level can be started.
+ //
+ // Purpose: Called by the Board's Update method, this returns true
+ // when the board should initialize the next level, so that when the
+ // level up effect fades out, the next level will appear underneath it.
+ // When the function returns true, it automatically sets internal variables
+ // so that the next time the function is called, it will return false,
+ // preventing the Board from accidentally initializing the same level
+ // multiple times. After the next call to Activate, it is allowed to
+ // return true again.
+ //
+ // Once the screen is totally filled after closing the stats display,
+ // the Board is allowed to init the next level.
+ //////////////////////////////////////////////////////////////////////////
+ bool StartNextLevel();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: IsDone
+ // Returns: true or false indicating if the entire sequence is done
+ //
+ // Purpose: Used to let the board know when playing of the next level
+ // can begin.
+ //////////////////////////////////////////////////////////////////////////
+ bool IsDone() {return mDone;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: IsActive
+ // Returns: true or false indicating if the sequence is running or not
+ //////////////////////////////////////////////////////////////////////////
+ bool IsActive() {return mActive;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ShowingStats
+ // Returns: true or false indicating if the stats display is visible
+ //////////////////////////////////////////////////////////////////////////
+ bool ShowingStats() {return mState == SHOWING_STATS;}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: HideBoard
+ // Returns: true or false indicating whether or not the board should
+ // hide all of its display stuff, except for the starfield which always
+ // displays.
+ //////////////////////////////////////////////////////////////////////////
+ bool HideBoard() {return (mState == SHOWING_STATS) || (mState == CURTAIN_OUT) || (mState == COVERING_STATS);}
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: HidePlanets
+ // Returns: true or false indicating if just the planets should be
+ // hidden.
+ //
+ // Purpose: Used to hide the planets but still allow the rest of the
+ // game board to display. Used during the transtion to the stats
+ // display screen.
+ //////////////////////////////////////////////////////////////////////////
+ bool HidePlanets() {return IsActive() && (HideBoard() || (mState == LEVELUP_TEXT) || (mState == CURTAIN_IN));}
+};
+
+
+}
+
+#endif //__LEVELUP_EFFECT_H__ \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/OptionsDialog.cpp b/osframework/source/demos/Hun-garr/OptionsDialog.cpp
new file mode 100644
index 0000000..e5de450
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/OptionsDialog.cpp
@@ -0,0 +1,273 @@
+#include "OptionsDialog.h"
+#include "Res.h"
+#include "Board.h"
+#include "SexyAppFramework/SexyAppBase.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/Font.h"
+#include "SexyAppFramework/DialogButton.h"
+#include "SexyAppFramework/Checkbox.h"
+#include "SexyAppFramework/Slider.h"
+
+using namespace Sexy;
+
+
+OptionsDialog::OptionsDialog(Board* b) :
+Dialog(IMAGE_DIALOG_BOX, IMAGE_DIALOG_BUTTON, OptionsDialog::DIALOG_ID, true, _S("OPTIONS"), _S(""), _S("CLOSE"), Dialog::BUTTONS_FOOTER)
+{
+ mContentInsets = Insets(23, 20, 23, 20);
+ mSpaceAfterHeader = 30;
+
+ mBoard = b;
+
+ SetHeaderFont(FONT_DEFAULT);
+ SetLinesFont(FONT_DEFAULT);
+ SetButtonFont(FONT_DEFAULT);
+
+ SetColor(COLOR_HEADER, Color::Black);
+ SetColor(COLOR_LINES, Color::Black);
+
+ mMusicVolumeSlider = new Slider(IMAGE_SLIDER_TRACK, IMAGE_SLIDER_THUMB, OptionsDialog::MUSIC_SLIDER_ID, this);
+ mMusicVolumeSlider->SetValue(gSexyAppBase->GetMusicVolume());
+
+ mSfxVolumeSlider = new Slider(IMAGE_SLIDER_TRACK, IMAGE_SLIDER_THUMB, OptionsDialog::SFX_SLIDER_ID, this);
+ mSfxVolumeSlider->SetValue(gSexyAppBase->GetSfxVolume());
+
+ mQuitBtn = new DialogButton(IMAGE_DIALOG_BUTTON, OptionsDialog::QUIT_BTN_ID, this);
+ mQuitBtn->mLabel = _S("QUIT GAME");
+ mQuitBtn->SetFont(FONT_DEFAULT);
+
+ m3DCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, OptionsDialog::HARDWARE_CHECKBOX_ID, this);
+ mFSCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, OptionsDialog::FS_CHECKBOX_ID, this);
+ mCustomCursorsCheckbox = new Checkbox(IMAGE_CHECKBOX, IMAGE_CHECKBOX, OptionsDialog::FS_CHECKBOX_ID, this);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+OptionsDialog::~OptionsDialog()
+{
+ delete mMusicVolumeSlider;
+ delete mSfxVolumeSlider;
+ delete mQuitBtn;
+ delete mCustomCursorsCheckbox;
+ delete m3DCheckbox;
+ delete mFSCheckbox;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::Draw(Graphics* g)
+{
+ Dialog::Draw(g);
+
+ // Let's draw some labels for the sliders
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color::Black);
+
+ // We draw the X/Y at the slider's X/Y but we subtract off the dialog box's
+ // X/Y's from that. Why? The slider's XY's are in absolute screen coordinates,
+ // as are the dialog boxes. But as you may recall from Board::Draw(), where
+ // we explain graphics translation, once we get inside the draw loop of a
+ // widget, the graphics object is already moved (translated) to the widget's
+ // coordinates. Thus, in using the Graphics object, g, (0, 0) is located
+ // at the top left corner of the widget (our dialog box). So we
+ // just take the difference between the widget locations to produce the
+ // actual location we want to drawour text at:
+ g->DrawString(_S("Music volume:"), mMusicVolumeSlider->mX - mX,
+ mMusicVolumeSlider->mY - mY - mMusicVolumeSlider->mHeight);
+
+ g->DrawString(_S("Sound volume:"), mSfxVolumeSlider->mX - mX,
+ mSfxVolumeSlider->mY - mY - mSfxVolumeSlider->mHeight);
+
+ // Do the same for the checkboxes:
+ g->DrawString(_S("3D Mode:"), m3DCheckbox->mX - mX - 25, m3DCheckbox->mY - mY - m3DCheckbox->mHeight + 20);
+ g->DrawString(_S("Full Screen:"), mFSCheckbox->mX - mX - 25, mFSCheckbox->mY - mY - mFSCheckbox->mHeight + 20);
+ g->DrawString(_S("Custom Cursors:"), mCustomCursorsCheckbox->mX - mX - 25,
+ mCustomCursorsCheckbox->mY - mY - mCustomCursorsCheckbox->mHeight + 20);
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::AddedToManager(WidgetManager* theWidgetManager)
+{
+ Dialog::AddedToManager(theWidgetManager);
+ theWidgetManager->AddWidget(mMusicVolumeSlider);
+ theWidgetManager->AddWidget(mSfxVolumeSlider);
+ theWidgetManager->AddWidget(mQuitBtn);
+
+ int checkWidth = IMAGE_CHECKBOX->GetWidth() / 2;
+ m3DCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ m3DCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+
+ mFSCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ mFSCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+
+ mCustomCursorsCheckbox->mUncheckedRect = Rect(0, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+ mCustomCursorsCheckbox->mCheckedRect = Rect(checkWidth, 0, checkWidth, IMAGE_CHECKBOX->GetHeight());
+
+ m3DCheckbox->mChecked = gSexyAppBase->Is3DAccelerated();
+ mFSCheckbox->mChecked = !gSexyAppBase->mIsWindowed;
+ mCustomCursorsCheckbox->mChecked = gSexyAppBase->mCustomCursorsEnabled;
+
+ theWidgetManager->AddWidget(m3DCheckbox);
+ theWidgetManager->AddWidget(mFSCheckbox);
+ theWidgetManager->AddWidget(mCustomCursorsCheckbox);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::RemovedFromManager(WidgetManager* theWidgetManager)
+{
+ Dialog::RemovedFromManager(theWidgetManager);
+ theWidgetManager->RemoveWidget(mMusicVolumeSlider);
+ theWidgetManager->RemoveWidget(mSfxVolumeSlider);
+ theWidgetManager->RemoveWidget(mQuitBtn);
+ theWidgetManager->RemoveWidget(mCustomCursorsCheckbox);
+ theWidgetManager->RemoveWidget(m3DCheckbox);
+ theWidgetManager->RemoveWidget(mFSCheckbox);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::Resize(int theX, int theY, int theWidth, int theHeight)
+{
+ Dialog::Resize(theX, theY, theWidth, theHeight);
+
+ mMusicVolumeSlider->Resize(theX + mContentInsets.mLeft + 50,
+ theY + 100, 245, IMAGE_SLIDER_THUMB->GetHeight());
+
+ mSfxVolumeSlider->Layout(LAY_SameLeft | LAY_Below | LAY_SameWidth | LAY_SameHeight,
+ mMusicVolumeSlider, 0, 40, 0, 0);
+
+ mQuitBtn->Layout(LAY_SameLeft | LAY_SameSize | LAY_Above, mYesButton);
+
+ m3DCheckbox->Layout(LAY_SameLeft | LAY_Below, mSfxVolumeSlider, 0, 40, 0, 0);
+ m3DCheckbox->Resize(m3DCheckbox->mX, m3DCheckbox->mY,
+ IMAGE_CHECKBOX->mWidth / 2, IMAGE_CHECKBOX->mHeight);
+
+ mFSCheckbox->Layout(LAY_SameTop | LAY_SameWidth | LAY_SameHeight | LAY_Right, m3DCheckbox, 80);
+
+ mCustomCursorsCheckbox->Layout(LAY_SameTop | LAY_SameWidth | LAY_SameHeight | LAY_Right, mFSCheckbox, 80);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::SliderVal(int theId, double theVal)
+{
+ if (theId == OptionsDialog::MUSIC_SLIDER_ID)
+ {
+ // Let's set the music volume to whatever the slider position is
+ gSexyAppBase->SetMusicVolume(theVal);
+ }
+ else if (theId == OptionsDialog::SFX_SLIDER_ID)
+ {
+ // Set the sound value
+ gSexyAppBase->SetSfxVolume(theVal);
+
+ if (!mSfxVolumeSlider->mDragging)
+ gSexyAppBase->PlaySample(SOUND_TIMER);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::ButtonDepress(int theId)
+{
+ Dialog::ButtonDepress(theId);
+
+ // Previously, before framework 1.2, the line below looked like:
+ // else if (theId == 2000 + mId)
+ // With the 1.2 changes, there's just 1 slight incompatibility.
+ // If the DialogListener for a dialog your app (by default), and
+ // you don't implement your own DialogButton(De)press method (see V12Demo for
+ // more info on this), and instead are trapping button presses within ButtonDepress
+ // inside the dialog itself, then instead of the button ID being 2000 or 3000 + mId,
+ // it's just 0 for no/cancel/1-button dialog, and 1 for yes/ok. Hence we changed our
+ // check to look for 0, which is our default single close button at the bottom of this
+ // dialog.
+ if (theId == ID_YES)
+ {
+ // Close button pressed. Tell the app to remove ourselves. This
+ // will automatically safe delete the dialog at a later time.
+ // Let's apply the 3D and fullscreen mode settings first though.
+ // We call SwitchScreenMode. The first parameter is whether or not to run
+ // windowed (false means fullscreen), the second is whether or not to do 3d.
+ gSexyAppBase->SwitchScreenMode(!mFSCheckbox->mChecked, m3DCheckbox->mChecked);
+
+ gSexyAppBase->EnableCustomCursors(mCustomCursorsCheckbox->mChecked);
+
+ gSexyAppBase->KillDialog(this);
+
+ mBoard->OptionsDialogDone();
+ }
+ else if (theId == mQuitBtn->mId)
+ {
+ // Quit button pressed. Shut down the app.
+ gSexyAppBase->Shutdown();
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void OptionsDialog::CheckboxChecked(int theId, bool checked)
+{
+ // We'll wait until the dialog box is closed before actually applying any effects,
+ // since it's rather jarring if as soon as a user clicks the 3d or fullscreen
+ // toggle buttons to change right then and there.
+
+ if (theId == m3DCheckbox->mId)
+ {
+ if (checked)
+ {
+ // Turn on 3D acceleration. But we need to check if the user is
+ // even allowed to have it on. Some cards are just not compatible
+ // with the framework (less than 8MB RAM for instance):
+ if (!gSexyAppBase->Is3DAccelerationSupported())
+ {
+ // It's not supported. Don't let the checkbox get checked.
+ // Display an error dialog to the user to let them know why this happened.
+ // The reason we don't use a Popup or Windows-based message box here is because
+ // if the user was in full screen mode, they might not see the error message. Using
+ // a game dialog box is the safest way to warn them.
+ m3DCheckbox->SetChecked(false);
+ gSexyAppBase->DoDialog(OptionsDialog::MESSAGE_BOX_ID, true, _S("Not Supported"),
+ _S("Hardware acceleration can not be enabled on this computer. \nYour \
+ video card does not meet the minimum requirements for this game."),
+ _S("OK"), Dialog::BUTTONS_FOOTER);
+ }
+ else if(!gSexyAppBase->Is3DAccelerationRecommended())
+ {
+ // We can also check if 3D acceleration is not recommended for this computer
+ // with a call to Is3DAccelerationRecommended. This allows the user to override
+ // the default setting, but with a warning that it might not work or might cause
+ // problems. Some cards fail the detection process but wind up being OK to use.
+ gSexyAppBase->DoDialog(OptionsDialog::MESSAGE_BOX_ID, true, _S("Warning"),
+ _S("Your video card may not fully support this feature.\n\
+ If you experience slower performance, please disable Hardware Acceleration."),
+ _S("OK"), Dialog::BUTTONS_FOOTER);
+ }
+
+ }
+ }
+ else if (theId == mFSCheckbox->mId)
+ {
+ // Believe it or not, some people are not allowed to play in windowed mode.
+ // You can only run in windowed mode if your desktop is 16 or 32 bit, and
+ // if the resolution of their desktop is GREATER THAN the resolution of the
+ // game. It doesn't make sense to run a 800x600 game windowed when your desktop
+ // is 800x600 or less.
+ // We can determine if the user is not allowed to run in windowed mode by
+ // checking the value of SexyAppBase's mForceFullScreen variable.
+ if (gSexyAppBase->mForceFullscreen && !checked)
+ {
+ gSexyAppBase->DoDialog(OptionsDialog::MESSAGE_BOX_ID, true, _S("No Windowed Mode"),
+ _S("Windowed mode is only available if your desktop is running in\n\
+ either 16 bit or 32 bit color mode, which it is not."), _S("OK"), Dialog::BUTTONS_FOOTER);
+
+ // re-check the box to indicate that fullscreen is still the selected mode:
+ mFSCheckbox->SetChecked(true);
+ }
+ }
+} \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/OptionsDialog.h b/osframework/source/demos/Hun-garr/OptionsDialog.h
new file mode 100644
index 0000000..dd998cd
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/OptionsDialog.h
@@ -0,0 +1,110 @@
+//////////////////////////////////////////////////////////////////////////
+// OptionsDialog.h
+//
+// Represents a standard options dialog box where the user can toggle
+// 3D mode, full screen, custom cursors, adjust sound volumes, and
+// quit the game.
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef __OPTIONS_DIALOG_H__
+#define __OPTIONS_DIALOG_H__
+
+#include "SexyAppFramework/Dialog.h"
+#include "SexyAppFramework/SliderListener.h"
+#include "SexyAppFramework/CheckboxListener.h"
+
+namespace Sexy
+{
+
+ class Graphics;
+ class Slider;
+ class DialogButton;
+ class Checkbox;
+ class Board;
+
+ class OptionsDialog : public Dialog, public SliderListener, public CheckboxListener
+ {
+
+ protected:
+
+ Slider* mMusicVolumeSlider;
+ Slider* mSfxVolumeSlider;
+ DialogButton* mQuitBtn;
+ Board* mBoard;
+
+
+ public:
+
+ enum
+ {
+ MUSIC_SLIDER_ID,
+ SFX_SLIDER_ID,
+ QUIT_BTN_ID,
+ FS_CHECKBOX_ID,
+ HARDWARE_CHECKBOX_ID,
+ CUSTOM_CURSORS_CHECKBOX_ID,
+ MESSAGE_BOX_ID,
+ DIALOG_ID
+ };
+
+
+ Checkbox* m3DCheckbox;
+ Checkbox* mFSCheckbox;
+ Checkbox* mCustomCursorsCheckbox;
+
+
+ public:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: OptionsDialog
+ // Parameters:
+ // b - A pointer to the board, used to unpause when dialog closes
+ //
+ // Returns: none
+ //////////////////////////////////////////////////////////////////////////
+ OptionsDialog(Board* b);
+ virtual ~OptionsDialog();
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Draw
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Draw(Graphics* g);
+
+ //////////////////////////////////////////////////////////////////////////
+ // ButtonDepress
+ //////////////////////////////////////////////////////////////////////////
+ virtual void ButtonDepress(int theId);
+
+ //////////////////////////////////////////////////////////////////////////
+ // AddedToManager
+ //////////////////////////////////////////////////////////////////////////
+ virtual void AddedToManager(WidgetManager* theWidgetManager);
+
+ //////////////////////////////////////////////////////////////////////////
+ // RemovedFromManager
+ //////////////////////////////////////////////////////////////////////////
+ virtual void RemovedFromManager(WidgetManager* theWidgetManager);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Resize
+ //////////////////////////////////////////////////////////////////////////
+ virtual void Resize(int theX, int theY, int theWidth, int theHeight);
+
+ //////////////////////////////////////////////////////////////////////////
+ // SliderVal
+ //////////////////////////////////////////////////////////////////////////
+ virtual void SliderVal(int theId, double theVal);
+
+ //////////////////////////////////////////////////////////////////////////
+ // CheckboxChecked
+ //////////////////////////////////////////////////////////////////////////
+ void CheckboxChecked(int theId, bool checked);
+ };
+
+
+}
+
+
+#endif \ No newline at end of file
diff --git a/osframework/source/demos/Hun-garr/TitleScreen.cpp b/osframework/source/demos/Hun-garr/TitleScreen.cpp
new file mode 100644
index 0000000..510db94
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/TitleScreen.cpp
@@ -0,0 +1,150 @@
+#include "TitleScreen.h"
+#include "GameApp.h"
+#include "Res.h"
+#include "SexyAppFramework/Font.h"
+#include "SexyAppFramework/Graphics.h"
+#include "SexyAppFramework/Image.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/Rect.h"
+#include "SexyAppFramework/HyperlinkWidget.h"
+
+using namespace Sexy;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+TitleScreen::TitleScreen(GameApp *pApp)
+{
+ mApp = pApp;
+ mContinueLink = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+TitleScreen::~TitleScreen()
+{
+ delete mContinueLink;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::Init(void)
+{
+ mContinueLink = new HyperlinkWidget(1, this);
+ mContinueLink->SetFont(FONT_DEFAULT);
+ mContinueLink->mLabel = _S("CLICK TO CONTINUE");
+ mContinueLink->mColor = Color(255, 255, 255);
+ mContinueLink->mOverColor = Color(0, 255, 0);
+ mContinueLink->mUnderlineSize = 1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::AddedToManager(WidgetManager *theWidgetManager)
+{
+ Widget::AddedToManager(theWidgetManager);
+ mContinueLink->SetVisible(false);
+ mContinueLink->SetDisabled(true);
+
+ int labelWidth = FONT_DEFAULT->StringWidth(mContinueLink->mLabel);
+ int labelHeight = FONT_DEFAULT->GetHeight();
+ mContinueLink->Resize( mWidth / 2 - labelWidth / 2,
+ mHeight - labelHeight - 40,
+ labelWidth,
+ labelHeight+4);
+
+ mContinueLink->mDoFinger = true;
+ theWidgetManager->AddWidget(mContinueLink);
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::RemovedFromManager(WidgetManager *theWidgetManager)
+{
+ Widget::RemovedFromManager(theWidgetManager);
+ theWidgetManager->RemoveWidget(mContinueLink);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void TitleScreen::Draw(Graphics *g)
+{
+ 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 - 10, mContinueLink->mY - 80);
+
+ g->DrawImage(IMAGE_HUNGARR_LOGO, mWidth / 2 - IMAGE_HUNGARR_LOGO->mWidth / 2, 100);
+ g->SetColor(Color::White);
+ g->SetFont(FONT_HUNGARR);
+ SexyString s = _S("HUN-GARR NEEDS PLANETS!");
+ g->DrawString(s, mWidth / 2 - FONT_HUNGARR->StringWidth(s) / 2, 200);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+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 startr
+ // 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;
+ mApp->PlaySample(SOUND_CONTINUE);
+
+ // 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/Hun-garr/TitleScreen.h b/osframework/source/demos/Hun-garr/TitleScreen.h
new file mode 100644
index 0000000..d603bf5
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/TitleScreen.h
@@ -0,0 +1,121 @@
+#ifndef __TITLE_SCREEN_H__
+#define __TITLE_SCREEN_H__
+
+#include "SexyAppFramework/Widget.h"
+#include "SexyAppFramework/ButtonListener.h"
+
+namespace Sexy
+{
+
+class GameApp;
+class Graphics;
+class WidgetManager;
+class HyperlinkWidget;
+
+
+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/Hun-garr/main.cpp b/osframework/source/demos/Hun-garr/main.cpp
new file mode 100644
index 0000000..cfef199
--- /dev/null
+++ b/osframework/source/demos/Hun-garr/main.cpp
@@ -0,0 +1,41 @@
+//////////////////////////////////////////////////////////////////////////
+// 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 Hue, Saturation, Luminance values instead of RGB for color
+// * Custom cursors
+// * Handling loss/gain of application focus
+// * Basic particle effects
+// * Various programmatic effects/logic
+// * Putting most of the knowledge from the previous demos to work in a game
+//
+// IMPORTANT: Comments for topics covered in the previous demos will
+// be kept to a minimum and removed in most cases. You should read through
+// the previous demos to familiarize yourself with anything you don't
+// understand. All functions, variables, and concepts are explained
+// either in this demo, or in previous ones if they've already been covered.
+//////////////////////////////////////////////////////////////////////////
+
+#include "GameApp.h"
+
+
+using namespace Sexy;
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+
+
+ gHInstance = hInstance;
+
+ GameApp* anApp = new GameApp();
+ anApp->Init();
+ anApp->Start();
+
+ delete anApp;
+
+ return 0;
+}
diff --git a/osframework/source/demos/Res.cpp b/osframework/source/demos/Res.cpp
new file mode 100644
index 0000000..5b12cf1
--- /dev/null
+++ b/osframework/source/demos/Res.cpp
@@ -0,0 +1,378 @@
+#include "Res.h"
+#include "SexyAppFramework/ResourceManager.h"
+
+using namespace Sexy;
+
+#pragma warning(disable:4311 4312)
+
+static bool gNeedRecalcVariableToIdMap = false;
+
+bool Sexy::ExtractResourcesByName(ResourceManager *theManager, const char *theName)
+{
+ if (strcmp(theName,"Game")==0) return ExtractGameResources(theManager);
+ if (strcmp(theName,"Hungarr")==0) return ExtractHungarrResources(theManager);
+ if (strcmp(theName,"Init")==0) return ExtractInitResources(theManager);
+ if (strcmp(theName,"TitleScreen")==0) return ExtractTitleScreenResources(theManager);
+ return false;
+}
+
+Sexy::ResourceId Sexy::GetIdByStringId(const char *theStringId)
+{
+ typedef std::map<std::string,int> MyMap;
+ static MyMap aMap;
+ if(aMap.empty())
+ {
+ for(int i=0; i<RESOURCE_ID_MAX; i++)
+ aMap[GetStringIdById(i)] = i;
+ }
+
+ MyMap::iterator anItr = aMap.find(theStringId);
+ if (anItr == aMap.end())
+ return RESOURCE_ID_MAX;
+ else
+ return (ResourceId) anItr->second;
+}
+
+// Game Resources
+Image* Sexy::IMAGE_BG0;
+Image* Sexy::IMAGE_BG1;
+Image* Sexy::IMAGE_BG2;
+Image* Sexy::IMAGE_BUTTON_DOWN;
+Image* Sexy::IMAGE_BUTTON_NORMAL;
+Image* Sexy::IMAGE_BUTTON_OVER;
+Image* Sexy::IMAGE_CHECKBOX;
+Image* Sexy::IMAGE_DIALOG_BOX;
+Image* Sexy::IMAGE_DIALOG_BUTTON;
+Image* Sexy::IMAGE_ROBOTROBOT;
+Image* Sexy::IMAGE_SLIDER_THUMB;
+Image* Sexy::IMAGE_SLIDER_TRACK;
+int Sexy::SOUND_MUTATOR;
+int Sexy::SOUND_TIMER;
+
+bool Sexy::ExtractGameResources(ResourceManager *theManager)
+{
+ gNeedRecalcVariableToIdMap = true;
+
+ ResourceManager &aMgr = *theManager;
+ try
+ {
+ IMAGE_BG0 = aMgr.GetImageThrow("IMAGE_BG0");
+ IMAGE_BG1 = aMgr.GetImageThrow("IMAGE_BG1");
+ IMAGE_BG2 = aMgr.GetImageThrow("IMAGE_BG2");
+ IMAGE_BUTTON_DOWN = aMgr.GetImageThrow("IMAGE_BUTTON_DOWN");
+ IMAGE_BUTTON_NORMAL = aMgr.GetImageThrow("IMAGE_BUTTON_NORMAL");
+ IMAGE_BUTTON_OVER = aMgr.GetImageThrow("IMAGE_BUTTON_OVER");
+ IMAGE_CHECKBOX = aMgr.GetImageThrow("IMAGE_CHECKBOX");
+ IMAGE_DIALOG_BOX = aMgr.GetImageThrow("IMAGE_DIALOG_BOX");
+ IMAGE_DIALOG_BUTTON = aMgr.GetImageThrow("IMAGE_DIALOG_BUTTON");
+ IMAGE_ROBOTROBOT = aMgr.GetImageThrow("IMAGE_ROBOTROBOT");
+ IMAGE_SLIDER_THUMB = aMgr.GetImageThrow("IMAGE_SLIDER_THUMB");
+ IMAGE_SLIDER_TRACK = aMgr.GetImageThrow("IMAGE_SLIDER_TRACK");
+ SOUND_MUTATOR = aMgr.GetSoundThrow("SOUND_MUTATOR");
+ SOUND_TIMER = aMgr.GetSoundThrow("SOUND_TIMER");
+ }
+ catch(ResourceManagerException&)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Hungarr Resources
+Image* Sexy::IMAGE_ATOMIC_EXPLOSION;
+Image* Sexy::IMAGE_BOMB_RADIAL_DEATH;
+Image* Sexy::IMAGE_HUNGARR_BEAM_DOWN;
+Image* Sexy::IMAGE_HUNGARR_BEAM_LEFT;
+Image* Sexy::IMAGE_HUNGARR_BEAM_RIGHT;
+Image* Sexy::IMAGE_HUNGARR_BEAM_UP;
+Image* Sexy::IMAGE_HUNGARR_HORIZ;
+Image* Sexy::IMAGE_HUNGARR_SMALL;
+Image* Sexy::IMAGE_HUNGARR_VERT;
+Image* Sexy::IMAGE_PARTICLE_LIGHTNING;
+Image* Sexy::IMAGE_PLANETS;
+Image* Sexy::IMAGE_SPARK;
+int Sexy::SOUND_BEAM_HIT;
+int Sexy::SOUND_BEAM_MOVING;
+int Sexy::SOUND_BUTTON;
+int Sexy::SOUND_EXPLOSION;
+int Sexy::SOUND_GAME_OVER_CLICK;
+int Sexy::SOUND_GAME_OVER_RESTART;
+int Sexy::SOUND_GAME_OVER_STATS;
+int Sexy::SOUND_GAME_OVER_TEXT;
+int Sexy::SOUND_LEVEL_UP1;
+int Sexy::SOUND_LEVEL_UP2;
+int Sexy::SOUND_LEVEL_UP3;
+int Sexy::SOUND_LEVEL_UP4;
+int Sexy::SOUND_MAGZAP;
+int Sexy::SOUND_PLANET;
+int Sexy::SOUND_PLANET_HIT;
+int Sexy::SOUND_REGION_FILLED;
+
+bool Sexy::ExtractHungarrResources(ResourceManager *theManager)
+{
+ gNeedRecalcVariableToIdMap = true;
+
+ ResourceManager &aMgr = *theManager;
+ try
+ {
+ IMAGE_ATOMIC_EXPLOSION = aMgr.GetImageThrow("IMAGE_ATOMIC_EXPLOSION");
+ IMAGE_BOMB_RADIAL_DEATH = aMgr.GetImageThrow("IMAGE_BOMB_RADIAL_DEATH");
+ IMAGE_HUNGARR_BEAM_DOWN = aMgr.GetImageThrow("IMAGE_HUNGARR_BEAM_DOWN");
+ IMAGE_HUNGARR_BEAM_LEFT = aMgr.GetImageThrow("IMAGE_HUNGARR_BEAM_LEFT");
+ IMAGE_HUNGARR_BEAM_RIGHT = aMgr.GetImageThrow("IMAGE_HUNGARR_BEAM_RIGHT");
+ IMAGE_HUNGARR_BEAM_UP = aMgr.GetImageThrow("IMAGE_HUNGARR_BEAM_UP");
+ IMAGE_HUNGARR_HORIZ = aMgr.GetImageThrow("IMAGE_HUNGARR_HORIZ");
+ IMAGE_HUNGARR_SMALL = aMgr.GetImageThrow("IMAGE_HUNGARR_SMALL");
+ IMAGE_HUNGARR_VERT = aMgr.GetImageThrow("IMAGE_HUNGARR_VERT");
+ IMAGE_PARTICLE_LIGHTNING = aMgr.GetImageThrow("IMAGE_PARTICLE_LIGHTNING");
+ IMAGE_PLANETS = aMgr.GetImageThrow("IMAGE_PLANETS");
+ IMAGE_SPARK = aMgr.GetImageThrow("IMAGE_SPARK");
+ SOUND_BEAM_HIT = aMgr.GetSoundThrow("SOUND_BEAM_HIT");
+ SOUND_BEAM_MOVING = aMgr.GetSoundThrow("SOUND_BEAM_MOVING");
+ SOUND_BUTTON = aMgr.GetSoundThrow("SOUND_BUTTON");
+ SOUND_EXPLOSION = aMgr.GetSoundThrow("SOUND_EXPLOSION");
+ SOUND_GAME_OVER_CLICK = aMgr.GetSoundThrow("SOUND_GAME_OVER_CLICK");
+ SOUND_GAME_OVER_RESTART = aMgr.GetSoundThrow("SOUND_GAME_OVER_RESTART");
+ SOUND_GAME_OVER_STATS = aMgr.GetSoundThrow("SOUND_GAME_OVER_STATS");
+ SOUND_GAME_OVER_TEXT = aMgr.GetSoundThrow("SOUND_GAME_OVER_TEXT");
+ SOUND_LEVEL_UP1 = aMgr.GetSoundThrow("SOUND_LEVEL_UP1");
+ SOUND_LEVEL_UP2 = aMgr.GetSoundThrow("SOUND_LEVEL_UP2");
+ SOUND_LEVEL_UP3 = aMgr.GetSoundThrow("SOUND_LEVEL_UP3");
+ SOUND_LEVEL_UP4 = aMgr.GetSoundThrow("SOUND_LEVEL_UP4");
+ SOUND_MAGZAP = aMgr.GetSoundThrow("SOUND_MAGZAP");
+ SOUND_PLANET = aMgr.GetSoundThrow("SOUND_PLANET");
+ SOUND_PLANET_HIT = aMgr.GetSoundThrow("SOUND_PLANET_HIT");
+ SOUND_REGION_FILLED = aMgr.GetSoundThrow("SOUND_REGION_FILLED");
+ }
+ catch(ResourceManagerException&)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Init Resources
+Font* Sexy::FONT_DEFAULT;
+Font* Sexy::FONT_HUNGARR;
+Image* Sexy::IMAGE_CUSTOM_DRAGGING;
+Image* Sexy::IMAGE_CUSTOM_HAND;
+Image* Sexy::IMAGE_CUSTOM_POINTER;
+Image* Sexy::IMAGE_CUSTOM_TEXT;
+Image* Sexy::IMAGE_HUNGARR_LOGO;
+
+bool Sexy::ExtractInitResources(ResourceManager *theManager)
+{
+ gNeedRecalcVariableToIdMap = true;
+
+ ResourceManager &aMgr = *theManager;
+ try
+ {
+ FONT_DEFAULT = aMgr.GetFontThrow("FONT_DEFAULT");
+ FONT_HUNGARR = aMgr.GetFontThrow("FONT_HUNGARR");
+ IMAGE_CUSTOM_DRAGGING = aMgr.GetImageThrow("IMAGE_CUSTOM_DRAGGING");
+ IMAGE_CUSTOM_HAND = aMgr.GetImageThrow("IMAGE_CUSTOM_HAND");
+ IMAGE_CUSTOM_POINTER = aMgr.GetImageThrow("IMAGE_CUSTOM_POINTER");
+ IMAGE_CUSTOM_TEXT = aMgr.GetImageThrow("IMAGE_CUSTOM_TEXT");
+ IMAGE_HUNGARR_LOGO = aMgr.GetImageThrow("IMAGE_HUNGARR_LOGO");
+ }
+ catch(ResourceManagerException&)
+ {
+ return false;
+ }
+ return true;
+}
+
+// TitleScreen Resources
+Image* Sexy::IMAGE_LOADER_BAR;
+Image* Sexy::IMAGE_LOADER_LOADINGTXT;
+int Sexy::SOUND_CONTINUE;
+
+bool Sexy::ExtractTitleScreenResources(ResourceManager *theManager)
+{
+ gNeedRecalcVariableToIdMap = true;
+
+ ResourceManager &aMgr = *theManager;
+ try
+ {
+ IMAGE_LOADER_BAR = aMgr.GetImageThrow("IMAGE_LOADER_BAR");
+ IMAGE_LOADER_LOADINGTXT = aMgr.GetImageThrow("IMAGE_LOADER_LOADINGTXT");
+ SOUND_CONTINUE = aMgr.GetSoundThrow("SOUND_CONTINUE");
+ }
+ catch(ResourceManagerException&)
+ {
+ return false;
+ }
+ return true;
+}
+
+static void* gResources[] =
+{
+ &FONT_DEFAULT,
+ &FONT_HUNGARR,
+ &IMAGE_CUSTOM_POINTER,
+ &IMAGE_CUSTOM_HAND,
+ &IMAGE_CUSTOM_DRAGGING,
+ &IMAGE_CUSTOM_TEXT,
+ &IMAGE_HUNGARR_LOGO,
+ &IMAGE_LOADER_BAR,
+ &IMAGE_LOADER_LOADINGTXT,
+ &SOUND_CONTINUE,
+ &SOUND_MUTATOR,
+ &SOUND_TIMER,
+ &IMAGE_ROBOTROBOT,
+ &IMAGE_CHECKBOX,
+ &IMAGE_BG0,
+ &IMAGE_BG1,
+ &IMAGE_BG2,
+ &IMAGE_BUTTON_DOWN,
+ &IMAGE_BUTTON_OVER,
+ &IMAGE_BUTTON_NORMAL,
+ &IMAGE_DIALOG_BOX,
+ &IMAGE_DIALOG_BUTTON,
+ &IMAGE_SLIDER_TRACK,
+ &IMAGE_SLIDER_THUMB,
+ &IMAGE_HUNGARR_SMALL,
+ &IMAGE_HUNGARR_BEAM_UP,
+ &IMAGE_HUNGARR_BEAM_DOWN,
+ &IMAGE_HUNGARR_BEAM_LEFT,
+ &IMAGE_HUNGARR_BEAM_RIGHT,
+ &IMAGE_HUNGARR_HORIZ,
+ &IMAGE_HUNGARR_VERT,
+ &IMAGE_ATOMIC_EXPLOSION,
+ &IMAGE_BOMB_RADIAL_DEATH,
+ &IMAGE_PLANETS,
+ &IMAGE_SPARK,
+ &IMAGE_PARTICLE_LIGHTNING,
+ &SOUND_MAGZAP,
+ &SOUND_BUTTON,
+ &SOUND_PLANET,
+ &SOUND_LEVEL_UP1,
+ &SOUND_LEVEL_UP2,
+ &SOUND_EXPLOSION,
+ &SOUND_BEAM_HIT,
+ &SOUND_PLANET_HIT,
+ &SOUND_BEAM_MOVING,
+ &SOUND_LEVEL_UP4,
+ &SOUND_LEVEL_UP3,
+ &SOUND_GAME_OVER_CLICK,
+ &SOUND_GAME_OVER_STATS,
+ &SOUND_GAME_OVER_RESTART,
+ &SOUND_GAME_OVER_TEXT,
+ &SOUND_REGION_FILLED,
+ NULL
+};
+
+Image* Sexy::LoadImageById(ResourceManager *theManager, int theId)
+{
+ return (*((Image**)gResources[theId]) = theManager->LoadImage(GetStringIdById(theId)));
+}
+
+Image* Sexy::GetImageById(int theId)
+{
+ return *(Image**)gResources[theId];
+}
+
+Font* Sexy::GetFontById(int theId)
+{
+ return *(Font**)gResources[theId];
+}
+
+int Sexy::GetSoundById(int theId)
+{
+ return *(int*)gResources[theId];
+}
+
+static Sexy::ResourceId GetIdByVariable(const void *theVariable)
+{
+ typedef std::map<int,int> MyMap;
+ static MyMap aMap;
+ if(gNeedRecalcVariableToIdMap)
+ {
+ gNeedRecalcVariableToIdMap = false;
+ aMap.clear();
+ for(int i=0; i<RESOURCE_ID_MAX; i++)
+ aMap[*(int*)gResources[i]] = i;
+ }
+
+ MyMap::iterator anItr = aMap.find((int)theVariable);
+ if (anItr == aMap.end())
+ return RESOURCE_ID_MAX;
+ else
+ return (ResourceId) anItr->second;
+}
+
+Sexy::ResourceId Sexy::GetIdByImage(Image *theImage)
+{
+ return GetIdByVariable(theImage);
+}
+
+Sexy::ResourceId Sexy::GetIdByFont(Font *theFont)
+{
+ return GetIdByVariable(theFont);
+}
+
+Sexy::ResourceId Sexy::GetIdBySound(int theSound)
+{
+ return GetIdByVariable((void*)theSound);
+}
+
+const char* Sexy::GetStringIdById(int theId)
+{
+ switch(theId)
+ {
+ case FONT_DEFAULT_ID: return "FONT_DEFAULT";
+ case FONT_HUNGARR_ID: return "FONT_HUNGARR";
+ case IMAGE_CUSTOM_POINTER_ID: return "IMAGE_CUSTOM_POINTER";
+ case IMAGE_CUSTOM_HAND_ID: return "IMAGE_CUSTOM_HAND";
+ case IMAGE_CUSTOM_DRAGGING_ID: return "IMAGE_CUSTOM_DRAGGING";
+ case IMAGE_CUSTOM_TEXT_ID: return "IMAGE_CUSTOM_TEXT";
+ case IMAGE_HUNGARR_LOGO_ID: return "IMAGE_HUNGARR_LOGO";
+ case IMAGE_LOADER_BAR_ID: return "IMAGE_LOADER_BAR";
+ case IMAGE_LOADER_LOADINGTXT_ID: return "IMAGE_LOADER_LOADINGTXT";
+ case SOUND_CONTINUE_ID: return "SOUND_CONTINUE";
+ case SOUND_MUTATOR_ID: return "SOUND_MUTATOR";
+ case SOUND_TIMER_ID: return "SOUND_TIMER";
+ case IMAGE_ROBOTROBOT_ID: return "IMAGE_ROBOTROBOT";
+ case IMAGE_CHECKBOX_ID: return "IMAGE_CHECKBOX";
+ case IMAGE_BG0_ID: return "IMAGE_BG0";
+ case IMAGE_BG1_ID: return "IMAGE_BG1";
+ case IMAGE_BG2_ID: return "IMAGE_BG2";
+ case IMAGE_BUTTON_DOWN_ID: return "IMAGE_BUTTON_DOWN";
+ case IMAGE_BUTTON_OVER_ID: return "IMAGE_BUTTON_OVER";
+ case IMAGE_BUTTON_NORMAL_ID: return "IMAGE_BUTTON_NORMAL";
+ case IMAGE_DIALOG_BOX_ID: return "IMAGE_DIALOG_BOX";
+ case IMAGE_DIALOG_BUTTON_ID: return "IMAGE_DIALOG_BUTTON";
+ case IMAGE_SLIDER_TRACK_ID: return "IMAGE_SLIDER_TRACK";
+ case IMAGE_SLIDER_THUMB_ID: return "IMAGE_SLIDER_THUMB";
+ case IMAGE_HUNGARR_SMALL_ID: return "IMAGE_HUNGARR_SMALL";
+ case IMAGE_HUNGARR_BEAM_UP_ID: return "IMAGE_HUNGARR_BEAM_UP";
+ case IMAGE_HUNGARR_BEAM_DOWN_ID: return "IMAGE_HUNGARR_BEAM_DOWN";
+ case IMAGE_HUNGARR_BEAM_LEFT_ID: return "IMAGE_HUNGARR_BEAM_LEFT";
+ case IMAGE_HUNGARR_BEAM_RIGHT_ID: return "IMAGE_HUNGARR_BEAM_RIGHT";
+ case IMAGE_HUNGARR_HORIZ_ID: return "IMAGE_HUNGARR_HORIZ";
+ case IMAGE_HUNGARR_VERT_ID: return "IMAGE_HUNGARR_VERT";
+ case IMAGE_ATOMIC_EXPLOSION_ID: return "IMAGE_ATOMIC_EXPLOSION";
+ case IMAGE_BOMB_RADIAL_DEATH_ID: return "IMAGE_BOMB_RADIAL_DEATH";
+ case IMAGE_PLANETS_ID: return "IMAGE_PLANETS";
+ case IMAGE_SPARK_ID: return "IMAGE_SPARK";
+ case IMAGE_PARTICLE_LIGHTNING_ID: return "IMAGE_PARTICLE_LIGHTNING";
+ case SOUND_MAGZAP_ID: return "SOUND_MAGZAP";
+ case SOUND_BUTTON_ID: return "SOUND_BUTTON";
+ case SOUND_PLANET_ID: return "SOUND_PLANET";
+ case SOUND_LEVEL_UP1_ID: return "SOUND_LEVEL_UP1";
+ case SOUND_LEVEL_UP2_ID: return "SOUND_LEVEL_UP2";
+ case SOUND_EXPLOSION_ID: return "SOUND_EXPLOSION";
+ case SOUND_BEAM_HIT_ID: return "SOUND_BEAM_HIT";
+ case SOUND_PLANET_HIT_ID: return "SOUND_PLANET_HIT";
+ case SOUND_BEAM_MOVING_ID: return "SOUND_BEAM_MOVING";
+ case SOUND_LEVEL_UP4_ID: return "SOUND_LEVEL_UP4";
+ case SOUND_LEVEL_UP3_ID: return "SOUND_LEVEL_UP3";
+ case SOUND_GAME_OVER_CLICK_ID: return "SOUND_GAME_OVER_CLICK";
+ case SOUND_GAME_OVER_STATS_ID: return "SOUND_GAME_OVER_STATS";
+ case SOUND_GAME_OVER_RESTART_ID: return "SOUND_GAME_OVER_RESTART";
+ case SOUND_GAME_OVER_TEXT_ID: return "SOUND_GAME_OVER_TEXT";
+ case SOUND_REGION_FILLED_ID: return "SOUND_REGION_FILLED";
+ default: return "";
+ }
+}
+
diff --git a/osframework/source/demos/Res.h b/osframework/source/demos/Res.h
new file mode 100644
index 0000000..dbe0fdc
--- /dev/null
+++ b/osframework/source/demos/Res.h
@@ -0,0 +1,147 @@
+#ifndef __Res_H__
+#define __Res_H__
+
+namespace Sexy
+{
+ class ResourceManager;
+ class Image;
+ class Font;
+
+ Image* LoadImageById(ResourceManager *theManager, int theId);
+ bool ExtractResourcesByName(ResourceManager *theManager, const char *theName);
+
+ // Game Resources
+ bool ExtractGameResources(ResourceManager *theMgr);
+ extern Image* IMAGE_BG0;
+ extern Image* IMAGE_BG1;
+ extern Image* IMAGE_BG2;
+ extern Image* IMAGE_BUTTON_DOWN;
+ extern Image* IMAGE_BUTTON_NORMAL;
+ extern Image* IMAGE_BUTTON_OVER;
+ extern Image* IMAGE_CHECKBOX;
+ extern Image* IMAGE_DIALOG_BOX;
+ extern Image* IMAGE_DIALOG_BUTTON;
+ extern Image* IMAGE_ROBOTROBOT;
+ extern Image* IMAGE_SLIDER_THUMB;
+ extern Image* IMAGE_SLIDER_TRACK;
+ extern int SOUND_MUTATOR;
+ extern int SOUND_TIMER;
+
+ // Hungarr Resources
+ bool ExtractHungarrResources(ResourceManager *theMgr);
+ extern Image* IMAGE_ATOMIC_EXPLOSION;
+ extern Image* IMAGE_BOMB_RADIAL_DEATH;
+ extern Image* IMAGE_HUNGARR_BEAM_DOWN;
+ extern Image* IMAGE_HUNGARR_BEAM_LEFT;
+ extern Image* IMAGE_HUNGARR_BEAM_RIGHT;
+ extern Image* IMAGE_HUNGARR_BEAM_UP;
+ extern Image* IMAGE_HUNGARR_HORIZ;
+ extern Image* IMAGE_HUNGARR_SMALL;
+ extern Image* IMAGE_HUNGARR_VERT;
+ extern Image* IMAGE_PARTICLE_LIGHTNING;
+ extern Image* IMAGE_PLANETS;
+ extern Image* IMAGE_SPARK;
+ extern int SOUND_BEAM_HIT;
+ extern int SOUND_BEAM_MOVING;
+ extern int SOUND_BUTTON;
+ extern int SOUND_EXPLOSION;
+ extern int SOUND_GAME_OVER_CLICK;
+ extern int SOUND_GAME_OVER_RESTART;
+ extern int SOUND_GAME_OVER_STATS;
+ extern int SOUND_GAME_OVER_TEXT;
+ extern int SOUND_LEVEL_UP1;
+ extern int SOUND_LEVEL_UP2;
+ extern int SOUND_LEVEL_UP3;
+ extern int SOUND_LEVEL_UP4;
+ extern int SOUND_MAGZAP;
+ extern int SOUND_PLANET;
+ extern int SOUND_PLANET_HIT;
+ extern int SOUND_REGION_FILLED;
+
+ // Init Resources
+ bool ExtractInitResources(ResourceManager *theMgr);
+ extern Font* FONT_DEFAULT;
+ extern Font* FONT_HUNGARR;
+ extern Image* IMAGE_CUSTOM_DRAGGING;
+ extern Image* IMAGE_CUSTOM_HAND;
+ extern Image* IMAGE_CUSTOM_POINTER;
+ extern Image* IMAGE_CUSTOM_TEXT;
+ extern Image* IMAGE_HUNGARR_LOGO;
+
+ // TitleScreen Resources
+ bool ExtractTitleScreenResources(ResourceManager *theMgr);
+ extern Image* IMAGE_LOADER_BAR;
+ extern Image* IMAGE_LOADER_LOADINGTXT;
+ extern int SOUND_CONTINUE;
+
+ enum ResourceId
+ {
+ FONT_DEFAULT_ID,
+ FONT_HUNGARR_ID,
+ IMAGE_CUSTOM_POINTER_ID,
+ IMAGE_CUSTOM_HAND_ID,
+ IMAGE_CUSTOM_DRAGGING_ID,
+ IMAGE_CUSTOM_TEXT_ID,
+ IMAGE_HUNGARR_LOGO_ID,
+ IMAGE_LOADER_BAR_ID,
+ IMAGE_LOADER_LOADINGTXT_ID,
+ SOUND_CONTINUE_ID,
+ SOUND_MUTATOR_ID,
+ SOUND_TIMER_ID,
+ IMAGE_ROBOTROBOT_ID,
+ IMAGE_CHECKBOX_ID,
+ IMAGE_BG0_ID,
+ IMAGE_BG1_ID,
+ IMAGE_BG2_ID,
+ IMAGE_BUTTON_DOWN_ID,
+ IMAGE_BUTTON_OVER_ID,
+ IMAGE_BUTTON_NORMAL_ID,
+ IMAGE_DIALOG_BOX_ID,
+ IMAGE_DIALOG_BUTTON_ID,
+ IMAGE_SLIDER_TRACK_ID,
+ IMAGE_SLIDER_THUMB_ID,
+ IMAGE_HUNGARR_SMALL_ID,
+ IMAGE_HUNGARR_BEAM_UP_ID,
+ IMAGE_HUNGARR_BEAM_DOWN_ID,
+ IMAGE_HUNGARR_BEAM_LEFT_ID,
+ IMAGE_HUNGARR_BEAM_RIGHT_ID,
+ IMAGE_HUNGARR_HORIZ_ID,
+ IMAGE_HUNGARR_VERT_ID,
+ IMAGE_ATOMIC_EXPLOSION_ID,
+ IMAGE_BOMB_RADIAL_DEATH_ID,
+ IMAGE_PLANETS_ID,
+ IMAGE_SPARK_ID,
+ IMAGE_PARTICLE_LIGHTNING_ID,
+ SOUND_MAGZAP_ID,
+ SOUND_BUTTON_ID,
+ SOUND_PLANET_ID,
+ SOUND_LEVEL_UP1_ID,
+ SOUND_LEVEL_UP2_ID,
+ SOUND_EXPLOSION_ID,
+ SOUND_BEAM_HIT_ID,
+ SOUND_PLANET_HIT_ID,
+ SOUND_BEAM_MOVING_ID,
+ SOUND_LEVEL_UP4_ID,
+ SOUND_LEVEL_UP3_ID,
+ SOUND_GAME_OVER_CLICK_ID,
+ SOUND_GAME_OVER_STATS_ID,
+ SOUND_GAME_OVER_RESTART_ID,
+ SOUND_GAME_OVER_TEXT_ID,
+ SOUND_REGION_FILLED_ID,
+ RESOURCE_ID_MAX
+ };
+
+ Image* GetImageById(int theId);
+ Font* GetFontById(int theId);
+ int GetSoundById(int theId);
+
+ ResourceId GetIdByImage(Image *theImage);
+ ResourceId GetIdByFont(Font *theFont);
+ ResourceId GetIdBySound(int theSound);
+ const char* GetStringIdById(int theId);
+ ResourceId GetIdByStringId(const char *theStringId);
+
+} // namespace Sexy
+
+
+#endif
diff --git a/osframework/source/demos/V12Demo/.#Board.cpp.1.7 b/osframework/source/demos/V12Demo/.#Board.cpp.1.7
new file mode 100644
index 0000000..c176a74
--- /dev/null
+++ b/osframework/source/demos/V12Demo/.#Board.cpp.1.7
@@ -0,0 +1,442 @@
+#include "Board.h"
+#include "DemoWidget.h"
+#include "Res.h"
+#include "V12DemoApp.h"
+#include "..\SexyAppFramework\Font.h"
+#include "..\SexyAppFramework\Graphics.h"
+#include "..\SexyAppFramework\ButtonWidget.h"
+#include "..\SexyAppFramework\WidgetManager.h"
+#include "..\SexyAppFramework\Dialog.h"
+#include "..\SexyAppFramework\Flags.h"
+#include "..\SexyAppFramework\SexyMatrix.h"
+#include "..\SexyAppFramework\trivertex.h"
+
+using namespace Sexy;
+
+Board::Board(V12DemoApp* theApp)
+{
+ mApp = theApp;
+
+
+ // Remeber the flag explanation in the 1.2 doc and V12Demo.cpp? Sure you do.
+ // This is basically another use of it. All widgets by default have the following
+ // flags set:
+ // WIDGETFLAGS_UPDATE - The widget gets its Update and UpdateF methods called
+ // WIDGETFLAGS_DRAW - The widget is allowed to draw
+ // WIDGETFLAGS_CLIP - Set to clip Graphics passed into Draw to the widget's bounds
+ // WIDGETFLAGS_ALLOW_MOUSE - Set to allow mouse interaction
+ // WIDGETFLAGS_ALLOW_FOCUS - Set to allow focus to be maintained
+ //
+ // Previously, if you wanted to mark the widget dirty every frame (and thus draw every
+ // frame), you had to call MarkDirty() all the time. Instead of doing that, we can just
+ // use the flag system. By ORing WIDGETFLAGS_MARK_DIRTY with mWidgetFlagsMod.mAddFlags,
+ // when we are added to the widget manager, the manager will then know that we want to
+ // be marked dirty every frame automatically, instead of manually calling MarkDirty().
+ // Yes, I know, that's not a huge deal, but as you can see from the other flags,
+ // it's now easy to set/unset various flags for various widgets and..various reasons.
+ // If you wanted to remove flags set by default for this widget, you'd just OR the
+ // flags to remove with mWidgetFlagsMod.mRemoveFlags. You can affect ALL widgets if you
+ // want to set up widget defaults, by modifying mApp->mWidgetManager's mWidgetFlags
+ // structure in a similar way.
+
+ mWidgetFlagsMod.mAddFlags |= WIDGETFLAGS_MARK_DIRTY;
+
+ // Previously, it was annoying trying to place widgets on some sort of parent widget,
+ // since there was no notion of parent/child relationship. What you had to do was
+ // override the AddedToManager and RemovedFromManager functions, create and add your
+ // widgets or remove and nuke them, and in the case of AddedToManager, you also had
+ // to then place the widget using global coordinates that had no relation to the coordinates
+ // you set the parent widget at. Not anymore. What we can do now is to dispense with
+ // overriding those methods altogether! So now, in the parent's constructor, we can
+ // create our child widgets, resize them, and place them using relative coordinates.
+ // What this also means is that moving the parent widget around results in moving
+ // ALL the child widgets, which means you no longer have to manually move everything
+ // just because the parent moved. In addition, another nice thing is that you no longer
+ // have to remove your child widgets before deleting them: this is handled automatically
+ // for you.
+ mDemoButton = new ButtonWidget(0, this);
+ mDemoButton->mLabel = "Demo Widget";
+ mDemoButton->SetFont(FONT_DEFAULT);
+ mDemoButton->Resize(10, 10, 10 + FONT_DEFAULT->StringWidth(mDemoButton->mLabel), 50);
+
+ // VERY IMPORTANT: Notice that we're calling THIS CLASS' (or really, it's parent, WidgetContainer's)
+ // AddWidget method instead of the WidgetManager's method. In order to designate a widget as a child
+ // widget, you have to call the AddWidget method of the class that will be its parent.
+ AddWidget(mDemoButton);
+
+ mDialogButton = new ButtonWidget(1, this);
+ mDialogButton->mLabel = "Do Dialog";
+ mDialogButton->SetFont(FONT_DEFAULT);
+ int w = FONT_DEFAULT->StringWidth(mDialogButton->mLabel);
+ mDialogButton->Resize(mApp->mWidth - 20 - w, 10, w + 10, 50);
+ AddWidget(mDialogButton);
+
+ mCurtainButton = new ButtonWidget(2, this);
+ mCurtainButton->mLabel = "Do Transition";
+ mCurtainButton->SetFont(FONT_DEFAULT);
+ w = FONT_DEFAULT->StringWidth(mCurtainButton->mLabel);
+ mCurtainButton->Resize(mDemoButton->mX + 20 + mDemoButton->mWidth, 10, w + 10, 50);
+ AddWidget(mCurtainButton);
+
+ mDemoWidget = NULL;
+
+ // Position and set up our pulsing rectangle, as well as the location of the lost focus text.
+ mRect = Rect(mApp->mWidth / 2 - 1, mApp->mHeight / 2 - 1, 2, 2);
+ mExpanding = true;
+ mMsgX = Rand() % (mApp->mWidth - 100);
+ mMsgY = Rand() % (mApp->mHeight - 100);
+ mLostFocus = false;
+
+ mCurtainWidth = 0;
+ mCurtainMode = CURTAIN_INACTIVE;
+
+ // We'll toggle this between 0 and 2 every second when we are unfocussed
+ mDeferPriority = 0;
+}
+
+Board::~Board()
+{
+ // We need to remove child widgets before deleting them.
+ RemoveAllWidgets();
+
+ delete mDemoButton;
+ delete mDialogButton;
+ delete mCurtainButton;
+
+ if (mDemoWidget != NULL)
+ mApp->mWidgetManager->RemoveWidget(mDemoWidget);
+
+ delete mDemoWidget;
+}
+
+void Board::Update()
+{
+ Widget::Update();
+
+ if (mLostFocus)
+ {
+ if (mUpdateCnt % 100 == 0)
+ {
+ mMsgX = Rand() % (mApp->mWidth - 100);
+ mMsgY = Rand() % (mApp->mHeight - 100);
+
+ // Every second, we switch between drawing the overlay above or below
+ // the mDemoWidget object (assuming of course you have the widget on screen
+ // when you lose focus).
+ mDeferPriority = mDeferPriority == 0 ? 2 : 0;
+ }
+ }
+ else
+ {
+ // This just makes the rectangle in the middle grow/shrink. Nothing
+ // too crazy.
+ if (mExpanding)
+ {
+ mRect.mWidth += 2;
+ mRect.mHeight += 2;
+
+ if (mRect.mWidth >= mApp->mWidth)
+ {
+ mRect.mWidth = mApp->mWidth;
+ mExpanding = false;
+ }
+
+ if (mRect.mHeight >= mApp->mHeight)
+ {
+ mRect.mHeight = mApp->mHeight;
+ mExpanding = false;
+ }
+ }
+ else
+ {
+ mRect.mWidth -= 2;
+ mRect.mHeight -= 2;
+
+ if (mRect.mHeight <= 0)
+ {
+ mRect.mHeight = 0;
+ mExpanding = true;
+ }
+
+ if (mRect.mWidth <= 0)
+ {
+ mRect.mWidth = 0;
+ mExpanding = true;
+ }
+
+ }
+
+ mRect.mX = mApp->mWidth / 2 - mRect.mWidth / 2;
+ mRect.mY = mApp->mHeight / 2 - mRect.mHeight / 2;
+ }
+}
+
+void Board::Draw(Graphics* g)
+{
+ g->SetColor(Color::Black);
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // Draw our pulsing rectangle in the middle of the screen.
+ g->SetColor(Color(255, 0, 0));
+ g->FillRect(mRect);
+
+ if (!mLostFocus)
+ {
+ // Previously, any time you changed the
+ // graphic's state, you had to undo it, otherwise it affected anything
+ // drawn later. Common examples are SetColorizeImages, SetColor, SetDrawMode, etc.
+ // In Board::DrawOverlay, you'll see that we can use PushState and PopState to on-demand
+ // save/restore the graphics state. However, if we're either lazy, or after we draw
+ // our current stuff we don't have a need to reset the state and change it again, we
+ // can use the GraphicsAutoState object. This nifty helper class, upon instantiation on
+ // the stack, will automatically push the graphics state of the graphics object you pass in.
+ // Note that since stack variables are
+ // removed (and have their con/destructors called automatically, for classes/structs) when they
+ // go out of scope, the destructor for a GraphicsAutoState object takes care of popping the graphics
+ // state and restoring things to their previous..uh...state.
+ // NOTE: Graphics state is saved between widgets.
+ GraphicsAutoState auto_state(g);
+ g->DrawImage(IMAGE_HUNGARR_LOGO, 10, 100);
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+ g->SetColor(Color(mUpdateCnt % 128, mUpdateCnt % 255, mUpdateCnt % 64));
+ g->DrawImage(IMAGE_HUNGARR_LOGO, 10, 100);
+ }
+
+ if (mCurtainMode != CURTAIN_INACTIVE)
+ {
+ g->SetColor(Color(255, 255, 0));
+ g->FillRect(0, 0, mCurtainWidth, mHeight);
+ g->FillRect(mWidth - mCurtainWidth, 0, mCurtainWidth, mHeight);
+ }
+
+ // Instead of using an overlay widget to draw our stuff when focus is lost,
+ // we can just use DeferOverlay. You can ONLY call this in a Draw routine. What happens
+ // when you call DeferOverlay is that it schedules with the WidgetManager a call to
+ // this widget's DrawOverlay method at a later time. You can control the order of the
+ // overlay layer, and place it above or below other widgets by optionally specifying
+ // a defer priority in the call to DeferOverlay. The higher the priority, the more toplevel
+ // and thus the more widgets above it will be drawn. You'll notice that in DemoWidget's constructor,
+ // that we set its priority to 1. Thus, if we DeferOverlay with a value of 0, the overlay will be
+ // drawn BELOW the demo widget, but still above all our child widgets and ourself. When mDeferPriority
+ // is 2, it will be drawn above ALL widgets, including the demo widget, as its priority is only 1, which
+ // last time I checked, is less than 2. Note that widgets by default have priority 0 and dialogs have priority 1.
+ //if (mLostFocus)
+ DeferOverlay(mDeferPriority);
+
+}
+
+void Board::DrawOverlay(Graphics* g)
+{
+ // Make sure you've read through Board::Draw before this guy, as it explains
+ // how and why we get here.
+ g->SetColor(Color(0, 0, 255, 175));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color::White);
+ g->DrawString("LOST FOCUS", mMsgX, mMsgY);
+
+ // PushState is a new addition. Previously, any time you changed the
+ // graphic's state, you had to undo it, otherwise it affected anything
+ // drawn later. Common examples are SetColorizeImages, SetColor, SetDrawMode, etc.
+ // With PushState, you save the entire previous state of things. Then, you can make
+ // whatever changes you like, without needing to undo them, as a resulting call to
+ // PopState restores things back to normal. Note that you can push/pop as much as you want.
+ g->PushState();
+
+ // No need to turn this off! When we PopState the previous, non-colorized state,
+ // will return.
+ g->SetColorizeImages(true);
+ g->SetColor(Color(0, 255, 255));
+
+ // MORE NEW STUFF? Yes. Think back to the previous framework version:
+ // how would you draw in real-time, a rotated and scaled image at a given
+ // location? Well, you could mess around with destination Rects for scaling,
+ // but you would have a hard time scaling and rotating all at once. You could
+ // create images in memory to hold the scaled or rotated versions, but that's annoying.
+ // BEHOLD: DrawImageTransform/F. All you have to do is create a Transform object,
+ // and apply various transformations to it, then call DrawImageTransform/F.
+ // Let's take a look:
+ Transform t;
+
+ // Let's rotate the image between 0 and 360 degrees (note that you could also
+ // use the radian version of the function). So far, not hard, right?
+ t.RotateDeg((float)(mUpdateCnt % 360));
+
+ float sw = 1.0f;
+ float sh = 1.0f;
+
+ // Don't get scared here. This is just a little trickery to expand/contract
+ // the image depending on the update count. All it does is expand the image
+ // to normal size for a second, and then shrink it to almost invisible for
+ // another second, which makes that pulse effect happen.
+ int mod = mUpdateCnt % 200;
+ if (mod < 100)
+ {
+ sw = (float)(mod + 1) / 100.0f;
+ sh = (float)(mod + 1) / 100.0f;
+ }
+ else
+ {
+ mod = 200 - mod;
+ sw = (float)mod / 100.0f;
+ sh = (float)mod / 100.0f;
+ }
+
+ // And now we just tell the transform object, t, that we want to scale.
+ // The value for the x and y direction should be a %, so 1.0 means no change in scale.
+ // Let's also mirror and flip the image at the same time too. To mirror and flip, we'll
+ // just multiply sw and sh by -1. Of course, it'll be hard to tell that it's flipped and mirrored
+ // since it's rotating at the same time, so if you don't believe me you can try commenting
+ // out the t.RotateDeg(...) call above and you'll see that it works.
+ t.Scale(-sw, -sh);
+
+ // And now we just pass in our transform object and it works in both 2D and 3D! Note that we can also
+ // draw the image at a given XY as well. We'll make it move rightward depending on the update count.
+ // ******************IMPORTANT NOTE:*********************
+ // DrawImageTransform/F and DrawImageMatrix use the CENTER of the image rather than the top left
+ // for XY drawing. For images of even size, the non-F form of the function will just truncate
+ // the the center, but for the F forms, they will be offset by 0.5f since floating point is used.
+ if (gSexyAppBase->Is3DAccelerated())
+ g->DrawImageTransformF(IMAGE_HUNGARR_LOGO, t, (float)(mUpdateCnt % (mApp->mWidth + 340)), 200.0f);
+ else
+ g->DrawImageTransform(IMAGE_HUNGARR_LOGO, t, (float)(mUpdateCnt % (mApp->mWidth + 340)), 200.0f);
+
+ g->PopState();
+
+ // You can now draw using matrices. Why the heck would you want to use matrices? Besides doing some
+ // crazy stuff, you can also do some cool little tricks. For example, previously it used be a pain
+ // to in real-time flip and mirror an image. While I won't give a tutorial on matrix algebra
+ // (that would take a loooooong time), I'll explain the essential parts:
+ SexyTransform2D matrix;
+
+
+ // Multiplying the X coordinate by -1 (which is the 0, 0 element of the matrix) will result in our
+ // image being mirrored, while multiplying the Y coordinate by -1 (1, 1 in the matrix) will result in our
+ // image being flipped.
+ matrix.m[0][0] *= -1;
+ matrix.m[1][1] *= -1;
+ matrix.RotateDeg(45.0f);
+ g->SetFastStretch(true);
+ bool b = g->GetFastStretch();
+
+ // Let's also shear it. While mirroring/flipping could easily be done with the DrawImageTransform methods,
+ // doing more complex matrix manipulation (like shearing) can only be done with the DrawImageMatrix function.
+ matrix.m[0][1] = 2;
+
+ // And then we just make a call to DrawImageMatrix and give it our specified XY coordinates as well,
+ // and that's it! This works in both 2D and 3D modes.
+ g->DrawImageMatrix(IMAGE_HUNGARR_LOGO, matrix, 300, 400);
+
+ // IMPORTANT COMPARISON NOTE:
+ // DrawImageTransform/F will try to use the faster drawing methods if it recognizes certain
+ // common transforms, like rotating and scaling. This only works though if you are using
+ // either one operation, or multiple operations of the same type (i.e. you only used scale
+ // or rotate with the Transform object, or used the same one multiple times). If you mix
+ // operations, like we do above, the DrawImageTransform method will actually use DrawImageMatrix.
+ // With DrawImageTransform, you can't directly modify the underlying matrix, so if that's something
+ // you need to do, then DrawImageMatrix is a better option.
+}
+
+void Board::ButtonDepress(int id)
+{
+ if (id == mDemoButton->mId)
+ {
+ delete mDemoWidget;
+ mDemoWidget = new DemoWidget();
+ mApp->mWidgetManager->AddWidget(mDemoWidget);
+
+ // What, more flags? Yup. Since our little DemoWidget isn't a dialog, when we add it,
+ // it won't change anything about the widgets drawn below it. Which means, unmodified,
+ // mouse clicks could still be passed down to the board (if the click wasn't in the DemoWidget),
+ // the board still updates, still draws, etc. Let's turn off mouse clicks for all widgets below the
+ // DemoWidget. But, let's still allow all widgets below it to update. Note that if we used the form
+ // of the method that only takes one parameter, then it would use mDefaultBelowModalFlagsMod
+ // which we modified in our app. By passing in our own flags though, they're used instead.
+ // Which means the only flag we need to remove from the widgets below it is the allow mouse flag.
+ // We do that by making a temp FlagsMod object, and setting
+ // its mRemoveFlags variable to be ORed with WIDGETFLAGS_ALLOW_MOUSE. Upon calling
+ // the WidgetManager's AddBaseModal method, we then pass in the DemoWidget, and the above flags.
+ // AddBaseModal will then treat this new widget as a modal object, applying any flags we passed in.
+ FlagsMod flags;
+ flags.mRemoveFlags |= WIDGETFLAGS_ALLOW_MOUSE;
+ mApp->mWidgetManager->AddBaseModal(mDemoWidget, flags);
+ }
+ else if (id == mDialogButton->mId)
+ {
+ // With the new 1.2 changes, you can create dialogs very easily. Previously, you had to supply
+ // images in order to skin the dialog and be able to see it in the first place. You also had to
+ // override the SexyAppBase::NewDialog method, otherwise calls to SexyAppBase::DoDialog wouldn't
+ // do anything. Not so anymore. You can rapidly prototype with dialogs even without images.
+ // A default NewDialog implementation now exists, and if a dialog doesn't have an image, it will
+ // be drawn using colored rectangles. So now, to make a little dialog box appear, it's as simple as
+ // the single line of code below. No messy functions to write, no images to create, that's a hassel
+ // when you're starting a new app and don't care about the initial appearance of your UI elements and
+ // just want to start testing gameplay immediately.
+ Dialog* d = mApp->DoDialog(100, true, "Fun Dialog", "Line 1\nLine 2\nLine 3", "Close!", Dialog::BUTTONS_FOOTER);
+
+ // Using the default font, which is a system font, can sometimes cause problems on older OS's, like
+ // Windows 95 or 98, in which printing with it appears to produce blank results. Let's set the font
+ // for the button on the dialog box to be FONT_DEFAULT.
+ d->SetButtonFont(FONT_DEFAULT);
+ }
+ else if (id == mCurtainButton->mId)
+ {
+ mCurtainMode = CURTAIN_CLOSING;
+ mCurtainWidth = 0;
+
+ // Here's some more new stuff. Previously, if you wanted to do something like
+ // a transition after a button is pressed (for example), you had to set a bunch of
+ // variables in your class, check them, and process/draw differently depending on
+ // the transition state. That can be both messy and annoying to do. Why not just
+ // do the logic for the transition right at the site where it has to trigger, in this
+ // case, right when the button is pressed? If you ignore the UpdateApp() call below for
+ // a minute, what the loop looks like is just a simple loop that makes a variable expand
+ // to 1/2 the app width, and then contract back to 0. If you removed the call to UpdateApp,
+ // obviously the program would be stuck in the loop until it completed, making it look like the
+ // whole thing is frozen, and not updating the display. By putting UpdateApp in the while loop,
+ // you enable ALL the other widgets to update, and thus draw, which in turn means we can see
+ // our little curtain transition effect working as expected. You could even use this method
+ // to block while waiting for a dialog/widget to return, but to still allow other widgets
+ // to update/draw in the process. ONE VERY IMPORTANT THING TO NOTE THOUGH:
+ // If you have code like this in your Update methods, be careful, as you can run into some
+ // reentrancy problems. If you place this sort of code in your Update methods, make sure you
+ // protect it (you could just use a simple bool that's true if doing a transition, otherwise false).
+ // Why? Think about it like this: UpdateApp updates ALL widgets, including the one in which the
+ // while loop exists. Thus, when going back into Update for said widget, it will once again get
+ // stuck in the same while loop, which will effectively prevent any drawing from occurring.
+ // Just remember that UpdateApp will update EVERY widget, and so you will want to avoid having
+ // your while loop called more often than it should. Of course, an easy way to avoid all that
+ // is to have your transition code happen elsewhere that isn't updated every frame, like a
+ // button down method.
+ //
+ // What you'll notice is that if the game lost focus, the curtain call still updates, although
+ // the shrinking/expanding rectangle in the middle does not. That is because when focus is lost,
+ // we don't update that part of the app, but this while loop is still running, which means the
+ // curtain effect is still running too.
+ while ((mCurtainMode != CURTAIN_INACTIVE) && mApp->UpdateApp())
+ {
+ if (mCurtainMode == CURTAIN_CLOSING)
+ {
+ mCurtainWidth += 4;
+ if (mCurtainWidth >= mWidth / 2)
+ {
+ mCurtainWidth = mWidth / 2;
+ mCurtainMode = CURTAIN_OPENING;
+ }
+ }
+ else
+ {
+ mCurtainWidth -= 4;
+ if (mCurtainWidth <= 0)
+ {
+ mCurtainWidth = 0;
+ mCurtainMode = CURTAIN_INACTIVE;
+ }
+ }
+
+ }
+
+ }
+}
diff --git a/osframework/source/demos/V12Demo/.#Board.cpp.1.8 b/osframework/source/demos/V12Demo/.#Board.cpp.1.8
new file mode 100644
index 0000000..a38318b
--- /dev/null
+++ b/osframework/source/demos/V12Demo/.#Board.cpp.1.8
@@ -0,0 +1,442 @@
+#include "Board.h"
+#include "DemoWidget.h"
+#include "Res.h"
+#include "V12DemoApp.h"
+#include "..\SexyAppFramework\Font.h"
+#include "..\SexyAppFramework\Graphics.h"
+#include "..\SexyAppFramework\ButtonWidget.h"
+#include "..\SexyAppFramework\WidgetManager.h"
+#include "..\SexyAppFramework\Dialog.h"
+#include "..\SexyAppFramework\Flags.h"
+#include "..\SexyAppFramework\SexyMatrix.h"
+#include "..\SexyAppFramework\trivertex.h"
+
+using namespace Sexy;
+
+Board::Board(V12DemoApp* theApp)
+{
+ mApp = theApp;
+
+
+ // Remeber the flag explanation in the 1.2 doc and V12Demo.cpp? Sure you do.
+ // This is basically another use of it. All widgets by default have the following
+ // flags set:
+ // WIDGETFLAGS_UPDATE - The widget gets its Update and UpdateF methods called
+ // WIDGETFLAGS_DRAW - The widget is allowed to draw
+ // WIDGETFLAGS_CLIP - Set to clip Graphics passed into Draw to the widget's bounds
+ // WIDGETFLAGS_ALLOW_MOUSE - Set to allow mouse interaction
+ // WIDGETFLAGS_ALLOW_FOCUS - Set to allow focus to be maintained
+ //
+ // Previously, if you wanted to mark the widget dirty every frame (and thus draw every
+ // frame), you had to call MarkDirty() all the time. Instead of doing that, we can just
+ // use the flag system. By ORing WIDGETFLAGS_MARK_DIRTY with mWidgetFlagsMod.mAddFlags,
+ // when we are added to the widget manager, the manager will then know that we want to
+ // be marked dirty every frame automatically, instead of manually calling MarkDirty().
+ // Yes, I know, that's not a huge deal, but as you can see from the other flags,
+ // it's now easy to set/unset various flags for various widgets and..various reasons.
+ // If you wanted to remove flags set by default for this widget, you'd just OR the
+ // flags to remove with mWidgetFlagsMod.mRemoveFlags. You can affect ALL widgets if you
+ // want to set up widget defaults, by modifying mApp->mWidgetManager's mWidgetFlags
+ // structure in a similar way.
+
+ mWidgetFlagsMod.mAddFlags |= WIDGETFLAGS_MARK_DIRTY;
+
+ // Previously, it was annoying trying to place widgets on some sort of parent widget,
+ // since there was no notion of parent/child relationship. What you had to do was
+ // override the AddedToManager and RemovedFromManager functions, create and add your
+ // widgets or remove and nuke them, and in the case of AddedToManager, you also had
+ // to then place the widget using global coordinates that had no relation to the coordinates
+ // you set the parent widget at. Not anymore. What we can do now is to dispense with
+ // overriding those methods altogether! So now, in the parent's constructor, we can
+ // create our child widgets, resize them, and place them using relative coordinates.
+ // What this also means is that moving the parent widget around results in moving
+ // ALL the child widgets, which means you no longer have to manually move everything
+ // just because the parent moved. In addition, another nice thing is that you no longer
+ // have to remove your child widgets before deleting them: this is handled automatically
+ // for you.
+ mDemoButton = new ButtonWidget(0, this);
+ mDemoButton->mLabel = _S("Demo Widget");
+ mDemoButton->SetFont(FONT_DEFAULT);
+ mDemoButton->Resize(10, 10, 10 + FONT_DEFAULT->StringWidth(mDemoButton->mLabel), 50);
+
+ // VERY IMPORTANT: Notice that we're calling THIS CLASS' (or really, it's parent, WidgetContainer's)
+ // AddWidget method instead of the WidgetManager's method. In order to designate a widget as a child
+ // widget, you have to call the AddWidget method of the class that will be its parent.
+ AddWidget(mDemoButton);
+
+ mDialogButton = new ButtonWidget(1, this);
+ mDialogButton->mLabel = _S("Do Dialog");
+ mDialogButton->SetFont(FONT_DEFAULT);
+ int w = FONT_DEFAULT->StringWidth(mDialogButton->mLabel);
+ mDialogButton->Resize(mApp->mWidth - 20 - w, 10, w + 10, 50);
+ AddWidget(mDialogButton);
+
+ mCurtainButton = new ButtonWidget(2, this);
+ mCurtainButton->mLabel = _S("Do Transition");
+ mCurtainButton->SetFont(FONT_DEFAULT);
+ w = FONT_DEFAULT->StringWidth(mCurtainButton->mLabel);
+ mCurtainButton->Resize(mDemoButton->mX + 20 + mDemoButton->mWidth, 10, w + 10, 50);
+ AddWidget(mCurtainButton);
+
+ mDemoWidget = NULL;
+
+ // Position and set up our pulsing rectangle, as well as the location of the lost focus text.
+ mRect = Rect(mApp->mWidth / 2 - 1, mApp->mHeight / 2 - 1, 2, 2);
+ mExpanding = true;
+ mMsgX = Rand() % (mApp->mWidth - 100);
+ mMsgY = Rand() % (mApp->mHeight - 100);
+ mLostFocus = false;
+
+ mCurtainWidth = 0;
+ mCurtainMode = CURTAIN_INACTIVE;
+
+ // We'll toggle this between 0 and 2 every second when we are unfocussed
+ mDeferPriority = 0;
+}
+
+Board::~Board()
+{
+ // We need to remove child widgets before deleting them.
+ RemoveAllWidgets();
+
+ delete mDemoButton;
+ delete mDialogButton;
+ delete mCurtainButton;
+
+ if (mDemoWidget != NULL)
+ mApp->mWidgetManager->RemoveWidget(mDemoWidget);
+
+ delete mDemoWidget;
+}
+
+void Board::Update()
+{
+ Widget::Update();
+
+ if (mLostFocus)
+ {
+ if (mUpdateCnt % 100 == 0)
+ {
+ mMsgX = Rand() % (mApp->mWidth - 100);
+ mMsgY = Rand() % (mApp->mHeight - 100);
+
+ // Every second, we switch between drawing the overlay above or below
+ // the mDemoWidget object (assuming of course you have the widget on screen
+ // when you lose focus).
+ mDeferPriority = mDeferPriority == 0 ? 2 : 0;
+ }
+ }
+ else
+ {
+ // This just makes the rectangle in the middle grow/shrink. Nothing
+ // too crazy.
+ if (mExpanding)
+ {
+ mRect.mWidth += 2;
+ mRect.mHeight += 2;
+
+ if (mRect.mWidth >= mApp->mWidth)
+ {
+ mRect.mWidth = mApp->mWidth;
+ mExpanding = false;
+ }
+
+ if (mRect.mHeight >= mApp->mHeight)
+ {
+ mRect.mHeight = mApp->mHeight;
+ mExpanding = false;
+ }
+ }
+ else
+ {
+ mRect.mWidth -= 2;
+ mRect.mHeight -= 2;
+
+ if (mRect.mHeight <= 0)
+ {
+ mRect.mHeight = 0;
+ mExpanding = true;
+ }
+
+ if (mRect.mWidth <= 0)
+ {
+ mRect.mWidth = 0;
+ mExpanding = true;
+ }
+
+ }
+
+ mRect.mX = mApp->mWidth / 2 - mRect.mWidth / 2;
+ mRect.mY = mApp->mHeight / 2 - mRect.mHeight / 2;
+ }
+}
+
+void Board::Draw(Graphics* g)
+{
+ g->SetColor(Color::Black);
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // Draw our pulsing rectangle in the middle of the screen.
+ g->SetColor(Color(255, 0, 0));
+ g->FillRect(mRect);
+
+ if (!mLostFocus)
+ {
+ // Previously, any time you changed the
+ // graphic's state, you had to undo it, otherwise it affected anything
+ // drawn later. Common examples are SetColorizeImages, SetColor, SetDrawMode, etc.
+ // In Board::DrawOverlay, you'll see that we can use PushState and PopState to on-demand
+ // save/restore the graphics state. However, if we're either lazy, or after we draw
+ // our current stuff we don't have a need to reset the state and change it again, we
+ // can use the GraphicsAutoState object. This nifty helper class, upon instantiation on
+ // the stack, will automatically push the graphics state of the graphics object you pass in.
+ // Note that since stack variables are
+ // removed (and have their con/destructors called automatically, for classes/structs) when they
+ // go out of scope, the destructor for a GraphicsAutoState object takes care of popping the graphics
+ // state and restoring things to their previous..uh...state.
+ // NOTE: Graphics state is saved between widgets.
+ GraphicsAutoState auto_state(g);
+ g->DrawImage(IMAGE_HUNGARR_LOGO, 10, 100);
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+ g->SetColor(Color(mUpdateCnt % 128, mUpdateCnt % 255, mUpdateCnt % 64));
+ g->DrawImage(IMAGE_HUNGARR_LOGO, 10, 100);
+ }
+
+ if (mCurtainMode != CURTAIN_INACTIVE)
+ {
+ g->SetColor(Color(255, 255, 0));
+ g->FillRect(0, 0, mCurtainWidth, mHeight);
+ g->FillRect(mWidth - mCurtainWidth, 0, mCurtainWidth, mHeight);
+ }
+
+ // Instead of using an overlay widget to draw our stuff when focus is lost,
+ // we can just use DeferOverlay. You can ONLY call this in a Draw routine. What happens
+ // when you call DeferOverlay is that it schedules with the WidgetManager a call to
+ // this widget's DrawOverlay method at a later time. You can control the order of the
+ // overlay layer, and place it above or below other widgets by optionally specifying
+ // a defer priority in the call to DeferOverlay. The higher the priority, the more toplevel
+ // and thus the more widgets above it will be drawn. You'll notice that in DemoWidget's constructor,
+ // that we set its priority to 1. Thus, if we DeferOverlay with a value of 0, the overlay will be
+ // drawn BELOW the demo widget, but still above all our child widgets and ourself. When mDeferPriority
+ // is 2, it will be drawn above ALL widgets, including the demo widget, as its priority is only 1, which
+ // last time I checked, is less than 2. Note that widgets by default have priority 0 and dialogs have priority 1.
+ //if (mLostFocus)
+ DeferOverlay(mDeferPriority);
+
+}
+
+void Board::DrawOverlay(Graphics* g)
+{
+ // Make sure you've read through Board::Draw before this guy, as it explains
+ // how and why we get here.
+ g->SetColor(Color(0, 0, 255, 175));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color::White);
+ g->DrawString(_S("LOST FOCUS"), mMsgX, mMsgY);
+
+ // PushState is a new addition. Previously, any time you changed the
+ // graphic's state, you had to undo it, otherwise it affected anything
+ // drawn later. Common examples are SetColorizeImages, SetColor, SetDrawMode, etc.
+ // With PushState, you save the entire previous state of things. Then, you can make
+ // whatever changes you like, without needing to undo them, as a resulting call to
+ // PopState restores things back to normal. Note that you can push/pop as much as you want.
+ g->PushState();
+
+ // No need to turn this off! When we PopState the previous, non-colorized state,
+ // will return.
+ g->SetColorizeImages(true);
+ g->SetColor(Color(0, 255, 255));
+
+ // MORE NEW STUFF? Yes. Think back to the previous framework version:
+ // how would you draw in real-time, a rotated and scaled image at a given
+ // location? Well, you could mess around with destination Rects for scaling,
+ // but you would have a hard time scaling and rotating all at once. You could
+ // create images in memory to hold the scaled or rotated versions, but that's annoying.
+ // BEHOLD: DrawImageTransform/F. All you have to do is create a Transform object,
+ // and apply various transformations to it, then call DrawImageTransform/F.
+ // Let's take a look:
+ Transform t;
+
+ // Let's rotate the image between 0 and 360 degrees (note that you could also
+ // use the radian version of the function). So far, not hard, right?
+ t.RotateDeg((float)(mUpdateCnt % 360));
+
+ float sw = 1.0f;
+ float sh = 1.0f;
+
+ // Don't get scared here. This is just a little trickery to expand/contract
+ // the image depending on the update count. All it does is expand the image
+ // to normal size for a second, and then shrink it to almost invisible for
+ // another second, which makes that pulse effect happen.
+ int mod = mUpdateCnt % 200;
+ if (mod < 100)
+ {
+ sw = (float)(mod + 1) / 100.0f;
+ sh = (float)(mod + 1) / 100.0f;
+ }
+ else
+ {
+ mod = 200 - mod;
+ sw = (float)mod / 100.0f;
+ sh = (float)mod / 100.0f;
+ }
+
+ // And now we just tell the transform object, t, that we want to scale.
+ // The value for the x and y direction should be a %, so 1.0 means no change in scale.
+ // Let's also mirror and flip the image at the same time too. To mirror and flip, we'll
+ // just multiply sw and sh by -1. Of course, it'll be hard to tell that it's flipped and mirrored
+ // since it's rotating at the same time, so if you don't believe me you can try commenting
+ // out the t.RotateDeg(...) call above and you'll see that it works.
+ t.Scale(-sw, -sh);
+
+ // And now we just pass in our transform object and it works in both 2D and 3D! Note that we can also
+ // draw the image at a given XY as well. We'll make it move rightward depending on the update count.
+ // ******************IMPORTANT NOTE:*********************
+ // DrawImageTransform/F and DrawImageMatrix use the CENTER of the image rather than the top left
+ // for XY drawing. For images of even size, the non-F form of the function will just truncate
+ // the the center, but for the F forms, they will be offset by 0.5f since floating point is used.
+ if (gSexyAppBase->Is3DAccelerated())
+ g->DrawImageTransformF(IMAGE_HUNGARR_LOGO, t, (float)(mUpdateCnt % (mApp->mWidth + 340)), 200.0f);
+ else
+ g->DrawImageTransform(IMAGE_HUNGARR_LOGO, t, (float)(mUpdateCnt % (mApp->mWidth + 340)), 200.0f);
+
+ g->PopState();
+
+ // You can now draw using matrices. Why the heck would you want to use matrices? Besides doing some
+ // crazy stuff, you can also do some cool little tricks. For example, previously it used be a pain
+ // to in real-time flip and mirror an image. While I won't give a tutorial on matrix algebra
+ // (that would take a loooooong time), I'll explain the essential parts:
+ SexyTransform2D matrix;
+
+
+ // Multiplying the X coordinate by -1 (which is the 0, 0 element of the matrix) will result in our
+ // image being mirrored, while multiplying the Y coordinate by -1 (1, 1 in the matrix) will result in our
+ // image being flipped.
+ matrix.m[0][0] *= -1;
+ matrix.m[1][1] *= -1;
+ matrix.RotateDeg(45.0f);
+ g->SetFastStretch(true);
+ bool b = g->GetFastStretch();
+
+ // Let's also shear it. While mirroring/flipping could easily be done with the DrawImageTransform methods,
+ // doing more complex matrix manipulation (like shearing) can only be done with the DrawImageMatrix function.
+ matrix.m[0][1] = 2;
+
+ // And then we just make a call to DrawImageMatrix and give it our specified XY coordinates as well,
+ // and that's it! This works in both 2D and 3D modes.
+ g->DrawImageMatrix(IMAGE_HUNGARR_LOGO, matrix, 300, 400);
+
+ // IMPORTANT COMPARISON NOTE:
+ // DrawImageTransform/F will try to use the faster drawing methods if it recognizes certain
+ // common transforms, like rotating and scaling. This only works though if you are using
+ // either one operation, or multiple operations of the same type (i.e. you only used scale
+ // or rotate with the Transform object, or used the same one multiple times). If you mix
+ // operations, like we do above, the DrawImageTransform method will actually use DrawImageMatrix.
+ // With DrawImageTransform, you can't directly modify the underlying matrix, so if that's something
+ // you need to do, then DrawImageMatrix is a better option.
+}
+
+void Board::ButtonDepress(int id)
+{
+ if (id == mDemoButton->mId)
+ {
+ delete mDemoWidget;
+ mDemoWidget = new DemoWidget();
+ mApp->mWidgetManager->AddWidget(mDemoWidget);
+
+ // What, more flags? Yup. Since our little DemoWidget isn't a dialog, when we add it,
+ // it won't change anything about the widgets drawn below it. Which means, unmodified,
+ // mouse clicks could still be passed down to the board (if the click wasn't in the DemoWidget),
+ // the board still updates, still draws, etc. Let's turn off mouse clicks for all widgets below the
+ // DemoWidget. But, let's still allow all widgets below it to update. Note that if we used the form
+ // of the method that only takes one parameter, then it would use mDefaultBelowModalFlagsMod
+ // which we modified in our app. By passing in our own flags though, they're used instead.
+ // Which means the only flag we need to remove from the widgets below it is the allow mouse flag.
+ // We do that by making a temp FlagsMod object, and setting
+ // its mRemoveFlags variable to be ORed with WIDGETFLAGS_ALLOW_MOUSE. Upon calling
+ // the WidgetManager's AddBaseModal method, we then pass in the DemoWidget, and the above flags.
+ // AddBaseModal will then treat this new widget as a modal object, applying any flags we passed in.
+ FlagsMod flags;
+ flags.mRemoveFlags |= WIDGETFLAGS_ALLOW_MOUSE;
+ mApp->mWidgetManager->AddBaseModal(mDemoWidget, flags);
+ }
+ else if (id == mDialogButton->mId)
+ {
+ // With the new 1.2 changes, you can create dialogs very easily. Previously, you had to supply
+ // images in order to skin the dialog and be able to see it in the first place. You also had to
+ // override the SexyAppBase::NewDialog method, otherwise calls to SexyAppBase::DoDialog wouldn't
+ // do anything. Not so anymore. You can rapidly prototype with dialogs even without images.
+ // A default NewDialog implementation now exists, and if a dialog doesn't have an image, it will
+ // be drawn using colored rectangles. So now, to make a little dialog box appear, it's as simple as
+ // the single line of code below. No messy functions to write, no images to create, that's a hassel
+ // when you're starting a new app and don't care about the initial appearance of your UI elements and
+ // just want to start testing gameplay immediately.
+ Dialog* d = mApp->DoDialog(100, true, _S("Fun Dialog"), _S("Line 1\nLine 2\nLine 3"), _S("Close!"), Dialog::BUTTONS_FOOTER);
+
+ // Using the default font, which is a system font, can sometimes cause problems on older OS's, like
+ // Windows 95 or 98, in which printing with it appears to produce blank results. Let's set the font
+ // for the button on the dialog box to be FONT_DEFAULT.
+ d->SetButtonFont(FONT_DEFAULT);
+ }
+ else if (id == mCurtainButton->mId)
+ {
+ mCurtainMode = CURTAIN_CLOSING;
+ mCurtainWidth = 0;
+
+ // Here's some more new stuff. Previously, if you wanted to do something like
+ // a transition after a button is pressed (for example), you had to set a bunch of
+ // variables in your class, check them, and process/draw differently depending on
+ // the transition state. That can be both messy and annoying to do. Why not just
+ // do the logic for the transition right at the site where it has to trigger, in this
+ // case, right when the button is pressed? If you ignore the UpdateApp() call below for
+ // a minute, what the loop looks like is just a simple loop that makes a variable expand
+ // to 1/2 the app width, and then contract back to 0. If you removed the call to UpdateApp,
+ // obviously the program would be stuck in the loop until it completed, making it look like the
+ // whole thing is frozen, and not updating the display. By putting UpdateApp in the while loop,
+ // you enable ALL the other widgets to update, and thus draw, which in turn means we can see
+ // our little curtain transition effect working as expected. You could even use this method
+ // to block while waiting for a dialog/widget to return, but to still allow other widgets
+ // to update/draw in the process. ONE VERY IMPORTANT THING TO NOTE THOUGH:
+ // If you have code like this in your Update methods, be careful, as you can run into some
+ // reentrancy problems. If you place this sort of code in your Update methods, make sure you
+ // protect it (you could just use a simple bool that's true if doing a transition, otherwise false).
+ // Why? Think about it like this: UpdateApp updates ALL widgets, including the one in which the
+ // while loop exists. Thus, when going back into Update for said widget, it will once again get
+ // stuck in the same while loop, which will effectively prevent any drawing from occurring.
+ // Just remember that UpdateApp will update EVERY widget, and so you will want to avoid having
+ // your while loop called more often than it should. Of course, an easy way to avoid all that
+ // is to have your transition code happen elsewhere that isn't updated every frame, like a
+ // button down method.
+ //
+ // What you'll notice is that if the game lost focus, the curtain call still updates, although
+ // the shrinking/expanding rectangle in the middle does not. That is because when focus is lost,
+ // we don't update that part of the app, but this while loop is still running, which means the
+ // curtain effect is still running too.
+ while ((mCurtainMode != CURTAIN_INACTIVE) && mApp->UpdateApp())
+ {
+ if (mCurtainMode == CURTAIN_CLOSING)
+ {
+ mCurtainWidth += 4;
+ if (mCurtainWidth >= mWidth / 2)
+ {
+ mCurtainWidth = mWidth / 2;
+ mCurtainMode = CURTAIN_OPENING;
+ }
+ }
+ else
+ {
+ mCurtainWidth -= 4;
+ if (mCurtainWidth <= 0)
+ {
+ mCurtainWidth = 0;
+ mCurtainMode = CURTAIN_INACTIVE;
+ }
+ }
+
+ }
+
+ }
+}
diff --git a/osframework/source/demos/V12Demo/Board.cpp b/osframework/source/demos/V12Demo/Board.cpp
new file mode 100644
index 0000000..1aa2b1e
--- /dev/null
+++ b/osframework/source/demos/V12Demo/Board.cpp
@@ -0,0 +1,439 @@
+#include "Board.h"
+#include "DemoWidget.h"
+#include "Res.h"
+#include "V12DemoApp.h"
+#include "..\SexyAppFramework\Font.h"
+#include "..\SexyAppFramework\Graphics.h"
+#include "..\SexyAppFramework\ButtonWidget.h"
+#include "..\SexyAppFramework\WidgetManager.h"
+#include "..\SexyAppFramework\Dialog.h"
+#include "..\SexyAppFramework\Flags.h"
+#include "..\SexyAppFramework\SexyMatrix.h"
+#include "..\SexyAppFramework\trivertex.h"
+
+using namespace Sexy;
+
+Board::Board(V12DemoApp* theApp)
+{
+ mApp = theApp;
+
+
+ // Remeber the flag explanation in the 1.2 doc and V12Demo.cpp? Sure you do.
+ // This is basically another use of it. All widgets by default have the following
+ // flags set:
+ // WIDGETFLAGS_UPDATE - The widget gets its Update and UpdateF methods called
+ // WIDGETFLAGS_DRAW - The widget is allowed to draw
+ // WIDGETFLAGS_CLIP - Set to clip Graphics passed into Draw to the widget's bounds
+ // WIDGETFLAGS_ALLOW_MOUSE - Set to allow mouse interaction
+ // WIDGETFLAGS_ALLOW_FOCUS - Set to allow focus to be maintained
+ //
+ // Previously, if you wanted to mark the widget dirty every frame (and thus draw every
+ // frame), you had to call MarkDirty() all the time. Instead of doing that, we can just
+ // use the flag system. By ORing WIDGETFLAGS_MARK_DIRTY with mWidgetFlagsMod.mAddFlags,
+ // when we are added to the widget manager, the manager will then know that we want to
+ // be marked dirty every frame automatically, instead of manually calling MarkDirty().
+ // Yes, I know, that's not a huge deal, but as you can see from the other flags,
+ // it's now easy to set/unset various flags for various widgets and..various reasons.
+ // If you wanted to remove flags set by default for this widget, you'd just OR the
+ // flags to remove with mWidgetFlagsMod.mRemoveFlags. You can affect ALL widgets if you
+ // want to set up widget defaults, by modifying mApp->mWidgetManager's mWidgetFlags
+ // structure in a similar way.
+
+ mWidgetFlagsMod.mAddFlags |= WIDGETFLAGS_MARK_DIRTY;
+
+ // Previously, it was annoying trying to place widgets on some sort of parent widget,
+ // since there was no notion of parent/child relationship. What you had to do was
+ // override the AddedToManager and RemovedFromManager functions, create and add your
+ // widgets or remove and nuke them, and in the case of AddedToManager, you also had
+ // to then place the widget using global coordinates that had no relation to the coordinates
+ // you set the parent widget at. Not anymore. What we can do now is to dispense with
+ // overriding those methods altogether! So now, in the parent's constructor, we can
+ // create our child widgets, resize them, and place them using relative coordinates.
+ // What this also means is that moving the parent widget around results in moving
+ // ALL the child widgets, which means you no longer have to manually move everything
+ // just because the parent moved. In addition, another nice thing is that you no longer
+ // have to remove your child widgets before deleting them: this is handled automatically
+ // for you.
+ mDemoButton = new ButtonWidget(0, this);
+ mDemoButton->mLabel = _S("Demo Widget");
+ mDemoButton->SetFont(FONT_DEFAULT);
+ mDemoButton->Resize(10, 10, 10 + FONT_DEFAULT->StringWidth(mDemoButton->mLabel), 50);
+
+ // VERY IMPORTANT: Notice that we're calling THIS CLASS' (or really, it's parent, WidgetContainer's)
+ // AddWidget method instead of the WidgetManager's method. In order to designate a widget as a child
+ // widget, you have to call the AddWidget method of the class that will be its parent.
+ AddWidget(mDemoButton);
+
+ mDialogButton = new ButtonWidget(1, this);
+ mDialogButton->mLabel = _S("Do Dialog");
+ mDialogButton->SetFont(FONT_DEFAULT);
+ int w = FONT_DEFAULT->StringWidth(mDialogButton->mLabel);
+ mDialogButton->Resize(mApp->mWidth - 20 - w, 10, w + 10, 50);
+ AddWidget(mDialogButton);
+
+ mCurtainButton = new ButtonWidget(2, this);
+ mCurtainButton->mLabel = _S("Do Transition");
+ mCurtainButton->SetFont(FONT_DEFAULT);
+ w = FONT_DEFAULT->StringWidth(mCurtainButton->mLabel);
+ mCurtainButton->Resize(mDemoButton->mX + 20 + mDemoButton->mWidth, 10, w + 10, 50);
+ AddWidget(mCurtainButton);
+
+ mDemoWidget = NULL;
+
+ // Position and set up our pulsing rectangle, as well as the location of the lost focus text.
+ mRect = Rect(mApp->mWidth / 2 - 1, mApp->mHeight / 2 - 1, 2, 2);
+ mExpanding = true;
+ mMsgX = Rand() % (mApp->mWidth - 100);
+ mMsgY = Rand() % (mApp->mHeight - 100);
+ mLostFocus = false;
+
+ mCurtainWidth = 0;
+ mCurtainMode = CURTAIN_INACTIVE;
+
+ // We'll toggle this between 0 and 2 every second when we are unfocussed
+ mDeferPriority = 0;
+}
+
+Board::~Board()
+{
+ // We need to remove child widgets before deleting them.
+ RemoveAllWidgets();
+
+ delete mDemoButton;
+ delete mDialogButton;
+ delete mCurtainButton;
+
+ if (mDemoWidget != NULL)
+ mApp->mWidgetManager->RemoveWidget(mDemoWidget);
+
+ delete mDemoWidget;
+}
+
+void Board::Update()
+{
+ Widget::Update();
+
+ if (mLostFocus)
+ {
+ if (mUpdateCnt % 100 == 0)
+ {
+ mMsgX = Rand() % (mApp->mWidth - 100);
+ mMsgY = Rand() % (mApp->mHeight - 100);
+
+ // Every second, we switch between drawing the overlay above or below
+ // the mDemoWidget object (assuming of course you have the widget on screen
+ // when you lose focus).
+ mDeferPriority = mDeferPriority == 0 ? 2 : 0;
+ }
+ }
+ else
+ {
+ // This just makes the rectangle in the middle grow/shrink. Nothing
+ // too crazy.
+ if (mExpanding)
+ {
+ mRect.mWidth += 2;
+ mRect.mHeight += 2;
+
+ if (mRect.mWidth >= mApp->mWidth)
+ {
+ mRect.mWidth = mApp->mWidth;
+ mExpanding = false;
+ }
+
+ if (mRect.mHeight >= mApp->mHeight)
+ {
+ mRect.mHeight = mApp->mHeight;
+ mExpanding = false;
+ }
+ }
+ else
+ {
+ mRect.mWidth -= 2;
+ mRect.mHeight -= 2;
+
+ if (mRect.mHeight <= 0)
+ {
+ mRect.mHeight = 0;
+ mExpanding = true;
+ }
+
+ if (mRect.mWidth <= 0)
+ {
+ mRect.mWidth = 0;
+ mExpanding = true;
+ }
+
+ }
+
+ mRect.mX = mApp->mWidth / 2 - mRect.mWidth / 2;
+ mRect.mY = mApp->mHeight / 2 - mRect.mHeight / 2;
+ }
+}
+
+void Board::Draw(Graphics* g)
+{
+ g->SetColor(Color::Black);
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ // Draw our pulsing rectangle in the middle of the screen.
+ g->SetColor(Color(255, 0, 0));
+ g->FillRect(mRect);
+
+ if (!mLostFocus)
+ {
+ // Previously, any time you changed the
+ // graphic's state, you had to undo it, otherwise it affected anything
+ // drawn later. Common examples are SetColorizeImages, SetColor, SetDrawMode, etc.
+ // In Board::DrawOverlay, you'll see that we can use PushState and PopState to on-demand
+ // save/restore the graphics state. However, if we're either lazy, or after we draw
+ // our current stuff we don't have a need to reset the state and change it again, we
+ // can use the GraphicsAutoState object. This nifty helper class, upon instantiation on
+ // the stack, will automatically push the graphics state of the graphics object you pass in.
+ // Note that since stack variables are
+ // removed (and have their con/destructors called automatically, for classes/structs) when they
+ // go out of scope, the destructor for a GraphicsAutoState object takes care of popping the graphics
+ // state and restoring things to their previous..uh...state.
+ // NOTE: Graphics state is saved between widgets.
+ GraphicsAutoState auto_state(g);
+ g->DrawImage(IMAGE_HUNGARR_LOGO, 10, 100);
+ g->SetDrawMode(Graphics::DRAWMODE_ADDITIVE);
+ g->SetColorizeImages(true);
+ g->SetColor(Color(mUpdateCnt % 128, mUpdateCnt % 255, mUpdateCnt % 64));
+ g->DrawImage(IMAGE_HUNGARR_LOGO, 10, 100);
+ }
+
+ if (mCurtainMode != CURTAIN_INACTIVE)
+ {
+ g->SetColor(Color(255, 255, 0));
+ g->FillRect(0, 0, mCurtainWidth, mHeight);
+ g->FillRect(mWidth - mCurtainWidth, 0, mCurtainWidth, mHeight);
+ }
+
+ // Instead of using an overlay widget to draw our stuff when focus is lost,
+ // we can just use DeferOverlay. You can ONLY call this in a Draw routine. What happens
+ // when you call DeferOverlay is that it schedules with the WidgetManager a call to
+ // this widget's DrawOverlay method at a later time. You can control the order of the
+ // overlay layer, and place it above or below other widgets by optionally specifying
+ // a defer priority in the call to DeferOverlay. The higher the priority, the more toplevel
+ // and thus the more widgets above it will be drawn. You'll notice that in DemoWidget's constructor,
+ // that we set its priority to 1. Thus, if we DeferOverlay with a value of 0, the overlay will be
+ // drawn BELOW the demo widget, but still above all our child widgets and ourself. When mDeferPriority
+ // is 2, it will be drawn above ALL widgets, including the demo widget, as its priority is only 1, which
+ // last time I checked, is less than 2. Note that widgets by default have priority 0 and dialogs have priority 1.
+ if (mLostFocus)
+ DeferOverlay(mDeferPriority);
+
+}
+
+void Board::DrawOverlay(Graphics* g)
+{
+ // Make sure you've read through Board::Draw before this guy, as it explains
+ // how and why we get here.
+ g->SetColor(Color(0, 0, 255, 175));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color::White);
+ g->DrawString(_S("LOST FOCUS"), mMsgX, mMsgY);
+
+ // PushState is a new addition. Previously, any time you changed the
+ // graphic's state, you had to undo it, otherwise it affected anything
+ // drawn later. Common examples are SetColorizeImages, SetColor, SetDrawMode, etc.
+ // With PushState, you save the entire previous state of things. Then, you can make
+ // whatever changes you like, without needing to undo them, as a resulting call to
+ // PopState restores things back to normal. Note that you can push/pop as much as you want.
+ g->PushState();
+
+ // No need to turn this off! When we PopState the previous, non-colorized state,
+ // will return.
+ g->SetColorizeImages(true);
+ g->SetColor(Color(0, 255, 255));
+
+ // MORE NEW STUFF? Yes. Think back to the previous framework version:
+ // how would you draw in real-time, a rotated and scaled image at a given
+ // location? Well, you could mess around with destination Rects for scaling,
+ // but you would have a hard time scaling and rotating all at once. You could
+ // create images in memory to hold the scaled or rotated versions, but that's annoying.
+ // BEHOLD: DrawImageTransform/F. All you have to do is create a Transform object,
+ // and apply various transformations to it, then call DrawImageTransform/F.
+ // Let's take a look:
+ Transform t;
+
+ // Let's rotate the image between 0 and 360 degrees (note that you could also
+ // use the radian version of the function). So far, not hard, right?
+ t.RotateDeg((float)(mUpdateCnt % 360));
+
+ float sw = 1.0f;
+ float sh = 1.0f;
+
+ // Don't get scared here. This is just a little trickery to expand/contract
+ // the image depending on the update count. All it does is expand the image
+ // to normal size for a second, and then shrink it to almost invisible for
+ // another second, which makes that pulse effect happen.
+ int mod = mUpdateCnt % 200;
+ if (mod < 100)
+ {
+ sw = (float)(mod + 1) / 100.0f;
+ sh = (float)(mod + 1) / 100.0f;
+ }
+ else
+ {
+ mod = 200 - mod;
+ sw = (float)mod / 100.0f;
+ sh = (float)mod / 100.0f;
+ }
+
+ // And now we just tell the transform object, t, that we want to scale.
+ // The value for the x and y direction should be a %, so 1.0 means no change in scale.
+ // Let's also mirror and flip the image at the same time too. To mirror and flip, we'll
+ // just multiply sw and sh by -1. Of course, it'll be hard to tell that it's flipped and mirrored
+ // since it's rotating at the same time, so if you don't believe me you can try commenting
+ // out the t.RotateDeg(...) call above and you'll see that it works.
+ t.Scale(-sw, -sh);
+
+ // And now we just pass in our transform object and it works in both 2D and 3D! Note that we can also
+ // draw the image at a given XY as well. We'll make it move rightward depending on the update count.
+ // ******************IMPORTANT NOTE:*********************
+ // DrawImageTransform/F and DrawImageMatrix use the CENTER of the image rather than the top left
+ // for XY drawing. For images of even size, the non-F form of the function will just truncate
+ // the the center, but for the F forms, they will be offset by 0.5f since floating point is used.
+ if (gSexyAppBase->Is3DAccelerated())
+ g->DrawImageTransformF(IMAGE_HUNGARR_LOGO, t, (float)(mUpdateCnt % (mApp->mWidth + 340)), 200.0f);
+ else
+ g->DrawImageTransform(IMAGE_HUNGARR_LOGO, t, (float)(mUpdateCnt % (mApp->mWidth + 340)), 200.0f);
+
+ g->PopState();
+
+ // You can now draw using matrices. Why the heck would you want to use matrices? Besides doing some
+ // crazy stuff, you can also do some cool little tricks. For example, previously it used be a pain
+ // to in real-time flip and mirror an image. While I won't give a tutorial on matrix algebra
+ // (that would take a loooooong time), I'll explain the essential parts:
+ SexyTransform2D matrix;
+
+
+ // Multiplying the X coordinate by -1 (which is the 0, 0 element of the matrix) will result in our
+ // image being mirrored, while multiplying the Y coordinate by -1 (1, 1 in the matrix) will result in our
+ // image being flipped.
+ matrix.m[0][0] *= -1;
+ matrix.m[1][1] *= -1;
+
+ // Let's also shear it. While mirroring/flipping could easily be done with the DrawImageTransform methods,
+ // doing more complex matrix manipulation (like shearing) can only be done with the DrawImageMatrix function.
+ matrix.m[0][1] = 2;
+
+ // And then we just make a call to DrawImageMatrix and give it our specified XY coordinates as well,
+ // and that's it! This works in both 2D and 3D modes.
+ g->DrawImageMatrix(IMAGE_HUNGARR_LOGO, matrix, 300, 400);
+
+ // IMPORTANT COMPARISON NOTE:
+ // DrawImageTransform/F will try to use the faster drawing methods if it recognizes certain
+ // common transforms, like rotating and scaling. This only works though if you are using
+ // either one operation, or multiple operations of the same type (i.e. you only used scale
+ // or rotate with the Transform object, or used the same one multiple times). If you mix
+ // operations, like we do above, the DrawImageTransform method will actually use DrawImageMatrix.
+ // With DrawImageTransform, you can't directly modify the underlying matrix, so if that's something
+ // you need to do, then DrawImageMatrix is a better option.
+}
+
+void Board::ButtonDepress(int id)
+{
+ if (id == mDemoButton->mId)
+ {
+ delete mDemoWidget;
+ mDemoWidget = new DemoWidget();
+ mApp->mWidgetManager->AddWidget(mDemoWidget);
+
+ // What, more flags? Yup. Since our little DemoWidget isn't a dialog, when we add it,
+ // it won't change anything about the widgets drawn below it. Which means, unmodified,
+ // mouse clicks could still be passed down to the board (if the click wasn't in the DemoWidget),
+ // the board still updates, still draws, etc. Let's turn off mouse clicks for all widgets below the
+ // DemoWidget. But, let's still allow all widgets below it to update. Note that if we used the form
+ // of the method that only takes one parameter, then it would use mDefaultBelowModalFlagsMod
+ // which we modified in our app. By passing in our own flags though, they're used instead.
+ // Which means the only flag we need to remove from the widgets below it is the allow mouse flag.
+ // We do that by making a temp FlagsMod object, and setting
+ // its mRemoveFlags variable to be ORed with WIDGETFLAGS_ALLOW_MOUSE. Upon calling
+ // the WidgetManager's AddBaseModal method, we then pass in the DemoWidget, and the above flags.
+ // AddBaseModal will then treat this new widget as a modal object, applying any flags we passed in.
+ FlagsMod flags;
+ flags.mRemoveFlags |= WIDGETFLAGS_ALLOW_MOUSE;
+ mApp->mWidgetManager->AddBaseModal(mDemoWidget, flags);
+ }
+ else if (id == mDialogButton->mId)
+ {
+ // With the new 1.2 changes, you can create dialogs very easily. Previously, you had to supply
+ // images in order to skin the dialog and be able to see it in the first place. You also had to
+ // override the SexyAppBase::NewDialog method, otherwise calls to SexyAppBase::DoDialog wouldn't
+ // do anything. Not so anymore. You can rapidly prototype with dialogs even without images.
+ // A default NewDialog implementation now exists, and if a dialog doesn't have an image, it will
+ // be drawn using colored rectangles. So now, to make a little dialog box appear, it's as simple as
+ // the single line of code below. No messy functions to write, no images to create, that's a hassel
+ // when you're starting a new app and don't care about the initial appearance of your UI elements and
+ // just want to start testing gameplay immediately.
+ Dialog* d = mApp->DoDialog(100, true, _S("Fun Dialog"), _S("Line 1\nLine 2\nLine 3"), _S("Close!"), Dialog::BUTTONS_FOOTER);
+
+ // Using the default font, which is a system font, can sometimes cause problems on older OS's, like
+ // Windows 95 or 98, in which printing with it appears to produce blank results. Let's set the font
+ // for the button on the dialog box to be FONT_DEFAULT.
+ d->SetButtonFont(FONT_DEFAULT);
+ }
+ else if (id == mCurtainButton->mId)
+ {
+ mCurtainMode = CURTAIN_CLOSING;
+ mCurtainWidth = 0;
+
+ // Here's some more new stuff. Previously, if you wanted to do something like
+ // a transition after a button is pressed (for example), you had to set a bunch of
+ // variables in your class, check them, and process/draw differently depending on
+ // the transition state. That can be both messy and annoying to do. Why not just
+ // do the logic for the transition right at the site where it has to trigger, in this
+ // case, right when the button is pressed? If you ignore the UpdateApp() call below for
+ // a minute, what the loop looks like is just a simple loop that makes a variable expand
+ // to 1/2 the app width, and then contract back to 0. If you removed the call to UpdateApp,
+ // obviously the program would be stuck in the loop until it completed, making it look like the
+ // whole thing is frozen, and not updating the display. By putting UpdateApp in the while loop,
+ // you enable ALL the other widgets to update, and thus draw, which in turn means we can see
+ // our little curtain transition effect working as expected. You could even use this method
+ // to block while waiting for a dialog/widget to return, but to still allow other widgets
+ // to update/draw in the process. ONE VERY IMPORTANT THING TO NOTE THOUGH:
+ // If you have code like this in your Update methods, be careful, as you can run into some
+ // reentrancy problems. If you place this sort of code in your Update methods, make sure you
+ // protect it (you could just use a simple bool that's true if doing a transition, otherwise false).
+ // Why? Think about it like this: UpdateApp updates ALL widgets, including the one in which the
+ // while loop exists. Thus, when going back into Update for said widget, it will once again get
+ // stuck in the same while loop, which will effectively prevent any drawing from occurring.
+ // Just remember that UpdateApp will update EVERY widget, and so you will want to avoid having
+ // your while loop called more often than it should. Of course, an easy way to avoid all that
+ // is to have your transition code happen elsewhere that isn't updated every frame, like a
+ // button down method.
+ //
+ // What you'll notice is that if the game lost focus, the curtain call still updates, although
+ // the shrinking/expanding rectangle in the middle does not. That is because when focus is lost,
+ // we don't update that part of the app, but this while loop is still running, which means the
+ // curtain effect is still running too.
+ while ((mCurtainMode != CURTAIN_INACTIVE) && mApp->UpdateApp())
+ {
+ if (mCurtainMode == CURTAIN_CLOSING)
+ {
+ mCurtainWidth += 4;
+ if (mCurtainWidth >= mWidth / 2)
+ {
+ mCurtainWidth = mWidth / 2;
+ mCurtainMode = CURTAIN_OPENING;
+ }
+ }
+ else
+ {
+ mCurtainWidth -= 4;
+ if (mCurtainWidth <= 0)
+ {
+ mCurtainWidth = 0;
+ mCurtainMode = CURTAIN_INACTIVE;
+ }
+ }
+
+ }
+
+ }
+}
diff --git a/osframework/source/demos/V12Demo/Board.h b/osframework/source/demos/V12Demo/Board.h
new file mode 100644
index 0000000..f14f1db
--- /dev/null
+++ b/osframework/source/demos/V12Demo/Board.h
@@ -0,0 +1,87 @@
+#ifndef __BOARD_H__
+#define __BOARD_H__
+
+#include "..\SexyAppFramework\Widget.h"
+#include "..\SexyAppFramework\ButtonListener.h"
+#include "..\SexyAppFramework\Rect.h"
+
+namespace Sexy
+{
+
+class V12DemoApp;
+class DemoWidget;
+class ButtonWidget;
+
+class Board : public Widget, public ButtonListener
+{
+
+public:
+
+ V12DemoApp* mApp;
+
+private:
+
+ // We're going to do a curtain open/close effect when the mCurtainButton button is pressed.
+ enum
+ {
+ CURTAIN_CLOSING,
+ CURTAIN_OPENING,
+ CURTAIN_INACTIVE
+ };
+
+ DemoWidget* mDemoWidget;
+ ButtonWidget* mDemoButton; // Creates our DemoWidget
+ ButtonWidget* mDialogButton; // Creates a little dialog box
+ ButtonWidget* mCurtainButton; // Initiates the curtain closing/opening transition
+ Rect mRect; // A rectangle that gets larger/smaller over time
+
+ bool mExpanding; // Is the above (mRect) rectangle shrinking or growing?
+ bool mLostFocus; // If true, the app has lost focus, so we'll draw our overlay
+
+ int mCurtainMode; // One of the above enums
+ int mCurtainWidth; // How wide the curtain is. This ranges from 0 to app width / 2.
+ int mDeferPriority; // See the .cpp for full info, but we'll be toggling the overlay priority every second
+ int mMsgX, mMsgY; // For no valid reason, we'll move the "LOST FOCUS" text every second.
+
+public:
+
+ Board(V12DemoApp* theApp);
+ virtual ~Board();
+
+ void Update();
+ void Draw(Graphics* g);
+ void ButtonDepress(int id);
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DrawOverlay
+ // Parameters: g - The graphics object to draw with
+ //
+ // Purpose: Previously, you had to make a separate OverlayWidget object
+ // if you wanted to do a full screen overlay for say a paused state.
+ // That was annoying, since you had to deal with the messiness of ensuring
+ // that it covered all the appropriate widgets, and had to take care when
+ // removing it. Plus, it was a waste to have to make such a minor object
+ // just to draw a layer above other widgets. Enter the DrawOverlay method:
+ // In your main Draw(...) method, whenever you want the overlay to be drawn,
+ // you just make a call to DeferOverlay. You can pass in a priority that indicates
+ // when the overlay is drawn: the default is 0, but the higher the priority, the
+ // more toplevel (and thus the higher above the other widgets) it will be drawn at.
+ // This can be easily used to draw layers above ALL widgets, or to draw layers above
+ // most widgets but still below some sort of other widget, like an options dialog, etc.
+ // Widgets also have an mPriority variable (defaults to 0), which, setting it higher, will
+ // of course affect at which order in the drawing routine it runs at.
+ //
+ // NOTE: This can be used for anything, not just the pause state. You could
+ // easily have an effect that transitions from one level to the next, and
+ // it could be drawn above all the buttons/widgets on screen, rather than
+ // using some sort of overlay widget as well.
+ //////////////////////////////////////////////////////////////////////////
+ void DrawOverlay(Graphics* g);
+
+
+ void SetFocusLost(bool f) {mLostFocus = f; mDeferPriority = 2;}
+};
+
+}
+
+#endif //__BOARD_H__
diff --git a/osframework/source/demos/V12Demo/DemoWidget.cpp b/osframework/source/demos/V12Demo/DemoWidget.cpp
new file mode 100644
index 0000000..c705569
--- /dev/null
+++ b/osframework/source/demos/V12Demo/DemoWidget.cpp
@@ -0,0 +1,101 @@
+#include "DemoWidget.h"
+#include "Res.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/ButtonWidget.h"
+#include "V12DemoApp.h"
+
+using namespace Sexy;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+DemoWidget::DemoWidget()
+{
+
+ // Just for the heck of it, we'll resize ourselves at instantiation time.
+ int w = 200, h = 200;
+ Resize(gSexyAppBase->mWidth / 2 - w / 2, gSexyAppBase->mHeight / 2 - h / 2, w, h);
+
+ // Previously, it was annoying trying to place widgets on some sort of parent widget,
+ // since there was no notion of parent/child relationship. What you had to do was
+ // override the AddedToManager and RemovedFromManager functions, create and add your
+ // widgets or remove and nuke them, and in the case of AddedToManager, you also had
+ // to then place the widget using global coordinates that had no relation to the coordinates
+ // you set the parent widget at. Not anymore. What we can do now is to dispense with
+ // overriding those methods altogether! So now, in the parent's constructor, we can
+ // create our child widgets, resize them, and place them using relative coordinates.
+ // What this also means is that moving the parent widget around results in moving
+ // ALL the child widgets, which means you no longer have to manually move everything
+ // just because the parent moved. In addition, another nice thing is that you no longer
+ // have to remove your child widgets before deleting them: this is handled automatically
+ // for you.
+ mMoveButton = new ButtonWidget(0, this);
+ mMoveButton->mLabel = _S("MOVE");
+ mMoveButton->SetFont(FONT_DEFAULT);
+
+ mCloseButton = new ButtonWidget(1, this);
+ mCloseButton->mLabel = _S("CLOSE");
+ mCloseButton->SetFont(FONT_DEFAULT);
+
+ // VERY IMPORTANT: Notice that we're calling THIS CLASS' (or really, it's parent, WidgetContainer's)
+ // AddWidget method instead of the WidgetManager's method. In order to designate a widget as a child
+ // widget, you have to call the AddWidget method of the class that will be its parent.
+ AddWidget(mMoveButton);
+ AddWidget(mCloseButton);
+
+ mMoveButton->Resize(10, 150, 75, 50);
+ mCloseButton->Resize(115, 150, 75, 50);
+
+ // mPriority determines what..uh..priority...this widget (and thus its children)
+ // draws at when another widget is drawing an overlay (please see Board.cpp
+ // about the overlay stuff if you haven't already, in Board::Draw(...)).
+ // The higher priority widgets get drawn ABOVE (and thus AFTER) widgets
+ // with a lower priority. Thus, by changing the priority of a widget,
+ // you could enforce that it's always drawn above any overlay layer,
+ // or you could do just the opposite. We'll
+ // set it to 1, since in our Board::Draw method, you'll see that we
+ // toggle between drawing the overlay above and below this widget.
+ // Note that widgets by default have priority 0 and dialogs have priority 1.
+ mPriority = 1;
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+DemoWidget::~DemoWidget()
+{
+ // We need to remove child widgets before deleting them.
+ RemoveAllWidgets();
+
+ delete mMoveButton;
+ delete mCloseButton;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoWidget::ButtonDepress(int id)
+{
+ if (id == mMoveButton->mId)
+ {
+ // See how easy it is to move widgets now, using the new hierarchy system?
+ // By calling Move (or Resize as well), we also move ALL our child widgets,
+ // preserving their relative positions. Previously, you would have had to
+ // manually move all child widgets yourself.
+ Move(Rand() % (gSexyAppBase->mWidth - mWidth), Rand() % (gSexyAppBase->mHeight - mHeight));
+ }
+ else if (id == mCloseButton->mId)
+ {
+ // We'll remove ourselves when the close button is pressed.
+ gSexyAppBase->mWidgetManager->RemoveWidget(this);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void DemoWidget::Draw(Graphics* g)
+{
+ g->SetColor(Color(0, 255, 0, 200));
+ g->FillRect(0, 0, mWidth, mHeight);
+
+
+} \ No newline at end of file
diff --git a/osframework/source/demos/V12Demo/DemoWidget.h b/osframework/source/demos/V12Demo/DemoWidget.h
new file mode 100644
index 0000000..0b318ea
--- /dev/null
+++ b/osframework/source/demos/V12Demo/DemoWidget.h
@@ -0,0 +1,38 @@
+#ifndef __DEMO_WIDGET_H__
+#define __DEMO_WIDGET_H__
+
+#include "SexyAppFramework/Widget.h"
+#include "SexyAppFramework/ButtonListener.h"
+
+namespace Sexy
+{
+
+ class ButtonWidget;
+
+ //////////////////////////////////////////////////////////////////////////
+ // Noting new in this header. Check the previous demos if this makes
+ // no sense to you, as it's all covered there. CHECK OUT THE .CPP FILE
+ // THOUGH, there's new stuff there.
+ //////////////////////////////////////////////////////////////////////////
+
+
+ class DemoWidget : public Widget, public ButtonListener
+ {
+
+ private:
+
+ ButtonWidget* mMoveButton;
+ ButtonWidget* mCloseButton;
+
+ public:
+
+ DemoWidget();
+ virtual ~DemoWidget();
+
+ void Draw(Graphics* g);
+ void ButtonDepress(int id);
+ };
+
+}
+
+#endif //__DEMO_WIDGET_H__
diff --git a/osframework/source/demos/V12Demo/V12Demo VS2005 WideString.vcproj b/osframework/source/demos/V12Demo/V12Demo VS2005 WideString.vcproj
new file mode 100644
index 0000000..e20c275
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12Demo VS2005 WideString.vcproj
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="V12Demo"
+ ProjectGUID="{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="DebugVS2005"
+ IntermediateDirectory="DebugVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ >
+ <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"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ 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)/../../V12Demo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/V12Demo.pdb"
+ GenerateMapFile="true"
+ MapFileName="V12Demo.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"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ />
+ <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)/../../$(ProjectName).exe"
+ GenerateMapFile="true"
+ MapFileName="V12Demo.map"
+ SubSystem="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;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="Board.cpp"
+ >
+ </File>
+ <File
+ RelativePath="DemoWidget.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.cpp"
+ >
+ </File>
+ <File
+ RelativePath="V12DemoApp.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="DemoWidget.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.h"
+ >
+ </File>
+ <File
+ RelativePath="V12DemoApp.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/V12Demo/V12Demo VS2005.vcproj b/osframework/source/demos/V12Demo/V12Demo VS2005.vcproj
new file mode 100644
index 0000000..7494e94
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12Demo VS2005.vcproj
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="V12Demo"
+ ProjectGUID="{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="DebugVS2005"
+ IntermediateDirectory="DebugVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ >
+ <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"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ 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)/../../V12Demo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/V12Demo.pdb"
+ GenerateMapFile="true"
+ MapFileName="V12Demo.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"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ />
+ <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)/../../$(ProjectName).exe"
+ GenerateMapFile="true"
+ MapFileName="V12Demo.map"
+ SubSystem="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;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="Board.cpp"
+ >
+ </File>
+ <File
+ RelativePath="DemoWidget.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.cpp"
+ >
+ </File>
+ <File
+ RelativePath="V12DemoApp.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="DemoWidget.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.h"
+ >
+ </File>
+ <File
+ RelativePath="V12DemoApp.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/V12Demo/V12Demo WideString.vcproj b/osframework/source/demos/V12Demo/V12Demo WideString.vcproj
new file mode 100644
index 0000000..f44d063
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12Demo WideString.vcproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="V12Demo"
+ ProjectGUID="{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USE_WIDE_STRING"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../V12Demo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/V12Demo.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="V12Demo.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">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="FALSE"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ WarningLevel="3"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../$(ProjectName).exe"
+ GenerateMapFile="TRUE"
+ MapFileName="V12Demo.map"
+ 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>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="Board.cpp">
+ </File>
+ <File
+ RelativePath="DemoWidget.cpp">
+ </File>
+ <File
+ RelativePath="..\Res.cpp">
+ </File>
+ <File
+ RelativePath="V12DemoApp.cpp">
+ </File>
+ <File
+ RelativePath="main.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="Board.h">
+ </File>
+ <File
+ RelativePath="DemoWidget.h">
+ </File>
+ <File
+ RelativePath="..\Res.h">
+ </File>
+ <File
+ RelativePath="V12DemoApp.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/V12Demo/V12Demo.dsp b/osframework/source/demos/V12Demo/V12Demo.dsp
new file mode 100644
index 0000000..9a9491f
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12Demo.dsp
@@ -0,0 +1,141 @@
+# Microsoft Developer Studio Project File - Name="V12Demo" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=V12Demo - 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 "V12Demo.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 "V12Demo.mak" CFG="V12Demo - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "V12Demo - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "V12Demo - 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)" == "V12Demo - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "V12Demo___Win32_Release"
+# PROP BASE Intermediate_Dir "V12Demo___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 /FD /c
+# SUBTRACT CPP /YX /Yc /Yu
+# 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:"..\V12Demo.exe"
+
+!ELSEIF "$(CFG)" == "V12Demo - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "V12Demo___Win32_Debug"
+# PROP BASE Intermediate_Dir "V12Demo___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:"..\V12Demo_debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "V12Demo - Win32 Release"
+# Name "V12Demo - 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=.\DemoWidget.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=.\V12DemoApp.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=.\DemoWidget.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Res.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\V12DemoApp.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/V12Demo/V12Demo.vcproj b/osframework/source/demos/V12Demo/V12Demo.vcproj
new file mode 100644
index 0000000..8919386
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12Demo.vcproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="V12Demo"
+ ProjectGUID="{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../V12Demo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/V12Demo.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="V12Demo.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">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="FALSE"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ WarningLevel="3"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../$(ProjectName).exe"
+ GenerateMapFile="TRUE"
+ MapFileName="V12Demo.map"
+ 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>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="Board.cpp">
+ </File>
+ <File
+ RelativePath="DemoWidget.cpp">
+ </File>
+ <File
+ RelativePath="..\Res.cpp">
+ </File>
+ <File
+ RelativePath="V12DemoApp.cpp">
+ </File>
+ <File
+ RelativePath="main.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="Board.h">
+ </File>
+ <File
+ RelativePath="DemoWidget.h">
+ </File>
+ <File
+ RelativePath="..\Res.h">
+ </File>
+ <File
+ RelativePath="V12DemoApp.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/V12Demo/V12DemoApp.cpp b/osframework/source/demos/V12Demo/V12DemoApp.cpp
new file mode 100644
index 0000000..8573f05
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12DemoApp.cpp
@@ -0,0 +1,116 @@
+#include "V12DemoApp.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/DDImage.h"
+#include "SexyAppFramework/ResourceManager.h"
+#include "SexyAppFramework/Dialog.h"
+#include "SexyAppFramework/SWTri.h"
+#include "Board.h"
+#include "Res.h"
+
+using namespace Sexy;
+
+V12DemoApp::V12DemoApp()
+{
+ mProdName = "V12Demo";
+ mProductVersion = "1.0";
+ mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion);
+ mRegKey = "PopCap\\SexyAppFramework\\V12Demo";
+
+ mNoSoundNeeded = true;
+ mBoard = NULL;
+
+ // Important: You now need to make this call to enable
+ // DrawImageTransform and DrawImageMatrix to work!
+ // This requirement was added so that people who don't use these functions
+ // can avoid the extra code required to support the functions
+ // (about 400K in exe size, 150K zipped).
+ SWTri_AddAllDrawTriFuncs();
+}
+
+V12DemoApp::~V12DemoApp()
+{
+ delete mBoard;
+}
+
+void V12DemoApp::ShutdownHook()
+{
+ // Notice that we don't have to check for mShutdown and return immediately if it's true.
+ // Also note that we don't have to call our parent class' Shutdown() method. This
+ // ShutdownHook() function is only called once, and only after the parent gets Shutdown
+ // called. It just saves us a few lines of extra checking, and saves some headaches that can
+ // arise when you forget to call a parent class method.
+
+ if (mBoard != NULL)
+ mWidgetManager->RemoveWidget(mBoard);
+}
+
+void V12DemoApp::InitHook()
+{
+ // Like the ShutdownHook idea, we no longer need to call the parent class' Init method.
+ // This function only gets called once, and after the parent has finished its Init code.
+ // It just saves us a few lines of extra checking, and saves some headaches that can
+ // arise when you forget to call a parent class method.
+ LoadResourceManifest();
+
+ // We're just going to wind up using the default font from this resource group.
+ // Since there's very little to load, we'll dispense with the whole
+ // title screen loading stuff.
+ if (!mResourceManager->LoadResources("Init"))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ if (!ExtractInitResources(mResourceManager))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ // This is new. Widgets now contain flags that alter the behavior of them.
+ // Please read the document included with the 1.2 release for a full description,
+ // but here's the general rundown:
+ // The WidgetManager's mDefaultBelowModalFlagsMod contains flags that are applied
+ // anytime a dialog box pops up on screen. If we modify these, then we modify the
+ // default behavior for ALL dialog boxes, and don't have to mess around with other
+ // function calls and setting of misc. variables. All flags variables contain 2
+ // sub-variables: mAddFlags and mRemoveFlags. By ORing stuff with mAddFlags, when
+ // a dialog box pops up, the flags in mAddFlags are applied in addition to any
+ // other flags that exist. Similarly, mRemoveFlags contains flags that are removed
+ // from a widget when the dialog pops up. Below, what we're saying is that when
+ // a dialog box pops up, we DO NOT want any widgets beneath it to be able to update.
+ // What'll happen is that any widget below the dialog gets the WIDGETFLAGS_UPDATE
+ // flag removed. This will of course be restored when the dialog box closes.
+ // Again, please see the 1.2 doc for a list of all the flags and a much more
+ // thorough explanation.
+ mWidgetManager->mDefaultBelowModalFlagsMod.mRemoveFlags |= WIDGETFLAGS_UPDATE;
+
+ mBoard = new Board(this);
+ mBoard->Resize(0, 0, mWidth, mHeight);
+ mWidgetManager->AddWidget(mBoard);
+}
+
+void V12DemoApp::LostFocus()
+{
+ if (mBoard)
+ mBoard->SetFocusLost(true);
+}
+
+void V12DemoApp::GotFocus()
+{
+ if (mBoard)
+ mBoard->SetFocusLost(false);
+}
+
+void V12DemoApp::DialogButtonDepress(int dialog_id, int button_id)
+{
+ // See how easy it is now? We only create a dialog with 1 ID in this
+ // demo: ID of 100.
+ // See, all we have to do is check if the dialog id is of the dialog
+ // we're interested in, and if the button id is of the button that
+ // we want to act on.
+ if ((dialog_id == 100) && (button_id == Dialog::ID_OK))
+ KillDialog(100);
+} \ No newline at end of file
diff --git a/osframework/source/demos/V12Demo/V12DemoApp.h b/osframework/source/demos/V12Demo/V12DemoApp.h
new file mode 100644
index 0000000..fb19732
--- /dev/null
+++ b/osframework/source/demos/V12Demo/V12DemoApp.h
@@ -0,0 +1,79 @@
+#ifndef __V12DEMOAPP_H__
+#define __V12DEMOAPP_H__
+
+#include "..\SexyAppFramework\SexyAppBase.h"
+
+namespace Sexy
+{
+
+class Board;
+
+class V12DemoApp : public SexyAppBase
+{
+
+public:
+
+ Board* mBoard;
+
+public:
+
+ V12DemoApp();
+ virtual ~V12DemoApp();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ShutdownHook
+ // Purpose: Instead of overriding Shutdown() and having to remember to
+ // call ::Shutdown(), and to remember to check if mShutdown is true
+ // or not, you can use this and forget about those previous headaches.
+ // Guaranteed to not be called once mShutdown is true so no need to worry
+ // about it occurring multiple times (unless of course for some reason you
+ // manually call it more than once). Thus, you no longer need a ShutdownHook()
+ // override.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void ShutdownHook();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: InitHook
+ // Purpose: This uses the same idea behind ShutdownHook in that you don't
+ // have to worry about calling the base class' Init method anymore
+ // and can forget about those previous hassels. This method is guaranteed
+ // to be called only once, right after SexyAppBase::Init finishes. Thus,
+ // you no longer need an Init() override.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void InitHook();
+
+ //////////////////////////////////////////////////////////////////////////
+ // With these 2 functions, we'll pause the board if focus shifts to another
+ // application.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void LostFocus();
+ virtual void GotFocus();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: DialogButtonDepress
+ // Parameters:
+ // dialog_id - The ID of the dialog box whose button is emitting
+ // the DialogButtonDepress signal.
+ // button_id - The ID of the button in the above dialog box that
+ // has been depressed.
+ //
+ // Purpose: Previously, dialog button (de)presses were all routed through
+ // a ButtonListener. This was annoying, as to check which button was
+ // pressed, you had to check if the ID of the button was the ID of the
+ // dialog box + 2000 or + 3000. It also had the tendency to create large
+ // Button(De)press functions with giant case statements. With this new
+ // implementation, button (de)presses from a dialog box will be passed
+ // into this alternative method, and the IDs are their simple, original
+ // IDs that you assigned to the widgets upon initialization. For dialog
+ // boxes with a single button, the button's ID is 1, and for dialogs with
+ // 2 buttons, it's 1 for yes/ok and 0 for no/cancel. Of course, this is
+ // fully backwards compatible, so if you don't want to custom override
+ // the DialogButton(De)press method(s) you don't have to, and can still
+ // check which button was pressed using the old original method via the
+ // Button(De)press methods.
+ //////////////////////////////////////////////////////////////////////////
+ virtual void DialogButtonDepress(int dialog_id, int button_id);
+};
+
+}
+#endif //__V12DEMOAPP_H__
diff --git a/osframework/source/demos/V12Demo/main.cpp b/osframework/source/demos/V12Demo/main.cpp
new file mode 100644
index 0000000..a979784
--- /dev/null
+++ b/osframework/source/demos/V12Demo/main.cpp
@@ -0,0 +1,65 @@
+//////////////////////////////////////////////////////////////////////////
+// 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.
+//
+// ***********************************************************************
+// NOTE: You should have read and understood demos 1-5 before
+// this, as topics that are already covered will be either not commented
+// or minimally so. In addition, you REALLY REALLY
+// should have read through the documentation included with the 1.2 release.
+// ***********************************************************************
+//
+// This demo will teach you:
+// * How to use the new InitHook/ShutdownHook for slightly safer/easier
+// init/shutdown procedures
+//
+// * How to use the new DialogListener class, to listen to button events
+// specifically from a dialog (in contrast to using ButtonListener and
+// checking if the button ID is dialog ID + 2000 or 3000).
+//
+// * How to use flags to set the default behavior of a dialog box
+//
+// * How to use flags to modify widget behavior, such as always marking
+// dirty, not allowing mouse events, etc.
+//
+// * How to take advantage of the new widget heirarchy, which lets you
+// very easily add/place widgets within a parent widget with less code
+// and less mess and do some neat things without tons of code.
+//
+// * How to use the new overlay drawing system, which eliminates the need
+// for a widget overlay (like the one in the Hun-garr demo for pausing).
+//
+// * How to easily push/pop/preserve graphics state
+//
+// * How to use the new and powerful Graphics::DrawImageTransform/F to
+// very quickly and easily apply rotation, scaling, translation, or any combo
+// to an image, as opposed to the previous messy way of doing things.
+//
+// * How to use the also new and also cool Graphics::DrawImageMatrix
+// function to draw an image in 2D and/or 3D with a matrix. This allows
+// some neat and fast tricks like easy flipping, mirroring, scaling, etc
+// with a minimal number of lines.
+//
+// * How to use UpdateApp to help with transitions
+//
+// * How to be master of the universe. OK maybe not.
+//////////////////////////////////////////////////////////////////////////
+
+#include "V12DemoApp.h"
+
+using namespace Sexy;
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ gHInstance = hInstance;
+
+ V12DemoApp* anApp = new V12DemoApp();
+ anApp->Init();
+ anApp->Start();
+ delete anApp;
+
+ return 0;
+}
diff --git a/osframework/source/demos/XMLDemo/Board.cpp b/osframework/source/demos/XMLDemo/Board.cpp
new file mode 100644
index 0000000..e4117e8
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/Board.cpp
@@ -0,0 +1,50 @@
+#include "Board.h"
+#include "XMLDemoApp.h"
+#include "..\SexyAppFramework\Graphics.h"
+#include "Res.h"
+
+using namespace Sexy;
+
+Board::Board(XMLDemoApp* theApp)
+{
+ mApp = theApp;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+Board::~Board()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Update()
+{
+ Widget::Update();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void Board::Draw(Graphics* g)
+{
+ g->SetColor(Color::Black);
+ g->FillRect(0, 0, mWidth, mHeight);
+
+ g->SetFont(FONT_DEFAULT);
+ g->SetColor(Color::White);
+
+ // Just to verify things, print out the values of everything we cared to read in from demo.xml:
+
+ g->DrawString(StrFormat(_S("Section 1/Item1 text: %s"), mApp->mSection1.mItem1Text.c_str()), 10, 20);
+ g->DrawString(StrFormat(_S("Section 1/BoolParam text: %s"), mApp->mSection1.mBoolParamText.c_str()), 10, 40);
+ g->DrawString(StrFormat(_S("Section 1/BoolParam value: %s"), mApp->mSection1.mBoolParamElement ? _S("true") : _S("false")), 10, 60);
+
+ g->DrawString(StrFormat(_S("Section 2's s2attrib = %s"), mApp->mSection2.mSectionAttribText.c_str()), 10, 90);
+ g->DrawString(StrFormat(_S("Section 2/IntParam text: %s"), mApp->mSection2.mIntParamText.c_str()), 10, 110);
+ g->DrawString(StrFormat(_S("Section 2/IntParam value: %d"), mApp->mSection2.mIntParamElement), 10, 130);
+ g->DrawString(StrFormat(_S("Section 2/MultiAttrib/attrib1 = %s"), mApp->mSection2.mMultiAttrib1.c_str()), 10, 150);
+ g->DrawString(StrFormat(_S("Section 2/MultiAttrib/attrib2 = %s"), mApp->mSection2.mMultiAttrib2.c_str()), 10, 170);
+ g->DrawString(StrFormat(_S("Section 2/MultiAttrib/attrib3 = %s"), mApp->mSection2.mMultiAttrib3.c_str()), 10, 190);
+ g->DrawString(StrFormat(_S("Section 2/Subsection/Item2 value: %s"), mApp->mSection2.mSubsectionItem2.c_str()), 10, 210);
+}
+
diff --git a/osframework/source/demos/XMLDemo/Board.h b/osframework/source/demos/XMLDemo/Board.h
new file mode 100644
index 0000000..16e76bc
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/Board.h
@@ -0,0 +1,29 @@
+#ifndef __BOARD_H__
+#define __BOARD_H__
+
+#include "SexyAppFramework/Widget.h"
+
+namespace Sexy
+{
+
+class XMLDemoApp;
+
+class Board : public Widget
+{
+
+public:
+
+ XMLDemoApp* mApp;
+
+public:
+
+ Board(XMLDemoApp* theApp);
+ virtual ~Board();
+
+ void Update();
+ void Draw(Graphics* g);
+};
+
+}
+
+#endif //__BOARD_H__
diff --git a/osframework/source/demos/XMLDemo/XMLDemo VS2005 WideString.vcproj b/osframework/source/demos/XMLDemo/XMLDemo VS2005 WideString.vcproj
new file mode 100644
index 0000000..7c7339d
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemo VS2005 WideString.vcproj
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="XMLDemo"
+ ProjectGUID="{6A242898-B1D4-4EEA-AE61-AF1002462917}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="DebugVS2005"
+ IntermediateDirectory="DebugVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ >
+ <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"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ 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)/../../XMLDemo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/XMLDemo.pdb"
+ GenerateMapFile="true"
+ MapFileName="XMLDemo.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"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ />
+ <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)/../../$(ProjectName).exe"
+ GenerateMapFile="true"
+ MapFileName="XMLDemo.map"
+ SubSystem="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;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="Board.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.cpp"
+ >
+ </File>
+ <File
+ RelativePath="XMLDemoApp.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.h"
+ >
+ </File>
+ <File
+ RelativePath="XMLDemoApp.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/XMLDemo/XMLDemo VS2005.vcproj b/osframework/source/demos/XMLDemo/XMLDemo VS2005.vcproj
new file mode 100644
index 0000000..7f888ac
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemo VS2005.vcproj
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="XMLDemo"
+ ProjectGUID="{6A242898-B1D4-4EEA-AE61-AF1002462917}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="DebugVS2005"
+ IntermediateDirectory="DebugVS2005"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+ >
+ <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"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ 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)/../../XMLDemo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/XMLDemo.pdb"
+ GenerateMapFile="true"
+ MapFileName="XMLDemo.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"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="0"
+ />
+ <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)/../../$(ProjectName).exe"
+ GenerateMapFile="true"
+ MapFileName="XMLDemo.map"
+ SubSystem="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;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="Board.cpp"
+ >
+ </File>
+ <File
+ RelativePath="main.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.cpp"
+ >
+ </File>
+ <File
+ RelativePath="XMLDemoApp.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="Board.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Res.h"
+ >
+ </File>
+ <File
+ RelativePath="XMLDemoApp.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/XMLDemo/XMLDemo WideString.vcproj b/osframework/source/demos/XMLDemo/XMLDemo WideString.vcproj
new file mode 100644
index 0000000..f47318f
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemo WideString.vcproj
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="XMLDemo"
+ ProjectGUID="{6A242898-B1D4-4EEA-AE61-AF1002462917}">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USE_WIDE_STRING"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../XMLDemo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/XMLDemo.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="XMLDemo.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">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="FALSE"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USE_WIDE_STRING"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ WarningLevel="3"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../$(ProjectName).exe"
+ GenerateMapFile="TRUE"
+ MapFileName="XMLDemo.map"
+ 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>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="Board.cpp">
+ </File>
+ <File
+ RelativePath="..\Res.cpp">
+ </File>
+ <File
+ RelativePath="XMLDemoApp.cpp">
+ </File>
+ <File
+ RelativePath="main.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="Board.h">
+ </File>
+ <File
+ RelativePath="..\Res.h">
+ </File>
+ <File
+ RelativePath="XMLDemoApp.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/XMLDemo/XMLDemo.dsp b/osframework/source/demos/XMLDemo/XMLDemo.dsp
new file mode 100644
index 0000000..ae9aec5
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemo.dsp
@@ -0,0 +1,133 @@
+# Microsoft Developer Studio Project File - Name="XMLDemo" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=XMLDemo - 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 "XMLDemo.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 "XMLDemo.mak" CFG="XMLDemo - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "XMLDemo - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "XMLDemo - 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)" == "XMLDemo - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "XMLDemo___Win32_Release"
+# PROP BASE Intermediate_Dir "XMLDemo___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 /FD /c
+# SUBTRACT CPP /YX
+# 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:"..\XMLDemo.exe"
+
+!ELSEIF "$(CFG)" == "XMLDemo - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "XMLDemo___Win32_Debug"
+# PROP BASE Intermediate_Dir "XMLDemo___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 /Yc /Yu
+# 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:"..\XMLDemo_debug.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "XMLDemo - Win32 Release"
+# Name "XMLDemo - 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=.\main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Res.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMLDemoApp.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=..\Res.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\XMLDemoApp.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/XMLDemo/XMLDemo.vcproj b/osframework/source/demos/XMLDemo/XMLDemo.vcproj
new file mode 100644
index 0000000..0e265fd
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemo.vcproj
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="XMLDemo"
+ ProjectGUID="{6A242898-B1D4-4EEA-AE61-AF1002462917}">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../XMLDemo_debug.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/XMLDemo.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName="XMLDemo.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">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="FALSE"
+ AdditionalIncludeDirectories="..\;..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ WarningLevel="3"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib wsock32.lib"
+ OutputFile="$(OutDir)/../../$(ProjectName).exe"
+ GenerateMapFile="TRUE"
+ MapFileName="XMLDemo.map"
+ 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>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="Board.cpp">
+ </File>
+ <File
+ RelativePath="..\Res.cpp">
+ </File>
+ <File
+ RelativePath="XMLDemoApp.cpp">
+ </File>
+ <File
+ RelativePath="main.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="Board.h">
+ </File>
+ <File
+ RelativePath="..\Res.h">
+ </File>
+ <File
+ RelativePath="XMLDemoApp.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/osframework/source/demos/XMLDemo/XMLDemoApp.cpp b/osframework/source/demos/XMLDemo/XMLDemoApp.cpp
new file mode 100644
index 0000000..705f34f
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemoApp.cpp
@@ -0,0 +1,217 @@
+#include "XMLDemoApp.h"
+#include "SexyAppFramework/WidgetManager.h"
+#include "SexyAppFramework/ResourceManager.h"
+#include "SexyAppFramework/XMLParser.h"
+#include "Board.h"
+#include "Res.h"
+
+using namespace Sexy;
+
+XMLDemoApp::XMLDemoApp()
+{
+ mProdName = "XMLDemo";
+ mProductVersion = "1.0";
+ mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion);
+ mRegKey = "PopCap\\SexyAppFramework\\XMLDemo";
+
+ mBoard = NULL;
+ mParser = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+XMLDemoApp::~XMLDemoApp()
+{
+ delete mBoard;
+ delete mParser;
+ mResourceManager->DeleteResources("");
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void XMLDemoApp::ShutdownHook()
+{
+ if (mBoard != NULL)
+ mWidgetManager->RemoveWidget(mBoard);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+void XMLDemoApp::InitHook()
+{
+ LoadResourceManifest();
+
+ // We're just going to wind up using the default font from this resource group.
+ // Since there's very little to load, we'll dispense with the whole
+ // title screen loading stuff.
+ if (!mResourceManager->LoadResources("Init"))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ if (!ExtractInitResources(mResourceManager))
+ {
+ mLoadingFailed = true;
+ ShowResourceError(true);
+ return;
+ }
+
+ // Create our XML Parser object
+ mParser = new XMLParser();
+
+ // By default, comments are ignored and you won't see them at all once the file is read in.
+ // If you would like to not strip out the comments, you can call the AllowComments method
+ // of the XMLParser class and pass in true. Uncomment the line below to let XML comments
+ // be retained when loading the demo.xml file:
+ // mParser->AllowComments(true);
+
+ // Load in our demo XML file. If an error occurs, it'll return false.
+ if (!mParser->OpenFile("properties/demo.xml"))
+ {
+ mLoadingFailed = true;
+
+ // The parser will set an error string in the event that a problem occurred.
+ // You get this string via a call to GetErrorText().
+ MsgBox(StrFormat("Couldn't open properties/demo.xml. Error returned:\n\"%s\"",
+ mParser->GetErrorText().c_str()), "Error");
+ return;
+ }
+
+ ExtractXMLData();
+
+ mBoard = new Board(this);
+ mBoard->Resize(0, 0, mWidth, mHeight);
+ mWidgetManager->AddWidget(mBoard);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+bool XMLDemoApp::ExtractXMLData()
+{
+ // Everything will revolve around XML elements. We'll create
+ // one on the stack and pass it to the NextElement function below.
+ // The XMLElement class contains information on each element, such as
+ // whether it's a comment, start of a tag, end of a tag, what its
+ // attributes/values are, etc.
+ XMLElement e;
+
+ // We loop until there are no more elements left to process. NextElement
+ // returns false when done.
+ while (mParser->NextElement(&e))
+ {
+ // If you had enabled the option to not strip out comments (by default, comments
+ // are removed when loading an XML file, see line 65 of this file for more info),
+ // the type would be TYPE_COMMENT, the mSection field would be filled in as per usual,
+ // the mValue field would be the comment declaration syntax, !--, and the entire comment
+ // text (even if split across many lines) would be placed in mInstruction. Course, the
+ // default setup for this demo is to ignore comments, so you won't see them at all.
+
+ // TYPE_START denotes the start of a new section.
+ // For every TYPE_START, there will eventually be a corresponding
+ // TYPE_END with a matching mValue. For our current demo, we actually
+ // don't care about the end of a tag.
+ if (e.mType == XMLElement::TYPE_START)
+ {
+ // The type stays as TYPE_START until another item type appears, such as the
+ // end of a section/item, TYPE_ELEMENT is found (see a few paragraphs below),
+ // a comment is found, etc.
+ // In the meantime, the mSection field contains the full name of the current
+ // section.
+ if (e.mSection == _S("Section1"))
+ {
+ // Once inside a section, each item is read in. When an item is read in,
+ // it's tag is placed in the mValue field, and all attributes will be stored
+ // in a map (mAttributes) keyed by the attribute's string name, with a result of
+ // type std::string.
+ if (e.mValue == _S("Item1"))
+ {
+ // At this point, we've read the line from our demo.xml file:
+ // <Item1 text="Some text for Section1/Item1"/>
+ // that is, assuming you didn't change the contents of that file.
+ // As you can see, "Item1" is in the mValue field, and "text" is
+ // the key in our mAttributes map, with "Some text for Section1/Item1" as its value.
+ mSection1.mItem1Text = e.mAttributes[_S("text")];
+ }
+ else if (e.mValue == _S("BoolParam"))
+ {
+ // You'll notice that in demo.xml the line containing this part of the XML code reads:
+ // <BoolParam text="Some text for Section1/BoolParam">true</BoolParam>
+ //
+ // At this point in the processing though, we have only covered this part:
+ // <BoolParam text="Some text for Section1/BoolParam">
+ //
+ // The "true" part will be covered a few paragraphs below where we check for TYPE_ELEMENT.
+ // For now though, we can read in all parameters (in this case, just "text") stored
+ // as part of this item.
+ mSection1.mBoolParamText = e.mAttributes[_S("text")];
+ }
+ }
+ else if (e.mSection == _S("Section2"))
+ {
+ if (e.mValue == _S("IntParam"))
+ mSection2.mIntParamText = e.mAttributes[_S("text")];
+ else if (e.mValue == _S("MultiAttrib"))
+ {
+ // If you check out the demo.xml file, you'll see an entry declared like this:
+ //
+ // <MultiAttrib
+ // attrib1="attrib1"
+ // attrib2="2"
+ // attrib3="woo! attrib3!"
+ // />
+ //
+ // Again, the tag is in mValue, and all attributes are stored as key/value pairs
+ // in the mAttributes map. Note that the whitespace doesn't matter: you could
+ // have declared the above line on just a single line if you wanted to.
+ mSection2.mMultiAttrib1 = e.mAttributes[_S("attrib1")];
+ mSection2.mMultiAttrib2 = e.mAttributes[_S("attrib2")];
+ mSection2.mMultiAttrib3 = e.mAttributes[_S("attrib3")];
+ }
+
+ }
+ else if (e.mValue == _S("Section2"))
+ {
+ // Confused about this part? Don't be: When the very first line of a section
+ // is read in (in this case, it is: <Section2 s2attrib="Section2 attrib text">),
+ // if it doesn't also end on the same line (which in this case it doesn't, we get
+ // the </Section2> a few lines later) then mSection isn't updated and instead, the
+ // section name is stored in mValue. In this case, you'll see that mSection is "".
+ // That's because whitespace is ignored, so it's possible that this isn't a section
+ // and is perhaps just an item like the <MultiAttrib example above, split across several lines.
+ // Since when a line is read in, if it contains any attributes they too are read in,
+ // this is a good time to extract out the "s2attrib" attribute and record it in our mSection2
+ // structure.
+ mSection2.mSectionAttribText = e.mAttributes[_S("s2attrib")];
+ }
+
+ }
+ else if (e.mType == XMLElement::TYPE_ELEMENT)
+ {
+ // For lines of the form:
+ // <BoolParam text="Some text for Section1/BoolParam"> true </BoolParam>
+ // where there is data in between the start/end of the item (in this case, the data is "true"),
+ // the item is considered to be of type TYPE_ELEMENT. An element looks like a section declaration,
+ // except that it just contains a singular data value rather than nested XML syntax. For elements,
+ // the section name is the name of the previous sections + the tag name of the element. So in the
+ // above example, the section name is "Section1/BoolParam" since the previous (parent) section is
+ // "Section1" and the tag is "BoolParam". The data is contained in the mValue field.
+
+ if (e.mSection == _S("Section1/BoolParam"))
+ mSection1.mBoolParamElement = StringToLower(e.mValue) == _S("false") ? false : true;
+ else if (e.mSection == _S("Section2/IntParam"))
+ {
+ // This is just a handy std::string to integer function, that will return a boolean
+ // indicating success or failure. I'm ignoring the return type though in this
+ // particular case as I don't care for this particular example.
+ (void)StringToInt(e.mValue, &mSection2.mIntParamElement);
+ }
+ else if (e.mSection == _S("Section2/Subsection/Item2"))
+ mSection2.mSubsectionItem2 = e.mValue;
+ }
+ }
+
+ return true;
+}
diff --git a/osframework/source/demos/XMLDemo/XMLDemoApp.h b/osframework/source/demos/XMLDemo/XMLDemoApp.h
new file mode 100644
index 0000000..9d0c8d8
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/XMLDemoApp.h
@@ -0,0 +1,83 @@
+#ifndef __XMLDEMOAPP_H__
+#define __XMLDEMOAPP_H__
+
+#include "SexyAppFramework/SexyAppBase.h"
+
+namespace Sexy
+{
+
+class Board;
+
+// This is the new class we're going to be learning about.
+// It'll handle the loading and manipulation of XML files.
+class XMLParser;
+
+// These structs just represent the values from our properties/demo.xml
+// file. In a real game, you'd have your own made up config file format.
+// The names correspond to the attributes/sections from the XML file.
+struct s_Section1
+{
+ SexyString mItem1Text;
+
+ SexyString mBoolParamText;
+ bool mBoolParamElement;
+};
+
+struct s_Section2
+{
+ SexyString mSectionAttribText;
+
+ SexyString mIntParamText;
+ int mIntParamElement;
+
+ SexyString mMultiAttrib1;
+ SexyString mMultiAttrib2;
+ SexyString mMultiAttrib3;
+
+ SexyString mSubsectionItem2;
+};
+
+class XMLDemoApp : public SexyAppBase
+{
+
+public:
+
+ Board* mBoard;
+ s_Section1 mSection1;
+ s_Section2 mSection2;
+ SexyString mInstructionTag;
+ SexyString mInstruction;
+
+private:
+
+ // With this class, we'll read in our sample XML file, properties/demo.xml
+ XMLParser* mParser;
+
+private:
+
+ //////////////////////////////////////////////////////////////////////////
+ // Function: ExtractXMLData
+ // Parameters: none
+ // Returns: false on error, otherwise true
+ //
+ // Purpose: After opening an XML file via the XMLParser::OpenFile() method,
+ // this function then extracts out the data it needs from the sample XML file.
+ // When complete, mSection1 and mSection2 will have their values initialized.
+ //////////////////////////////////////////////////////////////////////////
+ bool ExtractXMLData();
+
+public:
+
+ XMLDemoApp();
+
+ virtual ~XMLDemoApp();
+
+ virtual void ShutdownHook();
+ virtual void InitHook();
+
+
+
+};
+
+}
+#endif //__XMLDEMOAPP_H__
diff --git a/osframework/source/demos/XMLDemo/main.cpp b/osframework/source/demos/XMLDemo/main.cpp
new file mode 100644
index 0000000..93995d4
--- /dev/null
+++ b/osframework/source/demos/XMLDemo/main.cpp
@@ -0,0 +1,34 @@
+//////////////////////////////////////////////////////////////////////////
+// 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.
+//
+// NOTE: You should have read and understood demos 1 and 2 before
+// this, as topics that are already covered will be either not commented
+// or minimally so. In addition, this demo uses just a couple features from the v.1.2
+// release of the framework, so it is beneficial to have read and understood
+// V12Demo as well. Though, if you fully understand demos 1 and 2, you'll probably
+// be fine enough.
+//
+// This demo will teach you:
+// * How to read in XML files from disk
+// * How to sift through the XML data and extract the information you need
+//////////////////////////////////////////////////////////////////////////
+
+#include "XMLDemoApp.h"
+
+using namespace Sexy;
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ gHInstance = hInstance;
+
+ XMLDemoApp* anApp = new XMLDemoApp();
+ anApp->Init();
+ anApp->Start();
+ delete anApp;
+
+ return 0;
+}
diff --git a/osframework/source/demos/bass.dll b/osframework/source/demos/bass.dll
new file mode 100644
index 0000000..06c3317
--- /dev/null
+++ b/osframework/source/demos/bass.dll
Binary files differ
diff --git a/osframework/source/demos/demos.txt b/osframework/source/demos/demos.txt
new file mode 100644
index 0000000..c1ed67d
--- /dev/null
+++ b/osframework/source/demos/demos.txt
@@ -0,0 +1,199 @@
+
+ PopCap Games Open Source Framework Demos
+
+ http://developer.popcap.com
+
+ Author: Jeff "Architekt" Weinstein
+
+ These demos are designed to quickly get you up to speed on
+ the most common and powerful features of the PopCap Framework.
+ Start at the first demo and completely read through each
+ .h and .cpp file. The suggested reading order is:
+ main.cpp, GameApp.h/.cpp, Board.h/.cpp and then any newly
+ added files after that. The demos are meant to illustrate some
+ of the most common and powerful features of the framework and
+ will not explain every single detail. However, after having
+ read through and understood each demo, you will be able
+ to figure out and understand the rest of the framework's
+ features.
+ Please note that the included images, sounds, and music
+ are taken from various PopCap games and may not be used
+ for commercial purposes. They are provided as a resource to
+ you to help out with the learning process.
+ If you find any inaccuracies, bugs, or have suggestions
+ for improving the demos, please use the forums on the
+ main website, http://developer.popcap.com
+
+ VERSION HISTORY
+
+ Framework 1.3:
+
+ * Updated all demos to work with the wide string projects.
+ Do not be alarmed by all the _S() macros: they don't do
+ anything in normal apps and are designed for the WideString
+ projects. All std::string's have been replaced with SexyString,
+ which is a typedef that is std::string in non-widestring versions,
+ and std::wstring in widestring versions.
+
+ * Fixed bug in all projects where the SexyAppFramework project was for some
+ reason not marked to build: this meant that you had to manually compile
+ the framework before you compiled all the demos. You should now simply be
+ able to do a Rebuild All without any manual fussing around.
+
+ Framework 1.22:
+
+ * Support for Visual Studio 2005
+ * Fixed some C++ language conformance issues
+ * Fixed some bugs with the flash widget and rendering issues
+ * Got tired of casting warnings, properly casting stuff now
+ * Fixed some demo bugs and bad programming practices
+ * IMPORTANT NEW CHANGE: in order to cut filesize bloat, caused
+ by the addition of the software triangle rasterizer
+ code in 1.21, you now need to do the following IF you
+ use DrawImageMatrix or DrawImageTransform (with a
+ complex transformation) or if you get errors compiling
+ or at run time you get the assert "You need to call
+ SWTri_AddDrawTriFunc or SWTri_AddAllDrawTriFuncs"
+
+ 1. Include "SexyAppFramework/SWTri.h"
+ 2. Call the function SWTri_AddAllDrawTriFuncs()
+ 3. Alternatively to #2, if you know which triangle draw
+ functions you need, you can add them specifically via
+ SWTri_AddDrawTriFunc(...) and specifying which draw
+ function you need (check SWTri.h for a list).
+
+
+ Framework 1.2:
+
+ * Corrected comment about the Popup function not working
+ in fullscreen mode.
+ * Removed call to Shutdown() in LoadingThreadProc (although
+ this is no longer incorrect as of Framework 1.2, it
+ IS incorrect in previous framework versions. For
+ backwards compatibility, it has been changed.)
+ * Removed some incorrect comments about resource manager
+ calling Shutdown
+ * Added new demo, XMLDemo, showing how to use the XMLParser
+ class for most video game XML needs.
+ * Added new demo, V12Demo, showing the new features of
+ Framework 1.2
+ * Updated Demo5::DemoDialog.cpp::ButtonDepress to work with
+ the 1.2 changes, as well as the options dialog in
+ Hun-garr.
+
+ Framework 1.0:
+ Initial release
+
+
+Demo1:
+-------
+* Setting app width/height
+* Drawing primitives
+* Changing colors
+* Loading thread proc
+* Widget basics: Adding, removing, drawing, updating
+
+Demo2:
+------
+* Loading and displaying fonts
+* Loading and displaying images
+* Colorizing images
+* Additive drawing
+* Paletizing images
+* Loading/playing sounds
+
+Demo3:
+------
+* Enabling auto-detect 3D
+* Modifying image bits
+* Stretching images
+* Mirroring/flipping images
+* Animation using image strips
+* Widgets: buttons, listeners, basic events, adding/removing, mouse move/drag/down/up
+
+Demo4:
+------
+* 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
+
+Demo5:
+------
+* Drawing differently if 3D or 2D
+* Using Translate instead of using XYs
+* Keyboard input, setting focus
+* Widgets: Dialog box, sliders, an options dialog box
+* Advanced widget topics: mClip, using Layout_ flags, using images
+* Random numbers
+* Catching memory leaks
+* Profiling
+
+
+Demo6:
+------
+* Game, using topics from above and including:
+* Custom cursors
+
+V12Demo:
+--------
+This demo shows off the new features in the 1.2 release of the framework.
+It builds on the knowledge of demos 1-5 so you MUST have read and understood
+those demos prior to reading this one, as previously covered material
+will either be not commented or minimally so. In addition, you REALLY REALLY
+should have read through the documentation included with the 1.2 release.
+
+
+* How to use the new InitHook/ShutdownHook for slightly safer/easier
+ init/shutdown procedures
+
+* How to use the new DialogListener class, to listen to button events
+ specifically from a dialog (in contrast to using ButtonListener and
+ checking if the button ID is dialog ID + 2000 or 3000).
+
+* How to use flags to set the default behavior of a dialog box
+
+* How to use flags to modify widget behavior, such as always marking
+ dirty, not allowing mouse events, etc.
+
+* How to take advantage of the new widget heirarchy, which lets you
+ very easily add/place widgets within a parent widget with less code
+ and less mess and do some neat things without tons of code.
+
+* How to use the new overlay drawing system, which eliminates the need
+ for a widget overlay (like the one in the Hun-garr demo for pausing).
+
+* How to easily push/pop/preserve graphics state
+
+* How to use the new and powerful Graphics::DrawImageTransform/F to
+ very quickly and easily apply rotation, scaling, translation, or any combo
+ to an image, as opposed to the previous messy way of doing things.
+
+* How to use the also new and also cool Graphics::DrawImageMatrix
+ function to draw an image in 2D and/or 3D with a matrix. This allows
+ some neat and fast tricks like easy flipping, mirroring, scaling, etc
+ with a minimal number of lines.
+
+* How to use UpdateApp to help with transitions
+
+* How to be master of the universe. OK maybe not.
+
+
+XMLDemo:
+--------
+* How to use the XMLParser class to read in XML files
+* How to sift through the XML data and extract the information you need
+
+NOTE: You should have read and understood demos 1 and 2 before
+this, as topics that are already covered will be either not commented
+or minimally so. In addition, this demo uses just a couple features from the v.1.2
+release of the framework, so it is beneficial to have read and understood
+V12Demo as well. Though, if you fully understand demos 1 and 2, you'll probably
+be fine enough.
+
+
+
diff --git a/osframework/source/demos/fonts/ArmorPiercing22.txt b/osframework/source/demos/fonts/ArmorPiercing22.txt
new file mode 100644
index 0000000..a4bfd53
--- /dev/null
+++ b/osframework/source/demos/fonts/ArmorPiercing22.txt
@@ -0,0 +1,67 @@
+Define CharList
+ ( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '~', '`',
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '[', '{',
+ ']', '}', ';', ':',"'", '"', ',', '<', '.', '>', '/', '?');
+
+Define WidthList
+ ( 11, 10, 11, 11, 11, 11, 11, 12, 7, 11, 12, 11, 14, 12, 11, 11,
+ 11, 10, 10, 11, 11, 12, 14, 13, 11, 11, 11, 10, 11, 11, 11, 11,
+ 11, 12, 7, 11, 12, 11, 14, 12, 11, 11, 11, 10, 10, 11, 11, 12,
+ 14, 13, 11, 11, 11, 9, 11, 11, 11, 11, 11, 10, 11, 11, 15, 7,
+ 8, 18, 18, 12, 20, 15, 11, 12, 12, 11, 12, 10, 12, 12, 11, 15,
+ 11, 15, 7, 7, 7, 11, 7, 13, 7, 13, 13, 12);
+
+Define RectList
+ ( ( 0, 0, 10, 32), ( 11, 0, 10, 32), ( 22, 0, 8, 32), ( 31, 0, 9, 32),
+ ( 41, 0, 8, 32), ( 50, 0, 8, 32), ( 59, 0, 8, 32), ( 68, 0, 9, 32),
+ ( 78, 0, 3, 32), ( 82, 0, 8, 32), ( 91, 0, 9, 32), ( 101, 0, 8, 32),
+ ( 110, 0, 14, 32), ( 125, 0, 9, 32), ( 135, 0, 8, 32), ( 144, 0, 9, 32),
+ ( 154, 0, 8, 32), ( 163, 0, 10, 32), ( 174, 0, 9, 32), ( 184, 0, 7, 32),
+ ( 192, 0, 8, 32), ( 201, 0, 10, 32), ( 212, 0, 14, 32), ( 227, 0, 10, 32),
+ ( 238, 0, 8, 32), ( 247, 0, 8, 32), ( 256, 0, 10, 32), ( 267, 0, 10, 32),
+ ( 278, 0, 8, 32), ( 287, 0, 9, 32), ( 297, 0, 8, 32), ( 306, 0, 8, 32),
+ ( 315, 0, 8, 32), ( 324, 0, 9, 32), ( 334, 0, 3, 32), ( 338, 0, 8, 32),
+ ( 347, 0, 9, 32), ( 357, 0, 8, 32), ( 366, 0, 14, 32), ( 381, 0, 9, 32),
+ ( 391, 0, 8, 32), ( 400, 0, 9, 32), ( 410, 0, 8, 32), ( 419, 0, 10, 32),
+ ( 430, 0, 9, 32), ( 440, 0, 7, 32), ( 448, 0, 8, 32), ( 457, 0, 10, 32),
+ ( 468, 0, 14, 32), ( 483, 0, 10, 32), ( 494, 0, 8, 32), ( 503, 0, 8, 32),
+ ( 512, 0, 8, 32), ( 521, 0, 5, 32), ( 527, 0, 8, 32), ( 536, 0, 8, 32),
+ ( 545, 0, 8, 32), ( 554, 0, 8, 32), ( 563, 0, 9, 32), ( 573, 0, 10, 32),
+ ( 584, 0, 8, 32), ( 593, 0, 9, 32), ( 603, 0, 12, 32), ( 616, 0, 4, 32),
+ ( 621, 0, 5, 32), ( 627, 0, 18, 32), ( 646, 0, 15, 32), ( 662, 0, 8, 32),
+ ( 671, 0, 17, 32), ( 689, 0, 12, 32), ( 702, 0, 7, 32), ( 710, 0, 11, 32),
+ ( 722, 0, 8, 32), ( 731, 0, 7, 32), ( 739, 0, 9, 32), ( 749, 0, 10, 32),
+ ( 760, 0, 9, 32), ( 770, 0, 9, 32), ( 780, 0, 8, 32), ( 789, 0, 12, 32),
+ ( 802, 0, 8, 32), ( 811, 0, 12, 32), ( 824, 0, 3, 32), ( 828, 0, 3, 32),
+ ( 832, 0, 3, 32), ( 836, 0, 8, 32), ( 845, 0, 3, 32), ( 849, 0, 11, 32),
+ ( 861, 0, 3, 32), ( 865, 0, 12, 32), ( 878, 0, 10, 32), ( 889, 0, 9, 32));
+
+Define OffsetList
+ ( ( 0, 0), ( 0, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), (-1, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), (-1, 0), ( 0, 0), ( 1, 0), ( 1, 0), ( 1, 0), (-1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 0, 0), ( 0, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), (-1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 1, 0), (-1, 0), ( 0, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ (-1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 1, 0), ( 0, 0), ( 1, 0), ( 0, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 0, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 0, 0),
+ ( 1, 0), ( 1, 0), ( 1, 0), ( 0, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 0, 0), ( 1, 0), ( 1, 0));
+
+CreateLayer Main;
+LayerSetImage Main 'ArmorPiercing22';
+LayerSetAscent Main 32;
+LayerSetCharWidths Main CharList WidthList;
+LayerSetCharWidths Main (' ') (7);
+LayerSetImageMap Main CharList RectList;
+LayerSetCharOffsets Main CharList OffsetList;
+LayerSetAscentPadding Main 0;
+LayerSetLineSpacingOffset Main 0;
+LayerSetPointSize Main 22;
+
+SetDefaultPointSize 22;
diff --git a/osframework/source/demos/fonts/ContinuumBold12.txt b/osframework/source/demos/fonts/ContinuumBold12.txt
new file mode 100644
index 0000000..7712cb5
--- /dev/null
+++ b/osframework/source/demos/fonts/ContinuumBold12.txt
@@ -0,0 +1,100 @@
+Define CharList
+ ( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '~', '`',
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '[', '{',
+ ']', '}', ';', ':',"'", '"', ',', '<', '.', '>', '/', '?', '¡', '¢', '£', '¥',
+ '§', '©', '®', '¿', 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë',
+ 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü',
+ 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í',
+ 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ');
+
+Define WidthList
+ ( 10, 9, 8, 9, 8, 8, 9, 9, 4, 5, 9, 8, 12, 9, 9, 9,
+ 9, 9, 8, 7, 9, 9, 13, 9, 9, 8, 8, 8, 7, 8, 8, 4,
+ 8, 8, 3, 3, 8, 3, 12, 8, 8, 8, 8, 4, 7, 4, 8, 8,
+ 11, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5,
+ 4, 11, 11, 8, 14, 9, 0, 7, 5, 5, 5, 8, 10, 9, 4, 5,
+ 4, 5, 4, 4, 3, 5, 3, 9, 3, 9, 9, 8, 4, 7, 10, 11,
+ 8, 12, 12, 8, 10, 10, 10, 10, 10, 10, 19, 10, 8, 8, 8, 9,
+ 4, 5, 4, 4, 11, 9, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9,
+ 9, 9, 9, 8, 8, 8, 8, 9, 14, 8, 8, 8, 8, 8, 4, 4,
+ 4, 4, 10, 9, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8);
+
+Define RectList
+ ( ( 0, 0, 10, 19), ( 11, 0, 9, 19), ( 21, 0, 8, 19), ( 30, 0, 9, 19),
+ ( 40, 0, 8, 19), ( 49, 0, 8, 19), ( 58, 0, 9, 19), ( 68, 0, 9, 19),
+ ( 78, 0, 3, 19), ( 82, 0, 5, 19), ( 88, 0, 9, 19), ( 98, 0, 8, 19),
+ ( 107, 0, 12, 19), ( 120, 0, 9, 19), ( 130, 0, 9, 19), ( 140, 0, 9, 19),
+ ( 150, 0, 8, 19), ( 159, 0, 8, 19), ( 168, 0, 8, 19), ( 177, 0, 8, 19),
+ ( 186, 0, 9, 19), ( 196, 0, 10, 19), ( 207, 0, 13, 19), ( 221, 0, 10, 19),
+ ( 232, 0, 10, 19), ( 243, 0, 9, 19), ( 253, 0, 8, 19), ( 262, 0, 8, 19),
+ ( 271, 0, 7, 19), ( 279, 0, 8, 19), ( 288, 0, 8, 19), ( 297, 0, 4, 19),
+ ( 302, 0, 8, 19), ( 311, 0, 8, 19), ( 320, 0, 3, 19), ( 324, 0, 5, 19),
+ ( 330, 0, 8, 19), ( 339, 0, 3, 19), ( 343, 0, 11, 19), ( 355, 0, 8, 19),
+ ( 364, 0, 8, 19), ( 373, 0, 8, 19), ( 382, 0, 8, 19), ( 391, 0, 4, 19),
+ ( 396, 0, 7, 19), ( 404, 0, 4, 19), ( 409, 0, 8, 19), ( 418, 0, 9, 19),
+ ( 428, 0, 11, 19), ( 440, 0, 8, 19), ( 449, 0, 8, 19), ( 458, 0, 8, 19),
+ ( 467, 0, 9, 19), ( 477, 0, 3, 19), ( 481, 0, 8, 19), ( 490, 0, 8, 19),
+ ( 499, 0, 8, 19), ( 508, 0, 7, 19), ( 516, 0, 9, 19), ( 526, 0, 8, 19),
+ ( 535, 0, 9, 19), ( 545, 0, 9, 19), ( 555, 0, 8, 19), ( 564, 0, 5, 19),
+ ( 570, 0, 3, 19), ( 574, 0, 11, 19), ( 586, 0, 11, 19), ( 598, 0, 8, 19),
+ ( 607, 0, 14, 19), ( 622, 0, 8, 19), ( 631, 0, 10, 19), ( 642, 0, 7, 19),
+ ( 650, 0, 4, 19), ( 655, 0, 4, 19), ( 660, 0, 5, 19), ( 666, 0, 9, 19),
+ ( 676, 0, 10, 19), ( 687, 0, 9, 19), ( 697, 0, 3, 19), ( 701, 0, 5, 19),
+ ( 707, 0, 3, 19), ( 711, 0, 5, 19), ( 717, 0, 4, 19), ( 722, 0, 4, 19),
+ ( 727, 0, 3, 19), ( 731, 0, 5, 19), ( 737, 0, 3, 19), ( 741, 0, 9, 19),
+ ( 751, 0, 3, 19), ( 755, 0, 9, 19), ( 765, 0, 9, 19), ( 775, 0, 8, 19),
+ ( 784, 0, 3, 19), ( 788, 0, 7, 19), ( 796, 0, 10, 19), ( 807, 0, 13, 19),
+ ( 821, 0, 8, 19), ( 830, 0, 12, 19), ( 843, 0, 12, 19), ( 856, 0, 8, 19),
+ ( 865, 0, 10, 19), ( 876, 0, 10, 19), ( 887, 0, 10, 19), ( 898, 0, 10, 19),
+ ( 909, 0, 10, 19), ( 920, 0, 10, 19), ( 931, 0, 21, 19), ( 953, 0, 10, 19),
+ ( 964, 0, 8, 19), ( 973, 0, 8, 19), ( 982, 0, 8, 19), ( 991, 0, 8, 19),
+ (1000, 0, 5, 19), (1006, 0, 5, 19), (1012, 0, 7, 19), (1020, 0, 6, 19),
+ (1027, 0, 11, 19), (1039, 0, 9, 19), (1049, 0, 9, 19), (1059, 0, 9, 19),
+ (1069, 0, 9, 19), (1079, 0, 9, 19), (1089, 0, 9, 19), (1099, 0, 13, 19),
+ (1113, 0, 9, 19), (1123, 0, 9, 19), (1133, 0, 9, 19), (1143, 0, 9, 19),
+ (1153, 0, 10, 19), (1164, 0, 8, 19), (1173, 0, 7, 19), (1181, 0, 8, 19),
+ (1190, 0, 8, 19), (1199, 0, 8, 19), (1208, 0, 8, 19), (1217, 0, 9, 19),
+ (1227, 0, 14, 19), (1242, 0, 9, 19), (1252, 0, 8, 19), (1261, 0, 8, 19),
+ (1270, 0, 8, 19), (1279, 0, 8, 19), (1288, 0, 3, 19), (1292, 0, 5, 19),
+ (1298, 0, 6, 19), (1305, 0, 6, 19), (1312, 0, 9, 19), (1322, 0, 8, 19),
+ (1331, 0, 8, 19), (1340, 0, 8, 19), (1349, 0, 9, 19), (1359, 0, 9, 19),
+ (1369, 0, 8, 19), (1378, 0, 11, 19), (1390, 0, 8, 19), (1399, 0, 8, 19),
+ (1408, 0, 8, 19), (1417, 0, 8, 19), (1426, 0, 8, 19), (1435, 0, 8, 19));
+
+Define OffsetList
+ ( ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 1, 0), ( 1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), (-1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 3, 0), ( 1, 0), ( 1, 0),
+ ( 1, 0), ( 1, 0), ( 0, 0), ( 1, 0), ( 0, 0), ( 0, 0), ( 1, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 1, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), (-1, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), (-1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ (-1, 0), ( 0, 0), (-1, 0), (-1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 1, 0), ( 1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), (-1, 0),
+ (-1, 0), (-1, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0));
+
+CreateLayer Main;
+LayerSetImage Main 'ContinuumBold12';
+LayerSetAscent Main 16;
+LayerSetCharWidths Main CharList WidthList;
+LayerSetCharWidths Main (' ') (9);
+LayerSetImageMap Main CharList RectList;
+LayerSetCharOffsets Main CharList OffsetList;
+LayerSetAscentPadding Main 0;
+LayerSetLineSpacingOffset Main 0;
+LayerSetPointSize Main 12;
+
+SetDefaultPointSize 12;
diff --git a/osframework/source/demos/fonts/Kiloton9.txt b/osframework/source/demos/fonts/Kiloton9.txt
new file mode 100644
index 0000000..531b72d
--- /dev/null
+++ b/osframework/source/demos/fonts/Kiloton9.txt
@@ -0,0 +1,56 @@
+Define CharList
+ ( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!',"'",
+ '"', ',', '.', '?');
+
+Define WidthList
+ ( 12, 12, 12, 12, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 9, 12, 12, 12, 12, 12, 12, 12, 12, 6, 6,
+ 10, 6, 6, 12);
+
+Define RectList
+ ( ( 0, 0, 9, 12), ( 10, 0, 9, 12), ( 20, 0, 9, 12), ( 30, 0, 9, 12),
+ ( 40, 0, 9, 12), ( 50, 0, 9, 12), ( 60, 0, 9, 12), ( 70, 0, 9, 12),
+ ( 80, 0, 3, 12), ( 84, 0, 9, 12), ( 94, 0, 9, 12), ( 104, 0, 9, 12),
+ ( 114, 0, 9, 12), ( 124, 0, 9, 12), ( 134, 0, 9, 12), ( 144, 0, 9, 12),
+ ( 154, 0, 9, 12), ( 164, 0, 9, 12), ( 174, 0, 9, 12), ( 184, 0, 9, 12),
+ ( 194, 0, 9, 12), ( 204, 0, 9, 12), ( 214, 0, 9, 12), ( 224, 0, 9, 12),
+ ( 234, 0, 9, 12), ( 244, 0, 9, 12), ( 254, 0, 9, 12), ( 264, 0, 9, 12),
+ ( 274, 0, 9, 12), ( 284, 0, 9, 12), ( 294, 0, 9, 12), ( 304, 0, 9, 12),
+ ( 314, 0, 9, 12), ( 324, 0, 9, 12), ( 334, 0, 3, 12), ( 338, 0, 9, 12),
+ ( 348, 0, 9, 12), ( 358, 0, 9, 12), ( 368, 0, 9, 12), ( 378, 0, 9, 12),
+ ( 388, 0, 9, 12), ( 398, 0, 9, 12), ( 408, 0, 9, 12), ( 418, 0, 9, 12),
+ ( 428, 0, 9, 12), ( 438, 0, 9, 12), ( 448, 0, 9, 12), ( 458, 0, 9, 12),
+ ( 468, 0, 9, 12), ( 478, 0, 9, 12), ( 488, 0, 9, 12), ( 498, 0, 9, 12),
+ ( 508, 0, 10, 12), ( 519, 0, 6, 12), ( 526, 0, 9, 12), ( 536, 0, 9, 12),
+ ( 546, 0, 9, 12), ( 556, 0, 9, 12), ( 566, 0, 9, 12), ( 576, 0, 9, 12),
+ ( 586, 0, 9, 12), ( 596, 0, 9, 12), ( 606, 0, 3, 12), ( 610, 0, 3, 12),
+ ( 614, 0, 8, 12), ( 623, 0, 3, 12), ( 627, 0, 3, 12), ( 631, 0, 9, 12));
+
+Define OffsetList
+ ( ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0));
+
+CreateLayer Main;
+LayerSetImage Main 'Kiloton9';
+LayerSetAscent Main 10;
+LayerSetCharWidths Main CharList WidthList;
+LayerSetCharWidths Main (' ') (6);
+LayerSetImageMap Main CharList RectList;
+LayerSetCharOffsets Main CharList OffsetList;
+LayerSetAscentPadding Main 0;
+LayerSetLineSpacingOffset Main 0;
+LayerSetPointSize Main 9;
+
+SetDefaultPointSize 9;
diff --git a/osframework/source/demos/fonts/_ArmorPiercing22.png b/osframework/source/demos/fonts/_ArmorPiercing22.png
new file mode 100644
index 0000000..756f4d3
--- /dev/null
+++ b/osframework/source/demos/fonts/_ArmorPiercing22.png
Binary files differ
diff --git a/osframework/source/demos/fonts/_ContinuumBold12.gif b/osframework/source/demos/fonts/_ContinuumBold12.gif
new file mode 100644
index 0000000..41646b7
--- /dev/null
+++ b/osframework/source/demos/fonts/_ContinuumBold12.gif
Binary files differ
diff --git a/osframework/source/demos/fonts/_Kiloton9.png b/osframework/source/demos/fonts/_Kiloton9.png
new file mode 100644
index 0000000..f89d0d4
--- /dev/null
+++ b/osframework/source/demos/fonts/_Kiloton9.png
Binary files differ
diff --git a/osframework/source/demos/fonts/_supernova20.png b/osframework/source/demos/fonts/_supernova20.png
new file mode 100644
index 0000000..258e125
--- /dev/null
+++ b/osframework/source/demos/fonts/_supernova20.png
Binary files differ
diff --git a/osframework/source/demos/fonts/supernova20.txt b/osframework/source/demos/fonts/supernova20.txt
new file mode 100644
index 0000000..34dda36
--- /dev/null
+++ b/osframework/source/demos/fonts/supernova20.txt
@@ -0,0 +1,28 @@
+Define CharList
+ ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', ',' , ':');
+
+Define WidthList
+ ( 13, 12, 13, 12, 13, 13, 13, 12, 13, 13, 13, 9, 3 , 3);
+
+Define RectList
+ ( ( 0, 0, 12, 28), ( 13, 0, 4, 28), ( 18, 0, 12, 28), ( 31, 0, 12, 28),
+ ( 44, 0, 12, 28), ( 57, 0, 12, 28), ( 70, 0, 12, 28), ( 83, 0, 11, 28),
+ ( 95, 0, 12, 28), ( 108, 0, 12, 28), ( 121, 0, 12, 28), ( 134, 0, 9, 28),
+ ( 144, 0, 3, 28), ( 148, 0, 3, 28));
+
+Define OffsetList
+ ( ( 0, 0), ( 6, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0),
+ ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0), ( 0, 0));
+
+CreateLayer Main;
+LayerSetImage Main 'supernova20';
+LayerSetAscent Main 23;
+LayerSetCharWidths Main CharList WidthList;
+LayerSetCharWidths Main (' ') (8);
+LayerSetImageMap Main CharList RectList;
+LayerSetCharOffsets Main CharList OffsetList;
+LayerSetAscentPadding Main 0;
+LayerSetLineSpacingOffset Main 0;
+LayerSetPointSize Main 20;
+
+SetDefaultPointSize 20;
diff --git a/osframework/source/demos/images/atomicexplosion.jpg b/osframework/source/demos/images/atomicexplosion.jpg
new file mode 100644
index 0000000..28958aa
--- /dev/null
+++ b/osframework/source/demos/images/atomicexplosion.jpg
Binary files differ
diff --git a/osframework/source/demos/images/atomicexplosion_.jpg b/osframework/source/demos/images/atomicexplosion_.jpg
new file mode 100644
index 0000000..7244652
--- /dev/null
+++ b/osframework/source/demos/images/atomicexplosion_.jpg
Binary files differ
diff --git a/osframework/source/demos/images/beam_opaque.jpg b/osframework/source/demos/images/beam_opaque.jpg
new file mode 100644
index 0000000..0af55d2
--- /dev/null
+++ b/osframework/source/demos/images/beam_opaque.jpg
Binary files differ
diff --git a/osframework/source/demos/images/beam_opaque_.gif b/osframework/source/demos/images/beam_opaque_.gif
new file mode 100644
index 0000000..928ebe0
--- /dev/null
+++ b/osframework/source/demos/images/beam_opaque_.gif
Binary files differ
diff --git a/osframework/source/demos/images/bomb_radial_death.jpg b/osframework/source/demos/images/bomb_radial_death.jpg
new file mode 100644
index 0000000..307efc2
--- /dev/null
+++ b/osframework/source/demos/images/bomb_radial_death.jpg
Binary files differ
diff --git a/osframework/source/demos/images/bomb_radial_death_.jpg b/osframework/source/demos/images/bomb_radial_death_.jpg
new file mode 100644
index 0000000..97563d2
--- /dev/null
+++ b/osframework/source/demos/images/bomb_radial_death_.jpg
Binary files differ
diff --git a/osframework/source/demos/images/btn_down.gif b/osframework/source/demos/images/btn_down.gif
new file mode 100644
index 0000000..914ef1c
--- /dev/null
+++ b/osframework/source/demos/images/btn_down.gif
Binary files differ
diff --git a/osframework/source/demos/images/btn_down_.gif b/osframework/source/demos/images/btn_down_.gif
new file mode 100644
index 0000000..af08bb0
--- /dev/null
+++ b/osframework/source/demos/images/btn_down_.gif
Binary files differ
diff --git a/osframework/source/demos/images/btn_over.gif b/osframework/source/demos/images/btn_over.gif
new file mode 100644
index 0000000..914ef1c
--- /dev/null
+++ b/osframework/source/demos/images/btn_over.gif
Binary files differ
diff --git a/osframework/source/demos/images/btn_over_.gif b/osframework/source/demos/images/btn_over_.gif
new file mode 100644
index 0000000..d5ca4e4
--- /dev/null
+++ b/osframework/source/demos/images/btn_over_.gif
Binary files differ
diff --git a/osframework/source/demos/images/btn_up.gif b/osframework/source/demos/images/btn_up.gif
new file mode 100644
index 0000000..914ef1c
--- /dev/null
+++ b/osframework/source/demos/images/btn_up.gif
Binary files differ
diff --git a/osframework/source/demos/images/btn_up_.gif b/osframework/source/demos/images/btn_up_.gif
new file mode 100644
index 0000000..fb59efc
--- /dev/null
+++ b/osframework/source/demos/images/btn_up_.gif
Binary files differ
diff --git a/osframework/source/demos/images/checkbox.gif b/osframework/source/demos/images/checkbox.gif
new file mode 100644
index 0000000..9c21121
--- /dev/null
+++ b/osframework/source/demos/images/checkbox.gif
Binary files differ
diff --git a/osframework/source/demos/images/checkbox_.gif b/osframework/source/demos/images/checkbox_.gif
new file mode 100644
index 0000000..9f10574
--- /dev/null
+++ b/osframework/source/demos/images/checkbox_.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_dragging.gif b/osframework/source/demos/images/custom_dragging.gif
new file mode 100644
index 0000000..9a4e254
--- /dev/null
+++ b/osframework/source/demos/images/custom_dragging.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_dragging_.gif b/osframework/source/demos/images/custom_dragging_.gif
new file mode 100644
index 0000000..a04bbae
--- /dev/null
+++ b/osframework/source/demos/images/custom_dragging_.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_hand.gif b/osframework/source/demos/images/custom_hand.gif
new file mode 100644
index 0000000..e39a2bb
--- /dev/null
+++ b/osframework/source/demos/images/custom_hand.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_hand_.gif b/osframework/source/demos/images/custom_hand_.gif
new file mode 100644
index 0000000..7484613
--- /dev/null
+++ b/osframework/source/demos/images/custom_hand_.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_pointer.gif b/osframework/source/demos/images/custom_pointer.gif
new file mode 100644
index 0000000..c6aaa92
--- /dev/null
+++ b/osframework/source/demos/images/custom_pointer.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_pointer_.gif b/osframework/source/demos/images/custom_pointer_.gif
new file mode 100644
index 0000000..c1caa3e
--- /dev/null
+++ b/osframework/source/demos/images/custom_pointer_.gif
Binary files differ
diff --git a/osframework/source/demos/images/custom_text.gif b/osframework/source/demos/images/custom_text.gif
new file mode 100644
index 0000000..05f6791
--- /dev/null
+++ b/osframework/source/demos/images/custom_text.gif
Binary files differ
diff --git a/osframework/source/demos/images/dialog.gif b/osframework/source/demos/images/dialog.gif
new file mode 100644
index 0000000..ced01fa
--- /dev/null
+++ b/osframework/source/demos/images/dialog.gif
Binary files differ
diff --git a/osframework/source/demos/images/dialog_.gif b/osframework/source/demos/images/dialog_.gif
new file mode 100644
index 0000000..cd24905
--- /dev/null
+++ b/osframework/source/demos/images/dialog_.gif
Binary files differ
diff --git a/osframework/source/demos/images/dialog_btn.gif b/osframework/source/demos/images/dialog_btn.gif
new file mode 100644
index 0000000..6b1ddee
--- /dev/null
+++ b/osframework/source/demos/images/dialog_btn.gif
Binary files differ
diff --git a/osframework/source/demos/images/dialog_btn_.gif b/osframework/source/demos/images/dialog_btn_.gif
new file mode 100644
index 0000000..650a3b6
--- /dev/null
+++ b/osframework/source/demos/images/dialog_btn_.gif
Binary files differ
diff --git a/osframework/source/demos/images/hungarr_logo.jpg b/osframework/source/demos/images/hungarr_logo.jpg
new file mode 100644
index 0000000..7f1f0d2
--- /dev/null
+++ b/osframework/source/demos/images/hungarr_logo.jpg
Binary files differ
diff --git a/osframework/source/demos/images/hungarr_logo_.gif b/osframework/source/demos/images/hungarr_logo_.gif
new file mode 100644
index 0000000..7b40389
--- /dev/null
+++ b/osframework/source/demos/images/hungarr_logo_.gif
Binary files differ
diff --git a/osframework/source/demos/images/layer0.jpg b/osframework/source/demos/images/layer0.jpg
new file mode 100644
index 0000000..a1784ad
--- /dev/null
+++ b/osframework/source/demos/images/layer0.jpg
Binary files differ
diff --git a/osframework/source/demos/images/layer1.png b/osframework/source/demos/images/layer1.png
new file mode 100644
index 0000000..e374608
--- /dev/null
+++ b/osframework/source/demos/images/layer1.png
Binary files differ
diff --git a/osframework/source/demos/images/layer2.png b/osframework/source/demos/images/layer2.png
new file mode 100644
index 0000000..19fd130
--- /dev/null
+++ b/osframework/source/demos/images/layer2.png
Binary files differ
diff --git a/osframework/source/demos/images/lightning.gif b/osframework/source/demos/images/lightning.gif
new file mode 100644
index 0000000..154b857
--- /dev/null
+++ b/osframework/source/demos/images/lightning.gif
Binary files differ
diff --git a/osframework/source/demos/images/lightning_.gif b/osframework/source/demos/images/lightning_.gif
new file mode 100644
index 0000000..acb7388
--- /dev/null
+++ b/osframework/source/demos/images/lightning_.gif
Binary files differ
diff --git a/osframework/source/demos/images/loader_bar.jpg b/osframework/source/demos/images/loader_bar.jpg
new file mode 100644
index 0000000..3a89e06
--- /dev/null
+++ b/osframework/source/demos/images/loader_bar.jpg
Binary files differ
diff --git a/osframework/source/demos/images/loader_loading.gif b/osframework/source/demos/images/loader_loading.gif
new file mode 100644
index 0000000..304c566
--- /dev/null
+++ b/osframework/source/demos/images/loader_loading.gif
Binary files differ
diff --git a/osframework/source/demos/images/loader_loading_.gif b/osframework/source/demos/images/loader_loading_.gif
new file mode 100644
index 0000000..98598fb
--- /dev/null
+++ b/osframework/source/demos/images/loader_loading_.gif
Binary files differ
diff --git a/osframework/source/demos/images/moon.gif b/osframework/source/demos/images/moon.gif
new file mode 100644
index 0000000..cce10f2
--- /dev/null
+++ b/osframework/source/demos/images/moon.gif
Binary files differ
diff --git a/osframework/source/demos/images/moon_.gif b/osframework/source/demos/images/moon_.gif
new file mode 100644
index 0000000..db1678f
--- /dev/null
+++ b/osframework/source/demos/images/moon_.gif
Binary files differ
diff --git a/osframework/source/demos/images/particle_lightning.jpg b/osframework/source/demos/images/particle_lightning.jpg
new file mode 100644
index 0000000..0574001
--- /dev/null
+++ b/osframework/source/demos/images/particle_lightning.jpg
Binary files differ
diff --git a/osframework/source/demos/images/planets_small.jpg b/osframework/source/demos/images/planets_small.jpg
new file mode 100644
index 0000000..012c544
--- /dev/null
+++ b/osframework/source/demos/images/planets_small.jpg
Binary files differ
diff --git a/osframework/source/demos/images/planets_small_.gif b/osframework/source/demos/images/planets_small_.gif
new file mode 100644
index 0000000..113bcee
--- /dev/null
+++ b/osframework/source/demos/images/planets_small_.gif
Binary files differ
diff --git a/osframework/source/demos/images/robotrobot.gif b/osframework/source/demos/images/robotrobot.gif
new file mode 100644
index 0000000..ca67363
--- /dev/null
+++ b/osframework/source/demos/images/robotrobot.gif
Binary files differ
diff --git a/osframework/source/demos/images/slider.gif b/osframework/source/demos/images/slider.gif
new file mode 100644
index 0000000..234000c
--- /dev/null
+++ b/osframework/source/demos/images/slider.gif
Binary files differ
diff --git a/osframework/source/demos/images/slider_thumb.gif b/osframework/source/demos/images/slider_thumb.gif
new file mode 100644
index 0000000..63e5a3b
--- /dev/null
+++ b/osframework/source/demos/images/slider_thumb.gif
Binary files differ
diff --git a/osframework/source/demos/images/spark.jpg b/osframework/source/demos/images/spark.jpg
new file mode 100644
index 0000000..54b2f58
--- /dev/null
+++ b/osframework/source/demos/images/spark.jpg
Binary files differ
diff --git a/osframework/source/demos/images/turbot_worry.gif b/osframework/source/demos/images/turbot_worry.gif
new file mode 100644
index 0000000..d5c0896
--- /dev/null
+++ b/osframework/source/demos/images/turbot_worry.gif
Binary files differ
diff --git a/osframework/source/demos/images/turbot_worry_.gif b/osframework/source/demos/images/turbot_worry_.gif
new file mode 100644
index 0000000..94e548b
--- /dev/null
+++ b/osframework/source/demos/images/turbot_worry_.gif
Binary files differ
diff --git a/osframework/source/demos/images/unicron_baby.JPG b/osframework/source/demos/images/unicron_baby.JPG
new file mode 100644
index 0000000..c694131
--- /dev/null
+++ b/osframework/source/demos/images/unicron_baby.JPG
Binary files differ
diff --git a/osframework/source/demos/images/unicron_baby_.GIF b/osframework/source/demos/images/unicron_baby_.GIF
new file mode 100644
index 0000000..0dc9607
--- /dev/null
+++ b/osframework/source/demos/images/unicron_baby_.GIF
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_down.jpg b/osframework/source/demos/images/unicron_beam_down.jpg
new file mode 100644
index 0000000..5e99e14
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_down.jpg
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_down_.gif b/osframework/source/demos/images/unicron_beam_down_.gif
new file mode 100644
index 0000000..256b6ad
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_down_.gif
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_left.jpg b/osframework/source/demos/images/unicron_beam_left.jpg
new file mode 100644
index 0000000..2c670cb
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_left.jpg
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_left_.gif b/osframework/source/demos/images/unicron_beam_left_.gif
new file mode 100644
index 0000000..f026aef
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_left_.gif
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_right.jpg b/osframework/source/demos/images/unicron_beam_right.jpg
new file mode 100644
index 0000000..05464c9
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_right.jpg
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_right_.gif b/osframework/source/demos/images/unicron_beam_right_.gif
new file mode 100644
index 0000000..1a96a80
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_right_.gif
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_up.jpg b/osframework/source/demos/images/unicron_beam_up.jpg
new file mode 100644
index 0000000..414d2cd
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_up.jpg
Binary files differ
diff --git a/osframework/source/demos/images/unicron_beam_up_.gif b/osframework/source/demos/images/unicron_beam_up_.gif
new file mode 100644
index 0000000..7af08a0
--- /dev/null
+++ b/osframework/source/demos/images/unicron_beam_up_.gif
Binary files differ
diff --git a/osframework/source/demos/images/unicron_horiz.jpg b/osframework/source/demos/images/unicron_horiz.jpg
new file mode 100644
index 0000000..de3ea7a
--- /dev/null
+++ b/osframework/source/demos/images/unicron_horiz.jpg
Binary files differ
diff --git a/osframework/source/demos/images/unicron_horiz_.gif b/osframework/source/demos/images/unicron_horiz_.gif
new file mode 100644
index 0000000..31b80ec
--- /dev/null
+++ b/osframework/source/demos/images/unicron_horiz_.gif
Binary files differ
diff --git a/osframework/source/demos/images/unicron_vert.jpg b/osframework/source/demos/images/unicron_vert.jpg
new file mode 100644
index 0000000..6eb277e
--- /dev/null
+++ b/osframework/source/demos/images/unicron_vert.jpg
Binary files differ
diff --git a/osframework/source/demos/images/unicron_vert_.gif b/osframework/source/demos/images/unicron_vert_.gif
new file mode 100644
index 0000000..6dc3be0
--- /dev/null
+++ b/osframework/source/demos/images/unicron_vert_.gif
Binary files differ
diff --git a/osframework/source/demos/music/hungarr.ogg b/osframework/source/demos/music/hungarr.ogg
new file mode 100644
index 0000000..1c1471f
--- /dev/null
+++ b/osframework/source/demos/music/hungarr.ogg
Binary files differ
diff --git a/osframework/source/demos/music/music.mo3 b/osframework/source/demos/music/music.mo3
new file mode 100644
index 0000000..533e78e
--- /dev/null
+++ b/osframework/source/demos/music/music.mo3
Binary files differ
diff --git a/osframework/source/demos/osfd VS2005.sln b/osframework/source/demos/osfd VS2005.sln
new file mode 100644
index 0000000..5167f7b
--- /dev/null
+++ b/osframework/source/demos/osfd VS2005.sln
@@ -0,0 +1,91 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SexyAppBase", "..\SexyAppFramework\SexyAppBase VS2005.vcproj", "{DA08CABA-92AC-40F0-B63D-6ACE7814D600}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo1", "Demo1\Demo1 VS2005.vcproj", "{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo2", "Demo2\Demo2 VS2005.vcproj", "{3729E951-A2F8-4516-BFF8-312040890EA4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo3", "Demo3\Demo3 VS2005.vcproj", "{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo4", "Demo4\Demo4 VS2005.vcproj", "{11091E68-2497-4470-9719-8ED84CECF827}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo5", "Demo5\Demo5 VS2005.vcproj", "{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hun-garr", "Hun-garr\Hun-garr VS2005.vcproj", "{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMLDemo", "XMLDemo\XMLDemo VS2005.vcproj", "{6A242898-B1D4-4EEA-AE61-AF1002462917}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V12Demo", "V12Demo\V12Demo VS2005.vcproj", "{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug|Win32.Build.0 = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release|Win32.ActiveCfg = Release|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release|Win32.Build.0 = Release|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug|Win32.Build.0 = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release|Win32.ActiveCfg = Release|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release|Win32.Build.0 = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug|Win32.Build.0 = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release|Win32.ActiveCfg = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release|Win32.Build.0 = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug|Win32.Build.0 = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release|Win32.ActiveCfg = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release|Win32.Build.0 = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug|Win32.ActiveCfg = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug|Win32.Build.0 = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release|Win32.ActiveCfg = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release|Win32.Build.0 = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug|Win32.Build.0 = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release|Win32.ActiveCfg = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release|Win32.Build.0 = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug|Win32.Build.0 = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release|Win32.ActiveCfg = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release|Win32.Build.0 = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug|Win32.Build.0 = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release|Win32.ActiveCfg = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release|Win32.Build.0 = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug|Win32.Build.0 = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release|Win32.ActiveCfg = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/osframework/source/demos/osfd WideString VS2005.sln b/osframework/source/demos/osfd WideString VS2005.sln
new file mode 100644
index 0000000..ba10250
--- /dev/null
+++ b/osframework/source/demos/osfd WideString VS2005.sln
@@ -0,0 +1,91 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo1", "Demo1\Demo1 VS2005 WideString.vcproj", "{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo2", "Demo2\Demo2 VS2005 WideString.vcproj", "{3729E951-A2F8-4516-BFF8-312040890EA4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo3", "Demo3\Demo3 VS2005 WideString.vcproj", "{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo4", "Demo4\Demo4 VS2005 WideString.vcproj", "{11091E68-2497-4470-9719-8ED84CECF827}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo5", "Demo5\Demo5 VS2005 WideString.vcproj", "{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hun-garr", "Hun-garr\Hun-garr VS2005 WideString.vcproj", "{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMLDemo", "XMLDemo\XMLDemo VS2005 WideString.vcproj", "{6A242898-B1D4-4EEA-AE61-AF1002462917}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V12Demo", "V12Demo\V12Demo VS2005 WideString.vcproj", "{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600} = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SexyAppBase WSTRING", "..\SexyAppFramework\SexyAppBase VS2005 WideString.vcproj", "{DA08CABA-92AC-40F0-B63D-6ACE7814D600}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug|Win32.Build.0 = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release|Win32.ActiveCfg = Release|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release|Win32.Build.0 = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug|Win32.Build.0 = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release|Win32.ActiveCfg = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release|Win32.Build.0 = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug|Win32.Build.0 = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release|Win32.ActiveCfg = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release|Win32.Build.0 = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug|Win32.ActiveCfg = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug|Win32.Build.0 = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release|Win32.ActiveCfg = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release|Win32.Build.0 = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug|Win32.Build.0 = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release|Win32.ActiveCfg = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release|Win32.Build.0 = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug|Win32.Build.0 = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release|Win32.ActiveCfg = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release|Win32.Build.0 = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug|Win32.Build.0 = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release|Win32.ActiveCfg = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release|Win32.Build.0 = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug|Win32.Build.0 = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release|Win32.ActiveCfg = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release|Win32.Build.0 = Release|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug|Win32.Build.0 = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release|Win32.ActiveCfg = Release|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/osframework/source/demos/osfd WideString.sln b/osframework/source/demos/osfd WideString.sln
new file mode 100644
index 0000000..4af2194
--- /dev/null
+++ b/osframework/source/demos/osfd WideString.sln
@@ -0,0 +1,80 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo1", "Demo1\Demo1 WideString.vcproj", "{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo2", "Demo2\Demo2 WideString.vcproj", "{3729E951-A2F8-4516-BFF8-312040890EA4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo3", "Demo3\Demo3 WideString.vcproj", "{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo4", "Demo4\Demo4 WideString.vcproj", "{11091E68-2497-4470-9719-8ED84CECF827}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo5", "Demo5\Demo5 WideString.vcproj", "{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hun-garr", "Hun-garr\Hun-garr WideString.vcproj", "{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMLDemo", "XMLDemo\XMLDemo WideString.vcproj", "{6A242898-B1D4-4EEA-AE61-AF1002462917}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V12Demo", "V12Demo\V12Demo WideString.vcproj", "{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SexyAppBase WSTRING", "..\SexyAppFramework\SexyAppBase WideString.vcproj", "{DA08CABA-92AC-40F0-B63D-6ACE7814D600}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {11091E68-2497-4470-9719-8ED84CECF827}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug.ActiveCfg = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug.Build.0 = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release.ActiveCfg = Release|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release.Build.0 = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug.ActiveCfg = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug.Build.0 = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release.ActiveCfg = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release.Build.0 = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug.ActiveCfg = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug.Build.0 = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release.ActiveCfg = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release.Build.0 = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug.ActiveCfg = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug.Build.0 = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release.ActiveCfg = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release.Build.0 = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug.ActiveCfg = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug.Build.0 = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release.ActiveCfg = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release.Build.0 = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug.ActiveCfg = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug.Build.0 = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release.ActiveCfg = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release.Build.0 = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug.ActiveCfg = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug.Build.0 = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release.ActiveCfg = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release.Build.0 = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug.ActiveCfg = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug.Build.0 = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release.ActiveCfg = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release.Build.0 = Release|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug.ActiveCfg = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug.Build.0 = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release.ActiveCfg = Release|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionItems) = postSolution
+ Item:1 = demos.txt
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/osframework/source/demos/osfd.dsw b/osframework/source/demos/osfd.dsw
new file mode 100644
index 0000000..9fb191c
--- /dev/null
+++ b/osframework/source/demos/osfd.dsw
@@ -0,0 +1,149 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Demo1"=.\Demo1\Demo1.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "Demo2"=.\Demo2\Demo2.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "Demo3"=.\Demo3\Demo3.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "Demo4"=.\Demo4\Demo4.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "Demo5"=.\Demo5\Demo5.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "Hungarr"=".\Hun-garr\Hungarr.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "SexyAppBase"=..\SexyAppFramework\SexyAppBase.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "V12Demo"=.\V12Demo\V12Demo.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "XMLDemo"=.\XMLDemo\XMLDemo.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name SexyAppBase
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/osframework/source/demos/osfd.sln b/osframework/source/demos/osfd.sln
new file mode 100644
index 0000000..efacc87
--- /dev/null
+++ b/osframework/source/demos/osfd.sln
@@ -0,0 +1,80 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SexyAppBase", "..\SexyAppFramework\SexyAppBase.vcproj", "{DA08CABA-92AC-40F0-B63D-6ACE7814D600}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo1", "Demo1\Demo1.vcproj", "{F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo2", "Demo2\Demo2.vcproj", "{3729E951-A2F8-4516-BFF8-312040890EA4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo3", "Demo3\Demo3.vcproj", "{07A2B4F6-12C3-47E6-AE89-B4013461A13A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo4", "Demo4\Demo4.vcproj", "{11091E68-2497-4470-9719-8ED84CECF827}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo5", "Demo5\Demo5.vcproj", "{7B08C75A-BF48-43F1-9B62-B1982584C06B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hun-garr", "Hun-garr\Hun-garr.vcproj", "{1D5FBC14-C869-4CC1-8337-B084767012C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMLDemo", "XMLDemo\XMLDemo.vcproj", "{6A242898-B1D4-4EEA-AE61-AF1002462917}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "V12Demo", "V12Demo\V12Demo.vcproj", "{9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {11091E68-2497-4470-9719-8ED84CECF827}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.0 = {DA08CABA-92AC-40F0-B63D-6ACE7814D600}
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug.ActiveCfg = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Debug.Build.0 = Debug|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release.ActiveCfg = Release|Win32
+ {DA08CABA-92AC-40F0-B63D-6ACE7814D600}.Release.Build.0 = Release|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug.ActiveCfg = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Debug.Build.0 = Debug|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release.ActiveCfg = Release|Win32
+ {F1FFB2ED-BC5D-40C9-A46B-92DAFEC91BBC}.Release.Build.0 = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug.ActiveCfg = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Debug.Build.0 = Debug|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release.ActiveCfg = Release|Win32
+ {3729E951-A2F8-4516-BFF8-312040890EA4}.Release.Build.0 = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug.ActiveCfg = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Debug.Build.0 = Debug|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release.ActiveCfg = Release|Win32
+ {07A2B4F6-12C3-47E6-AE89-B4013461A13A}.Release.Build.0 = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug.ActiveCfg = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Debug.Build.0 = Debug|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release.ActiveCfg = Release|Win32
+ {11091E68-2497-4470-9719-8ED84CECF827}.Release.Build.0 = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug.ActiveCfg = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Debug.Build.0 = Debug|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release.ActiveCfg = Release|Win32
+ {7B08C75A-BF48-43F1-9B62-B1982584C06B}.Release.Build.0 = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug.ActiveCfg = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Debug.Build.0 = Debug|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release.ActiveCfg = Release|Win32
+ {1D5FBC14-C869-4CC1-8337-B084767012C3}.Release.Build.0 = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug.ActiveCfg = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Debug.Build.0 = Debug|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release.ActiveCfg = Release|Win32
+ {6A242898-B1D4-4EEA-AE61-AF1002462917}.Release.Build.0 = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug.ActiveCfg = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Debug.Build.0 = Debug|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release.ActiveCfg = Release|Win32
+ {9A062D6E-B4A5-44F6-8D4D-84F19BCBF4FF}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionItems) = postSolution
+ Item:1 = demos.txt
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/osframework/source/demos/properties/demo.xml b/osframework/source/demos/properties/demo.xml
new file mode 100644
index 0000000..aa31984
--- /dev/null
+++ b/osframework/source/demos/properties/demo.xml
@@ -0,0 +1,38 @@
+<!-- below is an example of an instruction. The XMLParser class can handle instruction syntax,
+ but you'll notice that in the XMLDemo we don't actually use the value, we just ignore it. -->
+<?xml version="1.0"?>
+
+<!-- Sections contain nested items -->
+<Section1>
+
+ <!-- This item, "Item1", contains just 1 attribute, "text", and nothing more -->
+ <Item1 text="Some text for Section1/Item1"/>
+
+ <!-- This item, "BoolParam", contains an attribute, "text", as well as an element value,
+ which is the string "true" -->
+ <BoolParam text="Some text for Section1/BoolParam">true</BoolParam>
+
+ <!-- end of the section -->
+</Section1>
+
+<!-- This section contains an attribute in its line -->
+<Section2 s2attrib="Section2 attrib text">
+ <IntParam text="Some text for Section2/IntParam">1234</IntParam>
+
+ <!-- This just shows that you can split things up across lines. This is functionally equivalent to:
+ <MultiAttrib attrib1="attrib1" attrib2="2" attrib3="woo! attrib3!"/> -->
+
+ <MultiAttrib
+ attrib1="attrib1"
+ attrib2="2"
+ attrib3="woo! attrib3!"
+ />
+
+ <!-- The XMLParser class handles nested sections as well -->
+ <Subsection>
+ <!-- and of course, you can put more items in here, like any other section -->
+ <Item2>Text for Section2/Subsection/Item2</Item2>
+ </Subsection>
+
+</Section2>
+ \ No newline at end of file
diff --git a/osframework/source/demos/properties/resources.xml b/osframework/source/demos/properties/resources.xml
new file mode 100644
index 0000000..cf9d36d
--- /dev/null
+++ b/osframework/source/demos/properties/resources.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0"?>
+
+<!--
+ All resources.xml files must contain the ResourceManifest section.
+
+ Just like when we loaded resources manually in demos 1-3, you do
+ not have to specify the extensions for images and sounds.
+
+ Use the ResourceGen.exe program to convert this XML into C++ code.
+ The variable names that you give to the resources below will then be
+ accessible by any file that includes your resource header file
+ (generated by ResourceGen.exe).
+
+ Resource groups can be loaded/deleted at any time. Thus, it's advantageous
+ to split your resources into groups if you don't need to have every single
+ resource in memory at the same time. A common use for grouping is to
+ split the title screen, main menu, and main game elements up. Then,
+ when the main game is playing, you can kick out the main menu and title
+ screen data. Similarly, when you are back to the main menu, you can kick out
+ the game resources. How you use the grouping is up to you, it's provided
+ for your convenience.
+
+ Remember in previous demos how we had to manually set an image's
+ mNumRows and mNumCols by hand? Not anymore. If we had an image we
+ wanted to load that contained more than 1 row or column, we could
+ specify the optional parameters: cols and rows. As an example, here's
+ how we'd load in that lightning image from a previous demo:
+
+ <Image id="LIGHTNINGT" path="images/lightning" rows="8"/>
+
+ And then it's automatically set for you when you load the resource.
+-->
+
+<ResourceManifest>
+
+ <!-- You create resource groups with the Resources tag. Specify the
+ group name in the "id" field. We tend to use "Init" to mean the resources that
+ must be loaded before ANYTHING displays. We put our main font in here instead
+ of in the TileScreen group (below) because we want the font to stick around
+ for the duration of the game and not to be removed when we get rid of the
+ title screen. -->
+ <Resources id="Init">
+
+ <!-- You can set the default directory to look for the resources in, as
+ well as a standard prefix for the resource variable names when the C++
+ code is generated. -->
+ <SetDefaults path="fonts" idprefix="FONT_" />
+
+ <!-- The Font tag indicates that we want to load and initialize a font. Just
+ give the font a name (in this case, FONT_DEFAULT) and tell the manager where
+ to look for the data file. -->
+ <Font id="DEFAULT" path="ContinuumBold12.txt"/>
+ <Font id="HUNGARR" path="ArmorPiercing22.txt"/>
+
+ <SetDefaults path="images" idprefix="IMAGE_" />
+ <Image id="CUSTOM_POINTER" path="custom_pointer"/>
+ <Image id="CUSTOM_HAND" path="custom_hand"/>
+ <Image id="CUSTOM_DRAGGING" path="custom_dragging"/>
+ <Image id="CUSTOM_TEXT" path="custom_text"/>
+ <Image id="HUNGARR_LOGO" path="hungarr_logo"/>
+
+ </Resources>
+
+ <!-- These are the resources that are going to be used solely by the title screen.
+ Again, we could have named this resource group anything we wanted.
+ These resources will be deleted after we are done using the title screen. -->
+ <Resources id="TitleScreen">
+ <SetDefaults path="images" idprefix="IMAGE_"/>
+
+ <!-- The Image tag specifies that we want to load...an image.
+ There is also a Sound tag for loading sounds. All the tags work exactly the same:
+ you specify a variable name to use (if idprefix is specified it is prepended to
+ that name) and the name of the file to load. -->
+ <Image id="LOADER_BAR" path="loader_bar"/>
+ <Image id="LOADER_LOADINGTXT" path="loader_loading"/>
+
+ <SetDefaults path="sounds" idprefix="SOUND_"/>
+ <Sound id="CONTINUE" path="slowdown1"/>
+ </Resources>
+
+ <!-- And finally, we'll put all the resources that are needed for the main game
+ part of things in this group. -->
+ <Resources id="Game">
+ <SetDefaults path="sounds" idprefix="SOUND_"/>
+
+ <Sound id="MUTATOR" path="mutator"/>
+ <Sound id="TIMER" path="timer"/>
+
+ <SetDefaults path="images" idprefix="IMAGE_"/>
+
+ <!-- in case you're wondering about some of these filenames, they are taken
+ from various PopCap games. They haven't been changed. -->
+
+ <Image id="ROBOTROBOT" path="robotrobot"/>
+ <Image id="CHECKBOX" path="checkbox"/>
+ <Image id="BG0" path="layer0"/>
+ <Image id="BG1" path="layer1"/>
+ <Image id="BG2" path="layer2"/>
+ <Image id="BUTTON_DOWN" path="btn_down"/>
+ <Image id="BUTTON_OVER" path="btn_over"/>
+ <Image id="BUTTON_NORMAL" path="btn_up"/>
+
+ <Image id="DIALOG_BOX" path="dialog"/>
+ <Image id="DIALOG_BUTTON" path="dialog_btn"/>
+ <Image id="SLIDER_TRACK" path="slider"/>
+ <Image id="SLIDER_THUMB" path="slider_thumb"/>
+ </Resources>
+
+ <!-- Resources for the Hun-garr game -->
+ <Resources id="Hungarr">
+ <SetDefaults path="images" idprefix="IMAGE_"/>
+ <Image id="HUNGARR_SMALL" path="unicron_baby"/>
+ <Image id="HUNGARR_BEAM_UP" path="unicron_beam_up"/>
+ <Image id="HUNGARR_BEAM_DOWN" path="unicron_beam_down"/>
+ <Image id="HUNGARR_BEAM_LEFT" path="unicron_beam_left"/>
+ <Image id="HUNGARR_BEAM_RIGHT" path="unicron_beam_right"/>
+ <Image id="HUNGARR_HORIZ" path="unicron_horiz"/>
+ <Image id="HUNGARR_VERT" path="unicron_vert"/>
+ <Image id="ATOMIC_EXPLOSION" path="atomicexplosion" cols="15"/>
+ <Image id="BOMB_RADIAL_DEATH" path="bomb_radial_death" cols="10"/>
+ <Image id="PLANETS" path="planets_small" cols="11" rows="3"/>
+ <Image id="SPARK" path="spark"/>
+ <Image id="PARTICLE_LIGHTNING" path="particle_lightning" cols="19"/>
+
+ <SetDefaults path="sounds" idprefix="SOUND_"/>
+ <Sound id="MAGZAP" path="magzap1"/>
+ <Sound id="BUTTON" path="mouseover"/>
+ <Sound id="PLANET" path="planet"/>
+ <Sound id="LEVEL_UP1" path="level_up"/>
+ <Sound id="LEVEL_UP2" path="level_up2"/>
+ <Sound id="EXPLOSION" path="explosion"/>
+
+ <Sound id="BEAM_HIT" path="robotlaser"/>
+ <Sound id="PLANET_HIT" path="click2"/>
+ <Sound id="BEAM_MOVING" path="shorting"/>
+ <Sound id="LEVEL_UP4" path="laserpowerup"/>
+ <Sound id="LEVEL_UP3" path="killall_explode"/>
+ <Sound id="GAME_OVER_CLICK" path="bad2"/>
+ <Sound id="GAME_OVER_STATS" path="electro_start"/>
+ <Sound id="GAME_OVER_RESTART" path="whirlpool1"/>
+ <Sound id="GAME_OVER_TEXT" path="lament"/>
+ <Sound id="REGION_FILLED" path="metal_loop"/>
+
+ </Resources>
+</ResourceManifest>
diff --git a/osframework/source/demos/sounds/bad2.ogg b/osframework/source/demos/sounds/bad2.ogg
new file mode 100644
index 0000000..4c88300
--- /dev/null
+++ b/osframework/source/demos/sounds/bad2.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/click2.ogg b/osframework/source/demos/sounds/click2.ogg
new file mode 100644
index 0000000..6215476
--- /dev/null
+++ b/osframework/source/demos/sounds/click2.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/electro_start.ogg b/osframework/source/demos/sounds/electro_start.ogg
new file mode 100644
index 0000000..b5c33b1
--- /dev/null
+++ b/osframework/source/demos/sounds/electro_start.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/explosion.ogg b/osframework/source/demos/sounds/explosion.ogg
new file mode 100644
index 0000000..c4a0027
--- /dev/null
+++ b/osframework/source/demos/sounds/explosion.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/killall_explode.ogg b/osframework/source/demos/sounds/killall_explode.ogg
new file mode 100644
index 0000000..67ca4e9
--- /dev/null
+++ b/osframework/source/demos/sounds/killall_explode.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/lament.ogg b/osframework/source/demos/sounds/lament.ogg
new file mode 100644
index 0000000..c1f8946
--- /dev/null
+++ b/osframework/source/demos/sounds/lament.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/laserpowerup.ogg b/osframework/source/demos/sounds/laserpowerup.ogg
new file mode 100644
index 0000000..c66a149
--- /dev/null
+++ b/osframework/source/demos/sounds/laserpowerup.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/level_up.ogg b/osframework/source/demos/sounds/level_up.ogg
new file mode 100644
index 0000000..1f5df38
--- /dev/null
+++ b/osframework/source/demos/sounds/level_up.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/level_up2.ogg b/osframework/source/demos/sounds/level_up2.ogg
new file mode 100644
index 0000000..2387c05
--- /dev/null
+++ b/osframework/source/demos/sounds/level_up2.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/magzap1.ogg b/osframework/source/demos/sounds/magzap1.ogg
new file mode 100644
index 0000000..40c856e
--- /dev/null
+++ b/osframework/source/demos/sounds/magzap1.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/metal_loop.wav b/osframework/source/demos/sounds/metal_loop.wav
new file mode 100644
index 0000000..6ec418a
--- /dev/null
+++ b/osframework/source/demos/sounds/metal_loop.wav
Binary files differ
diff --git a/osframework/source/demos/sounds/mouseover.ogg b/osframework/source/demos/sounds/mouseover.ogg
new file mode 100644
index 0000000..762b24d
--- /dev/null
+++ b/osframework/source/demos/sounds/mouseover.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/mutator.ogg b/osframework/source/demos/sounds/mutator.ogg
new file mode 100644
index 0000000..fdf3aac
--- /dev/null
+++ b/osframework/source/demos/sounds/mutator.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/planet.ogg b/osframework/source/demos/sounds/planet.ogg
new file mode 100644
index 0000000..796542c
--- /dev/null
+++ b/osframework/source/demos/sounds/planet.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/robotlaser.ogg b/osframework/source/demos/sounds/robotlaser.ogg
new file mode 100644
index 0000000..5be5700
--- /dev/null
+++ b/osframework/source/demos/sounds/robotlaser.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/shorting.ogg b/osframework/source/demos/sounds/shorting.ogg
new file mode 100644
index 0000000..cb95541
--- /dev/null
+++ b/osframework/source/demos/sounds/shorting.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/slowdown1.ogg b/osframework/source/demos/sounds/slowdown1.ogg
new file mode 100644
index 0000000..953d624
--- /dev/null
+++ b/osframework/source/demos/sounds/slowdown1.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/timer.ogg b/osframework/source/demos/sounds/timer.ogg
new file mode 100644
index 0000000..bcf4392
--- /dev/null
+++ b/osframework/source/demos/sounds/timer.ogg
Binary files differ
diff --git a/osframework/source/demos/sounds/whirlpool1.ogg b/osframework/source/demos/sounds/whirlpool1.ogg
new file mode 100644
index 0000000..2993ffc
--- /dev/null
+++ b/osframework/source/demos/sounds/whirlpool1.ogg
Binary files differ