fysxasteroids/engine/ViewBase.cc

544 lines
13 KiB
C++

#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_LEQUAL);
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;
// get and save the screen resolution
mScreenHeight = SDL_GetVideoInfo()->current_h;
mScreenWidth = SDL_GetVideoInfo()->current_w;
mDrawFullscreen = false;
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, SDL_OPENGL ) == 0 ) {
LogError ("Video mode set failed: %s", SDL_GetError ());
exit (-1);
}
LogMessage ("Resolution is %dx%d", SDL_GetVideoInfo()->current_w, SDL_GetVideoInfo()->current_h);
InitGL ();
Resize (mWindowWidth, mWindowHeight);
LoadFont ("console.ttf");
mCurrentFont = mFonts["console.ttf"];
// Overlays
OverlayBasePtr console_overlay(new SimpleConsoleOverlay);
mOverlayManager.Register (console_overlay, 0);
//AddOverlay (console_overlay);
mDrawGrid = false;
mGridSizeX = 8;
mGridSizeZ = 8;
ViewInstance = this;
return 0;
}
void ViewBase::OnDestroy () {
std::map<std::string, OGLFT::Monochrome*>::iterator iter;
for (iter = mFonts.begin(); iter != mFonts.end(); ++iter) {
delete iter->second;
}
mFonts.clear();
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::PreDraw() {
// 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;
}
}
void ViewBase::Draw () {
// Perform pre-Draw actions
PreDraw ();
// Actual Drawing
UpdateCamera ();
if (mDrawGrid)
DrawGrid ();
DrawWorld ();
mOverlayManager.Draw();
// Perform post-Draw actions
PostDraw();
}
void ViewBase::PostDraw() {
SDL_GL_SwapBuffers ();
}
void ViewBase::SetFullscreen (bool fullscreen) {
if (fullscreen && mDrawFullscreen)
return;
if (!fullscreen && !mDrawFullscreen)
return;
if (mDrawFullscreen) {
mWindowHeight = VIEW_DEFAULT_HEIGHT;
mWindowWidth = VIEW_DEFAULT_WIDTH;
mDrawFullscreen = false;
} else {
mWindowWidth = mScreenWidth;
mWindowHeight = mScreenHeight;
mDrawFullscreen = true;
}
Resize (mWindowWidth, mWindowHeight);
}
/* Fonts */
/** \brief Parses font specifications strings into its values
*
* Fonts can be specified by strings such as
* name=default.ttf color=#ff0000 size=12
* color=#ff00ff size=12 otherfont.ttf
* myfont.ttf
* for which the appropriate values will be parsed. Default size is 12 and
* default color is white (#ffffff)
*/
void parse_font_spec_string (const std::string &spec_string,
std::string &font_name,
float font_color[3],
float *font_size) {
// set default values
font_name = "default.ttf";
font_color[0] = 1.f;
font_color[1] = 1.f;
font_color[2] = 1.f;
*font_size = 12.f;
// perform the actual parsing
std::string::size_type pos = 0;
while (pos < spec_string.size()) {
std::string::size_type next_start = spec_string.find_first_not_of(" \t", pos);
// if we don't find anything we break out of this loop
if (next_start == std::string::npos)
break;
// find the next token
std::string::size_type next_end = spec_string.find_first_of("\t ", next_start);
std::string token (spec_string.substr(next_start, next_end - next_start));
// If no id was given it is automatically set to name
std::string id("name");
std::string value(token);
// Split the token into id and value if there is an '=' sign.
if (token.find('=', 0) != std::string::npos) {
id = token.substr(0, token.find('=',0));
value = token.substr(id.size() + 1, token.size());
}
// std::cout << "id = " << id << " value = " << value << std::endl;
if (id == "name")
font_name = value;
else if (id == "size") {
std::istringstream istr(value);
istr >> *font_size;
} else if (id == "color") {
// we assume #RRGGBB specification
if (value[0] != '#' || value.size() != 7)
LogError ("Invalid font color specification '%s'. Please specify as #rrggbb!", value.c_str());
// convert the color string to float values
int num;
std::istringstream istr(value.substr(1, 2));
istr >> std::hex >> num;
font_color[0] = static_cast<float>(num) / 255.;
istr.clear();
istr.str(value.substr(3,2));
istr >> std::hex >> num;
font_color[1] = static_cast<float>(num) / 255.;
istr.clear();
istr.str(value.substr(5,2));
istr >> std::hex >> num;
font_color[2] = static_cast<float>(num) / 255.;
}
pos = next_end;
}
}
bool ViewBase::LoadFont (const std::string &font_spec_string) {
// font_spec_string can be of the form
// (name=)<name> (color=<color>) (size=<size>)
std::string font_name;
float font_size = 12.;
float font_color[3] = {1., 1., 1.};
parse_font_spec_string(font_spec_string, font_name, font_color, &font_size);
std::string font_path (GetResourceFullPath("/data/fonts/"));
font_path += font_name;
LogDebug ("Loading font %s color (%1.2f, %1.2f, %1.2f) size %f from %s", font_name.c_str(), font_color[0], font_color[1], font_color[2], font_size, font_path.c_str());
OGLFT::Monochrome *font = new OGLFT::Monochrome (font_path.c_str(), font_size);
if ( font == 0 || !font->isValid() ) {
LogError ("Could not load font %s! (ptr=%x", font_path.c_str(), (void*)font);
return false;
}
font->setForegroundColor(font_color[0], font_color[1], font_color[2], 1.);
font->setBackgroundColor(0., 0., 0., 0.);
mFonts.insert(std::make_pair<std::string, OGLFT::Monochrome*>(font_spec_string, font));
LogDebug ("Loading font %s successful!", font_name.c_str());
return true;
}
void ViewBase::SelectFont (const char *font) {
std::map<std::string, OGLFT::Monochrome*>::iterator font_iter;
font_iter = mFonts.find(font);
if (font_iter != mFonts.end()) {
mCurrentFont = font_iter->second;
return;
}
LogDebug ("Selecting font %s failed, trying to load it", font);
if (LoadFont (font)) {
LogDebug ("font count = %d", mFonts.size());
font_iter = mFonts.find(font);
assert (mFonts.find(font) != mFonts.end());
mCurrentFont = font_iter->second;
return;
}
LogError("Error trying to load font %s", font);
}
float ViewBase::GetCurrentFontSize() {
if (mCurrentFont == NULL) {
LogError ("Could not get current font size: no font selected!");
return 0.;
}
return mCurrentFont->pointSize();
}
void ViewBase::SetFontJustification (FontJustification justification) {
assert (mCurrentFont != NULL);
if (justification == FontJustificationRight)
mCurrentFont->setHorizontalJustification(OGLFT::Face::RIGHT);
else if (justification == FontJustificationCenter)
mCurrentFont->setHorizontalJustification(OGLFT::Face::CENTER);
else mCurrentFont->setHorizontalJustification(OGLFT::Face::LEFT);
}
void ViewBase::DrawGLString (float x, float y, const char* str) {
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
mCurrentFont->draw (x, y, str);
}
void ViewBase::DrawGLStringMeasure (const char* str, float *width, float *height) {
OGLFT::BBox bbox = mCurrentFont->measure (str);
*width = bbox.x_max_ - bbox.x_min_;
*height = bbox.y_max_ - bbox.y_min_;
// LogDebug ("measure bbox '%s' = %f,%f %f,%f",str, bbox.x_min_, bbox.y_min_, bbox.x_max_, bbox.y_max_);
}
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 (0.8, 0.8, 0.8);
glLineWidth(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
*/
Uint32 video_flags = SDL_OPENGL;
if (mDrawFullscreen)
video_flags = video_flags | SDL_FULLSCREEN;
if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, video_flags) == 0 ) {
LogError ("Video mode set failed: %s", SDL_GetError ());
exit (-1);
}
}
/*
bool ViewBase::SendKeyDown (const SDL_keysym &keysym) {
std::vector<OverlayBasePtr>::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<OverlayBasePtr>::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<OverlayBasePtr>::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<OverlayBasePtr>::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);
}
void SelectFont (const char* font) {
if (!ViewInstance) {
LogError ("Cannot select font: View not yet initialized!");
return;
}
ViewInstance->SelectFont(font);
}
void SetFontJustification (FontJustification justification) {
if (!ViewInstance) {
LogError ("Cannot select font: View not yet initialized!");
return;
}
ViewInstance->SetFontJustification (justification);
}
float GetCurrentFontSize() {
if (!ViewInstance) {
LogError ("Cannot get font size: View not yet initialized!");
return 0.;
}
return ViewInstance->GetCurrentFontSize();
}
unsigned int GetWindowWidth() {
return ViewInstance->GetWindowWidth ();
}
unsigned int GetWindowHeight() {
return ViewInstance->GetWindowHeight ();
}
int GetFrameRate () {
return ViewInstance->GetFrameRate ();
}
}