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

Go to the SVN repository for this file.

1 /* $Id: render_common.cpp 45793 2020-12-01 19:38:57Z asztalos $
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: Bob Falk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
35 #include <gui/opengl/glresmgr.hpp>
36 #include <gui/opengl/glmodel2d.hpp>
37 
38 
39  // define this to cause OpenGL actual state to be updated immediately on state
40  // update calls (useful if some code is using rendermanager and some isn't, and
41  // state is shared between the two)
42 #define GL_STATE_UPDATE
43 
45 
46 ////////////////////////////////////////////////////////////////////////////////
47 ////////////////////////////////////////////////////////////////////////////////
48 
50 {
52 }
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 ////////////////////////////////////////////////////////////////////////////////
56 
57 
59  : m_MatrixMode(GL_NONE)
60  , m_CurrentMode(GL_NONE)
61  , m_CurrentFont(NULL)
62 {
63  m_State.Reset(new CGlState());
64 
66 }
67 
69 {
70  m_CurrentMode = GL_NONE;
71  m_MatrixMode = GL_NONE;
72 
73  m_RenderNode.SetVBOGeom(nullptr);
74 }
75 
76 void CRenderCommon::Vertex3f(GLfloat x, GLfloat y, GLfloat z)
77 {
78  if (m_CurrentMode == GL_NONE) {
79  LOG_POST(Error << "CRenderCommon::Vertex3f() called without first calling CGlRender::Begin");
80  return;
81  }
82 
83  m_VertexBuffer.push_back(CVect3<float>(x, y, z));
84 
85  // If quads, break up quads into triangle pairs. Do this whenever
86  // 4 new vertices have been added (ignore groups of 6 since they
87  // are the previous triangles) (we do this because quads are deprecated
88  // in OpenGL 3+ and because PDF files do not support gouraud-shaded quads)
89  if (m_CurrentMode == GL_QUADS && m_VertexBuffer.size() % 6 == 4) {
90  size_t v1 = m_VertexBuffer.size() - 4;
91  size_t v3 = v1 + 2;
92 
93  // error condition:
94  if (m_State->GetPolygonMode() == GL_LINE) {
95  _TRACE("Warning: Rendering triangle pairs for quads in line mode");
96  }
97 
98  if (m_ColorBuffer.size() > 0) {
100  m_ColorBuffer.push_back(m_ColorBuffer[v1]);
101  m_ColorBuffer.push_back(m_ColorBuffer[v3]);
102  }
103 
104  if (m_TexCoord2DBuffer1.size() > 0) {
108  }
109 
110  // Do vertices last since x_SyncAttribs syncs size of attribute
111  // buffers to current size of this (m_VertexBuffer) buffer.
112  m_VertexBuffer.push_back(m_VertexBuffer[v1]);
113  m_VertexBuffer.push_back(m_VertexBuffer[v3]);
114  }
115 }
116 
117 void CRenderCommon::Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
118 {
119  if (m_CurrentMode != GL_NONE) {
120  LOG_POST(Error << "CRenderCommon::Rectf() called between Begin() and End()");
121  return;
122  }
123 
124  if (m_State->GetPolygonMode() == GL_LINE) {
125  Begin(GL_LINE_STRIP);
126  Vertex3f(x1, y1, 0.0f);
127  Vertex3f(x2, y1, 0.0f);
128  Vertex3f(x2, y2, 0.0f);
129  Vertex3f(x1, y2, 0.0f);
130  Vertex3f(x1, y1, 0.0f);
131  End();
132  }
133  else {
134  Begin(GL_TRIANGLE_STRIP);
135  Vertex3f(x1, y1, 0.0f);
136  Vertex3f(x2, y1, 0.0f);
137  Vertex3f(x1, y2, 0.0f);
138  Vertex3f(x2, y2, 0.0f);
139  End();
140  }
141 }
142 
144 {
145 #ifdef GL_STATE_UPDATE
146  glColor4f(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha());
147 #endif
148 
149  // Color is the one command that can be called both between Begin()/End() and
150  // outside of Begin()/End(). If we are outside, update the state. If we
151  // are inside, update the attribute array too.
152  if (m_CurrentMode == GL_NONE) {
153  m_State->ColorC(c);
154  return;
155  }
156 
157  size_t attrib_size = m_ColorBuffer.size();
158  size_t vert_size = m_VertexBuffer.size();
159 
160  // If an attribute (color, normal, texcoord) is provided for any
161  // vertex, there most be an attribute for all vertices since buffers
162  // must have same number of elements when rendered. Attributes should
163  // be provided ahead of vertices (it applies to the next vertex).
164 
165  // Just right
166  if (attrib_size == vert_size) {
167  m_ColorBuffer.push_back(c);
168  }
169  // already have correct # of attributes - replace last element
170  else if (attrib_size == vert_size + 1) {
171  m_ColorBuffer.back() = c;
172  }
173  // too few attributes (could be any number missing up to vert_size). This
174  // is normal opengl usage - e.g. one color applies to all vertices for a tri
175  if (attrib_size < vert_size) {
177  m_ColorBuffer.push_back(c);
178  }
179  // this should never happen
180  else if (attrib_size > vert_size + 1) {
181  LOG_POST(Error << "Error - color attributes exceed expected count");
182  m_ColorBuffer.back() = c;
183  }
184 
185  // remember color state so that if not set before next glbegin/glend, this color will be used
186  m_State->ColorC(c);
187 }
188 
189 
190 void CRenderCommon::TexCoord2f(GLfloat s, GLfloat t)
191 {
192  CVect2<float> v(s, t);
193 
194  size_t attrib_size = m_TexCoord2DBuffer1.size();
195  size_t vert_size = m_VertexBuffer.size();
196 
197  // If an attribute (color, normal, texcoord) is provided for any
198  // vertex, there most be an attribute for all vertices since buffers
199  // must have same number of elements when rendered. Attributes should
200  // be provided ahead of vertices (it applies to the next vertex).
201 
202  // Just right
203  if (attrib_size == vert_size) {
204  m_TexCoord2DBuffer1.push_back(v);
205  }
206  // already have correct # of attributes - replace last element
207  else if (attrib_size == vert_size + 1) {
208  m_TexCoord2DBuffer1.back() = v;
209  }
210  // too few attributes (could be any number missing up to vert_size). This
211  // is normal opengl usage - e.g. one color applies to all vertices for a tri
212  if (attrib_size < vert_size) {
214  m_TexCoord2DBuffer1.push_back(v);
215  }
216  // this should never happen
217  else if (attrib_size > vert_size + 1) {
218  LOG_POST(Error << "Error - texcoord2 attributes exceed expected count");
219  m_TexCoord2DBuffer1.back() = v;
220  }
221 }
222 
224 {
225  m_CurrentFont = font;
226  m_TextColor = color;
227 
229 }
230 
232 {
233  m_CurrentFont = font;
235 
237 }
238 
240 {
243 }
244 
246  const char* text,
247  TModelUnit rotate_degrees)
248 {
249  if (m_CurrentFont == NULL) {
250  LOG_POST(Error << "Unable to write text - must call BeginText() first");
251  return;
252  }
253 
254  m_CurrentFont->WriteText(x, y, text, m_TextColor.GetColorArray(), rotate_degrees);
255 }
256 
258  TModelUnit width, TModelUnit height,
259  const char* text,
262  TModelUnit rotate_degrees)
263 {
264  if (m_CurrentFont == NULL) {
265  LOG_POST(Error << "Unable to write text - must call BeginText() first");
266  return;
267  }
268 
269  m_CurrentFont->WriteText(x, y, width, height, text, m_TextColor.GetColorArray(), align, trunc, rotate_degrees);
270 }
271 
273  IGlFont::EMetric metric,
274  const char* text,
275  int len) const
276 {
277  return font->GetMetric(metric, text, len);
278 }
279 
281 {
282  return font->TextWidth(text);
283 }
284 
286 {
287  return font->TextHeight();
288 }
289 
291 {
292  return font->GetFontDescender();
293 }
294 
296 {
297  return font->GetAdvance(c);
298 }
299 
300 TModelUnit CRenderCommon::GetMaxWidth(const CGlTextureFont* font, int max_num) const
301 {
302  return font->GetMaxWidth(max_num);
303 }
304 
306 {
307  // If End wasn't called after last begin log an error (but continue so that subsequent
308  // rendering will work)
309  if (m_CurrentMode != GL_NONE) {
310  LOG_POST(Error << "CRenderCommon::Begin() called without first calling CGlRender::End()" << m_CurrentMode);
311  }
312 
314 
315  if (m_CurrentMode == GL_POLYGON) {
316  LOG_POST(Error << "Error - GL_POLYGON rendering not supported");
317  return;
318  }
319  else if (m_CurrentMode == GL_QUAD_STRIP) {
320  LOG_POST(Error << "Error - GL_QUAD_STRIP rendering not supported");
321  }
322 
323  m_VertexBuffer.clear();
324  m_ColorBuffer.clear();
325  m_TexCoord2DBuffer1.clear();
326 }
327 
329 {
330  size_t vert_size = m_VertexBuffer.size();
331 
332  if (m_CurrentMode == GL_NONE) {
333  LOG_POST(Error << "CRenderCommon::End() called without first calling CGlRender::Begin");
334  // Can't render anything if we don't know what user wanted (tris? lines?)
335  return;
336  }
337 
338  if (vert_size == 0) {
339  m_CurrentMode = GL_NONE;
340  return;
341  }
342 
343  // All attribute vectors that are in use must be the same
344  // size as the vertex buffer
345  if (m_ColorBuffer.size() > 0 && m_ColorBuffer.size() < vert_size)
347 
348  if (m_TexCoord2DBuffer1.size() > 0 && m_TexCoord2DBuffer1.size() < vert_size)
350 
351  // For quads we set the render mode passed to OpenGL to triangles since we
352  // break down quads into tris.
353  GLenum drawMode = (m_CurrentMode == GL_QUADS) ? GL_TRIANGLES : m_CurrentMode;
354 
355  if (!m_RenderNode.GetVBOGeom())
356  m_RenderNode.SetVBOGeom(drawMode);
357  else
358  m_RenderNode.GetVBOGeom()->x_SetDrawMode(drawMode);
359 
360  m_CurrentMode = GL_NONE;
361 
362  // Sync all vertex and attribute buffers with the stl vectors. It would be more efficient
363  // to copy directly into the vertex buffers but we can't do that with the begin/end api
364  // since we don't know in advance how many elements there will be.
367  if (m_TexCoord2DBuffer1.size() > 0)
369 
370  /*
371  CMatrix4<float> mat;
372  glGetFloatv(GL_MODELVIEW_MATRIX, mat.GetData());
373  mat.Transpose();
374  m_RenderNode.SetPosition(mat);
375  */
377 
379 }
380 
381 void CRenderCommon::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
382 {
383  m_Viewport[0] = x;
384  m_Viewport[1] = y;
385  m_Viewport[2] = width;
386  m_Viewport[3] = height;
387 }
388 
389 void CRenderCommon::GetViewport(GLint *params)
390 {
391  // Don't get from opengl since that is limited to max buffer size but viewport,
392  // when used for other targets, e.g. pdf, may be larger.
393  params[0] = m_Viewport[0];
394  params[1] = m_Viewport[1];
395  params[2] = m_Viewport[2];
396  params[3] = m_Viewport[3];
397 }
398 
399 void CRenderCommon::x_SyncAttribs(vector<CRgbaColor>& colors)
400 {
401  // OpenGL color default
402  CRgbaColor default_color = m_State->GetColor();
403 
404  // But if we already have attributes, most recent one is default:
405  if (colors.size() > 0) {
406  default_color = colors.back();
407  }
408 
409  // Copy default value into array until length equals vertex buffer length
410  colors.insert(colors.end(),
411  m_VertexBuffer.size() - colors.size(),
412  default_color);
413 }
414 
416 {
417  // default
418  CVect3<float> default_value(0.0f, 0.0f, 0.0f);
419 
420  // But if we already have attributes, most recent one is default:
421  if (vecs.size() > 0) {
422  default_value = vecs.back();
423  }
424 
425  // Copy default value into array until length equals vertex buffer length
426  vecs.insert(vecs.end(),
427  m_VertexBuffer.size() - vecs.size(),
428  default_value);
429 }
430 
432 {
433  // default
434  CVect2<float> default_value(0.0f, 0.0f);
435 
436  // But if we already have attributes, most recent one is default:
437  if (vecs.size() > 0) {
438  default_value = vecs.back();
439  }
440 
441  // Copy default value into array until length equals vertex buffer length
442  vecs.insert(vecs.end(),
443  m_VertexBuffer.size() - vecs.size(),
444  default_value);
445 }
446 
448 {
449  if (model != NULL) {
450  model->Render(pane);
451  }
452 }
453 
455 {
456  node->Render();
457 }
458 
CGlModel2D Base class for a model set up for rendering purposes.
Definition: glmodel2d.hpp:64
class CGlPane
Definition: glpane.hpp:62
CGlState Class to encapsulate Rendering state so that a set of user-selected GL state options can be ...
Definition: glstate.hpp:195
CGlVboNode A rendering node that holds a vertex buffer object.
Definition: glvbonode.hpp:64
virtual void TexCoord2f(GLfloat s, GLfloat t)
Texture coords.
virtual TModelUnit TextWidth(const CGlTextureFont *font, const char *text) const
virtual void Begin(GLenum mode)
Start rendering.
virtual TModelUnit GetFontDescender(const CGlTextureFont *font) const
virtual void BeginText(const CGlTextureFont *font, const CRgbaColor &color)
Text is drawn is pixel coordinates.
virtual void WriteText(TModelUnit x, TModelUnit y, const char *text, TModelUnit rotate_degrees=0.0)
Write text at specified model coords.
CGlVboNode m_RenderNode
vertex buffer node for rendering all Begin()/End() renders
CRef< CGlState > m_State
state used by all nodes
CRgbaColor m_TextColor
color and alpha for text only (other GL options do not apply to text)
virtual TModelUnit GetMaxWidth(const CGlTextureFont *font, int max_num) const
virtual void Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
Rect() functions also do Begin() and End() (as in OpenGL)
GLenum m_CurrentMode
rendering mode from Begin()
virtual void Clear()
Clear/delete any graphics/OpenGL memory.
virtual TModelUnit GetAdvance(const CGlTextureFont *font, char c) const
virtual TModelUnit GetMetric(const CGlTextureFont *font, IGlFont::EMetric metric, const char *text=NULL, int len=-1) const
Calls the standard font metric functions except for pdf in which case it first replaces any bitmap fo...
const CGlTextureFont * m_CurrentFont
text parameters
virtual void Render(CGlPane &pane, CGlModel2D *model)
virtual TModelUnit TextHeight(const CGlTextureFont *font) const
virtual void EndText()
Pops matrices and attributes after writing text.
GLint m_Viewport[4]
current projection set by Viewport()
vector< CVect2< float > > m_TexCoord2DBuffer1
vector< CRgbaColor > m_ColorBuffer
void x_SyncAttribs(vector< CRgbaColor > &colors)
virtual void End()
Finish rendering (create buffer and send to renderer)
virtual void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
virtual void Vertex3f(GLfloat x, GLfloat y, GLfloat z)
Explicit support not currently available for: GLbyte, GlShort and GLint calls, e.g.
GLenum m_MatrixMode
current modelview matrix and matrix mode
virtual void GetViewport(GLint *params)
virtual void ColorC(const CRgbaColor &color)
Colors (also defined in IGlState since they can be set either before or inside of Begin()/End().
virtual void x_RenderBuffer(CGlVboNode *node)
vector< CVect3< float > > m_VertexBuffer
class CRgbaColor provides a simple abstraction for managing colors.
Definition: rgba_color.hpp:58
static const Colors colors
Definition: cn3d_colors.cpp:50
static int trunc
Definition: array_out.c:8
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
void SetTexCoordBuffer(const vector< CVect2< float > > &data)
Definition: glvbonode.cpp:145
GLdouble TModelUnit
Definition: gltypes.hpp:48
GLenum GetPolygonMode() const
Definition: glstate.hpp:276
static CGlResMgr & Instance()
Definition: glresmgr.cpp:59
virtual CMatrix4< float > GetModelViewMatrix() const =0
CIRef< IRender > GetCurrentRenderer()
Returns current renderer, or NULL.
Definition: glresmgr.hpp:98
virtual void Render()
Set state and call x_Render() to render geometry.
IRender & GetGl()
convenience function for getting current render manager
void WriteText(TModelUnit x, TModelUnit y, const char *text, TModelUnit rotate_degrees=0.0) const
Write text at specified model coords.
CIRef< IVboGeom > GetVBOGeom()
Definition: glvbonode.hpp:82
void SetVertexBuffer3D(const vector< CVect3< float > > &data)
Definition: glvbonode.cpp:89
virtual TModelUnit GetFontDescender() const
void SetPosition(const CMatrix4< float > &mat)
Set 1 transformation and have it be "mat".
void SetState(CGlState *state)
Set/get current OpenGL state.
void SetVBOGeom(IVboGeom *geom)
Set/get geometry object. These can be shared between nodes.
Definition: glvbonode.hpp:79
void BeginText() const
WriteText interface The WriteText functions produce the same results as TextOut but they are more eff...
TModelUnit GetMaxWidth(int max_num) const
returns minimal space sufficient to render any number in [0, max_num].
CRgbaColor GetColor() const
Definition: glstate.hpp:259
void EndText() const
Pops matrices and attributes after writing text.
virtual TModelUnit GetMetric(EMetric metric, const char *text=NULL, int len=-1) const
virtual TModelUnit TextWidth(const char *text) const
Compute and return font metrics.
virtual TModelUnit TextHeight(void) const
void SetColorBuffer(const vector< CRgbaColor > &data)
Definition: glvbonode.cpp:103
virtual void Render(CGlPane &pane)
Draw to the screen.
Definition: glmodel2d.cpp:186
ETruncate
Definition: glfont.hpp:62
int TAlign
Definition: glfont.hpp:113
TModelUnit GetAdvance(char c) const
virtual void ColorC(const CRgbaColor &c)
Definition: glstate.cpp:449
float GetBlue(void) const
Definition: rgba_color.hpp:333
float GetGreen(void) const
Definition: rgba_color.hpp:327
float GetAlpha(void) const
Definition: rgba_color.hpp:339
const float * GetColorArray(void) const
Access the color array directly.
Definition: rgba_color.hpp:394
float GetRed(void) const
Get specific channels in floating point values.
Definition: rgba_color.hpp:321
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
TObjectType & GetObject(void)
Get object.
Definition: ncbiobj.hpp:1011
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
n background color
int len
static void text(MDB_val *v)
Definition: mdb_dump.c:62
mdb_mode_t mode
Definition: lmdb++.h:38
EIPRangeType t
Definition: ncbi_localip.c:101
Modified on Fri Sep 20 14:57:52 2024 by modify_doxy.py rev. 669887