1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 29 #ifndef __TestContext_H__ 30 #define __TestContext_H__ 31 32 #include "VisualTest.h" 33 #include "SampleContext.h" 34 #include "SamplePlugin.h" 35 36 #include <iostream> // for Apple 37 38 class TestBatch; 39 using namespace Ogre; 40 41 typedef std::map<String, OgreBites::SamplePlugin *> PluginMap; 42 43 /** The common environment that all of the tests run in */ 44 class TestContext : public OgreBites::SampleContext 45 { 46 public: 47 48 TestContext(int argc = 0, char** argv = 0); 49 virtual ~TestContext(); 50 51 /** Does basic setup for the context */ 52 virtual void setup(); 53 54 /** Frame listener callback, handles updating of the tests at the start of frames 55 * @param evt The frame event (passed in for the framelistener) */ 56 virtual bool frameStarted(const FrameEvent& evt); 57 58 /** Frame listener callback, handles updating of the tests at the end of frames 59 * @param evt The frame event (passed in for the framelistener) */ 60 virtual bool frameEnded(const FrameEvent& evt); 61 62 /** Runs a given test or sample 63 * @param s The OgreBites::Sample to run 64 * @remarks If s is a VisualTest, then timing and rand will be setup for 65 * determinism. */ 66 virtual void runSample(OgreBites::Sample* s); 67 68 /** Loads test plugins 69 * @param set The name of the test set to load 70 * @return The initial tets or sample to run */ 71 OgreBites::Sample* loadTests(String set); 72 73 /** Setup the Root */ 74 virtual void createRoot(); 75 76 /** Start it up */ 77 virtual void go(OgreBites::Sample* initialSample = 0); 78 79 /** Handles the config dialog */ 80 virtual bool oneTimeConfig(); 81 82 /** Set up directories for the tests to output to */ 83 virtual void setupDirectories(String batchName); 84 85 /** Called after tests successfully complete, generates output */ 86 virtual void finishedTests(); 87 88 /** Sets the timstep value 89 * @param timestep The time to simulate elapsed between each frame 90 * @remarks Use with care! Screenshots produced at different timesteps 91 * will almost certainly turn out different. */ 92 void setTimestep(Real timestep); 93 94 /** Gets the current timestep value */ 95 Real getTimestep(); 96 getCurrentTest()97 VisualTest* getCurrentTest() { return mCurrentTest; } 98 99 /// Returns whether the entire test was successful or not. wasSuccessful()100 bool wasSuccessful() const { 101 return mSuccess; 102 } 103 104 protected: 105 bool mSuccess; 106 107 /// The timestep 108 Real mTimestep; 109 110 /// Path to the test plugin directory 111 String mPluginDirectory; 112 113 /// List of available test sets 114 std::map<String, StringVector> mTestSets; 115 116 /// The tests to be run 117 std::deque<OgreBites::Sample*> mTests; 118 119 /// Path to the output directory for the running test 120 String mOutputDir; 121 122 /// Path to the reference set location 123 String mReferenceSetPath; 124 125 /// The active test (0 if none is active) 126 VisualTest* mCurrentTest; 127 128 /// The current frame of a running test 129 unsigned int mCurrentFrame; 130 131 /// Info about the running batch of tests 132 TestBatch* mBatch; 133 134 // A structure to map plugin names to class types 135 PluginMap mPluginNameMap; 136 137 // command line options 138 // Is a reference set being generated? 139 bool mReferenceSet; 140 // Should html output be created? 141 bool mGenerateHtml; 142 // Force the config dialog 143 bool mForceConfig; 144 // Do not confine mouse to window 145 bool mNoGrabMouse; 146 // Show usage details 147 bool mHelp; 148 // Render system to use 149 String mRenderSystemName; 150 // Optional name for this batch 151 String mBatchName; 152 // Set to compare against 153 String mCompareWith; 154 // Optional comment 155 String mComment; 156 // Name of the test set to use 157 String mTestSetName; 158 // Location to output a test summary (used for CTest) 159 String mSummaryOutputDir; 160 }; 161 162 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS && defined(__OBJC__) 163 #import <UIKit/UIKit.h> 164 #import <QuartzCore/QuartzCore.h> 165 166 @interface AppDelegate : NSObject <UIApplicationDelegate> 167 { 168 TestContext *tc; 169 170 CADisplayLink *mDisplayLink; 171 NSDate* mDate; 172 NSTimeInterval mLastFrameTime; 173 } 174 175 - (void)go; 176 - (void)renderOneFrame:(id)sender; 177 178 @property (nonatomic) NSTimeInterval mLastFrameTime; 179 180 @end 181 182 @implementation AppDelegate 183 184 @dynamic mLastFrameTime; 185 186 - (NSTimeInterval)mLastFrameTime 187 { 188 return mLastFrameTime; 189 } 190 191 - (void)setLastFrameTime:(NSTimeInterval)frameInterval 192 { 193 // Frame interval defines how many display frames must pass between each time the 194 // display link fires. The display link will only fire 30 times a second when the 195 // frame internal is two on a display that refreshes 60 times a second. The default 196 // frame interval setting of one will fire 60 times a second when the display refreshes 197 // at 60 times a second. A frame interval setting of less than one results in undefined 198 // behavior. 199 if (frameInterval >= 1) 200 { 201 mLastFrameTime = frameInterval; 202 } 203 } 204 205 - (void)go { 206 207 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 208 NSArray * arguments = [[NSProcessInfo processInfo] arguments]; 209 char *argv[[arguments count]+1]; 210 int i = 0; 211 for (NSString *str in arguments) 212 { 213 argv[i++] = (char *)[str UTF8String]; 214 } 215 argv[i] = NULL; 216 217 try { 218 tc = new TestContext([arguments count], &argv[0]); 219 tc->go(); 220 221 Root::getSingleton().getRenderSystem()->_initRenderTargets(); 222 223 // Clear event times 224 Root::getSingleton().clearEventTimes(); catch(Exception & e)225 } catch( Exception& e ) { 226 std::cerr << "An exception has occurred: " << 227 e.getFullDescription().c_str() << std::endl; 228 } 229 230 [pool release]; 231 } 232 233 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 234 { 235 // Defaulting to 2 means that we run at 30 frames per second. For 60 frames, use a value of 1. 236 // 30 FPS is usually sufficient and results in lower power consumption. 237 mLastFrameTime = 2; 238 mDisplayLink = nil; 239 240 [self go]; 241 242 return YES; 243 } 244 245 - (void)applicationWillTerminate:(UIApplication *)application 246 { 247 tc->finishedTests(); 248 } 249 250 - (void)applicationDidBecomeActive:(UIApplication *)application 251 { 252 // Reset event times and reallocate the date and displaylink objects 253 Root::getSingleton().clearEventTimes(); 254 mDate = [[NSDate alloc] init]; 255 mLastFrameTime = 2; // Reset the timer 256 257 mDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(renderOneFrame:)]; 258 [mDisplayLink setFrameInterval:mLastFrameTime]; 259 [mDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 260 } 261 262 - (void)applicationWillResignActive:(UIApplication *)application 263 { 264 Root::getSingleton().saveConfig(); 265 266 [mDate release]; 267 mDate = nil; 268 269 [mDisplayLink invalidate]; 270 mDisplayLink = nil; 271 } 272 273 - (void)renderOneFrame:(id)sender 274 { 275 // NSTimeInterval is a simple typedef for double 276 NSTimeInterval currentFrameTime = -[mDate timeIntervalSinceNow]; 277 NSTimeInterval differenceInSeconds = currentFrameTime - mLastFrameTime; 278 mLastFrameTime = currentFrameTime; 279 280 dispatch_async(dispatch_get_main_queue(), ^(void) 281 { 282 Root::getSingleton().renderOneFrame((Real)differenceInSeconds); 283 }); 284 285 if(Root::getSingletonPtr() && Root::getSingleton().isInitialised() && !tc->getCurrentTest()) 286 { 287 tc->finishedTests(); 288 289 // Force the app to exit. Acts like a crash which isn't very elegant but good enough in this case. 290 exit(0); 291 } 292 } 293 294 @end 295 296 #endif // OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS && defined(__OBJC__) 297 298 #endif 299