src/video/windows/SDL_gapirender.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Jan 2011 22:44:43 -0800
changeset 5138 da10636e5eca
parent 5090 327f181542f1
permissions -rw-r--r--
Making the API simpler, scaling is always defined as linear interpolation and should be supported as much as possible on all renderers.
     1 /***************************************************************************
     2  *   Copyright (C) 2010 by Andrey Afletdinov <afletdinov@gmail.com>        *
     3  *                                                                         *
     4  *   WinCE RAW/GAPI video driver                                           *
     5  *                                                                         *
     6  *   Part of the SDL - (Simple DirectMedia Layer)                          *
     7  *   http://www.libsdl.org                                                 *
     8  *                                                                         *
     9  *   This program is free software; you can redistribute it and/or modify  *
    10  *   it under the terms of the GNU General Public License as published by  *
    11  *   the Free Software Foundation; either version 2 of the License, or     *
    12  *   (at your option) any later version.                                   *
    13  *                                                                         *
    14  *   This program is distributed in the hope that it will be useful,       *
    15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
    16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
    17  *   GNU General Public License for more details.                          *
    18  *                                                                         *
    19  *   You should have received a copy of the GNU General Public License     *
    20  *   along with this program; if not, write to the                         *
    21  *   Free Software Foundation, Inc.,                                       *
    22  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
    23  ***************************************************************************/
    24 
    25 #include "SDL_config.h"
    26 
    27 #if SDL_VIDEO_RENDER_GAPI
    28 
    29 #include "SDL_windowsvideo.h"
    30 #include "SDL_windowswindow.h"
    31 #include "../SDL_yuv_sw_c.h"
    32 
    33 // RawFrameBufferInfo
    34 typedef struct
    35 {
    36    WORD wFormat;
    37    WORD wBPP;
    38    VOID *pFramePointer;
    39    int  cxStride;
    40    int  cyStride;
    41    int  cxPixels;
    42    int  cyPixels;
    43 } RawFrameBufferInfo;
    44 
    45 // GXDeviceInfo
    46 typedef struct
    47 {
    48     long Version;
    49     void* pvFrameBuffer;
    50     unsigned long cbStride;
    51     unsigned long cxWidth;
    52     unsigned long cyHeight;
    53     unsigned long cBPP;
    54     unsigned long ffFormat;
    55     char unknown[0x84 - 7 * 4];
    56 } GXDeviceInfo;
    57 
    58 // wince: GXDisplayProperties
    59 struct GXDisplayProperties
    60 {
    61     DWORD cxWidth;
    62     DWORD cyHeight;
    63     long cbxPitch;
    64     long cbyPitch;
    65     long cBPP;
    66     DWORD ffFormat;
    67 };
    68 
    69 // gx.dll
    70 typedef int   (*PFNGXOpenDisplay)(HWND hWnd, DWORD dwFlags);
    71 typedef int   (*PFNGXCloseDisplay)();
    72 typedef void* (*PFNGXBeginDraw)();
    73 typedef int   (*PFNGXEndDraw)();
    74 typedef struct GXDisplayProperties (*PFNGXGetDisplayProperties)();
    75 typedef int   (*PFNGXSuspend)();
    76 typedef int   (*PFNGXResume)();
    77 
    78 typedef struct
    79 {
    80     // gx.dll
    81     void*                     hGapiLib;
    82     PFNGXOpenDisplay          GXOpenDisplay;
    83     PFNGXCloseDisplay         GXCloseDisplay;
    84     PFNGXBeginDraw            GXBeginDraw;
    85     PFNGXEndDraw              GXEndDraw;
    86     PFNGXGetDisplayProperties GXGetDisplayProperties;
    87     PFNGXSuspend              GXSuspend;
    88     PFNGXResume               GXResume;
    89 } GapiInfo;
    90 
    91 //#ifndef DM_DISPLAYORIENTATION
    92 //#define DM_DISPLAYORIENTATION 0x00800000L
    93 //#endif
    94 
    95 #define FORMAT_565                1
    96 #define FORMAT_555                2
    97 #define FORMAT_OTHER                3
    98 
    99 #define GETRAWFRAMEBUFFER        0x00020001
   100 #define GETGXINFO                0x00020000
   101 
   102 #define kfPalette                0x10
   103 #define kfDirect                0x20
   104 #define kfDirect555                0x40
   105 #define kfDirect565                0x80
   106 
   107 #define GX_FULLSCREEN                0x01
   108 
   109 enum ScreenOrientation { ORIENTATION_UNKNOWN = -1, ORIENTATION_UP = DMDO_0, ORIENTATION_DOWN = DMDO_180, ORIENTATION_LEFT = DMDO_270, ORIENTATION_RIGHT = DMDO_90 };
   110 enum ScreenGeometry { GEOMETRY_UNKNOWN, GEOMETRY_PORTRAIT, GEOMETRY_LANDSCAPE, GEOMETRY_SQUARE };
   111 enum FrameBufferFlags { FB_SKIP_OFFSET = 0x0001, FB_RAW_MODE = 0x0002, FB_SUSPENDED = 0x0004 };
   112 
   113 // private framebuffer info
   114 typedef struct
   115 {
   116     int width;
   117     int height;
   118     int xpitch;
   119     int ypitch;
   120     int offset;
   121 } FrameBufferInfo;
   122 
   123 // private display data
   124 typedef struct
   125 {
   126     unsigned char* pixels;        // video memory
   127     int format;                        // video format
   128     FrameBufferInfo fb;                // framebuffer geometry
   129     GapiInfo* gapi;                // GAPI module
   130     int userOrientation;
   131     int systemOrientation;
   132     int hardwareGeometry;
   133     int flags;                        // fb flags
   134     float scale;                // scale pointer position
   135     int debug;
   136 
   137 } WINCE_RenderData;
   138 
   139 typedef struct
   140 {
   141     SDL_SW_YUVTexture *yuv;
   142     Uint32 format;
   143     void *pixels;
   144     int pitch;
   145 
   146 } WINCE_TextureData;
   147 
   148 
   149 // system func
   150 SDL_Renderer*        WINCE_CreateRenderer(SDL_Window* window, Uint32 flags);
   151 void                WINCE_DestroyRenderer(SDL_Renderer* renderer);
   152 
   153 int                WINCE_CreateTexture(SDL_Renderer* renderer, SDL_Texture* texture);
   154 void                WINCE_DestroyTexture(SDL_Renderer* renderer, SDL_Texture* texture);
   155 int                WINCE_QueryTexturePixels(SDL_Renderer* renderer, SDL_Texture* texture, void** pixels, int* pitch);
   156 int                WINCE_UpdateTexture(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* rect, const void* pixels, int pitch);
   157 int                WINCE_LockTexture(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* rect, int dirty, void** pixels, int* pitch);
   158 void                WINCE_UnlockTexture(SDL_Renderer* renderer, SDL_Texture* texture);
   159 
   160 int                WINCE_Available(void);
   161 void                WINCE_SetupOrientation(WINCE_RenderData* data, int width, int height);
   162 
   163 int                WINCE_RenderCopy(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* srect, const SDL_Rect* drect);
   164 void                WINCE_ShowWindow(_THIS, SDL_Window* window, int visible);
   165 
   166 void                WINCE_RenderPresent(SDL_Renderer* renderer);
   167 int                WINCE_RenderDrawPoints(SDL_Renderer* renderer, const SDL_Point* points, int count);
   168 int                WINCE_RenderDrawLines(SDL_Renderer* renderer, const SDL_Point* points, int count);
   169 int                WINCE_RenderDrawRects(SDL_Renderer* renderer, const SDL_Rect ** rects, int count);
   170 int                WINCE_RenderFillRects(SDL_Renderer* renderer, const SDL_Rect** rects, int count);
   171 
   172 void                WINCE_PointerCoordinateTransform(SDL_Window* window, POINT* pt);
   173 void                WINCE_DumpVideoInfo(WINCE_RenderData* data);
   174 void                WINCE_PortraitTransform(WINCE_RenderData* data, int width, int height);
   175 void                WINCE_LandscapeTransform(WINCE_RenderData* data, int width, int height);
   176 void                WINCE_SquareTransform(WINCE_RenderData* data, int width, int height);
   177 int                WINCE_FixedGeometry(FrameBufferInfo* fb, int bpp, int debug);
   178 int                WINCE_GetDMOrientation(void);
   179 int                WINCE_SetDMOrientation(int orientation);
   180 void                WINCE_UpdateYUVTextureData(SDL_Texture* texture);
   181 
   182 // gapi engine specific
   183 int                GAPI_Init(WINCE_RenderData* data, HWND hwnd);
   184 void                GAPI_Quit(WINCE_RenderData* data);
   185 
   186 // raw engine specific
   187 int                RAW_Init(WINCE_RenderData* data);
   188 void                RAW_Quit(WINCE_RenderData* data);
   189 
   190 // tools
   191 void                FrameBufferRotate(FrameBufferInfo* src, int orientation);
   192 int                GetFrameBufferOrientation(const FrameBufferInfo* src);
   193 void                PointerRotate(POINT* pt, const FrameBufferInfo* fb, int orientation);
   194 void                FrameBufferInitialize(FrameBufferInfo* fb);
   195 void                FrameBufferDumpInfo(const FrameBufferInfo* fb, const char*);
   196 const                char* GetOrientationName(int orientation);
   197 void                UpdateLine16to16(const FrameBufferInfo* fb, const Uint16* src, Uint16* dst, Uint16 width);
   198 
   199 // stdlib
   200 static __inline__ int        __abs(int x){ return x < 0 ? -x : x; };
   201 static __inline__ void        __swap(int* a, int* b){ int t = *a; *a = *b; *b = t; };
   202 
   203 #define GAPI_RENDER_NAME        "gapi"
   204 #define RAW_RENDER_NAME                "raw"
   205 //
   206 SDL_RenderDriver GAPI_RenderDriver = {
   207     WINCE_CreateRenderer,
   208     {
   209         GAPI_RENDER_NAME,
   210         (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD),
   211         (SDL_TEXTUREMODULATE_NONE),
   212         (SDL_BLENDMODE_NONE),
   213         7,
   214         {
   215             SDL_PIXELFORMAT_RGB555,
   216             SDL_PIXELFORMAT_RGB565,
   217             SDL_PIXELFORMAT_YV12,
   218             SDL_PIXELFORMAT_IYUV,
   219             SDL_PIXELFORMAT_YUY2,
   220             SDL_PIXELFORMAT_UYVY,
   221             SDL_PIXELFORMAT_YVYU
   222         },
   223         0,
   224         0
   225     }
   226 };
   227 
   228 SDL_RenderDriver RAW_RenderDriver = {
   229     WINCE_CreateRenderer,
   230     {
   231         RAW_RENDER_NAME,
   232         (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD),
   233         (SDL_TEXTUREMODULATE_NONE),
   234         (SDL_BLENDMODE_NONE),
   235         7,
   236         {
   237             SDL_PIXELFORMAT_RGB555,
   238             SDL_PIXELFORMAT_RGB565,
   239             SDL_PIXELFORMAT_YV12,
   240             SDL_PIXELFORMAT_IYUV,
   241             SDL_PIXELFORMAT_YUY2,
   242             SDL_PIXELFORMAT_UYVY,
   243             SDL_PIXELFORMAT_YVYU
   244         },
   245         0,
   246         0
   247     }
   248 };
   249 
   250 int WINCE_Available(void)
   251 {
   252     void* render_gapi;
   253     const char* preferably = SDL_getenv("SDL_VIDEO_RENDERER");
   254 
   255     // raw check
   256     RawFrameBufferInfo rfbi = { 0 };
   257     HDC hdc = GetDC(NULL);
   258     int render_raw = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *) &rfbi);
   259     ReleaseDC(NULL, hdc);
   260 
   261     if(render_raw != 0 && rfbi.cxPixels != 0 && rfbi.cyPixels != 0 &&
   262        rfbi.pFramePointer != 0 && rfbi.cxStride != 0 && rfbi.cyStride != 0)
   263         render_raw = 1;
   264 
   265     if(preferably && 0 == SDL_strcasecmp(preferably, RAW_RENDER_NAME)) return 0 != render_raw;
   266 
   267     // gapi check
   268     render_gapi = SDL_LoadObject("\\Windows\\gx.dll");
   269     if(0 == render_gapi)
   270         render_gapi = SDL_LoadObject("gx.dll");
   271     SDL_UnloadObject(render_gapi);
   272 
   273     if(preferably && 0 == SDL_strcasecmp(preferably, GAPI_RENDER_NAME)) return 0 != render_gapi;
   274 
   275     return 0 != render_raw || 0 != render_gapi;
   276 }
   277 
   278 void WINCE_AddRenderDriver(_THIS)
   279 {
   280     HDC hdc;
   281     void* render_gapi;
   282     int render_raw, ii;
   283     const char* preferably = SDL_getenv("SDL_VIDEO_RENDERER");
   284 
   285    // raw check
   286     RawFrameBufferInfo rfbi = { 0 };
   287     hdc = GetDC(NULL);
   288     render_raw = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *) &rfbi);
   289     ReleaseDC(NULL, hdc);
   290 
   291     if(render_raw != 0 && rfbi.cxPixels != 0 && rfbi.cyPixels != 0 &&
   292             rfbi.pFramePointer != 0 && rfbi.cxStride != 0 && rfbi.cyStride != 0)
   293             render_raw = 1;
   294 
   295     // gapi check
   296     render_gapi = SDL_LoadObject("\\Windows\\gx.dll");
   297     if(0 == render_gapi)
   298         render_gapi = SDL_LoadObject("gx.dll");
   299 
   300     if(render_gapi)
   301         SDL_UnloadObject(render_gapi);
   302 
   303     for(ii = 0; ii < _this->num_displays; ++ii)
   304     {
   305         if(preferably)
   306         {
   307             if(0 == SDL_strcasecmp(preferably, RAW_RENDER_NAME) && render_raw)
   308                 SDL_AddRenderDriver(&_this->displays[ii], &RAW_RenderDriver);
   309             else
   310             if(0 == SDL_strcasecmp(preferably, GAPI_RENDER_NAME) && render_gapi)
   311                 SDL_AddRenderDriver(&_this->displays[ii], &GAPI_RenderDriver);
   312         }
   313         else
   314         {
   315             if(render_raw)
   316                 SDL_AddRenderDriver(&_this->displays[ii], &RAW_RenderDriver);
   317             if(render_gapi)
   318                 SDL_AddRenderDriver(&_this->displays[ii], &GAPI_RenderDriver);
   319         }
   320     }
   321 }
   322 
   323 SDL_Renderer* WINCE_CreateRenderer(SDL_Window* window, Uint32 flags)
   324 {
   325     SDL_VideoDisplay* display = window->display;
   326     SDL_DisplayMode* displayMode = &display->current_mode;
   327     SDL_WindowData* windowdata = (SDL_WindowData *) window->driverdata;
   328     SDL_Renderer* renderer;
   329     WINCE_RenderData* data;
   330     int bpp;
   331     Uint32 Rmask, Gmask, Bmask, Amask;
   332 
   333     if(!(window->flags & SDL_WINDOW_FULLSCREEN))
   334         window->flags |= SDL_WINDOW_FULLSCREEN;
   335 
   336     if(!SDL_PixelFormatEnumToMasks(displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask))
   337     {
   338         SDL_SetError("Unknown display format");
   339         return NULL;
   340     }
   341 
   342     switch(window->fullscreen_mode.format)
   343     {
   344         case SDL_PIXELFORMAT_RGB555:
   345         case SDL_PIXELFORMAT_RGB565:
   346             break;
   347 
   348         default:
   349             SDL_SetError("Support only 16 or 15 bpp");
   350             return NULL;
   351     }
   352 
   353     renderer = (SDL_Renderer*) SDL_calloc(1, sizeof(SDL_Renderer));
   354     if(!renderer)
   355     {
   356         SDL_OutOfMemory();
   357         return NULL;
   358     }
   359 
   360     data = (WINCE_RenderData*) SDL_calloc(1, sizeof(WINCE_RenderData));
   361     if(!data)
   362     {
   363         WINCE_DestroyRenderer(renderer);
   364         SDL_OutOfMemory();
   365         return NULL;
   366     }
   367 
   368     // initialize internal engine
   369     if(!RAW_Init(data) && !GAPI_Init(data, windowdata->hwnd))
   370     {
   371         WINCE_DestroyRenderer(renderer);
   372         return NULL;
   373     }
   374 
   375 
   376     // set debug
   377     data->debug        = SDL_getenv("DEBUG_VIDEO_GAPI") || SDL_getenv("GAPI_RENDERER_DEBUG") ? 1 : 0;
   378 #if defined(DEBUG_VIDEO_GAPI) || defined(GAPI_RENDERER_DEBUG)
   379     data->debug        = 1;
   380 #endif
   381 
   382     windowdata->videodata->render = data->gapi ? RENDER_GAPI : RENDER_RAW;
   383     windowdata->videodata->CoordTransform = WINCE_PointerCoordinateTransform;
   384 
   385     window->display->device->MaximizeWindow = NULL;
   386     window->display->device->MinimizeWindow = NULL;
   387 
   388     WINCE_SetupOrientation(data, window->w, window->h);
   389 
   390     renderer->CreateTexture = WINCE_CreateTexture;
   391     renderer->DestroyTexture = WINCE_DestroyTexture;
   392     renderer->QueryTexturePixels = WINCE_QueryTexturePixels;
   393     renderer->UpdateTexture = WINCE_UpdateTexture;
   394     renderer->LockTexture = WINCE_LockTexture;
   395     renderer->UnlockTexture = WINCE_UnlockTexture;
   396 
   397     renderer->RenderCopy = WINCE_RenderCopy;
   398     renderer->DestroyRenderer = WINCE_DestroyRenderer;
   399 
   400     renderer->RenderPresent = WINCE_RenderPresent;
   401     renderer->RenderDrawPoints = WINCE_RenderDrawPoints;
   402     renderer->RenderDrawLines = WINCE_RenderDrawLines;
   403     renderer->RenderDrawRects = WINCE_RenderDrawRects;
   404     renderer->RenderFillRects = WINCE_RenderFillRects;
   405 
   406     renderer->info = data->gapi ? GAPI_RenderDriver.info : RAW_RenderDriver.info;
   407 
   408     renderer->window = window;
   409     renderer->driverdata = data;
   410 
   411     return renderer;
   412 }
   413 
   414 void WINCE_DestroyRenderer(SDL_Renderer* renderer)
   415 {
   416     WINCE_RenderData *renderdata = (WINCE_RenderData*) renderer->driverdata;
   417 
   418     if(renderdata)
   419     {
   420         if(renderdata->gapi)
   421             GAPI_Quit(renderdata);
   422         else
   423             RAW_Quit(renderdata);
   424 
   425         SDL_free(renderdata);
   426     }
   427 
   428     SDL_free(renderer);
   429 }
   430 
   431 int WINCE_CreateTexture(SDL_Renderer* renderer, SDL_Texture* texture)
   432 {
   433     WINCE_TextureData* texturedata = (WINCE_TextureData*) SDL_calloc(1, sizeof(WINCE_TextureData));
   434     if(NULL == texturedata)
   435     {
   436         SDL_OutOfMemory();
   437         return -1;
   438     }
   439 
   440     texturedata->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   441     texturedata->pixels = SDL_malloc(texture->h * texturedata->pitch);
   442     if(NULL == texturedata->pixels)
   443     {
   444         SDL_OutOfMemory();
   445         return -1;
   446     }
   447 
   448     if(SDL_ISPIXELFORMAT_FOURCC(texture->format))
   449     {
   450         SDL_Window* window = renderer->window;
   451         SDL_VideoDisplay* display = window->display;
   452 
   453         texturedata->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   454         if(NULL == texturedata->yuv)
   455         {
   456             SDL_OutOfMemory();
   457             return -1;
   458         }
   459         texturedata->format = display->current_mode.format;
   460     }
   461     else
   462     {
   463         texturedata->yuv = NULL;
   464         texturedata->format = texture->format;
   465     }
   466 
   467     texture->driverdata = texturedata;
   468 
   469     return 0;
   470 }
   471 
   472 void WINCE_DestroyTexture(SDL_Renderer* renderer, SDL_Texture* texture)
   473 {
   474     WINCE_TextureData *texturedata = (WINCE_TextureData*) texture->driverdata;
   475 
   476     if(texturedata)
   477     {
   478         if(texturedata->yuv) SDL_SW_DestroyYUVTexture(texturedata->yuv);
   479         if(texturedata->pixels) SDL_free(texturedata->pixels);
   480         SDL_free(texturedata);
   481         texture->driverdata = NULL;
   482     }
   483 }
   484 
   485 int WINCE_QueryTexturePixels(SDL_Renderer* renderer, SDL_Texture* texture, void** pixels, int* pitch)
   486 {
   487     WINCE_TextureData* texturedata = (WINCE_TextureData*) texture->driverdata;
   488 
   489     if(texturedata->yuv)
   490         return SDL_SW_QueryYUVTexturePixels(texturedata->yuv, pixels, pitch);
   491 
   492     *pixels = texturedata->pixels;
   493     *pitch = texturedata->pitch;
   494 
   495     return 0;
   496 }
   497 
   498 int WINCE_UpdateTexture(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* rect, const void* pixels, int pitch)
   499 {
   500     WINCE_TextureData* texturedata = (WINCE_TextureData*) texture->driverdata;
   501 
   502     if(texturedata->yuv)
   503     {
   504         if(SDL_SW_UpdateYUVTexture(texturedata->yuv, rect, pixels, pitch) < 0)
   505             return -1;
   506         WINCE_UpdateYUVTextureData(texture);
   507         return 0;
   508     }
   509 
   510     if(0 < rect->w && 0 < rect->h)
   511     {
   512         const unsigned char *src = ((const unsigned char*) pixels);
   513         unsigned char *dst = ((unsigned char*) texturedata->pixels) +
   514                                 rect->y * texturedata->pitch +
   515                                 rect->x * SDL_BYTESPERPIXEL(texture->format);
   516         int length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   517         int height = rect->h;
   518 
   519         while(height--)
   520         {
   521             SDL_memcpy(dst, src, length);
   522             dst += texturedata->pitch;
   523             src += pitch;
   524         }
   525     }
   526 
   527     return 0;
   528 }
   529 
   530 int WINCE_LockTexture(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* rect, int dirty, void** pixels, int* pitch)
   531 {
   532     WINCE_TextureData *texturedata = (WINCE_TextureData*) texture->driverdata;
   533 
   534     if(texturedata->yuv)
   535         return SDL_SW_LockYUVTexture(texturedata->yuv, rect, dirty, pixels, pitch);
   536 
   537     *pixels = (void *) ((unsigned char*) texturedata->pixels +
   538                     rect->y * texturedata->pitch +
   539                     rect->x * SDL_BYTESPERPIXEL(texture->format));
   540     *pitch = texturedata->pitch;
   541     return 0;
   542 }
   543 
   544 void WINCE_UnlockTexture(SDL_Renderer* renderer, SDL_Texture* texture)
   545 {
   546     WINCE_TextureData *texturedata = (WINCE_TextureData*) texture->driverdata;
   547 
   548     if(texturedata->yuv)
   549     {
   550         SDL_SW_UnlockYUVTexture(texturedata->yuv);
   551         WINCE_UpdateYUVTextureData(texture);
   552     }
   553 }
   554 
   555 int WINCE_RenderCopy(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* srect, const SDL_Rect* drect)
   556 {
   557     WINCE_RenderData* dstdata = (WINCE_RenderData*) renderer->driverdata;
   558     WINCE_TextureData* srcdata = (WINCE_TextureData*) texture->driverdata;
   559     const unsigned char *src;
   560     unsigned char *dst;
   561 
   562     if((dstdata->flags & FB_SUSPENDED) ||
   563        0 >= srect->w || 0 >= srect->h) return 0;
   564 
   565     // lock gapi
   566     if(dstdata->gapi) dstdata->gapi->GXBeginDraw();
   567 
   568     src = ((const unsigned char*) srcdata->pixels);
   569     dst = dstdata->pixels + (dstdata->flags & FB_SKIP_OFFSET ? 0 : dstdata->fb.offset) +
   570                                 drect->y * dstdata->fb.ypitch +
   571                                 drect->x * dstdata->fb.xpitch;
   572     if(srcdata->yuv)
   573     {
   574         return SDL_SW_CopyYUVToRGB(srcdata->yuv,
   575                                    srect, srcdata->format,
   576                                    drect->w, drect->h, dst,
   577                                    dstdata->fb.ypitch);
   578     }
   579     else
   580     {
   581         int height = drect->h;
   582         int length = drect->w * SDL_BYTESPERPIXEL(texture->format); // in bytes
   583 
   584         while(height--)
   585         {
   586             switch(SDL_BYTESPERPIXEL(texture->format))
   587             {
   588                 case 2: UpdateLine16to16(&dstdata->fb, (Uint16*) src, (Uint16*) dst, length >> 1); break;
   589 
   590                 default: break;
   591             }
   592 
   593             dst += dstdata->fb.ypitch;
   594             src += srcdata->pitch;
   595         }
   596     }
   597 
   598     // unlock gapi
   599     if(dstdata->gapi) dstdata->gapi->GXEndDraw();
   600 
   601     return 0;
   602 }
   603 
   604 void WINCE_RenderPresent(SDL_Renderer* renderer)
   605 {
   606 }
   607 
   608 int WINCE_RenderDrawPoints(SDL_Renderer* renderer, const SDL_Point* points, int count)
   609 {
   610     SDL_Unsupported();
   611     return -1;
   612 }
   613 
   614 int WINCE_RenderDrawLines(SDL_Renderer* renderer, const SDL_Point* points, int count)
   615 {
   616     SDL_Unsupported();
   617     return -1;
   618 }
   619 
   620 int WINCE_RenderDrawRects(SDL_Renderer* renderer, const SDL_Rect ** rects, int count)
   621 {
   622     SDL_Unsupported();
   623     return -1;
   624 }
   625 
   626 int WINCE_RenderFillRects(SDL_Renderer* renderer, const SDL_Rect** rects, int count)
   627 {
   628     SDL_Unsupported();
   629     return -1;
   630 }
   631 
   632 
   633 
   634 void WINCE_SetupOrientation(WINCE_RenderData* data, int width, int height)
   635 {
   636     const float maxW1 = (float)(GetSystemMetrics(SM_CXSCREEN) > GetSystemMetrics(SM_CYSCREEN) ? GetSystemMetrics(SM_CXSCREEN) : GetSystemMetrics(SM_CYSCREEN));
   637     const float maxW2 = (float)(data->fb.width > data->fb.height ? data->fb.width : data->fb.height);
   638 
   639     // scale define
   640     data->scale = maxW2 / maxW1;
   641 
   642     // init fb values
   643     FrameBufferInitialize(&data->fb);
   644 
   645     // orientation values
   646     data->userOrientation = ORIENTATION_UP;
   647     data->systemOrientation = WINCE_GetDMOrientation();
   648     data->hardwareGeometry = data->fb.width == data->fb.height ? GEOMETRY_SQUARE :
   649                                 (data->fb.width < data->fb.height ? GEOMETRY_PORTRAIT : GEOMETRY_LANDSCAPE);
   650 
   651     if(data->debug)
   652         WINCE_DumpVideoInfo(data);
   653 
   654     if(data->systemOrientation == ORIENTATION_UNKNOWN)
   655         data->systemOrientation = ORIENTATION_UP;
   656 
   657     data->userOrientation = ORIENTATION_UP;
   658 
   659     switch(data->hardwareGeometry)
   660     {
   661         case GEOMETRY_PORTRAIT:  WINCE_PortraitTransform(data, width, height); break;
   662         case GEOMETRY_LANDSCAPE: WINCE_LandscapeTransform(data, width, height); break;
   663         case GEOMETRY_SQUARE:    WINCE_SquareTransform(data, width, height); break;
   664         default: break;
   665     }
   666 
   667     // debug
   668     if(data->debug)
   669     {
   670         printf("\n");
   671         printf("user video width:          %d\n", width);
   672         printf("user video height:         %d\n", height);
   673         FrameBufferDumpInfo(&data->fb, "user");
   674     }
   675 }
   676 
   677 void WINCE_DumpVideoInfo(WINCE_RenderData* data)
   678 {
   679     // get oem info
   680     WCHAR oemInfo[48];
   681     SDL_memset(oemInfo, 0, sizeof(oemInfo));
   682     SystemParametersInfo(SPI_GETOEMINFO, sizeof(oemInfo) - sizeof(WCHAR), oemInfo, 0);
   683 
   684     printf("hardware oem: ");
   685     wprintf(oemInfo);
   686     printf("\n");
   687 
   688     printf("video driver mode:             %s\n", (data->flags & FB_RAW_MODE ? RAW_RENDER_NAME : GAPI_RENDER_NAME));
   689     printf("GetSystemMetrics(SM_CXSCREEN): %d\n", GetSystemMetrics(SM_CXSCREEN));
   690     printf("GetSystemMetrics(SM_CYSCREEN): %d\n", GetSystemMetrics(SM_CYSCREEN));
   691     printf("scale coord:                   %f\n", data->scale);
   692 
   693     FrameBufferDumpInfo(&data->fb, "hardware");
   694 
   695     printf("display format:                %p\n", data->format);
   696     printf("display bits per pixel:        %d\n", SDL_BITSPERPIXEL(data->format));
   697     printf("display bytes per pixel:       %d\n", SDL_BYTESPERPIXEL(data->format));
   698     printf("display memory:                %p\n", data->pixels);
   699     printf("system orientation:            %d, %s\n", data->systemOrientation, GetOrientationName(data->systemOrientation));
   700     printf("hardware geometry:             %d\n", data->hardwareGeometry);
   701 }
   702 
   703 void WINCE_ShowWindow(_THIS, SDL_Window* window, int visible)
   704 {
   705     SDL_WindowData* windowdata = (SDL_WindowData*) window->driverdata;
   706     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   707     SDL_Renderer* renderer = (SDL_Renderer*) window->renderer;
   708 
   709     if(visible)
   710     {
   711         if(window->flags & SDL_WINDOW_FULLSCREEN)
   712         {
   713             if(videodata->SHFullScreen)
   714                 videodata->SHFullScreen(windowdata->hwnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);
   715             ShowWindow(FindWindow(TEXT("HHTaskBar"), NULL), SW_HIDE);
   716         }
   717 
   718         ShowWindow(windowdata->hwnd, SW_SHOW);
   719         SetForegroundWindow(windowdata->hwnd);
   720 
   721         if(renderer &&
   722             (videodata->render == RENDER_GAPI || videodata->render == RENDER_RAW))
   723         {
   724             WINCE_RenderData* renderdata = (WINCE_RenderData*) renderer->driverdata;
   725             renderdata->flags &= ~FB_SUSPENDED;
   726             if(renderdata->gapi) renderdata->gapi->GXResume();
   727         }
   728     }
   729     else
   730     {
   731         if(renderer &&
   732             (videodata->render == RENDER_GAPI || videodata->render == RENDER_RAW))
   733         {
   734             WINCE_RenderData* renderdata = (WINCE_RenderData*) renderer->driverdata;
   735             if(renderdata->gapi) renderdata->gapi->GXSuspend();
   736             renderdata->flags |= FB_SUSPENDED;
   737         }
   738 
   739         ShowWindow(windowdata->hwnd, SW_HIDE);
   740 
   741         if(window->flags & SDL_WINDOW_FULLSCREEN)
   742         {
   743             if(videodata->SHFullScreen)
   744                 videodata->SHFullScreen(windowdata->hwnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON | SHFS_SHOWSIPBUTTON);
   745             ShowWindow(FindWindow(TEXT("HHTaskBar"), NULL), SW_SHOW);
   746         }
   747     }
   748 }
   749 
   750 
   751 void WINCE_PointerCoordinateTransform(SDL_Window* window, POINT* pt)
   752 {
   753     WINCE_RenderData* data = (WINCE_RenderData*) window->renderer->driverdata;
   754 
   755     pt->x = (LONG)(pt->x * data->scale);
   756     pt->y = (LONG)(pt->y * data->scale);
   757 
   758     PointerRotate(pt, &data->fb, data->userOrientation);
   759 }
   760 
   761 void WINCE_PortraitTransform(WINCE_RenderData* data, int width, int height)
   762 {
   763     if(data->systemOrientation != ORIENTATION_UP)
   764         FrameBufferRotate(&data->fb, data->systemOrientation);
   765 
   766     if(data->fb.width != width || data->fb.height != height) {
   767         switch(data->systemOrientation)
   768         {
   769             case ORIENTATION_UP:
   770             case ORIENTATION_LEFT: data->userOrientation = ORIENTATION_RIGHT; break;
   771             case ORIENTATION_RIGHT:
   772             case ORIENTATION_DOWN: data->userOrientation = ORIENTATION_LEFT; break;
   773             default: break;
   774         }
   775     }
   776 
   777     if(data->userOrientation != ORIENTATION_UP)
   778         FrameBufferRotate(&data->fb, data->userOrientation);
   779 }
   780 
   781 void WINCE_LandscapeTransform(WINCE_RenderData* data, int width, int height)
   782 {
   783     switch(data->systemOrientation)
   784     {
   785         case ORIENTATION_UP:  FrameBufferRotate(&data->fb, ORIENTATION_LEFT); break;
   786         case ORIENTATION_LEFT:FrameBufferRotate(&data->fb, ORIENTATION_DOWN); break;
   787         case ORIENTATION_DOWN:FrameBufferRotate(&data->fb, ORIENTATION_RIGHT); break;
   788         default: break;
   789     }
   790 
   791     if(data->fb.width != width || data->fb.height != height)
   792     switch(data->systemOrientation)
   793     {
   794         case ORIENTATION_UP:
   795         case ORIENTATION_LEFT: data->userOrientation = ORIENTATION_RIGHT; break;
   796         case ORIENTATION_RIGHT:
   797         case ORIENTATION_DOWN: data->userOrientation = ORIENTATION_LEFT; break;
   798         default: break;
   799     }
   800 
   801     if(data->userOrientation != ORIENTATION_UP)
   802         FrameBufferRotate(&data->fb, data->userOrientation);
   803 }
   804 
   805 void WINCE_SquareTransform(WINCE_RenderData* data, int width, int height)
   806 {
   807     WINCE_PortraitTransform(data, width, height);
   808 }
   809 
   810 int WINCE_FixedGeometry(FrameBufferInfo* fb, int bpp, int debug)
   811 {
   812     // check square
   813     if(GetSystemMetrics(SM_CXSCREEN) == GetSystemMetrics(SM_CYSCREEN) &&
   814         fb->width != fb->height)
   815     {
   816         if(fb->width < fb->height)
   817             fb->height = fb->width;
   818         else
   819         if(fb->height < fb->width)
   820             fb->width = fb->height;
   821     }
   822 
   823     // check width
   824     if(__abs(fb->xpitch) == bpp &&
   825         fb->width  != __abs(fb->ypitch) / bpp)
   826     {
   827         if(fb->height == __abs(fb->ypitch) / bpp)
   828             {
   829             __swap(&fb->width, &fb->height);
   830 
   831             if(debug)
   832                 printf("WINCE_FixedGeometry: width: %d, height: %d\n", fb->width, fb->height);
   833         }
   834         else
   835             return -1;
   836     }
   837     else
   838     // check height
   839     if(__abs(fb->ypitch) == bpp &&
   840         fb->height != __abs(fb->xpitch) / bpp)
   841     {
   842         if(fb->width  == __abs(fb->xpitch) / bpp)
   843             {
   844             __swap(&fb->width, &fb->height);
   845 
   846             if(debug)
   847                 printf("WINCE_FixedGeometry: width: %d, height: %d\n", fb->width, fb->height);
   848         }
   849         else
   850             return -1;
   851     }
   852 
   853     return 0;
   854 }
   855 
   856 void WINCE_UpdateYUVTextureData(SDL_Texture* texture)
   857 {
   858     WINCE_TextureData* texturedata = (WINCE_TextureData*) texture->driverdata;
   859     SDL_Rect rect;
   860 
   861     rect.x = 0;
   862     rect.y = 0;
   863     rect.w = texture->w;
   864     rect.h = texture->h;
   865     SDL_SW_CopyYUVToRGB(texturedata->yuv, &rect, texturedata->format, texture->w, texture->h, texturedata->pixels, texturedata->pitch);
   866 }
   867 
   868 int GAPI_Init(WINCE_RenderData* data, HWND hwnd)
   869 {
   870     if(NULL == data->gapi)
   871     {
   872         struct GXDisplayProperties gxProperties;
   873         GXDeviceInfo gxInfo = { 0 };
   874         HDC hdc;
   875         int enable, result;
   876         const char* preferably = SDL_getenv("SDL_VIDEO_RENDERER");
   877         if(preferably && 0 != SDL_strcasecmp(preferably, GAPI_RENDER_NAME)) return 0;
   878 
   879         data->gapi = (GapiInfo *) SDL_calloc(1, sizeof(GapiInfo));
   880         if(NULL == data->gapi)
   881         {
   882             SDL_OutOfMemory();
   883             return 0;
   884         }
   885 
   886         data->gapi->hGapiLib = SDL_LoadObject("\\Windows\\gx.dll");
   887         if(0 == data->gapi->hGapiLib)
   888         {
   889             data->gapi->hGapiLib = SDL_LoadObject("gx.dll");
   890             if(0 == data->gapi->hGapiLib) return 0;
   891         }
   892 
   893         // load gapi library
   894 #define LINK(type,name,import) name=(PFN##type)SDL_LoadFunction(data->gapi->hGapiLib,import)
   895         LINK(GXOpenDisplay,         data->gapi->GXOpenDisplay,         "?GXOpenDisplay@@YAHPAUHWND__@@K@Z");
   896         LINK(GXCloseDisplay,        data->gapi->GXCloseDisplay,        "?GXCloseDisplay@@YAHXZ");
   897         LINK(GXBeginDraw,           data->gapi->GXBeginDraw,           "?GXBeginDraw@@YAPAXXZ");
   898         LINK(GXEndDraw,             data->gapi->GXEndDraw,             "?GXEndDraw@@YAHXZ");
   899         LINK(GXGetDisplayProperties,data->gapi->GXGetDisplayProperties,"?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ");
   900         LINK(GXSuspend,             data->gapi->GXSuspend,             "?GXSuspend@@YAHXZ");
   901         LINK(GXResume,              data->gapi->GXResume,              "?GXResume@@YAHXZ");
   902 #undef LINK
   903 
   904         enable = data->gapi->GXGetDisplayProperties && data->gapi->GXCloseDisplay && data->gapi->GXOpenDisplay &&
   905             data->gapi->GXBeginDraw && data->gapi->GXEndDraw && data->gapi->GXSuspend && data->gapi->GXResume;
   906 
   907         if(!enable)
   908         {
   909             SDL_SetError("GAPI_Init: error gx.dll: internal error");
   910             GAPI_Quit(data);
   911             return 0;
   912         }
   913 
   914         if(0 == data->gapi->GXOpenDisplay(hwnd, GX_FULLSCREEN))
   915         {
   916             SDL_SetError("GAPI_Init: couldn't initialize GAPI");
   917             GAPI_Quit(data);
   918             return 0;
   919         }
   920 
   921         gxProperties = data->gapi->GXGetDisplayProperties();
   922 
   923         // fill FrameBufferInfo
   924         data->fb.xpitch = gxProperties.cbxPitch;
   925         data->fb.ypitch = gxProperties.cbyPitch;
   926         data->fb.width  = gxProperties.cxWidth;
   927         data->fb.height = gxProperties.cyHeight;
   928         data->fb.offset = 0;
   929 
   930         if((gxProperties.ffFormat & kfDirect565) || 16 == gxProperties.cBPP)
   931             data->format = SDL_PIXELFORMAT_RGB565;
   932         else
   933         if((gxProperties.ffFormat & kfDirect555) || 15 == gxProperties.cBPP)
   934             data->format = SDL_PIXELFORMAT_RGB555;
   935         else
   936             data->format = 0;
   937 
   938         // get pixels
   939         hdc = GetDC(NULL);
   940 
   941         gxInfo.Version = 100;
   942         result = ExtEscape(hdc, GETGXINFO, 0, NULL, sizeof(gxInfo), (char *) &gxInfo);
   943         ReleaseDC(NULL, hdc);
   944 
   945         if(result > 0)
   946         {
   947             // more debug
   948             if(data->debug)
   949             {
   950                 int i;
   951 
   952                 printf("GXDeviceInfo.pvFrameBuffer:    %p\n", gxInfo.pvFrameBuffer);
   953                 printf("GXDeviceInfo.cxWidth:          %d\n", gxInfo.cxWidth);
   954                 printf("GXDeviceInfo.cyHeight:         %d\n", gxInfo.cyHeight);
   955                 printf("GXDeviceInfo.cbStride:         %d\n", gxInfo.cbStride);
   956                 printf("GXDeviceInfo.cBPP:             %d\n", gxInfo.cBPP);
   957                 printf("GXDeviceInfo.ffFormat:        0x%x\n", gxInfo.ffFormat);
   958 
   959                 printf("GXDeviceInfo.unk:\n");
   960                 for(i = 0; i <  sizeof(gxInfo.unknown); ++i)
   961                     printf("0x%02hhX,", gxInfo.unknown[i]);
   962                 printf("\n");
   963             }
   964 
   965                 if(gxInfo.ffFormat && gxInfo.ffFormat != gxProperties.ffFormat) {
   966                     if((gxInfo.ffFormat & kfDirect565) || 16 == gxInfo.cBPP)
   967                         data->format = SDL_PIXELFORMAT_RGB565;
   968                     else
   969                     if((gxInfo.ffFormat & kfDirect555) || 15 == gxInfo.cBPP)
   970                         data->format = SDL_PIXELFORMAT_RGB555;
   971                 }
   972 
   973                 data->pixels = gxInfo.pvFrameBuffer;
   974         }
   975         else
   976         {
   977             data->flags |= FB_SKIP_OFFSET;
   978             data->pixels = data->gapi->GXBeginDraw();
   979             data->gapi->GXEndDraw();
   980 
   981             if(data->debug)
   982             {
   983                 printf("GAPI_Init\n");
   984                 printf("use GXBeginDraw:               %p\n", data->pixels);
   985                 printf("use skip offset\n");
   986             }
   987         }
   988 
   989         if(0 == data->format ||
   990             0 > WINCE_FixedGeometry(&data->fb, SDL_BYTESPERPIXEL(data->format), data->debug))
   991         {
   992             SDL_SetError("GAPI_Init: unknown hardware");
   993             GAPI_Quit(data);
   994             return 0;
   995         }
   996     }
   997 
   998     return data->gapi && data->pixels ? 1 : 0;
   999 }
  1000 
  1001 void GAPI_Quit(WINCE_RenderData* data)
  1002 {
  1003     if(data->gapi)
  1004     {
  1005         if(data->gapi->GXCloseDisplay) data->gapi->GXCloseDisplay(); 
  1006         if(data->gapi->hGapiLib)  SDL_UnloadObject(data->gapi->hGapiLib);
  1007 
  1008         SDL_free(data->gapi);
  1009         data->gapi = NULL;
  1010     }
  1011 }
  1012 
  1013 int RAW_Init(WINCE_RenderData* data)
  1014 {
  1015     RawFrameBufferInfo rfbi = { 0 };
  1016     HDC hdc;
  1017     int result;
  1018     const char* preferably = SDL_getenv("SDL_VIDEO_RENDERER");
  1019     if(preferably && 0 != SDL_strcasecmp(preferably, RAW_RENDER_NAME)) return 0;
  1020 
  1021     hdc = GetDC(NULL);
  1022     result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *) &rfbi);
  1023     ReleaseDC(NULL, hdc);
  1024 
  1025     //disable
  1026     if(result == 0 || rfbi.pFramePointer == 0 ||
  1027             rfbi.cxPixels == 0 || rfbi.cyPixels == 0 ||
  1028         rfbi.cxStride == 0 || rfbi.cyStride == 0) return 0;
  1029 
  1030     data->flags     = FB_RAW_MODE;
  1031 
  1032     // fill FrameBufferInfo
  1033     SDL_memset(&data->fb, 0, sizeof(FrameBufferInfo));
  1034 
  1035     data->fb.xpitch = rfbi.cxStride;
  1036     data->fb.ypitch = rfbi.cyStride;
  1037     data->fb.width  = rfbi.cxPixels;
  1038     data->fb.height = rfbi.cyPixels;
  1039     data->fb.offset = 0;
  1040 
  1041     if((FORMAT_565 & rfbi.wFormat) || 16 == rfbi.wBPP)
  1042         data->format = SDL_PIXELFORMAT_RGB565;
  1043     else
  1044     if((FORMAT_555 & rfbi.wFormat) || 15 == rfbi.wBPP)
  1045         data->format = SDL_PIXELFORMAT_RGB555;
  1046     else
  1047         data->format = 0;
  1048 
  1049     if(0 == data->format ||
  1050         0 > WINCE_FixedGeometry(&data->fb, SDL_BYTESPERPIXEL(data->format), data->debug))
  1051     {
  1052         SDL_SetError("RAW_Init: unknown hardware");
  1053         RAW_Quit(data);
  1054         return 0;
  1055     }
  1056 
  1057     data->pixels = rfbi.pFramePointer;
  1058 
  1059     return data->pixels ? 1 : 0;
  1060 }
  1061 
  1062 void RAW_Quit(WINCE_RenderData* data)
  1063 {
  1064 }
  1065 
  1066 void FrameBufferInitialize(FrameBufferInfo* fb)
  1067 {
  1068     int orientation = GetFrameBufferOrientation(fb);
  1069 
  1070     // set correct start offset
  1071     switch(orientation)
  1072     {
  1073         case ORIENTATION_UP:
  1074             fb->offset = 0;
  1075             break;
  1076 
  1077         case ORIENTATION_LEFT:
  1078             fb->offset = __abs(fb->ypitch * (fb->height - 1));
  1079             break;
  1080 
  1081         case ORIENTATION_RIGHT:
  1082             fb->offset = __abs(fb->xpitch * (fb->width - 1));
  1083             break;
  1084 
  1085         case ORIENTATION_DOWN:
  1086             fb->offset = __abs(fb->xpitch * (fb->width - 1) +
  1087                                 fb->ypitch * (fb->height - 1));
  1088             break;
  1089 
  1090         default: break;
  1091     }
  1092 
  1093     //if(orientation != ORIENTATION_UP)
  1094     switch(orientation)
  1095     {
  1096         case ORIENTATION_LEFT: FrameBufferRotate(fb, ORIENTATION_RIGHT); break;
  1097         case ORIENTATION_RIGHT:FrameBufferRotate(fb, ORIENTATION_LEFT); break;
  1098         case ORIENTATION_DOWN: FrameBufferRotate(fb, ORIENTATION_DOWN); break;
  1099 
  1100         default: break;
  1101     }
  1102 }
  1103 
  1104 int GetFrameBufferOrientation(const FrameBufferInfo* src)
  1105 {
  1106     if(src->xpitch > 0 && src->ypitch > 0)
  1107         return ORIENTATION_UP;
  1108     else
  1109     if(src->xpitch > 0 && src->ypitch < 0)
  1110         return ORIENTATION_LEFT;
  1111     else
  1112     if(src->xpitch < 0 && src->ypitch > 0)
  1113         return ORIENTATION_RIGHT;
  1114     else
  1115     if(src->xpitch < 0 && src->ypitch < 0)
  1116         return ORIENTATION_DOWN;
  1117 
  1118     return ORIENTATION_UNKNOWN;
  1119 }
  1120 
  1121 void FrameBufferRotate(FrameBufferInfo* dst, int orientation)
  1122 {
  1123     FrameBufferInfo src;
  1124     // copy dst -> src
  1125     SDL_memcpy(&src, dst, sizeof(FrameBufferInfo));
  1126 
  1127     switch(orientation)
  1128     {
  1129         case ORIENTATION_LEFT:
  1130             dst->width  = src.height;
  1131             dst->height = src.width;
  1132             dst->xpitch = src.ypitch;
  1133             dst->ypitch = -src.xpitch;
  1134             dst->offset = src.offset + src.xpitch * (src.width - 1);
  1135             break;
  1136 
  1137         case ORIENTATION_RIGHT:
  1138             dst->width  = src.height;
  1139             dst->height = src.width;
  1140             dst->xpitch = -src.ypitch;
  1141             dst->ypitch = src.xpitch;
  1142             dst->offset = src.offset + src.ypitch * (src.height - 1);
  1143             break;
  1144 
  1145         case ORIENTATION_DOWN:
  1146             FrameBufferRotate(dst, ORIENTATION_LEFT);
  1147             FrameBufferRotate(dst, ORIENTATION_LEFT);
  1148             break;
  1149 
  1150         default:
  1151             break;
  1152     }
  1153 }
  1154 
  1155 void PointerRotate(POINT* pt, const FrameBufferInfo* fb, int orientation)
  1156 {
  1157     switch(orientation)
  1158     {
  1159         case ORIENTATION_UP:
  1160             break;
  1161 
  1162         case ORIENTATION_LEFT:
  1163         {
  1164             int temp = pt->y;
  1165             pt->y = fb->height - pt->x;
  1166             pt->x = temp;
  1167         }
  1168             break;
  1169 
  1170         case ORIENTATION_RIGHT:
  1171         {
  1172             int temp = pt->x;
  1173             pt->x = fb->width - pt->y;
  1174             pt->y = temp;
  1175         }
  1176             break;
  1177 
  1178         case ORIENTATION_DOWN:
  1179             pt->x = fb->width  - pt->x;
  1180             pt->y = fb->height - pt->y;
  1181             break;
  1182 
  1183         default: break;
  1184     }
  1185 }
  1186 
  1187 const char* GetOrientationName(int orientation)
  1188 {
  1189     switch(orientation)
  1190     {
  1191         case ORIENTATION_UP:        return "UP";
  1192         case ORIENTATION_DOWN:      return "DOWN";
  1193         case ORIENTATION_LEFT:      return "LEFT";
  1194         case ORIENTATION_RIGHT:     return "RIGHT";
  1195         default: break;
  1196     }
  1197 
  1198     return "UNKNOWN";
  1199 }
  1200 
  1201 int WINCE_GetDMOrientation(void)
  1202 {
  1203     DEVMODE sDevMode = {0};
  1204     sDevMode.dmSize = sizeof(DEVMODE);
  1205     sDevMode.dmFields = DM_DISPLAYORIENTATION;
  1206 
  1207     // DMDO_0, DMDO_90, DMDO_180, DMDO_270
  1208     if(DISP_CHANGE_BADMODE != ChangeDisplaySettingsEx(NULL, &sDevMode, 0, CDS_TEST, NULL))
  1209         switch(sDevMode.dmDisplayOrientation)
  1210         {
  1211             case DMDO_0:        return DMDO_0;
  1212             case DMDO_90:        return DMDO_90;
  1213             case DMDO_180:        return DMDO_180;
  1214             case DMDO_270:        return DMDO_270;
  1215             default: break;
  1216         }
  1217 
  1218     SDL_SetError("WINCE_GetDMOrientation: ChangeDisplaySettingsEx return BADMODE");
  1219     return -1;
  1220 }
  1221 
  1222 int WINCE_SetDMOrientation(int orientation)
  1223 {
  1224     DEVMODE sDevMode = {0};
  1225     sDevMode.dmSize = sizeof(DEVMODE);
  1226     sDevMode.dmFields = DM_DISPLAYORIENTATION;
  1227 
  1228     switch(orientation)
  1229     {
  1230         case DMDO_0:        sDevMode.dmDisplayOrientation = DMDO_0;   break;
  1231         case DMDO_90:        sDevMode.dmDisplayOrientation = DMDO_90;  break;
  1232         case DMDO_180:        sDevMode.dmDisplayOrientation = DMDO_180; break;
  1233         case DMDO_270:        sDevMode.dmDisplayOrientation = DMDO_270; break;
  1234         default: return 0;
  1235     }
  1236 
  1237     if(DISP_CHANGE_BADMODE != ChangeDisplaySettingsEx(NULL, &sDevMode, 0, CDS_RESET, NULL))
  1238         return 1;
  1239 
  1240     SDL_SetError("WINCE_SetDMOrientation: ChangeDisplaySettingsEx return BADMODE");
  1241     return -1;
  1242 }
  1243 
  1244 void FrameBufferDumpInfo(const FrameBufferInfo* fb, const char* name)
  1245 {
  1246     int orientation;
  1247 
  1248     printf("%s fb.width:       %d\n", name, fb->width);
  1249     printf("%s fb.height:      %d\n", name, fb->height);
  1250     printf("%s fb.xpitch:      %d\n", name, fb->xpitch);
  1251     printf("%s fb.ypitch:      %d\n", name, fb->ypitch);
  1252     printf("%s fb.offset:      %d\n", name, fb->offset);
  1253 
  1254     orientation = GetFrameBufferOrientation(fb);
  1255     printf("%s fb.orientation: %d, %s\n", name, orientation, GetOrientationName(orientation));
  1256 }
  1257 
  1258 void UpdateLine16to16(const FrameBufferInfo* fb, const Uint16* src, Uint16* dst, Uint16 width)
  1259 {
  1260     if(2 == fb->xpitch)
  1261     {
  1262         switch(width)
  1263         {
  1264             case 1:
  1265                 *dst = *src;
  1266                 break;
  1267 
  1268             case 2:
  1269                 *((Uint32*) dst) = *((Uint32*) src);
  1270                 break;
  1271 
  1272             default:
  1273                 SDL_memcpy(dst, src, width * 2);
  1274                 break;
  1275         }
  1276     }
  1277     else
  1278     if(-2 == fb->xpitch)
  1279     {
  1280         while(width--)
  1281             *dst-- = *src++;
  1282     }
  1283     else
  1284     {
  1285         while(width--)
  1286         {
  1287             *dst = *src++;
  1288             dst += fb->xpitch / 2;
  1289         }
  1290     }
  1291 }
  1292 
  1293 #endif // SDL_VIDEO_RENDER_GAPI