diff --git a/Source/Resource/Models/AnimatedModelResource.h b/Source/Resource/Models/AnimatedModelResource.h index 8106c32f..2a1ac4c4 100644 --- a/Source/Resource/Models/AnimatedModelResource.h +++ b/Source/Resource/Models/AnimatedModelResource.h @@ -4,7 +4,11 @@ #include "Resource/Models/ModelResource.h" struct AnimatedModelFace { - /* 0000 */ std::uint32_t values[6]; + /* 0000 */ std::uint16_t vertices[3]; + /* 0006 */ std::uint16_t textureVertices[3]; + /* 000C */ std::uint32_t unknown_000C; + /* 0010 */ std::uint32_t unknown_0010; + /* 0014 */ int smoothGroup; }; struct AnimatedModelFrame { @@ -31,6 +35,7 @@ struct AnimatedModelNode { ~AnimatedModelNode(); AnimatedModelNode(const AnimatedModelNode&) = delete; AnimatedModelNode& operator=(const AnimatedModelNode&) = delete; + void Shade(const float* matrix, int frame, const float* light, const float* diffuse, const float* ambient, int shadeType, int alpha); /* 0000 */ std::string name; /* 0018 */ std::string parentName; diff --git a/Source/Resource/Models/GrannyModelResource.h b/Source/Resource/Models/GrannyModelResource.h index 33c40a20..c2ac2a96 100644 --- a/Source/Resource/Models/GrannyModelResource.h +++ b/Source/Resource/Models/GrannyModelResource.h @@ -8,8 +8,12 @@ #include class CTexture; +struct AffineMatrix; +struct granny_animation; struct granny_control; +struct granny_file; +struct granny_local_pose; struct granny_material; struct granny_mesh_binding; struct granny_mesh_deformer; @@ -65,6 +69,17 @@ struct granny_model { /* 0050 */ granny_model_mesh_binding* meshBindings; }; +struct granny_file_info { + /* 0000 */ unsigned char unknown_0000[0x10]; + /* 0010 */ std::int32_t textureCount; + /* 0014 */ unsigned char unknown_0014[0x2C]; + /* 0040 */ std::int32_t modelCount; + /* 0044 */ granny_model** models; + /* 0048 */ unsigned char unknown_0048[8]; + /* 0050 */ std::int32_t animationCount; + /* 0054 */ granny_animation** animations; +}; + extern "C" { __declspec(dllimport) extern const granny_pixel_layout GrannyRGBA8888PixelFormat; __declspec(dllimport) extern granny_data_type_definition GrannyPNT332VertexType[]; @@ -91,6 +106,16 @@ __declspec(dllimport) granny_mesh_deformer* WINAPI GrannyNewMeshDeformer( ); __declspec(dllimport) void WINAPI GrannyCopyMeshVertices(const granny_mesh* mesh, const granny_data_type_definition* vertexType, void* vertices); __declspec(dllimport) granny_texture* WINAPI GrannyGetMaterialTextureByType(const granny_material* material, std::int32_t type); +__declspec(dllimport) bool WINAPI GrannyVersionsMatch_(std::int32_t major, std::int32_t minor, std::int32_t customization, std::int32_t build); +__declspec(dllimport) granny_file* WINAPI GrannyReadEntireFileFromMemory(std::int32_t size, void* memory); +__declspec(dllimport) granny_file_info* WINAPI GrannyGetFileInfo(granny_file* file); +__declspec(dllimport) void WINAPI GrannyFreeFileSection(granny_file* file, std::int32_t section); +__declspec(dllimport) granny_local_pose* WINAPI GrannyNewLocalPose(std::int32_t boneCount); +__declspec(dllimport) void WINAPI GrannyFreeMeshDeformer(granny_mesh_deformer* deformer); +__declspec(dllimport) void WINAPI GrannyFreeModelInstance(granny_model_instance* instance); +__declspec(dllimport) void WINAPI GrannyFreeWorldPose(granny_world_pose* pose); +__declspec(dllimport) granny_control* WINAPI GrannyPlayControlledAnimation(float startTime, const granny_animation* animation, granny_model_instance* instance); +__declspec(dllimport) void WINAPI GrannySetControlLoopCount(granny_control* control, std::int32_t loopCount); } struct GrannyTextureEntry { @@ -115,12 +140,36 @@ struct GrannyModelInstance { /* 000C */ GrannyMeshEntry* meshes; }; +class GrannyAnimationLibrary { +public: + bool Load(const char* name, int job, int action); + void FreeInstance(); + granny_file* ReadAnimationFile(const char* name, const char* suffix); + + /* 0000 */ float unknown_0000; + /* 0004 */ unsigned char unknown_0004[0x14C]; + /* 0150 */ granny_file* file; + /* 0154 */ int textureCount; + /* 0158 */ GrannyTextureEntry* textures; + /* 015C */ int modelCount; + /* 0160 */ GrannyModelInstance* instance; + /* 0164 */ int maxBoneCount; + /* 0168 */ granny_local_pose* localPose; + /* 016C */ int deformBufferSize; + /* 0170 */ int unknown_0170; + /* 0174 */ unsigned char unknown_0174[8]; + /* 017C */ char fileName[MAX_PATH]; + /* 0280 */ granny_animation* animations[100][20]; +}; + class C3dGrannyModelRes : public CRes { public: void RebindMeshes(const C3dGrannyModelRes& target); void InstantiateModel(GrannyModelInstance* target, const granny_model* model); CTexture* CreateTexture(const granny_texture* texture, int option); void FreeControl(granny_control* control); + granny_control* PlayAnimation(unsigned action, granny_model_instance* instance, granny_control* control, int loopCount); + bool ProjectBounds(float* rect, const AffineMatrix& view, const AffineMatrix& world, const float* eye) const; /* 0110 */ unsigned char unknown_0110[0x150]; /* 0260 */ void* file; @@ -135,13 +184,11 @@ public: /* 0284 */ unsigned char unknown_0284[8]; /* 028C */ char fileName[MAX_PATH]; /* 0390 */ const granny_model* model; - /* 0394 */ int unknown_0394; - /* 0398 */ int unknown_0398; - /* 039C */ int unknown_039C; + /* 0394 */ float position[3]; /* 03A0 */ float unknown_03A0; /* 03A4 */ float unknown_03A4; - /* 03A8 */ void* animations; - /* 03AC */ int job; + /* 03A8 */ GrannyAnimationLibrary* animations; + /* 03AC */ unsigned job; /* 03B0 */ int unknown_03B0; /* 03B4 */ granny_skeleton* skeleton; @@ -159,6 +206,11 @@ static_assert(offsetof(C3dGrannyModelRes, file) == 0x260); static_assert(offsetof(C3dGrannyModelRes, fileName) == 0x28C); static_assert(offsetof(C3dGrannyModelRes, model) == 0x390); static_assert(offsetof(C3dGrannyModelRes, skeleton) == 0x3B4); +static_assert(offsetof(granny_file_info, models) == 0x44); +static_assert(offsetof(granny_file_info, animations) == 0x54); +static_assert(offsetof(GrannyAnimationLibrary, file) == 0x150); +static_assert(offsetof(GrannyAnimationLibrary, fileName) == 0x17C); +static_assert(offsetof(GrannyAnimationLibrary, animations) == 0x280); #endif #endif diff --git a/Source/Resource/Models/ModelResource.cpp b/Source/Resource/Models/ModelResource.cpp index 9df08251..7cad5822 100644 --- a/Source/Resource/Models/ModelResource.cpp +++ b/Source/Resource/Models/ModelResource.cpp @@ -1,4 +1,9 @@ #include "Client/Application/ErrorDialog.h" +#include "Contents/Jobs/JobNames.h" +#include "File/File.h" +#include "File/ResourcePath.h" +#include "Render/DeviceContext/DCSurface.h" +#include "Render/Renderer.h" #include "Render/Textures/Texture.h" #include "Render/Textures/TextureCache.h" #include "Resource/Bitmap/BitmapResource.h" @@ -6,9 +11,34 @@ #include "Resource/Models/GrannyModelResource.h" #include "Resource/Models/ModelResource.h" #include "Resource/ResourceByteReader.h" +#include "Utility/Math/AffineMatrix.h" #include +#include +#include #include +#include +#include + +// GLOBAL: gl_24708 +char g_modelPath[MAX_PATH]; +// GLOBAL: gl_24734 +char g_animationPath[MAX_PATH]; +// GLOBAL: gl_24707 +unsigned g_animationJobs[10] = {1288, 722, 1324, 1000, 1000, 1000, 1000, 1286, 1285, 1287}; +// GLOBAL: gl_24706 +const char* g_animationNames[5] = {"stand", "move", "attack", "dead", "damage"}; + +struct ShadeVector { + ShadeVector() : x(0.0f), y(0.0f), z(0.0f) { + } + + /* 0000 */ float x; + /* 0004 */ float y; + /* 0008 */ float z; +}; + +static_assert(sizeof(ShadeVector) == 12); // OFFSET: 0x00756D60 // FUNCTION: fn_07997 @@ -432,3 +462,383 @@ void C3dGrannyModelRes::FreeControl(granny_control* control) { GrannyFreeControl(control); } } + +// OFFSET: 0x007598B0 +// FUNCTION: fn_08019 +granny_file* GrannyAnimationLibrary::ReadAnimationFile(const char* name, const char* suffix) { + CFile file; + std::sprintf(g_animationPath, "%s%s.gr2", name, suffix); + + if (!file.Open(g_animationPath, 0, true, false)) { + const std::string path(g_animationPath); + const std::string message = std::string("Cannot find File : ") + path; + ShowErrorDialog(GetRenderSystemHolder()->system, message.c_str(), 0); + return nullptr; + } + + granny_file* result = GrannyReadEntireFileFromMemory(file.GetSize(), file.GetData()); + file.Close(); + return result; +} + +// OFFSET: 0x007594B0 +// FUNCTION: fn_08013 +void GrannyAnimationLibrary::FreeInstance() { + if (GrannyModelInstance* instance = this->instance) { + for (int index = 0; index < instance->meshCount; ++index) { + GrannyMeshEntry& entry = instance->meshes[index]; + GrannyFreeMeshBinding(entry.binding); + GrannyFreeMeshDeformer(entry.deformer); + delete entry.indices; + } + + GrannyFreeModelInstance(instance->instance); + GrannyFreeWorldPose(instance->worldPose); + delete[] instance->meshes; + } + + delete this->instance; + this->instance = nullptr; +} + +// OFFSET: 0x00757390 +// FUNCTION: fn_08005 +bool GrannyAnimationLibrary::Load(const char* name, int job, int action) { + bool result = false; + + if (!GrannyVersionsMatch_(2, 1, 0, 5)) { + ShowErrorDialog(GetRenderSystemHolder()->system, "doesn't match the .h file used during compilation", 0); + return false; + } + + this->modelCount = 0; + this->maxBoneCount = 0; + this->textureCount = 0; + this->unknown_0170 = 0; + CFile file; + + if (!file.Open(name, 0, true, false)) { + return false; + } + + this->file = GrannyReadEntireFileFromMemory(file.GetSize(), file.GetData()); + file.Close(); + + if (!this->file) { + return false; + } + + granny_file_info* info = GrannyGetFileInfo(this->file); + std::strcpy(this->fileName, name); + + if (!info) { + ShowErrorDialog(GetRenderSystemHolder()->system, "Unable to access file data .gr2", 0); + } else { + this->textureCount = info->textureCount; + this->modelCount = info->modelCount; + + if (this->instance) { + this->FreeInstance(); + } + + GrannyModelInstance* instance = new GrannyModelInstance; + this->instance = instance; + granny_model* model = info->models[0]; + const int boneCount = model->skeleton->boneCount; + + if (this->maxBoneCount < boneCount) { + this->maxBoneCount = boneCount; + } + + instance->instance = GrannyInstantiateModel(model); + instance->worldPose = GrannyNewWorldPose(boneCount); + instance->meshCount = model->meshBindingCount; + instance->meshes = new GrannyMeshEntry[instance->meshCount]; + + for (int index = 0; index < instance->meshCount; ++index) { + GrannyMeshEntry& entry = instance->meshes[index]; + granny_mesh* mesh = model->meshBindings[index].mesh; + entry.mesh = mesh; + granny_skeleton* skeleton = GrannyGetSourceSkeleton(instance->instance); + entry.binding = GrannyNewMeshBinding(mesh, skeleton, skeleton); + + const unsigned int indexCount = GrannyGetMeshIndexCount(mesh); + entry.indices = new std::uint16_t[indexCount]; + if (indexCount != 0) { + GrannyCopyMeshIndices(mesh, 2, entry.indices); + } + + const int vertexBytes = GrannyGetMeshVertexCount(mesh) * 32; + if (GrannyMeshIsRigid(mesh)) { + entry.deformer = nullptr; + } else { + if (this->deformBufferSize < vertexBytes) { + this->deformBufferSize = vertexBytes; + } + + entry.deformer = GrannyNewMeshDeformer(GrannyGetMeshVertexType(mesh), GrannyPNT332VertexType, 2); + if (!entry.deformer) { + ShowErrorDialog(GetRenderSystemHolder()->system, "Granny didn't find a matching deformer for the vertex format used by mesh", 0); + } + } + } + + if (info->animationCount != 0) { + granny_animation* animation = nullptr; + + if (char* extension = std::strchr(this->fileName, '.')) { + *extension = '\0'; + } + + if (granny_file* animationFile = this->ReadAnimationFile(this->fileName, "")) { + if (granny_file_info* animationInfo = GrannyGetFileInfo(animationFile)) { + if (!instance->instance || animationInfo->animationCount != 1) { + ShowErrorDialog(GetRenderSystemHolder()->system, "This sample only supports single-animation files", 0); + this->animations[job][action] = nullptr; + return false; + } + + animation = animationInfo->animations[0]; + } + } + + this->animations[job][action] = animation; + + if (!animation) { + return false; + } + } + + this->localPose = GrannyNewLocalPose(this->maxBoneCount); + + if (this->deformBufferSize != 0) { + this->unknown_0170 = 4; + } + + result = true; + } + + GrannyFreeFileSection(this->file, 1); + GrannyFreeFileSection(this->file, 2); + GrannyFreeFileSection(this->file, 4); + GrannyFreeFileSection(this->file, 5); + this->unknown_0000 = 1920.0f; + return result; +} + +// OFFSET: 0x00757270 +// FUNCTION: fn_08004 +granny_control* C3dGrannyModelRes::PlayAnimation(unsigned action, granny_model_instance* instance, granny_control* control, int loopCount) { + if (control) { + GrannySetControlActive(control, true); + return control; + } + + const unsigned job = this->job; + GrannyAnimationLibrary* library = this->animations; + granny_animation* const& animation = library->animations[job][action]; + + if (!animation) { + g_modelPath[0] = '\0'; + + if (job > 9 || action > 4) { + return nullptr; + } + + if (action == 0) { + std::sprintf(g_modelPath, "model\\3dmob\\%s", this->m_context->jobNames.Lookup(g_animationJobs[job], -1)); + } else { + std::sprintf(g_modelPath, "model\\3dmob_bone\\%d_%s.gr2", job, g_animationNames[action]); + } + + if (!g_modelPath[0] || !ResourceExists(g_modelPath, 0)) { + return nullptr; + } + + if (job != 1) { + library->Load(g_modelPath, job, action); + } + + if (!animation) { + return nullptr; + } + } + + granny_control* result = GrannyPlayControlledAnimation(0.0f, animation, instance); + if (!result) { + return nullptr; + } + + GrannySetControlLoopCount(result, loopCount); + return result; +} + +// OFFSET: 0x00758710 +// FUNCTION: fn_08008 +bool C3dGrannyModelRes::ProjectBounds(float* rect, const AffineMatrix& view, const AffineMatrix& world, const float* eye) const { + AffineMatrix matrix; + matrix.SetZRotation(3.141592f); + const float* m = matrix.values; + const float x = this->position[1] * m[3] + this->position[0] * m[0] + this->position[2] * m[6] + m[9]; + const float y = this->position[0] * m[1] + this->position[1] * m[4] + this->position[2] * m[7] + m[10]; + const float z = this->position[0] * m[2] + this->position[1] * m[5] + this->position[2] * m[8] + m[11]; + matrix.Compose(world, view); + + const float screenX = y * m[3] + x * m[0] + z * m[6] + m[9]; + const float screenY = x * m[1] + y * m[4] + z * m[7] + m[10]; + const float depth = y * m[5] + x * m[2] + z * m[8] + m[11]; + const float deltaY = eye[1] - y; + const float deltaX = eye[0] - x; + const float deltaZ = eye[2] - z; + const float distance = SquareRoot(deltaY * deltaY + deltaX * deltaX + deltaZ * deltaZ); + const float slope = std::min(std::fabs(1.0f / distance * deltaY), 1.0f); + const float height = this->unknown_03A4 - (this->unknown_03A4 - this->unknown_03A0) * slope; + const float halfWidth = SquareRoot(this->unknown_03A0 * this->unknown_03A0 * 0.5f); + const float halfHeight = SquareRoot(height * height * 0.5f); + const float inverseDepth = 1.0f / depth; + + rect[4] = inverseDepth; + rect[0] = (screenX - halfWidth) * g_renderer->viewport.scaleX * inverseDepth + static_cast(g_renderer->viewport.clipCenterX); + rect[1] = (screenY - halfHeight) * g_renderer->viewport.scaleY * inverseDepth + static_cast(g_renderer->viewport.clipCenterY); + rect[2] = (halfWidth + screenX) * g_renderer->viewport.scaleX * inverseDepth + static_cast(g_renderer->viewport.clipCenterX); + rect[3] = (halfHeight + screenY) * g_renderer->viewport.scaleY * inverseDepth + static_cast(g_renderer->viewport.clipCenterY); + + const unsigned width = g_renderer->viewport.width; + const unsigned screenHeight = g_renderer->viewport.height; + return !(static_cast(rect[0]) > width && static_cast(rect[2]) > width && static_cast(rect[1]) > screenHeight && + static_cast(rect[3]) > screenHeight); +} + +// OFFSET: 0x00757850 +// FUNCTION: fn_08007 +void AnimatedModelNode::Shade(const float* matrix, int frame, const float* light, const float* diffuse, const float* ambient, int shadeType, int alpha) { + // GLOBAL: gl_24735 + static ShadeVector faceNormals[30000]; + // GLOBAL: gl_24736 + static ShadeVector vertexNormals[30000]; + std::list groups[32]; + auto* colors = reinterpret_cast*>(this->faceNormals); + + if (shadeType == 0) { + for (int index = 0; index < this->faceCount; ++index) { + const std::uint32_t color = (alpha << 24) + 0xFFFFFF; + colors[index][0] = color; + colors[index][1] = color; + colors[index][2] = color; + } + } else if (shadeType == 1) { + for (int index = 0; index < this->faceCount; ++index) { + const AnimatedModelFace& face = this->faces[index]; + const std::array* vertices = this->frames[frame].vertices; + const std::array& v0 = vertices[face.vertices[0]]; + const std::array& v1 = vertices[face.vertices[1]]; + const std::array& v2 = vertices[face.vertices[2]]; + const float x2 = v2[0] * matrix[0] + v2[1] * matrix[3] + v2[2] * matrix[6] + matrix[9]; + const float y2 = v2[0] * matrix[1] + v2[1] * matrix[4] + v2[2] * matrix[7] + matrix[10]; + const float z2 = v2[0] * matrix[2] + v2[1] * matrix[5] + v2[2] * matrix[8] + matrix[11]; + const float ax = x2 - (matrix[0] * v0[0] + v0[1] * matrix[3] + v0[2] * matrix[6] + matrix[9]); + const float ay = y2 - (matrix[1] * v0[0] + matrix[4] * v0[1] + matrix[7] * v0[2] + matrix[10]); + const float az = z2 - (matrix[2] * v0[0] + matrix[5] * v0[1] + matrix[8] * v0[2] + matrix[11]); + const float bx = x2 - (v1[0] * matrix[0] + v1[1] * matrix[3] + v1[2] * matrix[6] + matrix[9]); + const float by = y2 - (v1[0] * matrix[1] + v1[1] * matrix[4] + v1[2] * matrix[7] + matrix[10]); + const float bz = z2 - (v1[0] * matrix[2] + v1[1] * matrix[5] + v1[2] * matrix[8] + matrix[11]); + const float nx = by * az - bz * ay; + const float ny = bz * ax - bx * az; + const float nz = bx * ay - by * ax; + const float inverse = 1.0f / SquareRoot(ny * ny + nx * nx + nz * nz); + const float intensity = std::max(0.0f, nx * inverse * light[0] + ny * inverse * light[1] + nz * inverse * light[2]); + const float red = std::min(intensity * diffuse[0] + ambient[0], 1.0f); + const float green = std::min(intensity * diffuse[1] + ambient[1], 1.0f); + const float blue = std::min(intensity * diffuse[2] + ambient[2], 1.0f); + + for (int corner = 0; corner < 3; ++corner) { + const int source = this->sharedTextureVertices ? 0 : frame; + const float scale = this->frames[source].textureVertices[face.textureVertices[corner]].shaded ? 128.0f : 255.0f; + colors[index][corner] = ((((alpha << 8) | static_cast(scale * red)) << 8 | static_cast(scale * green)) << 8) | static_cast(scale * blue); + } + } + } else if (shadeType == 2) { + for (int index = 0; index < this->faceCount; ++index) { + const AnimatedModelFace& face = this->faces[index]; + const std::array* vertices = this->frames[frame].vertices; + const std::array& v0 = vertices[face.vertices[0]]; + const std::array& v1 = vertices[face.vertices[1]]; + const std::array& v2 = vertices[face.vertices[2]]; + const float x2 = v2[0] * matrix[0] + v2[1] * matrix[3] + v2[2] * matrix[6] + matrix[9]; + const float y2 = v2[0] * matrix[1] + v2[1] * matrix[4] + v2[2] * matrix[7] + matrix[10]; + const float z2 = v2[0] * matrix[2] + v2[1] * matrix[5] + v2[2] * matrix[8] + matrix[11]; + const float ax = x2 - (v0[0] * matrix[0] + v0[1] * matrix[3] + v0[2] * matrix[6] + matrix[9]); + const float ay = y2 - (matrix[1] * v0[0] + matrix[4] * v0[1] + matrix[7] * v0[2] + matrix[10]); + const float az = z2 - (matrix[2] * v0[0] + matrix[5] * v0[1] + matrix[8] * v0[2] + matrix[11]); + const float bx = x2 - (v1[0] * matrix[0] + v1[1] * matrix[3] + v1[2] * matrix[6] + matrix[9]); + const float by = y2 - (v1[0] * matrix[1] + v1[1] * matrix[4] + v1[2] * matrix[7] + matrix[10]); + const float bz = z2 - (v1[0] * matrix[2] + v1[1] * matrix[5] + v1[2] * matrix[8] + matrix[11]); + ShadeVector& normal = faceNormals[index]; + normal.x = by * az - bz * ay; + normal.y = ax * bz - bx * az; + normal.z = bx * ay - ax * by; + const float inverse = 1.0f / SquareRoot(normal.y * normal.y + normal.x * normal.x + normal.z * normal.z); + normal.x = inverse * normal.x; + normal.y = inverse * normal.y; + normal.z = inverse * normal.z; + groups[face.smoothGroup].push_back(index); + } + + for (int group = 0; group < 32; ++group) { + if (groups[group].empty()) { + continue; + } + + for (int vertex = 0; vertex < this->vertexCount; ++vertex) { + ShadeVector& normal = vertexNormals[vertex]; + normal.x = 0.0f; + normal.y = 0.0f; + normal.z = 0.0f; + + for (int index = 0; index < this->faceCount; ++index) { + const AnimatedModelFace& face = this->faces[index]; + if (face.smoothGroup == group && (face.vertices[0] == vertex || face.vertices[1] == vertex || face.vertices[2] == vertex)) { + normal.x = faceNormals[index].x + normal.x; + normal.y = faceNormals[index].y + normal.y; + normal.z = normal.z + faceNormals[index].z; + } + } + + if (SquareRoot(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z) != 0.0f) { + const float inverse = 1.0f / SquareRoot(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z); + normal.x = inverse * normal.x; + normal.y = inverse * normal.y; + normal.z = inverse * normal.z; + } + } + + for (int index : groups[group]) { + const AnimatedModelFace& face = this->faces[index]; + + for (int corner = 0; corner < 3; ++corner) { + const ShadeVector& normal = vertexNormals[face.vertices[corner]]; + const int source = this->sharedTextureVertices ? 0 : frame; + const float intensity = std::max(0.0f, normal.y * light[1] + light[0] * normal.x + normal.z * light[2]); + const float red = std::min(intensity * diffuse[0] + ambient[0], 1.0f); + const float green = std::min(intensity * diffuse[1] + ambient[1], 1.0f); + const float blue = std::min(intensity * diffuse[2] + ambient[2], 1.0f); + const float scale = this->frames[source].textureVertices[face.textureVertices[corner]].shaded ? 128.0f : 255.0f; + colors[index][corner] = ((((alpha << 8) | static_cast(scale * red)) << 8 | static_cast(green * scale)) << 8) | static_cast(blue * scale); + } + } + } + } else { + for (int index = 0; index < this->faceCount; ++index) { + const std::uint32_t color = (alpha << 24) + 0xFFFFFF; + colors[index][0] = color; + colors[index][1] = color; + colors[index][2] = color; + } + + ShowErrorDialog(GetRenderSystemHolder()->system, "Invalid Shade Type", 0); + } + + for (AnimatedModelNode* child : this->children) { + child->Shade(matrix, frame, light, diffuse, ambient, shadeType, alpha); + } +} diff --git a/Source/Resource/Models/ModelResource.h b/Source/Resource/Models/ModelResource.h index eae80c6f..90e02e98 100644 --- a/Source/Resource/Models/ModelResource.h +++ b/Source/Resource/Models/ModelResource.h @@ -11,6 +11,7 @@ class ResourceBytes; class TextureCache; +struct JobNames; struct ResourceByteReader; class C3dModelRes; @@ -94,6 +95,7 @@ struct ModelResourceContext { ResourceBytes& file; TextureCache& textures; CRenderSystemBase*& renderSystem; + JobNames& jobNames; }; class C3dModelRes : public CRes {