initial commit
This commit is contained in:
		
						commit
						e7e0b39e82
					
				
							
								
								
									
										20
									
								
								.hgignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.hgignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| syntax:glob | ||||
| CMakeCache.txt | ||||
| CMakeFiles | ||||
| cmake_install.cmake | ||||
| install_manifest.txt | ||||
| debug | ||||
| tags | ||||
| Makefile | ||||
| 
 | ||||
| start | ||||
| runtests | ||||
| hasteroids | ||||
| 
 | ||||
| ./doc/html/* | ||||
| 
 | ||||
| *.log | ||||
| *.a | ||||
| *.o | ||||
| *.so | ||||
| *.swp | ||||
							
								
								
									
										45
									
								
								CMake/FindCEGUI.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								CMake/FindCEGUI.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| # Tries to find CEGUI (http://CEGUI.bespin.org) a simple and fast  | ||||
| # network library by Lee Salzman | ||||
| # | ||||
| 
 | ||||
| SET (CEGUI_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (CEGUI_INCLUDE_DIR CEGUI.h /usr/include/CEGUI | ||||
| 	/usr/local/include/CEGUI $ENV{CEGUI_PATH}/include/CEGUI | ||||
| 	$ENV{CEGUI_INCLUDE_PATH}/CEGUI) | ||||
| 
 | ||||
| FIND_LIBRARY (CEGUI_BASE_LIBRARIES NAMES CEGUIBase PATHS /usr/lib /usr/local/lib $ENV{CEGUI_PATH} $ENV{CEGUI_PATH}/lib ENV{CEGUI_LIBRARY_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (CEGUI_RENDERER_LIBRARIES NAMES CEGUIOpenGLRenderer PATHS /usr/lib /usr/local/lib $ENV{CEGUI_PATH} $ENV{CEGUI_PATH}/lib ENV{CEGUI_LIBRARY_PATH}) | ||||
| 
 | ||||
| SET ( CEGUI_LIBRARIES FALSE ) | ||||
| 
 | ||||
| IF ( CEGUI_BASE_LIBRARIES AND CEGUI_RENDERER_LIBRARIES ) | ||||
| 	SET ( CEGUI_LIBRARIES  | ||||
| 		${CEGUI_BASE_LIBRARIES}  | ||||
| 		${CEGUI_RENDERER_LIBRARIES} | ||||
| 		) | ||||
| ENDIF ( CEGUI_BASE_LIBRARIES AND CEGUI_RENDERER_LIBRARIES ) | ||||
| 
 | ||||
| MESSAGE (STATUS "CEGUI Libraries: ${CEGUI_LIBRARIES}") | ||||
| 
 | ||||
| IF (CEGUI_INCLUDE_DIR AND CEGUI_LIBRARIES) | ||||
| 	SET (CEGUI_FOUND TRUE) | ||||
| ENDIF (CEGUI_INCLUDE_DIR AND CEGUI_LIBRARIES) | ||||
| 
 | ||||
| IF (CEGUI_FOUND) | ||||
|    IF (NOT CEGUI_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found CEGUI: ${CEGUI_LIBRARIES}") | ||||
|    ENDIF (NOT CEGUI_FIND_QUIETLY) | ||||
| ELSE (CEGUI_FOUND) | ||||
|    IF (CEGUI_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find CEGUI") | ||||
|    ENDIF (CEGUI_FIND_REQUIRED) | ||||
| ENDIF (CEGUI_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	CEGUI_INCLUDE_DIR | ||||
| 	CEGUI_BASE_LIBRARIES | ||||
| 	CEGUI_RENDERER_LIBRARIES | ||||
| 	CEGUI_LIBRARIES | ||||
| 	) | ||||
							
								
								
									
										28
									
								
								CMake/FindENET.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								CMake/FindENET.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # Tries to find ENET (http://enet.bespin.org) a simple and fast  | ||||
| # network library by Lee Salzman | ||||
| # | ||||
| 
 | ||||
| SET (ENET_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (ENET_INCLUDE_DIR enet/enet.h /usr/include/ /usr/local/include/ $ENV{ENET_PATH}/include $ENV{ENET_INCLUDE_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (ENET_LIBRARIES NAMES enet PATHS /usr/lib /usr/local/lib $ENV{ENET_PATH} $ENV{ENET_PATH}/lib ENV{ENET_LIBRARY_PATH}) | ||||
| 
 | ||||
| IF (ENET_INCLUDE_DIR AND ENET_LIBRARIES) | ||||
| 	SET (ENET_FOUND TRUE) | ||||
| ENDIF (ENET_INCLUDE_DIR AND ENET_LIBRARIES) | ||||
| 
 | ||||
| IF (ENET_FOUND) | ||||
|    IF (NOT ENET_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found ENET: ${ENET_LIBRARIES}") | ||||
|    ENDIF (NOT ENET_FIND_QUIETLY) | ||||
| ELSE (ENET_FOUND) | ||||
|    IF (ENET_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find ENET") | ||||
|    ENDIF (ENET_FIND_REQUIRED) | ||||
| ENDIF (ENET_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	ENET_INCLUDE_DIR | ||||
| 	ENET_LIBRARIES | ||||
| 	) | ||||
							
								
								
									
										28
									
								
								CMake/FindFreeType2.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								CMake/FindFreeType2.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # Tries to find FREETYPE2 (http://freetype2.bespin.org) a simple and fast  | ||||
| # network library by Lee Salzman | ||||
| # | ||||
| 
 | ||||
| SET (FREETYPE2_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (FREETYPE2_INCLUDE_DIR freetype/freetype.h /usr/include/ /usr/local/include/ /usr/include/freetype2 /usr/local/include/freetype2 $ENV{FREETYPE2_PATH}/include $ENV{FREETYPE2_INCLUDE_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (FREETYPE2_LIBRARIES NAMES freetype PATHS /usr/lib /usr/local/lib $ENV{FREETYPE2_PATH} $ENV{FREETYPE2_PATH}/lib ENV{FREETYPE2_LIBRARY_PATH}) | ||||
| 
 | ||||
| IF (FREETYPE2_INCLUDE_DIR AND FREETYPE2_LIBRARIES) | ||||
| 	SET (FREETYPE2_FOUND TRUE) | ||||
| ENDIF (FREETYPE2_INCLUDE_DIR AND FREETYPE2_LIBRARIES) | ||||
| 
 | ||||
| IF (FREETYPE2_FOUND) | ||||
|    IF (NOT FREETYPE2_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found FREETYPE2: ${FREETYPE2_LIBRARIES}") | ||||
|    ENDIF (NOT FREETYPE2_FIND_QUIETLY) | ||||
| ELSE (FREETYPE2_FOUND) | ||||
|    IF (FREETYPE2_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find FREETYPE2") | ||||
|    ENDIF (FREETYPE2_FIND_REQUIRED) | ||||
| ENDIF (FREETYPE2_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	FREETYPE2_INCLUDE_DIR | ||||
| 	FREETYPE2_LIBRARIES | ||||
| 	) | ||||
							
								
								
									
										28
									
								
								CMake/FindUnitTest++.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								CMake/FindUnitTest++.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # - Try to find UnitTest++ | ||||
| # | ||||
| # | ||||
| 
 | ||||
| SET (UNITTEST++_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (UNITTEST++_INCLUDE_DIR UnitTest++.h /usr/include/unittest++ /usr/local/include/unittest++ $ENV{UNITTESTXX_PATH}/src $ENV{UNITTESTXX_INCLUDE_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (UNITTEST++_LIBRARY NAMES UnitTest++ PATHS /usr/lib /usr/local/lib $ENV{UNITTESTXX_PATH} ENV{UNITTESTXX_LIBRARY_PATH}) | ||||
| 
 | ||||
| IF (UNITTEST++_INCLUDE_DIR AND UNITTEST++_LIBRARY) | ||||
| 	SET (UNITTEST++_FOUND TRUE) | ||||
| ENDIF (UNITTEST++_INCLUDE_DIR AND UNITTEST++_LIBRARY) | ||||
| 
 | ||||
| IF (UNITTEST++_FOUND) | ||||
|    IF (NOT UnitTest++_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found UnitTest++: ${UNITTEST++_LIBRARY}") | ||||
|    ENDIF (NOT UnitTest++_FIND_QUIETLY) | ||||
| ELSE (UNITTEST++_FOUND) | ||||
|    IF (UnitTest++_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find UnitTest++") | ||||
|    ENDIF (UnitTest++_FIND_REQUIRED) | ||||
| ENDIF (UNITTEST++_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	UNITTEST++_INCLUDE_DIR | ||||
| 	UNITTEST++_LIBRARY | ||||
| 	) | ||||
							
								
								
									
										28
									
								
								CMake/Findfysx.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								CMake/Findfysx.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # - Try to find FYSX | ||||
| # | ||||
| # | ||||
| 
 | ||||
| SET (FYSX_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (FYSX_INCLUDE_DIR fysx.h /usr/include/ /usr/local/include/ $ENV{FYSX_PATH}/include $ENV{FYSX_INCLUDE_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (FYSX_LIBRARIES NAMES fysx PATHS /usr/lib /usr/local/lib $ENV{FYSX_PATH} $ENV{FYSX_PATH}/lib ENV{FYSX_LIBRARY_PATH}) | ||||
| 
 | ||||
| IF (FYSX_INCLUDE_DIR AND FYSX_LIBRARIES) | ||||
| 	SET (FYSX_FOUND TRUE) | ||||
| ENDIF (FYSX_INCLUDE_DIR AND FYSX_LIBRARIES) | ||||
| 
 | ||||
| IF (FYSX_FOUND) | ||||
|    IF (NOT FYSX_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found FYSX: ${FYSX_LIBRARIES}") | ||||
|    ENDIF (NOT FYSX_FIND_QUIETLY) | ||||
| ELSE (FYSX_FOUND) | ||||
|    IF (FYSX_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find FYSX") | ||||
|    ENDIF (FYSX_FIND_REQUIRED) | ||||
| ENDIF (FYSX_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	FYSX_INCLUDE_DIR | ||||
| 	FYSX_LIBRARIES | ||||
| 	) | ||||
							
								
								
									
										43
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| CMAKE_MINIMUM_REQUIRED(VERSION 2.6) | ||||
| 
 | ||||
| LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ) | ||||
| 
 | ||||
| # FIND_PACKAGE (Cal3D REQUIRED) | ||||
| 
 | ||||
| INCLUDE_DIRECTORIES (  | ||||
| 	src/ | ||||
| 	engine/ | ||||
| 	include/ | ||||
| 	engine/libraries/mathlib/ | ||||
| 	engine/libraries/coll2d/include | ||||
| 	engine/libraries/oglft/ | ||||
| 	${FREETYPE2_INCLUDE_DIR} | ||||
| 	) | ||||
| 
 | ||||
| SET_TARGET_PROPERTIES ( ${PROJECT_EXECUTABLES} PROPERTIES | ||||
| 		LINKER_LANGUAGE CXX | ||||
| 	) | ||||
| 
 | ||||
| ADD_SUBDIRECTORY ( engine ) | ||||
| 
 | ||||
| SET ( ASTEROIDS_SOURCES  | ||||
| 	asteroids/AsteroidEntity.cc | ||||
| 	asteroids/Controller.cc | ||||
| 	asteroids/ControllerCommands.cc | ||||
| 	asteroids/EntityFactory.cc | ||||
| 	asteroids/EnumToString.cc | ||||
| 	asteroids/main.cc | ||||
| 	asteroids/Model.cc | ||||
| 	asteroids/ModelCommands.cc | ||||
| 	asteroids/Physics.cc | ||||
| 	asteroids/RocketEntity.cc | ||||
| 	asteroids/ShipEntity.cc | ||||
| 	asteroids/View.cc | ||||
| 	asteroids/MenuOverlay.cc | ||||
| 	) | ||||
| 
 | ||||
| ADD_EXECUTABLE ( hasteroids ${ASTEROIDS_SOURCES} )  | ||||
| 
 | ||||
| TARGET_LINK_LIBRARIES ( hasteroids | ||||
| 	Engine | ||||
| 	) | ||||
							
								
								
									
										47
									
								
								asteroids/AsteroidEntity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								asteroids/AsteroidEntity.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| #include "ModelBase.h" | ||||
| 
 | ||||
| #include "AsteroidEntity.h" | ||||
| #include "Controller.h" | ||||
| #include "Model.h" | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| bool AsteroidEntity::CollisionEvent (Engine::EntityBase* entity_state) { | ||||
| 	GameEntityType other_type = (GameEntityType) entity_state->mType; | ||||
| 
 | ||||
| 	Engine::LogMessage ("CONTACT OF AN ASTEROID"); | ||||
| 
 | ||||
| 	if (other_type == GameEntityTypeRocket) { | ||||
| 		// First remove the rocket
 | ||||
| 		Engine::KillEntity (entity_state->mId); | ||||
| 
 | ||||
| 		Engine::LogMessage ("You killed an ASTEROID!"); | ||||
| 
 | ||||
| 		int i; | ||||
| 		for (i = 0; i < mSubAsteroidsCount; i++) { | ||||
| 			AsteroidEntity *asteroid = (AsteroidEntity*) Engine::CreateEntity (GameEntityTypeAsteroid); | ||||
| 			vector3d position (rand()/float(RAND_MAX) * 1. - 0.5, 0., rand()/float(RAND_MAX) * 1. - 0.5); | ||||
| 			asteroid->mSubAsteroidsCount = 0; | ||||
| 			asteroid->mPhysicState->mRadius = 2. * mPhysicState->mRadius / mSubAsteroidsCount; | ||||
| 			static_cast<coll2d::Sphere*>(asteroid->mPhysicState->mShape)->setRadius (asteroid->mPhysicState->mRadius); | ||||
| 			asteroid->mPhysicState->mPosition = mPhysicState->mPosition + position; | ||||
| 			asteroid->mPhysicState->mVelocity = position; | ||||
| 			asteroid->mPhysicState->mAngleVelocity = mPhysicState->mAngleVelocity + (rand()/float(RAND_MAX) * 2. - 1) * mPhysicState->mAngleVelocity; | ||||
| 		} | ||||
| 		 | ||||
| 		Engine::KillEntity (mId); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} else if (other_type == GameEntityTypeRocket) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										33
									
								
								asteroids/AsteroidEntity.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								asteroids/AsteroidEntity.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| #ifndef _ASTEROIDENTITY_H | ||||
| #define _ASTEROIDENTITY_H | ||||
| 
 | ||||
| #include "EntityBase.h" | ||||
| #include "AsteroidsEnums.h" | ||||
| #include "Sprite.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| struct AsteroidEntityPhysicState : public Engine::EntityPhysicState { | ||||
| 	AsteroidEntityPhysicState () { | ||||
| 		mBaseType = Engine::EntityBaseTypeBlock; | ||||
| 		mType = GameEntityTypeAsteroid; | ||||
| 	} | ||||
| 	virtual ~AsteroidEntityPhysicState() {}; | ||||
| }; | ||||
| 
 | ||||
| struct AsteroidEntity: public Engine::EntityBase { | ||||
| 	AsteroidEntity () { | ||||
| 		mBaseType = Engine::EntityBaseTypeBlock; | ||||
| 		mType = GameEntityTypeAsteroid; | ||||
| 
 | ||||
| 		mSubAsteroidsCount = 4; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual bool CollisionEvent (Engine::EntityBase *entity); | ||||
| 
 | ||||
| 	int mSubAsteroidsCount; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _ASTEROIDENTITY_H
 | ||||
							
								
								
									
										37
									
								
								asteroids/AsteroidsEnums.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								asteroids/AsteroidsEnums.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #if ( !defined(_ASTEROIDSENUMS_H) || defined(GENERATE_ENUM_STRINGS) ) | ||||
| 
 | ||||
| #if ( !defined(GENERATE_ENUM_STRINGS)) | ||||
| 	#define _ASTEROIDSENUMS_H | ||||
| #endif | ||||
| 
 | ||||
| #include "EnumToString.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| BEGIN_ENUM(GameEntityType) | ||||
| { | ||||
| 	DECL_ENUM_ELEMENT(GameEntityTypeUnknown), | ||||
| 	DECL_ENUM_ELEMENT(GameEntityTypeShip), | ||||
| 	DECL_ENUM_ELEMENT(GameEntityTypeRocket), | ||||
| 	DECL_ENUM_ELEMENT(GameEntityTypeAsteroid), | ||||
| 	DECL_ENUM_ELEMENT(GameEntityTypeShipPart), | ||||
| 	DECL_ENUM_ELEMENT(GameEntityTypeLast) | ||||
| } | ||||
| END_ENUM(GameEntityType) | ||||
| 
 | ||||
| BEGIN_ENUM(GameState) | ||||
| { | ||||
| 	DECL_ENUM_ELEMENT(GameStateMainMenu), | ||||
| 	DECL_ENUM_ELEMENT(GameStateRunning), | ||||
| 	DECL_ENUM_ELEMENT(GameStatePaused), | ||||
| 	DECL_ENUM_ELEMENT(GameStatePlayerDied), | ||||
| 	DECL_ENUM_ELEMENT(GameStateLevelComplete), | ||||
| 	DECL_ENUM_ELEMENT(GameStateGameOver) | ||||
| } | ||||
| END_ENUM(GameState) | ||||
| 
 | ||||
| #include "AsteroidsEvents.h" | ||||
| 
 | ||||
| } | ||||
| #endif /* _ASTEROIDSENUMS_H */ | ||||
| 
 | ||||
							
								
								
									
										14
									
								
								asteroids/AsteroidsEvents.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								asteroids/AsteroidsEvents.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #include "EnumToString.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| BEGIN_ENUM(Event) | ||||
| { | ||||
| 	DECL_ENUM_ELEMENT(EventAccelerateStart), | ||||
| 	DECL_ENUM_ELEMENT(EventAccelerateStop), | ||||
| 	DECL_ENUM_ELEMENT(EventShipExplode) | ||||
| } | ||||
| END_ENUM(Event) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										26
									
								
								asteroids/Controller.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								asteroids/Controller.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| #include "Controller.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| int Controller::OnInit (int argc, char *argv[]) { | ||||
| 	Engine::ControllerBase::OnInit (argc, argv); | ||||
| 
 | ||||
| 	mBindings[SDLK_q] = "quit"; | ||||
| 	 | ||||
| 	mBindings[SDLK_v] = "+forward"; | ||||
| 	mBindings[SDLK_h] = "+turnleft"; | ||||
| 	mBindings[SDLK_g] = "+turnright"; | ||||
| 
 | ||||
| 	mBindings[SDLK_UP] = "+forward"; | ||||
| 	mBindings[SDLK_LEFT] = "+turnleft"; | ||||
| 	mBindings[SDLK_RIGHT] = "+turnright"; | ||||
| 
 | ||||
| 	mBindings[SDLK_SPACE] = "attack"; | ||||
| 
 | ||||
| 	mBindings[SDLK_F8] = "toggleconsole"; | ||||
| 	mBindings[SDLK_F9] = "set playerspeed 5.0"; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										35
									
								
								asteroids/Controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								asteroids/Controller.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| #ifndef _CONTROLLER_H | ||||
| #define _CONTROLLER_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| #include "ControllerBase.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| /** \brief All possible controller states for an Entity
 | ||||
|  * | ||||
|  * These are used by the controller to update the current state of an Entity | ||||
|  * (e.g. EntityPhysicState). | ||||
|  */ | ||||
| enum EntityControllerKeyState { | ||||
| 	EntityKeyStateForward = 0, | ||||
| 	EntityKeyStateBack, | ||||
| 	EntityKeyStateLeft, | ||||
| 	EntityKeyStateRight, | ||||
| 	EntityKeyStateTurnLeft, | ||||
| 	EntityKeyStateTurnRight, | ||||
| 	EntityKeyStateLast | ||||
| }; | ||||
| 
 | ||||
| class Controller : public Engine::ControllerBase { | ||||
| 	public: | ||||
| 		Controller () {}; | ||||
| 	protected: | ||||
| 		/** \brief Set up basic keybindings */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Registers the commands of the cnotroller */ | ||||
| 		virtual void OnRegisterCommands (); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| #endif // _CONTROLLER_H
 | ||||
							
								
								
									
										217
									
								
								asteroids/ControllerCommands.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								asteroids/ControllerCommands.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,217 @@ | ||||
| // #include "Engine.h"
 | ||||
| 
 | ||||
| #include "Controller.h" | ||||
| #include "Model.h" | ||||
| #include "EntityBase.h" | ||||
| #include "EventsBase.h" | ||||
| 
 | ||||
| #include "Controller.h" | ||||
| #include "ShipEntity.h" | ||||
| 
 | ||||
| #include "AsteroidsEvents.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| static Controller *ControllerInstance = NULL; | ||||
| 
 | ||||
| /* +forward */ | ||||
| bool Cmd_ControllerForwardDown (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->SetControllerKeyState (EntityKeyStateForward); | ||||
| 
 | ||||
| 		Engine::EventBasePtr forward_event (new Engine::EventBase()); | ||||
| 		forward_event->mEventType = EventAccelerateStart; | ||||
| 		QueueEvent (forward_event); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* -forward */ | ||||
| bool Cmd_ControllerForwardUp (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->UnsetControllerKeyState (EntityKeyStateForward); | ||||
| 
 | ||||
| 		Engine::EventBasePtr forward_event (new Engine::EventBase()); | ||||
| 		forward_event->mEventType = EventAccelerateStop; | ||||
| 		QueueEvent (forward_event); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* +back */ | ||||
| bool Cmd_ControllerBackDown (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->SetControllerKeyState (EntityKeyStateBack); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* -back */ | ||||
| bool Cmd_ControllerBackUp (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->UnsetControllerKeyState (EntityKeyStateBack); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* +left */ | ||||
| bool Cmd_ControllerLeftDown (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->SetControllerKeyState (EntityKeyStateLeft); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* -left */ | ||||
| bool Cmd_ControllerLeftUp (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->UnsetControllerKeyState (EntityKeyStateLeft); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* +right */ | ||||
| bool Cmd_ControllerRightDown (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->SetControllerKeyState (EntityKeyStateRight); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* -right */ | ||||
| bool Cmd_ControllerRightUp (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->UnsetControllerKeyState (EntityKeyStateRight); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* +turnleft */ | ||||
| bool Cmd_ControllerTurnLeftDown (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->SetControllerKeyState (EntityKeyStateTurnLeft); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* -turnleft */ | ||||
| bool Cmd_ControllerTurnLeftUp (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->UnsetControllerKeyState (EntityKeyStateTurnLeft); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* +turnright */ | ||||
| bool Cmd_ControllerTurnRightDown (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->SetControllerKeyState (EntityKeyStateTurnRight); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* -turnright */ | ||||
| bool Cmd_ControllerTurnRightUp (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	Engine::EntityBase* player_entity = Engine::GetEntity (Engine::GetPlayerEntityId()); | ||||
| 	if (player_entity) { | ||||
| 		player_entity->UnsetControllerKeyState (EntityKeyStateTurnRight); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* attack */ | ||||
| bool Cmd_ControllerAttack (std::vector<std::string> args) { | ||||
| 	assert (ControllerInstance); | ||||
| 
 | ||||
| 	ShipEntity* player_entity = (ShipEntity*) Engine::GetEntity (Engine::GetPlayerEntityId ()); | ||||
| 	assert (player_entity); | ||||
| 	player_entity->Attack (); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void Controller::OnRegisterCommands () { | ||||
| 	ControllerBase::OnRegisterCommands (); | ||||
| 
 | ||||
| 	ControllerInstance = this; | ||||
| 
 | ||||
| 	Engine::AddCommand ("+forward", Cmd_ControllerForwardDown); | ||||
| 	Engine::AddCommand ("-forward", Cmd_ControllerForwardUp); | ||||
| 	Engine::AddCommand ("+back", Cmd_ControllerBackDown); | ||||
| 	Engine::AddCommand ("-back", Cmd_ControllerBackUp); | ||||
| 
 | ||||
| 	Engine::AddCommand ("+left", Cmd_ControllerLeftDown); | ||||
| 	Engine::AddCommand ("-left", Cmd_ControllerLeftUp); | ||||
| 	Engine::AddCommand ("+right", Cmd_ControllerRightDown); | ||||
| 	Engine::AddCommand ("-right", Cmd_ControllerRightUp); | ||||
| 
 | ||||
| 	Engine::AddCommand ("+turnleft", Cmd_ControllerTurnLeftDown); | ||||
| 	Engine::AddCommand ("-turnleft", Cmd_ControllerTurnLeftUp); | ||||
| 	Engine::AddCommand ("+turnright", Cmd_ControllerTurnRightDown); | ||||
| 	Engine::AddCommand ("-turnright", Cmd_ControllerTurnRightUp); | ||||
| 
 | ||||
| 	Engine::AddCommand ("attack", Cmd_ControllerAttack); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										139
									
								
								asteroids/EntityFactory.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								asteroids/EntityFactory.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "EntityBase.h" | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| #include "EntityFactory.h" | ||||
| #include "ShipEntity.h" | ||||
| #include "RocketEntity.h" | ||||
| #include "AsteroidEntity.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| int EntityFactory::OnInit (int argc, char* argv[]) { | ||||
| 	Engine::LogMessage ("Initializing EntityFactory"); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| Engine::EntityPhysicState* EntityFactory::CreateEntityPhysicState (int type) { | ||||
| 	// In this simple factory the type is simply seen as the EntityBaseType.
 | ||||
| 	// However to prevent errors we do a simple check vor validity.
 | ||||
| 	if (type < 0 || type > GameEntityTypeLast ) { | ||||
| 		Engine::LogError ("Cannot create Entity with type %d: invalid type!", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	// Create the Entity
 | ||||
| 	Engine::EntityPhysicState* entity_physics = NULL; | ||||
| 
 | ||||
| 	// type specific initialization
 | ||||
| 	if (type == GameEntityTypeShip) { | ||||
| 		entity_physics = new ShipEntityPhysicState (); | ||||
| 		if (!entity_physics) { | ||||
| 			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 		entity_physics->mRadius = 0.5; | ||||
| 		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius); | ||||
| 
 | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else if (type == GameEntityTypeAsteroid) { | ||||
| 		entity_physics = new AsteroidEntityPhysicState (); | ||||
| 		if (!entity_physics) { | ||||
| 			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 		 | ||||
| 		entity_physics->mRadius = 1.; | ||||
| 		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius); | ||||
| 
 | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else if (type == GameEntityTypeRocket) { | ||||
| 		entity_physics = new RocketEntityPhysicState(); | ||||
| 		if (!entity_physics) { | ||||
| 			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 		entity_physics->mRadius = 0.1; | ||||
| 		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius); | ||||
| 	} else if (type == GameEntityTypeShipPart) { | ||||
| 		entity_physics = new RocketEntityPhysicState(); | ||||
| 		entity_physics->mBaseType = Engine::EntityBaseTypeBlock; | ||||
| 		if (!entity_physics) { | ||||
| 			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 		entity_physics->mRadius = 0.1; | ||||
| 		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius); | ||||
| 	} else { | ||||
| 		Engine::LogError ("No EntityPhysicState defined for GameEntity type '%d'", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	entity_physics->mType = type; | ||||
| 
 | ||||
| 	return entity_physics; | ||||
| } | ||||
| 
 | ||||
| Engine::EntityControllerState* EntityFactory::CreateEntityControllerState (int type) { | ||||
| 	// In this simple factory the type is simply seen as the EntityBaseType.
 | ||||
| 	// However to prevent errors we do a simple check vor validity.
 | ||||
| 	if (type < 0 || type >> Engine::EntityBaseTypeLast ) { | ||||
| 		Engine::LogError ("Cannot create Entity with type %d: invalid type!", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	 | ||||
| 	// Create the Entity
 | ||||
| 	Engine::EntityControllerState* entity_controller = NULL; | ||||
| 
 | ||||
| 	// specific values for each type
 | ||||
| 	if (type == GameEntityTypeShip) { | ||||
| 		entity_controller = new Engine::EntityControllerState (); | ||||
| 		if (!entity_controller) { | ||||
| 			Engine::LogError ("Could not allocate enough memory for EntityControllerState of type '%d'", type); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return entity_controller; | ||||
| } | ||||
| 
 | ||||
| Engine::EntityBase* EntityFactory::CreateEntity (int type) { | ||||
| 	// In this simple factory the type is simply seen as the EntityBaseType.
 | ||||
| 	// However to prevent errors we do a simple check vor validity.
 | ||||
| 	if (type < 0 || type > GameEntityTypeLast ) { | ||||
| 		Engine::LogError ("Cannot create Entity with type %d: invalid type!", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	// Create the Entity
 | ||||
| 	Engine::EntityBase *entity; | ||||
| 
 | ||||
| 	if (type == GameEntityTypeShip) { | ||||
| 		entity = new ShipEntity; | ||||
| 	} else if (type == GameEntityTypeAsteroid) { | ||||
| 		entity = new AsteroidEntity; | ||||
| 	} else if (type == GameEntityTypeRocket) { | ||||
| 		entity = new RocketEntity; | ||||
| 	} else if (type == GameEntityTypeShipPart) { | ||||
| 		entity = new Engine::EntityBase; | ||||
| 		entity->mBaseType = Engine::EntityBaseTypeBlock; | ||||
| 	} | ||||
| 
 | ||||
| 	entity->mType = type; | ||||
| 
 | ||||
| 	if (!entity) { | ||||
| 		Engine::LogError ("Could not allocate enough memory for EntityVisualState of type '%d'", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	entity->mPhysicState = CreateEntityPhysicState (type); | ||||
| 	entity->mControllerState = CreateEntityControllerState (type); | ||||
| 
 | ||||
| 	return entity; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										29
									
								
								asteroids/EntityFactory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								asteroids/EntityFactory.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| #ifndef _ENTITYFACTORY_H | ||||
| #define _ENTITYFACTORY_H | ||||
| 
 | ||||
| #include "EntityFactoryBase.h" | ||||
| #include "AsteroidsEnums.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 	struct EntityBase; | ||||
| 	struct EntityPhysicState; | ||||
| 	struct EntityControllerState; | ||||
| } | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| 	class EntityFactory: public Engine::EntityFactoryBase { | ||||
| 		public: | ||||
| 			EntityFactory () {}; | ||||
| 
 | ||||
| 			virtual Engine::EntityPhysicState* CreateEntityPhysicState (int type); | ||||
| 			virtual Engine::EntityControllerState* CreateEntityControllerState (int type); | ||||
| 
 | ||||
| 			virtual Engine::EntityBase* CreateEntity (int type); | ||||
| 
 | ||||
| 		protected: | ||||
| 			virtual int OnInit (int argc, char *argv[]); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| #endif // _ENTITYFACTORY_H
 | ||||
							
								
								
									
										7
									
								
								asteroids/EnumToString.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								asteroids/EnumToString.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "AsteroidsEnums.h" | ||||
| 
 | ||||
| #define GENERATE_ENUM_STRINGS | ||||
| 
 | ||||
| #include "AsteroidsEnums.h" | ||||
| 
 | ||||
| #undef GENERATE_ENUM_STRINGS | ||||
							
								
								
									
										176
									
								
								asteroids/MenuOverlay.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								asteroids/MenuOverlay.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | ||||
| #include "OGLFT.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| #include <GL/glu.h> | ||||
| 
 | ||||
| #include "DrawingsGL.h" | ||||
| 
 | ||||
| #include "OverlayBase.h" | ||||
| #include "MenuOverlay.h" | ||||
| #include "Model.h" | ||||
| #include "Sprite.h" | ||||
| #include "ShipEntity.h" | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| // static float left = 0;
 | ||||
| static float right = 0; | ||||
| // static float top = 0;
 | ||||
| static float bottom = 0; | ||||
| 
 | ||||
| void MenuOverlay::Init () { | ||||
| 	if (!mShipSprite.LoadFromPNG("./data/textures/ship.png")) | ||||
| 		Engine::LogError ("Could not load ship sprite!"); | ||||
| 
 | ||||
| 	assert (mShipSprite.GetWidth() > 1); | ||||
| 	mShipSprite.SetScale (0.1); | ||||
| } | ||||
| 
 | ||||
| bool MenuOverlay::OnKeyDown (const SDL_keysym &keysym) { | ||||
| 	if (mModel->GetGameState() == GameStateLevelComplete) { | ||||
| 		switch (keysym.sym) { | ||||
| 			case SDLK_RETURN: | ||||
| 				mModel->SetGameState(GameStateRunning); | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} else if (mModel->GetGameState() == GameStateRunning) { | ||||
| 		switch (keysym.sym) { | ||||
| 			case SDLK_ESCAPE: | ||||
| 				mModel->SetGameState(GameStatePaused); | ||||
| 				return true; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		return false; | ||||
| 	} else if (mModel->GetGameState() == GameStateGameOver) { | ||||
| 		switch (keysym.sym) { | ||||
| 			case SDLK_ESCAPE: | ||||
| 				mModel->SetGameState(GameStateMainMenu); | ||||
| 				break; | ||||
| 			case SDLK_RETURN: | ||||
| 				mModel->SetGameState(GameStateMainMenu); | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 	else if (mModel->GetGameState() == GameStateMainMenu | ||||
| 			|| mModel->GetGameState() == GameStatePaused) { | ||||
| 		switch (keysym.sym) { | ||||
| 			case SDLK_ESCAPE: | ||||
| 				Engine::RunCommand ("quit"); | ||||
| 				return true; | ||||
| 			case SDLK_RETURN: | ||||
| 				mModel->SetGameState(GameStateRunning); | ||||
| 				return true; | ||||
| 			default: | ||||
| 				return true; | ||||
| 		} | ||||
| 	} else if (mModel->GetGameState() == GameStatePlayerDied) { | ||||
| 		switch (keysym.sym) { | ||||
| 			case SDLK_RETURN: | ||||
| 				mModel->SetGameState(GameStateRunning); | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void MenuOverlay::Draw () { | ||||
| 	glClearColor (0.1, 0.1, 0.1, 1.); | ||||
| 
 | ||||
| 	right = static_cast<float> (Engine::GetWindowWidth()); | ||||
| 	bottom = static_cast<float> (Engine::GetWindowHeight()); | ||||
| 
 | ||||
| 	// we switch to orthographic projection and draw the contents of the 2d 
 | ||||
| 	// overlay on top of the previous drawings
 | ||||
| 	glMatrixMode (GL_PROJECTION); | ||||
| 	glPushMatrix (); | ||||
| 	glLoadIdentity (); | ||||
| 
 | ||||
| 	// first we have to get the size of the current viewport to set up the
 | ||||
| 	// orthographic projection correctly
 | ||||
| 	GLint viewport[4]; | ||||
| 	glGetIntegerv(GL_VIEWPORT, viewport); | ||||
| 	gluOrtho2D (viewport[0], viewport[2], viewport[3], viewport[1]); | ||||
| 
 | ||||
| 	glMatrixMode (GL_MODELVIEW); | ||||
| 	glPushMatrix (); | ||||
| 	glLoadIdentity (); | ||||
| 
 | ||||
| 	// then we do the drawings
 | ||||
| 	if (mModel->GetGameState() == GameStateRunning) { | ||||
| 		glClearColor (0., 0., 0., 1.); | ||||
| 		DrawGameRunning(); | ||||
| 	}	else if (mModel->GetGameState() == GameStateGameOver) | ||||
| 		DrawGameOverScreen (); | ||||
| 	else if (mModel->GetGameState() == GameStateMainMenu  | ||||
| 			|| mModel->GetGameState() == GameStatePaused) | ||||
| 		DrawGameMenu (); | ||||
| 	else if (mModel->GetGameState() == GameStateLevelComplete) | ||||
| 		DrawGameLevelComplete (); | ||||
| 	else if (mModel->GetGameState() == GameStatePlayerDied) | ||||
| 		DrawPlayerDied(); | ||||
| 
 | ||||
| 	glPopMatrix (); | ||||
| 
 | ||||
| 	glMatrixMode (GL_PROJECTION); | ||||
| 	glPopMatrix (); | ||||
| 
 | ||||
| 	glMatrixMode (GL_MODELVIEW); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| void MenuOverlay::DrawGameRunning() { | ||||
| 	right = static_cast<float> (Engine::GetWindowWidth()); | ||||
| 	bottom = static_cast<float> (Engine::GetWindowHeight()); | ||||
| 
 | ||||
| 	int i; | ||||
| 	for (i = 0; i < mModel->GetPlayerLives(); i++) { | ||||
| 		mShipSprite.DrawAt2D (right - 32 - i*20, bottom - 16); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void MenuOverlay::DrawPlayerDied () { | ||||
| 	std::ostringstream topbar_stream; | ||||
| 	topbar_stream << "You died ..."; | ||||
| 	Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8, topbar_stream.str().c_str ()); | ||||
| } | ||||
| 
 | ||||
| void MenuOverlay::DrawGameOverScreen() { | ||||
| 	std::ostringstream topbar_stream; | ||||
| 	topbar_stream << "That was pathetic! "; | ||||
| 	Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8, topbar_stream.str().c_str ()); | ||||
| } | ||||
| 
 | ||||
| void MenuOverlay::DrawGameMenu() { | ||||
| 	Engine::DrawGLString ( right * 0.5 - 100, bottom * 0.5 - 8 - 64, "A s t e r o i d s"); | ||||
| 	Engine::DrawGLString ( right * 0.5 - 100, bottom * 0.5 - 8 - 32, "Main Menu"); | ||||
| 
 | ||||
| 	if (mModel->GetGameState() == GameStatePaused) | ||||
| 		Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8 - 16, "[Return] - Resume Game"); | ||||
| 	else | ||||
| 		Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8 - 16, "[Return] - Start Game"); | ||||
| 
 | ||||
| 	Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8, "[Escape] - Quit"); | ||||
| } | ||||
| 
 | ||||
| void MenuOverlay::DrawGameLevelComplete() { | ||||
| 	Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8 - 16, "Congratulations - You rock!"); | ||||
| 	Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8, "[Return] - Next level ..."); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										41
									
								
								asteroids/MenuOverlay.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								asteroids/MenuOverlay.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| #ifndef MENUOVERLAY | ||||
| #define MENUOVERLAY | ||||
| 
 | ||||
| namespace Engine { | ||||
| class OverlayBase; | ||||
| } | ||||
| 
 | ||||
| #include "OverlayBase.h" | ||||
| #include "Sprite.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| class Model; | ||||
| 
 | ||||
| class MenuOverlay : public Engine::OverlayBase { | ||||
| 	public: | ||||
| 		MenuOverlay () { | ||||
| 		}; | ||||
| 		void Init (); | ||||
| 		virtual ~MenuOverlay() {}; | ||||
| 
 | ||||
| 		virtual bool OnKeyDown (const SDL_keysym &keysym); | ||||
| 		virtual void Draw (); | ||||
| 
 | ||||
| 		void DrawGameOverScreen (); | ||||
| 		void DrawGameMenu(); | ||||
| 		void DrawGameLevelComplete (); | ||||
| 		void DrawGamePaused (); | ||||
| 		void DrawGameRunning (); | ||||
| 		void DrawPlayerDied (); | ||||
| 
 | ||||
| 		void SetModel (Model *model) { mModel = model; }; | ||||
| 
 | ||||
| 	private: | ||||
| 		Model *mModel; | ||||
| 		Engine::Sprite mShipSprite; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* MENUOVERLAY */ | ||||
							
								
								
									
										213
									
								
								asteroids/Model.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								asteroids/Model.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,213 @@ | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| 
 | ||||
| #include "Model.h" | ||||
| #include "Physics.h" | ||||
| #include "PhysicsBase.h" | ||||
| 
 | ||||
| #include "EntityFactory.h" | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| static Model* ModelInstance = NULL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int Model::OnInit (int argc, char* argv[]) { | ||||
| 	int result = Engine::ModelBase::OnInit (argc, argv); | ||||
| 
 | ||||
| 	ModelInstance = this; | ||||
| 
 | ||||
| 	mGameState = GameStateMainMenu; | ||||
| 	mLastGameState = GameStateMainMenu; | ||||
| 
 | ||||
| 	Engine::LogMessage ("Model Initialization!"); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void Model::Process () { | ||||
| 	if (mLastGameState == mGameState) { | ||||
| 		if (mGameState == GameStateRunning) { | ||||
| 			Engine::ModelBase::Process(); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// when we are here we know that something has changed so we need to take
 | ||||
| 	// some action.
 | ||||
| 	Engine::LogDebug ("Switching from %s->%s", GetStringGameState(mLastGameState), GetStringGameState(mGameState)); | ||||
| 
 | ||||
| 	if (mLastGameState == GameStateMainMenu && mGameState == GameStateRunning) { | ||||
| 		mPlayerLives = 3; | ||||
| 		mLevel = 1; | ||||
| 		DoLoadLevel ("./data/levels/default.txt"); | ||||
| 	} | ||||
| 	else if (mLastGameState == GameStateRunning && mGameState == GameStatePlayerDied) { | ||||
| 		mPlayerLives --; | ||||
| 
 | ||||
| 		ClearEntities(); | ||||
| 
 | ||||
| 		if (mPlayerLives == 0) | ||||
| 			mGameState = GameStateGameOver; | ||||
| 	} | ||||
| 	else if (mLastGameState == GameStateLevelComplete && mGameState == GameStateRunning) | ||||
| 		DoLoadLevel ("./data/levels/default.txt"); | ||||
| 	else if (mLastGameState == GameStatePlayerDied && mGameState == GameStateRunning) | ||||
| 		DoLoadLevel ("./data/levels/default.txt"); | ||||
| 	else if (mLastGameState == GameStateRunning && mGameState == GameStateGameOver) | ||||
| 		ClearEntities(); | ||||
| 
 | ||||
| 	// ... and we have to set the last game state to the current gamestate
 | ||||
| 	// otherwise we end up in an infinit loop of performing the switching
 | ||||
| 	// action.
 | ||||
| 	mLastGameState = mGameState; | ||||
| } | ||||
| 
 | ||||
| int Model::DoLoadLevel (const char* filename) { | ||||
| 	Engine::LogMessage ("Loading level from %s", filename); | ||||
| 	std::fstream level_file (filename, std::ios::in); | ||||
| 	 | ||||
| 	if (!level_file) { | ||||
| 		Engine::LogError ("Unable to open file %s for writing!", filename); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	ClearEntities(); | ||||
| 	mAsteroids.clear(); | ||||
| 
 | ||||
| 	std::string entity_type_str; | ||||
| 
 | ||||
| 	int entity_count = 0; | ||||
| 
 | ||||
| 	while (level_file >> entity_type_str) { | ||||
| 		if (entity_type_str[0] == '#') { | ||||
| 			std::cout << "Read Comment: " << entity_type_str; | ||||
| 			getline (level_file, entity_type_str); | ||||
| 			std::cout << entity_type_str << std::endl; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		GameEntityType entity_type = GameEntityTypeUnknown; | ||||
| 
 | ||||
| 		if (entity_type_str == "GameEntityTypeShip") | ||||
| 			entity_type = GameEntityTypeShip; | ||||
| 		else if (entity_type_str == "GameEntityTypeAsteroid") | ||||
| 			entity_type = GameEntityTypeAsteroid; | ||||
| 		else { | ||||
| 			Engine::LogError ("Unknown Entity type: %s", entity_type_str.c_str()); | ||||
| 			exit (-1); | ||||
| 		} | ||||
| 
 | ||||
| 		Engine::EntityBase* entity = CreateEntity (entity_type); | ||||
| 
 | ||||
| 		bool is_player; | ||||
| 		level_file >> is_player; | ||||
| 
 | ||||
| 		if (is_player) | ||||
| 			mPlayerEntityId = entity->mId; | ||||
| 
 | ||||
| 		level_file >> entity->mPhysicState->mPosition[0]; | ||||
| 		level_file >> entity->mPhysicState->mPosition[1]; | ||||
| 		level_file >> entity->mPhysicState->mPosition[2]; | ||||
| 
 | ||||
| 		level_file >> entity->mPhysicState->mOrientation[0]; | ||||
| 		level_file >> entity->mPhysicState->mOrientation[1]; | ||||
| 		level_file >> entity->mPhysicState->mOrientation[2]; | ||||
| 
 | ||||
| 		level_file >> entity->mPhysicState->mVelocity[0]; | ||||
| 		level_file >> entity->mPhysicState->mVelocity[1]; | ||||
| 		level_file >> entity->mPhysicState->mVelocity[2]; | ||||
| 
 | ||||
| 		level_file >> entity->mPhysicState->mAngleVelocity; | ||||
| 
 | ||||
| 		entity_count ++; | ||||
| 	} | ||||
| 
 | ||||
| 	level_file.close(); | ||||
| 
 | ||||
| 	Engine::LogDebug ("%d Entities loaded!", mEntities.size()); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int Model::DoSaveLevel (const char* filename) { | ||||
| 	Engine::LogMessage ("Saving level to %s", filename); | ||||
| 	std::fstream level_file (filename, std::ios::out); | ||||
| 	 | ||||
| 	if (!level_file) { | ||||
| 		Engine::LogError ("Unable to open file %s for writing!", filename); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	level_file << "# Format" << std::endl; | ||||
| 	level_file << "# <Type> <player?> <xpos> <ypos> <zpos> <zrot> <yrot> <xrot> <xvel> <yvel> <zvel> <rotvel>" << std::endl; | ||||
| 
 | ||||
| 	std::map<unsigned int, Engine::EntityBase*>::iterator iter = mEntities.begin(); | ||||
| 	unsigned int player_id = GetPlayerEntityId(); | ||||
| 
 | ||||
| 	for (iter = mEntities.begin(); iter != mEntities.end(); iter++) { | ||||
| 		Engine::EntityBase* game_entity = iter->second; | ||||
| 
 | ||||
| 		level_file << GetStringGameEntityType((GameEntityType)game_entity->mType) << "\t" | ||||
| 			// this stores the player id
 | ||||
| 			<< (game_entity->mId == player_id) << "\t" | ||||
| 			<< game_entity->mPhysicState->mPosition[0] << "\t" | ||||
| 			<< game_entity->mPhysicState->mPosition[1] << "\t" | ||||
| 			<< game_entity->mPhysicState->mPosition[2] << "\t" | ||||
| 			<< game_entity->mPhysicState->mOrientation[0] << "\t" | ||||
| 			<< game_entity->mPhysicState->mOrientation[1] << "\t" | ||||
| 			<< game_entity->mPhysicState->mOrientation[2] << "\t" | ||||
| 			<< game_entity->mPhysicState->mVelocity[0] << "\t" | ||||
| 			<< game_entity->mPhysicState->mVelocity[1] << "\t" | ||||
| 			<< game_entity->mPhysicState->mVelocity[2] << "\t" | ||||
| 			<< game_entity->mPhysicState->mAngleVelocity << "\t" | ||||
| 			<< std::endl; | ||||
| 	} | ||||
| 	 | ||||
| 	level_file.close(); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void Model::OnCreateEntity (const int type, const unsigned int id) { | ||||
| 	GameEntityType entity_type = (GameEntityType) type; | ||||
| 
 | ||||
| 	if (entity_type == GameEntityTypeAsteroid) { | ||||
| 		mAsteroids.push_back (id); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Model::OnKillEntity (const Engine::EntityBase *entity) { | ||||
| 	GameEntityType entity_type = (GameEntityType) entity->mType; | ||||
| 
 | ||||
| 	if (entity_type == GameEntityTypeAsteroid) { | ||||
| 		unsigned int i; | ||||
| 
 | ||||
| 		for (i = 0; i < mAsteroids.size(); i++) { | ||||
| 			if (mAsteroids.at(i) == entity->mId) { | ||||
| 				std::vector<unsigned int>::iterator entity_iter = mAsteroids.begin() + i; | ||||
| 				mAsteroids.erase (entity_iter); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (mAsteroids.size() == 0) { | ||||
| 			SetGameState (GameStateLevelComplete); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| float Model::GetWorldWidth () { | ||||
| 	return static_cast<Physics*>(mPhysics)->GetWorldWidth(); | ||||
| } | ||||
| 
 | ||||
| float Model::GetWorldHeight () { | ||||
| 	return static_cast<Physics*>(mPhysics)->GetWorldHeight(); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										49
									
								
								asteroids/Model.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								asteroids/Model.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| #ifndef _MODEL_H | ||||
| #define _MODEL_H | ||||
| 
 | ||||
| #include "ModelBase.h" | ||||
| #include "AsteroidsEnums.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| class Model : public Engine::ModelBase { | ||||
| 	public: | ||||
| 		virtual void Process(); | ||||
| 		int DoLoadLevel (const char* filename); | ||||
| 		int DoSaveLevel (const char* filename); | ||||
| 
 | ||||
| 		void SetGameState (const GameState &state) { | ||||
| 			mLastGameState = mGameState; | ||||
| 			mGameState = state; | ||||
| 		}; | ||||
| 		GameState GetGameState () { return mGameState; }; | ||||
| 
 | ||||
| 		int GetPlayerLives () { return mPlayerLives; }; | ||||
| 
 | ||||
| 		float GetWorldWidth (); | ||||
| 		float GetWorldHeight (); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		virtual void OnRegisterCommands (); | ||||
| 
 | ||||
| 		virtual void OnCreateEntity (const int type, const unsigned int id); | ||||
| 		virtual void OnKillEntity (const Engine::EntityBase *entity);  | ||||
| 
 | ||||
| 	private: | ||||
| 		/** \brief Keeps a list of all asteroids */ | ||||
| 		std::vector<unsigned int> mAsteroids; | ||||
| 
 | ||||
| 		GameState mGameState; | ||||
| 		GameState mLastGameState; | ||||
| 
 | ||||
| 		int mPlayerLives; | ||||
| 		int mLevel; | ||||
| 
 | ||||
| 	friend class View; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _MODEL_H
 | ||||
							
								
								
									
										48
									
								
								asteroids/ModelCommands.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								asteroids/ModelCommands.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| #include "Model.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| static Model *ModelInstance = NULL; | ||||
| 
 | ||||
| bool Cmd_SaveLevel (const std::vector<std::string> args) { | ||||
| 	assert (ModelInstance); | ||||
| 
 | ||||
| 	if (args.size() != 1) { | ||||
| 		Engine::CommandSetErrorString ("usage: savelevel <path_to_level>"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ModelInstance->DoSaveLevel (args[0].c_str()) > 0) | ||||
| 		return true; | ||||
| 
 | ||||
| 	// ToDo: Maybe some error output?
 | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool Cmd_LoadLevel (const std::vector<std::string> args) { | ||||
| 	assert (ModelInstance); | ||||
| 
 | ||||
| 	if (args.size() != 1) { | ||||
| 		Engine::CommandSetErrorString ("usage: loadlevel <path_to_level>"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ModelInstance->DoLoadLevel (args[0].c_str()) > 0) | ||||
| 		return true; | ||||
| 
 | ||||
| 	// ToDo: Maybe some error output?
 | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void Model::OnRegisterCommands () { | ||||
| 	ModelInstance = this; | ||||
| 
 | ||||
| 	Engine::ModelBase::OnRegisterCommands (); | ||||
| 
 | ||||
| 	Engine::AddCommand ("savelevel", Cmd_SaveLevel); | ||||
| 	Engine::AddCommand ("loadlevel", Cmd_LoadLevel); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										58
									
								
								asteroids/Physics.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								asteroids/Physics.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| 
 | ||||
| #include "Model.h" | ||||
| #include "Physics.h" | ||||
| 
 | ||||
| #include "EntityFactory.h" | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| static Physics* PhysicsInstance = NULL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int Physics::OnInit (int argc, char* argv[]) { | ||||
| 	Engine::PhysicsBase::OnInit (argc, argv); | ||||
| 	 | ||||
| 	Engine::LogMessage ("Physics Initialization!"); | ||||
| 
 | ||||
| 	PhysicsInstance = this; | ||||
| 
 | ||||
| 	mWorldWidth = 16; | ||||
| 	mWorldHeight = 16; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int Physics::Simulate (float msec, Engine::ModelBase *model) { | ||||
| 	int result = Engine::PhysicsBase::Simulate (msec, model); | ||||
| 
 | ||||
| 	Engine::EntityPhysicState* entity = NULL; | ||||
| 	std::map<unsigned int, Engine::EntityPhysicState*>::iterator entity_iter; | ||||
| 
 | ||||
| 	for (entity_iter = mEntities.begin (); | ||||
| 			entity_iter != mEntities.end(); | ||||
| 			entity_iter++) { | ||||
| 		entity = entity_iter->second; | ||||
| 
 | ||||
| 		if (entity->mPosition[0] > mWorldWidth * 0.5) | ||||
| 			entity->mPosition[0] -= mWorldWidth; | ||||
| 		if (entity->mPosition[0] < - mWorldWidth * 0.5) | ||||
| 			entity->mPosition[0] += mWorldWidth; | ||||
| 
 | ||||
| 		if (entity->mPosition[2] > mWorldHeight * 0.5) | ||||
| 			entity->mPosition[2] -= mWorldHeight; | ||||
| 		if (entity->mPosition[2] < - mWorldHeight * 0.5) | ||||
| 			entity->mPosition[2] += mWorldHeight; | ||||
| 	} | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										34
									
								
								asteroids/Physics.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								asteroids/Physics.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| #ifndef _PHYSICS_H | ||||
| #define _PHYSICS_H | ||||
| 
 | ||||
| #include "PhysicsBase.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 	class Model; | ||||
| } | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| class Physics : public Engine::PhysicsBase { | ||||
| 	public: | ||||
| 		virtual int Simulate (float msec, Engine::ModelBase* model = NULL); | ||||
| 
 | ||||
| 		void SetWorldSize (float width, float height) { | ||||
| 			mWorldWidth = width; | ||||
| 			mWorldHeight = height; | ||||
| 		} | ||||
| 
 | ||||
| 		float GetWorldWidth () { return mWorldWidth; } | ||||
| 		float GetWorldHeight () { return mWorldHeight; } | ||||
| 
 | ||||
| 	protected: | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 
 | ||||
| 	private: | ||||
| 		float mWorldWidth; | ||||
| 		float mWorldHeight; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _PHYSICS_H
 | ||||
							
								
								
									
										17
									
								
								asteroids/RocketEntity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								asteroids/RocketEntity.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| #include "Model.h" | ||||
| 
 | ||||
| #include "RocketEntity.h" | ||||
| #include "Controller.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| void RocketEntity::Update (float delta_sec) { | ||||
| 	mSecToLive -= delta_sec; | ||||
| 
 | ||||
| 	if (mSecToLive <= 0.) | ||||
| 		Engine::KillEntity (mId); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										39
									
								
								asteroids/RocketEntity.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								asteroids/RocketEntity.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| #ifndef _ROCKETENTITY_H | ||||
| #define _ROCKETENTITY_H | ||||
| 
 | ||||
| #include "EntityBase.h" | ||||
| #include "AsteroidsEnums.h" | ||||
| 
 | ||||
| #include "Sprite.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| struct RocketEntityPhysicState : public Engine::EntityPhysicState { | ||||
| 	RocketEntityPhysicState () { | ||||
| 		mBaseType = Engine::EntityBaseTypeParticle; | ||||
| 		mType = GameEntityTypeRocket; | ||||
| 	} | ||||
| 	virtual ~RocketEntityPhysicState() {}; | ||||
| }; | ||||
| 
 | ||||
| struct RocketEntity: public Engine::EntityBase { | ||||
| 	RocketEntity () { | ||||
| 		mBaseType = Engine::EntityBaseTypeParticle; | ||||
| 		mType = GameEntityTypeRocket; | ||||
| 
 | ||||
| 		mSecToLive = 3.; | ||||
| 	} | ||||
| 	virtual ~RocketEntity() {}; | ||||
| 
 | ||||
| 	virtual void Update (float delta_sec); | ||||
| 	virtual bool CollisionEvent (Engine::EntityBase *entity) { | ||||
| 		Engine::LogMessage ("Rocket BOOM"); | ||||
| 		return false;  | ||||
| 	} | ||||
| 
 | ||||
| 	float mSecToLive; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _ROCKETENTITY_H
 | ||||
							
								
								
									
										122
									
								
								asteroids/ShipEntity.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								asteroids/ShipEntity.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| #include "Model.h" | ||||
| 
 | ||||
| #include "ShipEntity.h" | ||||
| #include "RocketEntity.h" | ||||
| #include "Controller.h" | ||||
| #include "AsteroidsEvents.h" | ||||
| 
 | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| static Engine::Variable var_ship_acceleration ("ship_acceleration", "10"); | ||||
| static Engine::Variable var_ship_maxspeed ("ship_maxspeed", "10"); | ||||
| static Engine::Variable var_ship_rotationspeed ("ship_rotationspeed", "180"); | ||||
| 
 | ||||
| void ShipEntity::Update (float delta_sec) { | ||||
| 	if (!mPhysicState || !mControllerState) | ||||
| 		return; | ||||
| 
 | ||||
| 	// If we die, we have to decrease the fade timer
 | ||||
| 	if (!mAlive) { | ||||
| 		mFadeTimer -= delta_sec; | ||||
| 
 | ||||
| 		if (mFadeTimer <= 0.) { | ||||
| 			Model *model = (Model*) Engine::EngineGetModel(); | ||||
| 			model->SetGameState (GameStatePlayerDied); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	mState = Idle; | ||||
| 
 | ||||
| 	// the local velocity
 | ||||
| 	vector3d local_velocity = mPhysicState->mVelocity; | ||||
| 	mPhysicState->LocalizeRotation (local_velocity); | ||||
| 
 | ||||
| 	// set the local velocity as the current state of the keys are
 | ||||
| 	if (mControllerState->GetKey (EntityKeyStateForward)) { | ||||
| 		local_velocity[0] += delta_sec * var_ship_acceleration.GetFloatValue(); | ||||
| 		mState = Accelerating; | ||||
| 	} | ||||
| 
 | ||||
| 	// now transform these to global velocities
 | ||||
| 	mPhysicState->GlobalizeRotation (local_velocity); | ||||
| 
 | ||||
| 	// now we can update the new global velocity
 | ||||
| 	mPhysicState->SetVelocity(local_velocity); | ||||
| 
 | ||||
| 	if (mControllerState->GetKey (EntityKeyStateTurnLeft)) { | ||||
| 		mPhysicState->mOrientation[1] += delta_sec * var_ship_rotationspeed.GetFloatValue(); | ||||
| 	} | ||||
| 	if (mControllerState->GetKey (EntityKeyStateTurnRight)) { | ||||
| 		mPhysicState->mOrientation[1] -= delta_sec * var_ship_rotationspeed.GetFloatValue(); | ||||
| 	} | ||||
| 
 | ||||
| 	// Check for the maximum speed
 | ||||
| 	float speed = mPhysicState->mVelocity.length(); | ||||
| 	if (speed > var_ship_maxspeed.GetFloatValue()) { | ||||
| 		mPhysicState->mVelocity *= var_ship_maxspeed.GetFloatValue() / speed; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool ShipEntity::CollisionEvent (Engine::EntityBase* entity) { | ||||
| 	GameEntityType other_type = (GameEntityType) entity->mType; | ||||
| 
 | ||||
| 	if (other_type == GameEntityTypeAsteroid) { | ||||
| 		Engine::LogMessage ("You died!"); | ||||
| 
 | ||||
| 		mPhysicState->mStatic = true; | ||||
| 
 | ||||
| 		mAlive = false; | ||||
| 		mFadeTimer = 3.; | ||||
| 		mState = Dying; | ||||
| 
 | ||||
| 		Engine::EventBasePtr explode_event (new Engine::EventBase()); | ||||
| 		explode_event->mEventType = EventShipExplode; | ||||
| 		explode_event->mEventUnsignedInt = mId; | ||||
| 		QueueEvent (explode_event); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} else if (other_type == GameEntityTypeRocket) { | ||||
| 		Engine::LogMessage ("You just killed yourself!"); | ||||
| 
 | ||||
| 		mPhysicState->mStatic = true; | ||||
| 
 | ||||
| 		mAlive = false; | ||||
| 		mFadeTimer = 1.; | ||||
| 		mState = Dying; | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void ShipEntity::Attack () { | ||||
| 	if (!mAlive) | ||||
| 		return; | ||||
| 
 | ||||
| 	Engine::LogMessage ("ATTACK"); | ||||
| 
 | ||||
| 	Engine::EntityPhysicState* entity_physic = Engine::GetEntityPhysicState (mId); | ||||
| 	vector3d attack_dir (1., 0., 0.); | ||||
| 
 | ||||
| 	entity_physic->GlobalizeRotation (attack_dir); | ||||
| 
 | ||||
| 	RocketEntity *rocket_entity = (RocketEntity*) Engine::CreateEntity (GameEntityTypeRocket); | ||||
| 
 | ||||
| 	rocket_entity->mSecToLive = 1.75; | ||||
| 
 | ||||
| 	RocketEntityPhysicState *rocket_physics = (RocketEntityPhysicState*) rocket_entity->mPhysicState; | ||||
| 	rocket_physics->mPosition = attack_dir; | ||||
| 	rocket_physics->mPosition *= mPhysicState->mRadius; | ||||
| 	rocket_physics->mPosition += entity_physic->mPosition; | ||||
| 	rocket_physics->mOrientation = entity_physic->mOrientation; | ||||
| 	rocket_physics->mVelocity = attack_dir.normalize(); | ||||
| 	rocket_physics->mVelocity *= var_ship_maxspeed.GetFloatValue() + 0.1; | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										58
									
								
								asteroids/ShipEntity.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								asteroids/ShipEntity.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| #ifndef _SHIPENTITY_H | ||||
| #define _SHIPENTITY_H | ||||
| 
 | ||||
| #include "EntityBase.h" | ||||
| #include "AsteroidsEnums.h" | ||||
| #include "Sprite.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| struct ShipEntityPhysicState : public Engine::EntityPhysicState { | ||||
| 	ShipEntityPhysicState () { | ||||
| 		mType = GameEntityTypeShip; | ||||
| 		mBaseType = Engine::EntityBaseTypeActor; | ||||
| 
 | ||||
| 		mAcceleration = 10.; | ||||
| 		mMaxSpeed = 10.; | ||||
| 		mRotationSpeed = 180.; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual ~ShipEntityPhysicState() {}; | ||||
| 
 | ||||
| 	float mAcceleration; | ||||
| 	float mMaxSpeed; | ||||
| 	float mRotationSpeed; | ||||
| }; | ||||
| 
 | ||||
| struct ShipEntity: public Engine::EntityBase { | ||||
| 	enum State { | ||||
| 		Idle = 0, | ||||
| 		Accelerating, | ||||
| 		Rotating, | ||||
| 		Shooting, | ||||
| 		Dying | ||||
| 	}; | ||||
| 
 | ||||
| 	ShipEntity () { | ||||
| 		mType = GameEntityTypeShip; | ||||
| 		mBaseType = Engine::EntityBaseTypeActor; | ||||
| 
 | ||||
| 		mAlive = true; | ||||
| 		mFadeTimer = 0.; | ||||
| 		mState = Idle; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual ~ShipEntity() {}; | ||||
| 
 | ||||
| 	virtual void Attack (); | ||||
| 	virtual void Update (float delta_sec); | ||||
| 	virtual bool CollisionEvent (Engine::EntityBase *entity); | ||||
| 
 | ||||
| 	bool mAlive; | ||||
| 	float mFadeTimer; | ||||
| 	State mState; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _SHIPENTITY_H
 | ||||
							
								
								
									
										359
									
								
								asteroids/View.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								asteroids/View.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,359 @@ | ||||
| #include "View.h" | ||||
| #include "CameraBase.h" | ||||
| #include "MenuOverlay.h" | ||||
| #include "SimpleConsoleOverlay.h" | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| #include "Physics.h" | ||||
| #include "Model.h" | ||||
| #include "EventsBase.h" | ||||
| 
 | ||||
| #include "ShipEntity.h" | ||||
| #include "AsteroidEntity.h" | ||||
| #include "AsteroidsEvents.h" | ||||
| #include "RocketEntity.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| 
 | ||||
| // #define DRAW_BOUNDARIES
 | ||||
| 
 | ||||
| #ifdef DRAW_BOUNDARIES | ||||
| 	#include "coll2d.h" | ||||
| 	#include "DrawingsGL.h" | ||||
| #endif | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| int View::OnInit (int argc, char* argv[]) { | ||||
| 	ViewBase::OnInit (argc, argv); | ||||
| 
 | ||||
| 	// We want menu
 | ||||
| 	mMenuOverlay = new MenuOverlay; | ||||
| 	mMenuOverlay->SetModel ((Model*) mModel); | ||||
| 	mMenuOverlay->Init(); | ||||
| 	AddOverlay (mMenuOverlay); | ||||
| 
 | ||||
| 	// We want the console
 | ||||
| 	Engine::SimpleConsoleOverlay *console = new Engine::SimpleConsoleOverlay; | ||||
| 	// We also want to display the log bar
 | ||||
| 	console->SetDrawLogBar (true); | ||||
| 	AddOverlay (console); | ||||
| 
 | ||||
| 	// This is a simple star field that makes the game so spacy
 | ||||
| 	int i; | ||||
| 	for (i = 0; i < 200; i++) { | ||||
| 		BackgroundStar star; | ||||
| 		star.position[0] = rand() / float(RAND_MAX); | ||||
| 		star.position[1] = rand() / float(RAND_MAX); | ||||
| 		star.position[2] = rand() / float(RAND_MAX); | ||||
| 
 | ||||
| 		mBackgroundStars.push_back (star); | ||||
| 	} | ||||
| 
 | ||||
| 	mAsteroidSprite.LoadFromPNG ("./data/textures/asteroid.png"); | ||||
| 	mShipSprite.LoadFromPNG ("./data/textures/ship.png"); | ||||
| 
 | ||||
| 	mShipThrustSprite.LoadFromPNG ("./data/textures/ship_thrust.png"); | ||||
| 	mShipThrustSprite.SetAnimation (4, 8); | ||||
| 
 | ||||
| 	mShipPartsSprite.LoadFromPNG ("./data/textures/ship_parts.png"); | ||||
| 	mShipPartsSprite.SetSubSpriteCount (10); | ||||
| 
 | ||||
| 	mAccelerateEventHandler = new AccelerateEventHandler (this); | ||||
| 	Engine::RegisterListener (mAccelerateEventHandler, EventAccelerateStart); | ||||
| 	Engine::RegisterListener (mAccelerateEventHandler, EventAccelerateStop); | ||||
| 
 | ||||
| 	mShipExplodeEventHandler = new ShipExplodeEventHandler (this); | ||||
| 	Engine::RegisterListener (mShipExplodeEventHandler, EventShipExplode); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void View::OnDestroy() { | ||||
| 	delete mAccelerateEventHandler; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Event Handlers | ||||
|  */ | ||||
| bool View::AccelerateEventHandler::HandleEvent (const Engine::EventBasePtr &event) const { | ||||
| 	if (event->mEventType == EventAccelerateStart) | ||||
| 		mView->mShipThrustSprite.ResetAnimation(); | ||||
| 
 | ||||
| 	Engine::LogMessage ("Received Acceleration Event: %d", event->mEventType); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool View::ShipExplodeEventHandler::HandleEvent (const Engine::EventBasePtr &event) const { | ||||
| 	if (event->mEventType == EventShipExplode) { | ||||
| 		Engine::EntityBase *ship_entity = Engine::GetEntity (event->mEventUnsignedInt); | ||||
| 		vector3d position = ship_entity->mPhysicState->mPosition; | ||||
| 		vector3d orientation = ship_entity->mPhysicState->mOrientation; | ||||
| 		vector3d velocity = ship_entity->mPhysicState->mVelocity; | ||||
| 
 | ||||
| 		unsigned int i; | ||||
| 		mView->mShipPartsEntityIds.clear(); | ||||
| 
 | ||||
| 		for (i = 0; i < mView->mShipPartsSprite.GetSubSpriteCount(); i++) { | ||||
| 			Engine::EntityBase* part_sprite_particle = Engine::CreateEntity (GameEntityTypeShipPart); | ||||
| 			part_sprite_particle->mPhysicState->mPosition = position; | ||||
| 			part_sprite_particle->mPhysicState->mOrientation = orientation; | ||||
| 			part_sprite_particle->mPhysicState->mVelocity = velocity; | ||||
| 			part_sprite_particle->mPhysicState->mVelocity = vector3d (velocity[0] * (rand()/float(RAND_MAX)) * 1.7, 0., velocity[2] * (rand()/float(RAND_MAX)) * 1.5); | ||||
| 			part_sprite_particle->mPhysicState->mAngleVelocity = (rand()/float(RAND_MAX) - 0.5 ) * 100.; | ||||
| 
 | ||||
| 			mView->mShipPartsEntityIds.push_back(part_sprite_particle->mId); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Engine::LogMessage ("Received Ship Explode Event: %d", event->mEventType); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| void View::UpdateCamera () { | ||||
| 	mCamera->SetEye ( | ||||
| 			0., | ||||
| 			9.5, | ||||
| 			0. | ||||
| 			); | ||||
| 	mCamera->SetPointOfIntrest ( | ||||
| 			0., | ||||
| 			0., | ||||
| 			0. | ||||
| 			); | ||||
| 	mCamera->SetUp ( | ||||
| 			0., | ||||
| 			0., | ||||
| 			-1. | ||||
| 			); | ||||
| 
 | ||||
| 	mCamera->Update (); | ||||
| } | ||||
| 
 | ||||
| void View::DrawStars() { | ||||
| 	unsigned int i; | ||||
| 	 | ||||
| 	float world_width, world_height; | ||||
| 	world_width = static_cast<Model*>(mModel)->GetWorldWidth();	 | ||||
| 	world_height = static_cast<Model*>(mModel)->GetWorldHeight(); | ||||
| 	vector3d velocity (1., 0., 0.); | ||||
| 
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef(-world_width * 0.5, 0, -world_height * 0.5); | ||||
| 	glColor3f (1., 1., 1.); | ||||
| 	glPointSize(2.); | ||||
| 	glBegin(GL_POINTS); | ||||
| 	float z_value; | ||||
| 	for (i = 0; i < mBackgroundStars.size(); i++) { | ||||
| //		glPointSize (2. + 300. *mBackgroundStars.at(i).position[1]);
 | ||||
| 		z_value = mBackgroundStars.at(i).position[1] + 0.1; | ||||
| 
 | ||||
| 		glColor3f (z_value, z_value, z_value); | ||||
| 		glVertex3f (mBackgroundStars.at(i).position[0] * world_width, | ||||
| 				-1., | ||||
| 				mBackgroundStars.at(i).position[2] * world_height); | ||||
| 
 | ||||
| 		mBackgroundStars.at(i).position -= vector3d(Engine::GetFrameDuration() * 0.7 * mBackgroundStars.at(i).position[1] / world_width, 0., 0.); | ||||
| 
 | ||||
| 		if (mBackgroundStars.at(i).position[0] < 0.) | ||||
| 			mBackgroundStars.at(i).position[0] += 1.; | ||||
| 		if (mBackgroundStars.at(i).position[0] >= 1.) | ||||
| 			mBackgroundStars.at(i).position[0] -= 1.; | ||||
| 	} | ||||
| 
 | ||||
| 	glEnd(); | ||||
| 	glPopMatrix(); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void View::DrawWorld() { | ||||
| 	std::map<unsigned int, Engine::EntityBase*>::iterator entity_iterator; | ||||
| 
 | ||||
| 	Model *game_model = static_cast<Model*> (mModel); | ||||
| 
 | ||||
| 	DrawStars (); | ||||
| 
 | ||||
| 	if ( game_model->GetGameState() != GameStateRunning) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ViewBase::DrawWorld(); | ||||
| 
 | ||||
| 	for (entity_iterator = game_model->mEntities.begin (); | ||||
| 			entity_iterator != game_model->mEntities.end(); | ||||
| 			entity_iterator++) { | ||||
| 		Engine::EntityBase* entity = entity_iterator->second; | ||||
| 
 | ||||
| 		// Perform multiple drawing if the entity is at the border
 | ||||
| 		Physics* game_physics = (Physics*) game_model->mPhysics; | ||||
| 		float world_width = game_physics->GetWorldWidth(); | ||||
| 		float world_height = game_physics->GetWorldHeight(); | ||||
| 
 | ||||
| 		// Drawing at the original position:
 | ||||
| 		glPushMatrix (); | ||||
| 		glTranslatef (entity->mPhysicState->mPosition[0], | ||||
| 				entity->mPhysicState->mPosition[1], | ||||
| 				entity->mPhysicState->mPosition[2]); | ||||
| 
 | ||||
| 		glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); | ||||
| 		glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); | ||||
| 		glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); | ||||
| 
 | ||||
| 		glColor3f (1., 1., 1.); | ||||
| 		DrawEntity (entity); | ||||
| 
 | ||||
| 		glPopMatrix (); | ||||
| 
 | ||||
| 		// If we move out the right side
 | ||||
| 		if (entity->mPhysicState->mPosition[0] + entity->mPhysicState->mRadius * 2  | ||||
| 				>= world_width * 0.5) { | ||||
| 
 | ||||
| 			glPushMatrix (); | ||||
| 			glTranslatef (entity->mPhysicState->mPosition[0] - world_width, | ||||
| 					entity->mPhysicState->mPosition[1], | ||||
| 					entity->mPhysicState->mPosition[2]); | ||||
| 
 | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); | ||||
| 
 | ||||
| 			glColor3f (1., 1., 1.); | ||||
| 			DrawEntity (entity); | ||||
| 
 | ||||
| 			glPopMatrix (); | ||||
| 		} | ||||
| 
 | ||||
| 		// if we move out the left side
 | ||||
| 		if (entity->mPhysicState->mPosition[0] - entity->mPhysicState->mRadius * 2 | ||||
| 				< - world_width * 0.5) { | ||||
| 			glPushMatrix (); | ||||
| 			glTranslatef (entity->mPhysicState->mPosition[0] + world_width, | ||||
| 					entity->mPhysicState->mPosition[1], | ||||
| 					entity->mPhysicState->mPosition[2]); | ||||
| 
 | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); | ||||
| 
 | ||||
| 			glColor3f (1., 1., 1.); | ||||
| 			DrawEntity (entity); | ||||
| 
 | ||||
| 			glPopMatrix (); | ||||
| 		} | ||||
| 
 | ||||
| 		// If we move out the bottom side
 | ||||
| 		if (entity->mPhysicState->mPosition[2] + entity->mPhysicState->mRadius * 2 | ||||
| 				>= world_height * 0.5) { | ||||
| 
 | ||||
| 			glPushMatrix (); | ||||
| 			glTranslatef (entity->mPhysicState->mPosition[0], | ||||
| 					entity->mPhysicState->mPosition[1], | ||||
| 					entity->mPhysicState->mPosition[2] - world_height); | ||||
| 
 | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); | ||||
| 
 | ||||
| 			glColor3f (1., 1., 1.); | ||||
| 			DrawEntity (entity); | ||||
| 
 | ||||
| 			glPopMatrix (); | ||||
| 		} | ||||
| 
 | ||||
| 		// if we move out the left side
 | ||||
| 		if (entity->mPhysicState->mPosition[2] - entity->mPhysicState->mRadius * 2 | ||||
| 				< - world_height* 0.5) { | ||||
| 			glPushMatrix (); | ||||
| 			glTranslatef (entity->mPhysicState->mPosition[0], | ||||
| 					entity->mPhysicState->mPosition[1], | ||||
| 					entity->mPhysicState->mPosition[2] + world_height); | ||||
| 
 | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); | ||||
| 			glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); | ||||
| 
 | ||||
| 			glColor3f (1., 1., 1.); | ||||
| 			DrawEntity (entity); | ||||
| 
 | ||||
| 			glPopMatrix (); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void View::DrawEntity (Engine::EntityBase *entity) { | ||||
| 	if (entity->mType == GameEntityTypeAsteroid) | ||||
| 		DrawAsteroid ((AsteroidEntity*) entity); | ||||
| 	else if (entity->mType == GameEntityTypeShip) | ||||
| 		DrawShip ((ShipEntity*) entity); | ||||
| 	else if (entity->mType == GameEntityTypeRocket) | ||||
| 		DrawRocket ((RocketEntity*) entity); | ||||
| 	else if (entity->mType == GameEntityTypeShipPart) | ||||
| 		DrawShipPart (entity); | ||||
| 	else { | ||||
| 		Engine::LogError ("Cannot draw entity: unknown type '%d'", entity->mType); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// \todo: Update of the animation ??
 | ||||
| void View::DrawShip (ShipEntity *ship) { | ||||
| 	if (!ship->mAlive) | ||||
| 		return; | ||||
| 
 | ||||
| 	mShipSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight()); | ||||
| 	mShipThrustSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight()); | ||||
| 
 | ||||
| 	if (ship->mState == ShipEntity::Accelerating) { | ||||
| 		mShipThrustSprite.UpdateAnimation (Engine::GetFrameDuration()); | ||||
| 		mShipThrustSprite.DrawAt(-0.5, 0., 0.); | ||||
| 	} | ||||
| 
 | ||||
| 	mShipSprite.DrawAt(0., 0., 0.); | ||||
| 
 | ||||
| #ifdef DRAW_BOUNDARIES | ||||
| 	glColor3f (1., 1., 1.); | ||||
| 	DrawCircle (ship->mPhysicState->mRadius, 20);	 | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void View::DrawAsteroid (AsteroidEntity *asteroid) { | ||||
| 	mAsteroidSprite.SetScale (2. * asteroid->mPhysicState->mRadius / mAsteroidSprite.GetWidth()); | ||||
| 	mAsteroidSprite.DrawAt(0., 0., 0.); | ||||
| 
 | ||||
| #ifdef DRAW_BOUNDARIES | ||||
| 	glColor3f (1., 1., 1.); | ||||
| 	DrawCircle (asteroid->mPhysicState->mRadius, 20); | ||||
| #endif	 | ||||
| } | ||||
| 
 | ||||
| void View::DrawRocket (RocketEntity *rocket) { | ||||
| 	glColor3f (1., 1., 1.); | ||||
| 	glBegin (GL_QUADS); | ||||
| 	glVertex3f (-0.25, 0., 0.05); | ||||
| 	glVertex3f (0.05, 0., 0.05); | ||||
| 	glVertex3f (0.05, 0., -0.05); | ||||
| 	glVertex3f (-0.25, 0., -0.05); | ||||
| 	glEnd (); | ||||
| } | ||||
| 
 | ||||
| void View::DrawShipPart (Engine::EntityBase *entity) { | ||||
| 	unsigned int i; | ||||
| 	mShipPartsSprite.SetScale (1. / mShipSprite.GetHeight()); | ||||
| 
 | ||||
| 	for (i = 0; i < mShipPartsEntityIds.size(); i++) { | ||||
| 		if (mShipPartsEntityIds.at(i) == entity->mId) { | ||||
| 			mShipPartsSprite.DrawSubAt (i, 0., 0., 0.); | ||||
| 		} | ||||
| 	} | ||||
| #ifdef DRAW_BOUNDARIES | ||||
| 	glColor3f (1., 1., 1.); | ||||
| 	DrawCircle (entity->mPhysicState->mRadius, 20); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										75
									
								
								asteroids/View.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								asteroids/View.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| #ifndef _VIEW_H | ||||
| #define _VIEW_H | ||||
| 
 | ||||
| #include "ViewBase.h" | ||||
| #include "mathlib.h" | ||||
| #include "Sprite.h" | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| namespace asteroids { | ||||
| 
 | ||||
| class MenuOverlay; | ||||
| struct ShipEntity; | ||||
| struct AsteroidEntity; | ||||
| struct RocketEntity; | ||||
| 
 | ||||
| struct BackgroundStar { | ||||
| 	vector3d position; | ||||
| }; | ||||
| 
 | ||||
| /** \brief Performs the actual drawing based on Camera and Model
 | ||||
|  */ | ||||
| class View : public Engine::ViewBase {  | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		int OnInit (int argc, char* argv[]); | ||||
| 		void OnDestroy (); | ||||
| 
 | ||||
| 		/** \brief Updates the camera for further drawing */ | ||||
| 		virtual void UpdateCamera (); | ||||
| 
 | ||||
| 	private: | ||||
| 		virtual void DrawWorld (); | ||||
| 		void DrawStars (); | ||||
| 
 | ||||
| 		void DrawEntity (Engine::EntityBase *entity); | ||||
| 		void DrawShip (ShipEntity *ship); | ||||
| 		void DrawAsteroid (AsteroidEntity *asteroid); | ||||
| 		void DrawRocket (RocketEntity *asteroid); | ||||
| 		void DrawShipPart (Engine::EntityBase *entity); | ||||
| 
 | ||||
| 		MenuOverlay *mMenuOverlay; | ||||
| 		std::vector<BackgroundStar> mBackgroundStars; | ||||
| 
 | ||||
| 		std::vector<unsigned int> mShipPartsEntityIds; | ||||
| 
 | ||||
| 		Engine::Sprite mAsteroidSprite; | ||||
| 		Engine::Sprite mShipSprite; | ||||
| 		Engine::Sprite mShipThrustSprite; | ||||
| 		Engine::Sprite mShipPartsSprite; | ||||
| 
 | ||||
| 		class AccelerateEventHandler : public Engine::EventListenerBase { | ||||
| 			public: | ||||
| 				explicit AccelerateEventHandler (View *view) : mView (view) {}; | ||||
| 				virtual bool HandleEvent (const Engine::EventBasePtr &event) const; | ||||
| 			private: | ||||
| 				View *mView; | ||||
| 		}; | ||||
| 
 | ||||
| 		class ShipExplodeEventHandler : public Engine::EventListenerBase { | ||||
| 			public: | ||||
| 				explicit ShipExplodeEventHandler (View *view) : mView (view) {}; | ||||
| 				virtual bool HandleEvent (const Engine::EventBasePtr &event) const; | ||||
| 			private: | ||||
| 				View *mView; | ||||
| 		}; | ||||
| 
 | ||||
| 		AccelerateEventHandler *mAccelerateEventHandler; | ||||
| 		ShipExplodeEventHandler *mShipExplodeEventHandler; | ||||
| 
 | ||||
| 		friend class AccelerateEventHandler; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _VIEW_H
 | ||||
							
								
								
									
										44
									
								
								asteroids/main.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								asteroids/main.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| #include <cstdlib> | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| #include "Controller.h" | ||||
| #include "View.h" | ||||
| #include "Model.h" | ||||
| #include "Physics.h" | ||||
| #include "EntityFactory.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| int main (int argc, char* argv[]) { | ||||
| 	cout << "Game Start" << endl; | ||||
| 	 | ||||
| 	Engine::Engine engine; | ||||
| 
 | ||||
| 	engine.SetEntityFactory (new asteroids::EntityFactory); | ||||
| 	engine.SetController (new asteroids::Controller); | ||||
| 	engine.SetModel (new asteroids::Model); | ||||
| 	engine.SetPhysics (new asteroids::Physics); | ||||
| 	engine.SetView (new asteroids::View); | ||||
| 
 | ||||
| 	SetLogPrintLevel (Engine::LogLevelDebug); | ||||
| 
 | ||||
| 	if (engine.Init (argc, argv) != 0) { | ||||
| 		cout << "Could not start engine!" << endl; | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	engine.GetView()->SetGridSize (8,8); | ||||
| 	dynamic_cast<asteroids::Physics*>(engine.GetPhysics())->SetWorldSize (28, 20); | ||||
| 
 | ||||
| 	SetLogPrintLevel (Engine::LogLevelDebug); | ||||
| 
 | ||||
| 	engine.MainLoop (); | ||||
| 
 | ||||
| 	engine.Destroy (); | ||||
| 
 | ||||
| 	cout << "Game Quit" << endl; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										12
									
								
								codingstyle.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								codingstyle.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| Indent: Tabs! | ||||
| 
 | ||||
| class Uppercase { | ||||
| 	int OnInit () | ||||
| 	void OnDestroy (); | ||||
| 
 | ||||
| 	void SetValue (); | ||||
| 	int GetValue (); | ||||
| 
 | ||||
| 	void SomeCoolFunction (); | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										
											BIN
										
									
								
								data/fonts/console.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/fonts/console.ttf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										5
									
								
								data/levels/default.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								data/levels/default.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| # Format | ||||
| # <Type> <player?> <xpos> <ypos> <zpos> <zrot> <yrot> <xrot> <xvel> <yvel> <zvel> <rotvel> | ||||
| GameEntityTypeShip	1	0	0	0	0	90	0	0	0	0	0 | ||||
| GameEntityTypeAsteroid	0	5	0	-2	0	0	0	-0.2	0	-0.1 -10 | ||||
| GameEntityTypeAsteroid	0	-2	0	2	0	0	0	0.3	0	0.1 5  | ||||
							
								
								
									
										
											BIN
										
									
								
								data/textures/asteroid.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/textures/asteroid.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 102 KiB | 
							
								
								
									
										
											BIN
										
									
								
								data/textures/ship.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/textures/ship.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 13 KiB | 
							
								
								
									
										
											BIN
										
									
								
								data/textures/ship_parts.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/textures/ship_parts.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 18 KiB | 
							
								
								
									
										
											BIN
										
									
								
								data/textures/ship_thrust.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/textures/ship_thrust.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 21 KiB | 
							
								
								
									
										28
									
								
								engine/CMake/FindFreeType2.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								engine/CMake/FindFreeType2.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # Tries to find FREETYPE2 (http://freetype2.bespin.org) a simple and fast  | ||||
| # network library by Lee Salzman | ||||
| # | ||||
| 
 | ||||
| SET (FREETYPE2_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (FREETYPE2_INCLUDE_DIR freetype/freetype.h /usr/include/ /usr/local/include/ /usr/include/freetype2 /usr/local/include/freetype2 $ENV{FREETYPE2_PATH}/include $ENV{FREETYPE2_INCLUDE_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (FREETYPE2_LIBRARIES NAMES freetype PATHS /usr/lib /usr/local/lib $ENV{FREETYPE2_PATH} $ENV{FREETYPE2_PATH}/lib ENV{FREETYPE2_LIBRARY_PATH}) | ||||
| 
 | ||||
| IF (FREETYPE2_INCLUDE_DIR AND FREETYPE2_LIBRARIES) | ||||
| 	SET (FREETYPE2_FOUND TRUE) | ||||
| ENDIF (FREETYPE2_INCLUDE_DIR AND FREETYPE2_LIBRARIES) | ||||
| 
 | ||||
| IF (FREETYPE2_FOUND) | ||||
|    IF (NOT FREETYPE2_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found FREETYPE2: ${FREETYPE2_LIBRARIES}") | ||||
|    ENDIF (NOT FREETYPE2_FIND_QUIETLY) | ||||
| ELSE (FREETYPE2_FOUND) | ||||
|    IF (FREETYPE2_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find FREETYPE2") | ||||
|    ENDIF (FREETYPE2_FIND_REQUIRED) | ||||
| ENDIF (FREETYPE2_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	FREETYPE2_INCLUDE_DIR | ||||
| 	FREETYPE2_LIBRARIES | ||||
| 	) | ||||
							
								
								
									
										60
									
								
								engine/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								engine/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| CMAKE_MINIMUM_REQUIRED (VERSION 2.6) | ||||
| 
 | ||||
| LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ) | ||||
| 
 | ||||
| FIND_PACKAGE (SDL REQUIRED) | ||||
| FIND_PACKAGE (OpenGL REQUIRED) | ||||
| FIND_PACKAGE (PNG REQUIRED) | ||||
| FIND_PACKAGE (FreeType2 REQUIRED) | ||||
| 
 | ||||
| ADD_SUBDIRECTORY ( libraries ) | ||||
| 
 | ||||
| SET ( ENGINE_SRCS | ||||
| 	CameraBase.cc | ||||
| 	ControllerBase.cc | ||||
| 	EntityBase.cc | ||||
| 	EntityFactoryBase.cc | ||||
| 	GameEntityBase.cc | ||||
| 	ModelBase.cc | ||||
| 	PhysicsBase.cc | ||||
| 	PhysicsEntityBase.cc | ||||
| 	ViewBase.cc | ||||
| 	EventsBase.cc | ||||
| 
 | ||||
| 	Commands.cc | ||||
| 	DrawingsGL.cc | ||||
| 	EngineCommands.cc | ||||
| 	Variables.cc | ||||
| 	VariablesCommands.cc | ||||
| 	SimpleConsoleOverlay.cc | ||||
| 	Sprite.cc | ||||
| 
 | ||||
| 	Engine.cc | ||||
| 	Logging.cc | ||||
| 	) | ||||
| 
 | ||||
| INCLUDE_DIRECTORIES ( | ||||
| 	${PROJECT_SOURCE_DIR} | ||||
| 	libraries/mathlib/ | ||||
| 	libraries/coll2d/include | ||||
| 	libraries/oglft/ | ||||
| 	${FREETYPE2_INCLUDE_DIR} | ||||
| 	) | ||||
| 
 | ||||
| IF ( WIN32 ) | ||||
| 	ADD_LIBRARY ( Engine STATIC ${ENGINE_SRCS} ) | ||||
| ELSE ( WIN32 ) | ||||
| 	ADD_LIBRARY ( Engine SHARED ${ENGINE_SRCS} ) | ||||
| ENDIF ( WIN32 ) | ||||
| 
 | ||||
| TARGET_LINK_LIBRARIES ( Engine | ||||
| 	${SDL_LIBRARY} | ||||
| 	${OPENGL_LIBRARIES} | ||||
| 	${PNG_LIBRARIES} | ||||
| 	mathlib | ||||
| 	oglft | ||||
| 	coll2d | ||||
| 	) | ||||
| 
 | ||||
| ADD_SUBDIRECTORY ( tests ) | ||||
| 
 | ||||
							
								
								
									
										49
									
								
								engine/CameraBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								engine/CameraBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| #include "CameraBase.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| #include <GL/glu.h> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int CameraBase::OnInit (int argc, char* argv[]) { | ||||
| 	LogDebug ("Camera Init"); | ||||
| 
 | ||||
| 	mEye[0] = 0.; | ||||
| 	mEye[1] = 1.; | ||||
| 	mEye[2] = 1.; | ||||
| 
 | ||||
| 	mPointOfIntrest[0] = 0.; | ||||
| 	mPointOfIntrest[1] = 0.; | ||||
| 	mPointOfIntrest[2] = 0.; | ||||
| 
 | ||||
| 	mUp[0] = 0.; | ||||
| 	mUp[1] = 1.; | ||||
| 	mUp[2] = 0.; | ||||
| 
 | ||||
| 	mFOVY = 90.; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void CameraBase::OnDestroy () { | ||||
| 	LogDebug ("Camera Destroy"); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| void CameraBase::Update () { | ||||
| 	glMatrixMode (GL_MODELVIEW); | ||||
| 
 | ||||
| 	glLoadIdentity (); | ||||
| 	gluLookAt(mEye[0], mEye[1], mEye[2], | ||||
| 			mPointOfIntrest[0], mPointOfIntrest[1], mPointOfIntrest[2], | ||||
| 			mUp[0], mUp[1], mUp[2]); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										61
									
								
								engine/CameraBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								engine/CameraBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| #ifndef _CAMERABASE_H | ||||
| #define _CAMERABASE_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Module; | ||||
| 
 | ||||
| /** \brief Controls from where the View is looking to
 | ||||
|  */ | ||||
| class CameraBase : public Module {  | ||||
| 	public: | ||||
| 		/** updates the projection and modelview matrices for the camera */ | ||||
| 		void Update (); | ||||
| 		float GetFOVY () { | ||||
| 			return mFOVY; | ||||
| 		} | ||||
| 
 | ||||
| 		/** sets the point where the camera is looking to */ | ||||
| 		void SetPointOfIntrest (float poi_x, float poi_y, float poi_z) { | ||||
| 			mPointOfIntrest[0] = poi_x; | ||||
| 			mPointOfIntrest[1] = poi_y; | ||||
| 			mPointOfIntrest[2] = poi_z; | ||||
| 		} | ||||
| 		/** sets the position where the camera is located */ | ||||
| 		void SetEye (float eye_x, float eye_y, float eye_z) { | ||||
| 			mEye[0] = eye_x; | ||||
| 			mEye[1] = eye_y; | ||||
| 			mEye[2] = eye_z; | ||||
| 		} | ||||
| 		/** returns the position of the eye */ | ||||
| 		void GetEye (float *eye_out) { | ||||
| 			eye_out[0] = mEye[0]; | ||||
| 			eye_out[1] = mEye[1]; | ||||
| 			eye_out[2] = mEye[2]; | ||||
| 		} | ||||
| 
 | ||||
| 		/** sets the up direction of the camera */ | ||||
| 		void SetUp (float up_x, float up_y, float up_z) { | ||||
| 			mUp[0] = up_x; | ||||
| 			mUp[1] = up_y; | ||||
| 			mUp[2] = up_z; | ||||
| 		} | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		void OnDestroy ();  | ||||
| 
 | ||||
| 		float mPointOfIntrest[3]; | ||||
| 		float mEye[3]; | ||||
| 		float mUp[3]; | ||||
| 
 | ||||
| 		float mFOVY; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _CAMERABASE_H
 | ||||
							
								
								
									
										245
									
								
								engine/Commands.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								engine/Commands.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,245 @@ | ||||
| #include "Commands.h"  | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| static Commands *CommandsInstance = NULL; | ||||
| 
 | ||||
| void trim_command_str (std::string &command_str) { | ||||
| 	std::string::size_type start = command_str.find_first_not_of (" \t"); | ||||
| 	if (start != std::string::npos) | ||||
| 		command_str = command_str.substr (start); | ||||
| 
 | ||||
| 	std::string::size_type end = command_str.find_first_of ("#;\n\r\0"); | ||||
| 
 | ||||
| 	if (end != std::string::npos) | ||||
| 		command_str = command_str.substr (0, end); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int Commands::OnInit (int argc, char* argv[]) { | ||||
| 	LogDebug ("Commands Init"); | ||||
| 	mErrorString = ""; | ||||
| 	if (CommandsInstance) { | ||||
| 		LogError ("Commands module already initialized!"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	CommandsInstance = this; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| void Commands::OnDestroy () { | ||||
| 	LogDebug ("Commands Destroy"); | ||||
| 
 | ||||
| 	if (CommandsInstance) | ||||
| 		CommandsInstance = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| std::string Commands::GetCommandName (const std::string &command) { | ||||
| 	return command.substr (0, command.find_first_of (" ;\n\0")); | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> Commands::ParseArgs (std::string &argument_str) { | ||||
| 	std::vector<std::string> args; | ||||
| 	std::string::size_type pos = argument_str.find_first_not_of (" "); | ||||
| 	std::string::size_type next_token = 0; | ||||
| 
 | ||||
| 	while ( argument_str.length ()> pos && argument_str.find_first_of (" \"", pos) != std::string::npos) { | ||||
| 		next_token = argument_str.find_first_of (" \"", pos); | ||||
| 
 | ||||
| 		if (next_token != std::string::npos && argument_str[next_token] =='"') { | ||||
| 			pos = next_token; | ||||
| 			next_token = argument_str.find_first_of ('"', pos + 1); | ||||
| 			if (next_token != std::string::npos) { | ||||
| 				args.push_back (argument_str.substr (pos + 1, next_token - pos - 1)); | ||||
| 			} | ||||
| 			pos = argument_str.find_first_not_of (" ", next_token + 1); | ||||
| 			 | ||||
| 		} else { | ||||
| 			args.push_back (argument_str.substr (pos, next_token - pos)); | ||||
| 			pos = argument_str.find_first_not_of (" ", next_token + 1); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (pos != std::string::npos) | ||||
| 		args.push_back (argument_str.substr (pos, argument_str.length ())); | ||||
| 
 | ||||
| 	return args; | ||||
| } | ||||
| 
 | ||||
| void Commands::AddCommand (const std::string &name, command_cb callback){ | ||||
| 	LogDebug ("Adding Command '%s' at %x", name.c_str(), (void *) callback); | ||||
| 
 | ||||
| 	mCommandsCallbacks[name] = callback; | ||||
| 
 | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| bool Commands::RunCommand (const std::string &command){ | ||||
| 	LogDebug ("Running Command: %s", command.c_str()); | ||||
| 
 | ||||
| 	std::string cmd_name = GetCommandName (command); | ||||
| 	std::string args; | ||||
| 
 | ||||
| 	if (command.length () > cmd_name.length () + 1) | ||||
| 		args = command.substr (cmd_name.length () + 1, command.length ()); | ||||
| 
 | ||||
| 	if (mCommandsCallbacks.find (cmd_name) != mCommandsCallbacks.end()) { | ||||
| 		std::vector<std::string> argv = ParseArgs (args); | ||||
| 		if (mCommandsCallbacks[cmd_name] (argv)) { | ||||
| 			mErrorString = ""; | ||||
| 			return true; | ||||
| 		} else { | ||||
| 				return false; | ||||
| 		} | ||||
| 	} else { | ||||
| 		LogWarning ("Command '%s' not registered!", cmd_name.c_str ()); | ||||
| 	} | ||||
| 
 | ||||
| 	SetErrorString ("Command '" + cmd_name + "' does not exist!"); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void Commands::QueueCommand (const std::string &command){ | ||||
| 	mCommandQueue.push (command); | ||||
| } | ||||
| 
 | ||||
| bool Commands::QueueExecute (){ | ||||
| 	bool result = true; | ||||
| 
 | ||||
| 	while (mCommandQueue.size() > 0) { | ||||
| 		result = RunCommand (mCommandQueue.front()); | ||||
| 		if (!result) { | ||||
| 			while (!mCommandQueue.empty()) | ||||
| 				mCommandQueue.pop(); | ||||
| 			 | ||||
| 			return false; | ||||
| 		} | ||||
| 		mCommandQueue.pop(); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void Commands::SetErrorString (const std::string &error_str){ | ||||
| 	mErrorString = error_str; | ||||
| 	LogWarning ("Command Error: %s", error_str.c_str ()); | ||||
| } | ||||
| 
 | ||||
| std::string Commands::GetErrorString (){ | ||||
| 	return mErrorString; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Global functions | ||||
|  */ | ||||
| bool CommandsInitialized () { | ||||
| 	if (!CommandsInstance) { | ||||
| 		LogError ("Commands System not yet initialized!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void AddCommand (const std::string &name, command_cb callback){ | ||||
| 	if (!CommandsInitialized ()) | ||||
| 		return; | ||||
| 
 | ||||
| 	CommandsInstance->AddCommand (name, callback); | ||||
| } | ||||
| 
 | ||||
| bool RunCommand (const std::string &command){ | ||||
| 	if (!CommandsInitialized ()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return CommandsInstance->RunCommand (command); | ||||
| } | ||||
| 
 | ||||
| void QueueCommand (const std::string &command){ | ||||
| 	if (!CommandsInitialized ()) | ||||
| 		return; | ||||
| 
 | ||||
| 	CommandsInstance->QueueCommand (command); | ||||
| } | ||||
| 
 | ||||
| bool CommandQueueExecute (){ | ||||
| 	if (!CommandsInitialized ()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return CommandsInstance->QueueExecute (); | ||||
| } | ||||
| 
 | ||||
| void CommandSetErrorString (const std::string &error_str){ | ||||
| 	if (!CommandsInitialized ()) | ||||
| 		return; | ||||
| 
 | ||||
| 	CommandsInstance->SetErrorString (error_str); | ||||
| } | ||||
| 
 | ||||
| std::string CommandGetErrorString (){ | ||||
| 	if (!CommandsInitialized ()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return CommandsInstance->GetErrorString(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Commands of the Command system | ||||
|  */ | ||||
| bool Cmd_Exec (const std::vector<std::string> args) { | ||||
| 	if (!CommandsInitialized()) | ||||
| 		return false; | ||||
| 
 | ||||
| 	if (args.size() != 1) { | ||||
| 		CommandsInstance->SetErrorString("usage: exec <path_to_file>"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	std::ifstream exec_file; | ||||
| 	exec_file.open(args[0].c_str(), std::ios_base::in); | ||||
| 
 | ||||
| 	if (!exec_file) { | ||||
| 		std::ostringstream error_msg; | ||||
| 		error_msg << "exec failed: could not open file '" | ||||
| 			<< args[0] << "'"; | ||||
| 		CommandsInstance->SetErrorString(error_msg.str()); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	int linecounter = 0; | ||||
| 	while (!exec_file.eof()) { | ||||
| 		std::string line; | ||||
| 		getline (exec_file, line); | ||||
| 		linecounter++; | ||||
| 
 | ||||
| 		trim_command_str (line); | ||||
| 
 | ||||
| 		if (line.size() == 0) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (!CommandsInstance->RunCommand (line)) { | ||||
| 			std::ostringstream error_msg; | ||||
| 			error_msg << "exec failed running command '" << line | ||||
| 				<< "' in file " << args[0] << ":" << linecounter << "."; | ||||
| 			CommandsInstance->SetErrorString (error_msg.str()); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	exec_file.close(); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void Commands::OnRegisterCommands () { | ||||
| 	AddCommand ("exec", Cmd_Exec); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										70
									
								
								engine/Commands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								engine/Commands.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| #ifndef _COMMANDS_H | ||||
| #define _COMMANDS_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Module; | ||||
| 
 | ||||
| /** \brief The callback signature for commands */ | ||||
| typedef bool (*command_cb) (std::vector<std::string>); | ||||
| 
 | ||||
| /** \brief Contains all the facilities to parse/add/execute/... commands
 | ||||
|  * | ||||
|  *	\todo make the command system case insensitive | ||||
|  * | ||||
|  *	This system is mainly used for passing instructions to the Model and | ||||
|  *	modifying it in this way. Commands can be added with a name (string) and a | ||||
|  *	function (callback). It also contains a CommandQueue to faciliate delayed | ||||
|  *	execution of commands and also does the parsing of functions passed to it. | ||||
|  * | ||||
|  *  Functions that should be callable by the Commands module must have the | ||||
|  *  following signature: | ||||
|  *  \code | ||||
|  *  bool MyFunc_cmd (std::vector<std::string> args); | ||||
|  *  \endcode | ||||
|  *	To keep things readable one is advised to add \c _cmd at the end of the | ||||
|  *	function so that it is clear that this function is meant to be called by | ||||
|  *	the Commands module. | ||||
|  * | ||||
|  *	Scope: Globally visible (since commands must be added) | ||||
|  * | ||||
|   */ | ||||
| class Commands : public Module {  | ||||
| 	public: | ||||
| 		/** \brief Adds the function callback as command for the given name*/ | ||||
| 		void AddCommand (const std::string &name, command_cb callback); | ||||
| 		/** \brief Executes the given command immediately */ | ||||
| 		bool RunCommand (const std::string &command); | ||||
| 		/** \brief Adds the given command to the command queue */ | ||||
| 		void QueueCommand (const std::string &command); | ||||
| 		/** \brief Executes the command queue */ | ||||
| 		bool QueueExecute (); | ||||
| 		/** \brief When a command fails it sets the error with this function */ | ||||
| 		void SetErrorString (const std::string &error_str); | ||||
| 		/** \brief Returns the error string */ | ||||
| 		std::string GetErrorString (); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		virtual void OnDestroy (); | ||||
| 		/** \brief Registers commands relevant to the Command system */ | ||||
| 		virtual void OnRegisterCommands ();	 | ||||
| 
 | ||||
| 		/** \brief All registered commands are in this map */ | ||||
| 		std::map<std::string, command_cb> mCommandsCallbacks; | ||||
| 		/** \brief Queue for the commands */ | ||||
| 		std::queue<std::string> mCommandQueue; | ||||
| 		/** \brief Holds the error message of a failed command */ | ||||
| 		std::string mErrorString; | ||||
| 
 | ||||
| 	private: | ||||
| 		std::string GetCommandName (const std::string &command); | ||||
| 		std::vector<std::string> ParseArgs (std::string &argument_str); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| #endif // _COMMANDS_H
 | ||||
							
								
								
									
										24
									
								
								engine/CommandsGlobal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								engine/CommandsGlobal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #ifndef _COMMANDSGLOBAL_H | ||||
| #define _COMMANDSGLOBAL_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| typedef bool (*command_cb) (std::vector<std::string>); | ||||
| 
 | ||||
| /** \brief Adds the function callback as command for the given name*/ | ||||
| void AddCommand (const std::string &name, command_cb callback); | ||||
| /** \brief Executes the given command immediately */ | ||||
| bool RunCommand (const std::string &command); | ||||
| /** \brief Adds the given command to the command queue */ | ||||
| void QueueCommand (const std::string &command); | ||||
| /** \brief Executes the command queue */ | ||||
| bool CommandQueueExecute (); | ||||
| /** \brief When a command fails it sets the error with this function */ | ||||
| void CommandSetErrorString (const std::string &error_str); | ||||
| /** \brief Returns the error string */ | ||||
| std::string CommandGetErrorString (); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* _COMMANDSGLOBAL_H */ | ||||
| 
 | ||||
							
								
								
									
										264
									
								
								engine/ControllerBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								engine/ControllerBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,264 @@ | ||||
| #include "ControllerBase.h" | ||||
| 
 | ||||
| #include "ModelBase.h" | ||||
| #include "ViewBase.h" | ||||
| #include "CommandsGlobal.h" | ||||
| 
 | ||||
| #include "keytable.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| static ControllerBase *ControllerInstance = NULL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Helper functions | ||||
|  */ | ||||
| 
 | ||||
| /** \brief Converts the SDL_BUTTON_* to a value we know */ | ||||
| MouseButton convert_sdl_button (Uint8 button) { | ||||
| 	MouseButton mouse_button; | ||||
| 	switch (button) { | ||||
| 		case SDL_BUTTON_LEFT: | ||||
| 			mouse_button = MouseButtonLeft; | ||||
| 			break; | ||||
| 		case SDL_BUTTON_MIDDLE: | ||||
| 			mouse_button = MouseButtonMiddle; | ||||
| 			break; | ||||
| 		case SDL_BUTTON_RIGHT: | ||||
| 			mouse_button = MouseButtonRight; | ||||
| 			break; | ||||
| 		case SDL_BUTTON_WHEELUP: | ||||
| 			mouse_button = MouseButtonWheelUp; | ||||
| 			break; | ||||
| 		case SDL_BUTTON_WHEELDOWN: | ||||
| 			mouse_button = MouseButtonWheelDown; | ||||
| 			break; | ||||
| 		default: | ||||
| 			mouse_button = MouseButtonUnknown; | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	return mouse_button; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int ControllerBase::OnInit (int argc, char* argv[]) { | ||||
| 	LogDebug ("Controller Init"); | ||||
| 
 | ||||
| 	// clear all bindings
 | ||||
| 	int i; | ||||
| 	for (i = 0; i < BINDING_KEYS_LAST; i++) | ||||
| 		mBindings[i] = ""; | ||||
| 
 | ||||
| 	ControllerInstance = this; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ControllerBase::OnDestroy () { | ||||
| 	ControllerInstance = NULL; | ||||
| 
 | ||||
| 	LogDebug ("Controller Destroy"); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions  | ||||
|  */ | ||||
| bool ControllerBase::BindKey (int key, const char *command) { | ||||
| 	if (key <= 0 || key >= BINDING_KEYS_LAST) { | ||||
| 		LogError ("Could not bind to key with index '%d': invalid index!", key); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	mBindings[key] = command; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void ControllerBase::Process () { | ||||
| 	ProcessEvents (); | ||||
| 
 | ||||
| 	mView->CalcWorldCoordinates (mMouseScreenPosition[0], mMouseScreenPosition[1], | ||||
| 			0., mMouseWorldPosition); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	LogMessage ("Screenpos = %2d,%2d Worldpos = %f,%f,%f", | ||||
| 			mMouseScreenPosition[0], mMouseScreenPosition[1], | ||||
| 			mMouseWorldPosition[0], mMouseWorldPosition[1], mMouseWorldPosition[2]); | ||||
| 	*/ | ||||
| } | ||||
| 
 | ||||
| void ControllerBase::ProcessEvents () { | ||||
| 	SDL_Event event; | ||||
| 
 | ||||
| 	while (SDL_PollEvent(&event)) { | ||||
| 		/* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */ | ||||
| 		switch (event.type) { | ||||
| 		case SDL_KEYDOWN: | ||||
| 			OnKeyDown (event.key.keysym); | ||||
| 			break; | ||||
| 
 | ||||
| 		case SDL_KEYUP: | ||||
| 			OnKeyUp (event.key.keysym); | ||||
| 			break; | ||||
| 
 | ||||
| 		case SDL_MOUSEMOTION: | ||||
| 			OnMouseMotion(event.motion.x, event.motion.y); | ||||
| 			break; | ||||
| 
 | ||||
| 		case SDL_MOUSEBUTTONDOWN: | ||||
| 			OnMouseButtonDown (event.button.button, event.button.x, event.button.y); | ||||
| 			break; | ||||
| 
 | ||||
| 		case SDL_MOUSEBUTTONUP: | ||||
| 			OnMouseButtonUp (event.button.button, event.button.x, event.button.y); | ||||
| 			break; | ||||
| 
 | ||||
| 		case SDL_VIDEORESIZE: | ||||
| 			OnVideoResize (event.resize.w, event.resize.h); | ||||
| 			break; | ||||
| 		 | ||||
| 		case SDL_QUIT: | ||||
| 			EngineSetStatus (EngineStatusStopping); | ||||
| 			break; | ||||
| 
 | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /** \brief Keyboard processing */ | ||||
| bool ControllerBase::OnKeyDown (const SDL_keysym &keysym) { | ||||
| 	if (mView->SendKeyDown (keysym)) | ||||
| 		return true; | ||||
| 
 | ||||
| 	if (mBindings[keysym.sym].size () != 0) { | ||||
| 		QueueCommand (mBindings[keysym.sym]); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /** \brief Keyboard processing */ | ||||
| bool ControllerBase::OnKeyUp (const SDL_keysym &keysym) { | ||||
| 	if (mView->SendKeyUp (keysym)) | ||||
| 		return true; | ||||
| 
 | ||||
| 	if (mBindings[keysym.sym].size () != 0) { | ||||
| 		if (mBindings[keysym.sym][0] == '+') { | ||||
| 			std::string upcommand = mBindings[keysym.sym]; | ||||
| 			upcommand[0] = '-'; | ||||
| 			QueueCommand (upcommand); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /** \brief Mouse processing */ | ||||
| bool ControllerBase::OnMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos) { | ||||
| 	MouseButton mouse_button = convert_sdl_button (button); | ||||
| 
 | ||||
| 	if (mView->SendMouseButtonDown (button, xpos, ypos)) | ||||
| 		return true; | ||||
| 
 | ||||
| 	if (mBindings[mouse_button].size () != 0) { | ||||
| 		QueueCommand (mBindings[mouse_button]); | ||||
| 		return true; | ||||
| 	} | ||||
| 	 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /** \brief Mouse processing */ | ||||
| bool ControllerBase::OnMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos) { | ||||
| 	MouseButton mouse_button = convert_sdl_button (button); | ||||
| 
 | ||||
| 	if (mView->SendMouseButtonUp (button, xpos, ypos)) | ||||
| 		return true; | ||||
| 
 | ||||
| 	if (mBindings[mouse_button].size () != 0) { | ||||
| 		if (mBindings[mouse_button][0] == '+') { | ||||
| 			std::string upcommand = mBindings[mouse_button]; | ||||
| 			upcommand[0] = '-'; | ||||
| 			QueueCommand (upcommand); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /** \brief Mouse processing */ | ||||
| bool ControllerBase::OnMouseMotion (const int xnew, const int ynew) { | ||||
| 	mMouseScreenPosition[0] = xnew; | ||||
| 	mMouseScreenPosition[1] = ynew; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /** \brief Video */ | ||||
| bool ControllerBase::OnVideoResize (int width, int height) { | ||||
| 	mView->Resize (width, height); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| int convert_keystring (const char *key_val) { | ||||
| 	std::string keystr (key_val); | ||||
| 	 | ||||
| 	// convert the keystr to lowercase
 | ||||
| 	for (std::string::iterator iter = keystr.begin(); iter != keystr.end(); iter++) | ||||
| 		(*iter) = tolower(*iter); | ||||
| 
 | ||||
| 	// now we search through the table for he value we were given
 | ||||
| 	int i = 0; | ||||
| 	while (key_table[i].keynum != keytable_last) { | ||||
| 		if (keystr.compare(key_table[i].keystr) == 0) | ||||
| 			return key_table[i].keynum; | ||||
| 
 | ||||
| 		i++; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Commands for the ControllerBase | ||||
|  */ | ||||
| bool Cmd_Bind (const std::vector<std::string> args) { | ||||
| 	if (ControllerInstance == NULL) { | ||||
| 		CommandSetErrorString("Could not bind key: Controller not yet initialized!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (args.size() != 2) { | ||||
| 		CommandSetErrorString("usage: bind <key> <command>"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	int key = convert_keystring (args[0].c_str()); | ||||
| 
 | ||||
| 	if (key == 0) { | ||||
| 		std::ostringstream error_msg; | ||||
| 		error_msg << "bind failed: invalid key '" << args[0] << '"'; | ||||
| 		CommandSetErrorString(error_msg.str()); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ControllerInstance->BindKey (key, args[1].c_str())) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void ControllerBase::OnRegisterCommands () { | ||||
| 	AddCommand ("bind", Cmd_Bind); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										92
									
								
								engine/ControllerBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								engine/ControllerBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| #ifndef _CONTROLLERBASE_H | ||||
| #define _CONTROLLERBASE_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class ModelBase; | ||||
| class Console; | ||||
| class Module; | ||||
| 
 | ||||
| /** \brief Defines the number of keys (keyboard + mous) that we can bind to.
 | ||||
|  *  | ||||
|  * As the keysym enum of SDL has about 320 keys defined and we might have some | ||||
|  * more we set this define to 400 which should suffice. See also the file | ||||
|  * keytable.h | ||||
|  */ | ||||
| #define BINDING_KEYS_LAST 400 | ||||
| 
 | ||||
| /** \brief Converts a string into the corresponding keycode */ | ||||
| int convert_keystring (const char *key_val); | ||||
| 
 | ||||
| /** \brief All input is sent here and distributed from here
 | ||||
|  * | ||||
|  *	Distributes and modifies the Model and indirectly the view by modifying the | ||||
|  *	camera. It also holds the configuration of the keybindings and sends | ||||
|  *	commands to the CommandQueue. | ||||
|  */ | ||||
| 
 | ||||
| class ControllerBase : public Module {  | ||||
| 	public: | ||||
| 		/** \brief Processes all inputs and performs all the controlling for the
 | ||||
| 		 * current frame. */ | ||||
| 		void Process (); | ||||
| 		/** \brief Returns the current mouse position in screen coordinates */ | ||||
| 		void GetMouseScreenPosition (int *pos_out) { | ||||
| 			pos_out[0] = mMouseScreenPosition[0]; | ||||
| 			pos_out[1] = mMouseScreenPosition[1]; | ||||
| 		} | ||||
| 		void GetMouseWorldPosition (float *pos_out) { | ||||
| 			pos_out[0] = mMouseWorldPosition[0]; | ||||
| 			pos_out[1] = mMouseWorldPosition[1]; | ||||
| 			pos_out[2] = mMouseWorldPosition[2]; | ||||
| 		} | ||||
| 		bool BindKey (int key, const char *command); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		virtual void OnDestroy (); | ||||
| 		/** \brief Registering of the commands of the ControllerBase */ | ||||
| 		virtual void OnRegisterCommands (); | ||||
| 
 | ||||
| 		/** \brief Processes all Events reported by SDL_PollEvent */ | ||||
| 		virtual void ProcessEvents (); | ||||
| 
 | ||||
| 		/** \brief Keyboard processing */ | ||||
| 		bool OnKeyDown (const SDL_keysym &keysym); | ||||
| 		/** \brief Keyboard processing */ | ||||
| 		bool OnKeyUp (const SDL_keysym &keysym); | ||||
| 		 | ||||
| 		/** \brief Mouse processing */ | ||||
| 		bool OnMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos); | ||||
| 		/** \brief Mouse processing */ | ||||
| 		bool OnMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos); | ||||
| 		/** \brief Mouse processing */ | ||||
| 		bool OnMouseMotion (const int xnew, const int ynew); | ||||
| 
 | ||||
| 		/** \brief Resizes the size of the View */ | ||||
| 		bool OnVideoResize (int width, int height); | ||||
| 
 | ||||
| 		/** \brief Needs the Model to modify it */ | ||||
| 		ModelBase * mModel; | ||||
| 		/** \brief Input might be sent to the Console, hence it is here */ | ||||
| 		Console * mConsole; | ||||
| 		/** \brief The View which can get modified by Controller */ | ||||
| 		ViewBase *mView; | ||||
| 
 | ||||
| 		/** \brief Stores the current mouse position in screen coordinates */ | ||||
| 		int mMouseScreenPosition[2]; | ||||
| 		/** \brief Stores the current mouse position on the y=0 plane in wolrd * coordinates */ | ||||
| 		float mMouseWorldPosition[3]; | ||||
| 
 | ||||
| 		/** \brief Contains all the bindings for the keyboard */ | ||||
| 		std::string mBindings[BINDING_KEYS_LAST]; | ||||
| 
 | ||||
| 		friend class Engine; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| #endif // _CONTROLLERBASE_H
 | ||||
							
								
								
									
										247
									
								
								engine/DrawingsGL.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								engine/DrawingsGL.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,247 @@ | ||||
| #include <math.h> | ||||
| 
 | ||||
| #include "mathlib.h" | ||||
| #include "DrawingsGL.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| 
 | ||||
| static void CubeVertices () { | ||||
| 	// front
 | ||||
| 	glVertex3f (0.5, -0.5, 0.5); | ||||
| 	glVertex3f (0.5, -0.5, -0.5); | ||||
| 	glVertex3f (0.5, 0.5, -0.5); | ||||
| 	glVertex3f (0.5, 0.5, 0.5); | ||||
| 	// back
 | ||||
| 	glVertex3f (-0.5, 0.5, 0.5); | ||||
| 	glVertex3f (-0.5, 0.5, -0.5); | ||||
| 	glVertex3f (-0.5, -0.5, -0.5); | ||||
| 	glVertex3f (-0.5, -0.5, 0.5); | ||||
| 	// left
 | ||||
| 	glVertex3f (-0.5, -0.5, 0.5); | ||||
| 	glVertex3f (0.5, -0.5, 0.5); | ||||
| 	glVertex3f (0.5, 0.5, 0.5); | ||||
| 	glVertex3f (-0.5, 0.5, 0.5); | ||||
| 	// right
 | ||||
| 	glVertex3f (-0.5, 0.5, -0.5); | ||||
| 	glVertex3f (0.5, 0.5, -0.5); | ||||
| 	glVertex3f (0.5, -0.5, -0.5); | ||||
| 	glVertex3f (-0.5, -0.5, -0.5); | ||||
| 	// bottom
 | ||||
| 	glVertex3f (-0.5, -0.5, -0.5); | ||||
| 	glVertex3f (0.5, -0.5, -0.5); | ||||
| 	glVertex3f (0.5, -0.5, 0.5); | ||||
| 	glVertex3f (-0.5, -0.5, 0.5); | ||||
| 	// top
 | ||||
| 	glVertex3f (-0.5, 0.5, 0.5); | ||||
| 	glVertex3f (0.5, 0.5, 0.5); | ||||
| 	glVertex3f (0.5, 0.5, -0.5); | ||||
| 	glVertex3f (-0.5, 0.5, -0.5); | ||||
| } | ||||
| 
 | ||||
| void DrawWireCube () { | ||||
| 	glBegin (GL_LINE_STRIP); | ||||
| 		CubeVertices (); | ||||
| 	glEnd (); | ||||
| } | ||||
| 
 | ||||
| void DrawSolidCube () { | ||||
| 	glBegin (GL_QUADS); | ||||
| 		CubeVertices (); | ||||
| 	glEnd (); | ||||
| } | ||||
| 
 | ||||
| void DrawCircle () { | ||||
| 	int i, segments; | ||||
| 	segments = 20; | ||||
| 	double x, z, rad, drad; | ||||
| 
 | ||||
| 	drad = (M_PI * 2) / segments; | ||||
| 
 | ||||
| 	// Top
 | ||||
| 	glBegin (GL_TRIANGLE_FAN); | ||||
| 	glVertex3f (0., 0.5, 0.); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		rad = drad * i; | ||||
| 		sincos (rad, &z, &x); | ||||
| 		glVertex3f (x * 0.5, 0., -z * 0.5); | ||||
| 	} | ||||
| 	glEnd (); | ||||
| } | ||||
| 
 | ||||
| void DrawTorus () { | ||||
| 	int i, segments; | ||||
| 	segments = 20; | ||||
| 	double x, z, rad, drad; | ||||
| 
 | ||||
| 	drad = (M_PI * 2) / segments; | ||||
| 
 | ||||
| 	// Top
 | ||||
| 	glBegin (GL_TRIANGLE_FAN); | ||||
| 	glVertex3f (0., 0.5, 0.); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		rad = drad * i; | ||||
| 		sincos (rad, &z, &x); | ||||
| 		glVertex3f (x * 0.5, 0.5, -z * 0.5); | ||||
| 	} | ||||
| 	glEnd (); | ||||
| 
 | ||||
| 	// Bottom
 | ||||
| 	glBegin (GL_TRIANGLE_FAN); | ||||
| 	glVertex3f (0., -0.5, 0.); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		rad = -drad * i; | ||||
| 		sincos (rad, &z, &x); | ||||
| 		glVertex3f (x * 0.5, -0.5, -z * 0.5); | ||||
| 	} | ||||
| 	glEnd (); | ||||
| 
 | ||||
| 	// Sides
 | ||||
| 	glBegin (GL_QUAD_STRIP); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		rad = drad * i; | ||||
| 		sincos (rad, &z, &x); | ||||
| 		glVertex3f (x * 0.5, 0.5, -z * 0.5); | ||||
| 		glVertex3f (x * 0.5, -0.5, -z * 0.5); | ||||
| 	} | ||||
| 	glEnd (); | ||||
| } | ||||
| 
 | ||||
| void DrawPoint (float r, float x, float y, float z) { | ||||
| 	glPointSize (r); | ||||
| 	glBegin (GL_POINTS); | ||||
| 	glVertex3f (x, y, z); | ||||
| 	glEnd (); | ||||
| 	glPointSize (1.); | ||||
| } | ||||
| 
 | ||||
| void DrawAxis() { | ||||
| 	glColor4f(1., 1., 1., 1.); | ||||
| 
 | ||||
| 	glBegin(GL_LINES); | ||||
| 	glVertex3f(0., 0., 0.); | ||||
| 	glVertex3f(1., 0., 0.); | ||||
| 	glVertex3f(0., 0., 0.); | ||||
| 	glVertex3f(0., 1., 0.); | ||||
| 	glVertex3f(0., 0., 0.); | ||||
| 	glVertex3f(0., 0., 1.); | ||||
| 	glEnd(); | ||||
| 
 | ||||
| 	// X
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef(1., 0., 0.); | ||||
| 	glColor3f(1., 0., 0.); | ||||
| 	glScalef(0.2, 0.1, 0.1); | ||||
| 	DrawCone(10); | ||||
| 	glTranslatef(0.4, 0., 0.); | ||||
| 	//		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'x');
 | ||||
| 	glPopMatrix(); | ||||
| 
 | ||||
| 	// Y
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef(0., 1., 0.); | ||||
| 	glRotatef(90, 0., 0., 1.); | ||||
| 	glColor3f(0., 1., 0.); | ||||
| 	glScalef(0.2, 0.1, 0.1); | ||||
| 	DrawCone(10); | ||||
| 	glTranslatef(0.4, 0., 0.); | ||||
| 	//		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'y');
 | ||||
| 	glPopMatrix(); | ||||
| 
 | ||||
| 	// Z
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef(0., 0., 1.); | ||||
| 	glRotatef(90, 0., -1., 0.); | ||||
| 	glColor3f(0., 0., 1.); | ||||
| 	glScalef(0.2, 0.1, 0.1); | ||||
| 	DrawCone(10); | ||||
| 	glPopMatrix(); | ||||
| } | ||||
| 
 | ||||
| void DrawDisc(float radius, int segments) { | ||||
| 	int i; | ||||
| 	float radiant; | ||||
| 	glBegin(GL_TRIANGLE_FAN); | ||||
| 	glVertex3f(0., 0., 0.); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		radiant = (float) i * ((2 * M_PI) / (float) segments); | ||||
| 		glVertex3f(radius * cos(radiant), 0., radius * sin(radiant)); | ||||
| 	} | ||||
| 	glEnd(); | ||||
| } | ||||
| 
 | ||||
| void DrawCircle(float radius, int segments) { | ||||
| 	int i; | ||||
| 	float radiant; | ||||
| 	glBegin(GL_LINE_STRIP); | ||||
| 	glVertex3f(0., 0., 0.); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		radiant = (float) i * ((2 * M_PI) / (float) segments); | ||||
| 		glVertex3f(radius * cos(radiant), 0., radius * sin(radiant)); | ||||
| 	} | ||||
| 	glEnd(); | ||||
| } | ||||
| 
 | ||||
| void DrawCone(int segments) { | ||||
| 	int i; | ||||
| 	float radiant; | ||||
| 
 | ||||
| 	glBegin(GL_TRIANGLE_FAN); | ||||
| 	glVertex3f(1., 0., 0.); | ||||
| 	for (i = 0; i <= segments; i++) { | ||||
| 		radiant = (float) (i * (2. * M_PI) / (float) segments); | ||||
| 
 | ||||
| 		glVertex3f(0., cos(radiant), sin(radiant)); | ||||
| 	} | ||||
| 
 | ||||
| 	glEnd(); | ||||
| } | ||||
| 
 | ||||
| void DrawVector(vector3d start, vector3d end) { | ||||
| 	vector3d direction (end - start); | ||||
| 
 | ||||
| 	glColor3f(1., 1., 1.); | ||||
|     glLineWidth(2.); | ||||
|     glBegin(GL_LINES); | ||||
|     glVertex3f(start[0], start[1], start[2]); | ||||
|     glVertex3f(end[0], end[1], end[2]); | ||||
|   glEnd(); | ||||
|   glLineWidth(1.); | ||||
| 
 | ||||
| 	vector3d right; | ||||
| 	vector3d up; | ||||
| 	vector3d direction_norm = direction / direction.length(); | ||||
| 	float cone_radius = 0.15; | ||||
| 	vector3d conebottom = end - direction_norm * 0.3; | ||||
| 
 | ||||
| 	// Draw the tip
 | ||||
| 	if (fabs(direction[0]) > fabs(direction[1]) && fabs(direction[2]) > fabs(direction[1])) { | ||||
| 		up.setValues (0., 1., 0.); | ||||
| 		vector3d right = direction.cross (up); | ||||
| 		right = right / right.length(); | ||||
| 
 | ||||
| 		int i; | ||||
| 		int segments = 20.; | ||||
| 		float rad_delta = 2. * M_PI / (float) segments; | ||||
| 		double s,c; | ||||
| 
 | ||||
| 		glColor3f(0.2, 0.2, 0.5); | ||||
| 		glPointSize (10.); | ||||
| 		glBegin (GL_TRIANGLE_FAN); | ||||
| 		glVertex3f (end[0], end[1], end[2]); | ||||
| 
 | ||||
| 		for (i = 0; i <= segments; i ++) { | ||||
| 			sincos (i * rad_delta, &s, &c); | ||||
| 			glVertex3f (conebottom[0] + right[0] * cone_radius * c, conebottom[1] + s * cone_radius, conebottom[2] + right[2] * cone_radius * c); | ||||
| 		} | ||||
| 
 | ||||
| 		glEnd (); | ||||
| 		glBegin (GL_TRIANGLE_FAN); | ||||
| 		glVertex3f (conebottom[0], conebottom[1], conebottom[2]); | ||||
| 		for (i = 0; i <= segments; i ++) { | ||||
| 			sincos (i * rad_delta, &s, &c); | ||||
| 			glVertex3f (conebottom[0] + right[0] * cone_radius * c, conebottom[1] + s * cone_radius, conebottom[2] + right[2] * cone_radius * c); | ||||
| 		} | ||||
| 
 | ||||
| 		glEnd (); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										21
									
								
								engine/DrawingsGL.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								engine/DrawingsGL.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| #ifndef _DRAWINGSGL_H | ||||
| #define _DRAWINGSGL_H | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	#include <windows.h> | ||||
| #endif | ||||
| 
 | ||||
| struct vector3d; | ||||
| 
 | ||||
| void DrawWireCube (); | ||||
| void DrawSolidCube (); | ||||
| void DrawCircle (); | ||||
| void DrawTorus (); | ||||
| void DrawPoint (float r, float x, float y, float z); | ||||
| void DrawAxis(); | ||||
| void DrawDisc(float radius, int segments); | ||||
| void DrawCircle(float radius, int segments); | ||||
| void DrawCone(int segments); | ||||
| void DrawVector(vector3d start, vector3d end); | ||||
| 
 | ||||
| #endif /* _DRAWINGSGL_H */ | ||||
							
								
								
									
										353
									
								
								engine/Engine.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								engine/Engine.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,353 @@ | ||||
| #include "Engine.h" | ||||
| #include "Logging.h" | ||||
| #include "Variables.h" | ||||
| #include "Commands.h" | ||||
| 
 | ||||
| #include "PhysicsBase.h" | ||||
| #include "CameraBase.h" | ||||
| 
 | ||||
| #include "ViewBase.h" | ||||
| #include "ModelBase.h" | ||||
| #include "ControllerBase.h" | ||||
| 
 | ||||
| #include "EntityFactoryBase.h" | ||||
| #include "EventsBase.h" | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <cstdio> | ||||
| #include <cstdarg> | ||||
| #include <cstdlib> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| int vasprintf (char **result, const char *format, va_list *string) { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /* Globaly visible classes */ | ||||
| Engine* EngineInstance = NULL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int Engine::OnInit (int argc, char* argv[]) { | ||||
| 	EngineInstance = this; | ||||
| 	mStatus = EngineStatusUndefined; | ||||
| 
 | ||||
| 	/* Initialization of the base modules */ | ||||
| 	if (mLogging == NULL) | ||||
| 		mLogging = new Logging (); | ||||
| 
 | ||||
| 	if (! mLogging ) { | ||||
| 		SetError ("Could not allocate memory for Logging!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 	mLogging->Init (argc, argv); | ||||
| 	SetStatus (EngineStatusInitializing); | ||||
| 
 | ||||
| 	if (mEventManager == NULL) | ||||
| 		mEventManager = new EventManager(); | ||||
| 
 | ||||
| 	mEventManager->Init (argc, argv); | ||||
| 
 | ||||
| 	if (mVariables == NULL) | ||||
| 		mVariables = new Variables (); | ||||
| 	if (! mVariables ) { | ||||
| 		SetError ("Could not allocate memory for Variables!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 	mVariables->Init (argc, argv); | ||||
| 
 | ||||
| 	if (mCommands == NULL) | ||||
| 		mCommands = new Commands (); | ||||
| 	if (! mCommands ) { | ||||
| 		SetError ("Could not allocate memory for Commands!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 	mCommands->Init (argc, argv); | ||||
| 
 | ||||
| 	// Initialize the SDL
 | ||||
| 	LogDebug ("Initializing SDL"); | ||||
| 	if ( SDL_Init ( SDL_INIT_VIDEO ) < 0) { | ||||
| 		LogError ("Error initializing SDL: %s", SDL_GetError ()); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* Model */ | ||||
| 	if (mModel == NULL) | ||||
| 		mModel = new ModelBase (); | ||||
| 
 | ||||
| 	if (! mModel ) { | ||||
| 		SetError ("Could not allocate memory for Model!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 	 | ||||
| 	/* Initialization of the modules for the model */ | ||||
| 	if (mEntityFactory == NULL) | ||||
| 		mEntityFactory = new EntityFactoryBase; | ||||
| 
 | ||||
| 	mModel->mEntityFactory = mEntityFactory; | ||||
| 
 | ||||
| 
 | ||||
| 	/* Physics */ | ||||
| 	if (mPhysics == NULL) { | ||||
| 		mPhysics = new PhysicsBase (); | ||||
| 
 | ||||
| 		if (! mPhysics ) { | ||||
| 			SetError ("Could not allocate memory for Physics!"); | ||||
| 			exit (-1); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	mModel->mPhysics = mPhysics; | ||||
| 	 | ||||
| 	mEntityFactory->Init (argc, argv); | ||||
| 		mModel->mPhysics->Init (argc, argv); | ||||
| 	mModel->Init (argc, argv); | ||||
| 
 | ||||
| 	/* View */ | ||||
| 	if (mView == NULL) | ||||
| 		mView = new ViewBase (); | ||||
| 
 | ||||
| 	if (! mView ) { | ||||
| 		SetError ("Could not allocate memory for View!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	mView->mCamera = new CameraBase (); | ||||
| 	mView->mCamera->Init (argc, argv); | ||||
| 
 | ||||
| 	mView->mModel = mModel; | ||||
| 	mView->Init (argc, argv); | ||||
| 
 | ||||
| 	/* Controller */ | ||||
| 	if (mController == NULL) | ||||
| 		mController = new ControllerBase (); | ||||
| 
 | ||||
| 	if (! mController ) { | ||||
| 		SetError ("Could not allocate memory for Controller!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	mController->mModel = mModel; | ||||
| 	mController->mView = mView; | ||||
| 
 | ||||
| 	mController->Init (argc, argv); | ||||
| 
 | ||||
| 	/* Now register the commands */ | ||||
| 	mLogging->RegisterCommands (); | ||||
| 	mVariables->RegisterCommands (); | ||||
| 	mCommands->RegisterCommands (); | ||||
| 	 | ||||
| 	mModel->mPhysics->RegisterCommands (); | ||||
| 	mModel->RegisterCommands (); | ||||
| 
 | ||||
| 	mView->mCamera->RegisterCommands (); | ||||
| 	mView->RegisterCommands (); | ||||
| 	 | ||||
| 	mController->RegisterCommands (); | ||||
| 
 | ||||
| 	RegisterCommands (); | ||||
| 	 | ||||
| 	/* Now we are done */ | ||||
| 	SetStatus (EngineStatusInitialized); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void Engine::OnDestroy () { | ||||
| 	SetStatus (EngineStatusDestroying); | ||||
| 
 | ||||
| 	// Quit the SDL
 | ||||
| 	SDL_Quit (); | ||||
| 
 | ||||
| 	if (mController) { | ||||
| 		mController->Destroy (); | ||||
| 		delete mController; | ||||
| 		mController = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mView) { | ||||
| 		if (mView->mCamera ) { | ||||
| 			mView->mCamera->Destroy (); | ||||
| 			delete mView->mCamera; | ||||
| 		} | ||||
| 
 | ||||
| 		mView->Destroy (); | ||||
| 		delete mView; | ||||
| 		mView = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mModel) { | ||||
| 		mModel->Destroy (); | ||||
| 
 | ||||
| 		if (mModel->mPhysics ) { | ||||
| 			mModel->mPhysics->Destroy (); | ||||
| 			delete mModel->mPhysics; | ||||
| 		} | ||||
| 
 | ||||
| 	delete mModel; | ||||
| 		mModel = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mCommands) { | ||||
| 		mCommands->Destroy (); | ||||
| 		delete mCommands; | ||||
| 		mCommands = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mVariables) { | ||||
| 		mVariables->Destroy (); | ||||
| 		delete mVariables; | ||||
| 		mVariables = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	SetStatus (EngineStatusStopped); | ||||
| 
 | ||||
| 	if (mEventManager) { | ||||
| 		mEventManager->Destroy(); | ||||
| 		delete mEventManager; | ||||
| 		mEventManager = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mLogging) { | ||||
| 		mLogging->Destroy (); | ||||
| 		delete mLogging; | ||||
| 		mLogging = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	mStatus = EngineStatusUndefined; | ||||
| 	EngineInstance = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| void Engine::SetStatus (EngineStatus new_status) { | ||||
| 	LogDebug ("EngineStatus Change: '%d' -> '%d'", mStatus, new_status); | ||||
| 	mStatus = new_status; | ||||
| } | ||||
| 
 | ||||
| EngineStatus Engine::GetStatus () { | ||||
| 	return mStatus; | ||||
| } | ||||
| 
 | ||||
| void Engine::OnMainLoop () { | ||||
| 	SetStatus (EngineStatusRunning); | ||||
| 
 | ||||
| 	while (mStatus == EngineStatusRunning) { | ||||
| 		mController->Process (); | ||||
| 		mCommands->QueueExecute (); | ||||
| 		mEventManager->Process(); | ||||
| 		mModel->UpdateTimer (); | ||||
| 		mModel->Process (); | ||||
| 		mView->Draw (); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Engine::SetError (const char* str, ...) { | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	mErrorString = msg; | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| } | ||||
| 
 | ||||
| const char* Engine::GetError () { | ||||
| 	return mErrorString.c_str(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Global functions | ||||
|  */ | ||||
| void EngineSetError (const char* str, ...) { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	EngineInstance->SetError (msg); | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| } | ||||
| 
 | ||||
| const char* EngineGetError () { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return EngineInstance->GetError (); | ||||
| } | ||||
| 
 | ||||
| void EngineSetStatus (const EngineStatus status) { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	 | ||||
| 	EngineInstance->SetStatus (status); | ||||
| } | ||||
| 
 | ||||
| EngineStatus EngineGetStatus () { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	 | ||||
| 	return EngineInstance->GetStatus (); | ||||
| } | ||||
| 
 | ||||
| ModelBase* EngineGetModel () { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	 | ||||
| 	return EngineInstance->GetModel(); | ||||
| } | ||||
| 
 | ||||
| ViewBase* EngineGetView () { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return EngineInstance->GetView(); | ||||
| } | ||||
| 
 | ||||
| ControllerBase* EngineGetController () { | ||||
| 	if (EngineInstance == NULL) { | ||||
| 		std::cerr << "Error: Engine Instance not yet initialized!" << std::endl; | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return EngineInstance->GetController(); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										167
									
								
								engine/Engine.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								engine/Engine.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,167 @@ | ||||
| #ifndef _ENGINE_H | ||||
| #define _ENGINE_H | ||||
| 
 | ||||
| #include <globals.h> | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <map> | ||||
| #include <queue> | ||||
| #include <bitset> | ||||
| 
 | ||||
| #include "Module.h" | ||||
| 
 | ||||
| // Some ugly #defines
 | ||||
| 
 | ||||
| /** \brief Defines the number of keys that can be defined for an EntityController
 | ||||
|  * | ||||
|  * The current state of the controls for an entity is stored in an std::bitset | ||||
|  * and each bit tells us whether the key is pressed or not. Unfortunately we | ||||
|  * have to know the number of bits that are to be reserved in advance so this | ||||
|  * is hard coded into the library for now. | ||||
|  */ | ||||
| #define ENTITY_CONTROLLER_MAX_KEY_STATES 64 | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class ModelBase; | ||||
| class ViewBase; | ||||
| class ControllerBase; | ||||
| class PhysicsBase; | ||||
| class EntityFactoryBase; | ||||
| class EventManager; | ||||
| 
 | ||||
| class Logging; | ||||
| class Commands; | ||||
| class Variables; | ||||
| class Variable; | ||||
| 
 | ||||
| enum EngineStatus { | ||||
| 	EngineStatusUndefined = 0, | ||||
| 	EngineStatusInitializing, | ||||
| 	EngineStatusInitialized, | ||||
| 	EngineStatusRunning, | ||||
| 	EngineStatusStopping, | ||||
| 	EngineStatusStopped, | ||||
| 	EngineStatusDestroying | ||||
| }; | ||||
| 
 | ||||
| /** \brief The outermost class which contains just everything!
 | ||||
|  * | ||||
|  * Engine::Engine takes care of initializing, running and destroying the whole | ||||
|  * Engine. | ||||
|  * | ||||
|  * When Initialize called, the submodules are created by Engine and | ||||
|  * initializes them. There are two initialization phases: | ||||
|  * - Basemodules initialization: | ||||
|  *   The first phase creates the base modules such as Engine::Logging, | ||||
|  *   Engine::Variables and Engine::Commands and calls Initialize () on them. | ||||
|  * - ModelViewController initialization:   | ||||
|  *   In the second phase at first the Submodules for each Engine::ModelBase, Engine::ViewBase and | ||||
|  *   Engine::ControllerBase are allocated an initialized. Then the Engine::ModelBase, | ||||
|  *   Engine::View and Engine::ControllerBase Modules are initialized. | ||||
|  */ | ||||
| class Engine : public Module { | ||||
| 	public: | ||||
| 		Engine () { | ||||
| 			mModel = NULL; | ||||
| 			mView = NULL; | ||||
| 			mController = NULL; | ||||
| 			mLogging = NULL; | ||||
| 			mCommands = NULL; | ||||
| 			mVariables = NULL; | ||||
| 			mEntityFactory = NULL; | ||||
| 			mEventManager = NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		virtual void MainLoop () { | ||||
| 			OnMainLoop (); | ||||
| 		} | ||||
| 
 | ||||
| 		void SetModel (ModelBase *model) { mModel = model; }; | ||||
| 		ModelBase* GetModel () { return mModel; }; | ||||
| 		void SetView (ViewBase *view) { mView = view; }; | ||||
| 		ViewBase* GetView () { return mView; }; | ||||
| 		void SetPhysics (PhysicsBase *physics) { mPhysics = physics; }; | ||||
| 		PhysicsBase* GetPhysics () { return mPhysics; }; | ||||
| 		void SetEntityFactory (EntityFactoryBase *entityfactory) { mEntityFactory = entityfactory; }; | ||||
| 
 | ||||
| 		void SetController (ControllerBase *controller) { mController = controller; }; | ||||
| 		ControllerBase* GetController () { return mController; }; | ||||
| 		void SetLogging (Logging *logging) { mLogging = logging; }; | ||||
| 		void SetCommands (Commands *commands) { mCommands = commands; }; | ||||
| 		void SetVariables (Variables *variables) { mVariables = variables; }; | ||||
| 
 | ||||
| 		void SetError (const char* str, ...); | ||||
| 		const char* GetError (); | ||||
| 		void SetStatus (const EngineStatus new_status); | ||||
| 		EngineStatus GetStatus (); | ||||
| 
 | ||||
| 	private: | ||||
| 		// Engine must not be created with the standard constructor! 
 | ||||
| 		// It must be ensured, that the correct EntityFactory is used!
 | ||||
| 	protected: | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		virtual void OnDestroy (); | ||||
| 		virtual void OnRegisterCommands (); | ||||
| 
 | ||||
| 		void OnMainLoop (); | ||||
| 
 | ||||
| 		ModelBase *mModel; | ||||
| 		ViewBase *mView; | ||||
| 		ControllerBase *mController; | ||||
| 		PhysicsBase *mPhysics; | ||||
| 		EntityFactoryBase *mEntityFactory; | ||||
| 		EventManager *mEventManager; | ||||
| 
 | ||||
| 		Logging *mLogging; | ||||
| 		Commands *mCommands; | ||||
| 		Variables *mVariables; | ||||
| 
 | ||||
| 		std::string mErrorString; | ||||
| 		EngineStatus mStatus; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Global visible functions and classes | ||||
|  */ | ||||
| 
 | ||||
| namespace Engine { | ||||
| /* Globaly visible classes */ | ||||
| extern Engine* EngineInstance; | ||||
| 
 | ||||
| /** \brief Sets the Engine::mErrorString to the given message */ | ||||
| void EngineSetError (const char* str, ...); | ||||
| /** \brief Returns Engine::mErrorString */ | ||||
| const char* EngineGetError (); | ||||
| 
 | ||||
| /** \brief Sets the current state of the Engine */ | ||||
| void EngineSetStatus (const EngineStatus status); | ||||
| /** \brief Returns the current state of the Engine */ | ||||
| EngineStatus EngineGetStatus (); | ||||
| 
 | ||||
| /** \brief Global access functions for the Model */ | ||||
| ModelBase* EngineGetModel (); | ||||
| /** \brief Global access functions for the View */ | ||||
| ViewBase* EngineGetView (); | ||||
| /** \brief Global access functions for the Controller */ | ||||
| ControllerBase* EngineGetController (); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /* Include the globally visible declarations of the other modules */ | ||||
| #include "LoggingGlobal.h" | ||||
| #include "VariablesGlobal.h" | ||||
| #include "CommandsGlobal.h" | ||||
| #include "ModelBaseGlobal.h" | ||||
| #include "ViewBaseGlobal.h" | ||||
| #include "EventsBaseGlobal.h" | ||||
| 
 | ||||
| #endif // _ENGINE_H
 | ||||
							
								
								
									
										15
									
								
								engine/EngineCommands.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								engine/EngineCommands.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| bool Cmd_EngineQuit (std::vector<std::string> args) { | ||||
| 	EngineSetStatus (EngineStatusStopping); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void Engine::OnRegisterCommands () { | ||||
| 	AddCommand ("quit", Cmd_EngineQuit); | ||||
| } | ||||
| 		 | ||||
| } | ||||
							
								
								
									
										45
									
								
								engine/EntityBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								engine/EntityBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| bool EntityControllerState::GetKey (int state) { | ||||
| 	assert (state < ENTITY_CONTROLLER_MAX_KEY_STATES && state >= 0); | ||||
| 
 | ||||
| 	return mKeyState.test (state); | ||||
| } | ||||
| 
 | ||||
| void EntityControllerState::SetKey (int state) { | ||||
| 	assert (state < ENTITY_CONTROLLER_MAX_KEY_STATES && state >= 0); | ||||
| 	 | ||||
| 	LogDebug ("Setting Entity Key State %d", state); | ||||
| 	mKeyState.set (state); | ||||
| } | ||||
| 
 | ||||
| void EntityControllerState::UnsetKey (int state) { | ||||
| 	assert (state < ENTITY_CONTROLLER_MAX_KEY_STATES && state >= 0); | ||||
| 	 | ||||
| 	LogDebug ("Unsetting Entity Key State %d", state); | ||||
| 	mKeyState.reset (state); | ||||
| } | ||||
| 
 | ||||
| void EntityBase::SetControllerKeyState (int state) { | ||||
| 	if (!mControllerState) { | ||||
| 		LogError ("Error when trying to send a KeyState to an Entity that has no EntityControllerState!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	mControllerState->SetKey (state); | ||||
| } | ||||
| 
 | ||||
| void EntityBase::UnsetControllerKeyState (int state) { | ||||
| 	if (!mControllerState) { | ||||
| 		LogError ("Error when trying to send a KeyState to an Entity that has no EntityControllerState!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	mControllerState->UnsetKey (state); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										154
									
								
								engine/EntityBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								engine/EntityBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| #ifndef _ENTITYBASE_H | ||||
| #define _ENTITYBASE_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| #include "mathlib.h" | ||||
| 
 | ||||
| #include "EntityBaseTypes.h" | ||||
| 
 | ||||
| namespace coll2d { | ||||
| 	class Shape; | ||||
| } | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Contains all the information for the physical simulation of the
 | ||||
|  * Entity | ||||
|  * | ||||
|  * Every Engine::Entity that should be simulated in the Engine::Physics module | ||||
|  * must have a Engine::EntityPhysicState counterpart. It represents the state | ||||
|  * of the Entity in the physical world of the engine. | ||||
|  * | ||||
|  * The Copy-Constructor and Assignment Operator is defined in EntityPhysics.cc | ||||
|  * as they require a call to coll2d::Shape::getCopy() which again requires the | ||||
|  * inclusion of coll2d.h which should stay out of Entity.h for faster | ||||
|  * compilation. | ||||
|  */ | ||||
| struct EntityPhysicState { | ||||
| 	/** \brief Standard constructor */ | ||||
| 	EntityPhysicState (): | ||||
| 		mId (0), | ||||
| 		mBaseType (EntityBaseTypeNone), | ||||
| 		mPosition (0., 0., 0.), | ||||
| 		mOrientation (0., 0., 0.), | ||||
| 		mVelocity (0., 0., 0.), | ||||
| 		mAngleVelocity (0.), | ||||
| 		mRadius (0.), | ||||
| 		mShape (NULL), | ||||
| 		mStatic (false), | ||||
| 		mAlive (true), | ||||
| 		mContactNormals() {}; | ||||
| 
 | ||||
| 	virtual ~EntityPhysicState() {}; | ||||
| 
 | ||||
| 	/** \brief Copy constructor */ | ||||
| 	EntityPhysicState (const EntityPhysicState& state); | ||||
| 
 | ||||
| 	/** \brief Assignment operator */ | ||||
| 	EntityPhysicState& operator= (const EntityPhysicState& state); | ||||
| 
 | ||||
| 	unsigned int mId; | ||||
| 	/** \brief The type from the game's perspective */ | ||||
| 	int mType; | ||||
| 	/** \brief The type from the engine's perspective */ | ||||
| 	EntityBaseType mBaseType; | ||||
| 
 | ||||
| 	vector3d mPosition; | ||||
| 	vector3d mOrientation; | ||||
| 	vector3d mVelocity; | ||||
| 	float	mAngleVelocity; | ||||
| 	float mRadius; | ||||
| 
 | ||||
| 	coll2d::Shape* mShape; | ||||
| 	bool mStatic; | ||||
| 
 | ||||
| 	/** \brief If false, the entity will be removed at the end of the frame. */ | ||||
| 	bool mAlive; | ||||
| 
 | ||||
| 	vector3d &GetPosition (); | ||||
| 	vector3d &GetVelocity (); | ||||
| 	vector3d &GetOrientation (); | ||||
| 	float &GetAngleVelocity (); | ||||
| 
 | ||||
| 	void SetPosition (const vector3d &position); | ||||
| 	void SetVelocity (const vector3d &velocity); | ||||
| 	void SetOrientation (const vector3d &orientation); | ||||
| 	void SetAngleVelocity (const float &angle_velocity); | ||||
| 
 | ||||
| 	/** \brief Transforms the given vector in local space to world coordinates */ | ||||
| 	void Globalize (vector3d &vec); | ||||
| 	/** \brief Transforms the given vector from world coordinates to local
 | ||||
| 	 * coordinates */ | ||||
| 	void Localize (vector3d &vec); | ||||
| 	/** \brief Performs only the rotational part of Globalize() */ | ||||
| 	void GlobalizeRotation (vector3d &vec); | ||||
| 	/** \brief Performs only the rotational part of Localize() */ | ||||
| 	void LocalizeRotation (vector3d &vec); | ||||
| 
 | ||||
| 	/** \brief Updates the shape for collision detection */ | ||||
| 	void UpdateShape (); | ||||
| 
 | ||||
| 	/** \brief Contains all the normal vectors of the planes with which we are in contact. */ | ||||
| 	std::map<unsigned int, vector3d> mContactNormals; | ||||
| }; | ||||
| 
 | ||||
| /** \brief Represents the current state of the Entity controller 
 | ||||
|  * | ||||
|  * This struct stores the current state for all EntityControllerKeyStates | ||||
|  * (e.g. whether the keys are currently pressed or not). | ||||
|  * | ||||
|  * \todo [Low] The current design is very unflexible. Is there a better way? | ||||
|  */ | ||||
| struct EntityControllerState { | ||||
| 	std::bitset<ENTITY_CONTROLLER_MAX_KEY_STATES> mKeyState; | ||||
| 
 | ||||
| 	bool GetKey (int state); | ||||
| 	void SetKey (int state); | ||||
| 	void UnsetKey (int state); | ||||
| }; | ||||
| 
 | ||||
| /** \brief Represents the base of everything that exists in the engine
 | ||||
|  * | ||||
|  * An Engine::Entity has different representations in the different | ||||
|  * submodules. Engine::EntityPhysicState stores the physical representation of | ||||
|  * the entity like its position, velocity, orientation, and shape. | ||||
|  * Engine::EntityVisualState is used for drawing an Entity by Engine::View. | ||||
|  */ | ||||
| struct EntityBase { | ||||
| 	unsigned int mId; | ||||
| 	/** \brief The type from the game's perspective */ | ||||
| 	int mType; | ||||
| 	/** \brief The type from the engine's perspective */ | ||||
| 	EntityBaseType mBaseType; | ||||
| 
 | ||||
| 	EntityPhysicState *mPhysicState; | ||||
| 	EntityControllerState *mControllerState; | ||||
| 
 | ||||
| 	/** \brief Applies the state of the EntityControllerState to the EntityPhysicState etc. */ | ||||
| 	virtual void Update (float delta_sec) {}; | ||||
| 
 | ||||
| 	/** \brief Adds the given state to the current movement state of the Entity */ | ||||
| 	virtual void SetControllerKeyState (int state); | ||||
| 	/** \brief Removes the given state to the current movement state of the Entity */ | ||||
| 	virtual void UnsetControllerKeyState (int state); | ||||
| 
 | ||||
| 	/** \brief Helper function to set the id to all substates */ | ||||
| 	void SetId (unsigned int id) { | ||||
| 		mId = id; | ||||
| 
 | ||||
| 		if (mPhysicState) | ||||
| 			mPhysicState->mId = id; | ||||
| 	} | ||||
| 
 | ||||
| 	/** Executes game logic for the collision event
 | ||||
| 	 * \returns true  if it was able to react for this type of entity, false | ||||
| 	 *          false otherwise | ||||
| 	 */ | ||||
| 	virtual bool CollisionEvent (EntityBase* entity_state) { | ||||
| 		return false; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _ENTITYBASE_H
 | ||||
							
								
								
									
										59
									
								
								engine/EntityBaseTypes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								engine/EntityBaseTypes.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| #ifndef _ENTITYBASETYPES_H | ||||
| #define _ENTITYBASETYPES_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| struct EntityBase; | ||||
| struct EntityPhysicState; | ||||
| struct EntityControllerState; | ||||
| 
 | ||||
| /** \brief Represents the different types of an entity from the Engines' perspective
 | ||||
|  * | ||||
|  * The different EntityBaseTypes define their basic behaviour when it comes to | ||||
|  * events such as collisions between two Entities. | ||||
|  * | ||||
|  * Here is an overview how collisions are handled: | ||||
|  *  | ||||
|  * <table> | ||||
|  * <tr> | ||||
|  *   <td></td> | ||||
|  *   <td>EntityBaseTypeParticle</td> | ||||
|  *   <td>EntityBaseTypeBlock</td> | ||||
|  *   <td>EntityBaseTypeActor</td> | ||||
|  * </tr> | ||||
|  * <tr> | ||||
|  *   <td>EntityBaseTypeParticle</td> | ||||
|  *   <td>-</td> | ||||
|  *   <td>C</td> | ||||
|  *   <td>C</td> | ||||
|  * </tr> | ||||
|  * <tr> | ||||
|  *   <td>EntityBaseTypeBlock</td> | ||||
|  *   <td>C</td> | ||||
|  *   <td>C</td> | ||||
|  *   <td>C</td> | ||||
|  * </tr> | ||||
|  * <tr> | ||||
|  *   <td>EntityBaseTypeActor</td> | ||||
|  *   <td>C</td> | ||||
|  *   <td>C</td> | ||||
|  *   <td>C</td> | ||||
|  * </tr> | ||||
|  * </table> | ||||
|  * | ||||
|  * A 'C' means that Engine::Physics::CheckPossibleCollisionPair() will return | ||||
|  * true (this results that the two types cannot penetrate each other). | ||||
|  */ | ||||
| enum EntityBaseType { | ||||
| 	EntityBaseTypeNone = 0, /**< is the default type and does not collide with anything */ | ||||
| 	EntityBaseTypeBlock,    /**< represents walls etc. that block Particles, Actors and other Blocks */ | ||||
| 	EntityBaseTypeParticle, /**< is used for projectiles or Entities that just move
 | ||||
| 														but are "dumb" apart from that */ | ||||
| 	EntityBaseTypeActor,    /**< is the type for objects that interact with each other */ | ||||
| 	EntityBaseTypeLast      /**< marks the maximum number of EntityBaseType */ | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _ENTITYBASETYPES_H
 | ||||
							
								
								
									
										117
									
								
								engine/EntityFactoryBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								engine/EntityFactoryBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "EntityFactoryBase.h" | ||||
| 
 | ||||
| #include "EntityBase.h" | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| int EntityFactoryBase::OnInit (int argc, char* argv[]) { | ||||
| 	LogMessage ("Initializing EntityFactory"); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| EntityPhysicState* EntityFactoryBase::CreateEntityPhysicState (int type) { | ||||
| 	// In this simple factory the type is simply seen as the EntityBaseType.
 | ||||
| 	// However to prevent errors we do a simple check vor validity.
 | ||||
| 	if (type < 0 || type >> EntityBaseTypeLast ) { | ||||
| 		LogError ("Cannot create Entity with type %d: invalid type!", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	EntityBaseType base_type = (EntityBaseType) type; | ||||
| 
 | ||||
| 	// Create the Entity
 | ||||
| 	EntityPhysicState* entity_physics = new EntityPhysicState (); | ||||
| 	if (!entity_physics) { | ||||
| 		LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	// default values for all entities
 | ||||
| 	entity_physics->mBaseType = base_type; | ||||
| 
 | ||||
|   // specific values for each Entity base_type
 | ||||
| 	if (base_type == EntityBaseTypeNone) { | ||||
| 		entity_physics->mShape = new coll2d::Sphere (0.01); | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else if (base_type == EntityBaseTypeActor) { | ||||
| 		entity_physics->mShape = new coll2d::Sphere (0.4); | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else if (base_type == EntityBaseTypeBlock) { | ||||
| 		entity_physics->mShape = new coll2d::Polygon (4); | ||||
| 		assert (entity_physics->mShape); | ||||
| 
 | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (0, vector3d (-0.5, 0., 0.5)); | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (1, vector3d (0.5, 0., 0.5)); | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (2, vector3d (0.5, 0., -0.5)); | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (3, vector3d (-0.5, 0., -0.5)); | ||||
| 	} else if (base_type == EntityBaseTypeParticle) { | ||||
| 		entity_physics->mShape = new coll2d::Sphere (0.05); | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else { | ||||
| 		LogError ("No EntityPhysicState defined for Entity base_type '%d'", base_type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return entity_physics; | ||||
| } | ||||
| 
 | ||||
| EntityControllerState* EntityFactoryBase::CreateEntityControllerState (int type) { | ||||
| 	// In this simple factory the type is simply seen as the EntityBaseType.
 | ||||
| 	// However to prevent errors we do a simple check vor validity.
 | ||||
| 	if (type < 0 || type >> EntityBaseTypeLast ) { | ||||
| 		LogError ("Cannot create Entity with type %d: invalid type!", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	EntityBaseType base_type = (EntityBaseType) type; | ||||
| 
 | ||||
| 	// Create the Entity
 | ||||
| 	EntityControllerState* entity_controller = NULL; | ||||
| 
 | ||||
| 	// specific values for each Entity base_type
 | ||||
| 	if (base_type == EntityBaseTypeNone) { | ||||
| 	} else if (base_type == EntityBaseTypeActor) { | ||||
| 		entity_controller = new EntityControllerState (); | ||||
| 		if (!entity_controller) { | ||||
| 			LogError ("Could not allocate enough memory for EntityControllerState of type '%d'", type); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 	} else if (base_type == EntityBaseTypeBlock) { | ||||
| 	} else if (base_type == EntityBaseTypeParticle) { | ||||
| 	} else { | ||||
| 		LogError ("No EntityPhysicState defined for Entity base_type '%d'", base_type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return entity_controller; | ||||
| } | ||||
| 
 | ||||
| EntityBase* EntityFactoryBase::CreateEntity (int type) { | ||||
| 	// In this simple factory the type is simply seen as the EntityBaseType.
 | ||||
| 	// However to prevent errors we do a simple check vor validity.
 | ||||
| 	if (type < 0 || type >> EntityBaseTypeLast ) { | ||||
| 		LogError ("Cannot create Entity with type %d: invalid type!", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	EntityBaseType base_type = (EntityBaseType) type; | ||||
| 
 | ||||
| 	// Create the Entity
 | ||||
| 	EntityBase *entity = new EntityBase; | ||||
| 	entity->mBaseType = base_type; | ||||
| 
 | ||||
| 	if (!entity) { | ||||
| 		LogError ("Could not allocate enough memory for EntityVisualState of type '%d'", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	entity->mPhysicState = CreateEntityPhysicState (type); | ||||
| 	entity->mControllerState = CreateEntityControllerState (type); | ||||
| 
 | ||||
| 	return entity; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										35
									
								
								engine/EntityFactoryBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								engine/EntityFactoryBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| #ifndef _ENTITYFACTORYBASE_H | ||||
| #define _ENTITYFACTORYASE_H | ||||
| 
 | ||||
| #include "Module.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| 	struct EntityBase; | ||||
| 
 | ||||
| 	struct EntityPhysicState; | ||||
| 	struct EntityControllerState; | ||||
| 
 | ||||
| 	/** \brief Takes care of the creation of user-defined Entities
 | ||||
| 	 * | ||||
| 	 * To be able to define custom types of Entities we use a Object Factory for | ||||
| 	 * which the actual CreateEntityXYZState () function can be overloaded with | ||||
| 	 * the creation of custom types. | ||||
| 	 * | ||||
| 	 * The method EntityFactory::CreateEntity() will be called by the | ||||
| 	 * Model::CreateEntity() function which also takes care of registering the | ||||
| 	 * Entity to required submodules. | ||||
| 	 */ | ||||
| 	class EntityFactoryBase : public Module { | ||||
| 		public: EntityFactoryBase () {}; | ||||
| 			virtual EntityPhysicState* CreateEntityPhysicState (int type); | ||||
| 			virtual EntityControllerState* CreateEntityControllerState (int type); | ||||
| 
 | ||||
| 			virtual EntityBase* CreateEntity (int type); | ||||
| 
 | ||||
| 		protected: | ||||
| 			virtual int OnInit (int argc, char* argv[]); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| #endif // _ENTITYFACTORYBASE_H
 | ||||
							
								
								
									
										21
									
								
								engine/EnumToString.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								engine/EnumToString.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| // File name: "EnumToString.h"
 | ||||
| //
 | ||||
| // From: http://www.codeproject.com/KB/cpp/C___enums_to_strings.aspx
 | ||||
| //
 | ||||
| // Thanks to Marcos F. Cardoso
 | ||||
| 
 | ||||
| #undef DECL_ENUM_ELEMENT | ||||
| #undef BEGIN_ENUM | ||||
| #undef END_ENUM | ||||
| 
 | ||||
| #ifndef GENERATE_ENUM_STRINGS | ||||
|     #define DECL_ENUM_ELEMENT( element ) element | ||||
|     #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME | ||||
|     #define END_ENUM( ENUM_NAME ) ENUM_NAME; \ | ||||
|             const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index); | ||||
| #else | ||||
| 		#define DECL_ENUM_ELEMENT( element ) #element | ||||
|     #define BEGIN_ENUM( ENUM_NAME ) const char* gs_##ENUM_NAME [] = | ||||
|     #define END_ENUM( ENUM_NAME ) ; const char* GetString##ENUM_NAME(enum \ | ||||
|             tag##ENUM_NAME index){ return gs_##ENUM_NAME [index]; } | ||||
| #endif | ||||
							
								
								
									
										88
									
								
								engine/EventsBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								engine/EventsBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| #include "EventsBase.h" | ||||
| #include "Logging.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| EventManager* EventManagerInstance = NULL; | ||||
| 
 | ||||
| int EventManager::OnInit (int argc, char* argv[]) { | ||||
| 	EventManagerInstance = this; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void EventManager::OnDestroy() { | ||||
| 	EventManagerInstance = NULL; | ||||
| } | ||||
| 
 | ||||
| bool EventManager::RegisterListener (const EventListenerBase *listener, const int event_type) { | ||||
| 	LogDebug ("Registering Event listener %x for event type %d", listener, event_type); | ||||
| 
 | ||||
| 	mEventTypeListeners[event_type].push_back(listener); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void EventManager::Process () { | ||||
| 	while (mQueuedEvents.size() > 0) { | ||||
| 		TriggerEvent (mQueuedEvents.front()); | ||||
| 		mQueuedEvents.pop(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool EventManager::QueueEvent (const EventBasePtr &event) { | ||||
| 	if (!HasEventTypeListener(event->mEventType)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	mQueuedEvents.push (event); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool EventManager::TriggerEvent (const EventBasePtr &event) { | ||||
| 	if (!HasEventTypeListener (event->mEventType)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	std::vector<const EventListenerBase*>::iterator listener_iter = mEventTypeListeners[event->mEventType].begin(); | ||||
| 	for ( ; listener_iter != mEventTypeListeners[event->mEventType].end(); listener_iter++) { | ||||
| 		if ((*listener_iter)->HandleEvent (event)) | ||||
| 			return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Global Functions | ||||
|  */ | ||||
| /** \brief Registers a listener to a given event type */ | ||||
| bool RegisterListener (const EventListenerBase *listener, const int event_type) { | ||||
| 	if (!EventManagerInstance) { | ||||
| 		LogError ("Could not register EventListenerBase: EventManager not initialized!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return EventManagerInstance->RegisterListener (listener, event_type); | ||||
| } | ||||
| 
 | ||||
| /** \brief Calls all event listeners to handle the events */ | ||||
| bool QueueEvent (const EventBasePtr &event) { | ||||
| 	if (!EventManagerInstance) { | ||||
| 		LogError ("Could not queue event: EventManager not initialized!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return EventManagerInstance->QueueEvent (event); | ||||
| } | ||||
| 
 | ||||
| /** \brief Calls the listener handlers immediately */ | ||||
| bool TriggerEvent (const EventBasePtr &event) { | ||||
| 	if (!EventManagerInstance) { | ||||
| 		LogError ("Could not trigger event: EventManager not initialized!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return EventManagerInstance->TriggerEvent (event); | ||||
| } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										88
									
								
								engine/EventsBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								engine/EventsBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| #ifndef EVENTSBASE_H | ||||
| #define EVENTSBASE_H | ||||
| 
 | ||||
| #include "Module.h" | ||||
| 
 | ||||
| #include <boost/shared_ptr.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
| #include <map> | ||||
| #include <vector> | ||||
| #include <queue> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Contains all information relevant to the Event */ | ||||
| struct EventBase { | ||||
| 	int mEventType; | ||||
| 
 | ||||
| 	/** \brief This might later be used for de-/serializing of the event data */ | ||||
| 	std::string mEventData; | ||||
| 	float mEventFloat; | ||||
| 	int mEventInt; | ||||
| 	unsigned int mEventUnsignedInt; | ||||
| }; | ||||
| 
 | ||||
| typedef boost::shared_ptr<EventBase> EventBasePtr; | ||||
| 
 | ||||
| /** \brief Takes care of the handling of the Event 
 | ||||
|  * | ||||
|  * Processing of the Event is done in the EventListenerBase::HandleEvent() | ||||
|  * function. | ||||
|  */ | ||||
| class EventListenerBase { | ||||
| 	public: | ||||
| 		virtual ~EventListenerBase() {}; | ||||
| 		/** \brief Handles the Event */ | ||||
| 		virtual bool HandleEvent (const EventBasePtr &event) const = 0; | ||||
| 		void just_for_the_vtable() {}; | ||||
| 
 | ||||
| 		/** \brief For debugging */ | ||||
| 		std::string mName; | ||||
| }; | ||||
| 
 | ||||
| typedef boost::shared_ptr<EventListenerBase> EventListenerPtr; | ||||
| 
 | ||||
| /** \brief Keeps track of all the EventListenerBase objects and receives Event notifications. 
 | ||||
|  */ | ||||
| class EventManager : public Module { | ||||
| 	public: | ||||
| 		virtual ~EventManager() {}; | ||||
| 
 | ||||
| 		/** \brief Registers a listener to a given event type */ | ||||
| 		bool RegisterListener (const EventListenerBase *listener, const int event_type); | ||||
| 		/** \brief Calls all event listeners to handle the events */ | ||||
| 		void Process (); | ||||
| 		/** \brief Queues the until Process() gets called */ | ||||
| 		bool QueueEvent (const EventBasePtr &event); | ||||
| 		/** \brief Calls the listener handlers immediately */ | ||||
| 		bool TriggerEvent (const EventBasePtr &event); | ||||
| 
 | ||||
| 		/** \brief Returns true if there is a listener for a given event type */ | ||||
| 		bool HasEventTypeListener (const int event_type) { | ||||
| 			return mEventTypeListeners.find(event_type) != mEventTypeListeners.end(); | ||||
| 		} | ||||
| 		/** \brief Returns the number of listeners for a given event type */ | ||||
| 		unsigned int GetEventTypeListenerCount (const int event_type) { | ||||
| 			if (!HasEventTypeListener (event_type)) | ||||
| 				return 0; | ||||
| 
 | ||||
| 			return (mEventTypeListeners.find(event_type))->second.size(); | ||||
| 		} | ||||
| 		unsigned int GetQueuedEventCount () { | ||||
| 			return mQueuedEvents.size(); | ||||
| 		} | ||||
| 
 | ||||
| 	protected: | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		virtual void OnDestroy(); | ||||
| 
 | ||||
| 	private: | ||||
| 		/** \brief Contains for each event type the list of listeners */ | ||||
| 		std::map <int, std::vector<const EventListenerBase*> > mEventTypeListeners; | ||||
| 		std::queue <EventBasePtr> mQueuedEvents; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* EVENTSBASE_H */ | ||||
							
								
								
									
										16
									
								
								engine/EventsBaseGlobal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								engine/EventsBaseGlobal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| #ifndef EVENTSBASEGLOBAL_H | ||||
| #define EVENTSBASEGLOBAL_H | ||||
| 
 | ||||
| #include "EventsBase.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Registers a listener to a given event type */ | ||||
| bool RegisterListener (const EventListenerBase *listener, const int event_type); | ||||
| /** \brief Calls all event listeners to handle the events */ | ||||
| bool QueueEvent (const EventBasePtr &event); | ||||
| /** \brief Calls the listener handlers immediately */ | ||||
| bool TriggerEvent (const EventBasePtr &event); | ||||
| 
 | ||||
| } | ||||
| #endif /* EVENTSBASEGLOBAL_H */ | ||||
							
								
								
									
										7
									
								
								engine/GameEntityBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								engine/GameEntityBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "EntityBase.h" | ||||
| #include "ModelBase.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										173
									
								
								engine/Logging.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								engine/Logging.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | ||||
| #include "Logging.h" | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <cstdarg> | ||||
| #include <cstdlib> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| static Logging *LoggingInstance = NULL; | ||||
| static LogLevel requested_level = LOG_DEFAULT_LEVEL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int Logging::OnInit (int argc, char* argv[]) { | ||||
| 	mPrintLevel = requested_level; | ||||
| 
 | ||||
| 	Log (LogLevelDebug, "Logging Init"); | ||||
| 	LoggingInstance = this; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void Logging::OnDestroy () { | ||||
| 	Log (LogLevelDebug, "Logging Destroy"); | ||||
| 
 | ||||
| 	LoggingInstance = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| void Logging::Log (LogLevel level, const char *str, ...) { | ||||
| 	if (level < mPrintLevel) | ||||
| 		return; | ||||
| 
 | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	static int i; | ||||
| 	 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| 	assert (last_length < LOG_MAX_MESSAGE_LENGTH); | ||||
| 
 | ||||
| 	std::cout << msg << std::endl; | ||||
| 
 | ||||
| 	LogEntry log_entry (level, msg); | ||||
| 	mLogEntries.push_back (log_entry); | ||||
| } | ||||
| 
 | ||||
| void Logging::SetLogPrintLevel (LogLevel print_level) { | ||||
| 	mPrintLevel = print_level; | ||||
| } | ||||
| 
 | ||||
| const LogEntry &Logging::GetLastEntry () { | ||||
| 	static LogEntry null_message (LogLevelMessage, ""); | ||||
| 
 | ||||
| 	if (mLogEntries.size() > 0) { | ||||
| 		return mLogEntries[mLogEntries.size() - 1]; | ||||
| 	} | ||||
| 
 | ||||
| 	return null_message; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Globally visible functions  | ||||
|  */ | ||||
| void SetLogPrintLevel (LogLevel print_level) { | ||||
| 	if (!LoggingInstance) { | ||||
| 		requested_level = print_level; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	LoggingInstance->SetLogPrintLevel (print_level); | ||||
| } | ||||
| 
 | ||||
| void LogError (const char* str, ...) { | ||||
| 	assert (LoggingInstance); | ||||
| 
 | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	static int i; | ||||
| 	 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| 	assert (last_length < LOG_MAX_MESSAGE_LENGTH); | ||||
| 
 | ||||
| 	LoggingInstance->Log (LogLevelError, msg); | ||||
| } | ||||
| 
 | ||||
| void LogWarning (const char* str, ...) { | ||||
| 	assert (LoggingInstance); | ||||
| 
 | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	static int i; | ||||
| 	 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| 	assert (last_length < LOG_MAX_MESSAGE_LENGTH); | ||||
| 
 | ||||
| 	LoggingInstance->Log (LogLevelWarning, msg); | ||||
| } | ||||
| 
 | ||||
| void LogMessage (const char* str, ...) { | ||||
| 	assert (LoggingInstance); | ||||
| 
 | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	static int i; | ||||
| 	 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| 	assert (last_length < LOG_MAX_MESSAGE_LENGTH); | ||||
| 
 | ||||
| 	LoggingInstance->Log (LogLevelMessage, msg); | ||||
| } | ||||
| 
 | ||||
| void LogDebug (const char* str, ...) { | ||||
| 	assert (LoggingInstance); | ||||
| 	static char msg[LOG_MAX_MESSAGE_LENGTH]; | ||||
| 	static int last_length = LOG_MAX_MESSAGE_LENGTH; | ||||
| 	static int i; | ||||
| 	 | ||||
| 	for (i = 0; i < last_length; i++) | ||||
| 		msg[i] = 0; | ||||
| 
 | ||||
| 	va_list ap; | ||||
| 	va_start(ap, str); | ||||
| 	vsprintf(msg, str, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	last_length = strlen (msg); | ||||
| 	assert (last_length < LOG_MAX_MESSAGE_LENGTH); | ||||
| 
 | ||||
| 	LoggingInstance->Log (LogLevelDebug, msg); | ||||
| } | ||||
| 
 | ||||
| const LogEntry& GetLastLogEntry () { | ||||
| 	assert (LoggingInstance); | ||||
| 	return LoggingInstance->GetLastEntry (); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										34
									
								
								engine/Logging.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								engine/Logging.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| #ifndef _LOGGING_H | ||||
| #define _LOGGING_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| class Module; | ||||
| 
 | ||||
| /** \brief All logging goes through this class
 | ||||
|  */ | ||||
| class Logging : public Module { | ||||
| 	public: | ||||
| 		void Log (LogLevel level, const char *str, ...); | ||||
| 		void SetLogPrintLevel (LogLevel print_level); | ||||
| 		/** \brief Returns the last LogEntry that was sent to the Logging module
 | ||||
| 		 */ | ||||
| 		const LogEntry& GetLastEntry (); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		virtual void OnDestroy (); | ||||
| 
 | ||||
| 	private: | ||||
| 		LogLevel mPrintLevel; | ||||
| 		/** \brief Stores all log messages that were sent to the Logging module
 | ||||
| 		 * \todo Restrict the number of entries to be stored! | ||||
| 		 */ | ||||
| 		std::vector<LogEntry> mLogEntries; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| #endif // _LOGGING_H
 | ||||
							
								
								
									
										45
									
								
								engine/LoggingGlobal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								engine/LoggingGlobal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| #ifndef _LOGGINGLOBAL_H | ||||
| #define _LOGGINGLOBAL_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| enum LogLevel { | ||||
| 	LogLevelDebug = 0, | ||||
| 	LogLevelWarning, | ||||
| 	LogLevelMessage, | ||||
| 	LogLevelError | ||||
| }; | ||||
| 
 | ||||
| /** \brief Represents a log message along with its level
 | ||||
|  */ | ||||
| struct LogEntry { | ||||
| 	LogEntry (LogLevel level, const char* message) { | ||||
| 		mLevel = level; | ||||
| 		mMessage = message; | ||||
| 	} | ||||
| 
 | ||||
| 	/** \brief the level of the message */ | ||||
| 	LogLevel mLevel; | ||||
| 	/** \brief the message itself */ | ||||
| 	const char *mMessage; | ||||
| }; | ||||
| 
 | ||||
| /* Global visible functions */ | ||||
| 
 | ||||
| /** \brief Sets the level for which messages should be printed out */ | ||||
| void SetLogPrintLevel (LogLevel print_level); | ||||
| 
 | ||||
| /** \brief Sends the Message to the Logging system */ | ||||
| void LogError (const char* str, ...); | ||||
| /** \brief Sends the Message to the Logging system */ | ||||
| void LogWarning (const char* str, ...); | ||||
| /** \brief Sends the Message to the Logging system */ | ||||
| void LogMessage (const char* str, ...); | ||||
| /** \brief Sends the Message to the Logging system */ | ||||
| void LogDebug (const char* str, ...); | ||||
| /** \brief Returns the last LogEntry sent to the Logging system */ | ||||
| const LogEntry &GetLastLogEntry (); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _LOGGINGLOBAL_H
 | ||||
							
								
								
									
										295
									
								
								engine/ModelBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								engine/ModelBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,295 @@ | ||||
| #include "ModelBase.h" | ||||
| 
 | ||||
| #include "PhysicsBase.h" | ||||
| #include "EntityBase.h" | ||||
| #include "EntityFactoryBase.h" | ||||
| 
 | ||||
| #include <coll2d.h> | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| static ModelBase* ModelInstance = NULL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int ModelBase::OnInit (int argc, char* argv[]) { | ||||
| 	LogDebug ("Model Init"); | ||||
| 
 | ||||
| 	ModelInstance = this; | ||||
| 	mKilledEntities.clear (); | ||||
| 	mEntityIdCounter = 0; | ||||
| 	mDeltaSec = 0.; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ModelBase::OnDestroy () { | ||||
| 	LogDebug ("Model Destroy"); | ||||
| 
 | ||||
| 	std::map<unsigned int, EntityBase*>::iterator iter = mEntities.begin (); | ||||
| 	std::map<unsigned int, EntityBase*>::iterator next = iter; | ||||
| 	 | ||||
| 	// Since DestroyEntity () also erases the entry in mEntities iter gets
 | ||||
| 	// invalid. Therefore we have to store the iterator that follows iter
 | ||||
| 	while (iter != mEntities.end ()) { | ||||
| 		next = iter; | ||||
| 		next ++; | ||||
| 		DestroyEntity (iter->first); | ||||
| 		iter = next; | ||||
| 	} | ||||
| 
 | ||||
| 	ModelInstance = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Model specific functions | ||||
|  */ | ||||
| void ModelBase::Process () { | ||||
| 	// Process the controllers and state of all entities
 | ||||
| 	std::map<unsigned int, EntityBase*>::iterator entity_iter = mEntities.begin(); | ||||
| 	do { | ||||
| 		if (entity_iter->second == NULL) { | ||||
| 			LogError ("Entity with id %d does not exist!", entity_iter->first); | ||||
| 			assert (0); | ||||
| 		} | ||||
| 		entity_iter->second->Update(mDeltaSec); | ||||
| 		entity_iter++; | ||||
| 	} while (entity_iter != mEntities.end()); | ||||
| 
 | ||||
| 	// simulate the world
 | ||||
| 	mPhysics->Simulate (mDeltaSec, this); | ||||
| 
 | ||||
| 	// remove killed entities
 | ||||
| 	unsigned int i; | ||||
| 	for (i = 0; i < mKilledEntities.size(); i++) | ||||
| 		UnregisterEntity (mKilledEntities[i]); | ||||
| 
 | ||||
| 	mKilledEntities.clear(); | ||||
| } | ||||
| 
 | ||||
| EntityBase* ModelBase::CreateEntity (int type) { | ||||
| 	// Create a new entity id
 | ||||
| 	unsigned int entity_id = CreateEntityId(); | ||||
| 
 | ||||
| 	// Call the event
 | ||||
| 	OnCreateEntity (type, entity_id); | ||||
| 	 | ||||
| 	// Create the entity
 | ||||
| 	EntityBase* result = mEntityFactory->CreateEntity (type); | ||||
| 	result->SetId (entity_id); | ||||
| 
 | ||||
| 	// And register it
 | ||||
| 	RegisterEntity (result); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void ModelBase::RegisterEntity (EntityBase* entity) { | ||||
| 	unsigned int id = entity->mId; | ||||
| 	LogDebug ("Registering Entity with id '%d'", id); | ||||
| 
 | ||||
| 	if (mEntities.find(id) != mEntities.end ()) { | ||||
| 		LogError ("Replacing Entity with id '%d'", id); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (entity->mPhysicState) | ||||
| 		mPhysics->RegisterEntity (entity->mPhysicState); | ||||
| 
 | ||||
| 	mEntities[id] = entity; | ||||
| } | ||||
| 
 | ||||
| void ModelBase::KillEntity (const unsigned int id) { | ||||
| 	std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id); | ||||
| 
 | ||||
| 	if (iter == mEntities.end ()) { | ||||
| 		LogError ("Could not kill Entity with id '%d': Entity not found!", id); | ||||
| 		assert (0); | ||||
| 		return; | ||||
| 	} else { | ||||
| 		EntityBase *entity = iter->second; | ||||
| 
 | ||||
| 		// call the event handler
 | ||||
| 		OnKillEntity (entity); | ||||
| 
 | ||||
| 		if (entity->mPhysicState) { | ||||
| 			entity->mPhysicState->mAlive = false; | ||||
| 		} | ||||
| 
 | ||||
| 		mKilledEntities.push_back (iter->first); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ModelBase::UnregisterEntity (const unsigned int id) { | ||||
| 	std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id); | ||||
| 
 | ||||
| 	if (iter == mEntities.end ()) { | ||||
| 		LogError ("Could not unregister Entity with id '%d': Entity not found!", id); | ||||
| 		assert (0); | ||||
| 		return; | ||||
| 	} else { | ||||
| 		EntityBase *entity = iter->second; | ||||
| 		if (entity->mPhysicState) { | ||||
| 			mPhysics->UnregisterEntity (id); | ||||
| 			entity->mPhysicState = NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		delete entity; | ||||
| 
 | ||||
| 		mEntities.erase (iter); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| EntityBase* ModelBase::GetEntity (const unsigned int id) { | ||||
| 	std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id); | ||||
| 
 | ||||
| 	if (iter != mEntities.end ()) { | ||||
| 		return iter->second; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| unsigned int ModelBase::CreateEntityId () { | ||||
| 	return ++mEntityIdCounter; | ||||
| } | ||||
| 
 | ||||
| void ModelBase::ClearEntities () { | ||||
| 	LogDebug ("Clearing all %d entities.", mEntities.size()); | ||||
| 
 | ||||
| 	std::map<unsigned int, EntityBase*>::iterator iter = mEntities.begin (); | ||||
| 	std::map<unsigned int, EntityBase*>::iterator next = iter; | ||||
| 	 | ||||
| 	// Since DestroyEntity () also erases the entry in mEntities iter gets
 | ||||
| 	// invalid. Therefore we have to store the iterator that follows iter
 | ||||
| 	while (iter != mEntities.end ()) { | ||||
| 		next = iter; | ||||
| 		next ++; | ||||
| 		DestroyEntity (iter->first); | ||||
| 		iter = next; | ||||
| 	} | ||||
| 
 | ||||
| 	mEntityIdCounter = 0; | ||||
| } | ||||
| 
 | ||||
| unsigned int ModelBase::GetPlayerEntityId () { | ||||
| 	return mPlayerEntityId; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * \param collision_time The time when the collision occured relative to the start of the simulation frame  | ||||
|  */ | ||||
| void ModelBase::SendEntityCollisionEvent (const unsigned int reference_entity_id, | ||||
| 		const unsigned int incidence_entity_id, float collision_time, vector3d normal) { | ||||
| 	// Check whether we report the same contact over and over
 | ||||
| 	static unsigned int last_reference_entity_id = 0; | ||||
| 	static unsigned int last_incidence_entity_id = 0; | ||||
| 	static float last_collision_time = -1.; | ||||
| 
 | ||||
| 	if (!reference_entity_id || !incidence_entity_id) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (last_reference_entity_id != 0) { | ||||
| 		if (last_reference_entity_id == reference_entity_id | ||||
| 				&& last_incidence_entity_id == incidence_entity_id | ||||
| 				&& last_collision_time == collision_time) { | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// update the last_* entries
 | ||||
| 	last_reference_entity_id = reference_entity_id; | ||||
| 	last_incidence_entity_id = incidence_entity_id; | ||||
| 	last_collision_time = collision_time; | ||||
| 
 | ||||
| 	// now we need to get the Entities and check whether we should
 | ||||
| 	// call EntityBase::CollisionEvent()
 | ||||
| 	EntityBase* reference_entity = GetEntity (reference_entity_id);	 | ||||
| 	EntityBase* incidence_entity = GetEntity (incidence_entity_id);	 | ||||
| 
 | ||||
| 	LogDebug ("Received collision type ref = %d type inc = %d", | ||||
| 			reference_entity->mType, | ||||
| 			incidence_entity->mType); | ||||
| 
 | ||||
| 	// If the incidence entity accepted the collision we can return, otherwise
 | ||||
| 	// we perform the symmetric collision event.
 | ||||
| 	if (incidence_entity->CollisionEvent (reference_entity)) | ||||
| 		return; | ||||
| 
 | ||||
| 	reference_entity->CollisionEvent (incidence_entity); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Global functions | ||||
|  */ | ||||
| unsigned int GetPlayerEntityId () { | ||||
| 	if (!ModelInstance) { | ||||
| 		LogError ("Couldn't create Entity: Model not initialized!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return ModelInstance->GetPlayerEntityId (); | ||||
| } | ||||
| 
 | ||||
| float GetFrameDuration () { | ||||
| 	if (!ModelInstance) { | ||||
| 		LogError ("Couldn't create Entity: Model not initialized!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return ModelInstance->GetFrameDuration (); | ||||
| } | ||||
| 
 | ||||
| EntityBase * CreateEntity (int type) { | ||||
| 	if (!ModelInstance) { | ||||
| 		LogError ("Couldn't create Entity: Model not initialized!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	EntityBase *result = ModelInstance->CreateEntity (type); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void DestroyEntity (unsigned int id) { | ||||
| 	if (!ModelInstance) { | ||||
| 		LogError ("Couldn't destroy Entity: Model not initialized!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	ModelInstance->UnregisterEntity (id); | ||||
| } | ||||
| 
 | ||||
| void KillEntity (unsigned int id) { | ||||
| 	if (!ModelInstance) { | ||||
| 		LogError ("Couldn't kill Entity: Model not initialized!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	ModelInstance->KillEntity (id); | ||||
| } | ||||
| 
 | ||||
| EntityBase * GetEntity (unsigned int id) { | ||||
| 	if (!ModelInstance) { | ||||
| 		LogError ("Couldn't execute GetEntity(): Model not initialized!"); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return ModelInstance->GetEntity (id); | ||||
| } | ||||
| 
 | ||||
| EntityPhysicState * GetEntityPhysicState (unsigned int id) { | ||||
| 	EntityBase *entity = GetEntity (id); | ||||
| 
 | ||||
| 	if (entity) | ||||
| 		return entity->mPhysicState; | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										140
									
								
								engine/ModelBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								engine/ModelBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | ||||
| #ifndef _MODELBASE_H | ||||
| #define _MODELBASE_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Module; | ||||
| class PhysicsBase; | ||||
| class Events; | ||||
| class EntityFactoryBase; | ||||
| 
 | ||||
| struct EntityBase; | ||||
| 
 | ||||
| /** \brief Represents the current state of the Engine
 | ||||
|  * | ||||
|  * Represents the State of the Engine and is unaware of anything except itself. | ||||
|  * It manages all Entities, Physics, etc. | ||||
|  * | ||||
|  *	It has the following subsystems: | ||||
|  *	- Events | ||||
|  *	- Physics | ||||
|  *	- Variables | ||||
|  * | ||||
|  * \note | ||||
|  * To create an Entity one must call Engine::CreateEntity() which will | ||||
|  * allocate the Entity and performs all the required registrations by calling | ||||
|  * Model::RegisterEntity(). | ||||
|  */ | ||||
| class ModelBase : public Module { | ||||
| 	public: | ||||
| 		/** Performs simulation, gamelogic, etc */ | ||||
| 		virtual void Process (); | ||||
| 		/** Updates the timer */ | ||||
| 		void UpdateTimer () { | ||||
| 			static float last_frame = 0; | ||||
| 			float current_frame = static_cast<float> (SDL_GetTicks ()) * 1.0e-3; | ||||
| 			mDeltaSec = current_frame - last_frame; | ||||
| 			last_frame = current_frame; | ||||
| 		} | ||||
| 		float GetFrameDuration () { | ||||
| 			return mDeltaSec; | ||||
| 		} | ||||
| 	 | ||||
| 		/** Adds the given Entity to the Model */ | ||||
| 		void RegisterEntity (EntityBase *entity); | ||||
| 		/** Removes the Entity with the given id */ | ||||
| 		void UnregisterEntity (const unsigned int id); | ||||
| 		/** Marks an Engine::Entity as killed so that it gets removed after the
 | ||||
| 		 * simulation */ | ||||
| 		void KillEntity (const unsigned int id); | ||||
| 
 | ||||
| 		/** Creates an Entity of the given type
 | ||||
| 		 * | ||||
| 		 * This calls the CreateEntity() function on the Model::mEntityFactory to | ||||
| 		 * create the proper Entity and registers it to the required submodules | ||||
| 		 * (so far only Model::mPhysics). | ||||
| 		 */ | ||||
| 		EntityBase* CreateEntity (int type); | ||||
| 		/** Returns the Entity with the given id */ | ||||
| 		EntityBase* GetEntity (const unsigned int id); | ||||
| 		/** Returns a unused id for an Entity */ | ||||
| 		unsigned int CreateEntityId (); | ||||
| 		/** Removes all Entities */ | ||||
| 		void ClearEntities (); | ||||
| 		 | ||||
| 		/** Returns the id of the entity the player is currently controlling */ | ||||
| 		unsigned int GetPlayerEntityId (); | ||||
| 
 | ||||
| 		/** Notifies the gamelogic of a collision event */ | ||||
| 		void SendEntityCollisionEvent (const unsigned int reference_entity_id, | ||||
| 				const unsigned int incidence_entity_id, float collision_time, vector3d normal); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		virtual void OnDestroy (); | ||||
| 
 | ||||
| 		/** \brief Gets called when an entity of the given type is being created */ | ||||
| 		virtual void OnCreateEntity (const int type, const unsigned int id) {}; | ||||
| 		/** \brief Gets called when an entity is marked to be killed */ | ||||
| 		virtual void OnKillEntity (const EntityBase *entity) {}; | ||||
| 
 | ||||
| 
 | ||||
| 		PhysicsBase *mPhysics; | ||||
| 		Events *mEvents; | ||||
| 
 | ||||
| 		/** \brief Creates Entities */ | ||||
| 		EntityFactoryBase *mEntityFactory; | ||||
| 
 | ||||
| 		/** \brief contains all Engine::Entities */ | ||||
| 		std::map<unsigned int, EntityBase *> mEntities; | ||||
| 		/** \brief contains all Engine::Entities that ceased to exist */ | ||||
| 		std::vector<unsigned int> mKilledEntities; | ||||
| 
 | ||||
| 		unsigned int mEntityIdCounter; | ||||
| 		unsigned int mPlayerEntityId; | ||||
| 
 | ||||
| 		float mDeltaSec; | ||||
| 
 | ||||
| 	friend class ViewBase; | ||||
| 	friend class Engine; | ||||
| 	friend class Controller; | ||||
| }; | ||||
| 
 | ||||
| /** \brief Creates an Entity of the given type and registers at the required modules *
 | ||||
|  * | ||||
|  * It allocates the memory needed to represent that specific type of Entity. | ||||
|  * At also performs the required registrations at the various Modules. | ||||
|  * | ||||
|  * All Entities that are created with this function get also destroyed in | ||||
|  * Model::Destroy () by calling DestroyEntity () for this Entity. | ||||
|  * | ||||
|  * \note All Entities must be created with this function if you intend to keep | ||||
|  * the different Modules in sync! | ||||
|  */ | ||||
| EntityBase * CreateEntity (int type); | ||||
| 
 | ||||
| /** \brief Frees the Memory required by the Entity and unregisters it 
 | ||||
|  * | ||||
|  * This function also frees the memory the Entity is using in its | ||||
|  * different representitions such as EntityVisualState and EntityPhysicState. | ||||
|  * | ||||
|  * It also unregisters the Entity from the different Modules where it was | ||||
|  * registered by CreateEntity. | ||||
|  */ | ||||
| void DestroyEntity (unsigned int id); | ||||
| /** \brief Tells the model that the entity is no more existant in the game
 | ||||
|  * world */ | ||||
| void KillEntity (unsigned int id); | ||||
| /** \brief Returns the Entity with the given id, NULL otherwise */ | ||||
| EntityBase * GetEntity (unsigned int id); | ||||
| /** \brief Returns the physical state of the Entity with the given id, NULL otherwise */ | ||||
| EntityPhysicState * GetEntityPhysicState (unsigned int id); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _MODEL_H
 | ||||
							
								
								
									
										15
									
								
								engine/ModelBaseGlobal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								engine/ModelBaseGlobal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #ifndef _MODELGLOBAL_H | ||||
| #define _MODELGLOBAL_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Adds the function callback as command for the given name*/ | ||||
| unsigned int GetPlayerEntityId (); | ||||
| 
 | ||||
| /** \brief Returns the duration of the frame in seconds */ | ||||
| float GetFrameDuration (); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* _MODELGLOBAL_H */ | ||||
| 
 | ||||
							
								
								
									
										51
									
								
								engine/Module.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								engine/Module.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| #ifndef MODULE_H | ||||
| #define MODULE_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Base class for the separate modules
 | ||||
|  * | ||||
|  * All Modules that are managed by the Engine::Engine base Module. Everything | ||||
|  * else is a Submodule of that or a Submodule of a Submodule. | ||||
|  */ | ||||
| class Module {  | ||||
| 	public: | ||||
| 		/** \brief Initializes the Module
 | ||||
| 		 *  | ||||
| 		 * \note This function must only return if it was able to initialize | ||||
| 		 * successfully, otherwise it should log an error with LogError and exit | ||||
| 		 * the program itself! | ||||
| 		 * | ||||
| 		 * In general at first the Submodules get initialized and then the Module | ||||
| 		 * that has pointers to the Submodules. Exception: The main Module | ||||
| 		 * Engine::Engine. | ||||
| 		 * | ||||
| 		 * \note | ||||
| 		 * The function Engine::OnInit () performs the allocation | ||||
| 		 * and Initialization of all its Submodules. | ||||
| 		 */ | ||||
| 		virtual int Init (int argc, char* argv[]) { return OnInit (argc, argv); } | ||||
| 		/** \brief Frees the used memory of the Module
 | ||||
| 		 * | ||||
| 		 * The Destroy function is always called at first for the Module itself | ||||
| 		 * and then for its submodules so that a Module is still completely | ||||
| 		 * working. Again for the main Module Engine::Engine the reverse is the | ||||
| 		 * case (such as in Module::Init). | ||||
| 		 */ | ||||
| 		virtual void Destroy () { OnDestroy (); } | ||||
| 		/** \brief Calls the function that registers its commands to the
 | ||||
| 		 * Commandsystem */ | ||||
| 		virtual void RegisterCommands () { OnRegisterCommands (); } | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief The actual function being called when Init () is called */ | ||||
| 		virtual int OnInit (int argc, char* argv[]) = 0; | ||||
| 		/** \brief Frees the memory */ | ||||
| 		virtual void OnDestroy () { }; | ||||
| 		/** \brief Registers the commands of the Module */ | ||||
| 		virtual void OnRegisterCommands () { }; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* MODULE_H */ | ||||
							
								
								
									
										25
									
								
								engine/OverlayBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								engine/OverlayBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| #ifndef OVERLAY | ||||
| #define OVERLAY | ||||
| 
 | ||||
| #include <SDL/SDL.h> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class OverlayBase { | ||||
| 	public: | ||||
| 		OverlayBase () {}; | ||||
| 		virtual ~OverlayBase() {}; | ||||
| 
 | ||||
| 		virtual bool OnKeyDown (const SDL_keysym &keysym) { return false; }; | ||||
| 		virtual bool OnKeyUp (const SDL_keysym &keysym) { return false; }; | ||||
| 		virtual bool OnMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos) { return false; }; | ||||
| 		virtual bool OnMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos) { return false; }; | ||||
| 
 | ||||
| 		virtual void Draw () = 0; | ||||
| 
 | ||||
| 		void _strange_function_for_vtable () {}; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* OVERLAY */ | ||||
							
								
								
									
										604
									
								
								engine/PhysicsBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										604
									
								
								engine/PhysicsBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,604 @@ | ||||
| #include "PhysicsBase.h" | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| // needed for GetEntityGameState() in ProcessCollisionEvent()
 | ||||
| #include "ModelBase.h" | ||||
| 
 | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| #define EPSILON 1.0e-4 | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int PhysicsBase::OnInit (int argc, char* argv[]) { | ||||
| 	LogDebug ("Physics Init"); | ||||
| 	mEntities.clear (); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void PhysicsBase::OnDestroy () { | ||||
| 	LogDebug ("Physics Destroy"); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| 
 | ||||
| void PhysicsBase::Move (float delta_msec) { | ||||
| 	EntityPhysicState* entity = NULL; | ||||
| 	std::map<unsigned int, EntityPhysicState*>::iterator entity_iter; | ||||
| 	std::map<unsigned int, EntityPhysicState*>::iterator collision_iter; | ||||
| 	vector3d velocity, orientation; | ||||
| 
 | ||||
| 	for (entity_iter = mEntities.begin (); entity_iter != mEntities.end(); entity_iter++){ | ||||
| 		entity = entity_iter->second; | ||||
| 		velocity = entity->GetVelocity (); | ||||
| 
 | ||||
| 		if (velocity.length2() == 0.) | ||||
| 				continue; | ||||
| 
 | ||||
| 		CheckContactCache (entity); | ||||
| 
 | ||||
| 		entity->SetPosition (entity->GetPosition () + velocity * delta_msec); | ||||
| 		entity->SetOrientation (vector3d(0., entity->GetOrientation()[1] + entity->GetAngleVelocity() * delta_msec, 0.)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int PhysicsBase::Simulate (float msec, ModelBase* model) { | ||||
| 	vector3d velocity, orientation; | ||||
| 
 | ||||
| 	unsigned int entity_a_id, entity_b_id; | ||||
| 	int resolve_steps = 0;; | ||||
| 	float current_time = 0, stepsize = msec / (float) 10; | ||||
| 
 | ||||
| 	while (current_time < msec) { | ||||
| 		if (msec - current_time < stepsize)  | ||||
| 			stepsize = msec - current_time; | ||||
| 
 | ||||
| 		coll2d::CollisionInfo info; | ||||
| 		bool collision_result = false; | ||||
| 
 | ||||
| 		collision_result = CalcNextCollision (stepsize, entity_a_id, entity_b_id, info); | ||||
| 
 | ||||
| 		if (collision_result == 0) { | ||||
| 			// there is no collision, so we integrate to the end of
 | ||||
| 			// the timestep
 | ||||
| 			current_time += stepsize; | ||||
| 			Move (stepsize); | ||||
| 		} else { | ||||
| 			LogDebug ("Collision between %u and %u", entity_a_id, entity_b_id); | ||||
| 			float collision_remaining_step = stepsize; | ||||
| 			resolve_steps = 0; | ||||
| 
 | ||||
| 			// This is the collision loop. It loops until there is no collision any
 | ||||
| 			// more within the stepsize.
 | ||||
| 			while (collision_remaining_step > 0.) { | ||||
| 				// with this we count how often we iterate through and can
 | ||||
| 				// detect certain false behaviour
 | ||||
| 				resolve_steps ++; | ||||
| 
 | ||||
| 				// info.time tells us in what time the contact will happen and
 | ||||
| 				// theoretically we can move to that point, however due to round-off
 | ||||
| 				// errors we might end up in a situation where the Entities overlap
 | ||||
| 				// which we must prevent to keep the collision detection working.
 | ||||
| 				// 
 | ||||
| 				// Therefore we only move to a portion of the time and resolve the
 | ||||
| 				// collision then. This alpha variable controls how much of the time
 | ||||
| 				// we skip.
 | ||||
| 				float alpha = 0.001;  | ||||
| 
 | ||||
| 				// If the timestep is already very small, we try to resolve it
 | ||||
| 				// immediately.
 | ||||
| 				if (info.time < EPSILON ) { | ||||
| 					// if the timestep is too small we simply resolve the collision and 
 | ||||
| 					// do not move beforehang
 | ||||
| 					LogDebug ("Time step too small ==> Resolving Step immediately"); | ||||
| 					ResolveCollision (0., entity_a_id, entity_b_id, info); | ||||
| 					// Send the collision event to the Model (if we have one)
 | ||||
| 					if (model) { | ||||
| 						model->SendEntityCollisionEvent (entity_a_id, entity_b_id, info.time, info.normal); | ||||
| 					} | ||||
| 					//	collision_remaining_step -= 1.0e-4;
 | ||||
| 				} else { | ||||
| 					Move (info.time * (1 - alpha)); | ||||
| 					LogDebug ("Resolving Step between %u and %u t = %f alpha = %f", entity_a_id, entity_b_id, info.time, alpha); | ||||
| 					ResolveCollision (info.time * (1 - alpha), entity_a_id, entity_b_id, info);	 | ||||
| 					// Send the collision event to the Model (if we have one)
 | ||||
| 					if (model) { | ||||
| 						model->SendEntityCollisionEvent (entity_a_id, entity_b_id, info.time, info.normal); | ||||
| 					} | ||||
| 					collision_remaining_step -= info.time * (1 - alpha); | ||||
| 				} | ||||
| 
 | ||||
| 				// At this point we resolved the collision we had found. Now we need
 | ||||
| 				// to check whether there is a new one
 | ||||
| 				collision_result = CalcNextCollision (collision_remaining_step, entity_a_id, entity_b_id, info); | ||||
| 
 | ||||
| 				// If there was none, we happily move on to the end of the frame and
 | ||||
| 				// set collision_remaining_step to 0 so that we jump out of the
 | ||||
| 				// collision loop.
 | ||||
| 				if (!collision_result) { | ||||
| 					Move (collision_remaining_step); | ||||
| 					collision_remaining_step = 0.; | ||||
| 					break; | ||||
| 				} | ||||
| 
 | ||||
| 				assert (resolve_steps <= 50); | ||||
| 			} | ||||
| 		}  | ||||
| 	} | ||||
| 	/* Postcondition: we simulated exactly msec milliseconds, no less, no more! */ | ||||
| 	assert (current_time == msec); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void PhysicsBase::RegisterEntity (EntityPhysicState* entity) { | ||||
| 	unsigned int id = entity->mId; | ||||
| 	LogDebug ("Registering EntityPhysicState with id '%d'", id); | ||||
| 	if (mEntities.find (id) == mEntities.end ()) | ||||
| 		mEntities[id] = entity; | ||||
| 	else { | ||||
| 		LogError ("Physics already has registered an Entity with id '%d'", id); | ||||
| 		assert (0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void PhysicsBase::UnregisterEntity (const unsigned int id) { | ||||
| 	std::map<unsigned int, EntityPhysicState*>::iterator iter = mEntities.find(id); | ||||
| 	LogDebug ("Unegistering EntityPhysicState with id '%d'", id); | ||||
| 
 | ||||
| 	if (iter != mEntities.end ()) { | ||||
| 		// Remove all the references of existing contacts to the Entity that is
 | ||||
| 		// going to be deleted.
 | ||||
| 		std::map<unsigned int, vector3d>::iterator temp_iter, contact_iter = iter->second->mContactNormals.begin(); | ||||
| 
 | ||||
| 		while (contact_iter != iter->second->mContactNormals.end()) { | ||||
| 			temp_iter = contact_iter; | ||||
| 			contact_iter ++; | ||||
| 
 | ||||
| 			ContactCacheRemove (id, temp_iter->first); | ||||
| 		} | ||||
| 
 | ||||
| 		// Remove the Entity from mEntities and erase the Entity
 | ||||
| 		EntityPhysicState* entity_physic_state = iter->second; | ||||
| 		mEntities.erase (iter); | ||||
| 
 | ||||
| 		// We also have to delete the state!
 | ||||
| 		if (entity_physic_state->mShape) | ||||
| 			delete entity_physic_state->mShape; | ||||
| 
 | ||||
| 		delete entity_physic_state; | ||||
| 	} else { | ||||
| 		LogError ("Could not unegister EntityPhysicState with id '%d': Entity not found!", id); | ||||
| 		assert (0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * This function also sorts out collisions that might be invalid such as | ||||
|  * Particle-Particle collision and the like. | ||||
|  */ | ||||
| inline bool PhysicsBase::CheckPossibleCollisionPair (EntityPhysicState* entity_a, EntityPhysicState* entity_b) { | ||||
| 	// no collision checks against itself
 | ||||
| 	if (entity_a == entity_b) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// no checks if both are static
 | ||||
| 	if (entity_a->mStatic && entity_a->mStatic) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// no checks if both are particles
 | ||||
| 	if (entity_a->mBaseType == EntityBaseTypeParticle  | ||||
| 			&& entity_b->mBaseType == EntityBaseTypeParticle) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// no checks if both are particles
 | ||||
| 	if (entity_a->mBaseType == EntityBaseTypeBlock | ||||
| 			&& entity_b->mBaseType == EntityBaseTypeBlock) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * \param stepsize  The timestep for which we want to check whether a | ||||
|  *                  collision occurs. | ||||
|  * \param reference_entity_id If a collision occurs the Id of the entity that | ||||
|  * 	is the reference entity is stored in this variable. | ||||
|  * \param incidence_entity_id If a collision occurs the Id of the entity that | ||||
|  * 	crashes into the reference entity is stored in this variable. | ||||
|  * \param info Contains information about the collision (normal, time, point) | ||||
|  * | ||||
|  * This function calls PhysicsBase::CheckPossibleCollisionPair() to sort out | ||||
|  * invalid collision pairs. | ||||
|  */ | ||||
| bool PhysicsBase::CalcNextCollision ( | ||||
| 		float stepsize, | ||||
| 		unsigned int &reference_entity_id, | ||||
| 		unsigned int &incidence_entity_id, | ||||
| 		coll2d::CollisionInfo &info) { | ||||
| 	std::map<unsigned int, EntityPhysicState*>::iterator collision_iter; | ||||
| 	std::map<unsigned int, EntityPhysicState*>::iterator collision_ref; | ||||
| 
 | ||||
| 	// We have to find the next collision, so we check everything and
 | ||||
| 	// take the first one that will happen.
 | ||||
| 	coll2d::CollisionInfo temp_info; | ||||
| 	info.time = 2.; | ||||
| 
 | ||||
| 	for (collision_ref = mEntities.begin (); collision_ref != mEntities.end (); collision_ref ++) { | ||||
| 		if (collision_ref->second->mId != 0) { | ||||
| 			collision_ref->second->UpdateShape(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (collision_ref = mEntities.begin (); collision_ref != mEntities.end (); collision_ref ++) { | ||||
| 		if (collision_ref->second->mAlive == false) | ||||
| 			continue; | ||||
| 		for (collision_iter = collision_ref; collision_iter != mEntities.end (); collision_iter ++) { | ||||
| 			if (collision_iter->second->mAlive == false) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (!CheckPossibleCollisionPair(collision_ref->second, collision_iter->second)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			EntityPhysicState *entity_a, *entity_b; | ||||
| 			entity_a = collision_ref->second; | ||||
| 			entity_b = collision_iter->second; | ||||
| 
 | ||||
| 			int coll2d_result = coll2d::check_collision (stepsize, entity_a->mShape, entity_b->mShape, &temp_info); | ||||
| 
 | ||||
| 			if (!HandleColl2dError (coll2d_result, stepsize, entity_a, entity_b, temp_info)) { | ||||
| 				LogError ("Could not handle coll2d error: %d\n", coll2d_result); | ||||
| 				assert (0); | ||||
| 			} | ||||
| 
 | ||||
| 			if (coll2d_result > 0 && temp_info.time < info.time ) { | ||||
| 				info = temp_info; | ||||
| 
 | ||||
| 				assert (info.reference_shape >= 0); | ||||
| 				if (info.reference_shape == 0) { | ||||
| 					reference_entity_id = collision_ref->first; | ||||
| 					incidence_entity_id = collision_iter->first; | ||||
| 				} else { | ||||
| 					reference_entity_id = collision_iter->first; | ||||
| 					incidence_entity_id = collision_ref->first; | ||||
| 					//assert (0);
 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if (info.time != 2.) | ||||
| 		return true; | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * This function updates the velocity of the Entity with id of | ||||
|  * incidence_entity_id so that it no more is in collision with with Entity | ||||
|  * with id reference_entity_id. Additionally to that we also cache the | ||||
|  * contact normals and check against them so that the new velocity does not | ||||
|  * violate previous contacts. | ||||
|  * | ||||
|  * We store the cached contact normals both in the incidence and the reference | ||||
|  * entity and we have to make sure that these references get cleared once one | ||||
|  * of the two get deleted! This is done in PhysicsBase::UnregisterEntity(). | ||||
|  */ | ||||
| void PhysicsBase::ResolveCollision (float stepsize, unsigned int reference_entity_id, unsigned int incidence_entity_id, coll2d::CollisionInfo &info) { | ||||
| 	EntityPhysicState* reference_entity = mEntities[reference_entity_id]; | ||||
| 	EntityPhysicState* incidence_entity = mEntities[incidence_entity_id]; | ||||
| 
 | ||||
| 	if (!reference_entity || !incidence_entity) { | ||||
| 		LogError ("Invalid entity IDs passed to %s: %u and %u", __FUNCTION__, reference_entity_id, incidence_entity_id); | ||||
| 	} | ||||
| 	assert (reference_entity && incidence_entity); | ||||
| 
 | ||||
| 	// So far only resolving of collision of sphere collisions is
 | ||||
| 	// allowed
 | ||||
| 	assert (dynamic_cast<coll2d::Sphere*> (incidence_entity->mShape)); | ||||
| 
 | ||||
| 	// First we calculate the velocity along the normal and then we calculate
 | ||||
| 	// the velocity that is tangential to the plane and set the new velocity to
 | ||||
| 	// it.
 | ||||
| 	vector3d new_velocity = incidence_entity->mVelocity; | ||||
| 	new_velocity -= reference_entity->mVelocity; | ||||
| 
 | ||||
| 	// It should be greater zero otherwise there was an error in the collision
 | ||||
| 	// detection.
 | ||||
| 	assert (new_velocity.length2 ()); | ||||
| 
 | ||||
| 	// The scalar proj tells us how far we went along the normal
 | ||||
| 	float proj = new_velocity * info.normal; | ||||
| 	// As there is a collision, and the incidence_entity is moving towards the
 | ||||
| 	// plane, this value must be strictly smaller than zero, otherwise we would
 | ||||
| 	// not penetrate the plane.
 | ||||
| 	if (proj > 0.) { | ||||
| 		LogError ("Projection invalid: %e", proj); | ||||
| 		info.doPrint ("Collision Info:\n"); | ||||
| 	} | ||||
| 	assert (proj < 0.); | ||||
| 
 | ||||
| 	// Collision handling start:
 | ||||
| 	// This is the code that tells us how we deal with collisions and how to
 | ||||
| 	// prevent them. To get real dynamics one has to adjust this section:
 | ||||
| 	vector3d old_velocity = incidence_entity->mVelocity; | ||||
| 	new_velocity = old_velocity + info.normal * proj * (-1.0); | ||||
| 	incidence_entity->SetVelocity (new_velocity); | ||||
| 	// Collision handling end
 | ||||
| 
 | ||||
| 	// And we also add the normal to the cached contacts for both incidence
 | ||||
| 	// and reference entity
 | ||||
| 	ContactCacheAdd (incidence_entity, reference_entity, info.normal);	 | ||||
| 
 | ||||
| 	// Now we check whether we are violating any of the cached contacts. For
 | ||||
| 	// this we loop through all contacts and try to adjust the velocity of
 | ||||
| 	// incidence_entity until we no more violate the cached contacts.
 | ||||
| 	std::map<unsigned int, vector3d>::iterator iter = incidence_entity->mContactNormals.begin(); | ||||
| 	int readjust = 0; | ||||
| 	while (iter != incidence_entity->mContactNormals.end()) { | ||||
| 		vector3d contact_normal = iter->second; | ||||
| 		float contact_velocity = new_velocity * contact_normal; | ||||
| 
 | ||||
| 		if (contact_velocity < 0.) { | ||||
| 			if (reference_entity_id == iter->first) { | ||||
| 				// In this case, the projection was not good enough. We simultaneously
 | ||||
| 				// damp the velocity and push a little harder. If it was damped too
 | ||||
| 				// much or we had to readjust too often, we set the velocity to zero.
 | ||||
| 				LogDebug ("Resolved collision needs to be readjusted"); | ||||
| 				new_velocity = incidence_entity->GetVelocity(); | ||||
| 				new_velocity *= 0.5; | ||||
| 				if (new_velocity.length2() < EPSILON) | ||||
| 					new_velocity.setValues (0., 0., 0.); | ||||
| 				else  | ||||
| 					new_velocity += info.normal * 0.001; | ||||
| 				incidence_entity->SetVelocity (new_velocity); | ||||
| 				readjust++; | ||||
| 
 | ||||
| 				// More than 10 readjusts? -> set velocity to zero
 | ||||
| 				if (readjust > 10) | ||||
| 					new_velocity.setValues (0., 0., 0.); | ||||
| 				 | ||||
| 				// and we redo all the checking:
 | ||||
| 				iter = incidence_entity->mContactNormals.begin(); | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			// In this case the proposed velocity is violating another contact
 | ||||
| 			// and we set the velocity to zero.
 | ||||
| 			LogDebug ("Cached collision: %e -> resetting velocity", contact_velocity); | ||||
| //			contact_normal.print ("contact normal: ");
 | ||||
| 			new_velocity.setValues (0., 0., 0.); | ||||
| 			incidence_entity->mVelocity = new_velocity; | ||||
| 		} else if (contact_velocity > 0.01) { | ||||
| 			// If we move sufficiently fast away from a contact we remove the
 | ||||
| 			// contact from the cache.
 | ||||
| 			 | ||||
| 			// * Attention! * As the function ContactCacheRemove() deletes an entry
 | ||||
| 			// of mContactNormals we have to increase the iterator *before* we
 | ||||
| 			// remove the cache. Otherwise the iterator might become invalid!
 | ||||
| 			unsigned int contact_id = iter->first; | ||||
| 			iter++; | ||||
| 
 | ||||
| 			ContactCacheRemove (contact_id, incidence_entity_id); | ||||
| 
 | ||||
| 			continue; | ||||
| 		} | ||||
| 		iter++; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Contact Cache Functions | ||||
|  */ | ||||
| void PhysicsBase::ContactCacheAdd (EntityPhysicState* incidence_entity, EntityPhysicState* reference_entity, vector3d normal) { | ||||
| 	incidence_entity->mContactNormals[reference_entity->mId] = normal; | ||||
| 	reference_entity->mContactNormals[incidence_entity->mId] = normal * -1.; | ||||
| 
 | ||||
| 	LogDebug ("Adding normal (%f,%f,%f) id=%d to entity %d", | ||||
| 			normal[0], normal[1], normal[2],  | ||||
| 			reference_entity->mId, incidence_entity->mId); | ||||
| 	LogDebug ("Adding normal (%f,%f,%f) id=%d to entity %d", | ||||
| 			normal[0] * -1., normal[1] * -1., normal[2] * -1.,  | ||||
| 			incidence_entity->mId, reference_entity->mId); | ||||
| } | ||||
| 
 | ||||
| void PhysicsBase::ContactCacheRemove (unsigned int entity_a_id, unsigned int entity_b_id) { | ||||
| 	assert (entity_a_id != entity_b_id); | ||||
| 
 | ||||
| //	LogDebug ("Removing start %d and %d", entity_a_id, entity_b_id);
 | ||||
| 
 | ||||
| 	EntityPhysicState *entity_a, *entity_b; | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	entity_a = mEntities[entity_a_id]; | ||||
| 	entity_b = mEntities[entity_b_id]; | ||||
| #else | ||||
| 	entity_a = mEntities.at(entity_a_id); | ||||
| 	entity_b = mEntities.at(entity_b_id); | ||||
| #endif | ||||
| 
 | ||||
| 	// Check the entries exist
 | ||||
| 	assert (entity_a->mContactNormals.find (entity_b_id) != entity_a->mContactNormals.end()); | ||||
| 	assert (entity_b->mContactNormals.find (entity_a_id) != entity_b->mContactNormals.end()); | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	vector3d contact_normal = entity_a->mContactNormals[entity_b_id]; | ||||
| #else | ||||
| 	vector3d contact_normal = entity_a->mContactNormals.at(entity_b_id); | ||||
| #endif | ||||
| 
 | ||||
| 	LogDebug ("Removing normal (%f,%f,%f) id=%d from entity %d", | ||||
| 			contact_normal[0], contact_normal[1], contact_normal[2], | ||||
| 			entity_a_id, entity_b_id); | ||||
| 	entity_a->mContactNormals.erase (entity_a->mContactNormals.find(entity_b_id)); | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	contact_normal = entity_b->mContactNormals[entity_a_id]; | ||||
| #else | ||||
| 	contact_normal = entity_b->mContactNormals.at(entity_a_id); | ||||
| #endif | ||||
| 	 | ||||
| 	LogDebug ("Removing normal (%f,%f,%f) id=%d from entity %d", | ||||
| 			contact_normal[0], contact_normal[1], contact_normal[2], | ||||
| 			entity_b_id, entity_a_id); | ||||
| 	entity_b->mContactNormals.erase (entity_b->mContactNormals.find(entity_a_id)); | ||||
| 
 | ||||
| //	LogDebug ("Removing done!");
 | ||||
| } | ||||
| 
 | ||||
| /** \brief Checks whether we are still in contact with the entities stored in mContactNormals
 | ||||
|  * | ||||
|  * To check whether we still are in contact, we modify temporarily the | ||||
|  * velocity of the given Entity that it moves towards the contact point (i.e. | ||||
|  * we add the negative normal to the velocity) and re-check for a collision. | ||||
|  * If the collision has a time value of 0.0 and the reported normal stays the | ||||
|  * same, we know, that the two Entities are still in contact. If not, we lost | ||||
|  * contact. | ||||
|  * | ||||
|  * We can skip the test, if the scalar product of the normal and velocity are | ||||
|  * positive (in this case we move away from the plane) | ||||
|  */ | ||||
| void PhysicsBase::CheckContactCache (EntityPhysicState* entity) { | ||||
| 	std::map<unsigned int, vector3d>::iterator contacts_iter, current_iter; | ||||
| 
 | ||||
| 	contacts_iter = entity->mContactNormals.begin(); | ||||
| 	while (contacts_iter != entity->mContactNormals.end()) { | ||||
| 		// * Attention! *
 | ||||
| 		// current_iter can be used throughout this environment and contacts_iter
 | ||||
| 		// can already now be increased as it *must not* be used! This is due to
 | ||||
| 		// the nature of ContactCachRemove() which might make contacts_iter
 | ||||
| 		// invalid if we were using that.
 | ||||
| 		current_iter = contacts_iter; | ||||
| 		contacts_iter ++; | ||||
| 
 | ||||
| 		unsigned int contact_entity_id = contacts_iter->first; | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 		EntityPhysicState* contact_entity = mEntities[contact_entity_id]; | ||||
| #else | ||||
| 		EntityPhysicState* contact_entity = mEntities.at (contact_entity_id); | ||||
| #endif | ||||
| 	 | ||||
| 		vector3d normal = contacts_iter->second; | ||||
| 		vector3d old_velocity = entity->GetVelocity(); | ||||
| 
 | ||||
| 		// If we already move away from the normal, we delete the contact.
 | ||||
| 		if (normal * old_velocity > 0.01) { | ||||
| 			LogDebug ("Lost Contact with entity %d!", current_iter->first); | ||||
| 			ContactCacheRemove (entity->mId, current_iter->first); | ||||
| 			continue; | ||||
| 		} else { | ||||
| 			vector3d new_velocity (old_velocity); | ||||
| 			new_velocity -= normal; | ||||
| 			entity->SetVelocity (new_velocity); | ||||
| 
 | ||||
| 			entity->UpdateShape(); | ||||
| 			contact_entity->UpdateShape(); | ||||
| 
 | ||||
| 			coll2d::CollisionInfo info; | ||||
| 			int coll2d_result; | ||||
| 
 | ||||
| 			coll2d_result = coll2d::check_collision (1.0, entity->mShape, contact_entity->mShape, &info); | ||||
| 
 | ||||
| 			if (!HandleColl2dError (coll2d_result, 1.0, entity, contact_entity, info)) { | ||||
| 				// error
 | ||||
| 				LogError ("Error when performing collision check: %s\n", __FUNCTION__); | ||||
| 				assert (0); | ||||
| 			} | ||||
| 			 | ||||
| 			if (coll2d_result == 0) { | ||||
| 				// no contact, so delete it:
 | ||||
| 				LogDebug ("Lost Contact with entity %d!", current_iter->first); | ||||
| 				ContactCacheRemove (entity->mId, current_iter->first); | ||||
| 	 | ||||
| 				entity->SetVelocity (old_velocity); | ||||
| 				continue; | ||||
| 			} else if ( coll2d_result > 0){ | ||||
| 				// contact
 | ||||
| 				if (info.time != 0. || normal != info.normal) { | ||||
| 					LogError ("Something strange happened when checking for contacts in %s\n", __FUNCTION__); | ||||
| 					assert (0); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			entity->SetVelocity (old_velocity); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * So far we ignore overlapping if one entity is an EntityBaseTypeActor and | ||||
|  * the other a EntityBaseTypeParticle. | ||||
|  * | ||||
|  * If this function returns true everything is ok and we can safely continue | ||||
|  * otherwise it is recommended to quit the application. | ||||
|  * | ||||
|  * \returns true if there was no error at all or we were able to deal with it | ||||
|  */ | ||||
| bool PhysicsBase::HandleColl2dError (int coll2d_result, float stepsize, | ||||
| 		EntityPhysicState* entity_a, EntityPhysicState* entity_b, coll2d::CollisionInfo &info) | ||||
| { | ||||
| 	if (coll2d_result < 0) { | ||||
| 		if (coll2d_result == CHECK_ERROR_OVERLAP) { | ||||
| 			// this can happen if an Actor is faster than its thrown Particle,
 | ||||
| 			// we ignore this for now
 | ||||
| 			/// \todo Handle overlaps of Actors and Particles better or define clear guidelines. Note this also in Entity.h
 | ||||
| 			if ( (entity_a->mBaseType == EntityBaseTypeParticle && entity_b->mBaseType == EntityBaseTypeActor)  | ||||
| 					|| (entity_b->mBaseType == EntityBaseTypeParticle && entity_a->mBaseType == EntityBaseTypeActor) ) | ||||
| 				LogDebug ("Ignoring CHECK_ERROR_OVERLAP"); | ||||
| 			return true; | ||||
| 		} else { | ||||
| 			LogError ("coll2d Error: %d (stepsize = %f, id_a = %d, id_b = %d)", coll2d_result, stepsize, entity_a->mId, entity_b->mId); | ||||
| 			entity_a->mShape->doPrint ("Debug: entity_a"); | ||||
| 			entity_b->mShape->doPrint ("Debug: entity_b"); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| EntityPhysicState* CreateEntityPhysicState (EntityBaseType type, unsigned int id) { | ||||
| 	EntityPhysicState* entity_physics = new EntityPhysicState (); | ||||
| 	if (!entity_physics) { | ||||
| 		LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 	// default values for all Entities
 | ||||
| 	entity_physics->mId = id; | ||||
| 	entity_physics->mBaseType = type; | ||||
| 
 | ||||
|   // specific values for each Entity type
 | ||||
| 	if (type == EntityBaseTypeNone) { | ||||
| 		entity_physics->mShape = new coll2d::Sphere (0.01); | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else if (type == EntityBaseTypeActor) { | ||||
| 		entity_physics->mShape = new coll2d::Sphere (0.4); | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else if (type == EntityBaseTypeBlock) { | ||||
| 		entity_physics->mShape = new coll2d::Polygon (4); | ||||
| 		assert (entity_physics->mShape); | ||||
| 
 | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (0, vector3d (-0.5, 0., 0.5)); | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (1, vector3d (0.5, 0., 0.5)); | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (2, vector3d (0.5, 0., -0.5)); | ||||
| 		static_cast<coll2d::Polygon*> (entity_physics->mShape)->setVertice (3, vector3d (-0.5, 0., -0.5)); | ||||
| 	} else if (type == EntityBaseTypeParticle) { | ||||
| 		entity_physics->mShape = new coll2d::Sphere (0.05); | ||||
| 		assert (entity_physics->mShape); | ||||
| 	} else { | ||||
| 		LogError ("No EntityPhysicState defined for Entity type '%d'", type); | ||||
| 		assert (0); | ||||
| 	} | ||||
| 
 | ||||
| 	return entity_physics; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										91
									
								
								engine/PhysicsBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								engine/PhysicsBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| #ifndef _PHYSICSBASE_H | ||||
| #define _PHYSICSBASE_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| namespace coll2d { | ||||
| 	struct CollisionInfo; | ||||
| } | ||||
| 
 | ||||
| /// \todo get rid of this forward declaration somehow
 | ||||
| struct vector3d; | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Module; | ||||
| class Events; | ||||
| 
 | ||||
| class EntityPhysicState; | ||||
| 
 | ||||
| /** \brief Performs the physical simulation of all Entities
 | ||||
|  * | ||||
|  * This class defines how the physical simulation is performed. Especially how | ||||
|  * collisions are treated is defined in the function | ||||
|  * Physics::ResolveCollision() . This function can be modified to simulate | ||||
|  * dynamics effects such as friction, bouncing, stacking etc.. | ||||
|  * | ||||
|  * \todo When running along multiple boxes that are perfectly aligned one hangs from time to time at the last box | ||||
|  */ | ||||
| class PhysicsBase : public Module {  | ||||
| 	public: | ||||
| 		/** \brief Performs the simulation for the next msec milliseconds
 | ||||
| 		 * \param msec The amount of time that is to be simulated | ||||
| 		 * \param model A pointer to the model that will be used to pass on collision events.*/ | ||||
| 		virtual int Simulate (float msec, ModelBase* model = NULL); | ||||
| 		/** \brief Registers the physical state of an Entity */ | ||||
| 		virtual void RegisterEntity (EntityPhysicState* entity); | ||||
| 		/** \brief Unregisters the physical state of an Entity */ | ||||
| 		virtual void UnregisterEntity (const unsigned int id); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		virtual int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		virtual void OnDestroy (); | ||||
| 
 | ||||
| 		/** \brief Moves all Entities for delta_msec milliseconds (can be
 | ||||
| 		 * negative!) */ | ||||
| 		void Move (float delta_msec); | ||||
| 
 | ||||
| 		/** \brief Checks whether two given Entities can collide */ | ||||
| 		bool CheckPossibleCollisionPair (EntityPhysicState* entity_a, EntityPhysicState* entity_b); | ||||
| 		/** \brief Calculates the next pair of Entities that will collide */ | ||||
| 		bool CalcNextCollision (float stepsize, | ||||
| 				unsigned int &reference_entity_id, | ||||
| 				unsigned int &incidence_entity_id, | ||||
| 				coll2d::CollisionInfo &info); | ||||
| 		/** \brief Resolves the collision that CalcNextCollision has found
 | ||||
| 		 * It resolves a found collision and prevents interpenetration of cached contacts. | ||||
| 		 */ | ||||
| 		void ResolveCollision (float stepsize, | ||||
| 				unsigned int reference_entity_id, | ||||
| 				unsigned int incidence_entity_id, | ||||
| 				coll2d::CollisionInfo &info); | ||||
| 
 | ||||
| 		/** \brief Contains all Entities with a physical state */ | ||||
| 		std::map<unsigned int, EntityPhysicState*> mEntities; | ||||
| 
 | ||||
| 	private: | ||||
| 		 /** \brief Caches the contact information between two entities
 | ||||
| 			*/ | ||||
| 		 void ContactCacheAdd (EntityPhysicState* incidence_entity, EntityPhysicState* reference_entity, vector3d normal); | ||||
| 		 /** \brief Removes the contact cache information of two entities in contact
 | ||||
| 			*/ | ||||
| 		 void ContactCacheRemove (unsigned int entity_a_id, unsigned int entity_b_id); | ||||
| 		 /** \brief Checks whether the entries in the contact cache are still valid
 | ||||
| 		  */ | ||||
| 		 void CheckContactCache (EntityPhysicState* entity); | ||||
| 
 | ||||
| 		 /** \brief Allows to ignore certain kinds of errors reported by coll2d
 | ||||
| 			*/ | ||||
| 		 bool HandleColl2dError (int coll2d_result, float stepsize, | ||||
| 		EntityPhysicState* entity_a, EntityPhysicState* entity_b, coll2d::CollisionInfo &info); | ||||
| }; | ||||
| 
 | ||||
| /** \brief Creates an EntityPhysicState with all the required information */ | ||||
| EntityPhysicState* CreateEntityPhysicState (EntityBaseType type, unsigned int id); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _PHYSICSBASE_H
 | ||||
							
								
								
									
										149
									
								
								engine/PhysicsEntityBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								engine/PhysicsEntityBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| #include "coll2d.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Copy constructor */ | ||||
| inline EntityPhysicState::EntityPhysicState (const EntityPhysicState& state): | ||||
| 	mId (state.mId), | ||||
| 	mBaseType (state.mBaseType), | ||||
| 	mPosition (state.mPosition), | ||||
| 	mOrientation (state.mOrientation), | ||||
| 	mVelocity (state.mVelocity), | ||||
| 	mAngleVelocity (state.mAngleVelocity), | ||||
| 	mStatic (state.mStatic), | ||||
| 	mAlive (state.mAlive), | ||||
| 	mContactNormals(state.mContactNormals) | ||||
| { | ||||
| 	mShape = state.mShape->getCopy(); | ||||
| }; | ||||
| 
 | ||||
| /** \brief Assignment operator */ | ||||
| inline EntityPhysicState& EntityPhysicState::operator= (const EntityPhysicState& state) { | ||||
| 	if (this != &state) { | ||||
| 		mId = state.mId; | ||||
| 		mBaseType = state.mBaseType; | ||||
| 		mPosition = state.mPosition; | ||||
| 		mOrientation = state.mOrientation; | ||||
| 		mVelocity = state.mVelocity; | ||||
| 		mAngleVelocity = state.mAngleVelocity; | ||||
| 		mShape = state.mShape->getCopy(); | ||||
| 		mStatic = state.mStatic; | ||||
| 		mAlive = state.mAlive; | ||||
| 		mContactNormals = state.mContactNormals; | ||||
| 	} | ||||
| 
 | ||||
| 	return *this; | ||||
| } | ||||
| 
 | ||||
| vector3d& EntityPhysicState::GetPosition () { | ||||
| 	return mPosition; | ||||
| } | ||||
| 
 | ||||
| vector3d& EntityPhysicState::GetVelocity () { | ||||
| 	return mVelocity; | ||||
| } | ||||
| 
 | ||||
| vector3d& EntityPhysicState::GetOrientation () { | ||||
| 	return mOrientation; | ||||
| } | ||||
| 
 | ||||
| float& EntityPhysicState::GetAngleVelocity () { | ||||
| 	return mAngleVelocity; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::SetPosition (const vector3d &position) { | ||||
| 	mPosition = position; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::SetVelocity (const vector3d &velocity) { | ||||
| 	mVelocity = velocity; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::SetOrientation (const vector3d &orientation) { | ||||
| 	mOrientation = orientation; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::SetAngleVelocity (const float &angle_velocity) { | ||||
| 	mAngleVelocity = angle_velocity; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::Globalize (vector3d &vec) { | ||||
| 	// make a copy of the local coordinates
 | ||||
| 	vector3d local (vec); | ||||
| 
 | ||||
| 	// calculate sin and cos for the current rotation
 | ||||
| 	float sintheta, costheta; | ||||
| 	sintheta = sin (- mOrientation[1] * M_PI / 180); | ||||
| 	costheta = cos (- mOrientation[1] * M_PI / 180); | ||||
| 
 | ||||
| 	// rotation
 | ||||
| 	vec[0] = - sintheta * local[2] + costheta * local[0]; | ||||
| 	vec[1] = local[1]; | ||||
| 	vec[2] = costheta * local[2] + sintheta * local[0] ; | ||||
| 
 | ||||
| 	// and translation
 | ||||
| 	vec += mPosition; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::Localize (vector3d &vec) { | ||||
| 	// translation
 | ||||
| 	vec -= mPosition; | ||||
| 
 | ||||
| 	vector3d global (vec); | ||||
| 
 | ||||
| 	// calculate sin and cos for the current rotation
 | ||||
| 	float sintheta, costheta; | ||||
| 	sintheta = sin (mOrientation[1] * M_PI / 180); | ||||
| 	costheta = cos (mOrientation[1] * M_PI / 180); | ||||
| 
 | ||||
| 	// rotation
 | ||||
| 	vec[0] = - sintheta * global[2] + costheta * global[0]; | ||||
| 	vec[1] = global[1]; | ||||
| 	vec[2] = costheta * global[2] + sintheta * global[0] ; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::GlobalizeRotation (vector3d &vec) { | ||||
| 	// make a copy of the local coordinates
 | ||||
| 	vector3d local (vec); | ||||
| 
 | ||||
| 	// calculate sin and cos for the current rotation
 | ||||
| 	float sintheta, costheta; | ||||
| 	sintheta = sin (- mOrientation[1] * M_PI / 180); | ||||
| 	costheta = cos (- mOrientation[1] * M_PI / 180); | ||||
| 
 | ||||
| 	// rotation
 | ||||
| 	vec[0] = - sintheta * local[2] + costheta * local[0]; | ||||
| 	vec[1] = local[1]; | ||||
| 	vec[2] = costheta * local[2] + sintheta * local[0] ; | ||||
| } | ||||
| 
 | ||||
| void EntityPhysicState::LocalizeRotation (vector3d &vec) { | ||||
| 	vector3d global (vec); | ||||
| 
 | ||||
| 	// calculate sin and cos for the current rotation
 | ||||
| 	float sintheta, costheta; | ||||
| 	sintheta = sin (mOrientation[1] * M_PI / 180); | ||||
| 	costheta = cos (mOrientation[1] * M_PI / 180); | ||||
| 
 | ||||
| 	// rotation
 | ||||
| 	vec[0] = - sintheta * global[2] + costheta * global[0]; | ||||
| 	vec[1] = global[1]; | ||||
| 	vec[2] = costheta * global[2] + sintheta * global[0] ; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void EntityPhysicState::UpdateShape () { | ||||
| 	assert (mShape); | ||||
| 
 | ||||
| 	mShape->setPosition (mPosition); | ||||
| 	mShape->setAngle (mOrientation[1] * M_PI / 180); | ||||
| 
 | ||||
| 	mShape->setVelocity (mVelocity); | ||||
| 	mShape->setAngleVelocity (mAngleVelocity); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										220
									
								
								engine/SimpleConsoleOverlay.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								engine/SimpleConsoleOverlay.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,220 @@ | ||||
| #include "DrawingsGL.h" | ||||
| #include "OverlayBase.h" | ||||
| #include "SimpleConsoleOverlay.h" | ||||
| 
 | ||||
| #include "OGLFT.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| #include <GL/glu.h> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| static Variable Var_ConsoleTransparency ("consoletransparency", "0.2"); | ||||
| 
 | ||||
| bool SimpleConsoleOverlay::OnKeyDown (const SDL_keysym &keysym) { | ||||
| 	if (keysym.sym == SDLK_F8) { | ||||
| 		if (mActive) { | ||||
| 			// We have to call SetActive() to actually
 | ||||
| 			// activate the unicode processing of SDL
 | ||||
| 			SetActive (false); | ||||
| 		} | ||||
| 		else { | ||||
| 			SetActive (true); | ||||
| 		} | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!mActive) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// check for input that requires actions
 | ||||
| 	switch (keysym.sym) { | ||||
| 		case SDLK_ESCAPE: | ||||
| 			SetActive (false); | ||||
| 			return true; | ||||
| 			break; | ||||
| 		case SDLK_BACKSPACE: | ||||
| 			if (mCurrentInput.size() > 0) | ||||
| 				mCurrentInput = mCurrentInput.substr (0, mCurrentInput.size() - 1 ); | ||||
| 			return true; | ||||
| 			break; | ||||
| 		case SDLK_RETURN: | ||||
| 			if (mCurrentInput.size() == 0) { | ||||
| 				mLastLines.push_back (""); | ||||
| 				return true; | ||||
| 			} | ||||
| 
 | ||||
| 			mLastLines.push_back (mCurrentInput); | ||||
| 
 | ||||
| 			// run the command and print out the error if there was one
 | ||||
| 			if (!RunCommand (mCurrentInput)) { | ||||
| 				mLastLines.push_back ("Error: " + CommandGetErrorString()); | ||||
| 			} | ||||
| 			mCurrentInput = ""; | ||||
| 			return true; | ||||
| 
 | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	// if we got input of a character that we can write add it to the current
 | ||||
| 	// input
 | ||||
| 	if (keysym.unicode) {	 | ||||
| 		if ((keysym.unicode & 0xFF80) == 0) { | ||||
| 			mCurrentInput += keysym.unicode & 0x7F; | ||||
| 			return true; | ||||
| 		} else { | ||||
| 			LogWarning ("Input key not supported!"); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void SimpleConsoleOverlay::Draw () { | ||||
| 	// we switch to orthographic projection and draw the contents of the 2d 
 | ||||
| 	// overlay on top of the previous drawings
 | ||||
| 	glMatrixMode (GL_PROJECTION); | ||||
| 	glPushMatrix (); | ||||
| 		glLoadIdentity (); | ||||
| 
 | ||||
| 		// first we have to get the size of the current viewport to set up the
 | ||||
| 		// orthographic projection correctly
 | ||||
| 		GLint viewport[4]; | ||||
| 		glGetIntegerv(GL_VIEWPORT, viewport); | ||||
| 		gluOrtho2D (viewport[0], viewport[2], viewport[3], viewport[1]); | ||||
| 
 | ||||
| 		glMatrixMode (GL_MODELVIEW); | ||||
| 		glPushMatrix (); | ||||
| 			glLoadIdentity (); | ||||
| 
 | ||||
| 			// then we do the drawings
 | ||||
| 			if (mDrawLogBar) | ||||
| 				DrawLogBar (); | ||||
| 			if (mActive) | ||||
| 				DrawConsole (); | ||||
| 			 | ||||
| 		glPopMatrix (); | ||||
| 
 | ||||
| 		glMatrixMode (GL_PROJECTION); | ||||
| 	glPopMatrix (); | ||||
| 
 | ||||
| 	glMatrixMode (GL_MODELVIEW); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| void SimpleConsoleOverlay::DrawLogBar () { | ||||
| 	// first we have to get the size of the current viewport to set up the
 | ||||
| 	// orthographic projection correctly
 | ||||
| 	GLint viewport[4]; | ||||
| 	glGetIntegerv(GL_VIEWPORT, viewport); | ||||
| 
 | ||||
| 	// we want to enable transparency
 | ||||
| 	glDisable(GL_DEPTH_TEST); | ||||
| 	glEnable (GL_BLEND); | ||||
| 	glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); | ||||
| 
 | ||||
| 	float left = 0; | ||||
| 	float right = static_cast<float> (GetWindowWidth()); | ||||
| 	float top = 0; | ||||
| //	float bottom = static_cast<float> (GetWindowHeight());
 | ||||
| 
 | ||||
| 	// draw the background
 | ||||
| 	glColor4f (0.2, 0.2, 0.2, 0.3); | ||||
| 	glBegin (GL_QUADS); | ||||
| 	glVertex2f (left, top); | ||||
| 	glVertex2f (left, top + 16); | ||||
| 	glVertex2f (right, top + 16); | ||||
| 	glVertex2f (right, top); | ||||
| 	glEnd (); | ||||
| 
 | ||||
| 	glDisable (GL_BLEND); | ||||
| 
 | ||||
| 	// draw the log
 | ||||
| 	std::ostringstream topbar_stream; | ||||
| 	topbar_stream << "Log: " << GetLastLogEntry().mMessage; | ||||
| 	DrawGLString ( 10, 10, topbar_stream.str().c_str ()); | ||||
| 
 | ||||
| 	// draw the FPS counter
 | ||||
| 	topbar_stream.str (""); | ||||
| 	topbar_stream << "FPS: " << GetFrameRate(); | ||||
| 	DrawGLString (right - 64 , 10, topbar_stream.str().c_str ()); | ||||
| 
 | ||||
| 	glEnable (GL_DEPTH_TEST); | ||||
| } | ||||
| 
 | ||||
| void SimpleConsoleOverlay::DrawConsole () { | ||||
| 	// first we have to get the size of the current viewport to set up the
 | ||||
| 	// orthographic projection correctly
 | ||||
| 	GLint viewport[4]; | ||||
| 	glGetIntegerv(GL_VIEWPORT, viewport); | ||||
| 
 | ||||
| 	// we want to enable transparency
 | ||||
| 	glDisable(GL_DEPTH_TEST); | ||||
| //	glEnable (GL_BLEND);
 | ||||
| //	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 | ||||
| //	glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA);
 | ||||
| 
 | ||||
| 	// calculate the screen coordinates which defines the size of the
 | ||||
| 	// console
 | ||||
| 	mLeft = (viewport[2] - viewport[0]) * 0.5 - (viewport[2] - viewport[0]) * 0.45 ; | ||||
| 	mRight = (viewport[2] - viewport[0]) * 0.5 + (viewport[2] - viewport[0]) * 0.45; | ||||
| 	mTop = -1; // Do not draw the mTop line
 | ||||
| 	mBottom = (viewport[3] - viewport[1]) * 0.7; | ||||
| 
 | ||||
| 	// draw the background
 | ||||
| 	glColor4f (0.2, 0.2, 0.2, Var_ConsoleTransparency.GetFloatValue()); | ||||
| 	glBegin (GL_QUADS); | ||||
| 	glVertex2f (mLeft, mTop); | ||||
| 	glVertex2f (mLeft, mBottom); | ||||
| 	glVertex2f (mRight, mBottom); | ||||
| 	glVertex2f (mRight, mTop); | ||||
| 	glEnd (); | ||||
| 
 | ||||
| 	// draw borders
 | ||||
| 	glColor3f (0.9, 0.9, 0.9); | ||||
| 	glBegin (GL_LINE_STRIP); | ||||
| 	glVertex2f (mLeft, mTop); | ||||
| 	glVertex2f (mLeft, mBottom); | ||||
| 	glVertex2f (mRight, mBottom); | ||||
| 	glVertex2f (mRight, mTop); | ||||
| 	glVertex2f (mLeft, mTop); | ||||
| 	glEnd (); | ||||
| 
 | ||||
| 	glDisable (GL_BLEND); | ||||
| 
 | ||||
| 	// now draw the contents
 | ||||
| 	DrawLastLines (); | ||||
| 	DrawCurrentInput (); | ||||
| 
 | ||||
| 	glEnable (GL_DEPTH_TEST); | ||||
| } | ||||
| 
 | ||||
| const std::vector<std::string> SimpleConsoleOverlay::GetLastLines (const unsigned int n) { | ||||
| 	assert (0); | ||||
| 	std::vector<std::string> result; | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void SimpleConsoleOverlay::DrawLastLines () { | ||||
| 	unsigned int i; | ||||
| 	for (i = 0; i < mLastLines.size(); i++) | ||||
| 		DrawGLString (mLeft + 8, mTop + 12 + 12 *i, mLastLines[i].c_str()); | ||||
| } | ||||
| 
 | ||||
| void SimpleConsoleOverlay::DrawCurrentInput () { | ||||
| 	// We add a '_' to the current input as a simple cursor
 | ||||
| 	static std::string current_input; | ||||
| 	current_input = mCurrentInput + "_"; | ||||
|   | ||||
| 	// We add a '>' at the beginning of the input line to highlight it
 | ||||
| 	DrawGLString (mLeft, mTop + 12 + 12 * (mLastLines.size()), ">"); | ||||
| 	DrawGLString (mLeft + 8, mTop + 12 + 12 * (mLastLines.size()), current_input.c_str()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										69
									
								
								engine/SimpleConsoleOverlay.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								engine/SimpleConsoleOverlay.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| #ifndef SIMPLECONSOLEOVERLAY | ||||
| #define SIMPLECONSOLEOVERLAY | ||||
| 
 | ||||
| #include "Variables.h" | ||||
| 
 | ||||
| #include <SDL/SDL.h> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class OverlayBase; | ||||
| 
 | ||||
| class SimpleConsoleOverlay : public OverlayBase { | ||||
| 	public: | ||||
| 		SimpleConsoleOverlay () { | ||||
| 			mActive = false; | ||||
| 			mDrawLogBar = false; | ||||
| 		}; | ||||
| 		virtual ~SimpleConsoleOverlay() {}; | ||||
| 
 | ||||
| 		virtual bool OnKeyDown (const SDL_keysym &keysym); | ||||
| 		virtual bool OnKeyUp (const SDL_keysym &keysym) { | ||||
| 			if(mActive) | ||||
| 				return true; | ||||
| 			return false; | ||||
| 		}; | ||||
| 
 | ||||
| 		virtual void Draw (); | ||||
| 
 | ||||
| 		void DrawLogBar (); | ||||
| 		void DrawConsole (); | ||||
| 	 | ||||
| 		/** \brief Returns the last n lines */ | ||||
| 		const std::vector<std::string> GetLastLines (const unsigned int n); | ||||
| 		/** \brief Returns true if the Console is active */ | ||||
| 		bool GetActive () { return mActive; }; | ||||
| 		/** \brief Activates or deactivates the the Console */ | ||||
| 		void SetActive (bool active) {  | ||||
| 			if (active) { | ||||
| 				SDL_EnableUNICODE (1); | ||||
| 				SDL_EnableKeyRepeat (500, 50); | ||||
| 			} | ||||
| 			else { | ||||
| 				SDL_EnableUNICODE (-1); | ||||
| 				SDL_EnableKeyRepeat (0, 100); | ||||
| 			} | ||||
| 			mActive = active; | ||||
| 		}; | ||||
| 		void SetDrawLogBar (bool value) { mDrawLogBar = value; }; | ||||
| 
 | ||||
| 		/** \brief Draws the console with the current content */ | ||||
| 		void DrawLastLines (); | ||||
| 		void DrawCurrentInput (); | ||||
| 
 | ||||
| 	private: | ||||
| 		std::vector<std::string> mLastLines; | ||||
| 		std::string mCurrentInput; | ||||
| 		bool mActive; | ||||
| 		bool mDrawLogBar; | ||||
| 
 | ||||
| 		float mLeft; | ||||
| 		float mTop; | ||||
| 		float mRight; | ||||
| 		float mBottom; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* SIMPLECONSOLEOVERLAY */ | ||||
							
								
								
									
										237
									
								
								engine/Sprite.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								engine/Sprite.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,237 @@ | ||||
| #include "Engine.h" | ||||
| #include "Sprite.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| #include <GL/glu.h> | ||||
| #include <png.h> | ||||
| 
 | ||||
| #include <cmath> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /* 
 | ||||
|  * Code is taken from http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures on
 | ||||
|  * Sunday, March 14 2010. | ||||
|  */ | ||||
| bool Sprite::LoadFromPNG (const char *filename) { | ||||
| 	LogDebug ("Loading png from %s", filename); | ||||
| 
 | ||||
| 	//header for testing if it is a png
 | ||||
| 	png_byte header[8]; | ||||
| 
 | ||||
| 	//open file as binary
 | ||||
| 	FILE *fp = fopen(filename, "rb"); | ||||
| 	if (!fp) { | ||||
| 		LogError ("Could not open file: %s", filename); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	//read the header
 | ||||
| 	fread(header, 1, 8, fp); | ||||
| 
 | ||||
| 	//test if png
 | ||||
| 	int is_png = !png_sig_cmp(header, 0, 8); | ||||
| 	if (!is_png) { | ||||
| 		LogError ("Error opening png file %s: file is not a png file!", filename); | ||||
| 		fclose(fp); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	//create png struct
 | ||||
| 	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, | ||||
| 			NULL, NULL); | ||||
| 	if (!png_ptr) { | ||||
| 		LogError ("Error opening png file %s: unable to read png header", filename); | ||||
| 		fclose(fp); | ||||
| 		return (false); | ||||
| 	} | ||||
| 
 | ||||
| 	//create png info struct
 | ||||
| 	png_infop info_ptr = png_create_info_struct(png_ptr); | ||||
| 	if (!info_ptr) { | ||||
| 		LogError ("Error opening png file %s: unable to read png header", filename); | ||||
| 		png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); | ||||
| 		fclose(fp); | ||||
| 		return (false); | ||||
| 	} | ||||
| 
 | ||||
| 	//create png info struct
 | ||||
| 	png_infop end_info = png_create_info_struct(png_ptr); | ||||
| 	if (!end_info) { | ||||
| 		LogError ("Error opening png file %s: unable to read png header", filename); | ||||
| 		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); | ||||
| 		fclose(fp); | ||||
| 		return (false); | ||||
| 	} | ||||
| 
 | ||||
| 	//png error stuff, not sure libpng man suggests this.
 | ||||
| 	if (setjmp(png_jmpbuf(png_ptr))) { | ||||
| 		LogError ("Error opening png file %s: unable to read png header", filename); | ||||
| 		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); | ||||
| 		fclose(fp); | ||||
| 		return (false); | ||||
| 	} | ||||
| 
 | ||||
| 	//init png reading
 | ||||
| 	png_init_io(png_ptr, fp); | ||||
| 
 | ||||
| 	//let libpng know you already read the first 8 bytes
 | ||||
| 	png_set_sig_bytes(png_ptr, 8); | ||||
| 
 | ||||
| 	// read all the info up to the image data
 | ||||
| 	png_read_info(png_ptr, info_ptr); | ||||
| 
 | ||||
| 	//variables to pass to get info
 | ||||
| 	int bit_depth, color_type; | ||||
| 	png_uint_32 tmWidth, tmHeight; | ||||
| 
 | ||||
| 	// get info about png
 | ||||
| 	png_get_IHDR(png_ptr, info_ptr, &tmWidth, &tmHeight, &bit_depth, &color_type, | ||||
| 			NULL, NULL, NULL); | ||||
| 
 | ||||
| 	//update mWidth and mHeight based on png info
 | ||||
| 	mWidth = tmWidth; | ||||
| 	mHeight = tmHeight; | ||||
| 	 | ||||
| 	// Update the png info struct.
 | ||||
| 	png_read_update_info(png_ptr, info_ptr); | ||||
| 
 | ||||
| 	// Row size in bytes.
 | ||||
| 	int rowbytes = png_get_rowbytes(png_ptr, info_ptr); | ||||
| 
 | ||||
| 	// Allocate the image_data as a big block, to be given to opengl
 | ||||
| 	png_byte *image_data = new png_byte[rowbytes * mHeight]; | ||||
| 	if (!image_data) { | ||||
| 		//clean up memory and close stuff
 | ||||
| 		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); | ||||
| 		fclose(fp); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	//row_pointers is for pointing to image_data for reading the png with libpng
 | ||||
| 	png_bytep *row_pointers = new png_bytep[mHeight]; | ||||
| 	if (!row_pointers) { | ||||
| 		//clean up memory and close stuff
 | ||||
| 		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); | ||||
| 		delete[] image_data; | ||||
| 		fclose(fp); | ||||
| 		return false; | ||||
| 	} | ||||
| 	// set the individual row_pointers to point at the correct offsets of image_data
 | ||||
| 	for (unsigned int i = 0; i < mHeight; ++i) | ||||
| 		row_pointers[mHeight - 1 - i] = image_data + i * rowbytes; | ||||
| 
 | ||||
| 	//read the png into image_data through row_pointers
 | ||||
| 	png_read_image(png_ptr, row_pointers); | ||||
| 
 | ||||
| 	//Now generate the OpenGL texture object
 | ||||
| 	glGenTextures(1, &mGlTextureName); | ||||
| 	glBindTexture(GL_TEXTURE_2D, mGlTextureName); | ||||
| 	glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, mWidth, mHeight, 0, | ||||
| 			GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*) image_data); | ||||
| 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||
| 
 | ||||
| 	//clean up memory and close stuff
 | ||||
| 	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); | ||||
| 	delete[] row_pointers; | ||||
| 	delete[] image_data; | ||||
| 
 | ||||
| 	fclose(fp); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void Sprite::DrawAt (float xpos, float ypos, float zpos) { | ||||
| 	float u_start = 0., u_end = 1.; | ||||
| 	if (mAnimation) { | ||||
| 		int frame_index = floor ( (mAnimationFrameRate) * mAnimationTimer); | ||||
| 		u_start = static_cast<float>(frame_index) / mAnimationFrameCount; | ||||
| 		u_end = (frame_index + 1.) / mAnimationFrameCount; | ||||
| 	} | ||||
| 
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef (xpos -mScale * mWidth * 0.5, ypos, zpos -mScale * mHeight * 0.5); | ||||
| 	glScalef (mScale, mScale, mScale); | ||||
| 	glDisable(GL_DEPTH_TEST); | ||||
| 	glEnable(GL_TEXTURE_2D); | ||||
| 	glEnable(GL_BLEND); | ||||
| 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
| 
 | ||||
| 	glBindTexture (GL_TEXTURE_2D, mGlTextureName); | ||||
| 
 | ||||
| 	glBegin(GL_QUADS); | ||||
| 	glTexCoord2f (u_start, 0.); glVertex3f (0., 0., 0.); | ||||
| 	glTexCoord2f (u_end, 0.); glVertex3f (0., 0., mHeight); | ||||
| 	glTexCoord2f (u_end, 1.); glVertex3f (mWidth, 0., mHeight); | ||||
| 	glTexCoord2f (u_start, 1.); glVertex3f (mWidth, 0.,0.); | ||||
| 	glEnd(); | ||||
| 
 | ||||
| 	glPopMatrix(); | ||||
| 
 | ||||
| 	glDisable(GL_TEXTURE_2D); | ||||
| 	glEnable(GL_DEPTH_TEST); | ||||
| } | ||||
| 
 | ||||
| void Sprite::DrawAt2D (float xpos, float ypos) { | ||||
| 	float u_start = 0., u_end = 1.; | ||||
| 	if (mAnimation) { | ||||
| 		int frame_index = floor ( (mAnimationFrameRate) * mAnimationTimer); | ||||
| 		u_start = static_cast<float>(frame_index) / mAnimationFrameCount; | ||||
| 		u_end = (frame_index + 1.) / mAnimationFrameCount; | ||||
| 	} | ||||
| 
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef (xpos -mScale * mWidth * 0.5, ypos, 0.); | ||||
| 	glScalef (mScale, mScale, mScale); | ||||
| 	// \TODO Make 2d drawing of sprites a bit nicer, seems a bit overkill for such a simple function
 | ||||
| 	glRotatef (-90, 0., 0., 1.); | ||||
| 	glDisable(GL_DEPTH_TEST); | ||||
| 	glEnable(GL_TEXTURE_2D); | ||||
| 	glEnable(GL_BLEND); | ||||
| 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
| 
 | ||||
| 	glBindTexture (GL_TEXTURE_2D, mGlTextureName); | ||||
| 
 | ||||
| 	glBegin(GL_QUADS); | ||||
| 	glTexCoord2f (u_start, 0.); glVertex2f (0., 0.); | ||||
| 	glTexCoord2f (u_end, 0.); glVertex2f (0., mHeight); | ||||
| 	glTexCoord2f (u_end, 1.); glVertex2f (mWidth, mHeight); | ||||
| 	glTexCoord2f (u_start, 1.); glVertex2f (mWidth,0.); | ||||
| 	glEnd(); | ||||
| 
 | ||||
| 	glPopMatrix(); | ||||
| 
 | ||||
| 	glDisable(GL_TEXTURE_2D); | ||||
| 	glEnable(GL_DEPTH_TEST); | ||||
| } | ||||
| 
 | ||||
| void Sprite::DrawSubAt (unsigned int index, float xpos, float ypos, float zpos) { | ||||
| 	assert (index < mSubSpriteCount); | ||||
| 
 | ||||
| 	float u_start = static_cast<float>(index) / mSubSpriteCount; | ||||
| 	float u_end = (index + 1.) / mSubSpriteCount; | ||||
| 
 | ||||
| 	glPushMatrix(); | ||||
| 	glTranslatef (xpos -mScale * mWidth * 0.5, ypos, zpos -mScale * mHeight * 0.5); | ||||
| 	glScalef (mScale, mScale, mScale); | ||||
| 	glDisable(GL_DEPTH_TEST); | ||||
| 	glEnable(GL_TEXTURE_2D); | ||||
| 	glEnable(GL_BLEND); | ||||
| 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
| 
 | ||||
| 	glBindTexture (GL_TEXTURE_2D, mGlTextureName); | ||||
| 
 | ||||
| 	glBegin(GL_QUADS); | ||||
| 	glTexCoord2f (u_start, 0.); glVertex3f (0., 0., 0.); | ||||
| 	glTexCoord2f (u_end, 0.); glVertex3f (0., 0., mHeight); | ||||
| 	glTexCoord2f (u_end, 1.); glVertex3f (mWidth, 0., mHeight); | ||||
| 	glTexCoord2f (u_start, 1.); glVertex3f (mWidth, 0.,0.); | ||||
| 	glEnd(); | ||||
| 
 | ||||
| 	glPopMatrix(); | ||||
| 
 | ||||
| 	glDisable(GL_TEXTURE_2D); | ||||
| 	glEnable(GL_DEPTH_TEST); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										71
									
								
								engine/Sprite.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								engine/Sprite.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| #ifndef SPRITE_H | ||||
| #define SPRITE_H | ||||
| 
 | ||||
| #include <cmath> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Sprite { | ||||
| 	public: | ||||
| 		Sprite() { | ||||
| 			mScale = 1.; | ||||
| 			mWidth = 0; | ||||
| 			mHeight = 0; | ||||
| 			mGlTextureName = 0; | ||||
| 
 | ||||
| 			mAnimation = false; | ||||
| 			mSubSpriteCount = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		bool LoadFromPNG (const char *filename); | ||||
| 		void DrawAt (float xpos, float ypos, float zpos); | ||||
| 		void DrawAt2D (float xpos, float ypos); | ||||
| 		unsigned int GetWidth() { return mWidth; }; | ||||
| 		unsigned int GetHeight() { return mHeight; }; | ||||
| 
 | ||||
| 		void SetScale (float scale) { mScale = scale; }; | ||||
| 
 | ||||
| 		void SetAnimation (int frame_count, float frame_rate) { | ||||
| 			mAnimation = true; | ||||
| 			mAnimationFrameCount = frame_count; | ||||
| 			mAnimationFrameRate = frame_rate; | ||||
| 			mAnimationTimer = 0.; | ||||
| 			mWidth = static_cast<unsigned int>(ceil (static_cast<float> (mWidth / mAnimationFrameCount))); | ||||
| 		} | ||||
| 		void ResetAnimation () { | ||||
| 			mAnimationTimer = 0.; | ||||
| 		} | ||||
| 		void UpdateAnimation (float seconds) { | ||||
| 			mAnimationTimer += seconds; | ||||
| 			while (mAnimationTimer >= mAnimationFrameCount / mAnimationFrameRate) { | ||||
| 				mAnimationTimer -= mAnimationFrameCount / mAnimationFrameRate; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		void SetSubSpriteCount (const unsigned int count) { | ||||
| 			mSubSpriteCount = count; | ||||
| 			mWidth = static_cast<unsigned int>(ceil (static_cast<float> (mWidth / mSubSpriteCount))); | ||||
| 		} | ||||
| 		unsigned int GetSubSpriteCount () const { | ||||
| 			return mSubSpriteCount; | ||||
| 		} | ||||
| 		void DrawSubAt (unsigned int index, float xpos, float ypos, float zpos); | ||||
| 
 | ||||
| 	private: | ||||
| 		float mScale; | ||||
| 
 | ||||
| 		unsigned int mWidth; | ||||
| 		unsigned int mHeight; | ||||
| 		unsigned int mGlTextureName; | ||||
| 
 | ||||
| 		unsigned int mSubSpriteCount; | ||||
| 
 | ||||
| 		bool mAnimation; | ||||
| 		int mAnimationFrameCount; | ||||
| 		float mAnimationTimer; | ||||
| 		float mAnimationFrameRate; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* SPRITE_H */ | ||||
							
								
								
									
										159
									
								
								engine/Variables.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								engine/Variables.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,159 @@ | ||||
| #include "Variables.h" | ||||
| 
 | ||||
| #include <cstdlib> | ||||
| #include <iostream> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| Variables* VariablesInstance = NULL; | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int Variables::OnInit (int argc, char* argv[]) { | ||||
| 	LogDebug ("Variables Init"); | ||||
| 
 | ||||
| 	VariablesInstance = this; | ||||
| 
 | ||||
| 	/* This definition of a variable causes the delayed variables to be loaded,
 | ||||
| 	 * please keep it here! */ | ||||
| 	static Variable VariableSystemUp_var ("variablesystemup", "true"); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void Variables::OnDestroy () { | ||||
| 	LogDebug ("Variables Destroy"); | ||||
| 
 | ||||
| 	VariablesInstance = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| void Variables::RegisterVariable (const std::string &name, Variable *var) { | ||||
| 	LogDebug ("Registering Variable '%s'", name.c_str ()); | ||||
| 	if (mVariablesData.find (name) != mVariablesData.end()) { | ||||
| 		// Variable already existing!
 | ||||
| 		mVariablesData[name] = var; | ||||
| 
 | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	mVariablesData[name] = var; | ||||
| 	 | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Variable class | ||||
|  */ | ||||
| Variable* Variables::GetVariable (const std::string &name) { | ||||
| 	if (mVariablesData.find (name) == mVariablesData.end()) { | ||||
| 		// Variable not existing!
 | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return mVariablesData[name]; | ||||
| } | ||||
| 
 | ||||
| Variable::Variable (const std::string &name, const std::string &value) { | ||||
| 	static std::vector<Variable*> delayed_variables; | ||||
| 
 | ||||
| 	mName = name; | ||||
| 	mStringValue = value; | ||||
| 	mFloatValue = atof (value.c_str()); | ||||
| 
 | ||||
| 	if (VariablesInstance == NULL) { | ||||
| 		delayed_variables.push_back (this); | ||||
| 	} else if (delayed_variables.size() > 0) { | ||||
| 		LogDebug ("Loading delayed Variables"); | ||||
| 		unsigned int i;  | ||||
| 		for (i = 0; i < delayed_variables.size(); i ++) | ||||
| 			VariablesInstance->RegisterVariable (delayed_variables[i]->mName, delayed_variables[i]); | ||||
| 
 | ||||
| 		delayed_variables.clear (); | ||||
| 
 | ||||
| 		RegisterVariable (name); | ||||
| 	} else { | ||||
| 		RegisterVariable (name); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Variable::RegisterVariable (const std::string &name) { | ||||
| 	if (! VariablesInstance ) { | ||||
| 		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str()); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	VariablesInstance->RegisterVariable (name, this); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Global functions | ||||
|  */ | ||||
| Variable* GetVariable (const std::string &name) { | ||||
| 	if (! VariablesInstance ) { | ||||
| 		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str()); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return VariablesInstance->GetVariable (name); | ||||
| } | ||||
| 
 | ||||
| bool SetVariableValue (const std::string &name, const std::string value) { | ||||
| 	if (! VariablesInstance ) { | ||||
| 		LogError ("Unable to set Variable '%s': Variables System not initialized!", name.c_str()); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	Variable *var = VariablesInstance->GetVariable (name); | ||||
| 	if (!var) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	var->SetStringValue (value); | ||||
| 	var->SetFloatValue (atof (value.c_str())); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| std::string& GetVariableString (const std::string &name, std::string def) { | ||||
| 	/* We use a static result variable for the case that def was not passed to
 | ||||
| 	 * is function */ | ||||
| 	static std::string def_result = def; | ||||
| 
 | ||||
| 	if (! VariablesInstance ) { | ||||
| 		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str()); | ||||
| 		return def_result; | ||||
| 	} | ||||
| 
 | ||||
| 	Variable *var = VariablesInstance->GetVariable (name); | ||||
| 	if (!var) { | ||||
| 		return def_result; | ||||
| 	} | ||||
| 
 | ||||
| 	return var->GetStringValue (); | ||||
| } | ||||
| 
 | ||||
| float &GetVariableFloat (const std::string &name, float def) { | ||||
| 	/* We use a static result variable for the case that def was not passed to
 | ||||
| 	 * is function */ | ||||
| 	static float def_result = def; | ||||
| 
 | ||||
| 	if (! VariablesInstance ) { | ||||
| 		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str()); | ||||
| 		return def_result; | ||||
| 	} | ||||
| 
 | ||||
| 	Variable *var = VariablesInstance->GetVariable (name); | ||||
| 	if (!var) { | ||||
| 		return def_result; | ||||
| 	} | ||||
| 
 | ||||
| 	return var->GetFloatValue (); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										37
									
								
								engine/Variables.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								engine/Variables.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #ifndef _VARIABLES_H | ||||
| #define _VARIABLES_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| #include <assert.h> | ||||
| #include <string> | ||||
| #include <map> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Module; | ||||
| class Variable; | ||||
| 
 | ||||
| /** \brief Manages all variables that can be changed by the Model itself
 | ||||
|  * | ||||
|  * \todo make the variable names case insensitive | ||||
|  * \todo only allow certain characters in variable names | ||||
|  */ | ||||
| class Variables : public Module{ | ||||
| 	public: | ||||
| 		void RegisterVariable (const std::string &name, Variable *var); | ||||
| 		Variable *GetVariable (const std::string &name); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		void OnDestroy (); | ||||
| 		void OnRegisterCommands (); | ||||
| 
 | ||||
| 		std::map<std::string, Variable*> mVariablesData; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // _VARIABLES_H
 | ||||
							
								
								
									
										27
									
								
								engine/VariablesCommands.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								engine/VariablesCommands.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| #include "Variables.h" | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| bool Cmd_Set (const std::vector<std::string> args) { | ||||
| 	if (args.size() != 2) { | ||||
| 		CommandSetErrorString ("Usage: set <name> <value>\nSets variables <name> to value <value>."); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	Variable *test = GetVariable (args[0]); | ||||
| 	if (test) { | ||||
| 		test->SetStringValue (args[1]); | ||||
| 		test->SetFloatValue (atof (args[1].c_str())); | ||||
| 		return true; | ||||
| 	} | ||||
| 	 | ||||
| 	CommandSetErrorString ("Variable '" + args[0] +"' not found!"); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void Variables::OnRegisterCommands () { | ||||
| 	AddCommand ("set", Cmd_Set); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										68
									
								
								engine/VariablesGlobal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								engine/VariablesGlobal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| #ifndef _VARIABLESGLOBAL_H | ||||
| #define _VARIABLESGLOBAL_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| /** \brief Represents a variable that can be modified and read within the game
 | ||||
|  * | ||||
|  * \note Variables \b MUST be declared as static variables, otherwise the memory that | ||||
|  * hold their values get invalidated and the system gets unstable! | ||||
|  */ | ||||
| class Variable { | ||||
| 	public: | ||||
| 		/** \brief The constructor to be used when initializing a Variable
 | ||||
| 		 * | ||||
| 		 * \param name  The name under which the variable is engine wide | ||||
| 		 * accessible | ||||
| 		 * \param value  The value it is assigned to. | ||||
| 		 * | ||||
| 		 * The value string gets automatically converted to a float with atof (). | ||||
| 		 * Modification of a Variable must always be made with the Get*, Set* | ||||
| 		 * functions. | ||||
| 		 */ | ||||
| 		Variable (const std::string &name, const std::string &value); | ||||
| 
 | ||||
| 		/** \brief Returns the string value of the Variable */ | ||||
| 		std::string& GetStringValue () { | ||||
| 			return mStringValue; | ||||
| 		} | ||||
| 		/** \brief Returns the float value of the Variable */ | ||||
| 		float& GetFloatValue () { | ||||
| 			return mFloatValue; | ||||
| 		} | ||||
| 		void SetStringValue (const std::string &value) { | ||||
| 			mStringValue = value; | ||||
| 		} | ||||
| 		void SetFloatValue (float value) { | ||||
| 			mFloatValue = value; | ||||
| 		} | ||||
| 
 | ||||
| 	private: | ||||
| 		/** \brief The default constructor must not be used.
 | ||||
| 		 * | ||||
| 		 * Use \code | ||||
| 		 * Variable (const std::string &name, const std::string &value) | ||||
| 		 * \endcode | ||||
| 		 * instead. | ||||
| 		 * */ | ||||
| 		Variable () { assert (0); } | ||||
| 		/** \brief Registeres this Variable with the Variables System */ | ||||
| 		void RegisterVariable (const std::string &name); | ||||
| 
 | ||||
| 		std::string mName; | ||||
| 		std::string mStringValue; | ||||
| 		float mFloatValue; | ||||
| 
 | ||||
| 		friend class Variables; | ||||
| }; | ||||
| 
 | ||||
| /** \brief Provides access to a Variable stored under the given name */ | ||||
| Variable* GetVariable (const std::string &name); | ||||
| /** \brief Sets the vaule of the Variable */ | ||||
| bool SetVariableValue (const std::string &name, const std::string &value); | ||||
| /** \brief Returns the string value of the Variable with the given name */ | ||||
| std::string& GetVariableString (const std::string &name, std::string def = ""); | ||||
| /** \brief Returns the float value of the Variable with the given name */ | ||||
| float& GetVariableFloat (const std::string &name, float def = 0.); | ||||
| 
 | ||||
| } | ||||
| #endif // _VARIABLESGLOBAL_H
 | ||||
							
								
								
									
										330
									
								
								engine/ViewBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								engine/ViewBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,330 @@ | ||||
| #include "ViewBase.h" | ||||
| 
 | ||||
| #include "ModelBase.h" | ||||
| #include "ControllerBase.h" | ||||
| #include "CameraBase.h" | ||||
| #include "OverlayBase.h" | ||||
| 
 | ||||
| #include "SimpleConsoleOverlay.h" | ||||
| #include "OGLFT.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| #include <GL/glu.h> | ||||
| 
 | ||||
| #include "DrawingsGL.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| static ViewBase* ViewInstance = NULL; | ||||
| 
 | ||||
| void InitGL () { | ||||
| 	glClearColor(0.3f, 0.3f, 0.3f, 1.0f); | ||||
| 	glClearDepth(1.0); | ||||
| 	glDepthFunc(GL_LESS); | ||||
| 	glEnable(GL_DEPTH_TEST); | ||||
| 	glShadeModel(GL_SMOOTH); | ||||
| 	glEnable (GL_CULL_FACE); | ||||
| 	glDisable (GL_FOG); | ||||
| 
 | ||||
| 	glMatrixMode (GL_PROJECTION); | ||||
| 	glLoadIdentity (); | ||||
| 	glMatrixMode (GL_MODELVIEW); | ||||
| 	glLoadIdentity (); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Inherited Module functions | ||||
|  */ | ||||
| int ViewBase::OnInit (int argc, char* argv[]) { | ||||
| 	LogMessage ("View Init"); | ||||
| 
 | ||||
| 	mWindowHeight = VIEW_DEFAULT_HEIGHT; | ||||
| 	mWindowWidth = VIEW_DEFAULT_WIDTH; | ||||
| 
 | ||||
| 	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); | ||||
| 
 | ||||
| 	if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, SDL_OPENGL | SDL_RESIZABLE ) == 0 ) { | ||||
| 		LogError ("Video mode set failed: %s", SDL_GetError ()); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	InitGL (); | ||||
| 	Resize (mWindowWidth, mWindowHeight); | ||||
| 
 | ||||
| 	mConsoleFont = new OGLFT::Monochrome ("./data/fonts/console.ttf", 12); | ||||
| 
 | ||||
| 	if ( mConsoleFont == 0 || !mConsoleFont->isValid() ) { | ||||
| 		LogError ("Could not load font %s!", "./data/fonts/console.ttf"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 
 | ||||
| 	SimpleConsoleOverlay* console_overlay = new SimpleConsoleOverlay; | ||||
| 	AddOverlay (console_overlay); | ||||
| 
 | ||||
| 	mConsoleFont->setForegroundColor (1., 1., 1.); | ||||
| 
 | ||||
| 	mDrawAxis = false; | ||||
| 
 | ||||
| 	mDrawGrid = false; | ||||
| 	mGridSizeX = 8; | ||||
| 	mGridSizeZ = 8; | ||||
| 
 | ||||
| 	ViewInstance = this; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ViewBase::OnDestroy () { | ||||
| 	if (mConsoleFont ) | ||||
| 		delete mConsoleFont; | ||||
| 	mConsoleFont = NULL; | ||||
| 
 | ||||
| 	std::vector<OverlayBase*>::iterator overlay_iter = mOverlays.begin(), overlay_temp; | ||||
| 	while (overlay_iter != mOverlays.end()) { | ||||
| 		overlay_temp = overlay_iter; | ||||
| 		delete *overlay_temp; | ||||
| 
 | ||||
| 		overlay_iter++; | ||||
| 	} | ||||
| 
 | ||||
| 	ViewInstance = NULL; | ||||
| 
 | ||||
| 	LogDebug ("View Destroy"); | ||||
| } | ||||
| 
 | ||||
| void ViewBase::CalcWorldCoordinates (int screen_x, int screen_y, float world_y, float *pos_out) { | ||||
| 	GLdouble modelMatrix[16], projMatrix[16]; | ||||
| 	GLint viewport[4]; | ||||
| 	GLdouble wx, wy, wz; | ||||
| 
 | ||||
| 	glGetIntegerv (GL_VIEWPORT, viewport); | ||||
| 	glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); | ||||
| 	glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); | ||||
| 
 | ||||
| 	int realy = viewport[3] - screen_y - 1; | ||||
| 
 | ||||
| 	gluUnProject ((GLdouble) screen_x, (GLdouble) realy, 1., | ||||
| 			modelMatrix, projMatrix, viewport, &wx, &wy, &wz); | ||||
| 
 | ||||
| 	GLdouble t; | ||||
| 	GLdouble d[3]; | ||||
| 	float	eye[3]; | ||||
| 
 | ||||
| 	mCamera->GetEye (&eye[0]); | ||||
| 
 | ||||
| 	d[0] = wx - eye[0]; | ||||
| 	d[1] = wy - eye[1]; | ||||
| 	d[2] = wz - eye[2]; | ||||
| 
 | ||||
| 	assert (fabs (d[1]) >= 1.0e-3); | ||||
| 	t = -eye[1]/d[1]  + world_y; | ||||
| 
 | ||||
| 	pos_out[0] = eye[0] + t * d[0]; | ||||
| 	pos_out[1] = eye[1] + t * d[1]; | ||||
| 	pos_out[2] = eye[2] + t * d[2]; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Module specific functions | ||||
|  */ | ||||
| void ViewBase::UpdateCamera () { | ||||
| 	EntityPhysicState* player_ent = GetEntityPhysicState (GetPlayerEntityId()); | ||||
| 
 | ||||
| 	if (!player_ent) { | ||||
| 		LogError ("Could not call Model::PositionCamera(): player entity not found!"); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| 	vector3d entity_camera_distance (-2, 3, 0); | ||||
| 	vector3d entity_position = player_ent->GetPosition(); | ||||
| 	player_ent->Globalize (entity_camera_distance); | ||||
| 
 | ||||
| 	mCamera->SetEye ( | ||||
| 			entity_camera_distance[0], | ||||
| 			entity_camera_distance[1], | ||||
| 			entity_camera_distance[2] | ||||
| 			); | ||||
| 	mCamera->SetPointOfIntrest ( | ||||
| 			entity_position[0], | ||||
| 			entity_position[1], | ||||
| 			entity_position[2] | ||||
| 			); | ||||
| 
 | ||||
| 	mCamera->Update (); | ||||
| } | ||||
| 
 | ||||
| void ViewBase::Draw () { | ||||
| 	// Clear the screen
 | ||||
| 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
| 
 | ||||
| 	// update the frame rate counter
 | ||||
| 	static Uint32 this_frame_ticks; | ||||
| 	static Uint32 last_frame_ticks = 0; | ||||
| 	static Uint32 last_fps_update = 0; | ||||
| 	static int frame_counter = 0; | ||||
| 
 | ||||
|   this_frame_ticks = SDL_GetTicks (); | ||||
| 	last_fps_update += this_frame_ticks - last_frame_ticks; | ||||
| 	last_frame_ticks = this_frame_ticks; | ||||
| 	frame_counter++; | ||||
| 
 | ||||
| 	if (last_fps_update > 1000) { | ||||
| 		mFrameRate = frame_counter; | ||||
| 		last_fps_update = 0; | ||||
| 		frame_counter = 0; | ||||
| 	} | ||||
| 	 | ||||
| 	UpdateCamera (); | ||||
| 
 | ||||
| 	if (mDrawGrid) | ||||
| 		DrawGrid (); | ||||
| 
 | ||||
| 	if (mDrawAxis) | ||||
| 		DrawAxis (); | ||||
| 
 | ||||
| 	DrawWorld (); | ||||
| 
 | ||||
| 	std::vector<OverlayBase*>::iterator overlay_iter; | ||||
| 	for (overlay_iter = mOverlays.begin(); overlay_iter != mOverlays.end(); overlay_iter++) { | ||||
| 		(*overlay_iter)->Draw(); | ||||
| 	} | ||||
| 
 | ||||
| 	// and update the screen
 | ||||
| 	SDL_GL_SwapBuffers (); | ||||
| } | ||||
| 
 | ||||
| void ViewBase::DrawGLString (float x, float y, const char* str) { | ||||
| 	glPixelStorei (GL_UNPACK_ALIGNMENT, 1); | ||||
| 	mConsoleFont->draw (x, y, str); | ||||
| } | ||||
| 
 | ||||
| void ViewBase::GetCamereEye (float *eye_out) { | ||||
| 	assert (mCamera); | ||||
| 	mCamera->GetEye (eye_out); | ||||
| } | ||||
| 
 | ||||
| void ViewBase::DrawGrid () { | ||||
| 	float xmin, xmax, xstep, zmin, zmax, zstep; | ||||
| 	int i, count_x, count_z; | ||||
| 
 | ||||
| 	xmin = -mGridSizeX; | ||||
| 	xmax = mGridSizeX; | ||||
| 	zmin = -mGridSizeZ; | ||||
| 	zmax = mGridSizeZ; | ||||
| 
 | ||||
| 	count_x = mGridSizeX * 2; | ||||
| 	count_z = mGridSizeZ * 2; | ||||
| 
 | ||||
| 	xstep = 1.; | ||||
| 	zstep = 1.; | ||||
| 
 | ||||
| 	glColor3f (1., 1., 1.); | ||||
| 	glBegin (GL_LINES); | ||||
| 	for (i = 0; i <= count_x; i++) { | ||||
| 		glVertex3f (i * xstep + xmin, 0., zmin); | ||||
| 		glVertex3f (i * xstep + xmin, 0., zmax); | ||||
| 	} | ||||
| 	for (i = 0; i <= count_z; i++) { | ||||
| 		glVertex3f (xmin, 0, i * zstep + zmin); | ||||
| 		glVertex3f (xmax, 0, i * zstep + zmin); | ||||
| 	} | ||||
| 	glEnd (); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void ViewBase::DrawWorld () { | ||||
| } | ||||
| 
 | ||||
| void ViewBase::Resize (int width, int height) { | ||||
| 	if (height == 0) | ||||
| 		height = 1; | ||||
| 
 | ||||
| 	mWindowWidth = static_cast<unsigned int> (width); | ||||
| 	mWindowHeight = static_cast<unsigned int> (height); | ||||
| 
 | ||||
| 	glViewport(0, 0, width, height); | ||||
| 	glMatrixMode(GL_PROJECTION); | ||||
| 	glLoadIdentity(); | ||||
| 	gluPerspective(mCamera->GetFOVY (), float (width) / float (height), 0.1, 100); | ||||
| 
 | ||||
| 	glMatrixMode(GL_MODELVIEW); | ||||
| 	glLoadIdentity (); | ||||
| 
 | ||||
| 	LogDebug ("Resize to: %d x %d", mWindowWidth,mWindowHeight); | ||||
| 
 | ||||
| 	/** \warning
 | ||||
| 	 * This call has to be made for SDL 1.2 for 1.3 there seems to be a | ||||
| 	 * workaround, however since I do not yet run SDL 1.3 I hold on to this. | ||||
| 	 * See http://lists.libsdl.org/pipermail/sdl-libsdl.org/2008-November/067306.html
 | ||||
| 	 */ | ||||
| 	if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, SDL_OPENGL | SDL_RESIZABLE ) == 0 ) { | ||||
| 		LogError ("Video mode set failed: %s", SDL_GetError ()); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool ViewBase::SendKeyDown (const SDL_keysym &keysym) { | ||||
| 	std::vector<OverlayBase*>::iterator overlay_iter; | ||||
| 	for (overlay_iter = mOverlays.begin(); overlay_iter != mOverlays.end(); overlay_iter++) { | ||||
| 		if ( (*overlay_iter)->OnKeyDown (keysym)) | ||||
| 			return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool ViewBase::SendKeyUp (const SDL_keysym &keysym) { | ||||
| 	std::vector<OverlayBase*>::iterator overlay_iter; | ||||
| 	for (overlay_iter = mOverlays.begin(); overlay_iter != mOverlays.end(); overlay_iter++) { | ||||
| 		if ( (*overlay_iter)->OnKeyUp (keysym)) | ||||
| 			return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool ViewBase::SendMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos) { | ||||
| 	std::vector<OverlayBase*>::iterator overlay_iter; | ||||
| 	for (overlay_iter = mOverlays.begin(); overlay_iter != mOverlays.end(); overlay_iter++) { | ||||
| 		if ( (*overlay_iter)->OnMouseButtonUp (button, xpos, ypos)) | ||||
| 			return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool ViewBase::SendMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos) { | ||||
| 	std::vector<OverlayBase*>::iterator overlay_iter; | ||||
| 	for (overlay_iter = mOverlays.begin(); overlay_iter != mOverlays.end(); overlay_iter++) { | ||||
| 		if ( (*overlay_iter)->OnMouseButtonDown (button, xpos, ypos)) | ||||
| 			return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Global functions | ||||
|  */ | ||||
| void DrawGLString (float x, float y, const char* str) { | ||||
| 	if (!ViewInstance) { | ||||
| 		LogError ("Cannot Draw GL String: View not yet initialized!"); | ||||
| 		return; | ||||
| 	} | ||||
| 	ViewInstance->DrawGLString (x, y, str); | ||||
| } | ||||
| 
 | ||||
| unsigned int GetWindowWidth() { | ||||
| 	return ViewInstance->GetWindowWidth (); | ||||
| } | ||||
| 
 | ||||
| unsigned int GetWindowHeight() { | ||||
| 	return ViewInstance->GetWindowHeight (); | ||||
| } | ||||
| 
 | ||||
| int GetFrameRate () { | ||||
| 	return ViewInstance->GetFrameRate (); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										98
									
								
								engine/ViewBase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								engine/ViewBase.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| #ifndef _VIEWBASE_H | ||||
| #define _VIEWBASE_H | ||||
| 
 | ||||
| #include "Engine.h" | ||||
| 
 | ||||
| // forward declarations for the OGLFT fonts
 | ||||
| namespace OGLFT { | ||||
| 	class Monochrome; | ||||
| } | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| class Module; | ||||
| class ModelBase; | ||||
| class CameraBase; | ||||
| class OverlayBase; | ||||
| 
 | ||||
| /** \brief Performs the actual drawing based on Camera and Model
 | ||||
|  */ | ||||
| 
 | ||||
| class ViewBase : public Module{  | ||||
| 	public: | ||||
| 		/** \brief Resizes the View */ | ||||
| 		void Resize (int width, int height); | ||||
| 
 | ||||
| 		/** \brief Performs all drawing */ | ||||
| 		virtual void Draw (); | ||||
| 
 | ||||
| 		/** \brief Draws a string at the given position using current projection
 | ||||
| 		 * and modelview matrices */ | ||||
| 		void DrawGLString (float x, float y, const char* str); | ||||
| 		/** \brief Stores the eye poisition in eye_out */ | ||||
| 		void GetCamereEye (float *eye_out); | ||||
| 
 | ||||
| 		/** \brief Calculates the world coordinates to given screen coordinates */ | ||||
| 		void CalcWorldCoordinates (int screen_x, int screen_y, float world_y, float *pos_out); | ||||
| 
 | ||||
| 		unsigned int GetWindowWidth () { return mWindowWidth; }; | ||||
| 		unsigned int GetWindowHeight () { return mWindowHeight; }; | ||||
| 		int GetFrameRate() { return mFrameRate; }; | ||||
| 
 | ||||
| 		void SetDrawAxis (bool draw_axis) { mDrawGrid = draw_axis; }; | ||||
| 		bool GetDrawAxis () { return mDrawGrid; }; | ||||
| 		void SetDrawGrid (bool draw_grid) { mDrawGrid = draw_grid; }; | ||||
| 		bool GetDrawGrid () { return mDrawGrid; }; | ||||
| 		void SetGridSize (int x, int z) {	mGridSizeX = x; mGridSizeZ = z;	} | ||||
| 
 | ||||
| 		void AddOverlay (OverlayBase *overlay) { mOverlays.push_back (overlay); }; | ||||
| 
 | ||||
| 		/* Input forwarding for the overlays */ | ||||
| 		bool SendKeyDown (const SDL_keysym &keysym); | ||||
| 		bool SendKeyUp (const SDL_keysym &keysym); | ||||
| 		bool SendMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos); | ||||
| 		bool SendMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos); | ||||
| 
 | ||||
| 	protected: | ||||
| 		/** \brief Initializes the system */ | ||||
| 		int OnInit (int argc, char* argv[]); | ||||
| 		/** \brief Destroys the system (must be called!) */ | ||||
| 		void OnDestroy (); | ||||
| 
 | ||||
| 		/** \brief Updates the camera for further drawing */ | ||||
| 		virtual void UpdateCamera (); | ||||
| 		/** \brief Draws a grid of 16 x 16 tiles */ | ||||
| 		void DrawGrid (); | ||||
| 		/** \brief Draws the level and all the visible Entities */ | ||||
| 		virtual void DrawWorld (); | ||||
| 		/** \brief Draws orthographic overlay*/ | ||||
| 		void DrawOverlay2D (); | ||||
| 
 | ||||
| 		ModelBase *mModel; | ||||
| 		CameraBase *mCamera; | ||||
| 
 | ||||
| 		std::vector<OverlayBase*> mOverlays; | ||||
| 
 | ||||
| 		/** \brief The height of the canvas we're drawing on */ | ||||
| 		unsigned int mWindowHeight; | ||||
| 		/** \brief The width of the canvas we're drawing on */ | ||||
| 		unsigned int mWindowWidth; | ||||
| 		/** \brief Stores the current frame rate */ | ||||
| 		int mFrameRate; | ||||
| 
 | ||||
| 		bool mDrawAxis; | ||||
| 		bool mDrawGrid; | ||||
| 		int mGridSizeX; | ||||
| 		int mGridSizeZ; | ||||
| 
 | ||||
| 		/** \brief Font that is used in the console */ | ||||
| 		OGLFT::Monochrome* mConsoleFont; | ||||
| 
 | ||||
| 		friend class Engine; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #include "ViewBaseGlobal.h" | ||||
| 
 | ||||
| #endif // _VIEWBase_H
 | ||||
							
								
								
									
										17
									
								
								engine/ViewBaseGlobal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								engine/ViewBaseGlobal.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| #ifndef _VIEWGLOBAL_H | ||||
| #define _VIEWGLOBAL_H | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| /** \brief Draws the given string at the given position using the current
 | ||||
|  * OpenGL transformations */ | ||||
| void DrawGLString (float x, float y, const char* str); | ||||
| 
 | ||||
| unsigned int GetWindowWidth(); | ||||
| unsigned int GetWindowHeight(); | ||||
| 
 | ||||
| int GetFrameRate (); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* _VIEWGLOBAL_H */ | ||||
							
								
								
									
										72
									
								
								engine/VisualEntityBase.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								engine/VisualEntityBase.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| #include "EntityBase.h" | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| 
 | ||||
| namespace Engine { | ||||
| 
 | ||||
| void EntityVisualState::Draw () { | ||||
| 	if (mBaseType == EntityBaseTypeActor) { | ||||
| 		int i, segments; | ||||
| 		segments = 20; | ||||
| 		double x, z, rad, drad; | ||||
| 
 | ||||
| 		drad = (M_PI * 2) / segments; | ||||
| 
 | ||||
| 		glBegin (GL_TRIANGLE_FAN); | ||||
| 		glVertex3f (0., 0., 0.); | ||||
| 		for (i = 0; i <= segments; i++) { | ||||
| 			rad = drad * i; | ||||
| 			sincos (rad, &z, &x); | ||||
| 			glVertex3f (x * mRadius, 0., -z * mRadius); | ||||
| 		} | ||||
| 		glEnd (); | ||||
| 
 | ||||
| 		glDisable (GL_DEPTH_TEST); | ||||
| 		glColor3f (0.8, 0., 0.2); | ||||
| 		glBegin (GL_TRIANGLES); | ||||
| 			glVertex3f (mRadius, 0., 0.); | ||||
| 			glVertex3f (0., 0., -mRadius * 0.3); | ||||
| 			glVertex3f (0., 0., mRadius * 0.3); | ||||
| 		glEnd (); | ||||
| 		glEnable (GL_DEPTH_TEST); | ||||
| 
 | ||||
| 		return; | ||||
| 	} else if (mBaseType == EntityBaseTypeBlock) { | ||||
| 		glBegin (GL_QUADS); | ||||
| 		glVertex3f (-0.5, 0., 0.5); | ||||
| 		glVertex3f (0.5, 0., 0.5); | ||||
| 		glVertex3f (0.5, 0., -0.5); | ||||
| 		glVertex3f (-0.5, 0., -0.5); | ||||
| 		glEnd (); | ||||
| 	} else if (mBaseType == EntityBaseTypeParticle) { | ||||
| 		int i, segments; | ||||
| 		segments = 20; | ||||
| 		double x, z, rad, drad; | ||||
| 
 | ||||
| 		drad = (M_PI * 2) / segments; | ||||
| 
 | ||||
| 		glDisable (GL_DEPTH_TEST); | ||||
| 		glColor3f (0., 0.8, 0.1); | ||||
| 		glBegin (GL_TRIANGLE_FAN); | ||||
| 		glVertex3f (0., 0., 0.); | ||||
| 		for (i = 0; i <= segments; i++) { | ||||
| 			rad = drad * i; | ||||
| 			sincos (rad, &z, &x); | ||||
| 			glVertex3f (x * mRadius, 0., -z * mRadius); | ||||
| 		} | ||||
| 		glEnd (); | ||||
| 
 | ||||
| 		glColor3f (0.8, 0., 0.2); | ||||
| 		glBegin (GL_TRIANGLES); | ||||
| 			glVertex3f (mRadius, 0., 0.); | ||||
| 			glVertex3f (0., 0., -mRadius * 0.3); | ||||
| 			glVertex3f (0., 0., mRadius * 0.3); | ||||
| 		glEnd (); | ||||
| 		glEnable (GL_DEPTH_TEST); | ||||
| 
 | ||||
| 		return; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										96
									
								
								engine/doc/Mainpage.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								engine/doc/Mainpage.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | ||||
| /** \file documentation.h \mainpage Main Page 
 | ||||
|  *  | ||||
|  * This is the documentation of Engine -- a game engine without a name. | ||||
|  * | ||||
|  * \section General Information | ||||
|  * | ||||
|  * To get an overview over the most important functions and classes have a | ||||
|  * look at Engine. For the structure of the Engine look at Engine::Engine. In | ||||
|  * \ref usecases you find documentation on how things are supposed to work and | ||||
|  * what the ideas behind certain designs is. | ||||
|  * | ||||
|  * \section Physics | ||||
|  * | ||||
|  * So far we only use a very simple physics system which is mostly defined by | ||||
|  * the Engine::Physics class. It uses the coll2d collision library. Collision | ||||
|  * response so far only tries to prevent interpenetration. | ||||
|  * | ||||
|  * \section Networking | ||||
|  * | ||||
|  * For easier networking it is assumed that everything runs over a network. | ||||
|  * The game itself is rather a smart client to a simple synchronization | ||||
|  * protocol. What is being synchronized is the game state and the client | ||||
|  * simply displays the current state it knows. The client is "smart" as it | ||||
|  * tries to guess what the next state will be. | ||||
|  * | ||||
|  * For networking we want to use Enet http://enet.bespin.org/.
 | ||||
|  * | ||||
|  * Notes for networking: At | ||||
|  * http://www.gamedev.net/community/forums/topic.asp?topic_id=550962 is an
 | ||||
|  * interesting thread about modeling the updates. Especially the answer of | ||||
|  * Antheus at http://www.gamedev.net/community/forums/viewreply.asp?ID=3546077
 | ||||
|  * describes two fundamental models: | ||||
|  * | ||||
|  * Level Triggering (GoF Observer Pattern): Entity A sends its changes to the | ||||
|  * Observer pattern and all objects that are interested in the state of Entity | ||||
|  * A get notfied by the observer. | ||||
|  * | ||||
|  * Edge Triggering: For each Entity A the Observer B is interested, it stores | ||||
|  * a flag for a value it is interested in (e.g. one for position, one for | ||||
|  * velocity, etc.). When Entity A modifies one of the values it notifies the | ||||
|  * observer that its current state has changed and the Observer sets the flag | ||||
|  * to "dirty". Anyone interested in events polls at the Observer and decides | ||||
|  * what to do with it. When the value is queried, the Observer reads the value | ||||
|  * from the Entity and clears the flag. | ||||
|  * | ||||
|  * For networking a combination can be used: During the simulation loop only | ||||
|  * Edge Triggering is performed and at the end of it, all dirty States get | ||||
|  * sent over the network. | ||||
|  * | ||||
|  * When notifying events such as "Add new Entity X" the user tomv describes at | ||||
|  * http://www.gamedev.net/community/forums/viewreply.asp?ID=3545586 a method
 | ||||
|  * to circumvent these messages. Instead, the server simply sends out updates | ||||
|  * about the Entities around a player where close Entities are updated more | ||||
|  * frequently than ones that are further away. It simply sends "Entity X | ||||
|  * changed by D". If a client does not know what the Entity X is, it queries | ||||
|  * the type and current state of the Entity X and therefore reconstructs the | ||||
|  * surroundings step-by-step. It is also robust against dropped messages of | ||||
|  * the form "Add new Entity X". | ||||
|  * | ||||
|  * At tomvas model there are some problems: How are events "Delete Entity X" | ||||
|  * handled? How to handle malicious clients that request the state of all | ||||
|  * Entities? (Solution for the last question: Request Queues). | ||||
|  * | ||||
|  * Kylotan cals tomvas model as a unreliable system for generic state | ||||
|  * [synchronization?] (http://www.gamedev.net/community/forums/viewreply.asp?ID=3548662).
 | ||||
|  * Additionally he mentions that it can increase occurences of short term | ||||
|  * unsynchronous states and reccomends using some reliable message passing. | ||||
|  * | ||||
|  * \section ToDos | ||||
|  * | ||||
|  * This is a loose list of items that are to be implemented. For a list of all | ||||
|  * todos within the code have a look at the \ref todo. | ||||
|  * | ||||
|  * \todo [high] Create a simple racing or asteroids game | ||||
|  * \todo [med] Clear all references of EntityVisualState and EntityGameState | ||||
|  * \todo [med] Clarify functionalities of CreateEntity, KillEntity, RegisterEntity, UnregisterEntity (which frees memory, which does only change the state of the Model?) | ||||
|  * \todo [med] Add basic networking | ||||
|  * \todo [med] Add serialization | ||||
|  * \todo [med] Add cal3d support | ||||
|  * \todo [med] Smooth Physics at convex collisions (somehow there is jitter) | ||||
|  * \todo [med] Create better collsion response | ||||
|  * \todo [med] In rare cases two Actors can penetrate each other (probably at slow velocities) | ||||
|  * \todo [low] Add a timer object to keep track of what is sucking performance. | ||||
|  * \todo [low] Add a inspector widget that shows information about a selected Entity | ||||
|  * \todo [low] Use a std::map<string, string> as initialization parameters for | ||||
|  * Engine::Module::Init() | ||||
|  * | ||||
|  * Done: | ||||
|  * - [high] In Physics remove dependancy on the Model to pass on collision | ||||
|  *   events | ||||
|  * - [high] Fix Physics bug when two actors collide actively (i.e. velocity | ||||
|  *   towards each other) | ||||
|  * - [med]  Better Game Input so that each Entity has its own ControllerState | ||||
|  *   that can be modified | ||||
|  * - [med] (31-01-2009) Add support for loading levels (and saving!) | ||||
|  */ | ||||
							
								
								
									
										114
									
								
								engine/doc/Usecases.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								engine/doc/Usecases.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| /** \page usecases Usecases
 | ||||
|  * | ||||
|  * This page contains some information on how various tasks are supposed to be | ||||
|  * performed with this engine. It should help understand how the internals | ||||
|  * work and how to avoid certain pitfalls. | ||||
|  * | ||||
|  * \section entity_management Entity Management | ||||
|  * | ||||
|  * Entities have to be created with Engine::CreateEntity() Factory Method. | ||||
|  * This will also cause the correct registration in all modules (especially in | ||||
|  * the Engine::Physics module). And create the registrations for it. | ||||
|  * | ||||
|  * Once an Entity is no more used, one has to call Engine::DestroyEntity(). | ||||
|  *  | ||||
|  * \section entitiy_drawing Drawing of an Entity | ||||
|  * | ||||
|  * Aim: The visual state must always represent the visual state of the game | ||||
|  * state. | ||||
|  * | ||||
|  * To do this we always have to update the visual entity from the game state | ||||
|  * entity. | ||||
|  * | ||||
|  * \code | ||||
|  * 	View::DrawEntity (Entity* entity) { | ||||
|  * 		// if this entity has no visual part we don't need to draw
 | ||||
|  * 		if (! entity->mPhysicState) return; | ||||
|  * | ||||
|  *		// update entity->mVisualState based on entity->mGameState
 | ||||
|  * | ||||
|  * 		// perform positioning based on entity->mPhysicState
 | ||||
|  * | ||||
|  *		// perform drawing based on entity->mVisualState
 | ||||
|  *	} | ||||
|  *	\endcode | ||||
|  * | ||||
|  * \section game_input Game Input | ||||
|  * | ||||
|  * Each Entity has a ControllerState which keeps track on how the Entity is | ||||
|  * currently steered. This is then processed by the model each frame for each | ||||
|  * entity and updates the velocities / orientations etc. before the physical | ||||
|  * simulation is started. The player input simply forwards its input to the | ||||
|  * Entity with the Player Id and updates the ControllerState of the Entity | ||||
|  * with the Id. | ||||
|  * | ||||
|  * To add a new key state one has to follow these steps: | ||||
|  * - add a new EntityControllerKeyState e.g. EntityKeyStateCrouch (must be added | ||||
|  *   above EntityKeyStateLast) | ||||
|  * - define the behaviour of the control in Entity::ProcessController() which | ||||
|  *   updates the EntityPhysicalState of the Entity | ||||
|  * - add a command to be able to bind a key to the EntityControllerKeyState | ||||
|  * | ||||
|  * \section console_input Console Input | ||||
|  * | ||||
|  * Since it could be that the key being pressed has to be forwarded to another | ||||
|  * system such as the Menu or the Engine::Console system, we have to query the | ||||
|  * Engine::Model whether it is active and forward the input if it is the case. | ||||
|  * Otherwise we just execute the binding for the key (if it exists). | ||||
|  * | ||||
|  * \code | ||||
|  * 	Controller::OnKeyDown (SDLKey key) { | ||||
|  * 		if (mConsole->GetActive ()) | ||||
|  * 			mConsole->OnKeyDown (key); | ||||
|  * | ||||
|  *		if (mBinding[key].size()) | ||||
|  *			mCommands->QueueCommand (mBinding[key]); | ||||
|  *	} | ||||
|  * \endcode | ||||
|  * | ||||
|  * \section addcommand Adding a Command to the Command System | ||||
|  * | ||||
|  * For the various Modules such as Engine::Controller, Engine::View, etc. | ||||
|  * separate files exist in which commands are defined. The filename pattern is | ||||
|  * usually [ModuleName]Commands.cc and contains the function | ||||
|  *	\code void ModuleName::OnRegisterCommands () \endcode which is run during the | ||||
|  * initialization phase of the Engine in Engine::OnInit. | ||||
|  * | ||||
|  * Commands themselves have the signature: | ||||
|  * \code bool Cmd_CrazyCommand (std::vector<std::string> args) \endcode | ||||
|  * and return true on success and error if some error has happened. The | ||||
|  * prefix \e Cmd_ is not mandatory but keeps things clear. | ||||
|  * | ||||
|  * Please make sure to call Engine::CommandSetErrorString in such a case. The | ||||
|  * message itself will be automatically reported to the Engine::Logging system | ||||
|  * as a warning since Command errors are hopefully not that important that | ||||
|  * they can crash the whole Engine. | ||||
|  * | ||||
|  * To register a Command to the Engine::Commands system you have to call \code | ||||
|  * AddCommand ("crazycommand", Cmd_CrazyCommand); \endcode in | ||||
|  * ModuleName::OnRegisterCommands. With this the Command is accessible through | ||||
|  * the Command system. | ||||
|  * | ||||
|  * \section addvariable Adding a Variable to the Engine::Variable System | ||||
|  * | ||||
|  * To register a variable to the Engine::Variables Module one \e must use a | ||||
|  * static variable of type Engine::Variable and use a special constructor: | ||||
|  * \code | ||||
|  *		static Var_Variable PlayerSpeed ("playerspeed", "1.25"); | ||||
|  * \endcode | ||||
|  * This constructor takes care of registering the Variable PlayerSpeedVariable | ||||
|  * and its value to the Engine::Variables Module. The first argument is the | ||||
|  * name of the variable which can be used to retrieve a pointer to the | ||||
|  * Variable with Engine::GetVariable, Engine::GetVariableString, etc. The | ||||
|  * second argument is the value which the system will automatically try to | ||||
|  * convert to a float. This float is then returned if Engine::GetVariableFloat | ||||
|  * is called. | ||||
|  * | ||||
|  * The prefix \e Var_ is for readability in the code. | ||||
|  * | ||||
|  * The keyword \e static ensures that the lifespan of the variable is not only | ||||
|  * in a local function environment and thus mandatory. However it is | ||||
|  * registered at that time the program executes the first time the line in | ||||
|  * which the definition was made. To be safe define all your variables in the | ||||
|  * global scope of te source file of your Engine::Module. | ||||
|  */ | ||||
							
								
								
									
										16
									
								
								engine/globals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								engine/globals.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| #ifndef _GLOBALS_H | ||||
| #define _GLOBALS_H | ||||
| 
 | ||||
| #define LOG_DEFAULT_LEVEL     LogLevelMessage | ||||
| #define LOG_MAX_MESSAGE_LENGTH 1024 | ||||
| 
 | ||||
| #define VIEW_DEFAULT_HEIGHT   600 | ||||
| #define VIEW_DEFAULT_WIDTH    800 | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	#include <windows.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <SDL/SDL.h> | ||||
| 
 | ||||
| #endif // _GLOBALS_H
 | ||||
							
								
								
									
										166
									
								
								engine/keytable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								engine/keytable.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | ||||
| #ifndef KEYTABLE_H | ||||
| #define KEYTABLE_H | ||||
| 
 | ||||
| #include <SDL/SDL.h> | ||||
| 
 | ||||
| /** \brief Defines the key codes for mouse buttons
 | ||||
|  * | ||||
|  * With this enum we can treat mouse button events the same way as we treat | ||||
|  * keyboard events. To do so we define the left button as the last keyboard | ||||
|  * button. | ||||
|  */ | ||||
| enum MouseButton { | ||||
| 	MouseButtonUnknown = SDLK_LAST, | ||||
| 	MouseButtonLeft, | ||||
| 	MouseButtonMiddle, | ||||
| 	MouseButtonRight, | ||||
| 	MouseButtonWheelUp, | ||||
| 	MouseButtonWheelDown, | ||||
| 	MouseButtonLast | ||||
| }; | ||||
| 
 | ||||
| struct key_definition { | ||||
| 	int keynum; | ||||
| 	const char *keystr; | ||||
| }; | ||||
| 
 | ||||
| const int keytable_last = MouseButtonLast; | ||||
| 
 | ||||
| static const key_definition key_table[] = { | ||||
| 	{SDLK_BACKSPACE, "backspace"},   	 | ||||
| 	{SDLK_TAB, "tab"}, | ||||
| //	{SDLK_CLEAR, "12"},
 | ||||
| 	{SDLK_RETURN, "return"}, | ||||
| 	{SDLK_PAUSE, "pause"}, | ||||
| 	{SDLK_ESCAPE, "escape"}, | ||||
| 	{SDLK_SPACE, "space"}, | ||||
| 	{SDLK_EXCLAIM, "exclaim"}, | ||||
| //	{SDLK_QUOTEDBL, ""},
 | ||||
| 	{SDLK_HASH, "#"}, | ||||
| 	{SDLK_DOLLAR, "$"}, | ||||
| 	{SDLK_AMPERSAND, "&"}, | ||||
| //	{SDLK_QUOTE, "39"},
 | ||||
| //	{SDLK_LEFTPAREN, "("},
 | ||||
| //	{SDLK_RIGHTPAREN, ")"},
 | ||||
| //	{SDLK_ASTERISK, "*"},
 | ||||
| 	{SDLK_PLUS, "+"}, | ||||
| 	{SDLK_COMMA, ","}, | ||||
| 	{SDLK_MINUS, "-"}, | ||||
| 	{SDLK_PERIOD, "."}, | ||||
| 	{SDLK_SLASH, "/"}, | ||||
| 	{SDLK_0, "0"}, | ||||
| 	{SDLK_1, "1"}, | ||||
| 	{SDLK_2, "2"}, | ||||
| 	{SDLK_3, "3"}, | ||||
| 	{SDLK_4, "4"}, | ||||
| 	{SDLK_5, "5"}, | ||||
| 	{SDLK_6, "6"}, | ||||
| 	{SDLK_7, "7"}, | ||||
| 	{SDLK_8, "8"}, | ||||
| 	{SDLK_9, "9"}, | ||||
| 	{SDLK_COLON, ":"}, | ||||
| 	{SDLK_SEMICOLON, ";"}, | ||||
| 	{SDLK_LESS, "<"}, | ||||
| 	{SDLK_EQUALS, "="}, | ||||
| 	{SDLK_GREATER, ">"}, | ||||
| 	{SDLK_QUESTION, "?"}, | ||||
| 	{SDLK_AT, "@"}, | ||||
| 	{SDLK_LEFTBRACKET, "["}, | ||||
| 	{SDLK_BACKSLASH, "\\"}, | ||||
| 	{SDLK_RIGHTBRACKET, "]"}, | ||||
| 	{SDLK_CARET, "^"}, | ||||
| 	{SDLK_UNDERSCORE, "_"}, | ||||
| 	{SDLK_BACKQUOTE, "`"}, | ||||
| 	{SDLK_a, "a"}, | ||||
| 	{SDLK_b, "b"}, | ||||
| 	{SDLK_c, "c"}, | ||||
| 	{SDLK_d, "d"}, | ||||
| 	{SDLK_e, "e"}, | ||||
| 	{SDLK_f, "f"}, | ||||
| 	{SDLK_g, "g"}, | ||||
| 	{SDLK_h, "h"}, | ||||
| 	{SDLK_i, "i"}, | ||||
| 	{SDLK_j, "j"}, | ||||
| 	{SDLK_k, "k"}, | ||||
| 	{SDLK_l, "l"}, | ||||
| 	{SDLK_m, "m"}, | ||||
| 	{SDLK_n, "n"}, | ||||
| 	{SDLK_o, "o"}, | ||||
| 	{SDLK_p, "p"}, | ||||
| 	{SDLK_q, "q"}, | ||||
| 	{SDLK_r, "r"}, | ||||
| 	{SDLK_s, "s"}, | ||||
| 	{SDLK_t, "t"}, | ||||
| 	{SDLK_u, "u"}, | ||||
| 	{SDLK_v, "v"}, | ||||
| 	{SDLK_w, "w"}, | ||||
| 	{SDLK_x, "x"}, | ||||
| 	{SDLK_y, "y"}, | ||||
| 	{SDLK_z, "z"}, | ||||
| 	{SDLK_KP0, "keypad_0"}, | ||||
| 	{SDLK_KP1, "keypad_1"}, | ||||
| 	{SDLK_KP2, "keypad_2"}, | ||||
| 	{SDLK_KP3, "keypad_3"}, | ||||
| 	{SDLK_KP4, "keypad_4"}, | ||||
| 	{SDLK_KP5, "keypad_5"}, | ||||
| 	{SDLK_KP6, "keypad_6"}, | ||||
| 	{SDLK_KP7, "keypad_7"}, | ||||
| 	{SDLK_KP8, "keypad_8"}, | ||||
| 	{SDLK_KP9, "keypad_9"}, | ||||
| 	{SDLK_KP_PERIOD, "keypad_period"}, | ||||
| 	{SDLK_KP_DIVIDE, "keypad_devide"}, | ||||
| 	{SDLK_KP_MULTIPLY, "keypad_multiply"}, | ||||
| 	{SDLK_KP_MINUS, "keypad_minus"}, | ||||
| 	{SDLK_KP_PLUS, "keypad_plus"}, | ||||
| 	{SDLK_KP_ENTER, "keypad_enter"}, | ||||
| 	{SDLK_KP_EQUALS, "keypad_equals"}, | ||||
| 	{SDLK_UP, "up"}, | ||||
| 	{SDLK_DOWN, "down"}, | ||||
| 	{SDLK_RIGHT, "right"}, | ||||
| 	{SDLK_LEFT, "left"}, | ||||
| 	{SDLK_INSERT, "insert"}, | ||||
| 	{SDLK_HOME, "home"}, | ||||
| 	{SDLK_END, "end"}, | ||||
| 	{SDLK_PAGEUP, "pageup"}, | ||||
| 	{SDLK_PAGEDOWN, "pagedown"}, | ||||
| 	{SDLK_F1,  "f1"}, | ||||
| 	{SDLK_F2,  "f2"}, | ||||
| 	{SDLK_F3,  "f3"}, | ||||
| 	{SDLK_F4,  "f4"}, | ||||
| 	{SDLK_F5,  "f5"}, | ||||
| 	{SDLK_F6,  "f6"}, | ||||
| 	{SDLK_F7,  "f7"}, | ||||
| 	{SDLK_F8,  "f8"}, | ||||
| 	{SDLK_F9,  "f9"}, | ||||
| 	{SDLK_F10, "f10"}, | ||||
| 	{SDLK_F11, "f11"}, | ||||
| 	{SDLK_F12, "f12"}, | ||||
| 	{SDLK_F13, "f13"}, | ||||
| 	{SDLK_F14, "f14"}, | ||||
| 	{SDLK_F15, "f15"}, | ||||
| 	{SDLK_NUMLOCK, "numlock"}, | ||||
| 	{SDLK_CAPSLOCK, "capslock"}, | ||||
| 	{SDLK_SCROLLOCK, "scrollock"}, | ||||
| 	{SDLK_RSHIFT, "right_shift"}, | ||||
| 	{SDLK_LSHIFT, "left_shift"}, | ||||
| 	{SDLK_RCTRL, "right_ctrl"}, | ||||
| 	{SDLK_LCTRL, "left_ctrl"}, | ||||
| 	{SDLK_RALT, "right_alt"}, | ||||
| 	{SDLK_LALT, "left_alt"}, | ||||
| 	{SDLK_RMETA, "right_meta"}, | ||||
| 	{SDLK_LMETA, "left_meta"}, | ||||
| 	{SDLK_LSUPER, "left_super"},		/* Left "Windows" key */ | ||||
| 	{SDLK_RSUPER, "right_super"},		/* Right "Windows" key */ | ||||
| 	{SDLK_MODE, "altgr"},		/* "Alt Gr" key */ | ||||
| 	{SDLK_COMPOSE, "compose"},		/* Multi-key compose key */ | ||||
| 	{SDLK_DELETE, "delete"}, | ||||
| 	{MouseButtonLeft, "mouse_left"}, | ||||
| 	{MouseButtonMiddle, "mouse_middle"}, | ||||
| 	{MouseButtonRight, "mouse_right"}, | ||||
| 	{MouseButtonWheelUp, "mouse_wheelup"}, | ||||
| 	{MouseButtonWheelDown, "mouse_wheeldown"}, | ||||
| 	{keytable_last, NULL} | ||||
| }; | ||||
| 
 | ||||
| #endif /* KEYTABLE_H */ | ||||
| 
 | ||||
							
								
								
									
										3
									
								
								engine/libraries/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								engine/libraries/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| ADD_SUBDIRECTORY ( mathlib ) | ||||
| ADD_SUBDIRECTORY ( coll2d ) | ||||
| ADD_SUBDIRECTORY ( oglft ) | ||||
							
								
								
									
										28
									
								
								engine/libraries/coll2d/CMake/FindUnitTest++.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								engine/libraries/coll2d/CMake/FindUnitTest++.cmake
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # - Try to find UnitTest++ | ||||
| # | ||||
| # | ||||
| 
 | ||||
| SET (UNITTEST++_FOUND FALSE) | ||||
| 
 | ||||
| FIND_PATH (UNITTEST++_INCLUDE_DIR UnitTest++.h /usr/include/unittest++ /usr/local/include/unittest++ $ENV{UNITTESTXX_PATH}/src $ENV{UNITTESTXX_INCLUDE_PATH}) | ||||
| 
 | ||||
| FIND_LIBRARY (UNITTEST++_LIBRARY NAMES UnitTest++ PATHS /usr/lib /usr/local/lib $ENV{UNITTESTXX_PATH} ENV{UNITTESTXX_LIBRARY_PATH}) | ||||
| 
 | ||||
| IF (UNITTEST++_INCLUDE_DIR AND UNITTEST++_LIBRARY) | ||||
| 	SET (UNITTEST++_FOUND TRUE) | ||||
| ENDIF (UNITTEST++_INCLUDE_DIR AND UNITTEST++_LIBRARY) | ||||
| 
 | ||||
| IF (UNITTEST++_FOUND) | ||||
|    IF (NOT UnitTest++_FIND_QUIETLY) | ||||
|       MESSAGE(STATUS "Found UnitTest++: ${UNITTEST++_LIBRARY}") | ||||
|    ENDIF (NOT UnitTest++_FIND_QUIETLY) | ||||
| ELSE (UNITTEST++_FOUND) | ||||
|    IF (UnitTest++_FIND_REQUIRED) | ||||
|       MESSAGE(FATAL_ERROR "Could not find UnitTest++") | ||||
|    ENDIF (UnitTest++_FIND_REQUIRED) | ||||
| ENDIF (UNITTEST++_FOUND) | ||||
| 
 | ||||
| MARK_AS_ADVANCED ( | ||||
| 	UNITTEST++_INCLUDE_DIR | ||||
| 	UNITTEST++_LIBRARY | ||||
| 	) | ||||
							
								
								
									
										21
									
								
								engine/libraries/coll2d/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								engine/libraries/coll2d/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| PROJECT (COLL2D) | ||||
| 
 | ||||
| CMAKE_MINIMUM_REQUIRED (VERSION 2.6) | ||||
| 
 | ||||
| # Needed for UnitTest++ | ||||
| LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ) | ||||
| 
 | ||||
| SET ( COLL2D_SRCS | ||||
|   src/coll2d.cc | ||||
|   ) | ||||
| 
 | ||||
| INCLUDE_DIRECTORIES ( include ../mathlib/ ) | ||||
| 
 | ||||
| SET_TARGET_PROPERTIES ( ${PROJECT_EXECUTABLES} PROPERTIES | ||||
|   LINKER_LANGUAGE CXX | ||||
| ) | ||||
| 
 | ||||
| SUBDIRS (tests) | ||||
| 
 | ||||
| ADD_LIBRARY ( coll2d ${COLL2D_SRCS} ) | ||||
| 
 | ||||
							
								
								
									
										346
									
								
								engine/libraries/coll2d/include/coll2d.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								engine/libraries/coll2d/include/coll2d.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,346 @@ | ||||
| #ifndef _COLL2D_H | ||||
| #define _COLL2D_H | ||||
| 
 | ||||
| /** \brief Coll2d - A 2d collision detection library
 | ||||
|  * \author Martin Felis <martin@silef.de> | ||||
|  * | ||||
|  * This library provides functions to detect collisions between polygons and | ||||
|  * spheres. | ||||
|  * | ||||
|  * Notes: | ||||
|  * - vertices of polygons are described in local coordinates | ||||
|  * - return values of check_collision are in global coordinates | ||||
|  * - all Shapes get copied to a temporary instance which will then get | ||||
|  *   transferred into global coordinates | ||||
|  * - Polygons are assumed to be convex and the vertices are stored | ||||
|  *   counter clockwise. | ||||
|  * - The transformation of the global position and velocities towards | ||||
|  *   relative position and velocities happens in the | ||||
|  *   int check_collision_<type>_<type> functions! | ||||
|  */ | ||||
| 
 | ||||
| #include <mathlib.h> | ||||
| #include <iostream> | ||||
| #include <cstring> | ||||
| 
 | ||||
| #include <coll2d_errors.h> | ||||
| 
 | ||||
| namespace coll2d { | ||||
| 
 | ||||
| /** \brief Contains the information of a collision
 | ||||
|  * | ||||
|  * \param normal  The normal of the reference plane | ||||
|  * \param point   The actual point where the collision happens in global | ||||
|  *                cooldinates | ||||
|  * \param time    If both objects move for this amount of time the contact | ||||
|  *                will occur. | ||||
|  * \param reference_shape | ||||
|  *                If 0, the first shape passed to he check_collision function | ||||
|  *                is the reference shape, otherwise the second. | ||||
| */ | ||||
| struct CollisionInfo { | ||||
| 	vector3d normal; | ||||
| 	vector3d point; | ||||
| 	float time; | ||||
| 	int reference_shape; | ||||
| 
 | ||||
| 	CollisionInfo () : normal (0., 0., 0.), point (0., 0., 0.), time (-1.), reference_shape (-1) { | ||||
| 	} | ||||
| 
 | ||||
| 	CollisionInfo& operator= (const CollisionInfo& info) { | ||||
| 		if (this != &info) { | ||||
| 			normal = info.normal; | ||||
| 			point = info.point; | ||||
| 			time = info.time; | ||||
| 			reference_shape = info.reference_shape; | ||||
| 		} | ||||
| 
 | ||||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	void doPrint (const char* msg) { | ||||
| 		std::cout << msg; | ||||
| 		std::cout <<  "Time   = " << time << std::endl; | ||||
| 		normal.print ("Normal = "); | ||||
| 		point.print ( "Point  = "); | ||||
| 		std::cout <<  "Reference = " << reference_shape << std::endl; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| /** \brief Base class for all shapes
 | ||||
|  * | ||||
|  */ | ||||
| class Shape { | ||||
| protected: | ||||
| 	vector3d mPosition; | ||||
| 	vector3d mVelocity; | ||||
| 	float mAngle; | ||||
| 	float mAngleVelocity; | ||||
| 
 | ||||
| 	virtual void dummy() { | ||||
| 	} | ||||
| public: | ||||
| 	Shape(): | ||||
| 		mPosition (0., 0., 0.), | ||||
| 		mVelocity (0., 0., 0.), | ||||
| 		mAngle (0.), | ||||
| 		mAngleVelocity (0.) { | ||||
| 	} | ||||
| 	Shape (const Shape &shape): | ||||
| 		mPosition (shape.mPosition), | ||||
| 		mVelocity (shape.mVelocity), | ||||
| 		mAngle (shape.mAngle), | ||||
| 		mAngleVelocity (shape.mAngleVelocity) | ||||
| 	{ } | ||||
| 
 | ||||
| 	virtual ~Shape () {}; | ||||
| 
 | ||||
| 	/** \brief Creates and returns a copy of itself */ | ||||
| 	virtual Shape* getCopy () = 0; | ||||
| 
 | ||||
| 	void setPosition(vector3d position) { | ||||
| 		mPosition = position; | ||||
| 	} | ||||
| 	vector3d getPosition() { | ||||
| 		return mPosition; | ||||
| 	} | ||||
| 	void setVelocity(vector3d velocity) { | ||||
| 		mVelocity = velocity; | ||||
| 	} | ||||
| 	vector3d getVelocity() { | ||||
| 		return mVelocity; | ||||
| 	} | ||||
| 
 | ||||
| 	void setAngle (const float &angle) { | ||||
| 		mAngle = angle; | ||||
| 	} | ||||
| 	float getAngle () { | ||||
| 		return mAngle; | ||||
| 	} | ||||
| 	void setAngleVelocity (float angle_velocity) { | ||||
| 		mAngleVelocity = angle_velocity; | ||||
| 	} | ||||
| 	float getAngleVelocity () { | ||||
| 		return mAngleVelocity; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void doPrintType() { | ||||
| 		std::cout << "Shape" << std::endl; | ||||
| 	} | ||||
| 	virtual void doPrint (const char* name) { | ||||
| 		std::cout << name << "<unknown shape>" << std::endl; | ||||
| 	} | ||||
| 	friend int check_collision_rel(Shape *shape_a, Shape *shape_b, | ||||
| 			vector3d *velocity_b, CollisionInfo* info); | ||||
| }; | ||||
| 
 | ||||
| class Polygon: public Shape { | ||||
| private: | ||||
| 	unsigned int mVerticeCount; | ||||
| 	vector3d *mVertices; | ||||
| 	bool mFreeVertices; | ||||
| public: | ||||
| 	Polygon() { | ||||
| 		mVerticeCount = 0; | ||||
| 		mVertices = NULL; | ||||
| 		mFreeVertices = false; | ||||
| 	} | ||||
| 	Polygon(unsigned int n) { | ||||
| 		mVerticeCount = n; | ||||
| 		mVertices = new vector3d[n]; | ||||
| 		mFreeVertices = true; | ||||
| 	} | ||||
| 	Polygon(unsigned int n, vector3d *vertices) { | ||||
| 		mVerticeCount = n; | ||||
| 		mFreeVertices = false; | ||||
| 
 | ||||
| 		if (vertices == NULL && n > 0) { | ||||
| 			mVertices = new vector3d [n]; | ||||
| 			mFreeVertices = true; | ||||
| 		} | ||||
| 
 | ||||
| 		mVertices = vertices; | ||||
| 	} | ||||
| 	Polygon (const Polygon &polygon) : Shape (polygon) { | ||||
| 		mVerticeCount = polygon.mVerticeCount; | ||||
| 		mFreeVertices = true; | ||||
| 
 | ||||
| 		mVertices = new vector3d[mVerticeCount]; | ||||
| 		memcpy (mVertices, polygon.mVertices, sizeof (vector3d) * mVerticeCount); | ||||
| 	} | ||||
| 	virtual ~Polygon () { | ||||
| 		if (mFreeVertices == true && mVertices) | ||||
| 			delete[] mVertices; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual Polygon* getCopy () { | ||||
| 		Polygon *copy = new Polygon (*this); | ||||
| 
 | ||||
| 		assert (copy); | ||||
| 
 | ||||
| 		return copy; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void doPrintType() { | ||||
| 		std::cout << "Polygon" << std::endl; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void doPrint (const char* name) { | ||||
| 		std::cout << name << " (Polygon)" << std::endl; | ||||
| 
 | ||||
| 		std::cout << "mVerticeCount = " << mVerticeCount << std::endl; | ||||
| 		unsigned int i; | ||||
| 		for (i = 0; i < mVerticeCount; i ++) { | ||||
| 			std::cout << i << " = " << mVertices[i][0] << ", " << | ||||
| 				mVertices[i][1] << ", " << | ||||
| 				mVertices[i][2] << std::endl; | ||||
| 		} | ||||
| 		std::cout << "mPosition = " << mPosition[0] <<", " << | ||||
| 			mPosition[1] << ", " << | ||||
| 			mPosition[2] << std::endl; | ||||
| 
 | ||||
| 		std::cout << "mVelocity = " << mVelocity[0] <<", " << | ||||
| 			mVelocity[1] << ", " << | ||||
| 			mVelocity[2] << std::endl; | ||||
| 
 | ||||
| 		std::cout << "mAngle = " << mAngle << std::endl; | ||||
| 		std::cout << "mAngleVelocity = " << mAngleVelocity << std::endl; | ||||
| 	} | ||||
| 
 | ||||
| 	unsigned int getVerticeCount () { | ||||
| 		return mVerticeCount; | ||||
| 	} | ||||
| 
 | ||||
| 	vector3d& getVertice (unsigned int i) { | ||||
| 		assert (i >= 0 && i < mVerticeCount); | ||||
| 		return mVertices [i]; | ||||
| 	} | ||||
| 
 | ||||
| 	void setVertice (unsigned int i, const vector3d &vertice) { | ||||
| 		assert (i >= 0 && i < mVerticeCount); | ||||
| 		mVertices[i] = vertice; | ||||
| 	} | ||||
| 
 | ||||
| 	friend int check_collision_polygon_sphere(Shape *polygon_a, | ||||
| 			Shape *sphere_b, CollisionInfo* info); | ||||
| }; | ||||
| 
 | ||||
| class Sphere: public Shape { | ||||
| private: | ||||
| 	float mRadius; | ||||
| public: | ||||
| 	Sphere (float radius) { | ||||
| 		mRadius = radius; | ||||
| 		Shape::setPosition (vector3d (0., 0., 0.)); | ||||
| 	} | ||||
| 
 | ||||
| 	Sphere(float radius, const vector3d &position) { | ||||
| 		mRadius = radius; | ||||
| 		Shape::setPosition(position); | ||||
| 	} | ||||
| 
 | ||||
| 	Sphere (const Sphere &sphere): | ||||
| 		Shape (sphere), | ||||
| 		mRadius (sphere.mRadius) { } | ||||
| 
 | ||||
| 	virtual Sphere* getCopy() { | ||||
| 		Sphere* copy = new Sphere (*this); | ||||
| 
 | ||||
| 		return copy; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void doPrintType() { | ||||
| 		std::cout << "Sphere" << std::endl; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void doPrint (const char* name) { | ||||
| 		std::cout << name << " (Sphere)" << std::endl; | ||||
| 
 | ||||
| 		std::cout << "mRadius = " << mRadius << std::endl; | ||||
| 		std::cout << "mPosition = " << mPosition[0] <<", " << | ||||
| 			mPosition[1] << ", " << | ||||
| 			mPosition[2] << std::endl; | ||||
| 
 | ||||
| 		std::cout << "mVelocity = " << mVelocity[0] <<", " << | ||||
| 			mVelocity[1] << ", " << | ||||
| 			mVelocity[2] << std::endl; | ||||
| 
 | ||||
| 		std::cout << "mAngle = " << mAngle << std::endl; | ||||
| 		std::cout << "mAngleVelocity = " << mAngleVelocity << std::endl; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	void setRadius (float radius) { | ||||
| 		mRadius = radius; | ||||
| 	} | ||||
| 
 | ||||
| 	float getRadius () { | ||||
| 		return mRadius; | ||||
| 	} | ||||
| 
 | ||||
| 	friend int check_collision_polygon_sphere(Shape *polygon_a, | ||||
| 			Shape *sphere_b, CollisionInfo* info); | ||||
| }; | ||||
| 
 | ||||
| /** \brief The higher level function to call for collision detection
 | ||||
|  * | ||||
|  * \param stepsize   the timestep within we want to check for the collision  | ||||
|  * \param shape_a    first shape | ||||
|  * \param shape_b    second shape | ||||
|  * \param info       information about the collision will be to info | ||||
|  * | ||||
|  * \returns 0 - no collision, negative on error, positive on collision | ||||
|  */ | ||||
| int check_collision(float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo* info); | ||||
| 
 | ||||
| /** \brief The higher level function to call for collision detection
 | ||||
|  * | ||||
|  * \param shape_a    first shape | ||||
|  * \param shape_b    second shape | ||||
|  * \param velocity_b relative velocity of b to a | ||||
|  * \param info       information about the collision will be to info | ||||
|  * | ||||
|  * \returns 0 - no collision, negative on error, positive on collision | ||||
|  */ | ||||
| int check_collision_rel(float timestep, Shape *shape_a, Shape *shape_b, vector3d *velocity_b, | ||||
| 		CollisionInfo* info); | ||||
| 
 | ||||
| /** \brief Callback signature for the check functions */ | ||||
| typedef int (*check_cb)(float timestep, Shape *shape_a, Shape *shape_b,	CollisionInfo* info); | ||||
| 
 | ||||
| /** \brief Returns the check functions which performs the checks depending
 | ||||
|  * on their types. */ | ||||
| check_cb get_check(Shape *shape_a, Shape *shape_b); | ||||
| 
 | ||||
| /** \brief Performs a check between a polygon and a sphere
 | ||||
|  */ | ||||
| int check_collision_polygon_sphere(float timestep, Shape *shape_a, Shape *shape_b, | ||||
| 		CollisionInfo* info); | ||||
| 
 | ||||
| /** \brief Performs a check between a sphere and a sphere
 | ||||
|  */ | ||||
| int check_collision_sphere_sphere(float timestep, Shape *shape_a, Shape *shape_b, | ||||
| 		CollisionInfo* info); | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Calculates the time it takes for a point to touch a plane
 | ||||
|  * | ||||
|  * \param normal   normal vector of the plane | ||||
|  * \param plane_point point on the vector | ||||
|  * \param point    point that is moving | ||||
|  * \param velocity velocity of the point | ||||
|  * | ||||
|  * \returns -1 if point is moving away from the plane (or is below and | ||||
|  *                moves even further below | ||||
|  *          >= 0 if point is moving along the plane or towards the plane | ||||
|  * | ||||
|  * This function depends on the scale of velocity. It is assumed | ||||
|  * that velocity represents the displacement in one frame. In this | ||||
|  * case a return value > 1 means there will not be a contact | ||||
|  * within this frame. | ||||
|  */ | ||||
| float calculate_contact_plane_point(vector3d &normal, vector3d &plane_point, vector3d &point, vector3d &velocity); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif /* _COLL2D_H */ | ||||
							
								
								
									
										9
									
								
								engine/libraries/coll2d/include/coll2d_errors.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								engine/libraries/coll2d/include/coll2d_errors.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| #ifndef _COLL2D_ERRORS | ||||
| #define _COLL2D_ERRORS | ||||
| 
 | ||||
| #define CHECK_ERROR_UNKNOWN -9999 | ||||
| #define CHECK_ERROR_NOT_IMPLEMENTED -1 | ||||
| #define CHECK_ERROR_INVALID_TYPES -2 | ||||
| #define CHECK_ERROR_OVERLAP -3 | ||||
| 
 | ||||
| #endif /* _COLL2D_ERRORS */ | ||||
							
								
								
									
										572
									
								
								engine/libraries/coll2d/src/coll2d.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										572
									
								
								engine/libraries/coll2d/src/coll2d.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,572 @@ | ||||
| #include <cstring> | ||||
| #include<coll2d.h> | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace coll2d { | ||||
| 
 | ||||
| int check_collision (float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo *info) { | ||||
| 	check_cb check = NULL; | ||||
| 
 | ||||
| 	check = get_check (shape_a, shape_b); | ||||
| 
 | ||||
| 	if ( check == NULL ) { | ||||
| 		return CHECK_ERROR_NOT_IMPLEMENTED; | ||||
| 	} | ||||
| 
 | ||||
| 	return check (timestep, shape_a, shape_b, info); | ||||
| }; | ||||
| 
 | ||||
| check_cb get_check (Shape *shape_a, Shape *shape_b) { | ||||
| 	if ( (dynamic_cast<Polygon*> (shape_a) != NULL) | ||||
| 			&& (dynamic_cast<Sphere*> (shape_b) != NULL) ) { | ||||
| 		return check_collision_polygon_sphere; | ||||
| 	} | ||||
| 	else if ( (dynamic_cast<Polygon*> (shape_b) != NULL) | ||||
| 			&& (dynamic_cast<Sphere*> (shape_a) != NULL) ) { | ||||
| 		return check_collision_polygon_sphere; | ||||
| 	}	else if ( (dynamic_cast<Sphere*> (shape_b) != NULL) | ||||
| 			&& (dynamic_cast<Sphere*> (shape_a) != NULL) ) { | ||||
| 		return check_collision_sphere_sphere; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| int check_collision_rel (float timestep, Shape *shape_a, Shape *shape_b, vector3d *velocity_b, CollisionInfo *info) { | ||||
| 	check_cb check = NULL; | ||||
| 
 | ||||
| 	shape_b->setVelocity (*velocity_b); | ||||
| 	check = get_check (shape_a, shape_b); | ||||
| 
 | ||||
| 	if ( check == NULL ) { | ||||
| 		return CHECK_ERROR_NOT_IMPLEMENTED; | ||||
| 	} | ||||
| 
 | ||||
| 	return check (timestep, shape_a, shape_b, info); | ||||
| }; | ||||
| 
 | ||||
| /** \brief calculates the time for a moving point to touch a plane
 | ||||
|  * | ||||
|  * \param normal      The normal of the plane | ||||
|  * \param plane_point a point on the plane | ||||
|  * \param point       the moving point | ||||
|  * \param velocity    the velocity of the point | ||||
|  * | ||||
|  * \returns If the return value is negative, the point is moving away from the | ||||
|  * plane or is below the plane and thus does not touch it. Otherwise  | ||||
|  *   point + (return value) * velocity | ||||
|  * is on the plane. | ||||
|  */ | ||||
| float calculate_contact_plane_point (vector3d &normal, vector3d &plane_point, vector3d &point, vector3d &velocity) { | ||||
| 	vector3d temp_vector (point); | ||||
| 	temp_vector -= plane_point; | ||||
| 
 | ||||
| 	// If the following is < 0 then the point is "below" the plane
 | ||||
| 	if (normal * temp_vector < 0) { | ||||
| 		// If the following is < 0 then we move even deeper
 | ||||
| 		if ( normal * velocity < 0 ) | ||||
| 			return -999; | ||||
| 		// Or towards the upper side of the plane.
 | ||||
| 		else | ||||
| 			return -111; | ||||
| 	} | ||||
| 
 | ||||
| 	int i,imax = -1; | ||||
| 	float vmax = 0.; | ||||
| 	for (i = 0; i < 3; i++) { | ||||
| 		if ( normal[i] * velocity[i] < vmax) { | ||||
| 			vmax = normal[i] * velocity[i]; | ||||
| 			imax = i; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (imax == -1) { | ||||
| 		return -1.; | ||||
| 	} | ||||
| 
 | ||||
| 	return (normal[imax] * plane_point[imax] - normal[imax] * point[imax]) / vmax; | ||||
| } | ||||
| 
 | ||||
| // #define VERBOSE_PHASE
 | ||||
| 
 | ||||
| /** \brief Checks whether a sphere penetrates one of the polygones edges
 | ||||
|  * | ||||
|  * This check only finds intersections of the sphere with one of the sides in | ||||
|  * other words it will not find intersections with the vertices. As for convex | ||||
|  * polygons a sphere will either touch one of the edges or one of the | ||||
|  * vertices. | ||||
|  * | ||||
|  * First thing we do is calculate the normals pointing out of the polygon. | ||||
|  * Then for each edge e of the polygon (is being done by the function | ||||
|  * calculate_contatc_plane_point (...): | ||||
|  * - Calculate the point that would be the first to touch edge e if a contact | ||||
|  *   occurs | ||||
|  * - Calculate the time it would take for this point to touch the edge with | ||||
|  *   the relative velocity of the sphere | ||||
|  * | ||||
|  * Next we calculatefor each edge the point on the sphere which would be the first to touch | ||||
|  * the polygon, if it was moving towards the current edge. | ||||
|  */ | ||||
| int check_collision_polygon_sphere_sides (Shape *shape_a, Shape *shape_b, CollisionInfo *info) { | ||||
| 	Polygon* polygon = dynamic_cast<Polygon*> (shape_a); | ||||
| 	Sphere* sphere = dynamic_cast<Sphere*> (shape_b); | ||||
| 
 | ||||
| 	if ( polygon == NULL && sphere == NULL) { | ||||
| 		polygon = dynamic_cast<Polygon*> (shape_b); | ||||
| 		sphere = dynamic_cast<Sphere*> (shape_a); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!polygon || !sphere) { | ||||
| 		return CHECK_ERROR_INVALID_TYPES; | ||||
| 	} | ||||
| 
 | ||||
| 	vector3d velocity_sphere = sphere->getVelocity(); | ||||
| 	 | ||||
| 	vector3d temp_vector (velocity_sphere); | ||||
| 	if (temp_vector.length2() == 0.) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	// Calculate the normals pointing OUT of the polygon
 | ||||
| 	float *t = NULL, t_min = 10000.; | ||||
| 	unsigned int i,j,vertices,count = 0; | ||||
| 	vertices = polygon->getVerticeCount(); | ||||
| 	vector3d *normals = NULL; | ||||
| 	vector3d side (0., 0., 0.); | ||||
| 	vector3d up (0., 1., 0.); | ||||
| /*
 | ||||
| 	if (polygon->getPosition().length() > 0.) { | ||||
| 		for (i = 0; i < vertices; i++) { | ||||
| 			polygon->getVertice(i) += polygon->getPosition(); | ||||
| 		} | ||||
| 	} | ||||
| */ | ||||
| 	// normals contains all the normal vectors out of
 | ||||
| 	// the polygon
 | ||||
| 	normals = new vector3d[vertices]; | ||||
| 	// The array t contains the time it takes until the sphere
 | ||||
| 	// would touch the plane with the given velocity
 | ||||
| 	t = new float[vertices]; | ||||
| 
 | ||||
| 	for (i = 0; i < vertices; i++) { | ||||
| 		j = (i + 1) % vertices; | ||||
| 		side = polygon->getVertice(j); | ||||
| 		side -= polygon->getVertice(i); | ||||
| 		normals[i] = cross_product (side, up); | ||||
| 		normals[i] /= normals[i].length (); | ||||
| 
 | ||||
| 		// temp_vector is the point on the sphere that would touch the plane first
 | ||||
| 		// if it was directly moving towards it
 | ||||
| 		temp_vector = normals[i]; | ||||
| 		temp_vector *= - sphere->getRadius(); | ||||
| 		temp_vector += sphere->getPosition(); | ||||
| 
 | ||||
| 		t[i] = calculate_contact_plane_point (normals[i], polygon->getVertice(i), temp_vector, velocity_sphere); | ||||
| 
 | ||||
| #ifdef VERBOSE_PHASE | ||||
| 		cout << "= next =" << endl; | ||||
| 		cout << "t[" << i << "] = " << t[i] << " normal = "; normals[i].print (); | ||||
| 		cout << "point       = "; temp_vector.print(); | ||||
| 		cout << "plane point = "; polygon->getVertice(i).print(); | ||||
| #endif | ||||
| 		if (t[i] < 0) | ||||
| 			normals[i].setValues (0., 0., 0.); | ||||
| 		else { | ||||
| 			if (t[i] < t_min) | ||||
| 				t_min = t[i]; | ||||
| 			count ++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (count == 0) { | ||||
| 		delete[] t; | ||||
| 		delete[] normals; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	vector3d contact_point, cp_near; | ||||
| 
 | ||||
| 	/// \ToDo: Instead of checking all planes, remember which ones to check
 | ||||
| 	for (i = 0; i < vertices; i++) { | ||||
| 		if ( t[i] >= 0) { | ||||
| 			// So there seems to occur an collision. Now we have to check,
 | ||||
| 			// whether this is actually between the points that define the
 | ||||
| 			// plane.
 | ||||
| 			unsigned int min_distance_vertex_index = i, other_vertice = (i + 1) % vertices; | ||||
| 			float min_distance; | ||||
| 			j = (i + 1) % vertices; | ||||
| 			// First we calculate the actual contact point:
 | ||||
| 			temp_vector = normals[i]; | ||||
| 			temp_vector *= - sphere->getRadius(); | ||||
| 			temp_vector *= t[i]; | ||||
| 			temp_vector += sphere->getPosition(); | ||||
| 
 | ||||
| 			contact_point = normals[i]; | ||||
| 			contact_point *= -sphere->getRadius(); | ||||
| 			contact_point += temp_vector; | ||||
| 
 | ||||
| 			// Now we calculate to which vertice this point is closer:
 | ||||
| 			temp_vector = contact_point; | ||||
| 			temp_vector -= polygon->getVertice(i); | ||||
| 			min_distance = temp_vector.length2 (); | ||||
| 
 | ||||
| 			temp_vector = contact_point; | ||||
| 			temp_vector -= polygon->getVertice(j); | ||||
| 
 | ||||
| 			if (min_distance > temp_vector.length2 ()) { | ||||
| 				min_distance_vertex_index = j; | ||||
| 				other_vertice = i; | ||||
| 			} | ||||
| 
 | ||||
| 			// Then we want to see, whether the contact point actually lies
 | ||||
| 			// on the vector that goes from one vertice to the other. For
 | ||||
| 			// this we calculate (cp - near) * (far - near). The value
 | ||||
| 			// cannot be greater than 1. (otherwise we would have picked
 | ||||
| 			// the other vector as near. If it is < 0 then it is outside
 | ||||
| 			// of the polygon.
 | ||||
| 			temp_vector = polygon->getVertice(other_vertice); | ||||
| 			temp_vector -= polygon->getVertice(min_distance_vertex_index); | ||||
| 
 | ||||
| 			temp_vector /= temp_vector.length(); | ||||
| 
 | ||||
| 			cp_near = contact_point; | ||||
| 			cp_near -= polygon->getVertice(min_distance_vertex_index); | ||||
| 
 | ||||
| 			float val = cp_near * temp_vector; | ||||
| 			if ( (val >= 0 && val <= 1) && (t[i] <= 1.)) { | ||||
| 				info->time = t[i]; | ||||
| 				info->normal = normals[i]; | ||||
| 
 | ||||
| 				info->point = sphere->getPosition(); | ||||
| 				info->point += sphere->getVelocity() * t[i]; | ||||
| 				info->point -= normals[i] * sphere->getRadius (); | ||||
| 
 | ||||
| 				delete[] t; | ||||
| 				delete[] normals; | ||||
| 				return 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	if ( (t_min <= 1.) && (t_min >= 0.)) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 	*/ | ||||
| 
 | ||||
| 	delete[] t; | ||||
| 	delete[] normals; | ||||
| 
 | ||||
| 	if (t_min > 1.) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return 0; | ||||
| //	return CHECK_ERROR_UNKNOWN;
 | ||||
| }; | ||||
| 
 | ||||
| int check_collision_polygon_sphere_vertices (Shape *shape_a, Shape *shape_b, CollisionInfo *info) { | ||||
| 	Polygon* polygon = dynamic_cast<Polygon*> (shape_a); | ||||
| 	Sphere* sphere = dynamic_cast<Sphere*> (shape_b); | ||||
| 
 | ||||
| 	if ( polygon == NULL && sphere == NULL) { | ||||
| 		polygon = dynamic_cast<Polygon*> (shape_b); | ||||
| 		sphere = dynamic_cast<Sphere*> (shape_a); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!polygon || !sphere) { | ||||
| 		return CHECK_ERROR_INVALID_TYPES; | ||||
| 	} | ||||
| 
 | ||||
| 	// Transform global velocities to relative velocities:
 | ||||
| 	/*
 | ||||
| 	sphere->setVelocity (sphere->getVelocity() - polygon->getVelocity()); | ||||
| */ | ||||
| 	vector3d velocity_sphere = sphere->getVelocity(); | ||||
| 	 | ||||
| 	vector3d temp_vector (velocity_sphere); | ||||
| 	if (temp_vector.length2() == 0.) { | ||||
| #ifdef VERBOSE_PHASE | ||||
| 		cout << "sphere has no velocity!" << endl; | ||||
| #endif | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	vector3d contact_point, cp_near; | ||||
| 
 | ||||
| 	// Okay if we happen to be here, there still might be one of
 | ||||
| 	// the corners colliding with the sphere.
 | ||||
| 	float a, b, c, t1, t2, t_min = 10000; | ||||
| 	unsigned int i, j, vertices; | ||||
| 	vector3d position (sphere->getPosition()); | ||||
| 	vector3d velocity (sphere->getVelocity()); | ||||
| 	float radius = sphere->getRadius(); | ||||
| 	vertices = polygon->getVerticeCount(); | ||||
| 
 | ||||
| 	for (i = 0; i < vertices; i++) { | ||||
| 		vector3d vertice (polygon->getVertice(i)); | ||||
| 		a = b = c = 0; | ||||
| 		 | ||||
| 		// We must ensure that all happens in the x-z-plane (so y == 0.)
 | ||||
| 		vertice[1] = 0.; | ||||
| 		position[1] = 0.; | ||||
| 
 | ||||
| 		vector3d distance_sphere_vertice; | ||||
| 		for (j = 0; j < 3; j++) { | ||||
| 			distance_sphere_vertice[j] = position[j] - vertice[j]; | ||||
| 		} | ||||
| #ifdef VERBOSE_PHASE | ||||
| 		cout << "  ===== " << endl; | ||||
| 		cout << "vertice = "; | ||||
| 		vertice.print (); | ||||
| 		velocity.print (); | ||||
| 		position.print (); | ||||
| 		cout << "radius = " << radius << endl; | ||||
| 		cout << "distance = " << distance_sphere_vertice.length () << endl;; | ||||
| #endif | ||||
| 		for (j = 0; j < 3; j++) { | ||||
| 			a += velocity[j]*velocity[j]; | ||||
| 			b += 2 * velocity[j] * (position[j] - vertice[j]); | ||||
| 			c += position[j] * position[j] - 2 * position[j] * vertice[j] + vertice[j] * vertice[j];  | ||||
| 		} | ||||
| 		c -= radius * radius; | ||||
| 
 | ||||
| 		if (solve_quadratic (a, b, c, &t1, &t2)) { | ||||
| //			cout << "solve_quadratic = " << t1 << "\t" << t2 << endl;
 | ||||
| 			float t_temp_min = t2; | ||||
| 			if (t1 < t2) | ||||
| 				t_temp_min = t1; | ||||
| 
 | ||||
| 			if (t_temp_min < t_min) { | ||||
| 				if ((t_temp_min <= 1.) && (t_temp_min >= 0.)) { | ||||
| 					t_min = t_temp_min; | ||||
| 					temp_vector = position; | ||||
| 					temp_vector -= vertice; | ||||
| 					temp_vector /= temp_vector.length (); | ||||
| #ifdef VERBOSE_PHASE | ||||
| 					cout << "new closest point t = " << t_min << endl; | ||||
| #endif				 | ||||
| 					info->time = t_min; | ||||
| 					info->normal = temp_vector; | ||||
| 					info->point = vertice; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ( (t_min <= 1.) && (t_min >= 0.)) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (t_min > 1.) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return CHECK_ERROR_UNKNOWN; | ||||
| }; | ||||
| 
 | ||||
| int check_collision_polygon_sphere (float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo *info) { | ||||
| 	/* If the first shape given is a sphere and the second one a shape, we have
 | ||||
| 	 * to remember it to set the right value to *info. | ||||
| 	 */ | ||||
| 	bool swapped = false; | ||||
| 	Polygon* polygon_cast_test = dynamic_cast<Polygon*> (shape_a); | ||||
| 	Sphere* sphere_cast_test = dynamic_cast<Sphere*> (shape_b); | ||||
| 
 | ||||
| 	if ( polygon_cast_test == NULL && sphere_cast_test == NULL) { | ||||
| 		polygon_cast_test = dynamic_cast<Polygon*> (shape_b); | ||||
| 		sphere_cast_test = dynamic_cast<Sphere*> (shape_a); | ||||
| 
 | ||||
| 		swapped = true; | ||||
| 	} | ||||
| 	 | ||||
| 	if (!polygon_cast_test || !sphere_cast_test) { | ||||
| 		return CHECK_ERROR_INVALID_TYPES; | ||||
| 	} | ||||
| 
 | ||||
| 	Polygon polygon_copy (*polygon_cast_test); | ||||
| 	Sphere sphere_copy (*sphere_cast_test); | ||||
| 	 | ||||
| 	unsigned int vertices; | ||||
| 	vertices = polygon_copy.getVerticeCount(); | ||||
| 
 | ||||
| #ifdef VERBOSE_PHASE | ||||
| 	cout << "======== New Polygon Sphere Test: Phase 1" << endl; | ||||
| 	if (swapped) | ||||
| 		cout << "Swapped!" << endl; | ||||
| 	cout << "Polygon position: "; | ||||
| 	polygon_copy.getPosition().print (); | ||||
| 	cout << "Polygon velocity: "; | ||||
| 	polygon_copy.getVelocity().print (); | ||||
| 	cout << "Sphere position: "; | ||||
| 	sphere_copy.getPosition().print (); | ||||
| 	cout << "Sphere velocity: "; | ||||
| 	sphere_copy.getVelocity().print (); | ||||
| 	cout << "Timestep       : " << timestep << endl; | ||||
| 
 | ||||
| 	cout << "Vertices before transformation = " << endl; | ||||
| 	int i; | ||||
| 	for (i = 0; i < vertices; i++) { | ||||
| 		polygon_copy.getVertice(i).print(); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	// Here we translate the polygon and its velocity into the reference frame
 | ||||
| 	// of the polygon.
 | ||||
| 	sphere_copy.setPosition (sphere_copy.getPosition() - polygon_copy.getPosition()); | ||||
| 	sphere_copy.setPosition (sphere_copy.getPosition().rotate_y (-polygon_copy.getAngle())); | ||||
| 	// Here scale the velocity so that our time horizon lies in [0., 1.]
 | ||||
| 	sphere_copy.setVelocity ((sphere_copy.getVelocity() - polygon_copy.getVelocity() ) * timestep ); | ||||
| 	sphere_copy.setVelocity (sphere_copy.getVelocity().rotate_y (-polygon_copy.getAngle())); | ||||
| 
 | ||||
| #ifdef VERBOSE_PHASE | ||||
| 	cout << "Vertices after transformation = " << endl; | ||||
| 	for (i = 0; i < vertices; i++) { | ||||
| 		polygon_copy.getVertice(i).print(); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifdef VERBOSE_PHASE | ||||
| 	cout << "After transformation:" << endl; | ||||
| 	cout << "Polygon position: "; | ||||
| 	polygon_copy.getPosition().print (); | ||||
| 	cout << "Polygon velocity: "; | ||||
| 	polygon_copy.getVelocity().print (); | ||||
| 	cout << "Sphere position: "; | ||||
| 	sphere_copy.getPosition().print (); | ||||
| 	cout << "Sphere velocity: "; | ||||
| 	sphere_copy.getVelocity().print (); | ||||
| #endif | ||||
| 
 | ||||
| 	CollisionInfo sides_info; | ||||
| 	CollisionInfo vertices_info; | ||||
| 	int sides_result = 0, vertices_result = 0; | ||||
| 
 | ||||
| 	/* Tricky part: Since polygons are assumed to be convex and we calculated
 | ||||
| 	 * with both methods a collision, we take the sides result. Since they are | ||||
| 	 * convex the first event to happen is the collision with the side. | ||||
| 	 * Otherwise it would first touch the vertice and then the side, which is | ||||
| 	 * not possible. (\Todo true?) | ||||
| 	 */ | ||||
| 
 | ||||
| 	sides_result = check_collision_polygon_sphere_sides (&polygon_copy, &sphere_copy, &sides_info); | ||||
| 	// We have to transform the time back to [0., timestep]
 | ||||
| 	sides_info.time *= timestep; | ||||
| #ifdef VERBOSE_PHASE | ||||
| 	cout << "sides_result = " << sides_result << " t = " << sides_info.time << endl; | ||||
| #endif	 | ||||
| 	if (sides_result > 0) { | ||||
| 		sides_info.point.rotate_y (polygon_copy.getAngle()); | ||||
| 		sides_info.normal.rotate_y (polygon_copy.getAngle()); | ||||
| 		sides_info.point += polygon_copy.getPosition(); | ||||
| 		memcpy (info, &sides_info, sizeof (CollisionInfo)); | ||||
| 		sides_info.time *= timestep; | ||||
| 		if (swapped == true) { | ||||
| 			info->reference_shape = 1; | ||||
| 		} else { | ||||
| 			info->reference_shape = 0; | ||||
| 		} | ||||
| 		return sides_result; | ||||
| 	}  | ||||
| 
 | ||||
| 	vertices_result = check_collision_polygon_sphere_vertices (&polygon_copy, &sphere_copy, &vertices_info); | ||||
| 	// We have to transform the time back to [0., timestep]
 | ||||
| 	vertices_info.time *= timestep; | ||||
| #ifdef VERBOSE_PHASE | ||||
| 	cout << "vertices_res = " << vertices_result << " t = " << vertices_info.time << endl; | ||||
| 	cout << "vertices_point = "; | ||||
| 	vertices_info.point.print(); | ||||
| #endif | ||||
| 	if (vertices_result > 0) { | ||||
| 		vertices_info.point.rotate_y (polygon_copy.getAngle()); | ||||
| 		vertices_info.normal.rotate_y (polygon_copy.getAngle()); | ||||
| 		vertices_info.point += polygon_copy.getPosition(); | ||||
| 		memcpy (info, &vertices_info, sizeof (CollisionInfo)); | ||||
| 		if (swapped == true) { | ||||
| 			info->reference_shape = 1; | ||||
| 		} else { | ||||
| 			info->reference_shape = 0; | ||||
| 		} | ||||
| 		return vertices_result; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((sides_result == 0) && (vertices_result == 0)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return CHECK_ERROR_UNKNOWN; | ||||
| }; | ||||
| 
 | ||||
| int check_collision_sphere_sphere (float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo *info) { | ||||
| 	/* If the first shape given is a sphere and the second one a shape, we have
 | ||||
| 	 * to remember it to set the right value to *info. | ||||
| 	 */ | ||||
| 	Sphere* sphere_test_a = dynamic_cast<Sphere*> (shape_a); | ||||
| 	Sphere* sphere_test_b = dynamic_cast<Sphere*> (shape_b); | ||||
| 
 | ||||
| 	if (!sphere_test_a || !sphere_test_b) { | ||||
| 		return CHECK_ERROR_INVALID_TYPES; | ||||
| 	} | ||||
| 
 | ||||
| 	Sphere sphere_a (*sphere_test_a); | ||||
| 	Sphere sphere_b (*sphere_test_b); | ||||
| 
 | ||||
| 	// First we check whether there is actually a relative velocity towards each
 | ||||
| 	// other:
 | ||||
| 	vector3d rel_velocity = sphere_b.getVelocity (); | ||||
| 	rel_velocity -= sphere_a.getVelocity (); | ||||
| 	rel_velocity *= timestep; | ||||
| 	if (rel_velocity.length2() == 0.) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	vector3d rel_position = sphere_b.getPosition (); | ||||
| 	rel_position -= sphere_a.getPosition (); | ||||
| 
 | ||||
| 	// We need to ignore height differences
 | ||||
| 	rel_position[1] = 0.; | ||||
| 	rel_velocity[1] = 0.; | ||||
| 
 | ||||
| 	vector3d rel_position_norm = rel_position; | ||||
| 	rel_position_norm.normalize (); | ||||
| 
 | ||||
| 	float velocity_projection = rel_position_norm * rel_velocity; | ||||
| 	float distance = rel_position.length(); | ||||
| 
 | ||||
| 	if (velocity_projection >= 0.)  | ||||
| 		return 0; | ||||
| 
 | ||||
| 	float t = (- distance +  sphere_a.getRadius () + sphere_b.getRadius ()) / velocity_projection; | ||||
| 
 | ||||
| #ifdef VERBOSE_PHASE | ||||
| 	cout << "==== New Sphere Sphere Test ====" << endl; | ||||
| 	cout << "Relative Position = "; | ||||
| 	rel_position.print (); | ||||
| 	cout << "Relative Velocity = "; | ||||
| 	rel_velocity.print (); | ||||
| 	cout << "velocity_projection = " << velocity_projection << endl; | ||||
| 	cout << "distance = " << distance << endl; | ||||
| 	cout << "- distance + Ra + Rb = " << - distance + sphere_a.getRadius () + sphere_b.getRadius () << endl; | ||||
| 	cout << "t = " << t << endl; | ||||
| #endif | ||||
| 
 | ||||
| 	// if t < 0 this means we would have to move back in time
 | ||||
| 	// to get to the point where the two spheres touched. In other words: they
 | ||||
| 	// are overlapping, hence it is an invalid state!
 | ||||
| 	if (t < 0) | ||||
| 		return CHECK_ERROR_OVERLAP; | ||||
| 	if (t > 1) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	info->point = sphere_a.getPosition() + rel_position_norm * t; | ||||
| 	info->time = t * timestep; | ||||
| 
 | ||||
| 	if (sphere_a.getVelocity().length2() == 0.) { | ||||
| 		info->normal = rel_position_norm; | ||||
| 		info->reference_shape = 0; | ||||
| 	} else { | ||||
| 		info->normal = rel_position_norm * -1.; | ||||
| 		info->reference_shape = 1; | ||||
| 	} | ||||
| 	return 1; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										51
									
								
								engine/libraries/coll2d/tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								engine/libraries/coll2d/tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| PROJECT (ENGINETESTS) | ||||
| 
 | ||||
| CMAKE_MINIMUM_REQUIRED (VERSION 2.6) | ||||
| 
 | ||||
| # Needed for UnitTest++ | ||||
| LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../CMake ) | ||||
| 
 | ||||
| SET ( TESTS_SRCS | ||||
| 	main.cc | ||||
| 	general.cc | ||||
| 	polygon_sphere.cc | ||||
| 	sphere_sphere.cc | ||||
| 	) | ||||
| 
 | ||||
| FIND_PACKAGE (UnitTest++) | ||||
| 
 | ||||
| INCLUDE_DIRECTORIES ( ../mathlib/ ) | ||||
| 
 | ||||
| SET_TARGET_PROPERTIES ( ${PROJECT_EXECUTABLES} PROPERTIES | ||||
|   LINKER_LANGUAGE CXX | ||||
| ) | ||||
| 
 | ||||
| IF ( UNITTEST++_FOUND ) | ||||
| 
 | ||||
| 	ADD_EXECUTABLE ( coll2dtests ${TESTS_SRCS} ) | ||||
| 
 | ||||
|   INCLUDE_DIRECTORIES ( ${UNITTEST++_INCLUDE_DIR} ) | ||||
| 
 | ||||
| 	SET_TARGET_PROPERTIES ( coll2dtests PROPERTIES | ||||
| 		LINKER_LANGUAGE CXX | ||||
| 		OUTPUT_NAME runtests  | ||||
| 		) | ||||
| 
 | ||||
| 	TARGET_LINK_LIBRARIES ( coll2dtests | ||||
| 			${UNITTEST++_LIBRARY} | ||||
| 			mathlib | ||||
| 			coll2d | ||||
| 		) | ||||
| 		 | ||||
| 	OPTION (RUN_AUTOMATIC_TESTS "Perform automatic tests after compilation?" OFF) | ||||
| 
 | ||||
| 	IF (RUN_AUTOMATIC_TESTS) | ||||
| 	ADD_CUSTOM_COMMAND (TARGET coll2dtests | ||||
| 		POST_BUILD | ||||
| 		COMMAND coll2dtests | ||||
| 		COMMENT "Running automated tests..." | ||||
| 		) | ||||
| 	ENDIF (RUN_AUTOMATIC_TESTS) | ||||
| 
 | ||||
| ENDIF ( UNITTEST++_FOUND ) | ||||
| 
 | ||||
							
								
								
									
										284
									
								
								engine/libraries/coll2d/tests/general.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								engine/libraries/coll2d/tests/general.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,284 @@ | ||||
| #include <UnitTest++.h> | ||||
| 
 | ||||
| #include <coll2d.h> | ||||
| 
 | ||||
| using namespace coll2d; | ||||
| using namespace std; | ||||
| 
 | ||||
| TEST ( SphereCopyConstructer ) { | ||||
| 	Sphere sphere_a (123.); | ||||
| 	sphere_a.setVelocity (vector3d(1., 2., 3.)); | ||||
| 
 | ||||
| 	Sphere sphere_b (sphere_a); | ||||
| 	CHECK_EQUAL (sphere_a.getRadius (), sphere_b.getRadius ()); | ||||
| 
 | ||||
| 	vector3d velocity_a = sphere_a.getVelocity (); | ||||
| 	vector3d velocity_b = sphere_b.getVelocity (); | ||||
| 
 | ||||
| 	CHECK (velocity_a == velocity_b ); | ||||
| 
 | ||||
| 	sphere_b.setVelocity (vector3d (0., 0., 0.)); | ||||
| 
 | ||||
| 	velocity_a = sphere_a.getVelocity (); | ||||
| 	velocity_b = sphere_b.getVelocity (); | ||||
| 
 | ||||
| 	CHECK (velocity_a != velocity_b ); | ||||
| } | ||||
| 
 | ||||
| TEST ( PolygonCopyConstructer ) { | ||||
| 	Polygon polygon_a (3); | ||||
| 
 | ||||
| 	vector3d vertice0 (-1., 0., -1.); | ||||
| 	vector3d vertice1 (1., 0., -1.); | ||||
| 	vector3d vertice2 (0., 0., 1.); | ||||
| 
 | ||||
| 	polygon_a.setVertice (0, vertice0); | ||||
| 	polygon_a.setVertice (1, vertice1); | ||||
| 	polygon_a.setVertice (2, vertice2); | ||||
| 
 | ||||
| 	polygon_a.setVelocity (vector3d(1., 2., 3.)); | ||||
| 
 | ||||
| 	Polygon polygon_b (polygon_a); | ||||
| 
 | ||||
| 	vector3d velocity_a = polygon_a.getVelocity (); | ||||
| 	vector3d velocity_b = polygon_b.getVelocity (); | ||||
| 
 | ||||
| 	CHECK (vertice0 == polygon_b.getVertice (0)); | ||||
| 	CHECK (vertice1 == polygon_b.getVertice (1)); | ||||
| 	CHECK (vertice2 == polygon_b.getVertice (2)); | ||||
| 
 | ||||
| 	polygon_b.setVelocity (vector3d (0., 0., 0.)); | ||||
| 	velocity_a = polygon_a.getVelocity (); | ||||
| 	velocity_b = polygon_b.getVelocity (); | ||||
| 	 | ||||
| 	CHECK (velocity_a != velocity_b ); | ||||
| } | ||||
| 
 | ||||
| /** Checks whether we identify the different shapes
 | ||||
|  * correctly. | ||||
|  */ | ||||
| TEST ( CheckShapeType ) { | ||||
| 	vector3d sphere_position (0., 0., 0.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (0, NULL); | ||||
| 	Shape* sphere = new Sphere (0, sphere_position); | ||||
| 
 | ||||
| 	Shape* cast_test = NULL; | ||||
| 
 | ||||
| 	cast_test = dynamic_cast <Sphere*> ( sphere ); | ||||
| 	CHECK_EQUAL (cast_test, sphere); | ||||
| 	cast_test = dynamic_cast <Sphere*> ( polygon ); | ||||
| 	CHECK (cast_test ==  NULL ); | ||||
| 	cast_test = dynamic_cast <Polygon*> (polygon); | ||||
| 	CHECK_EQUAL (cast_test, polygon); | ||||
| 	cast_test = dynamic_cast <Polygon*> (sphere); | ||||
| 	CHECK (cast_test == NULL ); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| /** Checks whether the right check function is chosen
 | ||||
|  */ | ||||
| TEST ( CheckGetCheck ) { | ||||
| 	vector3d sphere_position (0., 0., 0.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (0, NULL); | ||||
| 	Shape* sphere = new Sphere (0, sphere_position); | ||||
| 
 | ||||
| 	check_cb check = NULL; | ||||
| 
 | ||||
| 	// polygon - sphere -> polygon_sphere
 | ||||
| 	check = get_check (polygon, sphere); | ||||
| 	CHECK (static_cast<check_cb> (check) == static_cast<check_cb> (check_collision_polygon_sphere)); | ||||
| 
 | ||||
| 	// sphere - polygon -> polygon_sphere
 | ||||
| 	check = get_check (sphere, polygon); | ||||
| 	CHECK (static_cast<check_cb> (check) == static_cast<check_cb> (check_collision_polygon_sphere)); | ||||
| 
 | ||||
| 	// and we do not want that the pointers have changed!
 | ||||
| 	// (as it used to be in previous versions)
 | ||||
| 	CHECK (dynamic_cast <Polygon*> (sphere) == NULL); | ||||
| 	CHECK (dynamic_cast <Sphere*> (polygon) == NULL); | ||||
| 
 | ||||
| 	check = get_check (sphere, sphere); | ||||
| 	CHECK (check == check_collision_sphere_sphere); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckErrorNotImplemented ) { | ||||
| 	Shape* polygon = new Polygon (0, NULL); | ||||
| 	vector3d velocity (0., 0., 0.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, polygon, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK (result == CHECK_ERROR_NOT_IMPLEMENTED); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCalculateContactPlanePoint ) { | ||||
| 	vector3d normal (1., 0., 0.); | ||||
| 	vector3d plane_point (0., 0., 0.); | ||||
| 	vector3d point (1., 0., 0.); | ||||
| 	vector3d velocity (-1., 0., 0); | ||||
| 
 | ||||
| 	float result; | ||||
| 
 | ||||
| 	// Directly moving towards the plane
 | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	// Moving with a slight angle onto the plane
 | ||||
| 	velocity.setValues (-1., 0., 0.2); | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	velocity.setValues (-1., 0., 0.); | ||||
| 
 | ||||
| 	// Point is "below" the plane and moves even deeper
 | ||||
| 	plane_point.setValues (2., 0., 0); | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (-999, result); | ||||
| 
 | ||||
| 	// Point is "below" but moves towards the plane
 | ||||
| 	velocity.setValues (1., 0., 0); | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (-111, result); | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionStepsize ) { | ||||
| 	vector3d normal (1., 0., 0.); | ||||
| 	vector3d plane_point (0., 0., 0.); | ||||
| 	vector3d point (1., 0., 0.); | ||||
| 	vector3d velocity (-1., 0., 0); | ||||
| 
 | ||||
| 	float result; | ||||
| 
 | ||||
| 	// Directly moving towards the plane
 | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	// Moving with a slight angle onto the plane
 | ||||
| 	velocity.setValues (-1., 0., 0.2); | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	velocity.setValues (-1., 0., 0.); | ||||
| 
 | ||||
| 	// Point is "below" the plane and moves even deeper
 | ||||
| 	plane_point.setValues (2., 0., 0); | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (-999, result); | ||||
| 
 | ||||
| 	// Point is "below" but moves towards the plane
 | ||||
| 	velocity.setValues (1., 0., 0); | ||||
| 	result = calculate_contact_plane_point (normal, plane_point, point, velocity); | ||||
| 	CHECK_EQUAL (-111, result); | ||||
| } | ||||
| 
 | ||||
| /* Here we test, whether the value of info.reference_shape is correct.
 | ||||
|  * If we swap the shapes passed to check_collision, then the value must swap, | ||||
|  * too. | ||||
|  */ | ||||
| TEST ( CheckReferenceShapeValue ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	// first part of the test, the collision occurs 
 | ||||
| 	// on an edge
 | ||||
| 	vector3d sphere_position (2.3, 0., 0.); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 	sphere->setVelocity (vector3d (-1., 0., 0.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0, info.reference_shape); | ||||
| 
 | ||||
| 	result = check_collision (1., sphere, polygon, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (1, info.reference_shape); | ||||
| 
 | ||||
| 	// here the collision occurs on a vertice
 | ||||
| 	sphere->setPosition (vector3d (1.5, 0., -2.5)); | ||||
| 	sphere->setVelocity (vector3d (0., 0., 1.)); | ||||
| 
 | ||||
| 	result = check_collision (1., sphere, polygon, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (1, info.reference_shape); | ||||
| 
 | ||||
| 	result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0, info.reference_shape); | ||||
| 
 | ||||
| 	delete sphere; | ||||
| 	delete polygon; | ||||
| } | ||||
| 
 | ||||
| /* Test whether Polygon::getCopy() does what it should */ | ||||
| TEST ( CheckPolygonGetCopy ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Polygon* polygon = new Polygon (4, vertices); | ||||
| 	Polygon* polygon_copy = polygon->getCopy(); | ||||
| 
 | ||||
| 	CHECK (polygon != polygon_copy); | ||||
| 	CHECK_EQUAL (polygon->getVerticeCount(), polygon_copy->getVerticeCount()); | ||||
| 
 | ||||
| 	unsigned int i, count; | ||||
| 	count = polygon->getVerticeCount (); | ||||
| 
 | ||||
| 	for (i = 0; i < count; i ++) { | ||||
| 		vector3d vertice = polygon->getVertice (i); | ||||
| 		vector3d vertice_copy = polygon_copy->getVertice (i); | ||||
| 
 | ||||
| 		int j; | ||||
| 		for (j = 0; j < 3; j++) { | ||||
| 			CHECK_EQUAL (vertice[j], vertice_copy[j]); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete polygon_copy; | ||||
| } | ||||
| 
 | ||||
| /* Test whether Sphere::getCopy() does what it should */ | ||||
| TEST ( CheckSphereGetCopy ) { | ||||
| 	Sphere* sphere = new Sphere (1.23); | ||||
| 	Sphere* sphere_copy = sphere->getCopy(); | ||||
| 
 | ||||
| 	CHECK_EQUAL (sphere->getRadius(), sphere_copy->getRadius()); | ||||
| 	CHECK (sphere != sphere_copy); | ||||
| 
 | ||||
| 	delete sphere; | ||||
| 	delete sphere_copy; | ||||
| } | ||||
| 
 | ||||
| TEST ( SphereSetGetRadius ) { | ||||
| 	Sphere sphere (123.); | ||||
| 	CHECK_EQUAL (123, sphere.getRadius()); | ||||
| 
 | ||||
| 	sphere.setRadius (456.); | ||||
| 	CHECK_EQUAL (456, sphere.getRadius()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										6
									
								
								engine/libraries/coll2d/tests/main.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								engine/libraries/coll2d/tests/main.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #include <UnitTest++.h> | ||||
| 
 | ||||
| int main (int argc, char *argv[]) | ||||
| { | ||||
| 	return UnitTest::RunAllTests (); | ||||
| } | ||||
							
								
								
									
										544
									
								
								engine/libraries/coll2d/tests/polygon_sphere.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										544
									
								
								engine/libraries/coll2d/tests/polygon_sphere.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,544 @@ | ||||
| #include <UnitTest++.h> | ||||
| 
 | ||||
| #include <coll2d.h> | ||||
| 
 | ||||
| using namespace coll2d; | ||||
| using namespace std; | ||||
| 
 | ||||
| TEST ( CheckErrorInvalidTypes ) { | ||||
| 	Shape* polygon = new Polygon (0, NULL); | ||||
| 	vector3d velocity (0., 0., 0.); | ||||
| 	vector3d sphere_position (2.1, 0., 0.); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 	sphere->setVelocity (vector3d(0., 0., 0.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_polygon_sphere (1., sphere, sphere, &info); | ||||
| 	CHECK (result == CHECK_ERROR_INVALID_TYPES); | ||||
| 
 | ||||
| 	result = check_collision_polygon_sphere (1., polygon, polygon, &info); | ||||
| 	CHECK (result == CHECK_ERROR_INVALID_TYPES); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereNoVelocity ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., -1.); | ||||
| 	vertices[1].setValues (1., 0., -1.); | ||||
| 	vertices[2].setValues (1., 0., 1.); | ||||
| 	vertices[3].setValues (-1., 0., 1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2.1, 0., 0.); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (0., 0., 0.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK (result >= 0); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereDiverging ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2.1, 0., 0.); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (1., 0., 0.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK (result >= 0); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereContact ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2., 0., 0.); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 	sphere->setVelocity (vector3d (-1., 0., 0.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK (result > 0); | ||||
| 	CHECK_EQUAL (0.0, info.time); | ||||
| 	CHECK_EQUAL (1., info.normal[0]); | ||||
| 	CHECK_EQUAL (0., info.normal[1]); | ||||
| 	CHECK_EQUAL (0., info.normal[2]); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereColliding ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2.5, 0., 0.1); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (-1., 0., 0.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0.5, info.time); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingTop ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (0., 0., 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (0., 0., -1.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0.5, info.time); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingNonPerpendicular ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (0., 0., 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (0.01, 0., -1.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0.5, info.time); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingCorner) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position ( 1.5, 0., 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (0.0, 0., -1.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| // In this test we make sure, that the z value of both the polygon and the
 | ||||
| // sphere get ignored:
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingCornerIgnoreHeight) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position ( 1.5, 10., 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 	sphere->setVelocity (vector3d (0., 0., -1.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., -10., 1.); | ||||
| 	vertices[1].setValues (1., -10., 1.); | ||||
| 	vertices[2].setValues (1., -10., -1.); | ||||
| 	vertices[3].setValues (-1., -10., -1.); | ||||
| 
 | ||||
| 	sphere->setPosition (vector3d (1.5, 0., 2.5)); | ||||
| 	result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingCornerTop) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (1.5, 0., - 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (0., 0., 1.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingCornerNeighbour) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., -0.99); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (1.5 , 0., - 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (0., 0., 1.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK (info.point == vertices[2]); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereNonCollidingSetPosition ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2.5, 0., 0.1); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 	sphere->setPosition (vector3d (35, 0, 0)); | ||||
| 	vector3d velocity (-1., 0., 0.); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision_rel (1., polygon, sphere, &velocity, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (0, result); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| // In this test we set the velocity of the polygon instead of the
 | ||||
| // sphere.
 | ||||
| TEST ( CheckCollisionPolygonSphereCollidingPolygonSetVelocity ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2.5, 0., 0.); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (1., 0., 0.); | ||||
| 	polygon->setVelocity (velocity); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0.5, info.time); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckSetGetAngle ) { | ||||
| 	Shape* polygon = new Polygon (0, NULL); | ||||
| 
 | ||||
| 	polygon->setAngle (0.1234567); | ||||
| 
 | ||||
| 	CHECK (fabs (0.1234567 - polygon->getAngle ()) < 1.0e-7); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereDiamond ) { | ||||
| 	vector3d vertices[4]; | ||||
| 	float sqrt2 = sqrt (2); | ||||
| 
 | ||||
| 	vertices[0].setValues (-sqrt2, 0., 0.); | ||||
| 	vertices[1].setValues (0., 0., sqrt2); | ||||
| 	vertices[2].setValues (sqrt2, 0., 0.); | ||||
| 	vertices[3].setValues (0., 0., -sqrt2); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	Shape* sphere = new Sphere (1., vector3d (sqrt2 + 1.5, 0., 0.)); | ||||
| 	sphere->setVelocity (vector3d (-1., 0., 0.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK (fabs (0.5 - info.time) <= 1.0e-6); | ||||
| 	CHECK_EQUAL (0, info.reference_shape); | ||||
| 	 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckPolygonSpherePassingBy ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (1., 0., 2.5); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 	sphere->setVelocity (vector3d (-2., 0., 0.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (0, result); | ||||
| 
 | ||||
| 	delete sphere; | ||||
| 	delete polygon; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereReturnValuePoint ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 	polygon->setPosition (vector3d (sqrt (2), 0., - sqrt (2))); | ||||
| 	polygon->setAngle (M_PI * 0.25); | ||||
| 
 | ||||
| 	Shape* sphere = new Sphere (1, vector3d (-sqrt(2) * 0.5, 0., sqrt (2) * 0.5)); | ||||
| 	sphere->setVelocity (vector3d (sqrt (2), 0., -sqrt(2))); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK ( fabs (0.5 - info.time) < 1.0e-6); | ||||
| 	CHECK ( (info.point - vector3d (sqrt (2) * 0.5, 0., -sqrt(2) * 0.5)).length() < 1.0e-6 ); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereReturnValuePointTranslated ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 	polygon->setPosition (vector3d (sqrt (2) + 1., 0., - sqrt (2) - 1.)); | ||||
| 	polygon->setAngle (M_PI * 0.25); | ||||
| 
 | ||||
| 	Shape* sphere = new Sphere (1, vector3d (-sqrt(2) * 0.5 + 1., 0., sqrt (2) * 0.5 -1.)); | ||||
| 	sphere->setVelocity (vector3d (sqrt (2), 0., -sqrt(2))); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK ( fabs (0.5 - info.time) < 1.0e-6); | ||||
| 	CHECK ( (info.point - vector3d (sqrt (2) * 0.5 + 1, 0., -sqrt(2) * 0.5 - 1.)).length() < 1.0e-6 ); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereReturnValuePointVerticeTranslated ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 	polygon->setPosition (vector3d (0. + 2., 0., - sqrt (2) - 1.5)); | ||||
| 	polygon->setAngle (M_PI * 0.25); | ||||
| 
 | ||||
| 	Shape* sphere = new Sphere (1, vector3d (0. + 2., 0., 0.)); | ||||
| 	sphere->setVelocity (vector3d (0. , 0., -1.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK ( fabs (0.5 - info.time) < 1.0e-6); | ||||
| 	CHECK ( (info.point - vector3d (0. + 2., 0., -1.5)).length() < 1.0e-6 ); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereReferenceShapePolygon ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 	polygon->setPosition (vector3d (0., 0., 0.)); | ||||
| 	polygon->setVelocity (vector3d (1., 0., 0.)); | ||||
| 
 | ||||
| 	Shape* sphere = new Sphere (1, vector3d (2.5, 0., 0.)); | ||||
| 	sphere->setVelocity (vector3d (0., 0., 0.)); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK ( fabs (0.5 - info.time) < 1.0e-6); | ||||
| 	CHECK_EQUAL ( 0, info.reference_shape ); | ||||
| 	 | ||||
| 	polygon->setPosition (vector3d (0., 0., 0.)); | ||||
| 	polygon->setVelocity (vector3d (1., 0., 0.)); | ||||
| 	sphere->setPosition (vector3d (2.5, 0., 0.)); | ||||
| 	sphere->setVelocity (vector3d (0., 0., 0.)); | ||||
| 
 | ||||
| 	result = check_collision (1., sphere, polygon, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK ( fabs (0.5 - info.time) < 1.0e-6); | ||||
| 	CHECK_EQUAL ( 1, info.reference_shape ); | ||||
| 
 | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| TEST ( CheckCollisionPolygonSphereTimestep ) { | ||||
| 	vector3d vertices[4]; | ||||
| 
 | ||||
| 	vertices[0].setValues (-1., 0., 1.); | ||||
| 	vertices[1].setValues (1., 0., 1.); | ||||
| 	vertices[2].setValues (1., 0., -1.); | ||||
| 	vertices[3].setValues (-1., 0., -1.); | ||||
| 
 | ||||
| 	Shape* polygon = new Polygon (4, vertices); | ||||
| 
 | ||||
| 	vector3d sphere_position (2.5, 0., 0.1); | ||||
| 	Shape* sphere = new Sphere (1, sphere_position); | ||||
| 
 | ||||
| 	vector3d velocity (-1., 0., 0.); | ||||
| 	sphere->setVelocity (velocity); | ||||
| 
 | ||||
| 	CollisionInfo info; | ||||
| 	int result; | ||||
| 	result = check_collision (1., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0.5, info.time); | ||||
| 
 | ||||
| 	result = check_collision (2., polygon, sphere, &info); | ||||
| 
 | ||||
| 	CHECK_EQUAL (1, result); | ||||
| 	CHECK_EQUAL (0.5, info.time); | ||||
| 
 | ||||
| 	result = check_collision (0.499, polygon, sphere, &info); | ||||
| 	CHECK_EQUAL (0, result); | ||||
| 
 | ||||
| 	delete polygon; | ||||
| 	delete sphere; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user