#include "ViewBase.h" #include "ModelBase.h" #include "ControllerBase.h" #include "CameraBase.h" #include "OverlayBase.h" #include "SimpleConsoleOverlay.h" #include "OGLFT.h" #include #include #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::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(num) / 255.; istr.clear(); istr.str(value.substr(3,2)); istr >> std::hex >> num; font_color[1] = static_cast(num) / 255.; istr.clear(); istr.str(value.substr(5,2)); istr >> std::hex >> num; font_color[2] = static_cast(num) / 255.; } pos = next_end; } } bool ViewBase::LoadFont (const std::string &font_spec_string) { // font_spec_string can be of the form // (name=) (color=) (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!", font_path.c_str()); 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(font_spec_string, font)); return true; } void ViewBase::SelectFont (const char *font) { std::map::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); LogDebug ("font count = %d", mFonts.size()); 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); } 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 (width); mWindowHeight = static_cast (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::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::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::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::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); } unsigned int GetWindowWidth() { return ViewInstance->GetWindowWidth (); } unsigned int GetWindowHeight() { return ViewInstance->GetWindowHeight (); } int GetFrameRate () { return ViewInstance->GetFrameRate (); } }