X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Faxwin3_src%2FWM%2Fvideo.c;h=2f6fff8345c28e08cd062bee089cafabb9292c82;hb=845b6f9d90bb87b5e760e4d49aa93b0e003ab750;hp=8066a1baadb236a7d161a09659195b513da93fcb;hpb=f440462b381bb8bcfbe303e7c0c4b16ce4a97b6c;p=tpg%2Facess2.git diff --git a/Usermode/Applications/axwin3_src/WM/video.c b/Usermode/Applications/axwin3_src/WM/video.c index 8066a1ba..2f6fff83 100644 --- a/Usermode/Applications/axwin3_src/WM/video.c +++ b/Usermode/Applications/axwin3_src/WM/video.c @@ -7,93 +7,172 @@ */ #include #include -#include +#include +#include #include #include "resources/cursor.h" #include #include +#include +#include +#include "include/lowlevel.h" + +// === IMPORTS === +extern int giTerminalFD_Input; // === PROTOTYPES === void Video_Setup(void); +void Video_int_SetBufFmt(int NewFmt); void Video_SetCursorPos(short X, short Y); void Video_Update(void); -void Video_FillRect(short X, short Y, short W, short H, uint32_t Color); -void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color); +void Video_FillRect(int X, int Y, int W, int H, uint32_t Color); // === GLOBALS === int giVideo_CursorX; int giVideo_CursorY; uint32_t *gpScreenBuffer; + int giVideo_FirstDirtyLine; + int giVideo_LastDirtyLine; // === CODE === void Video_Setup(void) { - int tmpInt; + int rv; // Open terminal - giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE); + #if 0 + giTerminalFD = _SysOpen(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE); if( giTerminalFD == -1 ) { fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno); exit(-1); } - - // Set width - tmpInt = giScreenWidth; - tmpInt = ioctl( giTerminalFD, TERM_IOCTL_WIDTH, &tmpInt ); - if(tmpInt != giScreenWidth) + #else + giTerminalFD = 1; + giTerminalFD_Input = 0; + // Check that the console is a PTY + // - _SysIOCtl(..., 0, NULL) returns the type, which should be 2 + rv = _SysIOCtl(1, DRV_IOCTL_TYPE, NULL); + if( rv != DRV_TYPE_TERMINAL ) { - fprintf(stderr, "Warning: Selected width (%i) is invalid, clipped to %i\n", - giScreenWidth, tmpInt); - giScreenWidth = tmpInt; - } - - // Set height - tmpInt = giScreenHeight; - tmpInt = ioctl( giTerminalFD, TERM_IOCTL_HEIGHT, &tmpInt ); - if(tmpInt != giScreenHeight) - { - fprintf(stderr, "Warning: Selected height (%i) is invalid, clipped to %i\n", - giScreenHeight, tmpInt); - giScreenHeight = tmpInt; + fprintf(stderr, "stdout is not a PTY, can't start (%i exp, %i got)\n", + DRV_TYPE_TERMINAL, rv); + _SysDebug("stdout is not an PTY, can't start"); + exit(-1); } - + #endif + + // TODO: Check terminal echoback that it does support graphical modes + // And/or have terminal flags fetchable by the client + // Set mode to video - tmpInt = TERM_MODE_FB; - ioctl( giTerminalFD, TERM_IOCTL_MODETYPE, &tmpInt ); - - // Force VT to be shown - ioctl( giTerminalFD, TERM_IOCTL_FORCESHOW, NULL ); + Video_int_SetBufFmt(PTYBUFFMT_FB); + + // Get dimensions + struct ptydims dims; + rv = _SysIOCtl( giTerminalFD, PTY_IOCTL_GETDIMS, &dims ); + if( rv ) { + perror("Can't get terminal dimensions (WTF?)"); + exit(-1); + } + giScreenWidth = dims.PW; + giScreenHeight = dims.PH; + if( giScreenWidth < 640 || giScreenHeight < 480 ) { + Video_int_SetBufFmt(PTYBUFFMT_TEXT); + _SysDebug("Resoltion too small, 640x480 reqd but %ix%i avail", + giScreenWidth, giScreenHeight); + exit(-1); + } + _SysDebug("AxWin3 running at %ix%i", dims.PW, dims.PH); + + giVideo_LastDirtyLine = giScreenHeight; // Create local framebuffer (back buffer) gpScreenBuffer = malloc( giScreenWidth*giScreenHeight*4 ); -// memset(gpScreenBufferi -// Video_FillRect(0, 0, giScreenWidth, giScreenHeight, 0x8080FF); + //gpScreenBuffer = _SysMemMap( giTerminalFD, 0, giScreenWidth*giScreenHeight*4, NULL); // Set cursor position and bitmap - ioctl(giTerminalFD, TERM_IOCTL_SETCURSORBITMAP, &cCursorBitmap); + { + Video_int_SetBufFmt(PTYBUFFMT_2DCMD); + struct ptycmd_header hdr = {PTY2D_CMD_SETCURSORBMP,0,0}; + size_t size = sizeof(hdr) + sizeof(cCursorBitmap) + cCursorBitmap.W*cCursorBitmap.H*4; + hdr.len_low = size / 4; + hdr.len_hi = size / (256*4); + _SysWrite(giTerminalFD, &hdr, sizeof(hdr)); + _SysDebug("size = %i (%04x:%02x * 4)", size, hdr.len_hi, hdr.len_low); + _SysWrite(giTerminalFD, &cCursorBitmap, size-sizeof(hdr)); + } Video_SetCursorPos( giScreenWidth/2, giScreenHeight/2 ); - - Video_Update(); } void Video_Update(void) { - _SysDebug("Video_Update - gpScreenBuffer[0] = 0x%x", gpScreenBuffer[0]); - seek(giTerminalFD, 0, 1); - write(giTerminalFD, gpScreenBuffer, giScreenWidth*giScreenHeight*4); + #if 0 + int ofs = giVideo_FirstDirtyLine*giScreenWidth; + int size = (giVideo_LastDirtyLine-giVideo_FirstDirtyLine)*giScreenWidth; + + if( giVideo_LastDirtyLine == 0 ) return; + + _SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)", + giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size); + _SysSeek(giTerminalFD, ofs*4, SEEK_SET); + _SysDebug("Video_Update - Sending FD %i %p 0x%x", giTerminalFD, gpScreenBuffer+ofs, size*4); + _SysWrite(giTerminalFD, gpScreenBuffer+ofs, size*4); _SysDebug("Video_Update - Done"); + giVideo_FirstDirtyLine = giScreenHeight; + giVideo_LastDirtyLine = 0; + #else + size_t size = giScreenHeight * giScreenWidth; + Video_int_SetBufFmt(PTYBUFFMT_FB); + _SysWrite(giTerminalFD, gpScreenBuffer, size*4); + #endif +} + +void Video_int_SetBufFmt(int NewFmt) +{ + static int current_fmt; + + if( current_fmt == NewFmt ) + return ; + + struct ptymode mode = {.InputMode = 0, .OutputMode = NewFmt}; + int rv = _SysIOCtl( giTerminalFD, PTY_IOCTL_SETMODE, &mode ); + if( rv ) { + perror("Can't set PTY to framebuffer mode"); + exit(-1); + } + + current_fmt = NewFmt; } void Video_SetCursorPos(short X, short Y) { - struct { - uint16_t x; - uint16_t y; - } pos; - pos.x = giVideo_CursorX = X; - pos.y = giVideo_CursorY = Y; - ioctl(giTerminalFD, TERM_IOCTL_GETSETCURSOR, &pos); + struct ptycmd_setcursorpos cmd; + cmd.hdr.cmd = PTY2D_CMD_SETCURSORPOS; + cmd.hdr.len_low = sizeof(cmd)/4; + cmd.hdr.len_hi = 0; + cmd.x = giVideo_CursorX = X; + cmd.y = giVideo_CursorY = Y; + + Video_int_SetBufFmt(PTYBUFFMT_2DCMD); + _SysWrite(giTerminalFD, &cmd, sizeof(cmd)); +} + +void Video_FillRect(int X, int Y, int W, int H, uint32_t Colour) +{ + if(X < 0 || Y < 0) return; + if(W < 0 || H < 0) return; + if(W >= giScreenWidth) return; + if(H >= giScreenHeight) return; + if(X + W >= giScreenWidth) W = giScreenWidth - W; + if(Y + H >= giScreenHeight) W = giScreenHeight - H; + + uint32_t *dest = gpScreenBuffer + Y * giScreenWidth + X; + while(H --) + { + for( int i = W; i --; dest ++ ) *dest = Colour; + dest += giScreenWidth - W; + } } /** @@ -102,30 +181,87 @@ void Video_SetCursorPos(short X, short Y) */ void Video_Blit(uint32_t *Source, short DstX, short DstY, short W, short H) { - int i; uint32_t *buf; + short drawW = W; -// _SysDebug("Video_Blit: (%p (%i, %i) %ix%i)", Source, DstX, DstY, W, H); - if( DstX >= giScreenWidth) return ; if( DstY >= giScreenHeight) return ; - // TODO: Handle -ve X/Y by clipping - if( DstX < 0 || DstY < 0 ) return ; - // TODO: Handle out of bounds by clipping too - if( DstX + W > giScreenWidth ) return; + // Drawing oob to left/top, clip + if( DstX < 0 ) { + Source += -DstX; + drawW -= -DstX; + DstX = 0; + } + if( DstY < 0 ) { + Source += (-DstY)*W; + H -= -DstY; + DstY = 0; + } + if( drawW < 0 ) return ; + // Drawing oob to the right, clip + if( DstX + drawW > giScreenWidth ) { + //int oldw = drawW; + drawW = giScreenWidth - DstX; + } if( DstY + H > giScreenHeight ) - H = giScreenWidth - DstY; + H = giScreenHeight - DstY; if( W <= 0 || H <= 0 ) return; + + giVideo_FirstDirtyLine = MIN(DstY, giVideo_FirstDirtyLine); + giVideo_LastDirtyLine = MAX(DstY+H, giVideo_LastDirtyLine); -// _SysDebug(" Clipped to (%i, %i) %ix%i", DstX, DstY, W, H); -// _SysDebug(" Source[0] = 0x%x", Source[0]); buf = gpScreenBuffer + DstY*giScreenWidth + DstX; - while( H -- ) + if(drawW != giScreenWidth || W != giScreenWidth) + { + while( H -- ) + { + memcpy(buf, Source, drawW*4); + Source += W; + buf += giScreenWidth; + } + } + else { - for( i = W; i --; ) - *buf++ = *Source++; - buf += giScreenWidth - W; + // Only valid if copying full scanlines on both ends + memcpy(buf, Source, giScreenWidth*H*4); } } +tColour Video_AlphaBlend(tColour _orig, tColour _new, uint8_t _alpha) +{ + uint16_t ao,ro,go,bo; + uint16_t an,rn,gn,bn; + if( _alpha == 0 ) return _orig; + if( _alpha == 255 ) return _new; + + ao = (_orig >> 24) & 0xFF; + ro = (_orig >> 16) & 0xFF; + go = (_orig >> 8) & 0xFF; + bo = (_orig >> 0) & 0xFF; + + an = (_new >> 24) & 0xFF; + rn = (_new >> 16) & 0xFF; + gn = (_new >> 8) & 0xFF; + bn = (_new >> 0) & 0xFF; + + if( _alpha == 0x80 ) { + ao = (ao + an) / 2; + ro = (ro + rn) / 2; + go = (go + gn) / 2; + bo = (bo + bn) / 2; + } + else { + ao = ao*(255-_alpha) + an*_alpha; + ro = ro*(255-_alpha) + rn*_alpha; + go = go*(255-_alpha) + gn*_alpha; + bo = bo*(255-_alpha) + bn*_alpha; + ao /= 255*2; + ro /= 255*2; + go /= 255*2; + bo /= 255*2; + } + + return (ao << 24) | (ro << 16) | (go << 8) | bo; +} +