You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
873 lines
22 KiB
873 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spvidfb.c
|
|
|
|
Abstract:
|
|
|
|
Text setup display support for frame buffer displays.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 29-July-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
#define MINXRES 80
|
|
#define MINYRES 32
|
|
|
|
//
|
|
// Vector for frame buffer functions.
|
|
//
|
|
|
|
VIDEO_FUNCTION_VECTOR FrameBufferVideoVector =
|
|
|
|
{
|
|
FrameBufferDisplayString,
|
|
FrameBufferClearRegion,
|
|
FrameBufferSpecificInit,
|
|
FrameBufferSpecificReInit,
|
|
FrameBufferSpecificTerminate,
|
|
FrameBufferSpecificInitPalette,
|
|
FrameBufferSpecificScrollUp
|
|
};
|
|
|
|
|
|
BOOLEAN FrameBufferInitialized = FALSE;
|
|
|
|
|
|
//
|
|
// Variables that indicate whether we should double the width
|
|
// and/or height of a font glyph when it is drawn. This is useful
|
|
// on a 1280*1024 screen for example, to make things readable
|
|
// with an 8*12 font like vgaoem.fon.
|
|
//
|
|
BOOLEAN DoubleCharWidth,DoubleCharHeight;
|
|
|
|
//
|
|
// Number of bytes that make up a row of characters.
|
|
// Equal to the screen stride (number of bytes on a scan line)
|
|
// multiplied by the height of a char in bytes; double that
|
|
// if DoubleCharHeight is TRUE.
|
|
//
|
|
ULONG CharRowDelta;
|
|
|
|
ULONG ScaledCharWidth,HeightIterations;
|
|
ULONG BytesPerPixel;
|
|
|
|
PULONG GlyphMap;
|
|
|
|
|
|
//
|
|
// Pointer to a dynamically allocated buffer that is the size of one scanline.
|
|
//
|
|
|
|
VOID
|
|
pFrameBufferInitGlyphs(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
FrameBufferSpecificInit(
|
|
IN PVIDEO_MODE_INFORMATION VideoModes,
|
|
IN ULONG NumberOfModes,
|
|
IN ULONG ModeSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform frame buffer specific initialization. This includes
|
|
|
|
- setting the desired video mode.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
VIDEO_MODE VideoMode;
|
|
PVIDEO_MODE_INFORMATION mode;
|
|
|
|
//
|
|
// headless isn't enabled on frame buffer because no frame buffer systems
|
|
// currently exist. if this changes, then this code must be enabled for
|
|
// headless operation.
|
|
//
|
|
ASSERT( HeadlessTerminalConnected == FALSE );
|
|
|
|
if(FrameBufferInitialized) {
|
|
return;
|
|
}
|
|
|
|
mode = pFrameBufferDetermineModeToUse(VideoModes,NumberOfModes, ModeSize);
|
|
|
|
if(mode == 0) {
|
|
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_BADMODE, 0);
|
|
while(TRUE); // loop forever
|
|
}
|
|
|
|
//
|
|
// Save away the mode info in a global.
|
|
//
|
|
VideoVars.VideoModeInfo = *mode;
|
|
|
|
//
|
|
// Set the desired mode.
|
|
//
|
|
VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
|
|
|
|
Status = ZwDeviceIoControlFile(
|
|
VideoVars.hDisplay,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_VIDEO_SET_CURRENT_MODE,
|
|
&VideoMode,
|
|
sizeof(VideoMode),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
|
|
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
|
|
while(TRUE); // loop forever
|
|
}
|
|
|
|
//
|
|
// Map the frame buffer.
|
|
//
|
|
pSpvidMapVideoMemory(TRUE);
|
|
|
|
FrameBufferInitialized = TRUE;
|
|
|
|
//
|
|
// Determine the width of the screen. If it's double the size
|
|
// of the minimum number of characters per row (or larger)
|
|
// then we'll double the width of each character as we draw it.
|
|
//
|
|
VideoVars.ScreenWidth = VideoVars.VideoModeInfo.VisScreenWidth / FontCharacterWidth;
|
|
if(VideoVars.ScreenWidth >= 2*MINXRES) {
|
|
VideoVars.ScreenWidth /= 2;
|
|
DoubleCharWidth = TRUE;
|
|
} else {
|
|
DoubleCharWidth = FALSE;
|
|
}
|
|
|
|
//
|
|
// Determine the height of the screen. If it's double the size
|
|
// of the minimum number of characters per column (or larger)
|
|
// then we'll double the height of each character as we draw it.
|
|
//
|
|
VideoVars.ScreenHeight = VideoVars.VideoModeInfo.VisScreenHeight / FontCharacterHeight;
|
|
CharRowDelta = VideoVars.VideoModeInfo.ScreenStride * FontCharacterHeight;
|
|
if(VideoVars.ScreenHeight >= 2*MINYRES) {
|
|
VideoVars.ScreenHeight /= 2;
|
|
DoubleCharHeight = TRUE;
|
|
CharRowDelta *= 2;
|
|
} else {
|
|
DoubleCharHeight = FALSE;
|
|
}
|
|
|
|
BytesPerPixel = VideoVars.VideoModeInfo.BitsPerPlane / 8;
|
|
if(BytesPerPixel == 3) {
|
|
BytesPerPixel = 4;
|
|
}
|
|
ScaledCharWidth = (DoubleCharWidth ? 2 : 1) * FontCharacterWidth * BytesPerPixel;
|
|
HeightIterations = DoubleCharHeight ? 2 : 1;
|
|
|
|
//
|
|
// initialize glyphs.
|
|
//
|
|
|
|
pFrameBufferInitGlyphs();
|
|
|
|
//
|
|
// get hold of the space require for background textmode video buffer
|
|
// while upgrade graphics mode is running in the foreground
|
|
//
|
|
if (SP_IS_UPGRADE_GRAPHICS_MODE()) {
|
|
VideoVars.VideoBufferSize = VideoVars.VideoModeInfo.VisScreenHeight *
|
|
VideoVars.VideoModeInfo.VisScreenWidth * BytesPerPixel;
|
|
|
|
VideoVars.VideoBuffer = SpMemAlloc(VideoVars.VideoBufferSize);
|
|
|
|
if (!VideoVars.VideoBuffer) {
|
|
//
|
|
// Out of memory, run only in textmode
|
|
//
|
|
VideoVars.VideoBufferSize = 0;
|
|
SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
|
|
VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
|
|
} else {
|
|
VideoVars.ActiveVideoBuffer = VideoVars.VideoBuffer;
|
|
}
|
|
} else {
|
|
VideoVars.VideoBufferSize = 0;
|
|
VideoVars.VideoBuffer = NULL;
|
|
VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FrameBufferSpecificReInit(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
VIDEO_MODE VideoMode;
|
|
|
|
if (!FrameBufferInitialized) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set the desired mode.
|
|
//
|
|
VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
|
|
|
|
Status = ZwDeviceIoControlFile(
|
|
VideoVars.hDisplay,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_VIDEO_SET_CURRENT_MODE,
|
|
&VideoMode,
|
|
sizeof(VideoMode),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
|
|
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
|
|
while(TRUE); // loop forever
|
|
}
|
|
|
|
//
|
|
// Determine the width of the screen. If it's double the size
|
|
// of the minimum number of characters per row (or larger)
|
|
// then we'll double the width of each character as we draw it.
|
|
//
|
|
VideoVars.ScreenWidth = VideoVars.VideoModeInfo.VisScreenWidth / FontCharacterWidth;
|
|
|
|
if(VideoVars.ScreenWidth >= 2*MINXRES) {
|
|
VideoVars.ScreenWidth /= 2;
|
|
DoubleCharWidth = TRUE;
|
|
} else {
|
|
DoubleCharWidth = FALSE;
|
|
}
|
|
|
|
//
|
|
// Determine the height of the screen. If it's double the size
|
|
// of the minimum number of characters per column (or larger)
|
|
// then we'll double the height of each character as we draw it.
|
|
//
|
|
VideoVars.ScreenHeight = VideoVars.VideoModeInfo.VisScreenHeight / FontCharacterHeight;
|
|
CharRowDelta = VideoVars.VideoModeInfo.ScreenStride * FontCharacterHeight;
|
|
|
|
if(VideoVars.ScreenHeight >= 2*MINYRES) {
|
|
VideoVars.ScreenHeight /= 2;
|
|
DoubleCharHeight = TRUE;
|
|
CharRowDelta *= 2;
|
|
} else {
|
|
DoubleCharHeight = FALSE;
|
|
}
|
|
|
|
BytesPerPixel = VideoVars.VideoModeInfo.BitsPerPlane / 8;
|
|
if(BytesPerPixel == 3) {
|
|
BytesPerPixel = 4;
|
|
}
|
|
|
|
ScaledCharWidth = (DoubleCharWidth ? 2 : 1) * FontCharacterWidth * BytesPerPixel;
|
|
HeightIterations = DoubleCharHeight ? 2 : 1;
|
|
|
|
//
|
|
// initialize glyphs.
|
|
//
|
|
pFrameBufferInitGlyphs();
|
|
|
|
FrameBufferSpecificInitPalette();
|
|
|
|
//
|
|
// Blast the cached video memory to the real framebuffer now
|
|
//
|
|
if (SP_IS_UPGRADE_GRAPHICS_MODE() && VideoVars.VideoBuffer &&
|
|
VideoVars.VideoBufferSize) {
|
|
PUCHAR Source = VideoVars.VideoBuffer;
|
|
PUCHAR Destination = VideoVars.VideoMemoryInfo.FrameBufferBase;
|
|
ULONG Index;
|
|
|
|
for (Index=0; Index < VideoVars.VideoBufferSize; Index++) {
|
|
WRITE_REGISTER_UCHAR(Destination + Index, *(Source + Index));
|
|
}
|
|
|
|
SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
|
|
VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
FrameBufferSpecificInitPalette(
|
|
VOID
|
|
)
|
|
{
|
|
BOOLEAN rc;
|
|
ULONG NumEntries;
|
|
ULONG BufferSize;
|
|
PVIDEO_CLUT clut;
|
|
// NTSTATUS Status;
|
|
// IO_STATUS_BLOCK IoStatusBlock;
|
|
UCHAR i;
|
|
|
|
rc = TRUE;
|
|
|
|
//
|
|
// For non-palette-driven displays, we construct a simple palette
|
|
// for use w/ gamma correcting adapters.
|
|
//
|
|
|
|
if(!(VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN)) {
|
|
|
|
switch(BytesPerPixel) {
|
|
case 1:
|
|
NumEntries = 3;
|
|
break;
|
|
case 2:
|
|
NumEntries = 32;
|
|
break;
|
|
default:
|
|
NumEntries = 255;
|
|
break;
|
|
}
|
|
|
|
BufferSize = sizeof(VIDEO_CLUT)+(sizeof(VIDEO_CLUTDATA)*NumEntries); // size is close enough
|
|
clut = SpMemAlloc(BufferSize);
|
|
|
|
clut->NumEntries = (USHORT)NumEntries;
|
|
clut->FirstEntry = 0;
|
|
|
|
for(i=0; i<NumEntries; i++) {
|
|
clut->LookupTable[i].RgbArray.Red = i;
|
|
clut->LookupTable[i].RgbArray.Green = i;
|
|
clut->LookupTable[i].RgbArray.Blue = i;
|
|
clut->LookupTable[i].RgbArray.Unused = 0;
|
|
}
|
|
|
|
// Status = ZwDeviceIoControlFile(
|
|
// hDisplay,
|
|
// NULL,
|
|
// NULL,
|
|
// NULL,
|
|
// &IoStatusBlock,
|
|
// IOCTL_VIDEO_SET_COLOR_REGISTERS,
|
|
// clut,
|
|
// BufferSize,
|
|
// NULL,
|
|
// 0
|
|
// );
|
|
|
|
SpMemFree(clut);
|
|
|
|
// if(!NT_SUCCESS(Status)) {
|
|
// KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set palette (status = %lx)\n",Status));
|
|
// rc = FALSE;
|
|
// }
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
VOID
|
|
FrameBufferSpecificTerminate(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform frame buffer specific termination. This includes
|
|
|
|
- unmapping the frame buffer from memory
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
if(FrameBufferInitialized) {
|
|
|
|
//
|
|
// Be a good citizen and clear the screen. Important in Far East where
|
|
// we switch screen modes on the fly as we go in and out of localized mode.
|
|
//
|
|
FrameBufferClearRegion(0,0,VideoVars.ScreenWidth,VideoVars.ScreenHeight,ATT_FG_BLACK|ATT_BG_BLACK);
|
|
|
|
pSpvidMapVideoMemory(FALSE);
|
|
FrameBufferInitialized = FALSE;
|
|
|
|
SpMemFree(GlyphMap);
|
|
|
|
if (VideoVars.VideoBuffer && VideoVars.VideoBufferSize) {
|
|
SpMemFree(VideoVars.VideoBuffer);
|
|
VideoVars.VideoBuffer = NULL;
|
|
VideoVars.VideoBufferSize = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
FrameBufferDisplayString(
|
|
IN PSTR String,
|
|
IN UCHAR Attribute,
|
|
IN ULONG X, // 0-based coordinates (character units)
|
|
IN ULONG Y
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a string of characters to the display.
|
|
|
|
Arguments:
|
|
|
|
Character - supplies a string in the OEM character set, to be displayed
|
|
at the given position.
|
|
|
|
Attribute - supplies the attributes for the character.
|
|
|
|
X,Y - specify the character-based (0-based) position of the output.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG BgColorValue;
|
|
ULONG FgColorValue;
|
|
PUCHAR Destination;
|
|
ULONG I;
|
|
ULONG J;
|
|
ULONG K;
|
|
ULONG Length;
|
|
PUCHAR Origin;
|
|
ULONG Pixel;
|
|
ULONG PixelMap;
|
|
ULONG RealHeight;
|
|
|
|
ASSERT(X < VideoVars.ScreenWidth);
|
|
ASSERT(Y < VideoVars.ScreenHeight);
|
|
|
|
//
|
|
// Calculate the bit patterns that yield the foreground and background
|
|
// attributes when poked into the frame buffer.
|
|
//
|
|
|
|
FgColorValue = VideoVars.AttributeToColorValue[Attribute & 0x0f];
|
|
BgColorValue = VideoVars.AttributeToColorValue[(Attribute >> 4) & 0x0f];
|
|
|
|
//
|
|
// Calculate the address of the upper left pixel of the first character
|
|
// to be displayed.
|
|
//
|
|
|
|
Origin = (PUCHAR)VideoVars.ActiveVideoBuffer
|
|
+ (Y * CharRowDelta)
|
|
+ (X * ScaledCharWidth);
|
|
|
|
RealHeight = FontCharacterHeight * HeightIterations;
|
|
|
|
//
|
|
// Output the character string by generating a complete scanline into
|
|
// a temporary buffer using glyph segments from each character, then
|
|
// copy the scanline to the frame buffer.
|
|
//
|
|
|
|
Length = strlen(String);
|
|
for (I = 0; I < RealHeight; I += 1) {
|
|
Destination = Origin;
|
|
for (J = 0; J < Length; J += 1) {
|
|
PixelMap = *(GlyphMap + (((UCHAR)String[J] * RealHeight) + I));
|
|
for (K = 0; K < FontCharacterWidth; K += 1) {
|
|
|
|
Pixel = (PixelMap >> 31) ? FgColorValue : BgColorValue;
|
|
|
|
switch(BytesPerPixel) {
|
|
|
|
case 1:
|
|
*Destination++ = (UCHAR)Pixel;
|
|
if(DoubleCharWidth) {
|
|
*Destination++ = (UCHAR)Pixel;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
*(PUSHORT)Destination = (USHORT)Pixel;
|
|
Destination += 2;
|
|
if(DoubleCharWidth) {
|
|
*(PUSHORT)Destination = (USHORT)Pixel;
|
|
Destination += 2;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
*(PULONG)Destination = Pixel;
|
|
Destination += 4;
|
|
if(DoubleCharWidth) {
|
|
*(PULONG)Destination = Pixel;
|
|
Destination += 4;
|
|
}
|
|
break;
|
|
}
|
|
|
|
PixelMap <<= 1;
|
|
}
|
|
}
|
|
|
|
Origin += VideoVars.VideoModeInfo.ScreenStride;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
FrameBufferClearRegion(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG W,
|
|
IN ULONG H,
|
|
IN UCHAR Attribute
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clear out a screen region to a specific attribute.
|
|
|
|
Arguments:
|
|
|
|
X,Y,W,H - specify rectangle in 0-based character coordinates.
|
|
|
|
Attribute - Low nibble specifies attribute to be filled in the rectangle
|
|
(ie, the background color to be cleared to).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR Destination;
|
|
ULONG Fill;
|
|
ULONG i;
|
|
ULONG FillLength;
|
|
ULONG x;
|
|
ULONG Iterations;
|
|
|
|
ASSERT(X+W <= VideoVars.ScreenWidth);
|
|
ASSERT(Y+H <= VideoVars.ScreenHeight);
|
|
|
|
if(X+W > VideoVars.ScreenWidth) {
|
|
W = VideoVars.ScreenWidth-X;
|
|
}
|
|
|
|
if(Y+H > VideoVars.ScreenHeight) {
|
|
H = VideoVars.ScreenHeight-Y;
|
|
}
|
|
|
|
Fill = VideoVars.AttributeToColorValue[Attribute & 0x0f];
|
|
|
|
Destination = (PUCHAR)VideoVars.ActiveVideoBuffer
|
|
+ (Y * CharRowDelta)
|
|
+ (X * ScaledCharWidth);
|
|
|
|
FillLength = W * ScaledCharWidth;
|
|
Iterations = H * FontCharacterHeight * HeightIterations;
|
|
|
|
switch(BytesPerPixel) {
|
|
|
|
case 1:
|
|
for(i=0; i<Iterations; i++) {
|
|
for(x=0; x<FillLength; x++) {
|
|
((PUCHAR)Destination)[x] = (UCHAR)Fill;
|
|
}
|
|
Destination += VideoVars.VideoModeInfo.ScreenStride;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
for(i=0; i<Iterations; i++) {
|
|
for(x=0; x<FillLength/2; x++) {
|
|
((PUSHORT)Destination)[x] = (USHORT)Fill;
|
|
}
|
|
Destination += VideoVars.VideoModeInfo.ScreenStride;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
for(i=0; i<Iterations; i++) {
|
|
for(x=0; x<FillLength/4; x++) {
|
|
((PULONG)Destination)[x] = (ULONG)Fill;
|
|
}
|
|
Destination += VideoVars.VideoModeInfo.ScreenStride;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FrameBufferSpecificScrollUp(
|
|
IN ULONG TopLine,
|
|
IN ULONG BottomLine,
|
|
IN ULONG LineCount,
|
|
IN UCHAR FillAttribute
|
|
)
|
|
{
|
|
PUCHAR Source,Target;
|
|
ULONG Count;
|
|
|
|
Target = (PUCHAR)VideoVars.ActiveVideoBuffer
|
|
+ (TopLine * CharRowDelta);
|
|
|
|
Source = Target + (LineCount * CharRowDelta);
|
|
|
|
Count = (((BottomLine - TopLine) + 1) - LineCount) * CharRowDelta;
|
|
|
|
RtlMoveMemory(Target,Source,Count);
|
|
|
|
FrameBufferClearRegion(
|
|
0,
|
|
(BottomLine - LineCount) + 1,
|
|
VideoVars.ScreenWidth,
|
|
LineCount,
|
|
FillAttribute
|
|
);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
pFrameBufferInitGlyphs(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG I,J,z,FontValue;
|
|
UCHAR Character;
|
|
USHORT chr;
|
|
PUCHAR Glyph;
|
|
PULONG dest;
|
|
|
|
if (!GlyphMap) {
|
|
GlyphMap = SpMemAlloc(sizeof(ULONG)*256*FontCharacterHeight*HeightIterations);
|
|
}
|
|
|
|
dest = GlyphMap;
|
|
|
|
for(chr=0; chr<256; chr++) {
|
|
|
|
Character = (UCHAR)chr;
|
|
|
|
if((Character < FontHeader->FirstCharacter)
|
|
|| (Character > FontHeader->LastCharacter))
|
|
{
|
|
Character = FontHeader->DefaultCharacter;
|
|
}
|
|
|
|
Character -= FontHeader->FirstCharacter;
|
|
|
|
Glyph = (PUCHAR)FontHeader + FontHeader->Map[Character].Offset;
|
|
|
|
for (I = 0; I < FontCharacterHeight; I++) {
|
|
|
|
//
|
|
// Build up a bitmap of pixels that comprise the row of the glyph
|
|
// we are drawing.
|
|
//
|
|
FontValue = 0;
|
|
for (J = 0; J < FontBytesPerRow; J++) {
|
|
FontValue |= *(Glyph + (J * FontCharacterHeight)) << (24 - (J * 8));
|
|
}
|
|
Glyph++;
|
|
|
|
for(z=0; z<HeightIterations; z++) {
|
|
*dest++ = FontValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PVIDEO_MODE_INFORMATION
|
|
pFrameBufferLocateMode(
|
|
IN PVIDEO_MODE_INFORMATION VideoModes,
|
|
IN ULONG NumberOfModes,
|
|
IN ULONG ModeSize,
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG Bpp,
|
|
IN ULONG VRefresh
|
|
)
|
|
{
|
|
ULONG modenum;
|
|
PVIDEO_MODE_INFORMATION pVideoMode = &VideoModes[0];
|
|
|
|
for(modenum=0; modenum<NumberOfModes; modenum++) {
|
|
|
|
if((pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS)
|
|
&& (pVideoMode->VisScreenWidth == X)
|
|
&& (pVideoMode->VisScreenHeight == Y)
|
|
&& (((Bpp == (ULONG)(-1)) && (pVideoMode->BitsPerPlane >= 8)) || (pVideoMode->BitsPerPlane == Bpp))
|
|
&& ((VRefresh == (ULONG)(-1)) || (pVideoMode->Frequency == VRefresh)))
|
|
{
|
|
return(pVideoMode);
|
|
}
|
|
|
|
pVideoMode = (PVIDEO_MODE_INFORMATION) (((PUCHAR) pVideoMode) + ModeSize);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
PVIDEO_MODE_INFORMATION
|
|
pFrameBufferDetermineModeToUse(
|
|
IN PVIDEO_MODE_INFORMATION VideoModes,
|
|
IN ULONG NumberOfModes,
|
|
IN ULONG ModeSize
|
|
)
|
|
{
|
|
PCHAR p,q,end;
|
|
ULONG X,Y;
|
|
PVIDEO_MODE_INFORMATION mode;
|
|
|
|
ULONG i; //NEC98
|
|
|
|
//return(2); //TEDM
|
|
|
|
if(!NumberOfModes) {
|
|
return(0);
|
|
}
|
|
|
|
X = Y = 0;
|
|
|
|
//
|
|
// Get x and y resolution. If we have a monitor id string
|
|
// in the form XxY, then it is the resolution to use.
|
|
//
|
|
if((p=MonitorFirmwareIdString) && (q=strchr(p+3,'x')) && (strlen(q+1) >= 3)) {
|
|
|
|
*q++ = 0;
|
|
|
|
//
|
|
// Now p points to the x resolution and q to the y resolution.
|
|
//
|
|
X = SpMultiByteStringToUnsigned(p,&end);
|
|
if(X && (end == (q-1))) {
|
|
|
|
Y = SpMultiByteStringToUnsigned(q,&end);
|
|
if(end != (q+strlen(q))) {
|
|
Y = 0;
|
|
}
|
|
|
|
} else {
|
|
X = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we don't have x or y resolution yet, look in the
|
|
// monitor config data.
|
|
//
|
|
if((!X || !Y) && MonitorConfigData) {
|
|
|
|
X = (ULONG)MonitorConfigData->HorizontalResolution;
|
|
Y = (ULONG)MonitorConfigData->VerticalResolution;
|
|
}
|
|
|
|
if(X && Y) {
|
|
|
|
//
|
|
// We found what seems like a reasonable resolution.
|
|
// Now try to locate a mode that uses it.
|
|
//
|
|
|
|
//
|
|
// Find a mode of 8bpp with the x and y resolution at 60 Hz.
|
|
//
|
|
mode = pFrameBufferLocateMode(VideoModes,NumberOfModes,ModeSize,X,Y,8,60);
|
|
|
|
if (mode) {
|
|
return(mode);
|
|
}
|
|
|
|
//
|
|
// Couldn't find an 8bpp mode @ 60Hz; find any mode with that resolution at 8bpp.
|
|
//
|
|
mode = pFrameBufferLocateMode(VideoModes,NumberOfModes,ModeSize,X,Y,8,(ULONG)(-1));
|
|
if(mode) {
|
|
return(mode);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Can't find a mode so far. See if mode 0 is acceptable.
|
|
//
|
|
// First video mode in list is not for VGA on NEC98,
|
|
// so make a loop to check VGA mode.
|
|
// (First video mode in list is for VGA on PC/AT.)
|
|
//
|
|
for(i=0;
|
|
i<((!IsNEC_98) ? 1 : NumberOfModes);
|
|
i++, VideoModes=(PVIDEO_MODE_INFORMATION)(((PUCHAR)VideoModes)+ModeSize))
|
|
{
|
|
if((VideoModes->AttributeFlags & VIDEO_MODE_GRAPHICS)
|
|
&& (VideoModes->BitsPerPlane >= 8)
|
|
&& (VideoModes->VisScreenWidth >= 640)
|
|
&& (VideoModes->VisScreenHeight >= 480))
|
|
{
|
|
return(VideoModes);
|
|
}
|
|
} //NEC98
|
|
|
|
//
|
|
// Give up.
|
|
//
|
|
return(0);
|
|
}
|