mirror of
https://github.com/glest/glest-source.git
synced 2025-02-25 04:02:30 +01:00
- added support for pixel buffers and use it for color picking (eventually for screenshots)
This commit is contained in:
parent
2dd2afb296
commit
c4dc1e616b
@ -5762,7 +5762,6 @@ Vec3f Renderer::computeScreenPosition(const Vec3f &worldPos) {
|
||||
void Renderer::computeSelected( Selection::UnitContainer &units, const Object *&obj,
|
||||
const bool withObjectSelection,
|
||||
const Vec2i &posDown, const Vec2i &posUp) {
|
||||
|
||||
const Metrics &metrics= Metrics::getInstance();
|
||||
|
||||
//compute center and dimensions of selection rectangle
|
||||
@ -5801,6 +5800,8 @@ void Renderer::computeSelected( Selection::UnitContainer &units, const Object *&
|
||||
w= (w * metrics.getScreenW() / metrics.getVirtualW());
|
||||
h= (h * metrics.getScreenH() / metrics.getVirtualH());
|
||||
|
||||
PixelBufferWrapper::begin();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
@ -5831,6 +5832,7 @@ void Renderer::computeSelected( Selection::UnitContainer &units, const Object *&
|
||||
|
||||
//GraphicsInterface::getInstance().getCurrentContext()->swapBuffers();
|
||||
|
||||
PixelBufferWrapper::end();
|
||||
//printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
vector<BaseColorPickEntity *> rendererModels;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "texture_manager.h"
|
||||
#include "texture.h"
|
||||
#include "model_header.h"
|
||||
#include <memory>
|
||||
#include "leak_dumper.h"
|
||||
|
||||
using std::string;
|
||||
@ -216,17 +217,28 @@ private:
|
||||
void buildInterpolationData() const;
|
||||
};
|
||||
|
||||
class BaseColorPickEntity {
|
||||
private:
|
||||
static const int COLOR_COMPONENTS = 3;
|
||||
unsigned char uniqueColorID[COLOR_COMPONENTS];
|
||||
class PixelBufferWrapper {
|
||||
public:
|
||||
PixelBufferWrapper(int pboCount,int bufferSize);
|
||||
~PixelBufferWrapper();
|
||||
|
||||
static unsigned char nextColorID[COLOR_COMPONENTS];
|
||||
static Mutex mutexNextColorID;
|
||||
static Pixmap2D *getPixelBufferFor(int x,int y,int w,int h, int colorComponents);
|
||||
static void begin();
|
||||
static void end();
|
||||
|
||||
private:
|
||||
static bool isPBOEnabled;
|
||||
static int index;
|
||||
static vector<unsigned int> pboIds;
|
||||
};
|
||||
|
||||
class BaseColorPickEntity {
|
||||
|
||||
public:
|
||||
|
||||
BaseColorPickEntity();
|
||||
|
||||
static const int COLOR_COMPONENTS = 3;
|
||||
static void init(int bufferSize);
|
||||
static void beginPicking();
|
||||
static void endPicking();
|
||||
static vector<int> getPickedList(int x,int y,int w,int h, const vector<BaseColorPickEntity *> &rendererModels);
|
||||
@ -238,6 +250,14 @@ public:
|
||||
virtual string getUniquePickName() const = 0;
|
||||
|
||||
~BaseColorPickEntity() {};
|
||||
|
||||
private:
|
||||
unsigned char uniqueColorID[COLOR_COMPONENTS];
|
||||
|
||||
static unsigned char nextColorID[COLOR_COMPONENTS];
|
||||
static Mutex mutexNextColorID;
|
||||
|
||||
static auto_ptr<PixelBufferWrapper> pbo;
|
||||
};
|
||||
|
||||
|
||||
|
@ -24,49 +24,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Define FBO's (Frame Buffer Objects) for win32
|
||||
|
||||
/*
|
||||
#ifdef WIN32
|
||||
|
||||
#define GL_FRAMEBUFFER_EXT 0x8D40
|
||||
#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
|
||||
#define GL_RENDERBUFFER_EXT 0x8D41
|
||||
#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
|
||||
#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
|
||||
|
||||
typedef void (APIENTRY * PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint* framebuffers);
|
||||
typedef void (APIENTRY * PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
|
||||
typedef void (APIENTRY * PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
|
||||
typedef GLenum (APIENTRY * PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
|
||||
typedef void (APIENTRY * PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint* framebuffers);
|
||||
typedef void (APIENTRY * PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint* renderbuffers);
|
||||
typedef void (APIENTRY * PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
typedef void (APIENTRY * PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
typedef void (APIENTRY * PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
typedef void (APIENTRY * PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
|
||||
typedef void (APIENTRY * PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint* renderbuffers);
|
||||
typedef void (APIENTRY * PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
|
||||
typedef void (APIENTRY * PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
||||
typedef void (APIENTRY * PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params);
|
||||
typedef GLboolean (APIENTRY * PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
|
||||
typedef GLboolean (APIENTRY * PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
|
||||
typedef void (APIENTRY * PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
|
||||
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
|
||||
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
|
||||
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
|
||||
PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
|
||||
PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
|
||||
PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
|
||||
PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
|
||||
|
||||
#endif
|
||||
*/
|
||||
|
||||
namespace Shared { namespace Graphics { namespace Gl {
|
||||
|
||||
using namespace Platform;
|
||||
@ -81,12 +38,6 @@ static void setupGLExtensionMethods() {
|
||||
if(setupExtensions == true) {
|
||||
setupExtensions = false;
|
||||
|
||||
//glGenFramebuffersEXT= (PFNGLGENFRAMEBUFFERSEXTPROC)SDL_GL_GetProcAddress("glGenFramebuffersEXT");
|
||||
//glBindFramebufferEXT= (PFNGLBINDFRAMEBUFFEREXTPROC)SDL_GL_GetProcAddress("glBindFramebufferEXT");
|
||||
//glFramebufferTexture2DEXT= (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
|
||||
//glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
|
||||
//glCheckFramebufferStatusEXT= (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
|
||||
|
||||
if(isGlExtensionSupported("GL_EXT_framebuffer_object")) {
|
||||
//glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)wglGetProcAddress("glIsRenderbufferEXT");
|
||||
glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");
|
||||
|
@ -959,10 +959,104 @@ void Model::deletePixels() {
|
||||
}
|
||||
}
|
||||
|
||||
bool PixelBufferWrapper::isPBOEnabled = false;
|
||||
int PixelBufferWrapper::index = 0;
|
||||
vector<unsigned int> PixelBufferWrapper::pboIds;
|
||||
|
||||
PixelBufferWrapper::PixelBufferWrapper(int pboCount,int bufferSize) {
|
||||
if(isGlExtensionSupported("GL_ARB_pixel_buffer_object")) {
|
||||
PixelBufferWrapper::isPBOEnabled = true;
|
||||
pboIds.reserve(pboCount);
|
||||
glGenBuffersARB(pboCount, &pboIds[0]);
|
||||
|
||||
for(unsigned int i = 0; i < pboCount; ++i) {
|
||||
// create pixel buffer objects, you need to delete them when program exits.
|
||||
// glBufferDataARB with NULL pointer reserves only memory space.
|
||||
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[i]);
|
||||
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, 0, GL_STREAM_READ_ARB);
|
||||
}
|
||||
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Pixmap2D *PixelBufferWrapper::getPixelBufferFor(int x,int y,int w,int h, int colorComponents) {
|
||||
Pixmap2D *pixmapScreenShot = NULL;
|
||||
if(PixelBufferWrapper::isPBOEnabled == true) {
|
||||
// increment current index first then get the next index
|
||||
// "index" is used to read pixels from a framebuffer to a PBO
|
||||
// "nextIndex" is used to process pixels in the other PBO
|
||||
index = (index + 1) % 2;
|
||||
|
||||
// pbo index used for next frame
|
||||
int nextIndex = (index + 1) % 2;
|
||||
|
||||
// read framebuffer ///////////////////////////////
|
||||
// copy pixels from framebuffer to PBO
|
||||
// Use offset instead of pointer.
|
||||
// OpenGL should perform asynch DMA transfer, so glReadPixels() will return immediately.
|
||||
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// measure the time reading framebuffer
|
||||
//t1.stop();
|
||||
//readTime = t1.getElapsedTimeInMilliSec();
|
||||
|
||||
// process pixel data /////////////////////////////
|
||||
//t1.start();
|
||||
|
||||
// map the PBO that contain framebuffer pixels before processing it
|
||||
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
|
||||
//glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
|
||||
GLubyte* src = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
|
||||
if(src) {
|
||||
pixmapScreenShot = new Pixmap2D(w+1, h+1, colorComponents);
|
||||
memcpy(pixmapScreenShot->getPixels(),src,pixmapScreenShot->getPixelByteCount());
|
||||
|
||||
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); // release pointer to the mapped buffer
|
||||
|
||||
//pixmapScreenShot->save("debugPBO.png");
|
||||
}
|
||||
|
||||
// measure the time reading framebuffer
|
||||
//t1.stop();
|
||||
//processTime = t1.getElapsedTimeInMilliSec();
|
||||
|
||||
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
|
||||
}
|
||||
|
||||
return pixmapScreenShot;
|
||||
}
|
||||
|
||||
void PixelBufferWrapper::begin() {
|
||||
if(PixelBufferWrapper::isPBOEnabled == true) {
|
||||
// set the framebuffer to read
|
||||
glReadBuffer(GL_FRONT);
|
||||
}
|
||||
}
|
||||
|
||||
void PixelBufferWrapper::end() {
|
||||
if(PixelBufferWrapper::isPBOEnabled == true) {
|
||||
// set the framebuffer to read
|
||||
glReadBuffer(GL_BACK);
|
||||
}
|
||||
}
|
||||
|
||||
PixelBufferWrapper::~PixelBufferWrapper() {
|
||||
if(PixelBufferWrapper::isPBOEnabled == true) {
|
||||
if(pboIds.empty() == false) {
|
||||
glDeleteBuffersARB(pboIds.size(), &pboIds[0]);
|
||||
pboIds.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//unsigned char BaseColorPickEntity::nextColorID[COLOR_COMPONENTS] = {1, 1, 1, 1};
|
||||
unsigned char BaseColorPickEntity::nextColorID[COLOR_COMPONENTS] = { 1, 1, 1 };
|
||||
Mutex BaseColorPickEntity::mutexNextColorID;
|
||||
auto_ptr<PixelBufferWrapper> BaseColorPickEntity::pbo;
|
||||
|
||||
BaseColorPickEntity::BaseColorPickEntity() {
|
||||
MutexSafeWrapper safeMutex(&mutexNextColorID);
|
||||
@ -1010,6 +1104,12 @@ BaseColorPickEntity::BaseColorPickEntity() {
|
||||
}
|
||||
}
|
||||
|
||||
void BaseColorPickEntity::init(int bufferSize) {
|
||||
if(BaseColorPickEntity::pbo.get() == NULL) {
|
||||
BaseColorPickEntity::pbo.reset(new PixelBufferWrapper(2,bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
string BaseColorPickEntity::getColorDescription() const {
|
||||
string result = "";
|
||||
char szBuf[100]="";
|
||||
@ -1086,25 +1186,44 @@ vector<int> BaseColorPickEntity::getPickedList(int x,int y,int w,int h, const ve
|
||||
|
||||
static Chrono lastSnapshot(true);
|
||||
|
||||
// Only update the pixel buffer every 350 milliseconds or as required
|
||||
if(cachedPixels.get() == NULL || cachedPixelsW != w+1 || cachedPixelsH != h+1 ||
|
||||
lastSnapshot.getMillis() > 350) {
|
||||
//printf("Updating selection millis = %ld\n",lastSnapshot.getMillis());
|
||||
Pixmap2D *pixmapScreenShot = BaseColorPickEntity::pbo->getPixelBufferFor(x,y,w,h, COLOR_COMPONENTS);
|
||||
if(pixmapScreenShot != NULL) {
|
||||
// Only update the pixel buffer every 350 milliseconds or as required
|
||||
if(cachedPixels.get() == NULL || cachedPixelsW != w+1 || cachedPixelsH != h+1 ||
|
||||
lastSnapshot.getMillis() > 350) {
|
||||
//printf("Updating selection millis = %ld\n",lastSnapshot.getMillis());
|
||||
|
||||
lastSnapshot.reset();
|
||||
lastSnapshot.reset();
|
||||
|
||||
Pixmap2D *pixmapScreenShot = new Pixmap2D(w+1, h+1, COLOR_COMPONENTS);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
|
||||
//glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
cachedPixels.reset(new unsigned char[pixmapScreenShot->getPixelByteCount()]);
|
||||
memcpy(cachedPixels.get(),pixmapScreenShot->getPixels(),pixmapScreenShot->getPixelByteCount());
|
||||
cachedPixelsW = w+1;
|
||||
cachedPixelsH = h+1;
|
||||
|
||||
cachedPixels.reset(new unsigned char[pixmapScreenShot->getPixelByteCount()]);
|
||||
memcpy(cachedPixels.get(),pixmapScreenShot->getPixels(),pixmapScreenShot->getPixelByteCount());
|
||||
cachedPixelsW = w+1;
|
||||
cachedPixelsH = h+1;
|
||||
delete pixmapScreenShot;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Only update the pixel buffer every 350 milliseconds or as required
|
||||
if(cachedPixels.get() == NULL || cachedPixelsW != w+1 || cachedPixelsH != h+1 ||
|
||||
lastSnapshot.getMillis() > 350) {
|
||||
//printf("Updating selection millis = %ld\n",lastSnapshot.getMillis());
|
||||
|
||||
delete pixmapScreenShot;
|
||||
lastSnapshot.reset();
|
||||
|
||||
pixmapScreenShot = new Pixmap2D(w+1, h+1, COLOR_COMPONENTS);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
|
||||
//glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
cachedPixels.reset(new unsigned char[pixmapScreenShot->getPixelByteCount()]);
|
||||
memcpy(cachedPixels.get(),pixmapScreenShot->getPixels(),pixmapScreenShot->getPixelByteCount());
|
||||
cachedPixelsW = w+1;
|
||||
cachedPixelsH = h+1;
|
||||
|
||||
delete pixmapScreenShot;
|
||||
}
|
||||
}
|
||||
pixelBuffer = cachedPixels.get();
|
||||
|
||||
|
@ -19,10 +19,12 @@
|
||||
#include "window.h"
|
||||
#include <vector>
|
||||
//#include <SDL_image.h>
|
||||
#include "model.h"
|
||||
#include "leak_dumper.h"
|
||||
|
||||
using namespace Shared::Graphics::Gl;
|
||||
using namespace Shared::Util;
|
||||
using namespace Shared::Graphics;
|
||||
|
||||
namespace Shared{ namespace Platform{
|
||||
|
||||
@ -140,6 +142,8 @@ void PlatformContextGl::init(int colorBits, int depthBits, int stencilBits,bool
|
||||
// try to revert to 800x600
|
||||
screen = SDL_SetVideoMode(800, 600, i, flags);
|
||||
if(screen != 0) {
|
||||
resW = 800;
|
||||
resH = 600;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -149,6 +153,8 @@ void PlatformContextGl::init(int colorBits, int depthBits, int stencilBits,bool
|
||||
// try to revert to 640x480
|
||||
screen = SDL_SetVideoMode(640, 480, i, flags);
|
||||
if(screen != 0) {
|
||||
resW = 640;
|
||||
resH = 480;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -160,15 +166,16 @@ void PlatformContextGl::init(int colorBits, int depthBits, int stencilBits,bool
|
||||
}
|
||||
|
||||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||
}
|
||||
|
||||
if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
|
||||
GLuint err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
GLuint err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
fprintf(stderr, "Error [main]: glewInit failed: %s\n", glewGetErrorString(err));
|
||||
//return 1;
|
||||
throw std::runtime_error((char *)glewGetErrorString(err));
|
||||
}
|
||||
}
|
||||
|
||||
int bufferSize = (resW * resH * BaseColorPickEntity::COLOR_COMPONENTS);
|
||||
BaseColorPickEntity::init(bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user