From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- apps/plugins/sdl/src/video/photon/SDL_phyuv.c | 504 ++++++++++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 apps/plugins/sdl/src/video/photon/SDL_phyuv.c (limited to 'apps/plugins/sdl/src/video/photon/SDL_phyuv.c') diff --git a/apps/plugins/sdl/src/video/photon/SDL_phyuv.c b/apps/plugins/sdl/src/video/photon/SDL_phyuv.c new file mode 100644 index 0000000000..06c72fded4 --- /dev/null +++ b/apps/plugins/sdl/src/video/photon/SDL_phyuv.c @@ -0,0 +1,504 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* This is the QNX Realtime Platform version of SDL YUV video overlays */ + +#include + +#include +#include + +#include "SDL_video.h" +#include "SDL_phyuv_c.h" +#include "../SDL_yuvfuncs.h" + +#define OVERLAY_STATE_UNINIT 0 +#define OVERLAY_STATE_ACTIVE 1 + +/* The functions are used to manipulate software video overlays */ +static struct private_yuvhwfuncs ph_yuvfuncs = +{ + ph_LockYUVOverlay, + ph_UnlockYUVOverlay, + ph_DisplayYUVOverlay, + ph_FreeYUVOverlay +}; + +int grab_ptrs2(PgVideoChannel_t* channel, FRAMEDATA* Frame0, FRAMEDATA* Frame1) +{ + int planes = 0; + + /* Buffers have moved; re-obtain the pointers */ + Frame0->Y = (unsigned char *)PdGetOffscreenContextPtr(channel->yplane1); + Frame1->Y = (unsigned char *)PdGetOffscreenContextPtr(channel->yplane2); + Frame0->U = (unsigned char *)PdGetOffscreenContextPtr(channel->vplane1); + Frame1->U = (unsigned char *)PdGetOffscreenContextPtr(channel->vplane2); + Frame0->V = (unsigned char *)PdGetOffscreenContextPtr(channel->uplane1); + Frame1->V = (unsigned char *)PdGetOffscreenContextPtr(channel->uplane2); + + if (Frame0->Y) + planes++; + + if (Frame0->U) + planes++; + + if (Frame0->V) + planes++; + + return planes; +} + +SDL_Overlay* ph_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface* display) +{ + SDL_Overlay* overlay; + struct private_yuvhwdata* hwdata; + int vidport; + int rtncode; + int planes; + int i=0; + PhPoint_t pos; + + /* Create the overlay structure */ + overlay = SDL_calloc(1, sizeof(SDL_Overlay)); + + if (overlay == NULL) + { + SDL_OutOfMemory(); + return NULL; + } + + /* Fill in the basic members */ + overlay->format = format; + overlay->w = width; + overlay->h = height; + overlay->hwdata = NULL; + + /* Set up the YUV surface function structure */ + overlay->hwfuncs = &ph_yuvfuncs; + + /* Create the pixel data and lookup tables */ + hwdata = SDL_calloc(1, sizeof(struct private_yuvhwdata)); + + if (hwdata == NULL) + { + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return NULL; + } + + overlay->hwdata = hwdata; + + PhDCSetCurrent(0); + if (overlay->hwdata->channel == NULL) + { + if ((overlay->hwdata->channel = PgCreateVideoChannel(Pg_VIDEO_CHANNEL_SCALER, 0)) == NULL) + { + SDL_SetError("ph_CreateYUVOverlay(): Create channel failed: %s\n", strerror(errno)); + SDL_FreeYUVOverlay(overlay); + return NULL; + + } + } + + overlay->hwdata->forcedredraw=0; + + PtGetAbsPosition(window, &pos.x, &pos.y); + overlay->hwdata->CurrentWindowPos.x = pos.x; + overlay->hwdata->CurrentWindowPos.y = pos.y; + overlay->hwdata->CurrentViewPort.pos.x = 0; + overlay->hwdata->CurrentViewPort.pos.y = 0; + overlay->hwdata->CurrentViewPort.size.w = width; + overlay->hwdata->CurrentViewPort.size.h = height; + overlay->hwdata->State = OVERLAY_STATE_UNINIT; + overlay->hwdata->FrameData0 = (FRAMEDATA *) SDL_calloc(1, sizeof(FRAMEDATA)); + overlay->hwdata->FrameData1 = (FRAMEDATA *) SDL_calloc(1, sizeof(FRAMEDATA)); + + vidport = -1; + i=0; + + overlay->hwdata->ischromakey=0; + + do { + SDL_memset(&overlay->hwdata->caps, 0x00, sizeof(PgScalerCaps_t)); + overlay->hwdata->caps.size = sizeof(PgScalerCaps_t); + rtncode = PgGetScalerCapabilities(overlay->hwdata->channel, i, &overlay->hwdata->caps); + if (rtncode==0) + { + if (overlay->hwdata->caps.format==format) + { + if ((overlay->hwdata->caps.flags & Pg_SCALER_CAP_DST_CHROMA_KEY) == Pg_SCALER_CAP_DST_CHROMA_KEY) + { + overlay->hwdata->ischromakey=1; + } + vidport=1; + break; + } + } + else + { + break; + } + i++; + } while(1); + + + if (vidport == -1) + { + SDL_SetError("No available video ports for requested format\n"); + SDL_FreeYUVOverlay(overlay); + return NULL; + } + + overlay->hwdata->format = format; + overlay->hwdata->props.format = format; + overlay->hwdata->props.size = sizeof(PgScalerProps_t); + overlay->hwdata->props.src_dim.w = width; + overlay->hwdata->props.src_dim.h = height; + + /* overlay->hwdata->chromakey = PgGetOverlayChromaColor(); */ + overlay->hwdata->chromakey = PgRGB(12, 6, 12); /* very dark pink color */ + overlay->hwdata->props.color_key = overlay->hwdata->chromakey; + + PhAreaToRect(&overlay->hwdata->CurrentViewPort, &overlay->hwdata->props.viewport); + + overlay->hwdata->props.flags = Pg_SCALER_PROP_DOUBLE_BUFFER; + + if ((overlay->hwdata->ischromakey)&&(overlay->hwdata->chromakey)) + { + overlay->hwdata->props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE; + overlay->hwdata->props.flags |= Pg_SCALER_PROP_CHROMA_SPECIFY_KEY_MASK; + } + else + { + overlay->hwdata->props.flags &= ~Pg_SCALER_PROP_CHROMA_ENABLE; + } + + rtncode = PgConfigScalerChannel(overlay->hwdata->channel, &overlay->hwdata->props); + + switch(rtncode) + { + case -1: SDL_SetError("PgConfigScalerChannel failed\n"); + SDL_FreeYUVOverlay(overlay); + return NULL; + case 1: + case 0: + default: + break; + } + + planes = grab_ptrs2(overlay->hwdata->channel, overlay->hwdata->FrameData0, overlay->hwdata->FrameData1); + + if(overlay->hwdata->channel->yplane1 != NULL) + overlay->hwdata->YStride = overlay->hwdata->channel->yplane1->pitch; + if(overlay->hwdata->channel->vplane1 != NULL) + overlay->hwdata->UStride = overlay->hwdata->channel->vplane1->pitch; + if(overlay->hwdata->channel->uplane1 != NULL) + overlay->hwdata->VStride = overlay->hwdata->channel->uplane1->pitch; + + /* check for the validness of all planes */ + if ((overlay->hwdata->channel->yplane1 == NULL) && + (overlay->hwdata->channel->uplane1 == NULL) && + (overlay->hwdata->channel->vplane1 == NULL)) + { + SDL_FreeYUVOverlay(overlay); + SDL_SetError("PgConfigScaler() returns all planes equal NULL\n"); + return NULL; + } +/* + overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel); + + if (overlay->hwdata->current==0) + { + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; + } + else + { + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1; + } +*/ + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; + +/* + overlay->hwdata->locked = 1; +*/ + + /* Find the pitch and offset values for the overlay */ + overlay->planes = planes; + overlay->pitches = SDL_calloc(overlay->planes, sizeof(Uint16)); + overlay->pixels = SDL_calloc(overlay->planes, sizeof(Uint8*)); + if (!overlay->pitches || !overlay->pixels) + { + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + + if (overlay->planes > 0) + { + overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch; + overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y; + } + if (overlay->planes > 1) + { + overlay->pitches[1] = overlay->hwdata->channel->vplane1->pitch; + overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U; + } + if (overlay->planes > 2) + { + overlay->pitches[2] = overlay->hwdata->channel->uplane1->pitch; + overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V; + } + + overlay->hwdata->State = OVERLAY_STATE_ACTIVE; + overlay->hwdata->scaler_on = 0; + overlay->hw_overlay = 1; + + current_overlay=overlay; + + return overlay; +} + +int ph_LockYUVOverlay(_THIS, SDL_Overlay* overlay) +{ + if (overlay == NULL) + { + return -1; + } + + overlay->hwdata->locked = 1; + +/* overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel); + if (overlay->hwdata->current == -1) + { + SDL_SetError("ph_LockYUVOverlay: PgNextFrame() failed, bailing out\n"); + SDL_FreeYUVOverlay(overlay); + return 0; + } + + if (overlay->hwdata->current == 0) + { + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; + } + else + { + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1; + } + + if (overlay->planes > 0) + { + overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch; + overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y; + } + if (overlay->planes > 1) + { + overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch; + overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U; + } + if (overlay->planes > 2) + { + overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch; + overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V; + } +*/ + + return(0); +} + +void ph_UnlockYUVOverlay(_THIS, SDL_Overlay* overlay) +{ + if (overlay == NULL) + { + return; + } + + overlay->hwdata->locked = 0; +} + +int ph_DisplayYUVOverlay(_THIS, SDL_Overlay* overlay, SDL_Rect* src, SDL_Rect* dst) +{ + int rtncode; + PhPoint_t pos; + SDL_Rect backrect; + PhRect_t windowextent; + int winchanged=0; + + if ((overlay == NULL) || (overlay->hwdata==NULL)) + { + return -1; + } + + if (overlay->hwdata->State == OVERLAY_STATE_UNINIT) + { + return -1; + } + + PtGetAbsPosition(window, &pos.x, &pos.y); + if ((pos.x!=overlay->hwdata->CurrentWindowPos.x) || + (pos.y!=overlay->hwdata->CurrentWindowPos.y)) + { + winchanged=1; + overlay->hwdata->CurrentWindowPos.x=pos.x; + overlay->hwdata->CurrentWindowPos.y=pos.y; + } + + /* If CurrentViewPort position/size has been changed, then move/resize the viewport */ + if ((overlay->hwdata->CurrentViewPort.pos.x != dst->x) || + (overlay->hwdata->CurrentViewPort.pos.y != dst->y) || + (overlay->hwdata->CurrentViewPort.size.w != dst->w) || + (overlay->hwdata->CurrentViewPort.size.h != dst->h) || + (overlay->hwdata->scaler_on==0) || (winchanged==1) || + (overlay->hwdata->forcedredraw==1)) + { + + if (overlay->hwdata->ischromakey==1) + { + /* restore screen behind the overlay/chroma color. */ + backrect.x=overlay->hwdata->CurrentViewPort.pos.x; + backrect.y=overlay->hwdata->CurrentViewPort.pos.y; + backrect.w=overlay->hwdata->CurrentViewPort.size.w; + backrect.h=overlay->hwdata->CurrentViewPort.size.h; + this->UpdateRects(this, 1, &backrect); + + /* Draw the new rectangle of the chroma color at the viewport position */ + PgSetFillColor(overlay->hwdata->chromakey); + PgDrawIRect(dst->x, dst->y, dst->x+dst->w-1, dst->y+dst->h-1, Pg_DRAW_FILL); + PgFlush(); + } + + overlay->hwdata->props.flags |= Pg_SCALER_PROP_SCALER_ENABLE; + overlay->hwdata->scaler_on = 1; + + PhWindowQueryVisible(Ph_QUERY_CONSOLE, 0, PtWidgetRid(window), &windowextent); + overlay->hwdata->CurrentViewPort.pos.x = pos.x-windowextent.ul.x+dst->x; + overlay->hwdata->CurrentViewPort.pos.y = pos.y-windowextent.ul.y+dst->y; + overlay->hwdata->CurrentViewPort.size.w = dst->w; + overlay->hwdata->CurrentViewPort.size.h = dst->h; + PhAreaToRect(&overlay->hwdata->CurrentViewPort, &overlay->hwdata->props.viewport); + overlay->hwdata->CurrentViewPort.pos.x = dst->x; + overlay->hwdata->CurrentViewPort.pos.y = dst->y; + + rtncode = PgConfigScalerChannel(overlay->hwdata->channel, &(overlay->hwdata->props)); + + switch(rtncode) + { + case -1: + SDL_SetError("PgConfigScalerChannel() function failed\n"); + SDL_FreeYUVOverlay(overlay); + return -1; + case 1: + grab_ptrs2(overlay->hwdata->channel, overlay->hwdata->FrameData0, overlay->hwdata->FrameData1); + break; + case 0: + default: + break; + } + } + + +/* + if (overlay->hwdata->locked==0) + { + overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel); + if (overlay->hwdata->current == -1) + { + SDL_SetError("ph_LockYUVOverlay: PgNextFrame() failed, bailing out\n"); + SDL_FreeYUVOverlay(overlay); + return 0; + } + + if (overlay->hwdata->current == 0) + { + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; + } + else + { + overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1; + } + + if (overlay->planes > 0) + { + overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch; + overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y; + } + if (overlay->planes > 1) + { + overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch; + overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U; + } + if (overlay->planes > 2) + { + overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch; + overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V; + } + } +*/ + + return 0; +} + +void ph_FreeYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + SDL_Rect backrect; + + if (overlay == NULL) + { + return; + } + + if (overlay->hwdata == NULL) + { + return; + } + + current_overlay=NULL; + + /* restore screen behind the overlay/chroma color. */ + backrect.x=overlay->hwdata->CurrentViewPort.pos.x; + backrect.y=overlay->hwdata->CurrentViewPort.pos.y; + backrect.w=overlay->hwdata->CurrentViewPort.size.w; + backrect.h=overlay->hwdata->CurrentViewPort.size.h; + this->UpdateRects(this, 1, &backrect); + + /* it is need for some buggy drivers, that can't hide overlay before */ + /* freeing buffer, so we got trash on the srceen */ + overlay->hwdata->props.flags &= ~Pg_SCALER_PROP_SCALER_ENABLE; + PgConfigScalerChannel(overlay->hwdata->channel, &(overlay->hwdata->props)); + + overlay->hwdata->scaler_on = 0; + overlay->hwdata->State = OVERLAY_STATE_UNINIT; + + if (overlay->hwdata->channel != NULL) + { + PgDestroyVideoChannel(overlay->hwdata->channel); + overlay->hwdata->channel = NULL; + return; + } + + overlay->hwdata->CurrentFrameData = NULL; + + SDL_free(overlay->hwdata->FrameData0); + SDL_free(overlay->hwdata->FrameData1); + overlay->hwdata->FrameData0 = NULL; + overlay->hwdata->FrameData1 = NULL; + SDL_free(overlay->hwdata); +} -- cgit v1.2.3