2021-01-18 04:53:24 -05:00
|
|
|
// Portion of this source is taken from MoonAdditions https://github.com/THE-FYP/MoonAdditions
|
|
|
|
|
|
|
|
// Copyright (c) 2012 DK22Pac
|
|
|
|
// Copyright (c) 2017 FYP
|
|
|
|
// Copyright (c) 2021 Grinch_
|
|
|
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
// SOFTWARE.
|
|
|
|
|
2021-09-20 08:41:40 -04:00
|
|
|
#include "paint.h"
|
2020-12-02 16:19:16 -05:00
|
|
|
#include "NodeName.h"
|
2021-10-24 18:08:00 -04:00
|
|
|
#include "pch.h"
|
2021-09-20 08:41:40 -04:00
|
|
|
#include "util.h"
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-09-20 08:41:40 -04:00
|
|
|
Paint::Paint()
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
Events::vehicleRenderEvent.before += [](CVehicle *pVeh) {
|
|
|
|
VehData &data = m_VehData.Get(pVeh);
|
|
|
|
|
|
|
|
// reset custom color if color id changed
|
|
|
|
if (pVeh->m_nPrimaryColor != data.primary_color || pVeh->m_nSecondaryColor != data.secondary_color)
|
|
|
|
{
|
|
|
|
for (auto &it : data.materialProperties)
|
|
|
|
data.resetMaterialColor(it.first);
|
|
|
|
|
|
|
|
data.primary_color = pVeh->m_nPrimaryColor;
|
|
|
|
data.secondary_color = pVeh->m_nSecondaryColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &it : data.materialProperties)
|
|
|
|
{
|
|
|
|
if (it.second._recolor)
|
|
|
|
{
|
|
|
|
it.second._originalColor = it.first->color;
|
|
|
|
it.first->color = it.second._color;
|
|
|
|
it.second._originalGeometryFlags = it.second._geometry->flags;
|
|
|
|
it.second._geometry->flags |= rpGEOMETRYMODULATEMATERIALCOLOR;
|
|
|
|
}
|
|
|
|
if (it.second._retexture)
|
|
|
|
{
|
|
|
|
auto tex = it.second._texture;
|
|
|
|
if (tex)
|
|
|
|
{
|
|
|
|
it.second._originalTexture = it.first->texture;
|
|
|
|
it.first->texture = tex;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
it.second._retexture = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ThiscallEvent<AddressList<0x55332A, H_CALL>, PRIORITY_BEFORE, ArgPickN<CVehicle *, 0>, void(CVehicle *)>
|
|
|
|
vehicleResetAfterRender;
|
|
|
|
vehicleResetAfterRender += [](CVehicle *pVeh) {
|
|
|
|
for (auto &it : m_VehData.Get(pVeh).materialProperties)
|
|
|
|
{
|
|
|
|
if (it.second._recolor)
|
|
|
|
{
|
|
|
|
it.first->color = it.second._originalColor;
|
|
|
|
it.second._geometry->flags = it.second._originalGeometryFlags;
|
|
|
|
}
|
|
|
|
if (it.second._retexture)
|
|
|
|
{
|
|
|
|
it.first->texture = it.second._originalTexture;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::VehData::setMaterialColor(RpMaterial *material, RpGeometry *geometry, RwRGBA color, bool filter_mat)
|
2021-01-18 04:53:24 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
auto &matProps = materialProperties[material];
|
|
|
|
|
|
|
|
if (!filter_mat || (material->color.red == 0x3C && material->color.green == 0xFF && material->color.blue == 0x00) ||
|
|
|
|
(material->color.red == 0xFF && material->color.green == 0x00 && material->color.blue == 0xAF))
|
|
|
|
{
|
|
|
|
matProps._recolor = true;
|
|
|
|
matProps._color = color;
|
|
|
|
matProps._geometry = geometry;
|
|
|
|
}
|
2021-01-18 04:53:24 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::VehData::setMaterialTexture(RpMaterial *material, RwTexture *texture, bool filter_mat)
|
2021-01-18 04:53:24 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
auto &matProps = materialProperties[material];
|
|
|
|
|
|
|
|
if (!filter_mat || (material->color.red == 0x3C && material->color.green == 0xFF && material->color.blue == 0x00) ||
|
|
|
|
(material->color.red == 0xFF && material->color.green == 0x00 && material->color.blue == 0xAF))
|
|
|
|
{
|
|
|
|
matProps._retexture = true;
|
|
|
|
matProps._texture = texture;
|
|
|
|
}
|
2021-01-18 04:53:24 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::VehData::resetMaterialColor(RpMaterial *material)
|
2021-01-18 04:53:24 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
auto &matProps = materialProperties[material];
|
|
|
|
matProps._recolor = false;
|
|
|
|
matProps._color = {0, 0, 0, 0};
|
2021-01-18 04:53:24 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::VehData::resetMaterialTexture(RpMaterial *material)
|
2021-01-18 04:53:24 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
auto &matProps = materialProperties[material];
|
|
|
|
matProps._retexture = false;
|
|
|
|
matProps._texture = nullptr;
|
2021-01-18 04:53:24 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::NodeWrapperRecursive(RwFrame *frame, CVehicle *pVeh, std::function<void(RwFrame *)> func)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
if (frame)
|
|
|
|
{
|
|
|
|
func(frame);
|
|
|
|
|
|
|
|
if (RwFrame *newFrame = frame->child)
|
|
|
|
NodeWrapperRecursive(newFrame, pVeh, func);
|
|
|
|
if (RwFrame *newFrame = frame->next)
|
|
|
|
NodeWrapperRecursive(newFrame, pVeh, func);
|
|
|
|
}
|
|
|
|
return;
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::UpdateNodeListRecursive(CVehicle *pVeh)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
RwFrame *frame = (RwFrame *)pVeh->m_pRwClump->object.parent;
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
NodeWrapperRecursive(frame, pVeh, [](RwFrame *frame) {
|
|
|
|
const std::string name = GetFrameNodeName(frame);
|
2020-12-02 16:19:16 -05:00
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
if (!(std::find(veh_nodes::names_vec.begin(), veh_nodes::names_vec.end(), name) != veh_nodes::names_vec.end()))
|
|
|
|
veh_nodes::names_vec.push_back(name);
|
|
|
|
});
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::SetNodeColor(CVehicle *pVeh, std::string node_name, CRGBA color, bool filter_mat)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
RwFrame *frame = (RwFrame *)pVeh->m_pRwClump->object.parent;
|
|
|
|
|
|
|
|
NodeWrapperRecursive(frame, pVeh, [&](RwFrame *frame) {
|
|
|
|
const std::string name = GetFrameNodeName(frame);
|
|
|
|
|
|
|
|
struct ST
|
|
|
|
{
|
|
|
|
CRGBA _color;
|
|
|
|
bool _filter;
|
|
|
|
} st;
|
|
|
|
|
|
|
|
st._color = color;
|
|
|
|
st._filter = filter_mat;
|
|
|
|
|
|
|
|
if (node_name == "Default" || node_name == name)
|
|
|
|
{
|
|
|
|
RwFrameForAllObjects(
|
|
|
|
frame,
|
|
|
|
[](RwObject *object, void *data) -> RwObject * {
|
|
|
|
if (object->type == rpATOMIC)
|
|
|
|
{
|
|
|
|
RpAtomic *atomic = reinterpret_cast<RpAtomic *>(object);
|
|
|
|
|
|
|
|
ST *st = reinterpret_cast<ST *>(data);
|
|
|
|
CRGBA *color = &st->_color;
|
|
|
|
bool filter_mat = st->_filter;
|
|
|
|
|
|
|
|
VehData &data = m_VehData.Get(FindPlayerPed()->m_pVehicle);
|
|
|
|
|
|
|
|
for (int i = 0; i < atomic->geometry->matList.numMaterials; ++i)
|
|
|
|
data.setMaterialColor(atomic->geometry->matList.materials[i], atomic->geometry,
|
|
|
|
{color->r, color->g, color->b, 255}, filter_mat);
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
&st);
|
|
|
|
}
|
|
|
|
});
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::SetNodeTexture(CVehicle *pVeh, std::string node_name, std::string texturename, bool filter_mat)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
RwFrame *frame = (RwFrame *)pVeh->m_pRwClump->object.parent;
|
|
|
|
RwTexture *texture = nullptr;
|
|
|
|
|
|
|
|
for (auto const &tex : m_TextureData.m_ImagesList)
|
|
|
|
{
|
|
|
|
if (tex.get()->m_FileName == texturename)
|
|
|
|
{
|
|
|
|
texture = tex.get()->m_pRwTexture;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NodeWrapperRecursive(frame, pVeh, [&](RwFrame *frame) {
|
|
|
|
const std::string name = GetFrameNodeName(frame);
|
|
|
|
|
|
|
|
struct ST
|
|
|
|
{
|
|
|
|
RwTexture *_tex;
|
|
|
|
bool _filter;
|
|
|
|
} st;
|
|
|
|
|
|
|
|
st._tex = texture;
|
|
|
|
st._filter = filter_mat;
|
|
|
|
|
|
|
|
if (node_name == "Default" || node_name == name)
|
|
|
|
{
|
|
|
|
RwFrameForAllObjects(
|
|
|
|
frame,
|
|
|
|
[](RwObject *object, void *data) -> RwObject * {
|
|
|
|
if (object->type == rpATOMIC)
|
|
|
|
{
|
|
|
|
RpAtomic *atomic = reinterpret_cast<RpAtomic *>(object);
|
|
|
|
|
|
|
|
ST *st = reinterpret_cast<ST *>(data);
|
|
|
|
VehData &data = m_VehData.Get(FindPlayerPed()->m_pVehicle);
|
|
|
|
|
|
|
|
for (int i = 0; i < atomic->geometry->matList.numMaterials; ++i)
|
|
|
|
{
|
|
|
|
data.setMaterialTexture(atomic->geometry->matList.materials[i], st->_tex, st->_filter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
&st);
|
|
|
|
}
|
|
|
|
});
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::ResetNodeColor(CVehicle *pVeh, std::string node_name)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
RwFrame *frame = (RwFrame *)pVeh->m_pRwClump->object.parent;
|
|
|
|
|
|
|
|
NodeWrapperRecursive(frame, pVeh, [&](RwFrame *frame) {
|
|
|
|
const std::string name = GetFrameNodeName(frame);
|
|
|
|
|
|
|
|
if (node_name == "Default" || node_name == name)
|
|
|
|
{
|
|
|
|
RwFrameForAllObjects(
|
|
|
|
frame,
|
|
|
|
[](RwObject *object, void *data) -> RwObject * {
|
|
|
|
if (object->type == rpATOMIC)
|
|
|
|
{
|
|
|
|
RpAtomic *atomic = reinterpret_cast<RpAtomic *>(object);
|
|
|
|
VehData &data = m_VehData.Get(FindPlayerPed()->m_pVehicle);
|
|
|
|
|
|
|
|
for (int i = 0; i < atomic->geometry->matList.numMaterials; ++i)
|
|
|
|
data.resetMaterialColor(atomic->geometry->matList.materials[i]);
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
});
|
2020-12-02 16:19:16 -05:00
|
|
|
}
|
|
|
|
|
2021-10-24 18:08:00 -04:00
|
|
|
void Paint::ResetNodeTexture(CVehicle *pVeh, std::string node_name)
|
2020-12-02 16:19:16 -05:00
|
|
|
{
|
2021-10-24 18:08:00 -04:00
|
|
|
RwFrame *frame = (RwFrame *)pVeh->m_pRwClump->object.parent;
|
|
|
|
|
|
|
|
NodeWrapperRecursive(frame, pVeh, [&](RwFrame *frame) {
|
|
|
|
const std::string name = GetFrameNodeName(frame);
|
|
|
|
|
|
|
|
if (node_name == "Default" || node_name == name)
|
|
|
|
{
|
|
|
|
RwFrameForAllObjects(
|
|
|
|
frame,
|
|
|
|
[](RwObject *object, void *data) -> RwObject * {
|
|
|
|
if (object->type == rpATOMIC)
|
|
|
|
{
|
|
|
|
RpAtomic *atomic = reinterpret_cast<RpAtomic *>(object);
|
|
|
|
|
|
|
|
VehData &data = m_VehData.Get(FindPlayerPed()->m_pVehicle);
|
|
|
|
|
|
|
|
for (int i = 0; i < atomic->geometry->matList.numMaterials; ++i)
|
|
|
|
data.resetMaterialTexture(atomic->geometry->matList.materials[i]);
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
});
|
2021-06-18 12:49:11 -04:00
|
|
|
}
|