NCBI C++ ToolKit
cn3d_glcanvas.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: cn3d_glcanvas.cpp 92488 2021-01-26 18:35:08Z grichenk $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Paul Thiessen
27 *
28 * File Description:
29 * OpenGL canvas object
30 *
31 * ===========================================================================
32 */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbistd.hpp>
36 
37 #include <memory>
38 
40 
41 #include <wx/fontutil.h>
42 #include <wx/image.h>
43 
44 #include "cn3d_glcanvas.hpp"
45 #include "opengl_renderer.hpp"
46 #include "cn3d_tools.hpp"
47 #include "structure_set.hpp"
48 
51 
52 
53 BEGIN_SCOPE(Cn3D)
54 
55 BEGIN_EVENT_TABLE(Cn3DGLCanvas, wxGLCanvas)
56  EVT_SIZE (Cn3DGLCanvas::OnSize)
57  EVT_PAINT (Cn3DGLCanvas::OnPaint)
58  EVT_MOUSE_EVENTS (Cn3DGLCanvas::OnMouseEvent)
59  EVT_ERASE_BACKGROUND (Cn3DGLCanvas::OnEraseBackground)
61 
62 Cn3DGLCanvas::Cn3DGLCanvas(wxWindow *parent, int *attribList) :
63  wxGLCanvas(parent, -1, attribList, wxPoint(0, 0), wxDefaultSize, wxSUNKEN_BORDER, "Cn3DGLCanvas"),
64  structureSet(NULL), suspended(false)
65 {
66  glContext = new wxGLContext(this);
67  renderer = new OpenGLRenderer(this);
68 }
69 
71 {
72  if (structureSet) delete structureSet;
73  delete renderer;
74  delete glContext;
75 }
76 
78 {
79  wxGLCanvas::SetCurrent(*glContext);
80 }
81 
83 {
84  suspended = suspend;
85  if (!suspend) {
86  wxSizeEvent resize(GetSize());
87  OnSize(resize);
88  }
89 }
90 
92 {
93  // get font info from registry, and create wxFont
94  string nativeFont;
96  {
97  ERRORMSG("Cn3DGLCanvas::SetGLFontFromRegistry() - error getting font info from registry");
98  return;
99  }
100 
101  // create new font - assignment uses object reference to copy
102  wxNativeFontInfo fontInfo;
103  if (!fontInfo.FromString(nativeFont.c_str())) {
104  ERRORMSG("Cn3DGLCanvas::SetGLFontFromRegistry() - can't set wxNativeFontInfo fron native font string");
105  return;
106  }
107  if (fontScale != 1.0 && fontScale > 0.0)
108  fontInfo.SetPointSize((int)(fontScale * fontInfo.GetPointSize()));
109  unique_ptr<wxFont> newFont(wxFont::New(fontInfo));
110  if (!newFont.get() || !newFont->Ok()) {
111  ERRORMSG("Cn3DGLCanvas::SetGLFontFromRegistry() - can't get wxFont from wxNativeFontInfo");
112  return;
113  }
114  font = *newFont; // copy font
115 
116  // set up font display lists in dc and renderer
117  if (!memoryDC.
118 #if wxCHECK_VERSION(2,9,0)
119  IsOk()
120 #else
121  Ok()
122 #endif
123  ) {
124  wxBitmap tinyBitmap(1, 1, -1);
125  memoryBitmap = tinyBitmap; // copies by reference
126  memoryDC.SelectObject(memoryBitmap);
127  }
128  memoryDC.SetFont(font);
129 
131 }
132 
133 #define MYMAX(a, b) (((a) >= (b)) ? (a) : (b))
134 
135 bool Cn3DGLCanvas::MeasureText(const string& text, int *width, int *height, int *centerX, int *centerY)
136 {
137  wxCoord w, h;
138  memoryDC.GetTextExtent(text.c_str(), &w, &h);
139  *width = (int) w;
140  *height = (int) h;
141 
142  // GetTextExtent measures text+background when a character is drawn, but for OpenGL, we need
143  // to measure actual character pixels more precisely: render characters into memory bitmap,
144  // then find the minimal rect that contains actual character pixels, not text background
145  if (memoryBitmap.GetWidth() < w || memoryBitmap.GetHeight() < h) {
146  wxBitmap biggerBitmap(MYMAX(memoryBitmap.GetWidth(), w), MYMAX(memoryBitmap.GetHeight(), h), -1);
147  memoryBitmap = biggerBitmap; // copies by reference
148  memoryDC.SelectObject(memoryBitmap);
149  }
150  memoryDC.SetBackground(*wxBLUE_BRUSH);
151  memoryDC.SetBackgroundMode(wxSOLID);
152  memoryDC.SetTextBackground(*wxGREEN);
153  memoryDC.SetTextForeground(*wxRED);
154 
155 // memoryDC.BeginDrawing();
156  memoryDC.Clear();
157  memoryDC.DrawText(text.c_str(), 0, 0);
158 // memoryDC.EndDrawing();
159 
160  // then convert bitmap to image so that we can read individual pixels (ugh...)
161  wxImage image(memoryBitmap.ConvertToImage());
162 // wxInitAllImageHandlers();
163 // image.SaveFile("text.png", wxBITMAP_TYPE_PNG); // for testing
164 
165  // now find extent of actual (red) text pixels; wx coords put (0,0) at upper left
166  int x, y, top = image.GetHeight(), left = image.GetWidth(), bottom = -1, right = -1;
167  for (x=0; x<image.GetWidth(); ++x) {
168  for (y=0; y<image.GetHeight(); ++y) {
169  if (image.GetRed(x, y) >= 128) { // character pixel here
170  if (y < top) top = y;
171  if (x < left) left = x;
172  if (y > bottom) bottom = y;
173  if (x > right) right = x;
174  }
175  }
176  }
177  if (bottom < 0 || right < 0) {
178  WARNINGMSG("Cn3DGLCanvas::MeasureText() - no character pixels found!");
179  *centerX = *centerY = 0;
180  return false;
181  }
182 // TESTMSG("top: " << top << ", left: " << left << ", bottom: " << bottom << ", right: " << right);
183 
184  // set center{X,Y} to center of drawn glyph relative to bottom left
185  *centerX = (int) (((double) (right - left)) / 2 + 0.5);
186  *centerY = (int) (((double) (bottom - top)) / 2 + 0.5);
187 
188  return true;
189 }
190 
191 void Cn3DGLCanvas::OnPaint(wxPaintEvent& event)
192 {
193  // This is a dummy, to avoid an endless succession of paint messages.
194  // OnPaint handlers must always create a wxPaintDC.
195  wxPaintDC dc(this);
196 
197  if (/*!GetContext() ||*/ !renderer || suspended) return;
198  SetCurrent();
199  renderer->Display();
200  SwapBuffers();
201 }
202 
203 void Cn3DGLCanvas::OnSize(wxSizeEvent& event)
204 {
205  if (suspended /*|| !GetContext()*/) return;
206  SetCurrent();
207 
208  // this is necessary to update the context on some platforms
209  //wxGLCanvas::OnSize(event);
210 
211  // set GL viewport (not called by wxGLCanvas::OnSize on all platforms...)
212  int w, h;
213  GetClientSize(&w, &h);
214  glViewport(0, 0, (GLint) w, (GLint) h);
215 
216  renderer->NewView();
217 }
218 
220 {
221  int w, h;
222  GetClientSize(&w, &h);
223  wxSizeEvent se(wxSize(w, h));
224  OnSize(se);
225 }
226 
227 void Cn3DGLCanvas::OnMouseEvent(wxMouseEvent& event)
228 {
229  static bool dragging = false;
230  static long last_x, last_y;
231 
232  if (/*!GetContext() ||*/ !renderer || suspended) return;
233  SetCurrent();
234 
235 // in wxGTK >= 2.3.2, this causes a system crash on some Solaris machines...
236 #if !defined(__WXGTK__)
237  // keep mouse focus while holding down button
238  if (event.LeftDown())
239  CaptureMouse();
240  if (event.LeftDClick())
241  CaptureMouse();
242  if (event.LeftUp())
243  ReleaseMouse();
244 #endif
245 
246  if (event.LeftIsDown()) {
247  if (!dragging) {
248  dragging = true;
249  } else {
251  if (event.ShiftDown())
252  action = OpenGLRenderer::eXYTranslateHV; // shift-drag = translate
253 #ifdef __WXMAC__
254  else if (event.MetaDown()) // control key + mouse doesn't work on Mac?
255 #else
256  else if (event.ControlDown())
257 #endif
258  action = OpenGLRenderer::eZoomH; // ctrl-drag = zoom
259  else
260  action = OpenGLRenderer::eXYRotateHV; // normal rotate
261  renderer->ChangeView(action, event.GetX() - last_x, event.GetY() - last_y);
262  Refresh(false);
263  }
264  last_x = event.GetX();
265  last_y = event.GetY();
266  } else {
267  dragging = false;
268  }
269 
270  if (event.LeftDClick()) { // double-click = select, +ctrl = set center
271  unsigned int name;
272  if (structureSet && renderer->GetSelected(event.GetX(), event.GetY(), &name))
274 #ifdef __WXMAC__
275  event.MetaDown() // control key + mouse doesn't work on Mac?
276 #else
277  event.ControlDown()
278 #endif
279  );
280  }
281 }
282 
283 void Cn3DGLCanvas::OnEraseBackground(wxEraseEvent& event)
284 {
285  // Do nothing, to avoid flashing.
286 }
287 
288 END_SCOPE(Cn3D)
void OnEraseBackground(wxEraseEvent &event)
OpenGLRenderer * renderer
void OnPaint(wxPaintEvent &event)
void FakeOnSize(void)
void SetGLFontFromRegistry(double fontScale=1.0)
wxBitmap memoryBitmap
wxMemoryDC memoryDC
void SuspendRendering(bool suspend)
void OnSize(wxSizeEvent &event)
void OnMouseEvent(wxMouseEvent &event)
wxGLContext * glContext
void SetCurrent(void)
StructureSet * structureSet
bool MeasureText(const std::string &text, int *width, int *height, int *centerX, int *centerY)
bool GetSelected(int x, int y, unsigned int *name)
void ChangeView(eViewAdjust control, int dX=0, int dY=0, int X2=0, int Y2=0)
bool SetGLFont(int firstChar, int nChars, int fontBase)
void NewView(double eyeTranslateToAngleDegrees=0.0) const
static const unsigned int FONT_BASE
void SelectedAtom(unsigned int name, bool setCenter)
USING_SCOPE(objects)
USING_NCBI_SCOPE
#define MYMAX(a, b)
bool RegistryGetString(const string &section, const string &name, string *value)
Definition: cn3d_tools.cpp:263
static const std::string REG_OPENGL_FONT_SECTION
Definition: cn3d_tools.hpp:182
#define WARNINGMSG(stream)
Definition: cn3d_tools.hpp:85
static const std::string REG_FONT_NATIVE_FONT_INFO
Definition: cn3d_tools.hpp:184
#define ERRORMSG(stream)
Definition: cn3d_tools.hpp:86
Include a standard set of the NCBI C++ Toolkit most basic headers.
#define false
Definition: bool.h:36
#define NULL
Definition: ncbistd.hpp:225
#define END_SCOPE(ns)
End the previously defined scope.
Definition: ncbistl.hpp:75
#define BEGIN_SCOPE(ns)
Define a new scope.
Definition: ncbistl.hpp:72
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
END_EVENT_TABLE()
static void text(MDB_val *v)
Definition: mdb_dump.c:62
void resize(vector< SMethodDef > &container)
Modified on Tue May 28 05:51:33 2024 by modify_doxy.py rev. 669887