diff --git a/REDALERT/GADGET.CPP b/REDALERT/GADGET.CPP index 019e1fa..ca5a3f6 100644 --- a/REDALERT/GADGET.CPP +++ b/REDALERT/GADGET.CPP @@ -535,6 +535,8 @@ KeyNumType GadgetClass::Input(void) // jmarshall int flags = 0; WWSDL_ProcessEvents(key, flags); + + Show_Mouse(); // jmarshall: thsi shouldn't be here! // jmarshall end /* diff --git a/REDALERT/GSCREEN.CPP b/REDALERT/GSCREEN.CPP index e8e9195..f0a7213 100644 --- a/REDALERT/GSCREEN.CPP +++ b/REDALERT/GSCREEN.CPP @@ -275,6 +275,8 @@ void GScreenClass::Input(KeyNumType & key, int & x, int & y) x = Keyboard->Mouse_X(); y = Keyboard->Mouse_Y(); + Show_Mouse(); + if (Buttons != NULL) { /* diff --git a/REDALERT/INIT.CPP b/REDALERT/INIT.CPP index e1980bf..2b811b0 100644 --- a/REDALERT/INIT.CPP +++ b/REDALERT/INIT.CPP @@ -672,7 +672,7 @@ bool Select_Game(bool fade) // } Set_Logic_Page(SeenBuff); - display = false; + // display = false; Show_Mouse(); } else { @@ -3387,7 +3387,7 @@ static void Init_Mouse(void) ** to set one of our own. */ #ifdef WIN32 -// ShowCursor(false); + ShowCursor(false); #endif if (MouseInstalled) { void const * temp_mouse_shapes = MFCD::Retrieve("MOUSE.SHP"); diff --git a/REDALERT/MSGBOX.CPP b/REDALERT/MSGBOX.CPP index 87f948d..f05a1fe 100644 --- a/REDALERT/MSGBOX.CPP +++ b/REDALERT/MSGBOX.CPP @@ -274,7 +274,7 @@ int WWMessageBox::Process(const char * msg, const char * b1txt, const char * b2t #endif if (display) { - display = false; + //display = false; Hide_Mouse(); Dialog_Box(x, y, width, height); diff --git a/REDALERT/RedAlert.vcxproj b/REDALERT/RedAlert.vcxproj index 5bf13cc..e01f669 100644 --- a/REDALERT/RedAlert.vcxproj +++ b/REDALERT/RedAlert.vcxproj @@ -449,6 +449,7 @@ + @@ -739,6 +740,7 @@ + diff --git a/REDALERT/RedAlert.vcxproj.filters b/REDALERT/RedAlert.vcxproj.filters index 45979bb..265aab1 100644 --- a/REDALERT/RedAlert.vcxproj.filters +++ b/REDALERT/RedAlert.vcxproj.filters @@ -942,6 +942,9 @@ Source Files\win32lib + + Source Files\win32lib + @@ -1838,6 +1841,9 @@ Source Files\libsmacker + + Source Files\win32lib + diff --git a/REDALERT/SPECIAL.CPP b/REDALERT/SPECIAL.CPP index 69f23f0..091b0cf 100644 --- a/REDALERT/SPECIAL.CPP +++ b/REDALERT/SPECIAL.CPP @@ -527,12 +527,12 @@ int Fetch_Difficulty(void) ** Main Processing Loop. */ Set_Logic_Page(SeenBuff); - bool redraw = true; + //bool redraw = true; bool process = true; while (process) { - if (redraw) { - redraw = false; + { + // redraw = false; /* ** Draw the background of the dialog. @@ -575,7 +575,7 @@ int Fetch_Difficulty(void) */ if (AllSurfaces.SurfacesRestored) { AllSurfaces.SurfacesRestored=FALSE; - redraw = true; + //redraw = true; continue; } #endif //WIN32 diff --git a/REDALERT/WIN32LIB/MOUSE.H b/REDALERT/WIN32LIB/MOUSE.H index b40d07e..4c8781c 100644 --- a/REDALERT/WIN32LIB/MOUSE.H +++ b/REDALERT/WIN32LIB/MOUSE.H @@ -60,6 +60,24 @@ class WWMouseClass { void Set_Cursor_Clip(void); void Clear_Cursor_Clip(void); +// jmarshall - accessor functions to hook up mouse code from chronoshift. + int Get_Hotspot_X(void) { return MouseXHot; } + int Get_Hotspot_Y(void) { return MouseYHot; } + int Get_Cursor_Width(void) { return CursorWidth; } + int Get_Cursor_Height(void) { return CursorHeight; } + int Get_Max_Width(void) { return MaxWidth; } + int Get_Max_Height(void) { return MaxHeight; } + void Set_Hotspot_X(int hotspotX) { MouseXHot = hotspotX; } + void Set_Hotspot_Y(int hotspotY) { MouseYHot = hotspotY; } + void Set_Cursor_Width(int width) { CursorWidth = width; } + void Set_Cursor_Height(int height) { CursorHeight = height; } + void Set_Max_Width(int width) { MaxWidth = width; } + void Set_Max_Height(int height) { MaxHeight = height; } + + char* Get_Image_Buff(void) { return MouseCursor; } + void* Get_Frame_Pointer() { return PrevCursor; } + void Set_Frame_Pointer(void* frame) { PrevCursor = (char *)frame; } +// jmarshall end private: enum { CONDHIDE = 1, @@ -105,11 +123,9 @@ class WWMouseClass { }; -extern "C" { - void __cdecl Mouse_Shadow_Buffer(void *thisptr, GraphicViewPortClass *srcdst, void *buffer, int x, int y, int hotx, int hoty, int store); - void __cdecl Draw_Mouse(void *thisptr, GraphicViewPortClass *srcdst, int x, int y); - void * __cdecl ASM_Set_Mouse_Cursor(void * thisptr, int hotspotx, int hotspoty, VOID *cursor); -}; +void __cdecl Mouse_Shadow_Buffer(WWMouseClass& mouse, GraphicViewPortClass& viewport, void* buffer, int x_pos, int y_pos, int hspot_x, int hspot_y, BOOL save); +void __cdecl Mouse_Draw(WWMouseClass& mouse, GraphicViewPortClass& viewport, int x_pos, int y_pos); +void* __cdecl Mouse_Set_Cursor(WWMouseClass& mouse, int hspot_x, int hspot_y, void* frame); void Hide_Mouse(void); void Show_Mouse(void); diff --git a/REDALERT/WIN32LIB/MOUSEWW.CPP b/REDALERT/WIN32LIB/MOUSEWW.CPP index bdeb01a..1b080ed 100644 --- a/REDALERT/WIN32LIB/MOUSEWW.CPP +++ b/REDALERT/WIN32LIB/MOUSEWW.CPP @@ -37,6 +37,7 @@ static WWMouseClass *_Mouse=NULL; void CALLBACK Process_Mouse( UINT event_id, UINT res1 , DWORD user, DWORD res2, DWORD res3 ); extern bool GameInFocus; +extern int mousex, mousey; /*********************************************************************************************** * MOUSECLASS::MOUSECLASS -- Constructor for the Mouse Class * @@ -184,9 +185,6 @@ void WWMouseClass::Clear_Cursor_Clip(void) void WWMouseClass::Process_Mouse(void) { -//ST - 1/3/2019 10:50AM - return; -#if (0) POINT pt; // define a structure to hold current cursor pos // @@ -255,19 +253,10 @@ void WWMouseClass::Process_Mouse(void) // Allow other threads to lock the screen again // //Unblock_Mouse(Screen->Get_Graphic_Buffer()); -#endif } void *WWMouseClass::Set_Cursor(int xhotspot, int yhotspot, void *cursor) { -//ST - 1/3/2019 10:50AM - xhotspot; - yhotspot; - cursor; - return cursor; - -#if (0) - // // If the pointer to the cursor we got is invalid, or its the same as the // currently set cursor then just return. @@ -287,7 +276,7 @@ void *WWMouseClass::Set_Cursor(int xhotspot, int yhotspot, void *cursor) // Now convert the shape to a mouse cursor with the given hotspots and // set it as our current mouse. // - void *retval = ASM_Set_Mouse_Cursor(this, xhotspot, yhotspot, cursor); + void *retval = Mouse_Set_Cursor(*this, xhotspot, yhotspot, cursor); // // Show the mouse which will force it to appear with the new shape we // have assigned. @@ -302,24 +291,21 @@ void *WWMouseClass::Set_Cursor(int xhotspot, int yhotspot, void *cursor) // Asm_Set_Mouse_Cursor. // return(retval); -#endif } void WWMouseClass::Low_Hide_Mouse() { -//ST - 1/3/2019 10:50AM -#if (0) if (!State) { if (MouseBuffX != -1 || MouseBuffY != -1) { if (Screen->Lock()){ - Mouse_Shadow_Buffer(this, Screen, MouseBuffer, MouseBuffX, MouseBuffY, MouseXHot, MouseYHot, 0); + Mouse_Shadow_Buffer(*this, *Screen, MouseBuffer, MouseBuffX, MouseBuffY, MouseXHot, MouseYHot, 0); Screen->Unlock(); } } MouseBuffX = -1; MouseBuffY = -1; } -#endif + State++; } void WWMouseClass::Hide_Mouse() @@ -332,23 +318,11 @@ void WWMouseClass::Hide_Mouse() void WWMouseClass::Low_Show_Mouse(int x, int y) { - // - // If the mouse is already visible then just ignore the problem. - // - if (State == 0) return; - // - // Make the mouse a little bit more visible - // - State--; - -//ST - 1/3/2019 10:50AM -#if (0) - // // If the mouse is completely visible then draw it at its current // position. // - if (!State) { + { // // Try to lock the screen til we sucessfully get a lock. // @@ -356,11 +330,11 @@ void WWMouseClass::Low_Show_Mouse(int x, int y) // // Save off the area behind the mouse. // - Mouse_Shadow_Buffer(this, Screen, MouseBuffer, x, y, MouseXHot, MouseYHot, 1); + Mouse_Shadow_Buffer(*this, *Screen, MouseBuffer, x, y, MouseXHot, MouseYHot, 1); // // Draw the mouse in its new location // - ::Draw_Mouse(this, Screen, x, y); + Mouse_Draw(*this, *Screen, x, y); // // Save off the positions that we saved the buffer from // @@ -372,17 +346,16 @@ void WWMouseClass::Low_Show_Mouse(int x, int y) Screen->Unlock(); } } -#endif } void WWMouseClass::Show_Mouse() { - POINT pt; - GetCursorPos(&pt); - - MouseUpdate++; - Low_Show_Mouse(pt.x, pt.y); - MouseUpdate--; + //POINT pt; + //GetCursorPos(&pt); + // + //MouseUpdate++; + Low_Show_Mouse(mousex, mousey); + //MouseUpdate--; } void WWMouseClass::Conditional_Hide_Mouse(int x1, int y1, int x2, int y2) @@ -589,7 +562,7 @@ void WWMouseClass::Erase_Mouse(GraphicViewPortClass *scr, int forced) int WWMouseClass::Get_Mouse_State(void) { - return(State); + return 0;//(State); } /*********************************************************************************************** * WWKeyboardClass::Get_Mouse_X -- Returns the mouses current x position in pixels * @@ -603,9 +576,7 @@ int WWMouseClass::Get_Mouse_State(void) *=============================================================================================*/ int WWMouseClass::Get_Mouse_X(void) { - POINT pt; - GetCursorPos(&pt); - return(pt.x); + return mousex; } @@ -621,9 +592,7 @@ int WWMouseClass::Get_Mouse_X(void) *=============================================================================================*/ int WWMouseClass::Get_Mouse_Y(void) { - POINT pt; - GetCursorPos(&pt); - return(pt.y); + return mousey; } /*********************************************************************************************** @@ -638,12 +607,9 @@ int WWMouseClass::Get_Mouse_Y(void) * 10/17/1995 PWG : Created. * *=============================================================================================*/ void WWMouseClass::Get_Mouse_XY(int &x, int &y) -{ - POINT pt; - - GetCursorPos(&pt); - x = pt.x; - y = pt.y; +{ + x = mousex; + y = mousey; } //#pragma off(unreferenced) diff --git a/REDALERT/WIN32LIB/MouseShape.cpp b/REDALERT/WIN32LIB/MouseShape.cpp new file mode 100644 index 0000000..6808c9f --- /dev/null +++ b/REDALERT/WIN32LIB/MouseShape.cpp @@ -0,0 +1,304 @@ +/** + * @file + * + * @author OmniBlade + * @author CCHyper + * + * @brief Low level sprite drawing functions for Dune2 sprite format (used for mouse in early C&C games). + * + * @copyright Chronoshift is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "../FUNCTION.H" +#include +#include "mouse.h" +#include "mouseshape.h" +#include "gbuffer.h" +//#include "lcw.h" +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +using std::memcpy; + +uint8_t g_mouseShapeBuffer[65000]; // Original code shares the global ShapeBuffer with other sprite drawing. + +int Get_Shape_Uncomp_Size(void* shape) +{ + return static_cast(shape)->data_length; +} + +int Extract_Shape_Count(void* shape) +{ + return static_cast(shape)->frame_count; +} + +void* Extract_Shape(void* shape, int frame) +{ + char* data = static_cast(shape); + MouseShapeHeader* header = static_cast(shape); + + if (shape && frame >= 0 && header->frame_count > frame) { + return data + (&header->offset)[frame] + 2; + } + + return nullptr; +} + +int Get_Shape_Width(void* shape) +{ + // return static_cast(shape)->Width; + return static_cast(shape)->width; +} + +int Get_Shape_Height(void* shape) +{ + return static_cast(shape)->height; +} + +//int Restore_Shape_Height(void* shape) +//{ +// int oldheight = static_cast(shape)->height; +// static_cast(shape)->height = static_cast(shape)->original_height; +// return oldheight; +//} + +int Get_Shape_Original_Height(void* shape) +{ + return static_cast(shape)->original_height; +} + +void __cdecl Mouse_Shadow_Buffer(WWMouseClass& mouse, GraphicViewPortClass& viewport, void* buffer, int x_pos, int y_pos, int hspot_x, int hspot_y, BOOL save) +{ + int xstart = x_pos - hspot_x; + int ystart = y_pos - hspot_y; + int yend = mouse.Get_Cursor_Height() + ystart - 1; + int xend = mouse.Get_Cursor_Width() + xstart - 1; + int ms_img_offset = 0; + uint8_t* mouse_img = static_cast(buffer); + + //If we aren't drawing within the viewport, return + if (xstart >= viewport.Get_Width() || + ystart >= viewport.Get_Height() || + xend <= 0 || yend <= 0) { + return; + } + + if (xstart < 0) { + ms_img_offset = -xstart; + xstart = 0; + } + + if (ystart < 0) { + mouse_img += mouse.Get_Cursor_Width() * (-ystart); + ystart = 0; + } + + xend = MIN(xend, viewport.Get_Width() - 1); + yend = MIN(yend, viewport.Get_Height() - 1); + + int blit_height = yend - ystart + 1; + int blit_width = xend - xstart + 1; + int src_pitch; + int dst_pitch; + uint8_t* src; + uint8_t* dst; + + // Bool will control if we are copying to or from shadow buffer, set vars here + if (save) { + src_pitch = (viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width()); + dst_pitch = mouse.Get_Cursor_Width(); + src = (uint8_t*)(viewport.Get_Offset()) + src_pitch * ystart + xstart; + dst = mouse_img + ms_img_offset; + } + else { + src_pitch = mouse.Get_Cursor_Width(); + dst_pitch = (viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width()); + src = mouse_img + ms_img_offset; + dst = (uint8_t*)(viewport.Get_Offset()) + dst_pitch * ystart + xstart; + } + + while (blit_height--) { + memcpy(dst, src, blit_width); + src += src_pitch; + dst += dst_pitch; + } +} + +void __cdecl Mouse_Draw(WWMouseClass& mouse, GraphicViewPortClass& viewport, int x_pos, int y_pos) +{ + int xstart = x_pos - mouse.Get_Hotspot_X(); + int ystart = y_pos - mouse.Get_Hotspot_Y(); + int yend = mouse.Get_Cursor_Height() + ystart - 1; + int xend = mouse.Get_Cursor_Width() + xstart - 1; + int ms_img_offset = 0; + uint8_t* mouse_img = (uint8_t * )mouse.Get_Image_Buff(); + + //If we aren't drawing within the viewport, return + if (xstart >= viewport.Get_Width() || + ystart >= viewport.Get_Height() || + xend <= 0 || yend <= 0) { + return; + } + + if (xstart < 0) { + ms_img_offset = -xstart; + xstart = 0; + } + + if (ystart < 0) { + mouse_img += mouse.Get_Cursor_Width() * (-ystart); + ystart = 0; + } + + xend = MIN(xend, viewport.Get_Width() - 1); + yend = MIN(yend, viewport.Get_Height() - 1); + + int pitch = viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width(); + uint8_t* dst = xstart + pitch * ystart + (uint8_t*)(viewport.Get_Offset()); + uint8_t* src = ms_img_offset + mouse_img; + int blit_pitch = xend - xstart + 1; + + if ((xend > xstart) && (yend > ystart)) { + int blit_height = yend - ystart + 1; + int dst_pitch = pitch - blit_pitch; + int src_pitch = mouse.Get_Cursor_Width() - blit_pitch; + + while (blit_height--) { + int blit_width = blit_pitch; + while (blit_width--) { + uint8_t current = *src++; + if (current) { + *dst = current; + } + + ++dst; + //--blit_width; + } + + src += src_pitch; + dst += dst_pitch; + //--blit_height; + } + } +} + +void* __cdecl Mouse_Set_Cursor(WWMouseClass& mouse, int hspot_x, int hspot_y, void* frame) +{ + uint8_t* frame_buff; + uint8_t* data_buff; + uint8_t* decmp_buff; + uint8_t* lcw_buff; + int16_t frame_flags; + + int height; + int width; + int uncompsz; + + MouseShapeFrameHeader* frame_header = static_cast(frame); + + //Get the dimensions of our frame, mouse shp format can have variable + //dimensions for each frame. + uncompsz = Get_Shape_Uncomp_Size(frame); + width = Get_Shape_Width(frame); + height = Get_Shape_Original_Height(frame); + + if (width <= mouse.Get_Max_Width() && height <= mouse.Get_Max_Height()) { + frame_buff = (uint8_t * )mouse.Get_Image_Buff(); + data_buff = static_cast(frame); + frame_flags = frame_header->flags; + + //Flag bit 2 is flag for no compression on frame, decompress to + //intermediate buffer if flag is clear + if (!(frame_header->flags & 2)) { + decmp_buff = g_mouseShapeBuffer; + lcw_buff = reinterpret_cast(frame_header); + frame_flags = frame_header->flags | 2; + + memcpy(decmp_buff, lcw_buff, sizeof(MouseShapeFrameHeader)); + decmp_buff += sizeof(MouseShapeFrameHeader); + lcw_buff += sizeof(MouseShapeFrameHeader); + + //Copies a small lookup table if it exists, probably not in RA. + if (frame_flags & 1) { + memcpy(decmp_buff, lcw_buff, 16); + decmp_buff += 16; + lcw_buff += 16; + } + + LCW_Uncomp(lcw_buff, decmp_buff, uncompsz); + data_buff = g_mouseShapeBuffer; + } + + if (frame_flags & 1) { + uint8_t* data_start = data_buff + sizeof(MouseShapeFrameHeader); + uint8_t* image_start = data_buff + sizeof(MouseShapeFrameHeader) + 16; + int image_size = height * width; + //uint8_t current_byte = 0; + int run_len = 0; + + while (image_size) { + uint8_t current_byte = *image_start++; + if (current_byte) { + *frame_buff++ = data_start[current_byte]; + --image_size; + continue; + } + + if (!image_size) { + break; + } + + run_len = *image_start; + image_size -= run_len; + ++image_start; + + while (run_len--) { + *frame_buff++ = 0; + } + } + } + else { + uint8_t* data_start = data_buff + sizeof(MouseShapeFrameHeader); + int image_size = height * width; + int run_len = 0; + + while (image_size) { + uint8_t current_byte = *data_start++; + if (current_byte) { + *frame_buff++ = current_byte; + --image_size; + continue; + } + + if (!image_size) { + break; + } + + run_len = *data_start; + image_size -= run_len; + ++data_start; + + while (run_len--) { + *frame_buff++ = 0; + } + } + } + + mouse.Set_Hotspot_X(hspot_x); + mouse.Set_Hotspot_Y(hspot_y); + mouse.Set_Cursor_Height(height); + mouse.Set_Cursor_Width(width); + } + + void* result = mouse.Get_Frame_Pointer(); + mouse.Set_Frame_Pointer(frame); + + return result; +} diff --git a/REDALERT/WIN32LIB/MouseShape.h b/REDALERT/WIN32LIB/MouseShape.h new file mode 100644 index 0000000..dbfded0 --- /dev/null +++ b/REDALERT/WIN32LIB/MouseShape.h @@ -0,0 +1,67 @@ +/** + * @file + * + * @author OmniBlade + * @author CCHyper + * + * @brief Low level sprite drawing functions for Dune2 sprite format (used for mouse in early C&C games). + * + * @copyright Chronoshift is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once + +#ifndef MOUSESHAPE_H +#define MOUSESHAPE_H + +#pragma pack(push, 1) + // Header for each frame in the old SHP format... only used for mouse now. +struct MouseShapeFrameHeader +{ + //"MAKESHAPE_NORMAL" 0 + //"MAKESHAPE_COMPACT" 1 + //"MAKESHAPE_NOCOMP" 2 + //"MAKESHAPE_VARIABLE" 4 + uint16_t flags; // flag 1 specifies that a 16 byte color table follows the header. + // flag 2 specifies that this frame doesn't have LCW compression, + // this frame would only have RLE compression. + // flag 4 specifies a custom length color table follows the header. + uint8_t height; //height after RLE compression? + uint16_t width; + uint8_t original_height; // original frame height without any compression. + uint16_t shape_size; // full frame size including this header. + uint16_t data_length; // uncompressed size, frame size minus header if flag 2 is specified. + // + // Following this is optional data, in Dune 2 this was used to specify remap indexes. + // If flag 1 is set then a uint8_t color_table[16] follows. + // if flag 4 is set then a uint8_t color_table_size and uint8_t color_table[color_table_size] follows. +}; + +// Header for the old SHP format... only used for mouse now. Offset values need +2 to get actual frame pos. +struct MouseShapeHeader +{ + uint16_t frame_count; + uint32_t offset; +}; +#pragma pack(pop) + +class WWMouseClass; +class GraphicViewPortClass; + +int Get_Shape_Uncomp_Size(void* shape); +int Extract_Shape_Count(void* shape); +void* Extract_Shape(void* shape, int frame = 0); +int Get_Shape_Width(void* shape); +int Get_Shape_Height(void* shape); +int Restore_Shape_Height(void* shape); +int Get_Shape_Original_Height(void* shape); + +void __cdecl Mouse_Shadow_Buffer(WWMouseClass& mouse, GraphicViewPortClass& viewport, void* buffer, int x_pos, int y_pos, int hspot_x, int hspot_y, BOOL save); +void __cdecl Mouse_Draw(WWMouseClass& mouse, GraphicViewPortClass& viewport, int x_pos, int y_pos); +void* __cdecl Mouse_Set_Cursor(WWMouseClass& mouse, int hspot_x, int hspot_y, void* shape); + +#endif