initial commit

This commit is contained in:
2010-04-05 23:38:59 +02:00
commit e7e0b39e82
150 changed files with 28636 additions and 0 deletions
+28
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File
@@ -0,0 +1,7 @@
#include "EntityBase.h"
#include "ModelBase.h"
namespace Engine {
}
+173
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File
@@ -0,0 +1,3 @@
ADD_SUBDIRECTORY ( mathlib )
ADD_SUBDIRECTORY ( coll2d )
ADD_SUBDIRECTORY ( oglft )
@@ -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
View 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
View 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 */
@@ -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
View 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;
};
}
@@ -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
View 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
View File
@@ -0,0 +1,6 @@
#include <UnitTest++.h>
int main (int argc, char *argv[])
{
return UnitTest::RunAllTests ();
}
@@ -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;
}
@@ -0,0 +1,245 @@
#include <UnitTest++.h>
#include <coll2d.h>
using namespace coll2d;
using namespace std;
TEST ( CheckSphereSphereInvalidTypes ) {
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_sphere_sphere (1., polygon, sphere, &info);
CHECK (result == CHECK_ERROR_INVALID_TYPES);
delete polygon;
delete sphere;
}
TEST ( CheckSphereSphereNoVelocity ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (4., 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (0, result);
delete sphere_a;
delete sphere_b;
}
/* This tests whether we report a collision time of 0.0 when two spheres are
* in contact with each other
*/
TEST ( CheckCollisionSphereSphereContact ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (2., 0., 0.));
sphere_b->setVelocity (vector3d(-1., 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK (result >= 0);
CHECK_EQUAL (0.0, info.time);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereDiverging ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (4., 0., 0.));
sphere_b->setVelocity (vector3d (1., 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (0, result);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereCollision ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
sphere_b->setVelocity (vector3d (-1., 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereCollisionCheckOrder ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
sphere_a->setVelocity (vector3d (1., 0., 0.));
sphere_b->setVelocity (vector3d (-1.5, 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
vector3d normal = info.normal;
result = check_collision_sphere_sphere (1., sphere_b, sphere_a, &info);
CHECK_EQUAL (1, result);
CHECK ( normal[0] == -info.normal[0]);
CHECK ( normal[1] == -info.normal[1]);
CHECK ( normal[2] == -info.normal[2]);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereNoCollision ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
sphere_b->setVelocity (vector3d (-0.9, 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (0, result);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereCollisionResult ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (2.5, 0., 0.));
sphere_b->setVelocity (vector3d (-1, 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
CHECK_EQUAL (0.5, info.time);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereMovingNonHorizontal ) {
Shape* sphere_a = new Sphere (3., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1.5, vector3d (3., 0., 4.));
sphere_a->setVelocity (vector3d (3./5., 0., 4./5.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
vector3d result_normal = vector3d (-3., 0., -4.).normalize();
vector3d collision_point = result_normal * -0.5;
CHECK_EQUAL (1, result);
CHECK_EQUAL (0.5, info.time);
CHECK_EQUAL (1, info.reference_shape);
CHECK (result_normal == info.normal);
CHECK (collision_point == info.point);
sphere_a->setVelocity (vector3d (0., 0., 0.));
sphere_b->setVelocity (vector3d (-3./5., 0., -4./5.));
result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
CHECK_EQUAL (0.5, info.time);
delete sphere_a;
delete sphere_b;
}
/* If there is one of the sphere non moving we must ensure that we
* set the moving one as the incidence shape.
*/
TEST ( CheckSphereSphereReferenceShape ) {
Shape* sphere_a = new Sphere (3., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1.5, vector3d (3., 0., 4.));
sphere_a->setVelocity (vector3d (3./5., 0., 4./5.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
vector3d result_normal = vector3d (-3., 0., -4.).normalize();
vector3d collision_point = result_normal * 0.5;
CHECK_EQUAL (1, result);
CHECK_EQUAL (0.5, info.time);
CHECK (result_normal == info.normal);
CHECK_EQUAL (1, info.reference_shape);
sphere_a->setVelocity (vector3d (0., 0., 0.));
sphere_b->setVelocity (vector3d (-3./5., 0., -4./5.));
result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
CHECK (result_normal * -1. == info.normal);
CHECK_EQUAL (0.5, info.time);
CHECK_EQUAL (0, info.reference_shape);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereIgnoreHeight ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
sphere_b->setVelocity (vector3d (-2., 0., 0.));
sphere_a->setPosition (vector3d (0., 10., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckSphereSphereCollisionTimestep ) {
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
sphere_b->setVelocity (vector3d (-1., 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (1, result);
CHECK_EQUAL (1, info.time);
result = check_collision_sphere_sphere (2., sphere_a, sphere_b, &info);
CHECK_EQUAL (1., result);
CHECK_EQUAL (1., info.time);
result = check_collision_sphere_sphere (0.5, sphere_a, sphere_b, &info);
CHECK_EQUAL (0, result);
delete sphere_a;
delete sphere_b;
}
TEST ( CheckPerpendicularMovement ) {
Shape* sphere_a = new Sphere (0.4, vector3d (0., 0., 0.));
Shape* sphere_b = new Sphere (0.4, vector3d (0., 0., -1.));
sphere_a->setVelocity (vector3d (0., 0., 0.));
sphere_b->setVelocity (vector3d (5., 0., 0.));
CollisionInfo info;
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
CHECK_EQUAL (0, result);
delete sphere_a;
delete sphere_b;
}
+10
View File
@@ -0,0 +1,10 @@
PROJECT (MATHLIB CXX)
LIST ( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/ )
SET ( SRCS
mathlib.cc
main.cc
)
ADD_LIBRARY ( mathlib mathlib.cc mathlib.h)
+224
View File
@@ -0,0 +1,224 @@
#include <iostream>
#include <sstream>
#include <math.h>
#include <assert.h>
#include "mathlib.h"
using namespace std;
#ifdef WIN32
void sincos (float rad, double *s, double *c){
*s = sin (rad);
*c = cos (rad);
}
#endif
vector3d::vector3d ()
{
values[0] = 0.;
values[1] = 0.;
values[2] = 0.;
}
vector3d::vector3d (float u, float v, float w)
{
values[0] = u;
values[1] = v;
values[2] = w;
}
vector3d::vector3d (const vector3d &vec)
{
values[0] = vec.values[0];
values[1] = vec.values[1];
values[2] = vec.values[2];
}
vector3d vector3d::operator=(const vector3d &vec) {
if (this != &vec) {
values[0] = vec.values[0];
values[1] = vec.values[1];
values[2] = vec.values[2];
}
return *this;
}
vector3d::~vector3d ()
{
}
#ifndef MATHLIB_INLINE
vector3d vector3d::operator* (const float &f)
{
return vector3d (values[0] * f, values[1] * f, values[2] * f);
}
vector3d vector3d::operator/ (const float &f)
{
return vector3d (values[0] / f, values[1] / f, values[2] / f);
}
void vector3d::operator*= (const float &f)
{
values[0] *= f;
values[1] *= f;
values[2] *= f;
}
void vector3d::operator/= (const float &f)
{
values[0] /= f;
values[1] /= f;
values[2] /= f;
}
float vector3d::operator* (const vector3d &vec)
{
return values[0] * vec.values[0] + values[1] * vec.values[1] + values[2] * vec.values[2];
}
vector3d vector3d::operator+ (const vector3d &vec)
{
return vector3d (values[0] + vec.values[0], values[1] + vec.values[1], values[2] + vec.values[2]);
}
vector3d vector3d::operator- (const vector3d &vec)
{
return vector3d (values[0] - vec.values[0], values[1] - vec.values[1], values[2] - vec.values[2]);
}
void vector3d::operator+= (const vector3d &vec)
{
values[0] += vec.values[0];
values[1] += vec.values[1];
values[2] += vec.values[2];
}
void vector3d::operator-= (const vector3d &vec)
{
values[0] -= vec.values[0];
values[1] -= vec.values[1];
values[2] -= vec.values[2];
}
bool vector3d::operator== (const vector3d &vec)
{
if ( (values[0]==vec.values[0]) && (values[1]==vec.values[1]) && (values[2]==vec.values[2]) )
return true;
return false;
}
bool vector3d::operator!= (const vector3d &vec)
{
return ! (operator==(vec));
}
vector3d vector3d::cross (const vector3d &vec)
{
return vector3d (values[1] * vec.values[2] - values[2] * vec.values[1],
values[2] * vec.values[0] - values[0] * vec.values[2],
values[0] * vec.values[1] - values[1] * vec.values[0]);
}
float vector3d::length2 ()
{
return values[0]*values[0] + values[1]*values[1] + values[2]*values[2];
}
float vector3d::length ()
{
return sqrt (values[0]*values[0] + values[1]*values[1] + values[2]*values[2]);
}
#endif
vector3d& vector3d::rotate_x (float angle)
{
vector3d old (*this);
double s,c;
sincos (angle, &s, &c);
values[0] = old[0];
values[1] = c * old[1] - s * old[2];
values[2] = s * old[1] + c * old[2];
return *this;
}
vector3d& vector3d::rotate_y (float angle)
{
vector3d old (*this);
double s,c;
sincos (angle, &s, &c);
values[0] = c * old[0] + s * old[2];
values[1] = old[1];
values[2] = - s * old[0] + c * old[2];
return *this;
}
vector3d& vector3d::rotate_z (float angle)
{
vector3d old (*this);
double s,c;
sincos (angle, &s, &c);
values[0] = c * old[0] + -s * old[1];
values[1] = s * old[0] + c * old[1];
values[2] = old[2];
return *this;
}
vector3d& vector3d::normalize () {
float norm = length ();
values [0] /= norm;
values [1] /= norm;
values [2] /= norm;
return *this;
}
void vector3d::print ()
{
std::cout << values[0] << " " << values[1] << " " << values[2] << std::endl;
}
void vector3d::print (const char *str)
{
std::cout << str << values[0] << " " << values[1] << " " << values[2] << std::endl;
}
vector3d cross_product (vector3d &a, vector3d &b) {
return a.cross (b);
}
inline bool point_within (vector3d *a, vector3d *b, vector3d *point);
vector3d integrate_rk45 (float t, vector3d& ydot, vector3d& y)
{
vector3d k1 = ydot * t;
vector3d k2 = (ydot + k1 / 2) * t;
vector3d k3 = (ydot + k2 / 2 ) * t;
vector3d k4 = (ydot + k3) * t;
return y + (k1 + k2 * 2 + k3 * 2 + k4) / 6;
}
vector3d integrate (float t, vector3d& ydot, vector3d& y)
{
return integrate_rk45 (t, ydot, y);
}
int solve_quadratic (float a, float b, float c, float *x1, float *x2) {
if (b*b - 4 * a * c < 0)
return 0;
*x1 = static_cast<float> ((-b + sqrt (b*b - 4 * a * c)) / (2 * a));
*x2 = static_cast<float> ((-b - sqrt (b*b - 4 * a * c)) / (2 * a));
return 1;
}
+179
View File
@@ -0,0 +1,179 @@
#ifndef __MATHLIB_H
#define __MATHLIB_H
#include <iostream>
#include <cmath>
#include <assert.h>
#ifdef WIN32
#define M_PI 3.14159265
void sincos (float rad, double *s, double *c);
#endif
#define MATHLIB_INLINE
struct vector3d
{
float values[3];
vector3d ();
vector3d (float u, float v, float w);
vector3d (const vector3d &vec);
vector3d operator= (const vector3d &vec);
~vector3d ();
// Setter and getter
inline void setValues (float u, float v, float w) {
values[0] = u;
values[1] = v;
values[2] = w;
}
inline float& operator[] (const int index) {
assert (index >= 0);
assert (index <= 3);
return values[index];
}
vector3d operator* (const float &f);
vector3d operator/ (const float &f);
void operator*= (const float &f);
void operator/= (const float &f);
float operator* (const vector3d &vec);
vector3d operator+ (const vector3d &vec);
vector3d operator- (const vector3d &vec);
void operator+= (const vector3d &vec);
void operator-= (const vector3d &vec);
bool operator== (const vector3d &vec);
bool operator!= (const vector3d &vec);
vector3d cross (const vector3d &vec);
float length2 ();
float length ();
float get_angle () {
return atan2 (values[1], values[0]);
}
vector3d &rotate_x (float angle);
vector3d &rotate_y (float angle);
vector3d &rotate_z (float angle);
vector3d &normalize ();
void print ();
void print (const char* str);
};
#ifdef MATHLIB_INLINE
inline
vector3d vector3d::operator* (const float &f)
{
return vector3d (values[0] * f, values[1] * f, values[2] * f);
}
inline
vector3d vector3d::operator/ (const float &f)
{
return vector3d (values[0] / f, values[1] / f, values[2] / f);
}
inline
void vector3d::operator*= (const float &f)
{
values[0] *= f;
values[1] *= f;
values[2] *= f;
}
inline
void vector3d::operator/= (const float &f)
{
values[0] /= f;
values[1] /= f;
values[2] /= f;
}
inline
float vector3d::operator* (const vector3d &vec)
{
return values[0] * vec.values[0] + values[1] * vec.values[1] + values[2] * vec.values[2];
}
inline
vector3d vector3d::operator+ (const vector3d &vec)
{
return vector3d (values[0] + vec.values[0], values[1] + vec.values[1], values[2] + vec.values[2]);
}
inline
vector3d vector3d::operator- (const vector3d &vec)
{
return vector3d (values[0] - vec.values[0], values[1] - vec.values[1], values[2] - vec.values[2]);
}
inline
void vector3d::operator+= (const vector3d &vec)
{
values[0] += vec.values[0];
values[1] += vec.values[1];
values[2] += vec.values[2];
}
inline
void vector3d::operator-= (const vector3d &vec)
{
values[0] -= vec.values[0];
values[1] -= vec.values[1];
values[2] -= vec.values[2];
}
inline
bool vector3d::operator== (const vector3d &vec)
{
if ( (values[0]==vec.values[0]) && (values[1]==vec.values[1]) && (values[2]==vec.values[2]) )
return true;
return false;
}
inline
bool vector3d::operator!= (const vector3d &vec)
{
return ! (operator==(vec));
}
inline
vector3d vector3d::cross (const vector3d &vec)
{
return vector3d (values[1] * vec.values[2] - values[2] * vec.values[1],
values[2] * vec.values[0] - values[0] * vec.values[2],
values[0] * vec.values[1] - values[1] * vec.values[0]);
}
inline
float vector3d::length2 ()
{
return values[0]*values[0] + values[1]*values[1] + values[2]*values[2];
}
inline
float vector3d::length ()
{
return sqrt (values[0]*values[0] + values[1]*values[1] + values[2]*values[2]);
}
#endif
vector3d cross_product (vector3d &a, vector3d &b);
inline bool point_within (vector3d *a, vector3d *b, vector3d *point);
vector3d integrate_rk45 (float t,vector3d& ydot, vector3d& y);
vector3d integrate (float t, vector3d& ydot, vector3d& y);
int solve_quadratic (float a, float b, float c, float *x1, float *x2);
#endif /* __MATHLIB_H */
+5
View File
@@ -0,0 +1,5 @@
Authors of OGLFT
Allen Barnett
Oliver Bock
Nigel Stewart
@@ -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
)
+63
View File
@@ -0,0 +1,63 @@
project( OGLFT )
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
Set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake )
FIND_PACKAGE( OpenGL REQUIRED )
FIND_PACKAGE( FreeType2 REQUIRED )
if( ENABLE_QT )
find_package( Qt REQUIRED )
if( DESIRED_QT_VERSION EQUAL 3 )
find_package( KDE3 REQUIRED )
endif( DESIRED_QT_VERSION EQUAL 3 )
endif( ENABLE_QT )
if( ENABLE_GLE )
find_package( GLE )
endif( ENABLE_GLE )
#
# Test to determine if we want the "tripledot" (variable) form of the GLU tesselator callback.
#
if(NOT GLU_TESS_CALLBACK_TRIPLEDOT)
if(WIN32 OR CMAKE_SYSTEM_NAME MATCHES "Linux")
# Skip the compile check for platforms that never need the variable form
set(DEFAULT_GLU_TESS_CALLBACK_TRIPLEDOT false)
else(WIN32 OR CMAKE_SYSTEM_NAME MATCHES "Linux")
# For other platforms perform the check
include(CheckCXXSourceCompiles)
include(CheckIncludeFiles)
set(CMAKE_REQUIRED_INCLUDES ${OPENGL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENGL_LIBRARY})
check_include_files(OpenGL/gl.h HAVE_OPENGL_DIR)
if(HAVE_OPENGL_DIR)
set(OPENGL_DIR_PREFIX "OpenGL")
else(HAVE_OPENGL_DIR)
set(OPENGL_DIR_PREFIX "GL")
endif(HAVE_OPENGL_DIR)
set(GLUTESS_TEST_SOURCE "
#include <${OPENGL_DIR_PREFIX}/gl.h>
#include <${OPENGL_DIR_PREFIX}/glu.h>
typedef GLvoid (*GLUTessCallback)(...);
static void testcb(GLvoid *, void*) { }
int main() {
GLUtesselator *t = gluNewTess();
gluTessCallback(t, GLU_TESS_VERTEX_DATA, GLUTessCallback(testcb));
return 0;
}
")
check_cxx_source_compiles("${GLUTESS_TEST_SOURCE}" GLU_Tesselator_Needs_Variable_Parameter_Callback_Convention_Failure_Means_No)
set(GLU_TESS_CALLBACK_TRIPLEDOT ${GLU_Tesselator_Needs_Variable_Parameter_Callback_Convention_Failure_Means_No})
endif(WIN32 OR CMAKE_SYSTEM_NAME MATCHES "Linux")
endif(NOT GLU_TESS_CALLBACK_TRIPLEDOT)
add_subdirectory( liboglft )
set( BUILD_OGLFT_TESTS OFF CACHE BOOL "Build oglft tests." )
if( BUILD_OGLFT_TESTS )
enable_testing()
add_subdirectory( tests )
endif( BUILD_OGLFT_TESTS )
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+504
View File
@@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+432
View File
@@ -0,0 +1,432 @@
2002-07-12 Allen Barnett <allen@lignumcomputing.com>
* doc/Doxyfile, configure.ac: Updated to version 0.8.
* liboglft/OGLFT.cpp:
Removed unnecessary default arguments from constructors.
* tests/Makefile.am: Added extra demo3 header.
* liboglft/OGLFT.h: Improved the Doxygen comments.
2002-07-11 Allen Barnett <allen@lignumcomputing.com>
* doc/documentation.dox: Updated to version 0.8 information.
* NEWS: Added FreeType version warning.
* liboglft/OGLFT.cpp: Updated to be compilable by G++ 3.
Minor improvement of Doxygen comments.
Added height() method. Returns the "line spacing" of the font.
Added drawing of formatted numbers.
Made a couple of changes to support newer versions of FreeType:
* A default charmap is not activated if there is no UNICODE map.
* Adjust creation of monochrome bitmap to account for even
number of bytes now in FreeType bitmaps.
Correctly compute the vector size for each auxiliary face:
Type1 and TrueType fonts typically have different EM sizes.
Reverted to tesselating straight lines with one step.
* liboglft/OGLFT.h: Updated to be compilable by G++ 3.
Minor improvement of Doxygen comments.
Added height() method. Returns the "line spacing" of the font.
Added drawing of formatted numbers.
* tests/tutorial3.cpp: Updated to be compilable by G++ 3.
* tests/tutorial2.cpp: Updated to be compilable by G++ 3.
Also, minor modification to optionally (at compile time) use a
scalable representation. And, made it double buffered since that's the
only available visual with the Mach64 driver.
* tests/tutorial1.cpp, tests/speedtest.cpp, tests/demo.cpp:
Updated to be compilable by G++ 3.
* tests/demo3.cpp: Updated to be compilable by G++ 3.
Added example of number formatting.
* tests/demo2.cpp: Updated to be compilable by G++ 3.
* tests/Demo3UnicodeExample.h: Added GPL header.
* tests/Demo3UnicodeExample2.h: Initial checkin.
* README: Improved Qt project instructions.
* configure.ac: Updated version number.
* tests/tests.pro, OGLFT.pro, liboglft/liboglft.pro: Initial checkin.
* README, NEWS: Added new features for version 0.8.
2002-07-11 Allen Barnett <allen@lignumcomputing.com>
* doc/documentation.dox: Updated to version 0.8 information.
* NEWS: Added FreeType version warning.
* liboglft/OGLFT.cpp: Updated to be compilable by G++ 3.
Minor improvement of Doxygen comments.
Added height() method. Returns the "line spacing" of the font.
Added drawing of formatted numbers.
Made a couple of changes to support newer versions of FreeType:
* A default charmap is not activated if there is no UNICODE map.
* Adjust creation of monochrome bitmap to account for even
number of bytes now in FreeType bitmaps.
Correctly compute the vector size for each auxiliary face:
Type1 and TrueType fonts typically have different EM sizes.
Reverted to tesselating straight lines with one step.
* liboglft/OGLFT.h: Updated to be compilable by G++ 3.
Minor improvement of Doxygen comments.
Added height() method. Returns the "line spacing" of the font.
Added drawing of formatted numbers.
* tests/tutorial3.cpp: Updated to be compilable by G++ 3.
* tests/tutorial2.cpp: Updated to be compilable by G++ 3.
Also, minor modification to optionally (at compile time) use a
scalable representation. And, made it double buffered since that's the
only available visual with the Mach64 driver.
* tests/tutorial1.cpp, tests/speedtest.cpp, tests/demo.cpp:
Updated to be compilable by G++ 3.
* tests/demo3.cpp: Updated to be compilable by G++ 3.
Added example of number formatting.
* tests/demo2.cpp: Updated to be compilable by G++ 3.
* tests/Demo3UnicodeExample.h: Added GPL header.
* tests/Demo3UnicodeExample2.h: Initial checkin.
* README: Improved Qt project instructions.
* configure.ac: Updated version number.
* tests/tests.pro, OGLFT.pro, liboglft/liboglft.pro: Initial checkin.
* README, NEWS: Added new features for version 0.8.
2002-03-26 Allen Barnett <allen@lignumcomputing.com>
* tests/tutorial2.cpp, tests/tutorial1.cpp: Added <config.h>.
* tests/demo3.cpp:
Without GL_RASTER_POSITION_UNCLIPPED_IBM, need to adjust some of the
text items so that they are not clipped.
* tests/demo.cpp:
Reduced the size of the font since nVidia's OpenGL version does not
support the GL_RASTER_POSITION_UNCLIPPED_IBM.
* configure.ac:
Note that disabling Qt support also removes UNICODE support.
2002-03-26 allen@llama.lignumcomputing.org <allen@llama>
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/tutorial2.cpp, /home/allen/cvsroot/lignumCAD/OGLFT/tests/tutorial1.cpp:
Added <config.h>.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo3.cpp:
Without GL_RASTER_POSITION_UNCLIPPED_IBM, need to adjust some of the
text items so that they are not clipped.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo.cpp:
Reduced the size of the font since nVidia's OpenGL version does not
support the GL_RASTER_POSITION_UNCLIPPED_IBM.
* /home/allen/cvsroot/lignumCAD/OGLFT/configure.ac:
Note that disabling Qt support also removes UNICODE support.
2002-03-25 allen@llama.lignumcomputing.org <allen@llama>
* /home/allen/cvsroot/lignumCAD/OGLFT/configure.ac:
Update the version number to 0.7.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/Makefile.am:
Use the correct name for the embedded font file.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.cpp:
Updated Doxygen comments.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo3.cpp:
Use .h for embedded font file to make automake happier.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo3.cpp, /home/allen/cvsroot/lignumCAD/OGLFT/tests/Demo3UnicodeExample.c, /home/allen/cvsroot/lignumCAD/OGLFT/tests/Demo3UnicodeExample.sfd, /home/allen/cvsroot/lignumCAD/OGLFT/tests/Demo3UnicodeExample.ttf, /home/allen/cvsroot/lignumCAD/OGLFT/tests/tosrc.pl:
Add demo files for UNICODE and multiple fonts.
* /home/allen/cvsroot/lignumCAD/OGLFT/doc/documentation.dox:
Updated to 0.7.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
Updated the Doxygen comments.
* /home/allen/cvsroot/lignumCAD/OGLFT/NEWS: Addes the latest news.
* /home/allen/cvsroot/lignumCAD/OGLFT/README:
Mention UNICODE rendering dependence on Qt and how to build the test programs.
* /home/allen/cvsroot/lignumCAD/OGLFT/doc/Doxyfile:
Updated version number.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
Fix typos in description of vertical justification enum documentation.
* /home/allen/cvsroot/lignumCAD/OGLFT/configure.ac:
Now, if you have Qt and don't disable it, the library will compile
with UNICODE support, in the form of Qt's QString. Thus, the FLAGS
necessary to compile with Qt are propagated through to all the
Makefiles.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
* Added the ability to draw glyphs based on UNICODE characters. Here,
we use the Qt UNICODE representation: QString. Additionally, there
are methods to set the foreground and background colors using
QColor.
* Made the definition of measure(const char*) explicit in each of
Face's immediate subclasses in order to avoid a complaint from
gcc 2.95 about "using measure" from Face.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.cpp:
* Added the ability to draw glyphs based on UNICODE characters. Here,
we use the Qt UNICODE representation: QString. Additionally, there
are methods to set the foreground and background colors using
QColor.
* Removed redundant insertion of display list index in the glyph display
list cache.
* Removed memory leak on deletion of face. Was not freeing the glyph
display lists.
* Added check for validity of FT_Face in OGLFT::Face subclasses before
proceeding with subclass initiliation.
* For now at least, tessellation of straight lines is also broken into
segments so that the triangles produced by gluTess* are (slightly)
more regular.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
Fix issue with compiling under older version (2.95) of GCC g++.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.cpp:
Add extra case statements to silence compiler warning.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
Fix bug in BoundingBox auto-increment operator.
2002-02-05 allen@llama.lignumcomputing.org <allen@llama>
* /home/allen/cvsroot/lignumCAD/OGLFT/doc/documentation.dox:
Update copyright date and SourceForge logo reference.
2002-02-04 allen@llama.lignumcomputing.org <allen@llama>
* /home/allen/cvsroot/lignumCAD/OGLFT/NEWS, /home/allen/cvsroot/lignumCAD/OGLFT/configure.ac, /home/allen/cvsroot/lignumCAD/OGLFT/doc/Doxyfile:
Update to 0.6.
* /home/allen/cvsroot/lignumCAD/OGLFT/NEWS:
Comment on "Changes to improve compilation on SGI."
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h, /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.cpp:
Changes to improve compilation on SGI.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
Don't try to include mpatrol header if built without mpatrol.
* /home/allen/cvsroot/lignumCAD/OGLFT/configure.ac:
* Make sure to check for libm first.
* Do not continue build if proper freetype headers are not found.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo2.cpp:
stdio.h not included if mpatrol is undefined.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/Makefile.am:
Don't include moc_*.cpp files in distribution.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/vignette.h, /home/allen/cvsroot/lignumCAD/OGLFT/tests/speedtest.h:
Missing definition of exit() when built in "dist" mode (?)
* /home/allen/cvsroot/lignumCAD/OGLFT/ChangeLog:
Reran EMACS regeneration command.
* /home/allen/cvsroot/lignumCAD/OGLFT/NEWS:
Add note about already open FT_Face.
* /home/allen/cvsroot/lignumCAD/OGLFT/doc/html/classOGLFT_1_1ColorTess.html, /home/allen/cvsroot/lignumCAD/OGLFT/doc/html/classOGLFT_1_1ColorTess-members.html, /home/allen/cvsroot/lignumCAD/OGLFT/doc/html/classOGLFT_1_1TextureTess.html, /home/allen/cvsroot/lignumCAD/OGLFT/doc/html/classOGLFT_1_1TextureTess-members.html:
New structures.
* /home/allen/cvsroot/lignumCAD/OGLFT/ChangeLog, /home/allen/cvsroot/lignumCAD/OGLFT/Makefile.in, /home/allen/cvsroot/lignumCAD/OGLFT/NEWS:
Updates for version 0.5.
* /home/allen/cvsroot/lignumCAD/OGLFT/doc/Doxyfile:
Updated version number.
* /home/allen/cvsroot/lignumCAD/OGLFT/doc/documentation.dox:
Updates for version 0.5.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo2.cpp:
Demo of using an already open FT_Face.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo3.cpp: The spiffy demo.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/Makefile.am:
Renamed demo2 and demo3.
* /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.cpp, /home/allen/cvsroot/lignumCAD/OGLFT/liboglft/OGLFT.h:
Add a constructor where the FT_Face is already open.
* /home/allen/cvsroot/lignumCAD/OGLFT/README:
Updated compilation instructions to better describe configure options.
* /home/allen/cvsroot/lignumCAD/OGLFT/Makefile.am:
Add target for the bzip distribution.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/Makefile.am:
Added demo2 texture.png to distribution.
* /home/allen/cvsroot/lignumCAD/OGLFT/tests/demo2.cpp:
Run the per glyph display text in the other direction.
2002-02-04 Allen Barnett <allen@localhost.localdomain>
* NEWS: Comment on "Changes to improve compilation on SGI."
* liboglft/OGLFT.h, liboglft/OGLFT.cpp:
Changes to improve compilation on SGI.
* liboglft/OGLFT.h:
Don't try to include mpatrol header if built without mpatrol.
* configure.ac: * Make sure to check for libm first.
* Do not continue build if proper freetype headers are not found.
* tests/demo2.cpp: stdio.h not included if mpatrol is undefined.
* tests/Makefile.am: Don't include moc_*.cpp files in distribution.
* tests/vignette.h, tests/speedtest.h:
Missing definition of exit() when built in "dist" mode (?)
* ChangeLog: Reran EMACS regeneration command.
* NEWS: Add note about already open FT_Face.
* doc/Doxyfile: Updated version number.
* doc/documentation.dox: Updates for version 0.5.
* tests/demo2.cpp: Demo of using an already open FT_Face.
* tests/demo3.cpp: The spiffy demo.
* tests/Makefile.am: Renamed demo2 and demo3.
* liboglft/OGLFT.cpp, liboglft/OGLFT.h:
Add a constructor where the FT_Face is already open.
* README:
Updated compilation instructions to better describe configure options.
* Makefile.am: Add target for the bzip distribution.
* tests/Makefile.am: Added demo2 texture.png to distribution.
* tests/demo2.cpp:
Run the per glyph display text in the other direction.
2002-02-01 Allen Barnett <allen@localhost.localdomain>
* tests/background00a.png, tests/background00b.png, tests/background00.png, tests/background01.png, tests/background10a.png, tests/background10b.png, tests/background10.png, tests/background11.png, tests/background.png:
Background images for demo2.
* tests/tutorial3.cpp, tests/speedtest.cpp:
Accounted for absence of Solid face.
* configure.ac: Improved GLE checking.
* tests/demo2.cpp, tests/demo.cpp: Accounted for absence of Solid face.
* configure.ac: Added an mpatrol configuration option.
* liboglft/OGLFT.h:
Added definitions for Color and Texture callbacks during tessellation.
* liboglft/OGLFT.cpp: * Added color callback for Face::Outline.
* Added color and texture callbacks for Face::Filled.
* Properly set the character rotation reference for all face types.
* Cleaned up memory leak during GLU tesselation.
* tests/vignette.h, tests/demo2.cpp: Initial checkin
2002-02-01 Allen Barnett <allen@localhost.localdomain>
* tests/background00a.png, tests/background00b.png, tests/background00.png, tests/background01.png, tests/background10a.png, tests/background10b.png, tests/background10.png, tests/background11.png, tests/background.png:
Background images for demo2.
* tests/tutorial3.cpp, tests/speedtest.cpp:
Accounted for absence of Solid face.
* configure.ac: Improved GLE checking.
* tests/demo2.cpp, tests/demo.cpp: Accounted for absence of Solid face.
* configure.ac: Added an mpatrol configuration option.
* liboglft/OGLFT.h:
Added definitions for Color and Texture callbacks during tessellation.
* liboglft/OGLFT.cpp: * Added color callback for Face::Outline.
* Added color and texture callbacks for Face::Filled.
* Properly set the character rotation reference for all face types.
* Cleaned up memory leak during GLU tesselation.
* tests/vignette.h, tests/demo2.cpp: Initial checkin
2002-01-29 Allen Barnett <allen@localhost.localdomain>
* liboglft/OGLFT.cpp: Moved config.h to the main library source .
* liboglft/Makefile.am: Be sure to install the library header file.
* liboglft/OGLFT.h: Moved config.h to the main library source.
* tests/tutorial3.cpp, tests/tutorial2.cpp, tests/tutorial1.cpp, tests/speedtest.cpp:
Added revsion control keyword (Id).
* tests/speedtest.cpp, tests/speedtest.h:
Reorganized a little to help automake deal with .moc files.
+231
View File
@@ -0,0 +1,231 @@
Copyright 1994, 1995, 1996, 1999, 2000, 2001 Free Software Foundation,
Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for variables by setting
them in the environment. You can do that on the command line like this:
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it cannot guess the host type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the host
platform (i.e., that on which the generated programs will eventually be
run) with `--host=TYPE'. In this case, you should also specify the
build platform with `--build=TYPE', because, in this case, it may not
be possible to guess the build platform (it sometimes involves
compiling and running simple test programs, and this can't be done if
the compiler is a cross compiler).
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
+46
View File
@@ -0,0 +1,46 @@
New in OGLFT version 0.8
* Added the ability to draw numbers with a format à la printf.
There is also a format, %p, which will draw the number as
a fraction.
* Updated the source to be compilable with G++ 3.
* Added an (untested) Qt project for OSs which don't support
autoconf.
* Note: FreeType versions 2.0.9 through 2.1.2 contain a bug which
prevents rotated text from being rendered correctly.
New in OGLFT version 0.7
* Fixed another memory leak when deleting a Face which had compiled
its glyphs into display lists (the default behavior).
* Added the ability to render UNICODE glyphs using Qt QStrings.
* Added the ability to use mulitple FT_Faces in a single OGLFT::Face
so that you can cover more UNICODE points by combining fonts.
New in OGLFT version 0.6
Updates include:
* Fixed a pervasive memory leak (must call FT_Done_Glyph after each
call to FT_Get_Glyph).
* measure() now queries the OpenGL view and calls gluUnProject to
compute accurate glyph sizes.
* Autoconf-enabled.
* There is a user color callback for drawing the Outline face and
color and texture coordinate callbacks for the Filled face.
* Can pass an already open FreeType FT_Face to a rendering style.
* Changes to improve compilation on the SGI.
;;;Local variables: ***
;;;mode: text ***
;;;End: ***
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
OGLFT Version 0.8
OGLFT is a library for drawing text in OpenGL. It usees the FreeType 2
library to extract information from font files on your system. OGLFT
can handle any of the files which FreeType can read, both vector and
bitmapped (although currently the bitmap routines are not implemented).
The software is available from www.sf.net/project/oglft.
The documentation is in ./doc/html/index.html.
The mailing list is oglft-devel@lists.sourceforge.net.
A couple of installation notes:
OGLFT depends on the GLE Tubing and Extrusion library to create solid
characters. If you don't have this library (or don't want solid
glyphs), you can disable this feature with:
./configure --disable-solid
If the configure script can't find the GLE library and header files,
it is disabled automatically.
UNICODE character rendering, Demo3 and the performance test code
depend on the Qt library. You can disable them with:
./configure --disable-qt
Note that the configure script depends on finding the environment
variable QTDIR in order to locate the headers and library for Qt (if
not disabled). If the configure script can't successfully build a
simple Qt app, Qt is disabled automatically.
'make check' builds the test programs in the tests/ directory.
There is also a (mostly untested) Qt project file from which it may be
possible to generate a Makefile for operating systems for which
autoconf is not supported. Edit the files ./OGLFT/OGLFT.pro and
./tests/tests.pro to change the values to those appropriate for your
operating system. Generate the library and the test program by doing a
"make install" (this will actually only copy the library to the ./lib
directory).
---------------------------------------------------------------------
lignum Computing, Inc., July, 2002
oglft@lignumcomputing.com
;;;Local variables: ***
;;;mode: text ***
;;;End: ***
@@ -0,0 +1,45 @@
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
FIND_PACKAGE ( FreeType2 REQUIRED )
FILE( GLOB sources *.cpp )
IF( DESIRED_QT_VERSION EQUAL 3)
INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} )
ELSEIF( DESIRED_QT_VERSION EQUAL 4 )
INCLUDE_DIRECTORIES( ${QT_QTCORE_INCLUDE_DIR} )
INCLUDE_DIRECTORIES( ${QT_QTGUI_INCLUDE_DIR} )
ENDIF( DESIRED_QT_VERSION EQUAL 3)
INCLUDE_DIRECTORIES(
${FREETYPE2_INCLUDE_DIR}
)
INCLUDE_DIRECTORIES( ${PROJECT_BINARY_DIR} )
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/OGLFT.h.cmake"
"${PROJECT_BINARY_DIR}/OGLFT.h"
)
IF( WIN32 )
ADD_DEFINITIONS( -DOGLFT_BUILD )
ENDIF( WIN32 )
ADD_LIBRARY( oglft STATIC ${sources} )
TARGET_LINK_LIBRARIES(
oglft
${FREETYPE2_LIBRARIES}
${OPENGL_LIBRARIES}
)
INSTALL(
TARGETS oglft
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
COMPONENT libraries
)
INSTALL(
FILES "${PROJECT_BINARY_DIR}/OGLFT.h"
DESTINATION include/OGLFT
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
COMPONENT headers
)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+117
View File
@@ -0,0 +1,117 @@
FIND_PACKAGE( GLUT )
LINK_LIBRARIES( oglft ${FREETYPE2_LIBRARIES})
INCLUDE_DIRECTORIES( ${PROJECT_BINARY_DIR} )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} )
INCLUDE_DIRECTORIES( ${FREETYPE2_INCLUDE_DIR}
${FREETYPE2_INCLUDE_DIR}/freetype2
)
INCLUDE_DIRECTORIES( ${GLUT_INCLUDE_DIR} )
IF( ENABLE_QT )
IF( DESIRED_QT_VERSION EQUAL 3)
INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} )
LINK_LIBRARIES( oglft ${FREETYPE2_LIBRARIES} ${QT_LIBRARIES} )
ELSEIF( DESIRED_QT_VERSION EQUAL 4 )
INCLUDE_DIRECTORIES( ${QT_QTCORE_INCLUDE_DIR} )
INCLUDE_DIRECTORIES( ${QT_QTGUI_INCLUDE_DIR} )
INCLUDE_DIRECTORIES( ${QT_QTOPENGL_INCLUDE_DIR} )
LINK_LIBRARIES( oglft ${FREETYPE2_LIBRARIES} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} )
ENDIF( DESIRED_QT_VERSION EQUAL 3)
ENDIF( ENABLE_QT )
ADD_EXECUTABLE(
tutorial1
tutorial1.cpp
)
TARGET_LINK_LIBRARIES(
tutorial1
${GLUT_LIBRARIES}
)
ADD_EXECUTABLE(
tutorial2
tutorial2.cpp
)
TARGET_LINK_LIBRARIES(
tutorial2
${GLUT_LIBRARIES}
)
ADD_EXECUTABLE(
tutorial3
tutorial3.cpp
)
TARGET_LINK_LIBRARIES(
tutorial3
${GLUT_LIBRARIES}
)
ADD_EXECUTABLE(
tutorial3
tutorial3.cpp
)
TARGET_LINK_LIBRARIES(
tutorial3
${GLUT_LIBRARIES}
)
ADD_EXECUTABLE(
demo
demo.cpp
)
TARGET_LINK_LIBRARIES(
demo
${GLUT_LIBRARIES}
)
ADD_EXECUTABLE(
demo2
demo2.cpp
)
TARGET_LINK_LIBRARIES(
demo2
${GLUT_LIBRARIES}
)
IF( ENABLE_QT )
IF( DESIRED_QT_VERSION EQUAL 3 )
KDE3_AUTOMOC( demo3.cpp speedtest.cpp )
ELSEIF( DESIRED_QT_VERSION EQUAL 4 )
QT4_AUTOMOC( demo3.cpp speedtest.cpp )
ENDIF( DESIRED_QT_VERSION EQUAL 3 )
ADD_EXECUTABLE(
demo3
demo3.cpp
)
TARGET_LINK_LIBRARIES(
demo3
${OPENGL_LIBRARIES}
)
ADD_EXECUTABLE(
speedtest
speedtest.cpp
)
TARGET_LINK_LIBRARIES(
speedtest
${OPENGL_LIBRARIES}
)
ENDIF( ENABLE_QT )
# Copy some files needed by demo3 into the tests directory.
FILE( GLOB images *.png )
FOREACH( test_png ${images} )
GET_FILENAME_COMPONENT( png_file ${test_png} NAME )
CONFIGURE_FILE( ${test_png}
"${CMAKE_CURRENT_BINARY_DIR}/${png_file}" COPYONLY )
ENDFOREACH( test_png ${images} )
@@ -0,0 +1,211 @@
/*
* Demo3UnicodeExample.h: Sample font for demo3 example.
* Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
FT_Byte Demo3UnicodeExample_ttf[] = {
0,1,0,0,0,11,0,128,0,3,0,48,79,83,47,50,
83,120,128,90,0,0,0,188,0,0,0,86,99,109,97,112,
135,81,49,45,0,0,1,20,0,0,1,114,99,118,116,32,
5,238,9,153,0,0,2,136,0,0,0,36,103,108,121,102,
105,160,31,169,0,0,2,172,0,0,4,178,104,101,97,100,
212,135,107,129,0,0,7,96,0,0,0,54,104,104,101,97,
6,249,3,88,0,0,7,152,0,0,0,36,104,109,116,120,
20,76,1,64,0,0,7,188,0,0,0,40,108,111,99,97,
6,150,5,39,0,0,7,228,0,0,0,22,109,97,120,112,
0,78,0,250,0,0,7,252,0,0,0,32,110,97,109,101,
88,93,109,50,0,0,8,28,0,0,3,72,112,111,115,116,
11,139,233,133,0,0,11,100,0,0,0,100,0,1,3,232,
1,144,0,5,0,12,0,200,0,200,0,0,0,200,0,200,
0,200,0,0,0,200,0,49,1,2,0,0,2,0,5,3,
0,0,0,0,0,0,0,0,1,131,0,0,0,96,0,0,
0,0,0,0,0,0,80,102,69,100,0,64,0,0,34,43,
3,164,255,52,0,0,3,164,0,204,0,0,0,1,0,0,
0,0,0,0,0,0,0,2,0,3,0,1,0,0,0,20,
0,1,0,0,0,0,0,108,0,4,0,88,0,0,0,18,
0,16,0,3,0,2,3,169,3,195,3,200,33,38,33,146,
34,7,34,25,34,43,255,255,0,0,3,169,3,195,3,200,
33,38,33,146,34,7,34,25,34,43,255,255,252,90,252,65,
252,61,222,221,222,116,222,0,221,239,221,222,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,6,0,0,1,0,0,0,0,0,0,0,1,3,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,33,2,121,0,0,0,86,
0,83,1,30,0,100,0,12,0,74,2,25,0,92,2,222,
0,90,0,50,3,176,0,41,0,102,0,78,0,2,0,33,
0,0,1,110,2,154,0,3,0,7,0,46,177,1,0,47,
60,178,7,4,0,237,50,177,6,5,220,60,178,3,2,0,
237,50,0,177,3,0,47,60,178,5,4,0,237,50,178,7,
6,1,252,60,178,1,2,0,237,50,51,17,33,17,37,33,
17,33,33,1,77,254,212,1,11,254,245,2,154,253,102,33,
2,88,0,1,0,48,0,0,2,206,2,234,0,38,0,137,
0,177,20,2,63,176,21,47,176,37,51,176,38,51,177,0,
3,237,177,1,3,237,177,18,3,237,177,19,3,237,176,6,
47,176,28,51,176,29,51,176,30,51,177,10,4,237,1,176,
0,47,176,38,51,177,36,5,237,177,37,5,237,176,2,47,
176,3,51,176,4,51,176,5,51,177,6,6,237,177,33,6,
237,177,34,6,237,177,35,6,237,176,21,176,36,16,222,176,
22,50,177,19,5,237,177,20,5,237,176,23,176,34,16,222,
176,24,50,176,25,50,177,15,6,237,177,16,6,237,177,17,
6,237,177,40,16,16,204,48,49,55,51,38,53,39,54,55,
54,55,54,23,22,23,22,23,22,21,20,7,51,21,33,53,
54,61,1,54,39,38,7,38,7,49,6,23,20,23,21,33,
48,160,151,1,1,101,24,28,74,120,92,58,104,36,16,152,
160,254,226,178,3,71,63,95,110,66,53,2,177,254,226,86,
127,182,1,165,99,23,17,50,5,4,37,65,127,55,61,182,
128,86,81,83,216,2,127,82,72,1,2,96,78,104,220,85,
81,0,0,2,0,34,255,243,2,98,2,32,0,19,0,35,
0,98,0,177,8,7,63,176,9,47,176,10,51,177,27,8,
237,177,28,8,237,177,29,8,237,177,0,9,63,176,19,47,
177,1,8,237,177,2,8,237,1,176,13,47,176,14,51,176,
15,51,176,16,51,177,23,10,237,177,24,10,237,177,25,10,
237,176,31,176,24,16,222,176,32,50,176,33,50,177,3,10,
237,177,4,10,237,177,5,10,237,177,6,10,237,177,37,5,
16,204,48,49,1,21,35,22,21,23,20,7,6,35,34,47,
1,38,61,1,52,55,54,23,7,6,7,6,23,6,23,22,
23,54,55,54,39,52,39,38,2,98,145,66,1,73,68,108,
108,66,5,70,73,106,154,87,94,40,22,2,2,81,33,44,
102,38,19,1,75,35,2,19,73,62,130,1,143,67,67,65,
5,70,136,2,141,68,96,40,63,2,87,49,65,134,48,20,
1,1,95,47,61,130,50,23,0,1,0,61,255,52,2,157,
2,19,0,34,0,118,0,176,26,47,176,27,51,177,0,11,
237,177,1,11,237,177,9,11,237,177,10,11,237,177,17,11,
237,177,18,11,237,1,176,0,47,176,33,51,176,34,51,177,
1,12,237,177,2,12,237,177,3,12,237,176,8,176,1,16,
222,176,9,50,176,27,50,176,28,50,177,10,12,237,177,11,
12,237,177,25,12,237,177,26,12,237,176,14,176,10,16,222,
176,15,50,176,16,50,176,17,50,177,18,12,237,177,19,12,
237,177,20,12,237,177,36,18,16,204,48,49,19,51,17,22,
23,22,23,22,23,17,51,17,54,55,54,61,1,17,51,17,
6,7,6,7,6,7,21,35,53,38,39,38,39,38,39,61,
89,2,19,13,29,39,68,90,124,32,13,89,1,24,20,51,
59,103,90,138,63,43,9,5,1,2,19,254,250,97,34,25,
20,26,3,1,211,254,45,4,86,38,76,1,1,6,254,253,
122,47,39,35,38,3,192,192,5,68,48,55,32,76,0,1,
0,39,0,78,3,216,1,182,0,18,0,37,0,176,11,47,
176,12,51,177,13,13,237,177,14,13,237,1,176,12,47,176,
13,51,177,3,14,237,177,4,14,237,177,20,3,16,204,48,
49,1,22,31,1,21,6,7,6,7,35,54,55,33,53,33,
38,39,53,39,3,10,91,64,51,86,76,19,26,39,47,52,
252,227,3,29,51,20,26,1,182,98,41,27,23,44,78,20,
29,101,54,51,66,36,1,51,0,2,0,14,0,0,2,103,
2,182,0,2,0,5,0,23,0,176,3,47,176,5,51,177,
0,15,237,177,1,15,237,1,177,7,1,47,204,48,49,19,
33,1,3,27,1,14,2,88,254,198,168,200,220,2,182,253,
74,2,140,254,29,1,227,0,0,1,0,92,1,53,0,195,
1,156,0,3,0,37,0,176,0,47,176,3,51,177,1,16,
237,177,2,16,237,1,176,0,47,176,1,51,177,2,16,237,
177,3,16,237,177,5,2,16,204,48,49,19,53,51,21,92,
103,1,54,102,102,0,0,1,255,255,255,145,1,25,3,164,
0,46,0,29,176,0,47,176,26,51,176,38,51,176,45,51,
176,46,51,177,16,17,237,177,21,17,237,177,22,17,237,48,
49,27,1,54,55,54,55,54,23,22,21,22,7,6,35,34,
39,38,7,6,31,1,22,7,3,6,7,6,39,38,39,38,
55,54,55,54,23,22,23,22,63,1,54,39,38,39,38,17,
100,9,9,70,14,16,31,22,9,1,28,9,10,17,21,18,
15,8,1,4,20,1,8,4,41,25,43,25,17,21,6,3,
9,20,29,11,7,22,15,1,8,5,1,1,18,1,218,1,
10,155,29,6,2,1,28,13,14,35,13,4,18,19,15,9,
17,72,251,86,254,222,147,52,35,1,1,16,20,35,15,9,
22,11,5,8,24,14,1,15,48,12,8,158,1,1,0,0,
0,1,0,0,0,0,0,0,248,61,157,109,95,15,60,245,
0,19,3,232,0,0,0,0,184,197,19,226,0,0,0,0,
184,197,19,226,255,255,255,52,3,216,3,164,0,0,0,8,
0,2,0,0,0,0,0,0,0,1,0,0,3,32,255,56,
0,0,4,11,255,255,0,10,3,216,0,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,10,1,176,0,33,
0,0,0,0,1,77,0,0,2,248,0,48,2,142,0,34,
2,236,0,61,4,11,0,39,2,136,0,14,1,38,0,92,
1,35,255,255,0,0,0,43,0,43,0,43,0,171,1,22,
1,137,1,190,1,222,1,253,2,89,0,0,0,1,0,0,
0,10,0,47,0,2,0,0,0,0,0,2,0,0,0,64,
0,1,0,0,0,64,0,137,0,0,0,0,0,0,0,21,
1,2,0,1,0,0,0,0,0,0,0,65,0,0,0,1,
0,0,0,0,0,1,0,21,0,66,0,1,0,0,0,0,
0,2,0,7,0,88,0,1,0,0,0,0,0,3,0,47,
0,96,0,1,0,0,0,0,0,4,0,21,0,144,0,1,
0,0,0,0,0,5,0,7,0,166,0,1,0,0,0,0,
0,6,0,19,0,174,0,0,0,3,0,0,0,0,0,130,
0,194,0,0,0,3,0,0,0,1,0,42,1,70,0,0,
0,3,0,0,0,2,0,14,1,114,0,0,0,3,0,0,
0,3,0,94,1,130,0,0,0,3,0,0,0,4,0,42,
1,226,0,0,0,3,0,0,0,5,0,14,2,14,0,0,
0,3,0,0,0,6,0,38,2,30,0,3,0,1,4,9,
0,0,0,130,0,194,0,3,0,1,4,9,0,1,0,42,
1,70,0,3,0,1,4,9,0,2,0,14,1,114,0,3,
0,1,4,9,0,3,0,94,1,130,0,3,0,1,4,9,
0,4,0,42,1,226,0,3,0,1,4,9,0,5,0,14,
2,14,0,3,0,1,4,9,0,6,0,38,2,30,67,114,
101,97,116,101,100,32,98,121,32,65,108,108,101,110,32,66,
97,114,110,101,116,116,32,119,105,116,104,32,80,102,97,69,
100,105,116,32,49,46,48,32,40,104,116,116,112,58,47,47,
112,102,97,101,100,105,116,46,115,102,46,110,101,116,41,0,
68,101,109,111,51,32,85,110,105,99,111,100,101,32,69,120,
97,109,112,108,101,0,82,101,103,117,108,97,114,0,80,102,
97,69,100,105,116,32,49,46,48,32,58,32,68,101,109,111,
51,32,85,110,105,99,111,100,101,32,69,120,97,109,112,108,
101,32,58,32,50,53,45,50,45,50,48,55,50,0,68,101,
109,111,51,32,85,110,105,99,111,100,101,32,69,120,97,109,
112,108,101,0,48,48,49,46,48,48,48,0,68,101,109,111,
51,85,110,105,99,111,100,101,69,120,97,109,112,108,101,0,
0,67,0,114,0,101,0,97,0,116,0,101,0,100,0,32,
0,98,0,121,0,32,0,65,0,108,0,108,0,101,0,110,
0,32,0,66,0,97,0,114,0,110,0,101,0,116,0,116,
0,32,0,119,0,105,0,116,0,104,0,32,0,80,0,102,
0,97,0,69,0,100,0,105,0,116,0,32,0,49,0,46,
0,48,0,32,0,40,0,104,0,116,0,116,0,112,0,58,
0,47,0,47,0,112,0,102,0,97,0,101,0,100,0,105,
0,116,0,46,0,115,0,102,0,46,0,110,0,101,0,116,
0,41,0,0,0,68,0,101,0,109,0,111,0,51,0,32,
0,85,0,110,0,105,0,99,0,111,0,100,0,101,0,32,
0,69,0,120,0,97,0,109,0,112,0,108,0,101,0,0,
0,82,0,101,0,103,0,117,0,108,0,97,0,114,0,0,
0,80,0,102,0,97,0,69,0,100,0,105,0,116,0,32,
0,49,0,46,0,48,0,32,0,58,0,32,0,68,0,101,
0,109,0,111,0,51,0,32,0,85,0,110,0,105,0,99,
0,111,0,100,0,101,0,32,0,69,0,120,0,97,0,109,
0,112,0,108,0,101,0,32,0,58,0,32,0,50,0,53,
0,45,0,50,0,45,0,50,0,48,0,55,0,50,0,0,
0,68,0,101,0,109,0,111,0,51,0,32,0,85,0,110,
0,105,0,99,0,111,0,100,0,101,0,32,0,69,0,120,
0,97,0,109,0,112,0,108,0,101,0,0,0,48,0,48,
0,49,0,46,0,48,0,48,0,48,0,0,0,68,0,101,
0,109,0,111,0,51,0,85,0,110,0,105,0,99,0,111,
0,100,0,101,0,69,0,120,0,97,0,109,0,112,0,108,
0,101,0,0,0,2,0,0,0,0,0,0,255,156,0,50,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,10,0,0,0,1,0,2,1,2,1,3,
1,4,1,5,1,6,1,7,0,156,7,117,110,105,48,51,
65,57,5,115,105,103,109,97,3,112,115,105,10,97,114,114,
111,119,114,105,103,104,116,8,103,114,97,100,105,101,110,116,
7,117,110,105,50,50,49,57,
};
const int Demo3UnicodeExample_ttf_size = sizeof( Demo3UnicodeExample_ttf );
@@ -0,0 +1,949 @@
SplineFontDB: 1.0
FontName: Demo3UnicodeExample
FullName: Demo3 Unicode Example
FamilyName: Demo3 Unicode Example
Weight: Medium
Copyright: Created by Allen Barnett with PfaEdit 1.0 (http://pfaedit.sf.net)
Version: 001.000
ItalicAngle: 0
UnderlinePosition: -100
UnderlineWidth: 50
Ascent: 800
Descent: 200
FSType: 12
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
Panose: 2 0 5 3 0 0 0 0 0 0
Encoding: 26
DisplaySize: -24
AntiAlias: 1
BeginChars: 65536 263
StartChar: space
Encoding: 32 32
Width: 1000
EndChar
StartChar: exclam
Encoding: 33 33
Width: 1000
EndChar
StartChar: quotedbl
Encoding: 34 34
Width: 1000
EndChar
StartChar: numbersign
Encoding: 35 35
Width: 1000
EndChar
StartChar: dollar
Encoding: 36 36
Width: 1000
EndChar
StartChar: percent
Encoding: 37 37
Width: 1000
EndChar
StartChar: ampersand
Encoding: 38 38
Width: 1000
EndChar
StartChar: quotesingle
Encoding: 39 39
Width: 1000
EndChar
StartChar: parenleft
Encoding: 40 40
Width: 1000
EndChar
StartChar: parenright
Encoding: 41 41
Width: 1000
EndChar
StartChar: asterisk
Encoding: 42 42
Width: 1000
EndChar
StartChar: plus
Encoding: 43 43
Width: 1000
EndChar
StartChar: comma
Encoding: 44 44
Width: 1000
EndChar
StartChar: hyphen
Encoding: 45 45
Width: 1000
EndChar
StartChar: period
Encoding: 46 46
Width: 1000
EndChar
StartChar: slash
Encoding: 47 47
Width: 1000
EndChar
StartChar: zero
Encoding: 48 48
Width: 1000
EndChar
StartChar: one
Encoding: 49 49
Width: 1000
EndChar
StartChar: two
Encoding: 50 50
Width: 1000
EndChar
StartChar: three
Encoding: 51 51
Width: 1000
EndChar
StartChar: four
Encoding: 52 52
Width: 1000
EndChar
StartChar: five
Encoding: 53 53
Width: 1000
EndChar
StartChar: six
Encoding: 54 54
Width: 1000
EndChar
StartChar: seven
Encoding: 55 55
Width: 1000
EndChar
StartChar: eight
Encoding: 56 56
Width: 1000
EndChar
StartChar: nine
Encoding: 57 57
Width: 1000
EndChar
StartChar: colon
Encoding: 58 58
Width: 1000
EndChar
StartChar: semicolon
Encoding: 59 59
Width: 1000
EndChar
StartChar: less
Encoding: 60 60
Width: 1000
EndChar
StartChar: equal
Encoding: 61 61
Width: 1000
EndChar
StartChar: greater
Encoding: 62 62
Width: 1000
EndChar
StartChar: question
Encoding: 63 63
Width: 1000
EndChar
StartChar: at
Encoding: 64 64
Width: 1000
EndChar
StartChar: A
Encoding: 65 65
Width: 1000
EndChar
StartChar: B
Encoding: 66 66
Width: 1000
EndChar
StartChar: C
Encoding: 67 67
Width: 1000
EndChar
StartChar: D
Encoding: 68 68
Width: 1000
EndChar
StartChar: E
Encoding: 69 69
Width: 1000
EndChar
StartChar: F
Encoding: 70 70
Width: 1000
EndChar
StartChar: G
Encoding: 71 71
Width: 1000
EndChar
StartChar: H
Encoding: 72 72
Width: 1000
EndChar
StartChar: I
Encoding: 73 73
Width: 1000
EndChar
StartChar: J
Encoding: 74 74
Width: 1000
EndChar
StartChar: K
Encoding: 75 75
Width: 1000
EndChar
StartChar: L
Encoding: 76 76
Width: 1000
EndChar
StartChar: M
Encoding: 77 77
Width: 1000
EndChar
StartChar: N
Encoding: 78 78
Width: 1000
EndChar
StartChar: O
Encoding: 79 79
Width: 1000
EndChar
StartChar: P
Encoding: 80 80
Width: 1000
EndChar
StartChar: Q
Encoding: 81 81
Width: 1000
EndChar
StartChar: R
Encoding: 82 82
Width: 1000
EndChar
StartChar: S
Encoding: 83 83
Width: 1000
EndChar
StartChar: T
Encoding: 84 84
Width: 1000
EndChar
StartChar: U
Encoding: 85 85
Width: 1000
EndChar
StartChar: V
Encoding: 86 86
Width: 1000
EndChar
StartChar: W
Encoding: 87 87
Width: 1000
EndChar
StartChar: X
Encoding: 88 88
Width: 1000
EndChar
StartChar: Y
Encoding: 89 89
Width: 1000
EndChar
StartChar: Z
Encoding: 90 90
Width: 1000
EndChar
StartChar: bracketleft
Encoding: 91 91
Width: 1000
EndChar
StartChar: backslash
Encoding: 92 92
Width: 1000
EndChar
StartChar: bracketright
Encoding: 93 93
Width: 1000
EndChar
StartChar: asciicircum
Encoding: 94 94
Width: 1000
EndChar
StartChar: underscore
Encoding: 95 95
Width: 1000
EndChar
StartChar: grave
Encoding: 96 96
Width: 1000
EndChar
StartChar: a
Encoding: 97 97
Width: 1000
EndChar
StartChar: b
Encoding: 98 98
Width: 1000
EndChar
StartChar: c
Encoding: 99 99
Width: 1000
EndChar
StartChar: d
Encoding: 100 100
Width: 1000
EndChar
StartChar: e
Encoding: 101 101
Width: 1000
EndChar
StartChar: f
Encoding: 102 102
Width: 1000
EndChar
StartChar: g
Encoding: 103 103
Width: 1000
EndChar
StartChar: h
Encoding: 104 104
Width: 1000
EndChar
StartChar: i
Encoding: 105 105
Width: 1000
EndChar
StartChar: j
Encoding: 106 106
Width: 1000
EndChar
StartChar: k
Encoding: 107 107
Width: 1000
EndChar
StartChar: l
Encoding: 108 108
Width: 1000
EndChar
StartChar: m
Encoding: 109 109
Width: 1000
EndChar
StartChar: n
Encoding: 110 110
Width: 1000
EndChar
StartChar: o
Encoding: 111 111
Width: 1000
EndChar
StartChar: p
Encoding: 112 112
Width: 1000
EndChar
StartChar: q
Encoding: 113 113
Width: 1000
EndChar
StartChar: r
Encoding: 114 114
Width: 1000
EndChar
StartChar: s
Encoding: 115 115
Width: 1000
EndChar
StartChar: t
Encoding: 116 116
Width: 1000
EndChar
StartChar: u
Encoding: 117 117
Width: 1000
EndChar
StartChar: v
Encoding: 118 118
Width: 1000
EndChar
StartChar: w
Encoding: 119 119
Width: 1000
EndChar
StartChar: x
Encoding: 120 120
Width: 1000
EndChar
StartChar: y
Encoding: 121 121
Width: 1000
EndChar
StartChar: z
Encoding: 122 122
Width: 1000
EndChar
StartChar: braceleft
Encoding: 123 123
Width: 1000
EndChar
StartChar: bar
Encoding: 124 124
Width: 1000
EndChar
StartChar: braceright
Encoding: 125 125
Width: 1000
EndChar
StartChar: asciitilde
Encoding: 126 126
Width: 1000
EndChar
StartChar: nonbreakingspace
Encoding: 160 160
Width: 1000
EndChar
StartChar: exclamdown
Encoding: 161 161
Width: 1000
EndChar
StartChar: cent
Encoding: 162 162
Width: 1000
EndChar
StartChar: sterling
Encoding: 163 163
Width: 1000
EndChar
StartChar: currency
Encoding: 164 164
Width: 1000
EndChar
StartChar: yen
Encoding: 165 165
Width: 1000
EndChar
StartChar: brokenbar
Encoding: 166 166
Width: 1000
EndChar
StartChar: section
Encoding: 167 167
Width: 1000
EndChar
StartChar: dieresis
Encoding: 168 168
Width: 1000
EndChar
StartChar: copyright
Encoding: 169 169
Width: 1000
EndChar
StartChar: ordfeminine
Encoding: 170 170
Width: 1000
EndChar
StartChar: guillemotleft
Encoding: 171 171
Width: 1000
EndChar
StartChar: logicalnot
Encoding: 172 172
Width: 1000
EndChar
StartChar: softhyphen
Encoding: 173 173
Width: 1000
EndChar
StartChar: registered
Encoding: 174 174
Width: 1000
EndChar
StartChar: macron
Encoding: 175 175
Width: 1000
EndChar
StartChar: degree
Encoding: 176 176
Width: 1000
EndChar
StartChar: plusminus
Encoding: 177 177
Width: 1000
EndChar
StartChar: twosuperior
Encoding: 178 178
Width: 1000
EndChar
StartChar: threesuperior
Encoding: 179 179
Width: 1000
EndChar
StartChar: acute
Encoding: 180 180
Width: 1000
EndChar
StartChar: mu
Encoding: 181 181
Width: 1000
EndChar
StartChar: paragraph
Encoding: 182 182
Width: 1000
EndChar
StartChar: periodcentered
Encoding: 183 183
Width: 1000
EndChar
StartChar: cedilla
Encoding: 184 184
Width: 1000
EndChar
StartChar: onesuperior
Encoding: 185 185
Width: 1000
EndChar
StartChar: ordmasculine
Encoding: 186 186
Width: 1000
EndChar
StartChar: guillemotright
Encoding: 187 187
Width: 1000
EndChar
StartChar: onequarter
Encoding: 188 188
Width: 1000
EndChar
StartChar: onehalf
Encoding: 189 189
Width: 1000
EndChar
StartChar: threequarters
Encoding: 190 190
Width: 1000
EndChar
StartChar: questiondown
Encoding: 191 191
Width: 1000
EndChar
StartChar: Agrave
Encoding: 192 192
Width: 1000
EndChar
StartChar: Aacute
Encoding: 193 193
Width: 1000
EndChar
StartChar: Acircumflex
Encoding: 194 194
Width: 1000
EndChar
StartChar: Atilde
Encoding: 195 195
Width: 1000
EndChar
StartChar: Adieresis
Encoding: 196 196
Width: 1000
EndChar
StartChar: Aring
Encoding: 197 197
Width: 1000
EndChar
StartChar: AE
Encoding: 198 198
Width: 1000
EndChar
StartChar: Ccedilla
Encoding: 199 199
Width: 1000
EndChar
StartChar: Egrave
Encoding: 200 200
Width: 1000
EndChar
StartChar: Eacute
Encoding: 201 201
Width: 1000
EndChar
StartChar: Ecircumflex
Encoding: 202 202
Width: 1000
EndChar
StartChar: Edieresis
Encoding: 203 203
Width: 1000
EndChar
StartChar: Igrave
Encoding: 204 204
Width: 1000
EndChar
StartChar: Iacute
Encoding: 205 205
Width: 1000
EndChar
StartChar: Icircumflex
Encoding: 206 206
Width: 1000
EndChar
StartChar: Idieresis
Encoding: 207 207
Width: 1000
EndChar
StartChar: Eth
Encoding: 208 208
Width: 1000
EndChar
StartChar: Ntilde
Encoding: 209 209
Width: 1000
EndChar
StartChar: Ograve
Encoding: 210 210
Width: 1000
EndChar
StartChar: Oacute
Encoding: 211 211
Width: 1000
EndChar
StartChar: Ocircumflex
Encoding: 212 212
Width: 1000
EndChar
StartChar: Otilde
Encoding: 213 213
Width: 1000
EndChar
StartChar: Odieresis
Encoding: 214 214
Width: 1000
EndChar
StartChar: multiply
Encoding: 215 215
Width: 1000
EndChar
StartChar: Oslash
Encoding: 216 216
Width: 1000
EndChar
StartChar: Ugrave
Encoding: 217 217
Width: 1000
EndChar
StartChar: Uacute
Encoding: 218 218
Width: 1000
EndChar
StartChar: Ucircumflex
Encoding: 219 219
Width: 1000
EndChar
StartChar: Udieresis
Encoding: 220 220
Width: 1000
EndChar
StartChar: Yacute
Encoding: 221 221
Width: 1000
EndChar
StartChar: Thorn
Encoding: 222 222
Width: 1000
EndChar
StartChar: germandbls
Encoding: 223 223
Width: 1000
EndChar
StartChar: agrave
Encoding: 224 224
Width: 1000
EndChar
StartChar: aacute
Encoding: 225 225
Width: 1000
EndChar
StartChar: acircumflex
Encoding: 226 226
Width: 1000
EndChar
StartChar: atilde
Encoding: 227 227
Width: 1000
EndChar
StartChar: adieresis
Encoding: 228 228
Width: 1000
EndChar
StartChar: aring
Encoding: 229 229
Width: 1000
EndChar
StartChar: ae
Encoding: 230 230
Width: 1000
EndChar
StartChar: ccedilla
Encoding: 231 231
Width: 1000
EndChar
StartChar: egrave
Encoding: 232 232
Width: 1000
EndChar
StartChar: eacute
Encoding: 233 233
Width: 1000
EndChar
StartChar: ecircumflex
Encoding: 234 234
Width: 1000
EndChar
StartChar: edieresis
Encoding: 235 235
Width: 1000
EndChar
StartChar: igrave
Encoding: 236 236
Width: 1000
EndChar
StartChar: iacute
Encoding: 237 237
Width: 1000
EndChar
StartChar: icircumflex
Encoding: 238 238
Width: 1000
EndChar
StartChar: idieresis
Encoding: 239 239
Width: 1000
EndChar
StartChar: eth
Encoding: 240 240
Width: 1000
EndChar
StartChar: ntilde
Encoding: 241 241
Width: 1000
EndChar
StartChar: ograve
Encoding: 242 242
Width: 1000
EndChar
StartChar: oacute
Encoding: 243 243
Width: 1000
EndChar
StartChar: ocircumflex
Encoding: 244 244
Width: 1000
EndChar
StartChar: otilde
Encoding: 245 245
Width: 1000
EndChar
StartChar: odieresis
Encoding: 246 246
Width: 1000
EndChar
StartChar: divide
Encoding: 247 247
Width: 1000
EndChar
StartChar: oslash
Encoding: 248 248
Width: 1000
EndChar
StartChar: ugrave
Encoding: 249 249
Width: 1000
EndChar
StartChar: uacute
Encoding: 250 250
Width: 1000
EndChar
StartChar: ucircumflex
Encoding: 251 251
Width: 1000
EndChar
StartChar: udieresis
Encoding: 252 252
Width: 1000
EndChar
StartChar: yacute
Encoding: 253 253
Width: 1000
EndChar
StartChar: thorn
Encoding: 254 254
Width: 1000
EndChar
StartChar: ydieresis
Encoding: 255 255
Width: 1000
EndChar
StartChar: uni03A9
Encoding: 937 937
Width: 760
Flags: W
HStem: 0 86.5<55 192 560 711> 662.5 82.6191<368 400>
VStem: 48.5 285.5<1 81> 56.5 100.5<368 416> 432.5 285<1 81> 610.5 99<368 416>
Fore
48.5 86.5 m 1
208.5 86.5 l 1
107.167 171.167 56.5 274.5 56.5 396.5 c 1
56.7101 536.75 118.58 644.249 209.5 699.75 c 1
297.509 759.342 465.523 760.85 554.25 703.5 c 1
642.338 648.475 711.166 540.692 709.5 396.5 c 1
709.5 274.5 658.833 171.167 557.5 86.5 c 1
717.5 86.5 l 1
717.5 0 l 1
432.5 0 l 1
432.5 81 l 1
551.167 136.333 610.5 236.5 610.5 381.5 c 1
613.683 531.395 525.526 663.23 384.5 662.5 c 1
242.961 665.005 154.417 531.689 157 386.5 c 1
157 239.5 216 137.667 334 81 c 1
334 0 l 1
48.5 0 l 1
48.5 86.5 l 1
EndSplineSet
MinimumDistance: x5,-1
EndChar
StartChar: sigma
Encoding: 963 963
Width: 654
Flags: W
HStem: -11.9998 73.9998<282 299.31> 458 73<466 594> 468.5 74.5483<280.625 302.587>
VStem: 34 92.5<243 265 265.575 298.829> 440 91.5<243 291>
Fore
609.5 531 m 1
609.5 458 l 1
465 458 l 1
509.333 416.667 531.5 352.333 531.5 265 c 0
531.5 170 507.25 100.083 458.75 55.25 c 1
367.585 -35.1072 191 -34.6289 104 58 c 1
57.333 104.667 34 173.833 34 265.5 c 0
34 359.833 58.25 429.667 106.75 475 c 1
176.138 537.884 259.745 558.789 367 531 c 1
609.5 531 l 1
280.5 468.5 m 1
180.415 465.592 122.839 382.568 126.5 265 c 1
124.033 145.734 177.982 64.8142 282 62 c 1
387.637 63.1845 442.118 149.124 440 265.5 c 1
439.941 377.605 391.876 470.041 280.5 468.5 c 1
EndSplineSet
MinimumDistance: x3,-1
EndChar
StartChar: psi
Encoding: 968 968
Width: 748
Flags: W
HStem: -203.5 734.5<320 410>
VStem: 61 89.5<244 530> 320 90<-188 -12 65 530> 579 89.5<244 530>
Fore
61 531 m 1
150.5 531 l 1
150.5 269 l 1
151.992 173.54 157.865 130.981 213.25 92.75 c 1
239.083 75.583 274.667 65.833 320 63.5 c 1
320 531 l 1
410 531 l 1
410 63.5 l 1
489.519 66.7047 544.824 98.0574 565.75 154.25 c 1
574.583 179.75 579 218 579 269 c 2
579 531 l 1
668.5 531 l 1
668.5 272 l 1
666.618 133.548 653.5 84.7044 571.5 29.25 c 1
532.5 4.08301 478.667 -9.66699 410 -12 c 1
410 -203.5 l 1
320 -203.5 l 1
320 -12 l 1
229.595 -8.79161 164.247 11.9517 118.75 61.25 c 1
67.0712 119.571 62.4383 155.542 61 272 c 1
61 531 l 1
EndSplineSet
MinimumDistance: x11,-1
EndChar
StartChar: arrowright
Encoding: 8594 8594
Width: 1035
Flags: W
HStem: 233 50.5<55 836>
VStem: 39.5 944.5<249 271>
Fore
777.5 438 m 1
848.958 360.788 901.645 310.333 984 271.5 c 1
984 249 l 1
897.46 204.953 850.008 159.158 777 78.5 c 1
738.5 78.5 l 1
769.833 145.5 802.667 197 837 233 c 1
39.5 233 l 1
39.5 283.5 l 1
837 283.5 l 1
782.642 353.947 781.915 354.515 739.5 438 c 1
777.5 438 l 1
EndSplineSet
MinimumDistance: x1,-1
EndChar
StartChar: gradient
Encoding: 8711 8711
Width: 648
Flags: W
HStem: 652.5 41<134 551>
DStem: 14.5 693.5 132.5 652.5 300.5 0 332 169 552 652.5 614.5 693.5 332 169 300.5 0
Fore
14.5 693.5 m 1
614.5 693.5 l 1
300.5 0 l 1
14.5 693.5 l 1
132.5 652.5 m 1
332 169 l 1
552 652.5 l 1
132.5 652.5 l 1
EndSplineSet
MinimumDistance: x1,-1
EndChar
StartChar: uni2219
Encoding: 8729 8729
Width: 294
Flags: W
HStem: 309.5 102.5<108 194>
VStem: 92.5 102.5<325 411>
Fore
92.5 309.5 m 1
92.5 412 l 1
195 412 l 1
195 309.5 l 1
92.5 309.5 l 1
EndSplineSet
MinimumDistance: x2,-1
EndChar
StartChar: integral
Encoding: 8747 8747
Width: 291
Flags: W
VStem: 100.5 77.8252<327.709 474>
Fore
100.5 474 m 1
109 739.5 l 1
114.542 833.138 134.534 923.622 217.5 931.5 c 1
247.522 933.096 280.447 905.565 280 878 c 1
280.849 848.918 261.127 825.941 234 826 c 1
222.333 826 209.667 832 196 844 c 1
176.357 863.99 153.522 851.038 156 822 c 1
156 808 157.5 783.833 160.5 749.5 c 1
184.169 438.285 182.123 484.679 171 123 c 1
168.333 24.667 153.333 -41.833 126 -76.5 c 1
101.122 -110.714 47.8807 -123.362 16.5 -93 c 1
-3.17021 -74.8996 -6.32757 -33.0899 12.75 -13.5 c 1
30.257 5.46361 62.8625 4.28698 79.5 -16 c 1
93.653 -31.3569 104.804 -38.4598 118 -25 c 1
129.244 -4.11259 121.392 22.5244 119 58.5 c 1
106.667 163.5 100.5 302 100.5 474 c 1
EndSplineSet
EndChar
EndChars
EndSplineFont
Binary file not shown.
@@ -0,0 +1,470 @@
/*
* Demo3UnicodeExample2.h: Additional symbols for demo3 example.
* Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
FT_Byte lCSymbols_ttf[] = {
0,1,0,0,0,12,0,128,0,3,0,64,79,83,47,50,
81,97,77,142,0,0,0,204,0,0,0,86,99,109,97,112,
224,46,4,241,0,0,1,36,0,0,1,82,99,118,116,32,
4,48,5,221,0,0,2,120,0,0,0,34,103,108,121,102,
109,46,45,11,0,0,2,156,0,0,18,254,104,101,97,100,
211,187,118,221,0,0,21,156,0,0,0,54,104,104,101,97,
6,115,1,120,0,0,21,212,0,0,0,36,104,109,116,120,
28,67,1,223,0,0,21,248,0,0,0,100,107,101,114,110,
251,84,252,187,0,0,22,92,0,0,0,162,108,111,99,97,
51,201,56,104,0,0,23,0,0,0,0,52,109,97,120,112,
0,94,1,24,0,0,23,52,0,0,0,32,110,97,109,101,
31,28,131,163,0,0,23,84,0,0,3,167,112,111,115,116,
142,120,183,88,0,0,26,252,0,0,1,4,0,1,3,232,
1,144,0,5,0,12,0,200,0,200,0,0,0,200,0,200,
0,200,0,0,0,200,0,49,1,2,0,0,2,0,5,3,
0,0,0,0,0,0,0,0,0,3,16,0,0,8,0,0,
0,0,0,0,0,0,80,102,69,100,0,64,0,32,224,25,
2,234,255,52,0,90,2,234,0,204,0,0,0,1,0,0,
0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,28,
0,1,0,0,0,0,0,76,0,3,0,1,0,0,0,28,
0,4,0,48,0,0,0,8,0,8,0,2,0,0,33,4,
224,10,224,25,255,255,0,0,33,4,224,0,224,16,255,255,
222,255,32,4,31,255,0,1,0,0,0,0,0,0,0,0,
0,0,1,6,0,0,1,0,0,0,0,0,0,0,1,3,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,33,2,121,0,86,0,83,
0,100,0,97,1,202,0,37,0,46,1,112,0,43,0,242,
0,48,0,41,0,237,0,0,0,21,0,0,0,2,0,33,
0,0,1,110,2,154,0,3,0,7,0,46,177,1,0,47,
60,178,7,4,0,237,50,177,6,5,220,60,178,3,2,0,
237,50,0,177,3,0,47,60,178,5,4,0,237,50,178,7,
6,1,252,60,178,1,2,0,237,50,51,17,33,17,37,33,
17,33,33,1,77,254,212,1,11,254,245,2,154,253,102,33,
2,88,0,1,0,7,255,52,2,246,2,234,0,47,0,110,
0,176,11,47,176,12,51,177,9,2,237,177,10,2,237,176,
32,47,176,33,51,176,34,51,177,24,3,237,177,25,3,237,
177,26,3,237,1,176,17,47,176,18,51,176,19,51,176,20,
51,177,39,4,237,177,40,4,237,177,41,4,237,177,42,4,
237,176,12,47,176,13,51,176,45,51,176,46,51,177,0,5,
237,177,7,5,237,177,8,5,237,177,9,5,237,177,47,5,
237,176,12,16,177,10,6,237,177,11,6,237,48,49,37,54,
55,23,6,7,6,15,1,21,33,21,33,53,38,47,1,38,
61,1,52,55,54,55,54,51,50,23,22,23,7,38,47,1,
34,7,6,15,1,6,29,1,20,23,22,23,17,51,1,141,
130,31,97,46,161,24,26,1,1,105,254,54,183,70,1,39,
122,22,25,80,97,176,81,20,13,96,45,128,23,135,63,12,
8,3,23,112,39,42,97,76,31,150,24,185,47,7,3,1,
108,86,194,19,166,1,91,104,1,198,100,18,14,44,136,35,
43,22,141,11,1,100,19,22,8,68,72,1,201,67,23,7,
1,198,0,2,0,21,1,97,1,5,2,216,0,12,0,30,
0,109,0,176,7,47,176,8,51,176,9,51,177,10,7,237,
177,17,7,237,177,18,7,237,177,19,7,237,176,26,176,10,
16,222,176,27,50,176,28,50,177,1,7,237,177,2,7,237,
177,3,7,237,1,176,0,47,176,1,51,176,11,51,176,12,
51,177,13,8,237,177,14,8,237,177,30,8,237,176,21,176,
13,16,222,176,22,50,176,23,50,176,24,50,177,5,8,237,
177,6,8,237,177,7,8,237,177,32,6,16,204,48,49,19,
52,51,50,23,22,21,20,35,34,39,38,53,55,20,23,51,
22,51,50,55,54,61,1,52,39,38,35,34,7,6,21,120,
85,26,8,119,53,30,37,47,20,1,21,31,31,21,21,21,
21,32,31,18,23,2,29,187,101,32,54,187,38,45,102,2,
90,30,30,30,30,88,2,90,30,30,27,33,0,1,0,55,
1,104,0,191,2,216,0,13,0,41,0,176,0,47,176,1,
51,177,11,9,237,177,12,9,237,177,13,9,237,1,176,1,
47,176,2,51,177,0,8,237,177,13,8,237,177,15,0,16,
204,48,49,19,35,17,6,7,6,7,53,54,55,54,63,1,
51,191,45,17,26,26,21,37,29,27,12,1,29,1,104,1,
31,16,15,16,8,44,18,25,25,23,1,0,0,1,0,15,
1,104,1,2,2,216,0,37,0,96,0,176,1,47,176,2,
51,177,0,10,237,177,37,10,237,176,15,176,0,16,222,176,
16,50,176,17,50,177,23,7,237,177,24,7,237,177,25,7,
237,1,176,2,47,176,3,51,177,0,11,237,177,1,11,237,
177,28,11,237,177,29,11,237,177,30,11,237,176,29,16,177,
10,8,237,177,11,8,237,177,12,8,237,177,13,8,237,177,
25,8,237,177,39,0,16,204,48,49,1,21,35,38,55,53,
54,55,54,55,54,61,1,52,39,38,35,34,7,21,7,39,
54,63,1,50,23,22,31,1,20,15,1,6,7,6,15,1,
1,2,242,2,36,21,38,60,21,21,41,13,15,56,13,3,
46,8,82,29,70,31,10,2,1,38,1,21,48,52,13,6,
1,147,43,37,42,1,24,32,49,28,28,25,1,43,16,5,
50,1,23,5,89,15,2,50,17,20,15,44,43,1,23,41,
44,17,10,0,0,1,0,21,1,97,1,6,2,216,0,52,
0,133,0,176,48,47,176,49,51,176,50,51,177,2,7,237,
177,3,7,237,177,4,7,237,176,13,176,2,16,222,176,14,
50,176,15,50,177,17,0,237,177,18,0,237,177,19,0,237,
176,26,176,17,16,222,176,27,50,176,28,50,177,33,7,237,
177,34,7,237,177,35,7,237,1,176,21,47,176,22,51,176,
23,51,176,24,51,176,35,51,177,38,8,237,177,39,8,237,
177,40,8,237,177,41,8,237,176,8,47,176,9,51,176,10,
51,176,11,51,177,44,12,237,177,45,12,237,177,46,12,237,
177,54,45,16,204,48,49,19,55,22,51,50,55,61,1,54,
61,1,52,39,38,35,34,7,55,23,50,55,54,61,1,52,
39,38,35,34,7,39,54,55,54,51,50,23,49,22,21,23,
20,7,22,31,1,20,7,6,35,34,39,38,22,44,15,57,
47,21,8,40,15,17,13,19,5,7,55,16,4,34,12,14,
56,10,45,13,63,16,18,59,31,17,1,51,59,8,2,57,
30,37,71,32,11,1,201,6,72,41,1,1,15,17,1,47,
18,6,4,39,1,38,11,12,1,38,14,5,66,8,73,17,
5,42,23,29,1,51,24,13,60,17,65,32,17,57,20,0,
0,2,0,6,1,104,1,4,2,215,0,10,0,13,0,114,
0,176,1,47,176,2,51,176,8,51,176,9,51,177,3,13,
237,177,6,13,237,177,7,13,237,177,11,13,237,177,13,13,
237,177,4,6,16,204,177,5,6,16,204,177,10,1,16,204,
177,0,1,16,204,1,176,0,47,176,1,51,176,11,51,176,
12,51,177,5,8,237,177,6,8,237,177,9,8,237,177,10,
8,237,177,4,6,16,204,177,8,6,16,204,177,7,6,16,
204,177,3,1,16,204,177,2,1,16,204,177,15,7,16,204,
48,49,19,53,35,53,55,51,21,51,21,35,21,39,53,7,
166,160,168,36,50,50,44,115,1,104,88,41,237,237,41,88,
129,165,165,0,0,1,0,21,1,97,1,9,2,210,0,36,
0,102,0,176,32,47,176,33,51,176,34,51,177,3,7,237,
177,4,7,237,177,5,7,237,176,12,176,3,16,222,176,13,
50,176,14,50,177,22,13,237,177,23,13,237,177,24,13,237,
176,19,176,22,16,222,176,20,50,177,17,10,237,177,18,10,
237,1,176,7,47,176,8,51,176,9,51,176,10,51,176,24,
51,177,27,12,237,177,28,12,237,177,29,12,237,177,30,12,
237,177,38,29,16,204,48,49,19,55,22,31,1,50,55,54,
61,1,52,39,38,35,34,7,39,55,51,21,35,7,54,51,
50,23,21,22,29,1,20,7,6,35,34,39,38,21,47,9,
47,15,51,19,7,46,15,17,44,22,43,36,182,146,20,33,
36,66,32,16,57,30,38,76,30,9,1,200,4,58,10,1,
49,18,21,1,59,19,5,35,5,189,44,98,23,55,1,27,
35,1,75,36,19,60,19,0,0,2,0,19,1,97,1,6,
2,216,0,29,0,47,0,136,0,176,17,47,176,18,51,176,
19,51,177,33,7,237,177,34,7,237,177,35,7,237,176,42,
176,33,16,222,176,43,50,176,44,50,176,45,50,177,8,13,
237,177,9,13,237,177,10,13,237,176,2,176,8,16,222,176,
3,50,176,4,50,177,25,7,237,177,26,7,237,177,27,7,
237,177,28,7,237,1,176,21,47,176,22,51,176,23,51,176,
24,51,177,6,10,237,177,7,10,237,176,10,47,176,37,51,
176,38,51,176,39,51,176,40,51,177,12,8,237,177,13,8,
237,177,14,8,237,177,15,8,237,177,49,14,16,204,48,49,
1,7,38,35,34,7,6,21,54,51,50,23,22,29,1,20,
7,6,35,34,39,38,39,53,52,55,54,51,50,23,7,20,
23,22,51,50,55,54,61,1,52,39,38,39,35,34,7,6,
0,255,45,13,49,48,23,13,32,57,64,30,14,52,27,36,
56,35,35,1,117,7,8,73,24,177,36,18,21,46,17,6,
41,11,14,5,47,19,7,2,125,4,58,57,30,55,49,57,
28,33,1,73,34,18,41,41,94,2,184,11,1,63,186,52,
25,11,49,16,19,1,56,19,6,1,44,16,0,1,0,24,
1,104,1,6,2,210,0,16,0,43,0,176,0,47,176,16,
51,177,1,10,237,177,2,10,237,176,9,47,176,10,47,1,
176,0,47,176,1,51,177,2,14,237,177,3,14,237,177,18,
2,16,204,48,49,19,53,51,21,6,7,6,7,6,7,35,
54,55,52,55,54,55,24,238,71,42,6,4,14,3,46,5,
86,1,17,19,2,166,44,35,75,120,16,15,46,55,140,129,
2,1,25,21,0,3,0,20,1,97,1,7,2,216,0,32,
0,51,0,69,0,207,0,176,24,47,176,25,51,176,26,51,
177,55,7,237,177,56,7,237,177,57,7,237,176,17,176,55,
16,222,176,31,50,176,64,50,176,65,50,176,66,50,177,36,
7,237,177,37,7,237,177,38,7,237,176,3,176,36,16,222,
176,45,50,176,46,50,176,47,50,177,5,7,237,177,6,7,
237,177,7,7,237,1,176,28,47,176,29,51,176,30,51,176,
31,51,177,52,8,237,177,53,8,237,177,68,8,237,177,69,
8,237,176,1,47,176,2,51,176,3,51,176,27,51,177,33,
8,237,177,34,8,237,177,50,8,237,177,51,8,237,176,40,
47,176,41,51,176,42,51,176,43,51,177,12,8,237,177,13,
8,237,177,14,8,237,177,15,8,237,176,59,47,176,60,51,
176,61,51,176,62,51,177,17,8,237,177,18,8,237,177,19,
8,237,177,20,8,237,177,21,8,237,177,22,8,237,177,71,
21,16,204,48,49,19,38,53,52,55,54,51,50,31,1,21,
23,22,29,1,20,7,22,23,20,29,1,20,7,6,35,34,
39,38,61,1,52,55,39,20,23,22,51,50,55,54,61,1,
52,39,38,35,34,15,1,6,21,7,20,23,22,51,50,55,
54,61,1,52,39,38,35,34,7,6,21,90,54,54,23,28,
63,29,1,1,12,54,67,2,58,28,34,72,33,16,67,6,
37,11,12,40,14,5,35,12,13,38,16,1,4,15,40,16,
19,48,19,7,41,16,19,47,19,7,2,47,20,55,59,25,
10,46,1,1,1,21,25,1,53,20,22,69,1,1,1,67,
30,14,52,26,33,1,73,19,77,42,13,4,34,10,11,1,
39,15,5,32,1,11,11,170,48,19,8,40,15,17,1,48,
20,7,40,15,17,0,0,2,0,21,1,97,1,7,2,216,
0,35,0,58,0,133,0,176,32,47,176,33,51,176,34,51,
177,2,7,237,177,3,7,237,177,4,7,237,176,11,176,2,
16,222,176,12,50,176,13,50,177,7,13,237,177,8,13,237,
177,53,13,237,177,54,13,237,177,55,13,237,176,41,176,8,
16,222,176,42,50,176,43,50,177,21,7,237,177,22,7,237,
177,23,7,237,1,176,16,47,176,17,51,176,18,51,176,19,
51,177,13,8,237,177,49,8,237,177,50,8,237,177,51,8,
237,176,6,47,176,7,51,176,8,51,176,9,51,177,28,10,
237,177,29,10,237,177,30,10,237,48,49,19,55,22,51,50,
55,54,53,55,39,6,15,1,34,39,53,38,61,1,52,55,
54,51,50,31,1,21,23,22,21,20,7,6,35,34,39,55,
52,39,34,49,38,35,34,15,1,21,7,21,6,21,20,23,
22,51,50,55,54,53,28,43,11,50,61,19,5,1,1,27,
52,8,65,30,14,54,27,34,72,34,1,4,15,60,30,41,
76,22,179,37,1,14,18,45,20,1,1,7,39,15,19,52,
15,4,1,189,4,58,79,24,28,2,8,43,4,1,58,1,
27,33,1,73,34,17,64,1,1,8,36,67,132,43,22,67,
185,54,22,9,45,1,1,1,1,18,21,50,21,8,52,14,
15,0,0,1,0,0,255,243,1,2,2,234,0,3,0,20,
176,0,47,176,1,47,176,2,47,176,3,47,1,177,5,2,
47,204,48,49,21,19,51,3,212,46,214,12,2,246,253,10,
0,2,0,21,255,249,1,5,1,112,0,12,0,31,0,113,
0,176,7,47,176,8,51,176,9,51,177,10,7,237,177,17,
7,237,177,18,7,237,177,19,7,237,176,26,176,10,16,222,
176,27,50,176,28,50,177,1,7,237,177,2,7,237,177,3,
7,237,1,176,0,47,176,1,51,176,11,51,176,12,51,177,
13,8,237,177,14,8,237,177,30,8,237,177,31,8,237,176,
21,176,13,16,222,176,22,50,176,23,50,176,24,50,177,5,
8,237,177,6,8,237,177,7,8,237,177,33,6,16,204,48,
49,55,52,51,50,23,22,21,20,35,34,39,38,53,55,20,
23,51,22,51,50,55,54,61,1,52,39,38,35,34,7,6,
21,21,120,85,26,8,119,53,30,37,47,20,1,21,31,31,
21,21,21,21,32,31,18,23,181,187,101,32,54,187,38,45,
102,2,90,30,30,30,30,88,2,90,30,30,27,33,89,0,
0,1,0,55,0,0,0,191,1,112,0,13,0,42,0,177,
0,15,63,176,1,51,177,11,9,237,177,12,9,237,177,13,
9,237,1,176,1,47,176,2,51,177,0,8,237,177,13,8,
237,177,15,0,16,204,48,49,51,35,17,6,7,6,7,53,
54,55,54,63,1,51,191,45,17,26,26,21,37,29,27,12,
1,29,1,31,16,15,16,8,44,18,25,25,23,1,0,1,
0,15,0,0,1,2,1,112,0,38,0,101,0,177,1,15,
63,176,2,51,177,0,10,237,177,38,10,237,176,14,176,0,
16,222,176,15,50,176,16,50,177,23,7,237,177,24,7,237,
177,25,7,237,1,176,2,47,176,3,51,177,0,11,237,177,
1,11,237,177,28,11,237,177,29,11,237,177,30,11,237,177,
31,11,237,176,28,16,177,9,8,237,177,10,8,237,177,11,
8,237,177,12,8,237,177,25,8,237,177,40,0,16,204,48,
49,37,21,35,38,55,54,55,54,55,54,61,1,52,39,38,
35,34,7,29,1,7,39,54,63,1,50,23,21,22,29,1,
20,15,1,6,7,6,15,1,1,2,242,2,36,21,38,60,
21,21,41,13,15,56,13,3,46,8,82,29,70,31,13,38,
1,21,48,52,13,6,43,43,38,42,24,32,49,28,28,25,
1,43,16,5,50,1,1,22,5,89,15,2,50,1,22,28,
1,44,43,1,23,41,44,17,10,0,0,1,0,21,255,249,
1,6,1,112,0,51,0,133,0,176,47,47,176,48,51,176,
49,51,177,2,7,237,177,3,7,237,177,4,7,237,176,11,
176,2,16,222,176,12,50,176,13,50,177,15,0,237,177,16,
0,237,177,17,0,237,176,24,176,15,16,222,176,25,50,176,
26,50,177,31,7,237,177,32,7,237,177,33,7,237,1,176,
19,47,176,20,51,176,21,51,176,22,51,176,33,51,177,37,
8,237,177,38,8,237,177,39,8,237,177,40,8,237,176,6,
47,176,7,51,176,8,51,176,9,51,177,43,12,237,177,44,
12,237,177,45,12,237,177,53,44,16,204,48,49,63,1,22,
51,50,55,54,61,1,52,39,38,35,34,7,55,23,50,55,
54,61,1,52,39,38,35,34,7,39,54,55,54,51,50,31,
1,49,22,21,23,20,7,22,31,1,20,7,6,39,34,39,
38,22,44,15,57,47,21,8,40,15,17,13,19,5,7,55,
16,4,34,12,14,56,10,45,13,63,16,18,61,30,1,15,
1,51,59,8,2,57,30,37,71,32,11,97,6,72,41,16,
18,1,47,18,6,4,39,1,38,11,12,1,38,14,5,66,
8,73,17,5,43,1,22,28,1,51,24,13,60,17,65,32,
18,1,57,20,0,2,0,6,0,0,1,4,1,111,0,10,
0,13,0,111,0,177,0,15,63,176,10,51,176,1,222,176,
2,50,176,8,50,176,9,50,177,3,13,237,177,6,13,237,
177,7,13,237,177,11,13,237,177,13,13,237,177,4,6,16,
204,177,5,6,16,204,1,176,0,47,176,1,51,176,11,51,
176,12,51,177,5,8,237,177,6,8,237,177,9,8,237,177,
10,8,237,177,4,6,16,204,177,8,6,16,204,177,7,6,
16,204,177,3,1,16,204,177,2,1,16,204,177,15,7,16,
204,48,49,51,53,35,53,55,51,21,51,21,35,21,39,53,
7,166,160,168,36,50,50,44,115,88,41,237,237,41,88,129,
165,165,0,1,0,21,255,249,1,9,1,106,0,36,0,106,
0,176,32,47,176,33,51,176,34,51,177,3,7,237,177,4,
7,237,177,5,7,237,177,6,7,237,176,13,176,3,16,222,
176,14,50,176,15,50,177,23,13,237,177,24,13,237,177,25,
13,237,176,20,176,23,16,222,176,21,50,177,18,10,237,177,
19,10,237,1,176,8,47,176,9,51,176,10,51,176,11,51,
176,25,51,177,27,12,237,177,28,12,237,177,29,12,237,177,
30,12,237,177,38,29,16,204,48,49,63,1,22,23,22,51,
50,55,54,61,1,52,39,38,35,34,7,39,55,51,21,35,
7,54,51,50,23,22,29,1,20,7,6,35,34,39,38,21,
47,9,47,7,8,51,19,7,46,15,17,44,22,43,36,182,
146,20,33,36,66,32,16,57,30,38,76,30,9,96,4,58,
10,1,49,18,21,1,59,19,5,35,5,189,44,98,23,55,
28,35,1,75,36,19,60,19,0,2,0,12,255,249,0,255,
1,112,0,31,0,49,0,129,0,176,17,47,176,18,51,176,
19,51,177,35,7,237,177,36,7,237,177,37,7,237,176,44,
176,35,16,222,176,45,50,176,46,50,177,8,13,237,177,9,
13,237,177,10,13,237,176,2,176,8,16,222,176,3,50,176,
4,50,177,25,7,237,177,26,7,237,177,27,7,237,1,176,
21,47,176,22,51,176,23,51,176,24,51,177,6,10,237,177,
7,10,237,176,10,47,176,39,51,176,40,51,176,41,51,176,
42,51,177,12,8,237,177,13,8,237,177,14,8,237,177,15,
8,237,177,51,14,16,204,48,49,19,7,38,35,34,7,6,
21,54,51,50,23,22,29,1,20,7,6,35,34,39,38,39,
53,52,63,1,50,23,21,22,23,7,20,23,22,51,50,55,
54,61,1,52,39,38,35,34,7,6,21,248,45,13,49,48,
23,13,32,57,64,30,14,52,27,35,57,35,35,1,117,15,
73,24,5,2,184,36,18,21,46,17,6,41,13,17,47,19,
7,1,21,4,58,57,30,55,49,57,28,33,1,73,34,18,
41,41,94,2,184,11,1,63,1,12,14,159,52,25,11,49,
16,19,1,56,19,7,44,16,18,0,0,1,0,24,0,0,
1,6,1,106,0,14,0,44,0,177,9,15,63,176,10,51,
176,0,222,176,14,50,177,1,10,237,177,2,10,237,1,176,
0,47,176,1,51,177,2,14,237,177,3,14,237,177,16,2,
16,204,48,49,19,53,51,21,6,7,6,7,6,7,35,54,
55,54,55,24,238,71,42,6,4,14,3,46,5,86,18,19,
1,62,44,35,75,120,16,15,46,55,140,129,27,22,0,3,
0,20,255,249,1,7,1,112,0,29,0,47,0,65,0,203,
0,176,20,47,176,21,51,176,22,51,177,51,7,237,177,52,
7,237,177,53,7,237,176,14,176,51,16,222,176,27,50,176,
60,50,176,61,50,176,62,50,177,33,7,237,177,34,7,237,
177,35,7,237,176,3,176,33,16,222,176,42,50,176,43,50,
176,44,50,177,5,7,237,177,6,7,237,177,7,7,237,1,
176,24,47,176,25,51,176,26,51,176,27,51,177,48,8,237,
177,49,8,237,177,64,8,237,177,65,8,237,176,1,47,176,
2,51,176,3,51,176,23,51,177,30,8,237,177,31,8,237,
177,46,8,237,177,47,8,237,176,37,47,176,38,51,176,39,
51,176,40,51,177,9,8,237,177,10,8,237,177,11,8,237,
177,12,8,237,176,55,47,176,56,51,176,57,51,176,58,51,
177,14,8,237,177,15,8,237,177,16,8,237,177,17,8,237,
177,18,8,237,177,67,17,16,204,48,49,55,38,53,52,55,
54,51,50,23,22,29,1,20,7,22,23,20,49,20,7,6,
35,34,39,38,61,1,52,55,50,39,20,23,22,51,50,55,
54,61,1,52,39,38,35,34,7,6,21,7,20,23,22,51,
50,55,54,61,1,52,39,38,35,34,7,6,21,90,54,54,
23,28,63,29,14,54,67,2,58,28,34,72,33,16,65,2,
6,37,11,12,40,14,5,35,12,13,38,16,5,15,40,16,
19,48,19,7,41,16,19,47,19,7,199,20,55,59,25,10,
46,22,27,1,53,20,22,69,3,67,30,14,52,26,33,1,
72,20,77,42,13,4,34,10,11,1,39,15,5,32,11,12,
170,48,19,8,40,15,17,1,48,20,7,40,15,17,0,2,
0,21,255,249,1,7,1,112,0,33,0,52,0,133,0,176,
29,47,176,30,51,176,31,51,177,2,7,237,177,3,7,237,
177,4,7,237,176,11,176,2,16,222,176,12,50,176,13,50,
177,7,13,237,177,8,13,237,177,47,13,237,177,48,13,237,
177,49,13,237,176,39,176,8,16,222,176,40,50,176,41,50,
177,20,7,237,177,21,7,237,177,22,7,237,1,176,15,47,
176,16,51,176,17,51,176,18,51,177,13,8,237,177,43,8,
237,177,44,8,237,177,45,8,237,176,6,47,176,7,51,176,
8,51,176,9,51,177,25,10,237,177,26,10,237,177,27,10,
237,48,49,63,1,22,51,50,55,54,53,55,39,6,15,1,
34,39,38,61,1,52,55,54,51,50,31,1,22,21,20,7,
6,35,34,39,38,55,52,39,34,49,38,35,34,7,6,21,
20,23,22,51,50,55,54,53,28,43,11,50,40,22,23,1,
1,27,52,8,65,30,14,54,27,34,72,34,5,15,60,30,
41,76,22,3,182,37,1,14,18,46,20,8,39,15,19,52,
15,4,85,4,58,35,36,60,2,8,43,4,1,58,27,34,
1,73,34,17,64,10,36,67,132,43,22,67,11,174,54,22,
9,46,20,22,50,21,8,52,14,15,0,0,0,1,0,0,
0,0,0,0,233,217,10,104,95,15,60,245,0,19,3,232,
0,0,0,0,184,207,153,237,0,0,0,0,184,207,153,237,
0,0,255,52,2,246,2,234,0,0,0,8,0,2,0,0,
0,0,0,0,0,1,0,0,3,32,255,56,0,90,2,142,
0,0,255,152,2,246,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,25,1,176,0,33,0,0,0,0,
1,77,0,0,2,142,0,7,1,15,0,21,0,235,0,55,
1,31,0,15,1,23,0,21,1,23,0,6,1,30,0,21,
1,28,0,19,1,25,0,24,1,28,0,20,1,23,0,21,
1,27,0,0,1,15,0,21,0,235,0,55,1,31,0,15,
1,25,0,21,1,22,0,6,1,31,0,21,1,21,0,12,
1,25,0,24,1,28,0,20,1,31,0,21,0,0,0,1,
0,0,0,158,0,1,0,24,0,96,0,4,255,208,0,4,
0,4,0,0,0,4,0,14,255,122,0,5,0,5,0,0,
0,5,0,14,255,152,0,6,0,6,0,0,0,6,0,14,
255,150,0,7,0,14,255,122,0,8,0,14,255,122,0,9,
0,14,255,115,0,10,0,14,255,115,0,11,0,14,255,92,
0,12,0,14,255,115,0,13,0,14,255,115,0,14,0,14,
255,211,0,14,0,15,255,107,0,14,0,16,255,85,0,14,
0,17,255,107,0,14,0,18,255,115,0,14,0,19,255,92,
0,14,0,20,255,100,0,14,0,21,255,107,0,14,0,22,
255,130,0,14,0,23,255,100,0,14,0,24,255,107,0,0,
0,0,0,43,0,43,0,43,0,171,1,16,1,64,1,172,
2,58,2,140,2,246,3,128,3,180,4,125,5,19,5,42,
5,146,5,193,6,47,6,188,7,11,7,118,7,255,8,49,
8,241,9,127,0,1,0,0,0,25,0,70,0,3,0,0,
0,0,0,2,0,0,0,1,0,1,0,0,0,64,0,207,
0,0,0,0,0,0,0,26,1,62,0,1,0,0,0,0,
0,0,0,65,0,0,0,1,0,0,0,0,0,1,0,9,
0,66,0,1,0,0,0,0,0,2,0,7,0,76,0,1,
0,0,0,0,0,3,0,34,0,84,0,1,0,0,0,0,
0,4,0,9,0,119,0,1,0,0,0,0,0,5,0,7,
0,129,0,1,0,0,0,0,0,6,0,9,0,137,0,0,
0,3,0,0,0,0,0,130,0,147,0,0,0,3,0,0,
0,1,0,18,1,23,0,0,0,3,0,0,0,2,0,14,
1,43,0,0,0,3,0,0,0,3,0,68,1,59,0,0,
0,3,0,0,0,4,0,18,1,129,0,0,0,3,0,0,
0,5,0,14,1,149,0,0,0,3,0,0,0,6,0,18,
1,165,0,3,0,1,4,9,0,0,0,130,0,147,0,3,
0,1,4,9,0,1,0,18,1,23,0,3,0,1,4,9,
0,2,0,14,1,43,0,3,0,1,4,9,0,3,0,68,
1,59,0,3,0,1,4,9,0,4,0,18,1,129,0,3,
0,1,4,9,0,5,0,14,1,149,0,3,0,1,4,9,
0,6,0,18,1,165,0,3,0,1,0,0,0,4,0,34,
1,185,0,3,0,1,0,0,0,8,0,44,1,221,0,3,
0,1,0,0,0,11,0,46,2,11,0,3,0,1,0,0,
0,13,0,6,2,59,0,3,0,1,0,0,0,14,0,36,
2,67,67,114,101,97,116,101,100,32,98,121,32,65,108,108,
101,110,32,66,97,114,110,101,116,116,32,119,105,116,104,32,
80,102,97,69,100,105,116,32,49,46,48,32,40,104,116,116,
112,58,47,47,112,102,97,101,100,105,116,46,115,102,46,110,
101,116,41,0,108,67,83,121,109,98,111,108,115,0,82,101,
103,117,108,97,114,0,80,102,97,69,100,105,116,32,49,46,
48,32,58,32,108,67,83,121,109,98,111,108,115,32,58,32,
50,45,51,45,50,48,55,50,0,108,67,83,121,109,98,111,
108,115,0,48,48,49,46,48,48,48,0,108,67,83,121,109,
98,111,108,115,0,0,67,0,114,0,101,0,97,0,116,0,
101,0,100,0,32,0,98,0,121,0,32,0,65,0,108,0,
108,0,101,0,110,0,32,0,66,0,97,0,114,0,110,0,
101,0,116,0,116,0,32,0,119,0,105,0,116,0,104,0,
32,0,80,0,102,0,97,0,69,0,100,0,105,0,116,0,
32,0,49,0,46,0,48,0,32,0,40,0,104,0,116,0,
116,0,112,0,58,0,47,0,47,0,112,0,102,0,97,0,
101,0,100,0,105,0,116,0,46,0,115,0,102,0,46,0,
110,0,101,0,116,0,41,0,0,0,108,0,67,0,83,0,
121,0,109,0,98,0,111,0,108,0,115,0,0,0,82,0,
101,0,103,0,117,0,108,0,97,0,114,0,0,0,80,0,
102,0,97,0,69,0,100,0,105,0,116,0,32,0,49,0,
46,0,48,0,32,0,58,0,32,0,108,0,67,0,83,0,
121,0,109,0,98,0,111,0,108,0,115,0,32,0,58,0,
32,0,50,0,45,0,51,0,45,0,50,0,48,0,55,0,
50,0,0,0,108,0,67,0,83,0,121,0,109,0,98,0,
111,0,108,0,115,0,0,0,48,0,48,0,49,0,46,0,
48,0,48,0,48,0,0,0,108,0,67,0,83,0,121,0,
109,0,98,0,111,0,108,0,115,0,0,0,108,0,105,0,
103,0,110,0,117,0,109,0,67,0,65,0,68,0,32,0,
83,0,121,0,109,0,98,0,111,0,108,0,115,0,0,0,
108,0,105,0,103,0,110,0,117,0,109,0,32,0,67,0,
111,0,109,0,112,0,117,0,116,0,105,0,110,0,103,0,
44,0,32,0,73,0,110,0,99,0,46,0,0,0,119,0,
119,0,119,0,46,0,108,0,105,0,103,0,110,0,117,0,
109,0,99,0,111,0,109,0,112,0,117,0,116,0,105,0,
110,0,103,0,46,0,99,0,111,0,109,0,0,0,71,0,
80,0,76,0,0,0,104,0,116,0,116,0,112,0,58,0,
47,0,47,0,119,0,119,0,119,0,46,0,103,0,110,0,
117,0,46,0,111,0,114,0,103,0,0,0,0,2,0,0,
0,0,0,0,255,156,0,50,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,25,0,0,
0,1,0,2,1,2,1,3,1,4,1,5,1,6,1,7,
1,8,1,9,1,10,1,11,1,12,1,13,1,14,1,15,
1,16,1,17,1,18,1,19,1,20,1,21,1,22,1,23,
7,117,110,105,50,49,48,52,7,117,110,105,69,48,48,48,
7,117,110,105,69,48,48,49,7,117,110,105,69,48,48,50,
7,117,110,105,69,48,48,51,7,117,110,105,69,48,48,52,
7,117,110,105,69,48,48,53,7,117,110,105,69,48,48,54,
7,117,110,105,69,48,48,55,7,117,110,105,69,48,48,56,
7,117,110,105,69,48,48,57,7,117,110,105,69,48,48,65,
7,117,110,105,69,48,49,48,7,117,110,105,69,48,49,49,
7,117,110,105,69,48,49,50,7,117,110,105,69,48,49,51,
7,117,110,105,69,48,49,52,7,117,110,105,69,48,49,53,
7,117,110,105,69,48,49,54,7,117,110,105,69,48,49,55,
7,117,110,105,69,48,49,56,7,117,110,105,69,48,49,57,
};
const int lCSymbols_ttf_size = sizeof( lCSymbols_ttf );
Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

+378
View File
@@ -0,0 +1,378 @@
/*
* demo.cpp: Demo of the OGLFT library
* Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <GL/glut.h>
#include <OGLFT.h>
static const char* USAGE = " fontfile";
static const char* commands = "a/A: char rotate X, s/S: char rotate Y, d/D: char rotate Z, f/F: string rotate, r: reset all";
static const char* text = "The quick brown fox jumps over a lazy dog.";
static const float point_size = 16;
static OGLFT::Monochrome* commands_face;
static OGLFT::Monochrome* monochrome_face;
static OGLFT::Grayscale* grayscale_face;
static OGLFT::Translucent* translucent_face;
static OGLFT::Outline* outline_face;
static OGLFT::Filled* filled_face;
#ifndef OGLFT_NO_SOLID
static OGLFT::Solid* solid_face;
#else
static OGLFT::Monochrome* solid_face;
#endif
static OGLFT::MonochromeTexture* monochrome_texture_face;
static OGLFT::GrayscaleTexture* grayscale_texture_face;
static OGLFT::TranslucentTexture* translucent_texture_face;
static float dy;
static int viewport_width;
static int viewport_height;
static void init ( int /*argc*/, char* argv[] )
{
std::cout << glGetString( GL_VENDOR ) << " " << glGetString( GL_RENDERER ) << " "
<< glGetString( GL_VERSION ) << std::endl;
commands_face = new OGLFT::Monochrome( argv[1], point_size / 2. );
commands_face->setHorizontalJustification( OGLFT::Face::CENTER );
monochrome_face = new OGLFT::Monochrome( argv[1], point_size );
monochrome_face->setHorizontalJustification( OGLFT::Face::CENTER );
monochrome_face->setForegroundColor( 1., 0., 0., 1. );
if ( !monochrome_face->isValid() ) {
std::cerr << "failed to open face. exiting." << std::endl;
exit( 1 );
}
grayscale_face = new OGLFT::Grayscale( argv[1], point_size );
grayscale_face->setHorizontalJustification( OGLFT::Face::CENTER );
grayscale_face->setForegroundColor( 0., 0., .5, 1. );
grayscale_face->setBackgroundColor( 0., 1., 1., 1. );
translucent_face = new OGLFT::Translucent( argv[1], point_size );
translucent_face->setHorizontalJustification( OGLFT::Face::CENTER );
translucent_face->setForegroundColor( 0., .5, 0., 1. );
outline_face = new OGLFT::Outline( argv[1], point_size );
outline_face->setHorizontalJustification( OGLFT::Face::CENTER );
outline_face->setForegroundColor( 1., 1., 0., 1. );
filled_face = new OGLFT::Filled( argv[1], point_size );
filled_face->setHorizontalJustification( OGLFT::Face::CENTER );
filled_face->setForegroundColor( .5, 0., 1., 1. );
#ifndef OGLFT_NO_SOLID
solid_face = new OGLFT::Solid( argv[1], point_size );
solid_face->setDepth( 10. );
solid_face->setCharacterRotationX( 25. );
solid_face->setCharacterRotationY( 25. );
solid_face->setTessellationSteps( 3 );
#else
solid_face = new OGLFT::Monochrome( argv[1], point_size );
#endif
solid_face->setHorizontalJustification( OGLFT::Face::CENTER );
solid_face->setForegroundColor( 1., .5, 0., 1. );
monochrome_texture_face = new OGLFT::MonochromeTexture( argv[1], point_size );
monochrome_texture_face->setHorizontalJustification( OGLFT::Face::CENTER );
monochrome_texture_face->setForegroundColor( 0., .5, .75, 1. );
grayscale_texture_face = new OGLFT::GrayscaleTexture( argv[1], point_size );
grayscale_texture_face->setHorizontalJustification( OGLFT::Face::CENTER );
grayscale_texture_face->setForegroundColor( 0.9, .65, .9, 1. );
grayscale_texture_face->setBackgroundColor( 0.5, .5, .75, 0.3 );
translucent_texture_face = new OGLFT::TranslucentTexture( argv[1], point_size );
translucent_texture_face->setHorizontalJustification( OGLFT::Face::CENTER );
translucent_texture_face->setForegroundColor( 0.75, 1., .75, 1. );
// Set various general parameters which don't affect performance (yet).
glClearColor( .75, .75, .75, 1. );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
#if defined(GL_RASTER_POSITION_UNCLIPPED_IBM)
glEnable( GL_RASTER_POSITION_UNCLIPPED_IBM );
#endif
glEnable( GL_LIGHT0 );
glDisable( GL_DITHER );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
}
static void reshape ( int width, int height )
{
viewport_width = width;
viewport_height = height;
glViewport( 0, 0, viewport_width, viewport_height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, viewport_width, 0, viewport_height, -100, 100 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
dy = viewport_height / ( 9 + 1 );
}
static void reset ( void )
{
monochrome_face->setCharacterRotationZ( 0 );
monochrome_face->setStringRotation( 0 );
grayscale_face->setCharacterRotationZ( 0 );
grayscale_face->setStringRotation( 0 );
translucent_face->setCharacterRotationZ( 0 );
translucent_face->setStringRotation( 0 );
outline_face->setCharacterRotationX( 0 );
outline_face->setCharacterRotationY( 0 );
outline_face->setCharacterRotationZ( 0 );
outline_face->setStringRotation( 0 );
filled_face->setCharacterRotationX( 0 );
filled_face->setCharacterRotationY( 0 );
filled_face->setCharacterRotationZ( 0 );
filled_face->setStringRotation( 0 );
#ifndef OGLFT_NO_SOLID
solid_face->setCharacterRotationX( 25. );
solid_face->setCharacterRotationY( 25. );
#endif
solid_face->setCharacterRotationZ( 0 );
solid_face->setStringRotation( 0 );
monochrome_texture_face->setCharacterRotationX( 0 );
monochrome_texture_face->setCharacterRotationY( 0 );
monochrome_texture_face->setCharacterRotationZ( 0 );
monochrome_texture_face->setStringRotation( 0 );
grayscale_texture_face->setCharacterRotationX( 0 );
grayscale_texture_face->setCharacterRotationY( 0 );
grayscale_texture_face->setCharacterRotationZ( 0 );
grayscale_texture_face->setStringRotation( 0 );
translucent_texture_face->setCharacterRotationX( 0 );
translucent_texture_face->setCharacterRotationY( 0 );
translucent_texture_face->setCharacterRotationZ( 0 );
translucent_texture_face->setStringRotation( 0 );
glViewport( 0, 0, viewport_width, viewport_height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, viewport_width, 0, viewport_height, -100, 100 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
static void char_rotate_x ( float dx )
{
outline_face->setCharacterRotationX( outline_face->characterRotationX()+dx );
filled_face->setCharacterRotationX( filled_face->characterRotationX()+dx );
#ifndef OGLFT_NO_SOLID
solid_face->setCharacterRotationX( solid_face->characterRotationX()+dx );
#endif
monochrome_texture_face->setCharacterRotationX(
monochrome_texture_face->characterRotationX()+dx );
grayscale_texture_face->setCharacterRotationX(
grayscale_texture_face->characterRotationX()+dx );
translucent_texture_face->setCharacterRotationX(
translucent_texture_face->characterRotationX()+dx );
}
static void char_rotate_y ( float dy )
{
outline_face->setCharacterRotationY( outline_face->characterRotationY()+dy );
filled_face->setCharacterRotationY( filled_face->characterRotationY()+dy );
#ifndef OGLFT_NO_SOLID
solid_face->setCharacterRotationY( solid_face->characterRotationY()+dy );
#endif
monochrome_texture_face->setCharacterRotationY(
monochrome_texture_face->characterRotationY()+dy );
grayscale_texture_face->setCharacterRotationY(
grayscale_texture_face->characterRotationY()+dy );
translucent_texture_face->setCharacterRotationY(
translucent_texture_face->characterRotationY()+dy );
}
static void char_rotate_z ( float dz )
{
monochrome_face->setCharacterRotationZ( monochrome_face->characterRotationZ()+dz );
grayscale_face->setCharacterRotationZ( grayscale_face->characterRotationZ()+dz );
translucent_face->setCharacterRotationZ( translucent_face->characterRotationZ()+dz );
outline_face->setCharacterRotationZ( outline_face->characterRotationZ()+dz );
filled_face->setCharacterRotationZ( filled_face->characterRotationZ()+dz );
solid_face->setCharacterRotationZ( solid_face->characterRotationZ()+dz );
monochrome_texture_face->setCharacterRotationZ( monochrome_texture_face->characterRotationZ()+dz );
grayscale_texture_face->setCharacterRotationZ( grayscale_texture_face->characterRotationZ()+dz );
translucent_texture_face->setCharacterRotationZ( translucent_texture_face->characterRotationZ()+dz );
}
static void string_rotate ( float dz )
{
monochrome_face->setStringRotation( monochrome_face->stringRotation()+dz );
grayscale_face->setStringRotation( grayscale_face->stringRotation()+dz );
translucent_face->setStringRotation( translucent_face->stringRotation()+dz );
outline_face->setStringRotation( outline_face->stringRotation()+dz );
filled_face->setStringRotation( filled_face->stringRotation()+dz );
solid_face->setStringRotation( solid_face->stringRotation()+dz );
monochrome_texture_face->setStringRotation( monochrome_texture_face->stringRotation()+dz );
grayscale_texture_face->setStringRotation( grayscale_texture_face->stringRotation()+dz );
translucent_texture_face->setStringRotation( translucent_texture_face->stringRotation()+dz );
}
static void display ( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
// Draw everything centered
glTranslatef( viewport_width/2., 0., 0. );
commands_face->draw( 0., 0., commands );
glTranslatef( 0., dy, 0. );
monochrome_face->draw( 0., 0., text );
glTranslatef( 0., dy, 0. );
grayscale_face->draw( 0., 0., text );
glEnable( GL_BLEND );
glTranslatef( 0., dy, 0. );
translucent_face->draw( 0., 0., text );
glDisable( GL_BLEND );
glTranslatef( 0., dy, 0. );
outline_face->draw( 0., 0., text );
glTranslatef( 0., dy, 0. );
filled_face->draw( 0., 0., text );
glTranslatef( 0., dy, 0. );
#ifndef OGLFT_NO_SOLID
glEnable( GL_LIGHTING );
glEnable( GL_DEPTH_TEST );
glEnable( GL_COLOR_MATERIAL );
solid_face->draw( 0., 0., text );
glDisable( GL_COLOR_MATERIAL );
glDisable( GL_DEPTH_TEST );
glDisable( GL_LIGHTING );
#else
solid_face->draw( 0., 0., "<Note: Solid face not available in library>" );
#endif
glEnable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
glEnable( GL_DEPTH_TEST );
glTranslatef( 0., dy, 0. );
monochrome_texture_face->draw( 0., 0., text );
glTranslatef( 0., dy, 0. );
grayscale_texture_face->draw( 0., 0., text );
glTranslatef( 0., dy, 0. );
translucent_texture_face->draw( 0., 0., text );
glDisable( GL_DEPTH_TEST );
glDisable( GL_BLEND );
glDisable( GL_TEXTURE_2D );
glPopMatrix();
glutSwapBuffers();
}
static void key ( unsigned char key, int /*x*/, int /*y*/ )
{
switch ( key ) {
case 'a':
char_rotate_x( -4 ); break;
case 'A':
char_rotate_x( 4 ); break;
case 's':
char_rotate_y( -4 ); break;
case 'S':
char_rotate_y( 4 ); break;
case 'd':
char_rotate_z( -4 ); break;
case 'D':
char_rotate_z( 4 ); break;
case 'f':
string_rotate( -4 ); break;
case 'F':
string_rotate( 4 ); break;
case 'r': case 'R':
reset(); break;
case 27:
exit( 0 );
default:
return;
}
glutPostRedisplay();
}
static void done ( void )
{
delete monochrome_face;
delete grayscale_face;
delete translucent_face;
delete outline_face;
delete filled_face;
delete solid_face;
delete monochrome_texture_face;
delete grayscale_texture_face;
delete translucent_texture_face;
}
int main ( int argc, char* argv[] )
{
if ( argc != 2 ) {
std::cerr << argv[0] << USAGE << std::endl;
return 1;
}
glutInit( &argc, argv );
glutInitWindowSize( 500, 500 );
glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
glutCreateWindow( argv[0] );
init( argc, argv );
atexit( done );
glutReshapeFunc( reshape );
glutDisplayFunc( display );
glutKeyboardFunc( key );
glutMainLoop();
return 0;
}
+183
View File
@@ -0,0 +1,183 @@
/*
* demo2.cpp: Second Demo of the OGLFT library
* Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <iostream>
#include <GL/glut.h>
#include <OGLFT.h>
#include FT_MULTIPLE_MASTERS_H
static const char* USAGE = " fontfile";
static FT_Library library;
static FT_Face ft_face;
static FT_Multi_Master master_info;
static FT_Long axis_averages[T1_MAX_MM_AXIS];
#if 0
static OGLFT::Filled* oglft_face;
#else
static OGLFT::Monochrome* oglft_face;
#endif
static int viewport_width;
static int viewport_height;
static void init ( int /*argc*/, char* argv[] )
{
std::cout << glGetString( GL_VENDOR ) << " " << glGetString( GL_RENDERER ) << " "
<< glGetString( GL_VERSION ) << std::endl;
library = OGLFT::Library::instance();
FT_Error error;
error = FT_New_Face( library, argv[1], 0, &ft_face );
if ( error != 0 ) {
std::cerr << "Could not create a font from file \"" << argv[1] << "\""
<< std::endl;
exit( 1 );
}
error = FT_Get_Multi_Master( ft_face, &master_info );
if ( error != 0 ) {
std::cerr << "Font file \"" << argv[1]
<< "\" does not contain a multi master font" << std::endl;
exit( 1 );
}
for ( unsigned int i = 0; i < master_info.num_axis; i++ )
axis_averages[i] = ( master_info.axis[i].minimum +
master_info.axis[i].maximum ) / 2;
FT_Set_MM_Design_Coordinates( ft_face, master_info.num_axis, axis_averages );
#if 0
oglft_face = new OGLFT::Filled( ft_face, 14 );
#else
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glEnable( GL_RASTER_POSITION_UNCLIPPED_IBM );
oglft_face = new OGLFT::Monochrome( ft_face, 14 );
#endif
oglft_face->setHorizontalJustification( OGLFT::Face::LEFT );
oglft_face->setForegroundColor( 1., 0., 0. );
oglft_face->setCompileMode( OGLFT::Face::IMMEDIATE );
}
static void reshape ( int width, int height )
{
viewport_width = width;
viewport_height = height;
glViewport( 0, 0, viewport_width, viewport_height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, viewport_width, 0, viewport_height, -100, 100 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
static void display ( void )
{
const int BUFSIZE = 128;
char buffer[BUFSIZE];
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
snprintf( buffer, sizeof(buffer), "There are %d axes", master_info.num_axis );
GLfloat y = 480.;
oglft_face->draw( 0., y, buffer );
for ( unsigned int i = 0; i < master_info.num_axis; i++ ) {
FT_Set_MM_Design_Coordinates( ft_face, master_info.num_axis, axis_averages );
snprintf( buffer, sizeof(buffer), "%s: min: %ld max: %ld",
master_info.axis[i].name,
master_info.axis[i].minimum, master_info.axis[i].maximum );
y -= 20.;
oglft_face->draw( 0., y, buffer );
FT_Long axis_average = axis_averages[i];
FT_Long d_axis = (master_info.axis[i].maximum - master_info.axis[i].minimum)/4;
axis_averages[i] = master_info.axis[i].minimum;
for ( int j = 0; j <= 4; j++ ) {
FT_Set_MM_Design_Coordinates( ft_face, master_info.num_axis, axis_averages );
snprintf( buffer, sizeof(buffer), " Style at axis = %ld\n", axis_averages[i] );
y -= 20.;
oglft_face->draw( 0., y, buffer );
axis_averages[i] += d_axis;
}
axis_averages[i] = axis_average;
}
glPopMatrix();
glutSwapBuffers();
}
static void key ( unsigned char key, int /*x*/, int /*y*/ )
{
switch ( key ) {
case 'q':
case 27:
exit( 0 );
default:
return;
}
glutPostRedisplay();
}
static void done ( void )
{
}
int main ( int argc, char* argv[] )
{
if ( argc != 2 ) {
std::cerr << argv[0] << USAGE << std::endl;
return 1;
}
glutInit( &argc, argv );
glutInitWindowSize( 500, 500 );
glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
glutCreateWindow( argv[0] );
init( argc, argv );
atexit( done );
glutReshapeFunc( reshape );
glutDisplayFunc( display );
glutKeyboardFunc( key );
glutMainLoop();
return 0;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
/* -*- c++ -*-
* speedtest.h: Header for Performance test for the OGLFT library
* Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SPEEDTEST_H
#define SPEEDTEST_H
#include <stdlib.h>
#include <qgl.h>
#include <qqueue.h>
#include <qtimer.h>
// Little animation vignettes. The function calls essentially follow
// those of the Qt OpenGL widget and are called at the corresponding times.
struct Vignette {
virtual ~Vignette ( void ) {}
virtual unsigned int frame_count ( void ) = 0;
virtual void init ( void ) = 0;
virtual void view ( GLdouble /*left*/, GLdouble /*right*/,
GLdouble /*bottom*/, GLdouble /*top*/ )
{}
virtual void reset ( void )
{}
virtual bool input ( QKeyEvent* e )
{
if ( e->key() == Qt::Key_Escape ) exit( 0 );
return false;
}
virtual void draw ( int frame_number ) = 0;
virtual void finish ( void ) = 0;
};
// Yet another OpenGL view widget.
class CharacterView : public QGLWidget {
Q_OBJECT
GLsizei window_width_, window_height_;
GLdouble view_width_, view_height_;
GLdouble view_left_, view_right_, view_bottom_, view_top_;
GLdouble rot_x_, rot_y_, rot_z_;
QTimer redraw_timer_;
QTimer performance_timer_;
unsigned int frame_counter_;
unsigned int counter_snapshot_;
unsigned int animation_frame_count_;
unsigned int iteration_counter_;
unsigned int maximum_iterations_;
static const unsigned int PERFORMANCE_SAMPLE_RATE_HZ = 1;
static const unsigned int MAXIMUM_ITERATIONS = 4;
QQueue<Vignette> vignettes;
protected slots:
void redraw ( void );
void measure_performance ( void );
public:
CharacterView ( const char* text, const char* fontfile,
QWidget* parent = 0, const char* name = 0 );
protected:
void initializeGL ( void );
void resizeGL ( int w, int h );
void paintGL ( void );
void keyPressEvent ( QKeyEvent* e );
void resetView ( void );
};
#endif /* SPEEDTEST_H */
Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/perl
use strict;
# Convert the file given on the commandline into something which
# can be compiled with C and linked into an executable.
# Use the generated object module with the following declarations:
# extern unsigned char ${ARGV[0]}[]; /* Array of data */
# extern int ${ARGV[0]}_size; /* Size of array */
# Note, .'s in the argument filename are converted to _'s
open FILE, $ARGV[0] or die "usage: $0 file";
# "Slurp the whole file"
undef $/;
my $contents = <FILE>;
# Replace .'s in the filename with _'s (since . is an operator in C)
my $label = $ARGV[0];
$label =~ s/\./_/;
print "FT_Byte $label\[\] = {\n";
for ( my $i = 0; $i < length $contents; $i += 16 ) {
print join( ",", unpack( "C*", substr( $contents, $i, 16 ) ) ), ",\n";
}
print "};\n";
print "const int ${label}_size = sizeof( $label );\n";
@@ -0,0 +1,98 @@
/*
* tutorial1.cpp: Tutorial for the OGLFT library
* Copyright (C) 2002 lignum Computing, Inc. <oglft@lignumcomputing.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <iostream>
#include <GL/glut.h>
#include <OGLFT.h> // Note: this will depend on where you've installed OGLFT
// Declare a Face variable of the desired style
OGLFT::Monochrome* monochrome;
void init ( const char* filename )
{
// Create a new face given the font filename and a size
monochrome = new OGLFT::Monochrome( filename, 36 );
// Always check to make sure the face was properly constructed
if ( monochrome == 0 || !monochrome->isValid() ) {
std::cerr << "Could not construct face from " << filename << std::endl;
return;
}
// Set the face color to red
monochrome->setForegroundColor( 1., 0., 0. );
// For the raster styles, it is essential that the pixel store
// unpacking alignment be set to 1
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
// Set the window's background color
glClearColor( .75, .75, .75, 1. );
}
static void display ( void )
{
// First clear the window ...
glClear( GL_COLOR_BUFFER_BIT );
// ... then draw the string
monochrome->draw( 0., 250., "Hello, World!" );
}
static void reshape ( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, width, 0, height, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
int main ( int argc, char* argv[] )
{
// Check to be sure the user specified something as a font file name
if ( argc != 2 ) {
std::cerr << "usage: " << argv[0] << " fontfile" << std::endl;
return 1;
}
// Standard GLUT setup commands
glutInit( &argc, argv );
glutInitWindowSize( 500, 500 );
glutInitDisplayMode( GLUT_RGB ); // Note: OGLFT really only works in RGB mode
glutCreateWindow( argv[0] );
init( argv[1] );
glutReshapeFunc( reshape );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}

Some files were not shown because too many files have changed in this diff Show More