diff --git a/DevIL.dll b/DevIL.dll new file mode 100644 index 0000000..1bd3822 Binary files /dev/null and b/DevIL.dll differ diff --git a/ILU.dll b/ILU.dll new file mode 100644 index 0000000..2966069 Binary files /dev/null and b/ILU.dll differ diff --git a/OpenAL32.dll b/OpenAL32.dll new file mode 100644 index 0000000..8da7b5f Binary files /dev/null and b/OpenAL32.dll differ diff --git a/SDL2.dll b/SDL2.dll new file mode 100644 index 0000000..d0849bf Binary files /dev/null and b/SDL2.dll differ diff --git a/cache/empty.txt b/cache/empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index ac694c7..2a6e5a7 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMakeList.txt : CMake project for Red Alert +# CMakeList.txt : CMake project for Red Alert cmake_minimum_required (VERSION 3.8) project(RedAlert ASM CXX C) @@ -547,6 +547,7 @@ set(src_redalert ./RedAlert/TEXTBTN.H ./RedAlert/THEME.CPP ./RedAlert/THEME.H + ./RedAlert/TILESET.CPP ./RedAlert/TOGGLE.CPP ./RedAlert/TOGGLE.H ./RedAlert/TOOLTIP.CPP @@ -708,10 +709,10 @@ set(src_external ) -add_definitions(-DCHEAT_KEYS -DIMGUI_IMPL_OPENGL_LOADER_GLEW -DSCENARIO_EDITOR -DWINDOWS_IGNORE_PACKING_MISMATCH -DTRUE_FALSE_DEFINED -DWIN32 -DWINDOWS -DENGLISH -D_USRDLL -DREDALERT_EXPORTS) +add_definitions(-D RA_AF -DCHEAT_KEYS -DIMGUI_IMPL_OPENGL_LOADER_GLEW -DSCENARIO_EDITOR -DWINDOWS_IGNORE_PACKING_MISMATCH -DTRUE_FALSE_DEFINED -DWIN32 -DWINDOWS -DENGLISH -D_USRDLL -DREDALERT_EXPORTS) add_compile_options(/permissive+ /Zc:forScope- /Zp1) add_executable(RedAlert ${src_win32lib} ${src_redalert} ${src_external}) -set_target_properties(RedAlert PROPERTIES OUTPUT_NAME "RedAlert" LINK_FLAGS "/PDB:\"RedAlert.pdb\" /SUBSYSTEM:WINDOWS" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/../../bin" ) +set_target_properties(RedAlert PROPERTIES OUTPUT_NAME "RedAlert" LINK_FLAGS "/PDB:\"RedAlert.pdb\" /SUBSYSTEM:WINDOWS" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/../" ) target_include_directories(RedAlert PRIVATE ./external/devil/;./external/;./redalert/win32lib;./external/lua/;./external/imgui;./external/dxsdk/Include;./external/ffmpeg-win32/include;./external/sdl2/include;./win32lib;./external/openal/include) -target_link_libraries(RedAlert "opengl32.lib" "winmm.lib" "Ws2_32.lib" "${CMAKE_SOURCE_DIR}/external/devil/DevIL.lib" "${CMAKE_SOURCE_DIR}/external/sdl2/lib/x86/SDL2.lib" "${CMAKE_SOURCE_DIR}/external/openal/out/build/x86-Release/OpenAL32.lib") +target_link_libraries(RedAlert "opengl32.lib" "winmm.lib" "Ws2_32.lib" "${CMAKE_SOURCE_DIR}/external/devil/ilu.lib" "${CMAKE_SOURCE_DIR}/external/devil/DevIL.lib" "${CMAKE_SOURCE_DIR}/external/sdl2/lib/x86/SDL2.lib" "${CMAKE_SOURCE_DIR}/external/openal/out/build/x86-Release/OpenAL32.lib") diff --git a/code/REDALERT/BDATA.CPP b/code/REDALERT/BDATA.CPP index 8e00452..56553f7 100644 --- a/code/REDALERT/BDATA.CPP +++ b/code/REDALERT/BDATA.CPP @@ -58,7 +58,7 @@ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" - +#include "Image.h" #define FATSHIP @@ -142,6 +142,9 @@ static short const OComList[] = {1, REFRESH_EOL}; static short const OList12[] = {0, REFRESH_EOL}; static short const OListTmpl[] = {0, 1, 2, REFRESH_EOL}; +#ifdef RA_AF +#include "BDATA_AF.H" +#endif /*************************************************************************** */ @@ -3026,6 +3029,9 @@ void BuildingTypeClass::Init_Heap(void) new BuildingTypeClass(ClassLarva2); // STRUCT_LARVA2 #endif +#ifdef RA_AF + new BuildingTypeClass(ClassAFV01); // STRUCT_AFV01 +#endif } @@ -3134,6 +3140,19 @@ void BuildingTypeClass::One_Time(void) */ _makepath(fullname, NULL, NULL, building.Graphic_Name(), ".SHP"); ((void const *&)building.ImageData) = MFCD::Retrieve(fullname); + { + char imageFileName[512]; + sprintf(imageFileName, "DATA/ART/TEXTURES/SRGB/RED_ALERT/STRUCTURES/%s/%s-0000.TGA", building.Graphic_Name(), building.Graphic_Name()); + ((void const*&)building.HDImageData) = Image_LoadImage(imageFileName, true, true); + + if (building.ImageData != NULL && building.HDImageData != NULL) { + int width = Get_Build_Frame_Width(building.ImageData); + int height = Get_Build_Frame_Height(building.ImageData); + + building.HDImageData->renderwidth = width; + building.HDImageData->renderheight = height; + } + } } // Try to load weap2.shp and tesla coil's lightning shapes @@ -3206,13 +3225,24 @@ StructType BuildingTypeClass::From_Name(char const * name) *=============================================================================================*/ void BuildingTypeClass::Display(int x, int y, WindowNumberType window, HousesType ) const { - void const * ptr = Get_Cameo_Data(); - if (ptr == NULL) { - IsTheaterShape = IsTheater; - ptr = Get_Image_Data(); +// jmarshall - hd buildings. + Image_t* hdimage = Get_HDImage_Data(); + if (hdimage != NULL) { + //CC_Draw_Shape((Image_t *)Get_HDImage_Data(), 0, x, y, window, SHAPE_CENTER | SHAPE_WIN_REL, NULL, NULL, DIR_N); + x += WindowList[window][WINDOWX]; + y += WindowList[window][WINDOWY]; + GL_RenderImage(hdimage, x, y, hdimage->renderwidth, hdimage->renderheight); } - CC_Draw_Shape(ptr, 0, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL); - IsTheaterShape = false; + else { + void const* ptr = Get_Cameo_Data(); + if (ptr == NULL) { + IsTheaterShape = IsTheater; + ptr = Get_Image_Data(); + } + CC_Draw_Shape(ptr, 0, x, y, window, SHAPE_CENTER | SHAPE_WIN_REL); + IsTheaterShape = false; + } +// jmarshall end } @@ -3235,7 +3265,7 @@ void BuildingTypeClass::Display(int x, int y, WindowNumberType window, HousesTyp void BuildingTypeClass::Prep_For_Add(void) { for (StructType index = STRUCT_FIRST; index < STRUCT_COUNT; index++) { - if (As_Reference(index).Get_Image_Data()) { + if (As_Reference(index).Get_Image_Data() || As_Reference(index).Get_HDImage_Data()) { Map.Add_To_List(&As_Reference(index)); } } @@ -3356,7 +3386,28 @@ void BuildingTypeClass::Init(TheaterType theater) if (classptr->IsTheater) { _makepath(fullname, NULL, NULL, classptr->Graphic_Name(), Theaters[theater].Suffix); ((void const *&)classptr->ImageData) = MFCD::Retrieve(fullname); +// jmarshall + { + char imageFileName[512]; + // Try load the theatre specific asset first + sprintf(imageFileName, "DATA/ART/TEXTURES/SRGB/RED_ALERT/TERRAIN/%s/%s.%s/%s.%s-0000.DDS", Theaters[theater].Name, classptr->Graphic_Name(), Theaters[theater].Suffix, classptr->Graphic_Name(), Theaters[theater].Suffix); + ((BuildingTypeClass*)classptr)->HDImageData = Image_LoadImage(imageFileName); + + if (!((BuildingTypeClass*)classptr)->HDImageData) { + sprintf(imageFileName, "DATA/ART/TEXTURES/SRGB/RED_ALERT/STRUCTURES/%s/%s-0000.TGA", classptr->Graphic_Name(), classptr->Graphic_Name()); + ((BuildingTypeClass*)classptr)->HDImageData = Image_LoadImage(imageFileName); + } + + if (classptr->ImageData != NULL && classptr->HDImageData != NULL) { + int width = Get_Build_Frame_Width(classptr->ImageData); + int height = Get_Build_Frame_Height(classptr->ImageData); + + classptr->HDImageData->renderwidth = width; + classptr->HDImageData->renderheight = height; + } + } +// jmarshall end /* ** Buildup data is probably theater specific as well. Fetch a pointer to the ** data at this time as well. diff --git a/code/REDALERT/BDATA_AF.H b/code/REDALERT/BDATA_AF.H new file mode 100644 index 0000000..e99510e --- /dev/null +++ b/code/REDALERT/BDATA_AF.H @@ -0,0 +1,34 @@ +// BDAD_AF.H +// + +// Building Data for Red Alert Allied Force. + +static BuildingTypeClass const ClassAFV01( + STRUCT_AFV01, + TXT_CIV1, // NAME: Short name of the structure. + "afV01", // NAME: Short name of the structure. + FACING_S, // Foundation direction from center of building. + XYP_COORD(0, 0), // Exit point for produced units. + REMAP_ALTERNATE, // Sidebar remap logic. + 0x0000, // Vertical offset. + 0x0000, // Primary weapon offset along turret centerline. + 0x0000, // Primary weapon lateral offset along turret centerline. + false, // Is this building a fake (decoy?) + true, // Animation rate is regulated for constant speed? + true, // Always use the given name for the building? + false, // Is this a wall type structure? + true, // Simple (one frame) damage imagery? + true, // Is it invisible to radar? + true, // Can the player select this? + true, // Is this a legal target for attack or move? + true, // Is this an insignificant building? + true, // Theater specific graphic image? + false, // Does it have a rotating turret? + false, // Can the building be color remapped to indicate owner? + RTTI_NONE, // The object type produced at this factory. + DIR_N, // Starting idle frame to match construction. + BSIZE_22, // SIZE: Building size. + NULL, // Preferred exit cell list. + (short const*)List0011, // OCCUPYLIST: List of active foundation squares. + (short const*)List1100 // OVERLAPLIST:List of overlap cell offset. +); \ No newline at end of file diff --git a/code/REDALERT/BUILDING.CPP b/code/REDALERT/BUILDING.CPP index 8a8e2d8..c78dd1d 100644 --- a/code/REDALERT/BUILDING.CPP +++ b/code/REDALERT/BUILDING.CPP @@ -451,6 +451,14 @@ void BuildingClass::Draw_It(int x, int y, WindowNumberType window) const { assert(Buildings.ID(this) == ID); assert(IsActive); +// jmarshall + Image_t* hdimage = Get_HDImage_Data(); + if (hdimage != NULL) { + Techno_Draw_Object_HD(hdimage, Shape_Number(), x, y, window); + TechnoClass::Draw_It(x, y, window); + return; + } +// jmarshall end /* ** The shape file to use for rendering depends on whether the building @@ -5919,6 +5927,13 @@ void const * BuildingClass::Get_Image_Data(void) const return(TechnoClass::Get_Image_Data()); } +struct Image_t *BuildingClass::Get_HDImage_Data(void) const +{ + if (BState == BSTATE_CONSTRUCTION) { + return NULL; + } + return(TechnoClass::Get_HDImage_Data()); +} /*********************************************************************************************** * BuildingClass::Value -- Determine the value of this building. * diff --git a/code/REDALERT/BUILDING.H b/code/REDALERT/BUILDING.H index f0f991a..2da8a8e 100644 --- a/code/REDALERT/BUILDING.H +++ b/code/REDALERT/BUILDING.H @@ -236,6 +236,9 @@ class BuildingClass : public TechnoClass */ virtual int Value(void) const; virtual void const * Get_Image_Data(void) const; +// jmarshall + struct Image_t* BuildingClass::Get_HDImage_Data(void) const; +// jmarshall end virtual int How_Many_Survivors(void) const; virtual DirType Turret_Facing(void) const; virtual CELL Find_Exit_Cell(TechnoClass const * techno) const; diff --git a/code/REDALERT/CDATA.CPP b/code/REDALERT/CDATA.CPP index 572246a..02e12b5 100644 --- a/code/REDALERT/CDATA.CPP +++ b/code/REDALERT/CDATA.CPP @@ -3184,8 +3184,8 @@ void TemplateTypeClass::Display(int x, int y, WindowNumberType window, HousesTyp for (index = 0; index < w*h; index++) { if (map[index] != 0xFF) { HidPage.Draw_Stamp(iconset, index, 0, 0, NULL, WINDOW_MAIN); + Buffer_Enable_HD_Texture(true); // At this point, Draw_Stamp creates a 32bit image. if (scale) { - HidPage.Scale((*LogicPage), 0, 0, x + ((index % w)*(ICON_PIXEL_W/2)), y + ((index / w)*(ICON_PIXEL_H/2)), @@ -3196,6 +3196,7 @@ void TemplateTypeClass::Display(int x, int y, WindowNumberType window, HousesTyp HidPage.Blit((*LogicPage), 0, 0, x + ((index % w)*(ICON_PIXEL_W)), y + ((index / w)*(ICON_PIXEL_H)), ICON_PIXEL_W, ICON_PIXEL_H); } + Buffer_Enable_HD_Texture(false); } } } diff --git a/code/REDALERT/CELL.CPP b/code/REDALERT/CELL.CPP index a8e0ed6..6d776c7 100644 --- a/code/REDALERT/CELL.CPP +++ b/code/REDALERT/CELL.CPP @@ -84,6 +84,11 @@ */ #include "SidebarGlyphx.h" +std::vector renderedFrameObjects; + +bool HasRenderedObject(const ObjectClass* technoClass) { + return std::find(renderedFrameObjects.begin(), renderedFrameObjects.end(), technoClass) != renderedFrameObjects.end(); +} /*********************************************************************************************** * CellClass::CellClass -- Constructor for cell objects. * @@ -993,8 +998,6 @@ bool CellClass::Get_Template_Info(char *template_name, int &icon, void *&image_d return false; } - - /*********************************************************************************************** * CellClass::Draw_It -- Draws the cell imagery at the location specified. * * * @@ -1088,7 +1091,7 @@ void CellClass::Draw_It(int x, int y, bool objects) const ** This is the underlying terrain icon. */ if (ttype->Get_Image_Data()) { - LogicPage->Draw_Stamp(ttype->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL); + LogicPage->Draw_Stamp(ttype, icon, x, y, NULL, WINDOW_TACTICAL); if (remap) { LogicPage->Remap(x+Map.TacPixelX, y+Map.TacPixelY, ICON_PIXEL_W, ICON_PIXEL_H, remap); } @@ -1210,7 +1213,9 @@ void CellClass::Draw_It(int x, int y, bool objects) const icon = (Cell_X(cell) - Cell_X(Map.ZoneCell + Map.ZoneOffset)) + (Cell_Y(cell) - Cell_Y(Map.ZoneCell + Map.ZoneOffset)) * tptr->Width; - LogicPage->Draw_Stamp(tptr->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall - pass in raw tptr + LogicPage->Draw_Stamp(tptr, icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall end } break; @@ -1334,6 +1339,10 @@ void CellClass::Draw_It(int x, int y, bool objects) const */ for (int index = 0; index < count; index++) { object = optr[index]; + if (HasRenderedObject(object)) { + continue; + } + renderedFrameObjects.push_back(object); int xx,yy; if (object->IsToDisplay && (!object->Is_Techno() || ((TechnoClass *)object)->Visual_Character() == VISUAL_NORMAL) && Map.Coord_To_Pixel(object->Render_Coord(), xx, yy)) { if (_Calc_Partial_Window(x, y, xx, yy)) { diff --git a/code/REDALERT/CONQUER.CPP b/code/REDALERT/CONQUER.CPP index 5c81f6d..2455d61 100644 --- a/code/REDALERT/CONQUER.CPP +++ b/code/REDALERT/CONQUER.CPP @@ -105,6 +105,7 @@ TcpipManagerClass Winsock; #include "vortex.h" #include "VQAMOVIE.H" #include "AUDIOMIX.H" +#include "image.h" #ifdef WOLAPI_INTEGRATION //#include "WolDebug.h" @@ -142,6 +143,9 @@ extern void Do_Draw(void); bool bNoMovies = false; #endif +KeyNumType g_globalKeyNumType = KN_NONE; +int g_globalKeyFlags = 0; + /**************************************** ** Function prototypes for this module ** *****************************************/ @@ -1634,6 +1638,8 @@ void Color_Cycle(void) *=============================================================================================*/ void Call_Back(void) { + WWSDL_ProcessEvents(g_globalKeyNumType, g_globalKeyFlags); + /* ** Music and speech maintenance */ @@ -2115,8 +2121,8 @@ static void Sync_Delay(void) ** Delay until the frame timer expires. This forces the game loop to be regulated to a ** speed controlled by the game options slider. */ - while (FrameTimer) { - Color_Cycle(); + while (FrameTimer) { + Color_Cycle(); Call_Back(); if (SpecialDialog == SDLG_NONE) { @@ -2130,10 +2136,12 @@ static void Sync_Delay(void) Keyboard_Process(input); } Map.Render(); - } + } + } + if (!FrameTimer) { + Color_Cycle(); + Call_Back(); } - Color_Cycle(); - Call_Back(); } @@ -2315,8 +2323,7 @@ Mono_Set_Cursor(0,0); ** Keep track of elapsed time in the game. */ Score.ElapsedTime += TIMER_SECOND / TICKS_PER_SECOND; - - Call_Back(); + //Call_Back(); /* ** Check for player wins or loses according to global event flag. @@ -2541,7 +2548,7 @@ void Go_Editor(bool flag) if (flag) { AudMix_SetMusicState(false); // jmarshall: disable music if we are in editor mode Hide_Mouse(); - ShowCursor(TRUE); + //ShowCursor(TRUE); Debug_Map = true; Debug_Unshroud = true; @@ -2574,7 +2581,7 @@ void Go_Editor(bool flag) } else { AudMix_SetMusicState(true); // jmarshall: enable music if we are going back into editor mode. Show_Mouse(); - ShowCursor(FALSE); + //ShowCursor(FALSE); /* ** Go into normal game mode @@ -3469,6 +3476,137 @@ void CC_Draw_Pip(const ObjectClass *object, void const * shapefile, int shapenum CC_Draw_Shape(shapefile, shapenum, x, y, window, flags, fadingdata, ghostdata, rotation); } +// jmarshall - this is for hd textures +void CC_Draw_Shape(Image_t* image, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const* fadingdata, void const* ghostdata, DirType rotation) { + int predoffset; + + /* + ** Special kludge for E3 to prevent crashes + */ + if ((flags & SHAPE_GHOST) && (!ghostdata)) { + ghostdata = DisplayClass::SpecialGhost; + } + //if ((flags & SHAPE_FADING) && (!fadingdata)) { + // fadingdata = DisplayClass::FadingShade; + //} + + static unsigned char* _xbuffer = 0; + + if (!_xbuffer) { + _xbuffer = new unsigned char[SHAPE_BUFFER_SIZE]; + } + + if (image != NULL && shapenum != -1) { + + int width = image->renderwidth; + int height = image->renderheight; + +#ifdef NEVER + /* + ** Perform a quick clip check against the destination rectangle. + */ + if (flags & SHAPE_CENTER) { + if (x - width / 2 >= WindowList[window][WINDOWWIDTH]) return; + if (y - width / 2 >= WindowList[window][WINDOWHEIGHT]) return; + if (x + width / 2 < 0) return; + if (y + height / 2 < 0) return; + + } + else { + if (x >= WindowList[window][WINDOWWIDTH]) return; + if (y >= WindowList[window][WINDOWHEIGHT]) return; + if (x + width < 0) return; + if (y + height < 0) return; + } +#endif + + + + { + //GraphicViewPortClass draw_window(LogicPage->Get_Graphic_Buffer(), + // WindowList[window][WINDOWX] + LogicPage->Get_XPos(), + // WindowList[window][WINDOWY] + LogicPage->Get_YPos(), + // WindowList[window][WINDOWWIDTH], + // WindowList[window][WINDOWHEIGHT]); + + UseOldShapeDraw = false; + /* + ** Rotation handler. + */ +// jmarshall: todo HD rotation code! +// if (rotation != DIR_N) { +// +// /* +// ** Get the raw shape data without the new header and flag to use the old shape drawing +// */ +// UseOldShapeDraw = true; +// +// if (Debug_Rotate) { +//#if (0)//PG +// GraphicBufferClass src(width, height, buffer); +// width *= 2; +// height *= 2; +// memset(_xbuffer, '\0', SHAPE_BUFFER_SIZE); +// GraphicBufferClass dst(width, height, _xbuffer); +// Rotate_Bitmap(&src, &dst, rotation); +// buffer = _xbuffer; +//#endif +// } +// else { +// +// BitmapClass bm(width, height, buffer); +// width *= 2; +// height *= 2; +// memset(_xbuffer, '\0', SHAPE_BUFFER_SIZE); +// GraphicBufferClass gb(width, height, _xbuffer); +// TPoint2D pt(width / 2, height / 2); +// +// gb.Scale_Rotate(bm, pt, 0x0100, (256 - (rotation - 64))); +// buffer = _xbuffer; +// } +// } +// jmarshall end + /* + ** Special shadow drawing code (used for aircraft and bullets). + */ + if ((flags & (SHAPE_FADING | SHAPE_PREDATOR)) == (SHAPE_FADING | SHAPE_PREDATOR)) { + flags = flags & ~(SHAPE_FADING | SHAPE_PREDATOR); + flags = flags | SHAPE_GHOST; + ghostdata = DisplayClass::SpecialGhost; + } + + predoffset = Frame; + + //if (x > ( WindowList[window][WINDOWWIDTH] << 2)) { + // predoffset = -predoffset; + //} + + Buffer_Enable_HD_Texture(true); + //if (draw_window.Lock()) { + if ((flags & (SHAPE_GHOST | SHAPE_FADING)) == (SHAPE_GHOST | SHAPE_FADING)) { + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); + } + else { + if (flags & SHAPE_FADING) { + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, fadingdata, 1, predoffset); + } + else { + if (flags & SHAPE_PREDATOR) { + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, predoffset); + } + else { + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, ghostdata, predoffset); + } + } + } + // draw_window.Unlock(); + //} + Buffer_Enable_HD_Texture(false); + } + } +} +// jmarshall end + /*********************************************************************************************** * CC_Draw_Shape -- Custom draw shape handler. * @@ -3558,13 +3696,16 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum /* ** In WIn95, build shape returns a pointer to the shape not its size */ + + Image_t* shape_image = NULL; shape_pointer = Build_Frame(shapefile, shapenum, _ShapeBuffer); + if (shape_pointer) { - GraphicViewPortClass draw_window(LogicPage->Get_Graphic_Buffer(), - WindowList[window][WINDOWX] + LogicPage->Get_XPos(), - WindowList[window][WINDOWY] + LogicPage->Get_YPos(), - WindowList[window][WINDOWWIDTH], - WindowList[window][WINDOWHEIGHT]); + //GraphicViewPortClass draw_window(LogicPage->Get_Graphic_Buffer(), + // WindowList[window][WINDOWX] + LogicPage->Get_XPos(), + // WindowList[window][WINDOWY] + LogicPage->Get_YPos(), + // WindowList[window][WINDOWWIDTH], + // WindowList[window][WINDOWHEIGHT]); unsigned char * buffer = (unsigned char *) shape_pointer; //Get_Shape_Header_Data((void*)shape_pointer); #else //WIN32 @@ -3615,6 +3756,18 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum } } + { + char tmp[512]; + sprintf(tmp, "s_%d_%d_%d_%d_%d", shapefile, shapenum, rotation, fadingdata, flags); + + if (flags & SHAPE_FADING) { + shape_image = Image_CreateImageFrom8Bit(tmp, width, height, (unsigned char*)buffer, (unsigned char*)fadingdata); + } + else { + shape_image = Image_CreateImageFrom8Bit(tmp, width, height, (unsigned char*)buffer, NULL); + } + } + /* ** Special shadow drawing code (used for aircraft and bullets). */ @@ -3626,25 +3779,24 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum predoffset = Frame; - if (x > ( WindowList[window][WINDOWWIDTH] << 2)) { - predoffset = -predoffset; - } + //if (x > ( WindowList[window][WINDOWWIDTH] << 2)) { + // predoffset = -predoffset; + //} - if (draw_window.Lock()) { + { if ((flags & (SHAPE_GHOST|SHAPE_FADING)) == (SHAPE_GHOST|SHAPE_FADING)) { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); } else { if (flags & SHAPE_FADING) { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, fadingdata, 1, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, fadingdata, 1, predoffset); } else { if (flags & SHAPE_PREDATOR) { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, predoffset); } else { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, ghostdata, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, ghostdata, predoffset); } } } - draw_window.Unlock(); } } } diff --git a/code/REDALERT/DEFINES.H b/code/REDALERT/DEFINES.H index d70a67e..cb64fe5 100644 --- a/code/REDALERT/DEFINES.H +++ b/code/REDALERT/DEFINES.H @@ -1472,6 +1472,9 @@ typedef enum StructType : char { STRUCT_LARVA2, #endif +#ifdef RA_AF + STRUCT_AFV01, +#endif STRUCT_COUNT, STRUCT_FIRST=0 } StructType; diff --git a/code/REDALERT/DIALOG.CPP b/code/REDALERT/DIALOG.CPP index 5dd28e1..001ab27 100644 --- a/code/REDALERT/DIALOG.CPP +++ b/code/REDALERT/DIALOG.CPP @@ -99,7 +99,7 @@ void Dialog_Box(int x, int y, int w, int h) int cx = w/2; int cy = h/2; // jmarshall - void const * shapedata = MFCD::Retrieve("DD-BKGND.SHP"); + //void const * shapedata = MFCD::Retrieve("DD-BKGND.SHP"); //#ifdef WIN32 // CC_Draw_Shape(shapedata, 0, cx-312, cy-192, WINDOW_PARTIAL, SHAPE_WIN_REL); // CC_Draw_Shape(shapedata, 1, cx, cy-192, WINDOW_PARTIAL, SHAPE_WIN_REL); @@ -197,17 +197,17 @@ void Dialog_Box(int x, int y, int w, int h) //CC_Draw_Shape(shapedata, 2, 0, h-(12*RESFACTOR), WINDOW_PARTIAL, SHAPE_WIN_REL); //CC_Draw_Shape(shapedata, 3, w-(12*RESFACTOR-1), h-(12*RESFACTOR), WINDOW_PARTIAL, SHAPE_WIN_REL); -#ifdef WIN32 - WWMouse->Draw_Mouse(&HidPage); - HidPage.Blit(SeenBuff, x, y, x, y, w, h, false); - WWMouse->Erase_Mouse(&HidPage, FALSE); -#else -// Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, Map.ShadowPage->Get_Buffer()); - Hide_Mouse(); - HidPage.Blit(SeenBuff); - Show_Mouse(); -// Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, ((GraphicBufferClass*)Map.Shadow_Address())->Get_Buffer()); -#endif +//#ifdef WIN32 +// WWMouse->Draw_Mouse(&HidPage); +// HidPage.Blit(SeenBuff, x, y, x, y, w, h, false); +// WWMouse->Erase_Mouse(&HidPage, FALSE); +//#else +//// Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, Map.ShadowPage->Get_Buffer()); +// Hide_Mouse(); +// HidPage.Blit(SeenBuff); +// Show_Mouse(); +//// Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, ((GraphicBufferClass*)Map.Shadow_Address())->Get_Buffer()); +//#endif Set_Logic_Page(oldpage); GL_ResetClipRect(); diff --git a/code/REDALERT/DISPLAY.H b/code/REDALERT/DISPLAY.H index e2fae5b..73c37b0 100644 --- a/code/REDALERT/DISPLAY.H +++ b/code/REDALERT/DISPLAY.H @@ -189,8 +189,9 @@ class DisplayClass: public MapClass void Repair_Mode_Control(int control); virtual void Flag_Cell(CELL cell); - bool Is_Cell_Flagged(CELL cell) const {return CellRedraw.Is_True(cell);}; - +// jmarshall + bool Is_Cell_Flagged(CELL cell) const { return true; } +// jmarshall end /* ** Computes starting position based on player's units' Coords. */ diff --git a/code/REDALERT/DLLInterface.cpp b/code/REDALERT/DLLInterface.cpp index 1d71c02..48daa36 100644 --- a/code/REDALERT/DLLInterface.cpp +++ b/code/REDALERT/DLLInterface.cpp @@ -1474,33 +1474,35 @@ bool Debug_Write_Shape(const char *file_name, void const * shapefile, int shapen /* ** Build frame returns a pointer now instead of the shapes length */ - char *shape_pointer = (char*) Build_Frame(shapefile , shapenum , _ShapeBuffer); - if (shape_pointer == NULL) { - return false;; - } - if (Get_Last_Frame_Length() > _ShapeBufferSize) { - return false;; - } - - int width = Get_Build_Frame_Width(shapefile); - int height = Get_Build_Frame_Height(shapefile); - - GraphicBufferClass temp_gbuffer(width, height); - GraphicViewPortClass temp_viewport(&temp_gbuffer, 0, 0, width, height); - - WindowList[WINDOW_CUSTOM][WINDOWX] = 0; - WindowList[WINDOW_CUSTOM][WINDOWY] = 0; - WindowList[WINDOW_CUSTOM][WINDOWWIDTH] = width; - WindowList[WINDOW_CUSTOM][WINDOWHEIGHT] = height; - - static const char _shape_trans = 0x40; - - if (flags == 0) { - Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, SHAPE_NORMAL|SHAPE_WIN_REL|_shape_trans); //, ghostdata, predoffset); - } else { - Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, flags, ghostdata); - } - Write_PCX_File((char*)file_name, temp_viewport, (unsigned char*)GamePalette.Get_Data()); +// jmarshall - do we need this? + //char *shape_pointer = (char*) Build_Frame(shapefile , shapenum , _ShapeBuffer); + //if (shape_pointer == NULL) { + // return false;; + //} + //if (Get_Last_Frame_Length() > _ShapeBufferSize) { + // return false;; + //} + // + //int width = Get_Build_Frame_Width(shapefile); + //int height = Get_Build_Frame_Height(shapefile); + // + //GraphicBufferClass temp_gbuffer(width, height); + //GraphicViewPortClass temp_viewport(&temp_gbuffer, 0, 0, width, height); + // + //WindowList[WINDOW_CUSTOM][WINDOWX] = 0; + //WindowList[WINDOW_CUSTOM][WINDOWY] = 0; + //WindowList[WINDOW_CUSTOM][WINDOWWIDTH] = width; + //WindowList[WINDOW_CUSTOM][WINDOWHEIGHT] = height; + // + //static const char _shape_trans = 0x40; + // + //if (flags == 0) { + // Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, SHAPE_NORMAL|SHAPE_WIN_REL|_shape_trans); //, ghostdata, predoffset); + //} else { + // Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, flags, ghostdata); + //} + //Write_PCX_File((char*)file_name, temp_viewport, (unsigned char*)GamePalette.Get_Data()); +// jmarshall end return true; } diff --git a/code/REDALERT/FUNCTION.H b/code/REDALERT/FUNCTION.H index c16c350..6c4decc 100644 --- a/code/REDALERT/FUNCTION.H +++ b/code/REDALERT/FUNCTION.H @@ -549,6 +549,7 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum // Added for draw intercept. ST - 1/17/2019 12:31PM void CC_Draw_Shape(const ObjectClass *object, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata = 0, void const * ghostdata = 0, DirType rotation = DIR_N, long virtualscale = 0x0100); +void CC_Draw_Shape(Image_t *image, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const* fadingdata, void const* ghostdata, DirType rotation); void CC_Draw_Shape(const ObjectClass *object, const char *shape_file_name, void const * shapefile, int shapenum, int x, int y, WindowNumberType window, ShapeFlags_Type flags, void const * fadingdata = 0, void const * ghostdata = 0, DirType rotation = DIR_N, long virtualscale = 0x0100, char override_owner = HOUSE_NONE); // Added for pip draw intercept - SKY @@ -704,12 +705,12 @@ void *Build_Translucent_Table(PaletteClass const & palette, TLucentType const *c void *Conquer_Build_Translucent_Table(PaletteClass const & palette, TLucentType const *control, int count, void *buffer); void * Make_Fading_Table(PaletteClass const & palette, void * dest, int color, int frac); +void Buffer_Enable_HD_Texture(bool hdTextureEnabled); + /* ** KEYFBUFF.ASM */ -extern "C" { - long __cdecl Buffer_Frame_To_Page(int x, int y, int w, int h, void *Buffer, GraphicViewPortClass &view, int flags, ...); -} +long __cdecl Buffer_Frame_To_Page(int x, int y, int w, int h, Image_t* image, unsigned int Window, int flags, ...); /* ** KEYFRAME.CPP @@ -1180,5 +1181,6 @@ __forceinline void COM_SetExtension(char* path, int maxSize, const char* extensi } extern bool g_inMainMenu; - +extern KeyNumType g_globalKeyNumType; +extern int g_globalKeyFlags; #endif \ No newline at end of file diff --git a/code/REDALERT/GADGET.CPP b/code/REDALERT/GADGET.CPP index ca5a3f6..3b8d5aa 100644 --- a/code/REDALERT/GADGET.CPP +++ b/code/REDALERT/GADGET.CPP @@ -533,10 +533,7 @@ KeyNumType GadgetClass::Input(void) ** rather the the mouse position at the time we get around to this function. */ // jmarshall - int flags = 0; - WWSDL_ProcessEvents(key, flags); - - Show_Mouse(); // jmarshall: thsi shouldn't be here! + int flags = g_globalKeyFlags; // jmarshall end /* diff --git a/code/REDALERT/GSCREEN.CPP b/code/REDALERT/GSCREEN.CPP index ee8cd9b..e315b54 100644 --- a/code/REDALERT/GSCREEN.CPP +++ b/code/REDALERT/GSCREEN.CPP @@ -397,7 +397,7 @@ void GScreenClass::Render(void) //if (Buttons && Buttons->Is_List_To_Redraw()) { // IsToRedraw = true; //} - + IsToRedraw = true; if (IsToUpdate || IsToRedraw) { BStart(BENCH_GSCREEN_RENDER); @@ -468,14 +468,20 @@ extern "C" { } void GScreenClass::Blit_Display(void) -{ - BStart(BENCH_BLIT_DISPLAY); - - WWMouse->Draw_Mouse(&HidPage); - HidPage.Blit(SeenBuff , 0 , 0 , 0 , 0 , HidPage.Get_Width() , HidPage.Get_Height() , (BOOL) FALSE ); - WWMouse->Erase_Mouse(&HidPage, FALSE); - - BEnd(BENCH_BLIT_DISPLAY); +{ + BEnd(BENCH_BLIT_DISPLAY); +#ifdef WIN32 + if (SeenBuff.Get_Width()!=320) { + WWMouse->Draw_Mouse(&HidPage); + //HidPage.Blit(SeenBuff , 0 , 0 , 0 , 0 , HidPage.Get_Width() , HidPage.Get_Height() , (BOOL) FALSE ); + memcpy(SeenBuff.Get_Graphic_Buffer()->GetMemoryBuffer(), HidPage.Get_Graphic_Buffer()->GetMemoryBuffer(), HidPage.Get_Width() * HidPage.Get_Height() * 4); + WWMouse->Erase_Mouse(&HidPage, FALSE); + } else { + //PG ModeX_Blit(&HiddenPage); + } + #else + Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, ShadowPage->Get_Buffer()); + #endif } diff --git a/code/REDALERT/HOUSECOLOR.H b/code/REDALERT/HOUSECOLOR.H new file mode 100644 index 0000000..13cedd6 --- /dev/null +++ b/code/REDALERT/HOUSECOLOR.H @@ -0,0 +1,58 @@ +// HOUSECOLOR.H +// + +#include "vectormath.h" + +struct HouseColorHD { + HouseColorHD(float3 lowerbounds, + float3 upperbounds, + float fudge, + float3 hsvshift, + float3 inputlevels, + float2 outputlevels, + float3 overallinputlevels, + float2 overalloutputlevels, + float3 radarmapcolor) + { + this->LowerBounds = lowerbounds; + this->UpperBounds = upperbounds; + this->Fudge = fudge; + this->HSVShift = hsvshift; + this->InputLevels = inputlevels; + this->OutputLevels = outputlevels; + this->OverallInputLevels = overallinputlevels; + this->OverallOutputLevels = overalloutputlevels; + this->RadarMapColor = radarmapcolor; + } + + float3 LowerBounds; + float3 UpperBounds; + float Fudge; + float3 HSVShift; + float3 InputLevels; + float2 OutputLevels; + float3 OverallInputLevels; + float2 OverallOutputLevels; + float3 RadarMapColor; +}; + +// This data has been sourced from the TD Original Skirmish Color mod by Pokey +// +static HouseColorHD *houseColors[8] = { + // Spain + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.713,-0.621, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.6421568, 0.4784698, 0.4784698)), + // Greece + new HouseColorHD(float3(0.264706f, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.310000f,-0.211000, 0.005000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0980f, 0.3922, 0.9216)), + // USSR + new HouseColorHD(float3(0.264706f, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.689000f,0.382000, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.756863f, 0.0, 0.015686)), + // England + new HouseColorHD(float3(0.26f, 1.0f, 1.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.777f,-0.196, -0.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.737255, 0.627451, 0.239216)), + // Ukraine + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.726,0.119, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.772549, 0.380392, 0.07451)), + // Germany + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.911f,-0.381, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.184314, 0.67451, 0.141176)), + // France + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.119,-0.233, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.1151961, 0.6911765, 0.4031861)), + // Turkey + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.685,-0.151, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.5784314, 0.1155861, 0.05387352)), +}; \ No newline at end of file diff --git a/code/REDALERT/IMGUTIL.H b/code/REDALERT/IMGUTIL.H new file mode 100644 index 0000000..98f35ea --- /dev/null +++ b/code/REDALERT/IMGUTIL.H @@ -0,0 +1,206 @@ +// IMGUTIL.H +// + +#ifdef _DEBUG +#pragma optimize( "", on ) +#endif + +// SRGB -> Linear color space conversion. +inline float ByteToLinear(byte p) { + float v; + v = ((float)p) / 255.0f; + v = (double)v >= 0.0404499992728233 ? (float)pow((200.0 * (double)v + 11.0) / 211.0, 2.40000009536743) : (float)((double)v * 25.0 / 323.0); + return v; +} + +inline float ToSRGB(float v) +{ + return (double)v >= 0.0031308 ? (float)((pow((double)v, 0.416666656732559) * 211.0 - 11.0) / 200.0) : (float)((double)v * 323.0 / 25.0); +} + +inline float PixelToHue(float R, float G, float B) { + if (R == G && G == B) + return 0; // 0 makes as good an UNDEFINED value as any + + float r = (float)R / 255.0f; + float g = (float)G / 255.0f; + float b = (float)B / 255.0f; + + float max, min; + float delta; + float hue = 0.0f; + + max = r; min = r; + + if (g > max) max = g; + if (b > max) max = b; + + if (g < min) min = g; + if (b < min) min = b; + + delta = max - min; + + if (r == max) { + hue = (g - b) / delta; + } + else if (g == max) { + hue = 2 + (b - r) / delta; + } + else if (b == max) { + hue = 4 + (r - g) / delta; + } + hue *= 60; + + if (hue < 0.0f) { + hue += 360.0f; + } + return hue; +} + +struct Turple { + Turple() { + memset(this, 0, sizeof(Turple)); + } + Turple(float Item1, float Item2, float Item3) { + this->Item1 = Item1; + this->Item2 = Item2; + this->Item3 = Item3; + this->Item4 = -1; + } + Turple(float Item1, float Item2, float Item3, float Item4) { + this->Item1 = Item1; + this->Item2 = Item2; + this->Item3 = Item3; + this->Item4 = Item4; + } + float Item1; + float Item2; + float Item3; + float Item4; +}; + + +float step(float a, float x) +{ + return x >= a; +} + +inline float4 lerp(float4 a, float4 b, float w) +{ + float4 l; + l.x = a.x + w * (b.x - a.x); + l.y = a.y + w * (b.y - a.y); + l.z = a.z + w * (b.z - a.z); + l.w = a.w + w * (b.w - a.w); + return l; +} + +inline float3 lerp(float3 a, float3 b, float w) +{ + float3 l; + l.x = a.x + w * (b.x - a.x); + l.y = a.y + w * (b.y - a.y); + l.z = a.z + w * (b.z - a.z); + return l; +} + +inline float3 frac(float3 v) +{ + float3 f; + f.x = v.x - floor(v.x); + f.y = v.y - floor(v.y); + f.z = v.z - floor(v.z); + return f; +} + +inline float frac(float v) +{ + return v - floor(v); +} + +inline float lerp(float a, float b, float w) +{ + return a + w * (b - a); +} + + +inline float3 clamp(float3 x, float a, float b) +{ + float3 r; + r.x = max(a, min(b, x.x)); + r.y = max(a, min(b, x.y)); + r.z = max(a, min(b, x.z)); + return r; +} + +inline float saturate(float x) +{ + return max(0, min(1, x)); +} + +inline void RenderTeamPalette(byte* pixel, HouseColorHD &teamColor) { + float linear1 = ByteToLinear(pixel[2]); + float linear2 = ByteToLinear(pixel[1]); + float linear3 = ByteToLinear(pixel[0]); + float num1 = linear1; + float num2 = linear2; + float num3 = (float)linear3; + Turple valueTuple1 = Turple(0.0f, -0.3333333, 0.6666667, -1 ); + Turple valueTuple2; + + if ((double)num2 >= (double)num3) + valueTuple2 = Turple( num2, num3, valueTuple1.Item1, valueTuple1.Item2 ); + else + valueTuple2 = Turple( num3, num2, valueTuple1.Item4, valueTuple1.Item3 ); + + Turple valueTuple3; + if ((double)num1 >= (double)valueTuple2.Item1) + valueTuple3 = Turple(num1, valueTuple2.Item2, valueTuple2.Item3, valueTuple2.Item1); + else + valueTuple3 = Turple(valueTuple2.Item1, valueTuple2.Item2, valueTuple2.Item4, num1); + double num4 = (double)valueTuple3.Item1 - (double)min(valueTuple3.Item4, valueTuple3.Item2); + float num5 = 1E-10f; + float num6 = (float)num4; + float num7 = num5; + float num8 = abs(valueTuple3.Item3 + (float)(((double)valueTuple3.Item4 - (double)valueTuple3.Item2) / (6.0 * (double)num6 + (double)num7))); + float num9 = num6 / (valueTuple3.Item1 + num7); + double num10 = (double)valueTuple3.Item1; + float num11 = num8; + float num12 = num9; + float num13 = (float)num10; + float num14 = PixelToHue(teamColor.LowerBounds.x, teamColor.LowerBounds.y, teamColor.LowerBounds.z) / 360; + float num15 = PixelToHue(teamColor.UpperBounds.x, teamColor.UpperBounds.y, teamColor.UpperBounds.z) / 360; + + if ((double)num11 >= (double)num14 && (double)num15 >= (double)num11) + { + float num16 = (float)((double)num11 / ((double)num15 - (double)num14) * ((double)num15 + (double)teamColor.Fudge - ((double)num14 - (double)teamColor.Fudge))) + teamColor.HSVShift.x; + float t = num12 + teamColor.HSVShift.y; + float num17 = num13 + teamColor.HSVShift.z; + Turple valueTuple4 = Turple(1.0f, 0.6666667, 0.3333333, 3); + Turple valueTuple5 = Turple(abs(frac(num16 + valueTuple4.Item1) * 6 - valueTuple4.Item4), abs(frac(num16 + valueTuple4.Item2) * 6 - valueTuple4.Item4), abs(frac(num16 + valueTuple4.Item3) * 6 - valueTuple4.Item4)); + float num18 = num17 * lerp(valueTuple4.Item1, saturate(valueTuple5.Item1 - valueTuple4.Item1), t); + float num19 = num17 * lerp(valueTuple4.Item1, saturate(valueTuple5.Item2 - valueTuple4.Item1), t); + float num20 = num17 * lerp(valueTuple4.Item1, saturate(valueTuple5.Item3 - valueTuple4.Item1), t); + Turple valueTuple6 = Turple(min(1, max(0.0f, num18 - teamColor.InputLevels.x) / (teamColor.InputLevels.z - teamColor.InputLevels.x)), min(1, max(0.0f, num19 - teamColor.InputLevels.x) / (teamColor.InputLevels.z - teamColor.InputLevels.x)), min(1, max(0.0f, num20 - teamColor.InputLevels.x) / (teamColor.InputLevels.z - teamColor.InputLevels.x))); + valueTuple6.Item1 = (float)pow((double)valueTuple6.Item1, (double)teamColor.InputLevels.y); + valueTuple6.Item2 = (float)pow((double)valueTuple6.Item2, (double)teamColor.InputLevels.y); + valueTuple6.Item3 = (float)pow((double)valueTuple6.Item3, (double)teamColor.InputLevels.y); + num1 = lerp(teamColor.OutputLevels.x, teamColor.OutputLevels.y, valueTuple6.Item1); + num2 = lerp(teamColor.OutputLevels.x, teamColor.OutputLevels.y, valueTuple6.Item2); + num3 = lerp(teamColor.OutputLevels.x, teamColor.OutputLevels.y, valueTuple6.Item3); + } + + Turple valueTuple7 = Turple(min(1, max(0.0f, num1 - teamColor.OverallInputLevels.x) / (teamColor.OverallInputLevels.z - teamColor.OverallInputLevels.x)), min(1, max(0.0f, num2 - teamColor.OverallInputLevels.x) / (teamColor.OverallInputLevels.z - teamColor.OverallInputLevels.x)), min(1, max(0.0f, num3 - teamColor.OverallInputLevels.x) / (teamColor.OverallInputLevels.z - teamColor.OverallInputLevels.x))); + valueTuple7.Item1 = (float)pow((double)valueTuple7.Item1, (double)teamColor.OverallInputLevels.y); + valueTuple7.Item2 = (float)pow((double)valueTuple7.Item2, (double)teamColor.OverallInputLevels.y); + valueTuple7.Item3 = (float)pow((double)valueTuple7.Item3, (double)teamColor.OverallInputLevels.y); + float v1 = lerp(teamColor.OverallOutputLevels.x, teamColor.OverallOutputLevels.y, valueTuple7.Item1); + float v2 = lerp(teamColor.OverallOutputLevels.x, teamColor.OverallOutputLevels.y, valueTuple7.Item2); + float v3 = lerp(teamColor.OverallOutputLevels.x, teamColor.OverallOutputLevels.y, valueTuple7.Item3); + pixel[2] = (byte)((double)ToSRGB(v1) * (double)255.0f); + pixel[1] = (byte)((double)ToSRGB(v2) * (double)255.0f); + pixel[0] = (byte)((double)ToSRGB(v3) * (double)255.0f); +} +#ifdef _DEBUG +#pragma optimize( "", off ) +#endif \ No newline at end of file diff --git a/code/REDALERT/INIT.CPP b/code/REDALERT/INIT.CPP index 90d0697..9ec0c7f 100644 --- a/code/REDALERT/INIT.CPP +++ b/code/REDALERT/INIT.CPP @@ -2532,7 +2532,9 @@ static void Init_Color_Remaps(void) GraphicBufferClass temp_page(320, 200, (void*)NULL); temp_page.Clear(); Load_Picture("PALETTE.CPS", temp_page, temp_page, NULL, BM_DEFAULT); - temp_page.Blit(HidPage); +// jmarshall + temp_page.BlitLegacy(HidPage, (BOOL)false); +// jmarshall end #else Load_Picture("PALETTE.CPS", HidPage, HidPage, NULL, BM_DEFAULT); #endif diff --git a/code/REDALERT/Image.h b/code/REDALERT/Image.h index b41b602..51700f2 100644 --- a/code/REDALERT/Image.h +++ b/code/REDALERT/Image.h @@ -1,11 +1,34 @@ // Image.h // +#define MAX_IMAGE_FRAMES 256 +#define MAX_HOUSE_COLORS 8 struct Image_t { + Image_t(); + ~Image_t(); + char name[512]; - unsigned int image; + int64_t namehash; + unsigned int image[MAX_HOUSE_COLORS][MAX_IMAGE_FRAMES]; + unsigned int numAnimFrames; int width; int height; + int renderwidth; + int renderheight; + //unsigned char* buffer[MAX_HOUSE_COLORS][MAX_IMAGE_FRAMES]; }; -Image_t* Image_LoadImage(const char* name); \ No newline at end of file +__forceinline Image_t::Image_t() { +// buffer = NULL; + numAnimFrames = 0; +} + +__forceinline Image_t::~Image_t() { + //if (buffer) { + // delete buffer; + // buffer = NULL; + //} +} + +Image_t* Image_LoadImage(const char* name, bool loadAnims = false, bool loadHouseColor = false); +Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char* data, unsigned char *remap = NULL); \ No newline at end of file diff --git a/code/REDALERT/KEY.CPP b/code/REDALERT/KEY.CPP index eef74e9..1d96f9d 100644 --- a/code/REDALERT/KEY.CPP +++ b/code/REDALERT/KEY.CPP @@ -62,6 +62,8 @@ #define ARRAY_SIZE(x) int(sizeof(x)/sizeof(x[0])) +int WWKeyboardClass::Head = 0; +int WWKeyboardClass::Tail = 0; /*********************************************************************************************** * WWKeyboardClass::WWKeyBoardClass -- Construction for Westwood Keyboard Class * @@ -75,9 +77,7 @@ *=============================================================================================*/ WWKeyboardClass::WWKeyboardClass(void) : MouseQX(0), - MouseQY(0), - Head(0), - Tail(0) + MouseQY(0) { // _Kbd = this; @@ -517,17 +517,7 @@ bool WWKeyboardClass::Is_Buffer_Empty(void) const *=============================================================================================*/ void WWKeyboardClass::Fill_Buffer_From_System(void) { - if (!Is_Buffer_Full()) - { - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { - if (!GetMessage( &msg, NULL, 0, 0 )) { - return; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } + } diff --git a/code/REDALERT/KEY.H b/code/REDALERT/KEY.H index fbaec2c..67f4cef 100644 --- a/code/REDALERT/KEY.H +++ b/code/REDALERT/KEY.H @@ -117,8 +117,8 @@ class WWKeyboardClass ** These are the tracking pointers to maintain the ** circular keyboard list. */ - int Head; - int Tail; + static int Head; + static int Tail; }; #define RA_SCANCODE_MASK (1<<30) diff --git a/code/REDALERT/MAPEDPLC.CPP b/code/REDALERT/MAPEDPLC.CPP index 444a862..4f072a2 100644 --- a/code/REDALERT/MAPEDPLC.CPP +++ b/code/REDALERT/MAPEDPLC.CPP @@ -428,14 +428,17 @@ int MapEditClass::Placement_Dialog(void) /* ** Refresh display if needed */ - if (display) { + //if (display) { /* ** Display the dialog box */ Hide_Mouse(); - Dialog_Box(D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W, D_DIALOG_H); + // Dialog_Box(D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W, D_DIALOG_H); // Draw_Caption(TXT_PLACE_OBJECT, D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W); +// jmarshall - temp render a black background here so the tool works. + LogicPage->Fill_Rect(D_DIALOG_X, D_DIALOG_Y, D_DIALOG_X + D_DIALOG_W, D_DIALOG_Y + D_DIALOG_H, 0); +// jamrshall end /* ** Display the current object: @@ -560,7 +563,7 @@ int MapEditClass::Placement_Dialog(void) Show_Mouse(); display = false; - } + // } display = true; @@ -756,9 +759,6 @@ int MapEditClass::Placement_Dialog(void) // default: // break; //} - KeyNumType _key; - int _type; - WWSDL_ProcessEvents(_key, _type); } /* diff --git a/code/REDALERT/MPLAYER.CPP b/code/REDALERT/MPLAYER.CPP index a8d7e35..9b0b91e 100644 --- a/code/REDALERT/MPLAYER.CPP +++ b/code/REDALERT/MPLAYER.CPP @@ -160,7 +160,7 @@ GameType Select_MPlayer_Game (void) // Initialize //------------------------------------------------------------------------ Set_Logic_Page(SeenBuff); - VisiblePage.Blit(seen_buff_save); + //VisiblePage.Blit(seen_buff_save); //------------------------------------------------------------------------ // Fill array of button ptrs @@ -694,7 +694,7 @@ int Surrender_Dialog(int text) //..................................................................... // Refresh display if needed //..................................................................... - if (display) { + { display = false; //.................................................................. @@ -730,6 +730,9 @@ int Surrender_Dialog(int text) // Get user input //..................................................................... KeyNumType input = commands->Input(); +// jmarshall + Call_Back(); +// jmarshall end //..................................................................... // Process input diff --git a/code/REDALERT/MSGBOX.CPP b/code/REDALERT/MSGBOX.CPP index e686bec..7418406 100644 --- a/code/REDALERT/MSGBOX.CPP +++ b/code/REDALERT/MSGBOX.CPP @@ -166,7 +166,9 @@ int WWMessageBox::Process(const char * msg, const char * b1txt, const char * b2t */ Set_Logic_Page(SeenBuff); #ifdef WIN32 - VisiblePage.Blit(seen_buff_save); +// jmarshall - not needed + //VisiblePage.Blit(seen_buff_save); +// jmarshall end #endif /* diff --git a/code/REDALERT/MapScript.cpp b/code/REDALERT/MapScript.cpp index 8c56eb5..dc42a44 100644 --- a/code/REDALERT/MapScript.cpp +++ b/code/REDALERT/MapScript.cpp @@ -5,10 +5,12 @@ #include "MapScript.h" /*********************************************************************************************** - * Script_GiveCreditsToPlayer - Gives a given player a given amount of credits * + * Script_GiveCredits - Gives a given player a given amount of credits * * * - * SCRIPT INPUT: houseType (int) - The player (house) index to give credits to * - * cashToGive (int) - The amount of cold hard credits to give the player * + * SCRIPT INPUT: cashToGive (int) - The amount of cold hard credits to give the player * + * * + * houseType (int) - The player (house) index to give credits to * + * or -1 to give to all players * * * * SCRIPT OUTPUT: void * * * @@ -22,16 +24,28 @@ * 6/11/2020 - JM Created * * 6/12/2020 - JJ Added player (house) index input * *=============================================================================================*/ -static int Script_GiveCreditsToPlayer(lua_State* L) { - int houseType = lua_tointeger(L, 1); - int cashToGive = lua_tointeger(L, 2); +static int Script_GiveCredits(lua_State* L) { + + int cashToGive = lua_tointeger(L, 1); + + int houseType = -1; + + // Optional houseType parameter + if (lua_gettop(L) == 2) { + houseType = lua_tointeger(L, 2); + } for (int h_index = 0; h_index < Houses.Count(); h_index++) { HouseClass* house = Houses.Ptr(h_index); - if (house->ID == houseType) { + if (house->ID == houseType || houseType == -1) { house->Refund_Money(cashToGive); + + // Discontinue giving out free cash if a specific house was specified + if (houseType >= 0) { + break; + } } } @@ -42,8 +56,11 @@ static int Script_GiveCreditsToPlayer(lua_State* L) { /*********************************************************************************************** * Script_NumBuildingTypeForPlayer - Returns the amount of specific buildings for a player * * * - * SCRIPT INPUT: houseType (int) - The player (house) index to count buildings for * - * structType (int) - The structure index to count buildings for * + * SCRIPT INPUT: structType (int) - The structure index to count buildings for * + * or -1 for all structures * + * * + * houseType (int) - The player (house) index to count buildings for * + * or -1 to for all players * * * * SCRIPT OUTPUT: result (number) - The amount of matching buildings for that player * * * @@ -54,15 +71,22 @@ static int Script_GiveCreditsToPlayer(lua_State* L) { * WARNINGS: ? * * * *=============================================================================================*/ -static int Script_NumBuildingTypeForPlayer(lua_State* L) { - int houseType = lua_tointeger(L, 1); - int structType = lua_tointeger(L, 2); +static int Script_CountBuildings(lua_State* L) { + int structType = lua_tointeger(L, 1); + + int houseType = -1; + + // Optional houseType parameter + if (lua_gettop(L) == 2) { + houseType = lua_tointeger(L, 2); + } + int result = 0; for (int b_index = 0; b_index < Buildings.Count(); b_index++) { BuildingClass* building = Buildings.Ptr(b_index); - if (building->Owner() == houseType) { - if (building->Class->Type == structType) { + if (building->Owner() == houseType || houseType == -1) { + if (building->Class->Type == structType || structType == -1) { result++; } } @@ -73,6 +97,243 @@ static int Script_NumBuildingTypeForPlayer(lua_State* L) { } +/*********************************************************************************************** + * Script_CountAircraft - Returns the amount of specific aircraft for a player * + * * + * SCRIPT INPUT: aircraftType (int) - The aircraft index to count aircraft for * + * or -1 for all aircraft * + * * + * houseType (int) - The player (house) index to count aircraft for * + * or -1 for all players * + * * + * SCRIPT OUTPUT: result (number) - The amount of matching aircraft for that player * + * * + * INPUT: lua_State - The current Lua state * + * * + * OUTPUT: int; Did the function run successfully? Return 1 * + * * + * WARNINGS: ? * + * * + *=============================================================================================*/ +static int Script_CountAircraft(lua_State* L) { + int aircraftType = lua_tointeger(L, 1); + + int houseType = -1; + + // Optional houseType parameter + if (lua_gettop(L) == 2) { + houseType = lua_tointeger(L, 2); + } + + int result = 0; + for (int a_index = 0; a_index < Aircraft.Count(); a_index++) { + AircraftClass* aircraft = Aircraft.Ptr(a_index); + + if (aircraft->Owner() == houseType || houseType == -1) { + if (aircraft->Class->Type == aircraftType || aircraftType == -1) { + result++; + } + } + } + + lua_pushnumber(L, result); + return 1; +} + +/*********************************************************************************************** + * Script_CountUnits - Returns the amount of specific units for a player * + * * + * SCRIPT INPUT: unitType (int) - The unit index to count units for * + * or -1 for all units * + * * + * houseType (int) - The player (house) index to count units for * + * or -1 for all players * + * * + * NOTE: -1 for either index input acts as ALL * + * * + * SCRIPT OUTPUT: result (number) - The amount of matching units for that player * + * * + * INPUT: lua_State - The current Lua state * + * * + * OUTPUT: int; Did the function run successfully? Return 1 * + * * + * WARNINGS: ? * + * * + *=============================================================================================*/ +static int Script_CountUnits(lua_State* L) { + int unitType = lua_tointeger(L, 1); + + int houseType = -1; + + // Optional houseType parameter + if (lua_gettop(L) == 2) { + houseType = lua_tointeger(L, 2); + } + + int result = 0; + for (int u_index = 0; u_index < Units.Count(); u_index++) { + UnitClass* unit = Units.Ptr(u_index); + + if (unit->Owner() == houseType || houseType == -1) { + if (unit->Class->Type == unitType || unitType == -1) { + result++; + } + } + } + + lua_pushnumber(L, result); + return 1; +} + + +/*********************************************************************************************** + * Script_CountInfantry - Returns the amount of specific infantry for a player * + * * + * SCRIPT INPUT: infantryType (int) - The infantry index to count infantry for * + * or -1 for all infantry * + * * + * houseType (int) - The player (house) index to count infantry for * + * or -1 for all players * + * * + * NOTE: -1 for either index input acts as ALL * + * * + * SCRIPT OUTPUT: result (number) - The amount of matching infantry for that player * + * * + * INPUT: lua_State - The current Lua state * + * * + * OUTPUT: int; Did the function run successfully? Return 1 * + * * + * WARNINGS: ? * + * * + *=============================================================================================*/ +static int Script_CountInfantry(lua_State* L) { + int infantryType = lua_tointeger(L, 1); + + int houseType = -1; + + // Optional houseType parameter + if (lua_gettop(L) == 2) { + houseType = lua_tointeger(L, 2); + } + + int result = 0; + for (int u_index = 0; u_index < Infantry.Count(); u_index++) { + InfantryClass* infantry = Infantry.Ptr(u_index); + + if (infantry->Owner() == houseType || houseType == -1) { + if (infantry->Class->Type == infantryType || infantryType == -1) { + result++; + } + } + } + + lua_pushnumber(L, result); + return 1; +} + + +/*********************************************************************************************** + * Script_CountVessels - Returns the amount of specific vessels for a player * + * * + * SCRIPT INPUT: vesselType (int) - The vessel index to count vessels for * + * or -1 for all vessels * + * * + * houseType (int) - The player (house) index to count vessels for * + * or -1 for all players * + * * + * NOTE: -1 for either index input acts as ALL * + * * + * SCRIPT OUTPUT: result (number) - The amount of matching vessels for that player * + * * + * INPUT: lua_State - The current Lua state * + * * + * OUTPUT: int; Did the function run successfully? Return 1 * + * * + * WARNINGS: ? * + * * + *=============================================================================================*/ +static int Script_CountVessels(lua_State* L) { + int vesselType = lua_tointeger(L, 1); + + int houseType = -1; + + // Optional houseType parameter + if (lua_gettop(L) == 2) { + houseType = lua_tointeger(L, 2); + } + + int result = 0; + for (int u_index = 0; u_index < Vessels.Count(); u_index++) { + VesselClass* vessel = Vessels.Ptr(u_index); + + if (vessel->Owner() == houseType || houseType == -1) { + if (vessel->Class->Type == vesselType || vesselType == -1) { + result++; + } + } + } + + lua_pushnumber(L, result); + return 1; +} + + +/*********************************************************************************************** + * Script_SetTriggerCallback - Adds a lua callback to an existing trigger * + * * + * SCRIPT INPUT: triggerName (string) - The ININame of the trigger via its class * + * * + * callbackName (string) - The function name to be called when the * + * actions have been met * + * * + * actionIndex (int) (opt.) - 0: always callback on any of the given paths * + * of the trigger * + * 1: only callback on first action * + * 2: only callback on second action * + * * + * SCRIPT OUTPUT: result (number) - The amount of matching buildings for that player * + * * + * INPUT: lua_State - The current Lua state * + * * + * OUTPUT: int; Did the function run successfully? Return 1 * + * * + * WARNINGS: ? * + * * + *=============================================================================================*/ +static int Script_SetTriggerCallback(lua_State* L) { + + const char* triggerName = lua_tostring(L, 1); + const char* callbackName = lua_tostring(L, 2); + char actionIndex = 0; + + // Optional actionIndex parameter + if (lua_gettop(L) == 3) { + actionIndex = lua_tointeger(L, 2); + } + + // Find the trigger and set up callback + for (int t_index = 0; t_index < Triggers.Count(); t_index++) { + TriggerClass* trigger = Triggers.Ptr(t_index); + + if (trigger != NULL) { + + if (strcmp(trigger->Name(), triggerName) == 0) { + + strncpy(trigger->MapScriptCallback,callbackName,sizeof(trigger->MapScriptCallback ) - 1); + trigger->MapScriptActionIndex = actionIndex; + + break; + } + + } + + } + + return 1; +} + + + /*********************************************************************************************** * Script_Win - The specified player wins * * * @@ -88,7 +349,7 @@ static int Script_NumBuildingTypeForPlayer(lua_State* L) { * * *=============================================================================================*/ static int Script_Win(lua_State* L) { - + int houseType = lua_tointeger(L, -1); if (houseType != HOUSE_NONE) { @@ -779,11 +1040,47 @@ static int Script_SetBriefingText(lua_State* L) { * * *=============================================================================================*/ void MapScript::CallFunction(const char* functionName) { + lua_getglobal(L, functionName); lua_pcall(L, 0, 0, 0); + } //BriefingText +/*********************************************************************************************** + * MapScript::setLuaPath - Sets Lua's path / extensions to search for scripts * + * * + * This helps Lua know where/how to look for files when using require(), otherwise we could * + * hard code path/extension as we did previously * + * * + * INPUT: pathvalue - See lua documentation RE: LUA_PATH to know how to deal with this * + * * + * OUTPUT: void * + * * + * WARNINGS: ? * + * * + *=============================================================================================*/ +void MapScript::SetLuaPath( const char* input_path) +{ + + // Needs space to keep the initial paths + char new_path[1024]; + + // Set new GLOBALS.package.path + lua_getglobal(L, "package"); + lua_getfield(L, -1, "path"); // get field "path" from table at top of stack (-1) + const char* cur_path = lua_tostring(L, -1); // grab path string from top of stack + + sprintf(new_path, "%s;%s", cur_path, input_path); + + lua_pop(L, 1); + lua_pushstring(L, new_path); + lua_setfield(L, -2, "path"); + lua_pop(L, 1); +} + + + /*********************************************************************************************** * MapScript::Init -- Loads and initializes script for a given map * * * @@ -798,10 +1095,28 @@ void MapScript::CallFunction(const char* functionName) { *=============================================================================================*/ bool MapScript::Init(const char* mapName) { char scriptName[256]; + + // Build map path sprintf(scriptName, "scripts/%s.script", mapName); L = luaL_newstate(); - if (luaL_loadfile(L, scriptName) || lua_pcall(L, 0, 0, 0)) { + luaL_openlibs(L); + + // Load file + if (luaL_loadfile(L, scriptName)){ + L = NULL; + return false; + } + + // TODO: I've tried several combinations of paths (including "scripts/?"), + // but I can only get "require 'basefilename'" to work within a + // script, not "require 'basefilename.script'". This may be completely + // normal within lua, but it seems odd. + + // This allows require() to work + SetLuaPath(";scripts/?.script;"); + + if (lua_pcall(L, 0, 0, 0)) { L = NULL; return false; } @@ -880,15 +1195,22 @@ bool MapScript::Init(const char* mapName) { *=============================================================================================*/ lua_register(L, "SetBriefingText", Script_SetBriefingText); // Sets the [text] on the mission briefing screen - lua_register(L, "GiveCreditsToPlayer", Script_GiveCreditsToPlayer); // Give [player] [credits] - lua_register(L, "NumBuildingTypeForPlayer", Script_NumBuildingTypeForPlayer); // Number of buildings of [type] for given [player] + lua_register(L, "GiveCredits", Script_GiveCredits); // Give [credits] to [player] + + lua_register(L, "CountBuildings", Script_CountBuildings); // Number of buildings of [type] for given [player] + lua_register(L, "CountAircraft", Script_CountAircraft); // Number of units of [type] for given [player] + lua_register(L, "CountUnits", Script_CountUnits); // Number of units of [type] for given [player] + lua_register(L, "CountInfantry", Script_CountInfantry); // Number of infantry of [type] for given [player] + lua_register(L, "CountVessels", Script_CountVessels); // Number of vessels of [type] for given [player] + lua_register(L, "SetTriggerCallback", Script_SetTriggerCallback); // Initiates a given [callback] on an existing [trigger] + /********************************************************************************************** * Script Globals * *=============================================================================================*/ - lua_pushnumber(L, PlayerPtr->ID); // Local (human) player + lua_pushnumber(L, PlayerPtr->ID); // Local player (house) index lua_setglobal(L, "_localPlayer"); diff --git a/code/REDALERT/MapScript.h b/code/REDALERT/MapScript.h index b12da67..b02c72d 100644 --- a/code/REDALERT/MapScript.h +++ b/code/REDALERT/MapScript.h @@ -1,6 +1,9 @@ // MapScript.h // +#ifndef MAPSCRIPT_H +#define MAPSCRIPT_H + // Lua is written in C, so compiler needs to know how to link its libraries extern "C" { # include "lua.h" @@ -15,6 +18,8 @@ class MapScript { public: bool Init(const char* mapName); void CallFunction(const char* functionName); + void SetLuaPath(const char* input_path); private: lua_State* L; }; +#endif \ No newline at end of file diff --git a/code/REDALERT/NEWBLIT.CPP b/code/REDALERT/NEWBLIT.CPP index 0e92de6..693953c 100644 --- a/code/REDALERT/NEWBLIT.CPP +++ b/code/REDALERT/NEWBLIT.CPP @@ -18,10 +18,10 @@ void GL_ResetClipRect(void) { ImGui::GetForegroundDrawList()->PopClipRect(); } -void GL_RenderImage(Image_t* image, int x, int y, int width, int height) { +void GL_RenderImage(Image_t* image, int x, int y, int width, int height, int colorRemap) { ImVec2 mi(x, y); ImVec2 ma(x + width, y + height); - ImGui::GetForegroundDrawList()->AddImage((ImTextureID)image->image, mi, ma); + ImGui::GetForegroundDrawList()->AddImage((ImTextureID)image->image[colorRemap][0], mi, ma); } void GL_FillRect(int color, int x, int y, int width, int height) { diff --git a/code/REDALERT/NEWBLIT.H b/code/REDALERT/NEWBLIT.H index 84eba03..b3e9508 100644 --- a/code/REDALERT/NEWBLIT.H +++ b/code/REDALERT/NEWBLIT.H @@ -2,7 +2,7 @@ // struct Image_t; -void GL_RenderImage(Image_t* image, int x, int y, int width, int height); +void GL_RenderImage(Image_t* image, int x, int y, int width, int height, int colorRemap = 0); void GL_DrawText(int color, int x, int y, char* text); void GL_FillRect(int color, int x, int y, int width, int height); void GL_DrawLine(int color, int x, int y, int dx, int dy); diff --git a/code/REDALERT/NULLDLG.CPP b/code/REDALERT/NULLDLG.CPP index d956acf..03e77e5 100644 --- a/code/REDALERT/NULLDLG.CPP +++ b/code/REDALERT/NULLDLG.CPP @@ -651,11 +651,6 @@ oh_dear_its_a_label: } } - /* - ........................ Invoke game callback ......................... - */ - Call_Back(); - #ifdef WIN32 /* ** If we have just received input focus again after running in the background then @@ -795,6 +790,11 @@ oh_dear_its_a_label: bool droplist_is_dropped = housebtn.IsDropped; input = commands->Input(); + /* + ........................ Invoke game callback ......................... + */ + Call_Back(); + Load_Title_Page(true); /* diff --git a/code/REDALERT/OBJECT.CPP b/code/REDALERT/OBJECT.CPP index 1322c4a..6b39275 100644 --- a/code/REDALERT/OBJECT.CPP +++ b/code/REDALERT/OBJECT.CPP @@ -164,6 +164,11 @@ void const * ObjectClass::Get_Image_Data(void) const return(Class_Of().Get_Image_Data()); } +struct Image_t *ObjectClass::Get_HDImage_Data(void) const +{ + return(Class_Of().Get_HDImage_Data()); +} + /*********************************************************************************************** * ObjectClass::Name -- Fetches the identification name of this object. * @@ -2177,7 +2182,8 @@ ObjectTypeClass::ObjectTypeClass( Armor(ARMOR_NONE), MaxStrength(0), ImageData(0), - RadarIcon(0) + RadarIcon(0), + HDImageData(0) { /* ** Init the DimensionData rect. Not sure how this was ever working before without being allocated. It was just trashing diff --git a/code/REDALERT/OBJECT.H b/code/REDALERT/OBJECT.H index 289f04c..5c5c47e 100644 --- a/code/REDALERT/OBJECT.H +++ b/code/REDALERT/OBJECT.H @@ -152,6 +152,7 @@ class ObjectClass : public AbstractClass */ virtual bool Is_Players_Army(void) const {return(false);} virtual void const * Get_Image_Data(void) const; + virtual struct Image_t *Get_HDImage_Data(void) const; virtual ActionType What_Action(ObjectClass const *) const; virtual ActionType What_Action(CELL) const; virtual LayerType In_Which_Layer(void) const; diff --git a/code/REDALERT/POWER.CPP b/code/REDALERT/POWER.CPP index 5e1fc0d..1f55d49 100644 --- a/code/REDALERT/POWER.CPP +++ b/code/REDALERT/POWER.CPP @@ -166,6 +166,10 @@ void PowerClass::Draw_It(bool complete) 0, -1, 0, 1, 0, -1, -2, -1, 0, 1, 2, 1 ,0 }; +// jmarshall - render the world before the power bar. + RadarClass::Draw_It(complete); +// jmarshall end + { BStart(BENCH_POWER); @@ -244,8 +248,7 @@ void PowerClass::Draw_It(bool complete) LogicPage->Unlock(); } BEnd(BENCH_POWER); - } - RadarClass::Draw_It(complete); + } } diff --git a/code/REDALERT/RADAR.CPP b/code/REDALERT/RADAR.CPP index 4c151e3..7626dd6 100644 --- a/code/REDALERT/RADAR.CPP +++ b/code/REDALERT/RADAR.CPP @@ -67,7 +67,7 @@ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" - +#include "Image.h" //void const * RadarClass::CoverShape; RadarClass::RTacticalClass RadarClass::RadarButton; @@ -1073,7 +1073,7 @@ void RadarClass::Plot_Radar_Pixel(CELL cell) */ if (color == TBLACK) { if (ZoomFactor > 1) { - void const * ptr = NULL; + const TemplateTypeClass* ptr = NULL; int icon; /* @@ -1081,7 +1081,7 @@ void RadarClass::Plot_Radar_Pixel(CELL cell) ** specified cell. */ if (cellptr->TType != TEMPLATE_NONE && cellptr->TType != 255) { - ptr = TemplateTypeClass::As_Reference(cellptr->TType).Get_Image_Data(); + ptr = &TemplateTypeClass::As_Reference(cellptr->TType); icon = cellptr->TIcon; } @@ -1090,11 +1090,11 @@ void RadarClass::Plot_Radar_Pixel(CELL cell) ** template or an illegal one. Setup for a clear template. */ if (ptr == NULL) { - ptr = TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1).Get_Image_Data(); + ptr = &TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1); icon = cellptr->Clear_Icon(); } - IconsetClass const * iconset = (IconsetClass const *)ptr; + IconsetClass const * iconset = (IconsetClass const *)ptr->Get_Image_Data(); unsigned char const * icondata = iconset->Icon_Data(); @@ -1103,10 +1103,18 @@ void RadarClass::Plot_Radar_Pixel(CELL cell) */ icon &= 0x00FF; icon = *(iconset->Map_Data() + icon); - +// jmarshall unsigned char * data = (unsigned char *)icondata + icon*(24*24); - Buffer_To_Page(0, 0, 24, 24, data, _TileStage); - _TileStage.Scale(*LogicPage, 0, 0, x, y, 24, 24, ZoomFactor, ZoomFactor, TRUE); + Image_t* image; + { + char tmp[512]; + sprintf(tmp, "radar_%d_%d", ptr->Type, icon); + image = Image_CreateImageFrom8Bit(tmp, 24, 24, (unsigned char*)data); + } + GL_RenderImage(image, x, y, ZoomFactor, ZoomFactor); +// jmarshall end + //Buffer_To_Page(0, 0, 24, 24, data, _TileStage); + //_TileStage.Scale(*LogicPage, 0, 0, x, y, 24, 24, ZoomFactor, ZoomFactor, TRUE); } else { // LogicPage->Fill_Rect(x, y, x+ZoomFactor-1, y+ZoomFactor-1, cellptr->Cell_Color(false)); /*BG*/ LogicPage->Put_Pixel(x, y, cellptr->Cell_Color(false)); diff --git a/code/REDALERT/SCENARIO.CPP b/code/REDALERT/SCENARIO.CPP index 018da86..3fb6a11 100644 --- a/code/REDALERT/SCENARIO.CPP +++ b/code/REDALERT/SCENARIO.CPP @@ -60,7 +60,6 @@ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" -#include "MapScript.h" #ifdef WIN32 #include "tcpip.h" #include "ccdde.h" @@ -111,7 +110,6 @@ bool Is_Mission_Counterstrike (char *file_name); bool Is_Mission_Aftermath (char *file_name); #endif -MapScript* mapScript = nullptr; bool mapScriptPlayStart = false; void Cmd_Map(void); @@ -332,13 +330,13 @@ bool Start_Scenario(char * name, bool briefing) } // jmarshall: map scripts - if (mapScript) { - delete mapScript; + if (Scen.mapScript) { + delete Scen.mapScript; } - mapScript = new MapScript(); - if (!mapScript->Init(name)) { - delete mapScript; - mapScript = nullptr; + Scen.mapScript = new MapScript(); + if (!Scen.mapScript->Init(name)) { + delete Scen.mapScript; + Scen.mapScript = nullptr; } else { mapScriptPlayStart = true; @@ -379,11 +377,11 @@ bool Start_Scenario(char * name, bool briefing) // } Theme.Stop(); // jmarshall - map scripts - if (mapScript) { + if (Scen.mapScript) { Hide_Mouse(); VisiblePage.Clear(); Show_Mouse(); - mapScript->CallFunction("map_briefing"); + Scen.mapScript->CallFunction("map_briefing"); } else if (briefing) { Hide_Mouse(); @@ -430,16 +428,16 @@ bool Start_Scenario(char * name, bool briefing) } void Scenario_MapScriptFrame(void) { - if (!mapScript) + if (!Scen.mapScript) return; if (mapScriptPlayStart) { - mapScript->CallFunction("map_start"); + Scen.mapScript->CallFunction("map_start"); mapScriptPlayStart = false; return; } - mapScript->CallFunction("map_frame"); + Scen.mapScript->CallFunction("map_frame"); } @@ -1628,7 +1626,7 @@ int BGMessageBox(char const * msg, int btn1, int btn2) HidPage.Blit(SeenPage); #ifdef WIN32 - VisiblePage.Blit(seen_buff_save); + //VisiblePage.Blit(seen_buff_save); #endif static unsigned char _scorepal[]={0,1,12,13,4,5,6,7,8,9,10,255,252,253,14,248}; diff --git a/code/REDALERT/SCENARIO.H b/code/REDALERT/SCENARIO.H index 10eb9fc..6012b64 100644 --- a/code/REDALERT/SCENARIO.H +++ b/code/REDALERT/SCENARIO.H @@ -36,6 +36,8 @@ #ifndef SCENARIO_H #define SCENARIO_H +#include "MapScript.h" + /* ** This class holds the information about the current game being played. This information is @@ -328,6 +330,12 @@ class ScenarioClass { #endif bool warpIntoMap; + + + /* + ** MapScript storage, to be accessed by triggers etc. + */ + MapScript* mapScript = nullptr; }; diff --git a/code/REDALERT/STARTUP.CPP b/code/REDALERT/STARTUP.CPP index 8e6c472..f5febf1 100644 --- a/code/REDALERT/STARTUP.CPP +++ b/code/REDALERT/STARTUP.CPP @@ -924,8 +924,8 @@ void Read_Setup_Options( RawFileClass *config_file ) VideoBackBufferAllowed = ini.Get_Bool("Options", "VideoBackBuffer", true); AllowHardwareBlitFills = ini.Get_Bool("Options", "HardwareFills", true); - ScreenWidth = 1024; - ScreenHeight = 768; + ScreenWidth = 1280; + ScreenHeight = 720; /* ** See if an alternative socket number has been specified diff --git a/code/REDALERT/Shape.cpp b/code/REDALERT/Shape.cpp index c97d4a6..7fa8e26 100644 --- a/code/REDALERT/Shape.cpp +++ b/code/REDALERT/Shape.cpp @@ -28,10 +28,20 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ +/* +============================ + +This file has been heavily modified by IceColdDuke(Justin Marshall) to render with OpenGL. + +============================ +*/ + #include "FUNCTION.H" #include #include +#include "Image.h" + #define le16toh(x) x #define le32toh(x) x @@ -99,6 +109,13 @@ static uint8_t* g_PredatorLimit = nullptr; typedef void (*BF_Function)(int, int, uint8_t*, uint8_t*, int, int, uint8_t*, uint8_t*, uint8_t*, int); typedef void (*Single_Line_Function)(int, uint8_t*, uint8_t*, uint8_t*, uint8_t*, uint8_t*, int); +bool renderHDTexture = false; +void Buffer_Enable_HD_Texture(bool hdTextureEnabled) { + renderHDTexture = hdTextureEnabled; +} + +#define ChannelBlend_Alpha(A,B,O) ((uint8_t)((O / 255.0f) * A + (1 - (O / 255.0f)) * B)) + // Just copy source to dest as is. void BF_Copy(int width, int height, uint8_t* dst, uint8_t* src, int dst_pitch, int src_pitch, uint8_t* ghost_lookup, uint8_t* ghost_tab, uint8_t* fade_tab, int count) @@ -114,20 +131,23 @@ void BF_Copy(int width, int height, uint8_t* dst, uint8_t* src, int dst_pitch, i void BF_Trans(int width, int height, uint8_t* dst, uint8_t* src, int dst_pitch, int src_pitch, uint8_t* ghost_lookup, uint8_t* ghost_tab, uint8_t* fade_tab, int count) { - while (height--) { - for (int i = width; i > 0; --i) { - uint8_t sbyte = *src++; + while (height--) { + for (int i = width; i > 0; --i) { + uint8_t sbyte = *src++; - if (sbyte) { - *dst = sbyte; - } + if (sbyte) { + dst[0] = backbuffer_palette[(sbyte * 3) + 0]; + dst[1] = backbuffer_palette[(sbyte * 3) + 1]; + dst[2] = backbuffer_palette[(sbyte * 3) + 2]; + dst[3] = 255; + } - ++dst; - } + dst += 4; + } - src += src_pitch; - dst += dst_pitch; - } + src += src_pitch; + dst += dst_pitch * 4; + } } // Fading table based shadow and transparency @@ -166,14 +186,17 @@ void BF_Ghost_Trans(int width, int height, uint8_t* dst, uint8_t* src, int dst_p sbyte = ghost_tab[*dst + fbyte * 256]; } - *dst = sbyte; + dst[0] = backbuffer_palette[(sbyte * 3) + 0]; + dst[1] = backbuffer_palette[(sbyte * 3) + 1]; + dst[2] = backbuffer_palette[(sbyte * 3) + 2]; + dst[3] = 255; } - ++dst; + dst += 4; } src += src_pitch; - dst += dst_pitch; + dst += dst_pitch * 4; } } @@ -258,14 +281,17 @@ void BF_Ghost_Fading_Trans(int width, int height, uint8_t* dst, uint8_t* src, in sbyte = fade_tab[sbyte]; } - *dst = sbyte; + dst[0] = backbuffer_palette[(sbyte * 3) + 0]; + dst[1] = backbuffer_palette[(sbyte * 3) + 1]; + dst[2] = backbuffer_palette[(sbyte * 3) + 2]; + dst[3] = 255; } - ++dst; + dst += 4; } src += src_pitch; - dst += dst_pitch; + dst += dst_pitch * 4; } } @@ -1370,7 +1396,7 @@ static void Single_Line_Flagger( } } -long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, GraphicViewPortClass& viewport, int flags, ...) +long Buffer_Frame_To_Page(int x, int y, int width, int height, struct Image_t * shape_image, unsigned int Window, int flags, ...) { BOOL use_old_drawer = false; int fade_count = 0; @@ -1379,27 +1405,10 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap uint8_t* ghost_table = nullptr; uint8_t* ghost_lookup = nullptr; - if (!shape) { + if (!shape_image) { return 0; } - uint8_t* frame_data = static_cast(shape); - - if (UseOldShapeDraw) { - use_old_drawer = true; - } - else if (UseBigShapeBuffer) { - draw_header = static_cast(shape); - uint8_t* shape_buff = reinterpret_cast(BigShapeBufferStart); - - if (draw_header->m_IsTheaterShape) { - shape_buff = reinterpret_cast(TheaterShapeBufferStart); - } - - frame_data = shape_buff + draw_header->m_FrameOffset; - use_old_drawer = false; - } - va_list ap; va_start(ap, flags); @@ -1426,10 +1435,6 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap use_old_drawer = true; } - if (use_old_drawer != true && (draw_header->m_DrawFlags == 0xFFFFFFFF || draw_header->m_DrawFlags != (flags & 0x1340))) { - Single_Line_Flagger(width, height, frame_data, draw_header, flags, ghost_table, ghost_lookup); - } - // Sets for BF_Fading functions if (flags & SHAPE_FADING) { fade_table = va_arg(ap, uint8_t*); @@ -1451,18 +1456,18 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap } // Sets for BF_Predator functions - if (flags & SHAPE_PREDATOR) { - int current_frame = va_arg(ap, uint32_t); - blit_style |= 8; - - g_PredFrame = ((unsigned)current_frame) % 8; - g_PartialCount = 0; - g_PartialPred = 256; - - // Calculates the end of the visible display buffer, hopefully prevent crashes from predator effect. - // Unused by default in RA, but would be nice on the phase tank in Aftermath. - g_PredatorLimit = (uint8_t*)(viewport.Get_Offset()) + viewport.Get_Full_Pitch() * viewport.Get_Height(); - } + //if (flags & SHAPE_PREDATOR) { + // int current_frame = va_arg(ap, uint32_t); + // blit_style |= 8; + // + // g_PredFrame = ((unsigned)current_frame) % 8; + // g_PartialCount = 0; + // g_PartialPred = 256; + // + // // Calculates the end of the visible display buffer, hopefully prevent crashes from predator effect. + // // Unused by default in RA, but would be nice on the phase tank in Aftermath. + // g_PredatorLimit = (uint8_t*)(viewport.Get_Offset()) + viewport.Get_Full_Pitch() * viewport.Get_Height(); + //} if (flags & SHAPE_PARTIAL) { g_PartialPred = va_arg(ap, int) & 0xFF; @@ -1477,67 +1482,107 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap int ms_img_offset = 0; // If we aren't drawing within the viewport, return. - if (xstart >= viewport.Get_Width() || ystart >= viewport.Get_Height() || xend <= 0 || yend <= 0) { - return 0; - } + //if (xstart >= viewport.Get_Width() || ystart >= viewport.Get_Height() || xend <= 0 || yend <= 0) { + // return 0; + //} // Do any needed clipping. - if (xstart < 0) { - ms_img_offset = -xstart; - xstart = 0; - use_old_drawer = true; - } + //if (xstart < 0) { + // ms_img_offset = -xstart; + // xstart = 0; + // use_old_drawer = true; + //} + // + //if (ystart < 0) { + // //frame_data += width * (-ystart); + // ystart = 0; + // use_old_drawer = true; + //} - if (ystart < 0) { - frame_data += width * (-ystart); - ystart = 0; - use_old_drawer = true; - } + if (xstart + width < 0 || ystart + height < 0) + return 0; - if (xend >= viewport.Get_Width() - 1) { - xend = viewport.Get_Width() - 1; - use_old_drawer = true; - } - - if (yend >= viewport.Get_Height() - 1) { - yend = viewport.Get_Height() - 1; - use_old_drawer = true; - } + // if (xend >= viewport.Get_Width() - 1) { + // xend = viewport.Get_Width() - 1; + // use_old_drawer = true; + // } + // + // if (yend >= viewport.Get_Height() - 1) { + // yend = viewport.Get_Height() - 1; + // use_old_drawer = true; + // } int blit_width = xend - xstart + 1; int blit_height = yend - ystart + 1; - int pitch = viewport.Get_Full_Pitch(); - uint8_t* dst = ystart * pitch + xstart + (uint8_t*)(viewport.Get_Offset()); - uint8_t* src = frame_data + ms_img_offset; - int dst_pitch = pitch - blit_width; - int src_pitch = width - blit_width; + //int pitch = viewport.Get_Full_Pitch(); + //uint8_t* dst = (ystart * pitch * 4) + (xstart * 4) + (uint8_t*)(viewport.Get_Offset()); + //uint8_t* src = frame_data + ms_img_offset; + //if (renderHDTexture) { + // Image_t* image = (Image_t*)shape; + // src = image->buffer + (ms_img_offset * 4); + //} + + //int dst_pitch = pitch - blit_width; + //int src_pitch = width - blit_width; // Use "new" line drawing routines that appear to have been added during the windows port. - if (use_old_drawer != true) { - // DEBUG_SAY("Drawing with Single_Line draw functions\n"); - - // Here we can use the individual line drawing routines - // Means we can skip drawing some lines all together or avoid using - // more expensive routines on some lines. - uint8_t* line_flags = reinterpret_cast(draw_header + 1); - - for (int i = 0; i < blit_height; ++i) { - NewShapeJumpTable[line_flags[i] & 0x1F](blit_width, dst, src, ghost_lookup, ghost_table, fade_table, fade_count); - src += width; - dst += pitch; - } - - return 0; - } + //if (use_old_drawer != true && !renderHDTexture) { + // // DEBUG_SAY("Drawing with Single_Line draw functions\n"); + // + // // Here we can use the individual line drawing routines + // // Means we can skip drawing some lines all together or avoid using + // // more expensive routines on some lines. + // uint8_t* line_flags = reinterpret_cast(draw_header + 1); + // + // for (int i = 0; i < blit_height; ++i) { + // NewShapeJumpTable[line_flags[i] & 0x1F](blit_width, dst, src, ghost_lookup, ghost_table, fade_table, fade_count); + // src += width; + // dst += pitch * 4; + // } + // + // return 0; + //} + xstart = xstart + WindowList[Window][WINDOWX];// + LogicPage->Get_XPos(); + ystart = ystart + WindowList[Window][WINDOWY];// + LogicPage->Get_YPos(); + //GL_SetClipRect(WindowList[Window][WINDOWX], WindowList[Window][WINDOWY], WindowList[Window][WINDOWWIDTH], WindowList[Window][WINDOWWIDTH]); + if(renderHDTexture) + GL_RenderImage(shape_image, xstart, ystart, width, height, (int)fade_table); + else + GL_RenderImage(shape_image, xstart, ystart, width, height, 0); // Here we just use the function that will blit the entire frame // using the appropriate effects. - if (blit_height > 0 && blit_width > 0) { - // DEBUG_SAY("Drawing with BF draw functions\n"); - OldShapeJumpTable[blit_style & 0xF]( - blit_width, blit_height, dst, src, dst_pitch, src_pitch, ghost_lookup, ghost_table, fade_table, fade_count); - } + //if (blit_height > 0 && blit_width > 0) { + // // DEBUG_SAY("Drawing with BF draw functions\n"); + // if (!renderHDTexture) + // { + // OldShapeJumpTable[blit_style & 0xF](blit_width, blit_height, dst, src, dst_pitch, src_pitch, ghost_lookup, ghost_table, fade_table, fade_count); + // } + // else + // { + // int src_index = 0; + // for (int f = 0; f < height; f++) + // { + // for (int i = width; i > 0; --i) { + // //if (src_index >= ((f + 1) * blit_height * 4)) + // // break; + // + // if (src[src_index + 3] > 0) { + // dst[0] = ChannelBlend_Alpha(src[(src_index) + 0], dst[0], src[(src_index) + 3]); + // dst[1] = ChannelBlend_Alpha(src[(src_index) + 1], dst[1], src[(src_index) + 3]); + // dst[2] = ChannelBlend_Alpha(src[(src_index) + 2], dst[2], src[(src_index) + 3]); + // dst[3] = 255; + // } + // src_index += 4; + // dst += 4; + // } + // + // src_index += src_pitch * 4; + // dst += dst_pitch * 4; + // } + // } + //} return 0; } diff --git a/code/REDALERT/TECHNO.CPP b/code/REDALERT/TECHNO.CPP index 2a9e3c8..7f9ea58 100644 --- a/code/REDALERT/TECHNO.CPP +++ b/code/REDALERT/TECHNO.CPP @@ -4450,6 +4450,19 @@ VisualType TechnoClass::Visual_Character(bool raw) const return(VISUAL_HIDDEN); } +void TechnoClass::Techno_Draw_Object_HD(struct Image_t* image, int shapenum, int x, int y, WindowNumberType window, DirType rotation, int scale) const { + //void const* remap = Remap_Table(); + void const* shadow = Map.UnitShadow; + + PlayerColorType remapColor = PCOLOR_GOLD; + if (Techno_Type_Class()->IsRemappable) { + remapColor = House->RemapColor; + } + + y -= Lepton_To_Pixel(Height); + + CC_Draw_Shape(image, shapenum, x, y, window, SHAPE_CENTER | SHAPE_WIN_REL | SHAPE_FADING | SHAPE_GHOST, (const void *)remapColor, shadow, rotation); +} /*********************************************************************************************** * TechnoClass::Techno_Draw_Object -- General purpose draw object routine. * diff --git a/code/REDALERT/TECHNO.H b/code/REDALERT/TECHNO.H index aa9e84c..ee1e558 100644 --- a/code/REDALERT/TECHNO.H +++ b/code/REDALERT/TECHNO.H @@ -369,6 +369,9 @@ class TechnoClass : public RadioClass, virtual void const * Remap_Table(void) const; VisualType Visual_Character(bool raw = false) const; void Techno_Draw_Object(void const * shapefile, int shapenum, int x, int y, WindowNumberType window, DirType rotation=DIR_N, int scale=0x0100) const; +// jmarshall + void Techno_Draw_Object_HD(struct Image_t* image, int shapenum, int x, int y, WindowNumberType window, DirType rotation = DIR_N, int scale = 0x0100) const; +// jmarshall end // Added. ST - 8/1/2019 5:37PM void Techno_Draw_Object_Virtual(void const * shapefile, int shapenum, int x, int y, WindowNumberType window, DirType rotation=DIR_N, int scale=0x0100, const char *shape_name = NULL) const; diff --git a/code/REDALERT/TILESET.CPP b/code/REDALERT/TILESET.CPP new file mode 100644 index 0000000..95f639e --- /dev/null +++ b/code/REDALERT/TILESET.CPP @@ -0,0 +1,341 @@ +/** + * @file + * + * @author CCHyper + * @author OmniBlade + * + * @brief Low level functions for loading and rendering C&C terrain tilesets. + * + * @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 + */ + /* + ============================ + + This file has been heavily modified by IceColdDuke(Justin Marshall) to render with OpenGL. + + ============================ + */ + +#include "FUNCTION.H" +#include "gbuffer.h" +#include "Image.h" +#include + +using std::memcpy; + +class GraphicViewPortClass; + +#define TD_TILESET_CHECK 0x20 + +Image_t* tileset_icon_cache[4096]; + +/** +* @brief union is to handle the parts of the header which vary between TD and RA format tiles. +*/ +struct IconControlType +{ + uint8_t* Get_Icon_Data() + { + if (td.icons == TD_TILESET_CHECK) { + return reinterpret_cast(this) + td.icons; + } + else { + return reinterpret_cast(this) + ra.icons; + } + } + + uint8_t* Get_Icon_Map() + { + if (td.icons == TD_TILESET_CHECK) { + return reinterpret_cast(this) + td.map; + } + else { + return reinterpret_cast(this) + ra.map; + } + } + + int16_t width; // always 24 (ICON_WIDTH) + int16_t height; // always 24 (ICON_HEIGHT) + int16_t count; // count of cells in set, not same as images + int16_t allocated; // is treated like a bool, always 0 in the file? + + union + { + struct + { + int32_t size; // filesize + int32_t icons; // always 0x00000020 + int32_t palettes; // seems to always be 0x00000000 + int32_t remaps; // unknown, bitfield? + int32_t trans_flag; // array of images length, unknown + int32_t map; // image index for each cell + } td; + + struct + { + int16_t map_width; // tile width in cells + int16_t map_height; // tile height in cells + int32_t size; // filesize + int32_t icons; // always 0x00000028 + int32_t palettes; // seems to always be 0x00000000 + int32_t remaps; // unknown, bitfield? + int32_t trans_flag; // array of images length, unknown + int32_t color_map; // terrain type index, ra only + int32_t map; // image index for each cell + } ra; + }; +}; + +static int IconEntry; +static void* IconData; +static IconControlType* LastIconset; +static uint8_t* StampPtr; +static uint8_t* TransFlagPtr; +static uint8_t* MapPtr; +static int IconWidth; +static int IconHeight; +static int IconSize; +static int IconCount; + +void __cdecl Init_Stamps(IconControlType* iconset) +{ + memset(&tileset_icon_cache, 0, sizeof(tileset_icon_cache)); + if (iconset && LastIconset != iconset) { + IconCount = (iconset->count); + IconWidth = (iconset->width); + IconHeight = (iconset->height); + LastIconset = iconset; + IconSize = IconWidth * IconHeight; + + // TD and RA tileset headers are slightly different, so check a constant that only exists in one type. + if ((iconset->td.icons) == TD_TILESET_CHECK) { + MapPtr = reinterpret_cast(iconset) + (iconset->td.map); + StampPtr = reinterpret_cast(iconset) + (iconset->td.icons); + TransFlagPtr = reinterpret_cast(iconset) + (iconset->td.trans_flag); + } + else { + MapPtr = reinterpret_cast(iconset) + (iconset->ra.map); + StampPtr = reinterpret_cast(iconset) + (iconset->ra.icons); + TransFlagPtr = reinterpret_cast(iconset) + (iconset->ra.trans_flag); + } + } +} + +void __cdecl Buffer_Draw_Stamp2(GraphicViewPortClass& viewport, IconControlType* tileset, int icon, int x, int y, const void* remapper) +{ + if (!tileset) { + return; + } + + if (LastIconset != tileset) { + Init_Stamps(tileset); + } + + int32_t icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; + + if (icon_index < IconCount) { + + int32_t fullpitch = viewport.Get_Full_Pitch(); //(viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width()); + uint8_t* dst = (x * 4) + (y * 4) * fullpitch + (uint8_t*)(viewport.Get_Offset()); + int32_t blitpitch = fullpitch - IconWidth; + uint8_t* src = &StampPtr[IconSize * icon_index]; + + if (remapper) { + const uint8_t* remap = static_cast(remapper); + for (int i = 0; i < IconHeight; ++i) { + for (int j = 0; j < IconWidth; ++j) { + uint8_t cur_byte = remap[*src++]; + + if (cur_byte) { + dst[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; + dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; + dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; + dst[3] = 255; + } + + dst+=4; + } + + dst += blitpitch; + } + + } + else if (TransFlagPtr[icon_index]) { + for (int i = 0; i < IconHeight; ++i) { + for (int j = 0; j < IconWidth; ++j) { + uint8_t cur_byte = *src++; + + if (cur_byte) { + dst[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; + dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; + dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; + dst[3] = 255; + } + + dst += 4; + } + + dst += blitpitch; + } + } + else { + for (int32_t i = 0; i < IconHeight; ++i) { + FastScanlinePaletteBlit(dst, src, IconWidth); + dst += fullpitch; + src += IconWidth * 4; + } + } + } +} + +void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, const void *icondata, int icon, int x, int y, const void* remapper, int left, int top, int right, int bottom) +{ + const TemplateTypeClass* ttype = (TemplateTypeClass const*)icondata; + IconControlType* tileset = (IconControlType * )ttype->Get_Image_Data(); + + // This is a awful hack, but need type info to generate unique id's for tileset generation. + if (icondata == DisplayClass::TransIconset) { + tileset = (IconControlType*)DisplayClass::TransIconset; + ttype = NULL; + } + + if (!tileset) { + return; + } + + if (LastIconset != tileset) { + Init_Stamps(tileset); + } + + int icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; + + if (icon_index < IconCount) { + int blit_height = IconHeight; + int blit_width = IconWidth; + uint8_t* src = &StampPtr[IconSize * icon_index]; + int width = left + right; + int xstart = left + x; + int height = top + bottom; + int ystart = top + y; + + // + if (!tileset_icon_cache[icon_index]) { + char tmp[512]; + if (ttype != NULL) { + sprintf(tmp, "icon_%d_%d", ttype->Type, icon_index); + } + else { + sprintf(tmp, "icon_%d_%d", icondata, icon_index); + } + tileset_icon_cache[icon_index] = Image_CreateImageFrom8Bit(tmp, IconWidth, IconHeight, (unsigned char *)src); + } + + if (xstart < width && ystart < height && IconHeight + ystart > top && IconWidth + xstart > left) { + if (xstart < left) { + src += left - xstart; + blit_width -= left - xstart; + xstart = left; + } + + int src_pitch = IconWidth - blit_width; + + if (blit_width + xstart > width) { + src_pitch += blit_width - (width - xstart); + blit_width = width - xstart; + } + + if (top > ystart) { + blit_height = IconHeight - (top - ystart); + src += IconWidth * (top - ystart); + ystart = top; + } + + if (blit_height + ystart > height) { + blit_height = height - ystart; + } + + int full_pitch = viewport.Get_Full_Pitch(); //(viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width()); + uint8_t* dst = (xstart * 4) + (ystart * 4) * full_pitch + (uint8_t*)(viewport.Get_Offset()); + int dst_pitch = full_pitch - blit_width; + + //if (remapper) { + // const uint8_t* remap = static_cast(remapper); + // for (int i = 0; i < blit_height; ++i) { + // for (int j = 0; j < blit_width; ++j) { + // uint8_t cur_byte = remap[*src++]; + // if (cur_byte) { + // dst[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; + // dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; + // dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; + // dst[3] = 255; + // } + // + // dst += 4; + // } + // dst += dst_pitch * 4; + // } + // + //} + //else if (TransFlagPtr[icon_index]) { + // for (int i = 0; i < blit_height; ++i) { + // for (int j = 0; j < blit_width; ++j) { + // uint8_t cur_byte = *src++; + // if (cur_byte) { + // dst[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; + // dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; + // dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; + // dst[3] = 255; + // } + // + // dst += 4; + // } + // src += src_pitch; + // dst += dst_pitch * 4; + // } + // + //} + //else { + { + //for (int i = 0; i < blit_height; ++i) { + // FastScanlinePaletteBlit(dst, src, blit_width); + // dst += full_pitch * 4; + // src += IconWidth; + //} + + GL_SetClipRect(xstart, ystart, blit_width, blit_height); + GL_RenderImage(tileset_icon_cache[icon_index], xstart, ystart, blit_width, blit_height); + GL_ResetClipRect(); + } + } + } +} + +extern "C" void __cdecl Buffer_Draw_Stamp_Clip(void const* this_object, void const* icondata, int icon, int x_pixel, int y_pixel, void const* remap, int min_x, int min_y, int max_x, int max_y) { + if (icondata == NULL) + return; + + Buffer_Draw_Stamp_Clip2(*((GraphicViewPortClass*)this_object), icondata, icon, x_pixel, y_pixel, remap, min_x, min_y, max_x, max_y); +} + +extern "C" void __cdecl Buffer_Draw_Stamp(void const* thisptr, void const* icondata, int icon, int x_pixel, int y_pixel, void const* remap) { + Buffer_Draw_Stamp2(*((GraphicViewPortClass*)thisptr), (IconControlType*)icondata, icon, x_pixel, y_pixel, remap); +} + +uint8_t* Get_Icon_Set_Map(void* temp) +{ + if (temp != nullptr) { + if ((static_cast(temp)->td.icons) == TD_TILESET_CHECK) { + return static_cast(temp) + (static_cast(temp)->td.icons); + } + else { + return static_cast(temp) + (static_cast(temp)->ra.icons); + } + } + + return nullptr; +} diff --git a/code/REDALERT/TRIGGER.CPP b/code/REDALERT/TRIGGER.CPP index 57dabfe..c7c9dcb 100644 --- a/code/REDALERT/TRIGGER.CPP +++ b/code/REDALERT/TRIGGER.CPP @@ -45,6 +45,7 @@ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" +#include "MapScript.h" #if defined(CHEAT_KEYS) || defined(SCENARIO_EDITOR) @@ -228,6 +229,7 @@ bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool f bool e1 = Class->Event1(Event1, event, Class->House, obj, forced); bool e2 = false; bool execute = false; + bool execute_mapScript = false; /* ** Forced triggers must presume that the cell parameter is invalid. It then @@ -295,6 +297,13 @@ bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool f } } + /* + ** We need to execute this trigger, so is there an attached MapScript callback? + */ + if (Scen.mapScript != NULL && strlen(MapScriptCallback) > 0) { + execute_mapScript = true; + } + /* ** For linked trigger events, perform the action associated with the matching ** trigger event. Otherwise perform the action for both events. @@ -302,19 +311,45 @@ bool TriggerClass::Spring(TEventType event, ObjectClass * obj, CELL cell, bool f bool ok = false; HousesType hh = Class->House; if (Class->EventControl == MULTI_LINKED) { - if (e1 || forced) ok |= Class->Action1(hh, obj, ID, cell); - if (e2 && !forced) ok |= Class->Action2(hh, obj, ID, cell); + if (e1 || forced) { + ok |= Class->Action1(hh, obj, ID, cell); + + // Execute MapScript Callback for action 1? + if (ok && execute_mapScript && MapScriptActionIndex <= 1) { + Scen.mapScript->CallFunction(MapScriptCallback); + } + } + if (e2 && !forced) { + ok |= Class->Action2(hh, obj, ID, cell); + + // Execute MapScript Callback for action 2? + if (ok && execute_mapScript && MapScriptActionIndex != 1) { + Scen.mapScript->CallFunction(MapScriptCallback); + } + } } else { switch (Class->ActionControl) { case MULTI_ONLY: ok |= Class->Action1(hh, obj, ID, cell); + + // Execute MapScript Callback for action 1? + if (ok && execute_mapScript && MapScriptActionIndex <= 1) { + Scen.mapScript->CallFunction(MapScriptCallback); + } + break; default: case MULTI_AND: ok |= Class->Action1(hh, obj, ID, cell); ok |= Class->Action2(hh, obj, ID, cell); + + // Execute MapScript Callback for action? + if (ok && execute_mapScript) { + Scen.mapScript->CallFunction(MapScriptCallback); + } + break; } } diff --git a/code/REDALERT/TRIGGER.H b/code/REDALERT/TRIGGER.H index cb0d772..7259f3d 100644 --- a/code/REDALERT/TRIGGER.H +++ b/code/REDALERT/TRIGGER.H @@ -115,6 +115,12 @@ class TriggerClass { ** Some additional padding in case we need to add data to the class and maintain backwards compatibility for save/load */ unsigned char SaveLoadPadding[32]; + + /* + ** Store MapScript callback function and optional action index (because there can be multiple outcomes) -- JJ 6/14/2020 + */ + char MapScriptCallback[32]; + char MapScriptActionIndex; }; diff --git a/code/REDALERT/TYPE.H b/code/REDALERT/TYPE.H index fb56bb9..a494210 100644 --- a/code/REDALERT/TYPE.H +++ b/code/REDALERT/TYPE.H @@ -257,7 +257,9 @@ class ObjectTypeClass : public AbstractTypeClass ** The "mutable" keyword allows easy modification to this otherwise const object. */ void const * ImageData; - +// jmarshall + struct Image_t *HDImageData; +// jmarshall end /* ** Points to the dimension data for each shape in the image list. By using this ** data, the minimum number of cells will be redrawn when the object changes shape. @@ -298,6 +300,9 @@ class ObjectTypeClass : public AbstractTypeClass virtual short const * Overlap_List(void) const; virtual BuildingClass * Who_Can_Build_Me(bool intheory, bool legal, HousesType house) const; virtual void const * Get_Cameo_Data(void) const; +// jmarshall + struct Image_t* Get_HDImage_Data(void) const { return HDImageData; } +// jmarshall end void const * Get_Image_Data(void) const {return ImageData;}; void const * Get_Radar_Data(void) const {return RadarIcon;}; diff --git a/code/REDALERT/VDATA.CPP b/code/REDALERT/VDATA.CPP index e5d04fa..1e111e5 100644 --- a/code/REDALERT/VDATA.CPP +++ b/code/REDALERT/VDATA.CPP @@ -49,7 +49,7 @@ #include "function.h" - +#include "Image.h" // Submarine static VesselTypeClass const VesselSubmarine( @@ -578,7 +578,6 @@ void VesselTypeClass::One_Time(void) */ _makepath(fullname, NULL, NULL, uclass.Graphic_Name(), ".SHP"); ((void const *&)uclass.ImageData) = MFCD::Retrieve(fullname); - ((int &)uclass.MaxSize) = 26; } } diff --git a/code/REDALERT/VORTEX.CPP b/code/REDALERT/VORTEX.CPP index bdf455a..da3dbe9 100644 --- a/code/REDALERT/VORTEX.CPP +++ b/code/REDALERT/VORTEX.CPP @@ -935,7 +935,9 @@ void ChronalVortexClass::Render (void) ** Draw the template */ if (ttype->Get_Image_Data()) { - RenderBuffer->Draw_Stamp(ttype->Get_Image_Data(), icon, x*CELL_PIXEL_W, y*CELL_PIXEL_H, NULL, WINDOW_MAIN); +// jmarshall - send down the raw ttype + RenderBuffer->Draw_Stamp(ttype, icon, x*CELL_PIXEL_W, y*CELL_PIXEL_H, NULL, WINDOW_MAIN); +// jmarshall end } /* diff --git a/code/REDALERT/WIN32LIB/DRAWBUFF.H b/code/REDALERT/WIN32LIB/DRAWBUFF.H index f30e477..38b46d4 100644 --- a/code/REDALERT/WIN32LIB/DRAWBUFF.H +++ b/code/REDALERT/WIN32LIB/DRAWBUFF.H @@ -43,6 +43,7 @@ extern "C" { long __cdecl Buffer_To_Page(int x, int y, int w, int h, void *Buffer, void *view); BOOL __cdecl Linear_Blit_To_Linear( void *thisptr, void * dest, int x_pixel, int y_pixel, int dx_pixel, int dy_pixel, int pixel_width, int pixel_height, BOOL trans); + BOOL __cdecl Linear_Blit_To_Linear_Pal(void* this_object, void* dest, int src_x, int src_y, int dst_x, int dst_y, int w, int h, BOOL use_key); BOOL __cdecl Linear_Scale_To_Linear( void *, void *, int, int, int, int, int, int, int, int, BOOL, char *); LONG __cdecl Buffer_Print(void *thisptr, const char *str, int x, int y, int fcolor, int bcolor); diff --git a/code/REDALERT/WIN32LIB/DrawMisc.cpp b/code/REDALERT/WIN32LIB/DrawMisc.cpp index 5c6b0e8..ad65e30 100644 --- a/code/REDALERT/WIN32LIB/DrawMisc.cpp +++ b/code/REDALERT/WIN32LIB/DrawMisc.cpp @@ -79,7 +79,7 @@ extern "C" int __cdecl Get_Free_Cache_Slot(void) {return -1;} void IconCacheClass::Draw_It (void *dest_surface , int x_pixel, int y_pixel, int window_left , int window_top , int window_width , int window_height) {} - +extern bool renderHDTexture; extern int CachedIconsDrawn; extern int UnCachedIconsDrawn; @@ -1054,231 +1054,34 @@ CODESEG #define OPTIMAL_BYTE_COPY 14 -void __cdecl Buffer_Fill_Rect(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color) +void __cdecl Buffer_Fill_Rect(void *thisptr, int x, int y, int w, int h, unsigned char color) { -/* - ;*=================================================================== - ;* define the arguements that our function takes. - ;*=================================================================== - ARG this_object:DWORD ; this is a member function - ARG x1_pixel:WORD - ARG y1_pixel:WORD - ARG x2_pixel:WORD - ARG y2_pixel:WORD - ARG color:BYTE ; what color should we clear to -*/ - - void *this_object = thisptr; - int x1_pixel = sx; - int y1_pixel = sy; - int x2_pixel = dx; - int y2_pixel = dy; - -/* - ;*=================================================================== - ; Define some locals so that we can handle things quickly - ;*=================================================================== - LOCAL VPwidth:DWORD ; the width of the viewport - LOCAL VPheight:DWORD ; the height of the viewport - LOCAL VPxadd:DWORD ; the additional x offset of viewport - LOCAL VPbpr:DWORD ; the number of bytes per row of viewport -*/ + GraphicViewPortClass& vp = (*(GraphicViewPortClass *)thisptr); - int VPwidth; - int VPheight; - int VPxadd; - int VPbpr; + // If we aren't drawing within the viewport, return + if (x >= vp.Get_Width() || y >= vp.Get_Height() || w < 0 || h < 0) { + return; + } - int local_ebp; // Can't use ebp + // Clipping + if (x < 0) { + x = 0; + } - __asm { + if (y < 0) { + y = 0; + } - ;*=================================================================== - ;* save off the viewport characteristics on the stack - ;*=================================================================== - mov ebx,[this_object] ; get a pointer to viewport - mov eax,[ebx]GraphicViewPortClass.Width ; get width from viewport - mov ecx,[ebx]GraphicViewPortClass.Height ; get height from viewport - mov edx,[ebx]GraphicViewPortClass.XAdd ; get xadd from viewport - add edx,[ebx]GraphicViewPortClass.Pitch ; extra pitch of direct draw surface - mov [VPwidth],eax ; store the width of locally - mov [VPheight],ecx - mov [VPxadd],edx - add eax,edx - mov [VPbpr],eax + w = min(w, vp.Get_Width() - 1); + h = min(h, vp.Get_Height() - 1); - ;*=================================================================== - ;* move the important parameters into local registers - ;*=================================================================== - mov eax,[x1_pixel] - mov ebx,[y1_pixel] - mov ecx,[x2_pixel] - mov edx,[y2_pixel] + uint8_t* offset = (y * 4) * vp.Get_Full_Pitch() + (x * 4) + (uint8_t*)(vp.Get_Offset()); + int height = h - y + 1; + int width = w - x + 1; - ;*=================================================================== - ;* Convert the x2 and y2 pixel to a width and height - ;*=================================================================== - cmp eax,ecx - jl no_swap_x - xchg eax,ecx - - no_swap_x: - sub ecx,eax - cmp ebx,edx - jl no_swap_y - xchg ebx,edx - no_swap_y: - sub edx,ebx - inc ecx - inc edx - - ;*=================================================================== - ;* Bounds check source X. - ;*=================================================================== - cmp eax, [VPwidth] ; compare with the max - jge done ; starts off screen, then later - jb short sx_done ; if it's not negative, it's ok - - ;------ Clip source X to left edge of screen. - add ecx, eax ; Reduce width (add in negative src X). - xor eax, eax ; Clip to left of screen. - sx_done: - - ;*=================================================================== - ;* Bounds check source Y. - ;*=================================================================== - cmp ebx, [VPheight] ; compare with the max - jge done ; starts off screen, then later - jb short sy_done ; if it's not negative, it's ok - - ;------ Clip source Y to top edge of screen. - add edx, ebx ; Reduce height (add in negative src Y). - xor ebx, ebx ; Clip to top of screen. - - sy_done: - ;*=================================================================== - ;* Bounds check width versus width of source and dest view ports - ;*=================================================================== - push ebx ; save off ebx for later use - mov ebx,[VPwidth] ; get the source width - sub ebx, eax ; Maximum allowed pixel width (given coordinates). - sub ebx, ecx ; Pixel width undershoot. - jns short width_ok ; if not signed no adjustment necessary - add ecx, ebx ; Reduce width to screen limits. - - width_ok: - pop ebx ; restore ebx to old value - - ;*=================================================================== - ;* Bounds check height versus height of source view port - ;*=================================================================== - push eax ; save of eax for later use - mov eax, [VPheight] ; get the source height - sub eax, ebx ; Maximum allowed pixel height (given coordinates). - sub eax, edx ; Pixel height undershoot. - jns short height_ok ; if not signed no adjustment necessary - add edx, eax ; Reduce height to screen limits. - height_ok: - pop eax ; restore eax to old value - - ;*=================================================================== - ;* Perform the last minute checks on the width and height - ;*=================================================================== - or ecx,ecx - jz done - - or edx,edx - jz done - - cmp ecx,[VPwidth] - ja done - cmp edx,[VPheight] - ja done - - ;*=================================================================== - ;* Get the offset into the virtual viewport. - ;*=================================================================== - xchg edi,eax ; save off the contents of eax - xchg esi,edx ; and edx for size test - mov eax,ebx ; move the y pixel into eax - mul [VPbpr] ; multiply by bytes per row - add edi,eax ; add the result into the x position - mov ebx,[this_object] - add edi,[ebx]GraphicViewPortClass.Offset - - mov edx,esi ; restore edx back to real value - mov eax,ecx ; store total width in ecx - sub eax,[VPwidth] ; modify xadd value to include clipped - sub [VPxadd],eax ; width bytes (subtract a negative number) - - ;*=================================================================== - ; Convert the color byte to a DWORD for fast storing - ;*=================================================================== - mov al,[color] ; get color to clear to - mov ah,al ; extend across WORD - mov ebx,eax ; extend across DWORD in - shl eax,16 ; several steps - mov ax,bx - - ;*=================================================================== - ; If there is no row offset then adjust the width to be the size of - ; the entire viewport and adjust the height to be 1 - ;*=================================================================== - mov esi,[VPxadd] - or esi,esi ; set the flags for esi - jnz row_by_row_aligned ; and act on them - - xchg eax,ecx ; switch bit pattern and width - mul edx ; multiply by edx to get size - xchg eax,ecx ; switch size and bit pattern - mov edx,1 ; only 1 line off view port size to do - - ;*=================================================================== - ; Find out if we should bother to align the row. - ;*=================================================================== - row_by_row_aligned: - mov [local_ebp],ecx ; width saved in ebp - cmp ecx,OPTIMAL_BYTE_COPY ; is it worth aligning them? - jl row_by_row ; if not then skip - - ;*=================================================================== - ; Figure out the alignment offset if there is any - ;*=================================================================== - mov ebx,edi ; get output position - and ebx,3 ; is there a remainder? - jz aligned_loop ; if not we are aligned - xor ebx,3 ; find number of align bytes - inc ebx ; this number is off by one - sub [local_ebp],ebx ; subtract from width - - ;*=================================================================== - ; Now that we have the alignment offset copy each row - ;*=================================================================== - aligned_loop: - mov ecx,ebx ; get number of bytes to align - rep stosb ; and move them over - mov ecx,[local_ebp] ; get number of aligned bytes - shr ecx,2 ; convert to DWORDS - rep stosd ; and move them over - mov ecx,[local_ebp] ; get number of aligned bytes - and ecx,3 ; find the remainder - rep stosb ; and move it over - add edi,esi ; fix the line offset - dec edx ; decrement the height - jnz aligned_loop ; if more to do than do it - jmp done ; we are all done - - ;*=================================================================== - ; If not enough bytes to bother aligning copy each line across a byte - ; at a time. - ;*=================================================================== - row_by_row: - mov ecx,[local_ebp] ; get total width in bytes - rep stosb ; store the width - add edi,esi ; handle the xadd - dec edx ; decrement the height - jnz row_by_row ; if any left then next line - done: + for (int i = 0; i < height; ++i) { + FastScanlinePaletteBlit(offset, color, width); + offset += vp.Get_Full_Pitch() * 4; } } @@ -1328,22 +1131,37 @@ void __cdecl Buffer_Clear(void *this_object, unsigned char color) */ // jmarshall - ported to c + + unsigned char* Draw_Dropsample(const unsigned char* in, int inwidth, int inheight, int outwidth, int outheight) { int i, j, k; const unsigned char* inrow; const unsigned char* pix1; unsigned char* out, * out_p; - static unsigned char ViewportPixelBuffer[4096 * 4096]; + static unsigned char ViewportPixelBuffer[4096 * 4096 * 4]; out = &ViewportPixelBuffer[0]; out_p = out; - for (i = 0; i < outheight; i++, out_p += outwidth * 1) { - inrow = in + 1 * inwidth * (int)((i + 0.25) * inheight / outheight); + int bpp = 1; + if (renderHDTexture) { + bpp = 4; + } + + for (i = 0; i < outheight; i++, out_p += outwidth * bpp) { + inrow = in + bpp * inwidth * (int)((i + 0.25) * inheight / outheight); for (j = 0; j < outwidth; j++) { k = j * inwidth / outwidth; - pix1 = inrow + k * 1; - out_p[j * 1 + 0] = pix1[0]; + pix1 = inrow + k * bpp; + if (renderHDTexture) { + out_p[j * 4 + 0] = pix1[0]; + out_p[j * 4 + 1] = pix1[1]; + out_p[j * 4 + 2] = pix1[2]; + out_p[j * 4 + 3] = pix1[3]; + } + else { + out_p[j * 1 + 0] = pix1[0]; + } //out_p[j * 3 + 1] = pix1[1]; //out_p[j * 3 + 2] = pix1[2]; } @@ -1352,145 +1170,111 @@ unsigned char* Draw_Dropsample(const unsigned char* in, int inwidth, int inheigh return out; } -BOOL __cdecl Linear_Scale_To_Linear(void* this_object, void* dest, int src_x, int src_y, int dst_x, int dst_y, int src_w, int src_h, int dst_w, int dst_h, BOOL use_keysrc, char* fade) + +/* +============== +R_CopyImage +============== +*/ +void Nearest_CopyImage(unsigned char* source, int sourceX, int sourceY, int sourceWidth, unsigned char* dest, int destX, int destY, int destWidth, int width, int height, BOOL trans) { - GraphicViewPortClass& src_vp = *(GraphicViewPortClass*)this_object; - GraphicViewPortClass& dst_vp = *(GraphicViewPortClass*)dest; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { - // If there is nothing to scale, just return. - if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { - return false; - } + int destPos = ((destWidth * (y + destY)) * 4) + ((x + destX) * 4); + int sourcePos = (sourceWidth * (y + (sourceY))) + (x + (sourceX)); + if (renderHDTexture) { + sourcePos = ((sourceWidth * (y + sourceY)) * 4) + ((x + sourceX) * 4); - int sx = src_x; - int sy = src_y; - int dx = dst_x; - int dy = dst_y; - int dw = dst_w + dst_x; - int dh = dst_h + dst_y; + // This needs some work! + if (source[0] == 0 && source[1] == 0 && source[2] == 0 && trans) + continue; - // These ifs are all for clipping purposes incase coords are outside - // the expected area. - if (src_x < 0) { - sx = 0; - dx = dst_x + ((dst_w * -src_x) / src_w); - } - - if (src_y < 0) { - sy = 0; - dy = dst_y + ((dst_h * -src_y) / src_h); - } - - if (src_x + src_w > src_vp.Get_Width() + 1) { - dw = dst_x + (dst_w * (src_vp.Get_Width() - src_x) / src_w); - } - - if (src_y + src_h > src_vp.Get_Height() + 1) { - dh = dst_y + (dst_h * (src_vp.Get_Height() - src_y) / src_h); - } - - if (dx < 0) { - dx = 0; - sx = src_x + ((src_w * -dst_x) / dst_w); - } - - if (dy < 0) { - dy = 0; - sy = src_y + ((src_h * -dst_y) / dst_h); - } - - if (dw > dst_vp.Get_Width() + 1) { - dw = dst_vp.Get_Width(); - } - - if (dh > dst_vp.Get_Height() + 1) { - dh = dst_vp.Get_Height(); - } - - if (dy > dh || dx > dw) { - return false; - } - - uint8_t* src = sy * src_vp.Get_Full_Pitch() + sx + (uint8_t*)(src_vp.Get_Offset()); - uint8_t* dst = dy * dst_vp.Get_Full_Pitch() + dx + (uint8_t*)(dst_vp.Get_Offset()); - dw -= dx; - dh -= dy; - int x_ratio = ((src_w << 16) / dw) + 1; - int y_ratio = ((src_h << 16) / dh) + 1; - - // keysrc basically means do we skip index 0 entries, thus treating them as - // transparent? - if (use_keysrc) { - if (fade != nullptr) { - for (int i = 0; i < dh; ++i) { - uint8_t* d = dst + i * dst_vp.Get_Full_Pitch(); - uint8_t* s = src + ((i * y_ratio) >> 16) * src_vp.Get_Full_Pitch(); - int xrat = 0; - - for (int j = 0; j < dw; ++j) { - uint8_t tmp = s[xrat >> 16]; - - if (tmp != 0) { - *d = ((uint8_t*)(fade))[tmp]; - } - - ++d; - xrat += x_ratio; - } + dest[destPos + 0] = source[sourcePos + 0]; + dest[destPos + 1] = source[sourcePos + 1]; + dest[destPos + 2] = source[sourcePos + 2]; + dest[destPos + 3] = 255; } - } - else { - for (int i = 0; i < dh; ++i) { - uint8_t* d = dst + i * dst_vp.Get_Full_Pitch(); - uint8_t* s = src + ((i * y_ratio) >> 16) * src_vp.Get_Full_Pitch(); - int xrat = 0; + else + { + unsigned char c = source[sourcePos]; - for (int j = 0; j < dw; ++j) { - uint8_t tmp = s[xrat >> 16]; - - if (tmp != 0) { - *d = tmp; - } - - ++d; - xrat += x_ratio; + if (c == 0 && trans) { + continue; } + + dest[destPos + 0] = backbuffer_palette[(c * 3) + 0]; + dest[destPos + 1] = backbuffer_palette[(c * 3) + 1]; + dest[destPos + 2] = backbuffer_palette[(c * 3) + 2]; + dest[destPos + 3] = 255; } } } - else { - if (fade != nullptr) { - for (int i = 0; i < dh; ++i) { - uint8_t* d = dst + i * dst_vp.Get_Full_Pitch(); - uint8_t* s = src + ((i * y_ratio) >> 16) * src_vp.Get_Full_Pitch(); - int xrat = 0; +} - for (int j = 0; j < dw; ++j) { - *d++ = ((uint8_t*)(fade))[s[xrat >> 16]]; - xrat += x_ratio; - } - } - } - else { - for (int i = 0; i < dh; ++i) { - uint8_t* d = dst + i * dst_vp.Get_Full_Pitch(); - uint8_t* s = src + ((i * y_ratio) >> 16) * src_vp.Get_Full_Pitch(); - int xrat = 0; - for (int j = 0; j < dw; ++j) { - *d++ = s[xrat >> 16]; - xrat += x_ratio; - } - } - } - } +BOOL __cdecl Linear_Scale_To_Linear(void* this_object, void* dest, int src_x, int src_y, int dst_x, int dst_y, int src_width, int src_height, int dst_width, int dst_height, BOOL trans, char* remap) +{ + GraphicViewPortClass* viewportClass = (GraphicViewPortClass*)this_object; + GraphicViewPortClass* destViewportClass = (GraphicViewPortClass*)dest; + + unsigned char* viewportBuffer = ((unsigned char*)viewportClass->Get_Offset()); + + // Scale the GraphicViewPortClass to dest_x, dest_y + unsigned char* scaled_buffer = Draw_Dropsample((unsigned char*)viewportBuffer, viewportClass->Get_Width(), viewportClass->Get_Height(), dst_width, dst_height); + + // Blit the scaled_buffer to dest. + Nearest_CopyImage(scaled_buffer, src_x, src_y, dst_width, (unsigned char*)destViewportClass->Get_Offset(), dst_x, dst_y, destViewportClass->Get_Width(), dst_width, dst_height, trans); return true; } -BOOL __cdecl Linear_Blit_To_Linear(void* this_object, void* dest, int src_x, int src_y, int dst_x, int dst_y, int w, int h, BOOL use_key) +BOOL __cdecl Linear_Blit_To_Linear(void* this_object, void* dest, int x_pixel, int y_pixel, int dest_x0, int dest_y0, int pixel_width, int pixel_height, BOOL trans) { - GraphicViewPortClass& src_vp = *(GraphicViewPortClass *)this_object; + GraphicViewPortClass* viewportClass = (GraphicViewPortClass*)this_object; + GraphicViewPortClass* destViewportClass = (GraphicViewPortClass*)dest; + bool needsUnlock = false; + bool sourceNeedsUnlock = false; + + unsigned char* viewportBuffer = NULL; + viewportBuffer = ((unsigned char*)viewportClass->Get_Offset()); + + unsigned char* destBuffer = NULL; + destBuffer = ((unsigned char*)destViewportClass->Get_Offset()); + + //if (destViewportClass->Get_Graphic_Buffer()->Get_Buffer() != NULL) { + // destBuffer = (byte*)destViewportClass->Get_Graphic_Buffer()->Get_Buffer(); + //} + //else { + // destViewportClass->Get_Graphic_Buffer()->Lock(); + // destBuffer = ((byte*)destViewportClass->Get_Graphic_Buffer()->GetMemoryBuffer()); + // needsUnlock = true; + //} + // + //if (viewportBuffer == NULL) { + // viewportClass->Get_Graphic_Buffer()->Lock(); + // viewportBuffer = ((byte*)viewportClass->Get_Graphic_Buffer()->GetMemoryBuffer()); + // sourceNeedsUnlock = true; + //} + + // Blit the buffer to dest. + Nearest_CopyImage(viewportBuffer, x_pixel, y_pixel, viewportClass->Get_Width(), (unsigned char*)destBuffer, dest_x0, dest_y0, destViewportClass->Get_Width(), pixel_width, pixel_height, trans); + + //if (needsUnlock) { + // destViewportClass->Get_Graphic_Buffer()->Unlock(); + //} + // + //if (sourceNeedsUnlock) { + // viewportClass->Get_Graphic_Buffer()->Unlock(); + //} + return true; +} + +BOOL __cdecl Linear_Blit_To_Linear_Pal(void* this_object, void* dest, int src_x, int src_y, int dst_x, int dst_y, int w, int h, BOOL use_key) +{ + GraphicViewPortClass& src_vp = *(GraphicViewPortClass*)this_object; GraphicViewPortClass& dst_vp = *(GraphicViewPortClass*)dest; uint8_t* src = (uint8_t*)(src_vp.Get_Offset()); @@ -1689,525 +1473,6 @@ fini: } -/* -;*********************************************************** - -;*********************************************************** -; DRAW_STAMP -; -; VOID cdecl Buffer_Draw_Stamp(VOID *icondata, WORD icon, WORD x_pixel, WORD y_pixel, VOID *remap); -; -; This routine renders the icon at the given coordinate. -; -; The remap table is a 256 byte simple pixel translation table to use when -; drawing the icon. Transparency check is performed AFTER the remap so it is possible to -; remap valid colors to be invisible (for special effect reasons). -; This routine is fastest when no remap table is passed in. -;* -*/ - -void __cdecl Buffer_Draw_Stamp(void const *this_object, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap) -{ - unsigned int modulo = 0; - unsigned int iwidth = 0; - unsigned char doremap = 0; - - -/* - PROC Buffer_Draw_Stamp C near - - ARG this_object:DWORD ; this is a member function - ARG icondata:DWORD ; Pointer to icondata. - ARG icon:DWORD ; Icon number to draw. - ARG x_pixel:DWORD ; X coordinate of icon. - ARG y_pixel:DWORD ; Y coordinate of icon. - ARG remap:DWORD ; Remap table. - - LOCAL modulo:DWORD ; Modulo to get to next row. - LOCAL iwidth:DWORD ; Icon width (here for speedy access). - LOCAL doremap:BYTE ; Should remapping occur? -*/ - - __asm { - - pushad - cmp [icondata],0 - je proc_out - - ; Initialize the stamp data if necessary. - mov eax,[icondata] - cmp [LastIconset],eax - je short noreset - push eax - call Init_Stamps - pop eax // Clean up stack. ST - 12/20/2018 10:42AM -noreset: - - ; Determine if the icon number requested is actually in the set. - ; Perform the logical icon to actual icon number remap if necessary. - mov ebx,[icon] - cmp [MapPtr],0 - je short notmap - mov edi,[MapPtr] - mov bl,[edi+ebx] -notmap: - cmp ebx,[IconCount] - jae proc_out - mov [icon],ebx ; Updated icon number. - - ; If the remap table pointer passed in is NULL, then flag this condition - ; so that the faster (non-remapping) icon draw loop will be used. - cmp [remap],0 - setne [doremap] - - ; Get pointer to position to render icon. EDI = ptr to destination page. - mov ebx,[this_object] - mov edi,[ebx]GraphicViewPortClass.Offset - mov eax,[ebx]GraphicViewPortClass.Width - add eax,[ebx]GraphicViewPortClass.XAdd - add eax,[ebx]GraphicViewPortClass.Pitch - push eax ; save viewport full width for lower - mul [y_pixel] - add edi,eax - add edi,[x_pixel] - - ; Determine row modulo for advancing to next line. - pop eax ; retrieve viewport width - sub eax,[IconWidth] - mov [modulo],eax - - ; Setup some working variables. - mov ecx,[IconHeight] ; Row counter. - mov eax,[IconWidth] - mov [iwidth],eax ; Stack copy of byte width for easy BP access. - - ; Fetch pointer to start of icon's data. ESI = ptr to icon data. - mov eax,[icon] - mul [IconSize] - mov esi,[StampPtr] - add esi,eax - - ; Determine whether simple icon draw is sufficient or whether the - ; extra remapping icon draw is needed. - cmp [BYTE PTR doremap],0 - je short istranscheck - - ;************************************************************ - ; Complex icon draw -- extended remap. - ; EBX = Palette pointer (ready for XLAT instruction). - ; EDI = Pointer to icon destination in page. - ; ESI = Pointer to icon data. - ; ECX = Number of pixel rows. - ;;; mov edx,[remap] - mov ebx,[remap] - xor eax,eax -xrowloop: - push ecx - mov ecx,[iwidth] - -xcolumnloop: - lodsb - ;;; mov ebx,edx - ;;; add ebx,eax - ;;; mov al,[ebx] ; New real color to draw. - xlatb - or al,al - jz short xskip1 ; Transparency skip check. - mov [edi],al -xskip1: - inc edi - loop xcolumnloop - - pop ecx - add edi,[modulo] - loop xrowloop - jmp short proc_out - - - ;************************************************************ - ; Check to see if transparent or generic draw is necessary. -istranscheck: - mov ebx,[IsTrans] - add ebx,[icon] - cmp [BYTE PTR ebx],0 - jne short rowloop - - ;************************************************************ - ; Fast non-transparent icon draw routine. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. - mov ebx,ecx - shr ebx,2 - mov edx,[modulo] - mov eax,[iwidth] - shr eax,2 -loop1: - mov ecx,eax - rep movsd - add edi,edx - - mov ecx,eax - rep movsd - add edi,edx - - mov ecx,eax - rep movsd - add edi,edx - - mov ecx,eax - rep movsd - add edi,edx - - dec ebx - jnz loop1 - jmp short proc_out - - ;************************************************************ - ; Transparent icon draw routine -- no extended remap. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. -rowloop: - push ecx - mov ecx,[iwidth] - -columnloop: - lodsb - or al,al - jz short skip1 ; Transparency check. - mov [edi],al -skip1: - inc edi - loop columnloop - - pop ecx - add edi,[modulo] - loop rowloop - - ; Cleanup and exit icon drawing routine. -proc_out: - popad - //ret - } -} - - - - -/* -;*********************************************************** -; DRAW_STAMP_CLIP -; -; VOID cdecl MCGA_Draw_Stamp_Clip(VOID *icondata, WORD icon, WORD x_pixel, WORD y_pixel, VOID *remap, LONG min_x, LONG min_y, LONG max_x, LONG max_y); -; -; This routine renders the icon at the given coordinate. -; -; The remap table is a 256 byte simple pixel translation table to use when -; drawing the icon. Transparency check is performed AFTER the remap so it is possible to -; remap valid colors to be invisible (for special effect reasons). -; This routine is fastest when no remap table is passed in. -;* -*/ -void __cdecl Buffer_Draw_Stamp_Clip(void const *this_object, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap, int min_x, int min_y, int max_x, int max_y) -{ - - - unsigned int modulo = 0; - unsigned int iwidth = 0; - unsigned int skip = 0; - unsigned char doremap = 0; - - -/* - ARG this_object:DWORD ; this is a member function - ARG icondata:DWORD ; Pointer to icondata. - ARG icon:DWORD ; Icon number to draw. - ARG x_pixel:DWORD ; X coordinate of icon. - ARG y_pixel:DWORD ; Y coordinate of icon. - ARG remap:DWORD ; Remap table. - ARG min_x:DWORD ; Clipping rectangle boundary - ARG min_y:DWORD ; Clipping rectangle boundary - ARG max_x:DWORD ; Clipping rectangle boundary - ARG max_y:DWORD ; Clipping rectangle boundary - - LOCAL modulo:DWORD ; Modulo to get to next row. - LOCAL iwidth:DWORD ; Icon width (here for speedy access). - LOCAL skip:DWORD ; amount to skip per row of icon data - LOCAL doremap:BYTE ; Should remapping occur? -*/ - __asm { - pushad - cmp [icondata],0 - je proc_out - - ; Initialize the stamp data if necessary. - mov eax,[icondata] - cmp [LastIconset],eax - je short noreset2 - push eax - call Init_Stamps - pop eax // Clean up stack. ST - 12/20/2018 10:42AM -noreset2: - - ; Determine if the icon number requested is actually in the set. - ; Perform the logical icon to actual icon number remap if necessary. - mov ebx,[icon] - cmp [MapPtr],0 - je short notmap2 - mov edi,[MapPtr] - mov bl,[edi+ebx] -notmap2: - cmp ebx,[IconCount] - jae proc_out - mov [icon],ebx ; Updated icon number. - - ; Setup some working variables. - mov ecx,[IconHeight] ; Row counter. - mov eax,[IconWidth] - mov [iwidth],eax ; Stack copy of byte width for easy BP access. - - ; Fetch pointer to start of icon's data. ESI = ptr to icon data. - mov eax,[icon] - mul [IconSize] - mov esi,[StampPtr] - add esi,eax - - ; Update the clipping window coordinates to be valid maxes instead of width & height - ; , and change the coordinates to be window-relative - mov ebx,[min_x] - add [max_x],ebx - add [x_pixel],ebx ; make it window-relative - mov ebx,[min_y] - add [max_y],ebx - add [y_pixel],ebx ; make it window-relative - - ; See if the icon is within the clipping window - ; First, verify that the icon position is less than the maximums - mov ebx,[x_pixel] - cmp ebx,[max_x] - jge proc_out - mov ebx,[y_pixel] - cmp ebx,[max_y] - jge proc_out - ; Now verify that the icon position is >= the minimums - add ebx,[IconHeight] - cmp ebx,[min_y] - jle proc_out - mov ebx,[x_pixel] - add ebx,[IconWidth] - cmp ebx,[min_x] - jle proc_out - - ; Now, clip the x, y, width, and height variables to be within the - ; clipping rectangle - mov ebx,[x_pixel] - cmp ebx,[min_x] - jge nominxclip - ; x < minx, so must clip - mov ebx,[min_x] - sub ebx,[x_pixel] - add esi,ebx ; source ptr += (minx - x) - sub [iwidth],ebx ; icon width -= (minx - x) - mov ebx,[min_x] - mov [x_pixel],ebx - -nominxclip: - mov eax,[IconWidth] - sub eax,[iwidth] - mov [skip],eax - - ; Check for x+width > max_x - mov eax,[x_pixel] - add eax,[iwidth] - cmp eax,[max_x] - jle nomaxxclip - ; x+width is greater than max_x, so must clip width down - mov eax,[iwidth] ; eax = old width - mov ebx,[max_x] - sub ebx,[x_pixel] - mov [iwidth],ebx ; iwidth = max_x - xpixel - sub eax,ebx - add [skip],eax ; skip += (old width - iwidth) -nomaxxclip: - ; check if y < miny - mov eax,[min_y] - cmp eax,[y_pixel] ; if(miny <= y_pixel), no clip needed - jle nominyclip - sub eax,[y_pixel] - sub ecx,eax ; height -= (miny - y) - mul [IconWidth] - add esi,eax ; icon source ptr += (width * (miny - y)) - mov eax,[min_y] - mov [y_pixel],eax ; y = miny -nominyclip: - ; check if (y+height) > max y - mov eax,[y_pixel] - add eax,ecx - cmp eax,[max_y] ; if (y + height <= max_y), no clip needed - jle nomaxyclip - mov ecx,[max_y] ; height = max_y - y_pixel - sub ecx,[y_pixel] -nomaxyclip: - - ; If the remap table pointer passed in is NULL, then flag this condition - ; so that the faster (non-remapping) icon draw loop will be used. - cmp [remap],0 - setne [doremap] - - ; Get pointer to position to render icon. EDI = ptr to destination page. - mov ebx,[this_object] - mov edi,[ebx]GraphicViewPortClass.Offset - mov eax,[ebx]GraphicViewPortClass.Width - add eax,[ebx]GraphicViewPortClass.XAdd - add eax,[ebx]GraphicViewPortClass.Pitch - push eax ; save viewport full width for lower - mul [y_pixel] - add edi,eax - add edi,[x_pixel] - - ; Determine row modulo for advancing to next line. - pop eax ; retrieve viewport width - sub eax,[iwidth] - mov [modulo],eax - - ; Determine whether simple icon draw is sufficient or whether the - ; extra remapping icon draw is needed. - cmp [BYTE PTR doremap],0 - je short istranscheck2 - - ;************************************************************ - ; Complex icon draw -- extended remap. - ; EBX = Palette pointer (ready for XLAT instruction). - ; EDI = Pointer to icon destination in page. - ; ESI = Pointer to icon data. - ; ECX = Number of pixel rows. - mov ebx,[remap] - xor eax,eax -xrowloopc: - push ecx - mov ecx,[iwidth] - -xcolumnloopc: - lodsb - xlatb - or al,al - jz short xskip1c ; Transparency skip check. - mov [edi],al -xskip1c: - inc edi - loop xcolumnloopc - - pop ecx - add edi,[modulo] - add esi,[skip] - loop xrowloopc - jmp short proc_out - - - ;************************************************************ - ; Check to see if transparent or generic draw is necessary. -istranscheck2: - mov ebx,[IsTrans] - add ebx,[icon] - cmp [BYTE PTR ebx],0 - jne short rowloopc - - ;************************************************************ - ; Fast non-transparent icon draw routine. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. - mov ebx,ecx - mov edx,[modulo] - mov eax,[iwidth] - - ; - ; Optimise copy by dword aligning the destination - ; -loop1c: - push eax - //rept 3 // No rept in inline asm. ST - 12/20/2018 10:43AM - test edi,3 - jz aligned - movsb - dec eax - jz finishedit - - test edi,3 - jz aligned - movsb - dec eax - jz finishedit - - test edi,3 - jz aligned - movsb - dec eax - jz finishedit - - //endm -aligned: - mov ecx,eax - shr ecx,2 - rep movsd - mov ecx,eax - and ecx,3 - rep movsb - -finishedit: - add edi,edx - add esi,[skip] - pop eax - - dec ebx - jnz loop1c - jmp short proc_out - - ;************************************************************ - ; Transparent icon draw routine -- no extended remap. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. -rowloopc: - push ecx - mov ecx,[iwidth] - -columnloopc: - lodsb - or al,al - jz short skip1c ; Transparency check. - mov [edi],al -skip1c: - inc edi - loop columnloopc - - pop ecx - add edi,[modulo] - add esi,[skip] - loop rowloopc - - ; Cleanup and exit icon drawing routine. -proc_out: - popad - //ret - } -} - - - - - - - - - - - - - - - VOID __cdecl Buffer_Draw_Line(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color); VOID __cdecl Buffer_Fill_Rect(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color); VOID __cdecl Buffer_Remap(void * thisptr, int sx, int sy, int width, int height, void *remap); @@ -4169,7 +3434,7 @@ extern "C" long __cdecl Buffer_To_Page(int x, int y, int w, int h, void *buffer, yend = min(yend, vp.Get_Height() - 1); int pitch = vp.Get_Pitch() + vp.Get_Width() + vp.Get_XAdd(); - uint8_t* dst = y * pitch + x + (uint8_t*)(vp.Get_Offset()); + uint8_t* dst = (y * 4) * pitch + (x * 4) + (uint8_t*)(vp.Get_Offset()); uint8_t* src = xoffset + w * yoffset + static_cast(buffer); // int dst_pitch = x_pos + pitch - xend; // int src_pitch = x_pos + width - xend; @@ -4178,9 +3443,9 @@ extern "C" long __cdecl Buffer_To_Page(int x, int y, int w, int h, void *buffer, // blit while (lines--) { - memcpy(dst, src, blit_width); + FastScanlinePaletteBlit(dst, src, blit_width); src += w; - dst += pitch; + dst += pitch * 4; } return 0; diff --git a/code/REDALERT/WIN32LIB/GBUFFER.CPP b/code/REDALERT/WIN32LIB/GBUFFER.CPP index 946545d..19d7cf8 100644 --- a/code/REDALERT/WIN32LIB/GBUFFER.CPP +++ b/code/REDALERT/WIN32LIB/GBUFFER.CPP @@ -172,7 +172,7 @@ void GraphicViewPortClass::Attach(GraphicBufferClass *gbuffer, int x, int y, int /*======================================================================*/ /* Get a pointer to the top left edge of the buffer. */ /*======================================================================*/ - Offset = gbuffer->Get_Offset() + ((gbuffer->Get_Width()+gbuffer->Get_Pitch()) * y) + x; + Offset = gbuffer->Get_Offset() + ((gbuffer->Get_Width()+gbuffer->Get_Pitch()) * y * 4) + (x * 4); /*======================================================================*/ /* Copy over all of the variables that we need to store. */ @@ -237,7 +237,7 @@ BOOL GraphicViewPortClass::Change(int x, int y, int w, int h) *=========================================================================*/ void GraphicBufferClass::DD_Init(GBC_Enum flags) { - rawCpuBuffer = new unsigned char[Width * Height]; + rawCpuBuffer = new unsigned char[Width * Height * 4]; Allocated = FALSE; // even if system alloced, dont flag it cuz // we dont want it freed. @@ -280,7 +280,7 @@ void GraphicBufferClass::Init(int w, int h, void *buffer, long size, GBC_Enum fl Buffer= (BYTE *)buffer; // point to it and mark Allocated = FALSE; // it as user allocated } else { - if (!Size) Size = w*h; + if (!Size) Size = w*h*4; Buffer = new BYTE[Size]; // otherwise allocate it and Allocated = TRUE; // mark it system alloced } diff --git a/code/REDALERT/WIN32LIB/GBUFFER.H b/code/REDALERT/WIN32LIB/GBUFFER.H index 3f8b3c1..ec7fb5d 100644 --- a/code/REDALERT/WIN32LIB/GBUFFER.H +++ b/code/REDALERT/WIN32LIB/GBUFFER.H @@ -138,7 +138,31 @@ #include "iconcach.h" #include "../NEWBLIT.H" +#include + extern unsigned char* backbuffer_data_raw; +extern unsigned char backbuffer_palette[768]; +__forceinline void FastScanlinePaletteBlit(uint8_t* dst, uint8_t* src, int length) { + for (int i = 0; i < length; i++) { + uint8_t color = src[i]; + if (color == 0) + continue; + + dst[(i * 4) + 0] = backbuffer_palette[(color * 3) + 0]; + dst[(i * 4) + 1] = backbuffer_palette[(color * 3) + 1]; + dst[(i * 4) + 2] = backbuffer_palette[(color * 3) + 2]; + dst[(i * 4) + 3] = 255; + } +} + +__forceinline void FastScanlinePaletteBlit(uint8_t* dst, uint8_t color, int length) { + for (int i = 0; i < length; i++) { + dst[(i * 4) + 0] = backbuffer_palette[(color * 3) + 0]; + dst[(i * 4) + 1] = backbuffer_palette[(color * 3) + 1]; + dst[(i * 4) + 2] = backbuffer_palette[(color * 3) + 2]; + dst[(i * 4) + 3] = 255; + } +} #ifndef FUNCTION_H //#pragma off (unreferenced) @@ -268,6 +292,7 @@ class GraphicViewPortClass { int dy_pixel, int pixel_width, int pixel_height, BOOL trans = FALSE); HRESULT Blit( GraphicViewPortClass& dest, int dx, int dy, BOOL trans = FALSE); HRESULT Blit( GraphicViewPortClass& dest, BOOL trans = FALSE); + HRESULT BlitLegacy(GraphicViewPortClass& dest, BOOL trans = FALSE); HRESULT Blit( VideoViewPortClass& dest, int x_pixel, int y_pixel, int dx_pixel, int dy_pixel, int pixel_width, int pixel_height, BOOL trans = FALSE); HRESULT Blit( VideoViewPortClass& dest, int dx, int dy, BOOL trans = FALSE); @@ -796,6 +821,40 @@ inline HRESULT GraphicViewPortClass::Blit( GraphicViewPortClass& dest, int dx, i } +/*************************************************************************** + * GVPC::BLIT -- stub 3 to call curr graphic mode Blit to GVPC * + * * + * INPUT: * + * * + * OUTPUT: * + * * + * WARNINGS: * + * * + * HISTORY: * + * 01/06/1995 PWG : Created. * + *=========================================================================*/ +inline HRESULT GraphicViewPortClass::BlitLegacy(GraphicViewPortClass& dest, BOOL trans) +{ + HRESULT return_code = 0; + + + if (Lock()) { + if (dest.Lock()) { + + return_code = (Linear_Blit_To_Linear_Pal(this, &dest, 0, 0 + , 0, 0 + , Width, Height, trans)); + + } + dest.Unlock(); + } + Unlock(); + + return (return_code); + +} + + /*************************************************************************** * GVPC::BLIT -- stub 3 to call curr graphic mode Blit to GVPC * * * @@ -810,7 +869,7 @@ inline HRESULT GraphicViewPortClass::Blit( GraphicViewPortClass& dest, int dx, i *=========================================================================*/ inline HRESULT GraphicViewPortClass::Blit( GraphicViewPortClass& dest, BOOL trans) { - HRESULT return_code=0; + HRESULT return_code = 0; if (Lock()) { @@ -1063,28 +1122,28 @@ inline void GraphicViewPortClass::Draw_Stamp(void const * icondata, int icon, in int cache_index=-1; int drewit = 0; - if (IconCacheAllowed){ - if (IsDirectDraw){ - if (!remap){ - cache_index = Is_Icon_Cached(icondata,icon); - } - - if (cache_index != -1){ - if (CachedIcons[cache_index].Get_Is_Cached() ){ - CachedIcons[cache_index].Draw_It (GraphicBuff->Get_DD_Surface() , x_pixel, y_pixel, - WindowList[clip_window][WINDOWX] + XPos, - WindowList[clip_window][WINDOWY] +YPos, - WindowList[clip_window][WINDOWWIDTH], - WindowList[clip_window][WINDOWHEIGHT]); - CachedIconsDrawn++; - drewit = 1; - } - } - } - } + //if (IconCacheAllowed){ + // if (IsDirectDraw){ + // if (!remap){ + // cache_index = Is_Icon_Cached(icondata,icon); + // } + // + // if (cache_index != -1){ + // if (CachedIcons[cache_index].Get_Is_Cached() ){ + // CachedIcons[cache_index].Draw_It (GraphicBuff->Get_DD_Surface() , x_pixel, y_pixel, + // WindowList[clip_window][WINDOWX] + XPos, + // WindowList[clip_window][WINDOWY] +YPos, + // WindowList[clip_window][WINDOWWIDTH], + // WindowList[clip_window][WINDOWHEIGHT]); + // CachedIconsDrawn++; + // drewit = 1; + // } + // } + // } + //} - if (drewit == 0) { + { if (Lock()){ UnCachedIconsDrawn++; extern int ScreenHeight, ScreenWidth; @@ -1114,7 +1173,10 @@ inline VOID GraphicViewPortClass::Draw_Line(int sx, int sy, int dx, int dy, unsi // Buffer_Draw_Line(this, sx, sy, dx, dy, color); //} //Unlock(); - + sx += XPos; + sy += YPos; + dx += XPos; + dy += YPos; GL_DrawLine(color, sx, sy, dx, dy); } @@ -1132,14 +1194,11 @@ inline VOID GraphicViewPortClass::Draw_Line(int sx, int sy, int dx, int dy, unsi *=========================================================================*/ inline VOID GraphicViewPortClass::Fill_Rect(int sx, int sy, int dx, int dy, unsigned char color) { -// jmarshall - // Still needed for gameplay. - if (Lock()) { - Buffer_Fill_Rect(this, sx, sy, dx, dy, color); - Unlock(); - } - //GL_FillRect(color, sx, sy, dx - sx, dy - sy); -// jmarshall end + sx += XPos; + sy += YPos; + dx += XPos; + dy += YPos; + GL_FillRect(color, sx - 1, sy - 1, (dx - sx) + 1, ((dy - sy) + 1)); } diff --git a/code/REDALERT/WIN32LIB/MOUSEWW.CPP b/code/REDALERT/WIN32LIB/MOUSEWW.CPP index e41649d..da56f02 100644 --- a/code/REDALERT/WIN32LIB/MOUSEWW.CPP +++ b/code/REDALERT/WIN32LIB/MOUSEWW.CPP @@ -252,7 +252,7 @@ void WWMouseClass::RenderMouse(void) { ImGui::SetMouseCursor(ImGuiMouseCursor_None); - ImGui::GetForegroundDrawList()->AddImage((ImTextureID)current_cursor->image, mi, ma); + ImGui::GetForegroundDrawList()->AddImage((ImTextureID)current_cursor->image[0][0], mi, ma); } void WWMouseClass::Low_Show_Mouse(int x, int y) diff --git a/code/REDALERT/WINSTUB.CPP b/code/REDALERT/WINSTUB.CPP index 5ff2587..ccab983 100644 --- a/code/REDALERT/WINSTUB.CPP +++ b/code/REDALERT/WINSTUB.CPP @@ -45,6 +45,7 @@ #include "examples/imgui_impl_sdl.h" #include "function.h" #include "il/il.h" +#include "il/ilu.h" #include "image.h" #ifdef WINSOCK_IPX @@ -62,9 +63,11 @@ #include #include +#include "HOUSECOLOR.H" +#include "IMGUTIL.H" GLuint backbuffer_texture = -1; -byte* backbuffer_data; +//byte* backbuffer_data; unsigned char* backbuffer_data_raw; byte backbuffer_palette[768]; HWND MainWindow; @@ -73,6 +76,8 @@ SDL_Window* game_window; SDL_GLContext game_context; int OverlappedVideoBlits = 0; +extern std::vector renderedFrameObjects; + bool renderConsole = false; void (*Misc_Focus_Loss_Function)(void) = nullptr; @@ -83,16 +88,86 @@ void (*Imgui_Dialog_Function)(void) = nullptr; bool show_oldframebuffer = true; void Show_OldFrameBuffer(bool show) { show_oldframebuffer = show; - memset(backbuffer_data, 0, ScreenWidth * ScreenHeight * 4); + memset(backbuffer_data_raw, 0, ScreenWidth * ScreenHeight * 4); } std::vector loaded_images; -Image_t* Image_LoadImage(const char* name) { - // Check to see if the image is already loaded. - for (int i = 0; i < loaded_images.size(); i++) { - if (!strcmp(loaded_images[i]->name, name)) { - return loaded_images[i]; +unsigned char* Draw_Dropsample(const unsigned char* in, int inwidth, int inheight, int outwidth, int outheight); + +/* +================ +return a hash value for the filename +================ +*/ +static int64_t generateHashValue(const char* fname, const int size) { + uint32_t hash = 0x811c9dc5; + uint32_t prime = 0x1000193; + + for (int i = 0; i < size; ++i) { + uint8_t value = fname[i]; + hash = hash ^ value; + hash *= prime; + } + + return hash; +} + +/* +================ +Image_WriteTGA +================ +*/ +void Image_WriteTGA(const char* filename, const byte* data, int width, int height, bool flipVertical) { + byte* buffer; + int i; + int bufferSize = width * height * 4 + 18; + int imgStart = 18; + + buffer = (byte*)malloc(bufferSize); + memset(buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = width & 255; + buffer[13] = width >> 8; + buffer[14] = height & 255; + buffer[15] = height >> 8; + buffer[16] = 32; // pixel size + + if (!flipVertical) { + buffer[17] = (1 << 5); // flip bit, for normal top to bottom raster order + } + + // swap rgba to bgra + for (i = imgStart; i < bufferSize; i += 4) { + buffer[i] = data[i - imgStart + 2]; // blue + buffer[i + 1] = data[i - imgStart + 1]; // green + buffer[i + 2] = data[i - imgStart + 0]; // red + buffer[i + 3] = data[i - imgStart + 3]; // alpha + } + char temp[512]; + strcpy(temp, filename); + COM_SetExtension(temp, strlen(temp), ".tga"); + FILE* f = fopen(temp, "wb"); + fwrite(buffer, 1, bufferSize, f); + fclose(f); + + free(buffer); +} + + +static char* Image_GetGeneratedName(Image_t* image, const char* name, int houseid, int animid, int64_t hash) { + static char generatedFileName[1024]; + sprintf(generatedFileName, "cache/%d.%d.%d.tga", hash, houseid, animid); + return &generatedFileName[0]; +} + +static bool Image_loadHDImage(Image_t *image, const char* name, int houseid, int animid, int64_t hash, bool writeGenerated) { + // Check to see if we can load a generated image first. + // We only generate images that need a houseid + if (!writeGenerated && houseid >= 0) { + char* generatedImageName = Image_GetGeneratedName(image, name, houseid, animid, hash); + if (Image_loadHDImage(image, generatedImageName, houseid, animid, hash, true)) { + return true; } } @@ -100,7 +175,14 @@ Image_t* Image_LoadImage(const char* name) { ilGenImages(1, &ImageName); ilBindImage(ImageName); if (!ilLoadImage(name)) { - return NULL; + ilDeleteImages(1, &ImageName); + return false; + } + + bool swapBGR = false; + if (strstr(name, ".TGA")) { + iluFlipImage(); + swapBGR = true; } ILuint Width, Height, Bpp; @@ -109,12 +191,28 @@ Image_t* Image_LoadImage(const char* name) { Bpp = ilGetInteger(IL_IMAGE_BPP); ILubyte* Data = ilGetData(); + if (Bpp == 4 && houseid != -1 && !writeGenerated) { + //Buffer_Enable_HD_Texture(true); + //Data = Draw_Dropsample(Data, Width, Height, Width / 2, Height / 2); + //Buffer_Enable_HD_Texture(false); + //Width = Width / 2; + //Height = Height / 2; + for (int i = 0; i < Width * Height; i++) { + RenderTeamPalette(&Data[i * 4], *houseColors[houseid]); + } + } + GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); if (Bpp == 4) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data); + if (swapBGR) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, Data); + } + else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data); + } } else if (Bpp == 3) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, Data); @@ -126,20 +224,141 @@ Image_t* Image_LoadImage(const char* name) { assert(!"Unknown BPP in image!"); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ilDeleteImages(1, &ImageName); - - Image_t* image = new Image_t(); + strcpy(image->name, name); - image->image = texture; - image->width = Width; - image->height = Height; + + if(houseid == -1) + image->image[0][animid] = texture; + else + image->image[houseid][animid] = texture; + image->namehash = hash; + image->renderwidth = image->width = Width; + image->renderheight = image->height = Height; + //image->buffer[houseid][animid] = new unsigned char[Width * Height * Bpp]; + //memcpy(image->buffer[houseid][animid], Data, Width * Height * Bpp); + + if (!writeGenerated && Bpp == 4 && houseid >= 0) { + char* generatedImageName = Image_GetGeneratedName(image, name, houseid, animid, hash); + Image_WriteTGA(generatedImageName, Data, Width, Height, false); + } + + ilDeleteImages(1, &ImageName); + + return true; +} + +Image_t* Image_LoadImage(const char* name, bool loadAnims, bool loadHouseColor) { + int64_t hash = generateHashValue(name, strlen(name)); + + int image_table_size = loaded_images.size(); + if (image_table_size > 0) + { + Image_t** image_table = &loaded_images[0]; + + // Check to see if the image is already loaded. + for (int i = 0; i < image_table_size; i++) { + if (image_table[i]->namehash == hash) { + return image_table[i]; + } + } + } + Image_t* image = new Image_t(); + + if (!loadAnims) { + unsigned char remap[3] = { 0, 0, 0 }; + if (!Image_loadHDImage(image, name, -1, 0, hash, false)) { + delete image; + return NULL; + } + } + else { + byte* palette = (byte *)CCPalette.Get_Data(); + for (int i = 0; i < MAX_MPLAYER_COLORS; i++) { + if (!Image_loadHDImage(image, name, i, 0, hash, false)) { + delete image; + return NULL; + } + } + } + loaded_images.push_back(image); return image; } +Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char *data, unsigned char* remap) { + int64_t hash = generateHashValue(name, strlen(name)); + + int image_table_size = loaded_images.size(); + if (image_table_size > 0) + { + Image_t** image_table = &loaded_images[0]; + + // Check to see if the image is already loaded. + for (int i = 0; i < image_table_size; i++) { + if (image_table[i]->namehash == hash) { + return image_table[i]; + } + } + } + + unsigned char* ccpalete = (unsigned char*)CCPalette.Get_Data(); + + Image_t* image = new Image_t(); + unsigned char *buffer = new unsigned char[Width * Height * 4]; + + for (int i = 0; i < Width * Height; i++) { + unsigned char c = data[i]; + if (remap) { + c = remap[c]; + } + + unsigned char r = ccpalete[(c * 3) + 0] << 2; + unsigned char g = ccpalete[(c * 3) + 1] << 2; + unsigned char b = ccpalete[(c * 3) + 2] << 2; + unsigned char a = 0; + + if ((r == 84 && g == 252 && b == 84) || (r == 0 && g == 168 && b == 0)) { + r = 0; + g = 0; + b = 0; + a = 128; + } + else if (c != 0) { + a = 255; + } + + + buffer[(i * 4) + 0] = r; + buffer[(i * 4) + 1] = g; + buffer[(i * 4) + 2] = b; + buffer[(i * 4) + 3] = a; + } + + + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + + strcpy(image->name, name); + image->image[0][0] = texture; + image->numAnimFrames = -1; + image->namehash = hash; + image->renderwidth = image->width = Width; + image->renderheight = image->height = Height; + loaded_images.push_back(image); + delete buffer; + return image; +} + + BOOL Set_Video_Mode(HWND hwnd, int w, int h, int bits_per_pixel) { // Todo implement resoluton scaling. return true; // Always return true; @@ -180,19 +399,21 @@ void ImGui_NewFrame(void) { ImGui::NewFrame(show_oldframebuffer); ImGui_ImplSDL2_NewFrame(game_window); + + renderedFrameObjects.clear(); } void Device_Present(void) { // Rasterize the palette. - for (int i = 0; i < ScreenWidth * ScreenHeight; i++) { - backbuffer_data[(i * 4) + 0] = backbuffer_palette[(backbuffer_data_raw[i] * 3) + 0]; - backbuffer_data[(i * 4) + 1] = backbuffer_palette[(backbuffer_data_raw[i] * 3) + 1]; - backbuffer_data[(i * 4) + 2] = backbuffer_palette[(backbuffer_data_raw[i] * 3) + 2]; - backbuffer_data[(i * 4) + 3] = 255; - } + //for (int i = 0; i < ScreenWidth * ScreenHeight; i++) { + // backbuffer_data[(i * 4) + 0] = backbuffer_palette[(backbuffer_data_raw[i] * 3) + 0]; + // backbuffer_data[(i * 4) + 1] = backbuffer_palette[(backbuffer_data_raw[i] * 3) + 1]; + // backbuffer_data[(i * 4) + 2] = backbuffer_palette[(backbuffer_data_raw[i] * 3) + 2]; + // backbuffer_data[(i * 4) + 3] = 255; + //} glBindTexture(GL_TEXTURE_2D, backbuffer_texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ScreenWidth, ScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, backbuffer_data); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ScreenWidth, ScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, backbuffer_data_raw); bool ScreenActive; ImGuiStyle& style = ImGui::GetStyle(); @@ -422,15 +643,13 @@ void Create_Main_Window ( HANDLE instance , int command_show , int width , int h glGenTextures(1, &backbuffer_texture); glBindTexture(GL_TEXTURE_2D, backbuffer_texture); + // Give the image to OpenGL + backbuffer_data_raw = new byte[width * height * 4]; + memset(backbuffer_data_raw, 0, width * height * 4); - // Give the image to OpenGL - backbuffer_data = new byte[width * height * 4]; - memset(backbuffer_data, 0, width * height * 4); - backbuffer_data_raw = new byte[width * height]; - memset(backbuffer_data_raw, 0, width * height); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, backbuffer_data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, backbuffer_data_raw); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glewInit(); @@ -669,6 +888,9 @@ void WWSDL_ProcessEvents(KeyNumType& key, int& flags, bool presentBuffer) { extern int mousex, mousey; bool leftMouseProcessed = false; + key = KN_NONE; + flags = 0; + SDL_GetMouseState(&mousex, &mousey); Keyboard->MouseQX = mousex; @@ -677,7 +899,8 @@ void WWSDL_ProcessEvents(KeyNumType& key, int& flags, bool presentBuffer) { // if (flags == LEFTRELEASE || flags == RIGHTRELEASE) // flags = 0; - SDL_Event event; + static SDL_Event event; + memset(&event, 0, sizeof(SDL_Event)); while (SDL_PollEvent(&event)) { switch (event.type) { @@ -720,10 +943,12 @@ void WWSDL_ProcessEvents(KeyNumType& key, int& flags, bool presentBuffer) { leftMouseProcessed = true; numFramesLMouse++; key = KN_LMOUSE; + Keyboard->Put_Element(KN_LMOUSE); } else if (event.button.button == SDL_BUTTON_RIGHT) { numFramesLMouse = 0; flags = GadgetClass::RIGHTPRESS; + Keyboard->Put_Element(KN_RMOUSE); key = KN_RMOUSE; } break; @@ -744,12 +969,12 @@ void WWSDL_ProcessEvents(KeyNumType& key, int& flags, bool presentBuffer) { renderConsole = !renderConsole; if (renderConsole) { - ShowCursor(TRUE); - Hide_Mouse(); + // ShowCursor(TRUE); + // Hide_Mouse(); } else { - ShowCursor(FALSE); - Show_Mouse(); + // ShowCursor(FALSE); + // Show_Mouse(); } break; } diff --git a/code/REDALERT/vectormath.h b/code/REDALERT/vectormath.h new file mode 100644 index 0000000..3c5c405 --- /dev/null +++ b/code/REDALERT/vectormath.h @@ -0,0 +1,2020 @@ +//-------------------------------------------------------------------------------------- +// Copyright 2013 Intel Corporation +// All Rights Reserved +// +// Permission is granted to use, copy, distribute and prepare derivative works of this +// software for any purpose and without fee, provided, that the above copyright notice +// and this statement appear in all copies. Intel makes no representations about the +// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS." +// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY, +// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, +// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not +// assume any responsibility for any errors which may appear in this software nor any +// responsibility to update it. +//-------------------------------------------------------------------------------------- + +#ifndef __CPUTMath_h__ +#define __CPUTMath_h__ +#include + +/* + * Constants + */ +static const float kEpsilon = 0.00001f; +static const float kPi = 3.14159265358979323846f; +static const float k2Pi = kPi*2.0f; +static const float kPiDiv2 = kPi/2.0f; +static const float kInvPi = 1.0f/kPi; +static const float kDegToRad = (kPi/180.0f); +static const float kRadToDeg = (180.0f/kPi); +static inline float DegToRad( float fDeg ) { return fDeg * kDegToRad; } +static inline float RadToDeg( float fRad ) { return fRad * kRadToDeg; } + +template +static inline void Swap(T &a, T &b) +{ + T t = b; + b = a; + a = t; +} + +static inline double InvSqrt(const double x) +{ + return 1.0 / sqrt(x); +} + +struct float2; +struct float3; +struct float4; + +/**************************************\ +float2 +\**************************************/ +struct float2 +{ + union + { + struct + { + float x; + float y; + }; + float f[2]; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float2() {} + explicit float2(float f) : x(f), y(f) { } + explicit float2(float _x, float _y) : x(_x), y(_y) { } + explicit float2(float* f) : x(f[0]), y(f[1]) { } + float2(const float2 &v) : x(v.x), y(v.y) { } + const float2 &operator=(const float2 &v) + { + x = v.x; + y = v.y; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + float2 operator+(const float2 &r) const + { + return float2(x+r.x, y+r.y); + } + const float2 &operator+=(const float2 &r) + { + x += r.x; + y += r.y; + return *this; + } + float2 operator-(const float2 &r) const + { + return float2(x-r.x, y-r.y); + } + const float2 &operator-=(const float2 &r) + { + x -= r.x; + y -= r.y; + return *this; + } + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float2 operator+(float f) const + { + return float2(x+f, y+f); + } + const float2 &operator+=(float f) + { + x += f; + y += f; + return *this; + } + float2 operator-(float f) const + { + return float2(x-f, y-f); + } + const float2 &operator-=(float f) + { + x -= f; + y -= f; + return *this; + } + float2 operator*(float f) const + { + return float2(x*f, y*f); + } + const float2 &operator*=(float f) + { + x *= f; + y *= f; + return *this; + } + float2 operator/(float f) const + { + return float2(x/f, y/f); + } + const float2 &operator/=(float f) + { + x /= f; + y /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float2 &r) const + { + return (x==r.x && y == r.y); + } + bool operator!=(const float2 &r) const + { + return !(*this == r); + } + + // Hadd + float hadd(void) const + { + return x + y; + } + + // Length + float lengthSq(void) const + { + return x*x + y*y; + } + float length(void) const + { + return sqrtf(lengthSq()); + } + void normalize(void) + { + *this /= length(); + } +}; + +inline float dot2(const float2 &l, const float2 &r) +{ + return l.x*r.x + l.y*r.y; +} + +inline float2 normalize(const float2 &v) +{ + float length = v.length(); + return v / length; +} + + + + + + + + +/**************************************\ +float3 +\**************************************/ +struct float3 +{ + union + { + struct + { + float x; + float y; + float z; + }; + float f[3]; + }; + + static const float3 Left; + static const float3 Right; + static const float3 Up; + static const float3 Down; + static const float3 Forward; + static const float3 Backward; + static const float3 ZeroF; + + /***************************************\ + | Constructors | + \***************************************/ + float3() {} + explicit float3(float f) : x(f), y(f), z(f) { } + explicit float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) { } + explicit float3(float* f) : x(f[0]), y(f[1]), z(f[2]) { } + float3(const float3 &v) : x(v.x), y(v.y), z(v.z) { } + float3(const float4 &v); + const float3 &operator=(const float3 &v) + { + x = v.x; + y = v.y; + z = v.z; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + float3 operator+(const float3 &r) const + { + return float3(x+r.x, y+r.y, z+r.z); + } + const float3 &operator+=(const float3 &r) + { + x += r.x; + y += r.y; + z += r.z; + return *this; + } + float3 operator-(const float3 &r) const + { + return float3(x-r.x, y-r.y, z-r.z); + } + float operator[](const int index) const { + return (&x)[index]; + } + + + float operator*(const float3 &a) const + { + return x * a.x + y * a.y + z * a.z; + } + + float Dot(const float3 &a) const + { + return x * a.x + y * a.y + z * a.z; + } + + static float Dot(const float3 &a, const float3 &b) + { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + + + float &operator[](const int index) { + return (&x)[index]; + } + const float3 &operator-=(const float3 &r) + { + x -= r.x; + y -= r.y; + z -= r.z; + return *this; + } + + float NormalizeFast() + { + float sqrLength, invLength; + + sqrLength = x * x + y * y + z * z; + invLength = InvSqrt(sqrLength); + x *= invLength; + y *= invLength; + z *= invLength; + return invLength * sqrLength; + } + + float3 operator*(float3 &r) + { + return float3(x*r.x, y*r.y, z*r.z); + } + + + float3 operator*(const float a) const { + return float3(x * a, y * a, z * a); + } + + friend float3 operator*(const float a, const float3 b) { + return float3(b.x * a, b.y * a, b.z * a); + } + + const float3 &operator*=(const float3 &r) + { + x *= r.x; + y *= r.y; + z *= r.z; + return *this; + } + float3 &operator*=(float3 &r) + { + x *= r.x; + y *= r.y; + z *= r.z; + return *this; + } + bool Compare(const float3 &a) const { + return ((x == a.x) && (y == a.y) && (z == a.z)); + } + + bool Compare(const float3 &a, const float epsilon) const { + if (fabs(x - a.x) > epsilon) { + return false; + } + + if (fabs(y - a.y) > epsilon) { + return false; + } + + if (fabs(z - a.z) > epsilon) { + return false; + } + + return true; + } + float3 operator/(const float3 &r) const + { + return float3(x/r.x, y/r.y, z/r.z); + } + const float3 &operator/=(const float3 &r) + { + x /= r.x; + y /= r.y; + z /= r.z; + return *this; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float3 operator+(float f) const + { + return float3(x+f, y+f, z+f); + } + const float3 &operator+=(float f) + { + x += f; + y += f; + z += f; + return *this; + } + float3 operator-(float f) const + { + return float3(x-f, y-f, z-f); + } + const float3 &operator-=(float f) + { + x -= f; + y -= f; + z -= f; + return *this; + } + + + const float3 &operator*=(float f) + { + x *= f; + y *= f; + z *= f; + return *this; + } + float3 operator/(float f) const + { + return float3(x/f, y/f, z/f); + } + const float3 &operator/=(float f) + { + x /= f; + y /= f; + z /= f; + return *this; + } + + void Zero() + { + x = 0; + y = 0; + z = 0; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float3 &r) const + { + return x==r.x &&y == r.y &&z == r.z; + } + bool operator!=(const float3 &r) const + { + return !(*this == r); + } + + // Hadd + float hadd(void) const + { + return x + y + z; + } + + // Length + float lengthSq(void) const + { + return x*x + y*y + z*z; + } + float length(void) const + { + return sqrtf(lengthSq()); + } + + float3 normalize(void) + { + return (*this /= length()); + } + + float NormalizeSelf() { + float sqrLength, invLength; + + sqrLength = x * x + y * y + z * z; + invLength = InvSqrt(sqrLength); + x *= invLength; + y *= invLength; + z *= invLength; + return invLength * sqrLength; + } + float3 Cross(const float3 &a) const + { + return float3(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x); + } + + float3 &Cross(const float3 &a, const float3 &b) + { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + + return *this; + } +}; + +inline float dot3(const float3 &l, const float3 &r) +{ + return l.x*r.x + l.y*r.y + l.z*r.z; +} +inline float3 cross3(const float3 &l, const float3 &r) +{ + return float3( l.y*r.z-l.z*r.y, + l.z*r.x-l.x*r.z, + l.x*r.y-l.y*r.x); +} +inline float3 normalize(const float3 &v) +{ + float length = v.length(); + return v / length; +} + +inline float3 abs3( const float3 &l ) +{ + float3 tmp; + tmp.x = fabs(l.x); + tmp.y = fabs(l.y); + tmp.z = fabs(l.z); + return tmp; +} + + +/**************************************\ +float4 +\**************************************/ +__declspec(align(16)) struct float4 +{ + union + { + struct + { + float x; + float y; + float z; + float w; + }; + float f[4]; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float4() {} + explicit float4(float f) : x(f), y(f), z(f), w(f) { } + explicit float4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } + explicit float4(float* f) : x(f[0]), y(f[1]), z(f[2]), w(f[3]) { } + float4(const float4 &v) : x(v.x), y(v.y), z(v.z), w(v.w) { } + float4(const float3 &v, float _w) : x(v.x), y(v.y), z(v.z), w(_w) { } + const float4 &operator=(const float4 &v) + { + x = v.x; + y = v.y; + z = v.z; + w = v.w; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + float4 operator+(const float4 &r) const + { + return float4(x+r.x, y+r.y, z+r.z, w+r.w); + } + const float4 &operator+=(const float4 &r) + { + x += r.x; + y += r.y; + z += r.z; + w += r.w; + return *this; + } + float4 operator-(const float4 &r) const + { + return float4(x-r.x, y-r.y, z-r.z, w-r.w); + } + const float4 &operator-=(const float4 &r) + { + x -= r.x; + y -= r.y; + z -= r.z; + w -= r.w; + return *this; + } + float4 operator*(const float4 &r) const + { + return float4(x*r.x, y*r.y, z*r.z, w*r.w); + } + const float4 &operator*=(const float4 &r) + { + x *= r.x; + y *= r.y; + z *= r.z; + w *= r.w; + return *this; + } + float4 operator/(const float4 &r) const + { + return float4(x/r.x, y/r.y, z/r.z, w/r.w); + } + const float4 &operator/=(const float4 &r) + { + x /= r.x; + y /= r.y; + z /= r.z; + w /= r.w; + return *this; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float4 operator+(float f) const + { + return float4(x+f, y+f, z+f, w+f); + } + const float4 &operator+=(float f) + { + x += f; + y += f; + z += f; + return *this; + } + float4 operator-(float f) const + { + return float4(x-f, y-f, z-f, w-f); + } + const float4 &operator-=(float f) + { + x -= f; + y -= f; + z -= f; + w -= f; + return *this; + } + float4 operator*(float f) const + { + return float4(x*f, y*f, z*f, w*f); + } + const float4 &operator*=(float f) + { + x *= f; + y *= f; + z *= f; + w *= f; + return *this; + } + float4 operator/(float f) const + { + return float4(x/f, y/f, z/f, w/f); + } + const float4 &operator/=(float f) + { + x /= f; + y /= f; + z /= f; + w /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float4 &r) const + { + return x==r.x && y == r.y && z == r.z && w == r.w; + } + bool operator!=(const float4 &r) const + { + return !(*this == r); + } + + // Hadd + float hadd(void) const + { + return x + y + z + w; + } + + // Length + float lengthSq(void) const + { + return x*x + y*y + z*z + w*w; + } + float length(void) const + { + return sqrtf(lengthSq()); + } + void normalize(void) + { + *this /= length(); + } +}; + +inline float dot4(const float4 &l, const float4 &r) +{ + return l.x*r.x + l.y*r.y + l.z*r.z + l.w*r.w; +} +inline float4 normalize(const float4 &v) +{ + float length = v.length(); + return v / length; +} + +inline float3::float3(const float4 &v) : x(v.x), y(v.y), z(v.z) { } + + +/**************************************\ +float3x3 +\**************************************/ +struct float4x4; +struct float3x3 +{ + struct + { + float3 r0; + float3 r1; + float3 r2; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float3x3() {} + explicit float3x3(float f) : r0(f), r1(f), r2(f) { } + explicit float3x3(float* f) : r0(f+0), r1(f+3), r2(f+6) { } + float3x3(const float3 &_r0, const float3 &_r1, const float3 &_r2) : r0(_r0), r1(_r1), r2(_r2) { } + float3x3(float _m00, float _m01, float _m02, + float _m10, float _m11, float _m12, + float _m20, float _m21, float _m22) + : r0(_m00,_m01,_m02) + , r1(_m10,_m11,_m12) + , r2(_m20,_m21,_m22) + { + } + float3x3(const float4x4 &m); + const float3x3 &operator=(const float3x3 &m) + { + r0 = m.r0; + r1 = m.r1; + r2 = m.r2; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + + #define MTX3_INDEX(f,r,c) ((f)[(r*3)+c]) + inline float3x3 operator*(const float3x3 &r) const + { + float3x3 m(1,0,0,0,1,0,0,0,1); + + const float* left = (const float*)&this->r0; + const float* right = (const float*)&r.r0; + float* result = (float*)&m; + + int ii, jj, kk; + for(ii=0; ii<3; ++ii) /* row */ + { + for(jj=0; jj<3; ++jj) /* column */ + { + float sum = MTX3_INDEX(left,ii,0)*MTX3_INDEX(right,0,jj); + for(kk=1; kk<3; ++kk) + { + sum += (MTX3_INDEX(left,ii,kk)*MTX3_INDEX(right,kk,jj)); + } + MTX3_INDEX(result,ii,jj) = sum; + } + } + return m; + } + #undef MTX3_INDEX + + inline float3 operator*(const float3 &v) const + { + float3 a; + + a.x = (r0*v); + a.y = (r1*v); + a.z = (r2*v); + + return a; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float3x3 operator+(float f) const + { + return float3x3(r0+f, r1+f, r2+f); + } + + float3 const &operator[](int index) const { + //assert( ( index >= 0 ) && ( index < 3 ) ); + return (&r0)[index]; + } + + float3 &operator[](int index) { + //assert( ( index >= 0 ) && ( index < 3 ) ); + return (&r0)[index]; + } + + const float3x3 &operator+=(float f) + { + r0 += f; + r1 += f; + r2 += f; + return *this; + } + + + friend float3 operator*(const float3 &vec, const float3x3 &mat) { + return mat * vec; + } + + friend float3x3 operator*(const float a, const float3x3 &mat) { + return mat * a; + } + + friend float3 &operator*=(float3 &vec, const float3x3 &mat) { + float x = mat[0].x * vec.x + mat[1].x * vec.y + mat[2].x * vec.z; + float y = mat[0].y * vec.x + mat[1].y * vec.y + mat[2].y * vec.z; + vec.z = mat[0].z * vec.x + mat[1].z * vec.y + mat[2].z * vec.z; + vec.x = x; + vec.y = y; + return vec; + } + + float3x3 &operator*=(const float3x3 &a) { + int i, j; + const float *m2Ptr; + float *m1Ptr, dst[3]; + + m1Ptr = reinterpret_cast(this); + m2Ptr = reinterpret_cast(&a); + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + dst[j] = m1Ptr[0] * m2Ptr[0 * 3 + j] + + m1Ptr[1] * m2Ptr[1 * 3 + j] + + m1Ptr[2] * m2Ptr[2 * 3 + j]; + } + m1Ptr[0] = dst[0]; m1Ptr[1] = dst[1]; m1Ptr[2] = dst[2]; + m1Ptr += 3; + } + return *this; + } + + float3x3 operator-(float f) const + { + return float3x3(r0-f, r1-f, r2-f); + } + bool Compare(const float3x3 &a) const { + if (r0.Compare(a[0]) && + r1.Compare(a[1]) && + r2.Compare(a[2])) { + return true; + } + return false; + } + + bool Compare(const float3x3 &a, const float epsilon) const { + if (r0.Compare(a[0], epsilon) && + r1.Compare(a[1], epsilon) && + r2.Compare(a[2], epsilon)) { + return true; + } + return false; + } + + const float3x3 &operator-=(float f) + { + r0 -= f; + r1 -= f; + r2 -= f; + return *this; + } + float3x3 operator*(float f) const + { + return float3x3(r0*f, r1*f, r2*f); + } + const float3x3 &operator*=(float f) + { + r0 *= f; + r1 *= f; + r2 *= f; + return *this; + } + float3x3 operator/(float f) const + { + return float3x3(r0/f, r1/f, r2/f); + } + const float3x3 &operator/=(float f) + { + r0 /= f; + r1 /= f; + r2 /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float3x3 &r) const + { + return r0 == r.r0 && r1 == r.r1 && r2 == r.r2; + } + bool operator!=(const float3x3 &r) const + { + return !(*this == r); + } + + float determinant() const + { + float f0 = r0.x * (r1.y*r2.z-r2.y*r1.z); + float f1 = r0.y * -(r1.x*r2.z-r2.x*r1.z); + float f2 = r0.z * (r1.x*r2.y-r2.x*r1.y); + + return f0 + f1 + f2; + } + + void transpose(void) + { + Swap(r0.y, r1.x); + Swap(r0.z, r2.x); + Swap(r1.z, r2.y); + } + + void invert(void) + { + float det = determinant(); + float3x3 inv; + + inv.r0.x = (r1.y*r2.z) - (r1.z*r2.y); + inv.r0.y = -((r1.x*r2.z) - (r1.z*r2.x)); + inv.r0.z = (r1.x*r2.y) - (r1.y*r2.x); + + inv.r1.x = -((r0.y*r2.z) - (r0.z*r2.y)); + inv.r1.y = (r0.x*r2.z) - (r0.z*r2.x); + inv.r1.z = -((r0.x*r2.y) - (r0.y*r2.x)); + + inv.r2.x = (r0.y*r1.z) - (r0.z*r1.y); + inv.r2.y = -((r0.x*r1.z) - (r0.z*r1.x)); + inv.r2.z = (r0.x*r1.y) - (r0.y*r1.x); + + inv.transpose(); + inv /= det; + + *this = inv; + } +}; +inline float3x3 float3x3Identity(void) +{ + return float3x3(1,0,0, + 0,1,0, + 0,0,1); +} +inline float determinant(const float3x3&m) +{ + return m.determinant(); +} + +inline float3x3 transpose(const float3x3 &m) +{ + float3x3 ret = m; + ret.transpose(); + return ret; +} + +inline float3x3 inverse(const float3x3 &m) +{ + float3x3 ret = m; + ret.invert(); + return ret; +} + +inline float3x3 float3x3RotationX(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float3x3 m( 1.0f, 0.0f, 0.0f, + 0.0f, c, s, + 0.0f, -s, c ); + return m; +} +inline float3x3 float3x3RotationY(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float3x3 m( c, 0.0f, -s, + 0.0f, 1.0f, 0.0f, + s, 0.0f, c ); + return m; +} +inline float3x3 float3x3RotationZ(float rad) +{ + + float c = cosf( rad ); + float s = sinf( rad ); + float3x3 m( c, s, 0.0f, + -s, c, 0.0f, + 0.0f, 0.0f, 1.0f ); + return m; +} + +inline float3x3 float3x3RotationAxis(const float3 &axis, float rad ) +{ + float3 normAxis = normalize(axis); + float c = cosf(rad); + float s = sinf(rad); + float t = 1 - c; + + float x = normAxis.x; + float y = normAxis.y; + float z = normAxis.z; + + float3x3 m; + + m.r0.x = (t * x * x) + c; + m.r0.y = (t * x * y) + s * z; + m.r0.z = (t * x * z) - s * y; + + m.r1.x = (t * x * y) - (s * z); + m.r1.y = (t * y * y) + c; + m.r1.z = (t * y * z) + (s * x); + + m.r2.x = (t * x * z) + (s * y); + m.r2.y = (t * y * z) - (s * x); + m.r2.z = (t * z * z) + c; + + return m; +} + +inline float3x3 float3x3Scale(float x, float y, float z) +{ + return float3x3(x,0,0, + 0,y,0, + 0,0,z); +} + +/**************************************\ +float4x4 +\**************************************/ +struct float4x4 +{ + struct + { + float4 r0; + float4 r1; + float4 r2; + float4 r3; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float4x4() {} + explicit float4x4(float f) : r0(f), r1(f), r2(f), r3(f) { } + explicit float4x4(float* f) : r0(f+0), r1(f+4), r2(f+8), r3(f+12) { } + float4x4(const float4 &_r0, const float4 &_r1, const float4 &_r2, const float4 &_r3) : r0(_r0), r1(_r1), r2(_r2), r3(_r3) { } + float4x4(float _m00, float _m01, float _m02, float _m03, + float _m10, float _m11, float _m12, float _m13, + float _m20, float _m21, float _m22, float _m23, + float _m30, float _m31, float _m32, float _m33) + : r0(_m00,_m01,_m02,_m03) + , r1(_m10,_m11,_m12,_m13) + , r2(_m20,_m21,_m22,_m23) + , r3(_m30,_m31,_m32,_m33) + { + } + float4x4(const float3x3 &m) + : r0(m.r0, 0.0f) + , r1(m.r1, 0.0f) + , r2(m.r2, 0.0f) + , r3(0.0f, 0.0f, 0.0f, 1.0f) + { + } + const float4x4 &operator=(const float4x4 &m) + { + r0 = m.r0; + r1 = m.r1; + r2 = m.r2; + r3 = m.r3; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + + #define MTX4_INDEX(f,r,c) ((f)[(r*4)+c]) + inline float4x4 operator*(const float4x4 &r) const + { + float4x4 m(1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1); + + const float* right = (const float*)&this->r0; + const float* left = (const float*)&r.r0; + float* result = (float*)&m; + + int ii, jj, kk; + for(ii=0; ii<4; ++ii) /* row */ + { + for(jj=0; jj<4; ++jj) /* column */ + { + float sum = MTX4_INDEX(left,ii,0)*MTX4_INDEX(right,0,jj); + for(kk=1; kk<4; ++kk) + { + sum += (MTX4_INDEX(left,ii,kk)*MTX4_INDEX(right,kk,jj)); + } + MTX4_INDEX(result,ii,jj) = sum; + } + } + return m; + } + #undef MTX4_INDEX + + inline float4 operator*(const float4 &v) const + { + float4 a; + + a.x = (r0*v).hadd(); + a.y = (r1*v).hadd(); + a.z = (r2*v).hadd(); + a.w = (r3*v).hadd(); + + return a; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float4x4 operator+(float f) const + { + return float4x4(r0+f, r1+f, r2+f, r3+f); + } + const float4x4 &operator+=(float f) + { + r0 += f; + r1 += f; + r2 += f; + r3 += f; + return *this; + } + float4x4 operator-(float f) const + { + return float4x4(r0-f, r1-f, r2-f, r3-f); + } + const float4x4 &operator-=(float f) + { + r0 -= f; + r1 -= f; + r2 -= f; + r3 -= f; + return *this; + } + float4x4 operator*(float f) const + { + return float4x4(r0*f, r1*f, r2*f, r3*f); + } + const float4x4 &operator*=(float f) + { + r0 *= f; + r1 *= f; + r2 *= f; + r3 *= f; + return *this; + } + float4x4 operator/(float f) const + { + return float4x4(r0/f, r1/f, r2/f, r3/f); + } + const float4x4 &operator/=(float f) + { + r0 /= f; + r1 /= f; + r2 /= f; + r3 /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float4x4 &r) const + { + return r0 == r.r0 && r1 == r.r1 && r2 == r.r2 && r3 == r.r3; + } + bool operator!=(const float4x4 &r) const + { + return !(*this == r); + } + + float determinant() const + { + float det = 0.0f; + + float3x3 a( r1.y,r1.z,r1.w, + r2.y,r2.z,r2.w, + r3.y,r3.z,r3.w); + + float3x3 b( r1.x,r1.z,r1.w, + r2.x,r2.z,r2.w, + r3.x,r3.z,r3.w); + + float3x3 c( r1.x,r1.y,r1.w, + r2.x,r2.y,r2.w, + r3.x,r3.y,r3.w); + + float3x3 d( r1.x,r1.y,r1.z, + r2.x,r2.y,r2.z, + r3.x,r3.y,r3.z); + + + det += r0.x * a.determinant(); + + det -= r0.y * b.determinant(); + + det += r0.z * c.determinant(); + + det -= r0.w * d.determinant(); + + return det; + } + + void transpose(void) + { + Swap(r0.y, r1.x); + Swap(r0.z, r2.x); + Swap(r0.w, r3.x); + Swap(r1.z, r2.y); + Swap(r1.w, r3.y); + Swap(r2.w, r3.z); + } + + void invert(void) + { + float4x4 ret; + float recip; + + /* temp matrices */ + + /* row 1 */ + float3x3 a( r1.y,r1.z,r1.w, + r2.y,r2.z,r2.w, + r3.y,r3.z,r3.w); + + float3x3 b( r1.x,r1.z,r1.w, + r2.x,r2.z,r2.w, + r3.x,r3.z,r3.w); + + float3x3 c( r1.x,r1.y,r1.w, + r2.x,r2.y,r2.w, + r3.x,r3.y,r3.w); + + float3x3 d( r1.x,r1.y,r1.z, + r2.x,r2.y,r2.z, + r3.x,r3.y,r3.z); + + /* row 2 */ + float3x3 e( r0.y,r0.z,r0.w, + r2.y,r2.z,r2.w, + r3.y,r3.z,r3.w); + + float3x3 f( r0.x,r0.z,r0.w, + r2.x,r2.z,r2.w, + r3.x,r3.z,r3.w); + + float3x3 g( r0.x,r0.y,r0.w, + r2.x,r2.y,r2.w, + r3.x,r3.y,r3.w); + + float3x3 h( r0.x,r0.y,r0.z, + r2.x,r2.y,r2.z, + r3.x,r3.y,r3.z); + + + /* row 3 */ + float3x3 i( r0.y,r0.z,r0.w, + r1.y,r1.z,r1.w, + r3.y,r3.z,r3.w); + + float3x3 j( r0.x,r0.z,r0.w, + r1.x,r1.z,r1.w, + r3.x,r3.z,r3.w); + + float3x3 k( r0.x,r0.y,r0.w, + r1.x,r1.y,r1.w, + r3.x,r3.y,r3.w); + + float3x3 l( r0.x,r0.y,r0.z, + r1.x,r1.y,r1.z, + r3.x,r3.y,r3.z); + + + /* row 4 */ + float3x3 m( r0.y, r0.z, r0.w, + r1.y, r1.z, r1.w, + r2.y, r2.z, r2.w); + + float3x3 n( r0.x, r0.z, r0.w, + r1.x, r1.z, r1.w, + r2.x, r2.z, r2.w); + + float3x3 o( r0.x,r0.y,r0.w, + r1.x,r1.y,r1.w, + r2.x,r2.y,r2.w); + + float3x3 p( r0.x,r0.y,r0.z, + r1.x,r1.y,r1.z, + r2.x,r2.y,r2.z); + + /* row 1 */ + ret.r0.x = a.determinant(); + + ret.r0.y = -b.determinant(); + + ret.r0.z = c.determinant(); + + ret.r0.w = -d.determinant(); + + /* row 2 */ + ret.r1.x = -e.determinant(); + + ret.r1.y = f.determinant(); + + ret.r1.z = -g.determinant(); + + ret.r1.w = h.determinant(); + + /* row 3 */ + ret.r2.x = i.determinant(); + + ret.r2.y = -j.determinant(); + + ret.r2.z = k.determinant(); + + ret.r2.w = -l.determinant(); + + /* row 4 */ + ret.r3.x = -m.determinant(); + + ret.r3.y = n.determinant(); + + ret.r3.z = -o.determinant(); + + ret.r3.w = p.determinant(); + + ret.transpose(); + recip = 1.0f/determinant(); + ret *= recip; + + *this = ret; + } + + // Axis access + float3 getXAxis(void) const + { + return r0; + } + float3 getYAxis(void) const + { + return r1; + } + float3 getZAxis(void) const + { + return r2; + } + float3 getPosition(void) const + { + return float3(r3); + } + + void orthonormalize(void) + { + float3 x = getXAxis(); + float3 y = getYAxis(); + float3 z; + + x.normalize(); + z = normalize(cross3(x, y)); + y = normalize(cross3(z, x)); + + r0 = float4(x, 0.0f); + r1 = float4(y, 0.0f); + r2 = float4(z, 0.0f); + } +}; + +inline float3x3::float3x3(const float4x4 &m) + : r0(m.r0) + , r1(m.r1) + , r2(m.r2) +{ +} +inline float determinant(const float4x4&m) +{ + return m.determinant(); +} +inline float4x4 float4x4Identity(void) +{ + return float4x4(1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1); +} +inline float4x4 transpose(const float4x4 &m) +{ + float4x4 ret = m; + ret.transpose(); + return ret; +} + +inline float4x4 inverse(const float4x4 &m) +{ + float4x4 ret = m; + ret.invert(); + return ret; +} + +inline float4x4 float4x4RotationX(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float4x4 m( 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, c, s, 0.0f, + 0.0f, -s, c, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + return m; +} +inline float4x4 float4x4RotationY(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float4x4 m( c, 0.0f, -s, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + s, 0.0f, c, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + return m; +} +inline float4x4 float4x4RotationZ(float rad) +{ + + float c = cosf( rad ); + float s = sinf( rad ); + float4x4 m( c, s, 0.0f, 0.0f, + -s, c, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + return m; +} + +inline float4x4 float4x4RotationAxis(const float3 &axis, float rad ) +{ + float3 normAxis = normalize(axis); + float c = cosf(rad); + float s = sinf(rad); + float t = 1 - c; + + float x = normAxis.x; + float y = normAxis.y; + float z = normAxis.z; + + float4x4 m = float4x4Identity(); + + m.r0.x = (t * x * x) + c; + m.r0.y = (t * x * y) + s * z; + m.r0.z = (t * x * z) - s * y; + + m.r1.x = (t * x * y) - (s * z); + m.r1.y = (t * y * y) + c; + m.r1.z = (t * y * z) + (s * x); + + m.r2.x = (t * x * z) + (s * y); + m.r2.y = (t * y * z) - (s * x); + m.r2.z = (t * z * z) + c; + + return m; +} + +inline float4x4 float4x4Scale(float x, float y, float z) +{ + return float4x4(x,0,0,0, + 0,y,0,0, + 0,0,z,0, + 0,0,0,1); +} + +inline float4x4 float4x4Translation(float x, float y, float z) +{ + float4x4 m = float4x4Identity(); + m.r3.x = x; + m.r3.y = y; + m.r3.z = z; + return m; +} +inline float4x4 float4x4Translation(const float3 &v) +{ + return float4x4Translation(v.x, v.y, v.z); +} + +inline float4x4 float4x4PerspectiveFovLH(float fov, float aspect, float nearPlane, float farPlane) +{ + float width = tanf(fov * 0.5f); + float height = width / aspect; + float diff = farPlane-nearPlane; + float div = farPlane / diff; + + float4x4 m( + 1.0f/width, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f/height, 0.0f, 0.0f, + 0.0f, 0.0f, div, 1.0f, + 0.0f, 0.0f, -nearPlane*div, 0.0f + ); + return m; +} +inline float4x4 float4x4PerspectiveFovRH(float fov, float aspect, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + float f = tanf(kPiDiv2 - (fov/2.0f)); + float diff = nearPlane-farPlane; + float div = farPlane / diff; + + m.r0.x = f/aspect; + m.r1.y = f; + m.r2.z = div; + m.r2.w = -1; + m.r3.z = nearPlane * div; + m.r3.w = 0; + return m; +} +inline float4x4 float4x4PerspectiveLH(float width, float height, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + m.r0.x = 2*nearPlane/width; + m.r1.y = 2*nearPlane/height; + m.r2.z = farPlane/(farPlane-nearPlane); + m.r2.w = 1; + m.r3.z = nearPlane*farPlane/(nearPlane-farPlane); + m.r3.w = 0; + return m; +} +inline float4x4 float4x4PerspectiveRH(float width, float height, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + m.r0.x = 2*nearPlane/width; + m.r1.y = 2*nearPlane/height; + m.r2.z = farPlane/(nearPlane-farPlane); + m.r2.w = -1; + m.r3.z = nearPlane*farPlane/(nearPlane-farPlane); + m.r3.w = 0; + return m; +} +inline float4x4 float4x4OrthographicOffCenterLH(float left, float right, float top, float bottom, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + float diff = farPlane-nearPlane; + + m.r0.x = 2.0f/(right-left); + m.r1.y = 2.0f/(top-bottom); + m.r2.z = 1.0f/diff; + m.r3.x = -((left+right)/(right-left)); + m.r3.y = -((top+bottom)/(top-bottom)); + m.r3.z = -nearPlane/diff; + + return m; +} +inline float4x4 float4x4OrthographicOffCenterRH(float left, float right, float top, float bottom, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + float diff = nearPlane-farPlane; + + m.r0.x = 2.0f/(right-left); + m.r1.y = 2.0f/(top-bottom); + m.r2.z = 1.0f/diff; + m.r3.x = -((left+right)/(right-left)); + m.r3.y = -((top+bottom)/(top-bottom)); + m.r3.z = nearPlane/diff; + + return m; +} +inline float4x4 float4x4OrthographicLH(float width, float height, float nearPlane, float farPlane) +{ + float halfWidth = width/2.0f; + float halfHeight = height/2.0f; + + return float4x4OrthographicOffCenterLH(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); +} +inline float4x4 float4x4OrthographicRH(float width, float height, float nearPlane, float farPlane) +{ + float halfWidth = width/2.0f; + float halfHeight = height/2.0f; + + return float4x4OrthographicOffCenterRH(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); +} + +/**************************************\ +Quaternion +\**************************************/ +struct quaternion : public float4 +{ + + /***************************************\ + | Constructors | + \***************************************/ + quaternion() {} + explicit quaternion(float f) : float4(f) { } + explicit quaternion(float _x, float _y, float _z, float _w) : float4(_x,_y,_z,_w) { } + explicit quaternion(float* f) : float4(f) { } + quaternion(const quaternion &v) : float4(v) { } + quaternion(const float3 &v, float _w) + { + float3 norm = ::normalize(v); + float a = _w*0.5f; + float s = sinf(a); + x = norm.x*s; + y = norm.y*s; + z = norm.z*s; + w = cosf(a); + } + const quaternion &operator=(const quaternion &v) + { + x = v.x; + y = v.y; + z = v.z; + w = v.w; + return *this; + } + + /* Methods */ + float3 getXAxis(void) const + { + float3 ret( 1-2*(y*y+z*z), + 2*(x*y+w*z), + 2*(x*z-y*w)); + return ret; + } + float3 getYAxis(void) const + { + float3 ret( 2*(x*y-z*w), + 1-2*(x*x+z*z), + 2*(y*z+x*w)); + return ret; + } + float3 getZAxis(void) const + { + float3 ret( 2*(x*z+y*w), + 2*(y*z-x*w), + 1-2*(x*x+y*y)); + return ret; + } + + float3x3 getMatrix(void) const + { + quaternion q = *this; + q.normalize(); + float xx = q.x * q.x; + float yy = q.y * q.y; + float zz = q.z * q.z; + + float xy = q.x * q.y; + float zw = q.z * q.w; + float xz = q.x * q.z; + float yw = q.y * q.w; + float yz = q.y * q.z; + float xw = q.x * q.w; + + float3x3 ret(1 - 2*(yy+zz), 2*(xy+zw), 2*(xz-yw), + 2*(xy-zw), 1 - 2*(xx+zz), 2*(yz+xw), + 2*(xz+yw), 2*(yz-xw), 1 - 2*(xx+yy) ); + return ret; + } + + quaternion conjugate(void) const + { + return quaternion(-x, -y, -z, w); + } + quaternion inverse(void) const + { + // Note: Only normalized quaternions are supportted at the moment + quaternion q = *this; + q.normalize(); + return q.conjugate(); + } +}; + +inline quaternion quaternionMultiply(const quaternion &l, const quaternion &r) +{ + quaternion q( r.w*l.x + r.x*l.w + r.y*l.z - r.z*l.y, + r.w*l.y + r.y*l.w + r.z*l.x - r.x*l.z, + r.w*l.z + r.z*l.w + r.x*l.y - r.y*l.x, + r.w*l.w - r.x*l.x - r.y*l.y - r.z*l.z ); + return q; +} + +inline quaternion quaternionIdentity(void) +{ + return quaternion(0.0f, 0.0f, 0.0f, 1.0f); +} + +inline float3 Min( float3 &v0, float3 &v1 ) +{ + float3 result; + result.x = v0.x < v1.x ? v0.x : v1.x; + result.y = v0.y < v1.y ? v0.y : v1.y; + result.z = v0.z < v1.z ? v0.z : v1.z; + return result; +} + +inline float3 Max( float3 &v0, float3 &v1 ) +{ + float3 result; + result.x = v0.x > v1.x ? v0.x : v1.x; + result.y = v0.y > v1.y ? v0.y : v1.y; + result.z = v0.z > v1.z ? v0.z : v1.z; + return result; +} + +inline float4 Min( float4 &v0, float4 &v1 ) +{ + float4 result; + result.x = v0.x < v1.x ? v0.x : v1.x; + result.y = v0.y < v1.y ? v0.y : v1.y; + result.z = v0.z < v1.z ? v0.z : v1.z; + result.w = v0.w < v1.w ? v0.w : v1.w; + return result; +} + +inline float4 Max( float4 &v0, float4 &v1 ) +{ + float4 result; + result.x = v0.x > v1.x ? v0.x : v1.x; + result.y = v0.y > v1.y ? v0.y : v1.y; + result.z = v0.z > v1.z ? v0.z : v1.z; + result.w = v0.w > v1.w ? v0.w : v1.w; + return result; +} + +inline float4 operator*(const float4 &v, const float4x4 &m) +{ + float4 result; + + result = m.r0 * v.x; + result += m.r1 * v.y; + result += m.r2 * v.z; + result += m.r3 * v.w; + + return result; +} + +/* +============================ +CreateLookAtMatrix +============================ +*/ +inline float4x4 CreateLookAtMatrix(float3 cameraPosition, float3 cameraTarget, float3 cameraUpVector) +{ + float3 vector3_1 = (cameraPosition - cameraTarget).normalize(); + float3 vector3_2; + + vector3_2.Cross(cameraUpVector, vector3_1); + vector3_2.NormalizeSelf(); + + float3 vector1; + vector1.Cross(vector3_1, vector3_2); + + float4x4 matrix; + matrix.r0.x = vector3_2.x; + matrix.r0.y = vector1.x; + matrix.r0.z = vector3_1.x; + matrix.r0.w = 0.0f; + matrix.r1.x = vector3_2.y; + matrix.r1.y = vector1.y; + matrix.r1.z = vector3_1.y; + matrix.r1.w = 0.0f; + matrix.r2.x = vector3_2.z; + matrix.r2.y = vector1.z; + matrix.r2.z = vector3_1.z; + matrix.r2.w = 0.0f; + matrix.r3.x = -float3::Dot(vector3_2, cameraPosition); + matrix.r3.y = -float3::Dot(vector1, cameraPosition); + matrix.r3.z = -float3::Dot(vector3_1, cameraPosition); + matrix.r3.w = 1.0f; + + return matrix; +} + +__inline float3 abs(const float3 xyz) +{ + float3 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z)); + return result; +} + + +__inline float4 abs(const float4 xyz) +{ + float4 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z), fabs(xyz.w)); + return result; +} + +__inline float3 fabs(const float3 xyz) +{ + float3 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z)); + return result; +} + + +__inline float4 fabs(const float4 xyz) +{ + float4 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z), fabs(xyz.w)); + return result; +} + +static const float Identity[16] = { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 +}; + +__inline void _math_matrix_rotate(float4x4 &matrix, float angle, float x, float y, float z) +{ + float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; + float m[16]; + bool optimized; + #define M_PI 3.14159265358979323846 + s = sinf(angle * M_PI / 180.0); + c = cosf(angle * M_PI / 180.0); + + memcpy(m, Identity, sizeof(Identity)); + optimized = false; + +#define M(row,col) m[col*4+row] + + if (x == 0.0F) { + if (y == 0.0F) { + if (z != 0.0F) { + optimized = true; + /* rotate only around z-axis */ + M(0, 0) = c; + M(1, 1) = c; + if (z < 0.0F) { + M(0, 1) = s; + M(1, 0) = -s; + } + else { + M(0, 1) = -s; + M(1, 0) = s; + } + } + } + else if (z == 0.0F) { + optimized = true; + /* rotate only around y-axis */ + M(0, 0) = c; + M(2, 2) = c; + if (y < 0.0F) { + M(0, 2) = -s; + M(2, 0) = s; + } + else { + M(0, 2) = s; + M(2, 0) = -s; + } + } + } + else if (y == 0.0F) { + if (z == 0.0F) { + optimized = true; + /* rotate only around x-axis */ + M(1, 1) = c; + M(2, 2) = c; + if (x < 0.0F) { + M(1, 2) = s; + M(2, 1) = -s; + } + else { + M(1, 2) = -s; + M(2, 1) = s; + } + } + } + + if (!optimized) { + const float mag = sqrtf(x * x + y * y + z * z); + + if (mag <= 1.0e-4F) { + /* no rotation, leave mat as-is */ + return; + } + + x /= mag; + y /= mag; + z /= mag; + + + /* + * Arbitrary axis rotation matrix. + * + * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied + * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation + * (which is about the X-axis), and the two composite transforms + * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary + * from the arbitrary axis to the X-axis then back. They are + * all elementary rotations. + * + * Rz' is a rotation about the Z-axis, to bring the axis vector + * into the x-z plane. Then Ry' is applied, rotating about the + * Y-axis to bring the axis vector parallel with the X-axis. The + * rotation about the X-axis is then performed. Ry and Rz are + * simply the respective inverse transforms to bring the arbitrary + * axis back to its original orientation. The first transforms + * Rz' and Ry' are considered inverses, since the data from the + * arbitrary axis gives you info on how to get to it, not how + * to get away from it, and an inverse must be applied. + * + * The basic calculation used is to recognize that the arbitrary + * axis vector (x, y, z), since it is of unit length, actually + * represents the sines and cosines of the angles to rotate the + * X-axis to the same orientation, with theta being the angle about + * Z and phi the angle about Y (in the order described above) + * as follows: + * + * cos ( theta ) = x / sqrt ( 1 - z^2 ) + * sin ( theta ) = y / sqrt ( 1 - z^2 ) + * + * cos ( phi ) = sqrt ( 1 - z^2 ) + * sin ( phi ) = z + * + * Note that cos ( phi ) can further be inserted to the above + * formulas: + * + * cos ( theta ) = x / cos ( phi ) + * sin ( theta ) = y / sin ( phi ) + * + * ...etc. Because of those relations and the standard trigonometric + * relations, it is pssible to reduce the transforms down to what + * is used below. It may be that any primary axis chosen will give the + * same results (modulo a sign convention) using thie method. + * + * Particularly nice is to notice that all divisions that might + * have caused trouble when parallel to certain planes or + * axis go away with care paid to reducing the expressions. + * After checking, it does perform correctly under all cases, since + * in all the cases of division where the denominator would have + * been zero, the numerator would have been zero as well, giving + * the expected result. + */ + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * s; + ys = y * s; + zs = z * s; + one_c = 1.0F - c; + + /* We already hold the identity-matrix so we can skip some statements */ + M(0, 0) = (one_c * xx) + c; + M(0, 1) = (one_c * xy) - zs; + M(0, 2) = (one_c * zx) + ys; + /* M(0,3) = 0.0F; */ + + M(1, 0) = (one_c * xy) + zs; + M(1, 1) = (one_c * yy) + c; + M(1, 2) = (one_c * yz) - xs; + /* M(1,3) = 0.0F; */ + + M(2, 0) = (one_c * zx) - ys; + M(2, 1) = (one_c * yz) + xs; + M(2, 2) = (one_c * zz) + c; + /* M(2,3) = 0.0F; */ + + /* + M(3,0) = 0.0F; + M(3,1) = 0.0F; + M(3,2) = 0.0F; + M(3,3) = 1.0F; + */ + } +#undef M + float4x4 _internalMatrix(&m[0]); + //_internalMatrix.r[0] = XMVectorSet(m[0], m[1], m[2], m[3]); + //_internalMatrix.r[1] = XMVectorSet(m[4], m[5], m[6], m[7]); + //_internalMatrix.r[2] = XMVectorSet(m[8], m[9], m[10], m[11]); + //_internalMatrix.r[3] = XMVectorSet(m[12], m[13], m[14], m[15]); + float4x4 temp = matrix * _internalMatrix; + matrix = temp; + + //matmul4(mat, mat, m); + //matrix_multf(mat, m, MAT_FLAG_ROTATION); +} + +static void glhFrustumf2(float *matrix, float left, float right, float bottom, float top, float znear, float zfar) +{ + float temp, temp2, temp3, temp4; + temp = 2.0 * znear; + temp2 = right - left; + temp3 = top - bottom; + temp4 = zfar - znear; + matrix[0] = temp / temp2; + matrix[1] = 0.0; + matrix[2] = 0.0; + matrix[3] = 0.0; + matrix[4] = 0.0; + matrix[5] = temp / temp3; + matrix[6] = 0.0; + matrix[7] = 0.0; + matrix[8] = (right + left) / temp2; + matrix[9] = (top + bottom) / temp3; + matrix[10] = (-zfar - znear) / temp4; + matrix[11] = -1.0; + matrix[12] = 0.0; + matrix[13] = 0.0; + matrix[14] = (-temp * zfar) / temp4; + matrix[15] = 0.0; +} + + +static void glhPerspectivef2(float *matrix, float fovyInDegrees, float aspectRatio, float znear, float zfar) +{ + float ymax, xmax; + float temp, temp2, temp3, temp4; + ymax = znear * tanf(fovyInDegrees * M_PI / 360.0); + //ymin = -ymax; + //xmin = -ymax * aspectRatio; + xmax = ymax * aspectRatio; + glhFrustumf2(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); +} + +#endif // #ifndef __CPUTMath_h__ \ No newline at end of file diff --git a/code/TIBERIANDAWN/GSCREEN.CPP b/code/TIBERIANDAWN/GSCREEN.CPP index 95c47eb..e241d0c 100644 --- a/code/TIBERIANDAWN/GSCREEN.CPP +++ b/code/TIBERIANDAWN/GSCREEN.CPP @@ -492,6 +492,7 @@ extern bool CanVblankSync; *=============================================================================================*/ void GScreenClass::Blit_Display(void) { +#if 0 // jmarshall - no longer used and saves on performance to disable it(3.6%). if (SeenBuff.Get_Width()!=320){ #if (0) if (HidPage.Get_IsDirectDraw() && (Options.GameSpeed >1 || Options.ScrollRate==6 && CanVblankSync) ){ @@ -520,7 +521,7 @@ void GScreenClass::Blit_Display(void) // ST - 1/2/2019 5:26PM //ModeX_Blit (&HiddenPage); } - +#endif } diff --git a/code/external/devil/ILU.lib b/code/external/devil/ILU.lib new file mode 100644 index 0000000..5ea04cb Binary files /dev/null and b/code/external/devil/ILU.lib differ diff --git a/textures/afv01.tem.png b/textures/afv01.tem.png new file mode 100644 index 0000000..7368367 Binary files /dev/null and b/textures/afv01.tem.png differ diff --git a/textures/afv02.tem.png b/textures/afv02.tem.png new file mode 100644 index 0000000..5c9433c Binary files /dev/null and b/textures/afv02.tem.png differ diff --git a/textures/afv03.tem.png b/textures/afv03.tem.png new file mode 100644 index 0000000..2019cb7 Binary files /dev/null and b/textures/afv03.tem.png differ