Modules - Use short command annotation in makefile ([CC] not $(CC))
[tpg/acess2.git] / AcessNative / acesskernel_src / video.c
1 /*
2  * Acess2 Native Kernel
3  * 
4  * Video Driver
5  */
6 #define VERSION ((0<<8)|10)
7 #define DEBUG   0
8 #include <acess.h>
9 #include <vfs.h>
10 #include <fs_devfs.h>
11 #include <modules.h>
12 #include <api_drv_video.h>
13 #include "ui.h"
14
15 // === PROTOTYPES ===
16  int    Video_Install(char **Arguments);
17 size_t  Video_Read(tVFS_Node *Node, Uint64 Offset, size_t Length, void *Buffer, Uint Flags);
18 size_t  Video_Write(tVFS_Node *Node, Uint64 Offset, size_t Length, const void *Buffer, Uint Flags);
19  int    Video_IOCtl(tVFS_Node *Node, int ID, void *Data);
20 // --- 2D Acceleration Functions --
21 void    Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
22 void    Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
23
24 // === GLOBALS ===
25 //MODULE_DEFINE(0, VERSION, NativeVideo, Video_Install, NULL, NULL);
26 tVFS_NodeType   gVideo_NodeType = {
27         .Read = Video_Read,
28         .Write = Video_Write,
29         .IOCtl = Video_IOCtl
30 };
31 tDevFS_Driver   gVideo_DriverStruct = {
32         NULL, "NativeVideo",
33         {
34                 .Type = &gVideo_NodeType
35         }
36 };
37  int    giVideo_DriverID;
38  int    giVideo_CurrentFormat;
39 // --- 2D Video Stream Handlers ---
40 tDrvUtil_Video_2DHandlers       gVideo_2DFunctions = {
41         NULL,
42         Video_2D_Fill,
43         Video_2D_Blit
44 };
45
46 // === CODE ===
47 int Video_Install(char **Arguments)
48 {
49         // Install Device
50         giVideo_DriverID = DevFS_AddDevice( &gVideo_DriverStruct );
51         if(giVideo_DriverID == -1)
52                 return MODULE_ERR_MISC;
53         
54         return MODULE_ERR_OK;
55 }
56
57 /**
58  * \brief Read from framebuffer (unimplemented)
59  */
60 size_t Video_Read(tVFS_Node *Node, Uint64 Offset, size_t Length, void *Buffer, Uint Flags)
61 {
62         return 0;
63 }
64
65 /**
66  * \brief Write to the framebuffer
67  */
68 size_t Video_Write(tVFS_Node *Node, Uint64 Offset, size_t Length, const void *Buffer, Uint Flags)
69 {
70          int    i;
71         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
72
73         if(Buffer == NULL) {
74                 LEAVE('i', 0);
75                 return 0;
76         }
77         // Text Mode
78         switch( giVideo_CurrentFormat )
79         {
80         case VIDEO_BUFFMT_TEXT:
81                 {
82                 const tVT_Char  *chars = Buffer;
83                 // int  pitch = giUI_Pitch;
84                  int    widthInChars = giUI_Width/giVT_CharWidth;
85                  int    heightInChars = giUI_Height/giVT_CharHeight;
86                  int    x, y;
87                 Uint32  tmpBuf[giVT_CharHeight*giVT_CharWidth];
88                 
89                 Length /= sizeof(tVT_Char);
90                 Offset /= sizeof(tVT_Char);
91                 
92                 x = Offset % widthInChars;
93                 y = Offset / widthInChars;
94                 
95                 // Sanity Check
96                 if( Offset > (Uint64)(heightInChars*widthInChars) ) {
97                         Log_Notice("Video", "Offset (%i) > %i*%i (%i)", Offset,
98                                 heightInChars, widthInChars, heightInChars*widthInChars);
99                         LEAVE('i', 0);
100                         return 0;
101                 }
102                 if(y >= heightInChars) {
103                         LEAVE('i', 0);
104                         return 0;
105                 }
106                 
107                 // Clip to screen size
108                 if( (int)Offset + (int)Length > heightInChars*widthInChars ) {
109                         Log_Debug("Video", "%i + %i > %i*%i (%i)",
110                                 (int)Offset, (int)Length, heightInChars, widthInChars, heightInChars*widthInChars);
111                         Length = heightInChars*widthInChars - Offset;
112                         Log_Notice("Video", "Clipping write size to %i characters", (int)Length);
113                 }
114                 
115 //              Log_Debug("Video", "(%i,%i) %i chars", x, y, (int)Length);
116                 
117                 // Print characters
118                 for( i = 0; i < (int)Length; i++ )
119                 {
120                         if( chars->Ch )
121                         {
122 //                              Log_Debug("Video", "Render Char 0x%x in 0x%03x:%03x",
123 //                                      chars->Ch, chars->FGCol, chars->BGCol);
124                                 memset(tmpBuf, 0xFF, giVT_CharWidth*giVT_CharHeight*4);
125                                 VT_Font_Render(
126                                         chars->Ch,
127                                         tmpBuf, 32, giVT_CharWidth*4,
128                                         VT_Colour12to24(chars->BGCol),
129                                         VT_Colour12to24(chars->FGCol)
130                                         );
131                                 UI_BlitBitmap(
132                                         x*giVT_CharWidth, y*giVT_CharHeight,
133                                         giVT_CharWidth, giVT_CharHeight,
134                                         tmpBuf
135                                         );
136                         }
137                         else
138                         {
139                                 UI_FillBitmap(
140                                         x*giVT_CharWidth, y*giVT_CharHeight,
141                                         giVT_CharWidth, giVT_CharHeight,
142                                         VT_Colour12to24(chars->BGCol)
143                                         );
144                         }
145                         
146                         chars ++;
147                         x ++;
148                         if( x >= widthInChars ) {
149                                 x = 0;
150                                 y ++;
151                                 //dest += pitch*giVT_CharHeight;
152                         }
153                 }
154                 Length *= sizeof(tVT_Char);
155                 }
156                 break;
157         
158         case VIDEO_BUFFMT_FRAMEBUFFER:
159                 {
160                  int    startX, startY;
161                 
162                 if(giUI_Pitch*giUI_Height < Offset+Length)
163                 {
164                         Log_Warning("Video", "Video_Write - Framebuffer Overflow");
165                         LEAVE('i', 0);
166                         return 0;
167                 }
168                 
169                 LOG("buffer = %p", Buffer);
170                 
171                 Offset /= 4;
172                 startX = Offset % giUI_Width;
173                 startY = Offset / giUI_Width;
174                 Length /= 4;
175
176                 if( startX + Length < giUI_Width )
177                 {
178                         // Single line
179                         UI_BlitBitmap(
180                                 startX, startY,
181                                 Length, 1,
182                                 Buffer);
183                 }
184                 else if( startX == 0 )
185                 {
186                         int     lines = Length / giUI_Width;
187                         int     rem = Length % giUI_Width;
188                         UI_BlitBitmap(0, startY, giUI_Width, lines, Buffer);
189                         if( rem ) {
190                                 UI_BlitBitmap(0, startY + lines, rem, 1, (Uint32*)Buffer + lines*giUI_Width);
191                         }
192                 }
193                 else
194                 {
195                         // First scanline (partial or full)
196                         UI_BlitBitmap(
197                                 startX, startY,
198                                 giUI_Width - startX, 1,
199                                 Buffer);
200                         
201                         Length -= giUI_Width - startX;
202                         Buffer += giUI_Width - startX;
203                         
204                         // Middle Scanlines
205                         for( i = 0; i < Length / giUI_Height; i ++ )
206                         {
207                                 UI_BlitBitmap(
208                                         0, startY + i,
209                                         giUI_Width, 1,
210                                         Buffer);
211                                 Buffer += giUI_Width;
212                         }
213                         
214                         // Final scanline (partial)
215                         if( Length % giUI_Height )
216                         {
217                                 UI_BlitBitmap(
218                                         0, startY + i,
219                                         Length % giUI_Height, 1,
220                                         Buffer);
221                         }
222                 }
223                 }
224                 break;
225         
226         case VIDEO_BUFFMT_2DSTREAM:
227                 Length = DrvUtil_Video_2DStream(
228                         NULL,   // Single framebuffer, so Ent is unused
229                         Buffer, Length, &gVideo_2DFunctions, sizeof(gVideo_2DFunctions)
230                         );
231                 break;
232         
233         default:
234                 LEAVE('i', -1);
235                 return -1;
236         }
237         
238         // Tell the UI to blit
239         UI_Redraw();
240         
241         LEAVE('X', Length);
242         return Length;
243 }
244
245 const char * csaVIDEO_IOCTLS[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};
246 /**
247  * \brief Handle messages to the device
248  */
249 int Video_IOCtl(tVFS_Node *Node, int ID, void *Data)
250 {
251          int    ret;
252         tVideo_IOCtl_Mode       *mode = Data;
253         switch(ID)
254         {
255         BASE_IOCTLS(DRV_TYPE_VIDEO, "NativeVideo", VERSION, csaVIDEO_IOCTLS);
256         
257         // Video mode control
258         // - We cheat, and only have one mode
259         case VIDEO_IOCTL_GETSETMODE:
260                 // - Abuse GETSETMODE to update size
261                 Node->Size = giUI_Pitch * giUI_Height;
262                 return 0;
263         case VIDEO_IOCTL_FINDMODE:
264         case VIDEO_IOCTL_MODEINFO:
265                 mode->id = 0;
266                 mode->width = giUI_Width;
267                 mode->height = giUI_Height;
268                 mode->bpp = 32;
269                 mode->flags = 0;
270                 return 0;
271         
272         // Buffer mode
273         case VIDEO_IOCTL_SETBUFFORMAT:
274                 ret = giVideo_CurrentFormat;
275                 if(Data) {
276                         giVideo_CurrentFormat = *(int*)Data;
277                 }
278                 return ret;
279         
280         #if 0
281         case VIDEO_IOCTL_SETCURSOR:     // Set cursor position
282                 #if !BLINKING_CURSOR
283                 if(giVideo_CursorX > 0)
284                         Video_FlipCursor(Node);
285                 #endif
286                 giVideo_CursorX = ((tVideo_IOCtl_Pos*)Data)->x;
287                 giVideo_CursorY = ((tVideo_IOCtl_Pos*)Data)->y;
288                 if(     giVideo_CursorX < 0 || giVesaCursorY < 0
289                 ||      giVideo_CursorX >= gpVesaCurMode->width/giVT_CharWidth
290                 ||      giVideo_CursorY >= gpVesaCurMode->height/giVT_CharHeight)
291                 {
292                         #if BLINKING_CURSOR
293                         if(giVesaCursorTimer != -1) {
294                                 Time_RemoveTimer(giVesaCursorTimer);
295                                 giVesaCursorTimer = -1;
296                         }
297                         #endif
298                         giVesaCursorX = -1;
299                         giVesaCursorY = -1;
300                 }
301                 else {
302                         #if BLINKING_CURSOR
303                 //      Log_Debug("VESA", "Updating timer %i?", giVesaCursorTimer);
304                         if(giVesaCursorTimer == -1)
305                                 giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, Node);
306                         #else
307                         Vesa_FlipCursor(Node);
308                         #endif
309                 }
310                 //Log_Debug("VESA", "Cursor position (%i,%i) Timer %i", giVesaCursorX, giVesaCursorY, giVesaCursorTimer);
311                 return 0;
312         #endif
313         }
314         return 0;
315 }
316
317 // --- 2D Acceleration Functions --
318 void Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
319 {
320         UI_FillBitmap(X, Y, W, H, Colour);
321 }
322
323 void Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
324 {
325         UI_BlitFramebuffer(DstX, DstY, SrcX, SrcY, W, H);
326 }

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