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/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 4bfc44d..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) @@ -715,4 +715,4 @@ 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}/../" ) 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 2aa0319..56553f7 100644 --- a/code/REDALERT/BDATA.CPP +++ b/code/REDALERT/BDATA.CPP @@ -3140,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 @@ -3218,7 +3231,7 @@ void BuildingTypeClass::Display(int x, int y, WindowNumberType window, HousesTyp //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->width, hdimage->height); + GL_RenderImage(hdimage, x, y, hdimage->renderwidth, hdimage->renderheight); } else { void const* ptr = Get_Cameo_Data(); @@ -3376,8 +3389,23 @@ void BuildingTypeClass::Init(TheaterType theater) // jmarshall { char imageFileName[512]; - sprintf(imageFileName, "textures/%s.png", fullname); - ((BuildingTypeClass *)classptr)->HDImageData = Image_LoadImage(imageFileName); + + // 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 /* diff --git a/code/REDALERT/CONQUER.CPP b/code/REDALERT/CONQUER.CPP index 3f5f763..2455d61 100644 --- a/code/REDALERT/CONQUER.CPP +++ b/code/REDALERT/CONQUER.CPP @@ -3486,9 +3486,9 @@ void CC_Draw_Shape(Image_t* image, int shapenum, int x, int y, WindowNumberType if ((flags & SHAPE_GHOST) && (!ghostdata)) { ghostdata = DisplayClass::SpecialGhost; } - if ((flags & SHAPE_FADING) && (!fadingdata)) { - fadingdata = DisplayClass::FadingShade; - } + //if ((flags & SHAPE_FADING) && (!fadingdata)) { + // fadingdata = DisplayClass::FadingShade; + //} static unsigned char* _xbuffer = 0; @@ -3498,8 +3498,8 @@ void CC_Draw_Shape(Image_t* image, int shapenum, int x, int y, WindowNumberType if (image != NULL && shapenum != -1) { - int width = image->width; - int height = image->height; + int width = image->renderwidth; + int height = image->renderheight; #ifdef NEVER /* @@ -3758,7 +3758,7 @@ 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); + 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); 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/Image.h b/code/REDALERT/Image.h index 8ca0c14..51700f2 100644 --- a/code/REDALERT/Image.h +++ b/code/REDALERT/Image.h @@ -1,27 +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; - unsigned char* buffer; + int renderwidth; + int renderheight; + //unsigned char* buffer[MAX_HOUSE_COLORS][MAX_IMAGE_FRAMES]; }; __forceinline Image_t::Image_t() { - buffer = NULL; +// buffer = NULL; + numAnimFrames = 0; } __forceinline Image_t::~Image_t() { - if (buffer) { - delete buffer; - buffer = NULL; - } + //if (buffer) { + // delete buffer; + // buffer = NULL; + //} } -Image_t* Image_LoadImage(const char* name); +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/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/OBJECT.CPP b/code/REDALERT/OBJECT.CPP index ad1b2e4..6b39275 100644 --- a/code/REDALERT/OBJECT.CPP +++ b/code/REDALERT/OBJECT.CPP @@ -2182,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/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/Shape.cpp b/code/REDALERT/Shape.cpp index 9c2480e..7fa8e26 100644 --- a/code/REDALERT/Shape.cpp +++ b/code/REDALERT/Shape.cpp @@ -1546,8 +1546,10 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, struct Image_t * 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]); - GL_RenderImage(shape_image, xstart, ystart, width, height); - + 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. diff --git a/code/REDALERT/TECHNO.CPP b/code/REDALERT/TECHNO.CPP index 71ff47a..7f9ea58 100644 --- a/code/REDALERT/TECHNO.CPP +++ b/code/REDALERT/TECHNO.CPP @@ -4451,11 +4451,17 @@ VisualType TechnoClass::Visual_Character(bool raw) const } 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* remap = Remap_Table(); void const* shadow = Map.UnitShadow; - y -= Lepton_To_Pixel(Height); - CC_Draw_Shape(image, shapenum, x, y, window, SHAPE_CENTER | SHAPE_WIN_REL | SHAPE_FADING | SHAPE_GHOST, remap, shadow, rotation); + 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); } /*********************************************************************************************** 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/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 ce14c0a..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,6 +63,8 @@ #include #include +#include "HOUSECOLOR.H" +#include "IMGUTIL.H" GLuint backbuffer_texture = -1; //byte* backbuffer_data; @@ -90,11 +93,81 @@ void Show_OldFrameBuffer(bool show) { 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; } } @@ -103,7 +176,13 @@ Image_t* Image_LoadImage(const char* name) { ilBindImage(ImageName); if (!ilLoadImage(name)) { ilDeleteImages(1, &ImageName); - return NULL; + return false; + } + + bool swapBGR = false; + if (strstr(name, ".TGA")) { + iluFlipImage(); + swapBGR = true; } ILuint Width, Height, Bpp; @@ -112,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); @@ -132,32 +227,87 @@ Image_t* Image_LoadImage(const char* name) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - Image_t* image = new Image_t(); + strcpy(image->name, name); - image->image = texture; - image->width = Width; - image->height = Height; - image->buffer = new unsigned char[Width * Height * Bpp]; - memcpy(image->buffer, Data, Width * Height * Bpp); - loaded_images.push_back(image); + 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) { - // 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]; + 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(); - image->buffer = new unsigned char[Width * Height * 4]; + unsigned char *buffer = new unsigned char[Width * Height * 4]; for (int i = 0; i < Width * Height; i++) { unsigned char c = data[i]; @@ -181,10 +331,10 @@ Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsi } - image->buffer[(i * 4) + 0] = r; - image->buffer[(i * 4) + 1] = g; - image->buffer[(i * 4) + 2] = b; - image->buffer[(i * 4) + 3] = a; + buffer[(i * 4) + 0] = r; + buffer[(i * 4) + 1] = g; + buffer[(i * 4) + 2] = b; + buffer[(i * 4) + 3] = a; } @@ -192,16 +342,19 @@ Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsi glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->buffer); + 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 = texture; - image->width = Width; - image->height = Height; + 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; } 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