Commit 618a5f0e authored by Maciej Suminski's avatar Maciej Suminski

OpenGL multitarget rendering (compositing).

parent a8f47913
...@@ -29,11 +29,15 @@ add_custom_target( ...@@ -29,11 +29,15 @@ add_custom_target(
) )
set(GAL_SRCS set(GAL_SRCS
# Common part
drawpanel_gal.cpp drawpanel_gal.cpp
painter.cpp painter.cpp
gal/graphics_abstraction_layer.cpp gal/graphics_abstraction_layer.cpp
gal/stroke_font.cpp gal/stroke_font.cpp
gal/color4d.cpp gal/color4d.cpp
view/wx_view_controls.cpp
# OpenGL GAL
gal/opengl/opengl_gal.cpp gal/opengl/opengl_gal.cpp
gal/opengl/shader.cpp gal/opengl/shader.cpp
gal/opengl/vertex_item.cpp gal/opengl/vertex_item.cpp
...@@ -42,8 +46,10 @@ set(GAL_SRCS ...@@ -42,8 +46,10 @@ set(GAL_SRCS
gal/opengl/noncached_container.cpp gal/opengl/noncached_container.cpp
gal/opengl/vertex_manager.cpp gal/opengl/vertex_manager.cpp
gal/opengl/gpu_manager.cpp gal/opengl/gpu_manager.cpp
gal/opengl/opengl_compositor.cpp
# Cairo GAL
gal/cairo/cairo_gal.cpp gal/cairo/cairo_gal.cpp
view/wx_view_controls.cpp
) )
add_library(gal STATIC ${GAL_SRCS}) add_library(gal STATIC ${GAL_SRCS})
......
...@@ -280,6 +280,12 @@ void CAIRO_GAL::RestoreScreen() ...@@ -280,6 +280,12 @@ void CAIRO_GAL::RestoreScreen()
} }
void CAIRO_GAL::SetTarget( RenderTarget aTarget )
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{ {
cairo_move_to( cairoImage, aStartPoint.x, aStartPoint.y ); cairo_move_to( cairoImage, aStartPoint.x, aStartPoint.y );
......
...@@ -62,6 +62,8 @@ void GAL::DrawGrid() ...@@ -62,6 +62,8 @@ void GAL::DrawGrid()
if( !gridVisibility ) if( !gridVisibility )
return; return;
SetTarget( TARGET_NONCACHED );
// The grid consists of lines // The grid consists of lines
// For the drawing the start points, end points and increments have to be calculated in world coordinates // For the drawing the start points, end points and increments have to be calculated in world coordinates
VECTOR2D screenStartPoint( 0, 0 ); VECTOR2D screenStartPoint( 0, 0 );
......
...@@ -77,9 +77,11 @@ void GPU_MANAGER::SetShader( SHADER& aShader ) ...@@ -77,9 +77,11 @@ void GPU_MANAGER::SetShader( SHADER& aShader )
// Cached manager // Cached manager
GPU_CACHED_MANAGER::GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ) : GPU_CACHED_MANAGER::GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ) :
GPU_MANAGER( aContainer ), m_buffersInitialized( false ), m_indicesPtr( NULL ), GPU_MANAGER( aContainer ), m_buffersInitialized( false ),
m_indicesSize( 0 ) m_indicesSize( 0 )
{ {
// Allocate the biggest possible buffer for indices
m_indices.reset( new GLuint[aContainer->GetSize()] );
} }
...@@ -252,7 +254,6 @@ void GPU_NONCACHED_MANAGER::EndDrawing() ...@@ -252,7 +254,6 @@ void GPU_NONCACHED_MANAGER::EndDrawing()
VERTEX* vertices = m_container->GetAllVertices(); VERTEX* vertices = m_container->GetAllVertices();
GLfloat* coordinates = (GLfloat*) ( vertices ); GLfloat* coordinates = (GLfloat*) ( vertices );
GLubyte* colors = (GLubyte*) ( vertices ) + ColorOffset; GLubyte* colors = (GLubyte*) ( vertices ) + ColorOffset;
GLfloat* shaders = (GLfloat*) ( vertices ) + ShaderOffset / sizeof(GLfloat);
// Prepare buffers // Prepare buffers
glEnableClientState( GL_VERTEX_ARRAY ); glEnableClientState( GL_VERTEX_ARRAY );
...@@ -263,6 +264,8 @@ void GPU_NONCACHED_MANAGER::EndDrawing() ...@@ -263,6 +264,8 @@ void GPU_NONCACHED_MANAGER::EndDrawing()
if( m_shader != NULL ) // Use shader if applicable if( m_shader != NULL ) // Use shader if applicable
{ {
GLfloat* shaders = (GLfloat*) ( vertices ) + ShaderOffset / sizeof(GLfloat);
m_shader->Use(); m_shader->Use();
glEnableVertexAttribArray( m_shaderAttrib ); glEnableVertexAttribArray( m_shaderAttrib );
glVertexAttribPointer( m_shaderAttrib, ShaderStride, GL_FLOAT, GL_FALSE, glVertexAttribPointer( m_shaderAttrib, ShaderStride, GL_FLOAT, GL_FALSE,
......
/*i
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http:O//www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file opengl_compositor.cpp
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image (OpenGL flavour).
*/
#include <gal/opengl/opengl_compositor.h>
#include <wx/log.h>
using namespace KiGfx;
OPENGL_COMPOSITOR::OPENGL_COMPOSITOR() :
m_initialized( false ), m_current( 0 )
{
}
OPENGL_COMPOSITOR::~OPENGL_COMPOSITOR()
{
if( m_initialized )
clean();
}
void OPENGL_COMPOSITOR::Initialize()
{
if( m_initialized )
return;
// Get the maximum number of buffers
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, (GLint*) &m_maxBuffers );
// We need framebuffer objects for drawing the screen contents
// Generate framebuffer and a depth buffer
glGenFramebuffers( 1, &m_framebuffer );
glBindFramebuffer( GL_FRAMEBUFFER, m_framebuffer );
m_currentFbo = m_framebuffer;
// Allocate memory for the depth buffer
// Attach the depth buffer to the framebuffer
glGenRenderbuffers( 1, &m_depthBuffer );
glBindRenderbuffer( GL_RENDERBUFFER, m_depthBuffer );
// Use here a size of 24 bits for the depth buffer, 8 bits for the stencil buffer
// this is required later for anti-aliasing
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_STENCIL, m_width, m_height );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, m_depthBuffer );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, m_depthBuffer );
// Check the status, exit if the framebuffer can't be created
GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if( status != GL_FRAMEBUFFER_COMPLETE )
{
wxLogFatalError( wxT( "Cannot create the framebuffer." ) );
}
// Unbind the framebuffer, so by default all the rendering goes directly to the display
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
m_currentFbo = 0;
m_initialized = true;
}
void OPENGL_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight )
{
if( m_initialized )
clean();
m_width = aWidth;
m_height = aHeight;
}
unsigned int OPENGL_COMPOSITOR::GetBuffer()
{
wxASSERT( m_initialized );
if( m_buffers.size() < m_maxBuffers )
{
// GL_COLOR_ATTACHMENTn are consecutive integers
GLuint attachmentPoint = GL_COLOR_ATTACHMENT0 + usedBuffers();
GLuint textureTarget;
// Generate the texture for the pixel storage
glGenTextures( 1, &textureTarget );
glBindTexture( GL_TEXTURE_2D, textureTarget );
// Set texture parameters
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
// Bind the texture to the specific attachment point, clear and rebind the screen
glBindFramebuffer( GL_FRAMEBUFFER, m_framebuffer );
m_currentFbo = m_framebuffer;
glFramebufferTexture2D( GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, textureTarget, 0 );
ClearBuffer();
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
m_currentFbo = 0;
// Store the new buffer
BUFFER_ITEM buffer = { textureTarget, attachmentPoint };
m_buffers.push_back( buffer );
return usedBuffers();
}
// Unfortunately we have no more buffers left
return 0;
}
void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
{
if( aBufferHandle <= usedBuffers() )
{
// Change the rendering destination to the selected attachment point
if( m_currentFbo != m_framebuffer )
{
glBindFramebuffer( GL_FRAMEBUFFER, m_framebuffer );
m_currentFbo = m_framebuffer;
}
if( m_current != aBufferHandle - 1 )
{
glDrawBuffer( m_buffers[m_current].attachmentPoint );
m_current = aBufferHandle - 1;
}
}
}
void OPENGL_COMPOSITOR::ClearBuffer()
{
wxASSERT( m_initialized );
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
void OPENGL_COMPOSITOR::BlitBuffer( unsigned int aBufferHandle )
{
wxASSERT( m_initialized );
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void OPENGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle, double aDepth )
{
wxASSERT( m_initialized );
// Switch to the main framebuffer and blit the scene
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
m_currentFbo = 0;
// Depth test has to be disabled to make transparency working
glDisable( GL_DEPTH_TEST );
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
// Enable texturing and bind the main texture
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_buffers[aBufferHandle - 1].textureTarget );
// Draw a full screen quad with the texture
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLES );
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -1.0f, -1.0f, aDepth );
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( 1.0f, -1.0f, aDepth );
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( 1.0f, 1.0f, aDepth );
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -1.0f, -1.0f, aDepth );
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( 1.0f, 1.0f, aDepth );
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( -1.0f, 1.0f, aDepth );
glEnd();
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
void OPENGL_COMPOSITOR::clean()
{
wxASSERT( m_initialized );
glDeleteFramebuffers( 1, &m_framebuffer );
glDeleteRenderbuffers( 1, &m_depthBuffer );
Buffers::const_iterator it;
for( it = m_buffers.begin(); it != m_buffers.end(); ++it )
{
glDeleteTextures( 1, &it->textureTarget );
}
m_buffers.clear();
m_initialized = false;
}
GLuint OPENGL_COMPOSITOR::m_currentFbo = 0;
...@@ -54,7 +54,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, ...@@ -54,7 +54,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize, wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
wxEXPAND, aName ), wxEXPAND, aName ),
cachedManager( true ), cachedManager( true ),
nonCachedManager( false ) nonCachedManager( false ),
overlayManager( false )
{ {
// Create the OpenGL-Context // Create the OpenGL-Context
glContext = new wxGLContext( this ); glContext = new wxGLContext( this );
...@@ -67,9 +68,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, ...@@ -67,9 +68,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) ); SetCursorColor( COLOR4D( 1.0, 1.0, 1.0, 1.0 ) );
// Initialize the flags // Initialize the flags
isDeleteSavedPixels = true;
isGlewInitialized = false; isGlewInitialized = false;
isFrameBufferInitialized = false; isFramebufferInitialized = false;
isUseShader = isUseShaders; isUseShader = isUseShaders;
isShaderInitialized = false; isShaderInitialized = false;
isGrouping = false; isGrouping = false;
...@@ -109,9 +109,6 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, ...@@ -109,9 +109,6 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
// Compute the unit circle vertices and store them in a buffer for faster drawing // Compute the unit circle vertices and store them in a buffer for faster drawing
computeCircle(); computeCircle();
// By default we draw non-cached objects, it changes on BeginGroup()/EndGroup()
currentManager = &nonCachedManager;
} }
...@@ -119,13 +116,6 @@ OPENGL_GAL::~OPENGL_GAL() ...@@ -119,13 +116,6 @@ OPENGL_GAL::~OPENGL_GAL()
{ {
glFlush(); glFlush();
// Delete the buffers
if( isFrameBufferInitialized )
{
deleteFrameBuffer( &frameBuffer, &depthBuffer, &texture );
deleteFrameBuffer( &frameBufferBackup, &depthBufferBackup, &textureBackup );
}
gluDeleteTess( tesselator ); gluDeleteTess( tesselator );
ClearCache(); ClearCache();
...@@ -143,15 +133,9 @@ void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight ) ...@@ -143,15 +133,9 @@ void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
{ {
screenSize = VECTOR2D( aWidth, aHeight ); screenSize = VECTOR2D( aWidth, aHeight );
// Delete old buffers for resizing // Resize framebuffers
if( isFrameBufferInitialized ) compositor.Resize( aWidth, aHeight );
{ isFramebufferInitialized = false;
deleteFrameBuffer( &frameBuffer, &depthBuffer, &texture );
deleteFrameBuffer( &frameBufferBackup, &depthBufferBackup, &textureBackup );
// This flag is used for recreating the buffers
isFrameBufferInitialized = false;
}
wxGLCanvas::SetSize( aWidth, aHeight ); wxGLCanvas::SetSize( aWidth, aHeight );
} }
...@@ -165,86 +149,35 @@ void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent ) ...@@ -165,86 +149,35 @@ void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
} }
void OPENGL_GAL::generateFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, void OPENGL_GAL::SaveScreen()
GLuint* aTexture )
{
// We need frame buffer objects for drawing the screen contents
// Generate frame buffer and a depth buffer
glGenFramebuffersEXT( 1, aFrameBuffer );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, *aFrameBuffer );
// Allocate memory for the depth buffer
// Attach the depth buffer to the frame buffer
glGenRenderbuffersEXT( 1, aDepthBuffer );
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, *aDepthBuffer );
// Use here a size of 24 bits for the depth buffer, 8 bits for the stencil buffer
// this is required later for anti-aliasing
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, screenSize.x,
screenSize.y );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
*aDepthBuffer );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, *aDepthBuffer );
// Generate the texture for the pixel storage
// Attach the texture to the frame buffer
glGenTextures( 1, aTexture );
glBindTexture( GL_TEXTURE_2D, *aTexture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, screenSize.x, screenSize.y, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
*aTexture, 0 );
// Check the status, exit if the frame buffer can't be created
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
{
wxLogError( wxT( "Can't create the frame buffer." ) );
exit( 1 );
}
isFrameBufferInitialized = true;
}
void OPENGL_GAL::deleteFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, GLuint* aTexture )
{ {
glDeleteFramebuffers( 1, aFrameBuffer ); wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
glDeleteRenderbuffers( 1, aDepthBuffer );
glDeleteTextures( 1, aTexture );
} }
void OPENGL_GAL::initFrameBuffers() void OPENGL_GAL::RestoreScreen()
{ {
generateFrameBuffer( &frameBuffer, &depthBuffer, &texture ); wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
generateFrameBuffer( &frameBufferBackup, &depthBufferBackup, &textureBackup );
} }
void OPENGL_GAL::SaveScreen() void OPENGL_GAL::SetTarget( RenderTarget aTarget )
{ {
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBufferBackup ); switch( aTarget )
glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer ); {
glBlitFramebuffer( 0, 0, screenSize.x, screenSize.y, 0, 0, screenSize.x, screenSize.y, default:
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, case TARGET_CACHED:
GL_NEAREST ); currentManager = &cachedManager;
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer ); break;
}
case TARGET_NONCACHED:
currentManager = &nonCachedManager;
break;
void OPENGL_GAL::RestoreScreen() case TARGET_OVERLAY:
{ currentManager = &overlayManager;
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer ); break;
glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBufferBackup ); }
glBlitFramebuffer( 0, 0, screenSize.x, screenSize.y, 0, 0, screenSize.x, screenSize.y,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_NEAREST );
} }
...@@ -275,7 +208,7 @@ void OPENGL_GAL::initGlew() ...@@ -275,7 +208,7 @@ void OPENGL_GAL::initGlew()
exit( 1 ); exit( 1 );
} }
// Frame buffers have to be supported // Framebuffers have to be supported
if( !GLEW_ARB_framebuffer_object ) if( !GLEW_ARB_framebuffer_object )
{ {
wxLogError( wxT( "Framebuffer objects are not supported!" ) ); wxLogError( wxT( "Framebuffer objects are not supported!" ) );
...@@ -303,8 +236,23 @@ void OPENGL_GAL::BeginDrawing() ...@@ -303,8 +236,23 @@ void OPENGL_GAL::BeginDrawing()
if( !isGlewInitialized ) if( !isGlewInitialized )
initGlew(); initGlew();
if( !isFrameBufferInitialized ) if( !isFramebufferInitialized )
initFrameBuffers(); {
// Set up the view port
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );
// Create the screen transformation
glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y, -depthRange.x, -depthRange.y );
// Prepare rendering target buffers
compositor.Initialize();
mainBuffer = compositor.GetBuffer();
overlayBuffer = compositor.GetBuffer();
isFramebufferInitialized = true;
}
// Compile the shaders // Compile the shaders
if( !isShaderInitialized && isUseShader ) if( !isShaderInitialized && isUseShader )
...@@ -321,19 +269,18 @@ void OPENGL_GAL::BeginDrawing() ...@@ -321,19 +269,18 @@ void OPENGL_GAL::BeginDrawing()
// Make VBOs use shaders // Make VBOs use shaders
cachedManager.SetShader( shader ); cachedManager.SetShader( shader );
nonCachedManager.SetShader( shader ); nonCachedManager.SetShader( shader );
overlayManager.SetShader( shader );
isShaderInitialized = true; isShaderInitialized = true;
} }
// Bind the main frame buffer object - all contents are drawn there
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBuffer );
// Disable 2D Textures // Disable 2D Textures
glDisable( GL_TEXTURE_2D ); glDisable( GL_TEXTURE_2D );
// Enable the depth buffer // Enable the depth buffer
glEnable( GL_DEPTH_TEST ); glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LESS ); glDepthFunc( GL_LESS );
// Setup blending, required for transparent objects // Setup blending, required for transparent objects
glEnable( GL_BLEND ); glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
...@@ -341,14 +288,6 @@ void OPENGL_GAL::BeginDrawing() ...@@ -341,14 +288,6 @@ void OPENGL_GAL::BeginDrawing()
// Enable smooth lines // Enable smooth lines
glEnable( GL_LINE_SMOOTH ); glEnable( GL_LINE_SMOOTH );
// Set up the view port
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );
// Create the screen transformation
glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y, -depthRange.x, -depthRange.y );
glMatrixMode( GL_MODELVIEW ); glMatrixMode( GL_MODELVIEW );
// Set up the world <-> screen transformation // Set up the world <-> screen transformation
...@@ -368,69 +307,34 @@ void OPENGL_GAL::BeginDrawing() ...@@ -368,69 +307,34 @@ void OPENGL_GAL::BeginDrawing()
// Set defaults // Set defaults
SetFillColor( fillColor ); SetFillColor( fillColor );
SetStrokeColor( strokeColor ); SetStrokeColor( strokeColor );
isDeleteSavedPixels = true;
// Prepare buffers for drawing
nonCachedManager.Clear(); nonCachedManager.Clear();
overlayManager.Clear();
cachedManager.BeginDrawing(); cachedManager.BeginDrawing();
nonCachedManager.BeginDrawing(); nonCachedManager.BeginDrawing();
} overlayManager.BeginDrawing();
void OPENGL_GAL::blitMainTexture( bool aIsClearFrameBuffer )
{
// Don't use blending for the final blitting
glDisable( GL_BLEND );
glColor4d( 1.0, 1.0, 1.0, 1.0 );
// Switch to the main frame buffer and blit the scene
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
if( aIsClearFrameBuffer )
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
// Enable texturing and bind the main texture
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, texture );
// Draw a full screen quad with the texture
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLES );
glTexCoord2i( 0, 1 );
glVertex3i( -1, -1, 0 );
glTexCoord2i( 1, 1 );
glVertex3i( 1, -1, 0 );
glTexCoord2i( 1, 0 );
glVertex3i( 1, 1, 0 );
glTexCoord2i( 0, 1 );
glVertex3i( -1, -1, 0 );
glTexCoord2i( 1, 0 );
glVertex3i( 1, 1, 0 );
glTexCoord2i( 0, 0 );
glVertex3i( -1, 1, 0 );
glEnd();
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
} }
void OPENGL_GAL::EndDrawing() void OPENGL_GAL::EndDrawing()
{ {
// Cached & non-cached containers are rendered to the same buffer
compositor.SetBuffer( mainBuffer );
compositor.ClearBuffer();
nonCachedManager.EndDrawing(); nonCachedManager.EndDrawing();
cachedManager.EndDrawing(); cachedManager.EndDrawing();
// Draw the remaining contents, blit the main texture to the screen, swap the buffers // Overlay container is rendered to a different buffer
compositor.SetBuffer( overlayBuffer );
compositor.ClearBuffer();
overlayManager.EndDrawing();
// Draw the remaining contents, blit the rendering targets to the screen, swap the buffers
glFlush(); glFlush();
blitMainTexture( true ); compositor.DrawBuffer( mainBuffer, -1.0 );
compositor.DrawBuffer( overlayBuffer, 0.0 );
SwapBuffers(); SwapBuffers();
delete clientDC; delete clientDC;
...@@ -530,8 +434,10 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP ...@@ -530,8 +434,10 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
VECTOR2D( lineLength, -aWidth / 2.0 ) ); VECTOR2D( lineLength, -aWidth / 2.0 ) );
// Draw line caps // Draw line caps
drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), ( aWidth + lineWidth ) / 2, M_PI / 2 ); drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ),
drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), ( aWidth + lineWidth ) / 2, -M_PI / 2 ); ( aWidth + lineWidth ) / 2, M_PI / 2 );
drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ),
( aWidth + lineWidth ) / 2, -M_PI / 2 );
Restore(); Restore();
} }
...@@ -643,15 +549,16 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -643,15 +549,16 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
v0 /_\/_\ v1 v0 /_\/_\ v1
*/ */
currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 ); currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 );
currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ), // v0
aCenterPoint.y - aRadius, layerDepth ); // v0 aCenterPoint.y - aRadius, layerDepth );
currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 ); currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 );
currentManager->Vertex( aCenterPoint.x + aRadius* sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x + aRadius* sqrt( 3.0f ), // v1
aCenterPoint.y - aRadius, layerDepth ); // v1 aCenterPoint.y - aRadius, layerDepth );
currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 ); currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2 currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, // v2
layerDepth );
} }
if( isStrokeEnabled ) if( isStrokeEnabled )
...@@ -661,8 +568,8 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -661,8 +568,8 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
/* Draw a triangle that contains the circle, then shade it leaving only the circle. /* Draw a triangle that contains the circle, then shade it leaving only the circle.
Parameters given to setShader are indices of the triangle's vertices Parameters given to setShader are indices of the triangle's vertices
(if you want to understand more, check the vertex shader source [shader.vert]). (if you want to understand more, check the vertex shader source [shader.vert]).
and the line width. Shader uses this coordinates to determine if fragments are inside and the line width. Shader uses this coordinates to determine if fragments are
the circle or not. inside the circle or not.
v2 v2
/\ /\
//\\ //\\
...@@ -670,15 +577,16 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -670,15 +577,16 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
*/ */
double outerRadius = aRadius + ( lineWidth / 2 ); double outerRadius = aRadius + ( lineWidth / 2 );
currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ), // v0
aCenterPoint.y - outerRadius, layerDepth ); // v0 aCenterPoint.y - outerRadius, layerDepth );
currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ), // v1
aCenterPoint.y - outerRadius, layerDepth ); // v1 aCenterPoint.y - outerRadius, layerDepth );
currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2 currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, // v2
layerDepth );
} }
} }
else else
...@@ -716,7 +624,8 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -716,7 +624,8 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
if( i % 3 == 0 ) if( i % 3 == 0 )
{ {
i++; i++;
// Depending on the vertex, next circle point may be stored in the next vertex.. // Depending on the vertex, next circle point
// may be stored in the next vertex..
next = i + 1; next = i + 1;
} }
else else
...@@ -750,7 +659,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -750,7 +659,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
} }
} }
// Filled circles are easy to draw by using the stored vertices list, scaling and translating // Filled circles are easy to draw by using the stored vertices list
if( isFillEnabled ) if( isFillEnabled )
{ {
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
...@@ -790,8 +699,8 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad ...@@ -790,8 +699,8 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
/* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. /* Draw a triangle that contains the semicircle, then shade it to leave only
Parameters given to setShader are indices of the triangle's vertices * the semicircle. Parameters given to setShader are indices of the triangle's vertices
(if you want to understand more, check the vertex shader source [shader.vert]). (if you want to understand more, check the vertex shader source [shader.vert]).
Shader uses this coordinates to determine if fragments are inside the semicircle or not. Shader uses this coordinates to determine if fragments are inside the semicircle or not.
v2 v2
...@@ -836,8 +745,8 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa ...@@ -836,8 +745,8 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
/* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. /* Draw a triangle that contains the semicircle, then shade it to leave only
Parameters given to setShader are indices of the triangle's vertices * the semicircle. Parameters given to setShader are indices of the triangle's vertices
(if you want to understand more, check the vertex shader source [shader.vert]), the (if you want to understand more, check the vertex shader source [shader.vert]), the
radius and the line width. Shader uses this coordinates to determine if fragments are radius and the line width. Shader uses this coordinates to determine if fragments are
inside the semicircle or not. inside the semicircle or not.
...@@ -957,10 +866,9 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a ...@@ -957,10 +866,9 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
outerScale += 1.0; outerScale += 1.0;
innerScale += 1.0; innerScale += 1.0;
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS; double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS;
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
for( double alpha = aStartAngle; alpha < aEndAngle; ) for( double alpha = aStartAngle; alpha < aEndAngle; )
{ {
double v0[] = { cos( alpha ) * innerScale, sin( alpha ) * innerScale }; double v0[] = { cos( alpha ) * innerScale, sin( alpha ) * innerScale };
...@@ -1155,8 +1063,7 @@ void OPENGL_GAL::ClearScreen() ...@@ -1155,8 +1063,7 @@ void OPENGL_GAL::ClearScreen()
{ {
// Clear screen // Clear screen
glClearColor( backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a ); glClearColor( backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
} }
...@@ -1219,7 +1126,6 @@ int OPENGL_GAL::BeginGroup() ...@@ -1219,7 +1126,6 @@ int OPENGL_GAL::BeginGroup()
isGrouping = true; isGrouping = true;
boost::shared_ptr<VERTEX_ITEM> newItem( new VERTEX_ITEM( cachedManager ) ); boost::shared_ptr<VERTEX_ITEM> newItem( new VERTEX_ITEM( cachedManager ) );
currentManager = &cachedManager;
int groupNumber = getNewGroupNumber(); int groupNumber = getNewGroupNumber();
groups.insert( std::make_pair( groupNumber, newItem ) ); groups.insert( std::make_pair( groupNumber, newItem ) );
...@@ -1229,8 +1135,6 @@ int OPENGL_GAL::BeginGroup() ...@@ -1229,8 +1135,6 @@ int OPENGL_GAL::BeginGroup()
void OPENGL_GAL::EndGroup() void OPENGL_GAL::EndGroup()
{ {
currentManager = &nonCachedManager;
isGrouping = false; isGrouping = false;
} }
...@@ -1399,6 +1303,8 @@ VECTOR2D OPENGL_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition ) ...@@ -1399,6 +1303,8 @@ VECTOR2D OPENGL_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition ) void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition )
{ {
wxLogWarning( wxT( "Not tested ") );
SetCurrent( *glContext ); SetCurrent( *glContext );
// Draw the cursor on the surface // Draw the cursor on the surface
...@@ -1409,14 +1315,12 @@ void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition ) ...@@ -1409,14 +1315,12 @@ void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition )
aCursorPosition = worldScreenMatrix * cursorPositionWorld; aCursorPosition = worldScreenMatrix * cursorPositionWorld;
// Switch to the main frame buffer and blit the scene // Switch to the main framebuffer and blit the scene
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); //glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); //glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity(); glLoadIdentity();
blitMainTexture( false );
glDisable( GL_TEXTURE_2D ); glDisable( GL_TEXTURE_2D );
glColor4d( cursorColor.r, cursorColor.g, cursorColor.b, cursorColor.a ); glColor4d( cursorColor.r, cursorColor.g, cursorColor.b, cursorColor.a );
......
...@@ -48,9 +48,9 @@ void VIEW::AddLayer( int aLayer, bool aDisplayOnly ) ...@@ -48,9 +48,9 @@ void VIEW::AddLayer( int aLayer, bool aDisplayOnly )
m_layers[aLayer].items = new VIEW_RTREE(); m_layers[aLayer].items = new VIEW_RTREE();
m_layers[aLayer].renderingOrder = aLayer; m_layers[aLayer].renderingOrder = aLayer;
m_layers[aLayer].enabled = true; m_layers[aLayer].enabled = true;
m_layers[aLayer].cached = true;
m_layers[aLayer].isDirty = false; m_layers[aLayer].isDirty = false;
m_layers[aLayer].displayOnly = aDisplayOnly; m_layers[aLayer].displayOnly = aDisplayOnly;
m_layers[aLayer].target = TARGET_CACHED;
} }
sortLayers(); sortLayers();
...@@ -136,7 +136,7 @@ int VIEW::Query( const BOX2I& aRect, std::vector<LayerItemPair>& aResult ) ...@@ -136,7 +136,7 @@ int VIEW::Query( const BOX2I& aRect, std::vector<LayerItemPair>& aResult )
VIEW::VIEW( bool aIsDynamic ) : VIEW::VIEW( bool aIsDynamic ) :
m_enableOrderModifier( false ), m_enableOrderModifier( false ),
m_scale ( 1.0 ), m_scale( 1.0 ),
m_painter( NULL ), m_painter( NULL ),
m_gal( NULL ), m_gal( NULL ),
m_dynamic( aIsDynamic ) m_dynamic( aIsDynamic )
...@@ -321,7 +321,7 @@ struct VIEW::updateItemsColor ...@@ -321,7 +321,7 @@ struct VIEW::updateItemsColor
void VIEW::UpdateLayerColor( int aLayer ) void VIEW::UpdateLayerColor( int aLayer )
{ {
// There is no point in updating non-cached layers // There is no point in updating non-cached layers
if( !m_layers[aLayer].cached ) if( m_layers[aLayer].target != TARGET_CACHED )
return; return;
BOX2I r; BOX2I r;
...@@ -344,7 +344,7 @@ void VIEW::UpdateAllLayersColor() ...@@ -344,7 +344,7 @@ void VIEW::UpdateAllLayersColor()
VIEW_LAYER* l = &( ( *i ).second ); VIEW_LAYER* l = &( ( *i ).second );
// There is no point in updating non-cached layers // There is no point in updating non-cached layers
if( !m_layers[l->id].cached ) if( l->target != TARGET_CACHED )
continue; continue;
updateItemsColor visitor( l->id, m_painter, m_gal ); updateItemsColor visitor( l->id, m_painter, m_gal );
...@@ -376,7 +376,7 @@ struct VIEW::changeItemsDepth ...@@ -376,7 +376,7 @@ struct VIEW::changeItemsDepth
void VIEW::ChangeLayerDepth( int aLayer, int aDepth ) void VIEW::ChangeLayerDepth( int aLayer, int aDepth )
{ {
// There is no point in updating non-cached layers // There is no point in updating non-cached layers
if( !m_layers[aLayer].cached ) if( m_layers[aLayer].target != TARGET_CACHED )
return; return;
BOX2I r; BOX2I r;
...@@ -483,7 +483,7 @@ struct VIEW::drawItem ...@@ -483,7 +483,7 @@ struct VIEW::drawItem
if( !drawCondition ) if( !drawCondition )
return; return;
if( currentLayer->cached ) if( currentLayer->target == TARGET_CACHED )
{ {
// Draw using cached information or create one // Draw using cached information or create one
int group = aItem->getGroup( currentLayer->id ); int group = aItem->getGroup( currentLayer->id );
...@@ -521,6 +521,7 @@ void VIEW::redrawRect( const BOX2I& aRect ) ...@@ -521,6 +521,7 @@ void VIEW::redrawRect( const BOX2I& aRect )
{ {
drawItem drawFunc( this, l ); drawItem drawFunc( this, l );
m_gal->SetTarget( l->target );
m_gal->SetLayerDepth( l->renderingOrder ); m_gal->SetLayerDepth( l->renderingOrder );
l->items->Query( aRect, drawFunc ); l->items->Query( aRect, drawFunc );
l->isDirty = false; l->isDirty = false;
...@@ -709,8 +710,10 @@ void VIEW::RecacheAllItems( bool aImmediately ) ...@@ -709,8 +710,10 @@ void VIEW::RecacheAllItems( bool aImmediately )
{ {
VIEW_LAYER* l = & ( ( *i ).second ); VIEW_LAYER* l = & ( ( *i ).second );
if( l->cached ) // Obviously, there is only one cached target that has to be recomputed
if( l->target == TARGET_CACHED )
{ {
m_gal->SetTarget( l->target );
m_gal->SetLayerDepth( l->renderingOrder ); m_gal->SetLayerDepth( l->renderingOrder );
recacheLayer visitor( this, m_gal, l->id, aImmediately ); recacheLayer visitor( this, m_gal, l->id, aImmediately );
l->items->Query( r, visitor ); l->items->Query( r, visitor );
......
...@@ -252,6 +252,9 @@ public: ...@@ -252,6 +252,9 @@ public:
/// @copydoc GAL::RestoreScreen() /// @copydoc GAL::RestoreScreen()
virtual void RestoreScreen(); virtual void RestoreScreen();
/// @copydoc GAL::SetTarget()
virtual void SetTarget( RenderTarget aTarget );
// ------- // -------
// Cursor // Cursor
// ------- // -------
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file compositor.h
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image.
*/
#ifndef COMPOSITOR_H_
#define COMPOSITOR_H_
namespace KiGfx
{
class COMPOSITOR
{
public:
virtual ~COMPOSITOR()
{
}
/**
* Function Reset()
* performs primary initialiation, necessary to use the object.
*/
virtual void Initialize() = 0;
/**
* Function Resize()
* clears the state of COMPOSITOR, so it has to be reinitialized again with the new dimensions.
*
* @param aWidth is the framebuffer width (in pixels).
* @param aHeight is the framebuffer height (in pixels).
*/
virtual void Resize( unsigned int aWidth, unsigned int aHeight ) = 0;
/**
* Function GetBuffer()
* prepares a new buffer that may be used as a rendering target.
*
* @return is the handle of the buffer. In case of failure 0 (zero) is returned as the handle.
*/
virtual unsigned int GetBuffer() = 0;
/**
* Function SetBuffer()
* sets the selected buffer as the rendering target. All the following drawing functions are
* going to be rendered in the selected buffer.
*
* @param aBufferHandle is the handle of the buffer or 0 in case of rendering directly to the
* display.
*/
virtual void SetBuffer( unsigned int aBufferHandle ) = 0;
/**
* Function ClearBuffer()
* clears the selected buffer (set by the SetBuffer() function).
*/
virtual void ClearBuffer() = 0;
/**
* Function BlitBuffer()
* pastes the content of the buffer to the current buffer (set by SetBuffer() function).
*
* @param aBufferHandle is the handle to the buffer that is going to be pasted.
*/
virtual void BlitBuffer( unsigned int aBufferHandle ) = 0;
/**
* Function DrawBuffer()
* draws the selected buffer on the screen.
*
* @param aBufferHandle is the handle of the buffer to be drawn.
* @param aDepth is the depth on which the buffer should be drawn. // TODO mention if higher depth value means close to the screen or is it opposite
*/
virtual void DrawBuffer( unsigned int aBufferHandle, double aDepth ) = 0;
protected:
unsigned int m_width; ///< Width of the buffer (in pixels)
unsigned int m_height; ///< Height of the buffer (in pixels)
};
} // namespace KiGfx
#endif /* COMPOSITOR_H_ */
...@@ -31,4 +31,17 @@ ...@@ -31,4 +31,17 @@
#define SWAP( varA, condition, varB ) if( varA condition varB ) { double tmp = varA; varA = varB; \ #define SWAP( varA, condition, varB ) if( varA condition varB ) { double tmp = varA; varA = varB; \
varB = tmp; } varB = tmp; }
namespace KiGfx
{
/**
* RenderTarget: Possible rendering targets
*/
enum RenderTarget
{
TARGET_CACHED, ///< Main rendering target (cached)
TARGET_NONCACHED, ///< Auxiliary rendering target (noncached)
TARGET_OVERLAY ///< Items that may change while the view stays the same (noncached)
};
}
#endif /* DEFINITIONS_H_ */ #endif /* DEFINITIONS_H_ */
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <math/matrix3x3.h> #include <math/matrix3x3.h>
#include <gal/color4d.h> #include <gal/color4d.h>
#include <gal/definitions.h>
#include <gal/stroke_font.h> #include <gal/stroke_font.h>
#include <newstroke_font.h> #include <newstroke_font.h>
...@@ -546,16 +547,27 @@ public: ...@@ -546,16 +547,27 @@ public:
return worldScale; return worldScale;
} }
// ---------------------------
// Buffer manipulation methods
// ---------------------------
/** /**
* @brief Save the screen contents. * @brief Save the screen contents.
*/ */
virtual void SaveScreen() = 0; virtual void SaveScreen() = 0;
/** /**
* @brief Save the screen contents. * @brief Restore the screen contents.
*/ */
virtual void RestoreScreen() = 0; virtual void RestoreScreen() = 0;
/**
* @brief Sets the target for rendering.
*
* @param aTarget is the new target for rendering.
*/
virtual void SetTarget( RenderTarget aTarget ) = 0;
// ------------- // -------------
// Grid methods // Grid methods
// ------------- // -------------
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file opengl_compositor.h
* @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and
* later compositing into a single image (OpenGL flavour).
*/
#ifndef OPENGL_COMPOSITOR_H_
#define OPENGL_COMPOSITOR_H_
#include <gal/compositor.h>
#include <GL/glew.h>
#include <vector>
namespace KiGfx
{
class OPENGL_COMPOSITOR : public COMPOSITOR
{
public:
OPENGL_COMPOSITOR();
virtual ~OPENGL_COMPOSITOR();
///< @copydoc COMPOSITOR::Initialize()
virtual void Initialize();
///< @copydoc COMPOSITOR::Resize()
virtual void Resize( unsigned int aWidth, unsigned int aHeight );
///< @copydoc COMPOSITOR::GetBuffer()
virtual unsigned int GetBuffer();
///< @copydoc COMPOSITOR::SetBuffer()
virtual void SetBuffer( unsigned int aBufferHandle );
///< @copydoc COMPOSITOR::ClearBuffer()
virtual void ClearBuffer();
///< @copydoc COMPOSITOR::BlitBuffer()
virtual void BlitBuffer( unsigned int aBufferHandle );
///< @copydoc COMPOSITOR::DrawBuffer()
virtual void DrawBuffer( unsigned int aBufferHandle, double aDepth );
protected:
typedef struct
{
GLuint textureTarget; ///< Main texture handle
GLuint attachmentPoint;
} BUFFER_ITEM;
bool m_initialized;
unsigned int m_current;
GLuint m_framebuffer; ///< Main FBO handle
GLuint m_depthBuffer; ///< Depth buffer handle
unsigned int m_maxBuffers; ///< Maximal amount of buffers
typedef std::vector<BUFFER_ITEM> Buffers;
Buffers m_buffers;
/// Store the currently used FBO name in case there was more than one compositor used
static GLuint m_currentFbo;
/**
* Function clean()
* performs freeing of resources.
*/
void clean();
///< Returns number of used buffers
unsigned int usedBuffers()
{
return m_buffers.size();
}
};
} // namespace KiGfx
#endif /* COMPOSITOR_H_ */
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <gal/opengl/vertex_manager.h> #include <gal/opengl/vertex_manager.h>
#include <gal/opengl/vertex_item.h> #include <gal/opengl/vertex_item.h>
#include <gal/opengl/noncached_container.h> #include <gal/opengl/noncached_container.h>
#include <gal/opengl/opengl_compositor.h>
#include <wx/wx.h> #include <wx/wx.h>
#include <wx/glcanvas.h> #include <wx/glcanvas.h>
...@@ -268,6 +269,9 @@ public: ...@@ -268,6 +269,9 @@ public:
/// @copydoc GAL::RestoreScreen() /// @copydoc GAL::RestoreScreen()
virtual void RestoreScreen(); virtual void RestoreScreen();
/// @copydoc GAL::SetTarget()
virtual void SetTarget( RenderTarget aTarget );
// ------- // -------
// Cursor // Cursor
// ------- // -------
...@@ -328,7 +332,7 @@ private: ...@@ -328,7 +332,7 @@ private:
wxEvtHandler* mouseListener; wxEvtHandler* mouseListener;
wxEvtHandler* paintListener; wxEvtHandler* paintListener;
// VBO buffered vertices for faster circle & semicircle drawing // Precomputed vertices for faster circle & semicircle drawing
NONCACHED_CONTAINER circleContainer; ///< Container for storing circle vertices NONCACHED_CONTAINER circleContainer; ///< Container for storing circle vertices
// Vertex buffer objects related fields // Vertex buffer objects related fields
...@@ -338,6 +342,12 @@ private: ...@@ -338,6 +342,12 @@ private:
VERTEX_MANAGER* currentManager; ///< Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs) VERTEX_MANAGER* currentManager; ///< Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
VERTEX_MANAGER cachedManager; ///< Container for storing cached VERTEX_ITEMs VERTEX_MANAGER cachedManager; ///< Container for storing cached VERTEX_ITEMs
VERTEX_MANAGER nonCachedManager; ///< Container for storing non-cached VERTEX_ITEMs VERTEX_MANAGER nonCachedManager; ///< Container for storing non-cached VERTEX_ITEMs
VERTEX_MANAGER overlayManager; ///< Container for storing overlaid VERTEX_ITEMs
// Framebuffer & compositing
OPENGL_COMPOSITOR compositor; ///< Handles multiple rendering targets
unsigned int mainBuffer; ///< Main rendering target
unsigned int overlayBuffer; ///< Auxiliary rendering target (for menus etc.)
// Polygon tesselation // Polygon tesselation
GLUtesselator* tesselator; ///< Pointer to the tesselator GLUtesselator* tesselator; ///< Pointer to the tesselator
...@@ -350,20 +360,11 @@ private: ...@@ -350,20 +360,11 @@ private:
int cursorSize; ///< Size of the cursor in pixels int cursorSize; ///< Size of the cursor in pixels
GLubyte* cursorShape; ///< Cursor pixel storage GLubyte* cursorShape; ///< Cursor pixel storage
GLubyte* cursorSave; ///< Saved cursor pixels GLubyte* cursorSave; ///< Saved cursor pixels
bool isDeleteSavedPixels; ///< Flag for deleting saved pixels
VECTOR2D savedCursorPosition; ///< Last saved cursor position VECTOR2D savedCursorPosition; ///< Last saved cursor position
// Frame buffer
GLuint frameBuffer; ///< Main FBO handle
GLuint depthBuffer; ///< Depth buffer handle
GLuint texture; ///< Main texture handle
GLuint frameBufferBackup; ///< Backup FBO handle
GLuint depthBufferBackup; ///< Backup depth buffer handle
GLuint textureBackup; ///< Backup texture handle
// Internal flags // Internal flags
bool isGlewInitialized; ///< Is GLEW initialized? bool isGlewInitialized; ///< Is GLEW initialized?
bool isFrameBufferInitialized; ///< Are the frame buffers initialized? bool isFramebufferInitialized; ///< Are the framebuffers initialized?
bool isShaderInitialized; ///< Was the shader initialized? bool isShaderInitialized; ///< Was the shader initialized?
bool isUseShader; ///< Should the shaders be used? bool isUseShader; ///< Should the shaders be used?
bool isGrouping; ///< Was a group started? bool isGrouping; ///< Was a group started?
...@@ -434,34 +435,6 @@ private: ...@@ -434,34 +435,6 @@ private:
*/ */
void initCursor( int aCursorSize ); void initCursor( int aCursorSize );
/**
* @brief Blit the main texture to the screen.
*
* @param aIsClearFrameBuffer if true, the frame buffer is cleared as well.
*/
void blitMainTexture( bool aIsClearFrameBuffer );
/// @brief Initialize the frame buffers for main contents and backup storage.
void initFrameBuffers();
/**
* @brief Generate a frame buffer for the screen contents.
*
* @param aFrameBuffer is the pointer to the frame buffer handle.
* @param aDepthBuffer is the pointer to the depth buffer handle.
* @param aTexture is the pointer to the texture handle.
*/
void generateFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, GLuint* aTexture );
/**
* @brief Delete the frame buffer for the screen contents.
*
* @param aFrameBuffer is the pointer to the frame buffer handle.
* @param aDepthBuffer is the pointer to the depth buffer handle.
* @param aTexture is the pointer to the texture handle.
*/
void deleteFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, GLuint* aTexture );
/** /**
* @brief Draw a quad for the line. * @brief Draw a quad for the line.
* *
......
...@@ -43,7 +43,7 @@ enum SHADER_TYPE ...@@ -43,7 +43,7 @@ enum SHADER_TYPE
SHADER_STROKED_CIRCLE, SHADER_STROKED_CIRCLE,
}; };
typedef struct VERTEX typedef struct
{ {
GLfloat x, y, z; // Coordinates GLfloat x, y, z; // Coordinates
GLubyte r, g, b, a; // Color GLubyte r, g, b, a; // Color
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
namespace KiGfx namespace KiGfx
{ {
class VERTEX;
class VERTEX_ITEM; class VERTEX_ITEM;
class SHADER; class SHADER;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <boost/unordered/unordered_map.hpp> #include <boost/unordered/unordered_map.hpp>
#include <math/box2.h> #include <math/box2.h>
#include <gal/definitions.h>
namespace KiGfx namespace KiGfx
{ {
...@@ -258,14 +259,14 @@ public: ...@@ -258,14 +259,14 @@ public:
} }
/** /**
* Function SetLayerCached() * Function SetLayerTarget()
* Turns on or off the cached parameter of a particular layer. * Changes the rendering target for a particular layer.
* @param aLayer: the layer * @param aLayer is the layer.
* @param aCached: the new parameter value * @param aTarget is the rendering target.
*/ */
inline void SetLayerCached( int aLayer, bool aCached = true ) inline void SetLayerTarget( int aLayer, RenderTarget aTarget )
{ {
m_layers[aLayer].cached = aCached; m_layers[aLayer].target = aTarget;
} }
/** /**
...@@ -367,14 +368,13 @@ private: ...@@ -367,14 +368,13 @@ private:
bool enabled; ///* is the layer to be rendered? bool enabled; ///* is the layer to be rendered?
bool isDirty; ///* does it contain any dirty items (updated since last redraw) bool isDirty; ///* does it contain any dirty items (updated since last redraw)
bool displayOnly; ///* is the layer display only? bool displayOnly; ///* is the layer display only?
bool cached; ///* items on non-cached layers are displayed in
///* immediate mode
VIEW_RTREE* items; ///* R-tree indexing all items on this layer. VIEW_RTREE* items; ///* R-tree indexing all items on this layer.
std::vector<VIEW_ITEM*> dirtyItems; ///* set of dirty items collected since last redraw std::vector<VIEW_ITEM*> dirtyItems; ///* set of dirty items collected since last redraw
int renderingOrder; ///* rendering order of this layer int renderingOrder; ///* rendering order of this layer
int id; ///* layer ID int id; ///* layer ID
BOX2I extents; ///* sum of bboxes of all items on the layer BOX2I extents; ///* sum of bboxes of all items on the layer
BOX2I dirtyExtents; ///* sum of bboxes of all dirty items on the layer BOX2I dirtyExtents; ///* sum of bboxes of all dirty items on the layer
RenderTarget target; ///* where the layer should be rendered
}; };
// Convenience typedefs // Convenience typedefs
......
...@@ -207,7 +207,7 @@ void PCB_BASE_FRAME::SetBoard( BOARD* aBoard ) ...@@ -207,7 +207,7 @@ void PCB_BASE_FRAME::SetBoard( BOARD* aBoard )
// so there is no point in caching them // so there is no point in caching them
for( LAYER_NUM layer = FIRST_NETNAME_LAYER; layer <= LAST_NETNAME_LAYER; ++layer ) for( LAYER_NUM layer = FIRST_NETNAME_LAYER; layer <= LAST_NETNAME_LAYER; ++layer )
{ {
view->SetLayerCached( layer, false ); view->SetLayerTarget( layer, KiGfx::TARGET_NONCACHED );
} }
// Load layer & elements visibility settings // Load layer & elements visibility settings
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment