⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scrcntl.cpp

📁 quake 游戏原代码
💻 CPP
字号:
/****************************************
scrcntl.cpp- a module to provide a layer of abstraction
between the OS graphics architecture and the application
It provides you the programmer with the ability to create offscreen
buffers, whose drawing surfaces you have direct access to, which 
blit to the screen across operating systems. To change the
destination operating system, simply change the file os.h
Also requires the file palcntl.cpp to load palettes in the bitmaps
A routine called App_Make_New_Screen must be in another source file. It
should perform any work that must be done for the app to run in the
new screen size
*****************************************/

#include "os.h"
#include "scrcntl.h"
#include "buffnode.h"
#include "memutil.h"
#include "scconint.h"
#include "palette.h"
#include <mem.h>

#ifdef OS_WINDOWS
#include "wingdll.h"
#endif

pbuffer_node buffer_list=NULL;
screen_ptr cur_screen_ptr;
void App_Make_New_Screen();

#ifdef OS_DOS

#define VGA_WIDTH 320
#define VGA_HEIGHT 200
#define SVGA_WIDTH 640
#define SVGA_HEIGHT 480

#include "vesa.h"
#include "screen.h"

void Screen_Copy(long offset, void * src, long ncopy);

BOOL super_vga;
void Attempt_Screen_Open(short & width, short & height)
{
	if ( (width>VGA_WIDTH) || (height>VGA_HEIGHT) ) {
		// must load a super vga screen to get requested dimensions
		VBE_detect();
		if (VESA_InitGraphics(width, height)) {
			// no svga so load vga dimensions
			setgmode(0x13);
			super_vga=FALSE;
			width=VGA_WIDTH;
			height=VGA_HEIGHT;
		} else {
			super_vga=TRUE;
		}
	} else {
		super_vga=FALSE;
		setgmode(0x13);
		width=VGA_WIDTH;
		height=VGA_HEIGHT;
	}
}

void Screen_Copy(long offset, void * src, long ncopy) {

if (cur_screen_ptr==NULL) {
	if (super_vga) {
		VESA_ScreenCopy(offset, src, ncopy);
	} else {
		memcpy(screen+offset, src, ncopy);
	} /* endif */
} else {
	memcpy(cur_screen_ptr+offset, src, ncopy);
}

}

#endif

#ifdef OS_WINDOWS
HBITMAP cur_hbitmap=NULL;
short stretch_factor=1;

typedef struct MY_BITMAP_HEADER
{
	BITMAPINFOHEADER Header;
	RGBQUAD aColors[256];
} my_bitmap_header;

my_bitmap_header os_header;

HBITMAP old_mono_bitmap;
HDC off_screen_DC;
WinGdll WinG;
#endif

void Allocate_Offscreen_Buffer(poff_screen_buff new_buff) {

#ifdef OS_DOS
	// allocate the off screen buffer manually
	(*(new_buff->buff_ptr_address))=(video_data_ptr)NewPtr(
		  Get_Phys_Screen_Width() * Get_Phys_Screen_Height());
#endif

#ifdef OS_WINDOWS
	// copy palette to buffer header
	// this is done now in case you want to load different palettes for each buffer
	// the currently loaded is made the buffer's palette. You don't have to do this
	// in dos because dos bitmaps have no palettes. To keep the bitmap's palette equal to
	// the loaded palette, you must call Change_Screen.

	for (short color_index=0; color_index< PALETTE_COLORS; color_index++) {
		os_header.aColors[color_index].rgbRed=Get_Palette_Red_Val(color_index);
		os_header.aColors[color_index].rgbGreen=Get_Palette_Green_Val(color_index);
		os_header.aColors[color_index].rgbBlue=Get_Palette_Blue_Val(color_index);
		os_header.aColors[color_index].rgbReserved=0;
	}

	// create the bitmap handle in the WinGDC
	new_buff->hbitmap=WinG.pCreateBitmap(off_screen_DC, (BITMAPINFO *)&os_header, 
		  (PVOID *)new_buff->buff_ptr_address);    
#endif

}

void Delete_Offscreen_Buffer(poff_screen_buff delete_buff) {

#ifdef OS_DOS
  DelPtr( (*(delete_buff->buff_ptr_address)));
#endif

#ifdef OS_WINDOWS
	if (cur_hbitmap==delete_buff->hbitmap) {
		SelectObject(off_screen_DC, old_mono_bitmap);
		cur_hbitmap=old_mono_bitmap;
	}
	DeleteObject(delete_buff->hbitmap);
#endif

}

poff_screen_buff Create_Offscreen_Buffer(video_data_ptr * buff_ptr_address)
{
	// make a new off_screen_buff structure
	poff_screen_buff new_buff=(poff_screen_buff)NewPtr(sizeof(off_screen_buff));
	new_buff->buff_ptr_address=buff_ptr_address;

	// just what is says
	Allocate_Offscreen_Buffer(new_buff);

// put the new buffer in the list of buffers
pbuffer_node new_buff_node=BN_Create_Node();
BN_Set_Data(new_buff_node, new_buff);
BN_Set_Next_Node(new_buff_node, buffer_list);
BN_Set_Node(buffer_list, new_buff_node);

return new_buff;
}

void Dispose_Buffer(poff_screen_buff os_buffer) {
	pbuffer_node cur_node, next_node;
	BOOL found;

	// are we dealing with and empty list, if so the node does not exist
	if (BN_Empty_Node(buffer_list)) {
		return;
	}

	// if node is the start of list, update list and delete node
	if (BN_Get_Data(buffer_list)==os_buffer) {
		BN_Set_Node(next_node, BN_Get_Next_Node(buffer_list));
		Delete_Offscreen_Buffer(BN_Get_Data(buffer_list));
		BN_Delete_Node(buffer_list);
		BN_Set_Node(buffer_list, next_node);
		return;
	}

	// find the node to be deleted
	BN_Set_Node(cur_node, buffer_list);
	found=FALSE;
	while (!BN_Empty_Node(BN_Get_Next_Node(cur_node))) {
		if (BN_Get_Data(BN_Get_Next_Node(cur_node))==os_buffer) {
			found=TRUE;
			break;
		}
		BN_Set_Node(cur_node, BN_Get_Next_Node(cur_node));
	} /* endwhile */

	// Remove the node from list and delete it
	if (found) {
		BN_Set_Node(next_node, BN_Get_Next_Node(BN_Get_Next_Node(cur_node)));
		Delete_Offscreen_Buffer(BN_Get_Data(BN_Get_Next_Node(cur_node)));
		BN_Delete_Node(BN_Get_Next_Node(cur_node));
		BN_Set_Next_Node(cur_node, next_node);
	}
}

extern "C" short LOGICAL_SCREEN_HEIGHT; // stores without screen orientation
extern "C" short LOGICAL_SCREEN_WIDTH; // same for width

void Activate_Graphics() {
#ifdef OS_DOS
	Attempt_Screen_Open(LOGICAL_SCREEN_WIDTH,  LOGICAL_SCREEN_HEIGHT);    
#endif
}

void Init_Screen(short width, short height) {

	short valid_width=((width+3)/4)*4; // bitmap should be 32 bits wide, so width must
	  // be a multiple of 4
	short valid_height=height;

#ifdef OS_DOS
	Init_Phys_Screen(valid_width, valid_height);
#endif

#ifdef OS_WINDOWS
if (!WinG.Load()) { //link to WinG DLL.
	MessageBox(0,"Can't find WING32.DLL","WTWIN Error!",MB_OK);
	return;
}
Init_Phys_Screen(valid_width, valid_height);
if(WinG.pRecommendDIBFormat((BITMAPINFO *)&os_header)) {
	//  make sure it's 8bpp and remember the orientation

	os_header.Header.biBitCount = 8;
	os_header.Header.biCompression = BI_RGB;
	Set_Phys_Orientation(os_header.Header.biHeight*(-1));
} else {
	//  set it up ourselves

	os_header.Header.biSize = sizeof(BITMAPINFOHEADER);
	os_header.Header.biPlanes = 1;
	os_header.Header.biBitCount = 8;
	os_header.Header.biCompression = BI_RGB;
	os_header.Header.biSizeImage = 0;
	os_header.Header.biClrUsed = 0;
	os_header.Header.biClrImportant = 0;
}

os_header.Header.biWidth=Get_Phys_Screen_Width();
os_header.Header.biHeight=Get_Phys_Screen_Height()*Get_Phys_Orientation() * (-1);

off_screen_DC=WinG.pCreateDC();

old_mono_bitmap=(HBITMAP)GetCurrentObject(off_screen_DC, OBJ_BITMAP);
cur_hbitmap=old_mono_bitmap;

stretch_factor=1;
#endif

Set_Screen_Window(NULL);
}

void Change_Screen(short width, short height) {
	short valid_width=((width+3)/4)*4; // bitmap should be 32 bits wide, so width must
	  // be a multiple of 4
	short valid_height=height;

#ifdef OS_DOS
  Attempt_Screen_Open(valid_width, valid_height);
  Set_Phys_Screen(valid_width, valid_height);
#endif

#ifdef OS_WINDOWS
	valid_width/=stretch_factor;
	valid_height/=stretch_factor;
	Set_Phys_Screen(valid_width, valid_height);
	// set buffer dimensions
	os_header.Header.biWidth=Get_Phys_Screen_Width();
	os_header.Header.biHeight=Get_Phys_Screen_Height() * Get_Phys_Orientation() * (-1);

#endif

// clear all buffers
pbuffer_node cur_node;
BN_Set_Node(cur_node, buffer_list);
while (!BN_Empty_Node(cur_node)) {
	Delete_Offscreen_Buffer(BN_Get_Data(cur_node));
	Allocate_Offscreen_Buffer(BN_Get_Data(cur_node));
	BN_Set_Node(cur_node, BN_Get_Next_Node(cur_node));
} /* endwhile */

// let application adjust to the change in size
App_Make_New_Screen();
}

void End_Graphics() {

// clear all buffers
pbuffer_node cur_node, next_node;
BN_Set_Node(cur_node, buffer_list);
while (!BN_Empty_Node(cur_node)) {
	Delete_Offscreen_Buffer(BN_Get_Data(cur_node));
	BN_Set_Node(next_node, BN_Get_Next_Node(cur_node));
	BN_Delete_Node(cur_node);
	BN_Set_Node(cur_node, next_node);
} /* endwhile */

// perform OS dependent graphics shutdowns
#ifdef OS_DOS
if (super_vga) {
	VESA_EndGraphics();
} else {
	setgmode(0x3);
} /* endif */
#endif

#ifdef OS_WINDOWS
DeleteDC(off_screen_DC);
WinG.Free(); //terminate WinG DLL link.
#endif

}

void Blt_Buffer(poff_screen_buff os_buffer) {
#ifdef OS_DOS
	Screen_Copy(0, (*os_buffer->buff_ptr_address), Get_Phys_Screen_Width() * Get_Phys_Screen_Height());
#endif

#ifdef OS_WINDOWS
if (cur_hbitmap!=os_buffer->hbitmap) {
	SelectObject(off_screen_DC, os_buffer->hbitmap);
	cur_hbitmap=os_buffer->hbitmap;
} /* endif */

// do a wing blit, calling a liner blit only is stretch factor is 1
	if (stretch_factor != 1)
		WinG.pStretchBlt(cur_screen_ptr,0,0,
					 stretch_factor*Get_Phys_Screen_Width(),
					 stretch_factor*Get_Phys_Screen_Height(),
		off_screen_DC,0,0,
					 Get_Phys_Screen_Width(),
					 Get_Phys_Screen_Height());
	else
		WinG.pBitBlt(cur_screen_ptr,0,0,
					 Get_Phys_Screen_Width(),
					 Get_Phys_Screen_Height(),
					 off_screen_DC,0,0);
#endif

}

#ifdef OS_WINDOWS
void Set_Stretch_Factor(short new_factor) {
	stretch_factor=new_factor;
}

short Get_Stretch_Factor() {
	return stretch_factor;
}
#endif

void Set_Screen_Window(screen_ptr new_screen_ptr) {

cur_screen_ptr=new_screen_ptr;

#ifdef OS_WINDOWS
if (cur_screen_ptr==NULL)
	cur_screen_ptr=GetDC(NULL);
#endif
}

void Release_Screen_Window() {
	Set_Screen_Window(NULL);
}

screen_ptr Get_Screen_Window() {
	return cur_screen_ptr;
}

void Clear_Buffer(poff_screen_buff os_buffer) {
#ifdef OS_DOS
memset(*(os_buffer->buff_ptr_address),BLACK_COLOR,
				Get_Phys_Screen_Width() * Get_Phys_Screen_Height() * sizeof(unsigned char));
#endif

#ifdef OS_WINDOWS
if (cur_hbitmap!=os_buffer->hbitmap) {
	SelectObject(off_screen_DC, os_buffer->hbitmap);
	cur_hbitmap=os_buffer->hbitmap;
} /* endif */

PatBlt(off_screen_DC, 0, 0, Get_Phys_Screen_Width(), Get_Phys_Screen_Height(), BLACK_COLOR);
#endif

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -