feat: finish CKLight class.
- basically finish CKLight but no test now.
This commit is contained in:
parent
ff5a590cf4
commit
3eeb1f6cb6
@ -48,7 +48,7 @@ namespace LibCmo::CK2::ObjImpls {
|
||||
CKDWORD m_ZOrder; // replace the whole heavy CKSceneGraphNode
|
||||
|
||||
VxMath::VX_MOVEABLE_FLAGS m_MoveableFlags;
|
||||
// YYCMARK: This field is called m_EntityFlags in reverse project.
|
||||
// MARK: This field is called m_EntityFlags in reverse project.
|
||||
// I change this because I want to give it a more explicit name to make it is different with other flags.
|
||||
CK_3DENTITY_FLAGS m_3dEntityFlags;
|
||||
|
||||
|
@ -3,4 +3,246 @@
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKLight::CKLight(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CK3dEntity(ctx, ckid, name),
|
||||
m_LightData(), m_LightFlags(LightFlags::Active), m_LightPower(1.0f) {
|
||||
// Setup light data
|
||||
m_LightData.m_Type = VxMath::VXLIGHT_TYPE::VX_LIGHTPOINT;
|
||||
m_LightData.m_Diffuse = VxMath::VxColor(1.0f, 1.0f, 1.0f);
|
||||
m_LightData.m_Specular = VxMath::VxColor(0);
|
||||
m_LightData.m_Ambient = VxMath::VxColor(0.0f, 0.0f, 0.0f);
|
||||
m_LightData.m_Range = 5000.0f;
|
||||
m_LightData.m_Falloff = 1.0f;
|
||||
m_LightData.m_Attenuation0 = 1.0f;
|
||||
m_LightData.m_Attenuation1 = 0.0f;
|
||||
m_LightData.m_Attenuation2 = 0.0f;
|
||||
m_LightData.m_InnerSpotCone = 0.69813174f; // MARK: Perhaps 40 deg in rad.
|
||||
m_LightData.m_OuterSpotCone = 0.78539819f; // MARK: Perhaps 45 deg in rad.
|
||||
}
|
||||
|
||||
CKLight::~CKLight() {}
|
||||
|
||||
bool CKLight::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CK3dEntity::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// Save main data
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA);
|
||||
|
||||
// Combine light type and flags data.
|
||||
CKDWORD light_type_and_flags = static_cast<CKDWORD>(m_LightFlags) & 0xFFFFFF00u;
|
||||
light_type_and_flags |= static_cast<CKDWORD>(m_LightData.m_Type) & 0xFFu;
|
||||
chunk->WriteStruct(light_type_and_flags);
|
||||
|
||||
// Save diffuse color with constant 1.0 alpha factor.
|
||||
chunk->WriteStruct(m_LightData.m_Diffuse.ToARGB() | 0xFF000000u);
|
||||
|
||||
chunk->WriteStruct(m_LightData.m_Attenuation0);
|
||||
chunk->WriteStruct(m_LightData.m_Attenuation1);
|
||||
chunk->WriteStruct(m_LightData.m_Attenuation2);
|
||||
|
||||
chunk->WriteStruct(m_LightData.m_Range);
|
||||
|
||||
if (m_LightData.m_Type == VxMath::VXLIGHT_TYPE::VX_LIGHTSPOT) {
|
||||
chunk->WriteStruct(m_LightData.m_OuterSpotCone);
|
||||
chunk->WriteStruct(m_LightData.m_InnerSpotCone);
|
||||
chunk->WriteStruct(m_LightData.m_Falloff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save light power
|
||||
if (m_LightPower != 1.0f) {
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA2);
|
||||
chunk->WriteStruct(m_LightPower);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_LIGHT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKLight::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CK3dEntity::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// MARK: I drop the read process for too low version.
|
||||
// return false anyway.
|
||||
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MAJORCHANGE_VERSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read main data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA)) {
|
||||
// Read a DWORD storing light type and flags
|
||||
// Because the lowest byte in light flags always is 0x00,
|
||||
// so Virtools use it to store light type.
|
||||
// After removing light type component, the rest of data is light flags.
|
||||
// (do not need any SHIFT! It's okey that just set the lowest byte to zero.)
|
||||
CKDWORD light_type_and_flags;
|
||||
chunk->ReadStruct(light_type_and_flags);
|
||||
m_LightData.m_Type = static_cast<VxMath::VXLIGHT_TYPE>(light_type_and_flags & 0xFFu);
|
||||
m_LightFlags = static_cast<LightFlags>(light_type_and_flags & 0xFFFFFF00u);
|
||||
|
||||
CKDWORD dword_diffuse;
|
||||
chunk->ReadStruct(dword_diffuse);
|
||||
m_LightData.m_Diffuse = VxMath::VxColor(dword_diffuse);
|
||||
|
||||
chunk->ReadStruct(m_LightData.m_Attenuation0);
|
||||
chunk->ReadStruct(m_LightData.m_Attenuation1);
|
||||
chunk->ReadStruct(m_LightData.m_Attenuation2);
|
||||
|
||||
chunk->ReadStruct(m_LightData.m_Range);
|
||||
|
||||
if (m_LightData.m_Type == VxMath::VXLIGHT_TYPE::VX_LIGHTSPOT) {
|
||||
chunk->ReadStruct(m_LightData.m_OuterSpotCone);
|
||||
chunk->ReadStruct(m_LightData.m_InnerSpotCone);
|
||||
chunk->ReadStruct(m_LightData.m_Falloff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Read light power
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA2)) {
|
||||
chunk->ReadStruct(m_LightPower);
|
||||
} else {
|
||||
m_LightPower = 1.0f;
|
||||
}
|
||||
|
||||
// Correct light type to prevent accident out of range value.
|
||||
switch (m_LightData.m_Type) {
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTPOINT:
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTSPOT:
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTDIREC:
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTPARA:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
// reset it to point
|
||||
m_LightData.m_Type = VxMath::VXLIGHT_TYPE::VX_LIGHTPOINT;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma region Class Operations
|
||||
|
||||
VxMath::VXLIGHT_TYPE CKLight::GetType() const {
|
||||
return m_LightData.m_Type;
|
||||
}
|
||||
|
||||
void CKLight::SetType(VxMath::VXLIGHT_TYPE light_type) {
|
||||
m_LightData.m_Type = light_type;
|
||||
}
|
||||
|
||||
const VxMath::VxColor& CKLight::GetColor() const {
|
||||
return m_LightData.m_Diffuse;
|
||||
}
|
||||
|
||||
void CKLight::SetColor(const VxMath::VxColor& c) {
|
||||
m_LightData.m_Diffuse = c;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetConstantAttenuation() const {
|
||||
return m_LightData.m_Attenuation0;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetLinearAttenuation() const {
|
||||
return m_LightData.m_Attenuation1;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetQuadraticAttenuation() const {
|
||||
return m_LightData.m_Attenuation2;
|
||||
}
|
||||
|
||||
void CKLight::SetConstantAttenuation(CKFLOAT value) {
|
||||
m_LightData.m_Attenuation0 = value;
|
||||
}
|
||||
|
||||
void CKLight::SetLinearAttenuation(CKFLOAT value) {
|
||||
m_LightData.m_Attenuation1 = value;
|
||||
}
|
||||
|
||||
void CKLight::SetQuadraticAttenuation(CKFLOAT value) {
|
||||
m_LightData.m_Attenuation2 = value;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetRange() const {
|
||||
return m_LightData.m_Range;
|
||||
}
|
||||
|
||||
void CKLight::SetRange(CKFLOAT value) {
|
||||
m_LightData.m_Range = value;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetHotSpot() const {
|
||||
return m_LightData.m_InnerSpotCone;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetFalloff() const {
|
||||
return m_LightData.m_OuterSpotCone;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetFalloffShape() const {
|
||||
return m_LightData.m_Falloff;
|
||||
}
|
||||
|
||||
void CKLight::SetHotSpot(CKFLOAT value) {
|
||||
m_LightData.m_InnerSpotCone = value;
|
||||
}
|
||||
|
||||
void CKLight::SetFalloff(CKFLOAT value) {
|
||||
m_LightData.m_OuterSpotCone = value;
|
||||
}
|
||||
|
||||
void CKLight::SetFalloffShape(CKFLOAT value) {
|
||||
m_LightData.m_Falloff = value;
|
||||
}
|
||||
|
||||
bool CKLight::GetActivity() const {
|
||||
return YYCC::EnumHelper::Has(m_LightFlags, LightFlags::Active);
|
||||
}
|
||||
|
||||
void CKLight::Active(bool active) {
|
||||
if (active) {
|
||||
YYCC::EnumHelper::Add(m_LightFlags, LightFlags::Active);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_LightFlags, LightFlags::Active);
|
||||
}
|
||||
}
|
||||
|
||||
bool CKLight::GetSpecularFlag() const {
|
||||
return YYCC::EnumHelper::Has(m_LightFlags, LightFlags::Specular);
|
||||
}
|
||||
|
||||
void CKLight::SetSpecularFlag(bool specular) {
|
||||
if (specular) {
|
||||
YYCC::EnumHelper::Add(m_LightFlags, LightFlags::Specular);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_LightFlags, LightFlags::Specular);
|
||||
}
|
||||
}
|
||||
|
||||
CK3dEntity* CKLight::GetTarget() const {
|
||||
// Normal light do not support target.
|
||||
// So it always return nullptr.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CKLight::SetTarget(CK3dEntity* target) {
|
||||
// Normal light do not support target.
|
||||
// So, do nothing.
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetLightPower() const {
|
||||
return m_LightPower;
|
||||
}
|
||||
|
||||
void CKLight::SetLightPower(CKFLOAT power) {
|
||||
m_LightPower = power;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
|
@ -75,10 +75,15 @@ namespace LibCmo::CK2::ObjImpls {
|
||||
CKFLOAT m_InnerSpotCone;
|
||||
CKFLOAT m_OuterSpotCone;
|
||||
};
|
||||
enum class LightFlags : CKDWORD {
|
||||
None = 0,
|
||||
Active = 0x100u, /**< if set, this light is active. */
|
||||
Specular = 0x200u, /**< if set, this light has specular flag. */
|
||||
};
|
||||
|
||||
CKLightData m_LightData;
|
||||
// YYCMARK: This variable is called in m_Flags in reverse code.
|
||||
DWORD m_LightFlags;
|
||||
// MARK: This variable is called in m_Flags in reverse code.
|
||||
LightFlags m_LightFlags;
|
||||
CKFLOAT m_LightPower;
|
||||
};
|
||||
|
||||
|
@ -375,33 +375,6 @@ namespace LibCmo::VxMath {
|
||||
VxColor(CKFLOAT _r, CKFLOAT _g, CKFLOAT _b, CKFLOAT _a) : r(_r), g(_g), b(_b), a(_a) {}
|
||||
VxColor(CKDWORD argb) { FromARGB(argb); }
|
||||
YYCC_DEF_CLS_COPY_MOVE(VxColor);
|
||||
void FromARGB(CKDWORD argb) {
|
||||
a = ((argb & 0xFF000000) >> 24) / 255.0f;
|
||||
r = ((argb & 0x00FF0000) >> 16) / 255.0f;
|
||||
g = ((argb & 0x0000FF00) >> 8) / 255.0f;
|
||||
b = ((argb & 0x000000FF) >> 0) / 255.0f;
|
||||
}
|
||||
CKDWORD ToARGB() const {
|
||||
CKDWORD argb = 0;
|
||||
argb |= static_cast<CKDWORD>(a * 255.0f);
|
||||
argb <<= 8;
|
||||
argb |= static_cast<CKDWORD>(r * 255.0f);
|
||||
argb <<= 8;
|
||||
argb |= static_cast<CKDWORD>(g * 255.0f);
|
||||
argb <<= 8;
|
||||
argb |= static_cast<CKDWORD>(b * 255.0f);
|
||||
return argb;
|
||||
}
|
||||
void Regulate() {
|
||||
if (r > 1.0f) r = 1.0f;
|
||||
else if (r < 0.0f) r = 0.0f;
|
||||
if (g > 1.0f) g = 1.0f;
|
||||
else if (g < 0.0f) g = 0.0f;
|
||||
if (b > 1.0f) b = 1.0f;
|
||||
else if (b < 0.0f) b = 0.0f;
|
||||
if (a > 1.0f) a = 1.0f;
|
||||
else if (a < 0.0f) a = 0.0f;
|
||||
}
|
||||
CKFLOAT& operator[](size_t i) {
|
||||
switch (i) {
|
||||
case 0: return r;
|
||||
@ -429,6 +402,35 @@ namespace LibCmo::VxMath {
|
||||
if (auto cmp = b <=> rhs.b; cmp != 0) return cmp;
|
||||
return a <=> rhs.a;
|
||||
}
|
||||
|
||||
VxColor(CKFLOAT _r, CKFLOAT _g, CKFLOAT _b) : r(_r), g(_g), b(_b), a(1.0f) {}
|
||||
void FromARGB(CKDWORD argb) {
|
||||
a = ((argb & 0xFF000000) >> 24) / 255.0f;
|
||||
r = ((argb & 0x00FF0000) >> 16) / 255.0f;
|
||||
g = ((argb & 0x0000FF00) >> 8) / 255.0f;
|
||||
b = ((argb & 0x000000FF) >> 0) / 255.0f;
|
||||
}
|
||||
CKDWORD ToARGB() const {
|
||||
CKDWORD argb = 0;
|
||||
argb |= static_cast<CKDWORD>(a * 255.0f);
|
||||
argb <<= 8;
|
||||
argb |= static_cast<CKDWORD>(r * 255.0f);
|
||||
argb <<= 8;
|
||||
argb |= static_cast<CKDWORD>(g * 255.0f);
|
||||
argb <<= 8;
|
||||
argb |= static_cast<CKDWORD>(b * 255.0f);
|
||||
return argb;
|
||||
}
|
||||
void Regulate() {
|
||||
if (r > 1.0f) r = 1.0f;
|
||||
else if (r < 0.0f) r = 0.0f;
|
||||
if (g > 1.0f) g = 1.0f;
|
||||
else if (g < 0.0f) g = 0.0f;
|
||||
if (b > 1.0f) b = 1.0f;
|
||||
else if (b < 0.0f) b = 0.0f;
|
||||
if (a > 1.0f) a = 1.0f;
|
||||
else if (a < 0.0f) a = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user