diff --git a/src/render/ogc/SDL_render_ogc.c b/src/render/ogc/SDL_render_ogc.c index ece76c7fcde78..39996c8aececb 100644 --- a/src/render/ogc/SDL_render_ogc.c +++ b/src/render/ogc/SDL_render_ogc.c @@ -40,7 +40,6 @@ typedef struct { SDL_BlendMode current_blend_mode; - GXColor clear_color; int ops_after_present; bool vsync; u8 efb_pixel_format; @@ -67,8 +66,6 @@ static void OGC_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event static void set_blend_mode_real(SDL_Renderer *renderer, SDL_BlendMode blend_mode) { - OGC_RenderData *data = renderer->driverdata; - switch (blend_mode) { case SDL_BLENDMODE_NONE: GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_INVSRCALPHA, GX_LO_CLEAR); @@ -88,21 +85,19 @@ static void set_blend_mode_real(SDL_Renderer *renderer, SDL_BlendMode blend_mode default: return; } - - data->current_blend_mode = blend_mode; } static inline void OGC_SetBlendMode(SDL_Renderer *renderer, SDL_BlendMode blend_mode) { OGC_RenderData *data = renderer->driverdata; - if (data->ops_after_present > 0 && - blend_mode == data->current_blend_mode) { + if (blend_mode == data->current_blend_mode) { /* Nothing to do */ return; } set_blend_mode_real(renderer, blend_mode); + data->current_blend_mode = blend_mode; } static void load_efb_from_texture(SDL_Renderer *renderer, SDL_Texture *texture) @@ -111,6 +106,10 @@ static void load_efb_from_texture(SDL_Renderer *renderer, SDL_Texture *texture) OGC_load_texture(ogc_tex->texels, texture->w, texture->h, ogc_tex->format, SDL_ScaleModeNearest); + OGC_SetBlendMode(renderer, SDL_BLENDMODE_NONE); + + /* The viewport is reset when OGC_SetRenderTarget() returns. */ + OGC_set_viewport(0, 0, texture->w, texture->h); GX_ClearVtxDesc(); GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); @@ -119,9 +118,10 @@ static void load_efb_from_texture(SDL_Renderer *renderer, SDL_Texture *texture) GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 0); GX_SetNumTexGens(1); + GX_SetNumChans(0); GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL); GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); GX_SetNumTevStages(1); @@ -137,7 +137,7 @@ static void load_efb_from_texture(SDL_Renderer *renderer, SDL_Texture *texture) GX_End(); } -static void save_efb_to_texture(SDL_Texture *texture) +static void save_efb_to_texture(SDL_Texture *texture, bool must_clear) { OGC_TextureData *ogc_tex = texture->driverdata; u32 texture_size; @@ -148,7 +148,7 @@ static void save_efb_to_texture(SDL_Texture *texture) GX_SetTexCopySrc(0, 0, texture->w, texture->h); GX_SetTexCopyDst(texture->w, texture->h, ogc_tex->format, GX_FALSE); - GX_CopyTex(ogc_tex->texels, GX_TRUE); + GX_CopyTex(ogc_tex->texels, must_clear ? GX_TRUE : GX_FALSE); GX_PixModeSync(); } @@ -233,7 +233,7 @@ static void OGC_SetTextureScaleMode(SDL_Renderer *renderer, * loading it in OGC_load_texture(). */ } -static SDL_Texture *create_efb_texture(OGC_RenderData *data, SDL_Texture *target) +static SDL_Texture *create_efb_texture(OGC_RenderData *data, SDL_Window *window) { /* Note: we do return a SDL_Texture, but not via SDL's API, since that does * a bunch of other stuffs we don't care about. We create this texture for @@ -248,10 +248,10 @@ static SDL_Texture *create_efb_texture(OGC_RenderData *data, SDL_Texture *target ogc_tex = SDL_calloc(1, sizeof(OGC_TextureData)); if (!ogc_tex) goto fail_ogc_tex_alloc; - ogc_tex->format = data->efb_pixel_format == GX_PF_RGB565_Z16 ? - GX_TF_RGB565 : GX_TF_RGBA8; - texture->w = target->w; - texture->h = target->h; + ogc_tex->format = data->efb_pixel_format == GX_PF_RGBA6_Z24 ? + GX_TF_RGBA8 : GX_TF_RGB565; + texture->w = window->w; + texture->h = window->h; texture_size = GX_GetTexBufferSize(texture->w, texture->h, ogc_tex->format, GX_FALSE, 0); ogc_tex->texels = memalign(32, texture_size); @@ -274,24 +274,25 @@ static int OGC_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) OGC_RenderData *data = renderer->driverdata; u8 desired_efb_pixel_format = GX_PF_RGB8_Z24; + if (data->render_target) { + save_efb_to_texture(data->render_target, false); + } else if (data->ops_after_present > 0) { + /* Save the current EFB contents if we already drew something onto + * it. We'll restore it later, when the rendering target is reset + * to NULL (the screen). */ + if (!data->saved_efb_texture) + data->saved_efb_texture = create_efb_texture(data, renderer->window); + save_efb_to_texture(data->saved_efb_texture, false); + } + if (texture) { if (texture->w > MAX_EFB_WIDTH || texture->h > MAX_EFB_HEIGHT) { - return SDL_SetError("Render target bigger than EFB"); - } - - if (data->ops_after_present > 0) { - /* Save the current EFB contents if we already drew something onto - * it. We'll restore it later, when the rendering target is reset - * to NULL (the screen). */ - data->saved_efb_texture = create_efb_texture(data, texture); - save_efb_to_texture(data->saved_efb_texture); + return SDL_SetError("Render target (%dx%d) bigger than EFB", texture->w, texture->h); } if (SDL_ISPIXELFORMAT_ALPHA(texture->format)) { desired_efb_pixel_format = GX_PF_RGBA6_Z24; } - } else if (data->render_target) { - save_efb_to_texture(data->render_target); } data->render_target = texture; @@ -301,15 +302,13 @@ static int OGC_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) GX_SetPixelFmt(data->efb_pixel_format, GX_ZC_LINEAR); } - /* Restore the EFB to how it was before the we started to render to a - * texture. */ - if (!texture && data->saved_efb_texture) { + if (texture) { + load_efb_from_texture(renderer, texture); + } else if (data->saved_efb_texture) { + /* Restore the EFB to how it was before the we started to render to a + * texture. */ load_efb_from_texture(renderer, data->saved_efb_texture); - /* Flush the draw operation before destroying the texture */ - GX_DrawDone(); - OGC_DestroyTexture(renderer, data->saved_efb_texture); - SDL_free(data->saved_efb_texture); - data->saved_efb_texture = NULL; + /* We don't free data->saved_efb_texture, it will be reused */ } return 0; @@ -439,9 +438,11 @@ static int OGC_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) GX_SetScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h); - GX_SetClipMode(GX_CLIP_ENABLE); } else { - GX_SetClipMode(GX_CLIP_DISABLE); + GX_SetScissor(renderer->viewport.x, + renderer->viewport.y, + renderer->viewport.w, + renderer->viewport.h); } return 0; @@ -457,22 +458,35 @@ static int OGC_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) cmd->data.color.b, cmd->data.color.a }; + int16_t x1 = 0; + int16_t y1 = 0; + int16_t x2 = renderer->window->w; + int16_t y2 = renderer->window->h; + OGC_set_viewport(0, 0, renderer->window->w, renderer->window->h); + OGC_SetBlendMode(renderer, SDL_BLENDMODE_NONE); - /* If nothing has been drawn after Present, and if the clear color has not - * changed, there's no need to do anything here. */ - if (data->ops_after_present == 0 && - GX_COLOR_AS_U32(c) == GX_COLOR_AS_U32(data->clear_color)) { - return 0; - } + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); + GX_SetTevColor(GX_TEVREG0, c); + GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_C0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); + GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_A0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); + GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GX_SetNumTevStages(1); + GX_SetNumChans(0); - data->clear_color = c; - GX_SetCopyClear(c, GX_MAX_Z24); - if (renderer->target) { - save_efb_to_texture(renderer->target); - } else { - GX_CopyDisp(OGC_video_get_xfb(SDL_GetVideoDevice()), GX_TRUE); - } + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(x1, y1); + GX_Position2s16(x2, y1); + GX_Position2s16(x2, y2); + GX_Position2s16(x1, y2); + GX_End(); + data->ops_after_present++; + /* Restore the viewport */ + OGC_set_viewport(renderer->viewport.x, renderer->viewport.y, + renderer->viewport.w, renderer->viewport.h); return 0; } @@ -513,7 +527,9 @@ static int OGC_RenderGeometry(SDL_Renderer *renderer, void *vertices, GX_SetNumTevStages(stage - GX_TEVSTAGE0 + 1); } else { GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetNumTevStages(1); } + GX_SetNumChans(1); GX_Begin(GX_TRIANGLES, GX_VTXFMT0, count); for (int i = 0; i < count; i++) { @@ -538,6 +554,8 @@ int OGC_RenderPrimitive(SDL_Renderer *renderer, u8 primitive, OGC_RenderData *data = renderer->driverdata; size_t count = cmd->data.draw.count; const SDL_FPoint *verts = (SDL_FPoint *)(vertices + cmd->data.draw.first); + Mtx mv; + bool did_change_matrix = false; GXColor c = { cmd->data.draw.r, cmd->data.draw.g, @@ -548,6 +566,14 @@ int OGC_RenderPrimitive(SDL_Renderer *renderer, u8 primitive, data->ops_after_present++; OGC_SetBlendMode(renderer, cmd->data.draw.blend); + if (primitive == GX_LINESTRIP || primitive == GX_POINTS) { + float adjustment = 0.5; + guMtxIdentity(mv); + guMtxTransApply(mv, mv, adjustment, adjustment, 0); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + did_change_matrix = true; + } + /* TODO: optimize state changes. */ GX_SetTevColor(GX_TEVREG0, c); GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_C0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); @@ -569,11 +595,18 @@ int OGC_RenderPrimitive(SDL_Renderer *renderer, u8 primitive, /* The last point is not drawn */ if (primitive == GX_LINESTRIP) { - GX_Begin(GX_POINTS, GX_VTXFMT0, 1); - GX_Position2f32(verts[count - 1].x, verts[count - 1].y); + GX_Begin(GX_POINTS, GX_VTXFMT0, count); + for (int i = 0; i < count; i++) { + GX_Position2f32(verts[i].x, verts[i].y); + } GX_End(); } + if (did_change_matrix) { + guMtxIdentity(mv); + GX_LoadPosMtxImm(mv, GX_PNMTX0); + } + return 0; } @@ -657,6 +690,12 @@ static void OGC_DestroyRenderer(SDL_Renderer *renderer) OGC_RenderData *data = renderer->driverdata; if (data) { + GX_DrawDone(); + if (data->saved_efb_texture) { + OGC_DestroyTexture(renderer, data->saved_efb_texture); + SDL_free(data->saved_efb_texture); + } + SDL_free(data); } diff --git a/src/video/ogc/SDL_ogcevents.c b/src/video/ogc/SDL_ogcevents.c index 6fb8ac4557e34..4e4440d12dffe 100644 --- a/src/video/ogc/SDL_ogcevents.c +++ b/src/video/ogc/SDL_ogcevents.c @@ -84,6 +84,10 @@ static void pump_ir_events(_THIS) } } } + + if (OGC_prep_draw_cursor(_this)) { + OGC_video_flip(_this, false); + } } #endif diff --git a/src/video/ogc/SDL_ogcgxcommon.c b/src/video/ogc/SDL_ogcgxcommon.c index 56c017f271763..ed7e096369c5a 100644 --- a/src/video/ogc/SDL_ogcgxcommon.c +++ b/src/video/ogc/SDL_ogcgxcommon.c @@ -54,20 +54,8 @@ void OGC_set_viewport(int x, int y, int w, int h) void OGC_draw_init(int w, int h) { - Mtx mv; - SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "OGC_draw_init called with %d, %d", w, h); - guMtxIdentity(mv); - /* Ideally we would use 0.5 to center the coordinates on the pixels, but - * this causes some visual artifacts due to rounding: in the VVVVVV game, - * all 8x8 pixel textures lose their rightmost column and bottom row, - * except when they are drawn on the bottom-right quadrant of the screen. - * Values from 0.1 to 0.4 fix this issue, while preserving pixel accuracy - * on drawing operations. */ - guMtxTransApply(mv, mv, 0.4, 0.4, 0); - GX_LoadPosMtxImm(mv, GX_PNMTX0); - GX_ClearVtxDesc(); GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX8); diff --git a/src/video/ogc/SDL_ogcmouse.c b/src/video/ogc/SDL_ogcmouse.c index 7f750ec7e0fe7..6e3bda25650cc 100644 --- a/src/video/ogc/SDL_ogcmouse.c +++ b/src/video/ogc/SDL_ogcmouse.c @@ -33,9 +33,12 @@ #include "../SDL_sysvideo.h" #include "../../render/SDL_sysrender.h" +#include #include #include #include +#include +#include #include typedef struct _OGC_CursorData @@ -45,20 +48,69 @@ typedef struct _OGC_CursorData int w, h; } OGC_CursorData; -static void draw_cursor_rect(OGC_CursorData *curdata) +typedef struct +{ + void *texels; + int16_t x, y; + uint16_t w, h, maxside; +} OGC_CursorBackground; + +static OGC_CursorBackground s_cursor_background; +static int s_draw_counter = 0; +static bool s_extra_draw_enabled = false; +static bool s_2d_viewport_setup = false; + +static void draw_rect(s16 x, s16 y, u16 w, u16 h) { GX_Begin(GX_QUADS, GX_VTXFMT0, 4); - GX_Position2s16(-curdata->hot_x, -curdata->hot_y); + GX_Position2s16(x, y); GX_TexCoord2u8(0, 0); - GX_Position2s16(curdata->w - curdata->hot_x, -curdata->hot_y); + GX_Position2s16(x + w, y); GX_TexCoord2u8(1, 0); - GX_Position2s16(curdata->w - curdata->hot_x, curdata->h - curdata->hot_y); + GX_Position2s16(x + w, h + y); GX_TexCoord2u8(1, 1); - GX_Position2s16(-curdata->hot_x, curdata->h - curdata->hot_y); + GX_Position2s16(x, h + y); GX_TexCoord2u8(0, 1); GX_End(); } +static void draw_cursor_rect(OGC_CursorData *curdata) +{ + draw_rect(-curdata->hot_x, -curdata->hot_y, curdata->w, curdata->h); +} + +static void setup_2d_viewport(_THIS) +{ + int screen_w, screen_h; + + if (s_2d_viewport_setup) return; + + screen_w = _this->displays[0].current_mode.w; + screen_h = _this->displays[0].current_mode.h; + + OGC_set_viewport(0, 0, screen_w, screen_h); + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 0); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetNumTevStages(1); + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE); + GX_SetCullMode(GX_CULL_NONE); + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + + GX_SetNumTexGens(1); + GX_SetCurrentMtx(GX_PNMTX1); + + s_2d_viewport_setup = true; +} + /* Create a cursor from a surface */ static SDL_Cursor *OGC_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) { @@ -178,6 +230,11 @@ void OGC_draw_cursor(_THIS) int screen_w, screen_h; float angle = 0.0f; + s_draw_counter++; + + /* mark the texture as invalid */ + s_cursor_background.x = SHRT_MIN; + if (!mouse || !mouse->cursor_shown || !mouse->cur_cursor || !mouse->cur_cursor->driverdata) { return; @@ -195,6 +252,62 @@ void OGC_draw_cursor(_THIS) screen_h = _this->displays[0].current_mode.h; curdata = mouse->cur_cursor->driverdata; + + if (s_extra_draw_enabled) { + /* Save the are behind the cursor. We could use GX_ReadBoundingBox() to + * figure out which area to save, but that would require calling the + * drawing function once mode. So, let's just take a guess at the area, + * taking into account possible cursor rotation. */ + s16 x, y; + u16 w, h, radius, side; + u32 texture_size; + + /* +1 is for the rounding of x and y */ + radius = MAX(curdata->w, curdata->h) + 1; + x = mouse->x - radius; + y = mouse->y - radius; + /* x and y must be multiples of 2 */ + if (x % 2) x--; + if (y % 2) y--; + w = h = side = radius * 2; + if (x < 0) { + w += x; + x = 0; + } else if (x + w > screen_w) { + w = screen_w - x; + } + + if (y < 0) { + h += y; + y = 0; + } else if (y + h > screen_h) { + h = screen_h - y; + } + + /* Make sure all our variables are properly aligned */ + while (side % 4) side++; + while (w % 4) w++; + while (h % 4) h++; + + if (w > 0 && h > 0) { + texture_size = GX_GetTexBufferSize(side, side, GX_TF_RGBA8, + GX_FALSE, 0); + if (!s_cursor_background.texels || side > s_cursor_background.maxside) { + free(s_cursor_background.texels); + s_cursor_background.texels = memalign(32, texture_size); + s_cursor_background.maxside = side; + } + DCInvalidateRange(s_cursor_background.texels, texture_size); + GX_SetTexCopySrc(x, y, w, h); + GX_SetTexCopyDst(w, h, GX_TF_RGBA8, GX_FALSE); + GX_CopyTex(s_cursor_background.texels, GX_FALSE); + s_cursor_background.x = x; + s_cursor_background.y = y; + s_cursor_background.w = w; + s_cursor_background.h = h; + } + } + OGC_load_texture(curdata->texels, curdata->w, curdata->h, GX_TF_RGBA8, SDL_ScaleModeNearest); @@ -208,33 +321,19 @@ void OGC_draw_cursor(_THIS) guMtxTransApply(mv, mv, mouse->x, mouse->y, 0); GX_LoadPosMtxImm(mv, GX_PNMTX1); - OGC_set_viewport(0, 0, screen_w, screen_h); - - GX_ClearVtxDesc(); - GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); - GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 0); - GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); - - GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - GX_SetNumTevStages(1); - GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); - GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE); - GX_SetCullMode(GX_CULL_NONE); - GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); - + setup_2d_viewport(_this); - GX_SetNumTexGens(1); - GX_SetCurrentMtx(GX_PNMTX1); draw_cursor_rect(curdata); - GX_SetCurrentMtx(GX_PNMTX0); GX_DrawDone(); +} +void OGC_restore_viewport(_THIS) +{ /* Restore default state for SDL (opengx restores it at every frame, so we * don't care about it) */ + s_2d_viewport_setup = false; GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GX_SetCurrentMtx(GX_PNMTX0); if (_this->windows) { /* Restore previous viewport for the renderer */ SDL_Renderer *renderer = SDL_GetRenderer(_this->windows); @@ -245,6 +344,73 @@ void OGC_draw_cursor(_THIS) } } +bool OGC_prep_draw_cursor(_THIS) +{ + GXTexObj background; + Mtx mv; + static u32 last_draw_ms = 0; + u32 current_time_ms, elapsed_ms; + static int call_counter = 0; + static int last_draw_counter = 0; + + /* Ignore calls when a render target is set or OpenGL is not ready to swap + * the framebuffer */ + SDL_Renderer *renderer = SDL_GetRenderer(_this->windows); + if (renderer && renderer->target) return false; + + if (_this->gl_config.driver_loaded && + ogx_prepare_swap_buffers() < 0) return false; + + /* If this function is called repeatedly during the same frame, we assume + * that this is one of those applications that call SDL_OGC_GL_SwapWindow, + * SDL_UpdateWindowSurface or SDL_RenderPresent only if the video contents + * have actually changed. + * If that's the case, we toggle a flag that makes us redraw the screen + * when the mouse position has changed. + */ + if (!s_extra_draw_enabled) { + if (last_draw_counter != s_draw_counter) { + call_counter = 1; + last_draw_counter = s_draw_counter; + return false; + } + + if (call_counter++ > 10) { + s_extra_draw_enabled = true; + } else { + return false; + } + } + + /* Avoid drawing too often. 30 FPS should be enough */ + current_time_ms = gettime() / TB_TIMER_CLOCK; + elapsed_ms = current_time_ms - last_draw_ms; + if (elapsed_ms < 33) return false; + + /* If we have a texture for the cursor background, restore it; otherwise, + * we shouldn't draw the cursor. */ + if (!s_cursor_background.texels) return false; + + if (s_cursor_background.x != SHRT_MIN) { + setup_2d_viewport(_this); + + GX_PixModeSync(); + GX_InitTexObj(&background, s_cursor_background.texels, + s_cursor_background.w, s_cursor_background.h, + GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + GX_InitTexObjLOD(&background, GX_NEAR, GX_NEAR, + 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1); + GX_LoadTexObj(&background, GX_TEXMAP0); + GX_InvalidateTexAll(); + + guMtxIdentity(mv); + GX_LoadPosMtxImm(mv, GX_PNMTX1); + draw_rect(s_cursor_background.x, s_cursor_background.y, + s_cursor_background.w, s_cursor_background.h); + last_draw_ms = current_time_ms; + } + return true; +} #endif /* SDL_VIDEO_DRIVER_OGC */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/ogc/SDL_ogcmouse.h b/src/video/ogc/SDL_ogcmouse.h index 5035b4745a299..aa9ff173feb5a 100644 --- a/src/video/ogc/SDL_ogcmouse.h +++ b/src/video/ogc/SDL_ogcmouse.h @@ -28,6 +28,8 @@ void OGC_InitMouse(_THIS); void OGC_QuitMouse(_THIS); void OGC_draw_cursor(_THIS); +void OGC_restore_viewport(_THIS); +bool OGC_prep_draw_cursor(_THIS); SDL_Cursor *OGC_CreateSystemCursor(SDL_SystemCursor id); #endif /* SDL_OGC_mouse_h_ */ diff --git a/src/video/ogc/SDL_ogcvideo.c b/src/video/ogc/SDL_ogcvideo.c index a1c32b96d4657..5653700f738c3 100644 --- a/src/video/ogc/SDL_ogcvideo.c +++ b/src/video/ogc/SDL_ogcvideo.c @@ -205,6 +205,15 @@ static void OGC_ShowWindow(_THIS, SDL_Window *window) SDL_SetKeyboardFocus(window); } +static int OGC_ShowMessageBox(_THIS, const SDL_MessageBoxData *messageboxdata, + int *buttonid) +{ + /* Unimplemented, but at least show the message in the log */ + SDL_SetError("ShowMessageBox unimplemented: \"%s\", \"%s\"", + messageboxdata->title, messageboxdata->message); + return 0; +} + /* OGC driver bootstrap functions */ static void OGC_DeleteDevice(SDL_VideoDevice *device) @@ -243,6 +252,7 @@ static SDL_VideoDevice *OGC_CreateDevice(void) device->CreateWindowFramebuffer = SDL_OGC_CreateWindowFramebuffer; device->UpdateWindowFramebuffer = SDL_OGC_UpdateWindowFramebuffer; device->DestroyWindowFramebuffer = SDL_OGC_DestroyWindowFramebuffer; + device->ShowMessageBox = OGC_ShowMessageBox; #ifdef SDL_VIDEO_OPENGL device->GL_LoadLibrary = SDL_OGC_GL_LoadLibrary; @@ -345,12 +355,14 @@ void OGC_video_flip(_THIS, bool vsync) SDL_VideoData *videodata = _this->driverdata; void *xfb = OGC_video_get_xfb(_this); - if (ogx_prepare_swap_buffers() < 0) return; + if (_this->gl_config.driver_loaded && + ogx_prepare_swap_buffers() < 0) return; #ifdef __wii__ OGC_draw_cursor(_this); + OGC_restore_viewport(_this); #endif - GX_CopyDisp(xfb, GX_TRUE); + GX_CopyDisp(xfb, GX_FALSE); GX_DrawDone(); GX_Flush();