Momentan gibt es einen Port der OgreEngine auf das iPhone, sowie ein XCode Template und eine Sample App.
Ich werde in diesem Blogeintrag beschreiben, wie man die SampleApp auf seinem Mac einrichted, und sie dann wieder los wird, um mit einem minimalen Sysem sein eigenes Spiel zu starten:
Da das Projekt sich noch in Arbeit befindet, ist auch dieser Eintrag noch nicht fertig . Alle denen es unter den Nägeln brennt, sind eingeladen weiterzulesen – allen Anderen Empfehle ich auf die Strukturierte Variante zu warten
Erstmal die Bezugsquellen:
http://www.ogre3d.org/wiki/index.php/Ogre_iPhone
Statt from source zu builden habe ich mich entschieden die 1.7 Version zu nehmen
http://sourceforge.net/projects/ogre/files/
Hier läd man sich unter Ogre -> 1.7 das iPhone sdk und unter ogre_mac_dependecies -> das Xcode Template
(die iPhone dependencies braucht man nach meiner Erfahrung nicht – da die Libs auch im Release folder liegen)
Für das ganze braucht man dann noch cmake installiert und zwar in der Version 2.8.0 die 2.8.1 hat im Moment noch einige Bugs, die dazu führen das man nicht compilieren kann.
Dann das XCode template installieren
und dann kanns losgehen mit sample builden.
Wer als Debug compilieren möchte (was man tun sollte wenn man an den Samples arbeiten möchte oder daran arbeiten) der muss entweder bei den Lib Search Pathes bei eingestelltem Debug modus den Release Ordner hinzufügen oder sämtliche Libs aus lib/Release nach lib/Debug kopieren.
Wenn die Templates und alle Libs richtig installiert wurden – sollte die SampleApp Compilieren und sich im Simulator abspielen lassen.
Hier kann man sich erst einmal einen Überblick verschaffen zu was die Engine auf dem iPhone alles Fähig ist.
Wer in dem Sample Codes ein wenig rumspielen will sollte folgendes beachten.
Im Sample Ordner liegen sämtliche header files nocheinmal in dem unterordner Samples/include. Wenn man nun n XCode unter den einzellnen Samples die Headerfiles editiert um ein wenig mit Ogre rumzuspielen passiert erstmal gar nix.
Den Ordner include löscht man daher am besten und fügt stattdessen unter in Search_path->Header Search Path den Pfad: $SRCROOT/Samples/** hinzu (** steht für Rekursiv durchsuchen) ($SRCROOT ist der Ordner in dem sich das Project befindet)
Nun kann man erstmal mit den Samples ein wenig rumspielen und wenn man Ogre noch nicht kennt anhand der Basic Tutorials durchspielen.
Ich habe zum testen immer sehr gerne die SkyDome scene genonmmen da sie recht übersichtlich ist. Und wenn man nicht ewig durch die vielen Samples scrollen will beim testen, der kann in der SamplesBrowser.h in der Methode setup das laden der SamplePlugins auskommentieren. Das erste Sample (BSP) muss allerdings da bleiben, und natürlich das an dem man arbeitet.
Der nächste Schritt war für mich dann eine App zu bauen die ohne die Samples auskommt, und vorallem den (zwar sehr schicken – aber für ein eigenes Spiel hinderlichen) SampleBrowser loszuwerden.
Meine ersten Versuche selber ein neuen Project aufzusetzen und die Settings aus dem Sampleproject zu übernehmen sind leider an einer menge komischer Compilerfehler gescheitert.(Handelt sich um einen Bug im iPhone sdk – wens intressiert: google
)
Deswegen habe ich mir das SampleProject nochmal vorgenommen und das reduziert, mit folgende Schritten:
1. xcode Project datei kopieren und ihr einen neuen Namen verpasst.
2. neuen Ordner angelegen, in dem man seinen eigenen Quellcode unterbringen kann.
3. aus dem Ordner Sample/Browser/include die Datei SampleBrowser.h und aus Browser/src die Datei SampeBrowser.cpp in den Quellcode
ordner kopieren (und gegebenenfalls umbennen)
4. das kopierte XCode project aufmachen und die Dateien SampleBrowser.cpp und .h umlegen auf die kopierten Dateien (Rechtsklick -> GetInfo -> Rechts neben der Pfad angaben auf Choose klicken und Dateien auswählen)
5. Die SampleBrowser.cpp habe ich nur geringfügig Abgeändert (siehe unten)
6. die SampleBrowser.h habe ich komplett neu geschrieben (als Anleitung kann man hier das Basic Tutorial 6 nehmen).
Manche Sachen (wie das Resource Managment) habe ich erstmal aus der SampleContext.h übernommen.
Bei mir sind beim einige Laufzeitfehler beim ResourceMangement passiert, bei denen ich Momentan noch nicht weiß warum sie auftreten, deswegen habe ich mir eine eigene resource.cfg Datei angelegt (original zu finden unter bin/resource.cfg), und nur die nötigsten Sachen eingeladen (Siehe unten)
7. Entgegen dem Basic tutorial 6 darf man nicht schon in der go() routine den RenderLoop starten (Root->startRendering()), sonst kehrt die go niemals zurück und es wird zwar gerendert aber der Splashscreen bleibt stehen und mann sieht nix.
(Der Splashscreen bleibt immer dann stehen wenn die AppDidFinishLaunching Methode nicht zurückkehrt)
Deswegen darf die go Routine nur setupen. Das starten des Renderings passiert dann über die Hauptroutine, in der SampleBrowser.cpp
Ich habe dazu den nTimer aus der cpp datei auf Repeat:NO gestellt und in der RenderOneFrame Methode dann das Rendering gestartet.
Hier muss man dann je nachdem wie man sein Spiel aufgebaut hat selber schrauben.
8. Wenn das dann alles geht, kann man anfangen die alles was man von den Samples nicht braucht rauszuschmeißen. Dazugehören auf jeden Fall alle SamplePlugins. Dazu löscht man die Quelldateien (aber nur die Referencen es sei denn man will das Sample nicht behalten), dann schmeißt man unter den LinkerOptions die ganzen Samples raus. Außerdem kann man unter Targets alle Targest außer dem SampleBrowser löschen.
Vom SampleBrowser benötigt man noch die folgenden Dateien:
FileSystemLayerImpl.h und die mm
OgreStaticPluginLoader.h
Wenn man die App umbenennt bekommt man einige Probleme – das behebt sich wenn man die PreBuild und das ReRun script bearbeitet siehe weiter unten.
Außerdem hatte ich öfter das Problem, das er das Rendersystem nicht finden konnte – das lag daran das in der OgreStaticPluginLoader Ogre_STATIC_GLES nicht defined war und deswegen beim laden nicht eingebunden wurde, mit einem #define OGRE_STATIC_GLES ist die Sache erledigt
Um die Sample Dateien nun vollständig loszuwerden sind noch folgende Schritte nötig:
Im XCode: Linke Seite unter Active Target ausklappen -> dort sind 3 Ordner drunter
Unter PrebuildScripts im XCode unter PrebuildScript(letzter Ordner) doppelklicken dort befindet sich ein make -C befehl.
-C ändert den Aktuellen Arbeitspfad (der aktuell auf $SRCROOT/Samples/Browser steht und evtl auch angepasst werden muss, auf den gleichen Folder in dem sich dann auch der CMakeScript Ordner befindet). Danach kommt der Befehl mit dem das Prebuild Script aufgerufen wird – das Script kann man sich kopieren und in dem Script dann alle Pfade abändern, und an die eigenen Belange anpassen. das Script liegt bei den Samples in /Samples/Browser/CMakeScript/SampleBrowser_postBuildPhase.makeDebug drinne befinden sich pfade
die muss man ersetzen.
Dieses PreBuild Script kopiert im Grunde alle benötigten Resourcen (MeshFiles, cfg Files etc) in den *.app Folder im bin verzeichnis, damit der iPhonesimulator damit arbeiten kann.
Ebenfalls unter ausgeklappten Target links Im Projectfolder CMakeScript befindet sich noch eine ReRun Datei. Hier auch doppelt klicken und schauen wo die Datei liegt – in dieser Datei müssen auch wieder die SampleBrowser Pfade angepasste werden.
Die Dritte Stelle die man noch für Abhängigkeiten checken muss sind natürlich die Project Settings in XCode
Nun kann man den Sample Folder komplett löschen, und seine eigene App aufbauen.
plugins.cfg braucht man nicht – die Aufgabe wird auf dem iPhone vom StaticPluginLoader übernommen
Anhang: Quellcode:
SampleBrowser.h
#include "Ogre.h"
#include "OgrePlugin.h"
#include "macutils.h"
#include "FileSystemLayerImpl.h"
// Static plugins declaration section
// Note that every entry in here adds an extra header / library dependency
# ifdef OGRE_BUILD_RENDERSYSTEM_GL
# define OGRE_STATIC_GL
# endif
# ifdef OGRE_BUILD_RENDERSYSTEM_GLES
# define OGRE_STATIC_GLES
# endif
# if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
# ifdef OGRE_BUILD_RENDERSYSTEM_D3D9
# define OGRE_STATIC_Direct3D9
# endif
// dx10 will only work on vista, so be careful about statically linking
# ifdef OGRE_BUILD_RENDERSYSTEM_D3D10
# define OGRE_STATIC_Direct3D10
# endif
# ifdef OGRE_BUILD_RENDERSYSTEM_D3D11
# define OGRE_STATIC_Direct3D11
# endif
# endif
# ifdef OGRE_BUILD_PLUGIN_BSP
# define OGRE_STATIC_BSPSceneManager
# endif
# ifdef OGRE_BUILD_PLUGIN_PFX
# define OGRE_STATIC_ParticleFX
# endif
# ifdef OGRE_BUILD_PLUGIN_CG
# define OGRE_STATIC_CgProgramManager
# endif
# ifdef OGRE_USE_PCZ
# ifdef OGRE_BUILD_PLUGIN_PCZ
# define OGRE_STATIC_PCZSceneManager
# define OGRE_STATIC_OctreeZone
# endif
# else
# ifdef OGRE_BUILD_PLUGIN_OCTREE
# define OGRE_STATIC_OctreeSceneManager
# endif
# endif
# include "OgreStaticPluginLoader.h"
using namespace OgreBites;
#import "AnimationListener.h"
class SampleBrowser {
private:
Ogre::Root *mRoot;
FileSystemLayer* mFSLayer;
Ogre::RenderWindow* mWindow;
Ogre::StaticPluginLoader mStaticPluginLoader;
AnimationListener *mListener;
Ogre::AnimationState* mAnimationState;
Ogre::AnimationState* mAnimationState2;
public:
SampleBrowser(){
mFSLayer = OGRE_NEW_T(FileSystemLayerImpl, Ogre::MEMCATEGORY_GENERAL)(OGRE_VERSION_NAME);
//mRoot = 0;
}
void go(){
createRoot();
defineResources();
setupRenderSystem();
createRenderWindow();
initializeResourceGroups();
createFrameListener();
setupScene();
/**/
}
void createRoot()
{
Ogre::String pluginsPath = Ogre::StringUtil::BLANK;
//pluginsPath = mFSLayer->getConfigFilePath("plugins.cfg");
//pluginsPath = "/Users/paulinealtmann/FID/ogre_1_7_stable/OgreSDK/Samples/Browser/";
//std::cout << std::endl << "Readed Plug Path: " << pluginsPath << std::endl;
mRoot = OGRE_NEW Ogre::Root(pluginsPath, mFSLayer->getWritablePath("ogre.cfg"), mFSLayer->getWritablePath("ogre.log"));
mStaticPluginLoader.load();
}
void defineResources()
{
// load resource paths from config file
Ogre::ConfigFile cf;
cf.load(mFSLayer->getConfigFilePath("/Users/paulinealtmann/FID/ogre_iPhone/OgreSDK/bin/resources_my.cfg"));
//cf.load(mFSLayer->getConfigFilePath("resources_my.cfg"));
Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
Ogre::String sec, type, arch;
// go through all specified resource groups
while (seci.hasMoreElements())
{
sec = seci.peekNextKey();
Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();
Ogre::ConfigFile::SettingsMultiMap::iterator i;
// go through all resource paths
for (i = settings->begin(); i != settings->end(); i++)
{
type = i->first;
arch = i->second;
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
// OS X does not set the working directory relative to the app,
// In order to make things portable on OS X we need to provide
// the loading with it's own bundle path location
if (!Ogre::StringUtil::startsWith(arch, "/", false)) // only adjust relative dirs
arch = Ogre::String(Ogre::macBundlePath() + "/" + arch);
#endif
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch, type, sec);
}
}
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Essential");
//Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Popular");
//Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
void setupRenderSystem()
{
Ogre::RenderSystemList rsList = mRoot->getAvailableRenderers();
if(rsList.size()>0)
{
// mRoot->setRenderSystem(mRoot->getRenderSystemByName(rsList[0]->getName()));
std::cout << "Found Renderer: " << rsList[0]->getName()<< std::endl;
//mRoot->setRenderSystem(mRoot->getRenderSystemByName("OpenGL ES 1.x Rendering Subsystem"));
}
else {
std::cout << "Error no Available Renderer found" << std::endl;
}
}
void createRenderWindow()
{
mWindow = mRoot->initialise(true);
//[[UIApplication sharedApplication] keyWindow];
}
void initializeResourceGroups()
{
Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
}
void createFrameListener()
{
mListener = new AnimationListener();
mRoot->addFrameListener(mListener);
}
void setupScene()
{
mWindow->removeAllViewports();
Ogre::SceneManager *mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, "Default SceneManager");
Ogre::Camera *mCamera = mSceneMgr->createCamera("Camera");
Ogre::Viewport *mViewport = mWindow->addViewport(mCamera);
mViewport->setBackgroundColour(Ogre::ColourValue(0.5,0.50,0.50));
mCamera->setPosition(Ogre::Vector3(100,100,100));
mCamera->lookAt(Ogre::Vector3(0,0,0));
mCamera->setNearClipDistance(1);
mCamera->setFarClipDistance(1000);
mCamera->setAspectRatio((Ogre::Real)mViewport->getActualWidth() / (Ogre::Real)mViewport->getActualHeight());
// setup some basic lighting for our scene
mSceneMgr->setAmbientLight(Ogre::ColourValue(1, 1, 1));
mSceneMgr->createLight()->setPosition(20, 80, 50);
// create a floor mesh resource
//Ogre::MeshManager::getSingleton().createPlane("floor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
// Ogre::Plane(Ogre::Vector3::UNIT_Y, -30), 1000, 1000, 10, 10, true, 1, 8, 8, Ogre::Vector3::UNIT_Z);
// create a floor entity, give it a material, and place it at the origin
/*Ogre::Entity* floor = mSceneMgr->createEntity("Floor", "floor");
floor->setMaterialName("Examples/BumpyMetal");
mSceneMgr->getRootSceneNode()->attachObject(floor);*/
Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("penguin2",Ogre::Vector3(-50.0f, 0.0f, 30.0f));
Ogre::SceneNode* node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode("penguin",Ogre::Vector3(0.0f, 0.0f, 0.0f));
Ogre::Entity* penguin2 = mSceneMgr->createEntity("Penguin1", "penguin.mesh");
node->attachObject(penguin2);
node->setScale(0.5f, 0.5f, 0.5f);
Ogre::Entity* head = mSceneMgr->createEntity("Penguin2", "penguin.mesh");
node2->attachObject(head);
// Set idle animation
mAnimationState = head->getAnimationState("amuse");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
mAnimationState->setTimePosition(123);
mListener->addAnimationState(mAnimationState);
// Set idle animation
mAnimationState2 = penguin2->getAnimationState("amuse");
mAnimationState2->setLoop(true);
mAnimationState2->setEnabled(true);
mListener->addAnimationState(mAnimationState2);
}
Ogre::Root* getRoot(){
return mRoot;
}
};
SampleBrowser.cpp
#include "OgrePlatform.h"
#include "game_main.h"
#import
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
[pool release];
return retVal;
}
@interface AppDelegate : NSObject
{
//UIWindow *window;
NSTimer *mTimer;
//OgreBites::SampleBrowser sb;
SampleBrowser sb;
}
- (void)go;
- (void)renderOneFrame:(id)sender;
@property (retain) NSTimer *mTimer;
@end
@implementation AppDelegate
@synthesize mTimer;
- (void)go {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
try {
sb.go();
Ogre::Root::getSingleton().getRenderSystem()->_initRenderTargets();
// Clear event times
Ogre::Root::getSingleton().clearEventTimes();
} catch( Ogre::Exception& e ) {
std::cerr << "An exception has occurred: " <<
e.getFullDescription().c_str() << std::endl;
}
mTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0f / 60.0f)
target:self
selector:@selector(renderOneFrame:)
userInfo:nil
repeats:NO];
[pool release];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES];
[self go];
}
- (void)renderOneFrame:(id)sender
{
//[sb.mGestureView becomeFirstResponder];
// Start Rendering
sb.getRoot()->startRendering();
//Ogre::Root::getSingleton().renderOneFrame((Ogre::Real)[mTimer timeInterval]);
}
- (void)applicationWillTerminate:(UIApplication *)application {
Ogre::Root::getSingleton().queueEndRendering();
}
//- (void)applicationWillResignActive:(UIApplication *)application
//{
// // Pause FrameListeners and rendering
//}
//
//- (void)applicationDidBecomeActive:(UIApplication *)application
//{
// // Resume FrameListeners and rendering
//}
- (void)dealloc {
[mTimer release];
[super dealloc];
}
@end
plugins.cfg
# Defines plugins to load
# Define plugin folder
PluginFolder=
# Define plugins
# Plugin=RenderSystem_GL
Plugin=RenderSystem_GLES
Plugin=Plugin_ParticleFX
Plugin=Plugin_BSPSceneManager
Plugin=Plugin_PCZSceneManager
Plugin=Plugin_OctreeZone
Plugin=Plugin_OctreeSceneManager
Da ich ein neuling unter XCode und Mac bin: hier noch ein paar Dinge zu XCode die mir aufgefallen sind:
XCode Section
Eine sehr hilfreiche Sache: Mehrere Zeilen einrücken in XCode macht man mit alt+cmd + 6 zurück dann mit alt+cmd+5
Eine Sache mit der ich als VS Nutzer lange gekämpft habe: Die Settings für den Linker macht man unter:
(Nicht die Project Settings)
$SRCROOT ist beim Einstellen von Pfaden die Varible zu dem Folder in dem sich das Projekt befindet.
FAQ:
iPhone (device) bleibt schwarz – ohne das Fehler angezeigt werden:
1. OpenGL muss immer im haupt thread rendern
2. Haupthread darf nicht blockiert werden. (Zum bsp. mit startRenderloop())
Tags: Tutorials // Add Comment »