a65ddf961c2863d03d4a2d3634bd8090c0d95245
[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(int X, int Y, int W, int H, uint32_t Color);
23
24 // === GLOBALS ===
25  int    giVideo_CursorX;
26  int    giVideo_CursorY;
27 uint32_t        *gpScreenBuffer;
28  int    giVideo_FirstDirtyLine;
29  int    giVideo_LastDirtyLine;
30
31 // === CODE ===
32 void Video_Setup(void)
33 {
34          int    tmpInt;
35         
36         // Open terminal
37         giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
38         if( giTerminalFD == -1 )
39         {
40                 fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
41                 exit(-1);
42         }
43         
44         
45         // Set mode to video
46         tmpInt = TERM_MODE_FB;
47         ioctl( giTerminalFD, TERM_IOCTL_MODETYPE, &tmpInt );
48         
49         // Get dimensions
50         giScreenWidth = ioctl( giTerminalFD, TERM_IOCTL_WIDTH, NULL );
51         giScreenHeight = ioctl( giTerminalFD, TERM_IOCTL_HEIGHT, NULL );
52
53         giVideo_LastDirtyLine = giScreenHeight;
54         
55         // Force VT to be shown
56         ioctl( giTerminalFD, TERM_IOCTL_FORCESHOW, NULL );
57         
58         // Create local framebuffer (back buffer)
59         gpScreenBuffer = malloc( giScreenWidth*giScreenHeight*4 );
60
61         // Set cursor position and bitmap
62         ioctl(giTerminalFD, TERM_IOCTL_SETCURSORBITMAP, &cCursorBitmap);
63         Video_SetCursorPos( giScreenWidth/2, giScreenHeight/2 );
64 }
65
66 void Video_Update(void)
67 {
68          int    ofs = giVideo_FirstDirtyLine*giScreenWidth;
69          int    size = (giVideo_LastDirtyLine-giVideo_FirstDirtyLine)*giScreenWidth;
70         
71         if( giVideo_LastDirtyLine == 0 )        return; 
72
73         _SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)",
74                 giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size);
75         seek(giTerminalFD, ofs*4, 1);
76         write(giTerminalFD, gpScreenBuffer+ofs, size*4);
77         _SysDebug("Video_Update - Done");
78         giVideo_FirstDirtyLine = 0;
79         giVideo_LastDirtyLine = 0;
80 }
81
82 void Video_SetCursorPos(short X, short Y)
83 {
84         struct {
85                 uint16_t        x;
86                 uint16_t        y;
87         } pos;
88         pos.x = giVideo_CursorX = X;
89         pos.y = giVideo_CursorY = Y;
90         ioctl(giTerminalFD, TERM_IOCTL_GETSETCURSOR, &pos);
91 }
92
93 void Video_FillRect(int X, int Y, int W, int H, uint32_t Colour)
94 {
95         uint32_t        *dest;
96          int    i;
97         
98         if(X < 0 || Y < 0)      return;
99         if(W >= giScreenWidth)  return;
100         if(H >= giScreenHeight) return;
101         if(X + W >= giScreenWidth)      W = giScreenWidth - W;
102         if(Y + H >= giScreenHeight)     W = giScreenHeight - H;
103         
104         dest = gpScreenBuffer + Y * giScreenWidth + X;
105         while(H --)
106         {
107                 for( i = W; i --; dest ++ )     *dest = Colour;
108                 dest += giScreenWidth - W;
109         }
110 }
111
112 /**
113  * \brief Blit an entire buffer to the screen
114  * \note Assumes Pitch = 4*W
115  */
116 void Video_Blit(uint32_t *Source, short DstX, short DstY, short W, short H)
117 {
118         uint32_t        *buf;
119
120         if( DstX >= giScreenWidth)      return ;
121         if( DstY >= giScreenHeight)     return ;
122         // TODO: Handle -ve X/Y by clipping
123         if( DstX < 0 || DstY < 0 )      return ;
124         // TODO: Handle out of bounds by clipping too
125         if( DstX + W > giScreenWidth )  return;
126         if( DstY + H > giScreenHeight )
127                 H = giScreenWidth - DstY;
128
129         if( W <= 0 || H <= 0 )  return;
130
131         if( DstX < giVideo_FirstDirtyLine )
132                 giVideo_FirstDirtyLine = DstY;
133         if( DstY + H > giVideo_LastDirtyLine )
134                 giVideo_LastDirtyLine = DstY + H;
135         
136         buf = gpScreenBuffer + DstY*giScreenWidth + DstX;
137         if(W != giScreenWidth)
138         {
139                 while( H -- )
140                 {
141                         memcpy(buf, Source, W*4);
142                         Source += W;
143                         buf += giScreenWidth;
144                 }
145         }
146         else
147         {
148                 memcpy(buf, Source, giScreenWidth*H*4);
149         }
150 }
151
152 tColour Video_AlphaBlend(tColour _orig, tColour _new, uint8_t _alpha)
153 {
154         uint16_t        ao,ro,go,bo;
155         uint16_t        an,rn,gn,bn;
156         if( _alpha == 0 )       return _orig;
157         if( _alpha == 255 )     return _new;
158         
159         ao = (_orig >> 24) & 0xFF;
160         ro = (_orig >> 16) & 0xFF;
161         go = (_orig >>  8) & 0xFF;
162         bo = (_orig >>  0) & 0xFF;
163         
164         an = (_new >> 24) & 0xFF;
165         rn = (_new >> 16) & 0xFF;
166         gn = (_new >>  8) & 0xFF;
167         bn = (_new >>  0) & 0xFF;
168
169         if( _alpha == 0x80 ) {
170                 ao = (ao + an) / 2;
171                 ro = (ro + rn) / 2;
172                 go = (go + gn) / 2;
173                 bo = (bo + bn) / 2;
174         }
175         else {
176                 ao = ao*(255-_alpha) + an*_alpha;
177                 ro = ro*(255-_alpha) + rn*_alpha;
178                 go = go*(255-_alpha) + gn*_alpha;
179                 bo = bo*(255-_alpha) + bn*_alpha;
180                 ao /= 255*2;
181                 ro /= 255*2;
182                 go /= 255*2;
183                 bo /= 255*2;
184         }
185
186         return (ao << 24) | (ro << 16) | (go << 8) | bo;
187 }
188

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