[client] huge rewrite of renderer API deal with mouse updates

This commit is contained in:
Geoffrey McRae 2017-12-13 02:22:47 +11:00
parent a157f40690
commit 893bb7e603
6 changed files with 251 additions and 109 deletions

View File

@ -17,7 +17,6 @@ CFLAGS += -DBUILD_VERSION='"$(shell git describe --always --long --dirty --abbr
OBJS = main.o \ OBJS = main.o \
spice/spice.o \ spice/spice.o \
ivshmem/ivshmem.o \ ivshmem/ivshmem.o \
renderers/basic.o \
renderers/opengl.o renderers/opengl.o
BUILD_OBJS = $(foreach obj,$(OBJS),$(BUILD)/$(obj)) BUILD_OBJS = $(foreach obj,$(OBJS),$(BUILD)/$(obj))

View File

@ -25,18 +25,18 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <SDL_ttf.h> #include <SDL_ttf.h>
#define IS_LG_RENDERER_VALID(x) \ #define IS_LG_RENDERER_VALID(x) \
((x)->get_name && \ ((x)->get_name && \
(x)->initialize && \ (x)->initialize && \
(x)->deinitialize && \ (x)->deinitialize && \
(x)->is_compatible && \ (x)->is_compatible && \
(x)->on_resize && \ (x)->on_resize && \
(x)->on_mouse_event && \
(x)->render) (x)->render)
typedef struct LG_RendererParams typedef struct LG_RendererParams
{ {
SDL_Window * window; SDL_Window * window;
TTF_Font * font; TTF_Font * font;
bool vsync;
bool showFPS; bool showFPS;
int width; int width;
int height; int height;
@ -62,12 +62,14 @@ typedef struct LG_RendererRect
} }
LG_RendererRect; LG_RendererRect;
typedef const char * (* LG_RendererGetName )(); typedef const char * (* LG_RendererGetName )();
typedef bool (* LG_RendererInitialize )(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format); typedef bool (* LG_RendererInitialize )(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format);
typedef void (* LG_RendererDeInitialize)(void * opaque); typedef void (* LG_RendererDeInitialize )(void * opaque);
typedef bool (* LG_RendererIsCompatible)(void * opaque, const LG_RendererFormat format); typedef bool (* LG_RendererIsCompatible )(void * opaque, const LG_RendererFormat format);
typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect); typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect);
typedef bool (* LG_RendererRender )(void * opaque, const uint8_t * data, bool resample); typedef bool (* LG_RendererOnMouseEvent )(void * opaque, const bool visible , const int x, const int y);
typedef bool (* LG_RendererOnFrameEvent )(void * opaque, const uint8_t * data, bool resample);
typedef bool (* LG_RendererRender )(void * opaque);
typedef struct LG_Renderer typedef struct LG_Renderer
{ {
@ -76,6 +78,8 @@ typedef struct LG_Renderer
LG_RendererDeInitialize deinitialize; LG_RendererDeInitialize deinitialize;
LG_RendererIsCompatible is_compatible; LG_RendererIsCompatible is_compatible;
LG_RendererOnResize on_resize; LG_RendererOnResize on_resize;
LG_RendererOnMouseEvent on_mouse_event;
LG_RendererOnFrameEvent on_frame_event;
LG_RendererRender render; LG_RendererRender render;
} }
LG_Renderer; LG_Renderer;

View File

@ -26,6 +26,5 @@ extern const LG_Renderer LGR_Basic;
const LG_Renderer * LG_Renderers[] = const LG_Renderer * LG_Renderers[] =
{ {
&LGR_OpenGL, &LGR_OpenGL,
&LGR_Basic,
NULL // end of array sentinal NULL // end of array sentinal
}; };

View File

@ -49,6 +49,7 @@ struct AppState
TTF_Font *font; TTF_Font *font;
SDL_Point srcSize; SDL_Point srcSize;
LG_RendererRect dstRect; LG_RendererRect dstRect;
SDL_Point cursor;
float scaleX, scaleY; float scaleX, scaleY;
const LG_Renderer * lgr ; const LG_Renderer * lgr ;
@ -61,7 +62,6 @@ struct AppState
struct AppParams struct AppParams
{ {
bool vsync;
bool autoResize; bool autoResize;
bool allowResize; bool allowResize;
bool keepAspect; bool keepAspect;
@ -82,7 +82,6 @@ struct AppParams
struct AppState state; struct AppState state;
struct AppParams params = struct AppParams params =
{ {
.vsync = true,
.autoResize = false, .autoResize = false,
.allowResize = true, .allowResize = true,
.keepAspect = true, .keepAspect = true,
@ -145,23 +144,22 @@ int renderThread(void * unused)
{ {
bool error = false; bool error = false;
struct KVMFRHeader header; struct KVMFRHeader header;
volatile int32_t * updateCount = &state.shm->updateCount - 1; volatile uint32_t * updateCount = &state.shm->updateCount;
while(state.running) while(state.running)
{ {
// if the next frame isn't aready available // poll until we have a new frame, or we time out
if (header.updateCount == *updateCount) while(header.updateCount == *updateCount && state.running) {
{ const struct timespec s = {
// poll until we have a new frame, or we time out .tv_sec = 0,
while(header.updateCount == *updateCount && state.running) { .tv_nsec = 1000
const struct timespec s = { };
.tv_sec = 0, nanosleep(&s, NULL);
.tv_nsec = 1000
};
nanosleep(&s, NULL);
}
} }
if (!state.running)
break;
// we must take a copy of the header, both to let the guest advance and to // we must take a copy of the header, both to let the guest advance and to
// prevent the contained arguments being abused to overflow buffers // prevent the contained arguments being abused to overflow buffers
memcpy(&header, state.shm, sizeof(struct KVMFRHeader)); memcpy(&header, state.shm, sizeof(struct KVMFRHeader));
@ -180,8 +178,10 @@ int renderThread(void * unused)
continue; continue;
} }
if(header.flags & KVMFR_HEADER_FLAG_FRAME) // if we have a frame
if (header.flags & KVMFR_HEADER_FLAG_FRAME)
{ {
// sainty check of the frame format
if ( if (
header.frame.type >= FRAME_TYPE_MAX || header.frame.type >= FRAME_TYPE_MAX ||
header.frame.width == 0 || header.frame.width == 0 ||
@ -239,7 +239,6 @@ int renderThread(void * unused)
lgrParams.window = state.window; lgrParams.window = state.window;
lgrParams.font = state.font; lgrParams.font = state.font;
lgrParams.showFPS = params.showFPS; lgrParams.showFPS = params.showFPS;
lgrParams.vsync = params.vsync;
lgrParams.width = width; lgrParams.width = width;
lgrParams.height = height; lgrParams.height = height;
@ -299,16 +298,40 @@ int renderThread(void * unused)
updatePositionInfo(); updatePositionInfo();
} }
if (!state.lgr->render( const uint8_t * data = (const uint8_t *)state.shm + header.frame.dataPos;
state.lgrData, if (!state.lgr->on_frame_event(state.lgrData, data, params.useMipmap))
(uint8_t *)state.shm + header.frame.dataPos,
params.useMipmap
))
{ {
DEBUG_ERROR("Failed to render the frame"); DEBUG_ERROR("Failed to render the frame");
break; break;
} }
} }
// if we have cursor data
if (header.flags & KVMFR_HEADER_FLAG_CURSOR)
{
if (header.cursor.flags & KVMFR_CURSOR_FLAG_POS)
{
state.cursor.x = header.cursor.x;
state.cursor.y = header.cursor.y;
}
if (header.cursor.flags & KVMFR_CURSOR_FLAG_SHAPE)
{
}
if (state.lgr)
{
state.lgr->on_mouse_event(
state.lgrData,
(header.cursor.flags & KVMFR_CURSOR_FLAG_VISIBLE) != 0,
state.cursor.x,
state.cursor.y
);
}
}
if (state.lgr)
state.lgr->render(state.lgrData);
} }
if (state.lgr) if (state.lgr)
@ -484,13 +507,12 @@ int eventThread(void * arg)
x = (float)x * state.scaleX; x = (float)x * state.scaleX;
y = (float)y * state.scaleY; y = (float)y * state.scaleY;
} }
x -= state.shm->cursor.x; x -= state.cursor.x;
y -= state.shm->cursor.y; y -= state.cursor.y;
realignGuest = false; realignGuest = false;
if (!spice_mouse_motion(x, y)) if (!spice_mouse_motion(x, y))
DEBUG_ERROR("SDL_MOUSEMOTION: failed to send message"); DEBUG_ERROR("SDL_MOUSEMOTION: failed to send message");
break; break;
} }
@ -612,9 +634,7 @@ int run()
FcPatternDestroy(pat); FcPatternDestroy(pat);
} }
if (!params.vsync) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
state.window = SDL_CreateWindow( state.window = SDL_CreateWindow(
"Looking Glass (Client)", "Looking Glass (Client)",
params.center ? SDL_WINDOWPOS_CENTERED : params.x, params.center ? SDL_WINDOWPOS_CENTERED : params.x,
@ -837,7 +857,7 @@ void doLicense()
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
int c; int c;
while((c = getopt(argc, argv, "hf:sc:p:jMmvkanrdx:y:w:b:l")) != -1) while((c = getopt(argc, argv, "hf:sc:p:jMmkanrdx:y:w:b:l")) != -1)
switch(c) switch(c)
{ {
case '?': case '?':
@ -874,10 +894,6 @@ int main(int argc, char * argv[])
params.useMipmap = false; params.useMipmap = false;
break; break;
case 'v':
params.vsync = false;
break;
case 'k': case 'k':
params.showFPS = true; params.showFPS = true;
break; break;

View File

@ -37,7 +37,7 @@ bool lgr_basic_initialize(void ** opaque, const LG_RendererParams params, const
this->renderer = SDL_CreateRenderer(params.window, -1, this->renderer = SDL_CreateRenderer(params.window, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_ACCELERATED |
(params.vsync ? SDL_RENDERER_PRESENTVSYNC : 0) SDL_RENDERER_PRESENTVSYNC
); );
if (!this->renderer) if (!this->renderer)

View File

@ -16,6 +16,11 @@
#define VBO_BUFFERS 2 #define VBO_BUFFERS 2
#define FPS_TEXTURE (VBO_BUFFERS )
#define MOUSE_TEXTURE (VBO_BUFFERS+1)
#define TEXTURE_COUNT MOUSE_TEXTURE
static PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI = NULL; static PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI = NULL;
static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI = NULL; static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI = NULL;
@ -25,6 +30,8 @@ struct LGR_OpenGL
bool initialized; bool initialized;
SDL_GLContext glContext; SDL_GLContext glContext;
bool resizeWindow; bool resizeWindow;
bool mouseUpdate;
bool frameUpdate;
LG_RendererFormat format; LG_RendererFormat format;
GLuint intFormat; GLuint intFormat;
@ -41,7 +48,7 @@ struct LGR_OpenGL
LG_RendererRect destRect; LG_RendererRect destRect;
bool hasTextures; bool hasTextures;
GLuint vboTex[VBO_BUFFERS + 1]; // extra texture for FPS GLuint textures[TEXTURE_COUNT];
uint gpuFrameCount; uint gpuFrameCount;
bool fpsTexture; bool fpsTexture;
@ -49,6 +56,11 @@ struct LGR_OpenGL
uint64_t renderTime; uint64_t renderTime;
uint64_t frameCount; uint64_t frameCount;
SDL_Rect fpsRect; SDL_Rect fpsRect;
bool mouseRepair;
SDL_Point mouseRepairPos;
bool mouseVisible;
SDL_Point mousePos;
}; };
void lgr_opengl_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect); void lgr_opengl_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect);
@ -112,7 +124,7 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
} }
} }
SDL_GL_SetSwapInterval(params.vsync ? 1 : 0); SDL_GL_SetSwapInterval(0);
// check if the GPU supports GL_ARB_buffer_storage first // check if the GPU supports GL_ARB_buffer_storage first
// there is no advantage to this renderer if it is not present. // there is no advantage to this renderer if it is not present.
@ -180,7 +192,7 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
} }
// create the textures // create the textures
glGenTextures(VBO_BUFFERS + (params.showFPS ? 1 : 0), this->vboTex); glGenTextures(TEXTURE_COUNT, this->textures);
if (lgr_opengl_check_error("glGenTextures")) if (lgr_opengl_check_error("glGenTextures"))
return false; return false;
this->hasTextures = true; this->hasTextures = true;
@ -188,7 +200,7 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
// bind the textures to the unpack buffers // bind the textures to the unpack buffers
for (int i = 0; i < VBO_BUFFERS; ++i) for (int i = 0; i < VBO_BUFFERS; ++i)
{ {
glBindTexture(GL_TEXTURE_2D, this->vboTex[i]); glBindTexture(GL_TEXTURE_2D, this->textures[i]);
if (lgr_opengl_check_error("glBindTexture")) if (lgr_opengl_check_error("glBindTexture"))
return false; return false;
@ -207,10 +219,13 @@ bool lgr_opengl_initialize(void ** opaque, const LG_RendererParams params, const
return false; return false;
} }
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);
glEnable(GL_SCISSOR_TEST);
this->resizeWindow = true; this->resizeWindow = true;
this->drawStart = nanotime(); this->drawStart = nanotime();
@ -229,7 +244,7 @@ void lgr_opengl_deinitialize(void * opaque)
return; return;
if (this->hasTextures) if (this->hasTextures)
glDeleteTextures(VBO_BUFFERS, this->vboTex); glDeleteTextures(VBO_BUFFERS, this->textures);
if (this->hasBuffers) if (this->hasBuffers)
glDeleteBuffers(VBO_BUFFERS, this->vboID); glDeleteBuffers(VBO_BUFFERS, this->vboID);
@ -262,7 +277,24 @@ void lgr_opengl_on_resize(void * opaque, const int width, const int height, cons
this->resizeWindow = true; this->resizeWindow = true;
} }
bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample) bool lgr_opengl_on_mouse_event(void * opaque, const bool visible, const int x, const int y)
{
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized)
return false;
if (this->mousePos.x == x && this->mousePos.y == y)
return true;
this->mouseUpdate = true;
this->mouseVisible = visible;
this->mousePos.x = x;
this->mousePos.y = y;
return false;
}
bool lgr_opengl_on_frame_event(void * opaque, const uint8_t * data, bool resample)
{ {
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque; struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized) if (!this || !this->initialized)
@ -274,34 +306,9 @@ bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample)
return false; return false;
} }
if (this->resizeWindow) if (++this->texIndex == VBO_BUFFERS)
{ this->texIndex = 0;
// setup the projection matrix
glViewport(0, 0, this->params.width, this->params.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, this->params.width, this->params.height, 0);
glMatrixMode(GL_MODELVIEW);
// update the display lists
for(int i = 0; i < VBO_BUFFERS; ++i)
{
glNewList(this->texList + i, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, this->vboTex[i]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f); glVertex2i(this->destRect.x , this->destRect.y );
glTexCoord2f(1.0f, 0.0f); glVertex2i(this->destRect.x + this->destRect.w, this->destRect.y );
glTexCoord2f(0.0f, 1.0f); glVertex2i(this->destRect.x , this->destRect.y + this->destRect.h);
glTexCoord2f(1.0f, 1.0f); glVertex2i(this->destRect.x + this->destRect.w, this->destRect.y + this->destRect.h);
glEnd();
glEndList();
}
this->resizeWindow = false;
}
glClear(GL_COLOR_BUFFER_BIT);
if (this->params.showFPS && this->renderTime > 1e9) if (this->params.showFPS && this->renderTime > 1e9)
{ {
char str[128]; char str[128];
@ -315,9 +322,9 @@ bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample)
return false; return false;
} }
glBindTexture(GL_TEXTURE_2D , this->vboTex[VBO_BUFFERS]); glBindTexture(GL_TEXTURE_2D , this->textures[VBO_BUFFERS]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 ); glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH, textSurface->w ); glPixelStorei(GL_UNPACK_ROW_LENGTH, textSurface->w );
glTexImage2D( glTexImage2D(
GL_TEXTURE_2D, GL_TEXTURE_2D,
0, 0,
@ -360,7 +367,7 @@ bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample)
glEnd(); glEnd();
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->vboTex[VBO_BUFFERS]); glBindTexture(GL_TEXTURE_2D, this->textures[VBO_BUFFERS]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP); glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f , 0.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y ); glTexCoord2f(0.0f , 0.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y );
@ -374,14 +381,13 @@ bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample)
// copy the buffer to the texture // copy the buffer to the texture
memcpySSE(this->texPixels[this->texIndex], data, this->texSize); memcpySSE(this->texPixels[this->texIndex], data, this->texSize);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texIndex]); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texIndex]);
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize); glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize);
// bind the texture and update it // bind the texture and update it
glBindTexture(GL_TEXTURE_2D , this->vboTex[this->texIndex]); glBindTexture(GL_TEXTURE_2D , this->textures[this->texIndex]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 ); glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH , this->format.width ); glPixelStorei(GL_UNPACK_ROW_LENGTH , this->format.width );
// update the texture // update the texture
glTexSubImage2D( glTexSubImage2D(
@ -417,37 +423,155 @@ bool lgr_opengl_render(void * opaque, const uint8_t * data, bool resample)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} }
// draw the screen this->frameUpdate = true;
glCallList(this->texList + this->texIndex); return true;
}
if (this->fpsTexture) void lgr_opengl_draw_mouse(struct LGR_OpenGL * this)
glCallList(this->fpsList); {
if (this->mouseRepair)
{
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(1.0f / (float)this->format.width, 1.0f / (float)this->format.height, 1.0f);
glTranslatef(this->mouseRepairPos.x, this->mouseRepairPos.y, 0.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(this->mouseRepairPos.x, this->mouseRepairPos.y, 0.0f);
glFlush(); // repair the damage from the cursor's last position
glBindTexture(GL_TEXTURE_2D, this->textures[this->texIndex]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0 , 0 ); glVertex2i(0 , 0 );
glTexCoord2f(32, 0 ); glVertex2i(32, 0 );
glTexCoord2f(0 , 32); glVertex2i(0 , 32);
glTexCoord2f(32, 32); glVertex2i(32, 32);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
this->mouseRepair = false;
++this->frameCount; glMatrixMode(GL_TEXTURE);
SDL_GL_SwapWindow(this->params.window); glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
// wait until the frame has been presented, this is to avoid the video card if (!this->mouseVisible)
// buffering frames, we would rather skip a frame then fall behind the guest return;
glXWaitVideoSyncSGI(1, 0, &this->gpuFrameCount);
const uint64_t t = nanotime(); this->mouseRepairPos.x = this->mousePos.x;
this->renderTime += t - this->lastFrameTime; this->mouseRepairPos.y = this->mousePos.y;
this->lastFrameTime = t; this->mouseRepair = true;
if (++this->texIndex == VBO_BUFFERS) glPushMatrix();
this->texIndex = 0; glTranslatef(this->mouseRepairPos.x, this->mouseRepairPos.y, 0.0f);
glDisable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glVertex2i(0 , 0 );
glVertex2i(32, 0 );
glVertex2i(0 , 32);
glVertex2i(32, 32);
glEnd();
glEnable(GL_TEXTURE_2D);
glPopMatrix();
}
bool lgr_opengl_render(void * opaque)
{
struct LGR_OpenGL * this = (struct LGR_OpenGL *)opaque;
if (!this || !this->initialized)
return false;
if (SDL_GL_MakeCurrent(this->params.window, this->glContext) != 0)
{
DEBUG_ERROR("Failed to make the GL context current");
return false;
}
if (this->resizeWindow)
{
// setup the projection matrix
glViewport(0, 0, this->params.width, this->params.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, this->params.width, this->params.height, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(this->destRect.x, this->destRect.y, 0.0f);
glScalef(
(float)this->destRect.w / (float)this->format.width,
(float)this->destRect.h / (float)this->format.height,
1.0f
);
// update the display lists
for(int i = 0; i < VBO_BUFFERS; ++i)
{
glNewList(this->texList + i, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, this->textures[i]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f); glVertex2i(0 , 0 );
glTexCoord2f(1.0f, 0.0f); glVertex2i(this->format.width, 0 );
glTexCoord2f(0.0f, 1.0f); glVertex2i(0 , this->format.height);
glTexCoord2f(1.0f, 1.0f); glVertex2i(this->format.width, this->format.height);
glEnd();
glEndList();
}
// update the scissor rect to prevent drawing outside of the frame
glScissor(0, 0, this->format.width, this->format.height);
this->resizeWindow = false;
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
}
if (this->frameUpdate)
{
glXWaitVideoSyncSGI(1, 0, &this->gpuFrameCount);
glFinish();
glCallList(this->texList + this->texIndex);
this->mouseRepair = false;
lgr_opengl_draw_mouse(this);
if (this->fpsTexture)
glCallList(this->fpsList);
glFlush();
++this->frameCount;
const uint64_t t = nanotime();
this->renderTime += t - this->lastFrameTime;
this->lastFrameTime = t;
}
else
if (this->mouseUpdate)
{
lgr_opengl_draw_mouse(this);
glFlush();
}
this->frameUpdate = false;
this->mouseUpdate = false;
return true; return true;
} }
const LG_Renderer LGR_OpenGL = const LG_Renderer LGR_OpenGL =
{ {
.get_name = lgr_opengl_get_name, .get_name = lgr_opengl_get_name,
.initialize = lgr_opengl_initialize, .initialize = lgr_opengl_initialize,
.deinitialize = lgr_opengl_deinitialize, .deinitialize = lgr_opengl_deinitialize,
.is_compatible = lgr_opengl_is_compatible, .is_compatible = lgr_opengl_is_compatible,
.on_resize = lgr_opengl_on_resize, .on_resize = lgr_opengl_on_resize,
.render = lgr_opengl_render .on_mouse_event = lgr_opengl_on_mouse_event,
.on_frame_event = lgr_opengl_on_frame_event,
.render = lgr_opengl_render
}; };