Usermode/AxWin3 - Bugfixing rendering/layout issues
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / video.c
1 /*
2  * Acess2 GUI (AxWin) Version 3
3  * - By John Hodge (thePowersGang)
4  *
5  * video.c
6  * - Video methods
7  */
8 #include <common.h>
9 #include <acess/sys.h>
10 #include <acess/devices/terminal.h>
11 #include <image.h>
12 #include "resources/cursor.h"
13 #include <stdio.h>
14 #include <video.h>
15 #include <wm.h>
16 #include <string.h>
17
18 // === PROTOTYPES ===
19 void    Video_Setup(void);
20 void    Video_SetCursorPos(short X, short Y);
21 void    Video_Update(void);
22 void    Video_FillRect(short X, short Y, short W, short H, uint32_t Color);
23 void    Video_DrawRect(short X, short Y, short W, short H, uint32_t Color);
24
25 // === GLOBALS ===
26  int    giVideo_CursorX;
27  int    giVideo_CursorY;
28 uint32_t        *gpScreenBuffer;
29  int    giVideo_FirstDirtyLine;
30  int    giVideo_LastDirtyLine;
31
32 // === CODE ===
33 void Video_Setup(void)
34 {
35          int    tmpInt;
36         
37         // Open terminal
38         giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
39         if( giTerminalFD == -1 )
40         {
41                 fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
42                 exit(-1);
43         }
44         
45         
46         // Set mode to video
47         tmpInt = TERM_MODE_FB;
48         ioctl( giTerminalFD, TERM_IOCTL_MODETYPE, &tmpInt );
49         
50         // Get dimensions
51         giScreenWidth = ioctl( giTerminalFD, TERM_IOCTL_WIDTH, NULL );
52         giScreenHeight = ioctl( giTerminalFD, TERM_IOCTL_HEIGHT, NULL );
53
54         giVideo_LastDirtyLine = giScreenHeight;
55         
56         // Force VT to be shown
57         ioctl( giTerminalFD, TERM_IOCTL_FORCESHOW, NULL );
58         
59         // Create local framebuffer (back buffer)
60         gpScreenBuffer = malloc( giScreenWidth*giScreenHeight*4 );
61
62         // Set cursor position and bitmap
63         ioctl(giTerminalFD, TERM_IOCTL_SETCURSORBITMAP, &cCursorBitmap);
64         Video_SetCursorPos( giScreenWidth/2, giScreenHeight/2 );
65 }
66
67 void Video_Update(void)
68 {
69          int    ofs = giVideo_FirstDirtyLine*giScreenWidth;
70          int    size = (giVideo_LastDirtyLine-giVideo_FirstDirtyLine)*giScreenWidth;
71         
72         if( giVideo_LastDirtyLine == 0 )        return; 
73
74         _SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)",
75                 giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size);
76         seek(giTerminalFD, ofs*4, 1);
77         write(giTerminalFD, gpScreenBuffer+ofs, size*4);
78         _SysDebug("Video_Update - Done");
79         giVideo_FirstDirtyLine = 0;
80         giVideo_LastDirtyLine = 0;
81 }
82
83 void Video_SetCursorPos(short X, short Y)
84 {
85         struct {
86                 uint16_t        x;
87                 uint16_t        y;
88         } pos;
89         pos.x = giVideo_CursorX = X;
90         pos.y = giVideo_CursorY = Y;
91         ioctl(giTerminalFD, TERM_IOCTL_GETSETCURSOR, &pos);
92 }
93
94 /**
95  * \brief Blit an entire buffer to the screen
96  * \note Assumes Pitch = 4*W
97  */
98 void Video_Blit(uint32_t *Source, short DstX, short DstY, short W, short H)
99 {
100         uint32_t        *buf;
101
102         if( DstX >= giScreenWidth)      return ;
103         if( DstY >= giScreenHeight)     return ;
104         // TODO: Handle -ve X/Y by clipping
105         if( DstX < 0 || DstY < 0 )      return ;
106         // TODO: Handle out of bounds by clipping too
107         if( DstX + W > giScreenWidth )  return;
108         if( DstY + H > giScreenHeight )
109                 H = giScreenWidth - DstY;
110
111         if( W <= 0 || H <= 0 )  return;
112
113         if( DstX < giVideo_FirstDirtyLine )
114                 giVideo_FirstDirtyLine = DstY;
115         if( DstY + H > giVideo_LastDirtyLine )
116                 giVideo_LastDirtyLine = DstY + H;
117         
118         buf = gpScreenBuffer + DstY*giScreenWidth + DstX;
119         if(W != giScreenWidth)
120         {
121                 while( H -- )
122                 {
123                         memcpy(buf, Source, W*4);
124                         Source += W;
125                         buf += giScreenWidth;
126                 }
127         }
128         else
129         {
130                 memcpy(buf, Source, giScreenWidth*H*4);
131         }
132 }
133
134 tColour Video_AlphaBlend(tColour _orig, tColour _new, uint8_t _alpha)
135 {
136         uint16_t        ao,ro,go,bo;
137         uint16_t        an,rn,gn,bn;
138         if( _alpha == 0 )       return _orig;
139         if( _alpha == 255 )     return _new;
140         
141         ao = (_orig >> 24) & 0xFF;
142         ro = (_orig >> 16) & 0xFF;
143         go = (_orig >>  8) & 0xFF;
144         bo = (_orig >>  0) & 0xFF;
145         
146         an = (_new >> 24) & 0xFF;
147         rn = (_new >> 16) & 0xFF;
148         gn = (_new >>  8) & 0xFF;
149         bn = (_new >>  0) & 0xFF;
150
151         if( _alpha == 0x80 ) {
152                 ao = (ao + an) / 2;
153                 ro = (ro + rn) / 2;
154                 go = (go + gn) / 2;
155                 bo = (bo + bn) / 2;
156         }
157         else {
158                 ao = ao*(255-_alpha) + an*_alpha;
159                 ro = ro*(255-_alpha) + rn*_alpha;
160                 go = go*(255-_alpha) + gn*_alpha;
161                 bo = bo*(255-_alpha) + bn*_alpha;
162                 ao /= 255*2;
163                 ro /= 255*2;
164                 go /= 255*2;
165                 bo /= 255*2;
166         }
167
168         return (ao << 24) | (ro << 16) | (go << 8) | bo;
169 }
170

UCC git Repository :: git.ucc.asn.au