Blob Blame Raw


#include "qtofflinegl.h"
#include <traster.h>
#include <tconvert.h>

//-----------------------------------------------------------------------------

#ifdef _WIN32

void swapRedBlueChannels(void *buffer, int bufferSize) // Flips The Red And Blue Bytes (WidthxHeight)
{
	void *b = buffer; // Pointer To The Buffer

#ifdef x64
	int size = bufferSize;
	UCHAR *pix = (UCHAR *)b;
	while (size > 0) {
		UCHAR r = *pix;
		UCHAR b = *(pix + 2);
		*pix = b;
		*(pix + 2) = r;
		pix += 4;
		size--;
	}
#else
	__asm		  // Assembler Code To Follow
	{
		mov ecx, bufferSize // Counter Set To Dimensions Of Our Memory Block
			mov ebx, b // Points ebx To Our Data (b)
			label: // Label Used For Looping
			mov al,[ebx+0] // Loads Value At ebx Into al
			mov ah,[ebx+2] // Loads Value At ebx+2 Into ah
			mov [ebx+2],al // Stores Value In al At ebx+2
			mov [ebx+0],ah // Stores Value In ah At ebx

			add ebx,4 // Moves Through The Data By 4 Bytes
			dec ecx // Decreases Our Loop Counter
			jnz label // If Not Zero Jump Back To Label
	}
#endif
}

#endif

//-----------------------------------------------------------------------------

#if defined(MACOSX)
#if defined(powerpc)

void rightRotateBits(UCHAR *buf, int bufferSize)
{
	UINT *buffer = (UINT *)buf;
	UINT app;
	for (int i = 0; i < bufferSize; i++, buffer++) {
		app = *buffer;
		*buffer = app >> 8 | app << 24;
	}
}
#else
void rightRotateBits(UCHAR *buf, int bufferSize)
{
	UINT *buffer = (UINT *)buf;
	UINT app;
	for (int i = 0; i < bufferSize; i++, buffer++) {
		app = *buffer;
		*buffer = (app >> 16 & 0x000000ff) | (app << 16 & 0x00ff0000) | (app & 0xff00ff00);
	}
}
#endif
#endif

//-----------------------------------------------------------------------------

//=============================================================================
// QtOfflineGL : implem. offlineGL usando QT
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------

QtOfflineGL::QtOfflineGL(TDimension rasterSize, std::shared_ptr<TOfflineGL::Imp> shared)
	: TOfflineGL::Imp(rasterSize.lx, rasterSize.ly)
	, m_context(0)
	, m_oldContext(0)
{
	createContext(rasterSize, std::move(shared));
	/*
  makeCurrent();

  glClearColor(0.0f,0.0f,0.0f,0.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  doneCurrent();
*/
}

//-----------------------------------------------------------------------------

QtOfflineGL::~QtOfflineGL()
{
}

//-----------------------------------------------------------------------------

void QtOfflineGL::createContext(TDimension rasterSize, std::shared_ptr<TOfflineGL::Imp> shared)
{
	// Imposto il formato dei Pixel (pixelFormat)
	/*
	 32,                    // 32-bit color depth
	 0, 0, 0, 0, 0, 0,      // color bits ignored
	 8,                     // no alpha buffer
	 0,                     // shift bit ignored
	 0,                     // no accumulation buffer
	 0, 0, 0, 0,            // accum bits ignored
	 32,                    // 32-bit z-buffer
	 32,                    // max stencil buffer
	 0,                     // no auxiliary buffer
	 PFD_MAIN_PLANE,        // main layer
	 0,                     // reserved
	 0, 0, 0                // layer masks ignored

	 ATTENZIONE !! SU MAC IL FORMATO E' DIVERSO (casomai possiamo mettere un ifdef)

	 SPECIFICHE  MAC = depth_size 24, stencil_size 8, alpha_size 1

  */

	QGLFormat fmt;

#ifdef _WIN32
	fmt.setAlphaBufferSize(8);
	fmt.setAlpha(true);
	fmt.setRgba(true);
	fmt.setDepthBufferSize(32);
	fmt.setDepth(true);
	fmt.setStencilBufferSize(32);
	fmt.setStencil(true);
	fmt.setAccum(false);
	fmt.setPlane(0);
#elif MACOSX
	fmt = QGLFormat::defaultFormat();
	//printf("GL Version: %s\n",glGetString(GL_VERSION));
	fmt.setVersion(2, 1); /* OSX10.8 では 3.2 だめかも */
#if 0
  fmt.setAlphaBufferSize(8);
  fmt.setAlpha(true);
  fmt.setRgba(true);
  fmt.setDepthBufferSize(32);
  fmt.setDepth(true);
  fmt.setStencilBufferSize(8);
  fmt.setStencil(true);
  fmt.setAccum(false);
  fmt.setPlane(0);
  fmt.setDirectRendering(false);
#endif
#endif

	QSurfaceFormat format;
	format.setProfile(QSurfaceFormat::CompatibilityProfile);

	m_surface = std::make_shared<QOffscreenSurface>();
	m_surface->setFormat(format);
	m_surface->create();

	m_context = std::make_shared<QOpenGLContext>();
	m_context->setFormat(format);
	m_context->create();
	m_context->makeCurrent(m_surface.get());

	QOpenGLFramebufferObjectFormat fbo_format;
	m_fbo = std::make_shared<QOpenGLFramebufferObject>(rasterSize.lx, rasterSize.ly, fbo_format);
	m_fbo->bind();

	printf("create context:%p [thread:0x%x]\n", m_context.get(), QThread::currentThreadId());

	// Creo il contesto OpenGL - assicurandomi che sia effettivamente creato
	// NOTA: Se il contesto non viene creato, di solito basta ritentare qualche volta.

}
//-----------------------------------------------------------------------------

void QtOfflineGL::makeCurrent()
{
	if (m_context) {
	        m_context->moveToThread(QThread::currentThread());
		m_context->makeCurrent(m_surface.get());
	}
	// else
	//  m_oldContext = 0;
}

//-----------------------------------------------------------------------------

void QtOfflineGL::doneCurrent()
{
	if (m_context) {
		m_context->doneCurrent();
	}
}

//-----------------------------------------------------------------------------

void QtOfflineGL::saveCurrentContext()
{
	//  m_oldContext = const_cast<QGLContext*>(QGLContext::currentContext());
}

//-----------------------------------------------------------------------------

void QtOfflineGL::restoreCurrentContext()
{
	//  if(m_oldContext) m_oldContext->makeCurrent();
	//  m_oldContext = 0;
}

//-----------------------------------------------------------------------------

void QtOfflineGL::getRaster(TRaster32P raster)
{
	makeCurrent();
	glFlush();

	int lx = raster->getLx();
	int ly = raster->getLy();

	raster->lock();
	raster->copy( TRaster32P(lx, ly, m_fbo->width(), (TPixelRGBM32 *)m_fbo->toImage(false).bits(), false) );
	raster->unlock();
}

//QGLPixelBuffer::hasOpenGLPbuffers() (statica) -> true se la scheda supporta i PBuffer

//=============================================================================
// QtOfflineGLPBuffer : implem. offlineGL usando QT e PBuffer
//-----------------------------------------------------------------------------

QtOfflineGLPBuffer::QtOfflineGLPBuffer(TDimension rasterSize)
	: TOfflineGL::Imp(rasterSize.lx, rasterSize.ly), m_context(0)
{
	createContext(rasterSize);

	makeCurrent();

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	doneCurrent();
}

//-----------------------------------------------------------------------------

QtOfflineGLPBuffer::~QtOfflineGLPBuffer()
{
}

//-----------------------------------------------------------------------------

void QtOfflineGLPBuffer::createContext(TDimension rasterSize)
{
	// Imposto il formato dei Pixel (pixelFormat)
	/*
      32,                    // 32-bit color depth
      0, 0, 0, 0, 0, 0,      // color bits ignored
      8,                     // no alpha buffer
      0,                     // shift bit ignored
      0,                     // no accumulation buffer
      0, 0, 0, 0,            // accum bits ignored
      32,                    // 32-bit z-buffer
      32,                    // max stencil buffer
      0,                     // no auxiliary buffer
      PFD_MAIN_PLANE,        // main layer
      0,                     // reserved
      0, 0, 0                // layer masks ignored

      ATTENZIONE !! SU MAC IL FORMATO E' DIVERSO (casomai possiamo mettere un ifdef)

      SPECIFICHE  MAC = depth_size 24, stencil_size 8, alpha_size 1

    */

	QGLFormat fmt;

#ifdef _WIN32
	fmt.setAlphaBufferSize(8);
	fmt.setAlpha(false);
	fmt.setRgba(true);
	fmt.setDepthBufferSize(32);
	fmt.setDepth(true);
	fmt.setStencilBufferSize(32);
	fmt.setStencil(true);
	fmt.setAccum(false);
	fmt.setPlane(0);
#elif MACOSX
	fmt.setAlphaBufferSize(1);
	fmt.setAlpha(false);
	fmt.setRgba(true);
	fmt.setDepthBufferSize(24);
	fmt.setDepth(true);
	fmt.setStencilBufferSize(8);
	fmt.setStencil(true);
	fmt.setAccum(false);
	fmt.setPlane(0);
#endif

	// Il PixelBuffer deve essere con width ed height potenze di 2

	int sizeMax = tmax(rasterSize.lx, rasterSize.ly);

	// trovo la potenza di 2 che "contiene" sizeMax e la utilizzo per il PBuffer
	int pBufferSize = 2;
	while (pBufferSize < sizeMax)
		pBufferSize *= 2;

	m_context = std::make_shared<QGLPixelBuffer>(QSize(pBufferSize, pBufferSize), fmt);
}

//-----------------------------------------------------------------------------

void QtOfflineGLPBuffer::makeCurrent()
{
        if (m_context){
		m_context->makeCurrent();
	}
}

//-----------------------------------------------------------------------------

void QtOfflineGLPBuffer::doneCurrent()
{
	if (m_context)
		m_context->doneCurrent();
}

//-----------------------------------------------------------------------------

void QtOfflineGLPBuffer::getRaster(TRaster32P raster)
{
	makeCurrent();
	glFlush();

	//The image is stored using a 32-bit ARGB format (0xAARRGGBB).
	QImage image = m_context->toImage();

	int lx = raster->getLx(), ly = raster->getLy();

	static const TRaster32P emptyRaster;
	if (image.height() == 0 || image.width() == 0)
		return;

	// devo iniziare a leggere la Y da un certo offset
	// dato dalla differenza tra la y della image e la y del raster
	int yOffset = image.height() - ly;
	raster->lock();

	for (int y = 0; y < ly; y++) {
		QRgb *inpPix = (QRgb *)image.scanLine(yOffset + y);

		TPixel32 *pix = raster->pixels(ly - 1 - y);
		TPixel32 *endPix = pix + lx;

		for (; pix < endPix; ++pix) {
			pix->m = 255;
			pix->r = qRed(*inpPix);
			pix->g = qGreen(*inpPix);
			pix->b = qBlue(*inpPix);
			*inpPix++;
		}
	}
	raster->unlock();
}