#include "ViewBase.h" #include "ModelBase.h" #include "ControllerBase.h" #include "CameraBase.h" #include "OverlayBase.h" #include "SimpleConsoleOverlay.h" #include "OGLFT.h" #include #include #include "OBJModel.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); // Initialize GLEW and check for anything we need GLenum err = glewInit(); if (GLEW_OK != err) { LogError ("Could not init GLEW properly: %s", glewGetErrorString(err)); } LogDebug ("Using GLEW version %s", glewGetString(GLEW_VERSION)); if (glewIsExtensionSupported("GL_ARB_vertex_buffer_object")) { } else { LogError ("VBOs are not supported!"); } // read OpenGL version std::string gl_version (reinterpret_cast(glGetString(GL_VERSION))); if (gl_version.size() == 0) LogError ("Could not retrieve GL version!"); std::string major_number_str = gl_version.substr(0, gl_version.find('.')); std::string minor_number_str = gl_version.substr(major_number_str.size() + 1, gl_version.find_first_of(". ", major_number_str.size())); mGLVersionInfo.GLMajor = atoi (major_number_str.c_str()); mGLVersionInfo.GLMinor = atoi (minor_number_str.c_str()); // read GLSL version std::string glsl_version (reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION))); if (glsl_version.size() == 0) LogError ("Could not retrieve GLSL version!"); major_number_str = glsl_version.substr(0, glsl_version.find('.')); minor_number_str = glsl_version.substr(major_number_str.size() + 1, glsl_version.find_first_of(". ", major_number_str.size())); mGLVersionInfo.GLSLMajor = atoi (major_number_str.c_str()); mGLVersionInfo.GLSLMinor = atoi (minor_number_str.c_str()); LogMessage ("GL Version = %s, gl_major = %d, gl_minor = %d", gl_version.c_str(), mGLVersionInfo.GLMajor, mGLVersionInfo.GLMinor); LogMessage ("GLSL Version = %s, gl_major = %d, gl_minor = %d", gl_version.c_str(), mGLVersionInfo.GLSLMajor, mGLVersionInfo.GLSLMinor); if (mGLVersionInfo.GLMajor >= 2 && mGLVersionInfo.GLMinor >= 0) mUseShaders = true; else mUseShaders = false; // load the shaders if possible if (mUseShaders) { mBlinnPhongShader = LoadShaderProgram (GetResourceFullPath("/data/shaders/blinn_phong.glsl")); mNormalMappingShader = LoadShaderProgram (GetResourceFullPath("/data/shaders/normal_mapping.glsl")); } else { mBlinnPhongShader = 0; mNormalMappingShader = 0; } // Create a null texture that can be used for objects without textures // taken from http://www.dhpoware.com/demos/glslNormalMapping.html int pitch = ((2 * 32 + 31) & ~31) >> 3; // align to 4-byte boundaries std::vector pixels(pitch * 2, 255); mNullTexture = 0; glGenTextures(1, &mNullTexture); glBindTexture(GL_TEXTURE_2D, mNullTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_BGRA, GL_UNSIGNED_BYTE, &pixels[0]); // Load fonts etc. 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! (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(font_spec_string, font)); LogDebug ("Loading font %s successful!", font_name.c_str()); 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); 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_); } GLuint ViewBase::LoadTextureFromPNG (const std::string &filename) { std::map::iterator texture_iterator = mGLTextures.find(filename); if (texture_iterator != mGLTextures.end()) { return texture_iterator->second; } Sprite temp_sprite; temp_sprite.LoadFromPNG (filename.c_str()); // register the texture in the View mGLTextures[filename] = temp_sprite.GetGLTextureName(); return temp_sprite.GetGLTextureName(); } /* * OBJModel loading and drawing */ OBJModelPtr ViewBase::LoadOBJModel (const std::string &model_filename) { LogDebug ("Loading OBJ model %s", model_filename.c_str()); OBJModelPtr result_model (new OBJModel); if(!result_model->import (model_filename.c_str(), true)) { LogError("Could not load model %s", model_filename.c_str()); return result_model; } result_model->normalize(); result_model->reverseWinding(); // Load any associated textures. // Note the path where the textures are assumed to be located. const OBJModel::Material *pMaterial = 0; GLuint textureId = 0; std::string::size_type offset = 0; std::string filename; for (int i = 0; i < result_model->getNumberOfMaterials(); ++i) { pMaterial = &result_model->getMaterial(i); // Look for and load any diffuse color map textures. if (!pMaterial->colorMapFilename.empty()) { // Try load the texture using the path in the .MTL file. textureId = LoadTextureFromPNG(pMaterial->colorMapFilename.c_str()); if (!textureId) { offset = pMaterial->colorMapFilename.find_last_of('\\'); if (offset != std::string::npos) filename = pMaterial->colorMapFilename.substr(++offset); else filename = pMaterial->colorMapFilename; // Try loading the texture from the same directory as the OBJ file. textureId = LoadTextureFromPNG((filename).c_str()); } } else { LogMessage ("No diffuse color map found!"); } // Look for and load any normal map textures. if (!pMaterial->bumpMapFilename.empty()) { // Try load the texture using the path in the .MTL file. textureId = LoadTextureFromPNG((pMaterial->bumpMapFilename).c_str()); if (!textureId) { offset = pMaterial->bumpMapFilename.find_last_of('\\'); if (offset != std::string::npos) filename = pMaterial->bumpMapFilename.substr(++offset); else filename = pMaterial->bumpMapFilename; // Try loading the texture from the same directory as the OBJ file. textureId = LoadTextureFromPNG((result_model->getPath() + filename).c_str()); } } else { LogMessage ("Material has no bumpmap!"); continue; } } // Update the window caption. LogMessage ("Loaded model %s successful, dimensions (whl): %f, %f, %f meshes %d vertices %d triangles: %d", model_filename.c_str(), result_model->getWidth(), result_model->getHeight(), result_model->getLength(), result_model->getNumberOfMeshes(), result_model->getNumberOfVertices(), result_model->getNumberOfTriangles() ); return result_model; } void ViewBase::DrawOBJModel (OBJModelPtr obj_model) { if (mUseShaders) { DrawOBJModelShaded(obj_model); } else { DrawOBJModelSolid (obj_model); } } void ViewBase::DrawOBJModelSolid (OBJModelPtr obj_model) { const OBJModel::Mesh *pMesh = 0; const OBJModel::Material *pMaterial = 0; const OBJModel::Vertex *pVertices = 0; std::map::const_iterator iter; for (int i = 0; i < obj_model->getNumberOfMeshes(); ++i) { pMesh = &obj_model->getMesh(i); pMaterial = pMesh->pMaterial; pVertices = obj_model->getVertexBuffer(); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pMaterial->ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pMaterial->diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, pMaterial->specular); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pMaterial->shininess * 128.0f); if (pMaterial->colorMapFilename.size() > 0) { iter = mGLTextures.find(pMaterial->colorMapFilename); if (iter == mGLTextures.end()) { LogError ("Could not find required colormap '%s'", pMaterial->colorMapFilename.c_str()); glDisable(GL_TEXTURE_2D); } else { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, iter->second); } } else { glDisable(GL_TEXTURE_2D); } if (obj_model->hasPositions()) { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->position); } if (obj_model->hasTextureCoords()) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->texCoord); } if (obj_model->hasNormals()) { glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->normal); } glDrawElements(GL_TRIANGLES, pMesh->triangleCount * 3, GL_UNSIGNED_INT, obj_model->getIndexBuffer() + pMesh->startIndex); if (obj_model->hasNormals()) glDisableClientState(GL_NORMAL_ARRAY); if (obj_model->hasTextureCoords()) glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (obj_model->hasPositions()) glDisableClientState(GL_VERTEX_ARRAY); // disable texture drawing if active if (pMaterial->colorMapFilename.size() > 0) glDisable(GL_TEXTURE_2D); } } void ViewBase::DrawOBJModelShaded (OBJModelPtr obj_model) { const OBJModel::Mesh *pMesh = 0; const OBJModel::Material *pMaterial = 0; const OBJModel::Vertex *pVertices = 0; std::map::const_iterator iter; GLuint texture = 0; for (int i = 0; i < obj_model->getNumberOfMeshes(); ++i) { pMesh = &obj_model->getMesh(i); pMaterial = pMesh->pMaterial; pVertices = obj_model->getVertexBuffer(); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pMaterial->ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pMaterial->diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, pMaterial->specular); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pMaterial->shininess * 128.0f); // if there is no bumpmap we will simply use a blinn phong shader and draw // the color map onto our model if (pMaterial->bumpMapFilename.empty()) { // LogMessage ("using Blinn Phong shader"); // Per fragment Blinn-Phong code path. glUseProgram(mBlinnPhongShader); // Bind the color map texture. texture = mNullTexture; if (pMaterial->colorMapFilename.size() > 0) { iter = mGLTextures.find(pMaterial->colorMapFilename); if (iter != mGLTextures.end()) texture = iter->second; } else { // LogMessage ("Disabling textures"); } glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); // Update shader parameters. assert (glIsProgram (mBlinnPhongShader) == GL_TRUE); assert (glGetUniformLocation(mBlinnPhongShader, "materialAlpha") != -1); assert (glGetUniformLocation(mBlinnPhongShader, "colorMap") != -1); glUniform1i(glGetUniformLocation( mBlinnPhongShader, "colorMap"), 0); glUniform1f(glGetUniformLocation( mBlinnPhongShader, "materialAlpha"), pMaterial->alpha); } else { // if there is a bumpmap we use both the bump map and the color map and // apply it on our model // LogMessage ("using Normal Mapping Shader"); // Normal mapping code path. glUseProgram(mNormalMappingShader); // Bind the normal map texture. iter = mGLTextures.find(pMaterial->bumpMapFilename); if (iter != mGLTextures.end()) { texture = iter->second; glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); } else { LogError ("bumpmap %s not found", pMaterial->bumpMapFilename.c_str()); } // Bind the color map texture. texture = mNullTexture; if (pMaterial->colorMapFilename.size() > 0) { iter = mGLTextures.find(pMaterial->colorMapFilename); if (iter != mGLTextures.end()) { texture = iter->second; } else { LogError ("color map %s not found", pMaterial->colorMapFilename.c_str()); } } glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); // Update shader parameters. assert (glGetUniformLocation(mNormalMappingShader, "colorMap") != -1); assert (glGetUniformLocation(mNormalMappingShader, "normalMap") != -1); assert (glGetUniformLocation(mNormalMappingShader, "materialAlpha") != -1); glUniform1i(glGetUniformLocation( mNormalMappingShader, "colorMap"), 0); glUniform1i(glGetUniformLocation( mNormalMappingShader, "normalMap"), 1); glUniform1f(glGetUniformLocation( mNormalMappingShader, "materialAlpha"), pMaterial->alpha); } // Render mesh. if (obj_model->hasPositions()) { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->position); } if (obj_model->hasTextureCoords()) { glClientActiveTexture(GL_TEXTURE0); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->texCoord); } if (obj_model->hasNormals()) { glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->normal); } if (obj_model->hasTangents()) { glClientActiveTexture(GL_TEXTURE1); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, obj_model->getVertexSize(), obj_model->getVertexBuffer()->tangent); } glDrawElements(GL_TRIANGLES, pMesh->triangleCount * 3, GL_UNSIGNED_INT, obj_model->getIndexBuffer() + pMesh->startIndex); if (obj_model->hasTangents()) { glClientActiveTexture(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (obj_model->hasNormals()) glDisableClientState(GL_NORMAL_ARRAY); if (obj_model->hasTextureCoords()) { glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (obj_model->hasPositions()) glDisableClientState(GL_VERTEX_ARRAY); } // as we might be using multiple textures (at least for the normal mapping // case) we have to disable both textures glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glUseProgram(0); } /* * Shader loading, compiling, linking */ /** Compiles a shader program * * This function contains code mainly taken from dhpowares excellent * objviewer example (see http://www.dhpoware.com/demos/gl3NormalMapping.html ). */ GLuint ViewBase::CompileShader (GLenum type, const GLchar *source, GLint length) { GLuint shader = glCreateShader(type); if (shader) { GLint compiled = 0; glShaderSource (shader, 1, &source, &length); glCompileShader(shader); glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLsizei info_log_size = 0; std::string info_log; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_size); info_log.resize (info_log_size); glGetShaderInfoLog (shader, info_log_size, &info_log_size, &info_log[0]); LogError ("Error compiling shader: %s", info_log.c_str()); } } return shader; } /** Links the given shader programs * * This function contains code mainly taken from dhpowares excellent * objviewer example (see http://www.dhpoware.com/demos/gl3NormalMapping.html ). */ GLuint ViewBase::LinkShaders (GLuint vertex_shader, GLuint fragment_shader) { GLuint program = glCreateProgram(); if (program) { GLint linked = 0; if (vertex_shader) glAttachShader (program, vertex_shader); if (fragment_shader) glAttachShader (program, fragment_shader); glLinkProgram (program); glGetProgramiv (program, GL_LINK_STATUS, &linked); if (!linked) { GLsizei info_log_size = 0; std::string info_log; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_size); info_log.resize (info_log_size); glGetProgramInfoLog (program, info_log_size, &info_log_size, &info_log[0]); LogError ("Error linking shaders vert: %d, frag: %d", vertex_shader, fragment_shader); } if (vertex_shader) glDeleteShader (vertex_shader); if (fragment_shader) glDeleteShader (fragment_shader); } return program; } /** Loads a vertex or fragment shader program * * This function contains code mainly taken from dhpowares excellent * objviewer example (see http://www.dhpoware.com/demos/gl3NormalMapping.html ). */ GLuint ViewBase::LoadShaderProgram (const std::string &filename) { LogDebug ("Loading shader program %s", filename.c_str()); std::ifstream program_file (filename.c_str()); if (!program_file) { LogError ("Could not open file '%s' while loading shader program", filename.c_str()); } // read the whole file into a string std::string shader_program ((std::istreambuf_iterator(program_file)), std::istreambuf_iterator()); program_file.close(); GLuint program = 0; if (shader_program.size() > 0) { const GLchar *source; GLint length = 0; GLuint vertex_shader = 0; GLuint fragment_shader = 0; std::string::size_type vertex_shader_offset = shader_program.find("[vert]"); std::string::size_type fragment_shader_offset = shader_program.find("[frag]"); if (vertex_shader_offset != std::string::npos) { // skip over the [vert] tag vertex_shader_offset += 6; source = reinterpret_cast (&shader_program[vertex_shader_offset]); length = static_cast(fragment_shader_offset - vertex_shader_offset); vertex_shader = CompileShader (GL_VERTEX_SHADER, source, length); LogMessage ("Compiled vertex shader with id %d", vertex_shader); } if (fragment_shader_offset != std::string::npos) { // skip over the [vert] tag fragment_shader_offset += 6; source = reinterpret_cast (&shader_program[fragment_shader_offset]); length = static_cast(shader_program.length() - fragment_shader_offset - 1); fragment_shader = CompileShader (GL_FRAGMENT_SHADER, source, length); LogMessage ("Compiled fragment shader with id %d", fragment_shader); } program = LinkShaders (vertex_shader, fragment_shader); LogMessage ("Successfully linked shaders vert: %d frag: %d from file %s into program %d", vertex_shader, fragment_shader, filename.c_str(), program); } mShaderPrograms[filename] = program; return program; } /* * Camera and other auxillary functions */ 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., 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); } 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 (); } }