mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 14:57:20 +00:00
[client] huge rewrite of renderer API deal with mouse updates
This commit is contained in:
parent
a157f40690
commit
893bb7e603
@ -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))
|
||||||
|
@ -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;
|
@ -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
|
||||||
};
|
};
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user