📄 glchartrenderer.cpp
字号:
/* GHelm - Nautical Navigation Software * Copyright (C) 2004 Jon Michaelchuck * * This application is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This software 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 software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */#include <iostream>#include <sstream>#include <math.h>#include "glchartrenderer.h"#include "util.h"#include "waypointdialog.h"/** * Constructor * @param glconf GL config to use */GLChartRenderer::GLChartRenderer(Glib::RefPtr<Gdk::GL::Config> glconf) : Gtk::GL::DrawingArea(glconf), glerror(GL_NO_ERROR), input_mode(PAN_MODE), left_mouse_button(false), last_x(0), last_y(0), pointer_x(0), pointer_y(0), pointer_lat(0), pointer_long(0), xsize(0), ysize(0), zoom(1), left_edge(0), bottom_edge(0), slat(-10800), wlon(-10800), nlat(10800), elon(10800), selection_rect_drawn(false), chart(NULL), configuration(NULL){ for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; j++) { selection_rect[i][j] = 0; } }}/** * Constructor * @param glconf GL config to use * @param cont GL sharing context to use */GLChartRenderer::GLChartRenderer(Glib::RefPtr<Gdk::GL::Config> glconf, Glib::RefPtr<Gdk::GL::Context> cont) : Gtk::GL::DrawingArea(glconf, cont, true), glerror(GL_NO_ERROR), input_mode(PAN_MODE), left_mouse_button(false), last_x(0), last_y(0), pointer_x(0), pointer_y(0), pointer_lat(0), pointer_long(0), xsize(0), ysize(0), zoom(1), left_edge(0), bottom_edge(0), slat(-10800), wlon(-10800), nlat(10800), elon(10800), selection_rect_drawn(false), chart(NULL), configuration(NULL){ for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; j++) { selection_rect[i][j] = 0; } }}/** * Destructor */GLChartRenderer::~GLChartRenderer(){}/** * Initialize the glspace. * @param conf Configuration to use * @return 0 on success, -1 on failure */int GLChartRenderer::Init(Configuration *conf){ configuration = conf; // We need to enable our events add_events(Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::SCROLL_MASK | Gdk::VISIBILITY_NOTIFY_MASK); signal_button_press_event().connect(sigc::mem_fun(*this, &GLChartRenderer::on_button_press_event)); signal_button_release_event().connect(sigc::mem_fun(*this, &GLChartRenderer::on_button_release_event)); signal_motion_notify_event().connect(sigc::mem_fun(*this, &GLChartRenderer::on_motion_notify_event)); signal_scroll_event().connect(sigc::mem_fun(*this, &GLChartRenderer::on_scroll_event)); //DEBUG glGenTextures(1, &texture); return 0;}/** * Set the current chart * @param ch Chart to load */void GLChartRenderer::SetChart(Chart *ch){ chart = ch; slat = chart->slat; wlon = chart->wlon; nlat = chart->nlat; elon = chart->elon; left_edge = wlon; bottom_edge = slat; if (left_edge >= 10800) left_edge = 10799; else if (left_edge <= -10800) left_edge = -10799; if (bottom_edge >= 10800) bottom_edge = 10799; else if (bottom_edge <= -10800) bottom_edge = -10799; double y = (nlat - slat); double x = (elon - wlon); double zoomy = ysize / y; double zoomx = xsize / x; if (zoomy > zoomx) zoom = zoomy; else zoom = zoomx; chart->absolute_zoom_factor = zoom; Render();}//// rendering///** * Render tick */void GLChartRenderer::Render(){ SetView(); Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window(); if (!glwindow->gl_begin(get_gl_context())) std::cerr << "GLChartRenderer::Render() unable to get GL context" << std::endl; glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glTranslatef(-left_edge, -bottom_edge, 0); if (chart) { chart->Draw(zoom, *configuration); std::vector<waypoint_t>::iterator it; std::vector<waypoint_t>::iterator end = chart->waypoints.end(); glPointSize(8); glColor3f(0,0,1); glBegin(GL_POINTS); for (it = chart->waypoints.begin(); it != end; ++it) glVertex2dv(it->longlat); glEnd(); glPointSize(1); } glPopMatrix(); glPushMatrix(); // draw a selection rectangle if we have one if (selection_rect_drawn) DrawSelectionRect(); glPopMatrix(); // check for a gl error if ((glerror = glGetError()) != GL_NO_ERROR) std::cerr << "GLChartRenderer::Render(): glError : " << gluErrorString(glerror) << std::endl; // swap buffers if (glwindow->is_double_buffered()) glwindow->swap_buffers(); else glFlush(); // end opengl mode glwindow->gl_end();}//DEBUG/TEST featurevoid GLChartRenderer::RenderToTexture(){ SetView(); Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window(); if (!glwindow->gl_begin(get_gl_context())) std::cerr << "GLChartRenderer::Render() unable to get GL context" << std::endl; glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glTranslatef(-left_edge, -bottom_edge, 0); if (chart) chart->Draw(zoom, *configuration); glPopMatrix(); glDrawBuffer(GL_FRONT); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_ch); glReadBuffer(GL_BACK); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 256, 256); glDrawBuffer(GL_FRONT); SetView(); glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2f(0, 0); glTexCoord2f(1,0); glVertex2f(100, 0); glTexCoord2f(1,1); glVertex2f(100, 100); glTexCoord2f(0,1); glVertex2f(0, 100); glEnd(); glDisable(GL_TEXTURE_2D); glDrawBuffer(GL_BACK); glwindow->gl_end();}//DEBUG/TEST featurevoid GLChartRenderer::AddWaypoint(double x, double y){ if (chart) { x /= zoom; y /= zoom; x += left_edge; y += bottom_edge; WaypointDialog waypoint_dialog; waypoint_t *waypoint = waypoint_dialog.Run(x, y); if (waypoint) { chart->waypoints.push_back(*waypoint); signal_add_waypoint.emit(waypoint); Render(); } }}/** * Draw the selection rectangle */void GLChartRenderer::DrawSelectionRect(){ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor4f(0,0,.2,.5); glBegin(GL_QUADS); glVertex2dv(selection_rect[0]); glVertex2dv(selection_rect[1]); glVertex2dv(selection_rect[2]); glVertex2dv(selection_rect[3]); glEnd(); glDisable(GL_BLEND); glColor3f(0,0,.5); glBegin(GL_LINE_LOOP); glVertex2dv(selection_rect[0]); glVertex2dv(selection_rect[1]); glVertex2dv(selection_rect[2]); glVertex2dv(selection_rect[3]); glEnd();}/** * Viewing transformation */void GLChartRenderer::SetView(){ Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window(); if (!glwindow->gl_begin(get_gl_context())) std::cerr << "GLChartRenderer::SetView() unable to get GL context" << std::endl; glMatrixMode(GL_PROJECTION); // the projection transformation glLoadIdentity(); glOrtho(0, xsize/zoom, 0, ysize/zoom, -1, 1); glMatrixMode(GL_MODELVIEW); // modelview glViewport(0, 0, xsize, ysize); // viewport glwindow->gl_end(); signal_set_view_rect.emit(left_edge, bottom_edge, xsize/zoom, ysize/zoom);}//// zooming and scrolling///** * Zoom on the render space * @param dir Direction to zoom (true = in, false = out) * @param mag Magnitude of zoom */void GLChartRenderer::Zoom(bool dir, float mag){ // we manage this such that when the user attempts // to zoom out in a way which would expose non-chart area we handle // it gracefully. This means either scrolling the contents of the // window or only allowing a smaller zoom (or no zoom at all) double old_zoom = zoom; double xfactor = xsize/pointer_x; double yfactor = ysize/pointer_y; if (dir) { zoom *= mag; left_edge += (xsize/old_zoom - xsize/zoom)/xfactor; bottom_edge += (ysize/old_zoom - ysize/zoom)/yfactor; } else { // first lets see if the zoom will bring us into territory // outside our boundaries. double new_zoom; double new_left_edge; double new_bottom_edge; new_zoom = zoom / mag; new_left_edge = left_edge + (xsize/old_zoom - xsize/new_zoom)/xfactor; new_bottom_edge = bottom_edge + (ysize/old_zoom - ysize/new_zoom)/yfactor; // first see if any of the new dimensions are larger than the // chart. if so we just do a full zoom out. if (((new_bottom_edge + ysize/new_zoom) - (new_bottom_edge)) > (nlat - slat)) { bottom_edge = slat; double y = nlat - slat; double x = xsize/new_zoom; double zoomy = ysize / y; double zoomx = xsize / x; if (zoomy > zoomx) zoom = zoomy; else zoom = zoomx; } else if ((((new_left_edge + xsize/new_zoom) - (new_left_edge)) > (elon - wlon))) { left_edge = wlon; double x = elon - wlon; double y = ysize/new_zoom; double zoomy = ysize / y; double zoomx = xsize / x; if (zoomy > zoomx) zoom = zoomy; else zoom = zoomx; } else { // check if after the zoom we need to pan if (new_left_edge < wlon) left_edge = wlon; else if ((new_left_edge + xsize/new_zoom) > elon) left_edge = elon - xsize/new_zoom; else left_edge = new_left_edge; if (new_bottom_edge < slat) bottom_edge = slat; else if ((new_bottom_edge + ysize/new_zoom) > nlat) bottom_edge = nlat - ysize/new_zoom; else bottom_edge = new_bottom_edge; zoom = new_zoom; } } Render();}/** * Zoom to fit */void GLChartRenderer::ZoomFit(){ // FIXME this doesn't center correctly. if (chart) SetChart(chart);}/** * Scroll about the render space * @param x x component to scroll * @param y y component to scroll */void GLChartRenderer::Scroll(gdouble x, gdouble y){ // disallow scrolling beyond lat/long double newy = bottom_edge + y/zoom;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -